Commit 76fbc03d authored by Roman Walch's avatar Roman Walch
Browse files

add bellman implementations

parent 7233da5a
Copyright (c) 2021 Graz University of Technology
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Cargo.lock
target/
[package]
name = "hash_r1cs"
version = "0.1.0"
authors = ["Roman Walch <roman.walch@iaik.tugraz.at>"]
description = "Rust implementations of different permutations in SNARK"
edition = "2018"
[dependencies]
bellman_ce = {version="0.3.5", default-features=false}
rand = "0.4" # held back for bellman_ce
lazy_static = "1.4"
sha3 = "0.9"
[dev-dependencies]
criterion = "0.3"
[features]
default = []
multicore = ["bellman_ce/multicore"]
[[bench]]
name = "merkle_proof_bls12"
harness = false
[[bench]]
name = "merkle_proof_bn256"
harness = false
[[bench]]
name = "perm_proof_bls12"
harness = false
[[bench]]
name = "perm_proof_bn256"
harness = false
[[bench]]
name = "plain_bls12"
harness = false
[[bench]]
name = "plain_bn256"
harness = false
[[example]]
name = "griffin_mt"
path = "examples/griffin_mt.rs"
[[example]]
name = "rescue_mt"
path = "examples/rescue_mt.rs"
[[example]]
name = "poseidon_mt"
path = "examples/poseidon_mt.rs"
[[example]]
name = "grendel_mt"
path = "examples/grendel_mt.rs"
[[example]]
name = "gmimc_mt"
path = "examples/gmimc_mt.rs"
[[example]]
name = "neptune_mt"
path = "examples/neptune_mt.rs"
[[example]]
name = "griffin"
path = "examples/griffin.rs"
[[example]]
name = "rescue"
path = "examples/rescue.rs"
[[example]]
name = "poseidon"
path = "examples/poseidon.rs"
[[example]]
name = "grendel"
path = "examples/grendel.rs"
[[example]]
name = "gmimc"
path = "examples/gmimc.rs"
[[example]]
name = "neptune"
path = "examples/neptune.rs"
[profile.release]
# Enable link-time optimization, eliminates more code and inlines across crate boundaries.
# Default: false
lto = true
# codegen-units of 1 gives best optimization, but disables parallel building.
# Default: 16
codegen-units = 1
# Includes debug information in release builds. Necessary for profiling. Does not
# slow down the executable.
debug = true
# The default optimization level is 3 for release mode builds.
# 0 means disable optimization and is the default for debug mode buids.
# (Setting opt-level=1 for debug builds is a good way of speeding them up a bit.)
# "s" means optimize for size, "z" reduces size even more.
opt-level = 3
[profile.bench]
# Enable link-time optimization, eliminates more code and inlines across crate boundaries.
# Default: false
lto = true
# codegen-units of 1 gives best optimization, but disables parallel building.
# Default: 16
codegen-units = 1
# Includes debug information in release builds. Necessary for profiling. Does not
# slow down the executable.
debug = true
# The default optimization level is 3 for release mode builds.
# 0 means disable optimization and is the default for debug mode buids.
# (Setting opt-level=1 for debug builds is a good way of speeding them up a bit.)
# "s" means optimize for size, "z" reduces size even more.
opt-level = 3
# Performance Comparison of different Hash Functions for ZKP
This repository contains Rust implementations of different hash functions for Zero-Knowledge applications, as well as implementations of proving knowledge of preimages and witnesses of Merkle-tree accumulators in the [bellman_ce](https://github.com/matter-labs/bellman) library. For benchmarks we refer to [1].
## Hash Functions
The following hash functions are already implemented:
- [Griffin](???)
- [Rescue-Prime](https://www.esat.kuleuven.be/cosic/publications/article-3259.pdf)
- [Poseidon](https://eprint.iacr.org/2019/458.pdf)
- [Neptune](https://eprint.iacr.org/2021/1695.pdf)
- [Grendel](https://eprint.iacr.org/2021/984.pdf)
- [GMiMC](https://eprint.iacr.org/2019/397.pdf) (Updated round numbers as described [here](https://eprint.iacr.org/2021/267.pdf))
[1] Not yet public
use std::sync::Arc;
use bellman_ce::pairing::{bls12_381::Bls12, Engine};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use hash_r1cs::{
circuits::Permutation,
gmimc::{
gmimc::Gmimc, gmimc_circuit::GmimcCircuit, gmimc_instance_bls12::*,
gmimc_params::GmimcParams,
},
grendel::{
grendel::Grendel, grendel_circuit::GrendelCircuit, grendel_instance_bls12::*,
grendel_params::GrendelParams,
},
griffin::{
griffin::Griffin, griffin_circuit::GriffinCircuit, griffin_instances::*,
griffin_params::GriffinParams,
},
merkle_groth::MerkleGroth,
merkle_tree::MerkleTree,
mt_circuit::MerkleTreeCircuit,
neptune::{
neptune::Neptune, neptune_circuit::NeptuneCircuit, neptune_instances::*,
neptune_params::NeptuneParams,
},
poseidon::{
poseidon::Poseidon, poseidon_circuit::PoseidonCircuit, poseidon_instance_bls12::*,
poseidon_params::PoseidonParams,
},
rescue::{
rescue::Rescue, rescue_circuit::RescueCircuit, rescue_instance_bls12::*,
rescue_params::RescueParams,
},
utils,
};
use rand::{
distributions::{IndependentSample, Range},
thread_rng,
};
fn sample_set<E: Engine>(set_size: usize) -> Vec<E::Fr> {
// (0..set_size).map(|_| utils::random_scalar(true)).collect()
(0..set_size).map(|i| utils::from_u64(i as u64)).collect()
}
fn rescue_proof_verify<E: Engine>(
c: &mut Criterion,
params: &Arc<RescueParams<E::Fr>>,
log_set_size: usize,
) {
let perm = Rescue::new(params);
let t = perm.get_t();
let mut mt = MerkleTree::new(perm);
let set_size = 1 << log_set_size;
let arity = mt.get_arity();
let levels = f64::ceil((set_size as f64).log(arity as f64)) as usize;
let mut rng = thread_rng();
let dist: Range<usize> = Range::new(0, set_size);
let perm_circ = RescueCircuit::new(params);
let mt_circ = MerkleTreeCircuit::new(perm_circ, levels, arity);
let mut groth = MerkleGroth::<E, RescueCircuit<E>>::new(mt_circ);
groth.create_crs(&mut rng);
let pvk = groth.create_verify_key();
let set: Vec<E::Fr> = sample_set::<E>(set_size);
let index = dist.ind_sample(&mut rng);
mt.accumulate(&set);
let wit = mt.create_witness(&set[index]).unwrap();
let root = mt.get_root().unwrap();
let proof = groth.create_proof(&set[index], &wit, &mut rng);
let id = format!(
"Rescue MT BLS proof (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let proof =
groth.create_proof(black_box(&set[index]), black_box(&wit), black_box(&mut rng));
black_box(proof)
});
});
let id = format!(
"Rescue MT BLS verify (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let res = MerkleGroth::<E, RescueCircuit<E>>::verify_proof(
black_box(&pvk),
black_box(&proof),
black_box(&root),
);
black_box(res)
});
});
}
fn poseidon_proof_verify<E: Engine>(
c: &mut Criterion,
params: &Arc<PoseidonParams<E::Fr>>,
log_set_size: usize,
) {
let perm = Poseidon::new(params);
let t = perm.get_t();
let mut mt = MerkleTree::new(perm);
let set_size = 1 << log_set_size;
let arity = mt.get_arity();
let levels = f64::ceil((set_size as f64).log(arity as f64)) as usize;
let mut rng = thread_rng();
let dist: Range<usize> = Range::new(0, set_size);
let perm_circ = PoseidonCircuit::new(params);
let mt_circ = MerkleTreeCircuit::new(perm_circ, levels, arity);
let mut groth = MerkleGroth::<E, PoseidonCircuit<E>>::new(mt_circ);
groth.create_crs(&mut rng);
let pvk = groth.create_verify_key();
let set: Vec<E::Fr> = sample_set::<E>(set_size);
let index = dist.ind_sample(&mut rng);
mt.accumulate(&set);
let wit = mt.create_witness(&set[index]).unwrap();
let root = mt.get_root().unwrap();
let proof = groth.create_proof(&set[index], &wit, &mut rng);
let id = format!(
"Poseidon MT BLS proof (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let proof =
groth.create_proof(black_box(&set[index]), black_box(&wit), black_box(&mut rng));
black_box(proof)
});
});
let id = format!(
"Poseidon MT BLS verify (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let res = MerkleGroth::<E, PoseidonCircuit<E>>::verify_proof(
black_box(&pvk),
black_box(&proof),
black_box(&root),
);
black_box(res)
});
});
}
fn griffin_proof_verify<E: Engine>(
c: &mut Criterion,
params: &Arc<GriffinParams<E::Fr>>,
log_set_size: usize,
) {
let perm = Griffin::new(params);
let t = perm.get_t();
let mut mt = MerkleTree::new(perm);
let set_size = 1 << log_set_size;
let arity = mt.get_arity();
let levels = f64::ceil((set_size as f64).log(arity as f64)) as usize;
let mut rng = thread_rng();
let dist: Range<usize> = Range::new(0, set_size);
let perm_circ = GriffinCircuit::new(params);
let mt_circ = MerkleTreeCircuit::new(perm_circ, levels, arity);
let mut groth = MerkleGroth::<E, GriffinCircuit<E>>::new(mt_circ);
groth.create_crs(&mut rng);
let pvk = groth.create_verify_key();
let set: Vec<E::Fr> = sample_set::<E>(set_size);
let index = dist.ind_sample(&mut rng);
mt.accumulate(&set);
let wit = mt.create_witness(&set[index]).unwrap();
let root = mt.get_root().unwrap();
let proof = groth.create_proof(&set[index], &wit, &mut rng);
let id = format!(
"Griffin MT BLS proof (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let proof =
groth.create_proof(black_box(&set[index]), black_box(&wit), black_box(&mut rng));
black_box(proof)
});
});
let id = format!(
"Griffin MT BLS verify (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let res = MerkleGroth::<E, GriffinCircuit<E>>::verify_proof(
black_box(&pvk),
black_box(&proof),
black_box(&root),
);
black_box(res)
});
});
}
fn grendel_proof_verify<E: Engine>(
c: &mut Criterion,
params: &Arc<GrendelParams<E::Fr>>,
log_set_size: usize,
) {
let perm = Grendel::new(params);
let t = perm.get_t();
let mut mt = MerkleTree::new(perm);
let set_size = 1 << log_set_size;
let arity = mt.get_arity();
let levels = f64::ceil((set_size as f64).log(arity as f64)) as usize;
let mut rng = thread_rng();
let dist: Range<usize> = Range::new(0, set_size);
let perm_circ = GrendelCircuit::new(params);
let mt_circ = MerkleTreeCircuit::new(perm_circ, levels, arity);
let mut groth = MerkleGroth::<E, GrendelCircuit<E>>::new(mt_circ);
groth.create_crs(&mut rng);
let pvk = groth.create_verify_key();
let set: Vec<E::Fr> = sample_set::<E>(set_size);
let index = dist.ind_sample(&mut rng);
mt.accumulate(&set);
let wit = mt.create_witness(&set[index]).unwrap();
let root = mt.get_root().unwrap();
let proof = groth.create_proof(&set[index], &wit, &mut rng);
let id = format!(
"Grendel MT BLS proof (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let proof =
groth.create_proof(black_box(&set[index]), black_box(&wit), black_box(&mut rng));
black_box(proof)
});
});
let id = format!(
"Grendel MT BLS verify (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let res = MerkleGroth::<E, GrendelCircuit<E>>::verify_proof(
black_box(&pvk),
black_box(&proof),
black_box(&root),
);
black_box(res)
});
});
}
fn gmimc_proof_verify<E: Engine>(
c: &mut Criterion,
params: &Arc<GmimcParams<E::Fr>>,
log_set_size: usize,
) {
let perm = Gmimc::new(params);
let t = perm.get_t();
let mut mt = MerkleTree::new(perm);
let set_size = 1 << log_set_size;
let arity = mt.get_arity();
let levels = f64::ceil((set_size as f64).log(arity as f64)) as usize;
let mut rng = thread_rng();
let dist: Range<usize> = Range::new(0, set_size);
let perm_circ = GmimcCircuit::new(params);
let mt_circ = MerkleTreeCircuit::new(perm_circ, levels, arity);
let mut groth = MerkleGroth::<E, GmimcCircuit<E>>::new(mt_circ);
groth.create_crs(&mut rng);
let pvk = groth.create_verify_key();
let set: Vec<E::Fr> = sample_set::<E>(set_size);
let index = dist.ind_sample(&mut rng);
mt.accumulate(&set);
let wit = mt.create_witness(&set[index]).unwrap();
let root = mt.get_root().unwrap();
let proof = groth.create_proof(&set[index], &wit, &mut rng);
let id = format!(
"Gmimc MT BLS proof (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let proof =
groth.create_proof(black_box(&set[index]), black_box(&wit), black_box(&mut rng));
black_box(proof)
});
});
let id = format!(
"Gmimc MT BLS verify (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let res = MerkleGroth::<E, GmimcCircuit<E>>::verify_proof(
black_box(&pvk),
black_box(&proof),
black_box(&root),
);
black_box(res)
});
});
}
fn neptune_proof_verify<E: Engine>(
c: &mut Criterion,
params: &Arc<NeptuneParams<E::Fr>>,
log_set_size: usize,
) {
let perm = Neptune::new(params);
let t = perm.get_t();
let mut mt = MerkleTree::new(perm);
let set_size = 1 << log_set_size;
let arity = mt.get_arity();
let levels = f64::ceil((set_size as f64).log(arity as f64)) as usize;
let mut rng = thread_rng();
let dist: Range<usize> = Range::new(0, set_size);
let perm_circ = NeptuneCircuit::new(params);
let mt_circ = MerkleTreeCircuit::new(perm_circ, levels, arity);
let mut groth = MerkleGroth::<E, NeptuneCircuit<E>>::new(mt_circ);
groth.create_crs(&mut rng);
let pvk = groth.create_verify_key();
let set: Vec<E::Fr> = sample_set::<E>(set_size);
let index = dist.ind_sample(&mut rng);
mt.accumulate(&set);
let wit = mt.create_witness(&set[index]).unwrap();
let root = mt.get_root().unwrap();
let proof = groth.create_proof(&set[index], &wit, &mut rng);
let id = format!(
"Neptune MT BLS proof (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let proof =
groth.create_proof(black_box(&set[index]), black_box(&wit), black_box(&mut rng));
black_box(proof)
});
});
let id = format!(
"Neptune MT BLS verify (t = {}, set_size = 2^{})",
t, log_set_size
);
c.bench_function(&id, move |bench| {
bench.iter(|| {
let res = MerkleGroth::<E, NeptuneCircuit<E>>::verify_proof(
black_box(&pvk),
black_box(&proof),
black_box(&root),
);
black_box(res)
});
});
}
fn criterion_benchmark_mt_proof_bls12(c: &mut Criterion) {
let log_set_sizes = vec![24];
for log_set_size in log_set_sizes {
rescue_proof_verify::<Bls12>(c, &RESCUE_BLS_3_PARAMS, log_set_size);
rescue_proof_verify::<Bls12>(c, &RESCUE_BLS_4_PARAMS, log_set_size);
rescue_proof_verify::<Bls12>(c, &RESCUE_BLS_5_PARAMS, log_set_size);
rescue_proof_verify::<Bls12>(c, &RESCUE_BLS_8_PARAMS, log_set_size);
rescue_proof_verify::<Bls12>(c, &RESCUE_BLS_9_PARAMS, log_set_size);
rescue_proof_verify::<Bls12>(c, &RESCUE_BLS_12_PARAMS, log_set_size);
poseidon_proof_verify::<Bls12>(c, &POSEIDON_BLS_3_PARAMS, log_set_size);
poseidon_proof_verify::<Bls12>(c, &POSEIDON_BLS_4_PARAMS, log_set_size);
poseidon_proof_verify::<Bls12>(c, &POSEIDON_BLS_5_PARAMS, log_set_size);
poseidon_proof_verify::<Bls12>(c, &POSEIDON_BLS_8_PARAMS, log_set_size);
poseidon_proof_verify::<Bls12>(c, &POSEIDON_BLS_9_PARAMS, log_set_size);
poseidon_proof_verify::<Bls12>(c, &POSEIDON_BLS_12_PARAMS, log_set_size);
griffin_proof_verify::<Bls12>(c, &GRIFFIN_BLS_3_PARAMS, log_set_size);
griffin_proof_verify::<Bls12>(c, &GRIFFIN_BLS_4_PARAMS, log_set_size);
griffin_proof_verify::<Bls12>(c, &GRIFFIN_BLS_8_PARAMS, log_set_size);
griffin_proof_verify::<Bls12>(c, &GRIFFIN_BLS_12_PARAMS, log_set_size);
grendel_proof_verify::<Bls12>(c, &GRENDEL_BLS_3_PARAMS, log_set_size);
grendel_proof_verify::<Bls12>(c, &GRENDEL_BLS_4_PARAMS, log_set_size);
grendel_proof_verify::<Bls12>(c, &GRENDEL_BLS_5_PARAMS, log_set_size);
grendel_proof_verify::<Bls12>(c, &GRENDEL_BLS_8_PARAMS, log_set_size);
grendel_proof_verify::<Bls12>(c, &GRENDEL_BLS_9_PARAMS, log_set_size);
grendel_proof_verify::<Bls12>(c, &GRENDEL_BLS_12_PARAMS, log_set_size);
gmimc_proof_verify::<Bls12>(c, &GMIMC_BLS_3_PARAMS, log_set_size);
gmimc_proof_verify::<Bls12>(c, &GMIMC_BLS_4_PARAMS, log_set_size);
gmimc_proof_verify::<Bls12>(c, &GMIMC_BLS_5_PARAMS, log_set_size);
gmimc_proof_verify::<Bls12>(c, &GMIMC_BLS_8_PARAMS, log_set_size);
gmimc_proof_verify::<Bls12>(c, &GMIMC_BLS_9_PARAMS, log_set_size);
gmimc_proof_verify::<Bls12>(c, &GMIMC_BLS_12_PARAMS, log_set_size);
neptune_proof_verify::<Bls12>(c, &NEPTUNE_BLS_4_PARAMS, log_set_size);
neptune_proof_verify::<Bls12>(c, &NEPTUNE_BLS_8_PARAMS, log_set_size);
neptune_proof_verify::<Bls12>(c, &NEPTUNE_BLS_12_PARAMS, log_set_size);
}
}
criterion_group!(
name = benches;
config = Criterion::default();
targets = criterion_benchmark_mt_proof_bls12
);
criterion_main!(benches);