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 included_txs: Vec<Tx>,
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))
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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),
}
}

View File

@ -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)