cl: ban zero valued outputs
This commit is contained in:
parent
94bef73ba4
commit
4abd98b951
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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, ¬es);
|
||||
let mut proved_input = ProvedInput::prove(&input, ¬es).unwrap();
|
||||
|
||||
let expected_public_inputs = InputPublic {
|
||||
cm_root: cl::merkle::root(note_commitment_leaves(¬es)),
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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, ¬e_commitments);
|
||||
let proved_ptx = ProvedPartialTx::prove(&ptx_witness, death_proofs, ¬e_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.
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue