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 | ||||
// 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> | |||||
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. */ | ||||
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; | ||||
▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | secp256k1_ec_pubkey_serialize( | ||||
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) return false; | if (!fValid) { | ||||
return false; | |||||
} | |||||
vchSig.resize(72); | vchSig.resize(72); | ||||
size_t nSigLen = 72; | size_t nSigLen = 72; | ||||
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( | ||||
secp256k1_context_sign, (uint8_t *)&vchSig[0], &nSigLen, &sig); | secp256k1_context_sign, (uint8_t *)&vchSig[0], &nSigLen, &sig); | ||||
vchSig.resize(nSigLen); | vchSig.resize(nSigLen); | ||||
return true; | return true; | ||||
} | } | ||||
bool CKey::SignSchnorr(const uint256 &hash, std::vector<uint8_t> &vchSig, | |||||
uint32_t test_case) const { | |||||
if (!fValid) { | |||||
return false; | |||||
} | |||||
vchSig.resize(64); | |||||
uint8_t extra_entropy[32] = {0}; | |||||
WriteLE32(extra_entropy, test_case); | |||||
secp256k1_pubkey pubkey; | |||||
int retp = | |||||
secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin()); | |||||
assert(retp); | |||||
int ret = secp256k1_schnorr_sign( | |||||
secp256k1_context_sign, &vchSig[0], hash.begin(), begin(), &pubkey, | |||||
secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : nullptr); | |||||
assert(ret); | |||||
return true; | |||||
} | |||||
bool CKey::VerifyPubKey(const CPubKey &pubkey) const { | bool CKey::VerifyPubKey(const CPubKey &pubkey) const { | ||||
if (pubkey.IsCompressed() != fCompressed) { | if (pubkey.IsCompressed() != fCompressed) { | ||||
return false; | return false; | ||||
} | } | ||||
uint8_t rnd[8]; | uint8_t rnd[8]; | ||||
std::string str = "Bitcoin key verification\n"; | std::string str = "Bitcoin key verification\n"; | ||||
GetRandBytes(rnd, sizeof(rnd)); | GetRandBytes(rnd, sizeof(rnd)); | ||||
uint256 hash; | uint256 hash; | ||||
CHash256() | CHash256() | ||||
.Write((uint8_t *)str.data(), str.size()) | .Write((uint8_t *)str.data(), str.size()) | ||||
.Write(rnd, sizeof(rnd)) | .Write(rnd, sizeof(rnd)) | ||||
.Finalize(hash.begin()); | .Finalize(hash.begin()); | ||||
std::vector<uint8_t> vchSig; | std::vector<uint8_t> vchSig; | ||||
SignECDSA(hash, vchSig); | SignECDSA(hash, vchSig); | ||||
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) return false; | if (!fValid) { | ||||
return false; | |||||
} | |||||
vchSig.resize(65); | vchSig.resize(65); | ||||
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); | ||||
assert(ret); | assert(ret); | ||||
assert(rec != -1); | assert(rec != -1); | ||||
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); | vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); | ||||
return true; | return true; | ||||
} | } | ||||
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, | bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, | ||||
bool fSkipCheck = false) { | bool fSkipCheck = false) { | ||||
if (!ec_privkey_import_der(secp256k1_context_sign, (uint8_t *)begin(), | if (!ec_privkey_import_der(secp256k1_context_sign, (uint8_t *)begin(), | ||||
&privkey[0], privkey.size())) | &privkey[0], privkey.size())) | ||||
return false; | return false; | ||||
fCompressed = vchPubKey.IsCompressed(); | fCompressed = vchPubKey.IsCompressed(); | ||||
fValid = true; | fValid = true; | ||||
if (fSkipCheck) return true; | if (fSkipCheck) { | ||||
return true; | |||||
} | |||||
return VerifyPubKey(vchPubKey); | return VerifyPubKey(vchPubKey); | ||||
} | } | ||||
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()); | ||||
▲ Show 20 Lines • Show All 103 Lines • Show Last 20 Lines |