Off-by-one wallet decoy selection bug fix (stable branch)

This corrects an off-by-one error in decoy selection that would never
select immediately-spendable outputs, and so immediately spending an
output would reveal the true output in question.

From Monero, PR 8794.

The infinite loop quoted here is *also* something that I encountered,
though only in regression testing (which uses a fake, sparse chain).
This commit is contained in:
Jason Rhinelander 2023-05-24 16:31:50 -03:00
parent 56ac7a51db
commit 2db8e978ab
No known key found for this signature in database
GPG Key ID: C4992CE7A88D4262
2 changed files with 4 additions and 3 deletions

View File

@ -910,7 +910,7 @@ gamma_picker::gamma_picker(const std::vector<uint64_t> &rct_offsets, double shap
const size_t blocks_to_consider = std::min<size_t>(rct_offsets.size(), blocks_in_a_year);
const double outputs_to_consider = rct_offsets.back() - (blocks_to_consider < rct_offsets.size() ? rct_offsets[rct_offsets.size() - blocks_to_consider - 1] : 0);
begin = rct_offsets.data();
end = rct_offsets.data() + rct_offsets.size() - DEFAULT_TX_SPENDABLE_AGE;
end = rct_offsets.data() + rct_offsets.size() - (std::max(1, CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE) - 1);
num_rct_outputs = *(end - 1);
THROW_WALLET_EXCEPTION_IF(num_rct_outputs == 0, error::wallet_internal_error, "No rct outputs");
average_output_time = tools::to_seconds(TARGET_BLOCK_TIME) * blocks_to_consider / outputs_to_consider; // this assumes constant target over the whole rct range
@ -9314,7 +9314,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
else
{
// the base offset of the first rct output in the first unlocked block (or the one to be if there's none)
num_outs = rct_offsets[rct_offsets.size() - DEFAULT_TX_SPENDABLE_AGE];
num_outs = gamma->get_num_rct_outs();
LOG_PRINT_L1("" << num_outs << " unlocked rct outputs");
THROW_WALLET_EXCEPTION_IF(num_outs == 0, error::wallet_internal_error,
"histogram reports no unlocked rct outputs, not even ours");
@ -9612,7 +9612,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
}
bool use_histogram = amount != 0 || !has_rct_distribution;
if (!use_histogram)
num_outs = rct_offsets[rct_offsets.size() - DEFAULT_TX_SPENDABLE_AGE];
num_outs = gamma->get_num_rct_outs();
// make sure the real outputs we asked for are really included, along
// with the correct key and mask: this guards against an active attack

View File

@ -112,6 +112,7 @@ namespace tools
uint64_t pick();
gamma_picker(const std::vector<uint64_t> &rct_offsets);
gamma_picker(const std::vector<uint64_t> &rct_offsets, double shape, double scale);
uint64_t get_num_rct_outs() const { return num_rct_outputs; }
private:
struct gamma_engine