check zone id in zone funds auth

This commit is contained in:
Giacomo Pasini 2024-08-02 15:06:40 +02:00
parent e7ba67d09b
commit 584f814465
No known key found for this signature in database
GPG Key ID: FC08489D2D895D4B
4 changed files with 43 additions and 12 deletions

View File

@ -26,7 +26,7 @@ pub static ZONE_CL_FUNDS_UNIT: Lazy<Unit> = Lazy::new(|| crypto::hash_to_curve(b
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ZoneMetadata { pub struct ZoneMetadata {
pub self_vk: [u8; 32], pub zone_vk: [u8; 32],
pub funds_vk: [u8; 32], pub funds_vk: [u8; 32],
pub unit: Unit, pub unit: Unit,
} }
@ -34,7 +34,7 @@ pub struct ZoneMetadata {
impl ZoneMetadata { impl ZoneMetadata {
pub fn id(&self) -> [u8; 32] { pub fn id(&self) -> [u8; 32] {
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
hasher.update(&self.self_vk); hasher.update(&self.zone_vk);
hasher.update(&self.funds_vk); hasher.update(&self.funds_vk);
hasher.update(self.unit.compress().as_bytes()); hasher.update(self.unit.compress().as_bytes());
hasher.finalize().into() hasher.finalize().into()
@ -50,6 +50,12 @@ pub struct StateWitness {
} }
impl StateWitness { impl StateWitness {
/// Merkle tree over:
/// root
/// / \
/// io state
/// / \ / \
/// events txs zoneid balances
pub fn commit(&self) -> StateCommitment { pub fn commit(&self) -> StateCommitment {
let io_root = cl::merkle::node(self.events_root(), self.included_txs_root()); let io_root = cl::merkle::node(self.events_root(), self.included_txs_root());

View File

@ -34,6 +34,10 @@ pub struct SpendFundsPrivate {
pub spent_note: PartialTxOutputPrivate, pub spent_note: PartialTxOutputPrivate,
/// The event emitted by the zone that authorizes the spend /// The event emitted by the zone that authorizes the spend
pub spend_event: Spend, pub spend_event: Spend,
/// Path to the zone output state /// Path to the zone output events root
pub spend_event_state_path: Vec<cl::merkle::PathNode>, pub spend_event_state_path: Vec<cl::merkle::PathNode>,
/// Merkle root of txs included in the zone
pub txs_root: [u8; 32],
/// Merkle root of balances in the zone
pub balances_root: [u8; 32],
} }

View File

@ -16,21 +16,35 @@ fn main() {
spent_note, spent_note,
spend_event, spend_event,
spend_event_state_path, spend_event_state_path,
txs_root,
balances_root,
} = env::read(); } = env::read();
let ptx_root = in_zone_funds.ptx_root(); let ptx_root = in_zone_funds.ptx_root();
let nf = Nullifier::new(in_zone_funds.input.nf_sk, in_zone_funds.input.nonce); let nf = Nullifier::new(in_zone_funds.input.nf_sk, in_zone_funds.input.nonce);
// check the zone funds note is the one in the spend event // check the zone funds note is the one in the spend event
assert_eq!(nf, spend_event.nf); assert_eq!(nf, spend_event.nf);
assert_eq!(ptx_root, zone_note.ptx_root()); assert_eq!(ptx_root, zone_note.ptx_root());
// assert the spent event was an output of the zone stf
// ** Assert the spent event was an output of the correct zone stf **
// The zone state field is a merkle tree over:
// root
// / \
// io state
// / \ / \
// events txs zoneid balances
// We need to check that:
// 1) There is a valid path from the spend event to the events root
// 2) The zone id matches the one in the current funds note state
// 3) The witnesses for spend path, txs and balances allow to calculate the correct root
let zone_id = in_zone_funds.input.note.state; // TODO: is there more state?
let spend_event_leaf = merkle::leaf(&spend_event.to_bytes()); let spend_event_leaf = merkle::leaf(&spend_event.to_bytes());
// TODO: zones will have some more state let event_root = merkle::path_root(spend_event_leaf, &spend_event_state_path);
assert_eq!(
zone_note.output.note.state, let io_root = merkle::node(event_root, txs_root);
merkle::path_root(spend_event_leaf, &spend_event_state_path) let state_root = merkle::node(zone_id, balances_root);
); let root = merkle::node(io_root, state_root);
assert_eq!(root, zone_note.output.note.state);
assert_eq!(ptx_root, out_zone_funds.ptx_root()); assert_eq!(ptx_root, out_zone_funds.ptx_root());
@ -64,6 +78,11 @@ fn main() {
out_zone_funds.output.nonce, out_zone_funds.output.nonce,
NullifierNonce::from_bytes(Sha256::digest(&out_zone_funds.output.nonce.as_bytes()).into()) NullifierNonce::from_bytes(Sha256::digest(&out_zone_funds.output.nonce.as_bytes()).into())
); );
// the state is propagated
assert_eq!(
out_zone_funds.output.note.state,
in_zone_funds.input.note.state
);
assert_eq!(ptx_root, spent_note.ptx_root()); assert_eq!(ptx_root, spent_note.ptx_root());

View File

@ -93,6 +93,8 @@ fn deposit(
// 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, 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_out.note.death_constraint, funds_vk);
assert_eq!(zone_funds_in.note.state, state.zone_metadata.id());
assert_eq!(zone_funds_out.note.state, state.zone_metadata.id());
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
@ -141,7 +143,7 @@ fn validate_zone_input(
// should not be possible to create one but let's put this check here just in case // should not be possible to create one but let's put this check here just in case
debug_assert_eq!( debug_assert_eq!(
input.input.note.death_constraint, input.input.note.death_constraint,
state.zone_metadata.self_vk state.zone_metadata.zone_vk
); );
(ptx_root, nf) (ptx_root, nf)
@ -156,7 +158,7 @@ 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, state.zone_metadata.self_vk); // the death constraint is the correct one assert_eq!(output.note.death_constraint, state.zone_metadata.zone_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, state.zone_metadata.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