Squashed 'bellman/' changes from 4272cfa..2279da4

2279da4 Merge pull request #38 from debris/docs
2e57190 Remove documentation entry from Cargo.toml
346d540 bellman 0.2.0
8d79665 Merge pull request #93 from defuse/qed-it-lrz
f50079f Crate docs
701cb2b Update READMEs
ccf1ee9 CI: Check intra-doc links
ddd390a Add READMEs to Cargo.toml files
54d3122 Add missing cs.is_satisfied() to bellman test
52bf23c Fix build warnings
581ad35 boolean: adds tests for alloc_conditionally
0403396 blake2s: adds test vectors from go-jubjub
9f24e47 Fix blake2s test data length assertion.
42d5b3b Add blake2s test vectors for varying sizes from go-jubjub
b2597de pedersen_hash: removes debug prints
c903fad pedersen hashes: example of size limit bug
bc697c1 bellman: Fix compile errors without multicore feature
a4e5df9 Upgrade to hex-literal 0.2
c063509 Migrate bellman to crossbeam 0.7
1775843 Take self directly in into_* functions
614d784 Rename into_ -> to_ where &self is used.
08664b1 Address various clippy warnings/errors in bellman
bb11ef2 cargo fmt
cff2e2f cargo fix --edition-idioms for bellman
dc2a280 Add edition = 2018
1a2bc19 cargo fmt
ad37878 cargo fix --edition for bellman
e73d1a2 cargo fmt bellman
dfb86fc Move generic circuit gadgets into bellman
9b3d766 Migrate to rand 0.7
055280f Migrate ff, group, pairing, and bellman to rand 0.6
533d586 Migrate bellman to rand 0.5
bfa9aaf Merge pull request #61 from rex4539/fix-typos
3dd8490 Place bellman multicore operations behind a (default) feature flag
955e679 Merge pull request #46 from str4d/ff-traits
d4ddaa9 Fix typos
12f93f2 Add ff and group crates to Cargo workspace
2e35a32 Update sapling-crypto crate to use ff crate
2019e63 Update workspace after pulling in external crates

git-subtree-dir: bellman
git-subtree-split: 2279da422ca9d7b83e84cb85018c713976b873e5
This commit is contained in:
Sean Bowe
2020-03-03 17:46:04 -07:00
parent 76cd0d92bb
commit f337eb1f5c
140 changed files with 3568 additions and 34478 deletions

229
tests/mimc.rs Normal file
View File

@@ -0,0 +1,229 @@
// For randomness (during paramgen and proof generation)
use rand::thread_rng;
// For benchmarking
use std::time::{Duration, Instant};
// Bring in some tools for using pairing-friendly curves
use ff::{Field, ScalarEngine};
use pairing::Engine;
// We're going to use the BLS12-381 pairing-friendly elliptic curve.
use pairing::bls12_381::Bls12;
// We'll use these interfaces to construct our circuit.
use bellman::{Circuit, ConstraintSystem, SynthesisError};
// We're going to use the Groth16 proving system.
use bellman::groth16::{
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof,
};
const MIMC_ROUNDS: usize = 322;
/// This is an implementation of MiMC, specifically a
/// variant named `LongsightF322p3` for BLS12-381.
/// See http://eprint.iacr.org/2016/492 for more
/// information about this construction.
///
/// ```
/// function LongsightF322p3(xL ⦂ Fp, xR ⦂ Fp) {
/// for i from 0 up to 321 {
/// xL, xR := xR + (xL + Ci)^3, xL
/// }
/// return xL
/// }
/// ```
fn mimc<E: Engine>(mut xl: E::Fr, mut xr: E::Fr, constants: &[E::Fr]) -> E::Fr {
assert_eq!(constants.len(), MIMC_ROUNDS);
for i in 0..MIMC_ROUNDS {
let mut tmp1 = xl;
tmp1.add_assign(&constants[i]);
let mut tmp2 = tmp1;
tmp2.square();
tmp2.mul_assign(&tmp1);
tmp2.add_assign(&xr);
xr = xl;
xl = tmp2;
}
xl
}
/// This is our demo circuit for proving knowledge of the
/// preimage of a MiMC hash invocation.
struct MiMCDemo<'a, E: Engine> {
xl: Option<E::Fr>,
xr: Option<E::Fr>,
constants: &'a [E::Fr],
}
/// Our demo circuit implements this `Circuit` trait which
/// is used during paramgen and proving in order to
/// synthesize the constraint system.
impl<'a, E: Engine> Circuit<E> for MiMCDemo<'a, E> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
assert_eq!(self.constants.len(), MIMC_ROUNDS);
// Allocate the first component of the preimage.
let mut xl_value = self.xl;
let mut xl = cs.alloc(
|| "preimage xl",
|| xl_value.ok_or(SynthesisError::AssignmentMissing),
)?;
// Allocate the second component of the preimage.
let mut xr_value = self.xr;
let mut xr = cs.alloc(
|| "preimage xr",
|| xr_value.ok_or(SynthesisError::AssignmentMissing),
)?;
for i in 0..MIMC_ROUNDS {
// xL, xR := xR + (xL + Ci)^3, xL
let cs = &mut cs.namespace(|| format!("round {}", i));
// tmp = (xL + Ci)^2
let tmp_value = xl_value.map(|mut e| {
e.add_assign(&self.constants[i]);
e.square();
e
});
let tmp = cs.alloc(
|| "tmp",
|| tmp_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "tmp = (xL + Ci)^2",
|lc| lc + xl + (self.constants[i], CS::one()),
|lc| lc + xl + (self.constants[i], CS::one()),
|lc| lc + tmp,
);
// new_xL = xR + (xL + Ci)^3
// new_xL = xR + tmp * (xL + Ci)
// new_xL - xR = tmp * (xL + Ci)
let new_xl_value = xl_value.map(|mut e| {
e.add_assign(&self.constants[i]);
e.mul_assign(&tmp_value.unwrap());
e.add_assign(&xr_value.unwrap());
e
});
let new_xl = if i == (MIMC_ROUNDS - 1) {
// This is the last round, xL is our image and so
// we allocate a public input.
cs.alloc_input(
|| "image",
|| new_xl_value.ok_or(SynthesisError::AssignmentMissing),
)?
} else {
cs.alloc(
|| "new_xl",
|| new_xl_value.ok_or(SynthesisError::AssignmentMissing),
)?
};
cs.enforce(
|| "new_xL = xR + (xL + Ci)^3",
|lc| lc + tmp,
|lc| lc + xl + (self.constants[i], CS::one()),
|lc| lc + new_xl - xr,
);
// xR = xL
xr = xl;
xr_value = xl_value;
// xL = new_xL
xl = new_xl;
xl_value = new_xl_value;
}
Ok(())
}
}
#[test]
fn test_mimc() {
// This may not be cryptographically safe, use
// `OsRng` (for example) in production software.
let rng = &mut thread_rng();
// Generate the MiMC round constants
let constants = (0..MIMC_ROUNDS)
.map(|_| <Bls12 as ScalarEngine>::Fr::random(rng))
.collect::<Vec<_>>();
println!("Creating parameters...");
// Create parameters for our circuit
let params = {
let c = MiMCDemo::<Bls12> {
xl: None,
xr: None,
constants: &constants,
};
generate_random_parameters(c, rng).unwrap()
};
// Prepare the verification key (for proof verification)
let pvk = prepare_verifying_key(&params.vk);
println!("Creating proofs...");
// Let's benchmark stuff!
const SAMPLES: u32 = 50;
let mut total_proving = Duration::new(0, 0);
let mut total_verifying = Duration::new(0, 0);
// Just a place to put the proof data, so we can
// benchmark deserialization.
let mut proof_vec = vec![];
for _ in 0..SAMPLES {
// Generate a random preimage and compute the image
let xl = <Bls12 as ScalarEngine>::Fr::random(rng);
let xr = <Bls12 as ScalarEngine>::Fr::random(rng);
let image = mimc::<Bls12>(xl, xr, &constants);
proof_vec.truncate(0);
let start = Instant::now();
{
// Create an instance of our circuit (with the
// witness)
let c = MiMCDemo {
xl: Some(xl),
xr: Some(xr),
constants: &constants,
};
// Create a groth16 proof with our parameters.
let proof = create_random_proof(c, &params, rng).unwrap();
proof.write(&mut proof_vec).unwrap();
}
total_proving += start.elapsed();
let start = Instant::now();
let proof = Proof::read(&proof_vec[..]).unwrap();
// Check the proof
assert!(verify_proof(&pvk, &proof, &[image]).unwrap());
total_verifying += start.elapsed();
}
let proving_avg = total_proving / SAMPLES;
let proving_avg =
proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (proving_avg.as_secs() as f64);
let verifying_avg = total_verifying / SAMPLES;
let verifying_avg =
verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (verifying_avg.as_secs() as f64);
println!("Average proving time: {:?} seconds", proving_avg);
println!("Average verifying time: {:?} seconds", verifying_avg);
}