1 // Copyright (c) 2009-2014 The Bitcoin Core developers
2 // Copyright (c) 2017 The Zcash developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
9 #include <secp256k1_recovery.h>
13 /* Global secp256k1_context object used for verification. */
14 secp256k1_context* secp256k1_context_verify = NULL;
18 bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
21 secp256k1_pubkey pubkey;
22 secp256k1_ecdsa_signature sig;
23 if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
26 if (vchSig.size() == 0) {
29 /* Zcash, unlike Bitcoin, has always enforced strict DER signatures. */
30 if (!secp256k1_ecdsa_signature_parse_der(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
33 /* libsecp256k1's ECDSA verification requires lower-S signatures, which have
34 * not historically been enforced in Bitcoin or Zcash, so normalize them first. */
35 secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig);
36 return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey);
39 bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
40 if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
42 int recid = (vchSig[0] - 27) & 3;
43 bool fComp = ((vchSig[0] - 27) & 4) != 0;
44 secp256k1_pubkey pubkey;
45 secp256k1_ecdsa_recoverable_signature sig;
46 if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) {
49 if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {
52 unsigned char pub[PUBLIC_KEY_SIZE];
53 size_t publen = PUBLIC_KEY_SIZE;
54 secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
55 Set(pub, pub + publen);
59 bool CPubKey::IsFullyValid() const {
62 secp256k1_pubkey pubkey;
63 return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size());
66 bool CPubKey::Decompress() {
69 secp256k1_pubkey pubkey;
70 if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
73 unsigned char pub[PUBLIC_KEY_SIZE];
74 size_t publen = PUBLIC_KEY_SIZE;
75 secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
76 Set(pub, pub + publen);
80 bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
82 assert((nChild >> 31) == 0);
83 assert(size() == COMPRESSED_PUBLIC_KEY_SIZE);
84 unsigned char out[64];
85 BIP32Hash(cc, nChild, *begin(), begin()+1, out);
86 memcpy(ccChild.begin(), out+32, 32);
87 secp256k1_pubkey pubkey;
88 if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
91 if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) {
94 unsigned char pub[COMPRESSED_PUBLIC_KEY_SIZE];
95 size_t publen = COMPRESSED_PUBLIC_KEY_SIZE;
96 secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
97 pubkeyChild.Set(pub, pub + publen);
101 void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
103 memcpy(code+1, vchFingerprint, 4);
104 code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
105 code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
106 memcpy(code+9, chaincode.begin(), 32);
107 assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
108 memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
111 void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {
113 memcpy(vchFingerprint, code+1, 4);
114 nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8];
115 memcpy(chaincode.begin(), code+9, 32);
116 pubkey.Set(code+41, code+BIP32_EXTKEY_SIZE);
119 bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const {
120 out.nDepth = nDepth + 1;
121 CKeyID id = pubkey.GetID();
122 memcpy(&out.vchFingerprint[0], &id, 4);
124 return pubkey.Derive(out.pubkey, out.chaincode, nChild, chaincode);
127 /* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
128 secp256k1_ecdsa_signature sig;
130 /* Zcash, unlike Bitcoin, has always enforced strict DER signatures. */
131 if (!secp256k1_ecdsa_signature_parse_der(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
134 return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, NULL, &sig));
137 /* static */ int ECCVerifyHandle::refcount = 0;
139 ECCVerifyHandle::ECCVerifyHandle()
142 assert(secp256k1_context_verify == NULL);
143 secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
144 assert(secp256k1_context_verify != NULL);
149 ECCVerifyHandle::~ECCVerifyHandle()
153 assert(secp256k1_context_verify != NULL);
154 secp256k1_context_destroy(secp256k1_context_verify);
155 secp256k1_context_verify = NULL;