mirror of https://github.com/zcash/halo2.git
227 lines
6.6 KiB
Rust
227 lines
6.6 KiB
Rust
use ff::Field;
|
|
use halo2_proofs::{
|
|
circuit::{Layouter, SimpleFloorPlanner, Value},
|
|
pasta::Fp,
|
|
plonk::{
|
|
create_proof, keygen_pk, keygen_vk, verify_proof, Advice, Circuit, Column,
|
|
ConstraintSystem, Error, Instance, SingleVerifier,
|
|
},
|
|
poly::commitment::Params,
|
|
transcript::{Blake2bRead, Blake2bWrite, Challenge255},
|
|
};
|
|
use pasta_curves::{pallas, vesta};
|
|
|
|
use halo2_gadgets::poseidon::{
|
|
primitives::{self as poseidon, generate_constants, ConstantLength, Mds, Spec},
|
|
Hash, Pow5Chip, Pow5Config,
|
|
};
|
|
use std::convert::TryInto;
|
|
use std::marker::PhantomData;
|
|
|
|
use criterion::{criterion_group, criterion_main, Criterion};
|
|
use rand::rngs::OsRng;
|
|
|
|
#[derive(Clone, Copy)]
|
|
struct HashCircuit<S, const WIDTH: usize, const RATE: usize, const L: usize>
|
|
where
|
|
S: Spec<Fp, WIDTH, RATE> + Clone + Copy,
|
|
{
|
|
message: Value<[Fp; L]>,
|
|
_spec: PhantomData<S>,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
struct MyConfig<const WIDTH: usize, const RATE: usize, const L: usize> {
|
|
input: [Column<Advice>; L],
|
|
expected: Column<Instance>,
|
|
poseidon_config: Pow5Config<Fp, WIDTH, RATE>,
|
|
}
|
|
|
|
impl<S, const WIDTH: usize, const RATE: usize, const L: usize> Circuit<Fp>
|
|
for HashCircuit<S, WIDTH, RATE, L>
|
|
where
|
|
S: Spec<Fp, WIDTH, RATE> + Copy + Clone,
|
|
{
|
|
type Config = MyConfig<WIDTH, RATE, L>;
|
|
type FloorPlanner = SimpleFloorPlanner;
|
|
|
|
fn without_witnesses(&self) -> Self {
|
|
Self {
|
|
message: Value::unknown(),
|
|
_spec: PhantomData,
|
|
}
|
|
}
|
|
|
|
fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
|
|
let state = (0..WIDTH).map(|_| meta.advice_column()).collect::<Vec<_>>();
|
|
let expected = meta.instance_column();
|
|
meta.enable_equality(expected);
|
|
let partial_sbox = meta.advice_column();
|
|
|
|
let rc_a = (0..WIDTH).map(|_| meta.fixed_column()).collect::<Vec<_>>();
|
|
let rc_b = (0..WIDTH).map(|_| meta.fixed_column()).collect::<Vec<_>>();
|
|
|
|
meta.enable_constant(rc_b[0]);
|
|
|
|
Self::Config {
|
|
input: state[..RATE].try_into().unwrap(),
|
|
expected,
|
|
poseidon_config: Pow5Chip::configure::<S>(
|
|
meta,
|
|
state.try_into().unwrap(),
|
|
partial_sbox,
|
|
rc_a.try_into().unwrap(),
|
|
rc_b.try_into().unwrap(),
|
|
),
|
|
}
|
|
}
|
|
|
|
fn synthesize(
|
|
&self,
|
|
config: Self::Config,
|
|
mut layouter: impl Layouter<Fp>,
|
|
) -> Result<(), Error> {
|
|
let chip = Pow5Chip::construct(config.poseidon_config.clone());
|
|
|
|
let message = layouter.assign_region(
|
|
|| "load message",
|
|
|mut region| {
|
|
let message_word = |i: usize| {
|
|
let value = self.message.map(|message_vals| message_vals[i]);
|
|
region.assign_advice(
|
|
|| format!("load message_{}", i),
|
|
config.input[i],
|
|
0,
|
|
|| value,
|
|
)
|
|
};
|
|
|
|
let message: Result<Vec<_>, Error> = (0..L).map(message_word).collect();
|
|
Ok(message?.try_into().unwrap())
|
|
},
|
|
)?;
|
|
|
|
let hasher = Hash::<_, _, S, ConstantLength<L>, WIDTH, RATE>::init(
|
|
chip,
|
|
layouter.namespace(|| "init"),
|
|
)?;
|
|
let output = hasher.hash(layouter.namespace(|| "hash"), message)?;
|
|
|
|
layouter.constrain_instance(output.cell(), config.expected, 0)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
struct MySpec<const WIDTH: usize, const RATE: usize>;
|
|
|
|
impl<const WIDTH: usize, const RATE: usize> Spec<Fp, WIDTH, RATE> for MySpec<WIDTH, RATE> {
|
|
fn full_rounds() -> usize {
|
|
8
|
|
}
|
|
|
|
fn partial_rounds() -> usize {
|
|
56
|
|
}
|
|
|
|
fn sbox(val: Fp) -> Fp {
|
|
val.pow_vartime(&[5])
|
|
}
|
|
|
|
fn secure_mds() -> usize {
|
|
0
|
|
}
|
|
|
|
fn constants() -> (Vec<[Fp; WIDTH]>, Mds<Fp, WIDTH>, Mds<Fp, WIDTH>) {
|
|
generate_constants::<_, Self, WIDTH, RATE>()
|
|
}
|
|
}
|
|
|
|
const K: u32 = 7;
|
|
|
|
fn bench_poseidon<S, const WIDTH: usize, const RATE: usize, const L: usize>(
|
|
name: &str,
|
|
c: &mut Criterion,
|
|
) where
|
|
S: Spec<Fp, WIDTH, RATE> + Copy + Clone,
|
|
{
|
|
// Initialize the polynomial commitment parameters
|
|
let params: Params<vesta::Affine> = Params::new(K);
|
|
|
|
let empty_circuit = HashCircuit::<S, WIDTH, RATE, L> {
|
|
message: Value::unknown(),
|
|
_spec: PhantomData,
|
|
};
|
|
|
|
// Initialize the proving key
|
|
let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail");
|
|
let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail");
|
|
|
|
let prover_name = name.to_string() + "-prover";
|
|
let verifier_name = name.to_string() + "-verifier";
|
|
|
|
let mut rng = OsRng;
|
|
let message = (0..L)
|
|
.map(|_| pallas::Base::random(rng))
|
|
.collect::<Vec<_>>()
|
|
.try_into()
|
|
.unwrap();
|
|
let output = poseidon::Hash::<_, S, ConstantLength<L>, WIDTH, RATE>::init().hash(message);
|
|
|
|
let circuit = HashCircuit::<S, WIDTH, RATE, L> {
|
|
message: Value::known(message),
|
|
_spec: PhantomData,
|
|
};
|
|
|
|
c.bench_function(&prover_name, |b| {
|
|
b.iter(|| {
|
|
let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
|
|
create_proof(
|
|
¶ms,
|
|
&pk,
|
|
&[circuit],
|
|
&[&[&[output]]],
|
|
&mut rng,
|
|
&mut transcript,
|
|
)
|
|
.expect("proof generation should not fail")
|
|
})
|
|
});
|
|
|
|
// Create a proof
|
|
let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
|
|
create_proof(
|
|
¶ms,
|
|
&pk,
|
|
&[circuit],
|
|
&[&[&[output]]],
|
|
&mut rng,
|
|
&mut transcript,
|
|
)
|
|
.expect("proof generation should not fail");
|
|
let proof = transcript.finalize();
|
|
|
|
c.bench_function(&verifier_name, |b| {
|
|
b.iter(|| {
|
|
let strategy = SingleVerifier::new(¶ms);
|
|
let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]);
|
|
assert!(verify_proof(
|
|
¶ms,
|
|
pk.get_vk(),
|
|
strategy,
|
|
&[&[&[output]]],
|
|
&mut transcript
|
|
)
|
|
.is_ok());
|
|
});
|
|
});
|
|
}
|
|
|
|
fn criterion_benchmark(c: &mut Criterion) {
|
|
bench_poseidon::<MySpec<3, 2>, 3, 2, 2>("WIDTH = 3, RATE = 2", c);
|
|
bench_poseidon::<MySpec<9, 8>, 9, 8, 8>("WIDTH = 9, RATE = 8", c);
|
|
bench_poseidon::<MySpec<12, 11>, 12, 11, 11>("WIDTH = 12, RATE = 11", c);
|
|
}
|
|
|
|
criterion_group!(benches, criterion_benchmark);
|
|
criterion_main!(benches);
|