Changeset View
Changeset View
Standalone View
Standalone View
src/key.cpp
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Copyright (c) 2017 The Zcash developers | |||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <key.h> | #include <key.h> | ||||
#include <arith_uint256.h> | #include <arith_uint256.h> | ||||
#include <crypto/common.h> | #include <crypto/common.h> | ||||
#include <crypto/hmac_sha512.h> | #include <crypto/hmac_sha512.h> | ||||
#include <pubkey.h> | #include <pubkey.h> | ||||
#include <random.h> | #include <random.h> | ||||
#include <secp256k1.h> | #include <secp256k1.h> | ||||
#include <secp256k1_recovery.h> | #include <secp256k1_recovery.h> | ||||
#include <secp256k1_schnorr.h> | #include <secp256k1_schnorr.h> | ||||
static secp256k1_context *secp256k1_context_sign = nullptr; | static secp256k1_context *secp256k1_context_sign = nullptr; | ||||
/** | /** | ||||
* These functions are taken from the libsecp256k1 distribution and are very | * These functions are taken from the libsecp256k1 distribution and are very | ||||
* ugly. | * ugly. | ||||
*/ | */ | ||||
/** | |||||
* This parses a format loosely based on a DER encoding of the ECPrivateKey type | |||||
* from section C.4 of SEC 1 <http://www.secg.org/sec1-v2.pdf>, with the | |||||
* following caveats: | |||||
* | |||||
* * The octet-length of the SEQUENCE must be encoded as 1 or 2 octets. It is | |||||
* not required to be encoded as one octet if it is less than 256, as DER would | |||||
* require. | |||||
* * The octet-length of the SEQUENCE must not be greater than the remaining | |||||
* length of the key encoding, but need not match it (i.e. the encoding may | |||||
* contain junk after the encoded SEQUENCE). | |||||
* * The privateKey OCTET STRING is zero-filled on the left to 32 octets. | |||||
* * Anything after the encoding of the privateKey OCTET STRING is ignored, | |||||
* whether or not it is validly encoded DER. | |||||
* | |||||
* out32 must point to an output buffer of length at least 32 bytes. | |||||
*/ | |||||
static int ec_privkey_import_der(const secp256k1_context *ctx, uint8_t *out32, | static int ec_privkey_import_der(const secp256k1_context *ctx, uint8_t *out32, | ||||
const uint8_t *privkey, size_t privkeylen) { | const uint8_t *privkey, size_t privkeylen) { | ||||
const uint8_t *end = privkey + privkeylen; | const uint8_t *end = privkey + privkeylen; | ||||
int lenb = 0; | |||||
int len = 0; | |||||
memset(out32, 0, 32); | memset(out32, 0, 32); | ||||
/* sequence header */ | /* sequence header */ | ||||
if (end < privkey + 1 || *privkey != 0x30) { | if (end - privkey < 1 || *privkey != 0x30u) { | ||||
return 0; | return 0; | ||||
} | } | ||||
privkey++; | privkey++; | ||||
/* sequence length constructor */ | /* sequence length constructor */ | ||||
if (end < privkey + 1 || !(*privkey & 0x80)) { | if (end - privkey < 1 || !(*privkey & 0x80u)) { | ||||
return 0; | return 0; | ||||
} | } | ||||
lenb = *privkey & ~0x80; | ptrdiff_t lenb = *privkey & ~0x80u; | ||||
privkey++; | privkey++; | ||||
if (lenb < 1 || lenb > 2) { | if (lenb < 1 || lenb > 2) { | ||||
return 0; | return 0; | ||||
} | } | ||||
if (end < privkey + lenb) { | if (end - privkey < lenb) { | ||||
return 0; | return 0; | ||||
} | } | ||||
/* sequence length */ | /* sequence length */ | ||||
len = privkey[lenb - 1] | (lenb > 1 ? privkey[lenb - 2] << 8 : 0); | ptrdiff_t len = | ||||
privkey[lenb - 1] | (lenb > 1 ? privkey[lenb - 2] << 8 : 0u); | |||||
privkey += lenb; | privkey += lenb; | ||||
if (end < privkey + len) { | if (end - privkey < len) { | ||||
return 0; | return 0; | ||||
} | } | ||||
/* sequence element 0: version number (=1) */ | /* sequence element 0: version number (=1) */ | ||||
if (end < privkey + 3 || privkey[0] != 0x02 || privkey[1] != 0x01 || | if (end - privkey < 3 || privkey[0] != 0x02u || privkey[1] != 0x01u || | ||||
privkey[2] != 0x01) { | privkey[2] != 0x01u) { | ||||
return 0; | return 0; | ||||
} | } | ||||
privkey += 3; | privkey += 3; | ||||
/* sequence element 1: octet string, up to 32 bytes */ | /* sequence element 1: octet string, up to 32 bytes */ | ||||
if (end < privkey + 2 || privkey[0] != 0x04 || privkey[1] > 0x20 || | if (end - privkey < 2 || privkey[0] != 0x04u) { | ||||
end < privkey + 2 + privkey[1]) { | |||||
return 0; | return 0; | ||||
} | } | ||||
memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); | ptrdiff_t oslen = privkey[1]; | ||||
privkey += 2; | |||||
if (oslen > 32 || end - privkey < oslen) { | |||||
return 0; | |||||
} | |||||
memcpy(out32 + (32 - oslen), privkey, oslen); | |||||
if (!secp256k1_ec_seckey_verify(ctx, out32)) { | if (!secp256k1_ec_seckey_verify(ctx, out32)) { | ||||
memset(out32, 0, 32); | memset(out32, 0, 32); | ||||
return 0; | return 0; | ||||
} | } | ||||
return 1; | return 1; | ||||
} | } | ||||
/** | |||||
* This serializes to a DER encoding of the ECPrivateKey type from section C.4 | |||||
* of SEC 1 <http://www.secg.org/sec1-v2.pdf>. The optional parameters and | |||||
* publicKey fields are included. | |||||
* | |||||
* privkey must point to an output buffer of length at least | |||||
* CKey::PRIVATE_KEY_SIZE bytes. privkeylen must initially be set to the size of | |||||
* the privkey buffer. Upon return it will be set to the number of bytes used in | |||||
* the buffer. key32 must point to a 32-byte raw private key. | |||||
*/ | |||||
static int ec_privkey_export_der(const secp256k1_context *ctx, uint8_t *privkey, | static int ec_privkey_export_der(const secp256k1_context *ctx, uint8_t *privkey, | ||||
size_t *privkeylen, const uint8_t *key32, | size_t *privkeylen, const uint8_t *key32, | ||||
int compressed) { | int compressed) { | ||||
assert(*privkeylen >= CKey::PRIVATE_KEY_SIZE); | |||||
secp256k1_pubkey pubkey; | secp256k1_pubkey pubkey; | ||||
size_t pubkeylen = 0; | size_t pubkeylen = 0; | ||||
if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { | if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { | ||||
*privkeylen = 0; | *privkeylen = 0; | ||||
return 0; | return 0; | ||||
} | } | ||||
if (compressed) { | if (compressed) { | ||||
Show All 15 Lines | if (compressed) { | ||||
0x41, 0x02, 0x01, 0x01, 0xA1, 0x24, 0x03, 0x22, 0x00}; | 0x41, 0x02, 0x01, 0x01, 0xA1, 0x24, 0x03, 0x22, 0x00}; | ||||
uint8_t *ptr = privkey; | uint8_t *ptr = privkey; | ||||
memcpy(ptr, begin, sizeof(begin)); | memcpy(ptr, begin, sizeof(begin)); | ||||
ptr += sizeof(begin); | ptr += sizeof(begin); | ||||
memcpy(ptr, key32, 32); | memcpy(ptr, key32, 32); | ||||
ptr += 32; | ptr += 32; | ||||
memcpy(ptr, middle, sizeof(middle)); | memcpy(ptr, middle, sizeof(middle)); | ||||
ptr += sizeof(middle); | ptr += sizeof(middle); | ||||
pubkeylen = 33; | pubkeylen = CPubKey::COMPRESSED_PUBLIC_KEY_SIZE; | ||||
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, | secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, | ||||
SECP256K1_EC_COMPRESSED); | SECP256K1_EC_COMPRESSED); | ||||
ptr += pubkeylen; | ptr += pubkeylen; | ||||
*privkeylen = ptr - privkey; | *privkeylen = ptr - privkey; | ||||
assert(*privkeylen == CKey::COMPRESSED_PRIVATE_KEY_SIZE); | |||||
} else { | } else { | ||||
static const uint8_t begin[] = {0x30, 0x82, 0x01, 0x13, 0x02, | static const uint8_t begin[] = {0x30, 0x82, 0x01, 0x13, 0x02, | ||||
0x01, 0x01, 0x04, 0x20}; | 0x01, 0x01, 0x04, 0x20}; | ||||
static const uint8_t middle[] = { | static const uint8_t middle[] = { | ||||
0xA0, 0x81, 0xA5, 0x30, 0x81, 0xA2, 0x02, 0x01, 0x01, 0x30, 0x2C, | 0xA0, 0x81, 0xA5, 0x30, 0x81, 0xA2, 0x02, 0x01, 0x01, 0x30, 0x2C, | ||||
0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, | 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, | ||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||||
Show All 11 Lines | if (compressed) { | ||||
0x02, 0x01, 0x01, 0xA1, 0x44, 0x03, 0x42, 0x00}; | 0x02, 0x01, 0x01, 0xA1, 0x44, 0x03, 0x42, 0x00}; | ||||
uint8_t *ptr = privkey; | uint8_t *ptr = privkey; | ||||
memcpy(ptr, begin, sizeof(begin)); | memcpy(ptr, begin, sizeof(begin)); | ||||
ptr += sizeof(begin); | ptr += sizeof(begin); | ||||
memcpy(ptr, key32, 32); | memcpy(ptr, key32, 32); | ||||
ptr += 32; | ptr += 32; | ||||
memcpy(ptr, middle, sizeof(middle)); | memcpy(ptr, middle, sizeof(middle)); | ||||
ptr += sizeof(middle); | ptr += sizeof(middle); | ||||
pubkeylen = 65; | pubkeylen = CPubKey::PUBLIC_KEY_SIZE; | ||||
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, | secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, | ||||
SECP256K1_EC_UNCOMPRESSED); | SECP256K1_EC_UNCOMPRESSED); | ||||
ptr += pubkeylen; | ptr += pubkeylen; | ||||
*privkeylen = ptr - privkey; | *privkeylen = ptr - privkey; | ||||
assert(*privkeylen == CKey::PRIVATE_KEY_SIZE); | |||||
} | } | ||||
return 1; | return 1; | ||||
} | } | ||||
bool CKey::Check(const uint8_t *vch) { | bool CKey::Check(const uint8_t *vch) { | ||||
return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch); | return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch); | ||||
} | } | ||||
void CKey::MakeNewKey(bool fCompressedIn) { | void CKey::MakeNewKey(bool fCompressedIn) { | ||||
do { | do { | ||||
GetStrongRandBytes(keydata.data(), keydata.size()); | GetStrongRandBytes(keydata.data(), keydata.size()); | ||||
} while (!Check(keydata.data())); | } while (!Check(keydata.data())); | ||||
fValid = true; | fValid = true; | ||||
fCompressed = fCompressedIn; | fCompressed = fCompressedIn; | ||||
} | } | ||||
CPrivKey CKey::GetPrivKey() const { | CPrivKey CKey::GetPrivKey() const { | ||||
assert(fValid); | assert(fValid); | ||||
CPrivKey privkey; | CPrivKey privkey; | ||||
int ret; | int ret; | ||||
size_t privkeylen; | size_t privkeylen; | ||||
privkey.resize(279); | privkey.resize(PRIVATE_KEY_SIZE); | ||||
privkeylen = 279; | privkeylen = PRIVATE_KEY_SIZE; | ||||
ret = ec_privkey_export_der( | ret = ec_privkey_export_der( | ||||
secp256k1_context_sign, (uint8_t *)privkey.data(), &privkeylen, begin(), | secp256k1_context_sign, (uint8_t *)privkey.data(), &privkeylen, begin(), | ||||
fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); | fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); | ||||
assert(ret); | assert(ret); | ||||
privkey.resize(privkeylen); | privkey.resize(privkeylen); | ||||
return privkey; | return privkey; | ||||
} | } | ||||
CPubKey CKey::GetPubKey() const { | CPubKey CKey::GetPubKey() const { | ||||
assert(fValid); | assert(fValid); | ||||
secp256k1_pubkey pubkey; | secp256k1_pubkey pubkey; | ||||
size_t clen = 65; | size_t clen = CPubKey::PUBLIC_KEY_SIZE; | ||||
CPubKey result; | CPubKey result; | ||||
int ret = | int ret = | ||||
secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin()); | secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin()); | ||||
assert(ret); | assert(ret); | ||||
secp256k1_ec_pubkey_serialize( | secp256k1_ec_pubkey_serialize( | ||||
secp256k1_context_sign, (uint8_t *)result.begin(), &clen, &pubkey, | secp256k1_context_sign, (uint8_t *)result.begin(), &clen, &pubkey, | ||||
fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); | fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); | ||||
assert(result.size() == clen); | assert(result.size() == clen); | ||||
assert(result.IsValid()); | assert(result.IsValid()); | ||||
return result; | return result; | ||||
} | } | ||||
bool CKey::SignECDSA(const uint256 &hash, std::vector<uint8_t> &vchSig, | bool CKey::SignECDSA(const uint256 &hash, std::vector<uint8_t> &vchSig, | ||||
uint32_t test_case) const { | uint32_t test_case) const { | ||||
if (!fValid) { | if (!fValid) { | ||||
return false; | return false; | ||||
} | } | ||||
vchSig.resize(72); | vchSig.resize(CPubKey::SIGNATURE_SIZE); | ||||
size_t nSigLen = 72; | size_t nSigLen = CPubKey::SIGNATURE_SIZE; | ||||
uint8_t extra_entropy[32] = {0}; | uint8_t extra_entropy[32] = {0}; | ||||
WriteLE32(extra_entropy, test_case); | WriteLE32(extra_entropy, test_case); | ||||
secp256k1_ecdsa_signature sig; | secp256k1_ecdsa_signature sig; | ||||
int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), | int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), | ||||
begin(), secp256k1_nonce_function_rfc6979, | begin(), secp256k1_nonce_function_rfc6979, | ||||
test_case ? extra_entropy : nullptr); | test_case ? extra_entropy : nullptr); | ||||
assert(ret); | assert(ret); | ||||
secp256k1_ecdsa_signature_serialize_der( | secp256k1_ecdsa_signature_serialize_der( | ||||
Show All 35 Lines | bool CKey::VerifyPubKey(const CPubKey &pubkey) const { | ||||
return pubkey.VerifyECDSA(hash, vchSig); | return pubkey.VerifyECDSA(hash, vchSig); | ||||
} | } | ||||
bool CKey::SignCompact(const uint256 &hash, | bool CKey::SignCompact(const uint256 &hash, | ||||
std::vector<uint8_t> &vchSig) const { | std::vector<uint8_t> &vchSig) const { | ||||
if (!fValid) { | if (!fValid) { | ||||
return false; | return false; | ||||
} | } | ||||
vchSig.resize(65); | vchSig.resize(CPubKey::COMPACT_SIGNATURE_SIZE); | ||||
int rec = -1; | int rec = -1; | ||||
secp256k1_ecdsa_recoverable_signature sig; | secp256k1_ecdsa_recoverable_signature sig; | ||||
int ret = secp256k1_ecdsa_sign_recoverable( | int ret = secp256k1_ecdsa_sign_recoverable( | ||||
secp256k1_context_sign, &sig, hash.begin(), begin(), | secp256k1_context_sign, &sig, hash.begin(), begin(), | ||||
secp256k1_nonce_function_rfc6979, nullptr); | secp256k1_nonce_function_rfc6979, nullptr); | ||||
assert(ret); | assert(ret); | ||||
secp256k1_ecdsa_recoverable_signature_serialize_compact( | secp256k1_ecdsa_recoverable_signature_serialize_compact( | ||||
secp256k1_context_sign, (uint8_t *)&vchSig[1], &rec, &sig); | secp256k1_context_sign, (uint8_t *)&vchSig[1], &rec, &sig); | ||||
Show All 20 Lines | |||||
bool CKey::Derive(CKey &keyChild, ChainCode &ccChild, unsigned int nChild, | bool CKey::Derive(CKey &keyChild, ChainCode &ccChild, unsigned int nChild, | ||||
const ChainCode &cc) const { | const ChainCode &cc) const { | ||||
assert(IsValid()); | assert(IsValid()); | ||||
assert(IsCompressed()); | assert(IsCompressed()); | ||||
std::vector<uint8_t, secure_allocator<uint8_t>> vout(64); | std::vector<uint8_t, secure_allocator<uint8_t>> vout(64); | ||||
if ((nChild >> 31) == 0) { | if ((nChild >> 31) == 0) { | ||||
CPubKey pubkey = GetPubKey(); | CPubKey pubkey = GetPubKey(); | ||||
assert(pubkey.begin() + 33 == pubkey.end()); | assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); | ||||
BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin() + 1, vout.data()); | BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin() + 1, vout.data()); | ||||
} else { | } else { | ||||
assert(begin() + 32 == end()); | assert(size() == 32); | ||||
BIP32Hash(cc, nChild, 0, begin(), vout.data()); | BIP32Hash(cc, nChild, 0, begin(), vout.data()); | ||||
} | } | ||||
memcpy(ccChild.begin(), vout.data() + 32, 32); | memcpy(ccChild.begin(), vout.data() + 32, 32); | ||||
memcpy((uint8_t *)keyChild.begin(), begin(), 32); | memcpy((uint8_t *)keyChild.begin(), begin(), 32); | ||||
bool ret = secp256k1_ec_privkey_tweak_add( | bool ret = secp256k1_ec_privkey_tweak_add( | ||||
secp256k1_context_sign, (uint8_t *)keyChild.begin(), vout.data()); | secp256k1_context_sign, (uint8_t *)keyChild.begin(), vout.data()); | ||||
keyChild.fCompressed = true; | keyChild.fCompressed = true; | ||||
keyChild.fValid = ret; | keyChild.fValid = ret; | ||||
▲ Show 20 Lines • Show All 88 Lines • Show Last 20 Lines |