Proving
To make a proof, you must supply all of the arguments defined in your ZKP program function.
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 )?; Ok(()) }
Recall that zkp_program
arguments should appear in order private, public,
constant to match the prove
call.
Excluding the compiled ZKP program, all other arguments must be passed in via a Vec.
Let's break down the arguments to runtime.prove
:
- The first argument must be the compiled ZKP program
- The second argument must be private inputs (only viewable by the prover)
- The third argument must be be any public inputs (which are viewable by both the prover and verifier)
- The fourth argument must be any constant inputs (constant inputs are an advanced feature so this will often be empty!)
Notice that proof generation is a fallible operation. If you try to construct an invalid proof, the runtime will return an error, so that you don't end up trying to send an invalid proof to a verifier, only to be rejected later. This is for developer convenience; please note that security does not rely on this API decision.
ZKP proof builder
One issue you may run into is that prove
accepts vectors of type I: Into<ZkpProgramInput>
. In Rust, elements in a Vec
must all have the same
type. Consequently, if you have arguments with varying types, you'd have to
convert them all to ZkpProgramInput
.
However, we offer a convenient builder method for precisely this reason:
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>, #[private] 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) .private_input(x) .private_input(z) .public_input(ys) .prove()?; Ok(()) }