From 81cfd841cebf52a55cf597a61fb80eb155ddea51 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Mon, 3 Jul 2023 18:57:26 -0400 Subject: [PATCH] Replace EcdhInfo terminology The ECDH encrypted the amount, yet this struct contained the encrypted amount, not some ECDH. Also corrects the types on the original EcdhInfo struct. --- coins/monero/src/ringct/mod.rs | 47 +++++++++++++++-------------- coins/monero/src/transaction.rs | 2 +- coins/monero/src/wallet/mod.rs | 11 ++++--- coins/monero/src/wallet/scan.rs | 2 +- coins/monero/src/wallet/send/mod.rs | 12 ++++---- 5 files changed, 38 insertions(+), 36 deletions(-) diff --git a/coins/monero/src/ringct/mod.rs b/coins/monero/src/ringct/mod.rs index 445a6473..6c0fd9e0 100644 --- a/coins/monero/src/ringct/mod.rs +++ b/coins/monero/src/ringct/mod.rs @@ -32,26 +32,27 @@ pub fn generate_key_image(secret: &Zeroizing) -> EdwardsPoint { } #[derive(Clone, PartialEq, Eq, Debug)] -pub enum EcdhInfo { - Standard { mask: Scalar, amount: Scalar }, - Bulletproof { amount: [u8; 8] }, +pub enum EncryptedAmount { + Original { mask: [u8; 32], amount: [u8; 32] }, + Compact { amount: [u8; 8] }, } -impl EcdhInfo { - pub fn read(rct_type: u8, r: &mut R) -> io::Result { - Ok(match rct_type { - 0 ..= 3 => EcdhInfo::Standard { mask: read_scalar(r)?, amount: read_scalar(r)? }, - _ => EcdhInfo::Bulletproof { amount: read_bytes(r)? }, +impl EncryptedAmount { + pub fn read(compact: bool, r: &mut R) -> io::Result { + Ok(if !compact { + EncryptedAmount::Original { mask: read_bytes(r)?, amount: read_bytes(r)? } + } else { + EncryptedAmount::Compact { amount: read_bytes(r)? } }) } pub fn write(&self, w: &mut W) -> io::Result<()> { match self { - EcdhInfo::Standard { mask, amount } => { - write_scalar(mask, w)?; - write_scalar(amount, w) + EncryptedAmount::Original { mask, amount } => { + w.write_all(mask)?; + w.write_all(amount) } - EcdhInfo::Bulletproof { amount } => w.write_all(amount), + EncryptedAmount::Compact { amount } => w.write_all(amount), } } } @@ -59,7 +60,7 @@ impl EcdhInfo { #[derive(Clone, PartialEq, Eq, Debug)] pub struct RctBase { pub fee: u64, - pub ecdh_info: Vec, + pub encrypted_amounts: Vec, pub pseudo_outs: Vec, pub commitments: Vec, } @@ -78,8 +79,8 @@ impl RctBase { if rct_type == 2 { write_raw_vec(write_point, &self.pseudo_outs, w)?; } - for ecdh in &self.ecdh_info { - ecdh.write(w)?; + for encrypted_amount in &self.encrypted_amounts { + encrypted_amount.write(w)?; } write_raw_vec(write_point, &self.commitments, w) } @@ -90,13 +91,13 @@ impl RctBase { let rct_type = read_byte(r)?; Ok(( if rct_type == 0 { - RctBase { fee: 0, ecdh_info: vec![], pseudo_outs: vec![], commitments: vec![] } + RctBase { fee: 0, encrypted_amounts: vec![], pseudo_outs: vec![], commitments: vec![] } } else { RctBase { fee: read_varint(r)?, pseudo_outs: if rct_type == 2 { read_raw_vec(read_point, inputs, r)? } else { vec![] }, - ecdh_info: (0 .. outputs) - .map(|_| EcdhInfo::read(rct_type, r)) + encrypted_amounts: (0 .. outputs) + .map(|_| EncryptedAmount::read(rct_type >= 4, r)) .collect::>()?, commitments: read_raw_vec(read_point, outputs, r)?, } @@ -114,7 +115,7 @@ pub enum RctPrunable { mlsags: Vec, simple: bool, }, - BulletProof { + Bulletproofs { bulletproofs: Vec, mlsags: Vec, pseudo_outs: Vec, @@ -139,7 +140,7 @@ impl RctPrunable { 2 } } - RctPrunable::BulletProof { v2, .. } => { + RctPrunable::Bulletproofs { v2, .. } => { if !v2 { 3 } else { @@ -168,7 +169,7 @@ impl RctPrunable { write_raw_vec(BorromeanRange::write, range_sigs, w)?; write_raw_vec(Mlsag::write, mlsags, w) } - RctPrunable::BulletProof { bulletproofs, mlsags, pseudo_outs, v2 } => { + RctPrunable::Bulletproofs { bulletproofs, mlsags, pseudo_outs, v2 } => { if !v2 { w.write_all(&u32::try_from(bulletproofs.len()).unwrap().to_le_bytes())?; } else { @@ -205,7 +206,7 @@ impl RctPrunable { mlsags: decoys.iter().map(|d| Mlsag::read(*d, r)).collect::>()?, simple: rct_type == 2, }, - 3 | 4 => RctPrunable::BulletProof { + 3 | 4 => RctPrunable::Bulletproofs { bulletproofs: read_raw_vec( Bulletproofs::read, if rct_type == 3 { @@ -237,7 +238,7 @@ impl RctPrunable { RctPrunable::Clsag { bulletproofs, .. } => { bulletproofs.iter().try_for_each(|bp| bp.signature_write(w)) } - RctPrunable::BulletProof { bulletproofs, .. } => { + RctPrunable::Bulletproofs { bulletproofs, .. } => { bulletproofs.iter().try_for_each(|bp| bp.signature_write(w)) } RctPrunable::Borromean { range_sigs, .. } => range_sigs.iter().try_for_each(|rs| rs.write(w)), diff --git a/coins/monero/src/transaction.rs b/coins/monero/src/transaction.rs index dddeb080..c48c3feb 100644 --- a/coins/monero/src/transaction.rs +++ b/coins/monero/src/transaction.rs @@ -283,7 +283,7 @@ impl Transaction { let prefix = TransactionPrefix::read(r)?; let mut signatures = vec![]; let mut rct_signatures = RctSignatures { - base: RctBase { fee: 0, ecdh_info: vec![], pseudo_outs: vec![], commitments: vec![] }, + base: RctBase { fee: 0, encrypted_amounts: vec![], pseudo_outs: vec![], commitments: vec![] }, prunable: RctPrunable::Null, }; diff --git a/coins/monero/src/wallet/mod.rs b/coins/monero/src/wallet/mod.rs index 91d3315e..6953a3d5 100644 --- a/coins/monero/src/wallet/mod.rs +++ b/coins/monero/src/wallet/mod.rs @@ -35,7 +35,7 @@ pub use send::SignableTransactionBuilder; pub(crate) use send::InternalPayment; #[cfg(feature = "multisig")] pub use send::TransactionMachine; -use crate::ringct::EcdhInfo; +use crate::ringct::EncryptedAmount; fn key_image_sort(x: &EdwardsPoint, y: &EdwardsPoint) -> core::cmp::Ordering { x.compress().to_bytes().cmp(&y.compress().to_bytes()).reverse() @@ -93,13 +93,14 @@ 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() } -fn amount_decryption(amount: &EcdhInfo, key: Scalar) -> u64 { +fn amount_decryption(amount: &EncryptedAmount, key: Scalar) -> u64 { match amount { - EcdhInfo::Standard { mask: _, amount } => { + EncryptedAmount::Original { mask: _, amount } => { #[cfg(feature = "experimental")] { let shared_sec = hash(&hash(key.as_bytes())); - let amount_scalar = amount - Scalar::from_bytes_mod_order(shared_sec); + let amount_scalar = + Scalar::from_bytes_mod_order(*amount) - Scalar::from_bytes_mod_order(shared_sec); // d2b from rctTypes.cpp let amount_significant_bytes = amount_scalar.to_bytes()[0 .. 8].try_into().unwrap(); u64::from_le_bytes(amount_significant_bytes) @@ -111,7 +112,7 @@ fn amount_decryption(amount: &EcdhInfo, key: Scalar) -> u64 { todo!("decrypting a legacy monero transaction's amount") } } - EcdhInfo::Bulletproof { amount } => { + EncryptedAmount::Compact { amount } => { u64::from_le_bytes(amount_encryption(u64::from_le_bytes(*amount), key)) } } diff --git a/coins/monero/src/wallet/scan.rs b/coins/monero/src/wallet/scan.rs index 7f407fd9..5beef897 100644 --- a/coins/monero/src/wallet/scan.rs +++ b/coins/monero/src/wallet/scan.rs @@ -379,7 +379,7 @@ impl Scanner { commitment.amount = amount; // Regular transaction } else { - let amount = match tx.rct_signatures.base.ecdh_info.get(o) { + let amount = match tx.rct_signatures.base.encrypted_amounts.get(o) { Some(amount) => amount_decryption(amount, shared_key), // 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 diff --git a/coins/monero/src/wallet/send/mod.rs b/coins/monero/src/wallet/send/mod.rs index e7b92c24..8c637cff 100644 --- a/coins/monero/src/wallet/send/mod.rs +++ b/coins/monero/src/wallet/send/mod.rs @@ -53,7 +53,7 @@ pub use builder::SignableTransactionBuilder; mod multisig; #[cfg(feature = "multisig")] pub use multisig::TransactionMachine; -use crate::ringct::EcdhInfo; +use crate::ringct::EncryptedAmount; #[allow(non_snake_case)] #[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)] @@ -630,7 +630,7 @@ impl SignableTransaction { let mut fee = self.inputs.iter().map(|input| input.commitment().amount).sum::(); let mut tx_outputs = Vec::with_capacity(outputs.len()); - let mut ecdh_info = Vec::with_capacity(outputs.len()); + let mut encrypted_amounts = Vec::with_capacity(outputs.len()); for output in &outputs { fee -= output.commitment.amount; tx_outputs.push(Output { @@ -638,7 +638,7 @@ impl SignableTransaction { key: output.dest.compress(), view_tag: Some(output.view_tag).filter(|_| matches!(self.protocol, Protocol::v16)), }); - ecdh_info.push(EcdhInfo::Bulletproof { amount: output.amount }); + encrypted_amounts.push(EncryptedAmount::Compact { amount: output.amount }); } ( @@ -654,7 +654,7 @@ impl SignableTransaction { rct_signatures: RctSignatures { base: RctBase { fee, - ecdh_info, + encrypted_amounts, pseudo_outs: vec![], commitments: commitments.iter().map(|commitment| commitment.calculate()).collect(), }, @@ -758,8 +758,8 @@ impl Eventuality { view_tag: Some(expected.view_tag).filter(|_| matches!(self.protocol, Protocol::v16)), } != actual) || (Some(&expected.commitment.calculate()) != tx.rct_signatures.base.commitments.get(o)) || - (Some(&EcdhInfo::Bulletproof { amount: expected.amount }) != - tx.rct_signatures.base.ecdh_info.get(o)) + (Some(&EncryptedAmount::Compact { amount: expected.amount }) != + tx.rct_signatures.base.encrypted_amounts.get(o)) { return false; }