poseidon-ark/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}