poseidon with generic engine

This commit is contained in:
kilic 2020-04-23 21:12:43 +03:00
parent 6821b0f574
commit 9352948baf
1 changed files with 48 additions and 45 deletions

View File

@ -1,48 +1,45 @@
use blake2::{Blake2s, Digest};
use sapling_crypto::bellman::pairing::bn256;
use sapling_crypto::bellman::pairing::bn256::{Bn256, Fr};
use sapling_crypto::bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr};
use sapling_crypto::bellman::pairing::Engine;
#[test]
fn test_poseidon() {
use sapling_crypto::bellman::pairing::bn256;
use sapling_crypto::bellman::pairing::bn256::{Bn256, Fr};
let (t, rf, rp) = (3usize, 8usize, 57usize);
let mut hasher = Blake2s::new();
hasher.input(b"rln poseidion t3rf4rp57");
let seed = hasher.result().to_vec();
let person_full_round_constant = b"rlnhds01";
let full_round_constants = PoseidonParams::generate_constants(person_full_round_constant, seed.clone(), rf);
let full_round_constants = PoseidonParams::<Bn256>::generate_constants(person_full_round_constant, seed.clone(), rf);
let person_partial_round_constant = b"rlnhds02";
let partial_round_constants = PoseidonParams::generate_constants(person_partial_round_constant, seed.clone(), rp);
let partial_round_constants =
PoseidonParams::<Bn256>::generate_constants(person_partial_round_constant, seed.clone(), rp);
let person_mds_matrix = b"rlnhds03";
let mds_matrix = PoseidonParams::generate_mds_matrix(person_mds_matrix, seed.clone(), t);
let mds_matrix = PoseidonParams::<Bn256>::generate_mds_matrix(person_mds_matrix, seed.clone(), t);
let mut constants: Vec<Fr> = Vec::new();
for i in 0..rf / 2 {
constants.push(full_round_constants[i]);
}
for i in 0..rp {
constants.push(partial_round_constants[i]);
}
for i in 0..rf / 2 {
constants.push(full_round_constants[i]);
}
let mut hasher = Poseidon::new_with_params(rf, rp, t, constants, mds_matrix);
constants.extend_from_slice(&full_round_constants[0..rf / 2]);
constants.extend_from_slice(&partial_round_constants);
constants.extend_from_slice(&full_round_constants[(rf / 2)..rf]);
let mut hasher = Poseidon::<Bn256>::new_with_params(rf, rp, t, constants, mds_matrix);
let input = [Fr::zero()];
let r1 = hasher.hash(&input);
let r2 = hasher.hash(&input);
let r1: Fr = hasher.hash(&input);
let r2: Fr = hasher.hash(&input);
println!("{}", r1);
assert_eq!(r1, r2, "just to see if internal state resets");
}
struct PoseidonParams {
struct PoseidonParams<E: Engine> {
rf: usize,
rp: usize,
t: usize,
round_constants: Vec<Fr>,
mds_matrix: Vec<Fr>,
round_constants: Vec<E::Fr>,
mds_matrix: Vec<E::Fr>,
}
impl PoseidonParams {
pub fn new(rf: usize, rp: usize, t: usize, round_constants: Vec<Fr>, mds_matrix: Vec<Fr>) -> PoseidonParams {
impl<E: Engine> PoseidonParams<E> {
pub fn new(rf: usize, rp: usize, t: usize, round_constants: Vec<E::Fr>, mds_matrix: Vec<E::Fr>) -> PoseidonParams<E> {
assert_eq!(rf + rp, round_constants.len());
PoseidonParams {
rf,
@ -52,19 +49,19 @@ impl PoseidonParams {
mds_matrix,
}
}
pub fn generate_mds_matrix(persona: &[u8; 8], seed: Vec<u8>, t: usize) -> Vec<Fr> {
let mut matrix: Vec<Fr> = Vec::with_capacity(t * t);
let mut xs: Vec<Fr> = Vec::with_capacity(t);
let mut ys: Vec<Fr> = Vec::with_capacity(t);
pub fn generate_mds_matrix(persona: &[u8; 8], seed: Vec<u8>, t: usize) -> Vec<E::Fr> {
let mut matrix: Vec<E::Fr> = Vec::with_capacity(t * t);
let mut xs: Vec<E::Fr> = Vec::with_capacity(t);
let mut ys: Vec<E::Fr> = Vec::with_capacity(t);
let mut source = seed.clone();
loop {
let mut hasher = Blake2s::new();
hasher.input(persona);
hasher.input(source);
source = hasher.result().to_vec();
let mut candidate_repr = <bn256::Fr as PrimeField>::Repr::default();
let mut candidate_repr = <E::Fr as PrimeField>::Repr::default();
candidate_repr.read_le(&source[..]).unwrap();
if let Ok(candidate) = bn256::Fr::from_repr(candidate_repr) {
if let Ok(candidate) = E::Fr::from_repr(candidate_repr) {
xs.push(candidate);
if xs.len() == t {
break;
@ -76,9 +73,9 @@ impl PoseidonParams {
hasher.input(persona);
hasher.input(source);
source = hasher.result().to_vec();
let mut candidate_repr = <bn256::Fr as PrimeField>::Repr::default();
let mut candidate_repr = <E::Fr as PrimeField>::Repr::default();
candidate_repr.read_le(&source[..]).unwrap();
if let Ok(candidate) = bn256::Fr::from_repr(candidate_repr) {
if let Ok(candidate) = E::Fr::from_repr(candidate_repr) {
ys.push(candidate);
if ys.len() == t {
break;
@ -96,17 +93,17 @@ impl PoseidonParams {
matrix
}
fn generate_constants(persona: &[u8; 8], seed: Vec<u8>, len: usize) -> Vec<Fr> {
let mut constants: Vec<Fr> = Vec::new();
fn generate_constants(persona: &[u8; 8], seed: Vec<u8>, len: usize) -> Vec<E::Fr> {
let mut constants: Vec<E::Fr> = Vec::new();
let mut source = seed.clone();
loop {
let mut hasher = Blake2s::new();
hasher.input(persona);
hasher.input(source);
source = hasher.result().to_vec();
let mut candidate_repr = <bn256::Fr as PrimeField>::Repr::default();
let mut candidate_repr = <E::Fr as PrimeField>::Repr::default();
candidate_repr.read_le(&source[..]).unwrap();
if let Ok(candidate) = bn256::Fr::from_repr(candidate_repr) {
if let Ok(candidate) = E::Fr::from_repr(candidate_repr) {
constants.push(candidate);
if constants.len() == len {
break;
@ -117,18 +114,24 @@ impl PoseidonParams {
}
}
struct Poseidon {
state: Vec<Fr>,
struct Poseidon<E: Engine> {
state: Vec<E::Fr>,
round: usize,
params: PoseidonParams,
params: PoseidonParams<E>,
}
impl Poseidon {
pub fn new_with_params(rf: usize, rp: usize, t: usize, round_constants: Vec<Fr>, mds_matrix: Vec<Fr>) -> Poseidon {
impl<E: Engine> Poseidon<E> {
pub fn new_with_params(
rf: usize,
rp: usize,
t: usize,
round_constants: Vec<E::Fr>,
mds_matrix: Vec<E::Fr>,
) -> Poseidon<E> {
let params = PoseidonParams::new(rf, rp, t, round_constants, mds_matrix);
Poseidon::new(params)
}
pub fn new(params: PoseidonParams) -> Poseidon {
pub fn new(params: PoseidonParams<E>) -> Poseidon<E> {
Poseidon {
round: 0,
state: Vec::new(),
@ -136,25 +139,25 @@ impl Poseidon {
}
}
pub fn hash(&mut self, inputs: &[Fr]) -> Fr {
pub fn hash(&mut self, inputs: &[E::Fr]) -> E::Fr {
self.new_state(inputs);
while self.round() {}
self.round = 0;
self.result()
}
fn new_state(&mut self, inputs: &[Fr]) {
fn new_state(&mut self, inputs: &[E::Fr]) {
let t = self.t();
assert!(inputs.len() < t);
self.state = inputs.to_vec();
self.state.resize(t, Fr::zero());
self.state.resize(t, E::Fr::zero());
}
fn t(&self) -> usize {
self.params.t
}
fn result(&self) -> Fr {
fn result(&self) -> E::Fr {
self.state[0]
}
@ -214,7 +217,7 @@ impl Poseidon {
fn mul_mds_matrix(&mut self) {
let w = self.params.t;
let mut new_state = vec![Fr::zero(); w];
let mut new_state = vec![E::Fr::zero(); w];
for (i, ns) in new_state.iter_mut().enumerate() {
// slice and zip
for (j, s) in self.state.iter().enumerate() {