Merge pull request #13 from logos-co/cl/ensure-output-value-is-non-zero
cl: ban zero valued outputs
This commit is contained in:
commit
e9d43eaee9
|
@ -1,4 +1,4 @@
|
||||||
use crate::error::Result;
|
use crate::error::{Error, Result};
|
||||||
|
|
||||||
pub struct ProvedBundle {
|
pub struct ProvedBundle {
|
||||||
pub bundle: cl::Bundle,
|
pub bundle: cl::Bundle,
|
||||||
|
@ -6,7 +6,7 @@ pub struct ProvedBundle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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.
|
// need to show that bundle is balanced.
|
||||||
// i.e. the sum of ptx balances is 0
|
// i.e. the sum of ptx balances is 0
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ impl ProvedBundle {
|
||||||
let opts = risc0_zkvm::ProverOpts::succinct();
|
let opts = risc0_zkvm::ProverOpts::succinct();
|
||||||
let prove_info = prover
|
let prove_info = prover
|
||||||
.prove_with_opts(env, nomos_cl_risc0_proofs::BUNDLE_ELF, &opts)
|
.prove_with_opts(env, nomos_cl_risc0_proofs::BUNDLE_ELF, &opts)
|
||||||
.unwrap();
|
.map_err(|_| Error::Risc0ProofFailed)?;
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"STARK 'bundle' prover time: {:.2?}, total_cycles: {}",
|
"STARK 'bundle' prover time: {:.2?}, total_cycles: {}",
|
||||||
|
@ -33,10 +33,10 @@ impl ProvedBundle {
|
||||||
|
|
||||||
let receipt = prove_info.receipt;
|
let receipt = prove_info.receipt;
|
||||||
|
|
||||||
Self {
|
Ok(Self {
|
||||||
bundle: bundle.clone(),
|
bundle: bundle.clone(),
|
||||||
risc0_receipt: receipt,
|
risc0_receipt: receipt,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn public(&self) -> Result<cl::Balance> {
|
pub fn public(&self) -> Result<cl::Balance> {
|
||||||
|
|
|
@ -6,4 +6,6 @@ pub type Result<T> = core::result::Result<T, Error>;
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("risc0 failed to serde")]
|
#[error("risc0 failed to serde")]
|
||||||
Risc0Serde(#[from] risc0_zkvm::serde::Error),
|
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 proof_statements::input::{InputPrivate, InputPublic};
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::{Error, Result};
|
||||||
|
|
||||||
const MAX_NOTE_COMMS: usize = 2usize.pow(8);
|
const MAX_NOTE_COMMS: usize = 2usize.pow(8);
|
||||||
|
|
||||||
|
@ -11,7 +11,10 @@ pub struct ProvedInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 output_cm = input.note_commitment();
|
||||||
|
|
||||||
let cm_leaves = note_commitment_leaves(note_commitments);
|
let cm_leaves = note_commitment_leaves(note_commitments);
|
||||||
|
@ -42,7 +45,7 @@ impl ProvedInput {
|
||||||
let opts = risc0_zkvm::ProverOpts::succinct();
|
let opts = risc0_zkvm::ProverOpts::succinct();
|
||||||
let prove_info = prover
|
let prove_info = prover
|
||||||
.prove_with_opts(env, nomos_cl_risc0_proofs::INPUT_ELF, &opts)
|
.prove_with_opts(env, nomos_cl_risc0_proofs::INPUT_ELF, &opts)
|
||||||
.unwrap();
|
.map_err(|_| Error::Risc0ProofFailed)?;
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"STARK 'input' prover time: {:.2?}, total_cycles: {}",
|
"STARK 'input' prover time: {:.2?}, total_cycles: {}",
|
||||||
|
@ -52,13 +55,13 @@ impl ProvedInput {
|
||||||
// extract the receipt.
|
// extract the receipt.
|
||||||
let receipt = prove_info.receipt;
|
let receipt = prove_info.receipt;
|
||||||
|
|
||||||
Self {
|
Ok(Self {
|
||||||
input: InputPublic {
|
input: InputPublic {
|
||||||
cm_root: cl::merkle::root(cm_leaves),
|
cm_root: cl::merkle::root(cm_leaves),
|
||||||
input: input.commit(),
|
input: input.commit(),
|
||||||
},
|
},
|
||||||
risc0_receipt: receipt,
|
risc0_receipt: receipt,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn public(&self) -> Result<InputPublic> {
|
pub fn public(&self) -> Result<InputPublic> {
|
||||||
|
@ -103,7 +106,7 @@ mod test {
|
||||||
|
|
||||||
let notes = vec![input.note_commitment()];
|
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 {
|
let expected_public_inputs = InputPublic {
|
||||||
cm_root: cl::merkle::root(note_commitment_leaves(¬es)),
|
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 struct ProvedOutput {
|
||||||
pub output: cl::Output,
|
pub output: cl::Output,
|
||||||
|
@ -6,7 +6,7 @@ pub struct ProvedOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProvedOutput {
|
impl ProvedOutput {
|
||||||
pub fn prove(witness: &cl::OutputWitness) -> Self {
|
pub fn prove(witness: &cl::OutputWitness) -> Result<Self> {
|
||||||
let env = risc0_zkvm::ExecutorEnv::builder()
|
let env = risc0_zkvm::ExecutorEnv::builder()
|
||||||
.write(&witness)
|
.write(&witness)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -20,7 +20,7 @@ impl ProvedOutput {
|
||||||
let opts = risc0_zkvm::ProverOpts::succinct();
|
let opts = risc0_zkvm::ProverOpts::succinct();
|
||||||
let prove_info = prover
|
let prove_info = prover
|
||||||
.prove_with_opts(env, nomos_cl_risc0_proofs::OUTPUT_ELF, &opts)
|
.prove_with_opts(env, nomos_cl_risc0_proofs::OUTPUT_ELF, &opts)
|
||||||
.unwrap();
|
.map_err(|_| Error::Risc0ProofFailed)?;
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"STARK 'output' prover time: {:.2?}, total_cycles: {}",
|
"STARK 'output' prover time: {:.2?}, total_cycles: {}",
|
||||||
|
@ -30,10 +30,10 @@ impl ProvedOutput {
|
||||||
|
|
||||||
let receipt = prove_info.receipt;
|
let receipt = prove_info.receipt;
|
||||||
|
|
||||||
Self {
|
Ok(Self {
|
||||||
output: witness.commit(),
|
output: witness.commit(),
|
||||||
risc0_receipt: receipt,
|
risc0_receipt: receipt,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn public(&self) -> Result<cl::Output> {
|
pub fn public(&self) -> Result<cl::Output> {
|
||||||
|
@ -70,7 +70,7 @@ mod test {
|
||||||
nonce: cl::NullifierNonce::random(&mut rng),
|
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();
|
let expected_output_cm = output.commit();
|
||||||
|
|
||||||
|
@ -100,4 +100,17 @@ mod test {
|
||||||
assert!(!proved_output.verify());
|
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 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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PartialTxInput {
|
pub struct PartialTxInput {
|
||||||
|
@ -29,18 +31,27 @@ impl ProvedPartialTx {
|
||||||
ptx: &cl::PartialTxWitness,
|
ptx: &cl::PartialTxWitness,
|
||||||
mut death_proofs: BTreeMap<cl::Nullifier, DeathProof>,
|
mut death_proofs: BTreeMap<cl::Nullifier, DeathProof>,
|
||||||
note_commitments: &[cl::NoteCommitment],
|
note_commitments: &[cl::NoteCommitment],
|
||||||
) -> ProvedPartialTx {
|
) -> Result<ProvedPartialTx> {
|
||||||
Self {
|
let inputs = ptx
|
||||||
inputs: Vec::from_iter(ptx.inputs.iter().map(|i| {
|
.inputs
|
||||||
PartialTxInput {
|
.iter()
|
||||||
input: ProvedInput::prove(i, note_commitments),
|
.map(|i| {
|
||||||
|
Ok(PartialTxInput {
|
||||||
|
input: ProvedInput::prove(i, note_commitments)?,
|
||||||
death: death_proofs
|
death: death_proofs
|
||||||
.remove(&i.nullifier())
|
.remove(&i.nullifier())
|
||||||
.expect("Input missing death proof"),
|
.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 {
|
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 ...
|
// assume we only have one note commitment on chain for now ...
|
||||||
let note_commitments = vec![utxo.commit_note()];
|
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.
|
assert!(proved_ptx.verify()); // It's a valid ptx.
|
||||||
|
|
||||||
|
@ -80,6 +80,6 @@ fn test_simple_transfer() {
|
||||||
balance_blinding: ptx_witness.balance_blinding(),
|
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.
|
assert!(proved_bundle.verify()); // The bundle is balanced.
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,12 @@ use risc0_zkvm::guest::env;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let output: cl::OutputWitness = env::read();
|
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();
|
let output_cm = output.commit();
|
||||||
env::commit(&output_cm);
|
env::commit(&output_cm);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue