diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2018-08-13 11:54:07 +0200 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2018-08-13 12:07:20 +0200 |
commit | 2115cba9c60504ed1c0af8a56c5d90b5fd415497 (patch) | |
tree | 6b89e62e0e6e861898a8ffed77e3f74ff8627e85 /src/wallet | |
parent | 13d51a2b615b1ee3da083b87e2c99984426d278a (diff) | |
parent | e306be742932d4ea5aca0ea4768e54b2fc3dc6a0 (diff) |
Merge #13666: Always create signatures with Low R values
e306be742932d4ea5aca0ea4768e54b2fc3dc6a0 Use 72 byte dummy signatures when watching only inputs may be used (Andrew Chow)
48b1473c898129a99212e2db36c61cf93625ea17 Use 71 byte signature for DUMMY_SIGNATURE_CREATOR (Andrew Chow)
18dfea0dd082af18dfb02981b7ee1cd44d514388 Always create 70 byte signatures with low R values (Andrew Chow)
Pull request description:
When creating signatures for transactions, always make one which has a 32 byte or smaller R and 32 byte or smaller S value. This results in signatures that are always less than 71 bytes (32 byte R + 32 byte S + 6 bytes DER + 1 byte sighash) with low R values. In most cases, the signature will be 71 bytes.
Because R is not mutable in the same way that S is, a low R value can only be found by trying different nonces. RFC 6979 for deterministic nonce generation has the option to specify additional entropy, so we simply use that and add a uin32_t counter which we increment in order to try different nonces. Nonces are sill deterministically generated as the nonce used will the be the first one where the counter results in a nonce that results in a low R value. Because different nonces need to be tried, time to produce a signature does increase. On average, it takes twice as long to make a signature as two signatures need to be created, on average, to find one with a low R.
Having a fixed size signature makes size calculations easier and also saves half a byte of transaction size, on average.
DUMMY_SIGNATURE_CREATOR has been modified to produce 71 byte dummy signatures instead of 72 byte signatures.
Tree-SHA512: 3cd791505126ce92da7c631856a97ba0b59e87d9c132feff6e0eef1dc47768e81fbb38bfbe970371bedf9714b7f61a13a5fe9f30f962c81734092a4d19a4ef33
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/wallet.cpp | 33 | ||||
-rw-r--r-- | src/wallet/wallet.h | 29 |
2 files changed, 32 insertions, 30 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 73d2b205c2..5a7fdf9a85 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1542,30 +1542,29 @@ int64_t CWalletTx::GetTxTime() const return n ? n : nTimeReceived; } -// Helper for producing a max-sized low-S signature (eg 72 bytes) -bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout) const +// Helper for producing a max-sized low-S low-R signature (eg 71 bytes) +// or a max-sized low-S signature (e.g. 72 bytes) if use_max_sig is true +bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig) const { // Fill in dummy signatures for fee calculation. const CScript& scriptPubKey = txout.scriptPubKey; SignatureData sigdata; - if (!ProduceSignature(*this, DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigdata)) - { + if (!ProduceSignature(*this, use_max_sig ? DUMMY_MAXIMUM_SIGNATURE_CREATOR : DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigdata)) { return false; - } else { - UpdateInput(tx_in, sigdata); } + UpdateInput(tx_in, sigdata); return true; } -// Helper for producing a bunch of max-sized low-S signatures (eg 72 bytes) -bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts) const +// Helper for producing a bunch of max-sized low-S low-R signatures (eg 71 bytes) +bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, bool use_max_sig) const { // Fill in dummy signatures for fee calculation. int nIn = 0; for (const auto& txout : txouts) { - if (!DummySignInput(txNew.vin[nIn], txout)) { + if (!DummySignInput(txNew.vin[nIn], txout, use_max_sig)) { return false; } @@ -1574,7 +1573,7 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> return true; } -int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet) +int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig) { std::vector<CTxOut> txouts; // Look up the inputs. We should have already checked that this transaction @@ -1588,14 +1587,14 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wall assert(input.prevout.n < mi->second.tx->vout.size()); txouts.emplace_back(mi->second.tx->vout[input.prevout.n]); } - return CalculateMaximumSignedTxSize(tx, wallet, txouts); + return CalculateMaximumSignedTxSize(tx, wallet, txouts, use_max_sig); } // txouts needs to be in the order of tx.vin -int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts) +int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig) { CMutableTransaction txNew(tx); - if (!wallet->DummySignTx(txNew, txouts)) { + if (!wallet->DummySignTx(txNew, txouts, use_max_sig)) { // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) // implies that we can sign for every input. return -1; @@ -1603,11 +1602,11 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wall return GetVirtualTransactionSize(txNew); } -int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet) +int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, bool use_max_sig) { CMutableTransaction txn; txn.vin.push_back(CTxIn(COutPoint())); - if (!wallet->DummySignInput(txn.vin[0], txout)) { + if (!wallet->DummySignInput(txn.vin[0], txout, use_max_sig)) { // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) // implies that we can sign for every input. return -1; @@ -2334,7 +2333,7 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const bool solvable = IsSolvable(*this, pcoin->tx->vout[i].scriptPubKey); bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable)); - vCoins.push_back(COutput(pcoin, i, nDepth, spendable, solvable, safeTx)); + vCoins.push_back(COutput(pcoin, i, nDepth, spendable, solvable, safeTx, (coinControl && coinControl->fAllowWatchOnly))); // Checks the sum amount of all UTXO's. if (nMinimumSumAmount != MAX_MONEY) { @@ -2889,7 +2888,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac txNew.vin.push_back(CTxIn(coin.outpoint,CScript())); } - nBytes = CalculateMaximumSignedTxSize(txNew, this); + nBytes = CalculateMaximumSignedTxSize(txNew, this, coin_control.fAllowWatchOnly); if (nBytes < 0) { strFailReason = _("Signing transaction failed"); return false; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index ab3e38e807..57b22c0e49 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -276,7 +276,7 @@ public: }; //Get the marginal bytes of spending the specified output -int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet); +int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet, bool use_max_sig = false); /** * A transaction with a bunch of additional info that only the owner cares about. @@ -461,9 +461,9 @@ public: CAmount GetChange() const; // Get the marginal bytes if spending the specified output from this transaction - int GetSpendSize(unsigned int out) const + int GetSpendSize(unsigned int out, bool use_max_sig = false) const { - return CalculateMaximumSignedInputSize(tx->vout[out], pwallet); + return CalculateMaximumSignedInputSize(tx->vout[out], pwallet, use_max_sig); } void GetAmounts(std::list<COutputEntry>& listReceived, @@ -507,6 +507,9 @@ public: /** Whether we know how to spend this output, ignoring the lack of keys */ bool fSolvable; + /** Whether to use the maximum sized, 72 byte signature when calculating the size of the input spend. This should only be set when watch-only outputs are allowed */ + bool use_max_sig; + /** * Whether this output is considered safe to spend. Unconfirmed transactions * from outside keys and unconfirmed replacement transactions are considered @@ -514,13 +517,13 @@ public: */ bool fSafe; - COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn) + COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn, bool use_max_sig_in = false) { - tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn; nInputBytes = -1; + tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn; nInputBytes = -1; use_max_sig = use_max_sig_in; // If known and signable by the given wallet, compute nInputBytes // Failure will keep this value -1 if (fSpendable && tx) { - nInputBytes = tx->GetSpendSize(i); + nInputBytes = tx->GetSpendSize(i, use_max_sig); } } @@ -976,14 +979,14 @@ public: void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries); bool AddAccountingEntry(const CAccountingEntry&); bool AddAccountingEntry(const CAccountingEntry&, WalletBatch *batch); - bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts) const + bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, bool use_max_sig = false) const { std::vector<CTxOut> v_txouts(txouts.size()); std::copy(txouts.begin(), txouts.end(), v_txouts.begin()); - return DummySignTx(txNew, v_txouts); + return DummySignTx(txNew, v_txouts, use_max_sig); } - bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts) const; - bool DummySignInput(CTxIn &tx_in, const CTxOut &txout) const; + bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, bool use_max_sig = false) const; + bool DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig = false) const; CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE}; unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET}; @@ -1308,9 +1311,9 @@ public: }; // Calculate the size of the transaction assuming all signatures are max size -// Use DummySignatureCreator, which inserts 72 byte signatures everywhere. +// Use DummySignatureCreator, which inserts 71 byte signatures everywhere. // NOTE: this requires that all inputs must be in mapWallet (eg the tx should // be IsAllFromMe). -int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet); -int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts); +int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig = false); +int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig = false); #endif // BITCOIN_WALLET_WALLET_H |