Skip to main content

qp_poseidon_constants/
lib.rs

1#![no_std]
2// Auto-generated Poseidon2 constants for WIDTH=12
3// Generated with seed: 0x3141592653589793
4// External rounds: 8, Internal rounds: 22
5
6extern crate alloc;
7
8// ============================================================================
9// Poseidon2 Sponge Parameters
10// ============================================================================
11
12/// Width of the Poseidon2 sponge (number of field elements in state).
13pub const SPONGE_WIDTH: usize = 12;
14
15/// Rate of the sponge construction (number of field elements absorbed per permutation).
16/// With WIDTH=12 and RATE=8, the capacity is 4 field elements.
17pub const SPONGE_RATE: usize = 8;
18
19/// Capacity of the sponge (security parameter = WIDTH - RATE).
20pub const SPONGE_CAPACITY: usize = SPONGE_WIDTH - SPONGE_RATE;
21
22/// Number of output field elements in a Poseidon2 hash digest.
23pub const POSEIDON2_OUTPUT: usize = 4;
24
25/// Number of internal (partial) rounds in the Poseidon2 permutation.
26pub const POSEIDON2_INTERNAL_ROUNDS: usize = 22;
27
28/// Number of external (full) rounds in the Poseidon2 permutation (4 initial + 4 terminal).
29pub const POSEIDON2_EXTERNAL_ROUNDS: usize = 8;
30
31/// Seed used to derive Poseidon2 round constants (digits of pi).
32pub const POSEIDON2_SEED: u64 = 0x3141592653589793;
33
34/// Diagonal matrix constants for Poseidon2 internal diffusion layer (WIDTH=12).
35/// These match `MATRIX_DIAG_12_GOLDILOCKS` from p3-goldilocks.
36pub 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
56/// Raw u64 values for internal round constants
57pub 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
82/// Raw u64 values for initial external round constants
83pub 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
142/// Raw u64 values for terminal external round constants
143pub 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
202/// Create a Poseidon2 instance using precomputed constants
203///
204/// This is significantly faster than `Poseidon2Core::new()` since it avoids
205/// the expensive constant derivation process and runtime conversions.
206/// The constants are computed only once and stored as raw u64 values, then
207/// converted to field elements when this function is called.
208pub fn create_poseidon() -> Poseidon2Goldilocks<12> {
209	// Convert raw u64 arrays to Goldilocks field elements at runtime
210	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		// Test with zero input
255		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		// Test with sequential input
264		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		// Test multiple permutations to ensure consistency
281		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			// Apply the same permutation twice - should be deterministic
292			optimized.permute_mut(&mut state1);
293			optimized.permute_mut(&mut state2);
294
295			assert_eq!(state1, state2, "Permutation should be deterministic");
296		}
297	}
298}