diff options
Diffstat (limited to 'crypto/secp256k1/secp256.go')
-rw-r--r-- | crypto/secp256k1/secp256.go | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index 0ffa04fe0..eefbb99ee 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") ) @@ -113,12 +115,59 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { sigdata = (*C.uchar)(unsafe.Pointer(&sig[0])) msgdata = (*C.uchar)(unsafe.Pointer(&msg[0])) ) - if C.secp256k1_ecdsa_recover_pubkey(context, (*C.uchar)(unsafe.Pointer(&pubkey[0])), sigdata, msgdata) == 0 { + if C.secp256k1_ext_ecdsa_recover(context, (*C.uchar)(unsafe.Pointer(&pubkey[0])), sigdata, msgdata) == 0 { return nil, ErrRecoverFailed } 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_ext_ecdsa_verify(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 + } + var ( + pubkeydata = (*C.uchar)(unsafe.Pointer(&pubkey[0])) + pubkeylen = C.size_t(len(pubkey)) + out = make([]byte, 65) + outdata = (*C.uchar)(unsafe.Pointer(&out[0])) + outlen = C.size_t(len(out)) + ) + if C.secp256k1_ext_reencode_pubkey(context, outdata, outlen, pubkeydata, pubkeylen) == 0 { + return nil, nil + } + return new(big.Int).SetBytes(out[1:33]), new(big.Int).SetBytes(out[33:]) +} + +// CompressPubkey encodes a public key to 33-byte compressed format. +func CompressPubkey(x, y *big.Int) []byte { + var ( + pubkey = S256().Marshal(x, y) + pubkeydata = (*C.uchar)(unsafe.Pointer(&pubkey[0])) + pubkeylen = C.size_t(len(pubkey)) + out = make([]byte, 33) + outdata = (*C.uchar)(unsafe.Pointer(&out[0])) + outlen = C.size_t(len(out)) + ) + if C.secp256k1_ext_reencode_pubkey(context, outdata, outlen, pubkeydata, pubkeylen) == 0 { + panic("libsecp256k1 error") + } + return out +} + func checkSignature(sig []byte) error { if len(sig) != 65 { return ErrInvalidSignatureLen |