Merge branch 'beta' into mergemaster
# Conflicts: # src/main.cpp
This commit is contained in:
122
src/pubkey.cpp
122
src/pubkey.cpp
@@ -1,73 +1,101 @@
|
||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||
// Copyright (c) 2017 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "pubkey.h"
|
||||
|
||||
#include "eccryptoverify.h"
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_recovery.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
/* Global secp256k1_context object used for verification. */
|
||||
secp256k1_context* secp256k1_context_verify = NULL;
|
||||
}
|
||||
|
||||
#include "ecwrapper.h"
|
||||
|
||||
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
CECKey key;
|
||||
if (!key.SetPubKey(begin(), size()))
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
|
||||
return false;
|
||||
if (!key.Verify(hash, vchSig))
|
||||
}
|
||||
if (vchSig.size() == 0) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
/* Zcash, unlike Bitcoin, has always enforced strict DER signatures. */
|
||||
if (!secp256k1_ecdsa_signature_parse_der(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
|
||||
return false;
|
||||
}
|
||||
/* libsecp256k1's ECDSA verification requires lower-S signatures, which have
|
||||
* not historically been enforced in Bitcoin or Zcash, so normalize them first. */
|
||||
secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig);
|
||||
return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey);
|
||||
}
|
||||
|
||||
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
|
||||
if (vchSig.size() != 65)
|
||||
if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
|
||||
return false;
|
||||
int recid = (vchSig[0] - 27) & 3;
|
||||
bool fComp = ((vchSig[0] - 27) & 4) != 0;
|
||||
CECKey key;
|
||||
if (!key.Recover(hash, &vchSig[1], recid))
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ecdsa_recoverable_signature sig;
|
||||
if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) {
|
||||
return false;
|
||||
std::vector<unsigned char> pubkey;
|
||||
key.GetPubKey(pubkey, fComp);
|
||||
Set(pubkey.begin(), pubkey.end());
|
||||
}
|
||||
if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {
|
||||
return false;
|
||||
}
|
||||
unsigned char pub[PUBLIC_KEY_SIZE];
|
||||
size_t publen = PUBLIC_KEY_SIZE;
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
|
||||
Set(pub, pub + publen);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPubKey::IsFullyValid() const {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
CECKey key;
|
||||
if (!key.SetPubKey(begin(), size()))
|
||||
return false;
|
||||
return true;
|
||||
secp256k1_pubkey pubkey;
|
||||
return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size());
|
||||
}
|
||||
|
||||
bool CPubKey::Decompress() {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
CECKey key;
|
||||
if (!key.SetPubKey(begin(), size()))
|
||||
secp256k1_pubkey pubkey;
|
||||
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
|
||||
return false;
|
||||
std::vector<unsigned char> pubkey;
|
||||
key.GetPubKey(pubkey, false);
|
||||
Set(pubkey.begin(), pubkey.end());
|
||||
}
|
||||
unsigned char pub[PUBLIC_KEY_SIZE];
|
||||
size_t publen = PUBLIC_KEY_SIZE;
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
|
||||
Set(pub, pub + publen);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
|
||||
assert(IsValid());
|
||||
assert((nChild >> 31) == 0);
|
||||
assert(begin() + 33 == end());
|
||||
assert(size() == COMPRESSED_PUBLIC_KEY_SIZE);
|
||||
unsigned char out[64];
|
||||
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
|
||||
memcpy(ccChild.begin(), out+32, 32);
|
||||
CECKey key;
|
||||
bool ret = key.SetPubKey(begin(), size());
|
||||
ret &= key.TweakPublic(out);
|
||||
std::vector<unsigned char> pubkey;
|
||||
key.GetPubKey(pubkey, true);
|
||||
pubkeyChild.Set(pubkey.begin(), pubkey.end());
|
||||
return ret;
|
||||
secp256k1_pubkey pubkey;
|
||||
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
|
||||
return false;
|
||||
}
|
||||
if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) {
|
||||
return false;
|
||||
}
|
||||
unsigned char pub[COMPRESSED_PUBLIC_KEY_SIZE];
|
||||
size_t publen = COMPRESSED_PUBLIC_KEY_SIZE;
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
|
||||
pubkeyChild.Set(pub, pub + publen);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CExtPubKey::Encode(unsigned char code[74]) const {
|
||||
@@ -76,8 +104,8 @@ void CExtPubKey::Encode(unsigned char code[74]) const {
|
||||
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
|
||||
code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
|
||||
memcpy(code+9, chaincode.begin(), 32);
|
||||
assert(pubkey.size() == 33);
|
||||
memcpy(code+41, pubkey.begin(), 33);
|
||||
assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
|
||||
memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
|
||||
}
|
||||
|
||||
void CExtPubKey::Decode(const unsigned char code[74]) {
|
||||
@@ -95,3 +123,35 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const {
|
||||
out.nChild = nChild;
|
||||
return pubkey.Derive(out.pubkey, out.chaincode, nChild, chaincode);
|
||||
}
|
||||
|
||||
/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
|
||||
secp256k1_ecdsa_signature sig;
|
||||
|
||||
/* Zcash, unlike Bitcoin, has always enforced strict DER signatures. */
|
||||
if (!secp256k1_ecdsa_signature_parse_der(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
|
||||
return false;
|
||||
}
|
||||
return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, NULL, &sig));
|
||||
}
|
||||
|
||||
/* static */ int ECCVerifyHandle::refcount = 0;
|
||||
|
||||
ECCVerifyHandle::ECCVerifyHandle()
|
||||
{
|
||||
if (refcount == 0) {
|
||||
assert(secp256k1_context_verify == NULL);
|
||||
secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
assert(secp256k1_context_verify != NULL);
|
||||
}
|
||||
refcount++;
|
||||
}
|
||||
|
||||
ECCVerifyHandle::~ECCVerifyHandle()
|
||||
{
|
||||
refcount--;
|
||||
if (refcount == 0) {
|
||||
assert(secp256k1_context_verify != NULL);
|
||||
secp256k1_context_destroy(secp256k1_context_verify);
|
||||
secp256k1_context_verify = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user