add death constraints to metadata

This commit is contained in:
Giacomo Pasini 2024-08-02 14:42:13 +02:00
parent 2a459b7551
commit e7ba67d09b
No known key found for this signature in database
GPG Key ID: FC08489D2D895D4B
3 changed files with 44 additions and 18 deletions

View File

@ -9,3 +9,4 @@ cl = { path = "../../cl/cl" }
goas_proof_statements = { path = "../proof_statements" } goas_proof_statements = { path = "../proof_statements" }
proof_statements = { path = "../../cl/proof_statements" } proof_statements = { path = "../../cl/proof_statements" }
once_cell = "1" once_cell = "1"
sha2 = "0.10"

View File

@ -7,6 +7,7 @@ use cl::{
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::collections::BTreeMap; use std::collections::BTreeMap;
// TODO: sparse merkle tree // TODO: sparse merkle tree
@ -20,27 +21,44 @@ pub struct StateCommitment([u8; 32]);
pub type AccountId = u32; 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? // PLACEHOLDER: this is probably going to be NMO?
pub static ZONE_CL_FUNDS_UNIT: Lazy<Unit> = Lazy::new(|| crypto::hash_to_curve(b"NMO")); pub static ZONE_CL_FUNDS_UNIT: Lazy<Unit> = Lazy::new(|| crypto::hash_to_curve(b"NMO"));
// PLACEHOLDER
pub static ZONE_UNIT: Lazy<Unit> = Lazy::new(|| crypto::hash_to_curve(b"ZONE_UNIT")); #[derive(Debug, Clone, Serialize, Deserialize)]
// PLACEHOLDER pub struct ZoneMetadata {
pub const ZONE_NF_PK: NullifierCommitment = NullifierCommitment::from_bytes([0; 32]); 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)] #[derive(Clone, Serialize, Deserialize)]
pub struct StateWitness { pub struct StateWitness {
pub balances: BTreeMap<u32, u32>, pub balances: BTreeMap<u32, u32>,
pub included_txs: Vec<Input>, pub included_txs: Vec<Input>,
pub output_events: Vec<Event>, pub output_events: Vec<Event>,
pub zone_metadata: ZoneMetadata,
} }
impl StateWitness { impl StateWitness {
pub fn commit(&self) -> StateCommitment { pub fn commit(&self) -> StateCommitment {
let root = self.balances_root(); let io_root = cl::merkle::node(self.events_root(), self.included_txs_root());
let root = cl::merkle::node(self.events_root(), root);
let root = cl::merkle::node(self.included_txs_root(), 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) StateCommitment(root)
} }

View File

@ -54,6 +54,8 @@ fn deposit(
zone_funds_out, zone_funds_out,
} = deposit; } = deposit;
let funds_vk = state.zone_metadata.funds_vk;
// 1) Check there are no more input/output notes than expected // 1) Check there are no more input/output notes than expected
let inputs = [ let inputs = [
deposit.commit().to_bytes().to_vec(), deposit.commit().to_bytes().to_vec(),
@ -74,13 +76,13 @@ fn deposit(
assert_eq!(ptx_root, pub_inputs.ptx_root); assert_eq!(ptx_root, pub_inputs.ptx_root);
// 2) Check the deposit note is not already under control of the zone // 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 // 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 // in deposits (at least in a first version) to ensure fund tracking
assert_eq!(deposit.note.unit, *ZONE_UNIT); assert_eq!(deposit.note.unit, *ZONE_CL_FUNDS_UNIT);
assert_eq!(zone_funds_in.note.unit, *ZONE_UNIT); assert_eq!(zone_funds_in.note.unit, *ZONE_CL_FUNDS_UNIT);
assert_eq!(zone_funds_out.note.unit, *ZONE_UNIT); assert_eq!(zone_funds_out.note.unit, *ZONE_CL_FUNDS_UNIT);
let in_sum = deposit.note.value + zone_funds_in.note.value; 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"); assert_eq!(out_sum, in_sum, "deposit ptx is unbalanced");
// 4) Check the zone fund notes are correctly created // 4) Check the zone fund notes are correctly created
assert_eq!(zone_funds_in.note.death_constraint, ZONE_FUNDS_VK); assert_eq!(zone_funds_in.note.death_constraint, funds_vk);
assert_eq!(zone_funds_out.note.death_constraint, ZONE_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_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 assert_eq!(zone_funds_out.nf_pk, zone_funds_in.nf_sk.commit()); // the sk is the same
// nonce is correctly evolved // nonce is correctly evolved
@ -136,6 +138,11 @@ fn validate_zone_input(
let nf = Nullifier::new(input.input.nf_sk, input.input.nonce); let nf = Nullifier::new(input.input.nf_sk, input.input.nonce);
assert_eq!(input.input.note.state, <[u8; 32]>::from(state.commit())); 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) (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 assert_eq!(ptx, output.ptx_root()); // the ptx root is the same as in the input
let output = output.output; 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.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.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.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 // the nonce is correctly evolved
assert_eq!( assert_eq!(