diff --git a/coins/monero/src/wallet/send/mod.rs b/coins/monero/src/wallet/send/mod.rs index 531ea529..45f57123 100644 --- a/coins/monero/src/wallet/send/mod.rs +++ b/coins/monero/src/wallet/send/mod.rs @@ -87,6 +87,8 @@ pub enum TransactionError { NotEnoughFunds(u64, u64), #[error("invalid address")] InvalidAddress, + #[error("wrong spend private key")] + WrongPrivateKey, #[error("rpc error ({0})")] RpcError(RpcError), #[error("clsag error ({0})")] @@ -282,7 +284,12 @@ impl SignableTransaction { ) -> Result<Transaction, TransactionError> { let mut images = Vec::with_capacity(self.inputs.len()); for input in &self.inputs { - images.push(generate_key_image(&(spend + input.key_offset))); + let offset = spend + input.key_offset; + if (&offset * &ED25519_BASEPOINT_TABLE) != input.key { + Err(TransactionError::WrongPrivateKey)?; + } + + images.push(generate_key_image(&offset)); } images.sort_by(key_image_sort); diff --git a/coins/monero/src/wallet/send/multisig.rs b/coins/monero/src/wallet/send/multisig.rs index 02c3e4ff..18dba94b 100644 --- a/coins/monero/src/wallet/send/multisig.rs +++ b/coins/monero/src/wallet/send/multisig.rs @@ -83,6 +83,31 @@ impl SignableTransaction { } transcript.append_message(b"change", &self.change.as_bytes()); + // Sort included before cloning it around + included.sort_unstable(); + + for (i, input) in self.inputs.iter().enumerate() { + // Check this the right set of keys + let offset = keys.offset(dalek_ff_group::Scalar(input.key_offset)); + if offset.group_key().0 != input.key { + Err(TransactionError::WrongPrivateKey)?; + } + + clsags.push( + AlgorithmMachine::new( + ClsagMultisig::new( + transcript.clone(), + inputs[i].clone() + ).map_err(|e| TransactionError::MultisigError(e))?, + Arc::new(offset), + &included + ).map_err(|e| TransactionError::FrostError(e))? + ); + } + + // Verify these outputs by a dummy prep + self.prepare_outputs(rng, [0; 32])?; + // Select decoys // Ideally, this would be done post entropy, instead of now, yet doing so would require sign // to be async which isn't preferable. This should be suitably competent though @@ -97,25 +122,6 @@ impl SignableTransaction { &self.inputs ).await.map_err(|e| TransactionError::RpcError(e))?; - // Sort included before cloning it around - included.sort_unstable(); - - for (i, input) in self.inputs.iter().enumerate() { - clsags.push( - AlgorithmMachine::new( - ClsagMultisig::new( - transcript.clone(), - inputs[i].clone() - ).map_err(|e| TransactionError::MultisigError(e))?, - Arc::new(keys.offset(dalek_ff_group::Scalar(input.key_offset))), - &included - ).map_err(|e| TransactionError::FrostError(e))? - ); - } - - // Verify these outputs by a dummy prep - self.prepare_outputs(rng, [0; 32])?; - Ok(TransactionMachine { signable: self, i: keys.params().i(),