From b565c6562854dbdb394649691a2ccc270b00f723 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 20:46:40 -0300 Subject: [PATCH 1/7] fmt --- accounts/src/account_core/mod.rs | 4 +--- node_core/src/lib.rs | 12 ++---------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 0c7bbdd..38d9e9c 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -5,9 +5,7 @@ use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, transac use k256::AffinePoint; use log::info; use serde::Serialize; -use utxo::{ - utxo_core::{UTXOPayload, UTXO}, -}; +use utxo::utxo_core::{UTXOPayload, UTXO}; use crate::key_management::{ constants_types::{CipherText, Nonce}, diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 25be979..5228e9b 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -1101,11 +1101,7 @@ impl NodeCore { .map(|new_utxo_hash| { let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); - let new_utxo = acc - .utxos - .get(&new_utxo_hash) - .unwrap() - .clone(); + let new_utxo = acc.utxos.get(&new_utxo_hash).unwrap().clone(); new_utxo.log(); info!( @@ -1555,11 +1551,7 @@ impl NodeCore { .map(|(acc_addr_rec, new_utxo_hash)| { let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); - let new_utxo = acc - .utxos - .get(&new_utxo_hash) - .unwrap() - .clone(); + let new_utxo = acc.utxos.get(&new_utxo_hash).unwrap().clone(); new_utxo.log(); info!( From f1643492bc543ad6762f5e4367e36c23af91b578 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 20:45:35 -0300 Subject: [PATCH 2/7] Remove nullifier attribute --- accounts/src/account_core/mod.rs | 29 +------- sc_core/src/lib.rs | 1 - sc_core/src/utxo_manipulator.rs | 110 ------------------------------- utxo/src/utxo_core.rs | 33 ---------- 4 files changed, 1 insertion(+), 172 deletions(-) delete mode 100644 sc_core/src/utxo_manipulator.rs diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 38d9e9c..280fc57 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, hash::Hash}; use anyhow::Result; -use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, transaction::Tag}; +use common::{merkle_tree_public::TreeHashType, nullifier::{self, UTXONullifier}, transaction::Tag}; use k256::AffinePoint; use log::info; use serde::Serialize; @@ -84,19 +84,6 @@ impl Account { .decrypt_data(ephemeral_public_key_sender, ciphertext, nonce) } - pub fn mark_spent_utxo( - &mut self, - utxo_nullifier_map: HashMap, - ) -> Result<()> { - for (hash, nullifier) in utxo_nullifier_map { - if let Some(utxo_entry) = self.utxos.get_mut(&hash) { - utxo_entry.consume_utxo(nullifier)?; - } - } - - Ok(()) - } - pub fn add_new_utxo_outputs(&mut self, utxos: Vec) -> Result<()> { for utxo in utxos { if self.utxos.contains_key(&utxo.hash) { @@ -184,20 +171,6 @@ mod tests { assert!(account.key_holder.address != [0u8; 32]); // Check if the address is not empty } - #[test] - fn test_mark_spent_utxo() { - let mut account = Account::new(); - let utxo = generate_dummy_utxo(account.address, 100).unwrap(); - account.add_new_utxo_outputs(vec![utxo]).unwrap(); - - let mut utxo_nullifier_map = HashMap::new(); - utxo_nullifier_map.insert(account.address, generate_dummy_utxo_nullifier()); - - let result = account.mark_spent_utxo(utxo_nullifier_map); - - assert!(result.is_ok()); - } - #[test] fn test_add_new_utxo_outputs() { let mut account = Account::new(); diff --git a/sc_core/src/lib.rs b/sc_core/src/lib.rs index 769813d..a41ab82 100644 --- a/sc_core/src/lib.rs +++ b/sc_core/src/lib.rs @@ -1,4 +1,3 @@ pub mod cryptography; pub mod proofs_circuits; pub mod transaction_payloads_tools; -pub mod utxo_manipulator; diff --git a/sc_core/src/utxo_manipulator.rs b/sc_core/src/utxo_manipulator.rs deleted file mode 100644 index 8bc0e32..0000000 --- a/sc_core/src/utxo_manipulator.rs +++ /dev/null @@ -1,110 +0,0 @@ -use anyhow::Result; -use common::nullifier::UTXONullifier; -use utxo::utxo_core::{UTXOPayload, UTXO}; - -pub fn utxo_change_owner( - utxo: &mut UTXO, - nullifier: UTXONullifier, - new_owner: [u8; 32], -) -> Result { - let new_payload = UTXOPayload { - owner: new_owner, - asset: utxo.asset.clone(), - amount: utxo.amount, - privacy_flag: utxo.privacy_flag, - }; - - utxo.consume_utxo(nullifier)?; - - Ok(UTXO::create_utxo_from_payload(new_payload)?) -} - -pub fn utxo_substact_part_another_owner( - utxo: &mut UTXO, - nullifier: UTXONullifier, - amount: u128, - new_owner: [u8; 32], -) -> Result<(UTXO, UTXO)> { - if amount > utxo.amount { - anyhow::bail!("Amount too big"); - } - - let diff = utxo.amount - amount; - - let new_payload1 = UTXOPayload { - owner: utxo.owner, - asset: utxo.asset.clone(), - amount: diff, - privacy_flag: utxo.privacy_flag, - }; - - let new_payload2 = UTXOPayload { - owner: new_owner, - asset: utxo.asset.clone(), - amount, - privacy_flag: utxo.privacy_flag, - }; - - utxo.consume_utxo(nullifier)?; - - Ok(( - UTXO::create_utxo_from_payload(new_payload1)?, - UTXO::create_utxo_from_payload(new_payload2)?, - )) -} - -pub fn utxo_substract_part( - utxo: &mut UTXO, - nullifier: UTXONullifier, - amount: u128, -) -> Result<(UTXO, UTXO)> { - let new_owner = utxo.owner; - - utxo_substact_part_another_owner(utxo, nullifier, amount, new_owner) -} - -pub fn utxo_split_n_users( - utxo: &mut UTXO, - nullifier: UTXONullifier, - users_amounts: Vec<([u8; 32], u128)>, -) -> Result> { - let cumulative_diff = users_amounts - .iter() - .fold(0, |acc, (_, amount)| acc + *amount); - - if cumulative_diff > utxo.amount { - anyhow::bail!("Amount too big"); - } - - let mut utxo_res = vec![]; - - for (new_owner, amount) in users_amounts { - let new_payload = UTXOPayload { - owner: new_owner, - asset: utxo.asset.clone(), - amount, - privacy_flag: utxo.privacy_flag, - }; - - let new_utxo = UTXO::create_utxo_from_payload(new_payload)?; - - utxo_res.push(new_utxo); - } - - if cumulative_diff != utxo.amount { - let new_payload = UTXOPayload { - owner: utxo.owner, - asset: utxo.asset.clone(), - amount: utxo.amount - cumulative_diff, - privacy_flag: utxo.privacy_flag, - }; - - let new_utxo = UTXO::create_utxo_from_payload(new_payload)?; - - utxo_res.push(new_utxo); - } - - utxo.consume_utxo(nullifier)?; - - Ok(utxo_res) -} diff --git a/utxo/src/utxo_core.rs b/utxo/src/utxo_core.rs index a4777b3..c470968 100644 --- a/utxo/src/utxo_core.rs +++ b/utxo/src/utxo_core.rs @@ -12,7 +12,6 @@ pub type Asset = Vec; pub struct UTXO { pub hash: TreeHashType, pub owner: AccountId, - pub nullifier: Option, pub asset: Asset, // TODO: change to u256 pub amount: u128, @@ -41,23 +40,12 @@ impl UTXO { Ok(Self { hash, owner: payload_with_asset.owner, - nullifier: None, asset: payload_with_asset.asset, amount: payload_with_asset.amount, privacy_flag: payload_with_asset.privacy_flag, }) } - pub fn consume_utxo(&mut self, nullifier: UTXONullifier) -> Result<()> { - if self.nullifier.is_some() { - anyhow::bail!("UTXO already consumed"); - } else { - self.nullifier = Some(nullifier); - } - - Ok(()) - } - pub fn interpret_asset<'de, ToInterpret: Deserialize<'de>>(&'de self) -> Result { Ok(serde_json::from_slice(&self.asset)?) } @@ -74,10 +62,6 @@ impl UTXO { pub fn log(&self) { info!("UTXO hash is {:?}", hex::encode(self.hash)); info!("UTXO owner is {:?}", hex::encode(self.owner)); - info!( - "UTXO nullifier is {:?}", - self.nullifier.clone().map(|val| hex::encode(val.utxo_hash)) - ); info!("UTXO asset is {:?}", hex::encode(self.asset.clone())); info!("UTXO amount is {:?}", self.amount); info!("UTXO privacy_flag is {:?}", self.privacy_flag); @@ -127,23 +111,6 @@ mod tests { // Ensure hash is created and the UTXO fields are correctly assigned assert_eq!(utxo.owner, payload.owner); assert_eq!(utxo.asset, payload.asset); - assert!(utxo.nullifier.is_none()); - } - - #[test] - fn test_consume_utxo() { - let payload = sample_payload(); - let mut utxo = UTXO::create_utxo_from_payload(payload).unwrap(); - - let nullifier = sample_nullifier(); - - // First consumption should succeed - assert!(utxo.consume_utxo(nullifier.clone()).is_ok()); - assert_eq!(utxo.nullifier, Some(nullifier)); - - // Second consumption should fail - let result = utxo.consume_utxo(sample_nullifier()); - assert!(result.is_err()); } #[test] From 4524177931127ba24a4c8ae52fac743b276ae673 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 20:54:11 -0300 Subject: [PATCH 3/7] fmt --- accounts/src/account_core/mod.rs | 6 +++++- utxo/src/utxo_core.rs | 10 +--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 280fc57..d19ebab 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,7 +1,11 @@ use std::{collections::HashMap, hash::Hash}; use anyhow::Result; -use common::{merkle_tree_public::TreeHashType, nullifier::{self, UTXONullifier}, transaction::Tag}; +use common::{ + merkle_tree_public::TreeHashType, + nullifier::{self, UTXONullifier}, + transaction::Tag, +}; use k256::AffinePoint; use log::info; use serde::Serialize; diff --git a/utxo/src/utxo_core.rs b/utxo/src/utxo_core.rs index c470968..3a3074e 100644 --- a/utxo/src/utxo_core.rs +++ b/utxo/src/utxo_core.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use common::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, AccountId}; +use common::{merkle_tree_public::TreeHashType, AccountId}; use log::info; use serde::{Deserialize, Serialize}; use sha2::{digest::FixedOutput, Digest}; @@ -82,14 +82,6 @@ mod tests { AccountId::default() } - fn sample_nullifier() -> UTXONullifier { - UTXONullifier::default() - } - - fn sample_tree_hash() -> TreeHashType { - TreeHashType::default() - } - fn sample_payload() -> UTXOPayload { UTXOPayload { owner: sample_account(), From 1490b51f71116f398dd9572eadf5ee18c10da803 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 21:55:25 -0300 Subject: [PATCH 4/7] add randomness to UTXO --- Cargo.lock | 2 + accounts/src/account_core/mod.rs | 29 ++---- utxo/Cargo.toml | 1 + utxo/src/utxo_core.rs | 51 +++++++--- zkvm/Cargo.toml | 1 + zkvm/src/lib.rs | 97 ++++++++++++------- zkvm/test_methods/guest/src/bin/mint_utxo.rs | 3 + .../src/bin/mint_utxo_multiple_assets.rs | 3 + zkvm/test_methods/guest/src/bin/send_utxo.rs | 6 +- .../src/bin/send_utxo_multiple_assets.rs | 1 + 10 files changed, 129 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c84dec..8abf457 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5499,6 +5499,7 @@ dependencies = [ "hex", "log", "monotree", + "rand 0.8.5", "serde", "serde_json", "sha2 0.10.8", @@ -6207,6 +6208,7 @@ dependencies = [ "common", "env_logger", "log", + "rand 0.8.5", "risc0-zkvm", "serde", "serde_json", diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index d19ebab..6d81697 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -1,11 +1,7 @@ -use std::{collections::HashMap, hash::Hash}; +use std::collections::HashMap; use anyhow::Result; -use common::{ - merkle_tree_public::TreeHashType, - nullifier::{self, UTXONullifier}, - transaction::Tag, -}; +use common::{merkle_tree_public::TreeHashType, transaction::Tag}; use k256::AffinePoint; use log::info; use serde::Serialize; @@ -108,14 +104,12 @@ impl Account { amount: u128, privacy_flag: bool, ) -> Result<()> { - let payload_with_asset = UTXOPayload { - owner: self.address, - asset: serde_json::to_vec(&asset)?, + let asset_utxo = UTXO::new( + self.address, + serde_json::to_vec(&asset)?, amount, privacy_flag, - }; - - let asset_utxo = UTXO::create_utxo_from_payload(payload_with_asset)?; + ); self.utxos.insert(asset_utxo.hash, asset_utxo); @@ -153,16 +147,13 @@ impl Default for Account { mod tests { use super::*; - fn generate_dummy_utxo_nullifier() -> UTXONullifier { - UTXONullifier::default() - } - - fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> anyhow::Result { + fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> UTXO { let payload = UTXOPayload { owner: address, asset: vec![], amount, privacy_flag: false, + randomness: [0u8; 32], }; UTXO::create_utxo_from_payload(payload) } @@ -178,8 +169,8 @@ mod tests { #[test] fn test_add_new_utxo_outputs() { let mut account = Account::new(); - let utxo1 = generate_dummy_utxo(account.address, 100).unwrap(); - let utxo2 = generate_dummy_utxo(account.address, 200).unwrap(); + let utxo1 = generate_dummy_utxo(account.address, 100); + let utxo2 = generate_dummy_utxo(account.address, 200); let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]); diff --git a/utxo/Cargo.toml b/utxo/Cargo.toml index 9b99cf9..266f340 100644 --- a/utxo/Cargo.toml +++ b/utxo/Cargo.toml @@ -12,6 +12,7 @@ serde.workspace = true monotree.workspace = true sha2.workspace = true hex.workspace = true +rand.workspace = true [dependencies.common] path = "../common" diff --git a/utxo/src/utxo_core.rs b/utxo/src/utxo_core.rs index 3a3074e..bfb2ff0 100644 --- a/utxo/src/utxo_core.rs +++ b/utxo/src/utxo_core.rs @@ -1,11 +1,15 @@ +use std::hash::RandomState; + use anyhow::Result; use common::{merkle_tree_public::TreeHashType, AccountId}; use log::info; +use rand::{rngs::OsRng, RngCore}; use serde::{Deserialize, Serialize}; use sha2::{digest::FixedOutput, Digest}; ///Raw asset data pub type Asset = Vec; +pub type Randomness = [u8; 32]; #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] ///Container for raw utxo payload @@ -16,6 +20,7 @@ pub struct UTXO { // TODO: change to u256 pub amount: u128, pub privacy_flag: bool, + pub randomness: Randomness, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -25,25 +30,47 @@ pub struct UTXOPayload { // TODO: change to u256 pub amount: u128, pub privacy_flag: bool, + pub randomness: Randomness, +} + +impl UTXOPayload { + fn to_bytes(&self) -> Vec { + let mut result = Vec::new(); + result.extend_from_slice(&self.owner); + result.extend_from_slice(&self.asset); + result.extend_from_slice(&self.amount.to_be_bytes()); + result.push(self.privacy_flag as u8); + result.extend_from_slice(&self.randomness); + result + } } impl UTXO { - pub fn create_utxo_from_payload(payload_with_asset: UTXOPayload) -> anyhow::Result { - let raw_payload = serde_json::to_vec(&payload_with_asset)?; - + pub fn new(owner: AccountId, asset: Asset, amount: u128, privacy_flag: bool) -> Self { + let mut randomness = Randomness::default(); + OsRng.fill_bytes(&mut randomness); + let payload = UTXOPayload { + owner, + asset, + amount, + privacy_flag, + randomness, + }; + Self::create_utxo_from_payload(payload) + } + pub fn create_utxo_from_payload(payload_with_asset: UTXOPayload) -> Self { let mut hasher = sha2::Sha256::new(); - - hasher.update(&raw_payload); - + hasher.update(&payload_with_asset.to_bytes()); let hash = ::from(hasher.finalize_fixed()); - Ok(Self { + Self { hash, owner: payload_with_asset.owner, asset: payload_with_asset.asset, amount: payload_with_asset.amount, privacy_flag: payload_with_asset.privacy_flag, - }) + randomness: payload_with_asset.randomness, + } } pub fn interpret_asset<'de, ToInterpret: Deserialize<'de>>(&'de self) -> Result { @@ -56,6 +83,7 @@ impl UTXO { asset: self.asset.clone(), amount: self.amount, privacy_flag: self.privacy_flag, + randomness: self.randomness, } } @@ -92,13 +120,14 @@ mod tests { .unwrap(), amount: 10, privacy_flag: false, + randomness: Randomness::default(), } } #[test] fn test_create_utxo_from_payload() { let payload = sample_payload(); - let utxo = UTXO::create_utxo_from_payload(payload.clone()).unwrap(); + let utxo = UTXO::create_utxo_from_payload(payload.clone()); // Ensure hash is created and the UTXO fields are correctly assigned assert_eq!(utxo.owner, payload.owner); @@ -108,7 +137,7 @@ mod tests { #[test] fn test_interpret_asset() { let payload = sample_payload(); - let utxo = UTXO::create_utxo_from_payload(payload).unwrap(); + let utxo = UTXO::create_utxo_from_payload(payload); // Interpret asset as TestAsset let interpreted: TestAsset = utxo.interpret_asset().unwrap(); @@ -126,7 +155,7 @@ mod tests { fn test_interpret_invalid_asset() { let mut payload = sample_payload(); payload.asset = vec![0, 1, 2, 3]; // Invalid data for deserialization - let utxo = UTXO::create_utxo_from_payload(payload).unwrap(); + let utxo = UTXO::create_utxo_from_payload(payload); // This should fail because the asset is not valid JSON for TestAsset let result: Result = utxo.interpret_asset(); diff --git a/zkvm/Cargo.toml b/zkvm/Cargo.toml index f384a56..7de7002 100644 --- a/zkvm/Cargo.toml +++ b/zkvm/Cargo.toml @@ -10,6 +10,7 @@ env_logger.workspace = true log.workspace = true serde.workspace = true thiserror.workspace = true +rand.workspace = true risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.0" } test-methods = { path = "test_methods" } diff --git a/zkvm/src/lib.rs b/zkvm/src/lib.rs index 510aee5..7ab1225 100644 --- a/zkvm/src/lib.rs +++ b/zkvm/src/lib.rs @@ -1,8 +1,9 @@ use accounts::account_core::AccountAddress; use common::ExecutionFailureKind; +use rand::{rngs::OsRng, RngCore}; use risc0_zkvm::{default_executor, default_prover, sha::Digest, ExecutorEnv, Receipt}; use serde::Serialize; -use utxo::utxo_core::{UTXOPayload, UTXO}; +use utxo::utxo_core::{Randomness, UTXOPayload, UTXO}; pub mod gas_calculator; @@ -43,6 +44,12 @@ pub fn prove_mint_utxo( .write(&owner) .map_err(ExecutionFailureKind::write_error)?; + let mut randomness = Randomness::default(); + OsRng.fill_bytes(&mut randomness); + builder + .write(&randomness) + .map_err(ExecutionFailureKind::write_error)?; + let env = builder .build() .map_err(ExecutionFailureKind::builder_error)?; @@ -56,10 +63,7 @@ pub fn prove_mint_utxo( let digest: UTXOPayload = receipt.journal.decode()?; - Ok(( - UTXO::create_utxo_from_payload(digest).map_err(ExecutionFailureKind::write_error)?, - receipt, - )) + Ok((UTXO::create_utxo_from_payload(digest), receipt)) } pub fn prove_send_utxo( @@ -78,8 +82,18 @@ pub fn prove_send_utxo( builder .write(&utxo_payload) .map_err(ExecutionFailureKind::write_error)?; + + let owners_parts_with_randomness = owners_parts + .into_iter() + .map(|(amount, addr)| { + let mut randomness = Randomness::default(); + OsRng.fill_bytes(&mut randomness); + (amount, addr, randomness) + }) + .collect::>(); + builder - .write(&owners_parts) + .write(&owners_parts_with_randomness) .map_err(ExecutionFailureKind::write_error)?; let env = builder @@ -98,9 +112,8 @@ pub fn prove_send_utxo( Ok(( digest .into_iter() - .map(|(payload, addr)| (UTXO::create_utxo_from_payload(payload).map(|sel| (sel, addr)))) - .collect::>>() - .map_err(ExecutionFailureKind::write_error)?, + .map(|(payload, addr)| (UTXO::create_utxo_from_payload(payload), addr)) + .collect(), receipt, )) } @@ -148,14 +161,12 @@ pub fn prove_send_utxo_multiple_assets_one_receiver( .0 .into_iter() .map(|payload| UTXO::create_utxo_from_payload(payload)) - .collect::>>() - .map_err(ExecutionFailureKind::write_error)?, + .collect(), digest .1 .into_iter() .map(|payload| UTXO::create_utxo_from_payload(payload)) - .collect::>>() - .map_err(ExecutionFailureKind::write_error)?, + .collect(), receipt, )) } @@ -171,13 +182,7 @@ pub fn prove_send_utxo_shielded( return Err(ExecutionFailureKind::AmountMismatchError); } - let temp_utxo_to_spend = UTXO::create_utxo_from_payload(UTXOPayload { - owner, - asset: vec![], - amount, - privacy_flag: true, - }) - .map_err(ExecutionFailureKind::write_error)?; + let temp_utxo_to_spend = UTXO::new(owner, vec![], amount, true); let utxo_payload = temp_utxo_to_spend.into_payload(); let mut builder = ExecutorEnv::builder(); @@ -185,8 +190,18 @@ pub fn prove_send_utxo_shielded( builder .write(&utxo_payload) .map_err(ExecutionFailureKind::write_error)?; + + let owners_parts_with_randomness = owners_parts + .into_iter() + .map(|(amount, addr)| { + let mut randomness = Randomness::default(); + OsRng.fill_bytes(&mut randomness); + (amount, addr, randomness) + }) + .collect::>(); + builder - .write(&owners_parts) + .write(&owners_parts_with_randomness) .map_err(ExecutionFailureKind::write_error)?; let env = builder @@ -205,9 +220,8 @@ pub fn prove_send_utxo_shielded( Ok(( digest .into_iter() - .map(|(payload, addr)| (UTXO::create_utxo_from_payload(payload).map(|sel| (sel, addr)))) - .collect::>>() - .map_err(ExecutionFailureKind::write_error)?, + .map(|(payload, addr)| (UTXO::create_utxo_from_payload(payload), addr)) + .collect(), receipt, )) } @@ -228,8 +242,18 @@ pub fn prove_send_utxo_deshielded( builder .write(&utxo_payload) .map_err(ExecutionFailureKind::write_error)?; + + let owners_parts_with_randomness = owners_parts + .into_iter() + .map(|(amount, addr)| { + let mut randomness = Randomness::default(); + OsRng.fill_bytes(&mut randomness); + (amount, addr, randomness) + }) + .collect::>(); + builder - .write(&owners_parts) + .write(&owners_parts_with_randomness) .map_err(ExecutionFailureKind::write_error)?; let env = builder @@ -288,8 +312,7 @@ pub fn prove_mint_utxo_multiple_assets( digest .into_iter() .map(UTXO::create_utxo_from_payload) - .collect::>>() - .map_err(ExecutionFailureKind::write_error)?, + .collect(), receipt, )) } @@ -308,7 +331,7 @@ pub fn execute_mint_utxo(amount_to_mint: u128, owner: AccountAddress) -> anyhow: let digest: UTXOPayload = receipt.journal.decode()?; - UTXO::create_utxo_from_payload(digest) + Ok(UTXO::create_utxo_from_payload(digest)) } pub fn execute_send_utxo( @@ -320,7 +343,16 @@ pub fn execute_send_utxo( let utxo_payload = spent_utxo.into_payload(); builder.write(&utxo_payload)?; - builder.write(&owners_parts)?; + let owners_parts_with_randomness = owners_parts + .into_iter() + .map(|(amount, addr)| { + let mut randomness = Randomness::default(); + OsRng.fill_bytes(&mut randomness); + (amount, addr, randomness) + }) + .collect::>(); + + builder.write(&owners_parts_with_randomness)?; let env = builder.build()?; @@ -331,13 +363,12 @@ pub fn execute_send_utxo( let digest: (UTXOPayload, Vec<(UTXOPayload, AccountAddress)>) = receipt.journal.decode()?; Ok(( - UTXO::create_utxo_from_payload(digest.0)?, + UTXO::create_utxo_from_payload(digest.0), digest .1 .into_iter() - .map(|(payload, addr)| (UTXO::create_utxo_from_payload(payload).map(|sel| (sel, addr)))) - .collect::>>() - .map_err(ExecutionFailureKind::write_error)?, + .map(|(payload, addr)| (UTXO::create_utxo_from_payload(payload), addr)) + .collect(), )) } diff --git a/zkvm/test_methods/guest/src/bin/mint_utxo.rs b/zkvm/test_methods/guest/src/bin/mint_utxo.rs index ad51311..5123643 100644 --- a/zkvm/test_methods/guest/src/bin/mint_utxo.rs +++ b/zkvm/test_methods/guest/src/bin/mint_utxo.rs @@ -12,17 +12,20 @@ pub struct UTXOPayload { // TODO: change to u256 pub amount: u128, pub privacy_flag: bool, + pub randomness: [u8; 32], } fn main() { let amount_to_mint: u128 = env::read(); let owner: AccountAddr = env::read(); + let randomness: [u8; 32] = env::read(); let payload = UTXOPayload { owner, asset: vec![], amount: amount_to_mint, privacy_flag: true, + randomness, }; env::commit(&(payload)); diff --git a/zkvm/test_methods/guest/src/bin/mint_utxo_multiple_assets.rs b/zkvm/test_methods/guest/src/bin/mint_utxo_multiple_assets.rs index 8ba50c4..47ad2ac 100644 --- a/zkvm/test_methods/guest/src/bin/mint_utxo_multiple_assets.rs +++ b/zkvm/test_methods/guest/src/bin/mint_utxo_multiple_assets.rs @@ -12,12 +12,14 @@ pub struct UTXOPayload { // TODO: change to u256 pub amount: u128, pub privacy_flag: bool, + pub randomness: [u8; 32], } fn main() { let amount_to_mint: u128 = env::read(); let number_of_assets: usize = env::read(); let owner: AccountAddr = env::read(); + let randomness: [u8; 32] = env::read(); let mut asseted_utxos = vec![]; @@ -27,6 +29,7 @@ fn main() { asset: vec![i as u8], amount: amount_to_mint, privacy_flag: true, + randomness }; asseted_utxos.push(payload); diff --git a/zkvm/test_methods/guest/src/bin/send_utxo.rs b/zkvm/test_methods/guest/src/bin/send_utxo.rs index d05995c..64035a9 100644 --- a/zkvm/test_methods/guest/src/bin/send_utxo.rs +++ b/zkvm/test_methods/guest/src/bin/send_utxo.rs @@ -12,18 +12,20 @@ pub struct UTXOPayload { // TODO: change to u256 pub amount: u128, pub privacy_flag: bool, + pub randomness: [u8; 32], } fn main() { let utxo_spent: UTXOPayload = env::read(); - let owners_parts: Vec<(u128, AccountAddr)> = env::read(); + let owners_parts: Vec<(u128, AccountAddr, [u8; 32])> = env::read(); - let res: Vec<(UTXOPayload, AccountAddr)> = owners_parts.into_iter().map(|(amount, addr)| ( + let res: Vec<(UTXOPayload, AccountAddr)> = owners_parts.into_iter().map(|(amount, addr, randomness)| ( UTXOPayload { owner: addr.clone(), asset: vec![], amount, privacy_flag: true, + randomness, }, addr )).collect(); diff --git a/zkvm/test_methods/guest/src/bin/send_utxo_multiple_assets.rs b/zkvm/test_methods/guest/src/bin/send_utxo_multiple_assets.rs index 2568da3..e73f844 100644 --- a/zkvm/test_methods/guest/src/bin/send_utxo_multiple_assets.rs +++ b/zkvm/test_methods/guest/src/bin/send_utxo_multiple_assets.rs @@ -12,6 +12,7 @@ pub struct UTXOPayload { // TODO: change to u256 pub amount: u128, pub privacy_flag: bool, + pub randomness: [u8; 32], } fn main() { From 81f0cf72ae758c7f40e211ffe917f0d5769e0d22 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Fri, 16 May 2025 22:25:28 -0300 Subject: [PATCH 5/7] fix unused imports --- utxo/src/utxo_core.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/utxo/src/utxo_core.rs b/utxo/src/utxo_core.rs index bfb2ff0..4e40ce3 100644 --- a/utxo/src/utxo_core.rs +++ b/utxo/src/utxo_core.rs @@ -1,5 +1,3 @@ -use std::hash::RandomState; - use anyhow::Result; use common::{merkle_tree_public::TreeHashType, AccountId}; use log::info; From ecaa6874ce16e22be4dd0eb3194d1051432b1742 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Sat, 17 May 2025 17:00:41 -0300 Subject: [PATCH 6/7] fix imports --- accounts/src/account_core/mod.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 6d81697..76fd78e 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -5,7 +5,7 @@ use common::{merkle_tree_public::TreeHashType, transaction::Tag}; use k256::AffinePoint; use log::info; use serde::Serialize; -use utxo::utxo_core::{UTXOPayload, UTXO}; +use utxo::utxo_core::UTXO; use crate::key_management::{ constants_types::{CipherText, Nonce}, @@ -148,14 +148,7 @@ mod tests { use super::*; fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> UTXO { - let payload = UTXOPayload { - owner: address, - asset: vec![], - amount, - privacy_flag: false, - randomness: [0u8; 32], - }; - UTXO::create_utxo_from_payload(payload) + UTXO::new(address, vec![], amount, false) } #[test] From da5a0c87499a30ad7b7666885bc387d661303ae4 Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Sat, 17 May 2025 17:01:50 -0300 Subject: [PATCH 7/7] clippy --- accounts/src/account_core/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 76fd78e..728a189 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -91,7 +91,7 @@ impl Account { } self.utxos.insert(utxo.hash, utxo); } - return Ok(()); + Ok(()) } pub fn update_public_balance(&mut self, new_balance: u64) {