Some extra comments

This commit is contained in:
Pieter Wuille 2011-11-07 00:05:42 +01:00
parent 81a28d7a6f
commit d825e6a31b
7 changed files with 80 additions and 9 deletions

View File

@ -21,7 +21,7 @@
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
// Encode a byte sequence as a base58-encoded string
inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
{ {
CAutoBN_CTX pctx; CAutoBN_CTX pctx;
@ -62,11 +62,14 @@ inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char
return str; return str;
} }
// Encode a byte vector as a base58-encoded string
inline std::string EncodeBase58(const std::vector<unsigned char>& vch) inline std::string EncodeBase58(const std::vector<unsigned char>& vch)
{ {
return EncodeBase58(&vch[0], &vch[0] + vch.size()); return EncodeBase58(&vch[0], &vch[0] + vch.size());
} }
// Decode a base58-encoded string psz into byte vector vchRet
// returns true if decoding is succesful
inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet) inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet)
{ {
CAutoBN_CTX pctx; CAutoBN_CTX pctx;
@ -113,6 +116,8 @@ inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet)
return true; return true;
} }
// Decode a base58-encoded string str into byte vector vchRet
// returns true if decoding is succesful
inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet) inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
{ {
return DecodeBase58(str.c_str(), vchRet); return DecodeBase58(str.c_str(), vchRet);
@ -121,7 +126,7 @@ inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vch
// Encode a byte vector to a base58-encoded string, including checksum
inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
{ {
// add 4-byte hash check to the end // add 4-byte hash check to the end
@ -131,6 +136,8 @@ inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
return EncodeBase58(vch); return EncodeBase58(vch);
} }
// Decode a base58-encoded string psz that includes a checksum, into byte vector vchRet
// returns true if decoding is succesful
inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
{ {
if (!DecodeBase58(psz, vchRet)) if (!DecodeBase58(psz, vchRet))
@ -150,6 +157,8 @@ inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRe
return true; return true;
} }
// Decode a base58-encoded string str that includes a checksum, into byte vector vchRet
// returns true if decoding is succesful
inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet) inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
{ {
return DecodeBase58Check(str.c_str(), vchRet); return DecodeBase58Check(str.c_str(), vchRet);
@ -159,11 +168,14 @@ inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>
// Base class for all base58-encoded data
class CBase58Data class CBase58Data
{ {
protected: protected:
// the version byte
unsigned char nVersion; unsigned char nVersion;
// the actually encoded data
std::vector<unsigned char> vchData; std::vector<unsigned char> vchData;
CBase58Data() CBase58Data()
@ -174,6 +186,7 @@ protected:
~CBase58Data() ~CBase58Data()
{ {
// zero the memory, as it may contain sensitive data
if (!vchData.empty()) if (!vchData.empty())
memset(&vchData[0], 0, vchData.size()); memset(&vchData[0], 0, vchData.size());
} }
@ -238,7 +251,9 @@ public:
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; } bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
}; };
// base58-encoded bitcoin addresses
// Addresses have version 0 or 111 (testnet)
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key
class CBitcoinAddress : public CBase58Data class CBitcoinAddress : public CBase58Data
{ {
public: public:

View File

@ -13,15 +13,15 @@ const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
Private key encryption is done based on a CMasterKey, Private key encryption is done based on a CMasterKey,
which holds a salt and random encryption key. which holds a salt and random encryption key.
CMasterKeys is encrypted using AES-256-CBC using a key CMasterKeys are encrypted using AES-256-CBC using a key
derived using derivation method nDerivationMethod derived using derivation method nDerivationMethod
(0 == EVP_sha512()) and derivation iterations nDeriveIterations. (0 == EVP_sha512()) and derivation iterations nDeriveIterations.
vchOtherDerivationParameters is provided for alternative algorithms vchOtherDerivationParameters is provided for alternative algorithms
which may require more parameters (such as scrypt). which may require more parameters (such as scrypt).
Wallet Private Keys are then encrypted using AES-256-CBC Wallet Private Keys are then encrypted using AES-256-CBC
with the double-sha256 of the private key as the IV, and the with the double-sha256 of the public key as the IV, and the
master key's key as the encryption key. master key's key as the encryption key (see keystore.[ch]).
*/ */
class CMasterKey class CMasterKey

View File

@ -39,6 +39,7 @@
// see www.keylength.com // see www.keylength.com
// script supports up to 75 for single byte push // script supports up to 75 for single byte push
// Generate a private key from just the secret parameter
int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{ {
int ok = 0; int ok = 0;
@ -75,6 +76,9 @@ err:
return(ok); return(ok);
} }
// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
// recid selects which key is recovered
// if check is nonzero, additional checks are performed
int static inline ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) int static inline ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
{ {
if (!eckey) return 0; if (!eckey) return 0;
@ -154,7 +158,9 @@ public:
// secure_allocator is defined in serialize.h // secure_allocator is defined in serialize.h
// CPrivKey is a serialized private key, with all parameters included (279 bytes)
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey; typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
// CSecret is a serialization of just the secret parameter (32 bytes)
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret; typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
class CKey class CKey
@ -292,6 +298,9 @@ public:
} }
// create a compact signature (65 bytes), which allows reconstructing the used public key // create a compact signature (65 bytes), which allows reconstructing the used public key
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
// 0x1D = second key with even y, 0x1E = second key with odd y
bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig) bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
{ {
bool fOk = false; bool fOk = false;
@ -318,7 +327,7 @@ public:
} }
if (nRecId == -1) if (nRecId == -1)
throw key_error("CKEy::SignCompact() : unable to construct recoverable key"); throw key_error("CKey::SignCompact() : unable to construct recoverable key");
vchSig[0] = nRecId+27; vchSig[0] = nRecId+27;
BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
@ -330,6 +339,9 @@ public:
} }
// reconstruct public key from a compact signature // reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig) bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
{ {
if (vchSig.size() != 65) if (vchSig.size() != 65)
@ -359,6 +371,7 @@ public:
return true; return true;
} }
// Verify a compact signature
bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig) bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
{ {
CKey key; CKey key;
@ -369,6 +382,7 @@ public:
return true; return true;
} }
// Get the address corresponding to this key
CBitcoinAddress GetAddress() const CBitcoinAddress GetAddress() const
{ {
return CBitcoinAddress(GetPubKey()); return CBitcoinAddress(GetPubKey());

View File

@ -7,21 +7,34 @@
#include "crypter.h" #include "crypter.h"
// A virtual base class for key stores
class CKeyStore class CKeyStore
{ {
protected: protected:
mutable CCriticalSection cs_KeyStore; mutable CCriticalSection cs_KeyStore;
public: public:
// Add a key to the store.
virtual bool AddKey(const CKey& key) =0; virtual bool AddKey(const CKey& key) =0;
// Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CBitcoinAddress &address) const =0; virtual bool HaveKey(const CBitcoinAddress &address) const =0;
// Retrieve a key corresponding to a given address from the store.
// Return true if succesful.
virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const =0; virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const =0;
// Retrieve only the public key corresponding to a given address.
// This may succeed even if GetKey fails (e.g., encrypted wallets)
virtual bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const; virtual bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
// Generate a new key, and add it to the store
virtual std::vector<unsigned char> GenerateNewKey(); virtual std::vector<unsigned char> GenerateNewKey();
}; };
typedef std::map<CBitcoinAddress, CSecret> KeyMap; typedef std::map<CBitcoinAddress, CSecret> KeyMap;
// Basic key store, that keeps keys in an address->secret map
class CBasicKeyStore : public CKeyStore class CBasicKeyStore : public CKeyStore
{ {
protected: protected:
@ -53,6 +66,8 @@ public:
typedef std::map<CBitcoinAddress, std::pair<std::vector<unsigned char>, std::vector<unsigned char> > > CryptedKeyMap; typedef std::map<CBitcoinAddress, std::pair<std::vector<unsigned char>, std::vector<unsigned char> > > CryptedKeyMap;
// Keystore which keeps the private keys encrypted
// It derives from the basic key store, which is used if no encryption is active.
class CCryptoKeyStore : public CBasicKeyStore class CCryptoKeyStore : public CBasicKeyStore
{ {
private: private:

View File

@ -70,6 +70,9 @@ int fUseUPnP = false;
// dispatching functions // dispatching functions
// //
// These functions dispatch to one or all registered wallets
void RegisterWallet(CWallet* pwalletIn) void RegisterWallet(CWallet* pwalletIn)
{ {
CRITICAL_BLOCK(cs_setpwalletRegistered) CRITICAL_BLOCK(cs_setpwalletRegistered)
@ -86,6 +89,7 @@ void UnregisterWallet(CWallet* pwalletIn)
} }
} }
// check whether the passed transaction is from us
bool static IsFromMe(CTransaction& tx) bool static IsFromMe(CTransaction& tx)
{ {
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@ -94,6 +98,7 @@ bool static IsFromMe(CTransaction& tx)
return false; return false;
} }
// get the wallet transaction with the given hash (if it exists)
bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
{ {
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@ -102,42 +107,49 @@ bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
return false; return false;
} }
// erases transaction with the given hash from all wallets
void static EraseFromWallets(uint256 hash) void static EraseFromWallets(uint256 hash)
{ {
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->EraseFromWallet(hash); pwallet->EraseFromWallet(hash);
} }
// make sure all wallets know about the given transaction, in the given block
void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false) void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false)
{ {
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate); pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
} }
// notify wallets about a new best chain
void static SetBestChain(const CBlockLocator& loc) void static SetBestChain(const CBlockLocator& loc)
{ {
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->SetBestChain(loc); pwallet->SetBestChain(loc);
} }
// notify wallets about an updated transaction
void static UpdatedTransaction(const uint256& hashTx) void static UpdatedTransaction(const uint256& hashTx)
{ {
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->UpdatedTransaction(hashTx); pwallet->UpdatedTransaction(hashTx);
} }
// dump all wallets
void static PrintWallets(const CBlock& block) void static PrintWallets(const CBlock& block)
{ {
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->PrintWallet(block); pwallet->PrintWallet(block);
} }
// notify wallets about an incoming inventory (for request counts)
void static Inventory(const uint256& hash) void static Inventory(const uint256& hash)
{ {
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->Inventory(hash); pwallet->Inventory(hash);
} }
// ask wallets to resend their transactions
void static ResendWalletTransactions() void static ResendWalletTransactions()
{ {
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)

View File

@ -289,6 +289,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
return true; return true;
} }
// Add a transaction to the wallet, or update it.
// pblock is optional, but should be provided if the transaction is known to be in a block.
// If fUpdate is true, existing transactions will be updated.
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
{ {
uint256 hash = tx.GetHash(); uint256 hash = tx.GetHash();
@ -551,6 +554,9 @@ bool CWalletTx::WriteToDisk()
return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this); return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
} }
// Scan the block chain (starting in pindexStart) for transactions
// from or to us. If fUpdate is true, found transactions that already
// exist in the wallet will be updated.
int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
{ {
int ret = 0; int ret = 0;

View File

@ -13,6 +13,9 @@ class CWalletTx;
class CReserveKey; class CReserveKey;
class CWalletDB; class CWalletDB;
// A CWallet is an extension of a keystore, which also maintains a set of
// transactions and balances, and provides the ability to create new
// transactions
class CWallet : public CCryptoKeyStore class CWallet : public CCryptoKeyStore
{ {
private: private:
@ -57,9 +60,14 @@ public:
std::vector<unsigned char> vchDefaultKey; std::vector<unsigned char> vchDefaultKey;
// keystore implementation // keystore implementation
// Adds a key to the store, and saves it to disk.
bool AddKey(const CKey& key); bool AddKey(const CKey& key);
// Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); } bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
// Adds an encrypted key to the store, and saves it to disk.
bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
// Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); } bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
bool Unlock(const std::string& strWalletPassphrase); bool Unlock(const std::string& strWalletPassphrase);
@ -244,7 +252,7 @@ public:
unsigned int nTimeReceived; // time received by this node unsigned int nTimeReceived; // time received by this node
char fFromMe; char fFromMe;
std::string strFromAccount; std::string strFromAccount;
std::vector<char> vfSpent; std::vector<char> vfSpent; // which outputs are already spent
// memory only // memory only
mutable char fDebitCached; mutable char fDebitCached;
@ -371,6 +379,7 @@ public:
return fReturn; return fReturn;
} }
// make sure balances are recalculated
void MarkDirty() void MarkDirty()
{ {
fCreditCached = false; fCreditCached = false;