mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-12 05:59:23 +00:00
Correct handling of commitment masks when scanning
This commit is contained in:
@@ -93,28 +93,36 @@ pub(crate) fn amount_encryption(amount: u64, key: Scalar) -> [u8; 8] {
|
|||||||
(amount ^ u64::from_le_bytes(hash(&amount_mask)[.. 8].try_into().unwrap())).to_le_bytes()
|
(amount ^ u64::from_le_bytes(hash(&amount_mask)[.. 8].try_into().unwrap())).to_le_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn amount_decryption(amount: &EncryptedAmount, key: Scalar) -> u64 {
|
// TODO: Move this under EncryptedAmount?
|
||||||
|
fn amount_decryption(amount: &EncryptedAmount, key: Scalar) -> (Scalar, u64) {
|
||||||
match amount {
|
match amount {
|
||||||
EncryptedAmount::Original { mask: _, amount } => {
|
EncryptedAmount::Original { mask, amount } => {
|
||||||
#[cfg(feature = "experimental")]
|
#[cfg(feature = "experimental")]
|
||||||
{
|
{
|
||||||
let shared_sec = hash(&hash(key.as_bytes()));
|
let mask_shared_sec = hash(key.as_bytes());
|
||||||
|
let mask =
|
||||||
|
Scalar::from_bytes_mod_order(*mask) - Scalar::from_bytes_mod_order(mask_shared_sec);
|
||||||
|
|
||||||
|
let amount_shared_sec = hash(&mask_shared_sec);
|
||||||
let amount_scalar =
|
let amount_scalar =
|
||||||
Scalar::from_bytes_mod_order(*amount) - Scalar::from_bytes_mod_order(shared_sec);
|
Scalar::from_bytes_mod_order(*amount) - Scalar::from_bytes_mod_order(amount_shared_sec);
|
||||||
// d2b from rctTypes.cpp
|
// d2b from rctTypes.cpp
|
||||||
let amount_significant_bytes = amount_scalar.to_bytes()[0 .. 8].try_into().unwrap();
|
let amount = u64::from_le_bytes(amount_scalar.to_bytes()[0 .. 8].try_into().unwrap());
|
||||||
u64::from_le_bytes(amount_significant_bytes)
|
|
||||||
|
(mask, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "experimental"))]
|
#[cfg(not(feature = "experimental"))]
|
||||||
{
|
{
|
||||||
|
let _ = mask;
|
||||||
let _ = amount;
|
let _ = amount;
|
||||||
todo!("decrypting a legacy monero transaction's amount")
|
todo!("decrypting a legacy monero transaction's amount")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EncryptedAmount::Compact { amount } => {
|
EncryptedAmount::Compact { amount } => (
|
||||||
u64::from_le_bytes(amount_encryption(u64::from_le_bytes(*amount), key))
|
commitment_mask(key),
|
||||||
}
|
u64::from_le_bytes(amount_encryption(u64::from_le_bytes(*amount), key)),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ use crate::{
|
|||||||
rpc::{RpcError, RpcConnection, Rpc},
|
rpc::{RpcError, RpcConnection, Rpc},
|
||||||
wallet::{
|
wallet::{
|
||||||
PaymentId, Extra, address::SubaddressIndex, Scanner, uniqueness, shared_key, amount_decryption,
|
PaymentId, Extra, address::SubaddressIndex, Scanner, uniqueness, shared_key, amount_decryption,
|
||||||
commitment_mask,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -379,7 +378,7 @@ impl Scanner {
|
|||||||
commitment.amount = amount;
|
commitment.amount = amount;
|
||||||
// Regular transaction
|
// Regular transaction
|
||||||
} else {
|
} else {
|
||||||
let amount = match tx.rct_signatures.base.encrypted_amounts.get(o) {
|
let (mask, amount) = match tx.rct_signatures.base.encrypted_amounts.get(o) {
|
||||||
Some(amount) => amount_decryption(amount, shared_key),
|
Some(amount) => amount_decryption(amount, shared_key),
|
||||||
// This should never happen, yet it may be possible with miner transactions?
|
// This should never happen, yet it may be possible with miner transactions?
|
||||||
// Using get just decreases the possibility of a panic and lets us move on in that case
|
// Using get just decreases the possibility of a panic and lets us move on in that case
|
||||||
@@ -387,7 +386,7 @@ impl Scanner {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Rebuild the commitment to verify it
|
// Rebuild the commitment to verify it
|
||||||
commitment = Commitment::new(commitment_mask(shared_key), amount);
|
commitment = Commitment::new(mask, amount);
|
||||||
// If this is a malicious commitment, move to the next output
|
// If this is a malicious commitment, move to the next output
|
||||||
// Any other R value will calculate to a different spend key and are therefore ignorable
|
// Any other R value will calculate to a different spend key and are therefore ignorable
|
||||||
if Some(&commitment.calculate()) != tx.rct_signatures.base.commitments.get(o) {
|
if Some(&commitment.calculate()) != tx.rct_signatures.base.commitments.get(o) {
|
||||||
|
|||||||
Reference in New Issue
Block a user