@ -39,7 +39,6 @@ package secp256k1
import "C"
import (
"bytes"
"errors"
"unsafe"
@ -64,6 +63,12 @@ func init() {
context = C . secp256k1_context_create ( 3 ) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY
}
var (
ErrInvalidMsgLen = errors . New ( "invalid message length for signature recovery" )
ErrInvalidSignatureLen = errors . New ( "invalid signature length" )
ErrInvalidRecoveryID = errors . New ( "invalid signature recovery id" )
)
func GenerateKeyPair ( ) ( [ ] byte , [ ] byte ) {
var seckey [ ] byte = randentropy . GetEntropyCSPRNG ( 32 )
var seckey_ptr * C . uchar = ( * C . uchar ) ( unsafe . Pointer ( & seckey [ 0 ] ) )
@ -177,69 +182,20 @@ func VerifySeckeyValidity(seckey []byte) error {
return nil
}
func VerifySignatureValidity ( sig [ ] byte ) bool {
//64+1
if len ( sig ) != 65 {
return false
}
//malleability check, highest bit must be 1
if ( sig [ 32 ] & 0x80 ) == 0x80 {
return false
}
//recovery id check
if sig [ 64 ] >= 4 {
return false
}
return true
}
//for compressed signatures, does not need pubkey
func VerifySignature ( msg [ ] byte , sig [ ] byte , pubkey1 [ ] byte ) error {
if msg == nil || sig == nil || pubkey1 == nil {
return errors . New ( "inputs must be non-nil" )
}
if len ( sig ) != 65 {
return errors . New ( "invalid signature length" )
}
if len ( pubkey1 ) != 65 {
return errors . New ( "Invalid public key length" )
}
//to enforce malleability, highest bit of S must be 0
//S starts at 32nd byte
if ( sig [ 32 ] & 0x80 ) == 0x80 { //highest bit must be 1
return errors . New ( "Signature not malleable" )
}
if sig [ 64 ] >= 4 {
return errors . New ( "Recover byte invalid" )
}
// if pubkey recovered, signature valid
pubkey2 , err := RecoverPubkey ( msg , sig )
if err != nil {
return err
}
if len ( pubkey2 ) != 65 {
return errors . New ( "Invalid recovered public key length" )
}
if ! bytes . Equal ( pubkey1 , pubkey2 ) {
return errors . New ( "Public key does not match recovered public key" )
}
return nil
}
// recovers a public key from the signature
// RecoverPubkey returns the the public key of the signer.
// msg must be the 32-byte hash of the message to be signed.
// sig must be a 65-byte compact ECDSA signature containing the
// recovery id as the last element.
func RecoverPubkey ( msg [ ] byte , sig [ ] byte ) ( [ ] byte , error ) {
if len ( sig ) != 65 {
return nil , errors . New ( "Invalid signature length" )
if len ( msg ) != 32 {
return nil , ErrInvalidMsgLen
}
if err := checkSignature ( sig ) ; err != nil {
return nil , err
}
msg_ptr := ( * C . uchar ) ( unsafe . Pointer ( & msg [ 0 ] ) )
sig_ptr := ( * C . uchar ) ( unsafe . Pointer ( & sig [ 0 ] ) )
pubkey := make ( [ ] byte , 64 )
/ *
this slice is used for both the recoverable signature and the
@ -248,17 +204,15 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
pubkey recovery is one bottleneck during load in Ethereum
* /
bytes65 := make ( [ ] byte , 65 )
pubkey_ptr := ( * C . secp256k1_pubkey ) ( unsafe . Pointer ( & pubkey [ 0 ] ) )
recoverable_sig_ptr := ( * C . secp256k1_ecdsa_recoverable_signature ) ( unsafe . Pointer ( & bytes65 [ 0 ] ) )
recid := C . int ( sig [ 64 ] )
ret := C . secp256k1_ecdsa_recoverable_signature_parse_compact (
context ,
recoverable_sig_ptr ,
sig_ptr ,
recid )
if ret == C . int ( 0 ) {
return nil , errors . New ( "Failed to parse signature" )
}
@ -269,20 +223,28 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
recoverable_sig_ptr ,
msg_ptr ,
)
if ret == C . int ( 0 ) {
return nil , errors . New ( "Failed to recover public key" )
} else {
serialized_pubkey_ptr := ( * C . uchar ) ( unsafe . Pointer ( & bytes65 [ 0 ] ) )
var output_len C . size_t
C . secp256k1_ec_pubkey_serialize ( // always returns 1
context ,
serialized_pubkey_ptr ,
& output_len ,
pubkey_ptr ,
0 , // SECP256K1_EC_COMPRESSED
)
return bytes65 , nil
}
serialized_pubkey_ptr := ( * C . uchar ) ( unsafe . Pointer ( & bytes65 [ 0 ] ) )
var output_len C . size_t
C . secp256k1_ec_pubkey_serialize ( // always returns 1
context ,
serialized_pubkey_ptr ,
& output_len ,
pubkey_ptr ,
0 , // SECP256K1_EC_COMPRESSED
)
return bytes65 , nil
}
func checkSignature ( sig [ ] byte ) error {
if len ( sig ) != 65 {
return ErrInvalidSignatureLen
}
if sig [ 64 ] >= 4 {
return ErrInvalidRecoveryID
}
return nil
}