rework PACT recursion

This commit is contained in:
David Rusu 2024-12-09 15:23:43 +04:00
parent baaf10a429
commit 98f0a3b752
32 changed files with 367 additions and 327 deletions

1
emmarin/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*profile.pb

View File

@ -1,6 +1,14 @@
[workspace]
resolver = "2"
members = [ "cl", "ledger", "ledger_proof_statements", "risc0_proofs", "ledger_validity_proof"]
members = [
"cl",
"ledger",
"ledger_proof_statements",
"risc0_proofs",
"bundle_risc0_proof",
"ptx_risc0_proof",
"ledger_validity_proof"
]
# Always optimize; building and running the risc0_proofs takes much longer without optimization.
[profile.dev]

View File

@ -0,0 +1,11 @@
[package]
name = "nomos_cl_bundle_risc0_proof"
version = "0.1.0"
edition = "2021"
[build-dependencies]
risc0-build = { version = "1.0" }
[package.metadata.risc0]
methods = ["bundle"]

View File

@ -0,0 +1,3 @@
fn main() {
risc0_build::embed_methods();
}

View File

@ -1,5 +1,5 @@
[package]
name = "balance"
name = "bundle"
version = "0.1.0"
edition = "2021"
@ -10,6 +10,7 @@ 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" }
nomos_cl_ptx_risc0_proof = { path = "../../ptx_risc0_proof" }
[patch.crates-io]

View File

@ -0,0 +1,49 @@
use cl::cl::BalanceWitness;
use cl::zone_layer::notes::ZoneId;
use ledger_proof_statements::bundle::{BundlePrivate, BundlePublic, LedgerUpdate};
use risc0_zkvm::{guest::env, serde};
use std::collections::BTreeMap;
fn main() {
let bundle_private: BundlePrivate = env::read();
let bundle_id = bundle_private.id();
let BundlePrivate { bundle, balances } = bundle_private;
assert_eq!(bundle.len(), balances.len());
let mut zone_ledger_updates: BTreeMap<ZoneId, LedgerUpdate> = BTreeMap::new();
for (ptx_public, balance) in bundle.into_iter().zip(balances.iter()) {
assert_eq!(ptx_public.ptx.balance, balance.commit());
env::verify(
nomos_cl_ptx_risc0_proof::PTX_ID,
&serde::to_vec(&ptx_public).unwrap(),
)
.unwrap();
for (input, cm_mmr) in ptx_public.ptx.inputs.iter().zip(ptx_public.cm_mmrs) {
let zone_ledger_update = zone_ledger_updates.entry(input.zone_id).or_default();
zone_ledger_update.nullifiers.push(input.nullifier);
zone_ledger_update
.cm_roots
.extend(cm_mmr.roots.iter().map(|r| r.root));
}
for output in &ptx_public.ptx.outputs {
zone_ledger_updates
.entry(output.zone_id)
.or_default()
.commitments
.push(output.note_comm);
}
}
assert!(BalanceWitness::combine(balances, [0u8; 16]).is_zero());
env::commit(&BundlePublic {
bundle_id,
zone_ledger_updates,
});
}

View File

@ -0,0 +1 @@
include!(concat!(env!("OUT_DIR"), "/methods.rs"));

View File

@ -1,45 +1,41 @@
use serde::{Deserialize, Serialize};
use crate::{cl::partial_tx::PartialTx, zone_layer::notes::ZoneId};
use sha2::{Digest, Sha256};
use std::collections::HashSet;
use crate::cl::partial_tx::PartialTx;
/// The transaction bundle is a collection of partial transactions.
/// The goal in bundling transactions is to produce a set of partial transactions
/// that balance each other.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BundleId(pub [u8; 32]);
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Bundle {
pub partials: Vec<PartialTx>,
}
impl Bundle {
pub fn zones(&self) -> HashSet<ZoneId> {
self.partials
.iter()
.flat_map(|ptx| {
ptx.inputs
.iter()
.map(|i| i.zone_id)
.chain(ptx.outputs.iter().map(|o| o.zone_id))
})
.collect()
}
// impl Bundle {
// pub fn zones(&self) -> BTreeSet<ZoneId> {
// self.partials
// .iter()
// .flat_map(|ptx| {
// ptx.inputs
// .iter()
// .map(|i| i.zone_id)
// .chain(ptx.outputs.iter().map(|o| o.zone_id))
// })
// .collect()
// }
pub fn id(&self) -> BundleId {
// TODO: change to merkle root
let mut hasher = Sha256::new();
hasher.update(b"NOMOS_CL_BUNDLE_ID");
for ptx in &self.partials {
hasher.update(ptx.root().0);
}
// // TODO: remove this
// pub fn id(&self) -> BundleId {
// // TODO: change to merkle root
// let mut hasher = Sha256::new();
// hasher.update(b"NOMOS_CL_BUNDLE_ID");
// for ptx in &self.partials {
// hasher.update(ptx.root().0);
// }
BundleId(hasher.finalize().into())
}
}
// BundleId(hasher.finalize().into())
// }
// }
#[cfg(test)]
mod test {

View File

@ -27,7 +27,15 @@ impl LedgerWitness {
}
}
pub fn assert_nf_update(&mut self, nf: Nullifier, path: &[merkle::PathNode]) {
pub fn valid_cm_root(&self, root: [u8; 32]) -> bool {
self.commitments.roots.iter().any(|r| r.root == root)
}
pub fn add_commitment(&mut self, cm: &NoteCommitment) {
self.commitments.push(&cm.0);
}
pub fn assert_nf_update(&mut self, nf: &Nullifier, path: &[merkle::PathNode]) {
// verify that the path corresponds to the nullifier
assert_eq!(sparse_merkle::path_key(path), nf.0);
@ -57,7 +65,7 @@ impl LedgerState {
sparse_merkle::sparse_root(&self.nullifiers)
}
pub fn add_commitment(&mut self, cm: NoteCommitment) -> MMRProof {
pub fn add_commitment(&mut self, cm: &NoteCommitment) -> MMRProof {
self.commitments.push(&cm.0)
}

View File

@ -7,6 +7,8 @@ edition = "2021"
cl = { path = "../cl" }
ledger_proof_statements = { path = "../ledger_proof_statements" }
nomos_cl_risc0_proofs = { path = "../risc0_proofs" }
nomos_cl_bundle_risc0_proof = { path = "../bundle_risc0_proof" }
nomos_cl_ptx_risc0_proof = { path = "../ptx_risc0_proof" }
ledger_validity_proof = { path = "../ledger_validity_proof" }
risc0-zkvm = { version = "1.0", features = ["prove", "metal"] }
risc0-groth16 = { version = "1.0" }

View File

@ -1,57 +0,0 @@
use crate::error::{Error, Result};
use ledger_proof_statements::balance::{BalancePrivate, BalancePublic};
#[derive(Debug, Clone)]
pub struct ProvedBalance {
pub bundle: BalancePublic,
pub risc0_receipt: risc0_zkvm::Receipt,
}
impl ProvedBalance {
pub fn prove(balance_witness: &BalancePrivate) -> Result<Self> {
//show that the sum of ptx balances is 0
let env = risc0_zkvm::ExecutorEnv::builder()
.write(&balance_witness)
.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::BALANCE_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 public(&self) -> Result<ledger_proof_statements::balance::BalancePublic> {
Ok(self.risc0_receipt.journal.decode()?)
}
pub fn verify(&self) -> bool {
// let Ok(_bundle_public) = self.public() else {
// return false;
// };
// Vec::from_iter(self.bundle.partials.iter().map(|ptx| ptx.balance)) == bundle_public.balances
// &&
self.risc0_receipt
.verify(nomos_cl_risc0_proofs::BALANCE_ID)
.is_ok()
}
}

View File

@ -0,0 +1,52 @@
use ledger_proof_statements::bundle::{BundlePrivate, BundlePublic};
use crate::partial_tx::ProvedPartialTx;
#[derive(Debug, Clone)]
pub struct ProvedBundle {
pub risc0_receipt: risc0_zkvm::Receipt,
}
impl ProvedBundle {
pub fn prove(bundle: &BundlePrivate, partials: Vec<ProvedPartialTx>) -> Self {
//show that all ptx's are individually valid, and balance to 0
let mut env = risc0_zkvm::ExecutorEnv::builder();
for proved_ptx in partials {
env.add_assumption(proved_ptx.risc0_receipt);
}
let env = env.write(&bundle).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_bundle_risc0_proof::BUNDLE_ELF, &opts)
.unwrap();
println!(
"STARK 'bundle' prover time: {:.2?}, total_cycles: {}",
start_t.elapsed(),
prove_info.stats.total_cycles
);
let receipt = prove_info.receipt;
Self {
risc0_receipt: receipt,
}
}
pub fn public(&self) -> BundlePublic {
self.risc0_receipt.journal.decode().unwrap()
}
pub fn verify(&self) -> bool {
self.risc0_receipt
.verify(nomos_cl_bundle_risc0_proof::BUNDLE_ID)
.is_ok()
}
}

View File

@ -1,80 +1,66 @@
use ledger_proof_statements::ledger::{
LedgerBundleWitness, LedgerProofPrivate, LedgerProofPublic, LedgerPtxWitness,
};
use std::collections::BTreeMap;
use crate::{
balance::ProvedBalance,
constraint::ConstraintProof,
error::{Error, Result},
partial_tx::ProvedPartialTx,
};
use ledger_proof_statements::ledger::{LedgerBundleWitness, LedgerProofPrivate, LedgerProofPublic};
use crate::bundle::ProvedBundle;
use cl::zone_layer::{ledger::LedgerState, notes::ZoneId};
#[derive(Debug, Clone)]
pub struct ProvedLedgerTransition {
pub public: LedgerProofPublic,
pub risc0_receipt: risc0_zkvm::Receipt,
}
// TODO: find a better name
#[derive(Debug, Clone)]
pub struct ProvedBundle {
pub balance: ProvedBalance,
pub ptxs: Vec<ProvedPartialTx>,
}
impl ProvedBundle {
fn proofs(&self) -> Vec<risc0_zkvm::Receipt> {
let mut proofs = vec![self.balance.risc0_receipt.clone()];
proofs.extend(self.ptxs.iter().map(|p| p.risc0_receipt.clone()));
proofs
}
}
impl ProvedLedgerTransition {
pub fn prove(
mut ledger: LedgerState,
zone_id: ZoneId,
bundles: Vec<ProvedBundle>,
constraints: Vec<ConstraintProof>,
) -> Result<Self> {
pub fn prove(mut ledger: LedgerState, zone_id: ZoneId, bundles: Vec<ProvedBundle>) -> Self {
let mut witness = LedgerProofPrivate {
bundles: Vec::new(),
ledger: ledger.to_witness(),
id: zone_id,
};
let mut env = risc0_zkvm::ExecutorEnv::builder();
// prepare the sparse merkle tree nullifier proofs
for bundle in &bundles {
let mut partials = Vec::new();
for proved_bundle in &bundles {
env.add_assumption(proved_bundle.risc0_receipt.clone());
let bundle = proved_bundle.public();
println!("OUTSIDE LEDGER_PROOF {:?}", bundle);
println!("BUNDLE_ID {:?}", nomos_cl_bundle_risc0_proof::BUNDLE_ID);
let zone_ledger_update = bundle
.zone_ledger_updates
.get(&zone_id)
.expect("why are we proving this bundle for this zone if it's not involved?");
let cm_root_proofs =
BTreeMap::from_iter(zone_ledger_update.cm_roots.iter().map(|root| {
// We make the simplifying assumption that bundle proofs
// are done w.r.t. the latest MMR (hence, empty merkle proofs)
//
// We can remove this assumption by tracking old MMR roots in the LedgerState
(*root, vec![])
}));
for ptx in &bundle.ptxs {
let mut nf_proofs = Vec::new();
for input in &ptx.public.ptx.inputs {
let nf_proof = ledger.add_nullifier(input.nullifier);
for nf in &zone_ledger_update.nullifiers {
let nf_proof = ledger.add_nullifier(*nf);
nf_proofs.push(nf_proof);
}
partials.push(LedgerPtxWitness {
ptx: ptx.public.clone(),
for cm in &zone_ledger_update.commitments {
ledger.add_commitment(cm);
}
let ledger_bundle = LedgerBundleWitness {
bundle,
cm_root_proofs,
nf_proofs,
});
};
witness.bundles.push(ledger_bundle)
}
witness.bundles.push(LedgerBundleWitness { partials })
}
let mut env = risc0_zkvm::ExecutorEnv::builder();
for bundle in bundles {
for proof in bundle.proofs() {
env.add_assumption(proof);
}
}
for covenant in constraints {
env.add_assumption(covenant.risc0_receipt);
}
let env = env.write(&witness).unwrap().build().unwrap();
// Obtain the default prover.
@ -87,10 +73,7 @@ impl ProvedLedgerTransition {
let opts = risc0_zkvm::ProverOpts::succinct();
let prove_info = prover
.prove_with_opts(env, ledger_validity_proof::LEDGER_ELF, &opts)
.map_err(|e| {
eprintln!("{e}");
Error::Risc0ProofFailed
})?;
.unwrap();
println!(
"STARK 'ledger' prover time: {:.2?}, total_cycles: {}",
@ -98,14 +81,16 @@ impl ProvedLedgerTransition {
prove_info.stats.total_cycles
);
Ok(Self {
public: prove_info
.receipt
Self {
risc0_receipt: prove_info.receipt,
}
}
pub fn public(&self) -> LedgerProofPublic {
self.risc0_receipt
.journal
.decode::<LedgerProofPublic>()
.unwrap(),
risc0_receipt: prove_info.receipt,
})
.unwrap()
}
pub fn verify(&self) -> bool {

View File

@ -1,4 +1,4 @@
pub mod balance;
pub mod bundle;
pub mod constraint;
pub mod error;
pub mod ledger;

View File

@ -11,7 +11,6 @@ use cl::cl::{
#[derive(Debug, Clone)]
pub struct ProvedPartialTx {
pub public: PtxPublic,
pub risc0_receipt: risc0_zkvm::Receipt,
}
@ -42,7 +41,7 @@ impl ProvedPartialTx {
// 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::PTX_ELF, &opts)
.prove_with_opts(env, nomos_cl_ptx_risc0_proof::PTX_ELF, &opts)
.map_err(|_| Error::Risc0ProofFailed)?;
println!(
@ -52,14 +51,17 @@ impl ProvedPartialTx {
);
Ok(Self {
public: prove_info.receipt.journal.decode()?,
risc0_receipt: prove_info.receipt,
})
}
pub fn public(&self) -> PtxPublic {
self.risc0_receipt.journal.decode().unwrap()
}
pub fn verify(&self) -> bool {
self.risc0_receipt
.verify(nomos_cl_risc0_proofs::PTX_ID)
.verify(nomos_cl_ptx_risc0_proof::PTX_ID)
.is_ok()
}
}

View File

@ -18,12 +18,12 @@ impl ProvedUpdateBundle {
return false;
}
for bundle in &proof.public.cross_bundles {
for bundle in &proof.public().cross_bundles {
expected_zones.insert(bundle.id, HashSet::from_iter(bundle.zones.clone()));
actual_zones
.entry(bundle.id)
.or_insert_with(HashSet::new)
.insert(proof.public.id);
.insert(proof.public().id);
}
}
@ -48,8 +48,8 @@ impl ProvedUpdateBundle {
return false;
}
if ledger_proof.public.old_ledger != update.old.ledger
|| ledger_proof.public.ledger != update.new.ledger
if ledger_proof.public().old_ledger != update.old.ledger
|| ledger_proof.public().ledger != update.new.ledger
{
return false;
}

View File

@ -13,14 +13,10 @@ use cl::{
},
};
use ledger::{
balance::ProvedBalance,
constraint::ConstraintProof,
ledger::{ProvedBundle, ProvedLedgerTransition},
partial_tx::ProvedPartialTx,
stf::StfProof,
zone_update::ProvedUpdateBundle,
bundle::ProvedBundle, constraint::ConstraintProof, ledger::ProvedLedgerTransition,
partial_tx::ProvedPartialTx, stf::StfProof, zone_update::ProvedUpdateBundle,
};
use ledger_proof_statements::{balance::BalancePrivate, stf::StfPublic};
use ledger_proof_statements::{bundle::BundlePrivate, stf::StfPublic};
use rand_core::CryptoRngCore;
use std::sync::OnceLock;
@ -89,38 +85,32 @@ fn cross_transfer_transition(
)
.unwrap();
let balance = ProvedBalance::prove(&BalancePrivate {
let bundle = ProvedBundle::prove(
&BundlePrivate {
bundle: vec![proved_ptx.public()],
balances: vec![ptx_witness.balance()],
})
.unwrap();
},
vec![proved_ptx],
);
let zone_tx = ProvedBundle {
ptxs: vec![proved_ptx.clone()],
balance,
};
println!("proving ledger A transition");
let ledger_a_transition =
ProvedLedgerTransition::prove(ledger_a.clone(), zone_a, vec![bundle.clone()]);
let ledger_a_transition = ProvedLedgerTransition::prove(
ledger_a.clone(),
zone_a,
vec![zone_tx.clone()],
vec![constraint_proof],
)
.unwrap();
println!("proving ledger B transition");
let ledger_b_transition = ProvedLedgerTransition::prove(ledger_b.clone(), zone_b, vec![bundle]);
let ledger_b_transition =
ProvedLedgerTransition::prove(ledger_b.clone(), zone_b, vec![zone_tx], vec![]).unwrap();
ledger_a.add_commitment(change.commit_note());
ledger_a.add_commitment(&change.commit_note());
ledger_a.add_nullifier(input.nullifier());
ledger_b.add_commitment(transfer.commit_note());
ledger_b.add_commitment(&transfer.commit_note());
assert_eq!(
ledger_a_transition.public.ledger,
ledger_a_transition.public().ledger,
ledger_a.to_witness().commit()
);
assert_eq!(
ledger_b_transition.public.ledger,
ledger_b_transition.public().ledger,
ledger_b.to_witness().commit()
);
@ -149,7 +139,7 @@ fn zone_update_cross() {
let alice_input = InputWitness::from_output(utxo, alice.sk());
let mut ledger_a = LedgerState::default();
let alice_cm_path = ledger_a.add_commitment(utxo.commit_note());
let alice_cm_path = ledger_a.add_commitment(&utxo.commit_note());
let alice_cm_proof = (ledger_a.commitments.clone(), alice_cm_path);
let ledger_b = LedgerState::default();
@ -179,12 +169,12 @@ fn zone_update_cross() {
);
let zone_a_new = ZoneNote {
ledger: ledger_a_transition.public.ledger,
ledger: ledger_a_transition.public().ledger,
..zone_a_old
};
let zone_b_new = ZoneNote {
ledger: ledger_b_transition.public.ledger,
ledger: ledger_b_transition.public().ledger,
..zone_b_old
};

View File

@ -6,3 +6,4 @@ edition = "2021"
[dependencies]
cl = { path = "../cl" }
serde = { version = "1.0", features = ["derive"] }
sha2 = "0.10"

View File

@ -1,12 +0,0 @@
use cl::cl::{Balance, BalanceWitness};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BalancePublic {
pub balances: Vec<Balance>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BalancePrivate {
pub balances: Vec<BalanceWitness>,
}

View File

@ -0,0 +1,48 @@
use std::collections::{BTreeMap, BTreeSet};
use cl::{
cl::{BalanceWitness, NoteCommitment, Nullifier},
zone_layer::notes::ZoneId,
};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use crate::ptx::PtxPublic;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BundleId(pub [u8; 32]);
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BundlePublic {
pub bundle_id: BundleId,
pub zone_ledger_updates: BTreeMap<ZoneId, LedgerUpdate>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct LedgerUpdate {
// inputs in this bundle used the following roots in their cm membership proof.
pub cm_roots: BTreeSet<[u8; 32]>,
// these are the nullifiers of inputs used in this bundle.
pub nullifiers: Vec<Nullifier>,
// these are commitments to created notes in this bundle
pub commitments: Vec<NoteCommitment>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BundlePrivate {
pub bundle: Vec<PtxPublic>,
pub balances: Vec<BalanceWitness>,
}
impl BundlePrivate {
pub fn id(&self) -> BundleId {
// TODO: change to merkle root
let mut hasher = Sha256::new();
hasher.update(b"NOMOS_CL_BUNDLE_ID");
for ptx in &self.bundle {
hasher.update(ptx.ptx.root().0);
}
BundleId(hasher.finalize().into())
}
}

View File

@ -1,6 +1,8 @@
use crate::ptx::PtxPublic;
use cl::cl::merkle;
use cl::cl::{bundle::BundleId, Output};
use std::collections::BTreeMap;
use crate::bundle::BundleId;
use crate::bundle::BundlePublic;
use cl::cl::{merkle, NoteCommitment};
use cl::zone_layer::{
ledger::{Ledger, LedgerWitness},
notes::ZoneId,
@ -13,7 +15,7 @@ pub struct LedgerProofPublic {
pub ledger: Ledger,
pub id: ZoneId,
pub cross_bundles: Vec<CrossZoneBundle>,
pub outputs: Vec<Output>,
pub outputs: Vec<NoteCommitment>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -25,12 +27,8 @@ pub struct LedgerProofPrivate {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LedgerBundleWitness {
pub partials: Vec<LedgerPtxWitness>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LedgerPtxWitness {
pub ptx: PtxPublic,
pub bundle: BundlePublic,
pub cm_root_proofs: BTreeMap<[u8; 32], merkle::Path>,
pub nf_proofs: Vec<merkle::Path>,
}

View File

@ -1,4 +1,4 @@
pub mod balance;
pub mod bundle;
pub mod constraint;
pub mod ledger;
pub mod ptx;

View File

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PtxPublic {
pub ptx: PartialTx,
pub cm_mmr: Vec<MMR>,
pub cm_mmrs: Vec<MMR>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]

View File

@ -10,7 +10,7 @@ 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" }
nomos_cl_risc0_proofs = { path = "../../risc0_proofs" }
nomos_cl_bundle_risc0_proof = { path = "../../bundle_risc0_proof" }
[patch.crates-io]
# add RISC Zero accelerator support for all downstream usages of the following crates.

View File

@ -1,10 +1,6 @@
use cl::{
cl::{Bundle, Output},
zone_layer::{ledger::LedgerWitness, notes::ZoneId},
};
use cl::cl::merkle;
use ledger_proof_statements::{
balance::BalancePublic,
ledger::{CrossZoneBundle, LedgerProofPrivate, LedgerProofPublic, LedgerPtxWitness},
ledger::{CrossZoneBundle, LedgerProofPrivate, LedgerProofPublic, LedgerBundleWitness},
};
use risc0_zkvm::{guest::env, serde};
@ -15,82 +11,44 @@ fn main() {
bundles,
} = env::read();
let old_ledger = ledger.commit();
let old_ledger = ledger.clone();
let mut cross_bundles = vec![];
let mut outputs = vec![];
for bundle in bundles {
let balance_public = BalancePublic {
balances: bundle.partials.iter().map(|bundle_ptx| bundle_ptx.ptx.ptx.balance).collect::<Vec<_>>(),
};
for LedgerBundleWitness { bundle, cm_root_proofs, nf_proofs } in bundles {
println!("IN LEDGER PROOF {:?}", bundle);
println!("BUNDLE_ID {:?}", nomos_cl_bundle_risc0_proof::BUNDLE_ID);
env::verify(nomos_cl_bundle_risc0_proof::BUNDLE_ID, &serde::to_vec(&bundle).unwrap()).unwrap();
// verify bundle is balanced
env::verify(
nomos_cl_risc0_proofs::BALANCE_ID,
&serde::to_vec(&balance_public).unwrap(),
)
.unwrap();
for ptx in &bundle.partials {
let ptx_outputs = process_ptx(&mut ledger, ptx, id);
outputs.extend(ptx_outputs);
if let Some(ledger_update) = bundle.zone_ledger_updates.get(&id) {
for past_cm_root in &ledger_update.cm_roots {
let past_cm_root_proof = cm_root_proofs.get(past_cm_root).expect("missing cm root proof");
let expected_current_cm_root = merkle::path_root(*past_cm_root, past_cm_root_proof);
assert!(old_ledger.valid_cm_root(expected_current_cm_root))
}
assert_eq!(ledger_update.nullifiers.len(), nf_proofs.len());
for (nf, nf_proof) in ledger_update.nullifiers.iter().zip(nf_proofs) {
ledger.assert_nf_update(nf, &nf_proof);
}
for cm in &ledger_update.commitments {
ledger.add_commitment(cm);
outputs.push(*cm)
}
}
let bundle = Bundle {
partials: bundle.partials.into_iter().map(|ptx_witness| ptx_witness.ptx.ptx).collect(),
};
let zones = bundle.zones();
if zones.len() > 1 {
cross_bundles.push(CrossZoneBundle {
id: bundle.id(),
zones: zones.into_iter().collect(),
id: bundle.bundle_id,
zones: bundle.zone_ledger_updates.into_keys().collect(),
});
}
}
env::commit(&LedgerProofPublic {
old_ledger,
old_ledger: old_ledger.commit(),
ledger: ledger.commit(),
id,
cross_bundles,
outputs,
});
}
fn process_ptx(
ledger: &mut LedgerWitness,
ptx_witness: &LedgerPtxWitness,
zone_id: ZoneId,
) -> Vec<Output> {
let ptx = &ptx_witness.ptx;
let nf_proofs = &ptx_witness.nf_proofs;
// always verify the ptx to ensure outputs were derived with the correct zone id
env::verify(nomos_cl_risc0_proofs::PTX_ID, &serde::to_vec(&ptx).unwrap()).unwrap();
assert_eq!(ptx.ptx.inputs.len(), nf_proofs.len());
assert_eq!(ptx.ptx.inputs.len(), ptx.cm_mmr.len());
for ((input, nf_proof), cm_mmr) in ptx.ptx.inputs.iter().zip(nf_proofs).zip(ptx.cm_mmr.iter()) {
if input.zone_id != zone_id {
continue;
}
assert_eq!(cm_mmr, &ledger.commitments); // we force commitment proofs w.r.t. latest MMR
ledger.assert_nf_update(input.nullifier, nf_proof);
}
let mut outputs = vec![];
for output in &ptx.ptx.outputs {
if output.zone_id != zone_id {
continue;
}
ledger.commitments.push(&output.note_comm.0);
outputs.push(*output);
}
outputs
}

View File

@ -0,0 +1,11 @@
[package]
name = "nomos_cl_ptx_risc0_proof"
version = "0.1.0"
edition = "2021"
[build-dependencies]
risc0-build = { version = "1.0" }
[package.metadata.risc0]
methods = ["ptx"]

View File

@ -0,0 +1,3 @@
fn main() {
risc0_build::embed_methods();
}

View File

@ -1,6 +1,9 @@
/// Input Proof
use ledger_proof_statements::{constraint::ConstraintPublic, ptx::{PtxPrivate, PtxPublic}};
use risc0_zkvm::{serde, guest::env};
use ledger_proof_statements::{
constraint::ConstraintPublic,
ptx::{PtxPrivate, PtxPublic},
};
use risc0_zkvm::{guest::env, serde};
fn main() {
let PtxPrivate {
@ -12,20 +15,21 @@ fn main() {
let ptx_root = ptx_commit.root();
assert_eq!(ptx.inputs.len(), input_cm_proofs.len());
let mut cm_mmr = Vec::new();
let mut cm_mmrs = Vec::new();
for (input, (mmr, mmr_proof)) in ptx.inputs.iter().zip(input_cm_proofs) {
let note_cm = input.note_commitment();
assert!(mmr.verify_proof(&note_cm.0, &mmr_proof));
cm_mmr.push(mmr);
cm_mmrs.push(mmr);
env::verify(
input.note.constraint.0,
&serde::to_vec(&ConstraintPublic {
ptx_root,
nf: input.nullifier(),
}).unwrap(),
).unwrap();
})
.unwrap(),
)
.unwrap();
}
for output in ptx.outputs.iter() {
@ -34,6 +38,6 @@ fn main() {
env::commit(&PtxPublic {
ptx: ptx_commit,
cm_mmr,
cm_mmrs,
});
}

View File

@ -0,0 +1 @@
include!(concat!(env!("OUT_DIR"), "/methods.rs"));

View File

@ -7,5 +7,5 @@ edition = "2021"
risc0-build = { version = "1.0" }
[package.metadata.risc0]
methods = ["balance", "constraint_nop", "ptx", "stf_nop"]
methods = ["constraint_nop", "stf_nop"]

View File

@ -1,24 +0,0 @@
use cl::cl::BalanceWitness;
/// Bundle Proof
///
/// The bundle proof demonstrates that the set of partial transactions
/// balance to zero. i.e. \sum inputs = \sum outputs.
///
/// This is done by proving knowledge of some blinding factor `r` s.t.
/// \sum outputs - \sum input = 0*G + r*H
///
/// To avoid doing costly ECC in stark, we compute only the RHS in stark.
/// The sums and equality is checked outside of stark during proof verification.
use risc0_zkvm::guest::env;
fn main() {
let balance_private: ledger_proof_statements::balance::BalancePrivate = env::read();
let balance_public = ledger_proof_statements::balance::BalancePublic {
balances: Vec::from_iter(balance_private.balances.iter().map(|b| b.commit())),
};
assert!(BalanceWitness::combine(balance_private.balances, [0u8; 16]).is_zero());
env::commit(&balance_public);
}