From eead8e5024748da81d20f887b66891e61d925d60 Mon Sep 17 00:00:00 2001 From: Charon-Fan Date: Wed, 11 Dec 2024 09:43:29 +0800 Subject: [PATCH] refactor: reorganize module imports and improve code formatting --- rust/apps/monero/src/address.rs | 38 ++-- rust/apps/monero/src/errors.rs | 2 +- rust/apps/monero/src/key.rs | 17 +- rust/apps/monero/src/key_images.rs | 94 ++++---- rust/apps/monero/src/lib.rs | 6 +- rust/apps/monero/src/outputs.rs | 33 +-- rust/apps/monero/src/signed_transaction.rs | 22 +- rust/apps/monero/src/slow_hash/mod.rs | 2 +- rust/apps/monero/src/slow_hash/slow_hash.rs | 3 +- rust/apps/monero/src/transfer.rs | 239 +++++++++++++------- rust/apps/monero/src/transfer_key.rs | 199 ++++++++-------- rust/apps/monero/src/utils/constants.rs | 2 +- rust/apps/monero/src/utils/hash.rs | 33 ++- rust/apps/monero/src/utils/io.rs | 237 +++++++++---------- rust/apps/monero/src/utils/mod.rs | 55 +++-- rust/apps/monero/src/utils/sign.rs | 236 +++++++++---------- rust/apps/monero/src/utils/varinteger.rs | 2 +- 17 files changed, 670 insertions(+), 550 deletions(-) diff --git a/rust/apps/monero/src/address.rs b/rust/apps/monero/src/address.rs index c8f04d3c7..77d2eddd5 100644 --- a/rust/apps/monero/src/address.rs +++ b/rust/apps/monero/src/address.rs @@ -1,6 +1,6 @@ +use crate::errors::{MoneroError, Result}; use crate::key::*; use crate::structs::{AddressType, Network}; -use crate::errors::{MoneroError, Result}; use crate::utils::{constants::PUBKEY_LEH, hash::keccak256}; use alloc::format; use alloc::string::{String, ToString}; @@ -53,16 +53,18 @@ impl Address { unknown_prefix => return Err(MoneroError::InvalidPrefix(unknown_prefix.to_string())), }; let is_subaddress = prefix == "2A" || prefix == "3F" || prefix == "24"; - let public_spend = - match PublicKey::from_bytes(&decoded[1..33]).map_err(|e| format!("decode error: {:?}", e)) { - Ok(public_spend) => public_spend, - _ => return Err(MoneroError::FormatError), - }; + let public_spend = match PublicKey::from_bytes(&decoded[1..33]) + .map_err(|e| format!("decode error: {:?}", e)) + { + Ok(public_spend) => public_spend, + _ => return Err(MoneroError::FormatError), + }; let public_view = match PublicKey::from_bytes(&decoded[33..65]) - .map_err(|e| format!("decode error: {:?}", e)) { - Ok(public_view) => public_view, - _ => return Err(MoneroError::FormatError), - }; + .map_err(|e| format!("decode error: {:?}", e)) + { + Ok(public_view) => public_view, + _ => return Err(MoneroError::FormatError), + }; Ok(Address { network: net, addr_type: if is_subaddress { @@ -134,12 +136,7 @@ pub fn pub_keyring_to_address( Err(e) => return Err(e), }; - match pub_keys_to_address( - net, - is_subaddress, - &pub_spend_key, - &pub_view_key, - ) { + match pub_keys_to_address(net, is_subaddress, &pub_spend_key, &pub_view_key) { Ok(address) => Ok(address), Err(e) => Err(e), } @@ -202,7 +199,8 @@ pub fn generate_address( AddressType::Standard, public_spend_key.clone(), private_view_key.get_public_key(), - ).to_string()); + ) + .to_string()); } let point = public_spend_key.point.decompress().unwrap(); @@ -288,7 +286,8 @@ mod tests { let public_spend_key = keypair.spend.get_public_key(); let private_view_key = keypair.view; - let address = generate_address(&public_spend_key, &private_view_key, major, minor, true).unwrap(); + let address = + generate_address(&public_spend_key, &private_view_key, major, minor, true).unwrap(); assert_eq!( address, @@ -322,7 +321,8 @@ mod tests { "5a69bc37d807013f80e10959bc7855419f1b0b47258a64a6a8c440ffd223070f" ); - let sun_account = generate_address(&keypair.get_public_spend(), &keypair.view, 1, 0, true).unwrap(); + let sun_account = + generate_address(&keypair.get_public_spend(), &keypair.view, 1, 0, true).unwrap(); assert_eq!( sun_account, diff --git a/rust/apps/monero/src/errors.rs b/rust/apps/monero/src/errors.rs index 1e69997db..f4f6898d7 100644 --- a/rust/apps/monero/src/errors.rs +++ b/rust/apps/monero/src/errors.rs @@ -1,7 +1,7 @@ use alloc::string::{String, ToString}; use keystore::errors::KeystoreError; -use thiserror::Error; use thiserror; +use thiserror::Error; #[derive(Error, Debug, PartialEq)] pub enum MoneroError { diff --git a/rust/apps/monero/src/key.rs b/rust/apps/monero/src/key.rs index 7e6a93294..79e48aaae 100644 --- a/rust/apps/monero/src/key.rs +++ b/rust/apps/monero/src/key.rs @@ -1,5 +1,5 @@ -use crate::utils::{hash::hash_to_scalar, constants::PUBKEY_LEH}; use crate::errors::{MoneroError, Result}; +use crate::utils::{constants::PUBKEY_LEH, hash::hash_to_scalar}; use alloc::format; use alloc::string::{String, ToString}; use curve25519_dalek::edwards::{CompressedEdwardsY, EdwardsPoint}; @@ -45,16 +45,19 @@ impl PublicKey { } pub fn from_bytes(bytes: &[u8]) -> Result { - let pub_key = - match CompressedEdwardsY::from_slice(bytes).map_err(|e| format!("decode error: {:?}", e)) { - Ok(point) => PublicKey { point }, - _ => return Err(MoneroError::PublicKeyFromBytesError), - }; + let pub_key = match CompressedEdwardsY::from_slice(bytes) + .map_err(|e| format!("decode error: {:?}", e)) + { + Ok(point) => PublicKey { point }, + _ => return Err(MoneroError::PublicKeyFromBytesError), + }; Ok(pub_key) } pub fn from_str(s: &str) -> Result { - let bytes = hex::decode(s).map_err(|e| format!("decode error: {:?}", e)).unwrap(); + let bytes = hex::decode(s) + .map_err(|e| format!("decode error: {:?}", e)) + .unwrap(); PublicKey::from_bytes(&bytes) } } diff --git a/rust/apps/monero/src/key_images.rs b/rust/apps/monero/src/key_images.rs index 95e236dc5..76156e4c7 100644 --- a/rust/apps/monero/src/key_images.rs +++ b/rust/apps/monero/src/key_images.rs @@ -1,18 +1,21 @@ +use crate::errors::{MoneroError, Result}; use crate::key::{generate_key_image_from_priavte_key, KeyPair, PrivateKey, PublicKey}; +use crate::outputs::{ExportedTransferDetail, ExportedTransferDetails}; use crate::utils::{ - decrypt_data_with_pvk, encrypt_data_with_pvk, hash::{hash_to_scalar, keccak256}, - constants::*, sign::generate_ring_signature, varinteger::*, + constants::*, + decrypt_data_with_pvk, encrypt_data_with_pvk, + hash::{hash_to_scalar, keccak256}, + sign::generate_ring_signature, + varinteger::*, }; -use crate::outputs::{ExportedTransferDetails, ExportedTransferDetail}; -use crate::errors::{MoneroError, Result}; -use curve25519_dalek::EdwardsPoint; -use curve25519_dalek::edwards::CompressedEdwardsY; -use curve25519_dalek::scalar::Scalar; use alloc::string::{String, ToString}; use alloc::vec; use alloc::vec::Vec; -use rand_core::SeedableRng; +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::EdwardsPoint; use hex; +use rand_core::SeedableRng; use rand_core::{CryptoRng, RngCore}; #[derive(Debug, Clone, Copy)] @@ -24,7 +27,10 @@ impl Keyimage { } pub fn to_point(&self) -> EdwardsPoint { - CompressedEdwardsY::from_slice(&self.0).unwrap().decompress().unwrap() + CompressedEdwardsY::from_slice(&self.0) + .unwrap() + .decompress() + .unwrap() } pub fn to_bytes(&self) -> Vec { @@ -87,7 +93,6 @@ impl From<&Vec> for KeyImages { } } - fn calc_output_key_offset( keypair: &KeyPair, tx_pubkey: &[u8; 32], @@ -95,14 +100,20 @@ fn calc_output_key_offset( major: u32, minor: u32, ) -> Scalar { - let recv_derivation = - (keypair.view.scalar * PublicKey::from_bytes(tx_pubkey).unwrap().point.decompress().unwrap()).mul_by_cofactor(); + let recv_derivation = (keypair.view.scalar + * PublicKey::from_bytes(tx_pubkey) + .unwrap() + .point + .decompress() + .unwrap()) + .mul_by_cofactor(); let mut output_index_buf = vec![0; length(internal_output_index)]; encode(internal_output_index, &mut output_index_buf); let scalar = output_index_buf.to_vec(); - let mut key_offset = hash_to_scalar(&[&recv_derivation.compress().0, scalar.as_slice()].concat()); + let mut key_offset = + hash_to_scalar(&[&recv_derivation.compress().0, scalar.as_slice()].concat()); if major != 0 || minor != 0 { key_offset = key_offset + Scalar::from_bytes_mod_order(keypair.get_m(major, minor)); @@ -111,7 +122,6 @@ fn calc_output_key_offset( key_offset } - fn calc_key_image_private_key( keypair: &KeyPair, tx_pubkey: &[u8; 32], @@ -119,7 +129,8 @@ fn calc_key_image_private_key( major: u32, minor: u32, ) -> PrivateKey { - let key_offsset = calc_output_key_offset(keypair, tx_pubkey, internal_output_index, major, minor); + let key_offsset = + calc_output_key_offset(keypair, tx_pubkey, internal_output_index, major, minor); let prv_key = keypair.spend.scalar + key_offsset; @@ -133,27 +144,25 @@ fn generate_key_image( internal_output_index: u64, major: u32, minor: u32, - mut rng: R + mut rng: R, ) -> KeyImageAndSignature { - let prvkey = calc_key_image_private_key( - keypair, - tx_pubkey, - internal_output_index, - major, - minor, - ); + let prvkey = + calc_key_image_private_key(keypair, tx_pubkey, internal_output_index, major, minor); let image = generate_key_image_from_priavte_key(&prvkey.clone()); - let signature = - generate_ring_signature(&image.clone().compress().0, &image.clone(), vec![PublicKey::from_bytes(pubkey).unwrap()], &prvkey, 0, &mut rng); + let signature = generate_ring_signature( + &image.clone().compress().0, + &image.clone(), + vec![PublicKey::from_bytes(pubkey).unwrap()], + &prvkey, + 0, + &mut rng, + ); let signature = [signature[0][0].to_bytes(), signature[0][1].to_bytes()].concat(); - KeyImageAndSignature::new( - image.compress().0, - signature.try_into().unwrap(), - ) + KeyImageAndSignature::new(image.compress().0, signature.try_into().unwrap()) } fn generate_key_image_from_offset( @@ -179,15 +188,14 @@ pub fn try_to_generate_image( optional_minors: Vec, ) -> Result<(Keyimage, Scalar)> { for minor in optional_minors { - let offset = calc_output_key_offset(keypair, tx_pubkey, internal_output_index, major, minor); + let offset = + calc_output_key_offset(keypair, tx_pubkey, internal_output_index, major, minor); match generate_key_image_from_offset( &keypair.spend, &offset, &PublicKey::from_bytes(output_pubkey).unwrap(), ) { - Some(image) => return Ok( - (Keyimage::new(image.compress().to_bytes()), offset), - ), + Some(image) => return Ok((Keyimage::new(image.compress().to_bytes()), offset)), None => continue, }; } @@ -196,7 +204,11 @@ pub fn try_to_generate_image( } impl ExportedTransferDetail { - pub fn key_image(&self, keypair: &KeyPair, rng: R) -> KeyImageAndSignature { + pub fn key_image( + &self, + keypair: &KeyPair, + rng: R, + ) -> KeyImageAndSignature { generate_key_image( keypair, &self.tx_pubkey, @@ -218,7 +230,7 @@ impl ExportedTransferDetail { ( prvkey.get_public_key(), - Keyimage::new(generate_key_image_from_priavte_key(&prvkey).compress().0) + Keyimage::new(generate_key_image_from_priavte_key(&prvkey).compress().0), ) } } @@ -254,7 +266,11 @@ pub fn generate_export_ur_data(keypair: KeyPair, request_data: Vec) -> Resul .push(output.key_image(&keypair.clone(), &mut rng)); } - Ok(encrypt_data_with_pvk(keypair, key_images.to_bytes(), KEY_IMAGE_EXPORT_MAGIC)) + Ok(encrypt_data_with_pvk( + keypair, + key_images.to_bytes(), + KEY_IMAGE_EXPORT_MAGIC, + )) } #[cfg(test)] @@ -267,7 +283,8 @@ mod tests { .unwrap(); let data = hex::decode("4d6f6e65726f206b657920696d616765206578706f727403c2b43f259084a0587d10ce88fddf607949d1448ef00dfad2d82447c669cafc712403d954e3fa901554b67ec80b7dcf1a8b95beaa0d9b27c478b2917ce28934d8252b4903999e98de1bdf03d536fb40893dcaf16b3118a325f261de607ac3c0b7b4b4f11cf3e6e95f8c21756e49287596d4da6997f6943d561f1fbf8f5cffb76274307545a0890da57022e80e31eeb483f27c5ebc6481ca202b7e4431465d40ac54c7b74b439b13de79b3985a01caaadf1f41073f7ddeadf8198eb8d21482ef633313e9ae9feae092118772201ff309b42d364f6e34211a5b4abd13087908989e16ad1bb0fbc87494a86889a8d7a6d6dfcfe078f1f767643dd03bffc8adc18c6736bb03ac8f47f2d708b02d1138427f58270d8176b37a2d970f7ede15b2697f38d0f3dc74e8de8014477cf01c6445047bc6fedebefac3d9619b8ec4f42bbef03140e16fdfb5e836f785f379a6a17f760619f135c9fba9c299d76da04f3cf30868bead8e39fb4b56b2eccfb2fd208cbc47e37a95fbc3084426ef10e19118c4fc080a47052006558f4f7f731e3aafc261bf1136a57d7fb34ceb271f0b5c4b5a5f3e98063aaf50423111bc17f97862921cf9e4e28c83d67f622d54851f4ee81549d857203373cc8c3033494a6a1ccf5779cd4f84c7c1a3b879d640b6916ceef91c441da88c542a3cf3862820da4bc3e634638e969c439641e417982382e6bc71100752afcaed1426881003de976966b707c0e057b73a70e94e5635405a437aab095791b232348e39916e22e9168a948a94b71cbc503065c232f5301840dc8a4cb81ca3eb2a324060e764c15f4a59c9560c67460251ca6095cb6ff959c19851e69f0783667029514612e3c9722cb280e2119b9cbdcbae0b91dcd303ed573edb2af19758b73853954c486c1a4a082ece9c84cc4695cbc3a73caeca2fcdce509df2378c1743edf87239adc846de146e3993b43f58a42d65d64575509c73b2621179b20e4e0edb695a2901f55643a926df34e64de4c4fc514f77e31dbb9b1748834e75a7cbb89d9c21c3842de7cf4a7776936175784c3a93c3486f0ff5cdb0f05cfb01097a5e338522342fa3bba623d5dacd8fc77fd4ea4b552df00e3cfb7f4490f6ba9f8c101cd1a98c4ce8a97ac04111020f0d624f9df35c6764b898ea0826404bfbdb96175e7672089ea0a408095a9ac97c943b9383a08b32f9ae0b8e45edf3659e7f714341139f1073c7be2c46357881cc8373ce5667f36b2bbe5f435ad740884be1a9f1ec1611bee3df4c78d7646e8d83ec03472a2b35711aa0e75bfaafef66a89b934ab487ad01468d5730eb3fe69b4adf86a97adb141d891edffe092a137d7b51a7184624586317e3aae8c6b128516b92462cd5856ab30514f678a9a1aa5469279d7cfee6b86fe2e12c0c383d077940857cf4bc526cb2f947692409de52ec82658819bb6ee78bebc21134aab4c04b0f5bee12ad5e037fd786c70dcfe83f20b7dcf6be765414561167a2bcb0b7ad17906f87fdc913746320bdc3287e6f0417c7d33debc15011706584b9d1acb42b721008447c2434a3a745855408b6bb0f86a00caf06e280b64032623082f3f60d3fd4c62458778cae87198bbd19c185148c0854d532f64593911a85d8f93230b8d49aa7928d220a32bacb93c105983749f5e9f441e903a5b7a1ec2f03d44f5ec06673fffd6b6e7df2cbde6a33aeb2c9d2d892c5d13fb2c7b0e36f1b5b535e860fe34dc0e578bb7d052aa922fb2fec3e8a5df184f24d96ac11f3b35d2e1843077b7bedcf4854a763318443be315e134a15915d360ec47373d00b861dcb8b1303").unwrap(); - let res = decrypt_data_with_pvk(pvk.try_into().unwrap(), data, KEY_IMAGE_EXPORT_MAGIC).unwrap(); + let res = + decrypt_data_with_pvk(pvk.try_into().unwrap(), data, KEY_IMAGE_EXPORT_MAGIC).unwrap(); assert_eq!( hex::encode(res.pk1.unwrap().as_bytes()), @@ -334,7 +351,8 @@ mod tests { ); let keypair = crate::key::KeyPair::new(sec_v_key.clone(), sec_s_key.clone()); - let key_images_export_data = generate_export_ur_data(keypair.clone(), data.clone()).unwrap(); + let key_images_export_data = + generate_export_ur_data(keypair.clone(), data.clone()).unwrap(); assert_eq!(hex::encode(key_images_export_data), "4d6f6e65726f206b657920696d616765206578706f727403a7f77b9eb360d066d49f2eaa597fe16862b5c1c90eba00af226a1e6c43b774b2b468994d6ff7ee2a7d829812c2d6adedcb9131133f043ff98223531f2b721ff7c1468885baea1a7acd4d6c929ea8ce07161c7f443e9e6ed19677c6c6f53185a50a0418f14ce26d7988c2190e09a04809346d6d7aabdfe929ce88bed228531a44d4c9f1ee2826dcd2f4d78900"); } diff --git a/rust/apps/monero/src/lib.rs b/rust/apps/monero/src/lib.rs index 409c727d2..661432800 100644 --- a/rust/apps/monero/src/lib.rs +++ b/rust/apps/monero/src/lib.rs @@ -2,13 +2,13 @@ #![feature(error_in_core)] extern crate alloc; +mod extra; +mod signed_transaction; mod slow_hash; mod transfer_key; -mod signed_transaction; -mod extra; -pub mod errors; pub mod address; +pub mod errors; pub mod key; pub mod key_images; pub mod outputs; diff --git a/rust/apps/monero/src/outputs.rs b/rust/apps/monero/src/outputs.rs index 7d80c8a67..b3037b3ee 100644 --- a/rust/apps/monero/src/outputs.rs +++ b/rust/apps/monero/src/outputs.rs @@ -1,9 +1,9 @@ -use crate::key::{PublicKey, PrivateKey}; use crate::errors::Result; +use crate::key::PublicKey; +use crate::utils::{constants::OUTPUT_EXPORT_MAGIC, constants::PUBKEY_LEH, io::*}; use crate::utils::{decrypt_data_with_decrypt_key, fmt_monero_amount}; -use crate::utils::{constants::PUBKEY_LEH, io::*, constants::OUTPUT_EXPORT_MAGIC}; -use alloc::vec::Vec; use alloc::string::String; +use alloc::vec::Vec; #[allow(dead_code)] #[derive(Debug, Clone)] @@ -76,7 +76,7 @@ impl ExportedTransferDetails { let tx_pubkey = PublicKey::from_bytes(&bytes[offset..offset + PUBKEY_LEH]).unwrap(); let flags = bytes[offset + PUBKEY_LEH]; offset += PUBKEY_LEH + 1; - let amount= read_varinteger(&bytes, &mut offset); + let amount = read_varinteger(&bytes, &mut offset); // FIXME: additional_tx_keys let keys_num = read_varinteger(&bytes, &mut offset); let mut additional_tx_keys = Vec::new(); @@ -115,16 +115,16 @@ pub struct DisplayMoneroOutput { pub total_amount: String, } -pub fn parse_display_info(data: &[u8], decrypt_key: [u8; 32], pvk: [u8; 32]) -> Result { - let decrypted_data = match decrypt_data_with_decrypt_key( - decrypt_key, - pvk, - data.to_vec(), - OUTPUT_EXPORT_MAGIC, - ) { - Ok(data) => data, - Err(e) => return Err(e), - }; +pub fn parse_display_info( + data: &[u8], + decrypt_key: [u8; 32], + pvk: [u8; 32], +) -> Result { + let decrypted_data = + match decrypt_data_with_decrypt_key(decrypt_key, pvk, data.to_vec(), OUTPUT_EXPORT_MAGIC) { + Ok(data) => data, + Err(e) => return Err(e), + }; let outputs = match ExportedTransferDetails::from_bytes(&decrypted_data.data) { Ok(data) => data, Err(e) => return Err(e), @@ -140,8 +140,8 @@ pub fn parse_display_info(data: &[u8], decrypt_key: [u8; 32], pvk: [u8; 32]) -> #[cfg(test)] mod tests { - use crate::utils::*; use crate::utils::constants::OUTPUT_EXPORT_MAGIC; + use crate::utils::*; use hex; #[test] @@ -150,7 +150,8 @@ mod tests { .unwrap(); let data = hex::decode("4d6f6e65726f206f7574707574206578706f727404eb5fb0d1fc8358931053f6e24d93ec0766aad43a54453593287d0d3dcfdef9371f411a0e179a9c1b0da94a3fe3d51cccf3573c01b6f8d6ee215caf3238976d8e9af5347e44b0d575fa622accdd4b4d5d272e13d77ff897752f52d7617be986efb4d2b1f841bae6c1d041d6ff9df46262b1251a988d5b0fbe5012d2af7b9ff318381bfd8cbe06af6e0750c16ff7a61d31d36526d83d7b6b614b2fd602941f2e94de01d0e3fc5a84414cdeabd943e5d8f0226ab7bea5e47c97253bf2f062e92a6bf27b6099a47cb8bca47e5ad544049611d77bfeb5c16b5b7849ce5d46bb928ce2e9a2b6679653a769f53c7c17d3e91df35ae7b62a4cffcea2d25df1c2e21a58b1746aae00a273317ec3873c53d8ae71d89d70637a6bd1da974e548b48a0f96d119f0f7d04ff034bb7fed3dbe9081d3e3a3212d330328c0edbacad85bab43780f9b5dfd81f359b0827146ebc421e60dba0badab1941bc31a0086aac99d59f55f07d58c02a48a3e1f70222bae1a612dacd09d0b176345a115e6ae6523ecbc346d8a8078111da7f9932f31d6e35500f5195cfdfe6b6eb2b223d171430a1cb7e11a51ac41d06f3a81546378b1ff342a18fb1f01cfd10df9c1ac86531456f240e5500d9c7ba4c47ba8d4455ea2b7e460ee207c064b76019f6bb4efe5a3e27a126b0c8be6a2e6f3d7ede9580ff49598501aafa36187896e245d64461f9f1c24323b1271af9e0a7a9108422de5ecfdaccdcb2b4520a6d75b2511be6f17a272d21e05ead99818e697559714af0a220494004e393eeefdfe029cff0db22c3adadf6f00edbf6bf4fcbcfc1e225451be3c1c700fe796fce6480b02d0cb1f9fbcf6c05895df2eeb8192980df50a0523922c1247fef83a5f631cf64132125477e1a3b13bcbaa691da1e9b45288eb6c7669e7a7857f87ed45f74725b72b4604fda6b44d3999e1d6fab0786f9b14f00a6518ca3fbc5f865d9fc8acd6e5773208").unwrap(); - let res = decrypt_data_with_pvk(pvk.try_into().unwrap(), data, OUTPUT_EXPORT_MAGIC).unwrap(); + let res = + decrypt_data_with_pvk(pvk.try_into().unwrap(), data, OUTPUT_EXPORT_MAGIC).unwrap(); assert_eq!( hex::encode(res.pk1.unwrap().as_bytes()), diff --git a/rust/apps/monero/src/signed_transaction.rs b/rust/apps/monero/src/signed_transaction.rs index e64f1a2a7..1d3a9e7c4 100644 --- a/rust/apps/monero/src/signed_transaction.rs +++ b/rust/apps/monero/src/signed_transaction.rs @@ -1,10 +1,10 @@ -use alloc::{string::String, vec::Vec, vec}; -use monero_serai_mirror::transaction::{Transaction, NotPruned}; -use curve25519_dalek::Scalar; -use crate::transfer::{TxDestinationEntry, TxConstructionData}; use crate::key::*; use crate::key_images::Keyimage; +use crate::transfer::{TxConstructionData, TxDestinationEntry}; use crate::utils::io::*; +use alloc::{string::String, vec, vec::Vec}; +use curve25519_dalek::Scalar; +use monero_serai_mirror::transaction::{NotPruned, Transaction}; #[derive(Debug, Clone)] pub struct PendingTx { @@ -63,15 +63,19 @@ impl PendingTx { pub struct SignedTxSet { pub ptx: Vec, key_images: Vec, - tx_key_images: Vec<(PublicKey, Keyimage)> + tx_key_images: Vec<(PublicKey, Keyimage)>, } impl SignedTxSet { - pub fn new(ptx: Vec, key_images: Vec, tx_key_images: Vec<(PublicKey, Keyimage)>) -> Self { + pub fn new( + ptx: Vec, + key_images: Vec, + tx_key_images: Vec<(PublicKey, Keyimage)>, + ) -> Self { Self { ptx, key_images, - tx_key_images + tx_key_images, } } } @@ -121,7 +125,9 @@ impl SignedTxSet { for key_image in signed_tx_set.key_images.clone() { res.extend_from_slice(&key_image.to_bytes()); } - res.extend_from_slice(write_varinteger(signed_tx_set.tx_key_images.len() as u64).as_slice()); + res.extend_from_slice( + write_varinteger(signed_tx_set.tx_key_images.len() as u64).as_slice(), + ); for (public_key, key_image) in signed_tx_set.tx_key_images.clone() { res.push(2u8); res.extend_from_slice(&public_key.point.to_bytes()); diff --git a/rust/apps/monero/src/slow_hash/mod.rs b/rust/apps/monero/src/slow_hash/mod.rs index e4e39fe06..81bf8f397 100644 --- a/rust/apps/monero/src/slow_hash/mod.rs +++ b/rust/apps/monero/src/slow_hash/mod.rs @@ -1,7 +1,7 @@ mod blake256; mod cnaes; -mod util; mod slow_hash; +mod util; use slow_hash::cn_slow_hash; diff --git a/rust/apps/monero/src/slow_hash/slow_hash.rs b/rust/apps/monero/src/slow_hash/slow_hash.rs index cd9cd73d4..38366995d 100644 --- a/rust/apps/monero/src/slow_hash/slow_hash.rs +++ b/rust/apps/monero/src/slow_hash/slow_hash.rs @@ -1,7 +1,6 @@ -use core::mem::swap; use alloc::vec::Vec; use cnaes::{AES_BLOCK_SIZE, CN_AES_KEY_SIZE}; -// use digest::Digest as _; +use core::mem::swap; use groestl::Digest; use groestl::Groestl256; use jh::Jh256; diff --git a/rust/apps/monero/src/transfer.rs b/rust/apps/monero/src/transfer.rs index 59c799a64..2cc163d2d 100644 --- a/rust/apps/monero/src/transfer.rs +++ b/rust/apps/monero/src/transfer.rs @@ -1,27 +1,29 @@ +use crate::address::*; +use crate::errors::{MoneroError, Result}; +use crate::key::*; +use crate::key_images::{try_to_generate_image, Keyimage}; +use crate::outputs::ExportedTransferDetails; +use crate::signed_transaction::{PendingTx, SignedTxSet}; +use crate::structs::*; +use crate::utils::*; +use crate::utils::{constants::*, hash::*, io::*}; use alloc::borrow::ToOwned; +use alloc::string::{String, ToString}; use alloc::vec; use alloc::vec::Vec; -use alloc::string::{String, ToString}; +use core::fmt::Display; +use curve25519_dalek::scalar::Scalar; use curve25519_dalek::EdwardsPoint; +use monero_clsag_mirror::{Clsag, ClsagContext}; use monero_primitives_mirror::Decoys; -use crate::key_images::{Keyimage, try_to_generate_image}; -use crate::utils::*; -use crate::utils::{hash::*, io::*, constants::*}; -use crate::address::*; -use crate::structs::*; -use crate::key::*; -use crate::errors::{MoneroError, Result}; -use curve25519_dalek::scalar::Scalar; -use monero_serai_mirror::transaction::{Transaction, NotPruned, TransactionPrefix, Input, Output, Timelock}; -use monero_serai_mirror::ringct::bulletproofs::Bulletproof; -use monero_serai_mirror::ringct::{RctPrunable, RctBase, RctProofs}; use monero_serai_mirror::primitives::Commitment; +use monero_serai_mirror::ringct::bulletproofs::Bulletproof; +use monero_serai_mirror::ringct::{RctBase, RctProofs, RctPrunable}; +use monero_serai_mirror::transaction::{ + Input, NotPruned, Output, Timelock, Transaction, TransactionPrefix, +}; use rand_core::SeedableRng; -use monero_clsag_mirror::{Clsag, ClsagContext}; use zeroize::Zeroizing; -use crate::signed_transaction::{SignedTxSet, PendingTx}; -use core::fmt::Display; -use crate::outputs::ExportedTransferDetails; #[derive(Debug, Clone)] pub struct DisplayTransactionInfo { @@ -96,14 +98,14 @@ pub struct AccountPublicAddress { } impl AccountPublicAddress { - pub fn to_address( - &self, - network: Network, - is_subaddress: bool, - ) -> Address { + pub fn to_address(&self, network: Network, is_subaddress: bool) -> Address { let address = Address { network, - addr_type: if is_subaddress { AddressType::Subaddress } else { AddressType::Standard }, + addr_type: if is_subaddress { + AddressType::Subaddress + } else { + AddressType::Standard + }, public_spend: PublicKey::from_bytes(&self.spend_public_key).unwrap(), public_view: PublicKey::from_bytes(&self.view_public_key).unwrap(), }; @@ -176,7 +178,10 @@ impl InnerInputs { } pub fn get_inputs(&self) -> Vec { - self.0.iter().map(|inner_input| inner_input.input.clone()).collect() + self.0 + .iter() + .map(|inner_input| inner_input.input.clone()) + .collect() } pub fn get_key_offsets(&self, index: usize) -> Vec { @@ -184,7 +189,10 @@ impl InnerInputs { } pub fn get_sources(&self) -> Vec { - self.0.iter().map(|inner_input| inner_input.source.clone()).collect() + self.0 + .iter() + .map(|inner_input| inner_input.source.clone()) + .collect() } } @@ -205,11 +213,17 @@ impl InnerOutputs { } pub fn get_outputs(&self) -> Vec { - self.0.iter().map(|inner_output| inner_output.output.clone()).collect() + self.0 + .iter() + .map(|inner_output| inner_output.output.clone()) + .collect() } pub fn get_key_images(&self) -> Vec { - self.0.iter().map(|inner_output| inner_output.key_image.clone()).collect() + self.0 + .iter() + .map(|inner_output| inner_output.key_image.clone()) + .collect() } } @@ -242,7 +256,7 @@ impl TxConstructionData { let mut res = InnerInputs::new(); for (index, source) in self.sources.iter().enumerate() { let key_offsets = self.absolute_output_offsets_to_relative( - source.outputs.iter().map(|output| output.index).collect() + source.outputs.iter().map(|output| output.index).collect(), ); let key_image = self.calc_key_image_by_index(keypair, index); let input = Input::ToKey { @@ -259,12 +273,21 @@ impl TxConstructionData { } let key_image_sort = |x: &EdwardsPoint, y: &EdwardsPoint| -> core::cmp::Ordering { - x.compress().to_bytes().cmp(&y.compress().to_bytes()).reverse() + x.compress() + .to_bytes() + .cmp(&y.compress().to_bytes()) + .reverse() }; - res.0.sort_by(|a, b| key_image_sort( - &get_key_image_from_input(a.input.clone()).unwrap().to_point(), - &get_key_image_from_input(b.input.clone()).unwrap().to_point(), - )); + res.0.sort_by(|a, b| { + key_image_sort( + &get_key_image_from_input(a.input.clone()) + .unwrap() + .to_point(), + &get_key_image_from_input(b.input.clone()) + .unwrap() + .to_point(), + ) + }); res } @@ -274,7 +297,7 @@ impl TxConstructionData { buffer.extend_from_slice(b"view_tag"); buffer.extend_from_slice(&derivation.compress().to_bytes()); buffer.extend_from_slice(&write_varinteger(output_index)); - + keccak256(&buffer)[0] } @@ -282,11 +305,16 @@ impl TxConstructionData { let shared_key_derivations = self.shared_key_derivations(keypair); let mut res = InnerOutputs::new(); for (dest, shared_key_derivation) in self.splitted_dsts.iter().zip(shared_key_derivations) { - let image = generate_key_image_from_priavte_key(&PrivateKey::new(shared_key_derivation.shared_key)); + let image = generate_key_image_from_priavte_key(&PrivateKey::new( + shared_key_derivation.shared_key, + )); - let key = - PublicKey::from_bytes(&dest.addr.spend_public_key).unwrap().point.decompress().unwrap() + - EdwardsPoint::mul_base(&shared_key_derivation.shared_key); + let key = PublicKey::from_bytes(&dest.addr.spend_public_key) + .unwrap() + .point + .decompress() + .unwrap() + + EdwardsPoint::mul_base(&shared_key_derivation.shared_key); res.push(InnerOutput { output: Output { @@ -306,7 +334,11 @@ impl TxConstructionData { res } - fn calc_key_image_by_index(&self, keypair: &KeyPair, sources_index: usize) -> (Keyimage, Scalar) { + fn calc_key_image_by_index( + &self, + keypair: &KeyPair, + sources_index: usize, + ) -> (Keyimage, Scalar) { let source = self.sources[sources_index].clone(); let output_entry = source.outputs[source.real_output as usize]; let ctkey = output_entry.key; @@ -318,14 +350,15 @@ impl TxConstructionData { source.real_output_in_tx_index, self.subaddr_account, self.subaddr_indices.clone(), - ).unwrap() + ) + .unwrap() } fn calc_key_images(&self, keypair: &KeyPair) -> Vec { let mut key_images = vec![]; let tx = self; - for index in 0 .. tx.sources.iter().len() { + for index in 0..tx.sources.iter().len() { key_images.push(tx.calc_key_image_by_index(keypair, index).0); } @@ -341,7 +374,7 @@ impl TxConstructionData { } #[derive(Debug, Clone, Default)] -pub struct UnsignedTx { +pub struct UnsignedTx { pub txes: Vec, transfers: ExportedTransferDetails, } @@ -354,16 +387,23 @@ impl UnsignedTx { for source in tx.sources.iter() { let output = source.outputs[source.real_output as usize].clone(); let amount = source.amount; - inputs.push((PublicKey::from_bytes(&output.key.dest).unwrap(), fmt_monero_amount(amount))); + inputs.push(( + PublicKey::from_bytes(&output.key.dest).unwrap(), + fmt_monero_amount(amount), + )); } for dest in tx.splitted_dsts.iter() { let address = dest.addr.to_address(Network::Mainnet, dest.is_subaddress); let amount = dest.amount; - let is_change = address == tx.change_dts.addr.to_address(Network::Mainnet, tx.change_dts.is_subaddress); + let is_change = address + == tx + .change_dts + .addr + .to_address(Network::Mainnet, tx.change_dts.is_subaddress); outputs.push((address, fmt_monero_amount(amount), is_change)); } } - + DisplayTransactionInfo { inputs, outputs, @@ -389,7 +429,10 @@ impl UnsignedTx { let index = read_varinteger(bytes, &mut offset); let dest = read_next_u8_32(bytes, &mut offset); let mask = read_next_u8_32(bytes, &mut offset); - outputs.push(OutputEntry { index, key: CtKey { dest, mask } }); + outputs.push(OutputEntry { + index, + key: CtKey { dest, mask }, + }); } let real_output = read_next_u64(bytes, &mut offset); let real_out_tx_key = read_next_u8_32(bytes, &mut offset); @@ -492,17 +535,13 @@ impl UnsignedTx { } let transfers = ExportedTransferDetails::from_bytes(&bytes[offset..]).unwrap(); - UnsignedTx { - txes, - transfers, - } + UnsignedTx { txes, transfers } } pub fn transaction_without_signatures(&self, keypair: &KeyPair) -> Vec { let mut txes = vec![]; for tx in self.txes.iter() { - let commitments_and_encrypted_amounts = - tx.commitments_and_encrypted_amounts(keypair); + let commitments_and_encrypted_amounts = tx.commitments_and_encrypted_amounts(keypair); let mut commitments = Vec::with_capacity(tx.splitted_dsts.len()); let mut bp_commitments = Vec::with_capacity(tx.splitted_dsts.len()); let mut encrypted_amounts = Vec::with_capacity(tx.splitted_dsts.len()); @@ -518,13 +557,17 @@ impl UnsignedTx { let mut bp_rng = rand_chacha::ChaCha20Rng::from_seed(keccak256(&seed)); (match tx.rct_config.bp_version { RctType::RCTTypeFull => Bulletproof::prove(&mut bp_rng, bp_commitments), - RctType::RCTTypeNull | RctType::RCTTypeBulletproof2 => Bulletproof::prove_plus(&mut bp_rng, bp_commitments), + RctType::RCTTypeNull | RctType::RCTTypeBulletproof2 => { + Bulletproof::prove_plus(&mut bp_rng, bp_commitments) + } _ => panic!("unsupported RctType"), }) - .expect("couldn't prove BP(+)s for this many payments despite checking in constructor?") + .expect( + "couldn't prove BP(+)s for this many payments despite checking in constructor?", + ) }; - let tx: Transaction:: = Transaction::V2 { + let tx: Transaction = Transaction::V2 { prefix: TransactionPrefix { additional_timelock: Timelock::None, inputs: tx.inputs(keypair).get_inputs(), @@ -538,8 +581,12 @@ impl UnsignedTx { pseudo_outs: vec![], commitments, }, - prunable: RctPrunable::Clsag { bulletproof, clsags: vec![], pseudo_outs: vec![] }, - }) + prunable: RctPrunable::Clsag { + bulletproof, + clsags: vec![], + pseudo_outs: vec![], + }, + }), }; txes.push(tx); } @@ -554,17 +601,29 @@ impl UnsignedTx { let seed = keccak256(&txes[0].serialize()); let mut rng = rand_chacha::ChaCha20Rng::from_seed(seed); for (tx, unsigned_tx) in txes.iter().zip(self.txes.iter()) { - let mask_sum = unsigned_tx.sum_output_masks(keypair); let inputs = unsigned_tx.inputs(keypair); let mut clsag_signs = Vec::with_capacity(inputs.0.len()); for (i, input) in inputs.0.iter().enumerate() { - let ring: Vec<[EdwardsPoint; 2]> = input.source.outputs.iter().map(|output| { - [ - PublicKey::from_bytes(&output.key.dest).unwrap().point.decompress().unwrap(), - PublicKey::from_bytes(&output.key.mask).unwrap().point.decompress().unwrap(), - ] - }).collect(); + let ring: Vec<[EdwardsPoint; 2]> = input + .source + .outputs + .iter() + .map(|output| { + [ + PublicKey::from_bytes(&output.key.dest) + .unwrap() + .point + .decompress() + .unwrap(), + PublicKey::from_bytes(&output.key.mask) + .unwrap() + .point + .decompress() + .unwrap(), + ] + }) + .collect(); clsag_signs.push(( Zeroizing::new(keypair.spend.scalar + input.key_offset), ClsagContext::new( @@ -572,33 +631,38 @@ impl UnsignedTx { unsigned_tx.inputs(keypair).get_key_offsets(i), input.source.real_output as u8, ring.clone(), - ).unwrap(), + ) + .unwrap(), Commitment { mask: Scalar::from_bytes_mod_order(input.source.mask), amount: input.source.amount, - } - ).unwrap(), + }, + ) + .unwrap(), )); } let msg = tx.signature_hash().unwrap(); - let clsags_and_pseudo_outs = - Clsag::sign(&mut rng, clsag_signs, mask_sum, msg) - .unwrap(); + let clsags_and_pseudo_outs = Clsag::sign(&mut rng, clsag_signs, mask_sum, msg).unwrap(); let mut tx = tx.clone(); let inputs_len = tx.prefix().inputs.len(); let Transaction::V2 { proofs: Some(RctProofs { - prunable: RctPrunable::Clsag { ref mut clsags, ref mut pseudo_outs, .. }, + prunable: + RctPrunable::Clsag { + ref mut clsags, + ref mut pseudo_outs, + .. + }, .. }), .. - } = tx - else { - panic!("not signing clsag?") - }; + } = tx + else { + panic!("not signing clsag?") + }; *clsags = Vec::with_capacity(inputs_len); *pseudo_outs = Vec::with_capacity(inputs_len); for (clsag, pseudo_out) in clsags_and_pseudo_outs.iter() { @@ -639,24 +703,23 @@ impl UnsignedTx { )); for item in unsigned_tx.outputs(keypair).0.iter() { - tx_key_images.push(( - PublicKey::new(item.output.key), - item.key_image, - )); + tx_key_images.push((PublicKey::new(item.output.key), item.key_image)); } } for transfer in self.transfers.details.iter() { - tx_key_images.push( - transfer.generate_key_image_without_signature(keypair) - ); + tx_key_images.push(transfer.generate_key_image_without_signature(keypair)); } SignedTxSet::new(penging_tx, vec![], tx_key_images) } } -pub fn parse_unsigned(request_data: Vec, decrypt_key: [u8; 32], pvk: [u8; 32]) -> Result { +pub fn parse_unsigned( + request_data: Vec, + decrypt_key: [u8; 32], + pvk: [u8; 32], +) -> Result { let decrypted_data = match decrypt_data_with_decrypt_key( decrypt_key, pvk, @@ -666,7 +729,7 @@ pub fn parse_unsigned(request_data: Vec, decrypt_key: [u8; 32], pvk: [u8; 32 Ok(data) => data, Err(e) => match e { MoneroError::DecryptInvalidSignature => return Err(MoneroError::MismatchedMfp), - _ => return Err(e) + _ => return Err(e), }, }; @@ -684,7 +747,7 @@ pub fn sign_tx(keypair: KeyPair, request_data: Vec) -> Result> { Ok(data) => data, Err(e) => match e { MoneroError::DecryptInvalidSignature => return Err(MoneroError::MismatchedMfp), - _ => return Err(e) + _ => return Err(e), }, }; @@ -692,18 +755,22 @@ pub fn sign_tx(keypair: KeyPair, request_data: Vec) -> Result> { let signed_txes = unsigned_tx.sign(&keypair); - Ok(encrypt_data_with_pvk(keypair, signed_txes.serialize(), SIGNED_TX_PREFIX)) + Ok(encrypt_data_with_pvk( + keypair, + signed_txes.serialize(), + SIGNED_TX_PREFIX, + )) } #[cfg(test)] mod tests { use super::*; use crate::key::PrivateKey; - use rand_core::{RngCore, SeedableRng}; use alloc::vec; use core::ops::Deref; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; + use rand_core::{RngCore, SeedableRng}; #[test] fn test_clsag_signature() { diff --git a/rust/apps/monero/src/transfer_key.rs b/rust/apps/monero/src/transfer_key.rs index 21bce79fd..d405a53a8 100644 --- a/rust/apps/monero/src/transfer_key.rs +++ b/rust/apps/monero/src/transfer_key.rs @@ -1,98 +1,98 @@ -use alloc::vec; -use alloc::vec::Vec; +use crate::extra::*; +use crate::key::*; use crate::transfer::{TxConstructionData, TxDestinationEntry}; use crate::utils::*; use crate::utils::{hash::*, varinteger::*}; -use crate::key::*; -use crate::extra::*; +use alloc::vec; +use alloc::vec::Vec; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; -use rand_core::SeedableRng; use monero_serai_mirror::primitives::Commitment; use monero_serai_mirror::ringct::EncryptedAmount; +use rand_core::SeedableRng; #[derive(Debug, Clone, Copy, PartialEq)] pub struct SharedKeyDerivations { - pub view_tag: u8, - pub shared_key: Scalar, + pub view_tag: u8, + pub shared_key: Scalar, } - impl SharedKeyDerivations { - fn output_derivations( - ecdh: EdwardsPoint, - o: usize, - ) -> SharedKeyDerivations { - // 8Ra - let mut output_derivation = ecdh.mul_by_cofactor().compress().to_bytes().to_vec(); - // || o - { - let mut buffer = vec![0]; - encode(o as u64, &mut buffer); - output_derivation.extend(buffer); - } - let mut buffer = vec![]; - buffer.extend_from_slice(b"view_tag"); - buffer.extend_from_slice(&output_derivation); + fn output_derivations(ecdh: EdwardsPoint, o: usize) -> SharedKeyDerivations { + // 8Ra + let mut output_derivation = ecdh.mul_by_cofactor().compress().to_bytes().to_vec(); + // || o + { + let mut buffer = vec![0]; + encode(o as u64, &mut buffer); + output_derivation.extend(buffer); + } + let mut buffer = vec![]; + buffer.extend_from_slice(b"view_tag"); + buffer.extend_from_slice(&output_derivation); - let view_tag = keccak256(&buffer)[0]; + let view_tag = keccak256(&buffer)[0]; - SharedKeyDerivations { - view_tag, - shared_key: hash_to_scalar(&output_derivation), + SharedKeyDerivations { + view_tag, + shared_key: hash_to_scalar(&output_derivation), + } } - } - fn commitment_mask(&self) -> Scalar { - let mut mask = b"commitment_mask".to_vec(); - mask.extend(self.shared_key.as_bytes()); - let res = hash_to_scalar(&mask); - res - } + fn commitment_mask(&self) -> Scalar { + let mut mask = b"commitment_mask".to_vec(); + mask.extend(self.shared_key.as_bytes()); + let res = hash_to_scalar(&mask); + res + } - fn compact_amount_encryption(&self, amount: u64) -> [u8; 8] { - let mut amount_mask = b"amount".to_vec(); - amount_mask.extend(self.shared_key.to_bytes()); - let amount_mask = keccak256(&amount_mask); + fn compact_amount_encryption(&self, amount: u64) -> [u8; 8] { + let mut amount_mask = b"amount".to_vec(); + amount_mask.extend(self.shared_key.to_bytes()); + let amount_mask = keccak256(&amount_mask); - let mut amount_mask_8 = [0; 8]; - amount_mask_8.copy_from_slice(&amount_mask[.. 8]); + let mut amount_mask_8 = [0; 8]; + amount_mask_8.copy_from_slice(&amount_mask[..8]); - (amount ^ u64::from_le_bytes(amount_mask_8)).to_le_bytes() - } + (amount ^ u64::from_le_bytes(amount_mask_8)).to_le_bytes() + } - fn payment_id_xor(ecdh: EdwardsPoint) -> [u8; 8] { - // 8Ra - let output_derivation = ecdh.mul_by_cofactor().compress().to_bytes().to_vec(); + fn payment_id_xor(ecdh: EdwardsPoint) -> [u8; 8] { + // 8Ra + let output_derivation = ecdh.mul_by_cofactor().compress().to_bytes().to_vec(); - let mut payment_id_xor = vec![]; - payment_id_xor.extend_from_slice(&output_derivation); - payment_id_xor.extend_from_slice([0x8d].as_ref()); - let payment_id_xor = keccak256(&payment_id_xor); + let mut payment_id_xor = vec![]; + payment_id_xor.extend_from_slice(&output_derivation); + payment_id_xor.extend_from_slice([0x8d].as_ref()); + let payment_id_xor = keccak256(&payment_id_xor); - payment_id_xor[.. 8].try_into().unwrap() - } + payment_id_xor[..8].try_into().unwrap() + } } impl TxConstructionData { fn should_use_additional_keys(&self) -> bool { - self.sources.iter().any(|source| source.real_out_additional_tx_keys.len() > 0) + self.sources + .iter() + .any(|source| source.real_out_additional_tx_keys.len() > 0) } fn has_payments_to_subaddresses(&self) -> bool { self.splitted_dsts.iter().any(|dst| dst.is_subaddress) } - pub fn transaction_keys(&self) -> (PrivateKey, Vec, EdwardsPoint, Vec) { + pub fn transaction_keys( + &self, + ) -> (PrivateKey, Vec, EdwardsPoint, Vec) { let seed = keccak256(&self.extra); let mut rng = rand_chacha::ChaCha20Rng::from_seed(seed); let tx_key = generate_random_scalar(&mut rng); let mut additional_keys = vec![]; if self.should_use_additional_keys() { - for _ in 0 .. self.splitted_dsts.len() { - additional_keys.push( - PrivateKey::from_bytes(generate_random_scalar(&mut rng).as_bytes()) - ); + for _ in 0..self.splitted_dsts.len() { + additional_keys.push(PrivateKey::from_bytes( + generate_random_scalar(&mut rng).as_bytes(), + )); } } let tx_key = PrivateKey::from_bytes(tx_key.as_bytes()); @@ -102,14 +102,28 @@ impl TxConstructionData { let has_payments_to_subaddresses = self.has_payments_to_subaddresses(); let should_use_additional_keys = self.should_use_additional_keys(); if has_payments_to_subaddresses && !should_use_additional_keys { - let spend = self.splitted_dsts.iter().find(|dest| dest.is_subaddress).unwrap().addr.spend_public_key; - - tx_key_pub = tx_key.scalar * PublicKey::from_bytes(&spend).unwrap().point.decompress().unwrap(); + let spend = self + .splitted_dsts + .iter() + .find(|dest| dest.is_subaddress) + .unwrap() + .addr + .spend_public_key; + + tx_key_pub = tx_key.scalar + * PublicKey::from_bytes(&spend) + .unwrap() + .point + .decompress() + .unwrap(); } else if should_use_additional_keys { - for (additional_key, dest) in additional_keys.clone().into_iter().zip(&self.splitted_dsts) { + for (additional_key, dest) in + additional_keys.clone().into_iter().zip(&self.splitted_dsts) + { let spend = PublicKey::from_bytes(&dest.addr.spend_public_key).unwrap(); if dest.is_subaddress { - additional_keys_pub.push(additional_key.scalar * spend.point.decompress().unwrap()); + additional_keys_pub + .push(additional_key.scalar * spend.point.decompress().unwrap()); } else { additional_keys_pub.push(EdwardsPoint::mul_base(&additional_key.scalar)) } @@ -120,24 +134,27 @@ impl TxConstructionData { } pub fn is_change_dest(&self, dest: &TxDestinationEntry) -> bool { - dest == &self.change_dts + dest == &self.change_dts } fn ecdhs(&self, keypair: &KeyPair) -> Vec { - let ( - tx_key, - additional_keys, - tx_key_pub, - _ - ) = self.transaction_keys(); + let (tx_key, additional_keys, tx_key_pub, _) = self.transaction_keys(); let mut res = Vec::with_capacity(self.splitted_dsts.len()); for (i, dest) in self.splitted_dsts.iter().enumerate() { - let key_to_use = - if dest.is_subaddress { additional_keys.get(i).unwrap_or(&tx_key) } else { &tx_key }; + let key_to_use = if dest.is_subaddress { + additional_keys.get(i).unwrap_or(&tx_key) + } else { + &tx_key + }; res.push(if !self.is_change_dest(dest) { - key_to_use.scalar * PublicKey::from_bytes(&dest.addr.view_public_key).unwrap().point.decompress().unwrap() + key_to_use.scalar + * PublicKey::from_bytes(&dest.addr.view_public_key) + .unwrap() + .point + .decompress() + .unwrap() } else { - keypair.view.scalar * tx_key_pub + keypair.view.scalar * tx_key_pub }); } @@ -145,11 +162,11 @@ impl TxConstructionData { } fn payment_id_xors(&self, keypair: &KeyPair) -> Vec<[u8; 8]> { - let mut res = Vec::with_capacity(self.splitted_dsts.len()); - for ecdh in self.ecdhs(keypair) { - res.push(SharedKeyDerivations::payment_id_xor(ecdh)); - } - res + let mut res = Vec::with_capacity(self.splitted_dsts.len()); + for ecdh in self.ecdhs(keypair) { + res.push(SharedKeyDerivations::payment_id_xor(ecdh)); + } + res } pub fn extra(&self, keypair: &KeyPair) -> Vec { @@ -172,25 +189,19 @@ impl TxConstructionData { extra.serialize() } - pub fn shared_key_derivations( - &self, - keypair: &KeyPair, - ) -> Vec { + pub fn shared_key_derivations(&self, keypair: &KeyPair) -> Vec { let ecdhs = self.ecdhs(keypair); let mut res = Vec::with_capacity(self.splitted_dsts.len()); for (i, (_, ecdh)) in self.splitted_dsts.iter().zip(ecdhs).enumerate() { - res.push(SharedKeyDerivations::output_derivations( - ecdh, - i, - )); + res.push(SharedKeyDerivations::output_derivations(ecdh, i)); } res } pub fn commitments_and_encrypted_amounts( - &self, - keypair: &KeyPair, + &self, + keypair: &KeyPair, ) -> Vec<(Commitment, EncryptedAmount)> { let shared_key_derivations = self.shared_key_derivations(keypair); @@ -203,17 +214,15 @@ impl TxConstructionData { amount: shared_key_derivation.compact_amount_encryption(amount), }; res.push((commitment, encrypted_amount)); - } res } pub fn sum_output_masks(&self, keypair: &KeyPair) -> Scalar { - self - .commitments_and_encrypted_amounts(keypair) - .into_iter() - .map(|(commitment, _)| commitment.mask) - .sum() + self.commitments_and_encrypted_amounts(keypair) + .into_iter() + .map(|(commitment, _)| commitment.mask) + .sum() } -} \ No newline at end of file +} diff --git a/rust/apps/monero/src/utils/constants.rs b/rust/apps/monero/src/utils/constants.rs index d8273f184..93732492f 100644 --- a/rust/apps/monero/src/utils/constants.rs +++ b/rust/apps/monero/src/utils/constants.rs @@ -3,4 +3,4 @@ pub const KEY_IMAGE_EXPORT_MAGIC: &str = "Monero key image export\x03"; pub const UNSIGNED_TX_PREFIX: &str = "Monero unsigned tx set\x05"; pub const SIGNED_TX_PREFIX: &str = "Monero signed tx set\x05"; pub const PUBKEY_LEH: usize = 32; -pub const PRVKEY_LEH: usize = 32; \ No newline at end of file +pub const PRVKEY_LEH: usize = 32; diff --git a/rust/apps/monero/src/utils/hash.rs b/rust/apps/monero/src/utils/hash.rs index 8826d0597..eb2ed8c45 100644 --- a/rust/apps/monero/src/utils/hash.rs +++ b/rust/apps/monero/src/utils/hash.rs @@ -1,36 +1,35 @@ -use alloc::vec::Vec; use crate::utils::constants::*; -use curve25519_dalek::scalar::Scalar; +use alloc::vec::Vec; use cryptoxide::digest::Digest; use cryptoxide::hashing; use cryptoxide::ripemd160::Ripemd160; use cryptoxide::sha3::Keccak256; - +use curve25519_dalek::scalar::Scalar; pub(crate) fn sha256_digest(data: &[u8]) -> Vec { - hashing::sha256(&data).to_vec() + hashing::sha256(&data).to_vec() } fn ripemd160_digest(data: &[u8]) -> [u8; 20] { - let mut hasher = Ripemd160::new(); - hasher.input(data); - let mut output = [0u8; 20]; - hasher.result(&mut output); - output + let mut hasher = Ripemd160::new(); + hasher.input(data); + let mut output = [0u8; 20]; + hasher.result(&mut output); + output } pub fn hash_to_scalar(data: &[u8]) -> Scalar { - Scalar::from_bytes_mod_order(keccak256(data)) + Scalar::from_bytes_mod_order(keccak256(data)) } pub fn hash160(data: &[u8]) -> [u8; 20] { - ripemd160_digest(&sha256_digest(data)) + ripemd160_digest(&sha256_digest(data)) } pub fn keccak256(data: &[u8]) -> [u8; PUBKEY_LEH] { - let mut hasher = Keccak256::new(); - hasher.input(data); - let mut result = [0u8; PUBKEY_LEH]; - hasher.result(&mut result); - result -} \ No newline at end of file + let mut hasher = Keccak256::new(); + hasher.input(data); + let mut result = [0u8; PUBKEY_LEH]; + hasher.result(&mut result); + result +} diff --git a/rust/apps/monero/src/utils/io.rs b/rust/apps/monero/src/utils/io.rs index 6f897f0d3..2640601c9 100644 --- a/rust/apps/monero/src/utils/io.rs +++ b/rust/apps/monero/src/utils/io.rs @@ -1,159 +1,162 @@ -use alloc::vec; -use alloc::vec::Vec; -use alloc::string::String; -use crate::utils::varinteger::*; use crate::transfer::{ - TxConstructionData, TxDestinationEntry, OutputEntry, - TxSourceEntry, AccountPublicAddress, + AccountPublicAddress, OutputEntry, TxConstructionData, TxDestinationEntry, TxSourceEntry, }; +use crate::utils::varinteger::*; +use alloc::string::String; +use alloc::vec; +use alloc::vec::Vec; pub fn read_varinteger(data: &[u8], offset: &mut usize) -> u64 { - let mut value = 0u64; - *offset += decode_with_offset(data, *offset, &mut value); + let mut value = 0u64; + *offset += decode_with_offset(data, *offset, &mut value); - value + value } pub fn write_varinteger(value: u64) -> Vec { - let mut buffer = vec![0u8; length(value)]; - encode_with_offset(value, &mut buffer, 0); - buffer + let mut buffer = vec![0u8; length(value)]; + encode_with_offset(value, &mut buffer, 0); + buffer } - pub fn read_next_u8(bytes: &[u8], offset: &mut usize) -> u8 { - let value = u8::from_le_bytes(bytes[*offset..*offset + 1].try_into().unwrap()); - *offset += 1; - value + let value = u8::from_le_bytes(bytes[*offset..*offset + 1].try_into().unwrap()); + *offset += 1; + value } pub fn read_next_u32(bytes: &[u8], offset: &mut usize) -> u32 { - let value = u32::from_le_bytes(bytes[*offset..*offset + 4].try_into().unwrap()); - *offset += 4; - value + let value = u32::from_le_bytes(bytes[*offset..*offset + 4].try_into().unwrap()); + *offset += 4; + value } pub fn read_next_u64(bytes: &[u8], offset: &mut usize) -> u64 { - let value = u64::from_le_bytes(bytes[*offset..*offset + 8].try_into().unwrap()); - *offset += 8; - value + let value = u64::from_le_bytes(bytes[*offset..*offset + 8].try_into().unwrap()); + *offset += 8; + value } pub fn read_next_bool(bytes: &[u8], offset: &mut usize) -> bool { - read_next_u8(bytes, offset) != 0 + read_next_u8(bytes, offset) != 0 } pub fn read_next_vec_u8(bytes: &[u8], offset: &mut usize, len: usize) -> Vec { - let value = bytes[*offset..*offset + len].to_vec(); - *offset += len; - value + let value = bytes[*offset..*offset + len].to_vec(); + *offset += len; + value } pub fn read_next_tx_destination_entry(bytes: &[u8], offset: &mut usize) -> TxDestinationEntry { - let original_len = read_varinteger(bytes, offset) as usize; - let original = String::from_utf8(bytes[*offset..*offset + original_len].to_vec()).unwrap(); - *offset += original_len; - let amount = read_varinteger(bytes, offset); - let mut spend_public_key = [0u8; 32]; - spend_public_key.copy_from_slice(&bytes[*offset..*offset + 32]); - *offset += 32; - let mut view_public_key = [0u8; 32]; - view_public_key.copy_from_slice(&bytes[*offset..*offset + 32]); - *offset += 32; - let is_subaddress = read_next_bool(bytes, offset); - let is_integrated = read_next_bool(bytes, offset); - TxDestinationEntry { - original, - amount, - addr: AccountPublicAddress { spend_public_key, view_public_key }, - is_subaddress, - is_integrated, - } + let original_len = read_varinteger(bytes, offset) as usize; + let original = String::from_utf8(bytes[*offset..*offset + original_len].to_vec()).unwrap(); + *offset += original_len; + let amount = read_varinteger(bytes, offset); + let mut spend_public_key = [0u8; 32]; + spend_public_key.copy_from_slice(&bytes[*offset..*offset + 32]); + *offset += 32; + let mut view_public_key = [0u8; 32]; + view_public_key.copy_from_slice(&bytes[*offset..*offset + 32]); + *offset += 32; + let is_subaddress = read_next_bool(bytes, offset); + let is_integrated = read_next_bool(bytes, offset); + TxDestinationEntry { + original, + amount, + addr: AccountPublicAddress { + spend_public_key, + view_public_key, + }, + is_subaddress, + is_integrated, + } } pub fn write_tx_destination_entry(entry: &TxDestinationEntry) -> Vec { - let mut buffer = Vec::new(); - buffer.extend_from_slice(&write_varinteger(entry.original.len() as u64)); - buffer.extend_from_slice(entry.original.as_bytes()); - buffer.extend_from_slice(&write_varinteger(entry.amount)); - buffer.extend_from_slice(&entry.addr.spend_public_key); - buffer.extend_from_slice(&entry.addr.view_public_key); - buffer.push(entry.is_subaddress as u8); - buffer.push(entry.is_integrated as u8); - buffer + let mut buffer = Vec::new(); + buffer.extend_from_slice(&write_varinteger(entry.original.len() as u64)); + buffer.extend_from_slice(entry.original.as_bytes()); + buffer.extend_from_slice(&write_varinteger(entry.amount)); + buffer.extend_from_slice(&entry.addr.spend_public_key); + buffer.extend_from_slice(&entry.addr.view_public_key); + buffer.push(entry.is_subaddress as u8); + buffer.push(entry.is_integrated as u8); + buffer } pub fn write_output_entry(entry: &OutputEntry) -> Vec { - let mut buffer = Vec::new(); - buffer.push(2u8); - buffer.extend_from_slice(&write_varinteger(entry.index)); - buffer.extend_from_slice(&entry.key.dest); - buffer.extend_from_slice(&entry.key.mask); - buffer + let mut buffer = Vec::new(); + buffer.push(2u8); + buffer.extend_from_slice(&write_varinteger(entry.index)); + buffer.extend_from_slice(&entry.key.dest); + buffer.extend_from_slice(&entry.key.mask); + buffer } pub fn write_tx_source_entry(entry: &TxSourceEntry) -> Vec { - let mut buffer = Vec::new(); - buffer.extend_from_slice(&write_varinteger(entry.outputs.len() as u64)); - for output in entry.outputs.iter() { - buffer.extend_from_slice(&write_output_entry(output)); - } - buffer.extend_from_slice(&entry.real_output.to_le_bytes()); - buffer.extend_from_slice(&entry.real_out_tx_key); - buffer.extend_from_slice(&write_varinteger(entry.real_out_additional_tx_keys.len() as u64)); - for key in entry.real_out_additional_tx_keys.iter() { - buffer.extend_from_slice(key); - } - buffer.extend_from_slice(&entry.real_output_in_tx_index.to_le_bytes()); - buffer.extend_from_slice(&entry.amount.to_le_bytes()); - buffer.push(entry.rct as u8); - buffer.extend_from_slice(&entry.mask); - buffer.extend_from_slice(&entry.multisig_kLRki.k); - buffer.extend_from_slice(&entry.multisig_kLRki.L); - buffer.extend_from_slice(&entry.multisig_kLRki.R); - buffer.extend_from_slice(&entry.multisig_kLRki.ki); - buffer + let mut buffer = Vec::new(); + buffer.extend_from_slice(&write_varinteger(entry.outputs.len() as u64)); + for output in entry.outputs.iter() { + buffer.extend_from_slice(&write_output_entry(output)); + } + buffer.extend_from_slice(&entry.real_output.to_le_bytes()); + buffer.extend_from_slice(&entry.real_out_tx_key); + buffer.extend_from_slice(&write_varinteger( + entry.real_out_additional_tx_keys.len() as u64 + )); + for key in entry.real_out_additional_tx_keys.iter() { + buffer.extend_from_slice(key); + } + buffer.extend_from_slice(&entry.real_output_in_tx_index.to_le_bytes()); + buffer.extend_from_slice(&entry.amount.to_le_bytes()); + buffer.push(entry.rct as u8); + buffer.extend_from_slice(&entry.mask); + buffer.extend_from_slice(&entry.multisig_kLRki.k); + buffer.extend_from_slice(&entry.multisig_kLRki.L); + buffer.extend_from_slice(&entry.multisig_kLRki.R); + buffer.extend_from_slice(&entry.multisig_kLRki.ki); + buffer } pub fn write_tx_construction_data(data: &TxConstructionData) -> Vec { - let mut buffer = Vec::new(); - buffer.extend_from_slice(&write_varinteger(data.sources.len() as u64)); - for source in data.sources.iter() { - buffer.extend_from_slice(&write_tx_source_entry(source)); - } - buffer.extend_from_slice(&write_tx_destination_entry(&data.change_dts)); - buffer.extend_from_slice(&write_varinteger(data.splitted_dsts.len() as u64)); - for dst in data.splitted_dsts.iter() { - buffer.extend_from_slice(&write_tx_destination_entry(dst)); - } - buffer.extend_from_slice(&write_varinteger(data.selected_transfers.len() as u64)); - for transfer in data.selected_transfers.iter() { - buffer.extend_from_slice(&write_varinteger(*transfer as u64)); - } - buffer.extend_from_slice(&write_varinteger(data.extra.len() as u64)); - buffer.extend_from_slice(&data.extra); - buffer.extend_from_slice(&data.unlock_time.to_le_bytes()); - buffer.push(data.use_rct as u8); - buffer.extend_from_slice(&write_varinteger(data.rct_config.version as u64)); - buffer.extend_from_slice(&write_varinteger(data.rct_config.range_proof_type as u64)); - buffer.extend_from_slice(&write_varinteger(data.rct_config.bp_version as u64)); - // dests - buffer.extend_from_slice(&write_varinteger(data.dests.len() as u64)); - for dest in data.dests.iter() { - buffer.extend_from_slice(&write_tx_destination_entry(dest)); - } - buffer.extend_from_slice(&data.subaddr_account.to_le_bytes()); - buffer.extend_from_slice(&write_varinteger(data.subaddr_indices.len() as u64)); - for index in data.subaddr_indices.iter() { - buffer.extend_from_slice(&write_varinteger(*index as u64)); - } - buffer + let mut buffer = Vec::new(); + buffer.extend_from_slice(&write_varinteger(data.sources.len() as u64)); + for source in data.sources.iter() { + buffer.extend_from_slice(&write_tx_source_entry(source)); + } + buffer.extend_from_slice(&write_tx_destination_entry(&data.change_dts)); + buffer.extend_from_slice(&write_varinteger(data.splitted_dsts.len() as u64)); + for dst in data.splitted_dsts.iter() { + buffer.extend_from_slice(&write_tx_destination_entry(dst)); + } + buffer.extend_from_slice(&write_varinteger(data.selected_transfers.len() as u64)); + for transfer in data.selected_transfers.iter() { + buffer.extend_from_slice(&write_varinteger(*transfer as u64)); + } + buffer.extend_from_slice(&write_varinteger(data.extra.len() as u64)); + buffer.extend_from_slice(&data.extra); + buffer.extend_from_slice(&data.unlock_time.to_le_bytes()); + buffer.push(data.use_rct as u8); + buffer.extend_from_slice(&write_varinteger(data.rct_config.version as u64)); + buffer.extend_from_slice(&write_varinteger(data.rct_config.range_proof_type as u64)); + buffer.extend_from_slice(&write_varinteger(data.rct_config.bp_version as u64)); + // dests + buffer.extend_from_slice(&write_varinteger(data.dests.len() as u64)); + for dest in data.dests.iter() { + buffer.extend_from_slice(&write_tx_destination_entry(dest)); + } + buffer.extend_from_slice(&data.subaddr_account.to_le_bytes()); + buffer.extend_from_slice(&write_varinteger(data.subaddr_indices.len() as u64)); + for index in data.subaddr_indices.iter() { + buffer.extend_from_slice(&write_varinteger(*index as u64)); + } + buffer } pub fn read_next_u8_32(bytes: &[u8], offset: &mut usize) -> [u8; 32] { - let mut data = [0u8; 32]; - data.copy_from_slice(&bytes[*offset..*offset + 32]); - *offset += 32; + let mut data = [0u8; 32]; + data.copy_from_slice(&bytes[*offset..*offset + 32]); + *offset += 32; - data -} \ No newline at end of file + data +} diff --git a/rust/apps/monero/src/utils/mod.rs b/rust/apps/monero/src/utils/mod.rs index 0a2d18036..b1eb6671b 100644 --- a/rust/apps/monero/src/utils/mod.rs +++ b/rust/apps/monero/src/utils/mod.rs @@ -1,26 +1,26 @@ -use crate::key::{KeyPair, PrivateKey, PublicKey}; use crate::errors::{MoneroError, Result}; +use crate::key::{KeyPair, PrivateKey, PublicKey}; +use crate::key_images::Keyimage; +use crate::slow_hash::cryptonight_hash_v0; +use crate::utils::sign::*; +use crate::utils::{constants::*, hash::*}; +use alloc::format; use alloc::string::{String, ToString}; use alloc::vec; -use alloc::format; use alloc::vec::Vec; use chacha20::cipher::{generic_array::GenericArray, KeyIvInit, StreamCipher}; use chacha20::ChaCha20Legacy; -use crate::slow_hash::cryptonight_hash_v0; -use crate::utils::{hash::*, constants::*}; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::traits::{IsIdentity, MultiscalarMul}; -use rand_core::{RngCore, CryptoRng, SeedableRng}; -use crate::utils::sign::*; use monero_serai_mirror::transaction::Input; -use crate::key_images::Keyimage; +use rand_core::{CryptoRng, RngCore, SeedableRng}; -pub mod varinteger; +pub mod constants; pub mod hash; pub mod io; -pub mod constants; pub mod sign; +pub mod varinteger; pub struct DecryptUrData { pub pk1: Option, @@ -105,7 +105,11 @@ pub fn encrypt_data_with_pvk(keypair: KeyPair, data: Vec, magic: &str) -> Ve [magic_bytes, &nonce_num, &buffer].concat() } -pub fn decrypt_data_with_pvk(pvk: [u8; PUBKEY_LEH], data: Vec, magic: &str) -> Result { +pub fn decrypt_data_with_pvk( + pvk: [u8; PUBKEY_LEH], + data: Vec, + magic: &str, +) -> Result { if pvk.len() != PUBKEY_LEH { return Err(MoneroError::InvalidPrivateViewKey); } @@ -114,7 +118,12 @@ pub fn decrypt_data_with_pvk(pvk: [u8; PUBKEY_LEH], data: Vec, magic: &str) decrypt_data_with_decrypt_key(pvk_hash, pvk, data, magic) } -pub fn decrypt_data_with_decrypt_key(decrypt_key: [u8; PUBKEY_LEH], pvk: [u8; PUBKEY_LEH], data: Vec, magic: &str) -> Result { +pub fn decrypt_data_with_decrypt_key( + decrypt_key: [u8; PUBKEY_LEH], + pvk: [u8; PUBKEY_LEH], + data: Vec, + magic: &str, +) -> Result { let key = GenericArray::from_slice(&decrypt_key); let magic_bytes = magic.as_bytes(); @@ -188,13 +197,11 @@ pub fn generate_random_scalar(rng: &mut R) -> Scalar { pub fn get_key_image_from_input(input: Input) -> Result { match input { - Input::ToKey { key_image, .. } => - Ok(Keyimage::new(key_image.compress().to_bytes())), + Input::ToKey { key_image, .. } => Ok(Keyimage::new(key_image.compress().to_bytes())), _ => Err(MoneroError::UnsupportedInputType), } } - pub fn fmt_monero_amount(value: u64) -> String { let value = value as f64 / 1_000_000_000_000.0; let value = format!("{:.12}", value); @@ -289,7 +296,12 @@ mod tests { let rng_seed = [0u8; 32]; let mut rng = rand_chacha::ChaCha20Rng::from_seed(rng_seed); - let res = decrypt_data_with_pvk(pvk.clone().try_into().unwrap(), data.clone(), OUTPUT_EXPORT_MAGIC).unwrap(); + let res = decrypt_data_with_pvk( + pvk.clone().try_into().unwrap(), + data.clone(), + OUTPUT_EXPORT_MAGIC, + ) + .unwrap(); assert_eq!( hex::encode(res.hash.clone()), "5853d87db51d4d3c0a00b86d06897361b9e49f742fd02988abf6aeca585b988d" @@ -299,8 +311,13 @@ mod tests { "03000707013e8c52245d21b22cbcb90f95270a7937d4974d726209f0a41fdefc7f9df01fde01c8b486383e45d72b841a8b76094dbaa26f9800aac4eaced3bc06122a3380bcf6c666d2281480a0b787e905000000012d58a6378c07f230148c11979cc6e3bec2719f0ec92de21f7fae02029ab025e000f385873857dc102abc6d35c878db7be629646658ae1a418afb27a943f8a2591be4f450e9148094ebdc03000001014ef323a52d2e048594ad73acbe5fb7e588b1859ec9aa02b2670f487660b2700901f485873857dc102abc6d35c878db7be629646658ae1a418afb27a943f8a2591be4f450e914c0b5809ce50500000001cb8ab3c1b4dd10404a4a3c9275a7e2e1e9bf2e4edf1c84f61952bb97965573a300d0c78a38bdd50fdc0367b3141fdc055dec3af5e3ac920dd55816823dfe02f70c3d1816431480c2d72f00000301dd8c2a791056760d903bf06e7930585201e0bd20bcba1e720b85ad0e4d628e4801d1c78a38bdd50fdc0367b3141fdc055dec3af5e3ac920dd55816823dfe02f70c3d18164314a0eec19e03000000019b65ada69049d73e4b049ebd50393410cdc05dad5314690d2b4a36628c4e257600a4909d385d43421399107bd34350b8938f9ff69da18e8f083e6522adf6aa270b3f370ed41480e8eda1ba01000100016311ba60a0a8c636806e232db3e1ad7f79e26df3d24258e264e4351e47f4374d01a5909d385d43421399107bd34350b8938f9ff69da18e8f083e6522adf6aa270b3f370ed414c0c2b383ae04000000" ); - let sig = generate_signature(&res.hash, &res.pk2.unwrap(), &PrivateKey::from_bytes(&pvk), &mut rng) - .unwrap(); + let sig = generate_signature( + &res.hash, + &res.pk2.unwrap(), + &PrivateKey::from_bytes(&pvk), + &mut rng, + ) + .unwrap(); assert!(check_signature(&res.hash, &res.pk2.unwrap(), &sig)); } @@ -315,9 +332,7 @@ mod tests { hex::decode("7bb35441e077be8bb8d77d849c926bf1dd0e696c1c83017e648c20513d2d6907") .unwrap(); - let mut rng = rand_chacha::ChaCha20Rng::from_seed( - hash.clone().try_into().unwrap() - ); + let mut rng = rand_chacha::ChaCha20Rng::from_seed(hash.clone().try_into().unwrap()); let sig = generate_signature( &hash, diff --git a/rust/apps/monero/src/utils/sign.rs b/rust/apps/monero/src/utils/sign.rs index a75e256e9..1104f0232 100644 --- a/rust/apps/monero/src/utils/sign.rs +++ b/rust/apps/monero/src/utils/sign.rs @@ -1,6 +1,6 @@ -use alloc::vec::Vec; use crate::key::*; use crate::utils::*; +use alloc::vec::Vec; pub struct Signature(pub [u8; 64]); @@ -11,129 +11,129 @@ impl From for Vec { } pub fn generate_signature( - hash: &[u8], - pubkey: &PublicKey, - seckey: &PrivateKey, - rng: &mut R, + hash: &[u8], + pubkey: &PublicKey, + seckey: &PrivateKey, + rng: &mut R, ) -> Option { - if seckey.get_public_key().point != pubkey.point { - return None; - } - let mut c; - let mut r; - - loop { - let k = generate_random_scalar(rng); - let temp3 = EdwardsPoint::mul_base(&k); - - let data = [hash, pubkey.point.as_bytes(), temp3.compress().as_bytes()].concat(); - c = hash_to_scalar(&data); - if c == Scalar::ZERO { - continue; - } - r = k - c * seckey.scalar; - if r == Scalar::ZERO { - continue; - } - break; - } - - Some(Signature( - [c.to_bytes(), r.to_bytes()].concat().try_into().unwrap(), - )) + if seckey.get_public_key().point != pubkey.point { + return None; + } + let mut c; + let mut r; + + loop { + let k = generate_random_scalar(rng); + let temp3 = EdwardsPoint::mul_base(&k); + + let data = [hash, pubkey.point.as_bytes(), temp3.compress().as_bytes()].concat(); + c = hash_to_scalar(&data); + if c == Scalar::ZERO { + continue; + } + r = k - c * seckey.scalar; + if r == Scalar::ZERO { + continue; + } + break; + } + + Some(Signature( + [c.to_bytes(), r.to_bytes()].concat().try_into().unwrap(), + )) } pub fn check_signature(hash: &[u8], pubkey: &PublicKey, sig: &Signature) -> bool { - let sig = sig.0.to_vec(); - let c = &sig[..32]; - let r = &sig[32..]; - let point = pubkey.point.decompress().unwrap(); - - let scalar_a = Scalar::from_canonical_bytes(c.try_into().unwrap()); - let scalar_b = Scalar::from_canonical_bytes(r.try_into().unwrap()); - let is_valid_a: bool = scalar_a.is_some().into(); - let is_valid_b: bool = scalar_b.is_some().into(); - if !is_valid_a || !is_valid_b || scalar_b.unwrap() == Scalar::ZERO { - return false; - } - let result_point = EdwardsPoint::vartime_double_scalar_mul_basepoint( - &scalar_a.unwrap(), - &point, - &scalar_b.unwrap(), - ); - - if result_point.is_identity() { - return false; - } - - let data = [ - hash, - pubkey.point.as_bytes(), - result_point.compress().as_bytes(), - ] - .concat(); - let c2 = hash_to_scalar(&data); - - let res = c2 - Scalar::from_bytes_mod_order(c.try_into().unwrap()); - - res == Scalar::ZERO + let sig = sig.0.to_vec(); + let c = &sig[..32]; + let r = &sig[32..]; + let point = pubkey.point.decompress().unwrap(); + + let scalar_a = Scalar::from_canonical_bytes(c.try_into().unwrap()); + let scalar_b = Scalar::from_canonical_bytes(r.try_into().unwrap()); + let is_valid_a: bool = scalar_a.is_some().into(); + let is_valid_b: bool = scalar_b.is_some().into(); + if !is_valid_a || !is_valid_b || scalar_b.unwrap() == Scalar::ZERO { + return false; + } + let result_point = EdwardsPoint::vartime_double_scalar_mul_basepoint( + &scalar_a.unwrap(), + &point, + &scalar_b.unwrap(), + ); + + if result_point.is_identity() { + return false; + } + + let data = [ + hash, + pubkey.point.as_bytes(), + result_point.compress().as_bytes(), + ] + .concat(); + let c2 = hash_to_scalar(&data); + + let res = c2 - Scalar::from_bytes_mod_order(c.try_into().unwrap()); + + res == Scalar::ZERO } pub fn generate_ring_signature( - prefix_hash: &[u8; 32], - key_image: &EdwardsPoint, - pubs: Vec, - sec: &PrivateKey, - sec_idx: usize, - rng: &mut R, + prefix_hash: &[u8; 32], + key_image: &EdwardsPoint, + pubs: Vec, + sec: &PrivateKey, + sec_idx: usize, + rng: &mut R, ) -> Vec<[Scalar; 2]> { - if sec_idx >= pubs.len() { - panic!("Invalid sec_idx"); - } - - let buffer_len = 32 + 2 * 32 * pubs.len(); - let mut sig = vec![[Scalar::ZERO, Scalar::ZERO]; pubs.len()]; - let mut buff = Vec::new(); - buff.extend_from_slice(prefix_hash); - let mut sum = Scalar::ZERO; - let mut k = Scalar::ZERO; - - for index in 0..pubs.len() { - if index == sec_idx { - k = generate_random_scalar(rng); - let tmp3 = EdwardsPoint::mul_base(&k); - buff.extend_from_slice(&tmp3.compress().0); - - let tmp3 = monero_generators_mirror::hash_to_point(pubs[index].point.0); - let temp2 = k * tmp3; - buff.extend_from_slice(&temp2.compress().0); - } else { - sig[index][0] = generate_random_scalar(rng); - sig[index][1] = generate_random_scalar(rng); - let tmp3 = pubs[index].point.decompress().unwrap(); - let temp2 = EdwardsPoint::vartime_double_scalar_mul_basepoint( - &sig[index][0], - &tmp3, - &sig[index][1], - ); - buff.extend_from_slice(&temp2.compress().0); - let tmp3 = monero_generators_mirror::hash_to_point(tmp3.compress().0); - let tmp2 = EdwardsPoint::multiscalar_mul( - &[sig[index][1], sig[index][0]], - &[tmp3, key_image.clone()], - ); - buff.extend_from_slice(&tmp2.compress().0); - sum += sig[index][0]; - } - } - - let h = hash_to_scalar(&buff); - sig[sec_idx][0] = h - sum; - sig[sec_idx][1] = k - sig[sec_idx][0] * sec.scalar; - - if buffer_len != buff.len() { - panic!("Invalid buffer_len"); - } - - sig + if sec_idx >= pubs.len() { + panic!("Invalid sec_idx"); + } + + let buffer_len = 32 + 2 * 32 * pubs.len(); + let mut sig = vec![[Scalar::ZERO, Scalar::ZERO]; pubs.len()]; + let mut buff = Vec::new(); + buff.extend_from_slice(prefix_hash); + let mut sum = Scalar::ZERO; + let mut k = Scalar::ZERO; + + for index in 0..pubs.len() { + if index == sec_idx { + k = generate_random_scalar(rng); + let tmp3 = EdwardsPoint::mul_base(&k); + buff.extend_from_slice(&tmp3.compress().0); + + let tmp3 = monero_generators_mirror::hash_to_point(pubs[index].point.0); + let temp2 = k * tmp3; + buff.extend_from_slice(&temp2.compress().0); + } else { + sig[index][0] = generate_random_scalar(rng); + sig[index][1] = generate_random_scalar(rng); + let tmp3 = pubs[index].point.decompress().unwrap(); + let temp2 = EdwardsPoint::vartime_double_scalar_mul_basepoint( + &sig[index][0], + &tmp3, + &sig[index][1], + ); + buff.extend_from_slice(&temp2.compress().0); + let tmp3 = monero_generators_mirror::hash_to_point(tmp3.compress().0); + let tmp2 = EdwardsPoint::multiscalar_mul( + &[sig[index][1], sig[index][0]], + &[tmp3, key_image.clone()], + ); + buff.extend_from_slice(&tmp2.compress().0); + sum += sig[index][0]; + } + } + + let h = hash_to_scalar(&buff); + sig[sec_idx][0] = h - sum; + sig[sec_idx][1] = k - sig[sec_idx][0] * sec.scalar; + + if buffer_len != buff.len() { + panic!("Invalid buffer_len"); + } + + sig } diff --git a/rust/apps/monero/src/utils/varinteger.rs b/rust/apps/monero/src/utils/varinteger.rs index fab90b9f7..da0e61b1a 100644 --- a/rust/apps/monero/src/utils/varinteger.rs +++ b/rust/apps/monero/src/utils/varinteger.rs @@ -134,4 +134,4 @@ mod tests { assert_eq!(decode(&buf, &mut value), 2); assert_eq!(value, 268); } -} \ No newline at end of file +}