Experimental support for TX_PUBKEY_DROP spending.
[novacoin.git] / src / keystore.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "keystore.h"
7 #include "script.h"
8 #include "base58.h"
9
10 extern bool fWalletUnlockMintOnly;
11
12 bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
13 {
14     CKey key;
15     if (!GetKey(address, key))
16         return false;
17     vchPubKeyOut = key.GetPubKey();
18     return true;
19 }
20
21 bool CBasicKeyStore::AddKey(const CKey& key)
22 {
23     bool fCompressed = false;
24     CSecret secret = key.GetSecret(fCompressed);
25     {
26         LOCK(cs_KeyStore);
27         mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed);
28     }
29     return true;
30 }
31
32 bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
33 {
34     if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
35         return error("CBasicKeyStore::AddCScript() : redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
36
37     {
38         LOCK(cs_KeyStore);
39         mapScripts[redeemScript.GetID()] = redeemScript;
40     }
41     return true;
42 }
43
44 bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
45 {
46     bool result;
47     {
48         LOCK(cs_KeyStore);
49         result = (mapScripts.count(hash) > 0);
50     }
51     return result;
52 }
53
54
55 bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
56 {
57     {
58         LOCK(cs_KeyStore);
59         ScriptMap::const_iterator mi = mapScripts.find(hash);
60         if (mi != mapScripts.end())
61         {
62             redeemScriptOut = (*mi).second;
63             return true;
64         }
65     }
66     return false;
67 }
68
69 bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
70 {
71     LOCK(cs_KeyStore);
72
73     CTxDestination address;
74     if (ExtractDestination(dest, address)) {
75         CKeyID keyID;
76         CBitcoinAddress(address).GetKeyID(keyID);
77         if (HaveKey(keyID))
78             return false;
79     }
80
81     setWatchOnly.insert(dest);
82     return true;
83 }
84
85
86 bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest)
87 {
88     LOCK(cs_KeyStore);
89     setWatchOnly.erase(dest);
90     return true;
91 }
92
93 bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
94 {
95     LOCK(cs_KeyStore);
96     return setWatchOnly.count(dest) > 0;
97 }
98
99 bool CBasicKeyStore::HaveWatchOnly() const
100 {
101     LOCK(cs_KeyStore);
102     return (!setWatchOnly.empty());
103 }
104
105 CCryptoKeyStore::CCryptoKeyStore() : fUseCrypto(false)
106 {
107     std::string strMalleableKey = GetArg("-masterkey", "");
108     CMalleableKey malleableKey;
109     if (strMalleableKey != "")
110         malleableKey.SetString(strMalleableKey);
111     else
112         malleableKey.MakeNewKeys();
113
114     CMalleableKeyView keyView(malleableKey);
115
116     malleableKeyPair = std::pair<CMalleableKeyView, CMalleableKey>(keyView, malleableKey);
117 }
118
119 bool CCryptoKeyStore::SetCrypted()
120 {
121     {
122         LOCK(cs_KeyStore);
123         if (fUseCrypto)
124             return true;
125         if (!mapKeys.empty())
126             return false;
127         fUseCrypto = true;
128     }
129     return true;
130 }
131
132 bool CCryptoKeyStore::Lock()
133 {
134     if (!SetCrypted())
135         return false;
136
137     {
138         LOCK(cs_KeyStore);
139         vMasterKey.clear();
140         fWalletUnlockMintOnly = false;
141     }
142
143     NotifyStatusChanged(this);
144     return true;
145 }
146
147 bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
148 {
149     {
150         LOCK(cs_KeyStore);
151         if (!SetCrypted())
152             return false;
153
154         CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
155         for (; mi != mapCryptedKeys.end(); ++mi)
156         {
157             const CPubKey &vchPubKey = (*mi).second.first;
158             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
159             CSecret vchSecret;
160             if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
161                 return false;
162             if (vchSecret.size() != 32)
163                 return false;
164             CKey key;
165             key.SetPubKey(vchPubKey);
166             key.SetSecret(vchSecret);
167             if (key.GetPubKey() == vchPubKey)
168                 break;
169             return false;
170         }
171
172         vMasterKey = vMasterKeyIn;
173     }
174     NotifyStatusChanged(this);
175     return true;
176 }
177
178 bool CCryptoKeyStore::AddKey(const CKey& key)
179 {
180     {
181         LOCK(cs_KeyStore);
182
183         CScript script;
184         script.SetDestination(key.GetPubKey().GetID());
185
186         if (HaveWatchOnly(script))
187             return false;
188
189         if (!IsCrypted())
190             return CBasicKeyStore::AddKey(key);
191
192         if (IsLocked())
193             return false;
194
195         std::vector<unsigned char> vchCryptedSecret;
196         CPubKey vchPubKey = key.GetPubKey();
197         bool fCompressed;
198         if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
199             return false;
200
201         if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
202             return false;
203     }
204     return true;
205 }
206
207
208 bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
209 {
210     {
211         LOCK(cs_KeyStore);
212         if (!SetCrypted())
213             return false;
214
215         mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
216     }
217     return true;
218 }
219
220 bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
221 {
222     {
223         LOCK(cs_KeyStore);
224         if (!IsCrypted())
225             return CBasicKeyStore::GetKey(address, keyOut);
226
227         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
228         if (mi != mapCryptedKeys.end())
229         {
230             const CPubKey &vchPubKey = (*mi).second.first;
231             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
232             CSecret vchSecret;
233             if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
234                 return false;
235             if (vchSecret.size() != 32)
236                 return false;
237             keyOut.SetPubKey(vchPubKey);
238             keyOut.SetSecret(vchSecret);
239             return true;
240         }
241     }
242     return false;
243 }
244
245 bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
246 {
247     {
248         LOCK(cs_KeyStore);
249         if (!IsCrypted())
250             return CKeyStore::GetPubKey(address, vchPubKeyOut);
251
252         CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
253         if (mi != mapCryptedKeys.end())
254         {
255             vchPubKeyOut = (*mi).second.first;
256             return true;
257         }
258     }
259     return false;
260 }
261
262 bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
263 {
264     {
265         LOCK(cs_KeyStore);
266         if (!mapCryptedKeys.empty() || IsCrypted())
267             return false;
268
269         fUseCrypto = true;
270         BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
271         {
272             CKey key;
273             if (!key.SetSecret(mKey.second.first, mKey.second.second))
274                 return false;
275             const CPubKey vchPubKey = key.GetPubKey();
276             std::vector<unsigned char> vchCryptedSecret;
277             bool fCompressed;
278             if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
279                 return false;
280             if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
281                 return false;
282         }
283         mapKeys.clear();
284     }
285     return true;
286 }
287
288 bool CCryptoKeyStore::DecryptKeys(const CKeyingMaterial& vMasterKeyIn)
289 {
290     {
291         LOCK(cs_KeyStore);
292         if (!IsCrypted())
293             return false;
294
295         CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
296         for (; mi != mapCryptedKeys.end(); ++mi)
297         {
298             const CPubKey &vchPubKey = (*mi).second.first;
299             const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
300             CSecret vchSecret;
301             if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
302                 return false;
303             if (vchSecret.size() != 32)
304                 return false;
305             CKey key;
306             key.SetPubKey(vchPubKey);
307             key.SetSecret(vchSecret);
308             if (!CBasicKeyStore::AddKey(key))
309                 return false;
310         }
311
312         mapCryptedKeys.clear();
313     }
314
315     return true;
316 }