mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-13 12:33:42 +02:00
Use HMAC derivation for blinding keys
This commit is contained in:
parent
5daed69e36
commit
c5904a9da8
16 changed files with 373 additions and 103 deletions
|
|
@ -237,6 +237,9 @@ bool CBitcoinAddress::Set(const CTxDestination& dest)
|
|||
|
||||
CBitcoinAddress& CBitcoinAddress::AddBlindingKey(const CPubKey& pubkey)
|
||||
{
|
||||
if (!pubkey.IsValid()) {
|
||||
return *this;
|
||||
}
|
||||
assert(pubkey.size() == 33);
|
||||
assert(!IsBlinded());
|
||||
std::vector<unsigned char> data = vchVersion;
|
||||
|
|
|
|||
|
|
@ -298,11 +298,12 @@ static void MutateTxBlind(CMutableTransaction& tx, const string& strInput)
|
|||
|
||||
bool fBlindedIns = false;
|
||||
bool fBlindedOuts = false;
|
||||
std::vector<std::vector<unsigned char> > input_blinds;
|
||||
std::vector<std::vector<unsigned char> > output_blinds;
|
||||
std::vector<uint256> input_blinds;
|
||||
std::vector<uint256> output_blinds;
|
||||
std::vector<CPubKey> output_pubkeys;
|
||||
for (size_t nIn = 0; nIn < tx.vin.size(); nIn++) {
|
||||
std::vector<unsigned char> blind = ParseHex(input_blinding_factors[nIn]);
|
||||
uint256 blind;
|
||||
blind.SetHex(input_blinding_factors[nIn]);
|
||||
if (blind.size() == 0) {
|
||||
input_blinds.push_back(blind);
|
||||
} else if (blind.size() == 32) {
|
||||
|
|
@ -323,7 +324,7 @@ static void MutateTxBlind(CMutableTransaction& tx, const string& strInput)
|
|||
output_pubkeys.push_back(pubkey);
|
||||
fBlindedOuts = true;
|
||||
}
|
||||
output_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
output_blinds.push_back(uint256());
|
||||
}
|
||||
|
||||
if (fBlindedIns && !fBlindedOuts) {
|
||||
|
|
|
|||
|
|
@ -34,33 +34,32 @@ const secp256k1_context* ECC_Blinding_Context() {
|
|||
return secp256k1_blind_context;
|
||||
}
|
||||
|
||||
int UnblindOutput(const CKey &key, const CTxOut& txout, CAmount& amount_out, std::vector<unsigned char>& blinding_factor_out)
|
||||
bool UnblindOutput(const CKey &key, const CTxOut& txout, CAmount& amount_out, uint256& blinding_factor_out)
|
||||
{
|
||||
if (txout.nValue.IsAmount()) {
|
||||
amount_out = txout.nValue.GetAmount();
|
||||
blinding_factor_out.resize(0);
|
||||
return -1;
|
||||
if (!key.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
CPubKey ephemeral_key(txout.nValue.vchNonceCommitment);
|
||||
if (!ephemeral_key.IsValid()) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
uint256 nonce = key.ECDH(ephemeral_key);
|
||||
CSHA256().Write(nonce.begin(), 32).Finalize(nonce.begin());
|
||||
unsigned char msg[4096];
|
||||
int msg_size;
|
||||
uint64_t min_value, max_value, amount;
|
||||
blinding_factor_out.resize(32);
|
||||
int res = secp256k1_rangeproof_rewind(secp256k1_blind_context, &blinding_factor_out[0], &amount, msg, &msg_size, nonce.begin(), &min_value, &max_value, &txout.nValue.vchCommitment[0], &txout.nValue.vchRangeproof[0], txout.nValue.vchRangeproof.size());
|
||||
int res = secp256k1_rangeproof_rewind(secp256k1_blind_context, blinding_factor_out.begin(), &amount, msg, &msg_size, nonce.begin(), &min_value, &max_value, &txout.nValue.vchCommitment[0], &txout.nValue.vchRangeproof[0], txout.nValue.vchRangeproof.size());
|
||||
if (!res || amount > (uint64_t)MAX_MONEY || !MoneyRange((CAmount)amount)) {
|
||||
amount_out = 0;
|
||||
blinding_factor_out.resize(0);
|
||||
} else
|
||||
blinding_factor_out = uint256();
|
||||
return false;
|
||||
} else {
|
||||
amount_out = (CAmount)amount;
|
||||
return res ? 1 : 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void BlindOutputs(const std::vector<std::vector<unsigned char> >& input_blinding_factors, const std::vector<std::vector<unsigned char> >& output_blinding_factors, const std::vector<CPubKey>& output_pubkeys, CMutableTransaction& tx)
|
||||
void BlindOutputs(const std::vector<uint256 >& input_blinding_factors, const std::vector<uint256 >& output_blinding_factors, const std::vector<CPubKey>& output_pubkeys, CMutableTransaction& tx)
|
||||
{
|
||||
assert(tx.vout.size() == output_blinding_factors.size());
|
||||
assert(tx.vout.size() == output_pubkeys.size());
|
||||
|
|
@ -71,9 +70,9 @@ void BlindOutputs(const std::vector<std::vector<unsigned char> >& input_blinding
|
|||
|
||||
int nBlindsIn = 0;
|
||||
for (size_t nIn = 0; nIn < tx.vin.size(); nIn++) {
|
||||
if (input_blinding_factors[nIn].size() != 0) {
|
||||
if (input_blinding_factors[nIn] != uint256()) {
|
||||
assert(input_blinding_factors[nIn].size() == 32);
|
||||
blindptrs.push_back(&input_blinding_factors[nIn][0]);
|
||||
blindptrs.push_back(input_blinding_factors[nIn].begin());
|
||||
nBlindsIn++;
|
||||
}
|
||||
}
|
||||
|
|
@ -81,10 +80,9 @@ void BlindOutputs(const std::vector<std::vector<unsigned char> >& input_blinding
|
|||
int nBlindsOut = 0;
|
||||
int nToBlind = 0;
|
||||
for (size_t nOut = 0; nOut < tx.vout.size(); nOut++) {
|
||||
assert((output_blinding_factors[nOut].size() != 0) == !tx.vout[nOut].nValue.IsAmount());
|
||||
if (output_blinding_factors[nOut].size() != 0) {
|
||||
assert(output_blinding_factors[nOut].size() == 32);
|
||||
blindptrs.push_back(&output_blinding_factors[nOut][0]);
|
||||
assert((output_blinding_factors[nOut] != uint256()) == !tx.vout[nOut].nValue.IsAmount());
|
||||
if (output_blinding_factors[nOut] != uint256()) {
|
||||
blindptrs.push_back(output_blinding_factors[nOut].begin());
|
||||
nBlindsOut++;
|
||||
} else {
|
||||
if (output_pubkeys[nOut].IsValid()) {
|
||||
|
|
@ -98,7 +96,7 @@ void BlindOutputs(const std::vector<std::vector<unsigned char> >& input_blinding
|
|||
}
|
||||
|
||||
int nBlinded = 0;
|
||||
unsigned char blind[nToBlind][32];
|
||||
unsigned char blind[tx.vout.size()][32];
|
||||
|
||||
for (size_t nOut = 0; nOut < tx.vout.size(); nOut++) {
|
||||
if (tx.vout[nOut].nValue.IsAmount() && output_pubkeys[nOut].IsValid()) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
void ECC_Blinding_Start();
|
||||
void ECC_Blinding_Stop();
|
||||
|
||||
int UnblindOutput(const CKey& blinding_key, const CTxOut& txout, CAmount& amount_out, std::vector<unsigned char>& blinding_factor_out);
|
||||
void BlindOutputs(const std::vector<std::vector<unsigned char> >& input_blinding_factors, const std::vector<std::vector<unsigned char> >& output_blinding_factors, const std::vector<CPubKey>& output_pubkeys, CMutableTransaction& tx);
|
||||
bool UnblindOutput(const CKey& blinding_key, const CTxOut& txout, CAmount& amount_out, uint256& blinding_factor_out);
|
||||
void BlindOutputs(const std::vector<uint256>& input_blinding_factors, const std::vector<uint256>& output_blinding_factors, const std::vector<CPubKey>& output_pubkeys, CMutableTransaction& tx);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
|
|||
return QString();
|
||||
}
|
||||
}
|
||||
strAddress = CBitcoinAddress(newKey.GetID()).AddBlindingKey(wallet->blinding_pubkey).ToString();
|
||||
strAddress = CBitcoinAddress(newKey.GetID()).AddBlindingKey(wallet->GetBlindingPubKey(GetScriptForDestination(CTxDestination(newKey.GetID())))).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -397,3 +397,85 @@ Value dumpwallet(const Array& params, bool fHelp)
|
|||
file.close();
|
||||
return Value::null;
|
||||
}
|
||||
|
||||
Value dumpblindingkey(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 1 || params.size() > 1)
|
||||
throw runtime_error(
|
||||
"dumpblindingkey \"address\"\n"
|
||||
"\nDumps the private blinding key for a CT address in hex."
|
||||
"\nArguments:\n"
|
||||
"1. \"address\" (string, required) The CT address\n"
|
||||
);
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
if (!address.IsValid()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
}
|
||||
if (!address.IsBlinded()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not a CT address");
|
||||
}
|
||||
|
||||
CTxDestination dest = address.Get();
|
||||
CScript script = GetScriptForDestination(dest);
|
||||
CKey key;
|
||||
key = pwalletMain->GetBlindingKey(&script);
|
||||
if (key.IsValid()) {
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
if (pubkey == address.GetBlindingKey()) {
|
||||
return HexStr(key.begin(), key.end());
|
||||
}
|
||||
}
|
||||
// Just for backward compatibility
|
||||
key = pwalletMain->GetBlindingKey(NULL);
|
||||
if (key.IsValid()) {
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
if (pubkey == address.GetBlindingKey()) {
|
||||
return HexStr(key.begin(), key.end());
|
||||
}
|
||||
}
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Blinding key for address is unknown");
|
||||
}
|
||||
|
||||
Value importblindingkey(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 2 || params.size() > 2)
|
||||
throw runtime_error(
|
||||
"importblindingkey \"address\" \"blindinghex\"\n"
|
||||
"\nImports a private blinding key in hex for a CT address."
|
||||
"\nArguments:\n"
|
||||
"1. \"address\" (string, required) The CT address\n"
|
||||
"2. \"hexkey\" (string, required) The blinding key in hex\n"
|
||||
);
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
if (!address.IsValid()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
|
||||
}
|
||||
if (!address.IsBlinded()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not a CT address");
|
||||
}
|
||||
|
||||
if (!IsHex(params[1].get_str())) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid hexadecimal for key");
|
||||
}
|
||||
std::vector<unsigned char> keydata = ParseHex(params[1].get_str());
|
||||
if (keydata.size() != 32) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid hexadecimal key length");
|
||||
}
|
||||
|
||||
CKey key;
|
||||
key.Set(keydata.begin(), keydata.end(), true);
|
||||
if (!key.IsValid() || key.GetPubKey() != address.GetBlindingKey()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Address and key do not match");
|
||||
}
|
||||
|
||||
uint256 keyval;
|
||||
memcpy(keyval.begin(), &keydata[0], 32);
|
||||
if (!pwalletMain->AddSpecificBlindingKey(CScriptID(GetScriptForDestination(address.Get())), keyval)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Failed to import blinding key");
|
||||
}
|
||||
pwalletMain->MarkDirty();
|
||||
|
||||
return Value::null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,12 +196,13 @@ Value validateaddress(const Array& params, bool fHelp)
|
|||
}
|
||||
#ifdef ENABLE_WALLET
|
||||
isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
|
||||
if (address.IsBlinded() && address.GetBlindingKey() != pwalletMain->blinding_pubkey) {
|
||||
if (mine != ISMINE_NO && address.IsBlinded() && address.GetBlindingKey() != pwalletMain->GetBlindingPubKey(GetScriptForDestination(dest))) {
|
||||
// Note: this will fail to return ismine for deprecated static blinded addresses.
|
||||
mine = ISMINE_NO;
|
||||
}
|
||||
ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
|
||||
if (!address.IsBlinded() && mine != ISMINE_NO) {
|
||||
ret.push_back(Pair("confidential", address.AddBlindingKey(pwalletMain->blinding_pubkey).ToString()));
|
||||
ret.push_back(Pair("confidential", address.AddBlindingKey(pwalletMain->GetBlindingPubKey(GetScriptForDestination(dest))).ToString()));
|
||||
}
|
||||
if (mine != ISMINE_NO) {
|
||||
ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ Value listunspent(const Array& params, bool fHelp)
|
|||
if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
|
||||
CBitcoinAddress addr(address);
|
||||
if (out.tx->GetBlindingFactor(out.i).size() > 0) {
|
||||
addr.AddBlindingKey(pwalletMain->blinding_pubkey);
|
||||
addr.AddBlindingKey(out.tx->GetBlindingKey(out.i));
|
||||
}
|
||||
entry.push_back(Pair("address", addr.ToString()));
|
||||
if (pwalletMain->mapAddressBook.count(address))
|
||||
|
|
@ -588,8 +588,8 @@ Value rawblindrawtransaction(const Array& params, bool fHelp)
|
|||
|
||||
if (inputBlinds.size() != tx.vin.size()) throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter: one (potentially empty) input blind for each input must be provided"));
|
||||
|
||||
std::vector<std::vector<unsigned char> > input_blinds;
|
||||
std::vector<std::vector<unsigned char> > output_blinds;
|
||||
std::vector<uint256 > input_blinds;
|
||||
std::vector<uint256 > output_blinds;
|
||||
std::vector<CPubKey> output_pubkeys;
|
||||
for (size_t nOut = 0; nOut < tx.vout.size(); nOut++) {
|
||||
if (!tx.vout[nOut].nValue.IsAmount())
|
||||
|
|
@ -603,7 +603,7 @@ Value rawblindrawtransaction(const Array& params, bool fHelp)
|
|||
}
|
||||
output_pubkeys.push_back(pubkey);
|
||||
}
|
||||
output_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
output_blinds.push_back(uint256());
|
||||
}
|
||||
|
||||
BlindOutputs(input_blinds, output_blinds, output_pubkeys, tx);
|
||||
|
|
@ -649,8 +649,8 @@ Value blindrawtransaction(const Array& params, bool fHelp)
|
|||
|
||||
LOCK(pwalletMain->cs_wallet);
|
||||
|
||||
std::vector<std::vector<unsigned char> > input_blinds;
|
||||
std::vector<std::vector<unsigned char> > output_blinds;
|
||||
std::vector<uint256> input_blinds;
|
||||
std::vector<uint256> output_blinds;
|
||||
std::vector<CPubKey> output_pubkeys;
|
||||
for (size_t nIn = 0; nIn < tx.vin.size(); nIn++) {
|
||||
std::map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.find(tx.vin[nIn].prevout.hash);
|
||||
|
|
@ -665,7 +665,7 @@ Value blindrawtransaction(const Array& params, bool fHelp)
|
|||
|
||||
for (size_t nOut = 0; nOut < tx.vout.size(); nOut++) {
|
||||
if (!tx.vout[nOut].nValue.IsAmount()) {
|
||||
std::vector<unsigned char> blinding_factor;
|
||||
uint256 blinding_factor;
|
||||
CAmount amount;
|
||||
if (UnblindOutput(pwalletMain->blinding_key, tx.vout[nOut], amount, blinding_factor) != 0) {
|
||||
output_blinds.push_back(blinding_factor);
|
||||
|
|
@ -675,14 +675,14 @@ Value blindrawtransaction(const Array& params, bool fHelp)
|
|||
}
|
||||
} else if (tx.vout[nOut].nValue.vchNonceCommitment.size() == 0) {
|
||||
output_pubkeys.push_back(CPubKey());
|
||||
output_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
output_blinds.push_back(uint256());
|
||||
} else {
|
||||
CPubKey pubkey(tx.vout[nOut].nValue.vchNonceCommitment);
|
||||
if (!pubkey.IsValid()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter: invalid confidentiality public key given"));
|
||||
}
|
||||
output_pubkeys.push_back(pubkey);
|
||||
output_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
output_blinds.push_back(uint256());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -321,6 +321,7 @@ static const CRPCCommand vRPCCommands[] =
|
|||
{ "wallet", "backupwallet", &backupwallet, true, false, true },
|
||||
{ "wallet", "dumpprivkey", &dumpprivkey, true, false, true },
|
||||
{ "wallet", "dumpwallet", &dumpwallet, true, false, true },
|
||||
{ "wallet", "dumpblindingkey", &dumpblindingkey, true, false, true },
|
||||
{ "wallet", "encryptwallet", &encryptwallet, true, false, true },
|
||||
{ "wallet", "getaccountaddress", &getaccountaddress, true, false, true },
|
||||
{ "wallet", "getaccount", &getaccount, true, false, true },
|
||||
|
|
@ -336,6 +337,7 @@ static const CRPCCommand vRPCCommands[] =
|
|||
{ "wallet", "importprivkey", &importprivkey, true, false, true },
|
||||
{ "wallet", "importwallet", &importwallet, true, false, true },
|
||||
{ "wallet", "importaddress", &importaddress, true, false, true },
|
||||
{ "wallet", "importblindingkey", &importblindingkey, true, false, true },
|
||||
{ "wallet", "keypoolrefill", &keypoolrefill, true, false, true },
|
||||
{ "wallet", "listaccounts", &listaccounts, false, false, true },
|
||||
{ "wallet", "listaddressgroupings", &listaddressgroupings, false, false, true },
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@ extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool f
|
|||
extern json_spirit::Value importaddress(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value dumpblindingkey(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value importblindingkey(const json_spirit::Array& params, bool fHelp);
|
||||
|
||||
extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp
|
||||
extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp);
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ Value getnewaddress(const Array& params, bool fHelp)
|
|||
|
||||
pwalletMain->SetAddressBook(keyID, strAccount, "receive");
|
||||
|
||||
return CBitcoinAddress(keyID).AddBlindingKey(pwalletMain->blinding_pubkey).ToString();
|
||||
return CBitcoinAddress(keyID).AddBlindingKey(pwalletMain->GetBlindingPubKey(GetScriptForDestination(CTxDestination(keyID)))).ToString();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
|
|||
walletdb.WriteAccount(strAccount, account);
|
||||
}
|
||||
|
||||
return CBitcoinAddress(account.vchPubKey.GetID()).AddBlindingKey(pwalletMain->blinding_pubkey);
|
||||
return CBitcoinAddress(account.vchPubKey.GetID()).AddBlindingKey(pwalletMain->GetBlindingPubKey(GetScriptForDestination(account.vchPubKey.GetID())));
|
||||
}
|
||||
|
||||
Value getaccountaddress(const Array& params, bool fHelp)
|
||||
|
|
@ -205,7 +205,7 @@ Value getrawchangeaddress(const Array& params, bool fHelp)
|
|||
|
||||
CKeyID keyID = vchPubKey.GetID();
|
||||
|
||||
return CBitcoinAddress(keyID).AddBlindingKey(pwalletMain->blinding_pubkey).ToString();
|
||||
return CBitcoinAddress(keyID).AddBlindingKey(pwalletMain->GetBlindingPubKey(GetScriptForDestination(CTxDestination(keyID)))).ToString();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -300,9 +300,10 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
|
|||
|
||||
// Find all addresses that have the given account
|
||||
Array ret;
|
||||
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, pwalletMain->mapAddressBook)
|
||||
{
|
||||
const CBitcoinAddress& address = item.first;
|
||||
CBitcoinAddress address = item.first;
|
||||
address.AddBlindingKey(pwalletMain->GetBlindingPubKey(GetScriptForDestination(item.first)));
|
||||
const string& strName = item.second.name;
|
||||
if (strName == strAccount)
|
||||
ret.push_back(address.ToString());
|
||||
|
|
@ -426,7 +427,7 @@ Value listaddressgroupings(const Array& params, bool fHelp)
|
|||
{
|
||||
Array addressInfo;
|
||||
CBitcoinAddress addr(address);
|
||||
addr.AddBlindingKey(pwalletMain->blinding_pubkey);
|
||||
addr.AddBlindingKey(pwalletMain->GetBlindingPubKey(GetScriptForDestination(addr.Get())));
|
||||
addressInfo.push_back(addr.ToString());
|
||||
addressInfo.push_back(ValueFromAmount(balances[address]));
|
||||
{
|
||||
|
|
@ -521,8 +522,6 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
|
|||
CScript scriptPubKey = GetScriptForDestination(address.Get());
|
||||
if (!IsMine(*pwalletMain,scriptPubKey))
|
||||
return (double)0.0;
|
||||
if (address.IsBlinded() && address.GetBlindingKey() != pwalletMain->blinding_pubkey)
|
||||
return (double)0.0;
|
||||
|
||||
// Minimum confirmations
|
||||
int nMinDepth = 1;
|
||||
|
|
@ -976,6 +975,7 @@ Value addmultisigaddress(const Array& params, bool fHelp)
|
|||
|
||||
struct tallyitem
|
||||
{
|
||||
CBitcoinAddress address;
|
||||
CAmount nAmount;
|
||||
int nConf;
|
||||
vector<uint256> txids;
|
||||
|
|
@ -1006,7 +1006,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
|
|||
filter = filter | ISMINE_WATCH_ONLY;
|
||||
|
||||
// Tally
|
||||
map<CBitcoinAddress, tallyitem> mapTally;
|
||||
map<CTxDestination, tallyitem> mapTally;
|
||||
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
|
||||
{
|
||||
const CWalletTx& wtx = (*it).second;
|
||||
|
|
@ -1028,7 +1028,12 @@ Value ListReceived(const Array& params, bool fByAccounts)
|
|||
if(!(mine & filter))
|
||||
continue;
|
||||
|
||||
CBitcoinAddress bitcoinaddress(address);
|
||||
if (!wtx.vout[i].nValue.IsAmount()) {
|
||||
bitcoinaddress.AddBlindingKey(wtx.GetBlindingKey(i));
|
||||
}
|
||||
tallyitem& item = mapTally[address];
|
||||
item.address = bitcoinaddress;
|
||||
item.nAmount += wtx.GetValueOut(i);
|
||||
item.nConf = min(item.nConf, nDepth);
|
||||
item.txids.push_back(wtx.GetHash());
|
||||
|
|
@ -1040,19 +1045,21 @@ Value ListReceived(const Array& params, bool fByAccounts)
|
|||
// Reply
|
||||
Array ret;
|
||||
map<string, tallyitem> mapAccountTally;
|
||||
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, pwalletMain->mapAddressBook)
|
||||
{
|
||||
const CBitcoinAddress& address = item.first;
|
||||
const CTxDestination& address = item.first;
|
||||
const string& strAccount = item.second.name;
|
||||
map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
|
||||
map<CTxDestination, tallyitem>::iterator it = mapTally.find(address);
|
||||
if (it == mapTally.end() && !fIncludeEmpty)
|
||||
continue;
|
||||
|
||||
CBitcoinAddress fulladdress = address;
|
||||
CAmount nAmount = 0;
|
||||
int nConf = std::numeric_limits<int>::max();
|
||||
bool fIsWatchonly = false;
|
||||
if (it != mapTally.end())
|
||||
{
|
||||
fulladdress = (*it).second.address;
|
||||
nAmount = (*it).second.nAmount;
|
||||
nConf = (*it).second.nConf;
|
||||
fIsWatchonly = (*it).second.fIsWatchonly;
|
||||
|
|
@ -1070,7 +1077,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
|
|||
Object obj;
|
||||
if(fIsWatchonly)
|
||||
obj.push_back(Pair("involvesWatchonly", true));
|
||||
obj.push_back(Pair("address", address.ToString()));
|
||||
obj.push_back(Pair("address", fulladdress.ToString()));
|
||||
obj.push_back(Pair("account", strAccount));
|
||||
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
|
||||
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ BOOST_AUTO_TEST_CASE(naive_blinding_test)
|
|||
CPubKey pubkey1 = key1.GetPubKey();
|
||||
CPubKey pubkey2 = key2.GetPubKey();
|
||||
|
||||
std::vector<unsigned char> blind3, blind4;
|
||||
uint256 blind3, blind4;
|
||||
|
||||
{
|
||||
CCoinsModifier tx1 = cache.ModifyCoins(uint256(1));
|
||||
|
|
@ -52,12 +52,12 @@ BOOST_AUTO_TEST_CASE(naive_blinding_test)
|
|||
tx3.nTxFee = 22;
|
||||
BOOST_CHECK(cache.VerifyAmounts(tx3));
|
||||
|
||||
std::vector<std::vector<unsigned char> > input_blinds;
|
||||
std::vector<std::vector<unsigned char> > output_blinds;
|
||||
std::vector<uint256> input_blinds;
|
||||
std::vector<uint256> output_blinds;
|
||||
std::vector<CPubKey> output_pubkeys;
|
||||
input_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
input_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
output_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
input_blinds.push_back(uint256());
|
||||
input_blinds.push_back(uint256());
|
||||
output_blinds.push_back(uint256());
|
||||
output_pubkeys.push_back(pubkey1);
|
||||
BlindOutputs(input_blinds, output_blinds, output_pubkeys, tx3);
|
||||
BOOST_CHECK(!tx3.vout[0].nValue.IsAmount());
|
||||
|
|
@ -91,14 +91,14 @@ BOOST_AUTO_TEST_CASE(naive_blinding_test)
|
|||
tx4.nTxFee = 100 + 111 - 30 - 40 - 50;
|
||||
BOOST_CHECK(cache.VerifyAmounts(tx4));
|
||||
|
||||
std::vector<std::vector<unsigned char> > input_blinds;
|
||||
std::vector<std::vector<unsigned char> > output_blinds;
|
||||
std::vector<uint256> input_blinds;
|
||||
std::vector<uint256> output_blinds;
|
||||
std::vector<CPubKey> output_pubkeys;
|
||||
input_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
input_blinds.push_back(uint256());
|
||||
input_blinds.push_back(blind3);
|
||||
output_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
output_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
output_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
output_blinds.push_back(uint256());
|
||||
output_blinds.push_back(uint256());
|
||||
output_blinds.push_back(uint256());
|
||||
output_pubkeys.push_back(pubkey2);
|
||||
output_pubkeys.push_back(CPubKey());
|
||||
output_pubkeys.push_back(pubkey2);
|
||||
|
|
|
|||
145
src/wallet.cpp
145
src/wallet.cpp
|
|
@ -8,6 +8,7 @@
|
|||
#include "base58.h"
|
||||
#include "checkpoints.h"
|
||||
#include "coincontrol.h"
|
||||
#include "crypto/hmac_sha256.h"
|
||||
#include "net.h"
|
||||
#include "script/script.h"
|
||||
#include "script/sign.h"
|
||||
|
|
@ -895,7 +896,7 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
|
|||
COutputEntry output = {address, GetValueOut(i), (int)i, CPubKey()};
|
||||
|
||||
if (!txout.nValue.IsAmount() && GetValueOut(i) > 0) {
|
||||
output.confidentiality_pubkey = pwallet->blinding_pubkey;
|
||||
output.confidentiality_pubkey = GetBlindingKey(i);
|
||||
}
|
||||
|
||||
// If we are debited by the transaction, add the output as a "sent" entry
|
||||
|
|
@ -1614,7 +1615,7 @@ bool CWallet::CreateTransaction(const vector<CSend>& vecSend, const vector<CTxIn
|
|||
int pos = GetRandInt(txNew.vout.size()+1);
|
||||
vector<CTxOut>::iterator position = txNew.vout.begin()+pos;
|
||||
txNew.vout.insert(position, newTxOut);
|
||||
output_pubkeys.insert(output_pubkeys.begin() + pos, blinding_pubkey);
|
||||
output_pubkeys.insert(output_pubkeys.begin() + pos, GetBlindingPubKey(scriptChange));
|
||||
nValueOut += nChange;
|
||||
fBlindedOuts = true;
|
||||
}
|
||||
|
|
@ -1625,7 +1626,7 @@ bool CWallet::CreateTransaction(const vector<CSend>& vecSend, const vector<CTxIn
|
|||
if (fBlindedIns && !fBlindedOuts) {
|
||||
CTxOut newTxOut(0, CScript() << OP_RETURN);
|
||||
txNew.vout.push_back(newTxOut);
|
||||
output_pubkeys.push_back(blinding_pubkey);
|
||||
output_pubkeys.push_back(GetBlindingPubKey(newTxOut.scriptPubKey));
|
||||
fBlindedOuts = true;
|
||||
}
|
||||
// Fill vin
|
||||
|
|
@ -1636,14 +1637,14 @@ bool CWallet::CreateTransaction(const vector<CSend>& vecSend, const vector<CTxIn
|
|||
LogPrintf("Created transaction (before blinding): %s", CTransaction(txNew).ToString());
|
||||
|
||||
// Create blinded outputs
|
||||
std::vector<std::vector<unsigned char> > input_blinds;
|
||||
std::vector<std::vector<unsigned char> > output_blinds;
|
||||
std::vector<uint256> input_blinds;
|
||||
std::vector<uint256> output_blinds;
|
||||
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) {
|
||||
std::vector<unsigned char> blind =coin.first->GetBlindingFactor(coin.second);
|
||||
uint256 blind = coin.first->GetBlindingFactor(coin.second);
|
||||
input_blinds.push_back(blind);
|
||||
}
|
||||
for (size_t nOut = 0; nOut < txNew.vout.size(); nOut++) {
|
||||
output_blinds.push_back(std::vector<unsigned char>(0, 0));
|
||||
output_blinds.push_back(uint256());
|
||||
}
|
||||
if (fBlindedIns && !fBlindedOuts) {
|
||||
strFailReason = _("Confidential inputs without confidential outputs");
|
||||
|
|
@ -2528,3 +2529,133 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee)
|
|||
return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectInsaneFee);
|
||||
}
|
||||
|
||||
CKey CWallet::GetBlindingKey(const CScript* script) const
|
||||
{
|
||||
CKey key;
|
||||
|
||||
if (script != NULL) {
|
||||
std::map<CScriptID, uint256>::const_iterator it = mapSpecificBlindingKeys.find(CScriptID(*script));
|
||||
if (it != mapSpecificBlindingKeys.end()) {
|
||||
key.Set(it->second.begin(), it->second.end(), true);
|
||||
if (key.IsValid()) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (script != NULL && blinding_derivation_key != 0) {
|
||||
unsigned char vch[32];
|
||||
CHMAC_SHA256(blinding_derivation_key.begin(), blinding_derivation_key.size()).Write(&((*script)[0]), script->size()).Finalize(vch);
|
||||
key.Set(&vch[0], &vch[32], true);
|
||||
if (key.IsValid()) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
if (script == NULL && blinding_key.IsValid()) {
|
||||
return blinding_key;
|
||||
}
|
||||
|
||||
return CKey();
|
||||
}
|
||||
|
||||
CPubKey CWallet::GetBlindingPubKey(const CScript& script) const
|
||||
{
|
||||
CKey key = GetBlindingKey(&script);
|
||||
if (key.IsValid()) {
|
||||
return key.GetPubKey();
|
||||
}
|
||||
|
||||
return CPubKey();
|
||||
}
|
||||
|
||||
bool CWallet::LoadSpecificBlindingKey(const CScriptID& scriptid, const uint256& key)
|
||||
{
|
||||
AssertLockHeld(cs_wallet); // mapSpecificBlindingKeys
|
||||
mapSpecificBlindingKeys[scriptid] = key;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::AddSpecificBlindingKey(const CScriptID& scriptid, const uint256& key)
|
||||
{
|
||||
AssertLockHeld(cs_wallet); // mapSpecificBlindingKeys
|
||||
if (!LoadSpecificBlindingKey(scriptid, key))
|
||||
return false;
|
||||
|
||||
if (!fFileBacked)
|
||||
return true;
|
||||
return CWalletDB(strWalletFile).WriteSpecificBlindingKey(scriptid, key);
|
||||
}
|
||||
|
||||
void CWallet::ComputeBlindingData(const CTxOut& output, CAmount& amount, CPubKey& pubkey, uint256& blindingfactor) const
|
||||
{
|
||||
if (output.nValue.IsAmount()) {
|
||||
amount = output.nValue.GetAmount();
|
||||
pubkey = CPubKey();
|
||||
blindingfactor = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
CKey blinding_key;
|
||||
if ((blinding_key = GetBlindingKey(&output.scriptPubKey)).IsValid()) {
|
||||
// For outputs using derived blinding.
|
||||
if (UnblindOutput(blinding_key, output, amount, blindingfactor)) {
|
||||
pubkey = blinding_key.GetPubKey();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((blinding_key = GetBlindingKey(NULL)).IsValid()) {
|
||||
// For outputs using deprecated static blinding.
|
||||
if (UnblindOutput(blinding_key, output, amount, blindingfactor)) {
|
||||
pubkey = blinding_key.GetPubKey();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
amount = -1;
|
||||
pubkey = CPubKey();
|
||||
blindingfactor = 0;
|
||||
}
|
||||
|
||||
void CWalletTx::GetBlindingData(unsigned int nOut, CAmount* pamountOut, CPubKey* ppubkeyOut, uint256* pblindingfactorOut) const
|
||||
{
|
||||
// Blinding data is cached in a serialized record mapWallet["blindingdata"].
|
||||
// It contains a concatenation byte vectors, 74 bytes per txout.
|
||||
// Each consists of:
|
||||
// * 1 byte boolean marker (has the output been computed)?
|
||||
// * 8 bytes amount (-1 if unknown)
|
||||
// * 32 bytes blinding factor
|
||||
// * 33 bytes blinding pubkey (ECDH pubkey of the destination)
|
||||
// This is really ugly, and should use CDataStream serialization instead.
|
||||
|
||||
assert(nOut < vout.size());
|
||||
if (mapValue["blindingdata"].size() < (nOut + 1) * 74) {
|
||||
mapValue["blindingdata"].resize(vout.size() * 74);
|
||||
}
|
||||
|
||||
unsigned char* it = (unsigned char*)(&mapValue["blindingdata"][0]) + 74 * nOut;
|
||||
|
||||
CAmount amount = -1;
|
||||
CPubKey pubkey;
|
||||
uint256 blindingfactor;
|
||||
|
||||
if (*it == 1) {
|
||||
memcpy(&amount, &*(it + 1), 8);
|
||||
memcpy(blindingfactor.begin(), &*(it + 9), 32);
|
||||
pubkey.Set(it + 41, it + 74);
|
||||
} else {
|
||||
pwallet->ComputeBlindingData(vout[nOut], amount, pubkey, blindingfactor);
|
||||
*it = 1;
|
||||
memcpy(&*(it + 1), &amount, 8);
|
||||
memcpy(&*(it + 9), blindingfactor.begin(), 32);
|
||||
if (pubkey.IsValid() && pubkey.size() == 33) {
|
||||
memcpy(&*(it + 41), pubkey.begin(), 33);
|
||||
} else {
|
||||
memset(&*(it + 41), 0, 33);
|
||||
}
|
||||
}
|
||||
|
||||
if (pamountOut) *pamountOut = amount;
|
||||
if (ppubkeyOut) *ppubkeyOut = pubkey;
|
||||
if (pblindingfactorOut) *pblindingfactorOut = blindingfactor;
|
||||
}
|
||||
|
|
|
|||
62
src/wallet.h
62
src/wallet.h
|
|
@ -161,6 +161,7 @@ public:
|
|||
|
||||
std::set<int64_t> setKeyPool;
|
||||
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
|
||||
std::map<CScriptID, uint256> mapSpecificBlindingKeys;
|
||||
|
||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||
MasterKeyMap mapMasterKeys;
|
||||
|
|
@ -196,9 +197,8 @@ public:
|
|||
nNextResend = 0;
|
||||
nLastResend = 0;
|
||||
nTimeFirstKey = 0;
|
||||
unsigned char static_blinding_key[32] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32};
|
||||
blinding_key.Set(&static_blinding_key[0], &static_blinding_key[32], true);
|
||||
blinding_pubkey = blinding_key.GetPubKey();
|
||||
blinding_key = CKey();
|
||||
blinding_derivation_key = uint256();
|
||||
}
|
||||
|
||||
std::map<uint256, CWalletTx> mapWallet;
|
||||
|
|
@ -214,8 +214,12 @@ public:
|
|||
|
||||
int64_t nTimeFirstKey;
|
||||
|
||||
//! The actual blinding key is computed as HMAC-SHA256(key=blinding_derivation_key, msg=scriptPubKey).
|
||||
//! There can be exceptions in mapSpecificBlindingKeys.
|
||||
uint256 blinding_derivation_key;
|
||||
|
||||
//! Only for backward compatibility with older wallets (superseded by blinding_derivation_key).
|
||||
CKey blinding_key;
|
||||
CPubKey blinding_pubkey;
|
||||
|
||||
const CWalletTx* GetWalletTx(const uint256& hash) const;
|
||||
|
||||
|
|
@ -244,6 +248,10 @@ public:
|
|||
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
|
||||
//! Load metadata (used by LoadWallet)
|
||||
bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata);
|
||||
//! Adds a script-specific blinding key to the wallet, and saves it to disk.
|
||||
bool AddSpecificBlindingKey(const CScriptID& scriptid, const uint256& key);
|
||||
//! Adds a script-specific blinding key to the wallet without saving it to disk (used by LoadWallet)
|
||||
bool LoadSpecificBlindingKey(const CScriptID& scriptid, const uint256& key);
|
||||
|
||||
bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
|
||||
|
||||
|
|
@ -427,6 +435,12 @@ public:
|
|||
|
||||
/** Watch-only address added */
|
||||
boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged;
|
||||
|
||||
//! script == NULL gives the backward compatible blinding key
|
||||
CKey GetBlindingKey(const CScript* script) const;
|
||||
CPubKey GetBlindingPubKey(const CScript& script) const;
|
||||
|
||||
void ComputeBlindingData(const CTxOut& output, CAmount& amount, CPubKey& pubkey, uint256& blindingfactor) const;
|
||||
};
|
||||
|
||||
/** A key allocated from the key pool. */
|
||||
|
|
@ -552,7 +566,7 @@ private:
|
|||
const CWallet* pwallet;
|
||||
|
||||
public:
|
||||
mapValue_t mapValue;
|
||||
mutable mapValue_t mapValue;
|
||||
std::vector<std::pair<std::string, std::string> > vOrderForm;
|
||||
unsigned int fTimeReceivedIsTxTime;
|
||||
unsigned int nTimeReceived; //! time received by this node
|
||||
|
|
@ -561,8 +575,10 @@ public:
|
|||
std::string strFromAccount;
|
||||
int64_t nOrderPos; //! position in ordered transaction list
|
||||
|
||||
mutable std::vector<std::vector<unsigned char> > vBlindingFactors;
|
||||
// For each output
|
||||
mutable std::vector<uint256> vBlindingFactors;
|
||||
mutable std::vector<CAmount> vAmountsOut;
|
||||
mutable std::vector<CPubKey> vBlindingKeys;
|
||||
|
||||
// memory only
|
||||
mutable bool fDebitCached;
|
||||
|
|
@ -662,8 +678,6 @@ public:
|
|||
READWRITE(nTimeReceived);
|
||||
READWRITE(fFromMe);
|
||||
READWRITE(fSpent);
|
||||
READWRITE(vBlindingFactors);
|
||||
READWRITE(vAmountsOut);
|
||||
|
||||
if (ser_action.ForRead())
|
||||
{
|
||||
|
|
@ -930,31 +944,29 @@ public:
|
|||
|
||||
std::set<uint256> GetConflicts() const;
|
||||
|
||||
|
||||
private:
|
||||
void FillValuesAndBlindingFactors() const {
|
||||
if (!vAmountsOut.size()) {
|
||||
vAmountsOut.resize(vout.size());
|
||||
vBlindingFactors.resize(vout.size());
|
||||
for (unsigned int i = 0; i < vout.size(); i++) {
|
||||
std::vector<unsigned char> nonce(32, 0);
|
||||
int res = UnblindOutput(pwallet->blinding_key, vout[i], vAmountsOut[i], vBlindingFactors[i]);
|
||||
if (!res)
|
||||
vAmountsOut[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
void GetBlindingData(unsigned int nOut, CAmount* pamountOut, CPubKey* ppubkeyOut, uint256* pblindingfactorOut) const;
|
||||
|
||||
public:
|
||||
//! Returns either the value out (if it is to us) or 0
|
||||
CAmount GetValueOut(unsigned int nOut) const {
|
||||
FillValuesAndBlindingFactors();
|
||||
return vAmountsOut[nOut];
|
||||
CAmount ret;
|
||||
GetBlindingData(nOut, &ret, NULL, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//! Returns either the blinding factor (if it is to us) or 0
|
||||
std::vector<unsigned char> GetBlindingFactor(unsigned int nOut) const {
|
||||
FillValuesAndBlindingFactors();
|
||||
return vBlindingFactors[nOut];
|
||||
uint256 GetBlindingFactor(unsigned int nOut) const {
|
||||
uint256 ret;
|
||||
GetBlindingData(nOut, NULL, NULL, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CPubKey GetBlindingKey(unsigned int nOut) const {
|
||||
CPubKey ret;
|
||||
GetBlindingData(nOut, NULL, &ret, NULL);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -193,9 +193,14 @@ bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
|
|||
return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteBlindingKey(const CKey& privKey)
|
||||
bool CWalletDB::WriteSpecificBlindingKey(const CScriptID& scriptid, const uint256& key)
|
||||
{
|
||||
return Write(std::string("blindingkey"), std::vector<unsigned char>(privKey.begin(), privKey.end()));
|
||||
return Write(make_pair(std::string("specificblindingkey"), scriptid), key);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteBlindingDerivationKey(const uint256& key)
|
||||
{
|
||||
return Write(std::string("blindingderivationkey"), key);
|
||||
}
|
||||
|
||||
CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount)
|
||||
|
|
@ -595,14 +600,34 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
/* Only for backward compatibility with older wallets. */
|
||||
else if (strType == "blindingkey")
|
||||
{
|
||||
assert(!pwallet->blinding_key.IsValid());
|
||||
std::vector<unsigned char> vchBlindingKey;
|
||||
ssValue >> vchBlindingKey;
|
||||
pwallet->blinding_key.Set(vchBlindingKey.begin(), vchBlindingKey.end(), true);
|
||||
if (pwallet->blinding_key.IsValid()) {
|
||||
pwallet->blinding_pubkey = pwallet->blinding_key.GetPubKey();
|
||||
if (!pwallet->blinding_key.IsValid()) {
|
||||
strErr = "Error reading wallet blinding key";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (strType == "blindingderivationkey")
|
||||
{
|
||||
assert(pwallet->blinding_derivation_key == 0);
|
||||
uint256 key;
|
||||
ssValue >> key;
|
||||
pwallet->blinding_derivation_key = key;
|
||||
}
|
||||
else if (strType == "specificblindingkey")
|
||||
{
|
||||
CScriptID scriptid;
|
||||
ssKey >> scriptid;
|
||||
uint256 key;
|
||||
ssValue >> key;
|
||||
if (!pwallet->LoadSpecificBlindingKey(scriptid, key)) {
|
||||
strErr = "Error reading wallet database: LoadSpecificBlindingKey failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (...)
|
||||
|
|
@ -716,10 +741,15 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
|||
if (wss.fAnyUnordered)
|
||||
result = ReorderTransactions(pwallet);
|
||||
|
||||
if (!pwallet->blinding_key.IsValid()) {
|
||||
pwallet->blinding_key.MakeNewKey(true);
|
||||
pwallet->blinding_pubkey = pwallet->blinding_key.GetPubKey();
|
||||
WriteBlindingKey(pwallet->blinding_key);
|
||||
if (result == DB_LOAD_OK && pwallet->blinding_derivation_key == 0) {
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
uint256 keybin;
|
||||
memcpy(keybin.begin(), key.begin(), key.size());
|
||||
pwallet->blinding_derivation_key = keybin;
|
||||
if (!WriteBlindingDerivationKey(pwallet->blinding_derivation_key)) {
|
||||
result = DB_LOAD_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -123,7 +123,8 @@ public:
|
|||
CAmount GetAccountCreditDebit(const std::string& strAccount);
|
||||
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
|
||||
|
||||
bool WriteBlindingKey(const CKey& privKey);
|
||||
bool WriteSpecificBlindingKey(const CScriptID& scriptid, const uint256& key);
|
||||
bool WriteBlindingDerivationKey(const uint256& key);
|
||||
|
||||
DBErrors ReorderTransactions(CWallet* pwallet);
|
||||
DBErrors LoadWallet(CWallet* pwallet);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue