Off-by-one wallet decoy selection bug fix

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:26:32 -03:00
parent 7bda65c5d2
commit 5d45896bfa
No known key found for this signature in database
GPG Key ID: C4992CE7A88D4262
2 changed files with 5 additions and 3 deletions

View File

@ -1268,7 +1268,8 @@ gamma_picker::gamma_picker(const std::vector<uint64_t>& rct_offsets, double shap
? 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 =
@ -10599,7 +10600,7 @@ void wallet2::get_outs(
} 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::info(logcat, "{} unlocked rct outputs", num_outs);
THROW_WALLET_EXCEPTION_IF(
num_outs == 0,
@ -10923,7 +10924,7 @@ void wallet2::get_outs(
}
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

@ -105,6 +105,7 @@ class gamma_picker {
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 {