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(¶ms.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, ¶ms, &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}