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 state old-state ;
12 : <md5-state> ( -- md5-state )
15 { HEX: 67452301 HEX: efcdab89 HEX: 98badcfe HEX: 10325476 }
16 [ clone >>state ] [ >>old-state ] bi ;
20 : v-w+ ( v1 v2 -- v3 ) [ w+ ] 2map ;
22 : update-md5-state ( md5-state -- )
23 [ state>> ] [ old-state>> v-w+ dup clone ] [ ] tri
24 [ (>>old-state) ] [ (>>state) ] bi ; inline
27 sin abs 32 2^ * >integer ; inline
29 :: F ( X Y Z -- FXYZ )
30 #! F(X,Y,Z) = XY v not(X) Z
31 X Y bitand X bitnot Z bitand bitor ; inline
33 :: G ( X Y Z -- GXYZ )
34 #! G(X,Y,Z) = XZ v Y not(Z)
35 X Z bitand Y Z bitnot bitand bitor ; inline
38 #! H(X,Y,Z) = X xor Y xor Z
39 bitxor bitxor ; inline
41 :: I ( X Y Z -- IXYZ )
42 #! I(X,Y,Z) = Y xor (X v not(Z))
43 Z bitnot X bitor Y bitxor ; inline
67 :: (ABCD) ( x V a b c d k s i quot -- )
68 #! a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s)
72 d V nth-unsafe quot call w+
79 MACRO: with-md5-round ( ops quot -- )
80 '[ [ _ (ABCD) ] compose ] map '[ _ 2cleave ] ;
82 : (process-md5-block-F) ( block v -- )
100 } [ F ] with-md5-round ; inline
102 : (process-md5-block-G) ( block v -- )
106 [ c d a b 11 S23 19 ]
109 [ d a b c 10 S22 22 ]
110 [ c d a b 15 S23 23 ]
113 [ d a b c 14 S22 26 ]
116 [ a b c d 13 S21 29 ]
119 [ b c d a 12 S24 32 ]
120 } [ G ] with-md5-round ; inline
122 : (process-md5-block-H) ( block v -- )
126 [ c d a b 11 S33 35 ]
127 [ b c d a 14 S34 36 ]
131 [ b c d a 10 S34 40 ]
132 [ a b c d 13 S31 41 ]
137 [ d a b c 12 S32 46 ]
138 [ c d a b 15 S33 47 ]
140 } [ H ] with-md5-round ; inline
142 : (process-md5-block-I) ( block v -- )
146 [ c d a b 14 S43 51 ]
148 [ a b c d 12 S41 53 ]
150 [ c d a b 10 S43 55 ]
153 [ d a b c 15 S42 58 ]
155 [ b c d a 13 S44 60 ]
157 [ d a b c 11 S42 62 ]
160 } [ I ] with-md5-round ; inline
162 : (process-md5-block) ( block state -- )
164 [ 4 <groups> [ le> ] map ] [ state>> ] bi* {
165 [ (process-md5-block-F) ]
166 [ (process-md5-block-G) ]
167 [ (process-md5-block-H) ]
168 [ (process-md5-block-I) ]
174 :: process-md5-block ( block state -- )
176 [ state [ + ] change-bytes-read drop ] [ 64 = ] bi [
177 block state (process-md5-block)
179 block f state bytes-read>> pad-last-block
180 [ state (process-md5-block) ] each
183 : get-md5 ( md5-state -- bytes )
184 state>> [ 4 >le ] map B{ } concat-as ;
186 :: stream>md5 ( state stream -- )
187 64 stream stream-read
188 [ state process-md5-block ] [ length 64 = ] bi
189 [ state stream stream>md5 ] when ;
195 INSTANCE: md5 stream-checksum
197 M: md5 checksum-stream
198 drop [ <md5-state> ] dip [ stream>md5 ] [ drop get-md5 ] 2bi ;
200 GENERIC: initialize-checksum ( checksum -- state )
201 GENERIC# add-bytes 1 ( state bytes -- state )
202 GENERIC# add-stream 1 ( state stream -- state )
203 GENERIC: finish-checksum ( state -- bytes )
205 M: md5 initialize-checksum drop <md5-state> ;
207 M: md5-state finish-checksum get-md5 ;
209 M: md5-state add-bytes over [ binary <byte-reader> stream>md5 ] dip ;
211 M: md5-state add-stream over [ stream>md5 ] dip ;