1 ! Copyright (C) 2006, 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: kernel io io.binary io.files io.streams.byte-array math
4 math.functions math.parser namespaces splitting grouping strings
5 sequences byte-arrays locals sequences.private macros fry
6 io.encodings.binary math.bitwise checksums accessors
7 checksums.common checksums.stream combinators combinators.smart ;
10 TUPLE: md5-state bytes-read a b c d old-a old-b old-c old-d ;
12 : <md5-state> ( -- md5-state )
15 HEX: 67452301 [ >>a ] [ >>old-a ] bi
16 HEX: efcdab89 [ >>b ] [ >>old-b ] bi
17 HEX: 98badcfe [ >>c ] [ >>old-c ] bi
18 HEX: 10325476 [ >>d ] [ >>old-d ] bi ;
22 : update-md5-state ( md5-state -- md5-state )
24 [ [ a>> ] [ ] [ old-a>> ] tri [ w+ ] change-a (>>old-a) ]
25 [ [ b>> ] [ ] [ old-b>> ] tri [ w+ ] change-b (>>old-b) ]
26 [ [ c>> ] [ ] [ old-c>> ] tri [ w+ ] change-c (>>old-c) ]
27 [ [ d>> ] [ ] [ old-d>> ] tri [ w+ ] change-d (>>old-d) ]
31 : md5-state>bytes ( md5-state -- str )
32 [ { [ a>> ] [ b>> ] [ c>> ] [ d>> ] } cleave ] output>array
33 [ 4 >le ] map B{ } concat-as ;
36 sin abs 32 2^ * >integer ; foldable
38 :: F ( X Y Z -- FXYZ )
39 #! F(X,Y,Z) = XY v not(X) Z
40 X Y bitand X bitnot Z bitand bitor ;
42 :: G ( X Y Z -- GXYZ )
43 #! G(X,Y,Z) = XZ v Y not(Z)
44 X Z bitand Y Z bitnot bitand bitor ;
47 #! H(X,Y,Z) = X xor Y xor Z
50 :: I ( X Y Z -- IXYZ )
51 #! I(X,Y,Z) = Y xor (X v not(Z))
52 Z bitnot X bitor Y bitxor ;
74 SYMBOLS: a b c d old-a old-b old-c old-d ;
76 : initialize-md5 ( -- )
78 HEX: 67452301 dup a set old-a set
79 HEX: efcdab89 dup b set old-b set
80 HEX: 98badcfe dup c set old-c set
81 HEX: 10325476 dup d set old-d set ;
84 old-a a update-old-new
85 old-b b update-old-new
86 old-c c update-old-new
87 old-d d update-old-new ;
90 :: (ABCD) ( x a b c d k s i func -- )
91 #! a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s)
93 b get c get d get func call w+
100 MACRO: with-md5-round ( ops func -- )
101 '[ [ _ (ABCD) ] compose ] map '[ _ cleave ] ;
103 : (process-md5-block-F) ( block -- )
115 [ c d a b 10 S13 11 ]
116 [ b c d a 11 S14 12 ]
117 [ a b c d 12 S11 13 ]
118 [ d a b c 13 S12 14 ]
119 [ c d a b 14 S13 15 ]
120 [ b c d a 15 S14 16 ]
121 } [ F ] with-md5-round ;
123 : (process-md5-block-G) ( block -- )
127 [ c d a b 11 S23 19 ]
130 [ d a b c 10 S22 22 ]
131 [ c d a b 15 S23 23 ]
134 [ d a b c 14 S22 26 ]
137 [ a b c d 13 S21 29 ]
140 [ b c d a 12 S24 32 ]
141 } [ G ] with-md5-round ;
143 : (process-md5-block-H) ( block -- )
147 [ c d a b 11 S33 35 ]
148 [ b c d a 14 S34 36 ]
152 [ b c d a 10 S34 40 ]
153 [ a b c d 13 S31 41 ]
158 [ d a b c 12 S32 46 ]
159 [ c d a b 15 S33 47 ]
161 } [ H ] with-md5-round ;
163 : (process-md5-block-I) ( block -- )
167 [ c d a b 14 S43 51 ]
169 [ a b c d 12 S41 53 ]
171 [ c d a b 10 S43 55 ]
174 [ d a b c 15 S42 58 ]
176 [ b c d a 13 S44 60 ]
178 [ d a b c 11 S42 62 ]
181 } [ I ] with-md5-round ;
183 : (process-md5-block) ( block -- )
184 4 <groups> [ le> ] map {
185 [ (process-md5-block-F) ]
186 [ (process-md5-block-G) ]
187 [ (process-md5-block-H) ]
188 [ (process-md5-block-I) ]
193 : process-md5-block ( str -- )
194 dup length [ bytes-read [ + ] change ] keep 64 = [
197 f bytes-read get pad-last-block
198 [ (process-md5-block) ] each
201 : stream>md5 ( stream -- )
203 [ process-md5-block ] [ length 64 = ] bi
204 [ stream>md5 ] [ drop ] if ;
207 [ a b c d ] [ get 4 >le ] map concat >byte-array ;
213 INSTANCE: md5 stream-checksum
215 M: md5 checksum-stream
216 drop initialize-md5 stream>md5 get-md5 ;