         [ 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 ;
+    } [ I ] with-md5-round ; inline
 
-: (process-md5-block) ( block -- )
-    4 <groups> [ le> ] map {
-        [ (process-md5-block-F) ]
-        [ (process-md5-block-G) ]
-        [ (process-md5-block-H) ]
-        [ (process-md5-block-I) ]
-    } cleave
+: (process-md5-block) ( block state -- )
+    [
+        [ 4 <groups> [ le> ] map ] [ state>> ] bi* {
+            [ (process-md5-block-F) ]
+            [ (process-md5-block-G) ]
+            [ (process-md5-block-H) ]
+            [ (process-md5-block-I) ]
+        } 2cleave
+    ] [
+        nip update-md5-state
+    ] 2bi ;
 
-    update-md ;
-
-: process-md5-block ( str -- )
-    dup length [ bytes-read [ + ] change ] keep 64 = [
-        (process-md5-block)
+:: process-md5-block ( block state -- )
+    block length
+    [ state [ + ] change-bytes-read drop ] [ 64 = ] bi [
+        block state (process-md5-block)
     ] [
-        f bytes-read get pad-last-block
-        [ (process-md5-block) ] each
+        block f state bytes-read>> pad-last-block
+        [ state (process-md5-block) ] each
     ] if ;
     
-: stream>md5 ( stream -- )
-    64 over stream-read
-    [ process-md5-block ] [ length 64 = ] bi
-    [ stream>md5 ] [ drop ] if ;
+:: stream>md5 ( stream state -- )
+    64 stream stream-read
+    [ state process-md5-block ] [ length 64 = ] bi
+    [ stream state stream>md5 ] when ;
 
-: get-md5 ( -- str )
-    [ a b c d ] [ get 4 >le ] map concat >byte-array ;
+: get-md5 ( md5-state -- bytes )
+    state>> [ 4 >le ] map B{ } concat-as ;
 
 PRIVATE>
 

        [ 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 ;

: (process-md5-block-H) ( block -- )
    {
        [ a b c d 5  S31 33 ]
        [ d a b c 8  S32 34 ]

checksums.common checksums.stream combinators combinators.smart ;
IN: checksums.md5

TUPLE: md5-state bytes-read state old-state ;

: <md5-state> ( -- md5-state )
    md5-state new
        0 >>bytes-read
        { HEX: 67452301 HEX: efcdab89 HEX: 98badcfe HEX: 10325476 }
        [ clone >>state ] [ clone >>old-state ] bi ;

<PRIVATE

: v-w+ ( v1 v2 -- v3 ) [ w+ ] 2map ;

: update-md5-state ( md5-state -- )
    [ state>> ] [ old-state>> v-w+ dup clone ] [ ] tri
    [ (>>old-state) ] [ (>>state) ] bi ;

: T ( N -- Y )
    sin abs 32 2^ * >integer ; foldable

:: F ( X Y Z -- FXYZ )
    #! F(X,Y,Z) = XY v not(X) Z
    X Y bitand X bitnot Z bitand bitor ; inline

:: G ( X Y Z -- GXYZ )
    #! G(X,Y,Z) = XZ v Y not(Z)
    X Z bitand Y Z bitnot bitand bitor ; inline

: H ( X Y Z -- HXYZ )
    #! H(X,Y,Z) = X xor Y xor Z
    bitxor bitxor ; inline

:: I ( X Y Z -- IXYZ )
    #! I(X,Y,Z) = Y xor (X v not(Z))
    Z bitnot X bitor Y bitxor ; inline

CONSTANT: S11 7
CONSTANT: S12 12
