diff --git a/emmarin/cl/cl/src/cl/bundle.rs b/emmarin/cl/cl/src/cl/bundle.rs index aa6beef..c9166cf 100644 --- a/emmarin/cl/cl/src/cl/bundle.rs +++ b/emmarin/cl/cl/src/cl/bundle.rs @@ -6,7 +6,7 @@ use crate::cl::{partial_tx::PartialTx, BalanceWitness, PartialTxWitness}; /// The goal in bundling transactions is to produce a set of partial transactions /// that balance each other. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Bundle { pub partials: Vec, } @@ -30,7 +30,7 @@ impl BundleWitness { #[cfg(test)] mod test { - use crate::{ + use crate::cl::{ balance::UnitBalance, input::InputWitness, note::{derive_unit, NoteWitness}, diff --git a/emmarin/cl/cl/src/cl/input.rs b/emmarin/cl/cl/src/cl/input.rs index a0f2db0..6503b7b 100644 --- a/emmarin/cl/cl/src/cl/input.rs +++ b/emmarin/cl/cl/src/cl/input.rs @@ -2,10 +2,13 @@ /// /// Partial transactions, as the name suggests, are transactions /// which on their own may not balance (i.e. \sum inputs != \sum outputs) -use crate::cl::{ - note::{Constraint, NoteWitness}, - nullifier::{Nullifier, NullifierSecret}, - Nonce, NoteCommitment, OutputWitness, +use crate::{ + cl::{ + note::{Constraint, NoteWitness}, + nullifier::{Nullifier, NullifierSecret}, + Nonce, NoteCommitment, OutputWitness, + }, + zone_layer::notes::ZoneId, }; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -14,6 +17,7 @@ use sha2::{Digest, Sha256}; pub struct Input { pub nullifier: Nullifier, pub constraint: Constraint, + pub zone_id: ZoneId, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] @@ -63,10 +67,11 @@ impl InputWitness { Nullifier::new(tag, self.nf_sk, self.note_commitment(tag)) } - pub fn commit(&self, tag: &dyn AsRef<[u8]>) -> Input { + pub fn commit(&self, zone_id: ZoneId) -> Input { Input { - nullifier: self.nullifier(tag), + nullifier: self.nullifier(&zone_id), constraint: self.note.constraint, + zone_id, } } @@ -76,10 +81,11 @@ impl InputWitness { } impl Input { - pub fn to_bytes(&self) -> [u8; 64] { - let mut bytes = [0u8; 64]; + pub fn to_bytes(&self) -> [u8; 96] { + let mut bytes = [0u8; 96]; bytes[..32].copy_from_slice(self.nullifier.as_bytes()); bytes[32..64].copy_from_slice(&self.constraint.0); + bytes[64..96].copy_from_slice(&self.zone_id); bytes } } diff --git a/emmarin/cl/cl/src/cl/mod.rs b/emmarin/cl/cl/src/cl/mod.rs index 31b8cc8..e1d559e 100644 --- a/emmarin/cl/cl/src/cl/mod.rs +++ b/emmarin/cl/cl/src/cl/mod.rs @@ -7,7 +7,6 @@ pub mod merkle; pub mod note; pub mod nullifier; pub mod output; -pub mod pact; pub mod partial_tx; pub use balance::{Balance, BalanceWitness}; diff --git a/emmarin/cl/cl/src/cl/note.rs b/emmarin/cl/cl/src/cl/note.rs index d198d47..ca9c313 100644 --- a/emmarin/cl/cl/src/cl/note.rs +++ b/emmarin/cl/cl/src/cl/note.rs @@ -118,8 +118,8 @@ impl Nonce { #[cfg(test)] mod test { - use super::*; - use crate::nullifier::NullifierSecret; + // use super::*; + // use crate::cl::nullifier::NullifierSecret; // #[test] // fn test_note_commit_permutations() { diff --git a/emmarin/cl/cl/src/cl/nullifier.rs b/emmarin/cl/cl/src/cl/nullifier.rs index 3a522f6..c2340f4 100644 --- a/emmarin/cl/cl/src/cl/nullifier.rs +++ b/emmarin/cl/cl/src/cl/nullifier.rs @@ -84,7 +84,7 @@ impl Nullifier { #[cfg(test)] mod test { - use crate::{note::derive_unit, Constraint, Nonce, NoteWitness}; + // use crate::cl::{note::derive_unit, Constraint, Nonce, NoteWitness}; // use super::*; diff --git a/emmarin/cl/cl/src/cl/output.rs b/emmarin/cl/cl/src/cl/output.rs index 604ef66..40e7ccd 100644 --- a/emmarin/cl/cl/src/cl/output.rs +++ b/emmarin/cl/cl/src/cl/output.rs @@ -1,13 +1,17 @@ use serde::{Deserialize, Serialize}; -use crate::cl::{ - note::{NoteCommitment, NoteWitness}, - nullifier::NullifierCommitment, - NullifierSecret, +use crate::{ + cl::{ + note::{NoteCommitment, NoteWitness}, + nullifier::NullifierCommitment, + NullifierSecret, + }, + zone_layer::notes::ZoneId, }; #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct Output { + pub zone_id: ZoneId, pub note_comm: NoteCommitment, } @@ -31,15 +35,19 @@ impl OutputWitness { self.note.commit(tag, self.nf_pk) } - pub fn commit(&self, tag: &dyn AsRef<[u8]>) -> Output { + pub fn commit(&self, zone_id: ZoneId) -> Output { Output { - note_comm: self.commit_note(tag), + zone_id, + note_comm: self.commit_note(&zone_id), } } } impl Output { - pub fn to_bytes(&self) -> [u8; 32] { - self.note_comm.0 + pub fn to_bytes(&self) -> [u8; 64] { + let mut bytes = [0u8; 64]; + bytes[..32].copy_from_slice(&self.zone_id); + bytes[32..].copy_from_slice(&self.note_comm.0); + bytes } } diff --git a/emmarin/cl/cl/src/cl/pact.rs b/emmarin/cl/cl/src/cl/pact.rs deleted file mode 100644 index b231bc9..0000000 --- a/emmarin/cl/cl/src/cl/pact.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::cl::{PartialTx, PartialTxWitness}; -use crate::zone_layer::notes::ZoneId; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct Pact { - pub tx: PartialTx, - pub to: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct PactWitness { - pub tx: PartialTxWitness, - pub from: ZoneId, - pub to: Vec, -} - -impl PactWitness { - pub fn commit(&self) -> Pact { - assert_eq!(self.tx.outputs.len(), self.to.len()); - let ptx = PartialTx { - inputs: Vec::from_iter(self.tx.inputs.iter().map(|i| i.commit(&self.from))), - outputs: Vec::from_iter( - self.tx - .outputs - .iter() - .zip(&self.to) - .map(|(o, z)| o.commit(z)), - ), - balance: self.tx.balance().commit(), - }; - Pact { - tx: ptx, - to: self.to.clone(), - } - } -} diff --git a/emmarin/cl/cl/src/cl/partial_tx.rs b/emmarin/cl/cl/src/cl/partial_tx.rs index 5245ea1..2710a09 100644 --- a/emmarin/cl/cl/src/cl/partial_tx.rs +++ b/emmarin/cl/cl/src/cl/partial_tx.rs @@ -1,11 +1,14 @@ use rand_core::{CryptoRngCore, RngCore}; use serde::{Deserialize, Serialize}; -use crate::cl::{ - balance::{Balance, BalanceWitness}, - input::{Input, InputWitness}, - merkle, - output::{Output, OutputWitness}, +use crate::{ + cl::{ + balance::{Balance, BalanceWitness}, + input::{Input, InputWitness}, + merkle, + output::{Output, OutputWitness}, + }, + zone_layer::notes::ZoneId, }; pub const MAX_INPUTS: usize = 8; @@ -65,19 +68,32 @@ impl PartialTxWitness { BalanceWitness::from_ptx(self, self.balance_blinding) } - pub fn commit(&self, zone: &dyn AsRef<[u8]>) -> PartialTx { + pub fn commit(&self, input_zones: &[ZoneId], output_zones: &[ZoneId]) -> PartialTx { + assert_eq!(self.inputs.len(), input_zones.len()); + assert_eq!(self.outputs.len(), output_zones.len()); PartialTx { - inputs: Vec::from_iter(self.inputs.iter().map(|i| i.commit(zone))), - outputs: Vec::from_iter(self.outputs.iter().map(|o| o.commit(zone))), + inputs: self + .inputs + .iter() + .zip(input_zones.iter()) + .map(|(i, z)| i.commit(*z)) + .collect(), + + outputs: self + .outputs + .iter() + .zip(output_zones.iter()) + .map(|(o, z)| o.commit(*z)) + .collect(), balance: self.balance().commit(), } } - pub fn input_witness(&self, tag: &dyn AsRef<[u8]>, idx: usize) -> PartialTxInputWitness { + pub fn input_witness(&self, zone_id: ZoneId, idx: usize) -> PartialTxInputWitness { let input_bytes = Vec::from_iter( self.inputs .iter() - .map(|i| i.commit(tag).to_bytes().to_vec()), + .map(|i| i.commit(zone_id).to_bytes().to_vec()), ); let input_merkle_leaves = merkle::padded_leaves::(&input_bytes); @@ -86,11 +102,11 @@ impl PartialTxWitness { PartialTxInputWitness { input, path } } - pub fn output_witness(&self, tag: &dyn AsRef<[u8]>, idx: usize) -> PartialTxOutputWitness { + pub fn output_witness(&self, zone_id: ZoneId, idx: usize) -> PartialTxOutputWitness { let output_bytes = Vec::from_iter( self.outputs .iter() - .map(|o| o.commit(tag).to_bytes().to_vec()), + .map(|o| o.commit(zone_id).to_bytes().to_vec()), ); let output_merkle_leaves = merkle::padded_leaves::(&output_bytes); @@ -135,8 +151,8 @@ pub struct PartialTxInputWitness { } impl PartialTxInputWitness { - pub fn input_root(&self, tag: &dyn AsRef<[u8]>) -> [u8; 32] { - let leaf = merkle::leaf(&self.input.commit(tag).to_bytes()); + pub fn input_root(&self, zone_id: ZoneId) -> [u8; 32] { + let leaf = merkle::leaf(&self.input.commit(zone_id).to_bytes()); merkle::path_root(leaf, &self.path) } } @@ -149,8 +165,8 @@ pub struct PartialTxOutputWitness { } impl PartialTxOutputWitness { - pub fn output_root(&self, tag: &dyn AsRef<[u8]>) -> [u8; 32] { - let leaf = merkle::leaf(&self.output.commit(tag).to_bytes()); + pub fn output_root(&self, zone_id: ZoneId) -> [u8; 32] { + let leaf = merkle::leaf(&self.output.commit(zone_id).to_bytes()); merkle::path_root(leaf, &self.path) } } @@ -158,13 +174,13 @@ impl PartialTxOutputWitness { #[cfg(test)] mod test { - use crate::{ - balance::UnitBalance, - note::{derive_unit, NoteWitness}, - nullifier::NullifierSecret, - }; + // use crate::cl::{ + // balance::UnitBalance, + // note::{derive_unit, NoteWitness}, + // nullifier::NullifierSecret, + // }; - use super::*; + // use super::*; // #[test] // fn test_partial_tx_balance() { diff --git a/emmarin/cl/cl/tests/simple_transfer.rs b/emmarin/cl/cl/tests/simple_transfer.rs index f1a7a95..01a2cc8 100644 --- a/emmarin/cl/cl/tests/simple_transfer.rs +++ b/emmarin/cl/cl/tests/simple_transfer.rs @@ -1,7 +1,10 @@ -use cl::{note::derive_unit, BalanceWitness}; +use cl::cl::{ + note::derive_unit, BalanceWitness, BundleWitness, InputWitness, NoteWitness, + NullifierCommitment, NullifierSecret, OutputWitness, PartialTxWitness, +}; -fn receive_utxo(note: cl::NoteWitness, nf_pk: cl::NullifierCommitment) -> cl::OutputWitness { - cl::OutputWitness::new(note, nf_pk) +fn receive_utxo(note: NoteWitness, nf_pk: NullifierCommitment) -> OutputWitness { + OutputWitness::new(note, nf_pk) } #[test] @@ -9,27 +12,26 @@ fn test_simple_transfer() { let nmo = derive_unit("NMO"); let mut rng = rand::thread_rng(); - let sender_nf_sk = cl::NullifierSecret::random(&mut rng); + let sender_nf_sk = NullifierSecret::random(&mut rng); let sender_nf_pk = sender_nf_sk.commit(); - let recipient_nf_pk = cl::NullifierSecret::random(&mut rng).commit(); + let recipient_nf_pk = NullifierSecret::random(&mut rng).commit(); // Assume the sender has received an unspent output from somewhere - let utxo = receive_utxo(cl::NoteWitness::basic(10, nmo, &mut rng), sender_nf_pk); + let utxo = receive_utxo(NoteWitness::basic(10, nmo, &mut rng), sender_nf_pk); // and wants to send 8 NMO to some recipient and return 2 NMO to itself. let recipient_output = - cl::OutputWitness::new(cl::NoteWitness::basic(8, nmo, &mut rng), recipient_nf_pk); - let change_output = - cl::OutputWitness::new(cl::NoteWitness::basic(2, nmo, &mut rng), sender_nf_pk); + OutputWitness::new(NoteWitness::basic(8, nmo, &mut rng), recipient_nf_pk); + let change_output = OutputWitness::new(NoteWitness::basic(2, nmo, &mut rng), sender_nf_pk); - let ptx_witness = cl::PartialTxWitness { - inputs: vec![cl::InputWitness::from_output(utxo, sender_nf_sk)], + let ptx_witness = PartialTxWitness { + inputs: vec![InputWitness::from_output(utxo, sender_nf_sk)], outputs: vec![recipient_output, change_output], balance_blinding: BalanceWitness::random_blinding(&mut rng), }; - let bundle = cl::BundleWitness { + let bundle = BundleWitness { partials: vec![ptx_witness], }; diff --git a/emmarin/cl/ledger/src/bundle.rs b/emmarin/cl/ledger/src/bundle.rs index 25f0765..e8d4e8e 100644 --- a/emmarin/cl/ledger/src/bundle.rs +++ b/emmarin/cl/ledger/src/bundle.rs @@ -2,6 +2,7 @@ use crate::error::{Error, Result}; use cl::cl::BundleWitness; use ledger_proof_statements::bundle::{BundlePrivate, BundlePublic}; +#[derive(Debug, Clone)] pub struct ProvedBundle { pub bundle: BundlePublic, pub risc0_receipt: risc0_zkvm::Receipt, diff --git a/emmarin/cl/ledger/src/ledger.rs b/emmarin/cl/ledger/src/ledger.rs index 6fab328..7920972 100644 --- a/emmarin/cl/ledger/src/ledger.rs +++ b/emmarin/cl/ledger/src/ledger.rs @@ -1,47 +1,38 @@ -use ledger_proof_statements::ledger::{LedgerProofPrivate, LedgerProofPublic, ZoneTx}; +use ledger_proof_statements::{ + ledger::{LedgerProofPrivate, LedgerProofPublic}, + ptx::PtxPublic, +}; use crate::{ bundle::ProvedBundle, constraint::ConstraintProof, error::{Error, Result}, - pact::ProvedPact, partial_tx::ProvedPartialTx, }; use cl::zone_layer::{ledger::LedgerWitness, notes::ZoneId}; +#[derive(Debug, Clone)] pub struct ProvedLedgerTransition { pub public: LedgerProofPublic, pub risc0_receipt: risc0_zkvm::Receipt, } -pub enum ProvedZoneTx { - LocalTx { - bundle: ProvedBundle, - ptxs: Vec, - }, - Pact(ProvedPact), +// TODO: find a better name +#[derive(Debug, Clone)] +pub struct ProvedZoneTx { + pub bundle: ProvedBundle, + pub ptxs: Vec, } impl ProvedZoneTx { - fn to_public(&self) -> ZoneTx { - match self { - Self::LocalTx { ptxs, bundle } => ZoneTx::LocalTx { - ptxs: ptxs.iter().map(|p| p.public().unwrap()).collect(), - bundle: bundle.public().unwrap(), - }, - Self::Pact(pact) => ZoneTx::Pact(pact.public().unwrap()), - } + fn to_public(&self) -> Vec { + self.ptxs.iter().map(|p| p.public().unwrap()).collect() } fn proofs(&self) -> Vec { - match self { - Self::LocalTx { ptxs, bundle } => { - let mut proofs = vec![bundle.risc0_receipt.clone()]; - proofs.extend(ptxs.iter().map(|p| p.risc0_receipt.clone())); - proofs - } - Self::Pact(pact) => vec![pact.risc0_receipt.clone()], - } + let mut proofs = vec![self.bundle.risc0_receipt.clone()]; + proofs.extend(self.ptxs.iter().map(|p| p.risc0_receipt.clone())); + proofs } } @@ -53,7 +44,7 @@ impl ProvedLedgerTransition { constraints: Vec, ) -> Result { let witness = LedgerProofPrivate { - txs: ptxs.iter().map(|p| p.to_public()).collect(), + bundles: ptxs.iter().map(|p| p.to_public()).collect(), ledger, id: zone_id, }; diff --git a/emmarin/cl/ledger/src/lib.rs b/emmarin/cl/ledger/src/lib.rs index 93be05a..ad327b3 100644 --- a/emmarin/cl/ledger/src/lib.rs +++ b/emmarin/cl/ledger/src/lib.rs @@ -2,7 +2,6 @@ pub mod bundle; pub mod constraint; pub mod error; pub mod ledger; -pub mod pact; pub mod partial_tx; pub mod stf; pub mod zone_update; diff --git a/emmarin/cl/ledger/src/pact.rs b/emmarin/cl/ledger/src/pact.rs deleted file mode 100644 index 44d52eb..0000000 --- a/emmarin/cl/ledger/src/pact.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::error::{Error, Result}; -use cl::cl::{ - merkle, - pact::{Pact, PactWitness}, -}; -use ledger_proof_statements::pact::{PactPrivate, PactPublic}; - -#[derive(Debug, Clone)] -pub struct ProvedPact { - pub pact: Pact, - pub cm_root: [u8; 32], - pub risc0_receipt: risc0_zkvm::Receipt, -} - -impl ProvedPact { - pub fn prove( - pact: PactWitness, - input_cm_paths: Vec>, - cm_root: [u8; 32], - ) -> Result { - let pact_private = PactPrivate { - pact, - input_cm_paths, - cm_root, - }; - - let env = risc0_zkvm::ExecutorEnv::builder() - .write(&pact_private) - .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::PACT_ELF, &opts) - .map_err(|_| Error::Risc0ProofFailed)?; - - println!( - "STARK 'pact' prover time: {:.2?}, total_cycles: {}", - start_t.elapsed(), - prove_info.stats.total_cycles - ); - - Ok(Self { - pact: pact_private.pact.commit(), - cm_root, - risc0_receipt: prove_info.receipt, - }) - } - - pub fn public(&self) -> Result { - Ok(self.risc0_receipt.journal.decode()?) - } - - pub fn verify(&self) -> bool { - let Ok(proved_ptx_inputs) = self.public() else { - return false; - }; - let expected_ptx_inputs = PactPublic { - pact: self.pact.clone(), - cm_root: self.cm_root, - }; - if expected_ptx_inputs != proved_ptx_inputs { - return false; - } - - self.risc0_receipt - .verify(nomos_cl_risc0_proofs::PACT_ID) - .is_ok() - } -} diff --git a/emmarin/cl/ledger/src/partial_tx.rs b/emmarin/cl/ledger/src/partial_tx.rs index 6a1c614..d49891f 100644 --- a/emmarin/cl/ledger/src/partial_tx.rs +++ b/emmarin/cl/ledger/src/partial_tx.rs @@ -4,6 +4,7 @@ use crate::error::{Error, Result}; use cl::cl::{merkle, PartialTx, PartialTxWitness}; use cl::zone_layer::notes::ZoneId; +#[derive(Debug, Clone)] pub struct ProvedPartialTx { pub ptx: PartialTx, pub cm_root: [u8; 32], @@ -12,16 +13,19 @@ pub struct ProvedPartialTx { impl ProvedPartialTx { pub fn prove( - ptx: &PartialTxWitness, + ptx_witness: PartialTxWitness, input_cm_paths: Vec>, cm_root: [u8; 32], - id: ZoneId, + from: Vec, + to: Vec, ) -> Result { + let ptx = ptx_witness.commit(&from, &to); let ptx_private = PtxPrivate { - ptx: ptx.clone(), + ptx: ptx_witness, input_cm_paths, cm_root, - from: id, + from, + to, }; let env = risc0_zkvm::ExecutorEnv::builder() @@ -49,7 +53,7 @@ impl ProvedPartialTx { ); Ok(Self { - ptx: ptx.commit(&id), + ptx, cm_root, risc0_receipt: prove_info.receipt, }) diff --git a/emmarin/cl/ledger/tests/simple_transfer.rs b/emmarin/cl/ledger/tests/simple_transfer.rs index 879ca19..dbccf05 100644 --- a/emmarin/cl/ledger/tests/simple_transfer.rs +++ b/emmarin/cl/ledger/tests/simple_transfer.rs @@ -1,29 +1,36 @@ -use cl::{note::derive_unit, BalanceWitness}; +use cl::{ + cl::{ + note::derive_unit, BalanceWitness, BundleWitness, InputWitness, NoteWitness, + NullifierCommitment, NullifierSecret, OutputWitness, PartialTxWitness, + }, + zone_layer::ledger::LedgerWitness, +}; use ledger::{ + bundle::ProvedBundle, constraint::ConstraintProof, ledger::{ProvedLedgerTransition, ProvedZoneTx}, - pact::ProvedPact, + partial_tx::ProvedPartialTx, }; use rand_core::CryptoRngCore; -struct User(cl::NullifierSecret); +struct User(NullifierSecret); impl User { fn random(mut rng: impl CryptoRngCore) -> Self { - Self(cl::NullifierSecret::random(&mut rng)) + Self(NullifierSecret::random(&mut rng)) } - fn pk(&self) -> cl::NullifierCommitment { + fn pk(&self) -> NullifierCommitment { self.0.commit() } - fn sk(&self) -> cl::NullifierSecret { + fn sk(&self) -> NullifierSecret { self.0 } } -fn receive_utxo(note: cl::NoteWitness, nf_pk: cl::NullifierCommitment) -> cl::OutputWitness { - cl::OutputWitness::new(note, nf_pk) +fn receive_utxo(note: NoteWitness, nf_pk: NullifierCommitment) -> OutputWitness { + OutputWitness::new(note, nf_pk) } #[test] @@ -39,81 +46,82 @@ fn ledger_transition() { // Alice has an unspent note worth 10 NMO let utxo = receive_utxo( - cl::NoteWitness::stateless(10, nmo, ConstraintProof::nop_constraint(), &mut rng), + NoteWitness::stateless(10, nmo, ConstraintProof::nop_constraint(), &mut rng), alice.pk(), ); // Alice wants to send 8 NMO to bob - let bobs_output = cl::OutputWitness::new(cl::NoteWitness::basic(8, nmo, &mut rng), bob.pk()); + let bobs_output = OutputWitness::new(NoteWitness::basic(8, nmo, &mut rng), bob.pk()); - let alice_change = cl::OutputWitness::new(cl::NoteWitness::basic(2, nmo, &mut rng), alice.pk()); + let alice_change = OutputWitness::new(NoteWitness::basic(2, nmo, &mut rng), alice.pk()); - let alice_input = cl::InputWitness::from_output(utxo, alice.sk()); + let alice_input = InputWitness::from_output(utxo, alice.sk()); let zone_a = [0; 32]; let zone_b = [1; 32]; - let ledger_a = cl::zones::LedgerWitness { + let ledger_a = LedgerWitness { commitments: vec![utxo.commit_note(&zone_a)], nullifiers: vec![], }; - let ledger_b = cl::zones::LedgerWitness { + let ledger_b = LedgerWitness { commitments: vec![], nullifiers: vec![], }; - let expected_ledger_a = cl::zones::LedgerWitness { + let expected_ledger_a = LedgerWitness { commitments: vec![utxo.commit_note(&zone_a), alice_change.commit_note(&zone_a)], nullifiers: vec![alice_input.nullifier(&zone_a)], }; - let expected_ledger_b = cl::zones::LedgerWitness { + let expected_ledger_b = LedgerWitness { commitments: vec![bobs_output.commit_note(&zone_b)], nullifiers: vec![], }; // Construct the ptx consuming Alices inputs and producing the two outputs. - let alice_pact_witness = cl::zones::PactWitness { - tx: cl::PartialTxWitness { - inputs: vec![alice_input], - outputs: vec![bobs_output, alice_change], - - balance_blinding: BalanceWitness::random_blinding(&mut rng), - }, - from: zone_a, - to: vec![zone_b, zone_a], + let alice_ptx_witness = PartialTxWitness { + inputs: vec![alice_input], + outputs: vec![bobs_output, alice_change], + balance_blinding: BalanceWitness::random_blinding(&mut rng), }; - - let proved_pact = ProvedPact::prove( - alice_pact_witness, + let proved_ptx = ProvedPartialTx::prove( + alice_ptx_witness.clone(), vec![ledger_a .cm_path(&alice_input.note_commitment(&zone_a)) .unwrap()], ledger_a.cm_root(), + vec![zone_a], + vec![zone_b, zone_a], ) .unwrap(); - assert_eq!(proved_pact.cm_root, ledger_a.cm_root()); + let bundle = ProvedBundle::prove(&BundleWitness { + partials: vec![alice_ptx_witness], + }) + .unwrap(); + + assert_eq!(proved_ptx.cm_root, ledger_a.cm_root()); + + let zone_tx = ProvedZoneTx { + ptxs: vec![proved_ptx.clone()], + bundle, + }; // Prove the constraints for alices input (she uses the no-op constraint) let constraint_proof = - ConstraintProof::prove_nop(alice_input.nullifier(&zone_a), proved_pact.pact.tx.root()); + ConstraintProof::prove_nop(alice_input.nullifier(&zone_a), proved_ptx.ptx.root()); let ledger_a_transition = ProvedLedgerTransition::prove( ledger_a, zone_a, - vec![ProvedZoneTx::Pact(proved_pact.clone())], + vec![zone_tx.clone()], vec![constraint_proof], ) .unwrap(); - let ledger_b_transition = ProvedLedgerTransition::prove( - ledger_b, - zone_b, - vec![ProvedZoneTx::Pact(proved_pact)], - vec![], - ) - .unwrap(); + let ledger_b_transition = + ProvedLedgerTransition::prove(ledger_b, zone_b, vec![zone_tx], vec![]).unwrap(); assert_eq!( ledger_a_transition.public.ledger, diff --git a/emmarin/cl/ledger_proof_statements/src/ledger.rs b/emmarin/cl/ledger_proof_statements/src/ledger.rs index ed3d728..824246e 100644 --- a/emmarin/cl/ledger_proof_statements/src/ledger.rs +++ b/emmarin/cl/ledger_proof_statements/src/ledger.rs @@ -1,5 +1,3 @@ -use crate::bundle::BundlePublic; -use crate::pact::PactPublic; use crate::ptx::PtxPublic; use cl::cl::Output; use cl::zone_layer::{ @@ -21,14 +19,5 @@ pub struct LedgerProofPublic { pub struct LedgerProofPrivate { pub ledger: LedgerWitness, pub id: ZoneId, - pub txs: Vec, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum ZoneTx { - LocalTx { - ptxs: Vec, - bundle: BundlePublic, - }, - Pact(PactPublic), + pub bundles: Vec>, } diff --git a/emmarin/cl/ledger_proof_statements/src/lib.rs b/emmarin/cl/ledger_proof_statements/src/lib.rs index fa0941c..5d907dc 100644 --- a/emmarin/cl/ledger_proof_statements/src/lib.rs +++ b/emmarin/cl/ledger_proof_statements/src/lib.rs @@ -1,6 +1,5 @@ pub mod bundle; pub mod constraint; pub mod ledger; -pub mod pact; pub mod ptx; pub mod stf; diff --git a/emmarin/cl/ledger_proof_statements/src/pact.rs b/emmarin/cl/ledger_proof_statements/src/pact.rs deleted file mode 100644 index f9a6c8c..0000000 --- a/emmarin/cl/ledger_proof_statements/src/pact.rs +++ /dev/null @@ -1,18 +0,0 @@ -use cl::cl::{ - merkle, - pact::{Pact, PactWitness}, -}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct PactPublic { - pub pact: Pact, - pub cm_root: [u8; 32], -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct PactPrivate { - pub pact: PactWitness, - pub input_cm_paths: Vec>, - pub cm_root: [u8; 32], -} diff --git a/emmarin/cl/ledger_proof_statements/src/ptx.rs b/emmarin/cl/ledger_proof_statements/src/ptx.rs index a11070c..fe256cc 100644 --- a/emmarin/cl/ledger_proof_statements/src/ptx.rs +++ b/emmarin/cl/ledger_proof_statements/src/ptx.rs @@ -1,4 +1,7 @@ -use cl::cl::{merkle, PartialTx, PartialTxWitness}; +use cl::{ + cl::{merkle, PartialTx, PartialTxWitness}, + zone_layer::notes::ZoneId, +}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -12,5 +15,6 @@ pub struct PtxPrivate { pub ptx: PartialTxWitness, pub input_cm_paths: Vec>, pub cm_root: [u8; 32], - pub from: [u8; 32], + pub from: Vec, + pub to: Vec, } diff --git a/emmarin/cl/ledger_validity_proof/ledger/src/main.rs b/emmarin/cl/ledger_validity_proof/ledger/src/main.rs index 55bf280..b71212c 100644 --- a/emmarin/cl/ledger_validity_proof/ledger/src/main.rs +++ b/emmarin/cl/ledger_validity_proof/ledger/src/main.rs @@ -2,14 +2,19 @@ use cl::{ cl::Output, zone_layer::{ledger::LedgerWitness, notes::ZoneId}, }; -use ledger_proof_statements::{bundle::*, constraint::*, ledger::*, pact::PactPublic, ptx::*}; +use ledger_proof_statements::{ + bundle::BundlePublic, + constraint::ConstraintPublic, + ledger::{LedgerProofPrivate, LedgerProofPublic}, + ptx::PtxPublic, +}; use risc0_zkvm::{guest::env, serde}; fn main() { let LedgerProofPrivate { mut ledger, id, - txs, + bundles, } = env::read(); let old_ledger = ledger.commit(); @@ -19,18 +24,23 @@ fn main() { let mut cross_in = vec![]; let mut cross_out = vec![]; - for tx in txs { - match tx { - ZoneTx::LocalTx { bundle, ptxs } => { - ledger = process_bundle(ledger, ptxs, bundle, cm_root); - } - ZoneTx::Pact(pact) => { - let (new_ledger, consumed_commits, produced_commits) = - process_pact(ledger, pact, id, cm_root); - ledger = new_ledger; - cross_in.extend(consumed_commits); - cross_out.extend(produced_commits); - } + for bundle in bundles { + let bundle_public = BundlePublic { + balances: bundle.iter().map(|ptx| ptx.ptx.balance).collect::>(), + }; + // verify bundle is balanced + env::verify( + nomos_cl_risc0_proofs::BUNDLE_ID, + &serde::to_vec(&bundle_public).unwrap(), + ) + .unwrap(); + + for ptx in &bundle { + let (new_ledger, consumed_commitments, produced_commitments) = + process_ptx(ledger, ptx, id, cm_root); + cross_in.extend(consumed_commitments); + cross_out.extend(produced_commitments); + ledger = new_ledger; } } @@ -43,106 +53,51 @@ fn main() { }); } -fn process_bundle( +fn process_ptx( mut ledger: LedgerWitness, - ptxs: Vec, - bundle_proof: BundlePublic, - cm_root: [u8; 32], -) -> LedgerWitness { - assert_eq!( - ptxs.iter().map(|ptx| ptx.ptx.balance).collect::>(), - bundle_proof.balances - ); - // verify bundle is balanced - env::verify( - nomos_cl_risc0_proofs::BUNDLE_ID, - &serde::to_vec(&bundle_proof).unwrap(), - ) - .unwrap(); - - for ptx in ptxs { - ledger = process_ptx(ledger, ptx, cm_root); - } - - ledger -} - -fn process_ptx(mut ledger: LedgerWitness, ptx: PtxPublic, cm_root: [u8; 32]) -> LedgerWitness { - env::verify(nomos_cl_risc0_proofs::PTX_ID, &serde::to_vec(&ptx).unwrap()).unwrap(); - assert_eq!(ptx.cm_root, cm_root); - - let ptx = ptx.ptx; - - for input in &ptx.inputs { - assert!(!ledger.nullifiers.contains(&input.nullifier)); - ledger.nullifiers.push(input.nullifier); - - env::verify( - input.constraint.0, - &serde::to_vec(&ConstraintPublic { - ptx_root: ptx.root(), - nf: input.nullifier, - }) - .unwrap(), - ) - .unwrap(); - } - - for output in &ptx.outputs { - ledger.commitments.push(output.note_comm); - } - - ledger -} - -fn process_pact( - mut ledger: LedgerWitness, - pact: PactPublic, - id: ZoneId, + ptx: &PtxPublic, + zone_id: ZoneId, cm_root: [u8; 32], ) -> (LedgerWitness, Vec, Vec) { let mut cross_in = vec![]; let mut cross_out = vec![]; - env::verify( - nomos_cl_risc0_proofs::PACT_ID, - &serde::to_vec(&pact).unwrap(), - ) - .unwrap(); + env::verify(nomos_cl_risc0_proofs::PTX_ID, &serde::to_vec(&ptx).unwrap()).unwrap(); - let pact_cm_root = pact.cm_root; - let pact = pact.pact; + let ptx_cm_root = ptx.cm_root; + let ptx = &ptx.ptx; - if cm_root != pact_cm_root { - // zone is the receiver of the transfer - for (comm, zone) in pact.tx.outputs.iter().zip(&pact.to) { - if *zone == id { - cross_in.push(*comm); - ledger.commitments.push(comm.note_comm); - } - } - } else { - // zone is the sender of the transfer - // proof of non-membership - for input in &pact.tx.inputs { + // TODO: accept inputs from multiple zones + let check_inputs = ptx.inputs.iter().all(|input| input.zone_id == zone_id); + + if check_inputs { + assert_eq!(ptx_cm_root, cm_root); + for input in &ptx.inputs { assert!(!ledger.nullifiers.contains(&input.nullifier)); ledger.nullifiers.push(input.nullifier); env::verify( input.constraint.0, &serde::to_vec(&ConstraintPublic { - ptx_root: pact.tx.root(), + ptx_root: ptx.root(), nf: input.nullifier, }) .unwrap(), ) .unwrap(); } + } - for (output, to) in pact.tx.outputs.iter().zip(&pact.to) { - if *to == id { - ledger.commitments.push(output.note_comm); - } else { + for output in &ptx.outputs { + if output.zone_id == zone_id { + ledger.commitments.push(output.note_comm); + // if this output was not originating from this zone, it is a cross zone transaction + if !check_inputs { + cross_in.push(*output); + } + } else { + // if this output is not going to this zone but originated from this zone, it is a cross zone transaction + if check_inputs { cross_out.push(*output); } } diff --git a/emmarin/cl/risc0_proofs/Cargo.toml b/emmarin/cl/risc0_proofs/Cargo.toml index b34bd02..21cc296 100644 --- a/emmarin/cl/risc0_proofs/Cargo.toml +++ b/emmarin/cl/risc0_proofs/Cargo.toml @@ -7,5 +7,5 @@ edition = "2021" risc0-build = { version = "1.0" } [package.metadata.risc0] -methods = ["bundle", "constraint_nop", "ptx", "pact"] +methods = ["bundle", "constraint_nop", "ptx"] diff --git a/emmarin/cl/risc0_proofs/pact/Cargo.toml b/emmarin/cl/risc0_proofs/pact/Cargo.toml deleted file mode 100644 index 9fdfdc0..0000000 --- a/emmarin/cl/risc0_proofs/pact/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "pact" -version = "0.1.0" -edition = "2021" - -[workspace] - -[dependencies] -risc0-zkvm = { version = "1.0", default-features = false, features = ['std'] } -serde = { version = "1.0", features = ["derive"] } -cl = { path = "../../cl" } -ledger_proof_statements = { path = "../../ledger_proof_statements" } - - -[patch.crates-io] -# add RISC Zero accelerator support for all downstream usages of the following crates. -sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" } -crypto-bigint = { git = "https://github.com/risc0/RustCrypto-crypto-bigint", tag = "v0.5.5-risczero.0" } -curve25519-dalek = { git = "https://github.com/risc0/curve25519-dalek", tag = "curve25519-4.1.2-risczero.0" } diff --git a/emmarin/cl/risc0_proofs/pact/src/main.rs b/emmarin/cl/risc0_proofs/pact/src/main.rs deleted file mode 100644 index 0dd6e79..0000000 --- a/emmarin/cl/risc0_proofs/pact/src/main.rs +++ /dev/null @@ -1,30 +0,0 @@ -/// Input Proof -use cl::cl::merkle; -use ledger_proof_statements::pact::{PactPrivate, PactPublic}; -use risc0_zkvm::guest::env; - -fn main() { - let PactPrivate { - pact, - input_cm_paths, - cm_root, - } = env::read(); - - assert_eq!(pact.tx.inputs.len(), input_cm_paths.len()); - for (input, cm_path) in pact.tx.inputs.iter().zip(input_cm_paths) { - let note_cm = input.note_commitment(&pact.from); - let cm_leaf = merkle::leaf(note_cm.as_bytes()); - assert_eq!(cm_root, merkle::path_root(cm_leaf, &cm_path)); - } - - for output in pact.tx.outputs.iter() { - assert!(output.note.value > 0); - } - - assert!(pact.tx.balance().is_zero()); - - env::commit(&PactPublic { - pact: pact.commit(), - cm_root, - }); -} diff --git a/emmarin/cl/risc0_proofs/ptx/src/main.rs b/emmarin/cl/risc0_proofs/ptx/src/main.rs index 49012cc..af4c2b1 100644 --- a/emmarin/cl/risc0_proofs/ptx/src/main.rs +++ b/emmarin/cl/risc0_proofs/ptx/src/main.rs @@ -9,11 +9,12 @@ fn main() { input_cm_paths, cm_root, from, + to, } = env::read(); assert_eq!(ptx.inputs.len(), input_cm_paths.len()); - for (input, cm_path) in ptx.inputs.iter().zip(input_cm_paths) { - let note_cm = input.note_commitment(&from); + for ((input, cm_path), zone_id) in ptx.inputs.iter().zip(input_cm_paths).zip(&from) { + let note_cm = input.note_commitment(zone_id); let cm_leaf = merkle::leaf(note_cm.as_bytes()); assert_eq!(cm_root, merkle::path_root(cm_leaf, &cm_path)); } @@ -23,7 +24,7 @@ fn main() { } env::commit(&PtxPublic { - ptx: ptx.commit(&from), + ptx: ptx.commit(&from, &to), cm_root, }); }