Add sanity check after key generation
Add a sanity check to prevent cosmic rays from flipping a bit in the generated public key, or bugs in the elliptic curve code. This is simply done by signing a (randomized) message, and verifying the result.
This commit is contained in:
parent
cbf28c6619
commit
d0c41a7350
5 changed files with 44 additions and 4 deletions
19
src/key.cpp
19
src/key.cpp
|
@ -86,6 +86,20 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
|
||||
if (pubkey.IsCompressed() != fCompressed) {
|
||||
return false;
|
||||
}
|
||||
unsigned char rnd[8];
|
||||
std::string str = "Bitcoin key verification\n";
|
||||
GetRandBytes(rnd, sizeof(rnd));
|
||||
uint256 hash;
|
||||
CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize((unsigned char*)&hash);
|
||||
std::vector<unsigned char> vchSig;
|
||||
Sign(hash, vchSig);
|
||||
return pubkey.Verify(hash, vchSig);
|
||||
}
|
||||
|
||||
bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
|
||||
if (!fValid)
|
||||
return false;
|
||||
|
@ -111,10 +125,7 @@ bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
|
|||
if (fSkipCheck)
|
||||
return true;
|
||||
|
||||
if (GetPubKey() != vchPubKey)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return VerifyPubKey(vchPubKey);
|
||||
}
|
||||
|
||||
bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const {
|
||||
|
|
|
@ -136,6 +136,12 @@ public:
|
|||
//! Derive BIP32 child key.
|
||||
bool Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const;
|
||||
|
||||
/**
|
||||
* Verify thoroughly whether a private key and a public key match.
|
||||
* This is done using a different mechanism than just regenerating it.
|
||||
*/
|
||||
bool VerifyPubKey(const CPubKey& vchPubKey) const;
|
||||
|
||||
//! Load private key and check that public key matches.
|
||||
bool Load(CPrivKey& privkey, CPubKey& vchPubKey, bool fSkipCheck);
|
||||
|
||||
|
|
|
@ -112,6 +112,7 @@ Value importprivkey(const Array& params, bool fHelp)
|
|||
if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
|
||||
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
assert(key.VerifyPubKey(pubkey));
|
||||
CKeyID vchAddress = pubkey.GetID();
|
||||
{
|
||||
pwalletMain->MarkDirty();
|
||||
|
@ -253,6 +254,7 @@ Value importwallet(const Array& params, bool fHelp)
|
|||
continue;
|
||||
CKey key = vchSecret.GetKey();
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
assert(key.VerifyPubKey(pubkey));
|
||||
CKeyID keyid = pubkey.GetID();
|
||||
if (pwalletMain->HaveKey(keyid)) {
|
||||
LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString());
|
||||
|
|
|
@ -82,6 +82,26 @@ BOOST_AUTO_TEST_CASE(key_test1)
|
|||
CPubKey pubkey1C = key1C.GetPubKey();
|
||||
CPubKey pubkey2C = key2C.GetPubKey();
|
||||
|
||||
BOOST_CHECK(key1.VerifyPubKey(pubkey1));
|
||||
BOOST_CHECK(!key1.VerifyPubKey(pubkey1C));
|
||||
BOOST_CHECK(!key1.VerifyPubKey(pubkey2));
|
||||
BOOST_CHECK(!key1.VerifyPubKey(pubkey2C));
|
||||
|
||||
BOOST_CHECK(!key1C.VerifyPubKey(pubkey1));
|
||||
BOOST_CHECK(key1C.VerifyPubKey(pubkey1C));
|
||||
BOOST_CHECK(!key1C.VerifyPubKey(pubkey2));
|
||||
BOOST_CHECK(!key1C.VerifyPubKey(pubkey2C));
|
||||
|
||||
BOOST_CHECK(!key2.VerifyPubKey(pubkey1));
|
||||
BOOST_CHECK(!key2.VerifyPubKey(pubkey1C));
|
||||
BOOST_CHECK(key2.VerifyPubKey(pubkey2));
|
||||
BOOST_CHECK(!key2.VerifyPubKey(pubkey2C));
|
||||
|
||||
BOOST_CHECK(!key2C.VerifyPubKey(pubkey1));
|
||||
BOOST_CHECK(!key2C.VerifyPubKey(pubkey1C));
|
||||
BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
|
||||
BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
|
||||
|
||||
BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID()));
|
||||
BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID()));
|
||||
BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));
|
||||
|
|
|
@ -79,6 +79,7 @@ CPubKey CWallet::GenerateNewKey()
|
|||
SetMinVersion(FEATURE_COMPRPUBKEY);
|
||||
|
||||
CPubKey pubkey = secret.GetPubKey();
|
||||
assert(secret.VerifyPubKey(pubkey));
|
||||
|
||||
// Create new metadata
|
||||
int64_t nCreationTime = GetTime();
|
||||
|
|
Loading…
Reference in a new issue