arnaucube
arnaucube/poseidon-rsPublic Self-hosted repository
poseidon-rs/gen_constants/src/main.rs
gen_constants/src/main.rsRaw
  1use blake2::digest::{Input, VariableOutput};
  2use blake2::VarBlake2b;
  3
  4extern crate num;
  5extern crate num_bigint;
  6extern crate num_traits;
  7use num_bigint::{BigInt, Sign};
  8use num_traits::{One, Zero};
  9
 10const SEED: &str = "poseidon";
 11const NROUNDSF: usize = 8;
 12const NROUNDSP: usize = 57;
 13const T: usize = 6;
 14
 15#[derive(Debug)]
 16pub struct Constants {
 17    c: Vec<BigInt>,
 18    m: Vec<Vec<BigInt>>,
 19}
 20
 21pub fn generate_constants() -> Constants {
 22    let r: BigInt = BigInt::parse_bytes(
 23        b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
 24        10,
 25    )
 26    .unwrap();
 27
 28    let c = get_pseudo_random(&r, format!("{}{}", SEED, "_constants"), NROUNDSF + NROUNDSP);
 29    let m = get_mds(&r);
 30    Constants { c: c, m: m }
 31}
 32
 33pub fn get_pseudo_random(r: &BigInt, seed: String, n: usize) -> Vec<BigInt> {
 34    let mut hasher = VarBlake2b::new(32).unwrap();
 35    hasher.input(seed.as_bytes());
 36    let mut h = hasher.vec_result();
 37
 38    let mut res: Vec<BigInt> = Vec::new();
 39    while res.len() < n {
 40        let new_n: BigInt = modulus(&BigInt::from_bytes_le(Sign::Plus, &h), &r);
 41        res.push(new_n);
 42        let mut hasher = VarBlake2b::new(32).unwrap();
 43        hasher.input(h);
 44        h = hasher.vec_result();
 45    }
 46    res
 47}
 48
 49pub fn nonce_to_string(n: usize) -> String {
 50    let mut r = format!("{}", n);
 51    while r.len() < 4 {
 52        r = format!("0{}", r);
 53    }
 54    r
 55}
 56
 57pub fn get_mds(r: &BigInt) -> Vec<Vec<BigInt>> {
 58    let mut nonce = 0;
 59    let mut cauchy_matrix = get_pseudo_random(
 60        r,
 61        format!("{}_matrix_{}", SEED, nonce_to_string(nonce)),
 62        T * 2,
 63    );
 64    while !check_all_different(&cauchy_matrix) {
 65        nonce = nonce + 1;
 66        cauchy_matrix = get_pseudo_random(
 67            r,
 68            format!("{}_matrix_{}", SEED, nonce_to_string(nonce)),
 69            T * 2,
 70        );
 71    }
 72    let mut m: Vec<Vec<BigInt>> = Vec::new();
 73    for i in 0..T {
 74        let mut mi: Vec<BigInt> = Vec::new();
 75        for j in 0..T {
 76            mi.push(modinv(
 77                &modulus(&(&cauchy_matrix[i] - &cauchy_matrix[T + j]), &r),
 78                &r,
 79            ));
 80        }
 81        m.push(mi);
 82    }
 83    m
 84}
 85
 86pub fn check_all_different(v: &Vec<BigInt>) -> bool {
 87    let zero: BigInt = Zero::zero();
 88    for i in 0..v.len() {
 89        if v[i] == zero {
 90            return false;
 91        }
 92        for j in i + 1..v.len() {
 93            if v[i] == v[j] {
 94                return false;
 95            }
 96        }
 97    }
 98    true
 99}
100
101pub fn modulus(a: &BigInt, m: &BigInt) -> BigInt {
102    ((a % m) + m) % m
103}
104
105pub fn modinv(a: &BigInt, q: &BigInt) -> BigInt {
106    let mut mn = (q.clone(), a.clone());
107    let mut xy: (BigInt, BigInt) = (Zero::zero(), One::one());
108
109    let big_zero: BigInt = Zero::zero();
110    while mn.1 != big_zero {
111        xy = (xy.1.clone(), xy.0 - (mn.0.clone() / mn.1.clone()) * xy.1);
112        mn = (mn.1.clone(), modulus(&mn.0, &mn.1));
113    }
114
115    while xy.0 < Zero::zero() {
116        xy.0 = modulus(&xy.0, q);
117    }
118    xy.0
119}
120
121fn main() {
122    let c = generate_constants();
123    println!("let c_str: Vec<&str> = vec![");
124    for i in 0..c.c.len() {
125        println!("  {:?},", c.c[i].to_string());
126    }
127    println!("];\n");
128    println!("let m_str: Vec<Vec<&str>> = vec![");
129    for i in 0..c.m.len() {
130        println!("  vec![");
131        for j in 0..c.m[i].len() {
132            println!("      {:?},", c.m[i][j].to_string());
133        }
134        println!("  ],");
135    }
136    println!("];\n");
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142    use rustc_hex::ToHex;
143
144    #[test]
145    fn test_blake2_version() {
146        let mut hasher = VarBlake2b::new(32).unwrap();
147        hasher.input(b"poseidon_constants");
148        let h = hasher.vec_result();
149        assert_eq!(
150            h.to_hex(),
151            "e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1"
152        );
153    }
154}