         [ 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 ;
+    } [ H ] with-md5-round ; inline
 
-: (process-md5-block-I) ( block -- )
+: (process-md5-block-I) ( block v -- )
     {
         [ 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 ;

: (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

    update-md ;

: process-md5-block ( str -- )
    dup length [ bytes-read [ + ] change ] keep 64 = [
        (process-md5-block)
    ] [
        f bytes-read get pad-last-block
        [ (process-md5-block) ] each
    ] if ;
    
: stream>md5 ( stream -- )
    64 over stream-read
    [ process-md5-block ] [ length 64 = ] bi
    [ stream>md5 ] [ drop ] if ;

: get-md5 ( -- str )
    [ a b c d ] [ get 4 >le ] map concat >byte-array ;

PRIVATE>


CONSTANT: S43 15
CONSTANT: S44 21

CONSTANT: a 0
CONSTANT: b 1
CONSTANT: c 2
CONSTANT: d 3

:: (ABCD) ( x V 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+
        k x nth-unsafe w+
        i T w+
        s bitroll-32
        b V nth-unsafe w+
    ] change-nth ; inline

MACRO: with-md5-round ( ops quot -- )
    '[ [ _ (ABCD) ] compose ] map '[ _ 2cleave ] ;

: (process-md5-block-F) ( block v -- )
    {
        [ a b c d 0  S11 1  ]
        [ d a b c 1  S12 2  ]
