Files
Sunscreen/sunscreen/tests/zkp_program_tests.rs
Sam Tay badb8f9c8f ZKP tweaks (#279)
* Export type alias for bulletproof backend fields

Also, keep bulletproof stuff namespaced to a `bulletproofs` module.

* Change sudoku to use pub over const

* Docs updates

* Rename / clean up sudoku

* Export `Proof` type

Basically required for being able to deserialize a proof

* Add zkp/serde workspace example

* Drive by cleaning

* Exports necessary for gadget impls

* Rename compute_inputs to compute_hidden_inputs

* Add prove/verify builders

* Export the builder types

This isnt strictly necessary but it would be weird for these to not show up in the cargo docs

* Clippy fix

* Add helper .compile() & .runtime() methods to fhe prog fns

I do wonder if these should be defined in a separate trait, just so that they don't live next to the more internal functions in documentation.

* Use new swag to simplify the front-facing api docs example

* Add some whitespace

* Switch to an extension trait

* Add an extension to ZkpProgramFn

* Take an owned ZkpBackend, rather than reference

Its typical to have the caller handle cloning, rather than taking a reference, requiring Clone impl, and forcing clone. Plus, as of now the only backend is a zero size null struct, so nothing to be gained by using a reference. It also just looks weird to always pass `&BulletproofsBackend::new()`

* Update sudoku to use new swag

* Target second attribute in multi attribute error

* Enforce ordering zkp inputs: constants,public,private

Honestly this feels a little unnatural to me. Might want to reverse: private, public, constant and then change all the prove/verify methods to that ordering

* Build whitelist example in CI

* Reorder constant->public->private to private->public->constant

* Fix trailing ws

* Fix example

* Make .runtime() more consistent with .compile()

* Get rid of some boilerplate impls

* Add custom zkp type example

* Move example run checks into example tests

Should speed up CI a bit

* Change whitelist -> allowlist
2023-07-18 15:15:51 -04:00

213 lines
5.3 KiB
Rust

use sunscreen::{types::zkp::Field, zkp_program, Compiler, Runtime};
use sunscreen_runtime::ZkpProgramInput;
use sunscreen_zkp_backend::{bulletproofs::BulletproofsBackend, FieldSpec, ZkpBackend};
type BPField = Field<<BulletproofsBackend as ZkpBackend>::Field>;
#[test]
fn can_add_and_mul_native_fields() {
#[zkp_program]
fn add_mul<F: FieldSpec>(a: Field<F>, b: Field<F>, c: Field<F>) {
let x = a * b + c;
x.constrain_eq(Field::from(42u32))
}
let app = Compiler::new()
.zkp_backend::<BulletproofsBackend>()
.zkp_program(add_mul)
.compile()
.unwrap();
let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap();
let program = app.get_zkp_program(add_mul).unwrap();
let proof = runtime
.prove(
program,
vec![BPField::from(10u8), BPField::from(4u8), BPField::from(2u8)],
vec![],
vec![],
)
.unwrap();
runtime
.verify(program, &proof, Vec::<ZkpProgramInput>::new(), vec![])
.unwrap();
}
#[test]
fn get_input_mismatch_on_incorrect_args() {
use sunscreen_runtime::Error;
use sunscreen_zkp_backend::Error as ZkpError;
#[zkp_program]
fn add_mul<F: FieldSpec>(a: Field<F>, b: Field<F>) {
let _ = a + b * a;
}
let app = Compiler::new()
.zkp_backend::<BulletproofsBackend>()
.zkp_program(add_mul)
.compile()
.unwrap();
let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap();
let program = app.get_zkp_program(add_mul).unwrap();
let result = runtime.prove(program, vec![BPField::from(0u8)], vec![], vec![]);
assert!(matches!(
result,
Err(Error::ZkpError(ZkpError::InputsMismatch(_)))
));
}
#[test]
fn can_use_public_inputs() {
#[zkp_program]
fn add_mul<F: FieldSpec>(b: Field<F>, c: Field<F>, #[public] a: Field<F>) {
let x = a * b + c;
x.constrain_eq(Field::from(42u32))
}
let app = Compiler::new()
.zkp_backend::<BulletproofsBackend>()
.zkp_program(add_mul)
.compile()
.unwrap();
let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap();
let program = app.get_zkp_program(add_mul).unwrap();
let proof = runtime
.prove(
program,
vec![BPField::from(4u8), BPField::from(2u8)],
vec![BPField::from(10u8)],
vec![],
)
.unwrap();
runtime
.verify(program, &proof, vec![BPField::from(10u8)], vec![])
.unwrap();
}
#[test]
fn can_use_constant_inputs() {
#[zkp_program]
fn add_mul<F: FieldSpec>(b: Field<F>, c: Field<F>, #[constant] a: Field<F>) {
let x = a * b + c;
x.constrain_eq(Field::from(42u32))
}
let app = Compiler::new()
.zkp_backend::<BulletproofsBackend>()
.zkp_program(add_mul)
.compile()
.unwrap();
let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap();
let program = app.get_zkp_program(add_mul).unwrap();
let proof = runtime
.prove(
program,
vec![BPField::from(4u8), BPField::from(2u8)],
vec![],
vec![BPField::from(10u8)],
)
.unwrap();
runtime
.verify(program, &proof, vec![], vec![BPField::from(10u8)])
.unwrap();
}
#[test]
fn can_declare_array_inputs() {
#[zkp_program]
fn in_range<F: FieldSpec>(a: [[Field<F>; 9]; 64]) {
for (i, a_i) in a.iter().enumerate() {
for (j, a_i_j) in a_i.iter().enumerate() {
a_i_j.constrain_eq(Field::from((i + j) as u64));
}
}
}
let app = Compiler::new()
.zkp_backend::<BulletproofsBackend>()
.zkp_program(in_range)
.compile()
.unwrap();
let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap();
let program = app.get_zkp_program(in_range).unwrap();
let inputs = (0..64u64)
.flat_map(|i| (0..9u64).map(|j| BPField::from(i + j)).collect::<Vec<_>>())
.collect::<Vec<_>>();
let proof = runtime.prove(program, inputs, vec![], vec![]).unwrap();
runtime
.verify(program, &proof, Vec::<ZkpProgramInput>::new(), vec![])
.unwrap();
}
#[test]
fn builder_methods_work() {
#[zkp_program]
fn arbitrary<F: FieldSpec>(
x: Field<F>,
ys: [Field<F>; 9],
#[constant] zss: [[Field<F>; 9]; 64],
) {
for y in ys {
x.constrain_eq(y);
}
for zs in zss {
for (y, z) in ys.iter().zip(zs) {
y.constrain_eq(z);
}
}
}
let app = Compiler::new()
.zkp_backend::<BulletproofsBackend>()
.zkp_program(arbitrary)
.compile()
.unwrap();
let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap();
let program = app.get_zkp_program(arbitrary).unwrap();
let x = BPField::from(0);
let ys = [BPField::from(0); 9];
let zss = [[BPField::from(0); 9]; 64];
let proof = runtime
.proof_builder(program)
.constant_input(zss)
.private_input(x)
.private_input(ys)
.prove()
.unwrap();
runtime
.verification_builder(program)
.proof(&proof)
.constant_input(zss)
.verify()
.unwrap();
}