 : set-digest ( name ctx -- )
     handle>> swap digest-named f EVP_DigestInit_ex ssl-error ;
 
-: checksum-loop ( ctx -- )
-    dup handle>>
-    4096 read-partial dup [
-        dup length EVP_DigestUpdate ssl-error
-        checksum-loop
-    ] [ 3drop ] if ;
+PRIVATE>
 
-: digest-value ( ctx -- value )
+M: openssl-checksum initialize-checksum-state ( checksum -- evp-md-context )
+    maybe-init-ssl name>> <evp-md-context> [ set-digest ] keep ;
+
+M: evp-md-context add-checksum-bytes ( ctx bytes -- ctx' )
+    [ dup handle>> ] dip dup length EVP_DigestUpdate ssl-error ;
+
+M: evp-md-context get-checksum ( ctx -- value )
     handle>>
     { { int EVP_MAX_MD_SIZE } int }
     [ EVP_DigestFinal_ex ssl-error ] with-out-parameters
     memory>byte-array ;
 
-PRIVATE>
+M: openssl-checksum checksum-bytes ( bytes checksum -- value )
+    initialize-checksum-state [ swap add-checksum-bytes get-checksum ] with-disposal ;
 
-M: openssl-checksum checksum-stream
-    name>> swap [
-        [
-            [ set-digest ]
-            [ checksum-loop ]
-            [ digest-value ]
-            tri
-        ] with-evp-md-context
-    ] with-input-stream ;
+M: openssl-checksum checksum-stream ( stream checksum -- value )
+    initialize-checksum-state [ swap add-checksum-stream get-checksum ] with-disposal ;

! Copyright (C) 2008, 2010 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: accessors byte-arrays alien.c-types alien.data kernel
continuations destructors sequences io openssl openssl.libcrypto
checksums checksums.stream classes.struct ;
IN: checksums.openssl

ERROR: unknown-digest name ;

M: evp-md-context dispose*
    handle>> EVP_MD_CTX_destroy ;

<PRIVATE

: digest-named ( name -- md )
    dup EVP_get_digestbyname
