mirror of
https://github.com/logos-co/nomos-pocs.git
synced 2025-02-17 19:57:16 +00:00
uniform ptx and pacts
This commit is contained in:
parent
a940705b01
commit
a76bb268a1
@ -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
|
/// The goal in bundling transactions is to produce a set of partial transactions
|
||||||
/// that balance each other.
|
/// that balance each other.
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Bundle {
|
pub struct Bundle {
|
||||||
pub partials: Vec<PartialTx>,
|
pub partials: Vec<PartialTx>,
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@ impl BundleWitness {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{
|
use crate::cl::{
|
||||||
balance::UnitBalance,
|
balance::UnitBalance,
|
||||||
input::InputWitness,
|
input::InputWitness,
|
||||||
note::{derive_unit, NoteWitness},
|
note::{derive_unit, NoteWitness},
|
||||||
|
@ -2,10 +2,13 @@
|
|||||||
///
|
///
|
||||||
/// Partial transactions, as the name suggests, are transactions
|
/// Partial transactions, as the name suggests, are transactions
|
||||||
/// which on their own may not balance (i.e. \sum inputs != \sum outputs)
|
/// which on their own may not balance (i.e. \sum inputs != \sum outputs)
|
||||||
use crate::cl::{
|
use crate::{
|
||||||
note::{Constraint, NoteWitness},
|
cl::{
|
||||||
nullifier::{Nullifier, NullifierSecret},
|
note::{Constraint, NoteWitness},
|
||||||
Nonce, NoteCommitment, OutputWitness,
|
nullifier::{Nullifier, NullifierSecret},
|
||||||
|
Nonce, NoteCommitment, OutputWitness,
|
||||||
|
},
|
||||||
|
zone_layer::notes::ZoneId,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
@ -14,6 +17,7 @@ use sha2::{Digest, Sha256};
|
|||||||
pub struct Input {
|
pub struct Input {
|
||||||
pub nullifier: Nullifier,
|
pub nullifier: Nullifier,
|
||||||
pub constraint: Constraint,
|
pub constraint: Constraint,
|
||||||
|
pub zone_id: ZoneId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
@ -63,10 +67,11 @@ impl InputWitness {
|
|||||||
Nullifier::new(tag, self.nf_sk, self.note_commitment(tag))
|
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 {
|
Input {
|
||||||
nullifier: self.nullifier(tag),
|
nullifier: self.nullifier(&zone_id),
|
||||||
constraint: self.note.constraint,
|
constraint: self.note.constraint,
|
||||||
|
zone_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,10 +81,11 @@ impl InputWitness {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
pub fn to_bytes(&self) -> [u8; 64] {
|
pub fn to_bytes(&self) -> [u8; 96] {
|
||||||
let mut bytes = [0u8; 64];
|
let mut bytes = [0u8; 96];
|
||||||
bytes[..32].copy_from_slice(self.nullifier.as_bytes());
|
bytes[..32].copy_from_slice(self.nullifier.as_bytes());
|
||||||
bytes[32..64].copy_from_slice(&self.constraint.0);
|
bytes[32..64].copy_from_slice(&self.constraint.0);
|
||||||
|
bytes[64..96].copy_from_slice(&self.zone_id);
|
||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ pub mod merkle;
|
|||||||
pub mod note;
|
pub mod note;
|
||||||
pub mod nullifier;
|
pub mod nullifier;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
pub mod pact;
|
|
||||||
pub mod partial_tx;
|
pub mod partial_tx;
|
||||||
|
|
||||||
pub use balance::{Balance, BalanceWitness};
|
pub use balance::{Balance, BalanceWitness};
|
||||||
|
@ -118,8 +118,8 @@ impl Nonce {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
// use super::*;
|
||||||
use crate::nullifier::NullifierSecret;
|
// use crate::cl::nullifier::NullifierSecret;
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn test_note_commit_permutations() {
|
// fn test_note_commit_permutations() {
|
||||||
|
@ -84,7 +84,7 @@ impl Nullifier {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{note::derive_unit, Constraint, Nonce, NoteWitness};
|
// use crate::cl::{note::derive_unit, Constraint, Nonce, NoteWitness};
|
||||||
|
|
||||||
// use super::*;
|
// use super::*;
|
||||||
|
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::cl::{
|
use crate::{
|
||||||
note::{NoteCommitment, NoteWitness},
|
cl::{
|
||||||
nullifier::NullifierCommitment,
|
note::{NoteCommitment, NoteWitness},
|
||||||
NullifierSecret,
|
nullifier::NullifierCommitment,
|
||||||
|
NullifierSecret,
|
||||||
|
},
|
||||||
|
zone_layer::notes::ZoneId,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Output {
|
pub struct Output {
|
||||||
|
pub zone_id: ZoneId,
|
||||||
pub note_comm: NoteCommitment,
|
pub note_comm: NoteCommitment,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,15 +35,19 @@ impl OutputWitness {
|
|||||||
self.note.commit(tag, self.nf_pk)
|
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 {
|
Output {
|
||||||
note_comm: self.commit_note(tag),
|
zone_id,
|
||||||
|
note_comm: self.commit_note(&zone_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output {
|
impl Output {
|
||||||
pub fn to_bytes(&self) -> [u8; 32] {
|
pub fn to_bytes(&self) -> [u8; 64] {
|
||||||
self.note_comm.0
|
let mut bytes = [0u8; 64];
|
||||||
|
bytes[..32].copy_from_slice(&self.zone_id);
|
||||||
|
bytes[32..].copy_from_slice(&self.note_comm.0);
|
||||||
|
bytes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<ZoneId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub struct PactWitness {
|
|
||||||
pub tx: PartialTxWitness,
|
|
||||||
pub from: ZoneId,
|
|
||||||
pub to: Vec<ZoneId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,14 @@
|
|||||||
use rand_core::{CryptoRngCore, RngCore};
|
use rand_core::{CryptoRngCore, RngCore};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::cl::{
|
use crate::{
|
||||||
balance::{Balance, BalanceWitness},
|
cl::{
|
||||||
input::{Input, InputWitness},
|
balance::{Balance, BalanceWitness},
|
||||||
merkle,
|
input::{Input, InputWitness},
|
||||||
output::{Output, OutputWitness},
|
merkle,
|
||||||
|
output::{Output, OutputWitness},
|
||||||
|
},
|
||||||
|
zone_layer::notes::ZoneId,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MAX_INPUTS: usize = 8;
|
pub const MAX_INPUTS: usize = 8;
|
||||||
@ -65,19 +68,32 @@ impl PartialTxWitness {
|
|||||||
BalanceWitness::from_ptx(self, self.balance_blinding)
|
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 {
|
PartialTx {
|
||||||
inputs: Vec::from_iter(self.inputs.iter().map(|i| i.commit(zone))),
|
inputs: self
|
||||||
outputs: Vec::from_iter(self.outputs.iter().map(|o| o.commit(zone))),
|
.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(),
|
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(
|
let input_bytes = Vec::from_iter(
|
||||||
self.inputs
|
self.inputs
|
||||||
.iter()
|
.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::<MAX_INPUTS>(&input_bytes);
|
let input_merkle_leaves = merkle::padded_leaves::<MAX_INPUTS>(&input_bytes);
|
||||||
|
|
||||||
@ -86,11 +102,11 @@ impl PartialTxWitness {
|
|||||||
PartialTxInputWitness { input, path }
|
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(
|
let output_bytes = Vec::from_iter(
|
||||||
self.outputs
|
self.outputs
|
||||||
.iter()
|
.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::<MAX_OUTPUTS>(&output_bytes);
|
let output_merkle_leaves = merkle::padded_leaves::<MAX_OUTPUTS>(&output_bytes);
|
||||||
|
|
||||||
@ -135,8 +151,8 @@ pub struct PartialTxInputWitness {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialTxInputWitness {
|
impl PartialTxInputWitness {
|
||||||
pub fn input_root(&self, tag: &dyn AsRef<[u8]>) -> [u8; 32] {
|
pub fn input_root(&self, zone_id: ZoneId) -> [u8; 32] {
|
||||||
let leaf = merkle::leaf(&self.input.commit(tag).to_bytes());
|
let leaf = merkle::leaf(&self.input.commit(zone_id).to_bytes());
|
||||||
merkle::path_root(leaf, &self.path)
|
merkle::path_root(leaf, &self.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,8 +165,8 @@ pub struct PartialTxOutputWitness {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialTxOutputWitness {
|
impl PartialTxOutputWitness {
|
||||||
pub fn output_root(&self, tag: &dyn AsRef<[u8]>) -> [u8; 32] {
|
pub fn output_root(&self, zone_id: ZoneId) -> [u8; 32] {
|
||||||
let leaf = merkle::leaf(&self.output.commit(tag).to_bytes());
|
let leaf = merkle::leaf(&self.output.commit(zone_id).to_bytes());
|
||||||
merkle::path_root(leaf, &self.path)
|
merkle::path_root(leaf, &self.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,13 +174,13 @@ impl PartialTxOutputWitness {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use crate::{
|
// use crate::cl::{
|
||||||
balance::UnitBalance,
|
// balance::UnitBalance,
|
||||||
note::{derive_unit, NoteWitness},
|
// note::{derive_unit, NoteWitness},
|
||||||
nullifier::NullifierSecret,
|
// nullifier::NullifierSecret,
|
||||||
};
|
// };
|
||||||
|
|
||||||
use super::*;
|
// use super::*;
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn test_partial_tx_balance() {
|
// fn test_partial_tx_balance() {
|
||||||
|
@ -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 {
|
fn receive_utxo(note: NoteWitness, nf_pk: NullifierCommitment) -> OutputWitness {
|
||||||
cl::OutputWitness::new(note, nf_pk)
|
OutputWitness::new(note, nf_pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -9,27 +12,26 @@ fn test_simple_transfer() {
|
|||||||
let nmo = derive_unit("NMO");
|
let nmo = derive_unit("NMO");
|
||||||
let mut rng = rand::thread_rng();
|
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 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
|
// 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.
|
// and wants to send 8 NMO to some recipient and return 2 NMO to itself.
|
||||||
let recipient_output =
|
let recipient_output =
|
||||||
cl::OutputWitness::new(cl::NoteWitness::basic(8, nmo, &mut rng), recipient_nf_pk);
|
OutputWitness::new(NoteWitness::basic(8, nmo, &mut rng), recipient_nf_pk);
|
||||||
let change_output =
|
let change_output = OutputWitness::new(NoteWitness::basic(2, nmo, &mut rng), sender_nf_pk);
|
||||||
cl::OutputWitness::new(cl::NoteWitness::basic(2, nmo, &mut rng), sender_nf_pk);
|
|
||||||
|
|
||||||
let ptx_witness = cl::PartialTxWitness {
|
let ptx_witness = PartialTxWitness {
|
||||||
inputs: vec![cl::InputWitness::from_output(utxo, sender_nf_sk)],
|
inputs: vec![InputWitness::from_output(utxo, sender_nf_sk)],
|
||||||
outputs: vec![recipient_output, change_output],
|
outputs: vec![recipient_output, change_output],
|
||||||
balance_blinding: BalanceWitness::random_blinding(&mut rng),
|
balance_blinding: BalanceWitness::random_blinding(&mut rng),
|
||||||
};
|
};
|
||||||
|
|
||||||
let bundle = cl::BundleWitness {
|
let bundle = BundleWitness {
|
||||||
partials: vec![ptx_witness],
|
partials: vec![ptx_witness],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ use crate::error::{Error, Result};
|
|||||||
use cl::cl::BundleWitness;
|
use cl::cl::BundleWitness;
|
||||||
use ledger_proof_statements::bundle::{BundlePrivate, BundlePublic};
|
use ledger_proof_statements::bundle::{BundlePrivate, BundlePublic};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct ProvedBundle {
|
pub struct ProvedBundle {
|
||||||
pub bundle: BundlePublic,
|
pub bundle: BundlePublic,
|
||||||
pub risc0_receipt: risc0_zkvm::Receipt,
|
pub risc0_receipt: risc0_zkvm::Receipt,
|
||||||
|
@ -1,47 +1,38 @@
|
|||||||
use ledger_proof_statements::ledger::{LedgerProofPrivate, LedgerProofPublic, ZoneTx};
|
use ledger_proof_statements::{
|
||||||
|
ledger::{LedgerProofPrivate, LedgerProofPublic},
|
||||||
|
ptx::PtxPublic,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::ProvedBundle,
|
bundle::ProvedBundle,
|
||||||
constraint::ConstraintProof,
|
constraint::ConstraintProof,
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
pact::ProvedPact,
|
|
||||||
partial_tx::ProvedPartialTx,
|
partial_tx::ProvedPartialTx,
|
||||||
};
|
};
|
||||||
use cl::zone_layer::{ledger::LedgerWitness, notes::ZoneId};
|
use cl::zone_layer::{ledger::LedgerWitness, notes::ZoneId};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct ProvedLedgerTransition {
|
pub struct ProvedLedgerTransition {
|
||||||
pub public: LedgerProofPublic,
|
pub public: LedgerProofPublic,
|
||||||
pub risc0_receipt: risc0_zkvm::Receipt,
|
pub risc0_receipt: risc0_zkvm::Receipt,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ProvedZoneTx {
|
// TODO: find a better name
|
||||||
LocalTx {
|
#[derive(Debug, Clone)]
|
||||||
bundle: ProvedBundle,
|
pub struct ProvedZoneTx {
|
||||||
ptxs: Vec<ProvedPartialTx>,
|
pub bundle: ProvedBundle,
|
||||||
},
|
pub ptxs: Vec<ProvedPartialTx>,
|
||||||
Pact(ProvedPact),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProvedZoneTx {
|
impl ProvedZoneTx {
|
||||||
fn to_public(&self) -> ZoneTx {
|
fn to_public(&self) -> Vec<PtxPublic> {
|
||||||
match self {
|
self.ptxs.iter().map(|p| p.public().unwrap()).collect()
|
||||||
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 proofs(&self) -> Vec<risc0_zkvm::Receipt> {
|
fn proofs(&self) -> Vec<risc0_zkvm::Receipt> {
|
||||||
match self {
|
let mut proofs = vec![self.bundle.risc0_receipt.clone()];
|
||||||
Self::LocalTx { ptxs, bundle } => {
|
proofs.extend(self.ptxs.iter().map(|p| p.risc0_receipt.clone()));
|
||||||
let mut proofs = vec![bundle.risc0_receipt.clone()];
|
proofs
|
||||||
proofs.extend(ptxs.iter().map(|p| p.risc0_receipt.clone()));
|
|
||||||
proofs
|
|
||||||
}
|
|
||||||
Self::Pact(pact) => vec![pact.risc0_receipt.clone()],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +44,7 @@ impl ProvedLedgerTransition {
|
|||||||
constraints: Vec<ConstraintProof>,
|
constraints: Vec<ConstraintProof>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let witness = LedgerProofPrivate {
|
let witness = LedgerProofPrivate {
|
||||||
txs: ptxs.iter().map(|p| p.to_public()).collect(),
|
bundles: ptxs.iter().map(|p| p.to_public()).collect(),
|
||||||
ledger,
|
ledger,
|
||||||
id: zone_id,
|
id: zone_id,
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,6 @@ pub mod bundle;
|
|||||||
pub mod constraint;
|
pub mod constraint;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod ledger;
|
pub mod ledger;
|
||||||
pub mod pact;
|
|
||||||
pub mod partial_tx;
|
pub mod partial_tx;
|
||||||
pub mod stf;
|
pub mod stf;
|
||||||
pub mod zone_update;
|
pub mod zone_update;
|
||||||
|
@ -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<Vec<merkle::PathNode>>,
|
|
||||||
cm_root: [u8; 32],
|
|
||||||
) -> Result<ProvedPact> {
|
|
||||||
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<PactPublic> {
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,6 +4,7 @@ use crate::error::{Error, Result};
|
|||||||
use cl::cl::{merkle, PartialTx, PartialTxWitness};
|
use cl::cl::{merkle, PartialTx, PartialTxWitness};
|
||||||
use cl::zone_layer::notes::ZoneId;
|
use cl::zone_layer::notes::ZoneId;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct ProvedPartialTx {
|
pub struct ProvedPartialTx {
|
||||||
pub ptx: PartialTx,
|
pub ptx: PartialTx,
|
||||||
pub cm_root: [u8; 32],
|
pub cm_root: [u8; 32],
|
||||||
@ -12,16 +13,19 @@ pub struct ProvedPartialTx {
|
|||||||
|
|
||||||
impl ProvedPartialTx {
|
impl ProvedPartialTx {
|
||||||
pub fn prove(
|
pub fn prove(
|
||||||
ptx: &PartialTxWitness,
|
ptx_witness: PartialTxWitness,
|
||||||
input_cm_paths: Vec<Vec<merkle::PathNode>>,
|
input_cm_paths: Vec<Vec<merkle::PathNode>>,
|
||||||
cm_root: [u8; 32],
|
cm_root: [u8; 32],
|
||||||
id: ZoneId,
|
from: Vec<ZoneId>,
|
||||||
|
to: Vec<ZoneId>,
|
||||||
) -> Result<ProvedPartialTx> {
|
) -> Result<ProvedPartialTx> {
|
||||||
|
let ptx = ptx_witness.commit(&from, &to);
|
||||||
let ptx_private = PtxPrivate {
|
let ptx_private = PtxPrivate {
|
||||||
ptx: ptx.clone(),
|
ptx: ptx_witness,
|
||||||
input_cm_paths,
|
input_cm_paths,
|
||||||
cm_root,
|
cm_root,
|
||||||
from: id,
|
from,
|
||||||
|
to,
|
||||||
};
|
};
|
||||||
|
|
||||||
let env = risc0_zkvm::ExecutorEnv::builder()
|
let env = risc0_zkvm::ExecutorEnv::builder()
|
||||||
@ -49,7 +53,7 @@ impl ProvedPartialTx {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
ptx: ptx.commit(&id),
|
ptx,
|
||||||
cm_root,
|
cm_root,
|
||||||
risc0_receipt: prove_info.receipt,
|
risc0_receipt: prove_info.receipt,
|
||||||
})
|
})
|
||||||
|
@ -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::{
|
use ledger::{
|
||||||
|
bundle::ProvedBundle,
|
||||||
constraint::ConstraintProof,
|
constraint::ConstraintProof,
|
||||||
ledger::{ProvedLedgerTransition, ProvedZoneTx},
|
ledger::{ProvedLedgerTransition, ProvedZoneTx},
|
||||||
pact::ProvedPact,
|
partial_tx::ProvedPartialTx,
|
||||||
};
|
};
|
||||||
use rand_core::CryptoRngCore;
|
use rand_core::CryptoRngCore;
|
||||||
|
|
||||||
struct User(cl::NullifierSecret);
|
struct User(NullifierSecret);
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
fn random(mut rng: impl CryptoRngCore) -> Self {
|
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()
|
self.0.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sk(&self) -> cl::NullifierSecret {
|
fn sk(&self) -> NullifierSecret {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_utxo(note: cl::NoteWitness, nf_pk: cl::NullifierCommitment) -> cl::OutputWitness {
|
fn receive_utxo(note: NoteWitness, nf_pk: NullifierCommitment) -> OutputWitness {
|
||||||
cl::OutputWitness::new(note, nf_pk)
|
OutputWitness::new(note, nf_pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -39,81 +46,82 @@ fn ledger_transition() {
|
|||||||
|
|
||||||
// Alice has an unspent note worth 10 NMO
|
// Alice has an unspent note worth 10 NMO
|
||||||
let utxo = receive_utxo(
|
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.pk(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice wants to send 8 NMO to bob
|
// 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_a = [0; 32];
|
||||||
let zone_b = [1; 32];
|
let zone_b = [1; 32];
|
||||||
let ledger_a = cl::zones::LedgerWitness {
|
let ledger_a = LedgerWitness {
|
||||||
commitments: vec![utxo.commit_note(&zone_a)],
|
commitments: vec![utxo.commit_note(&zone_a)],
|
||||||
nullifiers: vec![],
|
nullifiers: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let ledger_b = cl::zones::LedgerWitness {
|
let ledger_b = LedgerWitness {
|
||||||
commitments: vec![],
|
commitments: vec![],
|
||||||
nullifiers: 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)],
|
commitments: vec![utxo.commit_note(&zone_a), alice_change.commit_note(&zone_a)],
|
||||||
nullifiers: vec![alice_input.nullifier(&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)],
|
commitments: vec![bobs_output.commit_note(&zone_b)],
|
||||||
nullifiers: vec![],
|
nullifiers: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Construct the ptx consuming Alices inputs and producing the two outputs.
|
// Construct the ptx consuming Alices inputs and producing the two outputs.
|
||||||
let alice_pact_witness = cl::zones::PactWitness {
|
let alice_ptx_witness = PartialTxWitness {
|
||||||
tx: cl::PartialTxWitness {
|
inputs: vec![alice_input],
|
||||||
inputs: vec![alice_input],
|
outputs: vec![bobs_output, alice_change],
|
||||||
outputs: vec![bobs_output, alice_change],
|
balance_blinding: BalanceWitness::random_blinding(&mut rng),
|
||||||
|
|
||||||
balance_blinding: BalanceWitness::random_blinding(&mut rng),
|
|
||||||
},
|
|
||||||
from: zone_a,
|
|
||||||
to: vec![zone_b, zone_a],
|
|
||||||
};
|
};
|
||||||
|
let proved_ptx = ProvedPartialTx::prove(
|
||||||
let proved_pact = ProvedPact::prove(
|
alice_ptx_witness.clone(),
|
||||||
alice_pact_witness,
|
|
||||||
vec![ledger_a
|
vec![ledger_a
|
||||||
.cm_path(&alice_input.note_commitment(&zone_a))
|
.cm_path(&alice_input.note_commitment(&zone_a))
|
||||||
.unwrap()],
|
.unwrap()],
|
||||||
ledger_a.cm_root(),
|
ledger_a.cm_root(),
|
||||||
|
vec![zone_a],
|
||||||
|
vec![zone_b, zone_a],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.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)
|
// Prove the constraints for alices input (she uses the no-op constraint)
|
||||||
let constraint_proof =
|
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(
|
let ledger_a_transition = ProvedLedgerTransition::prove(
|
||||||
ledger_a,
|
ledger_a,
|
||||||
zone_a,
|
zone_a,
|
||||||
vec![ProvedZoneTx::Pact(proved_pact.clone())],
|
vec![zone_tx.clone()],
|
||||||
vec![constraint_proof],
|
vec![constraint_proof],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let ledger_b_transition = ProvedLedgerTransition::prove(
|
let ledger_b_transition =
|
||||||
ledger_b,
|
ProvedLedgerTransition::prove(ledger_b, zone_b, vec![zone_tx], vec![]).unwrap();
|
||||||
zone_b,
|
|
||||||
vec![ProvedZoneTx::Pact(proved_pact)],
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ledger_a_transition.public.ledger,
|
ledger_a_transition.public.ledger,
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use crate::bundle::BundlePublic;
|
|
||||||
use crate::pact::PactPublic;
|
|
||||||
use crate::ptx::PtxPublic;
|
use crate::ptx::PtxPublic;
|
||||||
use cl::cl::Output;
|
use cl::cl::Output;
|
||||||
use cl::zone_layer::{
|
use cl::zone_layer::{
|
||||||
@ -21,14 +19,5 @@ pub struct LedgerProofPublic {
|
|||||||
pub struct LedgerProofPrivate {
|
pub struct LedgerProofPrivate {
|
||||||
pub ledger: LedgerWitness,
|
pub ledger: LedgerWitness,
|
||||||
pub id: ZoneId,
|
pub id: ZoneId,
|
||||||
pub txs: Vec<ZoneTx>,
|
pub bundles: Vec<Vec<PtxPublic>>,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub enum ZoneTx {
|
|
||||||
LocalTx {
|
|
||||||
ptxs: Vec<PtxPublic>,
|
|
||||||
bundle: BundlePublic,
|
|
||||||
},
|
|
||||||
Pact(PactPublic),
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
pub mod bundle;
|
pub mod bundle;
|
||||||
pub mod constraint;
|
pub mod constraint;
|
||||||
pub mod ledger;
|
pub mod ledger;
|
||||||
pub mod pact;
|
|
||||||
pub mod ptx;
|
pub mod ptx;
|
||||||
pub mod stf;
|
pub mod stf;
|
||||||
|
@ -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<Vec<merkle::PathNode>>,
|
|
||||||
pub cm_root: [u8; 32],
|
|
||||||
}
|
|
@ -1,4 +1,7 @@
|
|||||||
use cl::cl::{merkle, PartialTx, PartialTxWitness};
|
use cl::{
|
||||||
|
cl::{merkle, PartialTx, PartialTxWitness},
|
||||||
|
zone_layer::notes::ZoneId,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
@ -12,5 +15,6 @@ pub struct PtxPrivate {
|
|||||||
pub ptx: PartialTxWitness,
|
pub ptx: PartialTxWitness,
|
||||||
pub input_cm_paths: Vec<Vec<merkle::PathNode>>,
|
pub input_cm_paths: Vec<Vec<merkle::PathNode>>,
|
||||||
pub cm_root: [u8; 32],
|
pub cm_root: [u8; 32],
|
||||||
pub from: [u8; 32],
|
pub from: Vec<ZoneId>,
|
||||||
|
pub to: Vec<ZoneId>,
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,19 @@ use cl::{
|
|||||||
cl::Output,
|
cl::Output,
|
||||||
zone_layer::{ledger::LedgerWitness, notes::ZoneId},
|
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};
|
use risc0_zkvm::{guest::env, serde};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let LedgerProofPrivate {
|
let LedgerProofPrivate {
|
||||||
mut ledger,
|
mut ledger,
|
||||||
id,
|
id,
|
||||||
txs,
|
bundles,
|
||||||
} = env::read();
|
} = env::read();
|
||||||
|
|
||||||
let old_ledger = ledger.commit();
|
let old_ledger = ledger.commit();
|
||||||
@ -19,18 +24,23 @@ fn main() {
|
|||||||
let mut cross_in = vec![];
|
let mut cross_in = vec![];
|
||||||
let mut cross_out = vec![];
|
let mut cross_out = vec![];
|
||||||
|
|
||||||
for tx in txs {
|
for bundle in bundles {
|
||||||
match tx {
|
let bundle_public = BundlePublic {
|
||||||
ZoneTx::LocalTx { bundle, ptxs } => {
|
balances: bundle.iter().map(|ptx| ptx.ptx.balance).collect::<Vec<_>>(),
|
||||||
ledger = process_bundle(ledger, ptxs, bundle, cm_root);
|
};
|
||||||
}
|
// verify bundle is balanced
|
||||||
ZoneTx::Pact(pact) => {
|
env::verify(
|
||||||
let (new_ledger, consumed_commits, produced_commits) =
|
nomos_cl_risc0_proofs::BUNDLE_ID,
|
||||||
process_pact(ledger, pact, id, cm_root);
|
&serde::to_vec(&bundle_public).unwrap(),
|
||||||
ledger = new_ledger;
|
)
|
||||||
cross_in.extend(consumed_commits);
|
.unwrap();
|
||||||
cross_out.extend(produced_commits);
|
|
||||||
}
|
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,
|
mut ledger: LedgerWitness,
|
||||||
ptxs: Vec<PtxPublic>,
|
ptx: &PtxPublic,
|
||||||
bundle_proof: BundlePublic,
|
zone_id: ZoneId,
|
||||||
cm_root: [u8; 32],
|
|
||||||
) -> LedgerWitness {
|
|
||||||
assert_eq!(
|
|
||||||
ptxs.iter().map(|ptx| ptx.ptx.balance).collect::<Vec<_>>(),
|
|
||||||
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,
|
|
||||||
cm_root: [u8; 32],
|
cm_root: [u8; 32],
|
||||||
) -> (LedgerWitness, Vec<Output>, Vec<Output>) {
|
) -> (LedgerWitness, Vec<Output>, Vec<Output>) {
|
||||||
let mut cross_in = vec![];
|
let mut cross_in = vec![];
|
||||||
let mut cross_out = vec![];
|
let mut cross_out = vec![];
|
||||||
|
|
||||||
env::verify(
|
env::verify(nomos_cl_risc0_proofs::PTX_ID, &serde::to_vec(&ptx).unwrap()).unwrap();
|
||||||
nomos_cl_risc0_proofs::PACT_ID,
|
|
||||||
&serde::to_vec(&pact).unwrap(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let pact_cm_root = pact.cm_root;
|
let ptx_cm_root = ptx.cm_root;
|
||||||
let pact = pact.pact;
|
let ptx = &ptx.ptx;
|
||||||
|
|
||||||
if cm_root != pact_cm_root {
|
// TODO: accept inputs from multiple zones
|
||||||
// zone is the receiver of the transfer
|
let check_inputs = ptx.inputs.iter().all(|input| input.zone_id == zone_id);
|
||||||
for (comm, zone) in pact.tx.outputs.iter().zip(&pact.to) {
|
|
||||||
if *zone == id {
|
if check_inputs {
|
||||||
cross_in.push(*comm);
|
assert_eq!(ptx_cm_root, cm_root);
|
||||||
ledger.commitments.push(comm.note_comm);
|
for input in &ptx.inputs {
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// zone is the sender of the transfer
|
|
||||||
// proof of non-membership
|
|
||||||
for input in &pact.tx.inputs {
|
|
||||||
assert!(!ledger.nullifiers.contains(&input.nullifier));
|
assert!(!ledger.nullifiers.contains(&input.nullifier));
|
||||||
ledger.nullifiers.push(input.nullifier);
|
ledger.nullifiers.push(input.nullifier);
|
||||||
|
|
||||||
env::verify(
|
env::verify(
|
||||||
input.constraint.0,
|
input.constraint.0,
|
||||||
&serde::to_vec(&ConstraintPublic {
|
&serde::to_vec(&ConstraintPublic {
|
||||||
ptx_root: pact.tx.root(),
|
ptx_root: ptx.root(),
|
||||||
nf: input.nullifier,
|
nf: input.nullifier,
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (output, to) in pact.tx.outputs.iter().zip(&pact.to) {
|
for output in &ptx.outputs {
|
||||||
if *to == id {
|
if output.zone_id == zone_id {
|
||||||
ledger.commitments.push(output.note_comm);
|
ledger.commitments.push(output.note_comm);
|
||||||
} else {
|
// 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);
|
cross_out.push(*output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,5 @@ edition = "2021"
|
|||||||
risc0-build = { version = "1.0" }
|
risc0-build = { version = "1.0" }
|
||||||
|
|
||||||
[package.metadata.risc0]
|
[package.metadata.risc0]
|
||||||
methods = ["bundle", "constraint_nop", "ptx", "pact"]
|
methods = ["bundle", "constraint_nop", "ptx"]
|
||||||
|
|
||||||
|
@ -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" }
|
|
@ -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,
|
|
||||||
});
|
|
||||||
}
|
|
@ -9,11 +9,12 @@ fn main() {
|
|||||||
input_cm_paths,
|
input_cm_paths,
|
||||||
cm_root,
|
cm_root,
|
||||||
from,
|
from,
|
||||||
|
to,
|
||||||
} = env::read();
|
} = env::read();
|
||||||
|
|
||||||
assert_eq!(ptx.inputs.len(), input_cm_paths.len());
|
assert_eq!(ptx.inputs.len(), input_cm_paths.len());
|
||||||
for (input, cm_path) in ptx.inputs.iter().zip(input_cm_paths) {
|
for ((input, cm_path), zone_id) in ptx.inputs.iter().zip(input_cm_paths).zip(&from) {
|
||||||
let note_cm = input.note_commitment(&from);
|
let note_cm = input.note_commitment(zone_id);
|
||||||
let cm_leaf = merkle::leaf(note_cm.as_bytes());
|
let cm_leaf = merkle::leaf(note_cm.as_bytes());
|
||||||
assert_eq!(cm_root, merkle::path_root(cm_leaf, &cm_path));
|
assert_eq!(cm_root, merkle::path_root(cm_leaf, &cm_path));
|
||||||
}
|
}
|
||||||
@ -23,7 +24,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
env::commit(&PtxPublic {
|
env::commit(&PtxPublic {
|
||||||
ptx: ptx.commit(&from),
|
ptx: ptx.commit(&from, &to),
|
||||||
cm_root,
|
cm_root,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user