├── .gitignore ├── Cargo.toml ├── README.md └── src ├── cube.rs ├── main.rs └── multiply.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Jay Graber "] 3 | description = "examples for bellman zk-SNARK library" 4 | license = "MIT/Apache-2.0" 5 | name = "bellman-tutorial" 6 | version = "0.1.0" 7 | 8 | [dependencies] 9 | rand = "0.4" 10 | bit-vec = "0.4.4" 11 | pairing = "0.14" 12 | byteorder = "1" 13 | bellman = "0.1.0" 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bellman examples 2 | 3 | Examples of circuits for [bellman](https://github.com/zkcrypto/bellman/), a Rust zk-SNARKs library. 4 | 5 | Bellman provides a `Circuit` trait which you can use to synthesize the constraints in your program. 6 | 7 | `multiply.rs` contains a circuit for the statement "I know `x` and `y` such that `x * y = public_input`". 8 | 9 | `cube.rs` contains a circuit for the statement "I know `x` such that `x^3 + x + 5 == 35`" 10 | - This is the same example used in [Vitalik’s blog post](https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649) and [christianlundkvist's libsnark tutorial](https://github.com/christianlundkvist/libsnark-tutorial). 11 | 12 | ### Constructing a circuit 13 | 14 | To construct a circuit, first flatten your program into its constituent steps. 15 | 16 | Allocate the variables, then enforce the constraints. 17 | 18 | Enforcing the constraint takes the form of `A * B = C`. (is a linear combination, vectors of all your variables) 19 | 20 | The `lc` in the `cs.enforce` function stands for "linear combination", and is an inner product of all the variables with some vector of coefficients. 21 | 22 | ### Generating Parameters 23 | 24 | These examples use the function `generate_random_parameters` to generate a random set of parameters for testing. For real use cases, these parameters would have to be generated securely, through a multi-party computation. 25 | 26 | ### Creating a proof 27 | 28 | To create a proof, instantiate a version of the struct that is passed into the circuit, with the inputs to the circuit. 29 | 30 | In these examples, the function `create_random_proof` is used to create a random groth16 proof. 31 | 32 | ### Verifying a proof 33 | 34 | To verify a proof, prepare the verifying key by passing in `params.vk` to `prepare_verifying_key`. This gives you the prepared viewing key, `pvk`. 35 | 36 | The function `verify_proof` takes the prepared viewing key `pvk`, the `proof`, and the output as an array. 37 | 38 | ## Running 39 | 40 | `cargo build` 41 | 42 | `cargo test` runs test proofs using both example circuits. Tests are located at the bottom of their source files. 43 | 44 | `cargo run` runs the `cube.rs` example proof in the main file. 45 | -------------------------------------------------------------------------------- /src/cube.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | #![allow(unused_variables)] 3 | extern crate bellman; 4 | extern crate pairing; 5 | extern crate rand; 6 | 7 | // For randomness (during paramgen and proof generation) 8 | use self::rand::{thread_rng, Rng}; 9 | 10 | // Bring in some tools for using pairing-friendly curves 11 | use self::pairing::{ 12 | Engine, 13 | Field, 14 | PrimeField 15 | }; 16 | 17 | // We're going to use the BLS12-381 pairing-friendly elliptic curve. 18 | use self::pairing::bls12_381::{ 19 | Bls12, 20 | Fr 21 | }; 22 | 23 | // We'll use these interfaces to construct our circuit. 24 | use self::bellman::{ 25 | Circuit, 26 | ConstraintSystem, 27 | SynthesisError 28 | }; 29 | 30 | // We're going to use the Groth16 proving system. 31 | use self::bellman::groth16::{ 32 | Proof, 33 | generate_random_parameters, 34 | prepare_verifying_key, 35 | create_random_proof, 36 | verify_proof, 37 | }; 38 | 39 | // proving that I know x such that x^3 + x + 5 == 35 40 | // Generalized: x^3 + x + 5 == out 41 | pub struct CubeDemo { 42 | pub x: Option, 43 | } 44 | 45 | impl Circuit for CubeDemo { 46 | fn synthesize>( 47 | self, 48 | cs: &mut CS 49 | ) -> Result<(), SynthesisError> 50 | { 51 | // Flattened into quadratic equations (x^3 + x + 5 == 35): 52 | // x * x = tmp_1 53 | // tmp_1 * x = y 54 | // y + x = tmp_2 55 | // tmp_2 + 5 = out 56 | // Resulting R1CS with w = [one, x, tmp_1, y, tmp_2, out] 57 | 58 | // Allocate the first private "auxiliary" variable 59 | let x_val = self.x; 60 | let x = cs.alloc(|| "x", || { 61 | x_val.ok_or(SynthesisError::AssignmentMissing) 62 | })?; 63 | 64 | // Allocate: x * x = tmp_1 65 | let tmp_1_val = x_val.map(|mut e| { 66 | e.square(); 67 | e 68 | }); 69 | let tmp_1 = cs.alloc(|| "tmp_1", || { 70 | tmp_1_val.ok_or(SynthesisError::AssignmentMissing) 71 | })?; 72 | // Enforce: x * x = tmp_1 73 | cs.enforce( 74 | || "tmp_1", 75 | |lc| lc + x, 76 | |lc| lc + x, 77 | |lc| lc + tmp_1 78 | ); 79 | 80 | // Allocate: tmp_1 * x = y 81 | let x_cubed_val = tmp_1_val.map(|mut e| { 82 | e.mul_assign(&x_val.unwrap()); 83 | e 84 | }); 85 | let x_cubed = cs.alloc(|| "x_cubed", || { 86 | x_cubed_val.ok_or(SynthesisError::AssignmentMissing) 87 | })?; 88 | // Enforce: tmp_1 * x = y 89 | cs.enforce( 90 | || "x_cubed", 91 | |lc| lc + tmp_1, 92 | |lc| lc + x, 93 | |lc| lc + x_cubed 94 | ); 95 | 96 | // Allocating the public "primary" output uses alloc_input 97 | let out = cs.alloc_input(|| "out", || { 98 | let mut tmp = x_cubed_val.unwrap(); 99 | tmp.add_assign(&x_val.unwrap()); 100 | tmp.add_assign(&E::Fr::from_str("5").unwrap()); 101 | Ok(tmp) 102 | })?; 103 | // tmp_2 + 5 = out 104 | // => (tmp_2 + 5) * 1 = out 105 | cs.enforce( 106 | || "out", 107 | |lc| lc + x_cubed + x + (E::Fr::from_str("5").unwrap(), CS::one()), 108 | |lc| lc + CS::one(), 109 | |lc| lc + out 110 | ); 111 | // lc is an inner product of all variables with some vector of coefficients 112 | // bunch of variables added together with some coefficients 113 | 114 | // usually if mult by 1 can do more efficiently 115 | // x2 * x = out - x - 5 116 | 117 | // mult quadratic constraints 118 | // 119 | 120 | Ok(()) 121 | } 122 | } 123 | 124 | #[test] 125 | fn test_cube_proof(){ 126 | // This may not be cryptographically safe, use 127 | // `OsRng` (for example) in production software. 128 | let rng = &mut thread_rng(); 129 | 130 | println!("Creating parameters..."); 131 | 132 | // Create parameters for our circuit 133 | let params = { 134 | let c = CubeDemo:: { 135 | x: None 136 | }; 137 | 138 | generate_random_parameters(c, rng).unwrap() 139 | }; 140 | 141 | // Prepare the verification key (for proof verification) 142 | let pvk = prepare_verifying_key(¶ms.vk); 143 | 144 | println!("Creating proofs..."); 145 | 146 | // Create an instance of circuit 147 | let c = CubeDemo:: { 148 | x: Fr::from_str("3") 149 | }; 150 | 151 | // Create a groth16 proof with our parameters. 152 | let proof = create_random_proof(c, ¶ms, rng).unwrap(); 153 | 154 | assert!(verify_proof( 155 | &pvk, 156 | &proof, 157 | &[Fr::from_str("35").unwrap()] 158 | ).unwrap()); 159 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | #![allow(unused_variables)] 3 | extern crate bellman; 4 | extern crate pairing; 5 | extern crate rand; 6 | use bellman::{Circuit, ConstraintSystem, SynthesisError}; 7 | use pairing::{Engine, Field, PrimeField}; 8 | 9 | mod cube; 10 | 11 | fn main(){ 12 | use pairing::bls12_381::{Bls12, Fr}; 13 | use rand::thread_rng; 14 | use bellman::groth16::{ 15 | create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof, 16 | }; 17 | 18 | println!("Prove that I know x such that x^3 + x + 5 == 35."); 19 | 20 | let rng = &mut thread_rng(); 21 | 22 | println!("Creating parameters..."); 23 | 24 | // Create parameters for our circuit 25 | let params = { 26 | let c = cube::CubeDemo:: { 27 | x: None 28 | }; 29 | 30 | generate_random_parameters(c, rng).unwrap() 31 | }; 32 | 33 | // Prepare the verification key (for proof verification) 34 | let pvk = prepare_verifying_key(¶ms.vk); 35 | 36 | println!("Creating proofs..."); 37 | 38 | // Create an instance of circuit 39 | let c = cube::CubeDemo:: { 40 | x: Fr::from_str("3") 41 | }; 42 | 43 | // Create a groth16 proof with our parameters. 44 | let proof = create_random_proof(c, ¶ms, rng).unwrap(); 45 | 46 | assert!(verify_proof( 47 | &pvk, 48 | &proof, 49 | &[Fr::from_str("35").unwrap()] 50 | ).unwrap()); 51 | } -------------------------------------------------------------------------------- /src/multiply.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | #![allow(unused_variables)] 3 | extern crate bellman; 4 | extern crate pairing; 5 | extern crate rand; 6 | 7 | // For randomness (during paramgen and proof generation) 8 | use self::rand::{thread_rng}; 9 | 10 | // Bring in some tools for using pairing-friendly curves 11 | use self::pairing::{ 12 | Engine, 13 | Field, 14 | PrimeField 15 | }; 16 | 17 | // We're going to use the BLS12-381 pairing-friendly elliptic curve. 18 | use self::pairing::bls12_381::{ 19 | Bls12, 20 | Fr, 21 | }; 22 | 23 | // We'll use these interfaces to construct our circuit. 24 | use self::bellman::{ 25 | Circuit, 26 | ConstraintSystem, 27 | SynthesisError 28 | }; 29 | 30 | // We're going to use the Groth16 proving system. 31 | use self::bellman::groth16::{ 32 | Proof, 33 | generate_random_parameters, 34 | prepare_verifying_key, 35 | create_random_proof, 36 | verify_proof, 37 | }; 38 | 39 | // demo circuit 40 | // proving that I know a such that a * 3 = 21 41 | pub struct MultiplyDemo { 42 | pub a: Option, 43 | pub b: Option, 44 | pub c: Option 45 | } 46 | 47 | // create a demo circuit by using the `Circuit` trait which 48 | /// is used during paramgen and proving in order to 49 | /// synthesize the constraint system. 50 | impl Circuit for MultiplyDemo { 51 | fn synthesize>( 52 | self, 53 | cs: &mut CS 54 | ) -> Result<(), SynthesisError> 55 | { 56 | 57 | // Allocate the first value (private) 58 | let a = cs.alloc(|| "a", || { 59 | self.a.ok_or(SynthesisError::AssignmentMissing) 60 | })?; 61 | 62 | // Allocate the second value (private) 63 | let b = cs.alloc(|| "b", || { 64 | self.b.ok_or(SynthesisError::AssignmentMissing) 65 | })?; 66 | 67 | // Allocate the third value (public) 68 | // allocating a public input uses alloc_input 69 | let c = cs.alloc_input(|| "c", || { 70 | self.c.ok_or(SynthesisError::AssignmentMissing) 71 | })?; 72 | 73 | // a * b = c? 74 | cs.enforce( 75 | || "mult", 76 | |lc| lc + a, 77 | |lc| lc + b, 78 | |lc| lc + c 79 | ); 80 | 81 | Ok(()) 82 | } 83 | } 84 | 85 | #[test] 86 | fn test_multiply(){ 87 | // This may not be cryptographically safe, use 88 | // `OsRng` (for example) in production software. 89 | let rng = &mut thread_rng(); 90 | 91 | println!("Creating parameters..."); 92 | 93 | // Create parameters for our circuit 94 | let params = { 95 | let c = MultiplyDemo:: { 96 | a: None, 97 | // make option values as None for these variables, for paramgen 98 | // don't want to bake these nums into parameters 99 | b: None, 100 | c: None 101 | }; 102 | 103 | generate_random_parameters(c, rng).unwrap() 104 | }; 105 | 106 | // Prepare the verification key (for proof verification) 107 | let pvk = prepare_verifying_key(¶ms.vk); 108 | 109 | println!("Creating proofs..."); 110 | 111 | let public_input = Fr::from_str("21"); 112 | 113 | // Create an instance of circuit 114 | let c = MultiplyDemo:: { 115 | a: Fr::from_str("7"), 116 | // when creating instance here, pass in Some of actual variables you're using 117 | b: Fr::from_str("3"), 118 | c: public_input 119 | }; 120 | 121 | // Create a groth16 proof with our parameters. 122 | let proof = create_random_proof(c, ¶ms, rng).unwrap(); 123 | 124 | assert!(verify_proof( 125 | &pvk, 126 | &proof, 127 | &[public_input.unwrap()] 128 | ).unwrap()); 129 | } 130 | 131 | 132 | 133 | 134 | --------------------------------------------------------------------------------