|
|
@ -0,0 +1,154 @@ |
|
|
|
use blake2::digest::{Input, VariableOutput};
|
|
|
|
use blake2::VarBlake2b;
|
|
|
|
|
|
|
|
extern crate num;
|
|
|
|
extern crate num_bigint;
|
|
|
|
extern crate num_traits;
|
|
|
|
use num_bigint::{BigInt, Sign};
|
|
|
|
use num_traits::{One, Zero};
|
|
|
|
|
|
|
|
const SEED: &str = "poseidon";
|
|
|
|
const NROUNDSF: usize = 8;
|
|
|
|
const NROUNDSP: usize = 57;
|
|
|
|
const T: usize = 6;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Constants {
|
|
|
|
c: Vec<BigInt>,
|
|
|
|
m: Vec<Vec<BigInt>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn generate_constants() -> Constants {
|
|
|
|
let r: BigInt = BigInt::parse_bytes(
|
|
|
|
b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
|
|
|
|
10,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let c = get_pseudo_random(&r, format!("{}{}", SEED, "_constants"), NROUNDSF + NROUNDSP);
|
|
|
|
let m = get_mds(&r);
|
|
|
|
Constants { c: c, m: m }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_pseudo_random(r: &BigInt, seed: String, n: usize) -> Vec<BigInt> {
|
|
|
|
let mut hasher = VarBlake2b::new(32).unwrap();
|
|
|
|
hasher.input(seed.as_bytes());
|
|
|
|
let mut h = hasher.vec_result();
|
|
|
|
|
|
|
|
let mut res: Vec<BigInt> = Vec::new();
|
|
|
|
while res.len() < n {
|
|
|
|
let new_n: BigInt = modulus(&BigInt::from_bytes_le(Sign::Plus, &h), &r);
|
|
|
|
res.push(new_n);
|
|
|
|
let mut hasher = VarBlake2b::new(32).unwrap();
|
|
|
|
hasher.input(h);
|
|
|
|
h = hasher.vec_result();
|
|
|
|
}
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn nonce_to_string(n: usize) -> String {
|
|
|
|
let mut r = format!("{}", n);
|
|
|
|
while r.len() < 4 {
|
|
|
|
r = format!("0{}", r);
|
|
|
|
}
|
|
|
|
r
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_mds(r: &BigInt) -> Vec<Vec<BigInt>> {
|
|
|
|
let mut nonce = 0;
|
|
|
|
let mut cauchy_matrix = get_pseudo_random(
|
|
|
|
r,
|
|
|
|
format!("{}_matrix_{}", SEED, nonce_to_string(nonce)),
|
|
|
|
T * 2,
|
|
|
|
);
|
|
|
|
while !check_all_different(&cauchy_matrix) {
|
|
|
|
nonce = nonce + 1;
|
|
|
|
cauchy_matrix = get_pseudo_random(
|
|
|
|
r,
|
|
|
|
format!("{}_matrix_{}", SEED, nonce_to_string(nonce)),
|
|
|
|
T * 2,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
let mut m: Vec<Vec<BigInt>> = Vec::new();
|
|
|
|
for i in 0..T {
|
|
|
|
let mut mi: Vec<BigInt> = Vec::new();
|
|
|
|
for j in 0..T {
|
|
|
|
mi.push(modinv(
|
|
|
|
&modulus(&(&cauchy_matrix[i] - &cauchy_matrix[T + j]), &r),
|
|
|
|
&r,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
m.push(mi);
|
|
|
|
}
|
|
|
|
m
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn check_all_different(v: &Vec<BigInt>) -> bool {
|
|
|
|
let zero: BigInt = Zero::zero();
|
|
|
|
for i in 0..v.len() {
|
|
|
|
if v[i] == zero {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for j in i + 1..v.len() {
|
|
|
|
if v[i] == v[j] {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt {
|
|
|
|
((a % m) + m) % m
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn modinv(a: &BigInt, q: &BigInt) -> BigInt {
|
|
|
|
let mut mn = (q.clone(), a.clone());
|
|
|
|
let mut xy: (BigInt, BigInt) = (Zero::zero(), One::one());
|
|
|
|
|
|
|
|
let big_zero: BigInt = Zero::zero();
|
|
|
|
while mn.1 != big_zero {
|
|
|
|
xy = (xy.1.clone(), xy.0 - (mn.0.clone() / mn.1.clone()) * xy.1);
|
|
|
|
mn = (mn.1.clone(), modulus(&mn.0, &mn.1));
|
|
|
|
}
|
|
|
|
|
|
|
|
while xy.0 < Zero::zero() {
|
|
|
|
xy.0 = modulus(&xy.0, q);
|
|
|
|
}
|
|
|
|
xy.0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let c = generate_constants();
|
|
|
|
println!("let c_str: Vec<&str> = vec![");
|
|
|
|
for i in 0..c.c.len() {
|
|
|
|
println!(" {:?},", c.c[i].to_string());
|
|
|
|
}
|
|
|
|
println!("];\n");
|
|
|
|
println!("let m_str: Vec<Vec<&str>> = vec![");
|
|
|
|
for i in 0..c.m.len() {
|
|
|
|
println!(" vec![");
|
|
|
|
for j in 0..c.m[i].len() {
|
|
|
|
println!(" {:?},", c.m[i][j].to_string());
|
|
|
|
}
|
|
|
|
println!(" ],");
|
|
|
|
}
|
|
|
|
println!("];\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use rustc_hex::ToHex;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_blake2_version() {
|
|
|
|
let mut hasher = VarBlake2b::new(32).unwrap();
|
|
|
|
hasher.input(b"poseidon_constants");
|
|
|
|
let h = hasher.vec_result();
|
|
|
|
assert_eq!(
|
|
|
|
h.to_hex(),
|
|
|
|
"e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|