diff --git a/src/base58.h b/src/base58.h index 592756ff..cace423d 100644 --- a/src/base58.h +++ b/src/base58.h @@ -21,7 +21,7 @@ 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) { CAutoBN_CTX pctx; @@ -62,11 +62,14 @@ inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char return str; } +// Encode a byte vector as a base58-encoded string inline std::string EncodeBase58(const std::vector& vch) { 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& vchRet) { CAutoBN_CTX pctx; @@ -113,6 +116,8 @@ inline bool DecodeBase58(const char* psz, std::vector& vchRet) 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& vchRet) { return DecodeBase58(str.c_str(), vchRet); @@ -121,7 +126,7 @@ inline bool DecodeBase58(const std::string& str, std::vector& vch - +// Encode a byte vector to a base58-encoded string, including checksum inline std::string EncodeBase58Check(const std::vector& vchIn) { // add 4-byte hash check to the end @@ -131,6 +136,8 @@ inline std::string EncodeBase58Check(const std::vector& vchIn) 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& vchRet) { if (!DecodeBase58(psz, vchRet)) @@ -150,6 +157,8 @@ inline bool DecodeBase58Check(const char* psz, std::vector& vchRe 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& vchRet) { return DecodeBase58Check(str.c_str(), vchRet); @@ -159,11 +168,14 @@ inline bool DecodeBase58Check(const std::string& str, std::vector - +// Base class for all base58-encoded data class CBase58Data { protected: + // the version byte unsigned char nVersion; + + // the actually encoded data std::vector vchData; CBase58Data() @@ -174,6 +186,7 @@ protected: ~CBase58Data() { + // zero the memory, as it may contain sensitive data if (!vchData.empty()) memset(&vchData[0], 0, vchData.size()); } @@ -238,7 +251,9 @@ public: 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 { public: diff --git a/src/crypter.h b/src/crypter.h index 5b95ea41..e8ca30a8 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -13,15 +13,15 @@ const unsigned int WALLET_CRYPTO_SALT_SIZE = 8; Private key encryption is done based on a CMasterKey, 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 (0 == EVP_sha512()) and derivation iterations nDeriveIterations. vchOtherDerivationParameters is provided for alternative algorithms which may require more parameters (such as scrypt). Wallet Private Keys are then encrypted using AES-256-CBC -with the double-sha256 of the private key as the IV, and the -master key's key as the encryption key. +with the double-sha256 of the public key as the IV, and the +master key's key as the encryption key (see keystore.[ch]). */ class CMasterKey diff --git a/src/key.h b/src/key.h index 5ffd7b9c..df5cfeb3 100644 --- a/src/key.h +++ b/src/key.h @@ -39,6 +39,7 @@ // see www.keylength.com // 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 ok = 0; @@ -75,6 +76,9 @@ err: 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) { if (!eckey) return 0; @@ -154,7 +158,9 @@ public: // secure_allocator is defined in serialize.h +// CPrivKey is a serialized private key, with all parameters included (279 bytes) typedef std::vector > CPrivKey; +// CSecret is a serialization of just the secret parameter (32 bytes) typedef std::vector > CSecret; class CKey @@ -292,6 +298,9 @@ public: } // 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& vchSig) { bool fOk = false; @@ -318,7 +327,7 @@ public: } 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; BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); @@ -330,6 +339,9 @@ public: } // 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& vchSig) { if (vchSig.size() != 65) @@ -359,6 +371,7 @@ public: return true; } + // Verify a compact signature bool VerifyCompact(uint256 hash, const std::vector& vchSig) { CKey key; @@ -369,6 +382,7 @@ public: return true; } + // Get the address corresponding to this key CBitcoinAddress GetAddress() const { return CBitcoinAddress(GetPubKey()); diff --git a/src/keystore.h b/src/keystore.h index 1f2c6aea..4d889146 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -7,21 +7,34 @@ #include "crypter.h" +// A virtual base class for key stores class CKeyStore { protected: mutable CCriticalSection cs_KeyStore; public: + // Add a key to the store. 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; + + // 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; + + // 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& vchPubKeyOut) const; + + // Generate a new key, and add it to the store virtual std::vector GenerateNewKey(); }; typedef std::map KeyMap; +// Basic key store, that keeps keys in an address->secret map class CBasicKeyStore : public CKeyStore { protected: @@ -53,6 +66,8 @@ public: typedef std::map, std::vector > > 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 { private: diff --git a/src/main.cpp b/src/main.cpp index 45de76a3..47f10907 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,6 +70,9 @@ int fUseUPnP = false; // dispatching functions // +// These functions dispatch to one or all registered wallets + + void RegisterWallet(CWallet* pwalletIn) { 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) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) @@ -94,6 +98,7 @@ bool static IsFromMe(CTransaction& tx) return false; } +// get the wallet transaction with the given hash (if it exists) bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) @@ -102,42 +107,49 @@ bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) return false; } +// erases transaction with the given hash from all wallets void static EraseFromWallets(uint256 hash) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) 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) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate); } +// notify wallets about a new best chain void static SetBestChain(const CBlockLocator& loc) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->SetBestChain(loc); } +// notify wallets about an updated transaction void static UpdatedTransaction(const uint256& hashTx) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->UpdatedTransaction(hashTx); } +// dump all wallets void static PrintWallets(const CBlock& block) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->PrintWallet(block); } +// notify wallets about an incoming inventory (for request counts) void static Inventory(const uint256& hash) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->Inventory(hash); } +// ask wallets to resend their transactions void static ResendWalletTransactions() { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) diff --git a/src/wallet.cpp b/src/wallet.cpp index 46c57e2f..64ee5c3b 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -289,6 +289,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) 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) { uint256 hash = tx.GetHash(); @@ -551,6 +554,9 @@ bool CWalletTx::WriteToDisk() 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 ret = 0; diff --git a/src/wallet.h b/src/wallet.h index b6df1aa0..03c4703f 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -13,6 +13,9 @@ class CWalletTx; class CReserveKey; 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 { private: @@ -57,9 +60,14 @@ public: std::vector vchDefaultKey; // keystore implementation + // Adds a key to the store, and saves it to disk. 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); } + + // Adds an encrypted key to the store, and saves it to disk. bool AddCryptedKey(const std::vector &vchPubKey, const std::vector &vchCryptedSecret); + // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) bool LoadCryptedKey(const std::vector &vchPubKey, const std::vector &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); } bool Unlock(const std::string& strWalletPassphrase); @@ -244,7 +252,7 @@ public: unsigned int nTimeReceived; // time received by this node char fFromMe; std::string strFromAccount; - std::vector vfSpent; + std::vector vfSpent; // which outputs are already spent // memory only mutable char fDebitCached; @@ -371,6 +379,7 @@ public: return fReturn; } + // make sure balances are recalculated void MarkDirty() { fCreditCached = false;