From 3a1c6c7247c4cd0b5f8fefc55ae6967ecf8c3eee Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sun, 16 Jun 2024 12:26:14 -0400 Subject: [PATCH] Tidy up monero-serai as a meta crate --- coins/monero/src/bin/reserialize_chain.rs | 2 +- coins/monero/src/block.rs | 6 +-- coins/monero/src/lib.rs | 51 +++++-------------- coins/monero/src/merkle.rs | 8 +-- coins/monero/src/ring_signatures.rs | 6 +-- coins/monero/src/{ringct/mod.rs => ringct.rs} | 14 ++--- coins/monero/src/ringct/hash_to_point.rs | 8 --- coins/monero/src/tests/seed.rs | 15 +++--- coins/monero/src/transaction.rs | 21 ++++---- coins/monero/src/wallet/address.rs | 2 +- coins/monero/src/wallet/extra.rs | 5 +- coins/monero/src/wallet/mod.rs | 22 ++++---- coins/monero/src/wallet/scan.rs | 4 +- coins/monero/src/wallet/send/mod.rs | 12 ++--- tests/full-stack/src/tests/mint_and_burn.rs | 2 +- tests/processor/src/networks.rs | 2 +- 16 files changed, 68 insertions(+), 112 deletions(-) rename coins/monero/src/{ringct/mod.rs => ringct.rs} (96%) delete mode 100644 coins/monero/src/ringct/hash_to_point.rs diff --git a/coins/monero/src/bin/reserialize_chain.rs b/coins/monero/src/bin/reserialize_chain.rs index 9cc5e7cf..fcaa78af 100644 --- a/coins/monero/src/bin/reserialize_chain.rs +++ b/coins/monero/src/bin/reserialize_chain.rs @@ -8,7 +8,7 @@ mod binaries { pub(crate) use serde_json::json; pub(crate) use monero_serai::{ - Commitment, + primitives::Commitment, ringct::{RctPrunable, bulletproofs::BatchVerifier}, transaction::{Input, Transaction}, block::Block, diff --git a/coins/monero/src/block.rs b/coins/monero/src/block.rs index b4e97169..832caae5 100644 --- a/coins/monero/src/block.rs +++ b/coins/monero/src/block.rs @@ -4,9 +4,9 @@ use std_shims::{ }; use crate::{ - hash, + io::*, + primitives::keccak256, merkle::merkle_root, - serialize::*, transaction::{Input, Transaction}, }; @@ -99,7 +99,7 @@ impl Block { write_varint(&u64::try_from(hashable.len()).unwrap(), &mut hashing_blob).unwrap(); hashing_blob.append(&mut hashable); - let hash = hash(&hashing_blob); + let hash = keccak256(hashing_blob); if hash == CORRECT_BLOCK_HASH_202612 { return EXISTING_BLOCK_HASH_202612; }; diff --git a/coins/monero/src/lib.rs b/coins/monero/src/lib.rs index c03d4af4..76c6cdc4 100644 --- a/coins/monero/src/lib.rs +++ b/coins/monero/src/lib.rs @@ -2,21 +2,13 @@ #![doc = include_str!("../README.md")] #![cfg_attr(not(feature = "std"), no_std)] -#[cfg(not(feature = "std"))] -#[macro_use] -extern crate alloc; - -use std_shims::io; +use std_shims::io as stdio; use zeroize::Zeroize; -use sha3::{Digest, Keccak256}; - -use curve25519_dalek::scalar::Scalar; - -pub use monero_io::decompress_point; -pub use monero_generators::H; -pub use monero_primitives::INV_EIGHT; +pub use monero_io as io; +pub use monero_generators as generators; +pub use monero_primitives as primitives; mod merkle; @@ -114,7 +106,7 @@ impl Protocol { } } - pub(crate) fn write(&self, w: &mut W) -> io::Result<()> { + pub(crate) fn write(&self, w: &mut W) -> stdio::Result<()> { match self { Protocol::v14 => w.write_all(&[0, 14]), Protocol::v16 => w.write_all(&[0, 16]), @@ -130,13 +122,13 @@ impl Protocol { } } - pub(crate) fn read(r: &mut R) -> io::Result { + pub(crate) fn read(r: &mut R) -> stdio::Result { Ok(match read_byte(r)? { // Monero protocol 0 => match read_byte(r)? { 14 => Protocol::v14, 16 => Protocol::v16, - _ => Err(io::Error::other("unrecognized monero protocol"))?, + _ => Err(stdio::Error::other("unrecognized monero protocol"))?, }, // Custom 1 => match read_byte(r)? { @@ -145,41 +137,24 @@ impl Protocol { bp_plus: match read_byte(r)? { 0 => false, 1 => true, - _ => Err(io::Error::other("invalid bool serialization"))?, + _ => Err(stdio::Error::other("invalid bool serialization"))?, }, optimal_rct_type: RctType::from_byte(read_byte(r)?) - .ok_or_else(|| io::Error::other("invalid RctType serialization"))?, + .ok_or_else(|| stdio::Error::other("invalid RctType serialization"))?, view_tags: match read_byte(r)? { 0 => false, 1 => true, - _ => Err(io::Error::other("invalid bool serialization"))?, + _ => Err(stdio::Error::other("invalid bool serialization"))?, }, v16_fee: match read_byte(r)? { 0 => false, 1 => true, - _ => Err(io::Error::other("invalid bool serialization"))?, + _ => Err(stdio::Error::other("invalid bool serialization"))?, }, }, - _ => Err(io::Error::other("unrecognized custom protocol serialization"))?, + _ => Err(stdio::Error::other("unrecognized custom protocol serialization"))?, }, - _ => Err(io::Error::other("unrecognized protocol serialization"))?, + _ => Err(stdio::Error::other("unrecognized protocol serialization"))?, }) } } - -pub use monero_primitives::Commitment; - -pub(crate) fn hash(data: &[u8]) -> [u8; 32] { - Keccak256::digest(data).into() -} - -/// Hash the provided data to a scalar via keccak256(data) % l. -pub fn hash_to_scalar(data: &[u8]) -> Scalar { - let scalar = Scalar::from_bytes_mod_order(hash(data)); - // Monero will explicitly error in this case - // This library acknowledges its practical impossibility of it occurring, and doesn't bother to - // code in logic to handle it. That said, if it ever occurs, something must happen in order to - // not generate/verify a proof we believe to be valid when it isn't - assert!(scalar != Scalar::ZERO, "ZERO HASH: {data:?}"); - scalar -} diff --git a/coins/monero/src/merkle.rs b/coins/monero/src/merkle.rs index 8123b902..6c689618 100644 --- a/coins/monero/src/merkle.rs +++ b/coins/monero/src/merkle.rs @@ -1,11 +1,11 @@ use std_shims::vec::Vec; -use crate::hash; +use crate::primitives::keccak256; pub(crate) fn merkle_root(root: [u8; 32], leafs: &[[u8; 32]]) -> [u8; 32] { match leafs.len() { 0 => root, - 1 => hash(&[root, leafs[0]].concat()), + 1 => keccak256([root, leafs[0]].concat()), _ => { let mut hashes = Vec::with_capacity(1 + leafs.len()); hashes.push(root); @@ -29,7 +29,7 @@ pub(crate) fn merkle_root(root: [u8; 32], leafs: &[[u8; 32]]) -> [u8; 32] { let mut paired_hashes = Vec::with_capacity(overage); while let Some(left) = rightmost.next() { let right = rightmost.next().unwrap(); - paired_hashes.push(hash(&[left.as_ref(), &right].concat())); + paired_hashes.push(keccak256([left.as_ref(), &right].concat())); } drop(rightmost); @@ -42,7 +42,7 @@ pub(crate) fn merkle_root(root: [u8; 32], leafs: &[[u8; 32]]) -> [u8; 32] { while hashes.len() > 1 { let mut i = 0; while i < hashes.len() { - new_hashes.push(hash(&[hashes[i], hashes[i + 1]].concat())); + new_hashes.push(keccak256([hashes[i], hashes[i + 1]].concat())); i += 2; } diff --git a/coins/monero/src/ring_signatures.rs b/coins/monero/src/ring_signatures.rs index 72d30b0e..77528a96 100644 --- a/coins/monero/src/ring_signatures.rs +++ b/coins/monero/src/ring_signatures.rs @@ -7,9 +7,7 @@ use zeroize::Zeroize; use curve25519_dalek::{EdwardsPoint, Scalar}; -use monero_generators::hash_to_point; - -use crate::{serialize::*, hash_to_scalar}; +use crate::{io::*, generators::hash_to_point, primitives::keccak256_to_scalar}; #[derive(Clone, PartialEq, Eq, Debug, Zeroize)] pub struct Signature { @@ -67,6 +65,6 @@ impl RingSignature { sum += sig.c; } - sum == hash_to_scalar(&buf) + sum == keccak256_to_scalar(buf) } } diff --git a/coins/monero/src/ringct/mod.rs b/coins/monero/src/ringct.rs similarity index 96% rename from coins/monero/src/ringct/mod.rs rename to coins/monero/src/ringct.rs index 70cefc53..8278c4b7 100644 --- a/coins/monero/src/ringct/mod.rs +++ b/coins/monero/src/ringct.rs @@ -8,27 +8,21 @@ use zeroize::{Zeroize, Zeroizing}; use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint}; -pub(crate) mod hash_to_point; -pub use hash_to_point::{raw_hash_to_point, hash_to_point}; - -/// MLSAG struct, along with verifying functionality. pub use monero_mlsag as mlsag; -/// CLSAG struct, along with signing and verifying functionality. pub use monero_clsag as clsag; -/// BorromeanRange struct, along with verifying functionality. pub use monero_borromean as borromean; -/// Bulletproofs(+) structs, along with proving and verifying functionality. pub use monero_bulletproofs as bulletproofs; use crate::{ - Protocol, - serialize::*, + io::*, + generators::hash_to_point, ringct::{mlsag::Mlsag, clsag::Clsag, borromean::BorromeanRange, bulletproofs::Bulletproof}, + Protocol, }; /// Generate a key image for a given key. Defined as `x * hash_to_point(xG)`. pub fn generate_key_image(secret: &Zeroizing) -> EdwardsPoint { - hash_to_point(&(ED25519_BASEPOINT_TABLE * secret.deref())) * secret.deref() + hash_to_point((ED25519_BASEPOINT_TABLE * secret.deref()).compress().to_bytes()) * secret.deref() } /// An encrypted amount. diff --git a/coins/monero/src/ringct/hash_to_point.rs b/coins/monero/src/ringct/hash_to_point.rs deleted file mode 100644 index a36b6ee7..00000000 --- a/coins/monero/src/ringct/hash_to_point.rs +++ /dev/null @@ -1,8 +0,0 @@ -use curve25519_dalek::edwards::EdwardsPoint; - -pub use monero_generators::{hash_to_point as raw_hash_to_point}; - -/// Monero's hash to point function, as named `ge_fromfe_frombytes_vartime`. -pub fn hash_to_point(key: &EdwardsPoint) -> EdwardsPoint { - raw_hash_to_point(key.compress().to_bytes()) -} diff --git a/coins/monero/src/tests/seed.rs b/coins/monero/src/tests/seed.rs index 2c421abe..d62beac5 100644 --- a/coins/monero/src/tests/seed.rs +++ b/coins/monero/src/tests/seed.rs @@ -4,13 +4,12 @@ use rand_core::OsRng; use curve25519_dalek::scalar::Scalar; -use crate::{ - hash, - wallet::seed::{ - Seed, SeedType, SeedError, - classic::{self, trim_by_lang}, - polyseed, - }, +use monero_primitives::keccak256; + +use crate::wallet::seed::{ + Seed, SeedType, SeedError, + classic::{self, trim_by_lang}, + polyseed, }; #[test] @@ -217,7 +216,7 @@ fn test_classic_seed() { let view: [u8; 32] = hex::decode(vector.view).unwrap().try_into().unwrap(); // Monero then derives the view key as H(spend) assert_eq!( - Scalar::from_bytes_mod_order(hash(&spend)), + Scalar::from_bytes_mod_order(keccak256(spend)), Scalar::from_canonical_bytes(view).unwrap() ); diff --git a/coins/monero/src/transaction.rs b/coins/monero/src/transaction.rs index 2d351ff1..5d27e924 100644 --- a/coins/monero/src/transaction.rs +++ b/coins/monero/src/transaction.rs @@ -9,10 +9,11 @@ use zeroize::Zeroize; use curve25519_dalek::edwards::{EdwardsPoint, CompressedEdwardsY}; use crate::{ - Protocol, hash, - serialize::*, + io::*, + primitives::keccak256, ring_signatures::RingSignature, ringct::{bulletproofs::Bulletproof, RctType, RctBase, RctPrunable, RctSignatures}, + Protocol, }; #[derive(Clone, PartialEq, Eq, Debug)] @@ -240,7 +241,7 @@ impl TransactionPrefix { } pub fn hash(&self) -> [u8; 32] { - hash(&self.serialize()) + keccak256(self.serialize()) } } @@ -352,25 +353,25 @@ impl Transaction { let mut buf = Vec::with_capacity(2048); if self.prefix.version == 1 { self.write(&mut buf).unwrap(); - hash(&buf) + keccak256(buf) } else { let mut hashes = Vec::with_capacity(96); hashes.extend(self.prefix.hash()); self.rct_signatures.base.write(&mut buf, self.rct_signatures.rct_type()).unwrap(); - hashes.extend(hash(&buf)); + hashes.extend(keccak256(&buf)); buf.clear(); hashes.extend(&match self.rct_signatures.prunable { RctPrunable::Null => [0; 32], _ => { self.rct_signatures.prunable.write(&mut buf, self.rct_signatures.rct_type()).unwrap(); - hash(&buf) + keccak256(buf) } }); - hash(&hashes) + keccak256(hashes) } } @@ -386,13 +387,13 @@ impl Transaction { sig_hash.extend(self.prefix.hash()); self.rct_signatures.base.write(&mut buf, self.rct_signatures.rct_type()).unwrap(); - sig_hash.extend(hash(&buf)); + sig_hash.extend(keccak256(&buf)); buf.clear(); self.rct_signatures.prunable.signature_write(&mut buf).unwrap(); - sig_hash.extend(hash(&buf)); + sig_hash.extend(keccak256(buf)); - hash(&sig_hash) + keccak256(sig_hash) } fn is_rct_bulletproof(&self) -> bool { diff --git a/coins/monero/src/wallet/address.rs b/coins/monero/src/wallet/address.rs index e5cc3dc9..6ceebf05 100644 --- a/coins/monero/src/wallet/address.rs +++ b/coins/monero/src/wallet/address.rs @@ -5,7 +5,7 @@ use zeroize::Zeroize; use curve25519_dalek::edwards::EdwardsPoint; -use monero_io::decompress_point; +use crate::io::decompress_point; use base58_monero::base58::{encode_check, decode_check}; diff --git a/coins/monero/src/wallet/extra.rs b/coins/monero/src/wallet/extra.rs index deed8036..e84eb81b 100644 --- a/coins/monero/src/wallet/extra.rs +++ b/coins/monero/src/wallet/extra.rs @@ -8,10 +8,7 @@ use zeroize::Zeroize; use curve25519_dalek::edwards::EdwardsPoint; -use crate::serialize::{ - varint_len, read_byte, read_bytes, read_varint, read_point, read_vec, write_byte, write_varint, - write_point, write_vec, -}; +use crate::io::*; pub const MAX_TX_EXTRA_PADDING_COUNT: usize = 255; pub const MAX_TX_EXTRA_NONCE_SIZE: usize = 255; diff --git a/coins/monero/src/wallet/mod.rs b/coins/monero/src/wallet/mod.rs index 7debf3ed..3ed56272 100644 --- a/coins/monero/src/wallet/mod.rs +++ b/coins/monero/src/wallet/mod.rs @@ -10,7 +10,9 @@ use curve25519_dalek::{ }; use crate::{ - hash, hash_to_scalar, serialize::write_varint, Commitment, ringct::EncryptedAmount, + io::write_varint, + primitives::{Commitment, keccak256, keccak256_to_scalar}, + ringct::EncryptedAmount, transaction::Input, }; @@ -62,7 +64,7 @@ pub(crate) fn uniqueness(inputs: &[Input]) -> [u8; 32] { Input::ToKey { key_image, .. } => u.extend(key_image.compress().to_bytes()), } } - hash(&u) + keccak256(u) } // Hs("view_tag" || 8Ra || o), Hs(8Ra || o), and H(8Ra || 0x8d) with uniqueness inclusion in the @@ -78,12 +80,12 @@ pub(crate) fn shared_key( let mut payment_id_xor = [0; 8]; payment_id_xor - .copy_from_slice(&hash(&[output_derivation.as_ref(), [0x8d].as_ref()].concat())[.. 8]); + .copy_from_slice(&keccak256([output_derivation.as_ref(), [0x8d].as_ref()].concat())[.. 8]); // || o write_varint(&o, &mut output_derivation).unwrap(); - let view_tag = hash(&[b"view_tag".as_ref(), &output_derivation].concat())[0]; + let view_tag = keccak256([b"view_tag".as_ref(), &output_derivation].concat())[0]; // uniqueness || let shared_key = if let Some(uniqueness) = uniqueness { @@ -92,19 +94,19 @@ pub(crate) fn shared_key( output_derivation }; - (view_tag, hash_to_scalar(&shared_key), payment_id_xor) + (view_tag, keccak256_to_scalar(shared_key), payment_id_xor) } pub(crate) fn commitment_mask(shared_key: Scalar) -> Scalar { let mut mask = b"commitment_mask".to_vec(); mask.extend(shared_key.to_bytes()); - hash_to_scalar(&mask) + keccak256_to_scalar(mask) } pub(crate) fn compact_amount_encryption(amount: u64, key: Scalar) -> [u8; 8] { let mut amount_mask = b"amount".to_vec(); amount_mask.extend(key.to_bytes()); - (amount ^ u64::from_le_bytes(hash(&amount_mask)[.. 8].try_into().unwrap())).to_le_bytes() + (amount ^ u64::from_le_bytes(keccak256(amount_mask)[.. 8].try_into().unwrap())).to_le_bytes() } impl EncryptedAmount { @@ -116,11 +118,11 @@ impl EncryptedAmount { match self { // TODO: Add a test vector for this EncryptedAmount::Original { mask, amount } => { - let mask_shared_sec = hash(key.as_bytes()); + let mask_shared_sec = keccak256(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_shared_sec = keccak256(mask_shared_sec); let amount_scalar = Scalar::from_bytes_mod_order(*amount) - Scalar::from_bytes_mod_order(amount_shared_sec); // d2b from rctTypes.cpp @@ -157,7 +159,7 @@ impl ViewPair { } fn subaddress_derivation(&self, index: SubaddressIndex) -> Scalar { - hash_to_scalar(&Zeroizing::new( + keccak256_to_scalar(Zeroizing::new( [ b"SubAddr\0".as_ref(), Zeroizing::new(self.view.to_bytes()).as_ref(), diff --git a/coins/monero/src/wallet/scan.rs b/coins/monero/src/wallet/scan.rs index 46ddceed..c0900449 100644 --- a/coins/monero/src/wallet/scan.rs +++ b/coins/monero/src/wallet/scan.rs @@ -12,8 +12,8 @@ use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwar use monero_io::decompress_point; use crate::{ - Commitment, - serialize::{read_byte, read_u32, read_u64, read_bytes, read_scalar, read_point, read_raw_vec}, + io::*, + primitives::Commitment, transaction::{Input, Timelock, Transaction}, block::Block, rpc::{RpcError, RpcConnection, Rpc}, diff --git a/coins/monero/src/wallet/send/mod.rs b/coins/monero/src/wallet/send/mod.rs index ef2504b3..ccf8606b 100644 --- a/coins/monero/src/wallet/send/mod.rs +++ b/coins/monero/src/wallet/send/mod.rs @@ -25,11 +25,9 @@ use frost::FrostError; use monero_io::varint_len; use crate::{ - Protocol, Commitment, hash, - serialize::{ - read_byte, read_bytes, read_u64, read_scalar, read_point, read_vec, write_byte, write_scalar, - write_point, write_raw_vec, write_vec, - }, + io::*, + primitives::{Commitment, keccak256}, + Protocol, ringct::{ generate_key_image, clsag::{ClsagError, ClsagContext, Clsag}, @@ -628,8 +626,8 @@ impl SignableTransaction { for input in inputs { r_uniqueness.extend(input.compress().to_bytes()); } - ChaCha20Rng::from_seed(hash( - &[b"monero-serai_outputs".as_ref(), seed.as_ref(), &r_uniqueness].concat(), + ChaCha20Rng::from_seed(keccak256( + [b"monero-serai_outputs".as_ref(), seed.as_ref(), &r_uniqueness].concat(), )) }; diff --git a/tests/full-stack/src/tests/mint_and_burn.rs b/tests/full-stack/src/tests/mint_and_burn.rs index ccfb91da..c587b699 100644 --- a/tests/full-stack/src/tests/mint_and_burn.rs +++ b/tests/full-stack/src/tests/mint_and_burn.rs @@ -352,7 +352,7 @@ async fn mint_and_burn_test() { ViewPair, Scanner, DecoySelection, Decoys, Change, FeePriority, SignableTransaction, address::{Network, AddressType, AddressMeta, MoneroAddress}, }, - decompress_point, + io::decompress_point, }; // Grab the first output on the chain diff --git a/tests/processor/src/networks.rs b/tests/processor/src/networks.rs index c2d5d9fb..f460fce5 100644 --- a/tests/processor/src/networks.rs +++ b/tests/processor/src/networks.rs @@ -444,7 +444,7 @@ impl Wallet { SignableTransaction, }, rpc::HttpRpc, - decompress_point, + io::decompress_point, }; use processor::{additional_key, networks::Monero};