mirror of
https://github.com/wownero/wownero.git
synced 2026-10-17 07:31:35 +02:00
wallet2: fix infinite loop in estimate_tx_size_and_weight on large n_outputs
estimate_rct_tx_size() and estimate_tx_weight() compute the Bulletproof padded output count with `while ((1<<log_padded_outputs) < n_outputs)`, shifting a signed int. For n_outputs > 2^30 this reaches `1 << 31` (signed overflow, UB), and once the shift count exceeds the int width the value cycles and never reaches n_outputs, so the loop never terminates. estimate_tx_size_and_weight() accepts n_outputs up to INT_MAX (only negative is rejected), so a single wallet-rpc call spins the handling thread forever. Shift an unsigned 64-bit one and compare in uint64_t at all three shift sites, and accumulate the estimated size in size_t (cast the per-input and per-output terms) so the size arithmetic cannot overflow for large counts.
This commit is contained in:
+13
-13
@@ -806,10 +806,10 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
|
||||
size += 1 + 6;
|
||||
|
||||
// vin
|
||||
size += n_inputs * (1+6+(mixin+1)*2+32);
|
||||
size += (size_t)n_inputs * (1+6+((size_t)mixin+1)*2+32);
|
||||
|
||||
// vout
|
||||
size += n_outputs * (6+32);
|
||||
size += (size_t)n_outputs * (6+32);
|
||||
|
||||
// extra
|
||||
size += extra_size;
|
||||
@@ -823,31 +823,31 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
|
||||
if (bulletproof || bulletproof_plus)
|
||||
{
|
||||
size_t log_padded_outputs = 0;
|
||||
while ((1<<log_padded_outputs) < n_outputs)
|
||||
while ((UINT64_C(1) << log_padded_outputs) < (uint64_t)n_outputs)
|
||||
++log_padded_outputs;
|
||||
size += (2 * (6 + log_padded_outputs) + (bulletproof_plus ? 6 : (4 + 5))) * 32 + 3;
|
||||
}
|
||||
else
|
||||
size += (2*64*32+32+64*32) * n_outputs;
|
||||
size += (size_t)(2*64*32+32+64*32) * n_outputs;
|
||||
|
||||
// MGs/CLSAGs
|
||||
if (clsag)
|
||||
size += n_inputs * (32 * (mixin+1) + 64);
|
||||
size += (size_t)n_inputs * (32 * ((size_t)mixin+1) + 64);
|
||||
else
|
||||
size += n_inputs * (64 * (mixin+1) + 32);
|
||||
size += (size_t)n_inputs * (64 * ((size_t)mixin+1) + 32);
|
||||
|
||||
if (use_view_tags)
|
||||
size += n_outputs * sizeof(crypto::view_tag);
|
||||
size += (size_t)n_outputs * sizeof(crypto::view_tag);
|
||||
|
||||
// mixRing - not serialized, can be reconstructed
|
||||
/* size += 2 * 32 * (mixin+1) * n_inputs; */
|
||||
|
||||
// pseudoOuts
|
||||
size += 32 * n_inputs;
|
||||
size += (size_t)32 * n_inputs;
|
||||
// ecdhInfo
|
||||
size += 8 * n_outputs;
|
||||
size += (size_t)8 * n_outputs;
|
||||
// outPk - only commitment is saved
|
||||
size += 32 * n_outputs;
|
||||
size += (size_t)32 * n_outputs;
|
||||
// txnFee
|
||||
size += 4;
|
||||
|
||||
@@ -860,7 +860,7 @@ size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, si
|
||||
if (use_rct)
|
||||
return estimate_rct_tx_size(n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, use_view_tags);
|
||||
else
|
||||
return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size + (use_view_tags ? (n_outputs * sizeof(crypto::view_tag)) : 0);
|
||||
return (size_t)n_inputs * ((size_t)mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size + (use_view_tags ? ((size_t)n_outputs * sizeof(crypto::view_tag)) : 0);
|
||||
}
|
||||
|
||||
uint64_t estimate_tx_weight(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags)
|
||||
@@ -870,11 +870,11 @@ uint64_t estimate_tx_weight(bool use_rct, int n_inputs, int mixin, int n_outputs
|
||||
{
|
||||
const uint64_t bp_base = (32 * ((bulletproof_plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2)
|
||||
size_t log_padded_outputs = 2;
|
||||
while ((1<<log_padded_outputs) < n_outputs)
|
||||
while ((UINT64_C(1) << log_padded_outputs) < (uint64_t)n_outputs)
|
||||
++log_padded_outputs;
|
||||
uint64_t nlr = 2 * (6 + log_padded_outputs);
|
||||
const uint64_t bp_size = 32 * ((bulletproof_plus ? 6 : 9) + nlr);
|
||||
const uint64_t bp_clawback = (bp_base * (1<<log_padded_outputs) - bp_size) * 4 / 5;
|
||||
const uint64_t bp_clawback = (bp_base * (UINT64_C(1) << log_padded_outputs) - bp_size) * 4 / 5;
|
||||
MDEBUG("clawback on size " << size << ": " << bp_clawback);
|
||||
size += bp_clawback;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user