Commit f5a8b6b0 authored by Roman Walch's avatar Roman Walch
Browse files

add Griffin code

parent f698cb9c
......@@ -6,11 +6,11 @@ This repository contains Rust implementations of different hash functions for Ze
The following hash functions are already implemented:
- [Griffin](???)
- [Griffin](https://eprint.iacr.org/2022/???.pdf)
- [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
[1] [https://eprint.iacr.org/2022/???.pdf](https://eprint.iacr.org/2022/???.pdf)
use bellman_ce::pairing::bls12_381::{self, Bls12};
use hash_r1cs::{
circuits::Permutation,
griffin::{
griffin::Griffin, griffin_circuit::GriffinCircuit, griffin_instances::GRIFFIN_BLS_3_PARAMS,
},
perm_groth::PermGroth,
utils,
};
use rand::thread_rng;
type Scalar = bls12_381::Fr;
fn main() {
println!("Griffin proof (t = 3)");
let griffin = Griffin::new(&GRIFFIN_BLS_3_PARAMS);
let griffin_circuit = GriffinCircuit::new(&GRIFFIN_BLS_3_PARAMS);
let mut rng = thread_rng();
let mut groth = PermGroth::new(griffin_circuit);
println!("Create CRS");
groth.create_crs(&mut rng);
let pvk = groth.create_verify_key();
println!("Sample input");
let t = griffin.get_t();
let input: Vec<Scalar> = (0..t)
.map(|_| utils::random_scalar_rng(true, &mut rng))
.collect();
println!("Permutation");
let perm = griffin.permutation(&input);
println!("Create proof");
let proof = groth.create_proof(&input, &mut rng);
println!("Verify proof");
let result = PermGroth::<Bls12, GriffinCircuit<Bls12>>::verify_proof(&pvk, &proof, &perm);
match result {
Ok(verified) => match verified {
true => println!("Correct!"),
false => println!("Proof was incorrect?"),
},
Err(_) => println!("Synthesis Error!?"),
}
}
use bellman_ce::pairing::bls12_381::{self, Bls12};
use hash_r1cs::{
griffin::{
griffin::Griffin, griffin_circuit::GriffinCircuit, griffin_instances::GRIFFIN_BLS_3_PARAMS,
},
merkle_groth::MerkleGroth,
merkle_tree::MerkleTree,
mt_circuit::MerkleTreeCircuit,
utils,
};
use rand::{
distributions::{IndependentSample, Range},
thread_rng,
};
type Scalar = bls12_381::Fr;
fn main() {
println!("Griffin MT proof (2:1, 2^10 elements)");
let perm = Griffin::new(&GRIFFIN_BLS_3_PARAMS);
let mut mt = MerkleTree::new(perm);
let log_set_size = 10;
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(&GRIFFIN_BLS_3_PARAMS);
let mt_circ = MerkleTreeCircuit::new(perm_circ, levels, arity);
let mut groth = MerkleGroth::new(mt_circ);
println!("Create CRS");
groth.create_crs(&mut rng);
let pvk = groth.create_verify_key();
println!("Sample set");
let set: Vec<Scalar> = (0..set_size)
.map(|_| utils::random_scalar_rng(true, &mut rng))
.collect();
let index = dist.ind_sample(&mut rng);
println!("Accumulate set");
mt.accumulate(&set);
println!("Create MT witness");
let wit = mt.create_witness(&set[index]).unwrap();
println!("Create proof");
let proof = groth.create_proof(&set[index], &wit, &mut rng);
println!("Verify proof");
let result = MerkleGroth::<Bls12, GriffinCircuit<Bls12>>::verify_proof(
&pvk,
&proof,
&mt.get_root().unwrap(),
);
match result {
Ok(verified) => match verified {
true => println!("Correct!"),
false => println!("Proof was incorrect?"),
},
Err(_) => println!("Synthesis Error!?"),
}
}
# Griffin
This folder contains implementations of the [Griffin](https://eprint.iacr.org/2022/???.pdf) permutation. Instances were generated following the description in the original paper.
use bellman_ce::pairing::ff::{PrimeField, SqrtField};
use std::{sync::Arc, usize};
use crate::circuits::Permutation;
use super::griffin_params::GriffinParams;
#[derive(Clone, Debug)]
pub struct Griffin<S: PrimeField + SqrtField> {
pub(crate) params: Arc<GriffinParams<S>>,
}
impl<S: PrimeField + SqrtField> Griffin<S> {
pub fn new(params: &Arc<GriffinParams<S>>) -> Self {
Griffin {
params: Arc::clone(params),
}
}
fn affine_3(&self, input: &mut [S], round: usize) {
// multiplication by circ(2 1 1) is equal to state + sum(state)
let mut sum = input[0];
input.iter().skip(1).for_each(|el| sum.add_assign(el));
if round < self.params.rounds - 1 {
for (el, rc) in input
.iter_mut()
.zip(self.params.round_constants[round].iter())
{
el.add_assign(&sum);
el.add_assign(rc); // add round constant
}
} else {
// no round constant
for el in input.iter_mut() {
el.add_assign(&sum);
}
}
}
fn affine_4(&self, input: &mut [S], round: usize) {
// multiplication by circ(3 2 1 1) is equal to state + state + rot(state) + sum(state)
let mut sum = input[0];
input.iter().skip(1).for_each(|el| sum.add_assign(el));
let mut input_rot = input.to_owned();
input_rot.rotate_left(1);
if round < self.params.rounds - 1 {
for ((el, rot), rc) in input
.iter_mut()
.zip(input_rot.iter())
.zip(self.params.round_constants[round].iter())
{
el.double();
el.add_assign(rot);
el.add_assign(&sum);
el.add_assign(rc); // add round constant
}
} else {
// no round constant
for (el, rot) in input.iter_mut().zip(input_rot.iter()) {
el.double();
el.add_assign(rot);
el.add_assign(&sum);
}
}
}
fn affine(&self, input: &mut [S], round: usize) {
if self.params.t == 3 {
self.affine_3(input, round);
return;
}
if self.params.t == 4 {
self.affine_4(input, round);
return;
}
// first matrix
let t4 = self.params.t / 4;
for i in 0..t4 {
let startindex = i * 4;
let mut sum = input[startindex];
let start_el = sum;
input
.iter()
.skip(startindex + 1)
.take(3)
.for_each(|el| sum.add_assign(el));
for j in startindex..startindex + 3 {
input[j].double();
let tmp = input[j + 1];
input[j].add_assign(&tmp);
input[j].add_assign(&sum);
}
input[startindex + 3].double();
input[startindex + 3].add_assign(&start_el);
input[startindex + 3].add_assign(&sum);
}
// second matrix
let mut stored = [S::zero(); 4];
for l in 0..4 {
stored[l] = input[l];
for j in 1..t4 {
stored[l].add_assign(&input[4 * j + l]);
}
}
for i in 0..input.len() {
input[i].add_assign(&stored[i % 4]);
if round < self.params.rounds - 1 {
input[i].add_assign(&self.params.round_constants[round][i]); // add round constant
}
}
}
fn l(y01_i: &mut S, y0: &S, x: &S, i: usize) -> S {
if i == 0 {
y01_i.to_owned()
} else {
y01_i.add_assign(y0);
let mut out = y01_i.to_owned();
out.add_assign(x);
out
}
}
fn non_linear(&self, input: &[S]) -> Vec<S> {
// first two state words
let mut output = input.to_owned();
output[0] = output[0].pow(&self.params.d_inv);
output[1].square();
match self.params.d {
3 => {}
5 => output[1].square(),
_ => panic!(),
}
output[1].mul_assign(&input[1]);
let mut y01_i = output[0].to_owned(); // y0
let y0 = y01_i.to_owned(); // y0
y01_i.add_assign(&output[1]); // y0 + y1
// rest of the state
for (i, ((out, inp), con)) in output
.iter_mut()
.skip(2)
.zip(input.iter().skip(1))
.zip(self.params.alpha_beta.iter())
.enumerate()
{
let mut l = Self::l(&mut y01_i, &y0, inp, i);
let mut l_squ = l.to_owned();
l_squ.square();
l.mul_assign(&con[0]);
l.add_assign(&l_squ);
l.add_assign(&con[1]);
out.mul_assign(&l);
}
output
}
}
impl<S: PrimeField + SqrtField> Permutation<S> for Griffin<S> {
fn permutation(&self, input: &[S]) -> Vec<S> {
let mut current_state = input.to_owned();
self.affine(&mut current_state, self.params.rounds); // no RC
for r in 0..self.params.rounds {
current_state = self.non_linear(&current_state);
self.affine(&mut current_state, r);
}
current_state
}
fn get_t(&self) -> usize {
self.params.t
}
}
#[cfg(test)]
mod griffin_tests_bls12 {
use super::*;
use crate::{griffin::griffin_instances::GRIFFIN_BLS_3_PARAMS, utils};
use bellman_ce::pairing::bls12_381;
type Scalar = bls12_381::Fr;
static TESTRUNS: usize = 5;
#[test]
fn consistent_perm() {
let griffin = Griffin::new(&GRIFFIN_BLS_3_PARAMS);
let t = griffin.params.t;
for _ in 0..TESTRUNS {
let input1: Vec<Scalar> = (0..t).map(|_| utils::random_scalar(true)).collect();
let mut input2: Vec<Scalar>;
loop {
input2 = (0..t).map(|_| utils::random_scalar(true)).collect();
if input1 != input2 {
break;
}
}
let perm1 = griffin.permutation(&input1);
let perm2 = griffin.permutation(&input1);
let perm3 = griffin.permutation(&input2);
assert_eq!(perm1, perm2);
assert_ne!(perm1, perm3);
}
}
}
#[cfg(test)]
mod griffin_tests_bn256 {
use super::*;
use crate::{griffin::griffin_instances::GRIFFIN_BN_3_PARAMS, utils};
use bellman_ce::pairing::bn256;
type Scalar = bn256::Fr;
static TESTRUNS: usize = 5;
#[test]
fn consistent_perm() {
let griffin = Griffin::new(&GRIFFIN_BN_3_PARAMS);
let t = griffin.params.t;
for _ in 0..TESTRUNS {
let input1: Vec<Scalar> = (0..t).map(|_| utils::random_scalar(true)).collect();
let mut input2: Vec<Scalar>;
loop {
input2 = (0..t).map(|_| utils::random_scalar(true)).collect();
if input1 != input2 {
break;
}
}
let perm1 = griffin.permutation(&input1);
let perm2 = griffin.permutation(&input1);
let perm3 = griffin.permutation(&input2);
assert_eq!(perm1, perm2);
assert_ne!(perm1, perm3);
}
}
}
#[cfg(test)]
mod griffin_affine_tests_bls12 {
use crate::utils;
use super::*;
use bellman_ce::pairing::{bls12_381, ff::Field};
type Scalar = bls12_381::Fr;
static TESTRUNS: usize = 5;
fn matmul(input: &[Scalar], mat: &[Vec<Scalar>]) -> Vec<Scalar> {
let t = mat.len();
debug_assert!(t == input.len());
let mut out = vec![Scalar::zero(); t];
for row in 0..t {
for (col, inp) in input.iter().enumerate() {
let mut tmp = mat[row][col];
tmp.mul_assign(inp);
out[row].add_assign(&tmp);
}
}
out
}
fn affine_test(t: usize) {
let griffin_param = Arc::new(GriffinParams::<Scalar>::new(t, 5, 1));
let griffin = Griffin::<Scalar>::new(&griffin_param);
let mat = &griffin_param.mat;
for _ in 0..TESTRUNS {
let input: Vec<Scalar> = (0..t).map(|_| utils::random_scalar(true)).collect();
// affine 1
let output1 = matmul(&input, mat);
let mut output2 = input.to_owned();
griffin.affine(&mut output2, 1);
assert_eq!(output1, output2);
}
}
#[test]
fn affine_3() {
affine_test(3);
}
#[test]
fn affine_4() {
affine_test(4);
}
#[test]
fn affine_8() {
affine_test(8);
}
#[test]
fn affine_60() {
affine_test(60);
}
}
#[cfg(test)]
mod griffin_affine_tests_bn256 {
use crate::utils;
use super::*;
use bellman_ce::pairing::{bn256, ff::Field};
type Scalar = bn256::Fr;
static TESTRUNS: usize = 5;
fn matmul(input: &[Scalar], mat: &[Vec<Scalar>]) -> Vec<Scalar> {
let t = mat.len();
debug_assert!(t == input.len());
let mut out = vec![Scalar::zero(); t];
for row in 0..t {
for (col, inp) in input.iter().enumerate() {
let mut tmp = mat[row][col];
tmp.mul_assign(inp);
out[row].add_assign(&tmp);
}
}
out
}
fn affine_test(t: usize) {
let griffin_param = Arc::new(GriffinParams::<Scalar>::new(t, 5, 1));
let griffin = Griffin::<Scalar>::new(&griffin_param);
let mat = &griffin_param.mat;
for _ in 0..TESTRUNS {
let input: Vec<Scalar> = (0..t).map(|_| utils::random_scalar(true)).collect();
// affine 1
let output1 = matmul(&input, mat);
let mut output2 = input.to_owned();
griffin.affine(&mut output2, 1);
assert_eq!(output1, output2);
}
}
#[test]
fn affine_3() {
affine_test(3);
}
#[test]
fn affine_4() {
affine_test(4);
}
#[test]
fn affine_8() {
affine_test(8);
}
#[test]
fn affine_60() {
affine_test(60);
}
}
use std::sync::Arc;
use bellman_ce::{pairing::ff::Field, pairing::Engine, Circuit, ConstraintSystem, SynthesisError};
use crate::{
circuits::PermCircuit,
constraint_builder::{ConstraintBuilder, ProofVar},
};
use super::griffin_params::GriffinParams;
type CB = ConstraintBuilder;
#[derive(Clone, Debug)]
pub struct GriffinCircuit<E: Engine> {
input: Vec<Option<E::Fr>>,
pub(crate) params: Arc<GriffinParams<E::Fr>>,
}
impl<E: Engine> GriffinCircuit<E> {
pub fn new(params: &Arc<GriffinParams<E::Fr>>) -> Self {
GriffinCircuit {
input: vec![None; params.t],
params: Arc::clone(params),
}
}
fn l(
&self,
y01_i: &mut ProofVar<E>,
y0: &ProofVar<E>,
x: &ProofVar<E>,
i: usize,
) -> ProofVar<E> {
if i == 0 {
y01_i.to_owned()
} else {
*y01_i = CB::addition(y01_i, y0);
CB::addition(y01_i, x)
}
}
fn non_linear<CS: ConstraintSystem<E>>(
&self,
cs: &mut CS,
state: &[ProofVar<E>],
) -> Vec<ProofVar<E>> {
let mut result = state.to_owned();
// x0
let power = result[0].value.map(|a| a.pow(&self.params.d_inv));
result[0] = CB::new_variable(power, cs);
let mut sq = CB::multiplication_new(&result[0], &result[0], cs);
if self.params.d == 5 {
sq = CB::multiplication_new(&sq, &sq, cs);
}
CB::multiplication(&result[0], &sq, &state[0], cs);
// x1
let mut sq = CB::multiplication_new(&result[1], &result[1], cs);
if self.params.d == 5 {
sq = CB::multiplication_new(&sq, &sq, cs);
}
result[1] = CB::multiplication_new(&result[1], &sq, cs);
let y0 = result[0].to_owned(); // y0
let mut y01_i = CB::addition(&y0, &result[1]); // y0 + y1
// rest of the state
for (i, ((out, inp), con)) in result
.iter_mut()
.skip(2)
.zip(state.iter().skip(1))
.zip(self.params.alpha_beta.iter())
.enumerate()
{
let mut l = self.l(&mut y01_i, &y0, inp, i);
let l_squ = CB::multiplication_new(&l, &l, cs);
l = CB::scale(&l, &con[0]);
l = CB::addition(&l, &l_squ);
l = CB::add_constant::<E, CS>(&l, &con[1]);
*out = CB::multiplication_new(out, &l, cs);
}
result