--- ID: 1548 post_title: 'Bellman: zk-SNARKs in Rust' author: Sean Bowe post_excerpt: "" layout: post permalink: > https://blog.z.cash/bellman-zksnarks-in-rust/ published: true post_date: 2017-04-04 00:00:00 --- Bellman is a Rust-language library for building zk-SNARKs — small, cheap-to-verify zero-knowledge proofs of arbitrary computations. The goal of bellman is to make it easier for the general public to use and experiment with zk-SNARKs, and also as a step forward for improving the security and performance of Zcash's next major release, Sapling. Bellman contains an implementation of the BLS12-381 elliptic curve construction that we described a couple weeks ago, which will appear in an upcoming paper by our scientists. This construction was designed specifically for efficiently building zk-SNARKs, while maintaining a high security margin. This week, I've added a primitive implementation of a new zk-SNARK proving system designed by Jens Groth. Secure in the generic group model, the new design produces smaller proofs that can be constructed faster and with less memory.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
pub trait ConstraintSystem<E: Engine> { /// Allocate a private variable in the constraint system, setting it to /// the provided value. fn alloc(&mut self, value: E::Fr) -> Variable; /// Enforce that `A` * `B` = `C`. fn enforce( &mut self, a: LinearCombination<E>, b: LinearCombination<E>, c: LinearCombination<E> ); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#[derive(Clone)] pub struct Bit { var: Variable, value: bool } impl Bit { pub fn alloc<E, CS>(e: &E, cs: &mut CS, value: bool) -> Bit where E: Engine, CS: ConstraintSystem<E> + ?Sized { // Allocate the variable let var = cs.alloc( if value { E::Fr::one(e) } else { E::Fr::zero() } ); // Enforce (1 - var) * var = 0, which requires // var to be either 0 or 1 cs.enforce( LinearCombination::one(e) - var, LinearCombination::zero(e) + var, LinearCombination::zero(e) ); Bit { var: var, value: value } } pub fn xor<E, CS>(&self, e: &E, cs: &mut CS, other: &Bit) -> Bit where E: Engine, CS: ConstraintSystem<E> { let new_value = self.value ^ other.value; let new_var = cs.alloc( if new_value { E::Fr::one(e) } else { E::Fr::zero() } ); // 2a * b = a + b - c cs.enforce( LinearCombination::zero(e) + self.var + self.var, LinearCombination::zero(e) + other.var, LinearCombination::zero(e) + self.var + other.var - new_var ); Bit { var: new_var, value: new_value } } } |
1 2 3 4 5 6 7 8 9 10 11 |
pub trait Circuit<E: Engine> { type InputMap: Input<E>; fn synthesize<CS: ConstraintSystem<E>>(self, engine: &E, cs: &mut CS) -> Self::InputMap; } pub trait Input<E: Engine> { fn synthesize<CS: PublicConstraintSystem<E>>(self, engine: &E, cs: &mut CS); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// Create a proving key and verifying key let (pk, vk) = { let tau = E::Fr::random(e, rng); let alpha = E::Fr::random(e, rng); let beta = E::Fr::random(e, rng); let gamma = E::Fr::random(e, rng); let delta = E::Fr::random(e, rng); let c = DummyCircuit; groth16::keypair(e, c, &tau, &alpha, &beta, &gamma, &delta) }; // Construct a proof let proof = { let r = E::Fr::random(e, rng); let s = E::Fr::random(e, rng); let c = DummyCircuit; groth16::prove(e, c, &r, &s, &pk).unwrap() }; // Prepare the verifying key let pvk = groth16::prepare_verifying_key(e, &vk); // Verify proof assert!(groth16::verify(e, |cs| { DummyInput }, &proof, &pvk)); |