Verifying
Once we receive a proof, we can verify it!
use sunscreen::{ bulletproofs::BulletproofsBackend, types::zkp::{BulletproofsField, Field, FieldSpec}, zkp_program, zkp_var, Compiler, Error, ZkpRuntime, }; #[zkp_program] fn either<F: FieldSpec>( #[private] x: Field<F>, #[public] y: Field<F>, #[public] z: Field<F>, ) { let zero = zkp_var!(0); let poly = (y - x) * (z - x); poly.constrain_eq(zero); } fn main() -> Result<(), Error> { let app = Compiler::new() .zkp_backend::<BulletproofsBackend>() .zkp_program(either) .compile()?; let either_zkp = app.get_zkp_program(either).unwrap(); // ... let runtime = ZkpRuntime::new(BulletproofsBackend::new())?; let x = BulletproofsField::from(64); let y = BulletproofsField::from(64); let z = BulletproofsField::from(1000); let proof = runtime.prove( either_zkp, // compiled ZKP program vec![x], // private inputs vec![y, z], // public inputs vec![], // constant inputs )?; // Verify the proof runtime.verify( either_zkp, // compiled ZKP program &proof, // the proof to verify vec![y, z], // public inputs vec![], // constant inputs )?; Ok(()) }
Excluding the compiled ZKP program and proof, the remaining arguments must be passed in via a Vec.
Let's break down the arguments to runtime.verify
:
- The first argument will be the compiled ZKP program
- The second argument is the proof that we receive from the prover
- The third argument is any public inputs (viewable to both the prover and verifier)
- The fourth argument is any constant inputs (constant inputs are an advanced feature so this will often be empty)
Notice that, like proof generation, verification is also a fallible operation.
An Err
result indicates that verification of the proof failed and the verifier should
not trust the proof they were given.
ZKP verification builder
The same limitations discussed in the last chapter apply to the verify
method. If you have arguments of varying types, you will find the verification builder much more convenient to use:
use sunscreen::{ bulletproofs::BulletproofsBackend, types::zkp::{BulletproofsField, Field, FieldSpec}, zkp_program, zkp_var, Compiler, Error, ZkpRuntime, ZkpProgramInput, }; #[zkp_program] fn eval<F: FieldSpec>( #[private] x: Field<F>, #[public] z: Field<F>, #[public] ys: [Field<F>; 2], ) { let poly = (ys[0] - x) * (ys[1] - x); poly.constrain_eq(z); } fn main() -> Result<(), Error> { let app = Compiler::new() .zkp_backend::<BulletproofsBackend>() .zkp_program(eval) .compile()?; let eval_zkp = app.get_zkp_program(eval).unwrap(); let runtime = ZkpRuntime::new(BulletproofsBackend::new())?; // ... let x = BulletproofsField::from(64); let z = BulletproofsField::from(0); let ys = [BulletproofsField::from(64), BulletproofsField::from(1000)]; let proof = runtime.proof_builder(eval_zkp) .public_input(z) .public_input(ys) .private_input(x) .prove()?; runtime.verification_builder(eval_zkp) .proof(&proof) .public_input(z) .public_input(ys) .verify()?; Ok(()) }