diff --git a/emmarin/cl/cl/src/cl/output.rs b/emmarin/cl/cl/src/cl/output.rs index a1fc8e4..604ef66 100644 --- a/emmarin/cl/cl/src/cl/output.rs +++ b/emmarin/cl/cl/src/cl/output.rs @@ -6,7 +6,7 @@ use crate::cl::{ NullifierSecret, }; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct Output { pub note_comm: NoteCommitment, } diff --git a/emmarin/cl/cl/src/cl/pact.rs b/emmarin/cl/cl/src/cl/pact.rs index 3f5f3e1..b231bc9 100644 --- a/emmarin/cl/cl/src/cl/pact.rs +++ b/emmarin/cl/cl/src/cl/pact.rs @@ -1,5 +1,5 @@ -use crate::zone_layer::ZoneId; use crate::cl::{PartialTx, PartialTxWitness}; +use crate::zone_layer::notes::ZoneId; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] diff --git a/emmarin/cl/cl/src/zone_layer/ledger.rs b/emmarin/cl/cl/src/zone_layer/ledger.rs new file mode 100644 index 0000000..11acbe6 --- /dev/null +++ b/emmarin/cl/cl/src/zone_layer/ledger.rs @@ -0,0 +1,55 @@ +use crate::cl::{merkle, NoteCommitment, Nullifier}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +pub struct Ledger { + cm_root: [u8; 32], + nf_root: [u8; 32], +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct LedgerWitness { + pub commitments: Vec, + pub nullifiers: Vec, +} + +const MAX_COMM: usize = 256; +const MAX_NULL: usize = 256; + +impl LedgerWitness { + pub fn commit(&self) -> Ledger { + Ledger { + cm_root: self.cm_root(), + nf_root: self.nf_root(), + } + } + + pub fn nf_root(&self) -> [u8; 32] { + let bytes = self + .nullifiers + .iter() + .map(|i| i.as_bytes().to_vec()) + .collect::>(); + merkle::root(merkle::padded_leaves::(&bytes)) + } + + pub fn cm_root(&self) -> [u8; 32] { + let bytes = self + .commitments + .iter() + .map(|i| i.as_bytes().to_vec()) + .collect::>(); + merkle::root(merkle::padded_leaves::(&bytes)) + } + + pub fn cm_path(&self, cm: &NoteCommitment) -> Option> { + let bytes = self + .commitments + .iter() + .map(|i| i.as_bytes().to_vec()) + .collect::>(); + let leaves = merkle::padded_leaves::(&bytes); + let idx = self.commitments.iter().position(|c| c == cm)?; + Some(merkle::path(leaves, idx)) + } +} diff --git a/emmarin/cl/cl/src/zone_layer/mod.rs b/emmarin/cl/cl/src/zone_layer/mod.rs index 1487ef7..20710b3 100644 --- a/emmarin/cl/cl/src/zone_layer/mod.rs +++ b/emmarin/cl/cl/src/zone_layer/mod.rs @@ -1,66 +1,3 @@ -use crate::cl::{merkle, Constraint, NoteCommitment, Nullifier}; -use serde::{Deserialize, Serialize}; - -pub struct ZoneNote { - pub stf: Constraint, - pub state: State, - pub ledger: Ledger, - pub id: [u8; 32], -} - -pub type State = [u8; 32]; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Ledger { - cm_root: [u8; 32], - nf_root: [u8; 32], -} - -pub type ZoneId = [u8; 32]; -pub struct StateWitness; - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct LedgerWitness { - pub commitments: Vec, - pub nullifiers: Vec, -} - -const MAX_COMM: usize = 256; -const MAX_NULL: usize = 256; - -impl LedgerWitness { - pub fn commit(&self) -> Ledger { - Ledger { - cm_root: self.cm_root(), - nf_root: self.nf_root(), - } - } - - pub fn nf_root(&self) -> [u8; 32] { - let bytes = self - .nullifiers - .iter() - .map(|i| i.as_bytes().to_vec()) - .collect::>(); - merkle::root(merkle::padded_leaves::(&bytes)) - } - - pub fn cm_root(&self) -> [u8; 32] { - let bytes = self - .commitments - .iter() - .map(|i| i.as_bytes().to_vec()) - .collect::>(); - merkle::root(merkle::padded_leaves::(&bytes)) - } - - pub fn cm_path(&self, cm: &NoteCommitment) -> Option> { - let bytes = self - .commitments - .iter() - .map(|i| i.as_bytes().to_vec()) - .collect::>(); - let leaves = merkle::padded_leaves::(&bytes); - let idx = self.commitments.iter().position(|c| c == cm)?; - Some(merkle::path(leaves, idx)) - } -} +pub mod ledger; +pub mod notes; +pub mod tx; diff --git a/emmarin/cl/cl/src/zone_layer/notes.rs b/emmarin/cl/cl/src/zone_layer/notes.rs new file mode 100644 index 0000000..8adf0e4 --- /dev/null +++ b/emmarin/cl/cl/src/zone_layer/notes.rs @@ -0,0 +1,14 @@ +use super::ledger::Ledger; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +pub struct ZoneNote { + pub stf: Stf, + pub state: State, + pub ledger: Ledger, + pub id: [u8; 32], +} + +pub type Stf = [u8; 32]; +pub type ZoneId = [u8; 32]; +pub type State = [u8; 32]; diff --git a/emmarin/cl/cl/src/zone_layer/tx.rs b/emmarin/cl/cl/src/zone_layer/tx.rs new file mode 100644 index 0000000..02bb511 --- /dev/null +++ b/emmarin/cl/cl/src/zone_layer/tx.rs @@ -0,0 +1,24 @@ +use super::notes::ZoneNote; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct UpdateBundle { + pub updates: Vec, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ZoneUpdate { + pub old: ZoneNote, + pub new: ZoneNote, +} + +impl ZoneUpdate { + pub fn new(old: ZoneNote, new: ZoneNote) -> Self { + assert_eq!(old.id, new.id); + Self { old, new } + } + + pub fn well_formed(&self) -> bool { + self.old.id == self.new.id + } +} diff --git a/emmarin/cl/ledger/src/ledger.rs b/emmarin/cl/ledger/src/ledger.rs index b955cc7..6fab328 100644 --- a/emmarin/cl/ledger/src/ledger.rs +++ b/emmarin/cl/ledger/src/ledger.rs @@ -7,7 +7,7 @@ use crate::{ pact::ProvedPact, partial_tx::ProvedPartialTx, }; -use cl::zone_layer::{LedgerWitness, ZoneId}; +use cl::zone_layer::{ledger::LedgerWitness, notes::ZoneId}; pub struct ProvedLedgerTransition { pub public: LedgerProofPublic, @@ -101,26 +101,7 @@ impl ProvedLedgerTransition { }) } - 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 = PtxPublic { - // ptx: self.ptx.clone(), - // cm_root: self.cm_root, - // from: self.from, - // to: self.to, - // }; - // if expected_ptx_inputs != proved_ptx_inputs { - // return false; - // } - - // let ptx_root = self.ptx.root(); - self.risc0_receipt .verify(ledger_validity_proof::LEDGER_ID) .is_ok() diff --git a/emmarin/cl/ledger/src/lib.rs b/emmarin/cl/ledger/src/lib.rs index e95c59c..93be05a 100644 --- a/emmarin/cl/ledger/src/lib.rs +++ b/emmarin/cl/ledger/src/lib.rs @@ -4,5 +4,7 @@ pub mod error; pub mod ledger; pub mod pact; pub mod partial_tx; +pub mod stf; +pub mod zone_update; pub use constraint::ConstraintProof; diff --git a/emmarin/cl/ledger/src/partial_tx.rs b/emmarin/cl/ledger/src/partial_tx.rs index 29a333a..6a1c614 100644 --- a/emmarin/cl/ledger/src/partial_tx.rs +++ b/emmarin/cl/ledger/src/partial_tx.rs @@ -2,7 +2,7 @@ use ledger_proof_statements::ptx::{PtxPrivate, PtxPublic}; use crate::error::{Error, Result}; use cl::cl::{merkle, PartialTx, PartialTxWitness}; -use cl::zone_layer::ZoneId; +use cl::zone_layer::notes::ZoneId; pub struct ProvedPartialTx { pub ptx: PartialTx, diff --git a/emmarin/cl/ledger/src/stf.rs b/emmarin/cl/ledger/src/stf.rs new file mode 100644 index 0000000..f416008 --- /dev/null +++ b/emmarin/cl/ledger/src/stf.rs @@ -0,0 +1,33 @@ +use cl::zone_layer::notes::Stf; +use ledger_proof_statements::stf::StfPublic; + +#[derive(Debug, Clone)] +pub struct StfProof { + pub risc0_id: [u32; 8], + pub public: StfPublic, + pub risc0_receipt: risc0_zkvm::Receipt, +} + +pub fn risc0_constraint(risc0_id: [u32; 8]) -> Stf { + // TODO: hash + + unsafe { core::mem::transmute::<[u32; 8], [u8; 32]>(risc0_id) } +} + +impl StfProof { + pub fn from_risc0(risc0_id: [u32; 8], risc0_receipt: risc0_zkvm::Receipt) -> Self { + Self { + risc0_id, + public: risc0_receipt.journal.decode().unwrap(), + risc0_receipt, + } + } + + pub fn stf(&self) -> Stf { + risc0_constraint(self.risc0_id) + } + + pub fn verify(&self) -> bool { + self.risc0_receipt.verify(self.risc0_id).is_ok() + } +} diff --git a/emmarin/cl/ledger/src/zone_update.rs b/emmarin/cl/ledger/src/zone_update.rs new file mode 100644 index 0000000..efcb251 --- /dev/null +++ b/emmarin/cl/ledger/src/zone_update.rs @@ -0,0 +1,103 @@ +pub use crate::error::{Error, Result}; +use crate::{ledger::ProvedLedgerTransition, stf::StfProof}; +use cl::zone_layer::tx::UpdateBundle; +use std::collections::HashSet; + +pub struct ProvedUpdateBundle { + pub bundle: UpdateBundle, + pub ledger_proofs: Vec, + pub stf_proofs: Vec, +} + +impl ProvedUpdateBundle { + // pub fn prove(bundle_witness: &BundleWitness) -> Result { + // // need to show that bundle is balanced. + // // i.e. the sum of ptx balances is 0 + + // let bundle_private = BundlePrivate { + // balances: bundle_witness + // .partials + // .iter() + // .map(|ptx| ptx.balance()) + // .collect(), + // }; + + // let env = risc0_zkvm::ExecutorEnv::builder() + // .write(&bundle_private) + // .unwrap() + // .build() + // .unwrap(); + + // let prover = risc0_zkvm::default_prover(); + + // let start_t = std::time::Instant::now(); + + // let opts = risc0_zkvm::ProverOpts::succinct(); + // let prove_info = prover + // .prove_with_opts(env, nomos_cl_risc0_proofs::BUNDLE_ELF, &opts) + // .map_err(|_| Error::Risc0ProofFailed)?; + + // println!( + // "STARK 'bundle' prover time: {:.2?}, total_cycles: {}", + // start_t.elapsed(), + // prove_info.stats.total_cycles + // ); + + // let receipt = prove_info.receipt; + + // Ok(Self { + // bundle: receipt.journal.decode()?, + // risc0_receipt: receipt, + // }) + // } + + pub fn verify(&self) -> bool { + let mut consumed_commitments = HashSet::new(); + let mut produced_commitments = HashSet::new(); + for proof in &self.ledger_proofs { + if !proof.verify() { + return false; + } + + for comm in &proof.public.cross_out { + if produced_commitments.insert(comm) { + // already in? + } + } + for comm in &proof.public.cross_in { + if consumed_commitments.insert(comm) { + // already in? + } + } + } + + // check that cross zone transactions match + if consumed_commitments != produced_commitments { + return false; + } + + for ((update, stf_proof), ledger_proof) in self + .bundle + .updates + .iter() + .zip(self.stf_proofs.iter()) + .zip(self.ledger_proofs.iter()) + { + if !update.well_formed() { + return false; + } + + if ledger_proof.public.old_ledger != update.old.ledger + || ledger_proof.public.ledger != update.new.ledger + { + return false; + } + + if stf_proof.public.old != update.old || stf_proof.public.new != update.new { + return false; + } + } + + true + } +} diff --git a/emmarin/cl/ledger_proof_statements/src/ledger.rs b/emmarin/cl/ledger_proof_statements/src/ledger.rs index 04700fd..ed3d728 100644 --- a/emmarin/cl/ledger_proof_statements/src/ledger.rs +++ b/emmarin/cl/ledger_proof_statements/src/ledger.rs @@ -2,11 +2,15 @@ use crate::bundle::BundlePublic; use crate::pact::PactPublic; use crate::ptx::PtxPublic; use cl::cl::Output; -use cl::zone_layer::*; +use cl::zone_layer::{ + ledger::{Ledger, LedgerWitness}, + notes::ZoneId, +}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct LedgerProofPublic { + pub old_ledger: Ledger, pub ledger: Ledger, pub id: ZoneId, pub cross_in: Vec, diff --git a/emmarin/cl/ledger_proof_statements/src/lib.rs b/emmarin/cl/ledger_proof_statements/src/lib.rs index 12c64c5..fa0941c 100644 --- a/emmarin/cl/ledger_proof_statements/src/lib.rs +++ b/emmarin/cl/ledger_proof_statements/src/lib.rs @@ -3,3 +3,4 @@ pub mod constraint; pub mod ledger; pub mod pact; pub mod ptx; +pub mod stf; diff --git a/emmarin/cl/ledger_proof_statements/src/stf.rs b/emmarin/cl/ledger_proof_statements/src/stf.rs new file mode 100644 index 0000000..22eb9cc --- /dev/null +++ b/emmarin/cl/ledger_proof_statements/src/stf.rs @@ -0,0 +1,8 @@ +use cl::zone_layer::notes::ZoneNote; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +pub struct StfPublic { + pub old: ZoneNote, + pub new: ZoneNote, +} diff --git a/emmarin/cl/ledger_validity_proof/ledger/src/main.rs b/emmarin/cl/ledger_validity_proof/ledger/src/main.rs index 06cedcb..55bf280 100644 --- a/emmarin/cl/ledger_validity_proof/ledger/src/main.rs +++ b/emmarin/cl/ledger_validity_proof/ledger/src/main.rs @@ -1,4 +1,7 @@ -use cl::{zones::*, Output}; +use cl::{ + cl::Output, + zone_layer::{ledger::LedgerWitness, notes::ZoneId}, +}; use ledger_proof_statements::{bundle::*, constraint::*, ledger::*, pact::PactPublic, ptx::*}; use risc0_zkvm::{guest::env, serde}; @@ -9,6 +12,8 @@ fn main() { txs, } = env::read(); + let old_ledger = ledger.commit(); + let cm_root = ledger.cm_root(); let mut cross_in = vec![]; @@ -30,6 +35,7 @@ fn main() { } env::commit(&LedgerProofPublic { + old_ledger, ledger: ledger.commit(), id, cross_in,