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.
(cherry picked from commit a3deaab98a)
(cherry picked from commit ac37e75df8aedf43aa7afa1199ec24e229039f34)
This commit is contained in:
+13
-13
@@ -804,10 +804,10 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
|
|||||||
size += 1 + 6;
|
size += 1 + 6;
|
||||||
|
|
||||||
// vin
|
// vin
|
||||||
size += n_inputs * (1+6+(mixin+1)*2+32);
|
size += (size_t)n_inputs * (1+6+((size_t)mixin+1)*2+32);
|
||||||
|
|
||||||
// vout
|
// vout
|
||||||
size += n_outputs * (6+32);
|
size += (size_t)n_outputs * (6+32);
|
||||||
|
|
||||||
// extra
|
// extra
|
||||||
size += extra_size;
|
size += extra_size;
|
||||||
@@ -821,31 +821,31 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
|
|||||||
if (bulletproof || bulletproof_plus || bulletproof_plus_full_commit)
|
if (bulletproof || bulletproof_plus || bulletproof_plus_full_commit)
|
||||||
{
|
{
|
||||||
size_t log_padded_outputs = 0;
|
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;
|
++log_padded_outputs;
|
||||||
size += (2 * (6 + log_padded_outputs) + (bulletproof_plus_full_commit ? 6 : bulletproof_plus ? 6 : (4 + 5))) * 32 + 3;
|
size += (2 * (6 + log_padded_outputs) + (bulletproof_plus_full_commit ? 6 : bulletproof_plus ? 6 : (4 + 5))) * 32 + 3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
size += (2*64*32+32+64*32) * n_outputs;
|
size += (size_t)(2*64*32+32+64*32) * n_outputs;
|
||||||
|
|
||||||
// MGs/CLSAGs
|
// MGs/CLSAGs
|
||||||
if (clsag)
|
if (clsag)
|
||||||
size += n_inputs * (32 * (mixin+1) + 64);
|
size += (size_t)n_inputs * (32 * ((size_t)mixin+1) + 64);
|
||||||
else
|
else
|
||||||
size += n_inputs * (64 * (mixin+1) + 32);
|
size += (size_t)n_inputs * (64 * ((size_t)mixin+1) + 32);
|
||||||
|
|
||||||
if (use_view_tags)
|
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
|
// mixRing - not serialized, can be reconstructed
|
||||||
/* size += 2 * 32 * (mixin+1) * n_inputs; */
|
/* size += 2 * 32 * (mixin+1) * n_inputs; */
|
||||||
|
|
||||||
// pseudoOuts
|
// pseudoOuts
|
||||||
size += 32 * n_inputs;
|
size += (size_t)32 * n_inputs;
|
||||||
// ecdhInfo
|
// ecdhInfo
|
||||||
size += 8 * n_outputs;
|
size += (size_t)8 * n_outputs;
|
||||||
// outPk - only commitment is saved
|
// outPk - only commitment is saved
|
||||||
size += 32 * n_outputs;
|
size += (size_t)32 * n_outputs;
|
||||||
// txnFee
|
// txnFee
|
||||||
size += 4;
|
size += 4;
|
||||||
|
|
||||||
@@ -858,7 +858,7 @@ size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, si
|
|||||||
if (use_rct)
|
if (use_rct)
|
||||||
return estimate_rct_tx_size(n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
|
return estimate_rct_tx_size(n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
|
||||||
else
|
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 bulletproof_plus_full_commit, bool use_view_tags)
|
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 bulletproof_plus_full_commit, bool use_view_tags)
|
||||||
@@ -868,11 +868,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_full_commit ? 6 : bulletproof_plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2)
|
const uint64_t bp_base = (32 * ((bulletproof_plus_full_commit ? 6 : 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;
|
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;
|
++log_padded_outputs;
|
||||||
uint64_t nlr = 2 * (6 + log_padded_outputs);
|
uint64_t nlr = 2 * (6 + log_padded_outputs);
|
||||||
const uint64_t bp_size = 32 * ((bulletproof_plus_full_commit ? 6 : bulletproof_plus ? 6 : 9) + nlr);
|
const uint64_t bp_size = 32 * ((bulletproof_plus_full_commit ? 6 : 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);
|
MDEBUG("clawback on size " << size << ": " << bp_clawback);
|
||||||
size += bp_clawback;
|
size += bp_clawback;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user