From 8ecbb813613bbfe951b065e6ee4ee825a9ac13f0 Mon Sep 17 00:00:00 2001 From: Vincent Bernardoff Date: Wed, 1 Nov 2017 09:57:00 +0100 Subject: [PATCH] improve interface, more efficient binding --- .gitignore | 7 +- src/secp256k1.ml | 257 +++++++++++++++++++++++++++++++------------ src/secp256k1.mli | 71 +++++++++--- src/secp256k1_wrap.c | 206 +++++++++++----------------------- test/test.ml | 10 +- 5 files changed, 311 insertions(+), 240 deletions(-) diff --git a/.gitignore b/.gitignore index a8d9ca8..80ffef4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ _build *.install -**/.merlin -secp256* -setup.data -setup.log -test.native -*.clib \ No newline at end of file +**/.merlin \ No newline at end of file diff --git a/src/secp256k1.ml b/src/secp256k1.ml index f32b282..7fff742 100644 --- a/src/secp256k1.ml +++ b/src/secp256k1.ml @@ -16,6 +16,9 @@ module BA = struct let compare a b = compare_rec a b 0 (length a) (length b) + + let create len = + Bigarray.(create char c_layout len) end type buffer = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t @@ -49,49 +52,87 @@ module Secret = struct external verify : Context.t -> buffer -> bool = "ml_secp256k1_ec_seckey_verify" + let length = 32 + type t = buffer let compare = BA.compare - let of_bytes ctx buf = - if BA.length buf <> 32 then - invalid_arg "Secret.of_bytes: inputs must be 32 bytes long" ; + let of_bytes ctx ?(pos=0) buf = + let buflen = BA.length buf in + if pos < 0 || pos > buflen - length then + invalid_arg "Secret.of_bytes: pos < 0 or pos + 32 > buflen" ; + let buf = BA.sub buf pos length in match verify ctx buf with | true -> Some buf | false -> None - let of_bytes_exn ctx buf = + let of_bytes_exn ctx ?pos buf = match of_bytes ctx buf with | None -> failwith "Secret.of_bytes_exn" | Some sk -> sk + + let to_bytes t = t + + let write buf ?(pos=0) t = + let buflen = BA.length buf in + if pos < 0 || pos > buflen - length then + invalid_arg "Secret.write: pos < 0 or pos + 32 > buflen" ; + let buf = BA.sub buf pos length in + BA.blit t buf end module Public = struct type t = buffer - let compare = BA.compare - - external of_bytes : - Context.t -> buffer -> t = "ml_secp256k1_ec_pubkey_parse" + let length = 64 - external to_bytes : - Context.t -> t -> bool -> buffer = "ml_secp256k1_ec_pubkey_serialize" - - external of_secret : - Context.t -> Secret.t -> t = "ml_secp256k1_ec_pubkey_create" - - let of_bytes ctx buf = - if BA.(length buf <> 33 && length buf <> 65) then - invalid_arg "Public.of_bytes: input must be either 33 or 65 bytes long" ; - try Some (of_bytes ctx buf) with _ -> None + let compare = BA.compare - let of_bytes_exn ctx buf = - match of_bytes ctx buf with + external parse : + Context.t -> buffer -> buffer -> unit = "ml_secp256k1_ec_pubkey_parse" + + external write : + Context.t -> buffer -> t -> unit = "ml_secp256k1_ec_pubkey_serialize" + + external create : + Context.t -> buffer -> Secret.t -> unit = "ml_secp256k1_ec_pubkey_create" + + let of_secret ctx seckey = + let buf = BA.create length in + create ctx buf seckey ; + buf + + let of_bytes ctx ?(pos=0) inbuf = + let pklen = BA.length inbuf in + if pos < 0 || pos > pklen - 33 then + invalid_arg "Public.of_bytes: pos < 0 or pos > buflen - 33" ; + let inbuf = BA.(sub inbuf pos (length inbuf)) in + if BA.(length inbuf < 33) then + invalid_arg "Public.of_bytes: input must be at least 33 bytes long" ; + let outbuf = BA.create length in + try + parse ctx outbuf inbuf ; + Some outbuf + with _ -> None + + let of_bytes_exn ctx ?pos buf = + match of_bytes ctx ?pos buf with | None -> failwith "Public.of_bytes_exn" | Some pk -> pk let to_bytes ?(compress=true) ctx t = - to_bytes ctx t compress + let buf = BA.create (if compress then 33 else 65) in + write ctx buf t ; + buf + + let write ?(compress=true) ctx buf ?(pos=0) t = + let buflen = BA.length buf in + if pos < 0 || (compress && pos > buflen - 33) || pos > buflen - 65 then + invalid_arg "Public.write: pos < 0 or pos > buflen - (33|65)" ; + let len = if compress then 33 else 65 in + let buf = BA.sub buf pos len in + write ctx buf t end module Sign = struct @@ -99,87 +140,165 @@ module Sign = struct let compare = BA.compare + let length = 64 + external parse : - Context.t -> buffer -> bool -> t = "ml_secp256k1_ecdsa_signature_parse" + Context.t -> buffer -> buffer -> bool -> unit = "ml_secp256k1_ecdsa_signature_parse" external serialize : - Context.t -> t -> bool -> buffer = "ml_secp256k1_ecdsa_signature_serialize" - - let to_compact ctx t = serialize ctx t true - let to_der ctx t = serialize ctx t false - - let of_compact ctx buf = - try Some (parse ctx buf true) with _ -> None - - let of_compact_exn ctx buf = + Context.t -> buffer -> t -> bool -> int = "ml_secp256k1_ecdsa_signature_serialize" + + let to_compact ctx t = + let buf = BA.create length in + let (_:int) = serialize ctx buf t true in + buf + + let to_der ctx t = + let buf = BA.create 72 in + let len = serialize ctx buf t false in + BA.sub buf 0 len + + let write compact ctx buf ?(pos=0) t = + let buf = BA.(sub buf pos (length buf)) in + serialize ctx buf t compact + + let write_compact = write true + let write_der = write false + + let of_compact ctx ?(pos=0) inbuf = + let buflen = BA.length inbuf in + if pos < 0 || pos > buflen - length then + invalid_arg "Sign.of_compact: pos < 0 or pos > buflen - 64" ; + let outbuf = BA.create length in + try + parse ctx outbuf (BA.sub inbuf pos length) true ; + Some outbuf + with _ -> None + + let of_compact_exn ctx ?pos buf = match of_compact ctx buf with | None -> failwith "Sign.of_compact_exn" | Some signature -> signature - let of_der ctx buf = - try Some (parse ctx buf false) with _ -> None - - let of_der_exn ctx buf = + let of_der ctx ?(pos=0) inbuf = + let buflen = BA.length inbuf in + if pos < 0 || pos > buflen - length then + invalid_arg "Sign.of_der: pos < 0 or pos > buflen - 72" ; + let buf = BA.create length in + try + parse ctx buf BA.(sub inbuf pos (length inbuf)) false ; + Some buf + with _ -> None + + let of_der_exn ctx ?pos buf = match of_der ctx buf with | None -> failwith "Sign.of_der_exn" | Some signature -> signature external sign : - Context.t -> Secret.t -> buffer -> t = "ml_secp256k1_ecdsa_sign" + Context.t -> buffer -> Secret.t -> buffer -> unit = "ml_secp256k1_ecdsa_sign" external verify : Context.t -> Public.t -> buffer -> t -> bool = "ml_secp256k1_ecdsa_verify" - let sign ctx ~seckey ~msg = - if BA.length msg <> 32 then - invalid_arg "Sign.sign: msg must be 32 bytes long" ; - sign ctx seckey msg - - let verify ctx ~pubkey ~msg ~signature = - if BA.length msg <> 32 then - invalid_arg "Sign.verify: msg must be 32 bytes long" ; - verify ctx pubkey msg signature + let write_sign ctx ~seckey ~outbuf ?(outpos=0) ~inbuf ?(inpos=0) () = + let inbuflen = BA.length inbuf in + if inpos < 0 || inpos > inbuflen - 32 then + invalid_arg "Sign.sign: inpos < 0 or inpos > msglen - 32" ; + let outbuflen = BA.length outbuf in + if outpos < 0 || outpos > outbuflen - length then + invalid_arg "Sign.write_sign: outpos < 0 or outpos > outbuf - 64" ; + sign ctx (BA.sub outbuf outpos length) seckey (BA.sub inbuf inpos 32) + + let sign ctx ~seckey ?(pos=0) inbuf = + let buflen = BA.length inbuf in + if pos < 0 || pos > buflen - 32 then + invalid_arg "Sign.sign: pos < 0 || pos > msglen - 32" ; + let outbuf = BA.create length in + sign ctx outbuf seckey (BA.sub inbuf pos 32) ; + outbuf + + let verify ctx ~pubkey ~signature ?(pos=0) msg = + let msglen = BA.length msg in + if pos < 0 || pos > msglen - 32 then + invalid_arg "Sign.verify: msg must be at least 32 bytes long" ; + verify ctx pubkey (BA.sub msg pos 32) signature end module RecoverableSign = struct type t = buffer + let length = 65 + let compare = BA.compare external parse : - Context.t -> buffer -> int -> t = "ml_secp256k1_ecdsa_recoverable_signature_parse_compact" - - let of_compact ctx buf recid = - try Some (parse ctx buf recid) with _ -> None - - let of_compact_exn ctx buf recid = - match of_compact ctx buf recid with + Context.t -> buffer -> buffer -> int -> unit = "ml_secp256k1_ecdsa_recoverable_signature_parse_compact" + + let of_compact ctx ~recid ?(pos=0) inbuf = + let buflen = BA.length inbuf in + if pos < 0 || pos > buflen - Sign.length then + invalid_arg "RecoverableSign.of_compact: pos < 0 or pos > buflen - 64" ; + let buf = BA.create length in + try + parse ctx buf (BA.sub inbuf pos Sign.length) recid ; + Some buf + with _ -> None + + let of_compact_exn ctx ~recid ?pos inbuf = + match of_compact ctx ~recid ?pos inbuf with | None -> failwith "RecoverableSign.of_compact_exn" | Some signature -> signature external serialize : - Context.t -> t -> (buffer * int) = "ml_secp256k1_ecdsa_recoverable_signature_serialize_compact" + Context.t -> buffer -> t -> int = "ml_secp256k1_ecdsa_recoverable_signature_serialize_compact" + + let to_compact ctx sign = + let buf = BA.create 64 in + let recid = serialize ctx buf sign in + buf, recid - let to_compact ctx sign = serialize ctx sign + let write_compact ctx buf ?(pos=0) sign = + let buflen = BA.length buf in + if pos < 0 || pos > buflen - Sign.length then + invalid_arg "RecoverableSign.write_compact: pos < 0 or pos > buflen - 64" ; + serialize ctx (BA.sub buf pos Sign.length) sign external convert : - Context.t -> t -> Sign.t = "ml_secp256k1_ecdsa_recoverable_signature_convert" + Context.t -> buffer -> t -> unit = "ml_secp256k1_ecdsa_recoverable_signature_convert" - let convert ctx sign = convert ctx sign + let convert ctx sign = + let buf = BA.create Sign.length in + convert ctx buf sign ; + buf external sign : - Context.t -> Secret.t -> buffer -> t = "ml_secp256k1_ecdsa_sign_recoverable" - - let sign ctx ~seckey ~msg = - if BA.length msg <> 32 then - invalid_arg "RecoverableSign.sign: msg must be 32 bytes long" ; - sign ctx seckey msg + Context.t -> buffer -> Secret.t -> buffer -> unit = "ml_secp256k1_ecdsa_sign_recoverable" + + let write_sign ctx ~seckey ~outbuf ?(outpos=0) ~inbuf ?(inpos=0) () = + let inbuf_len = BA.length inbuf in + if inpos < 0 || inpos > inbuf_len - 32 then + invalid_arg "RecoverableSign.write_sign: inpos < 0 or inpos > inbuflen - 32" ; + let outbuf_len = BA.length outbuf in + if outpos < 0 || outpos > outbuf_len - length then + invalid_arg "RecoverableSign.write_sign: outpos < 0 or outpos > outbuflen - 65" ; + sign ctx (BA.sub outbuf outpos length) seckey (BA.sub inbuf inpos 32) + + let sign ctx ~seckey ?(pos=0) inbuf = + let inbuflen = BA.length inbuf in + if pos < 0 || pos > inbuflen - 32 then + invalid_arg "RecoverableSign.sign: buf must be at least 32 bytes long" ; + let outbuf = BA.create length in + sign ctx outbuf seckey (BA.sub inbuf pos 32) ; + outbuf external recover : - Context.t -> t -> buffer -> Public.t = "ml_secp256k1_ecdsa_recover" - - let recover ctx sign ~msg = - if BA.length msg <> 32 then - invalid_arg "RecoverableSign.recover: msg must be 32 bytes long" ; - recover ctx sign msg - + Context.t -> buffer -> t -> buffer -> unit = "ml_secp256k1_ecdsa_recover" + + let recover ctx sign ?(pos=0) inbuf = + let inbuflen = BA.length inbuf in + if pos < 0 || pos > inbuflen - 32 then + invalid_arg "RecoverableSign.recover: pos < 0 or pos > msglen - 32" ; + let buf = BA.create Public.length in + recover ctx buf sign (BA.sub inbuf pos 32) ; + buf end diff --git a/src/secp256k1.mli b/src/secp256k1.mli index 1d7ca44..08d14e8 100644 --- a/src/secp256k1.mli +++ b/src/secp256k1.mli @@ -53,12 +53,19 @@ module Secret : sig type t (** Opaque type of a valid ECDSA secret key. *) + val length : int + (** Size of a secp256k1 secret key in bytes (32). *) + val compare : t -> t -> int - val of_bytes : Context.t -> buffer -> t option - val of_bytes_exn : Context.t -> buffer -> t + val of_bytes : Context.t -> ?pos:int -> buffer -> t option + val of_bytes_exn : Context.t -> ?pos:int -> buffer -> t (** Verify an ECDSA secret key. Buffer must be 32 bytes long. *) + val to_bytes : t -> buffer + + val write : buffer -> ?pos:int -> t -> unit + (** [write buf ?pos key] writes [key] at [buf] starting at [pos]. *) end module Public : sig @@ -68,18 +75,22 @@ module Public : sig val compare : t -> t -> int - val of_bytes : Context.t -> buffer -> t option - val of_bytes_exn : Context.t -> buffer -> t + val of_bytes : Context.t -> ?pos:int -> buffer -> t option + val of_bytes_exn : Context.t -> ?pos:int -> buffer -> t (** Parse a variable-length public key. This function supports parsing compressed (33 bytes, header byte 0x02 or 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header byte 0x06 or 0x07) format public keys. *) + val of_secret : Context.t -> Secret.t -> t + (** Compute the public key for a secret key. *) + val to_bytes : ?compress:bool -> Context.t -> t -> buffer (** Serialize a pubkey object into a serialized byte sequence. *) - val of_secret : Context.t -> Secret.t -> t - (** Compute the public key for a secret key. *) + val write : ?compress:bool -> Context.t -> buffer -> ?pos:int -> t -> unit + (** [write ?compress ctx buf ?pos key] writes [key] at [but] + starting at [pos]. *) end module Sign : sig @@ -88,13 +99,13 @@ module Sign : sig val compare : t -> t -> int - val of_compact : Context.t -> buffer -> t option - val of_compact_exn : Context.t -> buffer -> t + val of_compact : Context.t -> ?pos:int -> buffer -> t option + val of_compact_exn : Context.t -> ?pos:int -> buffer -> t (** Parse an ECDSA signature in compact (64 bytes) format. Buffer must be 64 bytes long. *) - val of_der : Context.t -> buffer -> t option - val of_der_exn : Context.t -> buffer -> t + val of_der : Context.t -> ?pos:int -> buffer -> t option + val of_der_exn : Context.t -> ?pos:int -> buffer -> t (** Parse a DER ECDSA signature. *) val to_compact : Context.t -> t -> buffer @@ -103,11 +114,27 @@ module Sign : sig val to_der : Context.t -> t -> buffer (** Serialize an ECDSA signature in DER format. *) - val sign : Context.t -> seckey:Secret.t -> msg:buffer -> t + val write_compact : Context.t -> buffer -> ?pos:int -> t -> int + (** [write_compact ctx buf ?pos signature] writes [signature] at [buf] + starting at [pos] in compact format. *) + + val write_der : Context.t -> buffer -> ?pos:int -> t -> int + (** [write_der ctx buf ?pos signature] writes [signature] at [buf] + starting at [pos] in DER format. *) + + val sign : Context.t -> seckey:Secret.t -> ?pos:int -> buffer -> t (** Create an ECDSA signature. The created signature is always in lower-S form. Buffer must contain a 32-byte message hash. *) - val verify : Context.t -> pubkey:Public.t -> msg:buffer -> signature:t -> bool + val write_sign : Context.t -> seckey:Secret.t -> + outbuf:buffer -> ?outpos:int -> + inbuf:buffer -> ?inpos:int -> unit -> unit + (** [write_sign ctx ~seckey ~outbuf ~outpos ~inbuf ~inpos ()] signs + the message at [inbuf] starting at [inpos] and writes the + signature at [outbuf] starting at [outpos] using [seckey] *) + + val verify : + Context.t -> pubkey:Public.t -> signature:t -> ?pos:int -> buffer -> bool (** Verify an ECDSA signature. To avoid accepting malleable signatures, only ECDSA signatures in lower-S form are accepted. *) @@ -120,8 +147,8 @@ module RecoverableSign : sig val compare : t -> t -> int - val of_compact : Context.t -> buffer -> int -> t option - val of_compact_exn : Context.t -> buffer -> int -> t + val of_compact : Context.t -> recid:int -> ?pos:int -> buffer -> t option + val of_compact_exn : Context.t -> recid:int -> ?pos:int -> buffer -> t (** Parse an ECDSA recoverable signature in compact (64 bytes) format. Buffer must be 64 bytes. The third argument is the recovery id. *) @@ -130,14 +157,26 @@ module RecoverableSign : sig (** Serialize an ECDSA recoverable signature in compact (64 bytes) format. The returned int is the recovery id. *) + val write_compact : Context.t -> buffer -> ?pos:int -> t -> int + (** [write_compact ctx buf ?pos signature] writes [signature] at [buf] + starting at [pos] in compact format. *) + val convert : Context.t -> t -> Sign.t (** Convert an ECDSA recoverable signature into an ECDSA signature *) - val sign : Context.t -> seckey:Secret.t -> msg:buffer -> t + val sign : Context.t -> seckey:Secret.t -> ?pos:int -> buffer -> t (** Create an ECDSA recoverable signature. Buffer must contain a 32-byte message hash. *) - val recover : Context.t -> t -> msg:buffer -> Public.t + val write_sign : + Context.t -> seckey:Secret.t -> + outbuf:buffer -> ?outpos:int -> + inbuf:buffer -> ?inpos:int -> unit -> unit + (** [write_sign ctx ~seckey ~outbuf ~outpos ~inbuf ~inpos ()] signs + the message at [inbuf] starting at [inpos] and writes the + signature at [outbuf] starting at [outpos] using [seckey] *) + + val recover : Context.t -> t -> ?pos:int -> buffer -> Public.t (** Recover an ECDSA public key from a signature. Buffer must contain a 32-byte message hash. *) end diff --git a/src/secp256k1_wrap.c b/src/secp256k1_wrap.c index ccc6028..b125dc9 100644 --- a/src/secp256k1_wrap.c +++ b/src/secp256k1_wrap.c @@ -99,41 +99,31 @@ ml_secp256k1_ec_seckey_verify (value ml_context, value ml_seckey) { /* Create public key */ CAMLprim value -ml_secp256k1_ec_pubkey_create (value ml_context, value ml_seckey) { - CAMLparam2 (ml_context, ml_seckey); - CAMLlocal1 (result); +ml_secp256k1_ec_pubkey_create (value ml_context, value ml_buf, value ml_seckey) { + CAMLparam3 (ml_context, ml_buf, ml_seckey); - /* Create the publickey */ - secp256k1_pubkey pubkey; int ret; ret = secp256k1_ec_pubkey_create (Context_val (ml_context), - &pubkey, + Caml_ba_data_val(ml_buf), Caml_ba_data_val(ml_seckey)); if (!ret) caml_failwith ("ml_secp256k1_ec_pubkey_create"); - result = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, - NULL, - sizeof(secp256k1_pubkey)); - memcpy(Caml_ba_data_val(result), pubkey.data, sizeof(secp256k1_pubkey)); - - CAMLreturn (result); + CAMLreturn(Val_unit); } CAMLprim value -ml_secp256k1_ec_pubkey_serialize (value ml_context, value ml_pubkey, value ml_compressed) { - CAMLparam3 (ml_context, ml_pubkey, ml_compressed); - CAMLlocal1 (result); +ml_secp256k1_ec_pubkey_serialize (value ml_context, value ml_buf, value ml_pubkey) { + CAMLparam3 (ml_context, ml_buf, ml_pubkey); - size_t size = 65; + size_t size = Caml_ba_array_val(ml_buf)->dim[0]; unsigned int flags = - Bool_val(ml_compressed) ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED; - unsigned char pubkey[size]; + size == 33 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED; int ret = secp256k1_ec_pubkey_serialize(Context_val (ml_context), - pubkey, + Caml_ba_data_val(ml_buf), &size, Caml_ba_data_val(ml_pubkey), flags); @@ -141,61 +131,44 @@ ml_secp256k1_ec_pubkey_serialize (value ml_context, value ml_pubkey, value ml_co if (!ret) caml_failwith ("ml_secp256k1_ec_pubkey_serialize"); - result = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, NULL, size); - memcpy(Caml_ba_data_val(result), pubkey, size); - - CAMLreturn (result); + CAMLreturn(Val_unit); } CAMLprim value -ml_secp256k1_ec_pubkey_parse(value ml_context, value ml_buf) { - CAMLparam2 (ml_context, ml_buf); - CAMLlocal1 (result); - - secp256k1_pubkey pubkey; +ml_secp256k1_ec_pubkey_parse(value ml_context, value ml_buf, value ml_pk) { + CAMLparam3 (ml_context, ml_buf, ml_pk); int ret = secp256k1_ec_pubkey_parse(Context_val (ml_context), - &pubkey, Caml_ba_data_val(ml_buf), - Caml_ba_array_val(ml_buf)->dim[0]); + Caml_ba_data_val(ml_pk), + Caml_ba_array_val(ml_pk)->dim[0]); if (!ret) caml_failwith ("ml_secp256k1_ec_pubkey_parse"); - result = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, - NULL, - sizeof(secp256k1_pubkey)); - memcpy(Caml_ba_data_val(result), pubkey.data, sizeof(secp256k1_pubkey)); - - CAMLreturn (result); + CAMLreturn(Val_unit); } CAMLprim value -ml_secp256k1_ecdsa_signature_parse (value ml_context, value ml_buf, value ml_compact) { - CAMLparam3 (ml_context, ml_buf, ml_compact); - CAMLlocal1 (result); +ml_secp256k1_ecdsa_signature_parse (value ml_context, value ml_buf, value ml_sig, value ml_compact) { + CAMLparam4 (ml_context, ml_buf, ml_sig, ml_compact); + int ret; - secp256k1_ecdsa_signature sign; if (Bool_val (ml_compact)) ret = secp256k1_ecdsa_signature_parse_compact (Context_val (ml_context), - &sign, - Caml_ba_data_val(ml_buf)); + Caml_ba_data_val(ml_buf), + Caml_ba_data_val(ml_sig)); else ret = secp256k1_ecdsa_signature_parse_der (Context_val (ml_context), - &sign, Caml_ba_data_val(ml_buf), - Caml_ba_array_val(ml_buf)->dim[0]); + Caml_ba_data_val(ml_sig), + Caml_ba_array_val(ml_sig)->dim[0]); if (!ret) caml_failwith ("ml_secp256k1_ecdsa_signature_parse"); - result = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, - NULL, - sizeof(secp256k1_ecdsa_signature)); - memcpy(Caml_ba_data_val(result), sign.data, sizeof(secp256k1_ecdsa_signature)); - - CAMLreturn (result); + CAMLreturn (Val_unit); } /* Verify an ecdsa signature */ @@ -214,15 +187,13 @@ ml_secp256k1_ecdsa_verify (value ml_context, value ml_pubkey, value ml_msg, valu /* Sign a message with ECDSA */ CAMLprim value -ml_secp256k1_ecdsa_sign (value ml_context, value ml_seckey, value ml_msg) { - CAMLparam3(ml_context, ml_msg, ml_seckey); - CAMLlocal1 (result); +ml_secp256k1_ecdsa_sign (value ml_context, value ml_buf, value ml_seckey, value ml_msg) { + CAMLparam4(ml_context, ml_buf, ml_msg, ml_seckey); - secp256k1_ecdsa_signature sign; int ret; ret = secp256k1_ecdsa_sign (Context_val (ml_context), - &sign, + Caml_ba_data_val(ml_buf), Caml_ba_data_val(ml_msg), Caml_ba_data_val(ml_seckey), NULL, NULL); @@ -230,76 +201,56 @@ ml_secp256k1_ecdsa_sign (value ml_context, value ml_seckey, value ml_msg) { if (!ret) caml_failwith ("ml_secp256k1_ecdsa_sign"); - result = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, - NULL, - sizeof(secp256k1_ecdsa_signature)); - memcpy(Caml_ba_data_val(result), sign.data, sizeof(secp256k1_ecdsa_signature)); - - CAMLreturn (result); + CAMLreturn(Val_unit); } CAMLprim value -ml_secp256k1_ecdsa_signature_serialize(value ml_context, value ml_signature, value ml_compact) { - CAMLparam3 (ml_context, ml_signature, ml_compact); - CAMLlocal1 (result); +ml_secp256k1_ecdsa_signature_serialize(value ml_context, value ml_buf, value ml_signature, value ml_compact) { + CAMLparam4 (ml_context, ml_buf, ml_signature, ml_compact); int ret; - size_t size = 72; - unsigned char buf[size]; - if (Bool_val (ml_compact)) - ret = secp256k1_ecdsa_signature_serialize_compact(Context_val (ml_context), - buf, - Caml_ba_data_val(ml_signature)); - else - ret = secp256k1_ecdsa_signature_serialize_der(Context_val (ml_context), - buf, - &size, - Caml_ba_data_val(ml_signature)); + size_t size = Caml_ba_array_val(ml_buf)->dim[0]; + + ret = Bool_val(ml_compact) ? + secp256k1_ecdsa_signature_serialize_compact(Context_val (ml_context), + Caml_ba_data_val(ml_buf), + Caml_ba_data_val(ml_signature)) + : + secp256k1_ecdsa_signature_serialize_der(Context_val (ml_context), + Caml_ba_data_val(ml_buf), + &size, + Caml_ba_data_val(ml_signature)); if (!ret) caml_failwith ("ml_secp256k1_ecdsa_signature_serialize"); - result = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, - NULL, - size); - memcpy(Caml_ba_data_val(result), buf, size); - CAMLreturn (result); + CAMLreturn (Bool_val(ml_compact) ? Val_int(64) : Val_int(size)); } CAMLprim value -ml_secp256k1_ecdsa_recoverable_signature_parse_compact (value ml_context, value ml_buf, value ml_recid) { - CAMLparam3 (ml_context, ml_buf, ml_recid); - CAMLlocal1 (result); +ml_secp256k1_ecdsa_recoverable_signature_parse_compact (value ml_context, value ml_buf, value ml_signature, value ml_recid) { + CAMLparam4 (ml_context, ml_buf, ml_signature, ml_recid); int ret; - secp256k1_ecdsa_recoverable_signature sign; ret = secp256k1_ecdsa_recoverable_signature_parse_compact (Context_val (ml_context), - &sign, Caml_ba_data_val(ml_buf), + Caml_ba_data_val(ml_signature), Int_val(ml_recid)); if (!ret) caml_failwith ("ml_secp256k1_ecdsa_recoverable_signature_parse_compact"); - result = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, - NULL, - sizeof(secp256k1_ecdsa_recoverable_signature)); - memcpy(Caml_ba_data_val(result), sign.data, sizeof(secp256k1_ecdsa_recoverable_signature)); - - CAMLreturn (result); + CAMLreturn(Val_unit); } CAMLprim value -ml_secp256k1_ecdsa_sign_recoverable (value ml_context, value ml_seckey, value ml_msg) { - CAMLparam3(ml_context, ml_seckey, ml_msg); - CAMLlocal1 (result); - - secp256k1_ecdsa_recoverable_signature sign; +ml_secp256k1_ecdsa_sign_recoverable (value ml_context, value ml_buf, value ml_seckey, value ml_msg) { + CAMLparam4(ml_context, ml_buf, ml_seckey, ml_msg); int ret; ret = secp256k1_ecdsa_sign_recoverable (Context_val (ml_context), - &sign, + Caml_ba_data_val(ml_buf), Caml_ba_data_val(ml_msg), Caml_ba_data_val(ml_seckey), NULL, NULL); @@ -307,88 +258,55 @@ ml_secp256k1_ecdsa_sign_recoverable (value ml_context, value ml_seckey, value ml if (!ret) caml_failwith ("ml_secp256k1_ecdsa_sign_recoverable"); - result = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, - NULL, - sizeof(secp256k1_ecdsa_recoverable_signature)); - memcpy(Caml_ba_data_val(result), sign.data, sizeof(secp256k1_ecdsa_recoverable_signature)); - - CAMLreturn (result); + CAMLreturn(Val_unit); } CAMLprim value -ml_secp256k1_ecdsa_recoverable_signature_serialize_compact(value ml_context, value ml_signature) { - CAMLparam2 (ml_context, ml_signature); - CAMLlocal3 (result_tuple, result_buffer, result_recid); - +ml_secp256k1_ecdsa_recoverable_signature_serialize_compact(value ml_context, value ml_buf, value ml_signature) { + CAMLparam3 (ml_context, ml_buf, ml_signature); int ret; int recid; - size_t size = 64; - unsigned char buf[size]; + ret = secp256k1_ecdsa_recoverable_signature_serialize_compact(Context_val (ml_context), - buf, + Caml_ba_data_val(ml_buf), &recid, Caml_ba_data_val(ml_signature)); if (!ret) caml_failwith ("ml_secp256k1_ecdsa_recoverable_signature_serialize_compact"); - result_buffer = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, - NULL, - size); - memcpy(Caml_ba_data_val(result_buffer), buf, size); - - result_recid = Val_int(recid); - - result_tuple = caml_alloc_tuple(2); - Store_field(result_tuple, 0, result_buffer); - Store_field(result_tuple, 1, result_recid); - - CAMLreturn (result_tuple); + CAMLreturn(Val_int(recid)); } CAMLprim value -ml_secp256k1_ecdsa_recoverable_signature_convert(value ml_context, value ml_signature) { - CAMLparam2 (ml_context, ml_signature); - CAMLlocal1 (result); +ml_secp256k1_ecdsa_recoverable_signature_convert(value ml_context, value ml_buf, value ml_signature) { + CAMLparam3 (ml_context, ml_buf, ml_signature); int ret; - secp256k1_ecdsa_signature sign; ret = secp256k1_ecdsa_recoverable_signature_convert (Context_val (ml_context), - &sign, + Caml_ba_data_val(ml_buf), Caml_ba_data_val(ml_signature)); if (!ret) caml_failwith ("ml_secp256k1_ecdsa_recoverable_signature_convert"); - result = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, - NULL, - sizeof(secp256k1_ecdsa_signature)); - memcpy(Caml_ba_data_val(result), sign.data, sizeof(secp256k1_ecdsa_signature)); - - CAMLreturn (result); + CAMLreturn(Val_unit); } CAMLprim value -ml_secp256k1_ecdsa_recover(value ml_context, value ml_signature, value ml_msg) { - CAMLparam3 (ml_context, ml_signature, ml_msg); - CAMLlocal1 (result); +ml_secp256k1_ecdsa_recover(value ml_context, value ml_buf, value ml_signature, value ml_msg) { + CAMLparam4 (ml_context, ml_buf, ml_signature, ml_msg); - secp256k1_pubkey pubkey; int ret; ret = secp256k1_ecdsa_recover(Context_val (ml_context), - &pubkey, + Caml_ba_data_val(ml_buf), Caml_ba_data_val(ml_signature), Caml_ba_data_val(ml_msg)); if (!ret) caml_failwith ("ml_secp256k1_ecdsa_recover"); - result = caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT, 1, - NULL, - sizeof(secp256k1_pubkey)); - memcpy(Caml_ba_data_val(result), pubkey.data, sizeof(secp256k1_pubkey)); - - CAMLreturn (result); + CAMLreturn(Val_unit); } diff --git a/test/test.ml b/test/test.ml index 4c9ec07..e4c458a 100644 --- a/test/test.ml +++ b/test/test.ml @@ -39,7 +39,7 @@ let test_valid_signature octx = (`Hex "3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589") in let pubkey = pk_of_string ctx (`Hex "040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40") in - assert_equal true (Sign.verify ctx ~signature ~msg ~pubkey) + assert_equal true (Sign.verify ctx ~signature ~pubkey msg) let test_invalid_signature octx = let ctx = Context.create [Verify] in @@ -49,7 +49,7 @@ let test_invalid_signature octx = (`Hex "3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589") in let pubkey = pk_of_string ctx (`Hex "040a629506e1b65cd9d2e0ba9c75df9c4fed0db16dc9625ed14397f0afc836fae595dc53f8b0efe61e703075bd9b143bac75ec0e19f82a2208caeb32be53414c40") in - assert_equal false (Sign.verify ctx ~signature ~msg ~pubkey) + assert_equal false (Sign.verify ctx ~signature ~pubkey msg) let test_public_module octx = let pubtrue_hex = @@ -78,7 +78,7 @@ let test_sign octx = let msg = buffer_of_string (`Hex "CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90") in let seckey = sk_of_string ctx (`Hex "67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530") in let validsign = signature_of_string ctx (`Hex "30440220182a108e1448dc8f1fb467d06a0f3bb8ea0533584cb954ef8da112f1d60e39a202201c66f36da211c087f3af88b50edf4f9bdaa6cf5fd6817e74dca34db12390c6e9") in - let sign = Sign.sign ctx ~msg ~seckey in + let sign = Sign.sign ctx ~seckey msg in assert_equal 0 (Sign.compare sign validsign) let test_recover octx = @@ -89,9 +89,9 @@ let test_recover octx = let recoverable_sign = RecoverableSign.sign ctx seckey msg in let usual_sign = RecoverableSign.convert ctx recoverable_sign in let verify_ctx = Context.create [Verify] in - assert (Sign.verify verify_ctx pubkey msg usual_sign); + assert (Sign.verify verify_ctx pubkey usual_sign msg); let (compact, recid) = RecoverableSign.to_compact verify_ctx recoverable_sign in - let parsed = RecoverableSign.of_compact_exn verify_ctx compact recid in + let parsed = RecoverableSign.of_compact_exn verify_ctx compact ~recid in assert_equal 0 (RecoverableSign.compare parsed recoverable_sign); let recovered = RecoverableSign.recover verify_ctx recoverable_sign msg in assert_equal 0 (Public.compare recovered pubkey)