Skip to main content

nam_bellperson/
lib.rs

1#![allow(clippy::suspicious_arithmetic_impl)]
2//! `bellperson` is a crate for building zk-SNARK circuits. It provides circuit
3//! traits and and primitive structures, as well as basic gadget implementations
4//! such as booleans and number abstractions.
5//!
6//! # Example circuit
7//!
8//! Say we want to write a circuit that proves we know the preimage to some hash
9//! computed using SHA-256d (calling SHA-256 twice). The preimage must have a
10//! fixed length known in advance (because the circuit parameters will depend on
11//! it), but can otherwise have any value. We take the following strategy:
12//!
13//! - Witness each bit of the preimage.
14//! - Compute `hash = SHA-256d(preimage)` inside the circuit.
15//! - Expose `hash` as a public input using multiscalar packing.
16//!
17//! ```no_run
18//! # #[cfg(not(feature = "cuda-supraseal"))]
19//! # {
20//! use nam_bellperson::{
21//!     gadgets::{
22//!         boolean::{AllocatedBit, Boolean},
23//!         multipack,
24//!         sha256::sha256,
25//!     },
26//!     groth16, Circuit, ConstraintSystem, SynthesisError,
27//! };
28//! use blstrs::Bls12;
29//! use ff::PrimeField;
30//! use pairing::Engine;
31//! use rand::rngs::OsRng;
32//! use sha2::{Digest, Sha256};
33//!
34//! /// Our own SHA-256d gadget. Input and output are in little-endian bit order.
35//! fn sha256d<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
36//!     mut cs: CS,
37//!     data: &[Boolean],
38//! ) -> Result<Vec<Boolean>, SynthesisError> {
39//!     // Flip endianness of each input byte
40//!     let input: Vec<_> = data
41//!         .chunks(8)
42//!         .map(|c| c.iter().rev())
43//!         .flatten()
44//!         .cloned()
45//!         .collect();
46//!
47//!     let mid = sha256(cs.namespace(|| "SHA-256(input)"), &input)?;
48//!     let res = sha256(cs.namespace(|| "SHA-256(mid)"), &mid)?;
49//!
50//!     // Flip endianness of each output byte
51//!     Ok(res
52//!         .chunks(8)
53//!         .map(|c| c.iter().rev())
54//!         .flatten()
55//!         .cloned()
56//!         .collect())
57//! }
58//!
59//! struct MyCircuit {
60//!     /// The input to SHA-256d we are proving that we know. Set to `None` when we
61//!     /// are verifying a proof (and do not have the witness data).
62//!     preimage: Option<[u8; 80]>,
63//! }
64//!
65//! impl<Scalar: PrimeField> Circuit<Scalar> for MyCircuit {
66//!     fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
67//!         // Compute the values for the bits of the preimage. If we are verifying a proof,
68//!         // we still need to create the same constraints, so we return an equivalent-size
69//!         // Vec of None (indicating that the value of each bit is unknown).
70//!         let bit_values = if let Some(preimage) = self.preimage {
71//!             preimage
72//!                 .iter()
73//!                 .map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8))
74//!                 .flatten()
75//!                 .map(|b| Some(b))
76//!                 .collect()
77//!         } else {
78//!             vec![None; 80 * 8]
79//!         };
80//!         assert_eq!(bit_values.len(), 80 * 8);
81//!
82//!         // Witness the bits of the preimage.
83//!         let preimage_bits = bit_values
84//!             .into_iter()
85//!             .enumerate()
86//!             // Allocate each bit.
87//!             .map(|(i, b)| {
88//!                 AllocatedBit::alloc(cs.namespace(|| format!("preimage bit {}", i)), b)
89//!             })
90//!             // Convert the AllocatedBits into Booleans (required for the sha256 gadget).
91//!             .map(|b| b.map(Boolean::from))
92//!             .collect::<Result<Vec<_>, _>>()?;
93//!
94//!         // Compute hash = SHA-256d(preimage).
95//!         let hash = sha256d(cs.namespace(|| "SHA-256d(preimage)"), &preimage_bits)?;
96//!
97//!         // Expose the vector of 32 boolean variables as compact public inputs.
98//!         multipack::pack_into_inputs(cs.namespace(|| "pack hash"), &hash)
99//!     }
100//! }
101//!
102//! // Create parameters for our circuit. In a production deployment these would
103//! // be generated securely using a multiparty computation.
104//! let params = {
105//!     let c = MyCircuit { preimage: None };
106//!     groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
107//! };
108//!
109//! // Prepare the verification key (for proof verification).
110//! let pvk = groth16::prepare_verifying_key(&params.vk);
111//!
112//! // Pick a preimage and compute its hash.
113//! let preimage = [42; 80];
114//! let hash = Sha256::digest(&Sha256::digest(&preimage));
115//!
116//! // Create an instance of our circuit (with the preimage as a witness).
117//! let c = MyCircuit {
118//!     preimage: Some(preimage),
119//! };
120//!
121//! // Create a Groth16 proof with our parameters.
122//! let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();
123//!
124//! // Pack the hash as inputs for proof verification.
125//! let hash_bits = multipack::bytes_to_bits_le(&hash);
126//! let inputs = multipack::compute_multipacking::<<Bls12 as Engine>::Fr>(&hash_bits);
127//!
128//! // Check the proof!
129//! assert!(groth16::verify_proof(&pvk, &proof, &inputs).unwrap());
130//! # }
131//! ```
132//!
133//! # Roadmap
134//!
135//! `bellperson` is being refactored into a generic proving library. Currently it
136//! is pairing-specific, and different types of proving systems need to be
137//! implemented as sub-modules. After the refactor, `bellperson` will be generic
138//! using the [`ff`] and [`group`] crates, while specific proving systems will
139//! be separate crates that pull in the dependencies they require.
140
141#![cfg_attr(
142    all(target_arch = "aarch64", nightly),
143    feature(stdarch_aarch64_prefetch)
144)]
145
146#[cfg(test)]
147#[macro_use]
148extern crate hex_literal;
149
150pub mod domain;
151pub mod gadgets;
152pub mod gpu;
153#[cfg(feature = "groth16")]
154pub mod groth16;
155pub mod multiexp;
156pub mod util_cs;
157
158pub(crate) mod lc;
159pub use bellpepper_core::{Circuit, ConstraintSystem, Namespace, SynthesisError};
160pub use bellpepper_core::{Index, LinearCombination, Variable};
161
162pub const BELLMAN_VERSION: &str = env!("CARGO_PKG_VERSION");
163
164#[cfg(feature = "groth16")]
165pub(crate) fn le_bytes_to_u64s(le_bytes: &[u8]) -> Vec<u64> {
166    assert_eq!(
167        le_bytes.len() % 8,
168        0,
169        "length must be divisible by u64 byte length (8-bytes)"
170    );
171    le_bytes
172        .chunks(8)
173        .map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap()))
174        .collect()
175}