From e5e4c598dc43bb5e01b3a30aaeb2dfc9376bd7b4 Mon Sep 17 00:00:00 2001 From: 0xDEADFACE Date: Fri, 12 Feb 2016 15:43:57 -0800 Subject: [PATCH] Experimental support for TX_PUBKEY_DROP spending. --- src/key.cpp | 35 +++++++++++++++++++++++++++++++++++ src/key.h | 19 ++++++++++++++----- src/keystore.cpp | 15 +++++++++++++++ src/keystore.h | 29 ++++++++++++++++++++++++++--- src/script.cpp | 38 +++++++++++++++++++++++++++++++++++--- 5 files changed, 125 insertions(+), 11 deletions(-) diff --git a/src/key.cpp b/src/key.cpp index eb4f5c4..9503f95 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1004,6 +1004,14 @@ CMalleableKeyView::CMalleableKeyView(const CMalleableKey &b) vchPubKeyH = H.GetPubKey().Raw(); } +CMalleableKeyView::CMalleableKeyView(const CMalleableKeyView &b) +{ + assert(b.nVersion == CURRENT_VERSION); + vchSecretL = b.vchSecretL; + vchPubKeyH = b.vchPubKeyH; + nVersion = CURRENT_VERSION; +} + CMalleableKeyView::CMalleableKeyView(const CSecret &L, const CPubKey &pvchPubKeyH) { vchSecretL = L; @@ -1095,6 +1103,33 @@ bool CMalleableKeyView::CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubK return true; } +std::string CMalleableKeyView::ToString() +{ + CDataStream ssKey(SER_NETWORK, PROTOCOL_VERSION); + ssKey << *this; + std::vector vch(ssKey.begin(), ssKey.end()); + + return EncodeBase58Check(vch); +} + +bool CMalleableKeyView::SetString(const std::string& strMutableKey) +{ + std::vector vchTemp; + if (!DecodeBase58Check(strMutableKey, vchTemp)) { + throw key_error("CMalleableKeyView::SetString() : Provided key data seems corrupted."); + } + + CDataStream ssKey(vchTemp, SER_NETWORK, PROTOCOL_VERSION); + ssKey >> *this; + + return IsNull(); +} + +bool CMalleableKeyView::IsNull() const +{ + return nVersion != CURRENT_VERSION; +} + //// Asymmetric encryption void CPubKey::EncryptData(const std::vector& data, std::vector& encrypted) diff --git a/src/key.h b/src/key.h index f8404db..ca78c72 100644 --- a/src/key.h +++ b/src/key.h @@ -277,7 +277,6 @@ public: void GetSecrets(CSecret &pvchSecretL, CSecret &pvchSecretH) const; CMalleablePubKey GetMalleablePubKey() const; - bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant); bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant, CKey &privKeyVariant); }; @@ -285,15 +284,14 @@ public: class CMalleableKeyView { private: + unsigned char nVersion; CSecret vchSecretL; std::vector vchPubKeyH; - // disabled constructor - CMalleableKeyView() { }; - static const unsigned char CURRENT_VERSION = 1; public: + CMalleableKeyView() { nVersion = 0; }; CMalleableKeyView(const CMalleableKey &b); CMalleableKeyView(const CSecret &L, const CPubKey &pvchPubKeyH); @@ -301,8 +299,19 @@ public: CMalleableKeyView& operator=(const CMalleableKey &b); ~CMalleableKeyView(); - CMalleablePubKey GetMalleablePubKey() const; + IMPLEMENT_SERIALIZE( + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(vchSecretL); + READWRITE(vchPubKeyH); + ) + + bool IsNull() const; + std::string ToString(); + bool SetString(const std::string& strMalleablePubKey); + + CMalleablePubKey GetMalleablePubKey() const; bool CheckKeyVariant(const CPubKey &R, const CPubKey &vchPubKeyVariant); }; diff --git a/src/keystore.cpp b/src/keystore.cpp index ef61748..197b73e 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -102,6 +102,20 @@ 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(); + + CMalleableKeyView keyView(malleableKey); + + malleableKeyPair = std::pair(keyView, malleableKey); +} + bool CCryptoKeyStore::SetCrypted() { { @@ -154,6 +168,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) break; return false; } + vMasterKey = vMasterKeyIn; } NotifyStatusChanged(this); diff --git a/src/keystore.h b/src/keystore.h index 96285fb..7dc3464 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -64,11 +64,15 @@ public: vchSecret = key.GetSecret(fCompressed); return true; } + + virtual bool CheckOwnership(const CPubKey &pubKeyVariant, const CPubKey &R) const =0; + virtual bool CreatePrivKey(const CPubKey &pubKeyVariant, const CPubKey &R, CKey &privKey) const =0; }; typedef std::map > KeyMap; typedef std::map ScriptMap; typedef std::set WatchOnlySet; +typedef std::pair MalleableKeyPair; /** Basic key store, that keeps keys in an address->secret map */ class CBasicKeyStore : public CKeyStore @@ -77,6 +81,7 @@ protected: KeyMap mapKeys; ScriptMap mapScripts; WatchOnlySet setWatchOnly; + MalleableKeyPair malleableKeyPair; public: bool AddKey(const CKey& key); @@ -124,6 +129,26 @@ public: virtual bool RemoveWatchOnly(const CScript &dest); virtual bool HaveWatchOnly(const CScript &dest) const; virtual bool HaveWatchOnly() const; + + bool CheckOwnership(const CPubKey &pubKeyVariant, const CPubKey &R) const + { + bool result; + { + LOCK(cs_KeyStore); + result = const_cast(this)->malleableKeyPair.first.CheckKeyVariant(R, pubKeyVariant); + } + return result; + } + + bool CreatePrivKey(const CPubKey &pubKeyVariant, const CPubKey &R, CKey &privKey) const + { + bool result; + { + LOCK(cs_KeyStore); + result = const_cast(this)->malleableKeyPair.second.CheckKeyVariant(R, pubKeyVariant, privKey); + } + return result; + } }; typedef std::map > > CryptedKeyMap; @@ -152,9 +177,7 @@ protected: bool Unlock(const CKeyingMaterial& vMasterKeyIn); public: - CCryptoKeyStore() : fUseCrypto(false) - { - } + CCryptoKeyStore(); bool IsCrypted() const { diff --git a/src/script.cpp b/src/script.cpp index 9079102..26b7c94 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1328,6 +1328,21 @@ bool Sign1(const CKeyID& address, const CKeyStore& keystore, const uint256& hash return true; } +bool SignR(const CPubKey& pubKey, const CPubKey& R, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet) +{ + CKey key; + if (!keystore.CreatePrivKey(pubKey, R, key)) + return false; + + vector vchSig; + if (!key.Sign(hash, vchSig)) + return false; + vchSig.push_back((unsigned char)nHashType); + scriptSigRet << vchSig; + + return true; +} + bool SignN(const vector& multisigdata, const CKeyStore& keystore, const uint256& hash, int nHashType, CScript& scriptSigRet) { int nSigned = 0; @@ -1364,9 +1379,14 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, const uint25 case TX_NULL_DATA: return false; case TX_PUBKEY: - case TX_PUBKEY_DROP: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); + case TX_PUBKEY_DROP: + { + CPubKey key = CPubKey(vSolutions[0]); + CPubKey R = CPubKey(vSolutions[1]); + return SignR(key, R, keystore, hash, nHashType, scriptSigRet); + } case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) @@ -1480,11 +1500,23 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) case TX_NULL_DATA: break; case TX_PUBKEY: - case TX_PUBKEY_DROP: keyID = CPubKey(vSolutions[0]).GetID(); if (keystore.HaveKey(keyID)) return MINE_SPENDABLE; break; + case TX_PUBKEY_DROP: + { + CPubKey key = CPubKey(vSolutions[0]); + if (keystore.HaveKey(key.GetID())) + return MINE_SPENDABLE; + else + { + CPubKey R = CPubKey(vSolutions[1]); + if (keystore.CheckOwnership(key, R)) + return MINE_SPENDABLE; + } + } + break; case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (keystore.HaveKey(keyID)) @@ -1527,7 +1559,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) if (!Solver(scriptPubKey, whichType, vSolutions)) return false; - if (whichType == TX_PUBKEY) + if (whichType == TX_PUBKEY || whichType == TX_PUBKEY_DROP) { addressRet = CPubKey(vSolutions[0]).GetID(); return true; -- 1.7.1