2024-04-29

Navigation

Skip Navigation Links

Hash algorithms

Asymmetric Algorithms

Symmetric Cipher Algorithms

Encoding Algorithms

Compression Algorithms

Pseudo Random Number Algorithms

Steganography

Library Wrappers

String Comparison

Others

Syntax highlighting by Prism
PBCrypto.com Mirror

RIPEMD-160

Algorithm creator(s)

Hans Dobbertin, Antoon Bosselaers, Bart Preneel


PB author(s)

Greg Turgeon


Description

PBCC3/PBWIN7 implementation of the 160-bit RIPEMD cryptographic hash function. Intended to be used as a secure replacement for the 128-bit hash functions MD4, MD5, and RIPEMD.


Note


Source

https://forum.powerbasic.com/forum/user-to-user-discussions/source-code/24092-ripemd-160-secure-hash-for-3-0-7-0?t=23455


See also


Source Code

Download source code file ripemd-160.bas (Right-click -> "Save as ...")

#IF 0 
=====================================================================
                        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. 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 
=====================================================================
#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

Mirror provided by Knuth Konrad