From 034fe8eda5bf5ef1742ba7a7eaf74123bc2719fb Mon Sep 17 00:00:00 2001 From: David Rusu Date: Sun, 11 Aug 2024 23:08:40 +0400 Subject: [PATCH] goas: reuse ZoneNotes struct in the deposit/withdrawal scenarios --- goas/atomic_asset_transfer/common/src/lib.rs | 6 +- .../atomic_asset_transfer/executor/src/lib.rs | 96 +++++++++++++++++- .../executor/tests/atomic_transfer.rs | 99 +------------------ .../executor/tests/deposit_ptx.rs | 73 ++++---------- .../executor/tests/withdraw_ptx.rs | 92 +++++------------ 5 files changed, 142 insertions(+), 224 deletions(-) diff --git a/goas/atomic_asset_transfer/common/src/lib.rs b/goas/atomic_asset_transfer/common/src/lib.rs index 7786454..ae28fc7 100644 --- a/goas/atomic_asset_transfer/common/src/lib.rs +++ b/goas/atomic_asset_transfer/common/src/lib.rs @@ -28,8 +28,8 @@ pub struct ZoneMetadata { impl ZoneMetadata { pub fn id(&self) -> [u8; 32] { let mut hasher = Sha256::new(); - hasher.update(&self.zone_vk); - hasher.update(&self.funds_vk); + hasher.update(self.zone_vk); + hasher.update(self.funds_vk); hasher.update(self.unit.compress().as_bytes()); hasher.finalize().into() } @@ -118,7 +118,7 @@ impl StateWitness { pub fn evolve_nonce(self) -> Self { let updated_nonce = { let mut hasher = Sha256::new(); - hasher.update(&self.nonce); + hasher.update(self.nonce); hasher.update(b"NOMOS_ZONE_NONCE_EVOLVE"); hasher.finalize().into() }; diff --git a/goas/atomic_asset_transfer/executor/src/lib.rs b/goas/atomic_asset_transfer/executor/src/lib.rs index 3a13794..ca52f22 100644 --- a/goas/atomic_asset_transfer/executor/src/lib.rs +++ b/goas/atomic_asset_transfer/executor/src/lib.rs @@ -1,10 +1,104 @@ +use std::collections::BTreeMap; + use cl::{PartialTxInputWitness, PartialTxOutputWitness}; -use common::{BoundTx, IncludedTxWitness, StateRoots, StateWitness, ZoneMetadata}; +use common::{BoundTx, IncludedTxWitness, StateRoots, StateWitness, Tx, ZoneMetadata}; use goas_proof_statements::{ user_note::{UserAtomicTransfer, UserIntent}, zone_funds::SpendFundsPrivate, zone_state::ZoneStatePrivate, }; +use rand_core::CryptoRngCore; + +#[derive(Debug, Clone)] +pub struct ZoneNotes { + pub state: StateWitness, + pub state_note: cl::OutputWitness, + pub fund_note: cl::OutputWitness, +} + +impl ZoneNotes { + pub fn new_with_balances( + zone_name: &str, + balances: BTreeMap, + mut rng: impl CryptoRngCore, + ) -> Self { + let state = StateWitness { + balances, + included_txs: vec![], + zone_metadata: zone_metadata(zone_name), + nonce: [0; 32], + }; + let state_note = zone_state_utxo(&state, &mut rng); + let fund_note = zone_fund_utxo(state.total_balance(), state.zone_metadata, &mut rng); + Self { + state, + state_note, + fund_note, + } + } + + pub fn state_input_witness(&self) -> cl::InputWitness { + cl::InputWitness::public(self.state_note) + } + + pub fn fund_input_witness(&self) -> cl::InputWitness { + cl::InputWitness::public(self.fund_note) + } + + pub fn run(mut self, txs: impl IntoIterator) -> Self { + for tx in txs { + self.state = self.state.apply(tx); + } + self.state = self.state.evolve_nonce(); + + let state_in = self.state_input_witness(); + self.state_note = cl::OutputWitness::public( + cl::NoteWitness { + state: self.state.commit().0, + ..state_in.note + }, + state_in.evolved_nonce(), + ); + + let fund_in = self.fund_input_witness(); + self.fund_note = cl::OutputWitness::public( + cl::NoteWitness { + value: self.state.total_balance(), + ..fund_in.note + }, + cl::NullifierNonce::from_bytes(self.state.nonce), + ); + self + } +} + +fn zone_fund_utxo( + value: u64, + zone_meta: ZoneMetadata, + mut rng: impl CryptoRngCore, +) -> cl::OutputWitness { + cl::OutputWitness::public( + cl::NoteWitness { + value, + unit: *common::ZONE_CL_FUNDS_UNIT, + death_constraint: zone_meta.funds_vk, + state: zone_meta.id(), + }, + cl::NullifierNonce::random(&mut rng), + ) +} + +fn zone_state_utxo(zone: &StateWitness, mut rng: impl CryptoRngCore) -> cl::OutputWitness { + cl::OutputWitness::public( + cl::NoteWitness { + value: 1, + unit: zone.zone_metadata.unit, + death_constraint: zone.zone_metadata.zone_vk, + state: zone.commit().0, + }, + cl::NullifierNonce::random(&mut rng), + ) +} pub fn user_atomic_transfer_death_constraint() -> [u8; 32] { ledger::death_constraint::risc0_id_to_cl_death_constraint( diff --git a/goas/atomic_asset_transfer/executor/tests/atomic_transfer.rs b/goas/atomic_asset_transfer/executor/tests/atomic_transfer.rs index 4866dbd..f80a437 100644 --- a/goas/atomic_asset_transfer/executor/tests/atomic_transfer.rs +++ b/goas/atomic_asset_transfer/executor/tests/atomic_transfer.rs @@ -1,100 +1,9 @@ use std::collections::BTreeMap; use cl::{BundleWitness, NoteWitness, NullifierNonce}; -use common::{BoundTx, Deposit, StateWitness, Tx, Withdraw, ZoneMetadata}; +use common::{BoundTx, Deposit, Tx, Withdraw}; +use executor::ZoneNotes; use goas_proof_statements::user_note::UserIntent; -use rand_core::CryptoRngCore; - -fn zone_fund_utxo( - value: u64, - zone_meta: ZoneMetadata, - mut rng: impl CryptoRngCore, -) -> cl::OutputWitness { - cl::OutputWitness::public( - cl::NoteWitness { - value, - unit: *common::ZONE_CL_FUNDS_UNIT, - death_constraint: zone_meta.funds_vk, - state: zone_meta.id(), - }, - NullifierNonce::random(&mut rng), - ) -} - -fn zone_state_utxo(zone: &StateWitness, mut rng: impl CryptoRngCore) -> cl::OutputWitness { - cl::OutputWitness::public( - cl::NoteWitness { - value: 1, - unit: zone.zone_metadata.unit, - death_constraint: zone.zone_metadata.zone_vk, - state: zone.commit().0, - }, - NullifierNonce::random(&mut rng), - ) -} - -#[derive(Debug, Clone)] -struct ZoneNotes { - state: StateWitness, - state_note: cl::OutputWitness, - fund_note: cl::OutputWitness, -} - -impl ZoneNotes { - fn new_with_balances( - zone_name: &str, - balances: BTreeMap, - mut rng: impl CryptoRngCore, - ) -> Self { - let state = StateWitness { - balances, - included_txs: vec![], - zone_metadata: executor::zone_metadata(zone_name), - nonce: [0; 32], - }; - let state_note = zone_state_utxo(&state, &mut rng); - let fund_note = zone_fund_utxo(state.total_balance(), state.zone_metadata, &mut rng); - Self { - state, - state_note, - fund_note, - } - } - - fn state_input_witness(&self) -> cl::InputWitness { - cl::InputWitness::public(self.state_note) - } - - fn fund_input_witness(&self) -> cl::InputWitness { - cl::InputWitness::public(self.fund_note) - } - - fn run(mut self, txs: Vec) -> Self { - for tx in txs { - self.state = self.state.apply(tx); - } - self.state = self.state.evolve_nonce(); - - let state_in = self.state_input_witness(); - self.state_note = cl::OutputWitness::public( - cl::NoteWitness { - state: self.state.commit().0, - ..state_in.note - }, - state_in.evolved_nonce(), - ); - - let fund_in = self.fund_input_witness(); - self.fund_note = cl::OutputWitness::public( - cl::NoteWitness { - value: self.state.total_balance(), - ..fund_in.note - }, - NullifierNonce::from_bytes(self.state.nonce), - ); - self - } -} #[test] fn test_atomic_transfer() { @@ -137,11 +46,11 @@ fn test_atomic_transfer() { let zone_a_end = zone_a_start .clone() - .run(vec![Tx::Withdraw(alice_intent.withdraw)]); + .run([Tx::Withdraw(alice_intent.withdraw)]); let zone_b_end = zone_b_start .clone() - .run(vec![Tx::Deposit(alice_intent.deposit)]); + .run([Tx::Deposit(alice_intent.deposit)]); let alice_intent_in = cl::InputWitness::public(alice_intent_out); let atomic_transfer_ptx = cl::PartialTxWitness { diff --git a/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs b/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs index fedab1f..4b07a03 100644 --- a/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs +++ b/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs @@ -1,30 +1,9 @@ use std::collections::BTreeMap; -use cl::{NoteWitness, NullifierNonce, NullifierSecret}; -use common::{BoundTx, StateWitness, Tx, ZoneMetadata, ZONE_CL_FUNDS_UNIT}; +use cl::{NoteWitness, NullifierSecret}; +use common::{BoundTx, StateWitness, Tx, ZONE_CL_FUNDS_UNIT}; +use executor::ZoneNotes; use ledger::death_constraint::DeathProof; -use rand_core::CryptoRngCore; - -fn zone_fund_note(value: u64, zone_meta: ZoneMetadata) -> cl::NoteWitness { - cl::NoteWitness { - value, - unit: *common::ZONE_CL_FUNDS_UNIT, - death_constraint: zone_meta.funds_vk, - state: zone_meta.id(), - } -} - -fn zone_state_utxo(zone: &StateWitness, mut rng: impl CryptoRngCore) -> cl::OutputWitness { - cl::OutputWitness::public( - cl::NoteWitness { - value: 1, - unit: zone.zone_metadata.unit, - death_constraint: zone.zone_metadata.zone_vk, - state: zone.commit().0, - }, - NullifierNonce::random(&mut rng), - ) -} #[test] fn test_deposit() { @@ -33,36 +12,15 @@ fn test_deposit() { let alice = 42; let alice_sk = NullifierSecret::random(&mut rng); - let init_state = StateWitness { - balances: BTreeMap::new(), - included_txs: vec![], - zone_metadata: executor::zone_metadata("ZONE"), - nonce: [0; 32], - }; - - let zone_state_in = cl::InputWitness::public(zone_state_utxo(&init_state, &mut rng)); + let zone_start = ZoneNotes::new_with_balances("ZONE", BTreeMap::new(), &mut rng); let deposit = common::Deposit { to: alice, amount: 78, }; - let end_state = init_state - .clone() - .apply(Tx::Deposit(deposit)) - .evolve_nonce(); + let zone_end = zone_start.clone().run([Tx::Deposit(deposit)]); - let zone_state_out = cl::OutputWitness::public( - cl::NoteWitness { - state: end_state.commit().0, - ..zone_state_in.note - }, - zone_state_in.evolved_nonce(), - ); - let zone_fund_out = cl::OutputWitness::public( - zone_fund_note(78, init_state.zone_metadata), - NullifierNonce::from_bytes(end_state.nonce), - ); let alice_deposit = cl::InputWitness::random( cl::OutputWitness::random( NoteWitness::stateless( @@ -78,15 +36,15 @@ fn test_deposit() { ); let deposit_ptx = cl::PartialTxWitness { - inputs: vec![zone_state_in, alice_deposit], - outputs: vec![zone_state_out, zone_fund_out], + inputs: vec![zone_start.state_input_witness(), alice_deposit], + outputs: vec![zone_end.state_note, zone_end.fund_note], }; let death_proofs = BTreeMap::from_iter([ ( - zone_state_in.nullifier(), + zone_start.state_input_witness().nullifier(), executor::prove_zone_stf( - init_state.clone(), + zone_start.state.clone(), vec![BoundTx { tx: Tx::Deposit(deposit), bind: deposit_ptx.input_witness(1), // bind it to the deposit note @@ -103,7 +61,7 @@ fn test_deposit() { ]); let note_commitments = vec![ - zone_state_in.note_commitment(), + zone_start.state_note.commit_note(), alice_deposit.note_commitment(), ]; @@ -113,14 +71,17 @@ fn test_deposit() { assert!(deposit_proof.verify()); - assert_eq!(deposit_proof.outputs[0].output, zone_state_out.commit()); assert_eq!( - zone_state_out.note.state, + deposit_proof.outputs[0].output, + zone_end.state_note.commit() + ); + assert_eq!( + zone_end.state_note.note.state, StateWitness { balances: BTreeMap::from_iter([(alice, 78)]), included_txs: vec![Tx::Deposit(deposit)], - zone_metadata: init_state.zone_metadata, - nonce: init_state.evolve_nonce().nonce, + zone_metadata: zone_start.state.zone_metadata, + nonce: zone_start.state.evolve_nonce().nonce, } .commit() .0 diff --git a/goas/atomic_asset_transfer/executor/tests/withdraw_ptx.rs b/goas/atomic_asset_transfer/executor/tests/withdraw_ptx.rs index 155b5c4..17de9c7 100644 --- a/goas/atomic_asset_transfer/executor/tests/withdraw_ptx.rs +++ b/goas/atomic_asset_transfer/executor/tests/withdraw_ptx.rs @@ -2,37 +2,10 @@ use std::collections::BTreeMap; use cl::{NoteWitness, NullifierNonce, NullifierSecret}; use common::{BoundTx, StateWitness, Tx, ZoneMetadata, ZONE_CL_FUNDS_UNIT}; +use executor::ZoneNotes; use ledger::death_constraint::DeathProof; use rand_core::CryptoRngCore; -fn zone_fund_utxo( - value: u64, - zone_meta: ZoneMetadata, - mut rng: impl CryptoRngCore, -) -> cl::OutputWitness { - cl::OutputWitness::public( - cl::NoteWitness { - value, - unit: *common::ZONE_CL_FUNDS_UNIT, - death_constraint: zone_meta.funds_vk, - state: zone_meta.id(), - }, - NullifierNonce::random(&mut rng), - ) -} - -fn zone_state_utxo(zone: &StateWitness, mut rng: impl CryptoRngCore) -> cl::OutputWitness { - cl::OutputWitness::public( - cl::NoteWitness { - value: 1, - unit: zone.zone_metadata.unit, - death_constraint: zone.zone_metadata.zone_vk, - state: zone.commit().0, - }, - NullifierNonce::random(&mut rng), - ) -} - #[test] fn test_withdrawal() { let mut rng = rand::thread_rng(); @@ -40,16 +13,8 @@ fn test_withdrawal() { let alice = 42; let alice_sk = NullifierSecret::random(&mut rng); - let init_state = StateWitness { - balances: BTreeMap::from_iter([(alice, 100)]), - included_txs: vec![], - zone_metadata: executor::zone_metadata("ZONE"), - nonce: [0; 32], - }; - - let zone_fund_in = - cl::InputWitness::public(zone_fund_utxo(100, init_state.zone_metadata, &mut rng)); - let zone_state_in = cl::InputWitness::public(zone_state_utxo(&init_state, &mut rng)); + let zone_start = + ZoneNotes::new_with_balances("ZONE", BTreeMap::from_iter([(alice, 100)]), &mut rng); let alice_intent = cl::InputWitness::random( cl::OutputWitness::random( @@ -66,25 +31,7 @@ fn test_withdrawal() { amount: 78, }; - let end_state = init_state - .clone() - .apply(Tx::Withdraw(withdraw.clone())) - .evolve_nonce(); - - let zone_state_out = cl::OutputWitness::public( - cl::NoteWitness { - state: end_state.commit().0, - ..zone_state_in.note - }, - zone_state_in.evolved_nonce(), - ); - let zone_fund_out = cl::OutputWitness::public( - cl::NoteWitness { - value: zone_fund_in.note.value - withdraw.amount, - ..zone_fund_in.note - }, - NullifierNonce::from_bytes(end_state.nonce), - ); + let zone_end = zone_start.clone().run([Tx::Withdraw(withdraw)]); let alice_withdrawal = cl::OutputWitness::random( NoteWitness::stateless( @@ -97,15 +44,19 @@ fn test_withdrawal() { ); let withdraw_ptx = cl::PartialTxWitness { - inputs: vec![zone_state_in, zone_fund_in, alice_intent], - outputs: vec![zone_state_out, zone_fund_out, alice_withdrawal], + inputs: vec![ + zone_start.state_input_witness(), + zone_start.fund_input_witness(), + alice_intent, + ], + outputs: vec![zone_end.state_note, zone_end.fund_note, alice_withdrawal], }; let death_proofs = BTreeMap::from_iter([ ( - zone_state_in.nullifier(), + zone_start.state_input_witness().nullifier(), executor::prove_zone_stf( - init_state.clone(), + zone_start.state.clone(), vec![BoundTx { tx: Tx::Withdraw(withdraw.clone()), bind: withdraw_ptx.input_witness(2), @@ -116,11 +67,11 @@ fn test_withdrawal() { ), ), ( - zone_fund_in.nullifier(), + zone_start.fund_input_witness().nullifier(), executor::prove_zone_fund_withdraw( withdraw_ptx.input_witness(1), // input fund note (input #1) withdraw_ptx.output_witness(0), // output state note (output #0) - &end_state, + &zone_end.state, ), ), ( @@ -130,8 +81,8 @@ fn test_withdrawal() { ]); let note_commitments = vec![ - zone_state_in.note_commitment(), - zone_fund_in.note_commitment(), + zone_start.state_note.commit_note(), + zone_start.fund_note.commit_note(), alice_intent.note_commitment(), ]; @@ -141,14 +92,17 @@ fn test_withdrawal() { assert!(withdraw_proof.verify()); - assert_eq!(withdraw_proof.outputs[0].output, zone_state_out.commit()); assert_eq!( - zone_state_out.note.state, + withdraw_proof.outputs[0].output, + zone_end.state_note.commit() + ); + assert_eq!( + zone_end.state_note.note.state, StateWitness { balances: BTreeMap::from_iter([(alice, 22)]), included_txs: vec![Tx::Withdraw(withdraw)], - zone_metadata: init_state.zone_metadata, - nonce: init_state.evolve_nonce().nonce, + zone_metadata: zone_start.state.zone_metadata, + nonce: zone_start.state.evolve_nonce().nonce, } .commit() .0