! Copyright (C) 2006, 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel io io.binary io.files io.streams.byte-array math
-math.functions math.parser namespaces splitting grouping strings
-sequences byte-arrays locals sequences.private macros fry
-io.encodings.binary math.bitwise checksums accessors
-checksums.common checksums.stream combinators combinators.smart ;
+USING: alien.c-types alien.data kernel io io.binary io.files
+io.streams.byte-array math math.functions math.parser namespaces
+splitting grouping strings sequences byte-arrays locals
+sequences.private macros fry io.encodings.binary math.bitwise
+checksums accessors checksums.common checksums.stream
+combinators combinators.smart specialized-arrays literals hints ;
+FROM: sequences.private => change-nth-unsafe ;
+SPECIALIZED-ARRAY: uint
IN: checksums.md5
-TUPLE: md5-state bytes-read state old-state ;
+SINGLETON: md5
+
+INSTANCE: md5 stream-checksum
-: <md5-state> ( -- md5-state )
- md5-state new
- 0 >>bytes-read
- { HEX: 67452301 HEX: efcdab89 HEX: 98badcfe HEX: 10325476 }
+TUPLE: md5-state < checksum-state state old-state ;
+
+: <md5-state> ( -- md5 )
+ md5-state new-checksum-state
+ 64 >>block-size
+ uint-array{ 0x67452301 0xefcdab89 0x98badcfe 0x10325476 }
[ clone >>state ] [ >>old-state ] bi ;
+M: md5 initialize-checksum-state drop <md5-state> ;
+
<PRIVATE
: v-w+ ( v1 v2 -- v3 ) [ w+ ] 2map ;
-: update-md5-state ( md5-state -- )
+: update-md5 ( md5 -- )
[ state>> ] [ old-state>> v-w+ dup clone ] [ ] tri
- [ (>>old-state) ] [ (>>state) ] bi ; inline
+ [ old-state<< ] [ state<< ] bi ;
-: T ( N -- Y )
- sin abs 32 2^ * >integer ; inline
+CONSTANT: T
+ $[
+ 80 iota [ sin abs 32 2^ * >integer ] uint-array{ } map-as
+ ]
:: F ( X Y Z -- FXYZ )
#! F(X,Y,Z) = XY v not(X) Z
CONSTANT: c 2
CONSTANT: d 3
-:: (ABCD) ( x V a b c d k s i quot -- )
+:: (ABCD) ( x state a b c d k s i quot -- )
#! a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s)
- a V [
- b V nth-unsafe
- c V nth-unsafe
- d V nth-unsafe quot call w+
+ a state [
+ b state nth-unsafe
+ c state nth-unsafe
+ d state nth-unsafe quot call w+
k x nth-unsafe w+
- i T w+
+ i T nth-unsafe w+
s bitroll-32
- b V nth-unsafe w+
- ] change-nth ; inline
+ b state nth-unsafe w+ 32 bits
+ ] change-nth-unsafe ; inline
MACRO: with-md5-round ( ops quot -- )
'[ [ _ (ABCD) ] compose ] map '[ _ 2cleave ] ;
-: (process-md5-block-F) ( block v -- )
+: (process-md5-block-F) ( block state -- )
{
[ a b c d 0 S11 1 ]
[ d a b c 1 S12 2 ]
[ d a b c 13 S12 14 ]
[ c d a b 14 S13 15 ]
[ b c d a 15 S14 16 ]
- } [ F ] with-md5-round ; inline
+ } [ F ] with-md5-round ;
-: (process-md5-block-G) ( block v -- )
+: (process-md5-block-G) ( block state -- )
{
[ a b c d 1 S21 17 ]
[ d a b c 6 S22 18 ]
[ d a b c 2 S22 30 ]
[ c d a b 7 S23 31 ]
[ b c d a 12 S24 32 ]
- } [ G ] with-md5-round ; inline
+ } [ G ] with-md5-round ;
-: (process-md5-block-H) ( block v -- )
+: (process-md5-block-H) ( block state -- )
{
[ a b c d 5 S31 33 ]
[ d a b c 8 S32 34 ]
[ d a b c 12 S32 46 ]
[ c d a b 15 S33 47 ]
[ b c d a 2 S34 48 ]
- } [ H ] with-md5-round ; inline
+ } [ H ] with-md5-round ;
-: (process-md5-block-I) ( block v -- )
+: (process-md5-block-I) ( block state -- )
{
[ a b c d 0 S41 49 ]
[ d a b c 7 S42 50 ]
[ d a b c 11 S42 62 ]
[ c d a b 2 S43 63 ]
[ b c d a 9 S44 64 ]
- } [ I ] with-md5-round ; inline
+ } [ I ] with-md5-round ;
+
+HINTS: (process-md5-block-F) { uint-array md5-state } ;
+HINTS: (process-md5-block-G) { uint-array md5-state } ;
+HINTS: (process-md5-block-H) { uint-array md5-state } ;
+HINTS: (process-md5-block-I) { uint-array md5-state } ;
-: (process-md5-block) ( block state -- )
+: byte-array>le ( byte-array -- byte-array )
+ little-endian? [
+ dup 4 <sliced-groups> [
+ [ [ 1 2 ] dip exchange-unsafe ]
+ [ [ 0 3 ] dip exchange-unsafe ] bi
+ ] each
+ ] unless ;
+
+: uint-array-cast-le ( byte-array -- uint-array )
+ byte-array>le uint cast-array ;
+
+HINTS: uint-array-cast-le byte-array ;
+
+: uint-array>byte-array-le ( uint-array -- byte-array )
+ underlying>> byte-array>le ;
+
+HINTS: uint-array>byte-array-le uint-array ;
+
+M: md5-state checksum-block ( block state -- )
[
- [ 4 <groups> [ le> ] map ] [ state>> ] bi* {
+ [ uint-array-cast-le ] [ state>> ] bi* {
[ (process-md5-block-F) ]
[ (process-md5-block-G) ]
[ (process-md5-block-H) ]
[ (process-md5-block-I) ]
} 2cleave
] [
- nip update-md5-state
+ nip update-md5
] 2bi ;
-:: process-md5-block ( block state -- )
- block length
- [ state [ + ] change-bytes-read drop ] [ 64 = ] bi [
- block state (process-md5-block)
- ] [
- block f state bytes-read>> pad-last-block
- [ state (process-md5-block) ] each
- ] if ;
+: md5>checksum ( md5 -- bytes ) state>> uint-array>byte-array-le ;
-: get-md5 ( md5-state -- bytes )
- state>> [ 4 >le ] map B{ } concat-as ;
+M: md5-state clone ( md5 -- new-md5 )
+ call-next-method
+ [ clone ] change-state
+ [ clone ] change-old-state ;
-:: stream>md5 ( state stream -- )
- 64 stream stream-read
- [ state process-md5-block ] [ length 64 = ] bi
- [ state stream stream>md5 ] when ;
+M: md5-state get-checksum ( md5 -- bytes )
+ clone [ bytes>> f ] [ bytes-read>> pad-last-block ] [ ] tri
+ [ [ checksum-block ] curry each ] [ md5>checksum ] bi ;
-PRIVATE>
-
-SINGLETON: md5
-
-INSTANCE: md5 stream-checksum
-
-M: md5 checksum-stream
- drop [ <md5-state> ] dip [ stream>md5 ] [ drop get-md5 ] 2bi ;
+M: md5 checksum-stream ( stream checksum -- byte-array )
+ drop
+ [ <md5-state> ] dip add-checksum-stream get-checksum ;
-GENERIC: initialize-checksum ( checksum -- state )
-GENERIC# add-bytes 1 ( state bytes -- state )
-GENERIC# add-stream 1 ( state stream -- state )
-GENERIC: finish-checksum ( state -- bytes )
-
-M: md5 initialize-checksum drop <md5-state> ;
-
-M: md5-state finish-checksum get-md5 ;
-
-M: md5-state add-bytes over [ binary <byte-reader> stream>md5 ] dip ;
-
-M: md5-state add-stream over [ stream>md5 ] dip ;
+PRIVATE>