@@ -20,11 +20,11 @@ package secp256k1
20
20
21
21
/*
22
22
#cgo CFLAGS: -I./libsecp256k1
23
- #cgo darwin CFLAGS: -I/usr/local/include -I/opt/pkg/include
23
+ #cgo darwin CFLAGS: -I/usr/local/include
24
24
#cgo freebsd CFLAGS: -I/usr/local/include
25
25
#cgo linux,arm CFLAGS: -I/usr/local/arm/include
26
26
#cgo LDFLAGS: -lgmp
27
- #cgo darwin LDFLAGS: -L/usr/local/lib -L/opt/pkg/lib
27
+ #cgo darwin LDFLAGS: -L/usr/local/lib
28
28
#cgo freebsd LDFLAGS: -L/usr/local/lib
29
29
#cgo linux,arm LDFLAGS: -L/usr/local/arm/lib
30
30
#define USE_NUM_GMP
@@ -35,11 +35,14 @@ package secp256k1
35
35
#define NDEBUG
36
36
#include "./libsecp256k1/src/secp256k1.c"
37
37
#include "./libsecp256k1/src/modules/recovery/main_impl.h"
38
+
39
+ typedef void (*callbackFunc) (const char* msg, void* data);
40
+ extern void secp256k1GoPanicIllegal(const char* msg, void* data);
41
+ extern void secp256k1GoPanicError(const char* msg, void* data);
38
42
*/
39
43
import "C"
40
44
41
45
import (
42
- "bytes"
43
46
"errors"
44
47
"unsafe"
45
48
@@ -62,8 +65,16 @@ var context *C.secp256k1_context
62
65
func init () {
63
66
// around 20 ms on a modern CPU.
64
67
context = C .secp256k1_context_create (3 ) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY
68
+ C .secp256k1_context_set_illegal_callback (context , C .callbackFunc (C .secp256k1GoPanicIllegal ), nil )
69
+ C .secp256k1_context_set_error_callback (context , C .callbackFunc (C .secp256k1GoPanicError ), nil )
65
70
}
66
71
72
+ var (
73
+ ErrInvalidMsgLen = errors .New ("invalid message length for signature recovery" )
74
+ ErrInvalidSignatureLen = errors .New ("invalid signature length" )
75
+ ErrInvalidRecoveryID = errors .New ("invalid signature recovery id" )
76
+ )
77
+
67
78
func GenerateKeyPair () ([]byte , []byte ) {
68
79
var seckey []byte = randentropy .GetEntropyCSPRNG (32 )
69
80
var seckey_ptr * C.uchar = (* C .uchar )(unsafe .Pointer (& seckey [0 ]))
@@ -177,69 +188,20 @@ func VerifySeckeyValidity(seckey []byte) error {
177
188
return nil
178
189
}
179
190
180
- func VerifySignatureValidity (sig []byte ) bool {
181
- //64+1
182
- if len (sig ) != 65 {
183
- return false
184
- }
185
- //malleability check, highest bit must be 1
186
- if (sig [32 ] & 0x80 ) == 0x80 {
187
- return false
188
- }
189
- //recovery id check
190
- if sig [64 ] >= 4 {
191
- return false
192
- }
193
-
194
- return true
195
- }
196
-
197
- //for compressed signatures, does not need pubkey
198
- func VerifySignature (msg []byte , sig []byte , pubkey1 []byte ) error {
199
- if msg == nil || sig == nil || pubkey1 == nil {
200
- return errors .New ("inputs must be non-nil" )
201
- }
202
- if len (sig ) != 65 {
203
- return errors .New ("invalid signature length" )
204
- }
205
- if len (pubkey1 ) != 65 {
206
- return errors .New ("Invalid public key length" )
207
- }
208
-
209
- //to enforce malleability, highest bit of S must be 0
210
- //S starts at 32nd byte
211
- if (sig [32 ] & 0x80 ) == 0x80 { //highest bit must be 1
212
- return errors .New ("Signature not malleable" )
213
- }
214
-
215
- if sig [64 ] >= 4 {
216
- return errors .New ("Recover byte invalid" )
217
- }
218
-
219
- // if pubkey recovered, signature valid
220
- pubkey2 , err := RecoverPubkey (msg , sig )
221
- if err != nil {
222
- return err
223
- }
224
- if len (pubkey2 ) != 65 {
225
- return errors .New ("Invalid recovered public key length" )
226
- }
227
- if ! bytes .Equal (pubkey1 , pubkey2 ) {
228
- return errors .New ("Public key does not match recovered public key" )
229
- }
230
-
231
- return nil
232
- }
233
-
234
- // recovers a public key from the signature
191
+ // RecoverPubkey returns the the public key of the signer.
192
+ // msg must be the 32-byte hash of the message to be signed.
193
+ // sig must be a 65-byte compact ECDSA signature containing the
194
+ // recovery id as the last element.
235
195
func RecoverPubkey (msg []byte , sig []byte ) ([]byte , error ) {
236
- if len (sig ) != 65 {
237
- return nil , errors .New ("Invalid signature length" )
196
+ if len (msg ) != 32 {
197
+ return nil , ErrInvalidMsgLen
198
+ }
199
+ if err := checkSignature (sig ); err != nil {
200
+ return nil , err
238
201
}
239
202
240
203
msg_ptr := (* C .uchar )(unsafe .Pointer (& msg [0 ]))
241
204
sig_ptr := (* C .uchar )(unsafe .Pointer (& sig [0 ]))
242
-
243
205
pubkey := make ([]byte , 64 )
244
206
/*
245
207
this slice is used for both the recoverable signature and the
@@ -248,17 +210,15 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
248
210
pubkey recovery is one bottleneck during load in Ethereum
249
211
*/
250
212
bytes65 := make ([]byte , 65 )
251
-
252
213
pubkey_ptr := (* C .secp256k1_pubkey )(unsafe .Pointer (& pubkey [0 ]))
253
214
recoverable_sig_ptr := (* C .secp256k1_ecdsa_recoverable_signature )(unsafe .Pointer (& bytes65 [0 ]))
254
-
255
215
recid := C .int (sig [64 ])
216
+
256
217
ret := C .secp256k1_ecdsa_recoverable_signature_parse_compact (
257
218
context ,
258
219
recoverable_sig_ptr ,
259
220
sig_ptr ,
260
221
recid )
261
-
262
222
if ret == C .int (0 ) {
263
223
return nil , errors .New ("Failed to parse signature" )
264
224
}
@@ -269,20 +229,28 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
269
229
recoverable_sig_ptr ,
270
230
msg_ptr ,
271
231
)
272
-
273
232
if ret == C .int (0 ) {
274
233
return nil , errors .New ("Failed to recover public key" )
275
- } else {
276
- serialized_pubkey_ptr := (* C .uchar )(unsafe .Pointer (& bytes65 [0 ]))
277
-
278
- var output_len C.size_t
279
- C .secp256k1_ec_pubkey_serialize ( // always returns 1
280
- context ,
281
- serialized_pubkey_ptr ,
282
- & output_len ,
283
- pubkey_ptr ,
284
- 0 , // SECP256K1_EC_COMPRESSED
285
- )
286
- return bytes65 , nil
287
234
}
235
+
236
+ serialized_pubkey_ptr := (* C .uchar )(unsafe .Pointer (& bytes65 [0 ]))
237
+ var output_len C.size_t
238
+ C .secp256k1_ec_pubkey_serialize ( // always returns 1
239
+ context ,
240
+ serialized_pubkey_ptr ,
241
+ & output_len ,
242
+ pubkey_ptr ,
243
+ 0 , // SECP256K1_EC_COMPRESSED
244
+ )
245
+ return bytes65 , nil
246
+ }
247
+
248
+ func checkSignature (sig []byte ) error {
249
+ if len (sig ) != 65 {
250
+ return ErrInvalidSignatureLen
251
+ }
252
+ if sig [64 ] >= 4 {
253
+ return ErrInvalidRecoveryID
254
+ }
255
+ return nil
288
256
}
0 commit comments