]> gitweb.factorcode.org Git - factor.git/blob - basis/checksums/md5/md5.factor
13edf0ed5049f4b945236e55e5b9f8c7a58b7ece
[factor.git] / basis / checksums / md5 / md5.factor
1 ! Copyright (C) 2006, 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.c-types alien.data byte-arrays checksums
4 checksums.common checksums.stream combinators fry grouping hints
5 kernel kernel.private literals locals macros math math.bitwise
6 math.functions sequences sequences.private specialized-arrays ;
7 FROM: sequences.private => change-nth-unsafe ;
8 SPECIALIZED-ARRAY: uint
9 IN: checksums.md5
10
11 SINGLETON: md5
12
13 INSTANCE: md5 stream-checksum
14
15 TUPLE: md5-state < checksum-state
16 { state uint-array }
17 { old-state uint-array } ;
18
19 : <md5-state> ( -- md5 )
20     md5-state new-checksum-state
21         64 >>block-size
22         uint-array{ 0x67452301 0xefcdab89 0x98badcfe 0x10325476 }
23         [ clone >>state ] [ >>old-state ] bi ;
24
25 M: md5 initialize-checksum-state drop <md5-state> ;
26
27 <PRIVATE
28
29 : update-md5 ( md5 -- )
30     [ state>> ] [ old-state>> [ w+ ] 2map dup clone ] [ ] tri
31     [ old-state<< ] [ state<< ] bi ; inline
32
33 CONSTANT: T $[
34     80 iota [ sin abs 32 2^ * >integer ] uint-array{ } map-as
35 ]
36
37 :: F ( X Y Z -- FXYZ )
38     #! F(X,Y,Z) = XY v not(X) Z
39     X Y bitand X bitnot Z bitand bitor ; inline
40
41 :: G ( X Y Z -- GXYZ )
42     #! G(X,Y,Z) = XZ v Y not(Z)
43     X Z bitand Y Z bitnot bitand bitor ; inline
44
45 : H ( X Y Z -- HXYZ )
46     #! H(X,Y,Z) = X xor Y xor Z
47     bitxor bitxor ; inline
48
49 :: I ( X Y Z -- IXYZ )
50     #! I(X,Y,Z) = Y xor (X v not(Z))
51     Z bitnot X bitor Y bitxor ; inline
52
53 CONSTANT: S11 7
54 CONSTANT: S12 12
55 CONSTANT: S13 17
56 CONSTANT: S14 22
57 CONSTANT: S21 5
58 CONSTANT: S22 9
59 CONSTANT: S23 14
60 CONSTANT: S24 20
61 CONSTANT: S31 4
62 CONSTANT: S32 11
63 CONSTANT: S33 16
64 CONSTANT: S34 23
65 CONSTANT: S41 6
66 CONSTANT: S42 10
67 CONSTANT: S43 15
68 CONSTANT: S44 21
69
70 CONSTANT: a 0
71 CONSTANT: b 1
72 CONSTANT: c 2
73 CONSTANT: d 3
74
75 :: (ABCD) ( x state a b c d k s i quot -- )
76     #! a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s)
77     a state [
78         b state nth-unsafe
79         c state nth-unsafe
80         d state nth-unsafe quot call w+
81         k x nth-unsafe w+
82         i T nth-unsafe w+
83         s bitroll-32
84         b state nth-unsafe w+
85     ] change-nth-unsafe ; inline
86
87 MACRO: with-md5-round ( ops quot -- )
88     '[ [ _ (ABCD) ] compose ] map '[ _ 2cleave ] ;
89
90 : (process-md5-block-F) ( block state -- )
91     { uint-array uint-array } declare {
92         [ a b c d 0  S11 1  ]
93         [ d a b c 1  S12 2  ]
94         [ c d a b 2  S13 3  ]
95         [ b c d a 3  S14 4  ]
96         [ a b c d 4  S11 5  ]
97         [ d a b c 5  S12 6  ]
98         [ c d a b 6  S13 7  ]
99         [ b c d a 7  S14 8  ]
100         [ a b c d 8  S11 9  ]
101         [ d a b c 9  S12 10 ]
102         [ c d a b 10 S13 11 ]
103         [ b c d a 11 S14 12 ]
104         [ a b c d 12 S11 13 ]
105         [ d a b c 13 S12 14 ]
106         [ c d a b 14 S13 15 ]
107         [ b c d a 15 S14 16 ]
108     } [ F ] with-md5-round ;
109
110 : (process-md5-block-G) ( block state -- )
111     { uint-array uint-array } declare {
112         [ a b c d 1  S21 17 ]
113         [ d a b c 6  S22 18 ]
114         [ c d a b 11 S23 19 ]
115         [ b c d a 0  S24 20 ]
116         [ a b c d 5  S21 21 ]
117         [ d a b c 10 S22 22 ]
118         [ c d a b 15 S23 23 ]
119         [ b c d a 4  S24 24 ]
120         [ a b c d 9  S21 25 ]
121         [ d a b c 14 S22 26 ]
122         [ c d a b 3  S23 27 ]
123         [ b c d a 8  S24 28 ]
124         [ a b c d 13 S21 29 ]
125         [ d a b c 2  S22 30 ]
126         [ c d a b 7  S23 31 ]
127         [ b c d a 12 S24 32 ]
128     } [ G ] with-md5-round ;
129
130 : (process-md5-block-H) ( block state -- )
131     { uint-array uint-array } declare {
132         [ a b c d 5  S31 33 ]
133         [ d a b c 8  S32 34 ]
134         [ c d a b 11 S33 35 ]
135         [ b c d a 14 S34 36 ]
136         [ a b c d 1  S31 37 ]
137         [ d a b c 4  S32 38 ]
138         [ c d a b 7  S33 39 ]
139         [ b c d a 10 S34 40 ]
140         [ a b c d 13 S31 41 ]
141         [ d a b c 0  S32 42 ]
142         [ c d a b 3  S33 43 ]
143         [ b c d a 6  S34 44 ]
144         [ a b c d 9  S31 45 ]
145         [ d a b c 12 S32 46 ]
146         [ c d a b 15 S33 47 ]
147         [ b c d a 2  S34 48 ]
148     } [ H ] with-md5-round ;
149
150 : (process-md5-block-I) ( block state -- )
151     { uint-array uint-array } declare {
152         [ a b c d 0  S41 49 ]
153         [ d a b c 7  S42 50 ]
154         [ c d a b 14 S43 51 ]
155         [ b c d a 5  S44 52 ]
156         [ a b c d 12 S41 53 ]
157         [ d a b c 3  S42 54 ]
158         [ c d a b 10 S43 55 ]
159         [ b c d a 1  S44 56 ]
160         [ a b c d 8  S41 57 ]
161         [ d a b c 15 S42 58 ]
162         [ c d a b 6  S43 59 ]
163         [ b c d a 13 S44 60 ]
164         [ a b c d 4  S41 61 ]
165         [ d a b c 11 S42 62 ]
166         [ c d a b 2  S43 63 ]
167         [ b c d a 9  S44 64 ]
168     } [ I ] with-md5-round ;
169
170 : byte-array>le ( byte-array -- byte-array )
171     little-endian? [
172         dup 4 <groups> [
173             [ [ 1 2 ] dip exchange-unsafe ]
174             [ [ 0 3 ] dip exchange-unsafe ] bi
175         ] each
176     ] unless ;
177
178 HINTS: byte-array>le byte-array ;
179
180 M: md5-state checksum-block
181     [
182         [ byte-array>le uint cast-array ] [ state>> ] bi* {
183             [ (process-md5-block-F) ]
184             [ (process-md5-block-G) ]
185             [ (process-md5-block-H) ]
186             [ (process-md5-block-I) ]
187         } 2cleave
188     ] [
189         nip update-md5
190     ] 2bi ;
191
192 : md5>checksum ( md5 -- bytes )
193     state>> underlying>> byte-array>le ;
194
195 M: md5-state clone
196     call-next-method
197     [ clone ] change-state
198     [ clone ] change-old-state ;
199
200 M: md5-state get-checksum
201     clone
202     [ bytes>> f ] [ bytes-read>> pad-last-block ] [ ] tri
203     [ [ checksum-block ] curry each ] [ md5>checksum ] bi ;
204
205 M: md5 checksum-stream
206     drop
207     [ <md5-state> ] dip add-checksum-stream get-checksum ;
208
209 PRIVATE>