From 7f70ddc68f4afa4a87a15e620ba519afbc5c8b15 Mon Sep 17 00:00:00 2001 From: 0xDEADFACE Date: Sat, 13 Feb 2016 19:20:49 -0800 Subject: [PATCH] RPC: Add new methods suitable for malleable key pairs management; Save generated key pairs in the wallet.dat. Due to lack of time for a proper debugging the generation of malleable keys has been disabled on the main network. Of course it will be enabled in the near future. --- src/bitcoinrpc.cpp | 3 +- src/bitcoinrpc.h | 3 +- src/key.cpp | 30 ++++++++++++++++++++++++++++ src/key.h | 34 ++++++++++++++++++++++++++++++- src/keystore.cpp | 22 ++++++++------------ src/keystore.h | 29 +++++++++++++++++++++++---- src/rpcwallet.cpp | 54 ++++++++++++++++++++++++++++++++++++--------------- src/version.h | 2 +- src/wallet.cpp | 43 +++++++++++++++++++++++++++++++++++++++++ src/wallet.h | 10 ++++++++- src/walletdb.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++- src/walletdb.h | 13 ++++++++++++ 12 files changed, 249 insertions(+), 41 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 92042d0..c6b64fe 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -319,7 +319,8 @@ static const CRPCCommand vRPCCommands[] = { "newmalleablekey", &newmalleablekey, false, false}, { "adjustmalleablekey", &adjustmalleablekey, false, false}, { "adjustmalleablepubkey", &adjustmalleablepubkey, false, false}, - { "listmalleablepubkeys", &listmalleablepubkeys, false, false}, + { "listmalleableviews", &listmalleableviews, false, false}, + { "dumpmalleablekey", &dumpmalleablekey, false, false}, { "sendalert", &sendalert, false, false}, }; diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 226007b..abadd8b 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -209,7 +209,8 @@ extern json_spirit::Value mergecoins(const json_spirit::Array& params, bool fHel extern json_spirit::Value newmalleablekey(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value adjustmalleablekey(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value adjustmalleablepubkey(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listmalleablepubkeys(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listmalleableviews(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value dumpmalleablekey(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp); diff --git a/src/key.cpp b/src/key.cpp index dafffcf..c37b102 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -714,6 +714,15 @@ std::string CMalleablePubKey::ToString() const return EncodeBase58Check(vch); } +std::vector CMalleablePubKey::Raw() const +{ + CDataStream ssKey(SER_NETWORK, PROTOCOL_VERSION); + ssKey << *this; + std::vector vch(ssKey.begin(), ssKey.end()); + + return vch; +} + bool CMalleablePubKey::SetString(const std::string& strMalleablePubKey) { std::vector vchTemp; @@ -774,12 +783,14 @@ CMalleableKey::CMalleableKey(const CSecret &L, const CSecret &H) SetSecrets(L, H); } +/* CMalleableKey& CMalleableKey::operator=(const CMalleableKey &b) { SetSecrets(b.vchSecretL, b.vchSecretH); return (*this); } +*/ CMalleableKey::~CMalleableKey() { @@ -985,6 +996,15 @@ std::string CMalleableKey::ToString() const return EncodeBase58Check(vch); } +std::vector CMalleableKey::Raw() const +{ + CDataStream ssKey(SER_NETWORK, PROTOCOL_VERSION); + ssKey << *this; + std::vector vch(ssKey.begin(), ssKey.end()); + + return vch; +} + bool CMalleableKey::SetString(const std::string& strMutableKey) { std::vector vchTemp; @@ -1138,6 +1158,16 @@ bool CMalleableKeyView::SetString(const std::string& strMutableKey) return IsNull(); } +std::vector CMalleableKeyView::Raw() const +{ + CDataStream ssKey(SER_NETWORK, PROTOCOL_VERSION); + ssKey << *this; + std::vector vch(ssKey.begin(), ssKey.end()); + + return vch; +} + + bool CMalleableKeyView::IsNull() const { return nVersion != CURRENT_VERSION; diff --git a/src/key.h b/src/key.h index a829834..1ce14f8 100644 --- a/src/key.h +++ b/src/key.h @@ -235,10 +235,21 @@ public: bool operator==(const CMalleablePubKey &b); bool operator!=(const CMalleablePubKey &b) { return !(*this == b); } + CMalleablePubKey& operator=(const CMalleablePubKey& mpk) { + nVersion = mpk.nVersion; + pubKeyL = mpk.pubKeyL; + pubKeyH = mpk.pubKeyH; + return *this; + } std::string ToString() const; bool SetString(const std::string& strMalleablePubKey); - uint256 GetID() const; + + CKeyID GetID() const { + return pubKeyL.GetID(); + } + + std::vector Raw() const; CPubKey& GetL() { return pubKeyL; } CPubKey& GetH() { return pubKeyH; } @@ -260,7 +271,6 @@ public: CMalleableKey(); CMalleableKey(const CMalleableKey &b); CMalleableKey(const CSecret &L, const CSecret &H); - CMalleableKey& operator=(const CMalleableKey &b); ~CMalleableKey(); IMPLEMENT_SERIALIZE( @@ -272,6 +282,13 @@ public: std::string ToString() const; bool SetString(const std::string& strMalleablePubKey); + std::vector Raw() const; + CMalleableKey& operator=(const CMalleableKey& mk) { + nVersion = mk.nVersion; + vchSecretL = mk.vchSecretL; + vchSecretH = mk.vchSecretH; + return *this; + } void Reset(); void MakeNewKeys(); @@ -279,6 +296,9 @@ public: bool SetSecrets(const CSecret &pvchSecretL, const CSecret &pvchSecretH); void GetSecrets(CSecret &pvchSecretL, CSecret &pvchSecretH) const; + CKeyID GetID() const { + return GetMalleablePubKey().GetID(); + } CMalleablePubKey GetMalleablePubKey() const; bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant) const; bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant, CKey &privKeyVariant) const; @@ -313,7 +333,17 @@ public: bool IsNull() const; std::string ToString() const; bool SetString(const std::string& strMalleablePubKey); + std::vector Raw() const; + CMalleableKeyView& operator=(const CMalleableKeyView& mkv) { + nVersion = mkv.nVersion; + vchSecretL = mkv.vchSecretL; + vchPubKeyH = mkv.vchPubKeyH; + return *this; + } + CKeyID GetID() const { + return GetMalleablePubKey().GetID(); + } CMalleablePubKey GetMalleablePubKey() const; bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant) const; diff --git a/src/keystore.cpp b/src/keystore.cpp index fdba291..fdbecba 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -29,6 +29,15 @@ bool CBasicKeyStore::AddKey(const CKey& key) return true; } +bool CBasicKeyStore::AddMalleableKey(const CMalleableKey& mKey) +{ + { + LOCK(cs_KeyStore); + mapMalleableKeys[CMalleableKeyView(mKey)] = mKey; + } + return true; +} + bool CBasicKeyStore::AddCScript(const CScript& redeemScript) { if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) @@ -102,19 +111,6 @@ bool CBasicKeyStore::HaveWatchOnly() const return (!setWatchOnly.empty()); } -CCryptoKeyStore::CCryptoKeyStore() : fUseCrypto(false) -{ - std::string strMalleableKey = GetArg("-masterkey", ""); - CMalleableKey malleableKey; - if (strMalleableKey != "") - malleableKey.SetString(strMalleableKey); - else - malleableKey.MakeNewKeys(); - - const CMalleableKeyView& keyView(malleableKey); - mapMalleableKeys[keyView] = malleableKey; -} - bool CCryptoKeyStore::SetCrypted() { { diff --git a/src/keystore.h b/src/keystore.h index 7d49735..2193060 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -39,6 +39,10 @@ public: // Add a key to the store. virtual bool AddKey(const CKey& key) =0; + // Add a malleable key to store. + virtual bool AddMalleableKey(const CMalleableKey& mKey) =0; + virtual bool GetMalleableKey(const CMalleableKeyView &keyView, CMalleableKey &mKey) const =0; + // Check whether a key corresponding to a given address is present in the store. virtual bool HaveKey(const CKeyID &address) const =0; virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0; @@ -67,7 +71,7 @@ public: virtual bool CheckOwnership(const CPubKey &pubKeyVariant, const CPubKey &R) const =0; virtual bool CreatePrivKey(const CPubKey &pubKeyVariant, const CPubKey &R, CKey &privKey) const =0; - virtual void ListMalleablePubKeys(std::list &malleablePubKeyList) const =0; + virtual void ListMalleableViews(std::list &malleableViewList) const =0; }; typedef std::map > KeyMap; @@ -87,6 +91,21 @@ protected: public: bool AddKey(const CKey& key); + bool AddMalleableKey(const CMalleableKey& mKey); + bool GetMalleableKey(const CMalleableKeyView &keyView, CMalleableKey &mKey) const + { + { + LOCK(cs_KeyStore); + MalleableKeyMap::const_iterator mi = mapMalleableKeys.find(keyView); + if (mi != mapMalleableKeys.end()) + { + mKey = mi->second; + return true; + } + } + return false; + } + bool HaveKey(const CKeyID &address) const { bool result; @@ -158,14 +177,14 @@ public: return false; } - void ListMalleablePubKeys(std::list &malleablePubKeyList) const + void ListMalleableViews(std::list &malleableViewList) const { - malleablePubKeyList.clear(); + malleableViewList.clear(); { LOCK(cs_KeyStore); for (MalleableKeyMap::const_iterator mi = mapMalleableKeys.begin(); mi != mapMalleableKeys.end(); mi++) - malleablePubKeyList.push_back(mi->first.GetMalleablePubKey()); + malleableViewList.push_back(CMalleableKeyView(mi->first)); } } }; @@ -196,7 +215,7 @@ protected: bool Unlock(const CKeyingMaterial& vMasterKeyIn); public: - CCryptoKeyStore(); + CCryptoKeyStore() : fUseCrypto(false) { } bool IsCrypted() const { diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 6a7a3b1..8b3780e 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1866,17 +1866,39 @@ Value newmalleablekey(const Array& params, bool fHelp) "newmalleablekey\n" "Make a malleable public/private key pair.\n"); - CMalleableKey malleableKey; - malleableKey.MakeNewKeys(); - CMalleablePubKey malleablePubKey = malleableKey.GetMalleablePubKey(); + if (!fTestNet) + throw runtime_error("This feature has been disabled for mainNet clients"); + + CMalleableKeyView keyView = pwalletMain->GenerateNewMalleableKey(); + + CMalleableKey mKey; + if (!pwalletMain->GetMalleableKey(keyView, mKey)) + throw runtime_error("Unable to generate new malleable key"); + + Object result; + result.push_back(Pair("PublicPair", mKey.GetMalleablePubKey().ToString())); + result.push_back(Pair("KeyView", keyView.ToString())); + + return result; +} + +Value dumpmalleablekey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error ( + "dumpmalleablekey \n" + "Dump the private and public key pairs, which correspond to provided key view.\n"); - CDataStream ssPublicBytes(SER_NETWORK, PROTOCOL_VERSION); - ssPublicBytes << malleablePubKey; + CMalleableKey mKey; + CMalleableKeyView keyView; + keyView.SetString(params[0].get_str()); + + if (!pwalletMain->GetMalleableKey(keyView, mKey)) + throw runtime_error("There is no such item in the wallet"); Object result; - result.push_back(Pair("PrivatePair", malleableKey.ToString())); - result.push_back(Pair("PublicPair", malleablePubKey.ToString())); - result.push_back(Pair("PublicBytes", HexStr(ssPublicBytes.begin(), ssPublicBytes.end()))); + result.push_back(Pair("PrivatePair", mKey.ToString())); + result.push_back(Pair("PublicPair", mKey.GetMalleablePubKey().ToString())); return result; } @@ -1933,25 +1955,25 @@ Value adjustmalleablepubkey(const Array& params, bool fHelp) result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.Raw()))); result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString())); - return result; } -Value listmalleablepubkeys(const Array& params, bool fHelp) +Value listmalleableviews(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "listmalleablepubkeys\n" - "Get list of malleable public keys.\n"); + "listmalleableviews\n" + "Get list of views for generated malleable keys.\n"); - std::list keyList; - pwalletMain->ListMalleablePubKeys(keyList); + std::list keyViewList; + pwalletMain->ListMalleableViews(keyViewList); Array result; - BOOST_FOREACH(const CMalleablePubKey &key, keyList) + BOOST_FOREACH(const CMalleableKeyView &keyView, keyViewList) { - result.push_back(key.ToString()); + result.push_back(keyView.ToString()); } return result; } + diff --git a/src/version.h b/src/version.h index c19ad48..e7e3e32 100644 --- a/src/version.h +++ b/src/version.h @@ -30,7 +30,7 @@ static const int DATABASE_VERSION = 70507; // network protocol versioning // -static const int PROTOCOL_VERSION = 60016; +static const int PROTOCOL_VERSION = 60017; // earlier versions not supported as of Feb 2012, and are disconnected static const int MIN_PROTO_VERSION = 209; diff --git a/src/wallet.cpp b/src/wallet.cpp index d31b2e0..5c46a1b 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -57,6 +57,28 @@ CPubKey CWallet::GenerateNewKey() return key.GetPubKey(); } +CMalleableKeyView CWallet::GenerateNewMalleableKey() +{ + RandAddSeedPerfmon(); + + // Compressed public keys were introduced in version 0.6.0 + SetMinVersion(FEATURE_MALLKEY); + + CMalleableKey mKey; + mKey.MakeNewKeys(); + const CMalleableKeyView &keyView(mKey); + + // Create new metadata + int64_t nCreationTime = GetTime(); + mapMalleableKeyMetadata[keyView] = CKeyMetadata(nCreationTime); + if (!nTimeFirstKey || nCreationTime < nTimeFirstKey) + nTimeFirstKey = nCreationTime; + + if (!AddMalleableKey(mKey)) + throw std::runtime_error("CWallet::GenerateNewMalleableKey() : AddMalleableKey failed"); + return CMalleableKeyView(mKey); +} + bool CWallet::AddKey(const CKey& key) { CPubKey pubkey = key.GetPubKey(); @@ -69,6 +91,18 @@ bool CWallet::AddKey(const CKey& key) return true; } +bool CWallet::AddMalleableKey(const CMalleableKey& mKey) +{ + CMalleableKeyView keyView = CMalleableKeyView(mKey); + if (!CCryptoKeyStore::AddMalleableKey(mKey)) + return false; + if (!fFileBacked) + return true; + if (!IsCrypted()) + return CWalletDB(strWalletFile).WriteMalleableKey(keyView, mKey, mapMalleableKeyMetadata[keyView]); + return true; +} + bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector &vchCryptedSecret) { if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) @@ -101,6 +135,15 @@ bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta) return true; } +bool CWallet::LoadMalleableKeyMetadata(const CMalleableKeyView &keyView, const CKeyMetadata &metadata) +{ + if (metadata.nCreateTime && (!nTimeFirstKey || metadata.nCreateTime < nTimeFirstKey)) + nTimeFirstKey = metadata.nCreateTime; + + mapMalleableKeyMetadata[keyView] = metadata; + return true; +} + bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) diff --git a/src/wallet.h b/src/wallet.h index 8480b3b..20abe44 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -37,7 +37,8 @@ enum WalletFeature FEATURE_WALLETCRYPT = 40000, // wallet encryption FEATURE_COMPRPUBKEY = 60000, // compressed public keys - FEATURE_LATEST = 60000 + FEATURE_MALLKEY = 60017, + FEATURE_LATEST = 60017 }; /** A key pool entry */ @@ -95,6 +96,7 @@ public: std::set setKeyPool; std::map mapKeyMetadata; + std::map mapMalleableKeyMetadata; typedef std::map MasterKeyMap; MasterKeyMap mapMasterKeys; @@ -148,12 +150,18 @@ public: // keystore implementation // Generate a new key CPubKey GenerateNewKey(); + CMalleableKeyView GenerateNewMalleableKey(); // Adds a key to the store, and saves it to disk. bool AddKey(const CKey& key); + bool AddMalleableKey(const CMalleableKey& mKey); // Adds a key to the store, without saving it to disk (used by LoadWallet) bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); } // Load metadata (used by LoadWallet) bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata); + bool LoadMalleableKeyMetadata(const CMalleableKeyView &keyView, const CKeyMetadata &metadata); + + // Load malleable key without saving it to disk (used by LoadWallet) + bool LoadMalleableKey(const CMalleableKey &mKey) { return CCryptoKeyStore::AddMalleableKey(mKey); } bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 050d2ee..64168ee 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -220,6 +220,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, // Taking advantage of the fact that pair serialization // is just the two items serialized one after the other ssKey >> strType; + if (strType == "name") { string strAddress; @@ -301,6 +302,36 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, // so set the wallet birthday to the beginning of time. pwallet->nTimeFirstKey = 1; } + else if (strType == "malpair") + { + string strKey, strKeyView; + + CMalleableKey mKey; + CMalleableKeyView keyView; + + ssKey >> strKeyView; + ssValue >> strKey; + + keyView.SetString(strKeyView); + mKey.SetString(strKey); + + if (mKey.IsNull()) + { + strErr = "Error reading wallet database: CMalleableKey is corrupt"; + return false; + } + if (mKey.GetID() != keyView.GetID()) + { + strErr = "Error reading wallet database: CMalleableKey view inconsistency"; + return false; + } + + if (!pwallet->LoadMalleableKey(mKey)) + { + strErr = "Error reading wallet database: LoadMalleableKey failed"; + return false; + } + } else if (strType == "key" || strType == "wkey") { vector vchPubKey; @@ -385,6 +416,20 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } wss.fIsEncrypted = true; } + else if (strType == "malmeta") + { + string strKeyView; + ssKey >> strKeyView; + + CMalleableKeyView keyView; + keyView.SetString(strKeyView); + + CKeyMetadata keyMeta; + ssValue >> keyMeta; + wss.nKeyMeta++; + + pwallet->LoadMalleableKeyMetadata(keyView, keyMeta); + } else if (strType == "keymeta") { CPubKey vchPubKey; @@ -452,7 +497,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, static bool IsKeyType(string strType) { return (strType== "key" || strType == "wkey" || - strType == "mkey" || strType == "ckey"); + strType == "mkey" || strType == "ckey" || strType == "malpair"); } DBErrors CWalletDB::LoadWallet(CWallet* pwallet) diff --git a/src/walletdb.h b/src/walletdb.h index 6b6f55d..fe2b225 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -95,6 +95,19 @@ public: return true; } + bool WriteMalleableKey(const CMalleableKeyView& keyView, const CMalleableKey& malleableKey, const CKeyMetadata &keyMeta) + { + nWalletDBUpdated++; + if(!Write(std::make_pair(std::string("malmeta"), keyView.ToString()), keyMeta)) + return false; + + if(!Write(std::make_pair(std::string("malpair"), keyView.ToString()), malleableKey.ToString(), false)) + return false; + + return true; + } + + bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector& vchCryptedSecret, const CKeyMetadata &keyMeta) { nWalletDBUpdated++; -- 1.7.1