check zone updates

This commit is contained in:
Giacomo Pasini 2024-11-25 13:06:53 +01:00
parent a76bb268a1
commit 854fab935b
No known key found for this signature in database
GPG Key ID: FC08489D2D895D4B
7 changed files with 205 additions and 100 deletions

View File

@ -37,3 +37,4 @@ fn test_simple_transfer() {
assert!(bundle.balance().is_zero())
}

View File

@ -26,8 +26,38 @@ impl StfProof {
pub fn stf(&self) -> Stf {
risc0_constraint(self.risc0_id)
}
pub fn verify(&self) -> bool {
self.risc0_receipt.verify(self.risc0_id).is_ok()
}
pub fn prove_nop(public: StfPublic) -> Self {
let env = risc0_zkvm::ExecutorEnv::builder()
.write(&public)
.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::STF_NOP_ELF, &opts)
.unwrap();
println!(
"STARK 'stf' prover time: {:.2?}, total_cycles: {}",
start_t.elapsed(),
prove_info.stats.total_cycles
);
let receipt = prove_info.receipt;
Self {
risc0_id: nomos_cl_risc0_proofs::STF_NOP_ID,
public,
risc0_receipt: receipt,
}
}
}

View File

@ -10,47 +10,6 @@ pub struct ProvedUpdateBundle {
}
impl ProvedUpdateBundle {
// pub fn prove(bundle_witness: &BundleWitness) -> Result<Self> {
// // need to show that bundle is balanced.
// // i.e. the sum of ptx balances is 0
// let bundle_private = BundlePrivate {
// balances: bundle_witness
// .partials
// .iter()
// .map(|ptx| ptx.balance())
// .collect(),
// };
// let env = risc0_zkvm::ExecutorEnv::builder()
// .write(&bundle_private)
// .unwrap()
// .build()
// .unwrap();
// let prover = risc0_zkvm::default_prover();
// let start_t = std::time::Instant::now();
// let opts = risc0_zkvm::ProverOpts::succinct();
// let prove_info = prover
// .prove_with_opts(env, nomos_cl_risc0_proofs::BUNDLE_ELF, &opts)
// .map_err(|_| Error::Risc0ProofFailed)?;
// println!(
// "STARK 'bundle' prover time: {:.2?}, total_cycles: {}",
// start_t.elapsed(),
// prove_info.stats.total_cycles
// );
// let receipt = prove_info.receipt;
// Ok(Self {
// bundle: receipt.journal.decode()?,
// risc0_receipt: receipt,
// })
// }
pub fn verify(&self) -> bool {
let mut consumed_commitments = HashSet::new();
let mut produced_commitments = HashSet::new();

View File

@ -1,17 +1,30 @@
use cl::{
cl::{
note::derive_unit, BalanceWitness, BundleWitness, InputWitness, NoteWitness,
balance::Unit, note::derive_unit, BalanceWitness, BundleWitness, InputWitness, NoteWitness,
NullifierCommitment, NullifierSecret, OutputWitness, PartialTxWitness,
},
zone_layer::ledger::LedgerWitness,
zone_layer::{
ledger::LedgerWitness,
notes::ZoneNote,
tx::{UpdateBundle, ZoneUpdate},
},
};
use ledger::{
bundle::ProvedBundle,
constraint::ConstraintProof,
ledger::{ProvedLedgerTransition, ProvedZoneTx},
partial_tx::ProvedPartialTx,
stf::StfProof,
zone_update::ProvedUpdateBundle,
};
use ledger_proof_statements::stf::StfPublic;
use rand_core::CryptoRngCore;
use std::sync::OnceLock;
fn nmo() -> &'static Unit {
static NMO: OnceLock<Unit> = OnceLock::new();
NMO.get_or_init(|| derive_unit("NMO"))
}
struct User(NullifierSecret);
@ -33,63 +46,33 @@ fn receive_utxo(note: NoteWitness, nf_pk: NullifierCommitment) -> OutputWitness
OutputWitness::new(note, nf_pk)
}
#[test]
fn ledger_transition() {
let nmo = derive_unit("NMO");
fn cross_transfer_transition(
input: InputWitness,
to: User,
amount: u64,
zone_a: [u8; 32],
zone_b: [u8; 32],
ledger_a: LedgerWitness,
ledger_b: LedgerWitness,
) -> (ProvedLedgerTransition, ProvedLedgerTransition) {
let mut rng = rand::thread_rng();
// alice is sending 8 NMO to bob.
let alice = User::random(&mut rng);
let bob = User::random(&mut rng);
// Alice has an unspent note worth 10 NMO
let utxo = receive_utxo(
NoteWitness::stateless(10, nmo, ConstraintProof::nop_constraint(), &mut rng),
alice.pk(),
assert!(amount <= input.note.value);
let change = input.note.value - amount;
let transfer = OutputWitness::new(NoteWitness::basic(amount, *nmo(), &mut rng), to.pk());
let change = OutputWitness::new(
NoteWitness::basic(change, *nmo(), &mut rng),
input.nf_sk.commit(),
);
// Alice wants to send 8 NMO to bob
let bobs_output = OutputWitness::new(NoteWitness::basic(8, nmo, &mut rng), bob.pk());
let alice_change = OutputWitness::new(NoteWitness::basic(2, nmo, &mut rng), alice.pk());
let alice_input = InputWitness::from_output(utxo, alice.sk());
let zone_a = [0; 32];
let zone_b = [1; 32];
let ledger_a = LedgerWitness {
commitments: vec![utxo.commit_note(&zone_a)],
nullifiers: vec![],
};
let ledger_b = LedgerWitness {
commitments: vec![],
nullifiers: vec![],
};
let expected_ledger_a = LedgerWitness {
commitments: vec![utxo.commit_note(&zone_a), alice_change.commit_note(&zone_a)],
nullifiers: vec![alice_input.nullifier(&zone_a)],
};
let expected_ledger_b = LedgerWitness {
commitments: vec![bobs_output.commit_note(&zone_b)],
nullifiers: vec![],
};
// Construct the ptx consuming Alices inputs and producing the two outputs.
let alice_ptx_witness = PartialTxWitness {
inputs: vec![alice_input],
outputs: vec![bobs_output, alice_change],
// Construct the ptx consuming the input and producing the two outputs.
let ptx_witness = PartialTxWitness {
inputs: vec![input],
outputs: vec![transfer, change],
balance_blinding: BalanceWitness::random_blinding(&mut rng),
};
let proved_ptx = ProvedPartialTx::prove(
alice_ptx_witness.clone(),
vec![ledger_a
.cm_path(&alice_input.note_commitment(&zone_a))
.unwrap()],
ptx_witness.clone(),
vec![ledger_a.cm_path(&input.note_commitment(&zone_a)).unwrap()],
ledger_a.cm_root(),
vec![zone_a],
vec![zone_b, zone_a],
@ -97,12 +80,10 @@ fn ledger_transition() {
.unwrap();
let bundle = ProvedBundle::prove(&BundleWitness {
partials: vec![alice_ptx_witness],
partials: vec![ptx_witness],
})
.unwrap();
assert_eq!(proved_ptx.cm_root, ledger_a.cm_root());
let zone_tx = ProvedZoneTx {
ptxs: vec![proved_ptx.clone()],
bundle,
@ -110,7 +91,7 @@ fn ledger_transition() {
// Prove the constraints for alices input (she uses the no-op constraint)
let constraint_proof =
ConstraintProof::prove_nop(alice_input.nullifier(&zone_a), proved_ptx.ptx.root());
ConstraintProof::prove_nop(input.nullifier(&zone_a), proved_ptx.ptx.root());
let ledger_a_transition = ProvedLedgerTransition::prove(
ledger_a,
@ -123,6 +104,16 @@ fn ledger_transition() {
let ledger_b_transition =
ProvedLedgerTransition::prove(ledger_b, zone_b, vec![zone_tx], vec![]).unwrap();
let expected_ledger_a = LedgerWitness {
commitments: vec![input.note_commitment(&zone_a), change.commit_note(&zone_a)],
nullifiers: vec![input.nullifier(&zone_a)],
};
let expected_ledger_b = LedgerWitness {
commitments: vec![transfer.commit_note(&zone_b)],
nullifiers: vec![],
};
assert_eq!(
ledger_a_transition.public.ledger,
expected_ledger_a.commit()
@ -131,4 +122,101 @@ fn ledger_transition() {
ledger_b_transition.public.ledger,
expected_ledger_b.commit()
);
(ledger_a_transition, ledger_b_transition)
}
#[test]
fn zone_update_cross() {
let mut rng = rand::thread_rng();
// alice is sending 8 NMO to bob.
let alice = User::random(&mut rng);
let bob = User::random(&mut rng);
// Alice has an unspent note worth 10 NMO
let utxo = receive_utxo(
NoteWitness::stateless(10, *nmo(), ConstraintProof::nop_constraint(), &mut rng),
alice.pk(),
);
let alice_input = InputWitness::from_output(utxo, alice.sk());
let zone_a_id = [0; 32];
let zone_b_id = [1; 32];
let ledger_a = LedgerWitness {
commitments: vec![utxo.commit_note(&zone_a_id)],
nullifiers: vec![],
};
let ledger_b = LedgerWitness {
commitments: vec![],
nullifiers: vec![],
};
let zone_a_old = ZoneNote {
id: zone_a_id,
state: [0; 32],
ledger: ledger_a.commit(),
stf: [0; 32],
};
let zone_b_old = ZoneNote {
id: zone_b_id,
state: [0; 32],
ledger: ledger_b.commit(),
stf: [0; 32],
};
let (ledger_a_transition, ledger_b_transition) = cross_transfer_transition(
alice_input,
bob,
8,
zone_a_id,
zone_b_id,
ledger_a,
ledger_b,
);
let zone_a_new = ZoneNote {
ledger: ledger_a_transition.public.ledger,
..zone_a_old
};
let zone_b_new = ZoneNote {
ledger: ledger_b_transition.public.ledger,
..zone_b_old
};
let stf_proof_a = StfProof::prove_nop(StfPublic {
old: zone_a_old,
new: zone_a_new,
});
let stf_proof_b = StfProof::prove_nop(StfPublic {
old: zone_b_old,
new: zone_b_new,
});
let update_bundle = UpdateBundle {
updates: vec![
ZoneUpdate {
old: zone_a_old,
new: zone_a_new,
},
ZoneUpdate {
old: zone_b_old,
new: zone_b_new,
},
],
};
let proved_bundle = ProvedUpdateBundle {
bundle: update_bundle,
ledger_proofs: vec![ledger_a_transition, ledger_b_transition],
stf_proofs: vec![stf_proof_a, stf_proof_b],
};
assert!(proved_bundle.verify());
}

View File

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

View File

@ -0,0 +1,19 @@
[package]
name = "stf_nop"
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" }

View File

@ -0,0 +1,8 @@
/// Constraint No-op Proof
use ledger_proof_statements::stf::StfPublic;
use risc0_zkvm::guest::env;
fn main() {
let public: StfPublic = env::read();
env::commit(&public);
}