Τετάρτη 6 Μαρτίου 2019

Revision 4 Version 9.8 plus RIPEMD-160 example

New revision. Added Binary.Add() to add two or more numbers with modulo 2^32. This function needed for cryptographic functions.
This is one for RIPEMD-160, written for rosettacode.org task about it.

This implantation is for education only. We get the RIPEMD function from another function, the Prepare_RiPeMD_160() which make some arrays, and pass them as closures to the returned function. So in module TestHash we pass the lambda function and do all the tests. The last test, with 1 million "a", need more than an hour to complete. M2000 is an interpreter, with no AST yet. In my plans is a new version of M20000  to be prepared with an AST interpreter, to gain speed. The current interpreter consume source code as it runs. The AST interpreter, pass the source to a lexical analyzer, and then to a syntax analyzer. Compiling is not in my scope, but who knows, what a mind can think, sometimes.


Module Checkit {
 Function Prepare_RiPeMd_160 {
  Dim Base 0,  K(5), K1(5)
  K(0)=0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E
  K1(0)=0x50A28BE6,0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000
  Dim Base 0,r(80), r1(80), s(80), s1(80)
  r(0)=0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
  r(16)=7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8
  r(32)= 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12
  r(48)=1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2
  r(64)=4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
  k=r() : k*=4   ' k is a pointer to array. We have to multiply to make them offsets
  
  r1(0)=5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12
  r1(16)=6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2
  r1(32)=15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13
  r1(48)=8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14
  r1(64)=12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
  
  k=r1() : k*=4
  
  s(0)=11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8
  s(16)=7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12
  s(32)=11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5
  s(48)=11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12
  s(64)=9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
  
  s1(0)=8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6
  s1(16)=9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11
  s1(32)=9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5
  s1(48)=15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8
  s1(64)=8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
  
  Dim Base 0, T(5), TT(5)
  T(0)=lambda ->binary.xor(binary.xor(number,number),number)
  T(1)=lambda (B,C,D)->binary.or(binary.and(B,C), binary.and(binary.not(B), D))
  T(2)=lambda ->binary.xor(binary.or(number, binary.not(number)), number)
  T(3)=lambda (B,C,D)->binary.or(binary.and(B,D), binary.and(C,binary.not(D)))
  T(4)=lambda ->binary.xor(number, binary.or(number, binary.not(number)))
  
  \\ no need for variables we read form stack with number
  TT(0)=lambda ->binary.xor(number, binary.or(number, binary.not(number)))
  TT(1)=lambda (BB,CC,DD)->binary.or(binary.and(BB,DD), binary.and(CC,binary.not(DD))) 
  TT(2)=lambda ->binary.xor(binary.or(number, binary.not(number)), number)
  TT(3)=lambda (BB,CC,DD)->binary.or(binary.and(BB,CC), binary.and(binary.not(BB),DD)) 
  TT(4)=lambda ->binary.xor(binary.xor(number,number),number)
  
  \\ return of this function is a lambda function
  \\ all arrays are closures to this lambda
  =lambda K(),K1(),TT(), T(),r(),r1(), s(), s1() (&message$, ansi as boolean=true, ansiid=1033)-> {
   set fast!
   def h0 = 0x67452301, h1 = 0xEFCDAB89, h2 = 0x98BADCFE
   def h3 = 0x10325476, h4 = 0xC3D2E1F0
   def i, j, l, padding, l1, blocks, acc, f64 as boolean=true, oldid
   if ansi then oldid=locale : locale ansiid
   \\ we use a buffer of 64 bytes
   buffer clear message as byte*64
   l=len(message$)*if(ansi->1,2 )
   if binary.and(l,63)>55 then  padding=64 
   padding+= 64 - (l Mod 64)
   l1=padding+l+1
 
   f64=binary.and(l,63)<>0
 
   blocks=l1 div 64
rem
   Print "blocks:";blocks
   \\ now prepare the buffer
   PrepareBuffer()
   def decimal  A, B, C, D, E, AA, BB, CC, DD, EE, T, TT
   do
   A  = h0 : B  = h1 : C  = h2 : D  = h3 : E  = h4
   AA = h0 : BB = h1 : CC = h2 : DD = h3 : EE = h4
   for J=0 to 79 {
    JJ=J DIV 16
    PUSH binary.add(Binary.Rotate(binary.add(A,T(JJ)(B,C,D),eval(message ,r(j) as long),k(jj)), s(j)), e)
    A = E : E = D : D = Binary.Rotate(C, 10) : C = B : READ B 
    PUSH binary.add(Binary.Rotate(binary.add(AA,TT(JJ)(BB,CC,DD),eval(message, r1(j) as long),k1(jj)),s1(j)),EE)
    AA = EE : EE = DD : DD = Binary.Rotate(CC, 10) : CC = BB : READ BB
   }
   push binary.add(h1, C, DD)
   h1 = binary.add(h2, D, EE)
   h2 = binary.add(h3, E, AA)
   h3 = binary.add(h4, A, BB)
   h4 = binary.add(h0, B, CC)
   Read h0
   blocks--
rem
   print over $(0,8), blocks : Refresh
   if blocks=0 then exit
   PrepareBuffer()
   always
rem
   print
   buffer ans as byte*20
   \\ we put ulong (long is ulong in buffers)
   Return ans, 0:=h0 as long, 4:=h1 as long,8:=h2 as long, 12:=h3 as long, 16:=h4 as long
   =ans
   if ansi then locale oldid
   set fast
   Sub PrepareBuffer()
    
    if l-acc>=64 then
     LoadPart(64)
    else.if blocks=1 then
     return message, 0:=string$(chr$(0),32)
     if l-acc=0 and f64 then
      Return message, 56:=l*8 as long, 60 :=binary.shift(l,-29) as long
     else
      Return message, l-acc:=0x80, 56:=l*8 as long, 60 :=binary.shift(l,-29) as long
      if l>acc then LoadPart(l-acc)
     end if
    else
     Return message, l-acc:=0x80
     LoadPart(l-acc)
    end if
   End Sub
   sub LoadPart(many)
    \\ str$() convert to ansi, one byte per character
    \\ using 1033 as Ansi language
    if ansi then
     Return message, 0:=str$(mid$(message$,1+acc, many))
    else
     Return message, 0:=mid$(message$, 1+acc, many)
    end if
    acc+=many
   end sub
  }
 }
 Module TestHash (RIPEMD){
  Flush
  \\ push data to stack of values, as fifo (each entry append to end of stack)
  Data "b3be159860842cebaa7174c8fff0aa9e50a5199f","Rosetta Code"
  Data "9c1185a5c5e9fc54612808977ee8f548b2258d31",""
  Data "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe","a"
  Data "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc","abc"
  Data "5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"
  Data "f71c27109c692c1b56bbdceb5b9d2865b3708dbc","abcdefghijklmnopqrstuvwxyz"
  Data "b0e20b6e3116640286ed3a87a5713079b21f5189"
  Data "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
  Data "9b752e45573d4b39f4dbd3323cab82bf63326bfb", String$("1234567890",8)
rem  Data "52783243c1697bdbe16d37f97f68f08325dc1528", String$("a",1000000)
  
  While not empty
   Read check$, text$
   Print "RIPEMD160 for ";quote$(Left$(if$(len(text$)>30->left$(text$,27)+"...",  text$),30))
   \\ pass text$ by reference
   Display(RIPEMD(&text$))
  End While
  
  sub Display(ans)
   local answer$
   for i=0 to len(ans)-1
    answer$+=hex$(eval(ans,i),1)
   next i
   Print lcase$(answer$)
   Print lcase$(answer$)=check$
  end sub
 }
 TestHash Prepare_RiPeMd_160() 
}
Checkit

Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.