diff options
Diffstat (limited to 'crypto/secp256k1')
-rw-r--r-- | crypto/secp256k1/ext.h | 49 | ||||
-rw-r--r-- | crypto/secp256k1/secp256.go | 29 |
2 files changed, 78 insertions, 0 deletions
diff --git a/crypto/secp256k1/ext.h b/crypto/secp256k1/ext.h index ee759fde6..b0f30b73c 100644 --- a/crypto/secp256k1/ext.h +++ b/crypto/secp256k1/ext.h @@ -46,6 +46,55 @@ static int secp256k1_ecdsa_recover_pubkey( return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED); } +// secp256k1_ecdsa_verify_enc verifies an encoded compact signature. +// +// Returns: 1: signature is valid +// 0: signature is invalid +// Args: ctx: pointer to a context object (cannot be NULL) +// In: sigdata: pointer to a 64-byte signature (cannot be NULL) +// msgdata: pointer to a 32-byte message (cannot be NULL) +// pubkeydata: pointer to public key data (cannot be NULL) +// pubkeylen: length of pubkeydata +static int secp256k1_ecdsa_verify_enc( + const secp256k1_context* ctx, + const unsigned char *sigdata, + const unsigned char *msgdata, + const unsigned char *pubkeydata, + size_t pubkeylen +) { + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pubkey; + + if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigdata)) { + return 0; + } + if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, pubkeylen)) { + return 0; + } + return secp256k1_ecdsa_verify(ctx, &sig, msgdata, &pubkey); +} + +// secp256k1_decompress_pubkey decompresses a public key. +// +// Returns: 1: public key is valid +// 0: public key is invalid +// Args: ctx: pointer to a context object (cannot be NULL) +// Out: pubkey_out: the serialized 65-byte public key (cannot be NULL) +// In: pubkeydata: pointer to 33 bytes of compressed public key data (cannot be NULL) +static int secp256k1_decompress_pubkey( + const secp256k1_context* ctx, + unsigned char *pubkey_out, + const unsigned char *pubkeydata +) { + secp256k1_pubkey pubkey; + + if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, 33)) { + return 0; + } + size_t outputlen = 65; + return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED); +} + // secp256k1_pubkey_scalar_mul multiplies a point by a scalar in constant time. // // Returns: 1: multiplication was successful diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index 0ffa04fe0..00a1f8aaa 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -38,6 +38,7 @@ import "C" import ( "errors" + "math/big" "unsafe" ) @@ -55,6 +56,7 @@ var ( ErrInvalidSignatureLen = errors.New("invalid signature length") ErrInvalidRecoveryID = errors.New("invalid signature recovery id") ErrInvalidKey = errors.New("invalid private key") + ErrInvalidPubkey = errors.New("invalid public key") ErrSignFailed = errors.New("signing failed") ErrRecoverFailed = errors.New("recovery failed") ) @@ -119,6 +121,33 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { return pubkey, nil } +// VerifySignature checks that the given pubkey created signature over message. +// The signature should be in [R || S] format. +func VerifySignature(pubkey, msg, signature []byte) bool { + if len(msg) != 32 || len(signature) != 64 || len(pubkey) == 0 { + return false + } + sigdata := (*C.uchar)(unsafe.Pointer(&signature[0])) + msgdata := (*C.uchar)(unsafe.Pointer(&msg[0])) + keydata := (*C.uchar)(unsafe.Pointer(&pubkey[0])) + return C.secp256k1_ecdsa_verify_enc(context, sigdata, msgdata, keydata, C.size_t(len(pubkey))) != 0 +} + +// DecompressPubkey parses a public key in the 33-byte compressed format. +// It returns non-nil coordinates if the public key is valid. +func DecompressPubkey(pubkey []byte) (X, Y *big.Int) { + if len(pubkey) != 33 { + return nil, nil + } + buf := make([]byte, 65) + bufdata := (*C.uchar)(unsafe.Pointer(&buf[0])) + pubkeydata := (*C.uchar)(unsafe.Pointer(&pubkey[0])) + if C.secp256k1_decompress_pubkey(context, bufdata, pubkeydata) == 0 { + return nil, nil + } + return new(big.Int).SetBytes(buf[1:33]), new(big.Int).SetBytes(buf[33:]) +} + func checkSignature(sig []byte) error { if len(sig) != 65 { return ErrInvalidSignatureLen |