mirror of https://github.com/vacp2p/zerokit.git
feat(RLN): integrate Poseidon Hash (#44)
* refactor(rln): removing unused crates/dependencies * cargo fmt * refactor(rln): removed more dependencies; curve/fields as parameters * refactor(rln): use poseidon-rs hash instead of semaphore-rs poseidon * chore(rln): remove deps * refactor(rln): use exclusively arkworks Fr * refactor(rln): integrate poseidon-rs implementation to work with arkworks arithmetic * fix(rln): remove previous poseidon-rs wrapper
This commit is contained in:
parent
fb34ebe63c
commit
1131b76a66
|
@ -30,8 +30,6 @@ once_cell = "1.8"
|
|||
rand = "0.8"
|
||||
tiny-keccak = "2.0.2"
|
||||
num-traits = "0.2.15"
|
||||
ff = { package="ff_ce", version="0.11"}
|
||||
poseidon-rs = "0.0.8"
|
||||
|
||||
# serialization
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
|
|
|
@ -246,7 +246,7 @@ pub extern "C" fn hash(
|
|||
mod test {
|
||||
use super::*;
|
||||
use crate::circuit::*;
|
||||
use crate::poseidon_tree::poseidon_hash;
|
||||
use crate::poseidon_hash::poseidon_hash;
|
||||
use crate::protocol::*;
|
||||
use crate::utils::*;
|
||||
use ark_std::{rand::thread_rng, UniformRand};
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
pub mod circuit;
|
||||
pub mod ffi;
|
||||
pub mod merkle_tree;
|
||||
pub mod poseidon_constants;
|
||||
pub mod poseidon_hash;
|
||||
pub mod poseidon_tree;
|
||||
pub mod protocol;
|
||||
pub mod public;
|
||||
|
@ -12,7 +14,8 @@ pub mod utils;
|
|||
mod test {
|
||||
|
||||
use crate::circuit::{Fr, CIRCOM, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT, VK, ZKEY};
|
||||
use crate::poseidon_tree::{poseidon_hash, PoseidonTree};
|
||||
use crate::poseidon_hash::poseidon_hash;
|
||||
use crate::poseidon_tree::PoseidonTree;
|
||||
use crate::protocol::*;
|
||||
use crate::utils::str_to_fr;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,129 @@
|
|||
// This crate implements the Poseidon hash algorithm https://eprint.iacr.org/2019/458.pdf
|
||||
|
||||
// The implementation is taken from https://github.com/arnaucube/poseidon-rs/blob/233027d6075a637c29ad84a8a44f5653b81f0410/src/lib.rs
|
||||
// and slightly adapted to work over arkworks field data type
|
||||
|
||||
use crate::circuit::Fr;
|
||||
use crate::poseidon_constants::constants;
|
||||
use crate::utils::*;
|
||||
use ark_std::Zero;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Constants {
|
||||
pub c: Vec<Vec<Fr>>,
|
||||
pub m: Vec<Vec<Vec<Fr>>>,
|
||||
pub n_rounds_f: usize,
|
||||
pub n_rounds_p: Vec<usize>,
|
||||
}
|
||||
pub fn load_constants() -> Constants {
|
||||
let (c_str, m_str) = constants();
|
||||
let mut c: Vec<Vec<Fr>> = Vec::new();
|
||||
for i in 0..c_str.len() {
|
||||
let mut cci: Vec<Fr> = Vec::new();
|
||||
for j in 0..c_str[i].len() {
|
||||
let b: Fr = str_to_fr(c_str[i][j], 10);
|
||||
cci.push(b);
|
||||
}
|
||||
c.push(cci);
|
||||
}
|
||||
let mut m: Vec<Vec<Vec<Fr>>> = Vec::new();
|
||||
for i in 0..m_str.len() {
|
||||
let mut mi: Vec<Vec<Fr>> = Vec::new();
|
||||
for j in 0..m_str[i].len() {
|
||||
let mut mij: Vec<Fr> = Vec::new();
|
||||
for k in 0..m_str[i][j].len() {
|
||||
let b: Fr = str_to_fr(m_str[i][j][k], 10);
|
||||
mij.push(b);
|
||||
}
|
||||
mi.push(mij);
|
||||
}
|
||||
m.push(mi);
|
||||
}
|
||||
Constants {
|
||||
c: c,
|
||||
m: m,
|
||||
n_rounds_f: 8,
|
||||
n_rounds_p: vec![56, 57, 56, 60, 60, 63, 64, 63],
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Poseidon {
|
||||
constants: Constants,
|
||||
}
|
||||
impl Poseidon {
|
||||
pub fn new() -> Poseidon {
|
||||
Poseidon {
|
||||
constants: load_constants(),
|
||||
}
|
||||
}
|
||||
pub fn ark(&self, state: &mut [Fr], c: &[Fr], it: usize) {
|
||||
for i in 0..state.len() {
|
||||
state[i] += c[it + i];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sbox(&self, n_rounds_f: usize, n_rounds_p: usize, state: &mut [Fr], i: usize) {
|
||||
if (i < n_rounds_f / 2) || (i >= n_rounds_f / 2 + n_rounds_p) {
|
||||
for j in 0..state.len() {
|
||||
let aux = state[j];
|
||||
state[j] *= state[j];
|
||||
state[j] *= state[j];
|
||||
state[j] *= aux;
|
||||
}
|
||||
} else {
|
||||
let aux = state[0];
|
||||
state[0] *= state[0];
|
||||
state[0] *= state[0];
|
||||
state[0] *= aux;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mix(&self, state: &[Fr], m: &[Vec<Fr>]) -> Vec<Fr> {
|
||||
let mut new_state: Vec<Fr> = Vec::new();
|
||||
for i in 0..state.len() {
|
||||
new_state.push(Fr::zero());
|
||||
for j in 0..state.len() {
|
||||
let mut mij = m[i][j];
|
||||
mij *= state[j];
|
||||
new_state[i] += mij;
|
||||
}
|
||||
}
|
||||
new_state.clone()
|
||||
}
|
||||
|
||||
pub fn hash(&self, inp: Vec<Fr>) -> Result<Fr, String> {
|
||||
let t = inp.len() + 1;
|
||||
if inp.is_empty() || (inp.len() >= self.constants.n_rounds_p.len() - 1) {
|
||||
return Err("Wrong inputs length".to_string());
|
||||
}
|
||||
let n_rounds_f = self.constants.n_rounds_f;
|
||||
let n_rounds_p = self.constants.n_rounds_p[t - 2];
|
||||
|
||||
let mut state = vec![Fr::zero(); t];
|
||||
state[1..].clone_from_slice(&inp);
|
||||
|
||||
for i in 0..(n_rounds_f + n_rounds_p) {
|
||||
self.ark(&mut state, &self.constants.c[t - 2], i * t);
|
||||
self.sbox(n_rounds_f, n_rounds_p, &mut state, i);
|
||||
state = self.mix(&state, &self.constants.m[t - 2]);
|
||||
}
|
||||
|
||||
Ok(state[0])
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Poseidon {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// Poseidon Hash wrapper over above implementation. Adapted from semaphore-rs poseidon hash wrapper.
|
||||
static POSEIDON: Lazy<Poseidon> = Lazy::new(Poseidon::new);
|
||||
|
||||
pub fn poseidon_hash(input: &[Fr]) -> Fr {
|
||||
POSEIDON
|
||||
.hash(input.to_vec())
|
||||
.expect("hash with fixed input size can't fail")
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
// This crate defines RLN module default Merkle tree implementation and Hasher
|
||||
// This crate defines the RLN module default Merkle tree implementation and its Hasher
|
||||
|
||||
// Implementation inspired by https://github.com/worldcoin/semaphore-rs/blob/d462a4372f1fd9c27610f2acfe4841fab1d396aa/src/poseidon_tree.rs (no differences)
|
||||
|
||||
use crate::circuit::Fr;
|
||||
use crate::merkle_tree::*;
|
||||
use crate::utils::{fr_to_posfr, posfr_to_fr};
|
||||
use once_cell::sync::Lazy;
|
||||
use poseidon_rs::Poseidon;
|
||||
use crate::poseidon_hash::poseidon_hash;
|
||||
|
||||
// The zerokit RLN default Merkle tree implementation.
|
||||
// To switch to FullMerkleTree implementation it is enough to redefine the following two types
|
||||
|
@ -30,23 +29,6 @@ impl Hasher for PoseidonHash {
|
|||
}
|
||||
}
|
||||
|
||||
// Poseidon Hash wrapper over poseidon-rs implementation. Adapted from semaphore-rs poseidon hash wrapper.
|
||||
// TODO: integrate poseidon hash in zerokit
|
||||
static POSEIDON: Lazy<Poseidon> = Lazy::new(Poseidon::new);
|
||||
|
||||
pub fn poseidon_hash(input: &[Fr]) -> Fr {
|
||||
let input = input
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|x| fr_to_posfr(x))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
POSEIDON
|
||||
.hash(input)
|
||||
.map(|x| posfr_to_fr(x))
|
||||
.expect("hash with fixed input size can't fail")
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Tests
|
||||
////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -17,6 +17,7 @@ use thiserror::Error;
|
|||
use tiny_keccak::{Hasher as _, Keccak};
|
||||
|
||||
use crate::circuit::{Curve, Fr};
|
||||
use crate::poseidon_hash::poseidon_hash;
|
||||
use crate::poseidon_tree::*;
|
||||
use crate::public::RLN_IDENTIFIER;
|
||||
use crate::utils::*;
|
||||
|
@ -469,7 +470,7 @@ pub fn verify_proof(
|
|||
let pvk = prepare_verifying_key(verifying_key);
|
||||
//let pr: ArkProof<Curve> = (*proof).into();
|
||||
let now = Instant::now();
|
||||
let verified = ark_verify_proof(&pvk, &proof, &inputs)?;
|
||||
let verified = ark_verify_proof(&pvk, proof, &inputs)?;
|
||||
println!("verify took: {:.2?}", now.elapsed());
|
||||
|
||||
Ok(verified)
|
||||
|
|
|
@ -280,7 +280,7 @@ impl Default for RLN<'_> {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::poseidon_tree::poseidon_hash;
|
||||
use crate::poseidon_hash::poseidon_hash;
|
||||
use ark_std::{rand::thread_rng, UniformRand};
|
||||
use rand::Rng;
|
||||
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
|
||||
use crate::circuit::Fr;
|
||||
use ark_ff::{BigInteger, FpParameters, PrimeField};
|
||||
use ff::{PrimeField as _, PrimeFieldRepr as _};
|
||||
use num_bigint::{BigInt, BigUint};
|
||||
use num_traits::Num;
|
||||
use poseidon_rs::Fr as PosFr;
|
||||
use std::iter::Extend;
|
||||
|
||||
pub fn modulus_bit_size() -> usize {
|
||||
|
@ -30,8 +28,8 @@ pub fn str_to_fr(input: &str, radix: u32) -> Fr {
|
|||
|
||||
// We remove any quote present and we trim
|
||||
let single_quote: char = '\"';
|
||||
let input_clean = input.replace(single_quote, "");
|
||||
let input_clean = input_clean.trim();
|
||||
let mut input_clean = input.replace(single_quote, "");
|
||||
input_clean = input_clean.trim().to_string();
|
||||
|
||||
if radix == 10 {
|
||||
BigUint::from_str_radix(&input_clean, radix)
|
||||
|
@ -39,7 +37,7 @@ pub fn str_to_fr(input: &str, radix: u32) -> Fr {
|
|||
.try_into()
|
||||
.unwrap()
|
||||
} else {
|
||||
let input_clean = input_clean.replace("0x", "");
|
||||
input_clean = input_clean.replace("0x", "");
|
||||
BigUint::from_str_radix(&input_clean, radix)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
|
@ -179,7 +177,12 @@ pub fn bytes_be_to_vec_fr(input: &[u8]) -> (Vec<Fr>, usize) {
|
|||
(res, read)
|
||||
}
|
||||
|
||||
// Conversion Utilities between poseidon-rs Field and arkworks Fr (in order to call directly poseidon-rs poseidon_hash)
|
||||
/* Old conversion utilities between different libraries data types
|
||||
|
||||
// Conversion Utilities between poseidon-rs Field and arkworks Fr (in order to call directly poseidon-rs' poseidon_hash)
|
||||
|
||||
use ff::{PrimeField as _, PrimeFieldRepr as _};
|
||||
use poseidon_rs::Fr as PosFr;
|
||||
|
||||
pub fn fr_to_posfr(value: Fr) -> PosFr {
|
||||
let mut bytes = [0_u8; 32];
|
||||
|
@ -200,9 +203,9 @@ pub fn posfr_to_fr(value: PosFr) -> Fr {
|
|||
Fr::from_be_bytes_mod_order(&bytes)
|
||||
}
|
||||
|
||||
|
||||
// Conversion Utilities between semaphore-rs Field and arkworks Fr
|
||||
|
||||
/*
|
||||
use semaphore::Field;
|
||||
|
||||
pub fn to_fr(el: &Field) -> Fr {
|
||||
|
|
Loading…
Reference in New Issue