Commit 31f73d18 authored by Markus Schofnegger's avatar Markus Schofnegger
Browse files

update

parent 5b554e26
/target
Cargo.lock
flamegraph.svg
perf.data
perf.data.old
[package]
name = "tplonk"
version = "0.1.0"
authors = ["Roman Walch <roman.walch@iaik.tugraz.at>"]
description = "Rust implementaiton of the ReinforcedConcrete permutation"
edition = "2018"
[dependencies]
ff = {package = "ff_ce", version = "0.13", features = ["derive"] }
rand = "0.4" # held back for ff_ce
lazy_static = "1.4"
cfg-if = "1.0"
sha3 = "0.9"
# for sinsemilla:
group = "0.10"
halo2 = { git = "https://github.com/zcash/halo2.git", rev = "d04b532368d05b505e622f8cac4c0693574fbd93" }
pasta_curves = "0.1"
subtle = "2.3"
random = {package = "rand", version = "0.8"}
# for pederson_hash:
byteorder = "1.4"
jubjub = "0.7"
bls12_381 = "0.5"
[dev-dependencies]
criterion = "0.3"
sha2 = "0.9"
blake2 = "0.9" # SIMD currently broke?
[features]
default = []
asm = ["ff/asm_derive", "sha2/asm"]
[[bench]]
name = "rc_bls12"
harness = false
[[bench]]
name = "rc_bn256"
harness = false
[[bench]]
name = "rc_st"
harness = false
[[bench]]
name = "fp_bls12"
harness = false
[[bench]]
name = "fp_bn256"
harness = false
[[bench]]
name = "fp_st"
harness = false
[[bench]]
name = "fp4_bls12"
harness = false
[[bench]]
name = "fp4_bn256"
harness = false
[[bench]]
name = "fp4_st"
harness = false
[[bench]]
name = "hashes"
harness = false
[[example]]
name = "rc_bls12"
path = "examples/rc_bls12.rs"
[[example]]
name = "rc_bn256"
path = "examples/rc_bn256.rs"
[[example]]
name = "rc_st"
path = "examples/rc_st.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
# Plain Performance Comparison of different Hash Functions for ZKP
This repository contains Rust implementations of different hash functions for Zero-Knowledge applications.
## Hash Functions
The following hash functions are already implemented:
- [ReinforcedConcrete](https://todo)
- [Poseidon](https://eprint.iacr.org/2019/458.pdf)
- [Rescue](https://eprint.iacr.org/2019/426.pdf)
- [Rescue-Prime](https://www.esat.kuleuven.be/cosic/publications/article-3259.pdf)
- [Feistel-MiMC](https://eprint.iacr.org/2016/492.pdf)
- [Pedersen-Hash](https://zips.z.cash/protocol/protocol.pdf#concretepedersenhash), code extracted from [Zcash](https://github.com/zcash/librustzcash)
- [Sinsemilla](https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash), code extracted from [Orchard](https://github.com/zcash/orchard)
We also benchmark against various classical hash algorithms implemented in [RustCrypto](https://github.com/RustCrypto/hashes).
We instantiate the finite-field permutations (ReinforcedConcrete, Poseidon, Rescue, Rescue-Prime) with a statesize of three field elements in a sponge with one field element reserved as the capacity. Feistel-MiMC always has a statesize of two, which is why one can only absorb one field element per permutation call when instantiated in a sponge.
## Benchmarks
Here we give benchmarks for hashing input sizes of 512-bit (i.e., two field elements for the used prime fields). We, thus, benchmark one permutation call for all symmetric hash functions, except for Feistel-MiMC for which we require two. All benchmarks where obtained on a Linux Desktop PC with an Intel i7-4790 CPU (3.9 GHz) and 16 GB RAM using stable Rust version 1.53 and the `target-cpu=native` flag. Time in ns.
| Hash | | BN | BLS | ST |
|--------------------|--------:|--------:|--------:|--------:|
| ReinforcedConcrete | - | 3 284 | 3 265 | 1 032 |
| Poseidon | - | 17 598 | 18 174 | 17 320 |
| Rescue | - | 415 230 | 446 980 | 359 510 |
| Rescue-Prime | - | 362 870 | 391 560 | 294 660 |
| Feistel-MiMC | - | 33 800 | 35 847 | 28 594 |
| Sinsemilla | 131 460 | - | - | - |
| Pedersen-Hash | 39 807 | - | - | - |
| SHA-256 | 366.5 | - | - | - |
| Blake2b | 245.1 | - | - | - |
| Blake2s | 219.5 | - | - | - |
| SHA3-256 | 392.3 | - | - | - |
## Citing our work
Please use the following BibTeX entry to cite our work in academic papers.
```tex
@misc{HashZKP,
author = {Roman Walch},
title = {Hash functions for Zero-Knowledge applications},
howpublished = {\url{http://todo.org}},
month = jul,
year = 2021,
note = {IAIK, Graz University of Technology},
}
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::{thread_rng, Rng};
use tplonk::fields::{bls12::FpBLS12, utils4};
type Scalar = FpBLS12;
fn into_limbs(c: &mut Criterion) {
let input = utils4::random_scalar::<Scalar>(true);
c.bench_function("BLS12_4 into limbs", move |bench| {
bench.iter(|| {
let res = utils4::into_limbs(black_box(&input));
black_box(res);
});
});
}
fn from_limbs(c: &mut Criterion) {
let input = utils4::random_scalar::<Scalar>(true);
let limbs = utils4::into_limbs(&input);
c.bench_function("BLS12_4 from limbs", move |bench| {
bench.iter(|| {
let res = utils4::from_limbs::<Scalar>(black_box(&limbs));
black_box(res);
});
});
}
fn mult_by_word(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let mul = rng.gen::<u64>();
c.bench_function("BLS12_4 multiplication by word", move |bench| {
bench.iter(|| {
let res = utils4::mul_by_single_word(black_box(&repr), black_box(mul));
black_box(res)
});
});
}
fn div_by_u16(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
// let div = rng.gen::<u16>();
let div = 1023;
c.bench_function("BLS12_4 division by u16", move |bench| {
bench.iter(|| {
let (res, m) = utils4::divide_long(black_box(&repr), black_box(div));
black_box((res, m))
});
});
}
fn div_by_u16_recip(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
// let div = rng.gen::<u16>();
let div = 1023;
let (divisor, recip) = utils4::compute_normalized_divisor_and_reciproical(div);
let s = (div as u64).leading_zeros();
c.bench_function(
"BLS12_4 division by u16 using precomputed reciprocal",
move |bench| {
bench.iter(|| {
let (res, m) = utils4::divide_long_using_recip(
black_box(&repr),
black_box(divisor),
black_box(recip),
black_box(s),
);
black_box((res, m))
});
},
);
}
fn div_crandall(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let bit = 10;
c.bench_function("BLS12_4 division by 2^N-1 using crandall", move |bench| {
bench.iter(|| {
let (res, m) = utils4::div_mod_crandall(black_box(&repr), black_box(bit));
black_box((res, m))
});
});
}
fn div_mg(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
c.bench_function("BLS12_4 division by 1023 using MG", move |bench| {
bench.iter(|| {
let (res, m) = utils4::div1023(black_box(&repr));
black_box((res, m))
});
});
}
fn add_by_word(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let mul = rng.gen::<u64>();
c.bench_function("BLS12_4 addition by word", move |bench| {
bench.iter(|| {
let res = utils4::add_single_word(black_box(&repr), black_box(mul));
black_box(res)
});
});
}
fn partial_add(c: &mut Criterion) {
let mut rng = thread_rng();
let input1 = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr1 = utils4::into_limbs(&input1);
let input2 = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr2 = utils4::into_limbs(&input2);
c.bench_function("BLS12_4 partial addition", move |bench| {
bench.iter(|| {
let res = utils4::partial_add(black_box(&repr1), black_box(&repr2));
black_box(res)
});
});
}
fn full_shr(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let shift = rng.gen::<u32>() % 64;
c.bench_function("BLS12_4 full shift right", move |bench| {
bench.iter(|| {
let res = utils4::full_shr(black_box(&repr), black_box(shift));
black_box(res)
});
});
}
fn full_shl(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let shift = rng.gen::<u32>() % 64;
c.bench_function("BLS12_4 full shift left", move |bench| {
bench.iter(|| {
let res = utils4::full_shl(black_box(&repr), black_box(shift));
black_box(res)
});
});
}
fn partial_shl(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let shift = rng.gen::<u32>() % 64;
c.bench_function("BLS12_4 partial shift left", move |bench| {
bench.iter(|| {
let res = utils4::partial_shl(black_box(&repr), black_box(shift));
black_box(res)
});
});
}
fn criterion_benchmark_fields_st(c: &mut Criterion) {
mult_by_word(c);
div_by_u16(c);
div_by_u16_recip(c);
div_crandall(c);
div_mg(c);
add_by_word(c);
partial_add(c);
full_shr(c);
full_shl(c);
partial_shl(c);
into_limbs(c);
from_limbs(c);
}
criterion_group!(
name = benches;
config = Criterion::default();
targets = criterion_benchmark_fields_st
);
criterion_main!(benches);
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::{thread_rng, Rng};
use tplonk::fields::{bn256::FpBN256, utils4};
type Scalar = FpBN256;
fn into_limbs(c: &mut Criterion) {
let input = utils4::random_scalar::<Scalar>(true);
c.bench_function("BN256_4 into limbs", move |bench| {
bench.iter(|| {
let res = utils4::into_limbs(black_box(&input));
black_box(res);
});
});
}
fn from_limbs(c: &mut Criterion) {
let input = utils4::random_scalar::<Scalar>(true);
let limbs = utils4::into_limbs(&input);
c.bench_function("BN256_4 from limbs", move |bench| {
bench.iter(|| {
let res = utils4::from_limbs::<Scalar>(black_box(&limbs));
black_box(res);
});
});
}
fn mult_by_word(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let mul = rng.gen::<u64>();
c.bench_function("BN256_4 multiplication by word", move |bench| {
bench.iter(|| {
let res = utils4::mul_by_single_word(black_box(&repr), black_box(mul));
black_box(res)
});
});
}
fn div_by_u16(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
// let div = rng.gen::<u16>();
let div = 1023;
c.bench_function("BN256_4 division by u16", move |bench| {
bench.iter(|| {
let (res, m) = utils4::divide_long(black_box(&repr), black_box(div));
black_box((res, m))
});
});
}
fn div_by_u16_recip(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
// let div = rng.gen::<u16>();
let div = 1023;
let (divisor, recip) = utils4::compute_normalized_divisor_and_reciproical(div);
let s = (div as u64).leading_zeros();
c.bench_function(
"BN256_4 division by u16 using precomputed reciprocal",
move |bench| {
bench.iter(|| {
let (res, m) = utils4::divide_long_using_recip(
black_box(&repr),
black_box(divisor),
black_box(recip),
black_box(s),
);
black_box((res, m))
});
},
);
}
fn div_crandall(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let bit = 10;
c.bench_function("BN256_4 division by 2^N-1 using crandall", move |bench| {
bench.iter(|| {
let (res, m) = utils4::div_mod_crandall(black_box(&repr), black_box(bit));
black_box((res, m))
});
});
}
fn div_mg(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
c.bench_function("BN256_4 division by 1023 using MG", move |bench| {
bench.iter(|| {
let (res, m) = utils4::div1023(black_box(&repr));
black_box((res, m))
});
});
}
fn add_by_word(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let mul = rng.gen::<u64>();
c.bench_function("BN256_4 addition by word", move |bench| {
bench.iter(|| {
let res = utils4::add_single_word(black_box(&repr), black_box(mul));
black_box(res)
});
});
}
fn partial_add(c: &mut Criterion) {
let mut rng = thread_rng();
let input1 = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr1 = utils4::into_limbs(&input1);
let input2 = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr2 = utils4::into_limbs(&input2);
c.bench_function("BN256_4 partial addition", move |bench| {
bench.iter(|| {
let res = utils4::partial_add(black_box(&repr1), black_box(&repr2));
black_box(res)
});
});
}
fn full_shr(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let shift = rng.gen::<u32>() % 64;
c.bench_function("BN256_4 full shift right", move |bench| {
bench.iter(|| {
let res = utils4::full_shr(black_box(&repr), black_box(shift));
black_box(res)
});
});
}
fn full_shl(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let shift = rng.gen::<u32>() % 64;
c.bench_function("BN256_4 full shift left", move |bench| {
bench.iter(|| {
let res = utils4::full_shl(black_box(&repr), black_box(shift));
black_box(res)
});
});
}
fn partial_shl(c: &mut Criterion) {
let mut rng = thread_rng();
let input = utils4::random_scalar_rng::<Scalar, _>(true, &mut rng);
let repr = utils4::into_limbs(&input);
let shift = rng.gen::<u32>() % 64;
c.bench_function("BN256_4 partial shift left", move |bench| {
bench.iter(|| {
let res = utils4::partial_shl(black_box(&repr), black_box(shift));
black_box(res)
});
});
}
fn criterion_benchmark_fields_st(c: &mut Criterion) {
mult_by_word(c);
div_by_u16(c);
div_by_u16_recip(c);
div_crandall(c);
div_mg(c);
add_by_word(c);
partial_add(c);
full_shr(c);
full_shl(c);
partial_shl(c);
into_limbs(c);
from_limbs(c);
}
criterion_group!(
name = benches;
config = Criterion::default();
targets = criterion_benchmark_fields_st
);
criterion_main!(benches);
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::{thread_rng, Rng};
use tplonk::fields::{st::FpST, utils4};
type Scalar = FpST;
fn into_limbs(c: &mut Criterion) {
let input = utils4::random_scalar::<Scalar>(true);
c.bench_function("ST_4 into limbs", move |bench| {
bench.iter(|| {
let res = utils4::into_limbs(black_box(&input));
black_box(res);
});