Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

RIPEMD-160 Secure Hash for 3.0/7.0

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • RIPEMD-160 Secure Hash for 3.0/7.0

    #IF 0
    Code:
    =====================================================================
                            RIPEMD-160 SECURE HASH
    =====================================================================
       
    The RMD160 secure hash algorithm creates a 160-bit hash of an input 
    string of any length.  A hash is considered secure when it possesses 
    the following qualities:  1) Finding two input strings which hash to 
    the same value is considered not feasible.  2) Determining an input 
    string from its hash is considered not feasible.  
       
    From the RIPEMD-160 home page:
       User agrees to give due credit to K.U.Leuven in scientific 
       publications or communications in relation with the use of the 
       RIPEMD-160 software as follows: RIPEMD-160 software written by 
       Antoon Bosselaers, available at 
       http://www.esat.kuleuven.ac.be/~cosicart/ps/AB-9601/.  
       
    The PowerBASIC implementation appearing below is based on that of Brian 
    Gladman, which is available here: 
     http://fp.gladman.plus.com/cryptography_technology/ 
       
    This PB implementation is hereby placed in the public domain.  Use it 
    as you wish.  My hope is discourage reliance on home-grown encryption 
    schemes in favor of well-examined, strong, freely available 
    algorithms. 
       
    In this posting, test-bed code appears below the RMD160.BAS file 
    contents.  All code requires PB compiler releases 3.0/7.0 or later.
    All code compiles with either PBCC or PBWin.
       
       
    <U>Implementation Notes</U>
       
    -- The algorithm operates on plaintext blocks of 64 bytes.  Padding 
    of final blocks < 64 bytes must conform to a specific pattern and is 
    accomplished automatically by calling MDfinish().  The process of 
    hashing consists of the following essential steps: 
       
       ctx.pBuffer      = strptr(target_data)
       ctx.BufferLength = len(target_data)
       bufflen = ctx.BufferLength
       RMD160_Init ctx                           '<-- Initialize hashing of
       do while bufflen > (%BLOCKSIZE-1)         '    target_data
          Compress ctx                           '<-- hash target_data
          ctx.pBuffer = ctx.pBuffer + %BLOCKSIZE
          bufflen = bufflen - %BLOCKSIZE
       loop
       MDfinish ctx                              '<-- hash last block of 
                                                 '    target_data 
                                                 '    (if any) + padding
       
    -- Implementation here is handled through an #INCLUDE file.  No global 
    data is employed.  
       
    -- Because of the methods of data handling required for most 
    encryption and hashing, PowerBASIC's LONGs should be used to assure  
    correct bit-level results (as well as additional speed). 
       
    Greg Turgeon 07/2002
       
    #ENDIF
       
    %HASHLENGTH    = 20     'bytes
    %BLOCKSIZE     = 64     'bytes
       
    TYPE HASH_CONTEXT
    pBuffer      AS LONG PTR
    BufferLength AS LONG
    MD           AS LONG PTR
    MD_Buffer    AS STRING * %HASHLENGTH   '<-- Holds actual hash value
    END TYPE
       
    '--------------------
    ' Utility macros
    '--------------------
       
    '--------------------
    MACRO zbs(x)=string$(x,0) 'also defined in RMD160.BAS
       
    '--------------------
    MACRO FUNCTION rotlc(xx,constant_shiftval)
    retval = xx
    !  rol   retval, constant_shiftval
    END MACRO = retval
       
       
    '--------------------
    'RMD160 macros
    '--------------------
       
    '--------------------
    MACRO Fmd(x,y,z)=((x XOR y XOR z))
    '--------------------
    MACRO Gmd(x,y,z)=((x AND y) OR (NOT(x) AND z)) 
    '--------------------
    MACRO Hmd(x,y,z)=((x OR NOT(y)) XOR z)
    '--------------------
    MACRO Imd(x,y,z)=((x AND z) OR (y AND NOT(z))) 
    '--------------------
    MACRO Jmd(x,y,z)=(x XOR (y OR NOT(z)))
      
    '--------------------
    MACRO FFmd(a,b,c,d,e,x,s)
    a=a+Fmd(b,c,d)+x
    a=(rotlc(a,s))
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO GGmd(a,b,c,d,e,x,s)
    a=a+Gmd(b,c,d)+(x)+&h5a827999
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO HHmd(a,b,c,d,e,x,s)
    a=a+Hmd(b,c,d)+x+&h6ed9eba1
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    MACRO IImd(a,b,c,d,e,x,s)
    a=a+Imd(b,c,d)+x+&h8f1bbcdc
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO JJmd(a,b,c,d,e,x,s)
    a=a+Jmd(b,c,d)+x+&ha953fd4e
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO FFFmd(a,b,c,d,e,x,s)
    a=a+Fmd(b,c,d)+x
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO GGGmd(a,b,c,d,e,x,s)
    a=a+Gmd(b,c,d)+x+&h7a6d76e9
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO HHHmd(a,b,c,d,e,x,s)
    a=a+Hmd(b,c,d)+(x)+&h6d703ef3
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO IIImd(a,b,c,d,e,x,s)
    a=a+Imd(b,c,d)+x+&h5c4dd124
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO JJJmd(a,b,c,d,e,x,s)
    a=a+Jmd(b,c,d)+x+&h50a28be6
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
       
    DECLARE FUNCTION RMD160_Init(Ctx AS HASH_CONTEXT)
    DECLARE FUNCTION Compress(Ctx AS HASH_CONTEXT)
    DECLARE FUNCTION MDfinish(Ctx AS HASH_CONTEXT)
       
    '====================
    FUNCTION RMD160_Init(Ctx AS HASH_CONTEXT)
    Ctx.MD_Buffer = zbs(%HASHLENGTH)
    Ctx.MD        = varptr(Ctx.MD_Buffer)
    Ctx.@MD[0]    = &h67452301
    Ctx.@MD[1]    = &hefcdab89
    Ctx.@MD[2]    = &h98badcfe
    Ctx.@MD[3]    = &h10325476
    Ctx.@MD[4]    = &hc3d2e1f0
    END FUNCTION
       
       
    '====================
    FUNCTION Compress(Ctx AS HASH_CONTEXT)
    LOCAL aa&, bb&, cc&, dd&, ee&, aaa&, bbb&, ccc&, ddd&, eee&, x AS LONG PTR, retval&
       
    aa  = Ctx.@MD[0] : bb  = Ctx.@MD[1] : cc = Ctx.@MD[2]
    dd  = Ctx.@MD[3] : ee  = Ctx.@MD[4]
    aaa = Ctx.@MD[0] : bbb = Ctx.@MD[1] : ccc = Ctx.@MD[2]
    ddd = Ctx.@MD[3] : eee = Ctx.@MD[4]
       
    x = Ctx.pBuffer 'local copy
       
    '-- round 1 
    FFmd(aa,bb,cc,dd,ee,@x[0],11)
    FFmd(ee,aa,bb,cc,dd,@x[1],14)
    FFmd(dd,ee,aa,bb,cc,@x[2],15)
    FFmd(cc,dd,ee,aa,bb,@x[3],12)
    FFmd(bb,cc,dd,ee,aa,@x[4],5)
    FFmd(aa,bb,cc,dd,ee,@x[5],8)
    FFmd(ee,aa,bb,cc,dd,@x[6],7)
    FFmd(dd,ee,aa,bb,cc,@x[7],9)
    FFmd(cc,dd,ee,aa,bb,@x[8],11)
    FFmd(bb,cc,dd,ee,aa,@x[9],13)
    FFmd(aa,bb,cc,dd,ee,@x[10],14)
    FFmd(ee,aa,bb,cc,dd,@x[11],15)
    FFmd(dd,ee,aa,bb,cc,@x[12],6)
    FFmd(cc,dd,ee,aa,bb,@x[13],7)
    FFmd(bb,cc,dd,ee,aa,@x[14],9)
    FFmd(aa,bb,cc,dd,ee,@x[15],8)
       
    '-- round 2
    GGmd(ee,aa,bb,cc,dd,@x[7],7)
    GGmd(dd,ee,aa,bb,cc,@x[4],6)
    GGmd(cc,dd,ee,aa,bb,@x[13],8)
    GGmd(bb,cc,dd,ee,aa,@x[1],13)
    GGmd(aa,bb,cc,dd,ee,@x[10],11)
    GGmd(ee,aa,bb,cc,dd,@x[6],9)
    GGmd(dd,ee,aa,bb,cc,@x[15],7)
    GGmd(cc,dd,ee,aa,bb,@x[3],15)
    GGmd(bb,cc,dd,ee,aa,@x[12],7)
    GGmd(aa,bb,cc,dd,ee,@x[0],12)
    GGmd(ee,aa,bb,cc,dd,@x[9],15)
    GGmd(dd,ee,aa,bb,cc,@x[5],9)
    GGmd(cc,dd,ee,aa,bb,@x[2],11)
    GGmd(bb,cc,dd,ee,aa,@x[14],7)
    GGmd(aa,bb,cc,dd,ee,@x[11],13)
    GGmd(ee,aa,bb,cc,dd,@x[8],12)
       
    '-- round 3
    HHmd(dd,ee,aa,bb,cc,@x[3],11)
    HHmd(cc,dd,ee,aa,bb,@x[10],13)
    HHmd(bb,cc,dd,ee,aa,@x[14],6)
    HHmd(aa,bb,cc,dd,ee,@x[4],7)
    HHmd(ee,aa,bb,cc,dd,@x[9],14)
    HHmd(dd,ee,aa,bb,cc,@x[15],9)
    HHmd(cc,dd,ee,aa,bb,@x[8],13)
    HHmd(bb,cc,dd,ee,aa,@x[1],15)
    HHmd(aa,bb,cc,dd,ee,@x[2],14)
    HHmd(ee,aa,bb,cc,dd,@x[7],8)
    HHmd(dd,ee,aa,bb,cc,@x[0],13)
    HHmd(cc,dd,ee,aa,bb,@x[6],6)
    HHmd(bb,cc,dd,ee,aa,@x[13],5)
    HHmd(aa,bb,cc,dd,ee,@x[11],12)
    HHmd(ee,aa,bb,cc,dd,@x[5],7)
    HHmd(dd,ee,aa,bb,cc,@x[12],5)
       
    '-- round 4
    IImd(cc,dd,ee,aa,bb,@x[1],11)
    IImd(bb,cc,dd,ee,aa,@x[9],12)
    IImd(aa,bb,cc,dd,ee,@x[11],14)
    IImd(ee,aa,bb,cc,dd,@x[10],15)
    IImd(dd,ee,aa,bb,cc,@x[0],14)
    IImd(cc,dd,ee,aa,bb,@x[8],15)
    IImd(bb,cc,dd,ee,aa,@x[12],9)
    IImd(aa,bb,cc,dd,ee,@x[4],8)
    IImd(ee,aa,bb,cc,dd,@x[13],9)
    IImd(dd,ee,aa,bb,cc,@x[3],14)
    IImd(cc,dd,ee,aa,bb,@x[7],5)
    IImd(bb,cc,dd,ee,aa,@x[15],6)
    IImd(aa,bb,cc,dd,ee,@x[14],8)
    IImd(ee,aa,bb,cc,dd,@x[5],6)
    IImd(dd,ee,aa,bb,cc,@x[6],5)
    IImd(cc,dd,ee,aa,bb,@x[2],12)
       
    '-- round 5
    JJmd(bb,cc,dd,ee,aa,@x[4],9)
    JJmd(aa,bb,cc,dd,ee,@x[0],15)
    JJmd(ee,aa,bb,cc,dd,@x[5],5)
    JJmd(dd,ee,aa,bb,cc,@x[9],11)
    JJmd(cc,dd,ee,aa,bb,@x[7],6)
    JJmd(bb,cc,dd,ee,aa,@x[12],8)
    JJmd(aa,bb,cc,dd,ee,@x[2],13)
    JJmd(ee,aa,bb,cc,dd,@x[10],12)
    JJmd(dd,ee,aa,bb,cc,@x[14],5)
    JJmd(cc,dd,ee,aa,bb,@x[1],12)
    JJmd(bb,cc,dd,ee,aa,@x[3],13)
    JJmd(aa,bb,cc,dd,ee,@x[8],14)
    JJmd(ee,aa,bb,cc,dd,@x[11],11)
    JJmd(dd,ee,aa,bb,cc,@x[6],8)
    JJmd(cc,dd,ee,aa,bb,@x[15],5)
    JJmd(bb,cc,dd,ee,aa,@x[13],6)
       
    '-- parallel round 1
    JJJmd(aaa,bbb,ccc,ddd,eee,@x[5],8)
    JJJmd(eee,aaa,bbb,ccc,ddd,@x[14],9)
    JJJmd(ddd,eee,aaa,bbb,ccc,@x[7],9)
    JJJmd(ccc,ddd,eee,aaa,bbb,@x[0],11)
    JJJmd(bbb,ccc,ddd,eee,aaa,@x[9],13)
    JJJmd(aaa,bbb,ccc,ddd,eee,@x[2],15)
    JJJmd(eee,aaa,bbb,ccc,ddd,@x[11],15)
    JJJmd(ddd,eee,aaa,bbb,ccc,@x[4],5)
    JJJmd(ccc,ddd,eee,aaa,bbb,@x[13],7)
    JJJmd(bbb,ccc,ddd,eee,aaa,@x[6],7)
    JJJmd(aaa,bbb,ccc,ddd,eee,@x[15],8)
    JJJmd(eee,aaa,bbb,ccc,ddd,@x[8],11)
    JJJmd(ddd,eee,aaa,bbb,ccc,@x[1],14)
    JJJmd(ccc,ddd,eee,aaa,bbb,@x[10],14)
    JJJmd(bbb,ccc,ddd,eee,aaa,@x[3],12)
    JJJmd(aaa,bbb,ccc,ddd,eee,@x[12],6)
       
    '-- parallel round 2
    IIImd(eee,aaa,bbb,ccc,ddd,@x[6],9)
    IIImd(ddd,eee,aaa,bbb,ccc,@x[11],13)
    IIImd(ccc,ddd,eee,aaa,bbb,@x[3],15)
    IIImd(bbb,ccc,ddd,eee,aaa,@x[7],7)
    IIImd(aaa,bbb,ccc,ddd,eee,@x[0],12)
    IIImd(eee,aaa,bbb,ccc,ddd,@x[13],8)
    IIImd(ddd,eee,aaa,bbb,ccc,@x[5],9)
    IIImd(ccc,ddd,eee,aaa,bbb,@x[10],11)
    IIImd(bbb,ccc,ddd,eee,aaa,@x[14],7)
    IIImd(aaa,bbb,ccc,ddd,eee,@x[15],7)
    IIImd(eee,aaa,bbb,ccc,ddd,@x[8],12)
    IIImd(ddd,eee,aaa,bbb,ccc,@x[12],7)
    IIImd(ccc,ddd,eee,aaa,bbb,@x[4],6)
    IIImd(bbb,ccc,ddd,eee,aaa,@x[9],15)
    IIImd(aaa,bbb,ccc,ddd,eee,@x[1],13)
    IIImd(eee,aaa,bbb,ccc,ddd,@x[2],11)
       
    '-- parallel round 3
    HHHmd(ddd,eee,aaa,bbb,ccc,@x[15],9)
    HHHmd(ccc,ddd,eee,aaa,bbb,@x[5],7)
    HHHmd(bbb,ccc,ddd,eee,aaa,@x[1],15)
    HHHmd(aaa,bbb,ccc,ddd,eee,@x[3],11)
    HHHmd(eee,aaa,bbb,ccc,ddd,@x[7],8)
    HHHmd(ddd,eee,aaa,bbb,ccc,@x[14],6)
    HHHmd(ccc,ddd,eee,aaa,bbb,@x[6],6)
    HHHmd(bbb,ccc,ddd,eee,aaa,@x[9],14)
    HHHmd(aaa,bbb,ccc,ddd,eee,@x[11],12)
    HHHmd(eee,aaa,bbb,ccc,ddd,@x[8],13)
    HHHmd(ddd,eee,aaa,bbb,ccc,@x[12],5)
    HHHmd(ccc,ddd,eee,aaa,bbb,@x[2],14)
    HHHmd(bbb,ccc,ddd,eee,aaa,@x[10],13)
    HHHmd(aaa,bbb,ccc,ddd,eee,@x[0],13)
    HHHmd(eee,aaa,bbb,ccc,ddd,@x[4],7)
    HHHmd(ddd,eee,aaa,bbb,ccc,@x[13],5)
       
    '-- parallel round 4
    GGGmd(ccc,ddd,eee,aaa,bbb,@x[8],15)
    GGGmd(bbb,ccc,ddd,eee,aaa,@x[6],5)
    GGGmd(aaa,bbb,ccc,ddd,eee,@x[4],8)
    GGGmd(eee,aaa,bbb,ccc,ddd,@x[1],11)
    GGGmd(ddd,eee,aaa,bbb,ccc,@x[3],14)
    GGGmd(ccc,ddd,eee,aaa,bbb,@x[11],14)
    GGGmd(bbb,ccc,ddd,eee,aaa,@x[15],6)
    GGGmd(aaa,bbb,ccc,ddd,eee,@x[0],14)
    GGGmd(eee,aaa,bbb,ccc,ddd,@x[5],6)
    GGGmd(ddd,eee,aaa,bbb,ccc,@x[12],9)
    GGGmd(ccc,ddd,eee,aaa,bbb,@x[2],12)
    GGGmd(bbb,ccc,ddd,eee,aaa,@x[13],9)
    GGGmd(aaa,bbb,ccc,ddd,eee,@x[9],12)
    GGGmd(eee,aaa,bbb,ccc,ddd,@x[7],5)
    GGGmd(ddd,eee,aaa,bbb,ccc,@x[10],15)
    GGGmd(ccc,ddd,eee,aaa,bbb,@x[14],8)
       
    '-- parallel round 5
    FFFmd(bbb,ccc,ddd,eee,aaa,@x[12],8)
    FFFmd(aaa,bbb,ccc,ddd,eee,@x[15],5)
    FFFmd(eee,aaa,bbb,ccc,ddd,@x[10],12)
    FFFmd(ddd,eee,aaa,bbb,ccc,@x[4],9)
    FFFmd(ccc,ddd,eee,aaa,bbb,@x[1],12)
    FFFmd(bbb,ccc,ddd,eee,aaa,@x[5],5)
    FFFmd(aaa,bbb,ccc,ddd,eee,@x[8],14)
    FFFmd(eee,aaa,bbb,ccc,ddd,@x[7],6)
    FFFmd(ddd,eee,aaa,bbb,ccc,@x[6],8)
    FFFmd(ccc,ddd,eee,aaa,bbb,@x[2],13)
    FFFmd(bbb,ccc,ddd,eee,aaa,@x[13],6)
    FFFmd(aaa,bbb,ccc,ddd,eee,@x[14],5)
    FFFmd(eee,aaa,bbb,ccc,ddd,@x[0],15)
    FFFmd(ddd,eee,aaa,bbb,ccc,@x[3],13)
    FFFmd(ccc,ddd,eee,aaa,bbb,@x[9],11)
    FFFmd(bbb,ccc,ddd,eee,aaa,@x[11],11)
       
    '-- combine results
    ddd = ddd + cc + Ctx.@MD[1]
    Ctx.@MD[1] = Ctx.@MD[2] + dd + eee
    Ctx.@MD[2] = Ctx.@MD[3] + ee + aaa
    Ctx.@MD[3] = Ctx.@MD[4] + aa + bbb
    Ctx.@MD[4] = Ctx.@MD[0] + bb + ccc
    Ctx.@MD[0] = ddd
    END FUNCTION
       
       
    '=========================
    FUNCTION MakePadding$(BYVAL TotalBytes&)
    LOCAL padding$, buffbits&&, padbytes&
       
    buffbits = TotalBytes * 8
    padding = zbs(8)
    poke$ strptr(padding), peek$(varptr(buffbits),8)
       
    padbytes = %BLOCKSIZE - ((TotalBytes+9) AND (%BLOCKSIZE-1))
    function = chr$(&h80) + zbs(padbytes) + padding
    END FUNCTION
       
       
    '====================
    FUNCTION MDfinish(Ctx AS HASH_CONTEXT)
    LOCAL x_buffer$, x AS BYTE PTR, retval&, padding$, bytesleft&
       
    x_buffer$ = zbs(%BLOCKSIZE) : x = strptr(x_buffer$)
       
    padding = MakePadding$(Ctx.BufferLength)
    bytesleft = Ctx.BufferLength AND 63
    poke$ x, peek$(Ctx.pBuffer, bytesleft)
    poke$ x+bytesleft, padding
       
    Ctx.pBuffer = x
    Compress Ctx
    END FUNCTION
       
    '-- end RMD160.BAS
       
       
    '=====================================================================
    '                         RIPEMD-160 Test Bed code
    '               Compiles with either PBWIN 7.0+ or PBCC 3.0+
    '=====================================================================
    #COMPILE EXE
    #REGISTER NONE
    #DIM ALL
    '============
    DEFLNG A-Z
       
    '--------------------
    '-- Utility macros
    '--------------------
       
    #IF %def(%pb_win32)
       MACRO eol=$CR
       MACRO mbox(t)=msgbox t
    #ELSEIF %def(%pb_cc32)
       MACRO eol=$CRLF
       MACRO mbox(t)=stdout t
    #ENDIF
       
    '--------------------
    MACRO EnterCC
    #IF %def(%pb_cc32)
       LOCAL launched&
       if (cursory = 1) and (cursorx = 1) then launched = -1
    #ENDIF
    END MACRO
       
    '--------------------
    MACRO ExitCC
    #IF %def(%pb_cc32)
       if launched then
          input flush
          stdout "Press any key to end"
          waitkey$
       end if
    #ENDIF
    END MACRO
       
    ''--------------------
    'MACRO zbs(x)=string$(x,0) 'also defined in RMD160.BAS
       
    '%HASHLENGTH    = 20     'bytes
    '%BLOCKSIZE     = 64     'bytes
       
    'TYPE HASH_CONTEXT
    '  pBuffer      AS LONG PTR
    '  BufferLength AS LONG
    '  MD           AS LONG PTR
    '  MD_Buffer    AS STRING * %HASHLENGTH
    'END TYPE
       
       
    #INCLUDE "RMD160.BAS"
       
    DECLARE FUNCTION Hex2Show$(Buffer$)
       
    '====================
    FUNCTION PBMain&()
    LOCAL i&, plain$, hash$, shouldbe$, t$
    LOCAL ctx AS HASH_CONTEXT  ' defined in RMD160.BAS
    EnterCC
       
    '-- Standard RIPEMD-160 test vectors:
    plain    = ""        'empty string
    hash     = zbs(%HASHLENGTH)
    shouldbe = chr$(&h9c,&h11,&h85,&ha5,&hc5,&he9,&hfc,&h54,&h61,&h28,&h08,&h97,&h7e,&he8,&hf5,&h48,&hb2,&h25,&h8d,&h31)
    t = "plain:    " + plain + eol
    gosub DoRMD160
    t = t + "hash:     " + Hex2Show$(hash) + eol
    t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol + eol
       
    plain    = "a"
    hash     = zbs(%HASHLENGTH)
    shouldbe = chr$(&h0b,&hdc,&h9d,&h2d,&h25,&h6b,&h3e,&he9,&hda,&hae,&h34,&h7b,&he6,&hf4,&hdc,&h83,&h5a,&h46,&h7f,&hfe)
    t = T + "plain:    " + plain + eol
    gosub DoRMD160
    t = t + "hash:     " + Hex2Show$(hash) + eol
    t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol + eol
       
    plain    = "message digest" 
    hash     = zbs(%HASHLENGTH)
    shouldbe = chr$(&h5d,&h06,&h89,&hef,&h49,&hd2,&hfa,&he5,&h72,&hb8,&h81,&hb1,&h23,&ha8,&h5f,&hfa,&h21,&h59,&h5f,&h36)
    t = t + "plain:    " + plain + eol
    gosub DoRMD160
    t = t + "hash:     " + Hex2Show$(hash) + eol
    t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol + eol
       
       
    plain    = repeat$(1000000,"a")
    hash     = zbs(%HASHLENGTH)
    shouldbe = chr$(&h52,&h78,&h32,&h43,&hc1,&h69,&h7b,&hdb,&he1,&h6d,&h37,&hf9,&h7f,&h68,&hf0,&h83,&h25,&hdc,&h15,&h28)
    t = t + "Million chars test" + eol
    gosub DoRMD160
    t = t + "hash:     " + Hex2Show$(hash) + eol
    t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol + eol
       
    mbox(t)
       
    '============
    ExitPBMain:
    ExitCC
    exit function
       
    '============
    DoRMD160:
    REGISTER bufflen&
    ctx.pBuffer      = strptr(plain)
    ctx.BufferLength = len(plain)
    RMD160_Init ctx
       
    bufflen = ctx.BufferLength
    do while bufflen > (%BLOCKSIZE-1)
       Compress ctx
       ctx.pBuffer = ctx.pBuffer + %BLOCKSIZE
       bufflen = bufflen - %BLOCKSIZE
    loop
    MDfinish ctx
       
    hash = peek$(Ctx.MD, %HASHLENGTH)
    RETURN
    END FUNCTION
       
    '====================
    FUNCTION Hex2Show$(Buffer$)
    REGISTER i&
    LOCAL t$, b AS BYTE PTR
    b = strptr(Buffer$)
    for i = 0 to len(Buffer$)-1
       t = t + hex$(@b[i],2) + " "
    next i
    function = t
    END FUNCTION
       
    '-- end TESTBED.BAS
    [This message has been edited by Greg Turgeon (edited July 24, 2002).]

  • #2
    Code:
    #IF 0
    =====================================================================
                            RIPEMD-160 SECURE HASH
    =====================================================================
                          [See revision note below.]
       
    The RMD160 secure hash algorithm creates a 160-bit hash of an input 
    string of any length.  A hash is considered secure when it possesses 
    the following qualities:  1) Finding two input strings which hash to 
    the same value is considered not feasible.  2) Determining an input 
    string from its hash is considered not feasible.  
       
    From the RIPEMD-160 home page:
       User agrees to give due credit to K.U.Leuven in scientific 
       publications or communications in relation with the use of the 
       RIPEMD-160 software as follows: RIPEMD-160 software written by 
       Antoon Bosselaers, available at 
       http://www.esat.kuleuven.ac.be/~cosicart/ps/AB-9601/. 
       
    The PowerBASIC implementation appearing below is based on that of Brian 
    Gladman, which is available here: 
    http://fp.gladman.plus.com/cryptography_technology/
       
    This PB implementation is hereby placed in the public domain.  Use it 
    as you wish.  My hope is discourage reliance on home-grown encryption 
    schemes in favor of well-examined, strong, freely available 
    algorithms. 
       
    In this posting, test-bed code appears below the RMD160.BAS file 
    contents.  All code requires PB compiler releases 3.0/7.0 or later.
    All code compiles with either PBCC or PBWin.
       
       
    Implementation Notes
       
    -- The algorithm operates on plaintext blocks of 64 bytes.  Padding 
    of final blocks < 64 bytes must conform to a specific pattern and is 
    accomplished automatically by calling MDfinish().  The process of 
    hashing consists of the following essential steps: 
       
       ctx.pBuffer      = strptr(target_data)
       ctx.BufferLength = len(target_data)
       bufflen = ctx.BufferLength
       RMD160_Init ctx                           '<-- Initialize hashing of
       do while bufflen > (%BLOCKSIZE-1)         '    target_data
          Compress ctx                           '<-- hash target_data
          ctx.pBuffer = ctx.pBuffer + %BLOCKSIZE
          bufflen = bufflen - %BLOCKSIZE
       loop
       MDfinish ctx                              '<-- hash last block of 
                                                 '    target_data 
                                                 '    (if any) + padding
       
    -- Implementation here is handled through an #INCLUDE file.  No global 
    data is employed.  
       
    -- Because of the methods of data handling required for most 
    encryption and hashing, PowerBASIC's LONGs should be used to assure  
    correct bit-level results (as well as additional speed). 
       
    Greg Turgeon 07/2002
       
    ---------------------------------------------------------------------
    Rev. 9/2007:
    -- New MDfinish&() to avoid bad pointer with final blocks of certain 
       sizes
    ---------------------------------------------------------------------
    #ENDIF
       
    %HASHLENGTH    = 20     'bytes
    %BLOCKSIZE     = 64     'bytes
       
    TYPE HASH_CONTEXT
    pBuffer      AS LONG PTR
    BufferLength AS LONG
    MD           AS LONG PTR
    MD_Buffer    AS STRING * %HASHLENGTH   '<-- Holds actual hash value
    END TYPE
       
    '--------------------
    ' Utility macros
    '--------------------
       
    '--------------------
    MACRO zbs(x)=string$(x,0) 'also defined in RMD160.BAS
       
    '--------------------
    MACRO FUNCTION rotlc(xx,constant_shiftval)
    retval = xx
    !  rol   retval, constant_shiftval
    END MACRO = retval
       
       
    '--------------------
    'RMD160 macros
    '--------------------
       
    '--------------------
    MACRO Fmd(x,y,z)=((x XOR y XOR z))
    '--------------------
    MACRO Gmd(x,y,z)=((x AND y) OR (NOT(x) AND z)) 
    '--------------------
    MACRO Hmd(x,y,z)=((x OR NOT(y)) XOR z)
    '--------------------
    MACRO Imd(x,y,z)=((x AND z) OR (y AND NOT(z))) 
    '--------------------
    MACRO Jmd(x,y,z)=(x XOR (y OR NOT(z)))
      
    '--------------------
    MACRO FFmd(a,b,c,d,e,x,s)
    a=a+Fmd(b,c,d)+x
    a=(rotlc(a,s))
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO GGmd(a,b,c,d,e,x,s)
    a=a+Gmd(b,c,d)+(x)+&h5a827999
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO HHmd(a,b,c,d,e,x,s)
    a=a+Hmd(b,c,d)+x+&h6ed9eba1
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    MACRO IImd(a,b,c,d,e,x,s)
    a=a+Imd(b,c,d)+x+&h8f1bbcdc
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO JJmd(a,b,c,d,e,x,s)
    a=a+Jmd(b,c,d)+x+&ha953fd4e
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO FFFmd(a,b,c,d,e,x,s)
    a=a+Fmd(b,c,d)+x
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO GGGmd(a,b,c,d,e,x,s)
    a=a+Gmd(b,c,d)+x+&h7a6d76e9
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO HHHmd(a,b,c,d,e,x,s)
    a=a+Hmd(b,c,d)+(x)+&h6d703ef3
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO IIImd(a,b,c,d,e,x,s)
    a=a+Imd(b,c,d)+x+&h5c4dd124
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
    '--------------------
    MACRO JJJmd(a,b,c,d,e,x,s)
    a=a+Jmd(b,c,d)+x+&h50a28be6
    a=rotlc(a,s)
    a=a+e
    c=rotlc(c,10)
    END MACRO
       
       
    DECLARE FUNCTION RMD160_Init(Ctx AS HASH_CONTEXT)
    DECLARE FUNCTION Compress(Ctx AS HASH_CONTEXT)
    DECLARE FUNCTION MDfinish(Ctx AS HASH_CONTEXT)
       
    '====================
    FUNCTION RMD160_Init(Ctx AS HASH_CONTEXT)
    Ctx.MD_Buffer = zbs(%HASHLENGTH)
    Ctx.MD        = varptr(Ctx.MD_Buffer)
    Ctx.@MD[0]    = &h67452301
    Ctx.@MD[1]    = &hefcdab89
    Ctx.@MD[2]    = &h98badcfe
    Ctx.@MD[3]    = &h10325476
    Ctx.@MD[4]    = &hc3d2e1f0
    END FUNCTION
       
       
    '====================
    FUNCTION Compress(Ctx AS HASH_CONTEXT)
    LOCAL aa&, bb&, cc&, dd&, ee&, aaa&, bbb&, ccc&, ddd&, eee&, x AS LONG PTR, retval&
       
    aa  = Ctx.@MD[0] : bb  = Ctx.@MD[1] : cc = Ctx.@MD[2]
    dd  = Ctx.@MD[3] : ee  = Ctx.@MD[4]
    aaa = Ctx.@MD[0] : bbb = Ctx.@MD[1] : ccc = Ctx.@MD[2]
    ddd = Ctx.@MD[3] : eee = Ctx.@MD[4]
       
    x = Ctx.pBuffer 'local copy
       
    '-- round 1 
    FFmd(aa,bb,cc,dd,ee,@x[0],11)
    FFmd(ee,aa,bb,cc,dd,@x[1],14)
    FFmd(dd,ee,aa,bb,cc,@x[2],15)
    FFmd(cc,dd,ee,aa,bb,@x[3],12)
    FFmd(bb,cc,dd,ee,aa,@x[4],5)
    FFmd(aa,bb,cc,dd,ee,@x[5],8)
    FFmd(ee,aa,bb,cc,dd,@x[6],7)
    FFmd(dd,ee,aa,bb,cc,@x[7],9)
    FFmd(cc,dd,ee,aa,bb,@x[8],11)
    FFmd(bb,cc,dd,ee,aa,@x[9],13)
    FFmd(aa,bb,cc,dd,ee,@x[10],14)
    FFmd(ee,aa,bb,cc,dd,@x[11],15)
    FFmd(dd,ee,aa,bb,cc,@x[12],6)
    FFmd(cc,dd,ee,aa,bb,@x[13],7)
    FFmd(bb,cc,dd,ee,aa,@x[14],9)
    FFmd(aa,bb,cc,dd,ee,@x[15],8)
       
    '-- round 2
    GGmd(ee,aa,bb,cc,dd,@x[7],7)
    GGmd(dd,ee,aa,bb,cc,@x[4],6)
    GGmd(cc,dd,ee,aa,bb,@x[13],8)
    GGmd(bb,cc,dd,ee,aa,@x[1],13)
    GGmd(aa,bb,cc,dd,ee,@x[10],11)
    GGmd(ee,aa,bb,cc,dd,@x[6],9)
    GGmd(dd,ee,aa,bb,cc,@x[15],7)
    GGmd(cc,dd,ee,aa,bb,@x[3],15)
    GGmd(bb,cc,dd,ee,aa,@x[12],7)
    GGmd(aa,bb,cc,dd,ee,@x[0],12)
    GGmd(ee,aa,bb,cc,dd,@x[9],15)
    GGmd(dd,ee,aa,bb,cc,@x[5],9)
    GGmd(cc,dd,ee,aa,bb,@x[2],11)
    GGmd(bb,cc,dd,ee,aa,@x[14],7)
    GGmd(aa,bb,cc,dd,ee,@x[11],13)
    GGmd(ee,aa,bb,cc,dd,@x[8],12)
       
    '-- round 3
    HHmd(dd,ee,aa,bb,cc,@x[3],11)
    HHmd(cc,dd,ee,aa,bb,@x[10],13)
    HHmd(bb,cc,dd,ee,aa,@x[14],6)
    HHmd(aa,bb,cc,dd,ee,@x[4],7)
    HHmd(ee,aa,bb,cc,dd,@x[9],14)
    HHmd(dd,ee,aa,bb,cc,@x[15],9)
    HHmd(cc,dd,ee,aa,bb,@x[8],13)
    HHmd(bb,cc,dd,ee,aa,@x[1],15)
    HHmd(aa,bb,cc,dd,ee,@x[2],14)
    HHmd(ee,aa,bb,cc,dd,@x[7],8)
    HHmd(dd,ee,aa,bb,cc,@x[0],13)
    HHmd(cc,dd,ee,aa,bb,@x[6],6)
    HHmd(bb,cc,dd,ee,aa,@x[13],5)
    HHmd(aa,bb,cc,dd,ee,@x[11],12)
    HHmd(ee,aa,bb,cc,dd,@x[5],7)
    HHmd(dd,ee,aa,bb,cc,@x[12],5)
       
    '-- round 4
    IImd(cc,dd,ee,aa,bb,@x[1],11)
    IImd(bb,cc,dd,ee,aa,@x[9],12)
    IImd(aa,bb,cc,dd,ee,@x[11],14)
    IImd(ee,aa,bb,cc,dd,@x[10],15)
    IImd(dd,ee,aa,bb,cc,@x[0],14)
    IImd(cc,dd,ee,aa,bb,@x[8],15)
    IImd(bb,cc,dd,ee,aa,@x[12],9)
    IImd(aa,bb,cc,dd,ee,@x[4],8)
    IImd(ee,aa,bb,cc,dd,@x[13],9)
    IImd(dd,ee,aa,bb,cc,@x[3],14)
    IImd(cc,dd,ee,aa,bb,@x[7],5)
    IImd(bb,cc,dd,ee,aa,@x[15],6)
    IImd(aa,bb,cc,dd,ee,@x[14],8)
    IImd(ee,aa,bb,cc,dd,@x[5],6)
    IImd(dd,ee,aa,bb,cc,@x[6],5)
    IImd(cc,dd,ee,aa,bb,@x[2],12)
       
    '-- round 5
    JJmd(bb,cc,dd,ee,aa,@x[4],9)
    JJmd(aa,bb,cc,dd,ee,@x[0],15)
    JJmd(ee,aa,bb,cc,dd,@x[5],5)
    JJmd(dd,ee,aa,bb,cc,@x[9],11)
    JJmd(cc,dd,ee,aa,bb,@x[7],6)
    JJmd(bb,cc,dd,ee,aa,@x[12],8)
    JJmd(aa,bb,cc,dd,ee,@x[2],13)
    JJmd(ee,aa,bb,cc,dd,@x[10],12)
    JJmd(dd,ee,aa,bb,cc,@x[14],5)
    JJmd(cc,dd,ee,aa,bb,@x[1],12)
    JJmd(bb,cc,dd,ee,aa,@x[3],13)
    JJmd(aa,bb,cc,dd,ee,@x[8],14)
    JJmd(ee,aa,bb,cc,dd,@x[11],11)
    JJmd(dd,ee,aa,bb,cc,@x[6],8)
    JJmd(cc,dd,ee,aa,bb,@x[15],5)
    JJmd(bb,cc,dd,ee,aa,@x[13],6)
       
    '-- parallel round 1
    JJJmd(aaa,bbb,ccc,ddd,eee,@x[5],8)
    JJJmd(eee,aaa,bbb,ccc,ddd,@x[14],9)
    JJJmd(ddd,eee,aaa,bbb,ccc,@x[7],9)
    JJJmd(ccc,ddd,eee,aaa,bbb,@x[0],11)
    JJJmd(bbb,ccc,ddd,eee,aaa,@x[9],13)
    JJJmd(aaa,bbb,ccc,ddd,eee,@x[2],15)
    JJJmd(eee,aaa,bbb,ccc,ddd,@x[11],15)
    JJJmd(ddd,eee,aaa,bbb,ccc,@x[4],5)
    JJJmd(ccc,ddd,eee,aaa,bbb,@x[13],7)
    JJJmd(bbb,ccc,ddd,eee,aaa,@x[6],7)
    JJJmd(aaa,bbb,ccc,ddd,eee,@x[15],8)
    JJJmd(eee,aaa,bbb,ccc,ddd,@x[8],11)
    JJJmd(ddd,eee,aaa,bbb,ccc,@x[1],14)
    JJJmd(ccc,ddd,eee,aaa,bbb,@x[10],14)
    JJJmd(bbb,ccc,ddd,eee,aaa,@x[3],12)
    JJJmd(aaa,bbb,ccc,ddd,eee,@x[12],6)
       
    '-- parallel round 2
    IIImd(eee,aaa,bbb,ccc,ddd,@x[6],9)
    IIImd(ddd,eee,aaa,bbb,ccc,@x[11],13)
    IIImd(ccc,ddd,eee,aaa,bbb,@x[3],15)
    IIImd(bbb,ccc,ddd,eee,aaa,@x[7],7)
    IIImd(aaa,bbb,ccc,ddd,eee,@x[0],12)
    IIImd(eee,aaa,bbb,ccc,ddd,@x[13],8)
    IIImd(ddd,eee,aaa,bbb,ccc,@x[5],9)
    IIImd(ccc,ddd,eee,aaa,bbb,@x[10],11)
    IIImd(bbb,ccc,ddd,eee,aaa,@x[14],7)
    IIImd(aaa,bbb,ccc,ddd,eee,@x[15],7)
    IIImd(eee,aaa,bbb,ccc,ddd,@x[8],12)
    IIImd(ddd,eee,aaa,bbb,ccc,@x[12],7)
    IIImd(ccc,ddd,eee,aaa,bbb,@x[4],6)
    IIImd(bbb,ccc,ddd,eee,aaa,@x[9],15)
    IIImd(aaa,bbb,ccc,ddd,eee,@x[1],13)
    IIImd(eee,aaa,bbb,ccc,ddd,@x[2],11)
       
    '-- parallel round 3
    HHHmd(ddd,eee,aaa,bbb,ccc,@x[15],9)
    HHHmd(ccc,ddd,eee,aaa,bbb,@x[5],7)
    HHHmd(bbb,ccc,ddd,eee,aaa,@x[1],15)
    HHHmd(aaa,bbb,ccc,ddd,eee,@x[3],11)
    HHHmd(eee,aaa,bbb,ccc,ddd,@x[7],8)
    HHHmd(ddd,eee,aaa,bbb,ccc,@x[14],6)
    HHHmd(ccc,ddd,eee,aaa,bbb,@x[6],6)
    HHHmd(bbb,ccc,ddd,eee,aaa,@x[9],14)
    HHHmd(aaa,bbb,ccc,ddd,eee,@x[11],12)
    HHHmd(eee,aaa,bbb,ccc,ddd,@x[8],13)
    HHHmd(ddd,eee,aaa,bbb,ccc,@x[12],5)
    HHHmd(ccc,ddd,eee,aaa,bbb,@x[2],14)
    HHHmd(bbb,ccc,ddd,eee,aaa,@x[10],13)
    HHHmd(aaa,bbb,ccc,ddd,eee,@x[0],13)
    HHHmd(eee,aaa,bbb,ccc,ddd,@x[4],7)
    HHHmd(ddd,eee,aaa,bbb,ccc,@x[13],5)
       
    '-- parallel round 4
    GGGmd(ccc,ddd,eee,aaa,bbb,@x[8],15)
    GGGmd(bbb,ccc,ddd,eee,aaa,@x[6],5)
    GGGmd(aaa,bbb,ccc,ddd,eee,@x[4],8)
    GGGmd(eee,aaa,bbb,ccc,ddd,@x[1],11)
    GGGmd(ddd,eee,aaa,bbb,ccc,@x[3],14)
    GGGmd(ccc,ddd,eee,aaa,bbb,@x[11],14)
    GGGmd(bbb,ccc,ddd,eee,aaa,@x[15],6)
    GGGmd(aaa,bbb,ccc,ddd,eee,@x[0],14)
    GGGmd(eee,aaa,bbb,ccc,ddd,@x[5],6)
    GGGmd(ddd,eee,aaa,bbb,ccc,@x[12],9)
    GGGmd(ccc,ddd,eee,aaa,bbb,@x[2],12)
    GGGmd(bbb,ccc,ddd,eee,aaa,@x[13],9)
    GGGmd(aaa,bbb,ccc,ddd,eee,@x[9],12)
    GGGmd(eee,aaa,bbb,ccc,ddd,@x[7],5)
    GGGmd(ddd,eee,aaa,bbb,ccc,@x[10],15)
    GGGmd(ccc,ddd,eee,aaa,bbb,@x[14],8)
       
    '-- parallel round 5
    FFFmd(bbb,ccc,ddd,eee,aaa,@x[12],8)
    FFFmd(aaa,bbb,ccc,ddd,eee,@x[15],5)
    FFFmd(eee,aaa,bbb,ccc,ddd,@x[10],12)
    FFFmd(ddd,eee,aaa,bbb,ccc,@x[4],9)
    FFFmd(ccc,ddd,eee,aaa,bbb,@x[1],12)
    FFFmd(bbb,ccc,ddd,eee,aaa,@x[5],5)
    FFFmd(aaa,bbb,ccc,ddd,eee,@x[8],14)
    FFFmd(eee,aaa,bbb,ccc,ddd,@x[7],6)
    FFFmd(ddd,eee,aaa,bbb,ccc,@x[6],8)
    FFFmd(ccc,ddd,eee,aaa,bbb,@x[2],13)
    FFFmd(bbb,ccc,ddd,eee,aaa,@x[13],6)
    FFFmd(aaa,bbb,ccc,ddd,eee,@x[14],5)
    FFFmd(eee,aaa,bbb,ccc,ddd,@x[0],15)
    FFFmd(ddd,eee,aaa,bbb,ccc,@x[3],13)
    FFFmd(ccc,ddd,eee,aaa,bbb,@x[9],11)
    FFFmd(bbb,ccc,ddd,eee,aaa,@x[11],11)
       
    '-- combine results
    ddd = ddd + cc + Ctx.@MD[1]
    Ctx.@MD[1] = Ctx.@MD[2] + dd + eee
    Ctx.@MD[2] = Ctx.@MD[3] + ee + aaa
    Ctx.@MD[3] = Ctx.@MD[4] + aa + bbb
    Ctx.@MD[4] = Ctx.@MD[0] + bb + ccc
    Ctx.@MD[0] = ddd
    END FUNCTION
       
       
    '=========================
    FUNCTION MakePadding$(BYVAL TotalBytes&)
    LOCAL padding$, buffbits&&, padbytes&
       
    buffbits = TotalBytes * 8
    padding = zbs(8)
    poke$ strptr(padding), peek$(varptr(buffbits),8)
       
    padbytes = %BLOCKSIZE - ((TotalBytes+9) AND (%BLOCKSIZE-1))
    function = chr$(&h80) + zbs(padbytes) + padding
    END FUNCTION
       
       
    '====================
    FUNCTION MDfinish(Ctx AS HASH_CONTEXT)
    LOCAL data_length&, lastbuff$
       
    data_length = Ctx.BufferLength AND (%BLOCKSIZE-1)
    lastbuff = peek$(Ctx.pBuffer, data_length) + MakePadding$(Ctx.BufferLength)
       
    Ctx.pBuffer = strptr(lastbuff)
    data_length = len(lastbuff)
    do while data_length > 0
       Compress Ctx
       Ctx.pBuffer = Ctx.pBuffer + %BLOCKSIZE
       data_length = data_length - %BLOCKSIZE
    loop
    END FUNCTION
       
    '-- end RMD160.BAS
       
       
    '=====================================================================
    '                         RIPEMD-160 Test Bed code
    '               Compiles with either PBWIN 7.0+ or PBCC 3.0+
    '=====================================================================
    #COMPILE EXE
    #REGISTER NONE
    #DIM ALL
    '============
       
    '--------------------
    '-- Utility macros
    '--------------------
       
    #IF %def(%pb_win32)
       MACRO eol=$CR
       MACRO mbox(t)=msgbox t
    #ELSEIF %def(%pb_cc32)
       MACRO eol=$CRLF
       MACRO mbox(t)=stdout t
    #ENDIF
       
    '--------------------
    MACRO EnterCC
    #IF %def(%pb_cc32)
       LOCAL launched&
       if (cursory = 1) and (cursorx = 1) then launched = -1
    #ENDIF
    END MACRO
       
    '--------------------
    MACRO ExitCC
    #IF %def(%pb_cc32)
       if launched then
          input flush
          stdout "Press any key to end"
          waitkey$
       end if
    #ENDIF
    END MACRO
       
       
    #INCLUDE "RMD160.BAS"
    DECLARE FUNCTION Hex2Show$(Buffer$)
       
    '====================
    FUNCTION PBMain&()
    LOCAL i&, plain$, hash$, shouldbe$, t$
    LOCAL ctx AS HASH_CONTEXT  ' defined in RMD160.BAS
    EnterCC
       
    '-- Standard RIPEMD-160 test vectors:
    plain    = ""        'empty string
    hash     = zbs(%HASHLENGTH)
    shouldbe = chr$(&h9c,&h11,&h85,&ha5,&hc5,&he9,&hfc,&h54,&h61,&h28,&h08,&h97,&h7e,&he8,&hf5,&h48,&hb2,&h25,&h8d,&h31)
    t = "plain:    " + plain + eol
    gosub DoRMD160
    t = t + "hash:     " + Hex2Show$(hash) + eol
    t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol + eol
       
    plain    = "a"
    hash     = zbs(%HASHLENGTH)
    shouldbe = chr$(&h0b,&hdc,&h9d,&h2d,&h25,&h6b,&h3e,&he9,&hda,&hae,&h34,&h7b,&he6,&hf4,&hdc,&h83,&h5a,&h46,&h7f,&hfe)
    t = T + "plain:    " + plain + eol
    gosub DoRMD160
    t = t + "hash:     " + Hex2Show$(hash) + eol
    t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol + eol
       
    plain    = "message digest" 
    hash     = zbs(%HASHLENGTH)
    shouldbe = chr$(&h5d,&h06,&h89,&hef,&h49,&hd2,&hfa,&he5,&h72,&hb8,&h81,&hb1,&h23,&ha8,&h5f,&hfa,&h21,&h59,&h5f,&h36)
    t = t + "plain:    " + plain + eol
    gosub DoRMD160
    t = t + "hash:     " + Hex2Show$(hash) + eol
    t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol + eol
       
       
    plain    = repeat$(1000000,"a")
    hash     = zbs(%HASHLENGTH)
    shouldbe = chr$(&h52,&h78,&h32,&h43,&hc1,&h69,&h7b,&hdb,&he1,&h6d,&h37,&hf9,&h7f,&h68,&hf0,&h83,&h25,&hdc,&h15,&h28)
    t = t + "Million chars test" + eol
    gosub DoRMD160
    t = t + "hash:     " + Hex2Show$(hash) + eol
    t = t + "shouldbe: " + Hex2Show$(shouldbe) + eol + eol
       
    mbox(t)
       
    '============
    ExitPBMain:
    ExitCC
    exit function
       
    '============
    DoRMD160:
    REGISTER bufflen&
    ctx.pBuffer      = strptr(plain)
    ctx.BufferLength = len(plain)
    RMD160_Init ctx
       
    bufflen = ctx.BufferLength
    do while bufflen > (%BLOCKSIZE-1)
       Compress ctx
       ctx.pBuffer = ctx.pBuffer + %BLOCKSIZE
       bufflen = bufflen - %BLOCKSIZE
    loop
    MDfinish ctx
       
    hash = peek$(Ctx.MD, %HASHLENGTH)
    RETURN
    END FUNCTION
       
    '====================
    FUNCTION Hex2Show$(Buffer$)
    REGISTER i&
    LOCAL t$, b AS BYTE PTR
    b = strptr(Buffer$)
    for i = 0 to len(Buffer$)-1
       t = t + hex$(@b[i],2) + " "
    next i
    function = t
    END FUNCTION
       
    '-- end TESTBED.BAS

    Comment

    Working...
    X