From cffd687e50d6d4c214a866b5befd61fbfbe5c2ae Mon Sep 17 00:00:00 2001 From: David Rusu Date: Mon, 26 Aug 2024 23:53:51 +0400 Subject: [PATCH] goas: rename DeathConstraint to Constraint --- goas/atomic_asset_transfer/common/src/lib.rs | 10 +-- .../atomic_asset_transfer/executor/src/lib.rs | 53 +++++------ .../executor/tests/atomic_transfer.rs | 6 +- .../executor/tests/deposit_ptx.rs | 20 +++-- .../executor/tests/withdraw_ptx.rs | 19 ++-- .../proof_statements/src/lib.rs | 2 +- .../proof_statements/src/user_note.rs | 8 +- .../risc0_proofs/spend_zone_funds/src/main.rs | 4 +- .../user_atomic_transfer/src/main.rs | 4 +- .../risc0_proofs/zone_state/src/main.rs | 10 +-- goas/cl/cl/src/balance.rs | 2 +- goas/cl/cl/src/input.rs | 8 +- goas/cl/cl/src/lib.rs | 2 +- goas/cl/cl/src/note.rs | 38 ++++---- goas/cl/ledger/src/constraint.rs | 87 ++++++++++++++++++ goas/cl/ledger/src/death_constraint.rs | 90 ------------------- goas/cl/ledger/src/lib.rs | 4 +- goas/cl/ledger/src/partial_tx.rs | 34 +++---- goas/cl/ledger/tests/simple_transfer.rs | 13 +-- .../{death_constraint.rs => constraint.rs} | 2 +- goas/cl/ledger_proof_statements/src/lib.rs | 2 +- goas/cl/risc0_proofs/Cargo.toml | 2 +- .../Cargo.toml | 2 +- .../risc0_proofs/constraint_nop/src/main.rs | 8 ++ .../death_constraint_nop/src/main.rs | 8 -- 25 files changed, 224 insertions(+), 214 deletions(-) create mode 100644 goas/cl/ledger/src/constraint.rs delete mode 100644 goas/cl/ledger/src/death_constraint.rs rename goas/cl/ledger_proof_statements/src/{death_constraint.rs => constraint.rs} (84%) rename goas/cl/risc0_proofs/{death_constraint_nop => constraint_nop}/Cargo.toml (95%) create mode 100644 goas/cl/risc0_proofs/constraint_nop/src/main.rs delete mode 100644 goas/cl/risc0_proofs/death_constraint_nop/src/main.rs diff --git a/goas/atomic_asset_transfer/common/src/lib.rs b/goas/atomic_asset_transfer/common/src/lib.rs index 59c1901..03d1e71 100644 --- a/goas/atomic_asset_transfer/common/src/lib.rs +++ b/goas/atomic_asset_transfer/common/src/lib.rs @@ -1,6 +1,6 @@ pub mod mmr; -use cl::{balance::Unit, NoteCommitment}; +use cl::{balance::Unit, ConstraintCommitment, NoteCommitment}; use ed25519_dalek::{ ed25519::{signature::SignerMut, SignatureBytes}, Signature, SigningKey, VerifyingKey, PUBLIC_KEY_LENGTH, @@ -27,16 +27,16 @@ pub fn new_account(mut rng: impl CryptoRngCore) -> SigningKey { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct ZoneMetadata { - pub zone_vk: [u8; 32], - pub funds_vk: [u8; 32], + pub zone_constraint: ConstraintCommitment, + pub funds_constraint: ConstraintCommitment, pub unit: Unit, } impl ZoneMetadata { pub fn id(&self) -> [u8; 32] { let mut hasher = Sha256::new(); - hasher.update(self.zone_vk); - hasher.update(self.funds_vk); + hasher.update(self.zone_constraint.0); + hasher.update(self.funds_constraint.0); hasher.update(self.unit); hasher.finalize().into() } diff --git a/goas/atomic_asset_transfer/executor/src/lib.rs b/goas/atomic_asset_transfer/executor/src/lib.rs index 7cc8f33..15d97b5 100644 --- a/goas/atomic_asset_transfer/executor/src/lib.rs +++ b/goas/atomic_asset_transfer/executor/src/lib.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; +use cl::ConstraintCommitment; use common::{ mmr::MMR, AccountId, IncludedTxWitness, SignedBoundTx, StateWitness, Tx, ZoneMetadata, }; @@ -78,7 +79,7 @@ fn zone_fund_utxo( cl::NoteWitness { value, unit: *common::ZONE_CL_FUNDS_UNIT, - death_constraint: zone_meta.funds_vk, + constraint: zone_meta.funds_constraint, state: zone_meta.id(), }, cl::NullifierNonce::random(&mut rng), @@ -90,33 +91,29 @@ fn zone_state_utxo(zone: &StateWitness, mut rng: impl CryptoRngCore) -> cl::Outp cl::NoteWitness { value: 1, unit: zone.zone_metadata.unit, - death_constraint: zone.zone_metadata.zone_vk, + constraint: zone.zone_metadata.zone_constraint, state: zone.commit().0, }, cl::NullifierNonce::random(&mut rng), ) } -pub fn user_atomic_transfer_death_constraint() -> [u8; 32] { - ledger::death_constraint::risc0_id_to_cl_death_constraint( - goas_risc0_proofs::USER_ATOMIC_TRANSFER_ID, - ) +pub fn user_atomic_transfer_constraint() -> ConstraintCommitment { + ledger::constraint::risc0_constraint(goas_risc0_proofs::USER_ATOMIC_TRANSFER_ID) } -pub fn zone_state_death_constraint() -> [u8; 32] { - ledger::death_constraint::risc0_id_to_cl_death_constraint(goas_risc0_proofs::ZONE_STATE_ID) +pub fn zone_state_constraint() -> ConstraintCommitment { + ledger::constraint::risc0_constraint(goas_risc0_proofs::ZONE_STATE_ID) } -pub fn zone_fund_death_constraint() -> [u8; 32] { - ledger::death_constraint::risc0_id_to_cl_death_constraint( - goas_risc0_proofs::SPEND_ZONE_FUNDS_ID, - ) +pub fn zone_fund_constraint() -> ConstraintCommitment { + ledger::constraint::risc0_constraint(goas_risc0_proofs::SPEND_ZONE_FUNDS_ID) } pub fn zone_metadata(zone_mnemonic: &str) -> ZoneMetadata { ZoneMetadata { - zone_vk: zone_state_death_constraint(), - funds_vk: zone_fund_death_constraint(), + zone_constraint: zone_state_constraint(), + funds_constraint: zone_fund_constraint(), unit: cl::note::derive_unit(zone_mnemonic), } } @@ -127,7 +124,7 @@ pub fn prove_zone_stf( zone_in: cl::PartialTxInputWitness, zone_out: cl::PartialTxOutputWitness, funds_out: cl::PartialTxOutputWitness, -) -> ledger::DeathProof { +) -> ledger::ConstraintProof { let private_inputs = ZoneStatePrivate { state, inputs, @@ -156,14 +153,14 @@ pub fn prove_zone_stf( prove_info.stats.total_cycles ); let receipt = prove_info.receipt; - ledger::DeathProof::from_risc0(goas_risc0_proofs::ZONE_STATE_ID, receipt) + ledger::ConstraintProof::from_risc0(goas_risc0_proofs::ZONE_STATE_ID, receipt) } pub fn prove_zone_fund_constraint( in_zone_funds: cl::PartialTxInputWitness, zone_note: cl::PartialTxOutputWitness, out_zone_state: &StateWitness, -) -> ledger::DeathProof { +) -> ledger::ConstraintProof { let private_inputs = SpendFundsPrivate { in_zone_funds, zone_note, @@ -190,10 +187,10 @@ pub fn prove_zone_fund_constraint( prove_info.stats.total_cycles ); let receipt = prove_info.receipt; - ledger::DeathProof::from_risc0(goas_risc0_proofs::SPEND_ZONE_FUNDS_ID, receipt) + ledger::ConstraintProof::from_risc0(goas_risc0_proofs::SPEND_ZONE_FUNDS_ID, receipt) } -pub fn prove_user_atomic_transfer(atomic_transfer: UserAtomicTransfer) -> ledger::DeathProof { +pub fn prove_user_atomic_transfer(atomic_transfer: UserAtomicTransfer) -> ledger::ConstraintProof { let env = risc0_zkvm::ExecutorEnv::builder() .write(&atomic_transfer) .unwrap() @@ -214,7 +211,7 @@ pub fn prove_user_atomic_transfer(atomic_transfer: UserAtomicTransfer) -> ledger prove_info.stats.total_cycles ); let receipt = prove_info.receipt; - ledger::DeathProof::from_risc0(goas_risc0_proofs::USER_ATOMIC_TRANSFER_ID, receipt) + ledger::ConstraintProof::from_risc0(goas_risc0_proofs::USER_ATOMIC_TRANSFER_ID, receipt) } #[cfg(test)] @@ -225,7 +222,8 @@ mod tests { }; use common::{BoundTx, Deposit, Withdraw}; use goas_proof_statements::user_note::UserIntent; - use ledger_proof_statements::death_constraint::DeathConstraintPublic; + use ledger::ConstraintProof; + use ledger_proof_statements::constraint::ConstraintPublic; use super::*; @@ -277,7 +275,7 @@ mod tests { ptx.output_witness(1), ); - assert!(proof.verify(DeathConstraintPublic { + assert!(proof.verify(ConstraintPublic { nf: zone_start.state_input_witness().nullifier(), ptx_root: ptx.commit().root(), })) @@ -297,7 +295,7 @@ mod tests { let proof = prove_zone_fund_constraint(ptx.input_witness(0), ptx.output_witness(0), &zone.state); - assert!(proof.verify(DeathConstraintPublic { + assert!(proof.verify(ConstraintPublic { nf: zone.fund_input_witness().nullifier(), ptx_root: ptx.commit().root(), })) @@ -327,7 +325,12 @@ mod tests { }, }; let user_note = cl::InputWitness::public(cl::OutputWitness::public( - NoteWitness::new(1, derive_unit("INTENT"), [0u8; 32], user_intent.commit()), + NoteWitness::new( + 1, + derive_unit("INTENT"), + ConstraintProof::nop_constraint(), + user_intent.commit(), + ), NullifierNonce::random(&mut rng), )); @@ -353,7 +356,7 @@ mod tests { let proof = prove_user_atomic_transfer(user_atomic_transfer); - assert!(proof.verify(DeathConstraintPublic { + assert!(proof.verify(ConstraintPublic { nf: user_note.nullifier(), ptx_root: ptx.commit().root(), })) diff --git a/goas/atomic_asset_transfer/executor/tests/atomic_transfer.rs b/goas/atomic_asset_transfer/executor/tests/atomic_transfer.rs index 29e0fa8..9ddd039 100644 --- a/goas/atomic_asset_transfer/executor/tests/atomic_transfer.rs +++ b/goas/atomic_asset_transfer/executor/tests/atomic_transfer.rs @@ -34,7 +34,7 @@ fn test_atomic_transfer() { NoteWitness { value: 1, unit: cl::note::derive_unit("INTENT"), - death_constraint: executor::user_atomic_transfer_death_constraint(), + constraint: executor::user_atomic_transfer_constraint(), state: alice_intent.commit(), }, NullifierNonce::random(&mut rng), @@ -86,7 +86,7 @@ fn test_atomic_transfer() { &mut alice, ); - let death_proofs = BTreeMap::from_iter([ + let constraint_proofs = BTreeMap::from_iter([ ( alice_intent_in.nullifier(), executor::prove_user_atomic_transfer(UserAtomicTransfer { @@ -153,7 +153,7 @@ fn test_atomic_transfer() { let atomic_transfer_proof = ledger::partial_tx::ProvedPartialTx::prove( &atomic_transfer_ptx, - death_proofs, + constraint_proofs, ¬e_commitments, ) .expect("atomic transfer proof failed"); diff --git a/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs b/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs index b535fb0..aa2ffd4 100644 --- a/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs +++ b/goas/atomic_asset_transfer/executor/tests/deposit_ptx.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use cl::{BalanceWitness, NoteWitness, NullifierSecret}; use common::{mmr::MMR, new_account, BoundTx, SignedBoundTx, StateWitness, Tx, ZONE_CL_FUNDS_UNIT}; use executor::ZoneNotes; -use ledger::death_constraint::DeathProof; +use ledger::constraint::ConstraintProof; #[test] fn test_deposit() { @@ -27,7 +27,7 @@ fn test_deposit() { NoteWitness::stateless( 78, *ZONE_CL_FUNDS_UNIT, - DeathProof::nop_constraint(), // alice should demand a tx inclusion proof for the deposit + ConstraintProof::nop_constraint(), // alice should demand a tx inclusion proof for the deposit ), alice_cl_sk.commit(), &mut rng, @@ -49,7 +49,7 @@ fn test_deposit() { &mut alice, ); - let death_proofs = BTreeMap::from_iter([ + let constraint_proofs = BTreeMap::from_iter([ ( zone_start.state_input_witness().nullifier(), executor::prove_zone_stf( @@ -62,7 +62,10 @@ fn test_deposit() { ), ( alice_deposit.nullifier(), - ledger::DeathProof::prove_nop(alice_deposit.nullifier(), deposit_ptx.commit().root()), + ledger::ConstraintProof::prove_nop( + alice_deposit.nullifier(), + deposit_ptx.commit().root(), + ), ), ]); @@ -71,9 +74,12 @@ fn test_deposit() { alice_deposit.note_commitment(), ]; - let deposit_proof = - ledger::partial_tx::ProvedPartialTx::prove(&deposit_ptx, death_proofs, ¬e_commitments) - .expect("deposit proof failed"); + let deposit_proof = ledger::partial_tx::ProvedPartialTx::prove( + &deposit_ptx, + constraint_proofs, + ¬e_commitments, + ) + .expect("deposit proof failed"); assert!(deposit_proof.verify()); diff --git a/goas/atomic_asset_transfer/executor/tests/withdraw_ptx.rs b/goas/atomic_asset_transfer/executor/tests/withdraw_ptx.rs index eb9f266..596c6d3 100644 --- a/goas/atomic_asset_transfer/executor/tests/withdraw_ptx.rs +++ b/goas/atomic_asset_transfer/executor/tests/withdraw_ptx.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use cl::{BalanceWitness, NoteWitness, NullifierSecret}; use common::{mmr::MMR, new_account, BoundTx, SignedBoundTx, StateWitness, Tx, ZONE_CL_FUNDS_UNIT}; use executor::ZoneNotes; -use ledger::death_constraint::DeathProof; +use ledger::constraint::ConstraintProof; #[test] fn test_withdrawal() { @@ -18,7 +18,7 @@ fn test_withdrawal() { let alice_intent = cl::InputWitness::from_output( cl::OutputWitness::random( - NoteWitness::stateless(1, *ZONE_CL_FUNDS_UNIT, DeathProof::nop_constraint()), // TODO, intent should be in the death constraint + NoteWitness::stateless(1, *ZONE_CL_FUNDS_UNIT, ConstraintProof::nop_constraint()), // TODO, intent should be in the constraint alice_cl_sk.commit(), &mut rng, ), @@ -36,7 +36,7 @@ fn test_withdrawal() { NoteWitness::stateless( withdraw.amount, *ZONE_CL_FUNDS_UNIT, - DeathProof::nop_constraint(), + ConstraintProof::nop_constraint(), ), alice_cl_sk.commit(), &mut rng, @@ -60,7 +60,7 @@ fn test_withdrawal() { &mut alice, ); - let death_proofs = BTreeMap::from_iter([ + let constraint_proofs = BTreeMap::from_iter([ ( zone_start.state_input_witness().nullifier(), executor::prove_zone_stf( @@ -81,7 +81,7 @@ fn test_withdrawal() { ), ( alice_intent.nullifier(), - DeathProof::prove_nop(alice_intent.nullifier(), withdraw_ptx.commit().root()), + ConstraintProof::prove_nop(alice_intent.nullifier(), withdraw_ptx.commit().root()), ), ]); @@ -91,9 +91,12 @@ fn test_withdrawal() { alice_intent.note_commitment(), ]; - let withdraw_proof = - ledger::partial_tx::ProvedPartialTx::prove(&withdraw_ptx, death_proofs, ¬e_commitments) - .expect("withdraw proof failed"); + let withdraw_proof = ledger::partial_tx::ProvedPartialTx::prove( + &withdraw_ptx, + constraint_proofs, + ¬e_commitments, + ) + .expect("withdraw proof failed"); assert!(withdraw_proof.verify()); diff --git a/goas/atomic_asset_transfer/proof_statements/src/lib.rs b/goas/atomic_asset_transfer/proof_statements/src/lib.rs index 802ccbb..d0525df 100644 --- a/goas/atomic_asset_transfer/proof_statements/src/lib.rs +++ b/goas/atomic_asset_transfer/proof_statements/src/lib.rs @@ -9,6 +9,6 @@ pub fn assert_is_zone_note( ) { assert_eq!(state_roots.commit().0, note.state); assert_eq!(zone_meta.id(), state_roots.zone_id); - assert_eq!(zone_meta.zone_vk, note.death_constraint); + assert_eq!(zone_meta.zone_constraint, note.constraint); assert_eq!(zone_meta.unit, note.unit); } diff --git a/goas/atomic_asset_transfer/proof_statements/src/user_note.rs b/goas/atomic_asset_transfer/proof_statements/src/user_note.rs index 7a5036e..e244ebc 100644 --- a/goas/atomic_asset_transfer/proof_statements/src/user_note.rs +++ b/goas/atomic_asset_transfer/proof_statements/src/user_note.rs @@ -12,7 +12,7 @@ /// Thep User Note will encode the logic that orchestrates the withdrawal from zone A /// and deposit to zone B. /// -/// The User Notes death constraint requires the following statements to be satisfied +/// The User Notes constraint requires the following statements to be satisfied /// in order for the fee to be captured. /// /// 1. w_tx = withdraw(amt=100 NMO, from=Alice) tx was included in Zone A. @@ -22,7 +22,7 @@ /// Details: /// - the withdrawal in zone A must not be a general withdrawal tx, it must be bound to the user note. /// i.e. the user_note must be present in the ptx for the withdrawal to be valid in Zone A. -use ledger_proof_statements::death_constraint::DeathConstraintPublic; +use ledger_proof_statements::constraint::ConstraintPublic; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -67,7 +67,7 @@ pub struct UserAtomicTransfer { } impl UserAtomicTransfer { - pub fn assert_constraints(&self) -> DeathConstraintPublic { + pub fn assert_constraints(&self) -> ConstraintPublic { // user committed to these actions in the user note assert_eq!(self.user_intent.commit(), self.user_note.input.note.state); @@ -103,6 +103,6 @@ impl UserAtomicTransfer { let ptx_root = cl::PtxRoot(cl::merkle::node(input_root, output_root)); let nf = self.user_note.input.nullifier(); - DeathConstraintPublic { ptx_root, nf } + ConstraintPublic { ptx_root, nf } } } diff --git a/goas/atomic_asset_transfer/risc0_proofs/spend_zone_funds/src/main.rs b/goas/atomic_asset_transfer/risc0_proofs/spend_zone_funds/src/main.rs index 8b2abc1..184fcd9 100644 --- a/goas/atomic_asset_transfer/risc0_proofs/spend_zone_funds/src/main.rs +++ b/goas/atomic_asset_transfer/risc0_proofs/spend_zone_funds/src/main.rs @@ -4,7 +4,7 @@ use cl::merkle; use cl::partial_tx::PtxRoot; use goas_proof_statements::zone_funds::SpendFundsPrivate; -use ledger_proof_statements::death_constraint::DeathConstraintPublic; +use ledger_proof_statements::constraint::ConstraintPublic; use risc0_zkvm::guest::env; fn main() { @@ -25,5 +25,5 @@ fn main() { let nf = in_zone_funds.input.nullifier(); - env::commit(&DeathConstraintPublic { ptx_root, nf }); + env::commit(&ConstraintPublic { ptx_root, nf }); } diff --git a/goas/atomic_asset_transfer/risc0_proofs/user_atomic_transfer/src/main.rs b/goas/atomic_asset_transfer/risc0_proofs/user_atomic_transfer/src/main.rs index f4d31c9..a397978 100644 --- a/goas/atomic_asset_transfer/risc0_proofs/user_atomic_transfer/src/main.rs +++ b/goas/atomic_asset_transfer/risc0_proofs/user_atomic_transfer/src/main.rs @@ -1,9 +1,9 @@ use goas_proof_statements::user_note::UserAtomicTransfer; -use ledger_proof_statements::death_constraint::DeathConstraintPublic; +use ledger_proof_statements::constraint::ConstraintPublic; use risc0_zkvm::guest::env; fn main() { let transfer: UserAtomicTransfer = env::read(); - let public: DeathConstraintPublic = transfer.assert_constraints(); + let public: ConstraintPublic = transfer.assert_constraints(); env::commit(&public); } 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 cf8c3ba..4ad5083 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 @@ -5,7 +5,7 @@ use cl::{ use common::*; use goas_proof_statements::zone_state::ZoneStatePrivate; -use ledger_proof_statements::death_constraint::DeathConstraintPublic; +use ledger_proof_statements::constraint::ConstraintPublic; use risc0_zkvm::guest::env; fn validate_zone_transition( @@ -26,8 +26,8 @@ fn validate_zone_transition( assert_eq!(out_note.output.note.unit, metadata.unit); // ensure constraints match metadata - assert_eq!(in_note.input.note.death_constraint, metadata.zone_vk); - assert_eq!(out_note.output.note.death_constraint, metadata.zone_vk); + assert_eq!(in_note.input.note.constraint, metadata.zone_constraint); + assert_eq!(out_note.output.note.constraint, metadata.zone_constraint); // nullifier secret is propagated assert_eq!(in_note.input.nf_sk.commit(), out_note.output.nf_pk); @@ -39,7 +39,7 @@ fn validate_zone_transition( let expected_note_witness = NoteWitness::new( out_state.total_balance(), *ZONE_CL_FUNDS_UNIT, - metadata.funds_vk, + metadata.funds_constraint, metadata.id(), ); assert_eq!( @@ -65,7 +65,7 @@ fn main() { let input_root = zone_in.input_root(); let output_root = zone_out.output_root(); - let pub_inputs = DeathConstraintPublic { + let pub_inputs = ConstraintPublic { ptx_root: PtxRoot(cl::merkle::node(input_root, output_root)), nf: zone_in.input.nullifier(), }; diff --git a/goas/cl/cl/src/balance.rs b/goas/cl/cl/src/balance.rs index 765eb7c..10db851 100644 --- a/goas/cl/cl/src/balance.rs +++ b/goas/cl/cl/src/balance.rs @@ -25,7 +25,7 @@ pub struct UnitBalance { impl UnitBalance { pub fn is_zero(&self) -> bool { - return self.pos == self.neg; + self.pos == self.neg } } diff --git a/goas/cl/cl/src/input.rs b/goas/cl/cl/src/input.rs index 404e648..62e4b94 100644 --- a/goas/cl/cl/src/input.rs +++ b/goas/cl/cl/src/input.rs @@ -3,7 +3,7 @@ /// Partial transactions, as the name suggests, are transactions /// which on their own may not balance (i.e. \sum inputs != \sum outputs) use crate::{ - note::{DeathCommitment, NoteWitness}, + note::{ConstraintCommitment, NoteWitness}, nullifier::{Nullifier, NullifierNonce, NullifierSecret}, }; use serde::{Deserialize, Serialize}; @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct Input { pub nullifier: Nullifier, - pub death_cm: DeathCommitment, + pub constraint: ConstraintCommitment, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] @@ -60,7 +60,7 @@ impl InputWitness { pub fn commit(&self) -> Input { Input { nullifier: self.nullifier(), - death_cm: self.note.death_commitment(), + constraint: self.note.constraint, } } @@ -73,7 +73,7 @@ impl Input { pub fn to_bytes(&self) -> [u8; 64] { let mut bytes = [0u8; 64]; bytes[..32].copy_from_slice(self.nullifier.as_bytes()); - bytes[32..64].copy_from_slice(&self.death_cm.0); + bytes[32..64].copy_from_slice(&self.constraint.0); bytes } } diff --git a/goas/cl/cl/src/lib.rs b/goas/cl/cl/src/lib.rs index 43747ee..10261d0 100644 --- a/goas/cl/cl/src/lib.rs +++ b/goas/cl/cl/src/lib.rs @@ -12,7 +12,7 @@ pub mod partial_tx; pub use balance::{Balance, BalanceWitness}; pub use bundle::{Bundle, BundleWitness}; pub use input::{Input, InputWitness}; -pub use note::{DeathCommitment, NoteCommitment, NoteWitness}; +pub use note::{ConstraintCommitment, NoteCommitment, NoteWitness}; pub use nullifier::{Nullifier, NullifierCommitment, NullifierNonce, NullifierSecret}; pub use output::{Output, OutputWitness}; pub use partial_tx::{ diff --git a/goas/cl/cl/src/note.rs b/goas/cl/cl/src/note.rs index 2128d47..03277af 100644 --- a/goas/cl/cl/src/note.rs +++ b/goas/cl/cl/src/note.rs @@ -7,15 +7,17 @@ use crate::{ }; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct DeathCommitment(pub [u8; 32]); +pub struct ConstraintCommitment(pub [u8; 32]); -pub fn death_commitment(death_constraint: &[u8]) -> DeathCommitment { - let mut hasher = Sha256::new(); - hasher.update(b"NOMOS_CL_DEATH_COMMIT"); - hasher.update(death_constraint); - let death_cm: [u8; 32] = hasher.finalize().into(); +impl ConstraintCommitment { + pub fn from_vk(constraint_vk: &[u8]) -> Self { + let mut hasher = Sha256::new(); + hasher.update(b"NOMOS_CL_CONSTRAINT_COMMIT"); + hasher.update(constraint_vk); + let constraint_cm: [u8; 32] = hasher.finalize().into(); - DeathCommitment(death_cm) + Self(constraint_cm) + } } pub fn derive_unit(unit: &str) -> Unit { @@ -39,26 +41,26 @@ impl NoteCommitment { pub struct NoteWitness { pub value: u64, pub unit: Unit, - pub death_constraint: [u8; 32], // death constraint verification key + pub constraint: ConstraintCommitment, pub state: [u8; 32], } impl NoteWitness { - pub fn new(value: u64, unit: Unit, death_constraint: [u8; 32], state: [u8; 32]) -> Self { + pub fn new(value: u64, unit: Unit, constraint: ConstraintCommitment, state: [u8; 32]) -> Self { Self { value, unit, - death_constraint, + constraint, state, } } pub fn basic(value: u64, unit: Unit) -> Self { - Self::new(value, unit, [0u8; 32], [0u8; 32]) + Self::new(value, unit, ConstraintCommitment([0u8; 32]), [0u8; 32]) } - pub fn stateless(value: u64, unit: Unit, death_constraint: [u8; 32]) -> Self { - Self::new(value, unit, death_constraint, [0u8; 32]) + pub fn stateless(value: u64, unit: Unit, constraint: ConstraintCommitment) -> Self { + Self::new(value, unit, constraint, [0u8; 32]) } pub fn commit(&self, nf_pk: NullifierCommitment, nonce: NullifierNonce) -> NoteCommitment { @@ -73,8 +75,8 @@ impl NoteWitness { // COMMIT TO STATE hasher.update(self.state); - // COMMIT TO DEATH CONSTRAINT - hasher.update(self.death_constraint); + // COMMIT TO CONSTRAINT + hasher.update(self.constraint.0); // COMMIT TO NULLIFIER hasher.update(nf_pk.as_bytes()); @@ -83,10 +85,6 @@ impl NoteWitness { let commit_bytes: [u8; 32] = hasher.finalize().into(); NoteCommitment(commit_bytes) } - - pub fn death_commitment(&self) -> DeathCommitment { - death_commitment(&self.death_constraint) - } } #[cfg(test)] @@ -116,7 +114,7 @@ mod test { ..reference_note }, NoteWitness { - death_constraint: [1u8; 32], + constraint: ConstraintCommitment::from_vk(&[1u8; 32]), ..reference_note }, NoteWitness { diff --git a/goas/cl/ledger/src/constraint.rs b/goas/cl/ledger/src/constraint.rs new file mode 100644 index 0000000..8c98e78 --- /dev/null +++ b/goas/cl/ledger/src/constraint.rs @@ -0,0 +1,87 @@ +use cl::ConstraintCommitment; +use ledger_proof_statements::constraint::ConstraintPublic; + +use crate::error::Result; + +#[derive(Debug, Clone)] +pub struct ConstraintProof { + pub risc0_id: [u32; 8], + pub risc0_receipt: risc0_zkvm::Receipt, +} + +pub fn risc0_constraint(risc0_id: [u32; 8]) -> ConstraintCommitment { + // Commit to a RISC0 ID for use as a note constraint + + let mut bytes = [0u8; 32]; + + for (i, word) in risc0_id.iter().enumerate() { + let word_bytes = word.to_le_bytes(); + bytes[i * 4 + 0] = word_bytes[0]; + bytes[i * 4 + 1] = word_bytes[1]; + bytes[i * 4 + 2] = word_bytes[2]; + bytes[i * 4 + 3] = word_bytes[3]; + } + + ConstraintCommitment::from_vk(&bytes) +} + +impl ConstraintProof { + pub fn from_risc0(risc0_id: [u32; 8], risc0_receipt: risc0_zkvm::Receipt) -> Self { + Self { + risc0_id, + risc0_receipt, + } + } + + pub fn constraint(&self) -> ConstraintCommitment { + risc0_constraint(self.risc0_id) + } + + pub fn public(&self) -> Result { + Ok(self.risc0_receipt.journal.decode()?) + } + + pub fn verify(&self, expected_public: ConstraintPublic) -> bool { + let Ok(public) = self.public() else { + return false; + }; + + expected_public == public && self.risc0_receipt.verify(self.risc0_id).is_ok() + } + + pub fn nop_constraint() -> ConstraintCommitment { + risc0_constraint(nomos_cl_risc0_proofs::CONSTRAINT_NOP_ID) + } + + pub fn prove_nop(nf: cl::Nullifier, ptx_root: cl::PtxRoot) -> Self { + let constraint_public = ConstraintPublic { nf, ptx_root }; + let env = risc0_zkvm::ExecutorEnv::builder() + .write(&constraint_public) + .unwrap() + .build() + .unwrap(); + + // Obtain the default prover. + let prover = risc0_zkvm::default_prover(); + + let start_t = std::time::Instant::now(); + + // Proof information by proving the specified ELF binary. + // This struct contains the receipt along with statistics about execution of the guest + let opts = risc0_zkvm::ProverOpts::succinct(); + let prove_info = prover + .prove_with_opts(env, nomos_cl_risc0_proofs::CONSTRAINT_NOP_ELF, &opts) + .unwrap(); + + println!( + "STARK 'constraint-nop' prover time: {:.2?}, total_cycles: {}", + start_t.elapsed(), + prove_info.stats.total_cycles + ); + + // extract the receipt. + let receipt = prove_info.receipt; + + Self::from_risc0(nomos_cl_risc0_proofs::CONSTRAINT_NOP_ID, receipt) + } +} diff --git a/goas/cl/ledger/src/death_constraint.rs b/goas/cl/ledger/src/death_constraint.rs deleted file mode 100644 index 9138a43..0000000 --- a/goas/cl/ledger/src/death_constraint.rs +++ /dev/null @@ -1,90 +0,0 @@ -use ledger_proof_statements::death_constraint::DeathConstraintPublic; -use sha2::{Digest, Sha256}; - -use crate::error::Result; - -pub type Risc0DeathConstraintId = [u32; 8]; - -#[derive(Debug, Clone)] -pub struct DeathProof { - pub constraint: Risc0DeathConstraintId, - pub risc0_receipt: risc0_zkvm::Receipt, -} - -pub fn risc0_id_to_cl_death_constraint(risc0_id: Risc0DeathConstraintId) -> [u8; 32] { - // RISC0 proof ids have the format: [u32; 8], and cl death constraint ids have the format [u8; 32]. - // CL death constraints are meaningless beyond being binding, therefore we merely need a collision - // resisitant mapping of RISC0 ids to cl death constraints. - - let mut hasher = Sha256::new(); - hasher.update(b"NOMOS_RISC0_ID_TO_CL_DEATH_CONSTRAINT"); - for word in risc0_id { - hasher.update(u32::to_ne_bytes(word)); - } - let death_constraint: [u8; 32] = hasher.finalize().into(); - death_constraint -} - -impl DeathProof { - pub fn from_risc0( - risc0_id: Risc0DeathConstraintId, - risc0_receipt: risc0_zkvm::Receipt, - ) -> Self { - Self { - constraint: risc0_id, - risc0_receipt, - } - } - - pub fn death_commitment(&self) -> cl::DeathCommitment { - cl::note::death_commitment(&risc0_id_to_cl_death_constraint(self.constraint)) - } - - pub fn public(&self) -> Result { - Ok(self.risc0_receipt.journal.decode()?) - } - - pub fn verify(&self, expected_public: DeathConstraintPublic) -> bool { - let Ok(public) = self.public() else { - return false; - }; - - expected_public == public && self.risc0_receipt.verify(self.constraint).is_ok() - } - - pub fn nop_constraint() -> [u8; 32] { - risc0_id_to_cl_death_constraint(nomos_cl_risc0_proofs::DEATH_CONSTRAINT_NOP_ID) - } - - pub fn prove_nop(nf: cl::Nullifier, ptx_root: cl::PtxRoot) -> Self { - let death_public = DeathConstraintPublic { nf, ptx_root }; - let env = risc0_zkvm::ExecutorEnv::builder() - .write(&death_public) - .unwrap() - .build() - .unwrap(); - - // Obtain the default prover. - let prover = risc0_zkvm::default_prover(); - - let start_t = std::time::Instant::now(); - - // Proof information by proving the specified ELF binary. - // This struct contains the receipt along with statistics about execution of the guest - let opts = risc0_zkvm::ProverOpts::succinct(); - let prove_info = prover - .prove_with_opts(env, nomos_cl_risc0_proofs::DEATH_CONSTRAINT_NOP_ELF, &opts) - .unwrap(); - - println!( - "STARK 'death-nop' prover time: {:.2?}, total_cycles: {}", - start_t.elapsed(), - prove_info.stats.total_cycles - ); - - // extract the receipt. - let receipt = prove_info.receipt; - - Self::from_risc0(nomos_cl_risc0_proofs::DEATH_CONSTRAINT_NOP_ID, receipt) - } -} diff --git a/goas/cl/ledger/src/lib.rs b/goas/cl/ledger/src/lib.rs index e365360..cb6d4ca 100644 --- a/goas/cl/ledger/src/lib.rs +++ b/goas/cl/ledger/src/lib.rs @@ -1,6 +1,6 @@ pub mod bundle; -pub mod death_constraint; +pub mod constraint; pub mod error; pub mod partial_tx; -pub use death_constraint::DeathProof; +pub use constraint::ConstraintProof; diff --git a/goas/cl/ledger/src/partial_tx.rs b/goas/cl/ledger/src/partial_tx.rs index 7ba4bdc..67f0d73 100644 --- a/goas/cl/ledger/src/partial_tx.rs +++ b/goas/cl/ledger/src/partial_tx.rs @@ -1,28 +1,28 @@ use std::collections::BTreeMap; use ledger_proof_statements::{ - death_constraint::DeathConstraintPublic, + constraint::ConstraintPublic, ptx::{PtxPrivate, PtxPublic}, }; use crate::{ - death_constraint::DeathProof, error::{Error, Result} + constraint::ConstraintProof, + error::{Error, Result}, }; const MAX_NOTE_COMMS: usize = 2usize.pow(8); - pub struct ProvedPartialTx { pub ptx: cl::PartialTx, - pub cm_root: [u8;32], - pub death_proofs: BTreeMap, + pub cm_root: [u8; 32], + pub constraint_proofs: BTreeMap, pub risc0_receipt: risc0_zkvm::Receipt, } impl ProvedPartialTx { pub fn prove( ptx: &cl::PartialTxWitness, - death_proofs: BTreeMap, + constraint_proofs: BTreeMap, note_commitments: &[cl::NoteCommitment], ) -> Result { let cm_leaves = note_commitment_leaves(note_commitments); @@ -67,14 +67,12 @@ impl ProvedPartialTx { start_t.elapsed(), prove_info.stats.total_cycles ); - // extract the receipt. - let receipt = prove_info.receipt; Ok(Self { ptx: ptx.commit(), cm_root, - risc0_receipt: receipt, - death_proofs, + risc0_receipt: prove_info.receipt, + constraint_proofs, }) } @@ -86,7 +84,11 @@ impl ProvedPartialTx { let Ok(proved_ptx_inputs) = self.public() else { return false; }; - if (PtxPublic { ptx: self.ptx.clone(), cm_root: self.cm_root }) != proved_ptx_inputs { + let expected_ptx_inputs = PtxPublic { + ptx: self.ptx.clone(), + cm_root: self.cm_root, + }; + if expected_ptx_inputs != proved_ptx_inputs { return false; } @@ -94,15 +96,15 @@ impl ProvedPartialTx { for input in self.ptx.inputs.iter() { let nf = input.nullifier; - let Some(death_proof) = self.death_proofs.get(&nf) else { + let Some(constraint_proof) = self.constraint_proofs.get(&nf) else { return false; }; - if input.death_cm != death_proof.death_commitment() { - // ensure the death proof is actually for this input + if input.constraint != constraint_proof.constraint() { + // ensure the constraint proof is actually for this input return false; } - if !death_proof.verify(DeathConstraintPublic { nf, ptx_root }) { - // verify the death constraint was satisfied + if !constraint_proof.verify(ConstraintPublic { nf, ptx_root }) { + // verify the constraint was satisfied return false; } } diff --git a/goas/cl/ledger/tests/simple_transfer.rs b/goas/cl/ledger/tests/simple_transfer.rs index 2148a71..87009d0 100644 --- a/goas/cl/ledger/tests/simple_transfer.rs +++ b/goas/cl/ledger/tests/simple_transfer.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use cl::{note::derive_unit, BalanceWitness}; -use ledger::{bundle::ProvedBundle, death_constraint::DeathProof, partial_tx::ProvedPartialTx}; +use ledger::{bundle::ProvedBundle, constraint::ConstraintProof, partial_tx::ProvedPartialTx}; use rand_core::CryptoRngCore; struct User(cl::NullifierSecret); @@ -41,7 +41,7 @@ fn test_simple_transfer() { // Alice has an unspent note worth 10 NMO let utxo = receive_utxo( - cl::NoteWitness::stateless(10, nmo, DeathProof::nop_constraint()), + cl::NoteWitness::stateless(10, nmo, ConstraintProof::nop_constraint()), alice.pk(), &mut rng, ); @@ -61,17 +61,18 @@ fn test_simple_transfer() { balance_blinding: BalanceWitness::random_blinding(&mut rng), }; - // Prove the death constraints for alices input (she uses the no-op death constraint) - let death_proofs = BTreeMap::from_iter(ptx_witness.inputs.iter().map(|i| { + // Prove the constraints for alices input (she uses the no-op constraint) + let constraint_proofs = BTreeMap::from_iter(ptx_witness.inputs.iter().map(|i| { ( i.nullifier(), - DeathProof::prove_nop(i.nullifier(), ptx_witness.commit().root()), + ConstraintProof::prove_nop(i.nullifier(), ptx_witness.commit().root()), ) })); // assume we only have one note commitment on chain for now ... let note_commitments = vec![utxo.commit_note()]; - let proved_ptx = ProvedPartialTx::prove(&ptx_witness, death_proofs, ¬e_commitments).unwrap(); + let proved_ptx = + ProvedPartialTx::prove(&ptx_witness, constraint_proofs, ¬e_commitments).unwrap(); assert!(proved_ptx.verify()); // It's a valid ptx. diff --git a/goas/cl/ledger_proof_statements/src/death_constraint.rs b/goas/cl/ledger_proof_statements/src/constraint.rs similarity index 84% rename from goas/cl/ledger_proof_statements/src/death_constraint.rs rename to goas/cl/ledger_proof_statements/src/constraint.rs index 92e64f6..91e7aa4 100644 --- a/goas/cl/ledger_proof_statements/src/death_constraint.rs +++ b/goas/cl/ledger_proof_statements/src/constraint.rs @@ -2,7 +2,7 @@ use cl::{Nullifier, PtxRoot}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -pub struct DeathConstraintPublic { +pub struct ConstraintPublic { pub nf: Nullifier, pub ptx_root: PtxRoot, } diff --git a/goas/cl/ledger_proof_statements/src/lib.rs b/goas/cl/ledger_proof_statements/src/lib.rs index 17e0c7e..9d5377f 100644 --- a/goas/cl/ledger_proof_statements/src/lib.rs +++ b/goas/cl/ledger_proof_statements/src/lib.rs @@ -1,3 +1,3 @@ -pub mod death_constraint; +pub mod constraint; pub mod ptx; pub mod bundle; diff --git a/goas/cl/risc0_proofs/Cargo.toml b/goas/cl/risc0_proofs/Cargo.toml index d53a6fd..21cc296 100644 --- a/goas/cl/risc0_proofs/Cargo.toml +++ b/goas/cl/risc0_proofs/Cargo.toml @@ -7,5 +7,5 @@ edition = "2021" risc0-build = { version = "1.0" } [package.metadata.risc0] -methods = ["bundle", "death_constraint_nop", "ptx"] +methods = ["bundle", "constraint_nop", "ptx"] diff --git a/goas/cl/risc0_proofs/death_constraint_nop/Cargo.toml b/goas/cl/risc0_proofs/constraint_nop/Cargo.toml similarity index 95% rename from goas/cl/risc0_proofs/death_constraint_nop/Cargo.toml rename to goas/cl/risc0_proofs/constraint_nop/Cargo.toml index 5b7136a..1aac242 100644 --- a/goas/cl/risc0_proofs/death_constraint_nop/Cargo.toml +++ b/goas/cl/risc0_proofs/constraint_nop/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "death_constraint_nop" +name = "constraint_nop" version = "0.1.0" edition = "2021" diff --git a/goas/cl/risc0_proofs/constraint_nop/src/main.rs b/goas/cl/risc0_proofs/constraint_nop/src/main.rs new file mode 100644 index 0000000..25d9c0c --- /dev/null +++ b/goas/cl/risc0_proofs/constraint_nop/src/main.rs @@ -0,0 +1,8 @@ +/// Constraint No-op Proof +use ledger_proof_statements::constraint::ConstraintPublic; +use risc0_zkvm::guest::env; + +fn main() { + let public: ConstraintPublic = env::read(); + env::commit(&public); +} diff --git a/goas/cl/risc0_proofs/death_constraint_nop/src/main.rs b/goas/cl/risc0_proofs/death_constraint_nop/src/main.rs deleted file mode 100644 index 232c447..0000000 --- a/goas/cl/risc0_proofs/death_constraint_nop/src/main.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// Death Constraint No-op Proof -use ledger_proof_statements::death_constraint::DeathConstraintPublic; -use risc0_zkvm::guest::env; - -fn main() { - let public: DeathConstraintPublic = env::read(); - env::commit(&public); -}