cl: ban zero valued outputs

This commit is contained in:
David Rusu 2024-07-30 18:22:39 +04:00
parent 94bef73ba4
commit 4abd98b951
7 changed files with 64 additions and 29 deletions

View File

@ -1,4 +1,4 @@
use crate::error::Result;
use crate::error::{Error, Result};
pub struct ProvedBundle {
pub bundle: cl::Bundle,
@ -6,7 +6,7 @@ pub struct ProvedBundle {
}
impl ProvedBundle {
pub fn prove(bundle: &cl::Bundle, bundle_witness: &cl::BundleWitness) -> Self {
pub fn prove(bundle: &cl::Bundle, bundle_witness: &cl::BundleWitness) -> Result<Self> {
// need to show that bundle is balanced.
// i.e. the sum of ptx balances is 0
@ -23,7 +23,7 @@ impl ProvedBundle {
let opts = risc0_zkvm::ProverOpts::succinct();
let prove_info = prover
.prove_with_opts(env, nomos_cl_risc0_proofs::BUNDLE_ELF, &opts)
.unwrap();
.map_err(|_| Error::Risc0ProofFailed)?;
println!(
"STARK 'bundle' prover time: {:.2?}, total_cycles: {}",
@ -33,10 +33,10 @@ impl ProvedBundle {
let receipt = prove_info.receipt;
Self {
Ok(Self {
bundle: bundle.clone(),
risc0_receipt: receipt,
}
})
}
pub fn public(&self) -> Result<cl::Balance> {

View File

@ -6,4 +6,6 @@ pub type Result<T> = core::result::Result<T, Error>;
pub enum Error {
#[error("risc0 failed to serde")]
Risc0Serde(#[from] risc0_zkvm::serde::Error),
#[error("risc0 failed to prove execution of the zkvm")]
Risc0ProofFailed,
}

View File

@ -1,6 +1,6 @@
use proof_statements::input::{InputPrivate, InputPublic};
use crate::error::Result;
use crate::error::{Error, Result};
const MAX_NOTE_COMMS: usize = 2usize.pow(8);
@ -11,7 +11,10 @@ pub struct ProvedInput {
}
impl ProvedInput {
pub fn prove(input: &cl::InputWitness, note_commitments: &[cl::NoteCommitment]) -> Self {
pub fn prove(
input: &cl::InputWitness,
note_commitments: &[cl::NoteCommitment],
) -> Result<Self> {
let output_cm = input.note_commitment();
let cm_leaves = note_commitment_leaves(note_commitments);
@ -42,7 +45,7 @@ impl ProvedInput {
let opts = risc0_zkvm::ProverOpts::succinct();
let prove_info = prover
.prove_with_opts(env, nomos_cl_risc0_proofs::INPUT_ELF, &opts)
.unwrap();
.map_err(|_| Error::Risc0ProofFailed)?;
println!(
"STARK 'input' prover time: {:.2?}, total_cycles: {}",
@ -52,13 +55,13 @@ impl ProvedInput {
// extract the receipt.
let receipt = prove_info.receipt;
Self {
Ok(Self {
input: InputPublic {
cm_root: cl::merkle::root(cm_leaves),
input: input.commit(),
},
risc0_receipt: receipt,
}
})
}
pub fn public(&self) -> Result<InputPublic> {
@ -103,7 +106,7 @@ mod test {
let notes = vec![input.note_commitment()];
let mut proved_input = ProvedInput::prove(&input, &notes);
let mut proved_input = ProvedInput::prove(&input, &notes).unwrap();
let expected_public_inputs = InputPublic {
cm_root: cl::merkle::root(note_commitment_leaves(&notes)),

View File

@ -1,4 +1,4 @@
use crate::error::Result;
use crate::error::{Error, Result};
pub struct ProvedOutput {
pub output: cl::Output,
@ -6,7 +6,7 @@ pub struct ProvedOutput {
}
impl ProvedOutput {
pub fn prove(witness: &cl::OutputWitness) -> Self {
pub fn prove(witness: &cl::OutputWitness) -> Result<Self> {
let env = risc0_zkvm::ExecutorEnv::builder()
.write(&witness)
.unwrap()
@ -20,7 +20,7 @@ impl ProvedOutput {
let opts = risc0_zkvm::ProverOpts::succinct();
let prove_info = prover
.prove_with_opts(env, nomos_cl_risc0_proofs::OUTPUT_ELF, &opts)
.unwrap();
.map_err(|_| Error::Risc0ProofFailed)?;
println!(
"STARK 'output' prover time: {:.2?}, total_cycles: {}",
@ -30,10 +30,10 @@ impl ProvedOutput {
let receipt = prove_info.receipt;
Self {
Ok(Self {
output: witness.commit(),
risc0_receipt: receipt,
}
})
}
pub fn public(&self) -> Result<cl::Output> {
@ -70,7 +70,7 @@ mod test {
nonce: cl::NullifierNonce::random(&mut rng),
};
let mut proved_output = ProvedOutput::prove(&output);
let mut proved_output = ProvedOutput::prove(&output).unwrap();
let expected_output_cm = output.commit();
@ -100,4 +100,17 @@ mod test {
assert!(!proved_output.verify());
}
}
#[test]
fn test_zero_output_is_rejected() {
let mut rng = thread_rng();
let output = cl::OutputWitness::random(
cl::NoteWitness::basic(0, "NMO"),
cl::NullifierSecret::random(&mut rng).commit(),
&mut rng,
);
assert!(ProvedOutput::prove(&output).is_err());
}
}

View File

@ -2,7 +2,9 @@ use std::collections::BTreeMap;
use proof_statements::death_constraint::DeathConstraintPublic;
use crate::{death_constraint::DeathProof, input::ProvedInput, output::ProvedOutput};
use crate::{
death_constraint::DeathProof, error::Result, input::ProvedInput, output::ProvedOutput,
};
#[derive(Debug, Clone)]
pub struct PartialTxInput {
@ -29,18 +31,27 @@ impl ProvedPartialTx {
ptx: &cl::PartialTxWitness,
mut death_proofs: BTreeMap<cl::Nullifier, DeathProof>,
note_commitments: &[cl::NoteCommitment],
) -> ProvedPartialTx {
Self {
inputs: Vec::from_iter(ptx.inputs.iter().map(|i| {
PartialTxInput {
input: ProvedInput::prove(i, note_commitments),
) -> Result<ProvedPartialTx> {
let inputs = ptx
.inputs
.iter()
.map(|i| {
Ok(PartialTxInput {
input: ProvedInput::prove(i, note_commitments)?,
death: death_proofs
.remove(&i.nullifier())
.expect("Input missing death proof"),
}
})),
outputs: Vec::from_iter(ptx.outputs.iter().map(ProvedOutput::prove)),
}
})
})
.collect::<Result<_>>()?;
let outputs = ptx
.outputs
.iter()
.map(ProvedOutput::prove)
.collect::<Result<_>>()?;
Ok(Self { inputs, outputs })
}
pub fn ptx(&self) -> cl::PartialTx {

View File

@ -68,7 +68,7 @@ fn test_simple_transfer() {
// assume we only have one note commitment on chain for now ...
let note_commitments = vec![utxo.commit_note()];
let proved_ptx = ProvedPartialTx::prove(&ptx_witness, death_proofs, &note_commitments);
let proved_ptx = ProvedPartialTx::prove(&ptx_witness, death_proofs, &note_commitments).unwrap();
assert!(proved_ptx.verify()); // It's a valid ptx.
@ -80,6 +80,6 @@ fn test_simple_transfer() {
balance_blinding: ptx_witness.balance_blinding(),
};
let proved_bundle = ProvedBundle::prove(&bundle, &bundle_witness);
let proved_bundle = ProvedBundle::prove(&bundle, &bundle_witness).unwrap();
assert!(proved_bundle.verify()); // The bundle is balanced.
}

View File

@ -7,6 +7,12 @@ use risc0_zkvm::guest::env;
fn main() {
let output: cl::OutputWitness = env::read();
// 0 does not contribute to balance, implications of this are unclear
// therefore out of an abundance of caution, we disallow these zero
// valued "dummy notes".
assert!(output.note.value > 0);
let output_cm = output.commit();
env::commit(&output_cm);
}