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() {