From 213be6ccd7303afcd6d68ad8889f0761bd7076a1 Mon Sep 17 00:00:00 2001 From: David Rusu Date: Sat, 17 Aug 2024 16:58:13 +0400 Subject: [PATCH] goas: more robust nonce evolution strategy --- goas/atomic_asset_transfer/common/src/lib.rs | 35 ++++--------------- .../atomic_asset_transfer/executor/src/lib.rs | 6 ++-- .../executor/tests/deposit_ptx.rs | 1 - .../executor/tests/withdraw_ptx.rs | 1 - .../risc0_proofs/zone_state/src/main.rs | 7 ++-- goas/cl/cl/src/input.rs | 12 ++++--- goas/cl/cl/src/nullifier.rs | 7 ++-- 7 files changed, 24 insertions(+), 45 deletions(-) diff --git a/goas/atomic_asset_transfer/common/src/lib.rs b/goas/atomic_asset_transfer/common/src/lib.rs index ae28fc7..ca00ad9 100644 --- a/goas/atomic_asset_transfer/common/src/lib.rs +++ b/goas/atomic_asset_transfer/common/src/lib.rs @@ -40,7 +40,6 @@ pub struct StateWitness { pub balances: BTreeMap, pub included_txs: Vec, pub zone_metadata: ZoneMetadata, - pub nonce: [u8; 32], } impl StateWitness { @@ -50,7 +49,6 @@ impl StateWitness { pub fn state_roots(&self) -> StateRoots { StateRoots { - nonce: self.nonce, tx_root: self.included_txs_root(), zone_id: self.zone_metadata.id(), balance_root: self.balances_root(), @@ -115,19 +113,6 @@ impl StateWitness { self.balances.values().sum() } - pub fn evolve_nonce(self) -> Self { - let updated_nonce = { - let mut hasher = Sha256::new(); - hasher.update(self.nonce); - hasher.update(b"NOMOS_ZONE_NONCE_EVOLVE"); - hasher.finalize().into() - }; - Self { - nonce: updated_nonce, - ..self - } - } - fn included_tx_merkle_leaves(&self) -> [[u8; 32]; MAX_TXS] { let tx_bytes = self .included_txs @@ -221,25 +206,19 @@ impl IncludedTxWitness { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct StateRoots { - pub nonce: [u8; 32], pub tx_root: [u8; 32], pub zone_id: [u8; 32], pub balance_root: [u8; 32], } impl StateRoots { - /// Merkle tree over: - /// root - /// / \ - /// io state - /// / \ / \ - /// nonce txs zoneid balances + /// Merkle tree over: [txs, zoneid, balances] pub fn commit(&self) -> StateCommitment { - StateCommitment(cl::merkle::root([ - self.nonce, - self.tx_root, - self.zone_id, - self.balance_root, - ])) + let leaves = cl::merkle::padded_leaves::<4>(&[ + self.tx_root.to_vec(), + self.zone_id.to_vec(), + self.balance_root.to_vec(), + ]); + StateCommitment(cl::merkle::root(leaves)) } } diff --git a/goas/atomic_asset_transfer/executor/src/lib.rs b/goas/atomic_asset_transfer/executor/src/lib.rs index 43a6655..7474d98 100644 --- a/goas/atomic_asset_transfer/executor/src/lib.rs +++ b/goas/atomic_asset_transfer/executor/src/lib.rs @@ -23,7 +23,6 @@ impl ZoneNotes { 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); @@ -46,7 +45,6 @@ impl ZoneNotes { 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( @@ -54,7 +52,7 @@ impl ZoneNotes { state: self.state.commit().0, ..state_in.note }, - state_in.evolved_nonce(), + state_in.evolved_nonce(b"STATE_NONCE"), ); let fund_in = self.fund_input_witness(); @@ -63,7 +61,7 @@ impl ZoneNotes { value: self.state.total_balance(), ..fund_in.note }, - cl::NullifierNonce::from_bytes(self.state.nonce), + state_in.evolved_nonce(b"FUND_NONCE"), ); self } diff --git a/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs b/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs index 4b07a03..ddfdce8 100644 --- a/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs +++ b/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs @@ -81,7 +81,6 @@ fn test_deposit() { balances: BTreeMap::from_iter([(alice, 78)]), included_txs: vec![Tx::Deposit(deposit)], 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 1c9d061..1fa3476 100644 --- a/goas/atomic_asset_transfer/executor/tests/withdraw_ptx.rs +++ b/goas/atomic_asset_transfer/executor/tests/withdraw_ptx.rs @@ -101,7 +101,6 @@ fn test_withdrawal() { balances: BTreeMap::from_iter([(alice, 22)]), included_txs: vec![Tx::Withdraw(withdraw)], zone_metadata: zone_start.state.zone_metadata, - nonce: zone_start.state.evolve_nonce().nonce, } .commit() .0 diff --git a/goas/atomic_asset_transfer/risc0_proofs/zone_state/src/main.rs b/goas/atomic_asset_transfer/risc0_proofs/zone_state/src/main.rs index 1638536..8232640 100644 --- a/goas/atomic_asset_transfer/risc0_proofs/zone_state/src/main.rs +++ b/goas/atomic_asset_transfer/risc0_proofs/zone_state/src/main.rs @@ -1,5 +1,5 @@ use cl::{ - note::NoteWitness, nullifier::NullifierNonce, output::OutputWitness, + note::NoteWitness, output::OutputWitness, PtxRoot, }; @@ -39,7 +39,7 @@ fn validate_zone_transition( ); // the nonce is correctly evolved - assert_eq!(in_note.input.evolved_nonce(), out_note.output.nonce); + assert_eq!(in_note.input.evolved_nonce(b"STATE_NONCE"), out_note.output.nonce); // funds are still under control of the zone let expected_note_witness = NoteWitness::new( @@ -52,7 +52,7 @@ fn validate_zone_transition( out_funds.output, OutputWitness::public( expected_note_witness, - NullifierNonce::from_bytes(out_state.nonce) + in_note.input.evolved_nonce(b"FUND_NONCE") ) ); // funds belong to the same partial tx @@ -83,7 +83,6 @@ fn main() { state = state.apply(tx) } - let state = state.evolve_nonce(); validate_zone_transition(zone_in, zone_out, funds_out, in_state_cm, state); env::commit(&pub_inputs); diff --git a/goas/cl/cl/src/input.rs b/goas/cl/cl/src/input.rs index 718b1bd..8fa32d2 100644 --- a/goas/cl/cl/src/input.rs +++ b/goas/cl/cl/src/input.rs @@ -52,16 +52,20 @@ impl InputWitness { } } - pub fn evolved_nonce(&self) -> NullifierNonce { - self.nonce.evolve(&self.nf_sk) + pub fn evolved_nonce(&self, domain: &[u8]) -> NullifierNonce { + self.nonce.evolve(domain, &self.nf_sk, &self.note) } - pub fn evolve_output(&self, balance_blinding: BalanceWitness) -> crate::OutputWitness { + pub fn evolve_output( + &self, + domain: &[u8], + balance_blinding: BalanceWitness, + ) -> crate::OutputWitness { crate::OutputWitness { note: self.note, balance_blinding, nf_pk: self.nf_sk.commit(), - nonce: self.evolved_nonce(), + nonce: self.evolved_nonce(domain), } } diff --git a/goas/cl/cl/src/nullifier.rs b/goas/cl/cl/src/nullifier.rs index 4b8c59b..ada9f81 100644 --- a/goas/cl/cl/src/nullifier.rs +++ b/goas/cl/cl/src/nullifier.rs @@ -9,7 +9,7 @@ use rand_core::RngCore; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; -use crate::NoteCommitment; +use crate::{NoteCommitment, NoteWitness}; // TODO: create a nullifier witness and use it throughout. // struct NullifierWitness { @@ -92,11 +92,12 @@ impl NullifierNonce { Self(bytes) } - pub fn evolve(&self, nf_sk: &NullifierSecret) -> Self { + pub fn evolve(&self, domain: &[u8], nf_sk: &NullifierSecret, note: &NoteWitness) -> Self { let mut hasher = Sha256::new(); hasher.update(b"NOMOS_COIN_EVOLVE"); - hasher.update(&self.0); + hasher.update(domain); hasher.update(nf_sk.0); + hasher.update(note.commit(nf_sk.commit(), *self).0); let nonce_bytes: [u8; 32] = hasher.finalize().into(); Self(nonce_bytes)