From e7ba67d09bf61842587e27a0dd8fb73d06f9720c Mon Sep 17 00:00:00 2001 From: Giacomo Pasini Date: Fri, 2 Aug 2024 14:42:13 +0200 Subject: [PATCH] add death constraints to metadata --- goas/atomic_asset_transfer/common/Cargo.toml | 3 +- goas/atomic_asset_transfer/common/src/lib.rs | 36 ++++++++++++++----- .../risc0_proofs/zone_state/src/main.rs | 23 +++++++----- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/goas/atomic_asset_transfer/common/Cargo.toml b/goas/atomic_asset_transfer/common/Cargo.toml index 3fdc733..8c428bf 100644 --- a/goas/atomic_asset_transfer/common/Cargo.toml +++ b/goas/atomic_asset_transfer/common/Cargo.toml @@ -8,4 +8,5 @@ serde = { version = "1", features = ["derive"] } cl = { path = "../../cl/cl" } goas_proof_statements = { path = "../proof_statements" } proof_statements = { path = "../../cl/proof_statements" } -once_cell = "1" \ No newline at end of file +once_cell = "1" +sha2 = "0.10" \ No newline at end of file diff --git a/goas/atomic_asset_transfer/common/src/lib.rs b/goas/atomic_asset_transfer/common/src/lib.rs index a4bfbe8..6623080 100644 --- a/goas/atomic_asset_transfer/common/src/lib.rs +++ b/goas/atomic_asset_transfer/common/src/lib.rs @@ -7,6 +7,7 @@ use cl::{ }; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; use std::collections::BTreeMap; // TODO: sparse merkle tree @@ -20,27 +21,44 @@ pub struct StateCommitment([u8; 32]); pub type AccountId = u32; -// PLACEHOLDER: replace with the death constraint vk of the zone funds -pub const ZONE_FUNDS_VK: [u8; 32] = [0; 32]; // PLACEHOLDER: this is probably going to be NMO? pub static ZONE_CL_FUNDS_UNIT: Lazy = Lazy::new(|| crypto::hash_to_curve(b"NMO")); -// PLACEHOLDER -pub static ZONE_UNIT: Lazy = Lazy::new(|| crypto::hash_to_curve(b"ZONE_UNIT")); -// PLACEHOLDER -pub const ZONE_NF_PK: NullifierCommitment = NullifierCommitment::from_bytes([0; 32]); + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ZoneMetadata { + pub self_vk: [u8; 32], + pub funds_vk: [u8; 32], + pub unit: Unit, +} + +impl ZoneMetadata { + pub fn id(&self) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(&self.self_vk); + hasher.update(&self.funds_vk); + hasher.update(self.unit.compress().as_bytes()); + hasher.finalize().into() + } +} #[derive(Clone, Serialize, Deserialize)] pub struct StateWitness { pub balances: BTreeMap, pub included_txs: Vec, pub output_events: Vec, + pub zone_metadata: ZoneMetadata, } impl StateWitness { pub fn commit(&self) -> StateCommitment { - let root = self.balances_root(); - let root = cl::merkle::node(self.events_root(), root); - let root = cl::merkle::node(self.included_txs_root(), root); + let io_root = cl::merkle::node(self.events_root(), self.included_txs_root()); + + let balances_root = self.balances_root(); + let zone_id = self.zone_metadata.id(); + let state_root = cl::merkle::node(zone_id, balances_root); + + let root = cl::merkle::node(io_root, state_root); + StateCommitment(root) } 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 b7d7dc7..c4541bf 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 @@ -54,6 +54,8 @@ fn deposit( zone_funds_out, } = deposit; + let funds_vk = state.zone_metadata.funds_vk; + // 1) Check there are no more input/output notes than expected let inputs = [ deposit.commit().to_bytes().to_vec(), @@ -74,13 +76,13 @@ fn deposit( assert_eq!(ptx_root, pub_inputs.ptx_root); // 2) Check the deposit note is not already under control of the zone - assert_ne!(deposit.note.death_constraint, ZONE_FUNDS_VK); + assert_ne!(deposit.note.death_constraint, funds_vk); // 3) Check the ptx is balanced. This is not a requirement for standard ptxs, but we need it // in deposits (at least in a first version) to ensure fund tracking - assert_eq!(deposit.note.unit, *ZONE_UNIT); - assert_eq!(zone_funds_in.note.unit, *ZONE_UNIT); - assert_eq!(zone_funds_out.note.unit, *ZONE_UNIT); + assert_eq!(deposit.note.unit, *ZONE_CL_FUNDS_UNIT); + assert_eq!(zone_funds_in.note.unit, *ZONE_CL_FUNDS_UNIT); + assert_eq!(zone_funds_out.note.unit, *ZONE_CL_FUNDS_UNIT); let in_sum = deposit.note.value + zone_funds_in.note.value; @@ -89,8 +91,8 @@ fn deposit( assert_eq!(out_sum, in_sum, "deposit ptx is unbalanced"); // 4) Check the zone fund notes are correctly created - assert_eq!(zone_funds_in.note.death_constraint, ZONE_FUNDS_VK); - assert_eq!(zone_funds_out.note.death_constraint, ZONE_FUNDS_VK); + assert_eq!(zone_funds_in.note.death_constraint, funds_vk); + assert_eq!(zone_funds_out.note.death_constraint, funds_vk); assert_eq!(zone_funds_in.nf_sk, NullifierSecret::from_bytes([0; 16])); // there is no secret in the zone funds assert_eq!(zone_funds_out.nf_pk, zone_funds_in.nf_sk.commit()); // the sk is the same // nonce is correctly evolved @@ -136,6 +138,11 @@ fn validate_zone_input( let nf = Nullifier::new(input.input.nf_sk, input.input.nonce); assert_eq!(input.input.note.state, <[u8; 32]>::from(state.commit())); + // should not be possible to create one but let's put this check here just in case + debug_assert_eq!( + input.input.note.death_constraint, + state.zone_metadata.self_vk + ); (ptx_root, nf) } @@ -149,10 +156,10 @@ fn validate_zone_output( assert_eq!(ptx, output.ptx_root()); // the ptx root is the same as in the input let output = output.output; assert_eq!(output.note.state, <[u8; 32]>::from(state.commit())); // the state in the output is as calculated by this function - assert_eq!(output.note.death_constraint, input.note.death_constraint); // the death constraint is the same as the on in the input + assert_eq!(output.note.death_constraint, state.zone_metadata.self_vk); // the death constraint is the correct one assert_eq!(output.nf_pk, NullifierSecret::from_bytes([0; 16]).commit()); // the nullifier secret is public assert_eq!(output.balance_blinding, input.balance_blinding); // the balance blinding is the same as in the input - assert_eq!(output.note.unit, input.note.unit); // the balance unit is the same as in the input + assert_eq!(output.note.unit, state.zone_metadata.unit); // the balance unit is the same as in the input // the nonce is correctly evolved assert_eq!(