MD5v02.f

From: Wong, Leo <LRW_at_mail3.cs.state.ny.us>
Date: Fri, 22 Dec 2000 09:27:13 -0500

This revision uses the variables A B C D and gets rid of an embarrasing
gaffe.

Leo Wong hello_at_albany.net
http://www.albany.net/~hello/

\ md5v02.f Leo Wong 22 Dec 2000 +
\ md5 routine in ans forth after Fredrick W. Warren 02nov2000
\ Unofficial MD5 Homepage by Mordechai T. Abzug:
\ http://userpages.umbc.edu/~mabzug1/cs/md5/md5.html

\ tools

: 4dup ( n1 n2 n3 n4 -- n1 n2 n3 n4 n1 n2 n3 n4 ) 2OVER 2OVER ;
: variables 0 ?DO VARIABLE LOOP ;

\ MD5
5 VARIABLES A B C D message-length

\ Debugging words
: h? ( a -- ) HEX @ 8 U.R SPACE DECIMAL ;
: .ABCD ( -- ) CR A h? B h? C h? D h? ;

\ : f() ( b c d -- e ) >R OVER AND SWAP INVERT R> AND OR ;
: g() ( b c d -- e ) TUCK INVERT AND >R AND R> OR ;
: f() ( b c d -- e ) ROT g() ;
: h() ( b c d -- e ) XOR XOR ;
: i() ( b c d -- e ) INVERT ROT OR XOR ;

CREATE buf[] 64 allot

: b+ ( n -- ) CELLS buf[] + POSTPONE LITERAL ; IMMEDIATE
: op ( a e ac 'x -- a' a' ) @ + + + DUP ;
: ss ( s -- )
   32 OVER - POSTPONE LITERAL POSTPONE LITERAL ; IMMEDIATE
\ rotate a' left s bits
: lrotate ( a' a' 32-s s -- a'' ) >R RSHIFT SWAP R> LSHIFT OR ;

: out ( a b c d -- a b c d ) ( r: -- c b d )
   S" DUP 2OVER >R >R >R" EVALUATE ; IMMEDIATE
: back ( a'' -- d a''' b c ) ( r: c b d -- )
   S" R> SWAP R@ + R> R>" EVALUATE ; IMMEDIATE

HEX
: md-init ( -- )
   067452301 A ! 0efcdab89 B ! 098badcfe C ! 010325476 D !
   0 message-length ! ;

: round1 ( A B C D -- A' B' C' D' )
\ ac 'x s
   out f() 0d76aa478 [ 00 ] b+ op [ 07 ] ss lrotate back \ 1
   out f() 0e8c7b756 [ 01 ] b+ op [ 0c ] ss lrotate back \ 2
   out f() 0242070db [ 02 ] b+ op [ 11 ] ss lrotate back \ 3
   out f() 0c1bdceee [ 03 ] b+ op [ 16 ] ss lrotate back \ 4
   out f() 0f57c0faf [ 04 ] b+ op [ 07 ] ss lrotate back \ 5
   out f() 04787c62a [ 05 ] b+ op [ 0c ] ss lrotate back \ 6
   out f() 0a8304613 [ 06 ] b+ op [ 11 ] ss lrotate back \ 7
   out f() 0fd469501 [ 07 ] b+ op [ 16 ] ss lrotate back \ 8
   out f() 0698098d8 [ 08 ] b+ op [ 07 ] ss lrotate back \ 9
   out f() 08b44f7af [ 09 ] b+ op [ 0c ] ss lrotate back \ 10
   out f() 0ffff5bb1 [ 0a ] b+ op [ 11 ] ss lrotate back \ 11
   out f() 0895cd7be [ 0b ] b+ op [ 16 ] ss lrotate back \ 12
   out f() 06b901122 [ 0c ] b+ op [ 07 ] ss lrotate back \ 13
   out f() 0fd987193 [ 0d ] b+ op [ 0c ] ss lrotate back \ 14
   out f() 0a679438e [ 0e ] b+ op [ 11 ] ss lrotate back \ 15
   out f() 049b40821 [ 0f ] b+ op [ 16 ] ss lrotate back \ 16
  ;

: round2 ( A B C D -- A' B' C' D' )
   out g() 0f61e2562 [ 01 ] b+ op [ 05 ] ss lrotate back \ 1
   out g() 0c040b340 [ 06 ] b+ op [ 09 ] ss lrotate back \ 2
   out g() 0265e5a51 [ 0b ] b+ op [ 0e ] ss lrotate back \ 3
   out g() 0e9b6c7aa [ 00 ] b+ op [ 14 ] ss lrotate back \ 4
   out g() 0d62f105d [ 05 ] b+ op [ 05 ] ss lrotate back \ 5
   out g() 002441453 [ 0a ] b+ op [ 09 ] ss lrotate back \ 6
   out g() 0d8a1e681 [ 0f ] b+ op [ 0e ] ss lrotate back \ 7
   out g() 0e7d3fbc8 [ 04 ] b+ op [ 14 ] ss lrotate back \ 8
   out g() 021e1cde6 [ 09 ] b+ op [ 05 ] ss lrotate back \ 9
   out g() 0c33707d6 [ 0e ] b+ op [ 09 ] ss lrotate back \ 10
   out g() 0f4d50d87 [ 03 ] b+ op [ 0e ] ss lrotate back \ 11
   out g() 0455a14ed [ 08 ] b+ op [ 14 ] ss lrotate back \ 12
   out g() 0a9e3e905 [ 0d ] b+ op [ 05 ] ss lrotate back \ 13
   out g() 0fcefa3f8 [ 02 ] b+ op [ 09 ] ss lrotate back \ 14
   out g() 0676f02d9 [ 07 ] b+ op [ 0e ] ss lrotate back \ 15
   out g() 08d2a4c8a [ 0c ] b+ op [ 14 ] ss lrotate back \ 16
  ;

: round3 ( A B C D -- A' B' C' D' )
   out h() 0fffa3942 [ 05 ] b+ op [ 04 ] ss lrotate back \ 1
   out h() 08771f681 [ 08 ] b+ op [ 0b ] ss lrotate back \ 2
   out h() 06d9d6122 [ 0b ] b+ op [ 10 ] ss lrotate back \ 3
   out h() 0fde5380c [ 0e ] b+ op [ 17 ] ss lrotate back \ 4
   out h() 0a4beea44 [ 01 ] b+ op [ 04 ] ss lrotate back \ 5
   out h() 04bdecfa9 [ 04 ] b+ op [ 0b ] ss lrotate back \ 6
   out h() 0f6bb4b60 [ 07 ] b+ op [ 10 ] ss lrotate back \ 7
   out h() 0bebfbc70 [ 0a ] b+ op [ 17 ] ss lrotate back \ 8
   out h() 0289b7ec6 [ 0d ] b+ op [ 04 ] ss lrotate back \ 9
   out h() 0eaa127fa [ 00 ] b+ op [ 0b ] ss lrotate back \ 10
   out h() 0d4ef3085 [ 03 ] b+ op [ 10 ] ss lrotate back \ 11
   out h() 004881d05 [ 06 ] b+ op [ 17 ] ss lrotate back \ 12
   out h() 0d9d4d039 [ 09 ] b+ op [ 04 ] ss lrotate back \ 13
   out h() 0e6db99e5 [ 0c ] b+ op [ 0b ] ss lrotate back \ 14
   out h() 01fa27cf8 [ 0f ] b+ op [ 10 ] ss lrotate back \ 15
   out h() 0c4ac5665 [ 02 ] b+ op [ 17 ] ss lrotate back \ 16
  ;

: round4 ( A B C D -- A' B' C' D' )
   out i() 0f4292244 [ 00 ] b+ op [ 06 ] ss lrotate back \ 1
   out i() 0432aff97 [ 07 ] b+ op [ 0a ] ss lrotate back \ 2
   out i() 0ab9423a7 [ 0e ] b+ op [ 0f ] ss lrotate back \ 3
   out i() 0fc93a039 [ 05 ] b+ op [ 15 ] ss lrotate back \ 4
   out i() 0655b59c3 [ 0c ] b+ op [ 06 ] ss lrotate back \ 5
   out i() 08f0ccc92 [ 03 ] b+ op [ 0a ] ss lrotate back \ 6
   out i() 0ffeff47d [ 0a ] b+ op [ 0f ] ss lrotate back \ 7
   out i() 085845dd1 [ 01 ] b+ op [ 15 ] ss lrotate back \ 8
   out i() 06fa87e4f [ 08 ] b+ op [ 06 ] ss lrotate back \ 9
   out i() 0fe2ce6e0 [ 0f ] b+ op [ 0a ] ss lrotate back \ 10
   out i() 0a3014314 [ 06 ] b+ op [ 0f ] ss lrotate back \ 11
   out i() 04e0811a1 [ 0d ] b+ op [ 15 ] ss lrotate back \ 12
   out i() 0f7537e82 [ 04 ] b+ op [ 06 ] ss lrotate back \ 13
   out i() 0bd3af235 [ 0b ] b+ op [ 0a ] ss lrotate back \ 14
   out i() 02ad7d2bb [ 02 ] b+ op [ 0f ] ss lrotate back \ 15
   out i() 0eb86d391 [ 09 ] b+ op [ 15 ] ss lrotate back \ 16
  ;

DECIMAL
: transform ( -- )
   A @ B @ C @ D @
   round1 round2 round3 round4
   D +! C +! B +! A +! ;

\ Courtesy of Jean Grezel
: append-length ( -- )
   message-length @ 8 m* buf[] 60 + ! buf[] 56 + ! ;

\ do all 64 byte blocks leaving remainder block
: dofullblocks ( addr count -- addr' count' )
   BEGIN 2DUP 63 U>
   WHILE buf[] 64 CMOVE transform 64 /STRING REPEAT DROP ;

CREATE padding 64 allot padding 64 ERASE 128 padding c!
: movepartial ( addr count -- )
>R buf[] R@ CMOVE padding R@ buf[] + 64 R> - CMOVE ;

: dofinal ( addr count -- )
   TUCK movepartial 55 >
   IF transform buf[] 64 ERASE THEN
   append-length transform ;

\ compute md5 from a counted buffer of text
: md5full ( addr count -- )
  md-init dup message-length +!
  dofullblocks dofinal ;

\ functions for creating output string
create digit$
  48 c, 49 c, 50 c, 51 c, 52 c, 53 c, 54 c, 55 c, 56 c, 57 c,
  97 c, 98 c, 99 c, 100 c, 101 c, 102 c,

: savedigit ( n -- ) \ output digit at pad
   pad c@ 1+ dup pad c! pad + c! ;
: bytedigits ( n1 -- )
   dup 4 rshift digit$ + c@ savedigit 15 and digit$ + c@ savedigit ;

  : celldigits ( a1 -- ) 4 0 DO COUNT bytedigits LOOP DROP ;

: md5string ( -- addr count ) \ return address of counted md5 string
   0 PAD !
   A celldigits B celldigits C celldigits D celldigits
   PAD COUNT
;

\ test suite
: quotestring ( adr count -- )
  34 emit type 34 emit ;

: .md5 ( adr count -- )
  cr cr 2dup md5full md5string type space quotestring ;

: test s" message digest" .md5 ;

0 [IF]
\ MD5 for a file
\ Not tested by me. LW
TRUE VALUE md-init?
CREATE part[] 64 allot
: savepart ( adr count -- )
   message-length @ 63 AND if part[] swap CMOVE else 2drop then ;

: movepart ( adr1 count1 partindex -- adr2 count2 ) \ add to part[]
   2>R DUP part[] 64 R> /STRING R@ MIN >R R@ CMOVE 2R> /STRING ;

: md5update ( adr count -- )
  md-init? if md-init false to md-init? then
  message-length @ 63 AND over message-length +! ( a # partindex -- )
  dup if 2dup + 63 U>
         if movepart part[] 64 dofullblocks dofullblocks
             savepart cr
         else movepart 2drop then
      else drop dofullblocks savepart then ;

: md5final ( adr count -- )
  md-init? if md-init false to md-init? then
  message-length @ 63 AND over message-length +! ( a # partindex -- )
  dup if 2dup + 63 >
         if movepart part[] 64 dofullblocks dofullblocks dofinal
            else movepart 2drop part[] message-length @ 63 AND
                  dofinal then
      else drop dofullblocks dofinal then ;

 : foo ( -- )
  true to md-init?
  s" foo" r/o open-file 0=
  if begin dup pad 1024 rot read-file drop dup 1024 =
      while pad swap md5update
      repeat pad swap md5final
      close-file drop cr cr md5string type ." foo"
  else drop
  then ;

[THEN]

: md5test ( -- )
  ." md5 test suite results:"
  s" a" .md5
  s" abc" .md5
  s" message digest" .md5
  s" abcdefghijklmnopqrstuvwxyz" .md5
  s" abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789"
.md5
s"
1234567890123456789012345678901234567890123456789012345678901234567890123456
7890" .md5
  ( foo ) cr cr ;

\ SwiftForth specific performance test
\ On 233 MHz Pentium Win98 SwiftForth 1.50.4.21 Jan 1999:
\ 3525514 microseconds
\ Hash is: f38898bb69bb02bccb9594dfe471c5c0

 CREATE testspace 10000 ALLOT testspace 10000 BL FILL

: SPEED-TEST
   cr ." MD5 test: buffer of 10,000 spaces done 1000 times is "
   ucounter 1000 0 DO testspace 10000 MD5Full LOOP utimer
   ." microseconds "
   cr ." Hash is: " MD5string TYPE cr
;
Received on Fri Dec 22 2000 - 06:41:47 PST


Subscribe to our e-mail list service. It's free for all SwiftForth and SwiftX users!

This archive was generated 09-Feb-2012. Archive updated nightly.