[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#663520: Support for incremental updates, bigarrays and multithreading



Source: ocaml-sha
Version: 1.7-2
Severity: wishlist
Tags: upstream patch

Hi,

I'm afraid I combined a few things in a single patch. If needed I can
split it up into smaller chunks:

- Expose the context
  + Add type ctx
  + Expose init, update and finalize
- Add context copy function
- Rename update to unsafe_update_substring
- Add update_substring with range checking
- Add update_string
- Add bigarray support
  + Add type buf (shortcut because the full type is too long to type)
  + Add update_buffer
  + Add buffer
- Change stub_sha1_file() to release/aquire the runtime system

For me the important functions are buffer to compute the sha checksum
in a thread and init + update_buffer + finalize to do the same if the
data is split up into multiple blocks.

Since strings can be moved by the GC the string based functions can
not release the runtime system and therefore can not run concurrently
with other threads. Some simple tests with bigarrays show a speedup of
3.7 times on 4 cores even with smallish blocks.

MfG
	Goswin

-- System Information:
Debian Release: wheezy/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 3.1.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=C, LC_CTYPE=de_DE (charmap=ISO-8859-1)
Shell: /bin/sh linked to /bin/dash
Description: Support for update and bigarray
 This patch exposes the context and provides incremental update
 functions for strings and bigarrays. The bigarray functions run
 without holding the global lock and the file function is also changed
 to run without the global lock. This enables other threads to run
 concurrently while the sha checksum is being computed.
Author: Goswin von Brederlow <goswin-v-b@web.de>
Last-Update: 2012-03-11

---

Index: ocaml-sha-1.7/sha1_stubs.c
===================================================================
--- ocaml-sha-1.7.orig/sha1_stubs.c	2012-03-11 22:29:16.000000000 +0100
+++ ocaml-sha-1.7/sha1_stubs.c	2012-03-11 22:39:21.000000000 +0100
@@ -25,7 +25,7 @@
 	int fd; ssize_t n;
 	struct sha1_ctx ctx;
 
-	fd = open(filename, O_RDONLY);
+	fd = open(filename, O_RDONLY | O_CLOEXEC);
 	if (fd == -1)
 		return 1;
 	sha1_init(&ctx);
@@ -44,6 +44,8 @@
 #include <caml/alloc.h>
 #include <caml/custom.h>
 #include <caml/fail.h>
+#include <caml/bigarray.h>
+#include <caml/threads.h>
 
 #define GET_CTX_STRUCT(a) ((struct sha1_ctx *) a)
 
@@ -68,6 +70,19 @@
 	CAMLreturn(Val_unit);
 }
 
+CAMLprim value stub_sha1_update_bigarray(value ctx, value buf)
+{
+	CAMLparam2(ctx, buf);
+	unsigned char *data = Data_bigarray_val(buf);
+	size_t len = Bigarray_val(buf)->dim[0];
+
+	caml_release_runtime_system();
+	sha1_update(GET_CTX_STRUCT(ctx), data, len);
+	caml_acquire_runtime_system();
+
+	CAMLreturn(Val_unit);
+}
+
 CAMLprim value stub_sha1_finalize(value ctx)
 {
 	CAMLparam1(ctx);
@@ -79,14 +94,34 @@
 	CAMLreturn(result);
 }
 
+CAMLprim value stub_sha1_copy(value ctx)
+{
+	CAMLparam1(ctx);
+	CAMLlocal1(result);
+
+	result = caml_alloc(sizeof(struct sha1_ctx), Abstract_tag);
+	sha1_copy(GET_CTX_STRUCT(result), GET_CTX_STRUCT(ctx));
+
+	CAMLreturn(result);
+}
+
 CAMLprim value stub_sha1_file(value name)
 {
 	CAMLparam1(name);
 	CAMLlocal1(result);
 
+	char *name_dup = strdup(String_val(name));
+	sha1_digest digest;
+
+	caml_release_runtime_system();
+	if (sha1_file(name_dup, &digest)) {
+	    free(name_dup);
+	    caml_acquire_runtime_system();
+	    caml_failwith("file error");
+	}
+	caml_acquire_runtime_system();
 	result = caml_alloc(sizeof(sha1_digest), Abstract_tag);
-	if (sha1_file(String_val(name), (sha1_digest *) result))
-		caml_failwith("file error");
+	memcpy((sha1_digest *)result, &digest, sizeof(sha1_digest));
 
 	CAMLreturn(result);
 }
Index: ocaml-sha-1.7/sha1.mli
===================================================================
--- ocaml-sha-1.7.orig/sha1.mli	2012-03-11 22:29:16.000000000 +0100
+++ ocaml-sha-1.7/sha1.mli	2012-03-11 22:49:00.000000000 +0100
@@ -14,12 +14,44 @@
 
 (** SHA1 OCaml binding *)
 
+(** context type - opaque *)
+type ctx
+
+(** buffer type *)
+type buf = (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
+
 (** digest type - opaque *)
 type t
 
 (** The zero digest *)
 val zero : t
 
+(** Create a new context *)
+external init: unit -> ctx = "stub_sha1_init"
+
+(** Sha1.unsafe_update_substring ctx s ofs len updates the context
+    with the substring of s starting at character number ofs and
+    containing len characters. Unsafe: No range checking! *)
+external unsafe_update_substring: ctx -> string -> int -> int -> unit = "stub_sha1_update"
+
+(** Sha1.update_substring ctx s ofs len updates the context with the
+    substring of s starting at character number ofs and containing len
+    characters. *)
+val update_substring: ctx -> string -> int -> int -> unit
+
+(** Sha1.update_string ctx s updates the context with s. *)
+val update_string: ctx -> string -> unit
+
+(** Sha1.update_buffer ctx a updates the context with a.
+    Runs parallel to other threads if any exist. *)
+external update_buffer: ctx -> buf -> unit = "stub_sha1_update_bigarray"
+
+(** Finalize the context and return digest *)
+external finalize: ctx -> t = "stub_sha1_finalize"
+
+(** Return an copy of the context *)
+external copy : ctx -> ctx = "stub_sha1_copy"
+
 (** Return the digest of the given string. *)
 val string : string -> t
 
@@ -27,6 +59,9 @@
 at character number ofs and containing len characters. *)
 val substring : string -> int -> int -> t
 
+(** Return the digest of the given buffer. *)
+val buffer : buf -> t
+
 (** If len is nonnegative, Sha1.channel ic len reads len characters from
 channel ic and returns their digest, or raises End_of_file if end-of-file is
 reached before len characters are read. If len is negative, Sha1.channel ic
Index: ocaml-sha-1.7/sha1.ml
===================================================================
--- ocaml-sha-1.7.orig/sha1.ml	2012-03-11 22:29:16.000000000 +0100
+++ ocaml-sha-1.7/sha1.ml	2012-03-11 22:49:37.000000000 +0100
@@ -14,11 +14,14 @@
  *)
 
 type ctx
+type buf = (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
 type t
 
 external init: unit -> ctx = "stub_sha1_init"
-external update: ctx -> string -> int -> int -> unit = "stub_sha1_update"
+external unsafe_update_substring: ctx -> string -> int -> int -> unit = "stub_sha1_update"
+external update_buffer: ctx -> buf -> unit = "stub_sha1_update_bigarray"
 external finalize: ctx -> t = "stub_sha1_finalize"
+external copy : ctx -> ctx = "stub_sha1_copy"
 external to_bin: t -> string = "stub_sha1_to_bin"
 external to_hex: t -> string = "stub_sha1_to_hex"
 external file_fast: string -> t = "stub_sha1_file"
@@ -28,16 +31,29 @@
 
 let blksize = 4096
 
+let update_substring ctx s ofs len =
+	if len <= 0 && String.length s < ofs + len then
+		invalid_arg "substring";
+	unsafe_update_substring ctx s ofs len
+
+let update_string ctx s =
+	unsafe_update_substring ctx s 0 (String.length s)
+
 let string s =
 	let ctx = init () in
-	update ctx s 0 (String.length s);
+	unsafe_update_substring ctx s 0 (String.length s);
 	finalize ctx
 
 let substring s ofs len =
 	if len <= 0 && String.length s < ofs + len then
 		invalid_arg "substring";
 	let ctx = init () in
-	update ctx s ofs len;
+	unsafe_update_substring ctx s ofs len;
+	finalize ctx
+
+let buffer buf =
+	let ctx = init () in
+	update_buffer ctx buf;
 	finalize ctx
 
 let channel chan len =
@@ -52,7 +68,7 @@
 		if readed = 0 then
 			eof := true
 		else (
-			update ctx buf 0 readed;
+			unsafe_update_substring ctx buf 0 readed;
 			if !left <> -1 then left := !left - readed
 		)
 	done;
Index: ocaml-sha-1.7/sha1.c
===================================================================
--- ocaml-sha-1.7.orig/sha1.c	2012-03-11 22:29:16.000000000 +0100
+++ ocaml-sha-1.7/sha1.c	2012-03-11 22:29:29.000000000 +0100
@@ -33,6 +33,14 @@
 	ctx->h[4] = 0xC3D2E1F0;
 }
 
+/**
+ * sha1_copy - Copy SHA1 context
+ */
+void sha1_copy(struct sha1_ctx *dst, struct sha1_ctx *src)
+{
+	memcpy(dst, src, sizeof(*dst));
+}
+
 #define f1(x, y, z)   (z ^ (x & (y ^ z)))         /* x ? y : z */
 #define f2(x, y, z)   (x ^ y ^ z)                 /* XOR */
 #define f3(x, y, z)   ((x & y) + (z & (x ^ y)))   /* majority */
Index: ocaml-sha-1.7/sha1.h
===================================================================
--- ocaml-sha-1.7.orig/sha1.h	2012-03-11 22:29:16.000000000 +0100
+++ ocaml-sha-1.7/sha1.h	2012-03-11 22:29:29.000000000 +0100
@@ -25,6 +25,7 @@
 typedef struct { unsigned int digest[5]; } sha1_digest;
 
 void sha1_init(struct sha1_ctx *ctx);
+void sha1_copy(struct sha1_ctx *dst, struct sha1_ctx *src);
 void sha1_update(struct sha1_ctx *ctx, unsigned char *data, int len);
 void sha1_finalize(struct sha1_ctx *ctx, sha1_digest *out);
 void sha1_to_bin(sha1_digest *digest, char *out);
Index: ocaml-sha-1.7/sha256_stubs.c
===================================================================
--- ocaml-sha-1.7.orig/sha256_stubs.c	2012-03-11 20:56:00.000000000 +0100
+++ ocaml-sha-1.7/sha256_stubs.c	2012-03-11 22:39:38.000000000 +0100
@@ -25,7 +25,7 @@
 	int fd; ssize_t n;
 	struct sha256_ctx ctx;
 
-	fd = open(filename, O_RDONLY);
+	fd = open(filename, O_RDONLY | O_CLOEXEC);
 	if (fd == -1)
 		return 1;
 	sha256_init(&ctx);
@@ -44,6 +44,8 @@
 #include <caml/alloc.h>
 #include <caml/custom.h>
 #include <caml/fail.h>
+#include <caml/bigarray.h>
+#include <caml/threads.h>
 
 #define GET_CTX_STRUCT(a) ((struct sha256_ctx *) a)
 
@@ -67,6 +69,19 @@
 	CAMLreturn(Val_unit);
 }
 
+CAMLprim value stub_sha256_update_bigarray(value ctx, value buf)
+{
+	CAMLparam2(ctx, buf);
+	unsigned char *data = Data_bigarray_val(buf);
+	size_t len = Bigarray_val(buf)->dim[0];
+
+	caml_release_runtime_system();
+	sha256_update(GET_CTX_STRUCT(ctx), data, len);
+	caml_acquire_runtime_system();
+
+	CAMLreturn(Val_unit);
+}
+
 CAMLprim value stub_sha256_finalize(value ctx)
 {
 	CAMLparam1(ctx);
@@ -78,14 +93,34 @@
 	CAMLreturn(result);
 }
 
+CAMLprim value stub_sha256_copy(value ctx)
+{
+	CAMLparam1(ctx);
+	CAMLlocal1(result);
+
+	result = caml_alloc(sizeof(struct sha256_ctx), Abstract_tag);
+	sha256_copy(GET_CTX_STRUCT(result), GET_CTX_STRUCT(ctx));
+
+	CAMLreturn(result);
+}
+
 CAMLprim value stub_sha256_file(value name)
 {
 	CAMLparam1(name);
 	CAMLlocal1(result);
 
+	char *name_dup = strdup(String_val(name));
+	sha256_digest digest;
+
+	caml_release_runtime_system();
+	if (sha256_file(name_dup, &digest)) {
+	    free(name_dup);
+	    caml_acquire_runtime_system();
+	    caml_failwith("file error");
+	}
+	caml_acquire_runtime_system();
 	result = caml_alloc(sizeof(sha256_digest), Abstract_tag);
-	if (sha256_file(String_val(name), (sha256_digest *) result))
-		caml_failwith("file error");
+	memcpy((sha256_digest *)result, &digest, sizeof(sha256_digest));
 
 	CAMLreturn(result);
 }
Index: ocaml-sha-1.7/sha256.mli
===================================================================
--- ocaml-sha-1.7.orig/sha256.mli	2012-03-11 20:56:00.000000000 +0100
+++ ocaml-sha-1.7/sha256.mli	2012-03-11 22:50:18.000000000 +0100
@@ -14,12 +14,44 @@
 
 (** SHA256 OCaml binding *)
 
+(** context type - opaque *)
+type ctx
+
+(** buffer type *)
+type buf = (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
+
 (** digest type - opaque *)
 type t
 
 (** The zero digest *)
 val zero : t
 
+(** Create a new context *)
+external init: unit -> ctx = "stub_sha256_init"
+
+(** Sha256.unsafe_update_substring ctx s ofs len updates the context
+    with the substring of s starting at character number ofs and
+    containing len characters. Unsafe: No range checking! *)
+external unsafe_update_substring: ctx -> string -> int -> int -> unit = "stub_sha256_update"
+
+(** Sha256.update_substring ctx s ofs len updates the context with the
+    substring of s starting at character number ofs and containing len
+    characters. *)
+val update_substring: ctx -> string -> int -> int -> unit
+
+(** Sha256.update_string ctx s updates the context with s. *)
+val update_string: ctx -> string -> unit
+
+(** Sha256.update_buffer ctx a updates the context with a.
+    Runs parallel to other threads if any exist. *)
+external update_buffer: ctx -> buf -> unit = "stub_sha256_update_bigarray"
+
+(** Finalize the context and return digest *)
+external finalize: ctx -> t = "stub_sha256_finalize"
+
+(** Return an copy of the context *)
+external copy : ctx -> ctx = "stub_sha256_copy"
+
 (** Return the digest of the given string. *)
 val string : string -> t
 
@@ -27,6 +59,9 @@
 at character number ofs and containing len characters. *)
 val substring : string -> int -> int -> t
 
+(** Return the digest of the given buffer. *)
+val buffer : buf -> t
+
 (** If len is nonnegative, Sha256.channel ic len reads len characters from
 channel ic and returns their digest, or raises End_of_file if end-of-file is
 reached before len characters are read. If len is negative, Sha256.channel ic
Index: ocaml-sha-1.7/sha256.ml
===================================================================
--- ocaml-sha-1.7.orig/sha256.ml	2012-03-11 20:56:00.000000000 +0100
+++ ocaml-sha-1.7/sha256.ml	2012-03-11 22:49:52.000000000 +0100
@@ -14,11 +14,14 @@
  *)
 
 type ctx
+type buf = (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
 type t
 
 external init: unit -> ctx = "stub_sha256_init"
-external update: ctx -> string -> int -> int -> unit = "stub_sha256_update"
+external unsafe_update_substring: ctx -> string -> int -> int -> unit = "stub_sha256_update"
+external update_buffer: ctx -> buf -> unit = "stub_sha256_update_bigarray"
 external finalize: ctx -> t = "stub_sha256_finalize"
+external copy : ctx -> ctx = "stub_sha256_copy"
 external to_bin: t -> string = "stub_sha256_to_bin"
 external to_hex: t -> string = "stub_sha256_to_hex"
 external file_fast: string -> t = "stub_sha256_file"
@@ -28,16 +31,29 @@
 
 let blksize = 4096
 
+let update_substring ctx s ofs len =
+	if len <= 0 && String.length s < ofs + len then
+		invalid_arg "substring";
+	unsafe_update_substring ctx s ofs len
+
+let update_string ctx s =
+	unsafe_update_substring ctx s 0 (String.length s)
+
 let string s =
 	let ctx = init () in
-	update ctx s 0 (String.length s);
+	unsafe_update_substring ctx s 0 (String.length s);
 	finalize ctx
 
 let substring s ofs len =
 	if len <= 0 && String.length s < ofs + len then
 		invalid_arg "substring";
 	let ctx = init () in
-	update ctx s ofs len;
+	unsafe_update_substring ctx s ofs len;
+	finalize ctx
+
+let buffer buf =
+	let ctx = init () in
+	update_buffer ctx buf;
 	finalize ctx
 
 let channel chan len =
@@ -52,7 +68,7 @@
 		if readed = 0 then
 			eof := true
 		else (
-			update ctx buf 0 readed;
+			unsafe_update_substring ctx buf 0 readed;
 			if !left <> -1 then left := !left - readed
 		)
 	done;
Index: ocaml-sha-1.7/sha256.c
===================================================================
--- ocaml-sha-1.7.orig/sha256.c	2012-03-09 07:53:01.000000000 +0100
+++ ocaml-sha-1.7/sha256.c	2012-03-11 22:30:11.000000000 +0100
@@ -36,6 +36,14 @@
 	ctx->h[7] = 0x5be0cd19;
 }
 
+/**
+ * sha256_copy - Copy SHA256 context
+ */
+void sha256_copy(struct sha256_ctx *dst, struct sha256_ctx *src)
+{
+	memcpy(dst, src, sizeof(*dst));
+}
+
 /* 232 times the cube root of the first 64 primes 2..311 */
 static const unsigned int k[] = {
 	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
Index: ocaml-sha-1.7/sha256.h
===================================================================
--- ocaml-sha-1.7.orig/sha256.h	2009-11-09 12:09:21.000000000 +0100
+++ ocaml-sha-1.7/sha256.h	2012-03-11 22:29:29.000000000 +0100
@@ -25,6 +25,7 @@
 typedef struct { unsigned int digest[8]; } sha256_digest;
 
 void sha256_init(struct sha256_ctx *ctx);
+void sha256_copy(struct sha256_ctx *dst, struct sha256_ctx *src);
 void sha256_update(struct sha256_ctx *ctx, unsigned char *data, int len);
 void sha256_finalize(struct sha256_ctx *ctx, sha256_digest *out);
 void sha256_to_bin(sha256_digest *digest, char *out);
Index: ocaml-sha-1.7/sha512_stubs.c
===================================================================
--- ocaml-sha-1.7.orig/sha512_stubs.c	2012-03-11 20:56:00.000000000 +0100
+++ ocaml-sha-1.7/sha512_stubs.c	2012-03-11 22:39:50.000000000 +0100
@@ -25,7 +25,7 @@
 	int fd; ssize_t n;
 	struct sha512_ctx ctx;
 
-	fd = open(filename, O_RDONLY);
+	fd = open(filename, O_RDONLY | O_CLOEXEC);
 	if (fd == -1)
 		return 1;
 	sha512_init(&ctx);
@@ -44,6 +44,8 @@
 #include <caml/alloc.h>
 #include <caml/custom.h>
 #include <caml/fail.h>
+#include <caml/bigarray.h>
+#include <caml/threads.h>
 
 #define GET_CTX_STRUCT(a) ((struct sha512_ctx *) a)
 
@@ -67,6 +69,19 @@
 	CAMLreturn(Val_unit);
 }
 
+CAMLprim value stub_sha512_update_bigarray(value ctx, value buf)
+{
+	CAMLparam2(ctx, buf);
+	unsigned char *data = Data_bigarray_val(buf);
+	size_t len = Bigarray_val(buf)->dim[0];
+
+	caml_release_runtime_system();
+	sha512_update(GET_CTX_STRUCT(ctx), data, len);
+	caml_acquire_runtime_system();
+
+	CAMLreturn(Val_unit);
+}
+
 CAMLprim value stub_sha512_finalize(value ctx)
 {
 	CAMLparam1(ctx);
@@ -78,14 +93,34 @@
 	CAMLreturn(result);
 }
 
+CAMLprim value stub_sha512_copy(value ctx)
+{
+	CAMLparam1(ctx);
+	CAMLlocal1(result);
+
+	result = caml_alloc(sizeof(struct sha512_ctx), Abstract_tag);
+	sha512_copy(GET_CTX_STRUCT(result), GET_CTX_STRUCT(ctx));
+
+	CAMLreturn(result);
+}
+
 CAMLprim value stub_sha512_file(value name)
 {
 	CAMLparam1(name);
 	CAMLlocal1(result);
 
+	char *name_dup = strdup(String_val(name));
+	sha512_digest digest;
+
+	caml_release_runtime_system();
+	if (sha512_file(name_dup, &digest)) {
+	    free(name_dup);
+	    caml_acquire_runtime_system();
+	    caml_failwith("file error");
+	}
+	caml_acquire_runtime_system();
 	result = caml_alloc(sizeof(sha512_digest), Abstract_tag);
-	if (sha512_file(String_val(name), (sha512_digest *) result))
-		caml_failwith("file error");
+	memcpy((sha512_digest *)result, &digest, sizeof(sha512_digest));
 
 	CAMLreturn(result);
 }
Index: ocaml-sha-1.7/sha512.mli
===================================================================
--- ocaml-sha-1.7.orig/sha512.mli	2012-03-11 20:56:00.000000000 +0100
+++ ocaml-sha-1.7/sha512.mli	2012-03-11 22:50:28.000000000 +0100
@@ -14,12 +14,44 @@
 
 (** SHA512 OCaml binding *)
 
+(** context type - opaque *)
+type ctx
+
+(** buffer type *)
+type buf = (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
+
 (** digest type - opaque *)
 type t
 
 (** The zero digest *)
 val zero : t
 
+(** Create a new context *)
+external init: unit -> ctx = "stub_sha512_init"
+
+(** Sha512.unsafe_update_substring ctx s ofs len updates the context
+    with the substring of s starting at character number ofs and
+    containing len characters. Unsafe: No range checking! *)
+external unsafe_update_substring: ctx -> string -> int -> int -> unit = "stub_sha512_update"
+
+(** Sha512.update_substring ctx s ofs len updates the context with the
+    substring of s starting at character number ofs and containing len
+    characters. *)
+val update_substring: ctx -> string -> int -> int -> unit
+
+(** Sha512.update_string ctx s updates the context with s. *)
+val update_string: ctx -> string -> unit
+
+(** Sha512.update_buffer ctx a updates the context with a.
+    Runs parallel to other threads if any exist. *)
+external update_buffer: ctx -> buf -> unit = "stub_sha512_update_bigarray"
+
+(** Finalize the context and return digest *)
+external finalize: ctx -> t = "stub_sha512_finalize"
+
+(** Return an copy of the context *)
+external copy : ctx -> ctx = "stub_sha512_copy"
+
 (** Return the digest of the given string. *)
 val string : string -> t
 
@@ -27,6 +59,9 @@
 at character number ofs and containing len characters. *)
 val substring : string -> int -> int -> t
 
+(** Return the digest of the given buffer. *)
+val buffer : buf -> t
+
 (** If len is nonnegative, Sha512.channel ic len reads len characters from
 channel ic and returns their digest, or raises End_of_file if end-of-file is
 reached before len characters are read. If len is negative, Sha512.channel ic
Index: ocaml-sha-1.7/sha512.ml
===================================================================
--- ocaml-sha-1.7.orig/sha512.ml	2012-03-11 20:56:00.000000000 +0100
+++ ocaml-sha-1.7/sha512.ml	2012-03-11 22:50:01.000000000 +0100
@@ -14,11 +14,14 @@
  *)
 
 type ctx
+type buf = (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
 type t
 
 external init: unit -> ctx = "stub_sha512_init"
-external update: ctx -> string -> int -> int -> unit = "stub_sha512_update"
+external unsafe_update_substring: ctx -> string -> int -> int -> unit = "stub_sha512_update"
+external update_buffer: ctx -> buf -> unit = "stub_sha512_update_bigarray"
 external finalize: ctx -> t = "stub_sha512_finalize"
+external copy : ctx -> ctx = "stub_sha512_copy"
 external to_bin: t -> string = "stub_sha512_to_bin"
 external to_hex: t -> string = "stub_sha512_to_hex"
 external file_fast: string -> t = "stub_sha512_file"
@@ -28,16 +31,29 @@
 
 let blksize = 4096
 
+let update_substring ctx s ofs len =
+	if len <= 0 && String.length s < ofs + len then
+		invalid_arg "substring";
+	unsafe_update_substring ctx s ofs len
+
+let update_string ctx s =
+	unsafe_update_substring ctx s 0 (String.length s)
+
 let string s =
 	let ctx = init () in
-	update ctx s 0 (String.length s);
+	unsafe_update_substring ctx s 0 (String.length s);
 	finalize ctx
 
 let substring s ofs len =
 	if len <= 0 && String.length s < ofs + len then
 		invalid_arg "substring";
 	let ctx = init () in
-	update ctx s ofs len;
+	unsafe_update_substring ctx s ofs len;
+	finalize ctx
+
+let buffer buf =
+	let ctx = init () in
+	update_buffer ctx buf;
 	finalize ctx
 
 let channel chan len =
@@ -52,7 +68,7 @@
 		if readed = 0 then
 			eof := true
 		else (
-			update ctx buf 0 readed;
+			unsafe_update_substring ctx buf 0 readed;
 			if !left <> -1 then left := !left - readed
 		)
 	done;
Index: ocaml-sha-1.7/sha512.c
===================================================================
--- ocaml-sha-1.7.orig/sha512.c	2009-11-09 12:09:21.000000000 +0100
+++ ocaml-sha-1.7/sha512.c	2012-03-11 22:30:48.000000000 +0100
@@ -35,6 +35,14 @@
 	ctx->h[7] = 0x5be0cd19137e2179ULL;
 }
 
+/**
+ * sha512_copy - Copy SHA512 context
+ */
+void sha512_copy(struct sha512_ctx *dst, struct sha512_ctx *src)
+{
+	memcpy(dst, src, sizeof(*dst));
+}
+
 /* 232 times the cube root of the first 64 primes 2..311 */
 static const uint64_t k[] = {
 	0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
Index: ocaml-sha-1.7/sha512.h
===================================================================
--- ocaml-sha-1.7.orig/sha512.h	2009-11-09 12:09:21.000000000 +0100
+++ ocaml-sha-1.7/sha512.h	2012-03-11 22:29:29.000000000 +0100
@@ -27,6 +27,7 @@
 typedef struct { uint64_t digest[8]; } sha512_digest;
 
 void sha512_init(struct sha512_ctx *ctx);
+void sha512_copy(struct sha512_ctx *dst, struct sha512_ctx *src);
 void sha512_update(struct sha512_ctx *ctx, unsigned char *data, int len);
 void sha512_finalize(struct sha512_ctx *ctx, sha512_digest *out);
 void sha512_to_bin(sha512_digest *digest, char *out);

Reply to: