mirror of https://github.com/vacp2p/zerokit.git
Add `utils` module (#53)
* refactor(rln/zerokit): move poseidon to separate utils crate * refactor(rln/zerokit): move merkle tree to utils crate * refactor(rln/zerokit): move poseidon to separate utils crate * fix(utils/rln): fmt & conflict resolve * feat(utils): add parallel feature
This commit is contained in:
parent
c42fcfe644
commit
bbacc9dcce
|
@ -4,4 +4,5 @@ members = [
|
||||||
"semaphore",
|
"semaphore",
|
||||||
"rln",
|
"rln",
|
||||||
"rln-wasm",
|
"rln-wasm",
|
||||||
|
"utils",
|
||||||
]
|
]
|
||||||
|
|
|
@ -34,16 +34,13 @@ num-traits = "0.2.11"
|
||||||
once_cell = "1.14.0"
|
once_cell = "1.14.0"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
|
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
|
||||||
|
utils = { path = "../utils/", default-features = false }
|
||||||
|
|
||||||
# serialization
|
# serialization
|
||||||
serde_json = "1.0.48"
|
serde_json = "1.0.48"
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
|
|
||||||
hex-literal = "0.3.4"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["parallel", "wasmer/sys-default"]
|
default = ["parallel", "wasmer/sys-default"]
|
||||||
fullmerkletree = []
|
fullmerkletree = []
|
||||||
parallel = ["ark-ec/parallel", "ark-ff/parallel", "ark-std/parallel", "ark-groth16/parallel"]
|
parallel = ["ark-ec/parallel", "ark-ff/parallel", "ark-std/parallel", "ark-groth16/parallel", "utils/parallel"]
|
||||||
wasm = ["wasmer/js", "wasmer/std"]
|
wasm = ["wasmer/js", "wasmer/std"]
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
pub mod circuit;
|
pub mod circuit;
|
||||||
pub mod merkle_tree;
|
|
||||||
pub mod poseidon_constants;
|
|
||||||
pub mod poseidon_hash;
|
pub mod poseidon_hash;
|
||||||
pub mod poseidon_tree;
|
pub mod poseidon_tree;
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
// This crate implements the Poseidon hash algorithm https://eprint.iacr.org/2019/458.pdf
|
// This crate instantiate the Poseidon hash algorithm
|
||||||
|
|
||||||
// Implementation partially taken from https://github.com/arnaucube/poseidon-rs/blob/233027d6075a637c29ad84a8a44f5653b81f0410/src/lib.rs
|
use crate::circuit::Fr;
|
||||||
// and adapted to work over arkworks field traits and custom data structures
|
use once_cell::sync::Lazy;
|
||||||
|
use utils::poseidon::Poseidon;
|
||||||
|
|
||||||
use crate::poseidon_constants::find_poseidon_ark_and_mds;
|
// These indexed constants hardcodes the supported round parameters tuples (t, RF, RN, SKIP_MATRICES) for the Bn254 scalar field
|
||||||
use ark_ff::{FpParameters, PrimeField};
|
// SKIP_MATRICES is the index of the randomly generated secure MDS matrix. See security note in the zerokit_utils::poseidon::poseidon_constants crate on this.
|
||||||
|
// TODO: generate these parameters
|
||||||
// These indexed constants hardcodes the round parameters tuple (t, RF, RN) from the paper for the Bn254 scalar field
|
|
||||||
// SKIP_MATRICES is the index of the randomly generated secure MDS matrix. See security note in the poseidon_constants crate on this.
|
|
||||||
// TODO: generate in-code such parameters
|
|
||||||
pub const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [
|
pub const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [
|
||||||
(2, 8, 56, 0),
|
(2, 8, 56, 0),
|
||||||
(3, 8, 57, 0),
|
(3, 8, 57, 0),
|
||||||
|
@ -20,145 +18,7 @@ pub const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [
|
||||||
(9, 8, 63, 0),
|
(9, 8, 63, 0),
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct RoundParamenters<F: PrimeField> {
|
|
||||||
pub t: usize,
|
|
||||||
pub n_rounds_f: usize,
|
|
||||||
pub n_rounds_p: usize,
|
|
||||||
pub skip_matrices: usize,
|
|
||||||
pub c: Vec<F>,
|
|
||||||
pub m: Vec<Vec<F>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Poseidon<F: PrimeField> {
|
|
||||||
round_params: Vec<RoundParamenters<F>>,
|
|
||||||
}
|
|
||||||
impl<F: PrimeField> Poseidon<F> {
|
|
||||||
// Loads round parameters and generates round constants
|
|
||||||
// poseidon_params is a vector containing tuples (t, RF, RP, skip_matrices)
|
|
||||||
// where: t is the rate (input lenght + 1), RF is the number of full rounds, RP is the number of partial rounds
|
|
||||||
// and skip_matrices is a (temporary) parameter used to generate secure MDS matrices (see comments in the description of find_poseidon_ark_and_mds)
|
|
||||||
// TODO: implement automatic generation of round parameters
|
|
||||||
pub fn from(poseidon_params: &[(usize, usize, usize, usize)]) -> Self {
|
|
||||||
let mut read_params = Vec::<RoundParamenters<F>>::new();
|
|
||||||
|
|
||||||
for i in 0..poseidon_params.len() {
|
|
||||||
let (t, n_rounds_f, n_rounds_p, skip_matrices) = poseidon_params[i];
|
|
||||||
let (ark, mds) = find_poseidon_ark_and_mds::<F>(
|
|
||||||
1, // is_field = 1
|
|
||||||
0, // is_sbox_inverse = 0
|
|
||||||
F::Params::MODULUS_BITS as u64,
|
|
||||||
t,
|
|
||||||
n_rounds_f as u64,
|
|
||||||
n_rounds_p as u64,
|
|
||||||
skip_matrices,
|
|
||||||
);
|
|
||||||
let rp = RoundParamenters {
|
|
||||||
t: t,
|
|
||||||
n_rounds_p: n_rounds_p,
|
|
||||||
n_rounds_f: n_rounds_f,
|
|
||||||
skip_matrices: skip_matrices,
|
|
||||||
c: ark,
|
|
||||||
m: mds,
|
|
||||||
};
|
|
||||||
read_params.push(rp);
|
|
||||||
}
|
|
||||||
|
|
||||||
Poseidon {
|
|
||||||
round_params: read_params,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_parameters(&self) -> Vec<RoundParamenters<F>> {
|
|
||||||
self.round_params.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ark(&self, state: &mut [F], c: &[F], 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 [F], 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: &[F], m: &[Vec<F>]) -> Vec<F> {
|
|
||||||
let mut new_state: Vec<F> = Vec::new();
|
|
||||||
for i in 0..state.len() {
|
|
||||||
new_state.push(F::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<F>) -> Result<F, String> {
|
|
||||||
// Note that the rate t becomes input lenght + 1, hence for lenght N we pick parameters with T = N + 1
|
|
||||||
let t = inp.len() + 1;
|
|
||||||
|
|
||||||
// We seek the index (Poseidon's round_params is an ordered vector) for the parameters corresponding to t
|
|
||||||
let param_index = self.round_params.iter().position(|el| el.t == t);
|
|
||||||
|
|
||||||
if inp.is_empty() || param_index.is_none() {
|
|
||||||
return Err("No parameters found for inputs length".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
let param_index = param_index.unwrap();
|
|
||||||
|
|
||||||
let mut state = vec![F::zero(); t];
|
|
||||||
state[1..].clone_from_slice(&inp);
|
|
||||||
|
|
||||||
for i in 0..(self.round_params[param_index].n_rounds_f
|
|
||||||
+ self.round_params[param_index].n_rounds_p)
|
|
||||||
{
|
|
||||||
self.ark(
|
|
||||||
&mut state,
|
|
||||||
&self.round_params[param_index].c,
|
|
||||||
(i as usize) * self.round_params[param_index].t,
|
|
||||||
);
|
|
||||||
self.sbox(
|
|
||||||
self.round_params[param_index].n_rounds_f,
|
|
||||||
self.round_params[param_index].n_rounds_p,
|
|
||||||
&mut state,
|
|
||||||
i,
|
|
||||||
);
|
|
||||||
state = self.mix(&state, &self.round_params[param_index].m);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(state[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F> Default for Poseidon<F>
|
|
||||||
where
|
|
||||||
F: PrimeField,
|
|
||||||
{
|
|
||||||
// Default instantiation has no round constants set. Will return an error when hashing is attempted.
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::from(&[])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::circuit::Fr;
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
// Poseidon Hash wrapper over above implementation. Adapted from semaphore-rs poseidon hash wrapper.
|
// Poseidon Hash wrapper over above implementation. Adapted from semaphore-rs poseidon hash wrapper.
|
||||||
|
|
||||||
static POSEIDON: Lazy<Poseidon<Fr>> = Lazy::new(|| Poseidon::<Fr>::from(&ROUND_PARAMS));
|
static POSEIDON: Lazy<Poseidon<Fr>> = Lazy::new(|| Poseidon::<Fr>::from(&ROUND_PARAMS));
|
||||||
|
|
||||||
pub fn poseidon_hash(input: &[Fr]) -> Fr {
|
pub fn poseidon_hash(input: &[Fr]) -> Fr {
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
// Implementation inspired by https://github.com/worldcoin/semaphore-rs/blob/d462a4372f1fd9c27610f2acfe4841fab1d396aa/src/poseidon_tree.rs (no differences)
|
// Implementation inspired by https://github.com/worldcoin/semaphore-rs/blob/d462a4372f1fd9c27610f2acfe4841fab1d396aa/src/poseidon_tree.rs (no differences)
|
||||||
|
|
||||||
use crate::circuit::Fr;
|
use crate::circuit::Fr;
|
||||||
use crate::merkle_tree::*;
|
|
||||||
use crate::poseidon_hash::poseidon_hash;
|
use crate::poseidon_hash::poseidon_hash;
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
|
use utils::merkle_tree::*;
|
||||||
|
|
||||||
// The zerokit RLN default Merkle tree implementation is the OptimalMerkleTree.
|
// The zerokit RLN default Merkle tree implementation is the OptimalMerkleTree.
|
||||||
// To switch to FullMerkleTree implementation, it is enough to enable the fullmerkletree feature
|
// To switch to FullMerkleTree implementation, it is enough to enable the fullmerkletree feature
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ark-ff = { version = "0.3.0", default-features = false, features = ["asm"] }
|
||||||
|
num-bigint = { version = "0.4.3", default-features = false, features = ["rand"] }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
ark-bn254 = { version = "0.3.0" }
|
||||||
|
num-traits = "0.2.11"
|
||||||
|
hex-literal = "0.3.4"
|
||||||
|
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["parallel"]
|
||||||
|
parallel = ["ark-ff/parallel"]
|
|
@ -0,0 +1,5 @@
|
||||||
|
pub mod poseidon;
|
||||||
|
pub use self::poseidon::*;
|
||||||
|
|
||||||
|
pub mod merkle_tree;
|
||||||
|
pub use self::merkle_tree::*;
|
|
@ -13,6 +13,8 @@
|
||||||
//! * Disk based storage backend (using mmaped files should be easy)
|
//! * Disk based storage backend (using mmaped files should be easy)
|
||||||
//! * Implement serialization for tree and Merkle proof
|
//! * Implement serialization for tree and Merkle proof
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::{
|
use std::{
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod merkle_tree;
|
||||||
|
pub use self::merkle_tree::*;
|
|
@ -0,0 +1,5 @@
|
||||||
|
pub mod poseidon_hash;
|
||||||
|
pub use self::poseidon_hash::*;
|
||||||
|
|
||||||
|
pub mod poseidon_constants;
|
||||||
|
pub use self::poseidon_constants::*;
|
|
@ -12,7 +12,6 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use ark_ff::{FpParameters, PrimeField};
|
use ark_ff::{FpParameters, PrimeField};
|
||||||
use ark_std::vec::Vec;
|
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
|
|
||||||
pub struct PoseidonGrainLFSR {
|
pub struct PoseidonGrainLFSR {
|
||||||
|
@ -274,10 +273,10 @@ pub fn find_poseidon_ark_and_mds<F: PrimeField>(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
|
||||||
use crate::circuit::Fr;
|
|
||||||
use crate::poseidon_hash::Poseidon;
|
use crate::poseidon_hash::Poseidon;
|
||||||
use crate::utils::str_to_fr;
|
use ark_bn254::Fr;
|
||||||
|
use num_bigint::BigUint;
|
||||||
|
use num_traits::Num;
|
||||||
|
|
||||||
const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [
|
const ROUND_PARAMS: [(usize, usize, usize, usize); 8] = [
|
||||||
(2, 8, 56, 0),
|
(2, 8, 56, 0),
|
||||||
|
@ -290,14 +289,34 @@ mod test {
|
||||||
(9, 8, 63, 0),
|
(9, 8, 63, 0),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
fn str_to_fr(input: &str, radix: u32) -> Fr {
|
||||||
|
assert!((radix == 10) || (radix == 16));
|
||||||
|
|
||||||
|
// We remove any quote present and we trim
|
||||||
|
let single_quote: char = '\"';
|
||||||
|
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)
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
input_clean = input_clean.replace("0x", "");
|
||||||
|
BigUint::from_str_radix(&input_clean, radix)
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
// The following constants were taken from https://github.com/arnaucube/poseidon-rs/blob/233027d6075a637c29ad84a8a44f5653b81f0410/src/constants.rs
|
// The following constants were taken from https://github.com/arnaucube/poseidon-rs/blob/233027d6075a637c29ad84a8a44f5653b81f0410/src/constants.rs
|
||||||
// Constants were generated from the Poseidon reference implementation as
|
// Constants were generated from the Poseidon reference implementation as
|
||||||
// generate_parameters_grain.sage 1 0 254 T RF RP 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
|
// generate_parameters_grain.sage 1 0 254 T RF RP 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
|
||||||
// with T in [2, 3, 4, 5, 6, 7, 8, 9], RF in [8, 8, 8, 8, 8, 8, 8, 8] and RP in [56, 57, 56, 60, 60, 63, 64, 63], respectively.
|
// with T in [2, 3, 4, 5, 6, 7, 8, 9], RF in [8, 8, 8, 8, 8, 8, 8, 8] and RP in [56, 57, 56, 60, 60, 63, 64, 63], respectively.
|
||||||
// (in implementation, if we want to hash N elements we use parameters for T = N+1)
|
// (in implementation, if we want to hash N elements we use parameters for T = N+1)
|
||||||
// The constants were generated and are valid only for Bn254 scalar field characteristic, i.e. 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
|
// The constants were generated and are valid only for Bn254 scalar field characteristic, i.e. 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
|
||||||
|
// They should correspond to the one obtained by instantiating Poseidon with ROUND_PARAMS above (skip_matrices all set to 0)
|
||||||
// The following constants should correspond to the one obtained by instantiating Poseidon with ROUND_PARAMS above (skip_matrices all set to 0)
|
|
||||||
fn constants() -> (Vec<Vec<&'static str>>, Vec<Vec<Vec<&'static str>>>) {
|
fn constants() -> (Vec<Vec<&'static str>>, Vec<Vec<Vec<&'static str>>>) {
|
||||||
let c_str: Vec<Vec<&str>> = vec![
|
let c_str: Vec<Vec<&str>> = vec![
|
||||||
vec![
|
vec![
|
|
@ -0,0 +1,142 @@
|
||||||
|
// This crate implements the Poseidon hash algorithm https://eprint.iacr.org/2019/458.pdf
|
||||||
|
|
||||||
|
// Implementation partially taken from https://github.com/arnaucube/poseidon-rs/blob/233027d6075a637c29ad84a8a44f5653b81f0410/src/lib.rs
|
||||||
|
// and adapted to work over arkworks field traits and custom data structures
|
||||||
|
|
||||||
|
use crate::poseidon_constants::find_poseidon_ark_and_mds;
|
||||||
|
use ark_ff::{FpParameters, PrimeField};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct RoundParamenters<F: PrimeField> {
|
||||||
|
pub t: usize,
|
||||||
|
pub n_rounds_f: usize,
|
||||||
|
pub n_rounds_p: usize,
|
||||||
|
pub skip_matrices: usize,
|
||||||
|
pub c: Vec<F>,
|
||||||
|
pub m: Vec<Vec<F>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Poseidon<F: PrimeField> {
|
||||||
|
round_params: Vec<RoundParamenters<F>>,
|
||||||
|
}
|
||||||
|
impl<F: PrimeField> Poseidon<F> {
|
||||||
|
// Loads round parameters and generates round constants
|
||||||
|
// poseidon_params is a vector containing tuples (t, RF, RP, skip_matrices)
|
||||||
|
// where: t is the rate (input lenght + 1), RF is the number of full rounds, RP is the number of partial rounds
|
||||||
|
// and skip_matrices is a (temporary) parameter used to generate secure MDS matrices (see comments in the description of find_poseidon_ark_and_mds)
|
||||||
|
// TODO: implement automatic generation of round parameters
|
||||||
|
pub fn from(poseidon_params: &[(usize, usize, usize, usize)]) -> Self {
|
||||||
|
let mut read_params = Vec::<RoundParamenters<F>>::new();
|
||||||
|
|
||||||
|
for i in 0..poseidon_params.len() {
|
||||||
|
let (t, n_rounds_f, n_rounds_p, skip_matrices) = poseidon_params[i];
|
||||||
|
let (ark, mds) = find_poseidon_ark_and_mds::<F>(
|
||||||
|
1, // is_field = 1
|
||||||
|
0, // is_sbox_inverse = 0
|
||||||
|
F::Params::MODULUS_BITS as u64,
|
||||||
|
t,
|
||||||
|
n_rounds_f as u64,
|
||||||
|
n_rounds_p as u64,
|
||||||
|
skip_matrices,
|
||||||
|
);
|
||||||
|
let rp = RoundParamenters {
|
||||||
|
t: t,
|
||||||
|
n_rounds_p: n_rounds_p,
|
||||||
|
n_rounds_f: n_rounds_f,
|
||||||
|
skip_matrices: skip_matrices,
|
||||||
|
c: ark,
|
||||||
|
m: mds,
|
||||||
|
};
|
||||||
|
read_params.push(rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Poseidon {
|
||||||
|
round_params: read_params,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_parameters(&self) -> Vec<RoundParamenters<F>> {
|
||||||
|
self.round_params.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ark(&self, state: &mut [F], c: &[F], 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 [F], 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: &[F], m: &[Vec<F>]) -> Vec<F> {
|
||||||
|
let mut new_state: Vec<F> = Vec::new();
|
||||||
|
for i in 0..state.len() {
|
||||||
|
new_state.push(F::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<F>) -> Result<F, String> {
|
||||||
|
// Note that the rate t becomes input lenght + 1, hence for lenght N we pick parameters with T = N + 1
|
||||||
|
let t = inp.len() + 1;
|
||||||
|
|
||||||
|
// We seek the index (Poseidon's round_params is an ordered vector) for the parameters corresponding to t
|
||||||
|
let param_index = self.round_params.iter().position(|el| el.t == t);
|
||||||
|
|
||||||
|
if inp.is_empty() || param_index.is_none() {
|
||||||
|
return Err("No parameters found for inputs length".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let param_index = param_index.unwrap();
|
||||||
|
|
||||||
|
let mut state = vec![F::zero(); t];
|
||||||
|
state[1..].clone_from_slice(&inp);
|
||||||
|
|
||||||
|
for i in 0..(self.round_params[param_index].n_rounds_f
|
||||||
|
+ self.round_params[param_index].n_rounds_p)
|
||||||
|
{
|
||||||
|
self.ark(
|
||||||
|
&mut state,
|
||||||
|
&self.round_params[param_index].c,
|
||||||
|
(i as usize) * self.round_params[param_index].t,
|
||||||
|
);
|
||||||
|
self.sbox(
|
||||||
|
self.round_params[param_index].n_rounds_f,
|
||||||
|
self.round_params[param_index].n_rounds_p,
|
||||||
|
&mut state,
|
||||||
|
i,
|
||||||
|
);
|
||||||
|
state = self.mix(&state, &self.round_params[param_index].m);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(state[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F> Default for Poseidon<F>
|
||||||
|
where
|
||||||
|
F: PrimeField,
|
||||||
|
{
|
||||||
|
// Default instantiation has no round constants set. Will return an error when hashing is attempted.
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::from(&[])
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue