rework PACT recursion
This commit is contained in:
parent
baaf10a429
commit
98f0a3b752
|
@ -0,0 +1 @@
|
|||
*profile.pb
|
|
@ -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]
|
||||
|
|
|
@ -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"]
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
risc0_build::embed_methods();
|
||||
}
|
|
@ -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]
|
|
@ -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,
|
||||
});
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
include!(concat!(env!("OUT_DIR"), "/methods.rs"));
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
};
|
||||
|
||||
// prepare the sparse merkle tree nullifier proofs
|
||||
for bundle in &bundles {
|
||||
let mut partials = Vec::new();
|
||||
|
||||
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);
|
||||
nf_proofs.push(nf_proof);
|
||||
}
|
||||
|
||||
partials.push(LedgerPtxWitness {
|
||||
ptx: ptx.public.clone(),
|
||||
nf_proofs,
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
// prepare the sparse merkle tree nullifier proofs
|
||||
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![])
|
||||
}));
|
||||
|
||||
let mut nf_proofs = Vec::new();
|
||||
for nf in &zone_ledger_update.nullifiers {
|
||||
let nf_proof = ledger.add_nullifier(*nf);
|
||||
nf_proofs.push(nf_proof);
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
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
|
||||
.journal
|
||||
.decode::<LedgerProofPublic>()
|
||||
.unwrap(),
|
||||
Self {
|
||||
risc0_receipt: prove_info.receipt,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn public(&self) -> LedgerProofPublic {
|
||||
self.risc0_receipt
|
||||
.journal
|
||||
.decode::<LedgerProofPublic>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn verify(&self) -> bool {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pub mod balance;
|
||||
pub mod bundle;
|
||||
pub mod constraint;
|
||||
pub mod error;
|
||||
pub mod ledger;
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
balances: vec![ptx_witness.balance()],
|
||||
})
|
||||
.unwrap();
|
||||
let bundle = ProvedBundle::prove(
|
||||
&BundlePrivate {
|
||||
bundle: vec![proved_ptx.public()],
|
||||
balances: vec![ptx_witness.balance()],
|
||||
},
|
||||
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
|
||||
};
|
||||
|
||||
|
|
|
@ -6,3 +6,4 @@ edition = "2021"
|
|||
[dependencies]
|
||||
cl = { path = "../cl" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
sha2 = "0.10"
|
||||
|
|
|
@ -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>,
|
||||
}
|
|
@ -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())
|
||||
}
|
||||
}
|
|
@ -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>,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pub mod balance;
|
||||
pub mod bundle;
|
||||
pub mod constraint;
|
||||
pub mod ledger;
|
||||
pub mod ptx;
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
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))
|
||||
}
|
||||
|
||||
for ptx in &bundle.partials {
|
||||
let ptx_outputs = process_ptx(&mut ledger, ptx, id);
|
||||
outputs.extend(ptx_outputs);
|
||||
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(),
|
||||
});
|
||||
}
|
||||
cross_bundles.push(CrossZoneBundle {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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"]
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
risc0_build::embed_methods();
|
||||
}
|
|
@ -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(¬e_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,
|
||||
});
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
include!(concat!(env!("OUT_DIR"), "/methods.rs"));
|
|
@ -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"]
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue