1use alloc::vec::Vec;
11
12use p3_field::{Algebra, InjectiveMonomial};
13use p3_poseidon2::{
14 ExternalLayer, ExternalLayerConstants, ExternalLayerConstructor, HLMDSMat4, InternalLayer,
15 InternalLayerConstructor, MDSMat4, Poseidon2, add_rc_and_sbox_generic,
16 external_initial_permute_state, external_terminal_permute_state, internal_permute_state,
17 matmul_internal,
18};
19
20use crate::Goldilocks;
21
22const GOLDILOCKS_S_BOX_DEGREE: u64 = 7;
26
27pub type Poseidon2Goldilocks<const WIDTH: usize> = Poseidon2<
33 Goldilocks,
34 Poseidon2ExternalLayerGoldilocks<WIDTH>,
35 Poseidon2InternalLayerGoldilocks,
36 WIDTH,
37 GOLDILOCKS_S_BOX_DEGREE,
38>;
39
40pub type Poseidon2GoldilocksHL<const WIDTH: usize> = Poseidon2<
47 Goldilocks,
48 Poseidon2ExternalLayerGoldilocksHL<WIDTH>,
49 Poseidon2InternalLayerGoldilocks,
50 WIDTH,
51 GOLDILOCKS_S_BOX_DEGREE,
52>;
53
54pub const MATRIX_DIAG_8_GOLDILOCKS: [Goldilocks; 8] = Goldilocks::new_array([
55 0xa98811a1fed4e3a5,
56 0x1cc48b54f377e2a0,
57 0xe40cd4f6c5609a26,
58 0x11de79ebca97a4a3,
59 0x9177c73d8b7e929c,
60 0x2a6fe8085797e791,
61 0x3de6e93329f8d5ad,
62 0x3f7af9125da962fe,
63]);
64
65pub const MATRIX_DIAG_12_GOLDILOCKS: [Goldilocks; 12] = Goldilocks::new_array([
66 0xc3b6c08e23ba9300,
67 0xd84b5de94a324fb6,
68 0x0d0c371c5b35b84f,
69 0x7964f570e7188037,
70 0x5daf18bbd996604b,
71 0x6743bc47b9595257,
72 0x5528b9362c59bb70,
73 0xac45e25b7127b68b,
74 0xa2077d7dfbb606b5,
75 0xf3faac6faee378ae,
76 0x0c6388b51545e883,
77 0xd27dbb6944917b60,
78]);
79
80pub const MATRIX_DIAG_16_GOLDILOCKS: [Goldilocks; 16] = Goldilocks::new_array([
81 0xde9b91a467d6afc0,
82 0xc5f16b9c76a9be17,
83 0x0ab0fef2d540ac55,
84 0x3001d27009d05773,
85 0xed23b1f906d3d9eb,
86 0x5ce73743cba97054,
87 0x1c3bab944af4ba24,
88 0x2faa105854dbafae,
89 0x53ffb3ae6d421a10,
90 0xbcda9df8884ba396,
91 0xfc1273e4a31807bb,
92 0xc77952573d5142c0,
93 0x56683339a819b85e,
94 0x328fcbd8f0ddc8eb,
95 0xb5101e303fce9cb7,
96 0x774487b8c40089bb,
97]);
98
99pub const MATRIX_DIAG_20_GOLDILOCKS: [Goldilocks; 20] = Goldilocks::new_array([
100 0x95c381fda3b1fa57,
101 0xf36fe9eb1288f42c,
102 0x89f5dcdfef277944,
103 0x106f22eadeb3e2d2,
104 0x684e31a2530e5111,
105 0x27435c5d89fd148e,
106 0x3ebed31c414dbf17,
107 0xfd45b0b2d294e3cc,
108 0x48c904473a7f6dbf,
109 0xe0d1b67809295b4d,
110 0xddd1941e9d199dcb,
111 0x8cfe534eeb742219,
112 0xa6e5261d9e3b8524,
113 0x6897ee5ed0f82c1b,
114 0x0e7dcd0739ee5f78,
115 0x493253f3d0d32363,
116 0xbb2737f5845f05c0,
117 0xa187e810b06ad903,
118 0xb635b995936c4918,
119 0x0b3694a940bd2394,
120]);
121
122#[derive(Debug, Clone, Default)]
124pub struct Poseidon2InternalLayerGoldilocks {
125 internal_constants: Vec<Goldilocks>,
126}
127
128impl InternalLayerConstructor<Goldilocks> for Poseidon2InternalLayerGoldilocks {
129 fn new_from_constants(internal_constants: Vec<Goldilocks>) -> Self {
130 Self { internal_constants }
131 }
132}
133
134impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>>
135 InternalLayer<A, 8, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2InternalLayerGoldilocks
136{
137 fn permute_state(&self, state: &mut [A; 8]) {
139 internal_permute_state(
140 state,
141 |x| matmul_internal(x, MATRIX_DIAG_8_GOLDILOCKS),
142 &self.internal_constants,
143 );
144 }
145}
146
147impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>>
148 InternalLayer<A, 12, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2InternalLayerGoldilocks
149{
150 fn permute_state(&self, state: &mut [A; 12]) {
152 internal_permute_state(
153 state,
154 |x| matmul_internal(x, MATRIX_DIAG_12_GOLDILOCKS),
155 &self.internal_constants,
156 );
157 }
158}
159
160impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>>
161 InternalLayer<A, 16, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2InternalLayerGoldilocks
162{
163 fn permute_state(&self, state: &mut [A; 16]) {
165 internal_permute_state(
166 state,
167 |x| matmul_internal(x, MATRIX_DIAG_16_GOLDILOCKS),
168 &self.internal_constants,
169 );
170 }
171}
172
173impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>>
174 InternalLayer<A, 20, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2InternalLayerGoldilocks
175{
176 fn permute_state(&self, state: &mut [A; 20]) {
178 internal_permute_state(
179 state,
180 |x| matmul_internal(x, MATRIX_DIAG_20_GOLDILOCKS),
181 &self.internal_constants,
182 );
183 }
184}
185
186#[derive(Clone)]
188pub struct Poseidon2ExternalLayerGoldilocks<const WIDTH: usize> {
189 pub(crate) external_constants: ExternalLayerConstants<Goldilocks, WIDTH>,
190}
191
192impl<const WIDTH: usize> ExternalLayerConstructor<Goldilocks, WIDTH>
193 for Poseidon2ExternalLayerGoldilocks<WIDTH>
194{
195 fn new_from_constants(external_constants: ExternalLayerConstants<Goldilocks, WIDTH>) -> Self {
196 Self { external_constants }
197 }
198}
199
200impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>, const WIDTH: usize>
201 ExternalLayer<A, WIDTH, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2ExternalLayerGoldilocks<WIDTH>
202{
203 fn permute_state_initial(&self, state: &mut [A; WIDTH]) {
205 external_initial_permute_state(
206 state,
207 self.external_constants.get_initial_constants(),
208 add_rc_and_sbox_generic,
209 &MDSMat4,
210 );
211 }
212
213 fn permute_state_terminal(&self, state: &mut [A; WIDTH]) {
215 external_terminal_permute_state(
216 state,
217 self.external_constants.get_terminal_constants(),
218 add_rc_and_sbox_generic,
219 &MDSMat4,
220 );
221 }
222}
223
224#[derive(Clone)]
226pub struct Poseidon2ExternalLayerGoldilocksHL<const WIDTH: usize> {
227 pub(crate) external_constants: ExternalLayerConstants<Goldilocks, WIDTH>,
228}
229
230impl<const WIDTH: usize> ExternalLayerConstructor<Goldilocks, WIDTH>
231 for Poseidon2ExternalLayerGoldilocksHL<WIDTH>
232{
233 fn new_from_constants(external_constants: ExternalLayerConstants<Goldilocks, WIDTH>) -> Self {
234 Self { external_constants }
235 }
236}
237
238impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>, const WIDTH: usize>
239 ExternalLayer<A, WIDTH, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2ExternalLayerGoldilocksHL<WIDTH>
240{
241 fn permute_state_initial(&self, state: &mut [A; WIDTH]) {
243 external_initial_permute_state(
244 state,
245 self.external_constants.get_initial_constants(),
246 add_rc_and_sbox_generic,
247 &HLMDSMat4,
248 );
249 }
250
251 fn permute_state_terminal(&self, state: &mut [A; WIDTH]) {
253 external_terminal_permute_state(
254 state,
255 self.external_constants.get_terminal_constants(),
256 add_rc_and_sbox_generic,
257 &HLMDSMat4,
258 );
259 }
260}
261
262pub const HL_GOLDILOCKS_8_EXTERNAL_ROUND_CONSTANTS: [[[u64; 8]; 4]; 2] = [
263 [
264 [
265 0xdd5743e7f2a5a5d9,
266 0xcb3a864e58ada44b,
267 0xffa2449ed32f8cdc,
268 0x42025f65d6bd13ee,
269 0x7889175e25506323,
270 0x34b98bb03d24b737,
271 0xbdcc535ecc4faa2a,
272 0x5b20ad869fc0d033,
273 ],
274 [
275 0xf1dda5b9259dfcb4,
276 0x27515210be112d59,
277 0x4227d1718c766c3f,
278 0x26d333161a5bd794,
279 0x49b938957bf4b026,
280 0x4a56b5938b213669,
281 0x1120426b48c8353d,
282 0x6b323c3f10a56cad,
283 ],
284 [
285 0xce57d6245ddca6b2,
286 0xb1fc8d402bba1eb1,
287 0xb5c5096ca959bd04,
288 0x6db55cd306d31f7f,
289 0xc49d293a81cb9641,
290 0x1ce55a4fe979719f,
291 0xa92e60a9d178a4d1,
292 0x002cc64973bcfd8c,
293 ],
294 [
295 0xcea721cce82fb11b,
296 0xe5b55eb8098ece81,
297 0x4e30525c6f1ddd66,
298 0x43c6702827070987,
299 0xaca68430a7b5762a,
300 0x3674238634df9c93,
301 0x88cee1c825e33433,
302 0xde99ae8d74b57176,
303 ],
304 ],
305 [
306 [
307 0x014ef1197d341346,
308 0x9725e20825d07394,
309 0xfdb25aef2c5bae3b,
310 0xbe5402dc598c971e,
311 0x93a5711f04cdca3d,
312 0xc45a9a5b2f8fb97b,
313 0xfe8946a924933545,
314 0x2af997a27369091c,
315 ],
316 [
317 0xaa62c88e0b294011,
318 0x058eb9d810ce9f74,
319 0xb3cb23eced349ae4,
320 0xa3648177a77b4a84,
321 0x43153d905992d95d,
322 0xf4e2a97cda44aa4b,
323 0x5baa2702b908682f,
324 0x082923bdf4f750d1,
325 ],
326 [
327 0x98ae09a325893803,
328 0xf8a6475077968838,
329 0xceb0735bf00b2c5f,
330 0x0a1a5d953888e072,
331 0x2fcb190489f94475,
332 0xb5be06270dec69fc,
333 0x739cb934b09acf8b,
334 0x537750b75ec7f25b,
335 ],
336 [
337 0xe9dd318bae1f3961,
338 0xf7462137299efe1a,
339 0xb1f6b8eee9adb940,
340 0xbdebcc8a809dfe6b,
341 0x40fc1f791b178113,
342 0x3ac1c3362d014864,
343 0x9a016184bdb8aeba,
344 0x95f2394459fbc25e,
345 ],
346 ],
347];
348pub const HL_GOLDILOCKS_8_INTERNAL_ROUND_CONSTANTS: [u64; 22] = [
349 0x488897d85ff51f56,
350 0x1140737ccb162218,
351 0xa7eeb9215866ed35,
352 0x9bd2976fee49fcc9,
353 0xc0c8f0de580a3fcc,
354 0x4fb2dae6ee8fc793,
355 0x343a89f35f37395b,
356 0x223b525a77ca72c8,
357 0x56ccb62574aaa918,
358 0xc4d507d8027af9ed,
359 0xa080673cf0b7e95c,
360 0xf0184884eb70dcf8,
361 0x044f10b0cb3d5c69,
362 0xe9e3f7993938f186,
363 0x1b761c80e772f459,
364 0x606cec607a1b5fac,
365 0x14a0c2e1d45f03cd,
366 0x4eace8855398574f,
367 0xf905ca7103eff3e6,
368 0xf8c8f8d20862c059,
369 0xb524fe8bdd678e5a,
370 0xfbb7865901a1ec41,
371];
372
373#[cfg(test)]
374mod tests {
375 use core::array;
376
377 use p3_field::PrimeCharacteristicRing;
378 use p3_poseidon2::Poseidon2;
379 use p3_symmetric::Permutation;
380
381 use super::*;
382
383 type F = Goldilocks;
384
385 fn hl_poseidon2_goldilocks_width_8(input: &mut [F; 8]) {
388 const WIDTH: usize = 8;
389
390 let poseidon2: Poseidon2GoldilocksHL<WIDTH> = Poseidon2::new(
392 ExternalLayerConstants::<Goldilocks, WIDTH>::new_from_saved_array(
393 HL_GOLDILOCKS_8_EXTERNAL_ROUND_CONSTANTS,
394 Goldilocks::new_array,
395 ),
396 Goldilocks::new_array(HL_GOLDILOCKS_8_INTERNAL_ROUND_CONSTANTS).to_vec(),
397 );
398
399 poseidon2.permute_mut(input);
400 }
401
402 #[test]
404 fn test_poseidon2_width_8_zeros() {
405 let mut input: [F; 8] = [Goldilocks::ZERO; 8];
406
407 let expected: [F; 8] = Goldilocks::new_array([
408 4214787979728720400,
409 12324939279576102560,
410 10353596058419792404,
411 15456793487362310586,
412 10065219879212154722,
413 16227496357546636742,
414 2959271128466640042,
415 14285409611125725709,
416 ]);
417 hl_poseidon2_goldilocks_width_8(&mut input);
418 assert_eq!(input, expected);
419 }
420
421 #[test]
423 fn test_poseidon2_width_8_range() {
424 let mut input: [F; 8] = array::from_fn(|i| F::from_u64(i as u64));
425
426 let expected: [F; 8] = Goldilocks::new_array([
427 14266028122062624699,
428 5353147180106052723,
429 15203350112844181434,
430 17630919042639565165,
431 16601551015858213987,
432 10184091939013874068,
433 16774100645754596496,
434 12047415603622314780,
435 ]);
436 hl_poseidon2_goldilocks_width_8(&mut input);
437 assert_eq!(input, expected);
438 }
439
440 #[test]
445 fn test_poseidon2_width_8_random() {
446 let mut input: [F; 8] = Goldilocks::new_array([
447 5116996373749832116,
448 8931548647907683339,
449 17132360229780760684,
450 11280040044015983889,
451 11957737519043010992,
452 15695650327991256125,
453 17604752143022812942,
454 543194415197607509,
455 ]);
456
457 let expected: [F; 8] = Goldilocks::new_array([
458 1831346684315917658,
459 13497752062035433374,
460 12149460647271516589,
461 15656333994315312197,
462 4671534937670455565,
463 3140092508031220630,
464 4251208148861706881,
465 6973971209430822232,
466 ]);
467
468 hl_poseidon2_goldilocks_width_8(&mut input);
469 assert_eq!(input, expected);
470 }
471}