goas: more robust nonce evolution strategy

This commit is contained in:
David Rusu 2024-08-17 16:58:13 +04:00
parent 75ff879770
commit 213be6ccd7
7 changed files with 24 additions and 45 deletions

View File

@ -40,7 +40,6 @@ pub struct StateWitness {
pub balances: BTreeMap<AccountId, u64>, pub balances: BTreeMap<AccountId, u64>,
pub included_txs: Vec<Tx>, pub included_txs: Vec<Tx>,
pub zone_metadata: ZoneMetadata, pub zone_metadata: ZoneMetadata,
pub nonce: [u8; 32],
} }
impl StateWitness { impl StateWitness {
@ -50,7 +49,6 @@ impl StateWitness {
pub fn state_roots(&self) -> StateRoots { pub fn state_roots(&self) -> StateRoots {
StateRoots { StateRoots {
nonce: self.nonce,
tx_root: self.included_txs_root(), tx_root: self.included_txs_root(),
zone_id: self.zone_metadata.id(), zone_id: self.zone_metadata.id(),
balance_root: self.balances_root(), balance_root: self.balances_root(),
@ -115,19 +113,6 @@ impl StateWitness {
self.balances.values().sum() 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] { fn included_tx_merkle_leaves(&self) -> [[u8; 32]; MAX_TXS] {
let tx_bytes = self let tx_bytes = self
.included_txs .included_txs
@ -221,25 +206,19 @@ impl IncludedTxWitness {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct StateRoots { pub struct StateRoots {
pub nonce: [u8; 32],
pub tx_root: [u8; 32], pub tx_root: [u8; 32],
pub zone_id: [u8; 32], pub zone_id: [u8; 32],
pub balance_root: [u8; 32], pub balance_root: [u8; 32],
} }
impl StateRoots { impl StateRoots {
/// Merkle tree over: /// Merkle tree over: [txs, zoneid, balances]
/// root
/// / \
/// io state
/// / \ / \
/// nonce txs zoneid balances
pub fn commit(&self) -> StateCommitment { pub fn commit(&self) -> StateCommitment {
StateCommitment(cl::merkle::root([ let leaves = cl::merkle::padded_leaves::<4>(&[
self.nonce, self.tx_root.to_vec(),
self.tx_root, self.zone_id.to_vec(),
self.zone_id, self.balance_root.to_vec(),
self.balance_root, ]);
])) StateCommitment(cl::merkle::root(leaves))
} }
} }

View File

@ -23,7 +23,6 @@ impl ZoneNotes {
balances, balances,
included_txs: vec![], included_txs: vec![],
zone_metadata: zone_metadata(zone_name), zone_metadata: zone_metadata(zone_name),
nonce: [0; 32],
}; };
let state_note = zone_state_utxo(&state, &mut rng); let state_note = zone_state_utxo(&state, &mut rng);
let fund_note = zone_fund_utxo(state.total_balance(), state.zone_metadata, &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 { for tx in txs {
self.state = self.state.apply(tx); self.state = self.state.apply(tx);
} }
self.state = self.state.evolve_nonce();
let state_in = self.state_input_witness(); let state_in = self.state_input_witness();
self.state_note = cl::OutputWitness::public( self.state_note = cl::OutputWitness::public(
@ -54,7 +52,7 @@ impl ZoneNotes {
state: self.state.commit().0, state: self.state.commit().0,
..state_in.note ..state_in.note
}, },
state_in.evolved_nonce(), state_in.evolved_nonce(b"STATE_NONCE"),
); );
let fund_in = self.fund_input_witness(); let fund_in = self.fund_input_witness();
@ -63,7 +61,7 @@ impl ZoneNotes {
value: self.state.total_balance(), value: self.state.total_balance(),
..fund_in.note ..fund_in.note
}, },
cl::NullifierNonce::from_bytes(self.state.nonce), state_in.evolved_nonce(b"FUND_NONCE"),
); );
self self
} }

View File

@ -81,7 +81,6 @@ fn test_deposit() {
balances: BTreeMap::from_iter([(alice, 78)]), balances: BTreeMap::from_iter([(alice, 78)]),
included_txs: vec![Tx::Deposit(deposit)], included_txs: vec![Tx::Deposit(deposit)],
zone_metadata: zone_start.state.zone_metadata, zone_metadata: zone_start.state.zone_metadata,
nonce: zone_start.state.evolve_nonce().nonce,
} }
.commit() .commit()
.0 .0

View File

@ -101,7 +101,6 @@ fn test_withdrawal() {
balances: BTreeMap::from_iter([(alice, 22)]), balances: BTreeMap::from_iter([(alice, 22)]),
included_txs: vec![Tx::Withdraw(withdraw)], included_txs: vec![Tx::Withdraw(withdraw)],
zone_metadata: zone_start.state.zone_metadata, zone_metadata: zone_start.state.zone_metadata,
nonce: zone_start.state.evolve_nonce().nonce,
} }
.commit() .commit()
.0 .0

View File

@ -1,5 +1,5 @@
use cl::{ use cl::{
note::NoteWitness, nullifier::NullifierNonce, output::OutputWitness, note::NoteWitness, output::OutputWitness,
PtxRoot, PtxRoot,
}; };
@ -39,7 +39,7 @@ fn validate_zone_transition(
); );
// the nonce is correctly evolved // 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 // funds are still under control of the zone
let expected_note_witness = NoteWitness::new( let expected_note_witness = NoteWitness::new(
@ -52,7 +52,7 @@ fn validate_zone_transition(
out_funds.output, out_funds.output,
OutputWitness::public( OutputWitness::public(
expected_note_witness, expected_note_witness,
NullifierNonce::from_bytes(out_state.nonce) in_note.input.evolved_nonce(b"FUND_NONCE")
) )
); );
// funds belong to the same partial tx // funds belong to the same partial tx
@ -83,7 +83,6 @@ fn main() {
state = state.apply(tx) state = state.apply(tx)
} }
let state = state.evolve_nonce();
validate_zone_transition(zone_in, zone_out, funds_out, in_state_cm, state); validate_zone_transition(zone_in, zone_out, funds_out, in_state_cm, state);
env::commit(&pub_inputs); env::commit(&pub_inputs);

View File

@ -52,16 +52,20 @@ impl InputWitness {
} }
} }
pub fn evolved_nonce(&self) -> NullifierNonce { pub fn evolved_nonce(&self, domain: &[u8]) -> NullifierNonce {
self.nonce.evolve(&self.nf_sk) 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 { crate::OutputWitness {
note: self.note, note: self.note,
balance_blinding, balance_blinding,
nf_pk: self.nf_sk.commit(), nf_pk: self.nf_sk.commit(),
nonce: self.evolved_nonce(), nonce: self.evolved_nonce(domain),
} }
} }

View File

@ -9,7 +9,7 @@ use rand_core::RngCore;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use crate::NoteCommitment; use crate::{NoteCommitment, NoteWitness};
// TODO: create a nullifier witness and use it throughout. // TODO: create a nullifier witness and use it throughout.
// struct NullifierWitness { // struct NullifierWitness {
@ -92,11 +92,12 @@ impl NullifierNonce {
Self(bytes) 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(); let mut hasher = Sha256::new();
hasher.update(b"NOMOS_COIN_EVOLVE"); hasher.update(b"NOMOS_COIN_EVOLVE");
hasher.update(&self.0); hasher.update(domain);
hasher.update(nf_sk.0); hasher.update(nf_sk.0);
hasher.update(note.commit(nf_sk.commit(), *self).0);
let nonce_bytes: [u8; 32] = hasher.finalize().into(); let nonce_bytes: [u8; 32] = hasher.finalize().into();
Self(nonce_bytes) Self(nonce_bytes)