Tidy up monero-serai as a meta crate

This commit is contained in:
Luke Parker
2024-06-16 12:26:14 -04:00
parent 3e82ee60b3
commit 3a1c6c7247
16 changed files with 68 additions and 112 deletions

View File

@@ -8,7 +8,7 @@ mod binaries {
pub(crate) use serde_json::json; pub(crate) use serde_json::json;
pub(crate) use monero_serai::{ pub(crate) use monero_serai::{
Commitment, primitives::Commitment,
ringct::{RctPrunable, bulletproofs::BatchVerifier}, ringct::{RctPrunable, bulletproofs::BatchVerifier},
transaction::{Input, Transaction}, transaction::{Input, Transaction},
block::Block, block::Block,

View File

@@ -4,9 +4,9 @@ use std_shims::{
}; };
use crate::{ use crate::{
hash, io::*,
primitives::keccak256,
merkle::merkle_root, merkle::merkle_root,
serialize::*,
transaction::{Input, Transaction}, transaction::{Input, Transaction},
}; };
@@ -99,7 +99,7 @@ impl Block {
write_varint(&u64::try_from(hashable.len()).unwrap(), &mut hashing_blob).unwrap(); write_varint(&u64::try_from(hashable.len()).unwrap(), &mut hashing_blob).unwrap();
hashing_blob.append(&mut hashable); hashing_blob.append(&mut hashable);
let hash = hash(&hashing_blob); let hash = keccak256(hashing_blob);
if hash == CORRECT_BLOCK_HASH_202612 { if hash == CORRECT_BLOCK_HASH_202612 {
return EXISTING_BLOCK_HASH_202612; return EXISTING_BLOCK_HASH_202612;
}; };

View File

@@ -2,21 +2,13 @@
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))] use std_shims::io as stdio;
#[macro_use]
extern crate alloc;
use std_shims::io;
use zeroize::Zeroize; use zeroize::Zeroize;
use sha3::{Digest, Keccak256}; pub use monero_io as io;
pub use monero_generators as generators;
use curve25519_dalek::scalar::Scalar; pub use monero_primitives as primitives;
pub use monero_io::decompress_point;
pub use monero_generators::H;
pub use monero_primitives::INV_EIGHT;
mod merkle; mod merkle;
@@ -114,7 +106,7 @@ impl Protocol {
} }
} }
pub(crate) fn write<W: io::Write>(&self, w: &mut W) -> io::Result<()> { pub(crate) fn write<W: stdio::Write>(&self, w: &mut W) -> stdio::Result<()> {
match self { match self {
Protocol::v14 => w.write_all(&[0, 14]), Protocol::v14 => w.write_all(&[0, 14]),
Protocol::v16 => w.write_all(&[0, 16]), Protocol::v16 => w.write_all(&[0, 16]),
@@ -130,13 +122,13 @@ impl Protocol {
} }
} }
pub(crate) fn read<R: io::Read>(r: &mut R) -> io::Result<Protocol> { pub(crate) fn read<R: stdio::Read>(r: &mut R) -> stdio::Result<Protocol> {
Ok(match read_byte(r)? { Ok(match read_byte(r)? {
// Monero protocol // Monero protocol
0 => match read_byte(r)? { 0 => match read_byte(r)? {
14 => Protocol::v14, 14 => Protocol::v14,
16 => Protocol::v16, 16 => Protocol::v16,
_ => Err(io::Error::other("unrecognized monero protocol"))?, _ => Err(stdio::Error::other("unrecognized monero protocol"))?,
}, },
// Custom // Custom
1 => match read_byte(r)? { 1 => match read_byte(r)? {
@@ -145,41 +137,24 @@ impl Protocol {
bp_plus: match read_byte(r)? { bp_plus: match read_byte(r)? {
0 => false, 0 => false,
1 => true, 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)?) 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)? { view_tags: match read_byte(r)? {
0 => false, 0 => false,
1 => true, 1 => true,
_ => Err(io::Error::other("invalid bool serialization"))?, _ => Err(stdio::Error::other("invalid bool serialization"))?,
}, },
v16_fee: match read_byte(r)? { v16_fee: match read_byte(r)? {
0 => false, 0 => false,
1 => true, 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
}

View File

@@ -1,11 +1,11 @@
use std_shims::vec::Vec; 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] { pub(crate) fn merkle_root(root: [u8; 32], leafs: &[[u8; 32]]) -> [u8; 32] {
match leafs.len() { match leafs.len() {
0 => root, 0 => root,
1 => hash(&[root, leafs[0]].concat()), 1 => keccak256([root, leafs[0]].concat()),
_ => { _ => {
let mut hashes = Vec::with_capacity(1 + leafs.len()); let mut hashes = Vec::with_capacity(1 + leafs.len());
hashes.push(root); 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); let mut paired_hashes = Vec::with_capacity(overage);
while let Some(left) = rightmost.next() { while let Some(left) = rightmost.next() {
let right = rightmost.next().unwrap(); 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); drop(rightmost);
@@ -42,7 +42,7 @@ pub(crate) fn merkle_root(root: [u8; 32], leafs: &[[u8; 32]]) -> [u8; 32] {
while hashes.len() > 1 { while hashes.len() > 1 {
let mut i = 0; let mut i = 0;
while i < hashes.len() { 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; i += 2;
} }

View File

@@ -7,9 +7,7 @@ use zeroize::Zeroize;
use curve25519_dalek::{EdwardsPoint, Scalar}; use curve25519_dalek::{EdwardsPoint, Scalar};
use monero_generators::hash_to_point; use crate::{io::*, generators::hash_to_point, primitives::keccak256_to_scalar};
use crate::{serialize::*, hash_to_scalar};
#[derive(Clone, PartialEq, Eq, Debug, Zeroize)] #[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
pub struct Signature { pub struct Signature {
@@ -67,6 +65,6 @@ impl RingSignature {
sum += sig.c; sum += sig.c;
} }
sum == hash_to_scalar(&buf) sum == keccak256_to_scalar(buf)
} }
} }

View File

@@ -8,27 +8,21 @@ use zeroize::{Zeroize, Zeroizing};
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint}; 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; pub use monero_mlsag as mlsag;
/// CLSAG struct, along with signing and verifying functionality.
pub use monero_clsag as clsag; pub use monero_clsag as clsag;
/// BorromeanRange struct, along with verifying functionality.
pub use monero_borromean as borromean; pub use monero_borromean as borromean;
/// Bulletproofs(+) structs, along with proving and verifying functionality.
pub use monero_bulletproofs as bulletproofs; pub use monero_bulletproofs as bulletproofs;
use crate::{ use crate::{
Protocol, io::*,
serialize::*, generators::hash_to_point,
ringct::{mlsag::Mlsag, clsag::Clsag, borromean::BorromeanRange, bulletproofs::Bulletproof}, 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)`. /// Generate a key image for a given key. Defined as `x * hash_to_point(xG)`.
pub fn generate_key_image(secret: &Zeroizing<Scalar>) -> EdwardsPoint { pub fn generate_key_image(secret: &Zeroizing<Scalar>) -> 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. /// An encrypted amount.

View File

@@ -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())
}

View File

@@ -4,13 +4,12 @@ use rand_core::OsRng;
use curve25519_dalek::scalar::Scalar; use curve25519_dalek::scalar::Scalar;
use crate::{ use monero_primitives::keccak256;
hash,
wallet::seed::{ use crate::wallet::seed::{
Seed, SeedType, SeedError, Seed, SeedType, SeedError,
classic::{self, trim_by_lang}, classic::{self, trim_by_lang},
polyseed, polyseed,
},
}; };
#[test] #[test]
@@ -217,7 +216,7 @@ fn test_classic_seed() {
let view: [u8; 32] = hex::decode(vector.view).unwrap().try_into().unwrap(); let view: [u8; 32] = hex::decode(vector.view).unwrap().try_into().unwrap();
// Monero then derives the view key as H(spend) // Monero then derives the view key as H(spend)
assert_eq!( assert_eq!(
Scalar::from_bytes_mod_order(hash(&spend)), Scalar::from_bytes_mod_order(keccak256(spend)),
Scalar::from_canonical_bytes(view).unwrap() Scalar::from_canonical_bytes(view).unwrap()
); );

View File

@@ -9,10 +9,11 @@ use zeroize::Zeroize;
use curve25519_dalek::edwards::{EdwardsPoint, CompressedEdwardsY}; use curve25519_dalek::edwards::{EdwardsPoint, CompressedEdwardsY};
use crate::{ use crate::{
Protocol, hash, io::*,
serialize::*, primitives::keccak256,
ring_signatures::RingSignature, ring_signatures::RingSignature,
ringct::{bulletproofs::Bulletproof, RctType, RctBase, RctPrunable, RctSignatures}, ringct::{bulletproofs::Bulletproof, RctType, RctBase, RctPrunable, RctSignatures},
Protocol,
}; };
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
@@ -240,7 +241,7 @@ impl TransactionPrefix {
} }
pub fn hash(&self) -> [u8; 32] { 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); let mut buf = Vec::with_capacity(2048);
if self.prefix.version == 1 { if self.prefix.version == 1 {
self.write(&mut buf).unwrap(); self.write(&mut buf).unwrap();
hash(&buf) keccak256(buf)
} else { } else {
let mut hashes = Vec::with_capacity(96); let mut hashes = Vec::with_capacity(96);
hashes.extend(self.prefix.hash()); hashes.extend(self.prefix.hash());
self.rct_signatures.base.write(&mut buf, self.rct_signatures.rct_type()).unwrap(); self.rct_signatures.base.write(&mut buf, self.rct_signatures.rct_type()).unwrap();
hashes.extend(hash(&buf)); hashes.extend(keccak256(&buf));
buf.clear(); buf.clear();
hashes.extend(&match self.rct_signatures.prunable { hashes.extend(&match self.rct_signatures.prunable {
RctPrunable::Null => [0; 32], RctPrunable::Null => [0; 32],
_ => { _ => {
self.rct_signatures.prunable.write(&mut buf, self.rct_signatures.rct_type()).unwrap(); 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()); sig_hash.extend(self.prefix.hash());
self.rct_signatures.base.write(&mut buf, self.rct_signatures.rct_type()).unwrap(); 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(); buf.clear();
self.rct_signatures.prunable.signature_write(&mut buf).unwrap(); 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 { fn is_rct_bulletproof(&self) -> bool {

View File

@@ -5,7 +5,7 @@ use zeroize::Zeroize;
use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::edwards::EdwardsPoint;
use monero_io::decompress_point; use crate::io::decompress_point;
use base58_monero::base58::{encode_check, decode_check}; use base58_monero::base58::{encode_check, decode_check};

View File

@@ -8,10 +8,7 @@ use zeroize::Zeroize;
use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::edwards::EdwardsPoint;
use crate::serialize::{ use crate::io::*;
varint_len, read_byte, read_bytes, read_varint, read_point, read_vec, write_byte, write_varint,
write_point, write_vec,
};
pub const MAX_TX_EXTRA_PADDING_COUNT: usize = 255; pub const MAX_TX_EXTRA_PADDING_COUNT: usize = 255;
pub const MAX_TX_EXTRA_NONCE_SIZE: usize = 255; pub const MAX_TX_EXTRA_NONCE_SIZE: usize = 255;

View File

@@ -10,7 +10,9 @@ use curve25519_dalek::{
}; };
use crate::{ 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, 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()), 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 // 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]; let mut payment_id_xor = [0; 8];
payment_id_xor 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 // || o
write_varint(&o, &mut output_derivation).unwrap(); 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 || // uniqueness ||
let shared_key = if let Some(uniqueness) = uniqueness { let shared_key = if let Some(uniqueness) = uniqueness {
@@ -92,19 +94,19 @@ pub(crate) fn shared_key(
output_derivation 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 { pub(crate) fn commitment_mask(shared_key: Scalar) -> Scalar {
let mut mask = b"commitment_mask".to_vec(); let mut mask = b"commitment_mask".to_vec();
mask.extend(shared_key.to_bytes()); 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] { pub(crate) fn compact_amount_encryption(amount: u64, key: Scalar) -> [u8; 8] {
let mut amount_mask = b"amount".to_vec(); let mut amount_mask = b"amount".to_vec();
amount_mask.extend(key.to_bytes()); 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 { impl EncryptedAmount {
@@ -116,11 +118,11 @@ impl EncryptedAmount {
match self { match self {
// TODO: Add a test vector for this // TODO: Add a test vector for this
EncryptedAmount::Original { mask, amount } => { EncryptedAmount::Original { mask, amount } => {
let mask_shared_sec = hash(key.as_bytes()); let mask_shared_sec = keccak256(key.as_bytes());
let mask = let mask =
Scalar::from_bytes_mod_order(*mask) - Scalar::from_bytes_mod_order(mask_shared_sec); 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 = let amount_scalar =
Scalar::from_bytes_mod_order(*amount) - Scalar::from_bytes_mod_order(amount_shared_sec); Scalar::from_bytes_mod_order(*amount) - Scalar::from_bytes_mod_order(amount_shared_sec);
// d2b from rctTypes.cpp // d2b from rctTypes.cpp
@@ -157,7 +159,7 @@ impl ViewPair {
} }
fn subaddress_derivation(&self, index: SubaddressIndex) -> Scalar { fn subaddress_derivation(&self, index: SubaddressIndex) -> Scalar {
hash_to_scalar(&Zeroizing::new( keccak256_to_scalar(Zeroizing::new(
[ [
b"SubAddr\0".as_ref(), b"SubAddr\0".as_ref(),
Zeroizing::new(self.view.to_bytes()).as_ref(), Zeroizing::new(self.view.to_bytes()).as_ref(),

View File

@@ -12,8 +12,8 @@ use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwar
use monero_io::decompress_point; use monero_io::decompress_point;
use crate::{ use crate::{
Commitment, io::*,
serialize::{read_byte, read_u32, read_u64, read_bytes, read_scalar, read_point, read_raw_vec}, primitives::Commitment,
transaction::{Input, Timelock, Transaction}, transaction::{Input, Timelock, Transaction},
block::Block, block::Block,
rpc::{RpcError, RpcConnection, Rpc}, rpc::{RpcError, RpcConnection, Rpc},

View File

@@ -25,11 +25,9 @@ use frost::FrostError;
use monero_io::varint_len; use monero_io::varint_len;
use crate::{ use crate::{
Protocol, Commitment, hash, io::*,
serialize::{ primitives::{Commitment, keccak256},
read_byte, read_bytes, read_u64, read_scalar, read_point, read_vec, write_byte, write_scalar, Protocol,
write_point, write_raw_vec, write_vec,
},
ringct::{ ringct::{
generate_key_image, generate_key_image,
clsag::{ClsagError, ClsagContext, Clsag}, clsag::{ClsagError, ClsagContext, Clsag},
@@ -628,8 +626,8 @@ impl SignableTransaction {
for input in inputs { for input in inputs {
r_uniqueness.extend(input.compress().to_bytes()); r_uniqueness.extend(input.compress().to_bytes());
} }
ChaCha20Rng::from_seed(hash( ChaCha20Rng::from_seed(keccak256(
&[b"monero-serai_outputs".as_ref(), seed.as_ref(), &r_uniqueness].concat(), [b"monero-serai_outputs".as_ref(), seed.as_ref(), &r_uniqueness].concat(),
)) ))
}; };

View File

@@ -352,7 +352,7 @@ async fn mint_and_burn_test() {
ViewPair, Scanner, DecoySelection, Decoys, Change, FeePriority, SignableTransaction, ViewPair, Scanner, DecoySelection, Decoys, Change, FeePriority, SignableTransaction,
address::{Network, AddressType, AddressMeta, MoneroAddress}, address::{Network, AddressType, AddressMeta, MoneroAddress},
}, },
decompress_point, io::decompress_point,
}; };
// Grab the first output on the chain // Grab the first output on the chain

View File

@@ -444,7 +444,7 @@ impl Wallet {
SignableTransaction, SignableTransaction,
}, },
rpc::HttpRpc, rpc::HttpRpc,
decompress_point, io::decompress_point,
}; };
use processor::{additional_key, networks::Monero}; use processor::{additional_key, networks::Monero};