goas: more robust nonce evolution strategy
This commit is contained in:
parent
75ff879770
commit
213be6ccd7
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue