Skip to content

Commit 7a0a140

Browse files
authored
Merge pull request #7 from vbmithr/vb
improve interface, more efficient binding
2 parents a6b1989 + 8ecbb81 commit 7a0a140

File tree

5 files changed

+311
-240
lines changed

5 files changed

+311
-240
lines changed

.gitignore

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
11
_build
22
*.install
3-
**/.merlin
4-
secp256*
5-
setup.data
6-
setup.log
7-
test.native
8-
*.clib
3+
**/.merlin

src/secp256k1.ml

+188-69
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ module BA = struct
1616

1717
let compare a b =
1818
compare_rec a b 0 (length a) (length b)
19+
20+
let create len =
21+
Bigarray.(create char c_layout len)
1922
end
2023

2124
type buffer = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
@@ -49,137 +52,253 @@ module Secret = struct
4952
external verify :
5053
Context.t -> buffer -> bool = "ml_secp256k1_ec_seckey_verify"
5154

55+
let length = 32
56+
5257
type t = buffer
5358

5459
let compare = BA.compare
5560

56-
let of_bytes ctx buf =
57-
if BA.length buf <> 32 then
58-
invalid_arg "Secret.of_bytes: inputs must be 32 bytes long" ;
61+
let of_bytes ctx ?(pos=0) buf =
62+
let buflen = BA.length buf in
63+
if pos < 0 || pos > buflen - length then
64+
invalid_arg "Secret.of_bytes: pos < 0 or pos + 32 > buflen" ;
65+
let buf = BA.sub buf pos length in
5966
match verify ctx buf with
6067
| true -> Some buf
6168
| false -> None
6269

63-
let of_bytes_exn ctx buf =
70+
let of_bytes_exn ctx ?pos buf =
6471
match of_bytes ctx buf with
6572
| None -> failwith "Secret.of_bytes_exn"
6673
| Some sk -> sk
74+
75+
let to_bytes t = t
76+
77+
let write buf ?(pos=0) t =
78+
let buflen = BA.length buf in
79+
if pos < 0 || pos > buflen - length then
80+
invalid_arg "Secret.write: pos < 0 or pos + 32 > buflen" ;
81+
let buf = BA.sub buf pos length in
82+
BA.blit t buf
6783
end
6884

6985
module Public = struct
7086
type t = buffer
7187

72-
let compare = BA.compare
73-
74-
external of_bytes :
75-
Context.t -> buffer -> t = "ml_secp256k1_ec_pubkey_parse"
88+
let length = 64
7689

77-
external to_bytes :
78-
Context.t -> t -> bool -> buffer = "ml_secp256k1_ec_pubkey_serialize"
79-
80-
external of_secret :
81-
Context.t -> Secret.t -> t = "ml_secp256k1_ec_pubkey_create"
82-
83-
let of_bytes ctx buf =
84-
if BA.(length buf <> 33 && length buf <> 65) then
85-
invalid_arg "Public.of_bytes: input must be either 33 or 65 bytes long" ;
86-
try Some (of_bytes ctx buf) with _ -> None
90+
let compare = BA.compare
8791

88-
let of_bytes_exn ctx buf =
89-
match of_bytes ctx buf with
92+
external parse :
93+
Context.t -> buffer -> buffer -> unit = "ml_secp256k1_ec_pubkey_parse"
94+
95+
external write :
96+
Context.t -> buffer -> t -> unit = "ml_secp256k1_ec_pubkey_serialize"
97+
98+
external create :
99+
Context.t -> buffer -> Secret.t -> unit = "ml_secp256k1_ec_pubkey_create"
100+
101+
let of_secret ctx seckey =
102+
let buf = BA.create length in
103+
create ctx buf seckey ;
104+
buf
105+
106+
let of_bytes ctx ?(pos=0) inbuf =
107+
let pklen = BA.length inbuf in
108+
if pos < 0 || pos > pklen - 33 then
109+
invalid_arg "Public.of_bytes: pos < 0 or pos > buflen - 33" ;
110+
let inbuf = BA.(sub inbuf pos (length inbuf)) in
111+
if BA.(length inbuf < 33) then
112+
invalid_arg "Public.of_bytes: input must be at least 33 bytes long" ;
113+
let outbuf = BA.create length in
114+
try
115+
parse ctx outbuf inbuf ;
116+
Some outbuf
117+
with _ -> None
118+
119+
let of_bytes_exn ctx ?pos buf =
120+
match of_bytes ctx ?pos buf with
90121
| None -> failwith "Public.of_bytes_exn"
91122
| Some pk -> pk
92123

93124
let to_bytes ?(compress=true) ctx t =
94-
to_bytes ctx t compress
125+
let buf = BA.create (if compress then 33 else 65) in
126+
write ctx buf t ;
127+
buf
128+
129+
let write ?(compress=true) ctx buf ?(pos=0) t =
130+
let buflen = BA.length buf in
131+
if pos < 0 || (compress && pos > buflen - 33) || pos > buflen - 65 then
132+
invalid_arg "Public.write: pos < 0 or pos > buflen - (33|65)" ;
133+
let len = if compress then 33 else 65 in
134+
let buf = BA.sub buf pos len in
135+
write ctx buf t
95136
end
96137

97138
module Sign = struct
98139
type t = buffer
99140

100141
let compare = BA.compare
101142

143+
let length = 64
144+
102145
external parse :
103-
Context.t -> buffer -> bool -> t = "ml_secp256k1_ecdsa_signature_parse"
146+
Context.t -> buffer -> buffer -> bool -> unit = "ml_secp256k1_ecdsa_signature_parse"
104147
external serialize :
105-
Context.t -> t -> bool -> buffer = "ml_secp256k1_ecdsa_signature_serialize"
106-
107-
let to_compact ctx t = serialize ctx t true
108-
let to_der ctx t = serialize ctx t false
109-
110-
let of_compact ctx buf =
111-
try Some (parse ctx buf true) with _ -> None
112-
113-
let of_compact_exn ctx buf =
148+
Context.t -> buffer -> t -> bool -> int = "ml_secp256k1_ecdsa_signature_serialize"
149+
150+
let to_compact ctx t =
151+
let buf = BA.create length in
152+
let (_:int) = serialize ctx buf t true in
153+
buf
154+
155+
let to_der ctx t =
156+
let buf = BA.create 72 in
157+
let len = serialize ctx buf t false in
158+
BA.sub buf 0 len
159+
160+
let write compact ctx buf ?(pos=0) t =
161+
let buf = BA.(sub buf pos (length buf)) in
162+
serialize ctx buf t compact
163+
164+
let write_compact = write true
165+
let write_der = write false
166+
167+
let of_compact ctx ?(pos=0) inbuf =
168+
let buflen = BA.length inbuf in
169+
if pos < 0 || pos > buflen - length then
170+
invalid_arg "Sign.of_compact: pos < 0 or pos > buflen - 64" ;
171+
let outbuf = BA.create length in
172+
try
173+
parse ctx outbuf (BA.sub inbuf pos length) true ;
174+
Some outbuf
175+
with _ -> None
176+
177+
let of_compact_exn ctx ?pos buf =
114178
match of_compact ctx buf with
115179
| None -> failwith "Sign.of_compact_exn"
116180
| Some signature -> signature
117181

118-
let of_der ctx buf =
119-
try Some (parse ctx buf false) with _ -> None
120-
121-
let of_der_exn ctx buf =
182+
let of_der ctx ?(pos=0) inbuf =
183+
let buflen = BA.length inbuf in
184+
if pos < 0 || pos > buflen - length then
185+
invalid_arg "Sign.of_der: pos < 0 or pos > buflen - 72" ;
186+
let buf = BA.create length in
187+
try
188+
parse ctx buf BA.(sub inbuf pos (length inbuf)) false ;
189+
Some buf
190+
with _ -> None
191+
192+
let of_der_exn ctx ?pos buf =
122193
match of_der ctx buf with
123194
| None -> failwith "Sign.of_der_exn"
124195
| Some signature -> signature
125196

126197
external sign :
127-
Context.t -> Secret.t -> buffer -> t = "ml_secp256k1_ecdsa_sign"
198+
Context.t -> buffer -> Secret.t -> buffer -> unit = "ml_secp256k1_ecdsa_sign"
128199

129200
external verify :
130201
Context.t -> Public.t -> buffer -> t -> bool = "ml_secp256k1_ecdsa_verify"
131202

132-
let sign ctx ~seckey ~msg =
133-
if BA.length msg <> 32 then
134-
invalid_arg "Sign.sign: msg must be 32 bytes long" ;
135-
sign ctx seckey msg
136-
137-
let verify ctx ~pubkey ~msg ~signature =
138-
if BA.length msg <> 32 then
139-
invalid_arg "Sign.verify: msg must be 32 bytes long" ;
140-
verify ctx pubkey msg signature
203+
let write_sign ctx ~seckey ~outbuf ?(outpos=0) ~inbuf ?(inpos=0) () =
204+
let inbuflen = BA.length inbuf in
205+
if inpos < 0 || inpos > inbuflen - 32 then
206+
invalid_arg "Sign.sign: inpos < 0 or inpos > msglen - 32" ;
207+
let outbuflen = BA.length outbuf in
208+
if outpos < 0 || outpos > outbuflen - length then
209+
invalid_arg "Sign.write_sign: outpos < 0 or outpos > outbuf - 64" ;
210+
sign ctx (BA.sub outbuf outpos length) seckey (BA.sub inbuf inpos 32)
211+
212+
let sign ctx ~seckey ?(pos=0) inbuf =
213+
let buflen = BA.length inbuf in
214+
if pos < 0 || pos > buflen - 32 then
215+
invalid_arg "Sign.sign: pos < 0 || pos > msglen - 32" ;
216+
let outbuf = BA.create length in
217+
sign ctx outbuf seckey (BA.sub inbuf pos 32) ;
218+
outbuf
219+
220+
let verify ctx ~pubkey ~signature ?(pos=0) msg =
221+
let msglen = BA.length msg in
222+
if pos < 0 || pos > msglen - 32 then
223+
invalid_arg "Sign.verify: msg must be at least 32 bytes long" ;
224+
verify ctx pubkey (BA.sub msg pos 32) signature
141225
end
142226

143227
module RecoverableSign = struct
144228
type t = buffer
145229

230+
let length = 65
231+
146232
let compare = BA.compare
147233

148234
external parse :
149-
Context.t -> buffer -> int -> t = "ml_secp256k1_ecdsa_recoverable_signature_parse_compact"
150-
151-
let of_compact ctx buf recid =
152-
try Some (parse ctx buf recid) with _ -> None
153-
154-
let of_compact_exn ctx buf recid =
155-
match of_compact ctx buf recid with
235+
Context.t -> buffer -> buffer -> int -> unit = "ml_secp256k1_ecdsa_recoverable_signature_parse_compact"
236+
237+
let of_compact ctx ~recid ?(pos=0) inbuf =
238+
let buflen = BA.length inbuf in
239+
if pos < 0 || pos > buflen - Sign.length then
240+
invalid_arg "RecoverableSign.of_compact: pos < 0 or pos > buflen - 64" ;
241+
let buf = BA.create length in
242+
try
243+
parse ctx buf (BA.sub inbuf pos Sign.length) recid ;
244+
Some buf
245+
with _ -> None
246+
247+
let of_compact_exn ctx ~recid ?pos inbuf =
248+
match of_compact ctx ~recid ?pos inbuf with
156249
| None -> failwith "RecoverableSign.of_compact_exn"
157250
| Some signature -> signature
158251

159252
external serialize :
160-
Context.t -> t -> (buffer * int) = "ml_secp256k1_ecdsa_recoverable_signature_serialize_compact"
253+
Context.t -> buffer -> t -> int = "ml_secp256k1_ecdsa_recoverable_signature_serialize_compact"
254+
255+
let to_compact ctx sign =
256+
let buf = BA.create 64 in
257+
let recid = serialize ctx buf sign in
258+
buf, recid
161259

162-
let to_compact ctx sign = serialize ctx sign
260+
let write_compact ctx buf ?(pos=0) sign =
261+
let buflen = BA.length buf in
262+
if pos < 0 || pos > buflen - Sign.length then
263+
invalid_arg "RecoverableSign.write_compact: pos < 0 or pos > buflen - 64" ;
264+
serialize ctx (BA.sub buf pos Sign.length) sign
163265

164266
external convert :
165-
Context.t -> t -> Sign.t = "ml_secp256k1_ecdsa_recoverable_signature_convert"
267+
Context.t -> buffer -> t -> unit = "ml_secp256k1_ecdsa_recoverable_signature_convert"
166268

167-
let convert ctx sign = convert ctx sign
269+
let convert ctx sign =
270+
let buf = BA.create Sign.length in
271+
convert ctx buf sign ;
272+
buf
168273

169274
external sign :
170-
Context.t -> Secret.t -> buffer -> t = "ml_secp256k1_ecdsa_sign_recoverable"
171-
172-
let sign ctx ~seckey ~msg =
173-
if BA.length msg <> 32 then
174-
invalid_arg "RecoverableSign.sign: msg must be 32 bytes long" ;
175-
sign ctx seckey msg
275+
Context.t -> buffer -> Secret.t -> buffer -> unit = "ml_secp256k1_ecdsa_sign_recoverable"
276+
277+
let write_sign ctx ~seckey ~outbuf ?(outpos=0) ~inbuf ?(inpos=0) () =
278+
let inbuf_len = BA.length inbuf in
279+
if inpos < 0 || inpos > inbuf_len - 32 then
280+
invalid_arg "RecoverableSign.write_sign: inpos < 0 or inpos > inbuflen - 32" ;
281+
let outbuf_len = BA.length outbuf in
282+
if outpos < 0 || outpos > outbuf_len - length then
283+
invalid_arg "RecoverableSign.write_sign: outpos < 0 or outpos > outbuflen - 65" ;
284+
sign ctx (BA.sub outbuf outpos length) seckey (BA.sub inbuf inpos 32)
285+
286+
let sign ctx ~seckey ?(pos=0) inbuf =
287+
let inbuflen = BA.length inbuf in
288+
if pos < 0 || pos > inbuflen - 32 then
289+
invalid_arg "RecoverableSign.sign: buf must be at least 32 bytes long" ;
290+
let outbuf = BA.create length in
291+
sign ctx outbuf seckey (BA.sub inbuf pos 32) ;
292+
outbuf
176293

177294
external recover :
178-
Context.t -> t -> buffer -> Public.t = "ml_secp256k1_ecdsa_recover"
179-
180-
let recover ctx sign ~msg =
181-
if BA.length msg <> 32 then
182-
invalid_arg "RecoverableSign.recover: msg must be 32 bytes long" ;
183-
recover ctx sign msg
184-
295+
Context.t -> buffer -> t -> buffer -> unit = "ml_secp256k1_ecdsa_recover"
296+
297+
let recover ctx sign ?(pos=0) inbuf =
298+
let inbuflen = BA.length inbuf in
299+
if pos < 0 || pos > inbuflen - 32 then
300+
invalid_arg "RecoverableSign.recover: pos < 0 or pos > msglen - 32" ;
301+
let buf = BA.create Public.length in
302+
recover ctx buf sign (BA.sub inbuf pos 32) ;
303+
buf
185304
end

0 commit comments

Comments
 (0)