1#![no_std]
2extern crate alloc;
7
8pub const SPONGE_WIDTH: usize = 12;
14
15pub const SPONGE_RATE: usize = 8;
18
19pub const SPONGE_CAPACITY: usize = SPONGE_WIDTH - SPONGE_RATE;
21
22pub const POSEIDON2_OUTPUT: usize = 4;
24
25pub const POSEIDON2_INTERNAL_ROUNDS: usize = 22;
27
28pub const POSEIDON2_EXTERNAL_ROUNDS: usize = 8;
30
31pub const POSEIDON2_SEED: u64 = 0x3141592653589793;
33
34pub const POSEIDON2_MATRIX_DIAG_12_RAW: [u64; 12] = [
37 0xc3b6c08e23ba9300,
38 0xd84b5de94a324fb6,
39 0x0d0c371c5b35b84f,
40 0x7964f570e7188037,
41 0x5daf18bbd996604b,
42 0x6743bc47b9595257,
43 0x5528b9362c59bb70,
44 0xac45e25b7127b68b,
45 0xa2077d7dfbb606b5,
46 0xf3faac6faee378ae,
47 0x0c6388b51545e883,
48 0xd27dbb6944917b60,
49];
50
51use alloc::vec::Vec;
52use p3_field::integers::QuotientMap;
53use p3_goldilocks::{Goldilocks, Poseidon2Goldilocks};
54use p3_poseidon2::{ExternalLayerConstants, Poseidon2};
55
56pub const POSEIDON2_INTERNAL_CONSTANTS_RAW: [u64; 22] = [
58 0x97f7798a784ad863,
59 0xd1d2bf082f60d4f0,
60 0x69a377a79f9ad206,
61 0xa9d06906a3858e24,
62 0x295275001eede5b5,
63 0x5874e441117bd746,
64 0x8a084bbba8ed86cc,
65 0x3defd7645cde6425,
66 0x3998cfe6871cc137,
67 0x3e52ef8bca48314a,
68 0x964a209f85dc9ecc,
69 0x3fcc9ee82cc4577e,
70 0x8e79b4a5d0096d6d,
71 0x8492362ad2392556,
72 0xee72f470262574d6,
73 0x1e0e18496da2444a,
74 0x0f3a74bf215eaac6,
75 0x1b061b76a1c0ded3,
76 0x192c42d86803d7a6,
77 0xf6d49ff997ae0260,
78 0x3ec372e7a0fa3786,
79 0x5538cdf4f23445d3,
80];
81
82pub const POSEIDON2_INITIAL_EXTERNAL_CONSTANTS_RAW: [[u64; 12]; 4] = [
84 [
85 0xc002e770975b1607,
86 0xbca51a8dfe14593a,
87 0x72938dfbe774f7f9,
88 0xe4f2fe29e03234ac,
89 0xd5e0ba2f541b6449,
90 0xec33b868f3cc46c1,
91 0x486dcb55419d475a,
92 0x6c1cb2a358cc24f1,
93 0xe3f30d509a1436bb,
94 0xd9a64f068dca7c29,
95 0xe59b3f57aabba1ae,
96 0x2a3dd4505b478fdc,
97 ],
98 [
99 0xada1f8dc7676ed25,
100 0x2711aa8b5509d516,
101 0x4ae6acd0c9c92897,
102 0x56eb3d6b5256d67a,
103 0x1f7a9d55923bf51e,
104 0x3600427d397a7f68,
105 0xe5076df75b72c3d0,
106 0xfcd59aa12c6090ad,
107 0xcd895e8c68b57a9e,
108 0x41df7ef9d730ae3e,
109 0xee3e2b889abe977d,
110 0xd29bb7edbeb9c405,
111 ],
112 [
113 0x7d5c08eef608e382,
114 0x89ae889caaf0802c,
115 0xb35a8e976d2af617,
116 0xdb14234eafaf5173,
117 0x78f04462d48b1c98,
118 0x265293b0e47ce88a,
119 0x999a649b69b9d32f,
120 0x64b0a186698e01d3,
121 0xee0b22d0dfae8bb8,
122 0x4fd53e50ca04a7ee,
123 0x5762bfe181f25047,
124 0xf51593e2beb5e3bd,
125 ],
126 [
127 0x1e5e2b5760e32477,
128 0x622462a1f9aaaeed,
129 0xaa284b3ecdb222ae,
130 0x63c8e72f542bf3fc,
131 0x3ba588cacb43b5e0,
132 0x23eda6f3c99150dd,
133 0xaad3bea4baac9a5a,
134 0xe9da8d699b94184a,
135 0xcdb13f4cd93e024c,
136 0x902cbd0956f655e3,
137 0x5b4e40ffc759532f,
138 0xde795c20a2357af7,
139 ],
140];
141
142pub const POSEIDON2_TERMINAL_EXTERNAL_CONSTANTS_RAW: [[u64; 12]; 4] = [
144 [
145 0x7b72c539e0ea4c6e,
146 0x144573dae2ce9976,
147 0x802028b68f35fc88,
148 0x6d36c5022c4fe7c2,
149 0xa205d0ffa9b9def3,
150 0xf6e7e38b1ea6ba2f,
151 0x34f7909ae5258d64,
152 0xb0464d9d77b97fca,
153 0x64ddb9d5de7e00a6,
154 0x0ed0d75c27975d97,
155 0x1cbb36f11127338b,
156 0x6673e505cfd0b6ba,
157 ],
158 [
159 0x605f902830872e01,
160 0x3fd5eb927e95fe4f,
161 0xe81025b5a24c69cd,
162 0xf7d0ce75de23f74e,
163 0xf39942b6a8585089,
164 0x6d808a08f7b71df6,
165 0xf8806b6588f49a8b,
166 0x57df2d8c2a32107a,
167 0x16e7c2074d654a2d,
168 0x213de241fcf33835,
169 0xb0f2b8905a0976f6,
170 0xd8e3cf2bbd355417,
171 ],
172 [
173 0xe498691679d9330f,
174 0x763b45d2a3821b28,
175 0x0908bf65eb0a1f0d,
176 0x7691eb2d194b24f4,
177 0x0e43551233ae13b2,
178 0x93c393dbfc2fe76f,
179 0x98f607485d48cdea,
180 0xe3d95f30309819c0,
181 0x1ef581a93eaf6acf,
182 0x0b24c1b7a030fca4,
183 0x624370be5670b327,
184 0x5f1e28615a11e486,
185 ],
186 [
187 0xfe04051f909e042b,
188 0x7257e5b147fd3803,
189 0xe6ae134bb82f2e78,
190 0x5711fd5cf4784511,
191 0xf83a42660c08c0bc,
192 0x2cd8c96d9a3ce855,
193 0x7d2ffb1bb0e17271,
194 0x85ae1528caea3811,
195 0x52a345d5c7adb0b8,
196 0x504c4c51f3faee94,
197 0xbce34a649cfccaf9,
198 0xe0a3389266fb6dc9,
199 ],
200];
201
202pub fn create_poseidon() -> Poseidon2Goldilocks<12> {
209 let internal_constants: Vec<Goldilocks> = POSEIDON2_INTERNAL_CONSTANTS_RAW
211 .iter()
212 .map(|&x| Goldilocks::from_int(x))
213 .collect();
214
215 let initial_constants: Vec<[Goldilocks; 12]> = POSEIDON2_INITIAL_EXTERNAL_CONSTANTS_RAW
216 .iter()
217 .map(|round| {
218 let mut round_constants = [Goldilocks::from_int(0); 12];
219 for (i, &val) in round.iter().enumerate() {
220 round_constants[i] = Goldilocks::from_int(val);
221 }
222 round_constants
223 })
224 .collect();
225
226 let terminal_constants: Vec<[Goldilocks; 12]> = POSEIDON2_TERMINAL_EXTERNAL_CONSTANTS_RAW
227 .iter()
228 .map(|round| {
229 let mut round_constants = [Goldilocks::from_int(0); 12];
230 for (i, &val) in round.iter().enumerate() {
231 round_constants[i] = Goldilocks::from_int(val);
232 }
233 round_constants
234 })
235 .collect();
236
237 let external_constants = ExternalLayerConstants::new(initial_constants, terminal_constants);
238 Poseidon2::new(external_constants, internal_constants)
239}
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244 use p3_field::PrimeCharacteristicRing;
245 use p3_symmetric::Permutation;
246 use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng};
247
248 #[test]
249 fn test_hardcoded_matches_derived() {
250 let mut rng = ChaCha20Rng::seed_from_u64(POSEIDON2_SEED);
251 let original = Poseidon2Goldilocks::<12>::new_from_rng_128(&mut rng);
252 let optimized = create_poseidon();
253
254 let mut state1 = [Goldilocks::ZERO; 12];
256 let mut state2 = [Goldilocks::ZERO; 12];
257
258 original.permute_mut(&mut state1);
259 optimized.permute_mut(&mut state2);
260
261 assert_eq!(state1, state2, "Zero input test failed");
262
263 let test_input: [Goldilocks; 12] =
265 core::array::from_fn(|i| Goldilocks::from_int(i as u64 + 1));
266
267 let mut state1 = test_input;
268 let mut state2 = test_input;
269
270 original.permute_mut(&mut state1);
271 optimized.permute_mut(&mut state2);
272
273 assert_eq!(state1, state2, "Sequential input test failed");
274 }
275
276 #[test]
277 fn test_multiple_permutations() {
278 let optimized = create_poseidon();
279
280 let test_inputs = [
282 [Goldilocks::ZERO; 12],
283 core::array::from_fn(|i| Goldilocks::from_int(i as u64)),
284 core::array::from_fn(|i| Goldilocks::from_int((i * i) as u64)),
285 ];
286
287 for input in test_inputs {
288 let mut state1 = input;
289 let mut state2 = input;
290
291 optimized.permute_mut(&mut state1);
293 optimized.permute_mut(&mut state2);
294
295 assert_eq!(state1, state2, "Permutation should be deterministic");
296 }
297 }
298}