1#[cfg(not(feature = "std"))]
5use alloc::{vec, vec::Vec};
6use core::fmt::Debug;
7
8use plonky2_field::packed::PackedField;
9use unroll::unroll_for_loops;
10
11use crate::field::extension::{Extendable, FieldExtension};
12use crate::field::types::{Field, PrimeField64};
13use crate::gates::gate::Gate;
14use crate::gates::poseidon::PoseidonGate;
15use crate::gates::poseidon_mds::PoseidonMdsGate;
16use crate::hash::hash_types::{HashOut, RichField};
17use crate::hash::hashing::{compress, hash_n_to_hash_no_pad, PlonkyPermutation};
18use crate::iop::ext_target::ExtensionTarget;
19use crate::iop::target::{BoolTarget, Target};
20use crate::plonk::circuit_builder::CircuitBuilder;
21use crate::plonk::config::{AlgebraicHasher, Hasher};
22
23pub const SPONGE_RATE: usize = 8;
24pub const SPONGE_CAPACITY: usize = 4;
25pub const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY;
26
27pub const HALF_N_FULL_ROUNDS: usize = 4;
34pub(crate) const N_FULL_ROUNDS_TOTAL: usize = 2 * HALF_N_FULL_ROUNDS;
35pub const N_PARTIAL_ROUNDS: usize = 22;
36pub const N_ROUNDS: usize = N_FULL_ROUNDS_TOTAL + N_PARTIAL_ROUNDS;
37const MAX_WIDTH: usize = 12; #[inline(always)]
40const fn add_u160_u128((x_lo, x_hi): (u128, u32), y: u128) -> (u128, u32) {
41 let (res_lo, over) = x_lo.overflowing_add(y);
42 let res_hi = x_hi + (over as u32);
43 (res_lo, res_hi)
44}
45
46#[inline(always)]
47fn reduce_u160<F: PrimeField64>((n_lo, n_hi): (u128, u32)) -> F {
48 let n_lo_hi = (n_lo >> 64) as u64;
49 let n_lo_lo = n_lo as u64;
50 let reduced_hi: u64 = F::from_noncanonical_u96((n_lo_hi, n_hi)).to_noncanonical_u64();
51 let reduced128: u128 = ((reduced_hi as u128) << 64) + (n_lo_lo as u128);
52 F::from_noncanonical_u128(reduced128)
53}
54
55#[rustfmt::skip]
59pub const ALL_ROUND_CONSTANTS: [u64; MAX_WIDTH * N_ROUNDS] = [
60 0xb585f766f2144405, 0x7746a55f43921ad7, 0xb2fb0d31cee799b4, 0x0f6760a4803427d7,
68 0xe10d666650f4e012, 0x8cae14cb07d09bf1, 0xd438539c95f63e9f, 0xef781c7ce35b4c3d,
69 0xcdc4a239b0c44426, 0x277fa208bf337bff, 0xe17653a29da578a1, 0xc54302f225db2c76,
70 0x86287821f722c881, 0x59cd1a8a41c18e55, 0xc3b919ad495dc574, 0xa484c4c5ef6a0781,
71 0x308bbd23dc5416cc, 0x6e4a40c18f30c09c, 0x9a2eedb70d8f8cfa, 0xe360c6e0ae486f38,
72 0xd5c7718fbfc647fb, 0xc35eae071903ff0b, 0x849c2656969c4be7, 0xc0572c8c08cbbbad,
73 0xe9fa634a21de0082, 0xf56f6d48959a600d, 0xf7d713e806391165, 0x8297132b32825daf,
74 0xad6805e0e30b2c8a, 0xac51d9f5fcf8535e, 0x502ad7dc18c2ad87, 0x57a1550c110b3041,
75 0x66bbd30e6ce0e583, 0x0da2abef589d644e, 0xf061274fdb150d61, 0x28b8ec3ae9c29633,
76 0x92a756e67e2b9413, 0x70e741ebfee96586, 0x019d5ee2af82ec1c, 0x6f6f2ed772466352,
77 0x7cf416cfe7e14ca1, 0x61df517b86a46439, 0x85dc499b11d77b75, 0x4b959b48b9c10733,
78 0xe8be3e5da8043e57, 0xf5c0bc1de6da8699, 0x40b12cbf09ef74bf, 0xa637093ecb2ad631,
79 0x3cc3f892184df408, 0x2e479dc157bf31bb, 0x6f49de07a6234346, 0x213ce7bede378d7b,
80 0x5b0431345d4dea83, 0xa2de45780344d6a1, 0x7103aaf94a7bf308, 0x5326fc0d97279301,
81 0xa9ceb74fec024747, 0x27f8ec88bb21b1a3, 0xfceb4fda1ded0893, 0xfac6ff1346a41675,
82 0x7131aa45268d7d8c, 0x9351036095630f9f, 0xad535b24afc26bfb, 0x4627f5c6993e44be,
83 0x645cf794b8f1cc58, 0x241c70ed0af61617, 0xacb8e076647905f1, 0x3737e9db4c4f474d,
84 0xe7ea5e33e75fffb6, 0x90dee49fc9bfc23a, 0xd1b1edf76bc09c92, 0x0b65481ba645c602,
85 0x99ad1aab0814283b, 0x438a7c91d416ca4d, 0xb60de3bcc5ea751c, 0xc99cab6aef6f58bc,
86 0x69a5ed92a72ee4ff, 0x5e7b329c1ed4ad71, 0x5fc0ac0800144885, 0x32db829239774eca,
87 0x0ade699c5830f310, 0x7cc5583b10415f21, 0x85df9ed2e166d64f, 0x6604df4fee32bcb1,
88 0xeb84f608da56ef48, 0xda608834c40e603d, 0x8f97fe408061f183, 0xa93f485c96f37b89,
89 0x6704e8ee8f18d563, 0xcee3e9ac1e072119, 0x510d0e65e2b470c1, 0xf6323f486b9038f0,
90 0x0b508cdeffa5ceef, 0xf2417089e4fb3cbd, 0x60e75c2890d15730, 0xa6217d8bf660f29c,
91 0x7159cd30c3ac118e, 0x839b4e8fafead540, 0x0d3f3e5e82920adc, 0x8f7d83bddee7bba8,
92 0x780f2243ea071d06, 0xeb915845f3de1634, 0xd19e120d26b6f386, 0x016ee53a7e5fecc6,
93 0xcb5fd54e7933e477, 0xacb8417879fd449f, 0x9c22190be7f74732, 0x5d693c1ba3ba3621,
94 0xdcef0797c2b69ec7, 0x3d639263da827b13, 0xe273fd971bc8d0e7, 0x418f02702d227ed5,
95 0x8c25fda3b503038c, 0x2cbaed4daec8c07c, 0x5f58e6afcdd6ddc2, 0x284650ac5e1b0eba,
96 0x635b337ee819dab5, 0x9f9a036ed4f2d49f, 0xb93e260cae5c170e, 0xb0a7eae879ddb76d,
97 0xd0762cbc8ca6570c, 0x34c6efb812b04bf5, 0x40bf0ab5fa14c112, 0xb6b570fc7c5740d3,
98 0x5a27b9002de33454, 0xb1a5b165b6d2b2d2, 0x8722e0ace9d1be22, 0x788ee3b37e5680fb,
99 0x14a726661551e284, 0x98b7672f9ef3b419, 0xbb93ae776bb30e3a, 0x28fd3b046380f850,
100 0x30a4680593258387, 0x337dc00c61bd9ce1, 0xd5eca244c7a4ff1d, 0x7762638264d279bd,
101 0xc1e434bedeefd767, 0x0299351a53b8ec22, 0xb2d456e4ad251b80, 0x3e9ed1fda49cea0b,
102 0x2972a92ba450bed8, 0x20216dd77be493de, 0xadffe8cf28449ec6, 0x1c4dbb1c4c27d243,
103 0x15a16a8a8322d458, 0x388a128b7fd9a609, 0x2300e5d6baedf0fb, 0x2f63aa8647e15104,
104 0xf1c36ce86ecec269, 0x27181125183970c9, 0xe584029370dca96d, 0x4d9bbc3e02f1cfb2,
105 0xea35bc29692af6f8, 0x18e21b4beabb4137, 0x1e3b9fc625b554f4, 0x25d64362697828fd,
106 0x5a3f1bb1c53a9645, 0xdb7f023869fb8d38, 0xb462065911d4e1fc, 0x49c24ae4437d8030,
107 0xd793862c112b0566, 0xaadd1106730d8feb, 0xc43b6e0e97b0d568, 0xe29024c18ee6fca2,
108 0x5e50c27535b88c66, 0x10383f20a4ff9a87, 0x38e8ee9d71a45af8, 0xdd5118375bf1a9b9,
109 0x775005982d74d7f7, 0x86ab99b4dde6c8b0, 0xb1204f603f51c080, 0xef61ac8470250ecf,
110 0x1bbcd90f132c603f, 0x0cd1dabd964db557, 0x11a3ae5beb9d1ec9, 0xf755bfeea585d11d,
111 0xa3b83250268ea4d7, 0x516306f4927c93af, 0xddb4ac49c9efa1da, 0x64bb6dec369d4418,
112 0xf9cc95c22b4c1fcc, 0x08d37f755f4ae9f6, 0xeec49b613478675b, 0xf143933aed25e0b0,
113 0xe4c5dd8255dfc622, 0xe7ad7756f193198e, 0x92c2318b87fff9cb, 0x739c25f8fd73596d,
114 0x5636cac9f16dfed0, 0xdd8f909a938e0172, 0xc6401fe115063f5b, 0x8ad97b33f1ac1455,
115 0x0c49366bb25e8513, 0x0784d3d2f1698309, 0x530fb67ea1809a81, 0x410492299bb01f49,
116 0x139542347424b9ac, 0x9cb0bd5ea1a1115e, 0x02e3f615c38f49a1, 0x985d4f4a9c5291ef,
117 0x775b9feafdcd26e7, 0x304265a6384f0f2d, 0x593664c39773012c, 0x4f0a2e5fb028f2ce,
118 0xdd611f1000c17442, 0xd8185f9adfea4fd0, 0xef87139ca9a3ab1e, 0x3ba71336c34ee133,
119 0x7d3a455d56b70238, 0x660d32e130182684, 0x297a863f48cd1f43, 0x90e0a736a751ebb7,
120 0x549f80ce550c4fd3, 0x0f73b2922f38bd64, 0x16bf1f73fb7a9c3f, 0x6d1f5a59005bec17,
121 0x02ff876fa5ef97c4, 0xc5cb72a2a51159b0, 0x8470f39d2d5c900e, 0x25abb3f1d39fcb76,
122 0x23eb8cc9b372442f, 0xd687ba55c64f6364, 0xda8d9e90fd8ff158, 0xe3cbdc7d2fe45ea7,
123 0xb9a8c9b3aee52297, 0xc0d28a5c10960bd3, 0x45d7ac9b68f71a34, 0xeeb76e397069e804,
124 0x3d06c8bd1514e2d9, 0x9c9c98207cb10767, 0x65700b51aedfb5ef, 0x911f451539869408,
125 0x7ae6849fbc3a0ec6, 0x3bb340eba06afe7e, 0xb46e9d8b682ea65e, 0x8dcf22f9a3b34356,
126 0x77bdaeda586257a7, 0xf19e400a5104d20d, 0xc368a348e46d950f, 0x9ef1cd60e679f284,
127 0xe89cd854d5d01d33, 0x5cd377dc8bb882a2, 0xa7b0fb7883eee860, 0x7684403ec392950d,
128 0x5fa3f06f4fed3b52, 0x8df57ac11bc04831, 0x2db01efa1e1e1897, 0x54846de4aadb9ca2,
129 0xba6745385893c784, 0x541d496344d2c75b, 0xe909678474e687fe, 0xdfe89923f6c9c2ff,
130 0xece5a71e0cfedc75, 0x5ff98fd5d51fe610, 0x83e8941918964615, 0x5922040b47f150c1,
131 0xf97d750e3dd94521, 0x5080d4c2b86f56d7, 0xa7de115b56c78d70, 0x6a9242ac87538194,
132 0xf7856ef7f9173e44, 0x2265fc92feb0dc09, 0x17dfc8e4f7ba8a57, 0x9001a64209f21db8,
133 0x90004c1371b893c5, 0xb932b7cf752e5545, 0xa0b1df81b6fe59fc, 0x8ef1dd26770af2c2,
134 0x0541a4f9cfbeed35, 0x9e61106178bfc530, 0xb3767e80935d8af2, 0x0098d5782065af06,
135 0x31d191cd5c1466c7, 0x410fefafa319ac9d, 0xbdf8f242e316c4ab, 0x9e8cd55b57637ed0,
136 0xde122bebe9a39368, 0x4d001fd58f002526, 0xca6637000eb4a9f8, 0x2f2339d624f91f78,
137 0x6d1a7918c80df518, 0xdf9a4939342308e9, 0xebc2151ee6c8398c, 0x03cc2ba8a1116515,
138 0xd341d037e840cf83, 0x387cb5d25af4afcc, 0xbba2515f22909e87, 0x7248fe7705f38e47,
139 0x4d61e56a525d225a, 0x262e963c8da05d3d, 0x59e89b094d220ec2, 0x055d5b52b78b9c5e,
140 0x82b27eb33514ef99, 0xd30094ca96b7ce7b, 0xcf5cb381cd0a1535, 0xfeed4db6919e5a7c,
141 0x41703f53753be59f, 0x5eeea940fcde8b6f, 0x4cd1f1b175100206, 0x4a20358574454ec0,
142 0x1478d361dbbf9fac, 0x6f02dc07d141875c, 0x296a202ed8e556a2, 0x2afd67999bf32ee5,
143 0x7acfd96efa95491d, 0x6798ba0c0abb2c6d, 0x34c6f57b26c92122, 0x5736e1bad206b5de,
144 0x20057d2a0056521b, 0x3dea5bd5d0578bd7, 0x16e50d897d4634ac, 0x29bff3ecb9b7a6e3,
145 0x475cd3205a3bdcde, 0x18a42105c31b7e88, 0x023e7414af663068, 0x15147108121967d7,
146 0xe4a3dff1d7d6fef9, 0x01a8d1a588085737, 0x11b4c74eda62beef, 0xe587cc0d69a73346,
147 0x1ff7327017aa2a6e, 0x594e29c42473d06b, 0xf6f31db1899b12d5, 0xc02ac5e47312d3ca,
148 0xe70201e960cb78b8, 0x6f90ff3b6a65f108, 0x42747a7245e7fa84, 0xd1f507e43ab749b2,
149 0x1c86d265f15750cd, 0x3996ce73dd832c1c, 0x8e7fba02983224bd, 0xba0dec7103255dd4,
150 0x9e9cbd781628fc5b, 0xdae8645996edd6a5, 0xdebe0853b1a1d378, 0xa49229d24d014343,
151 0x7be5b9ffda905e1c, 0xa3c95eaec244aa30, 0x0230bca8f4df0544, 0x4135c2bebfe148c6,
152 0x166fc0cc438a3c72, 0x3762b59a8ae83efa, 0xe8928a4c89114750, 0x2a440b51a4945ee5,
153 0x80cefd2b7d99ff83, 0xbb9879c6e61fd62a, 0x6e7c8f1a84265034, 0x164bb2de1bbeddc8,
154 0xf3c12fe54d5c653b, 0x40b9e922ed9771e2, 0x551f5b0fbe7b1840, 0x25032aa7c4cb1811,
155 0xaaed34074b164346, 0x8ffd96bbf9c9c81d, 0x70fc91eb5937085c, 0x7f795e2a5f915440,
156 0x4543d9df5476d3cb, 0xf172d73e004fc90d, 0xdfd1c4febcc81238, 0xbc8dfb627fe558fc,
157];
158
159pub trait Poseidon: PrimeField64 {
160 const N_ROUND_CONSTANTS: usize = SPONGE_WIDTH * N_ROUNDS;
163
164 const MDS_MATRIX_CIRC: [u64; SPONGE_WIDTH];
168 const MDS_MATRIX_DIAG: [u64; SPONGE_WIDTH];
169
170 const FAST_PARTIAL_FIRST_ROUND_CONSTANT: [u64; SPONGE_WIDTH];
173 const FAST_PARTIAL_ROUND_CONSTANTS: [u64; N_PARTIAL_ROUNDS];
174 const FAST_PARTIAL_ROUND_VS: [[u64; SPONGE_WIDTH - 1]; N_PARTIAL_ROUNDS];
175 const FAST_PARTIAL_ROUND_W_HATS: [[u64; SPONGE_WIDTH - 1]; N_PARTIAL_ROUNDS];
176 const FAST_PARTIAL_ROUND_INITIAL_MATRIX: [[u64; SPONGE_WIDTH - 1]; SPONGE_WIDTH - 1];
177
178 #[inline(always)]
179 #[unroll_for_loops]
180 fn mds_row_shf(r: usize, v: &[u64; SPONGE_WIDTH]) -> u128 {
181 debug_assert!(r < SPONGE_WIDTH);
182 let mut res = 0u128;
190
191 for i in 0..12 {
193 if i < SPONGE_WIDTH {
194 res += (v[(i + r) % SPONGE_WIDTH] as u128) * (Self::MDS_MATRIX_CIRC[i] as u128);
195 }
196 }
197 res += (v[r] as u128) * (Self::MDS_MATRIX_DIAG[r] as u128);
198
199 res
200 }
201
202 fn mds_row_shf_field<F: FieldExtension<D, BaseField = Self>, const D: usize>(
204 r: usize,
205 v: &[F; SPONGE_WIDTH],
206 ) -> F {
207 debug_assert!(r < SPONGE_WIDTH);
208 let mut res = F::ZERO;
209
210 for i in 0..SPONGE_WIDTH {
211 res += v[(i + r) % SPONGE_WIDTH] * F::from_canonical_u64(Self::MDS_MATRIX_CIRC[i]);
212 }
213 res += v[r] * F::from_canonical_u64(Self::MDS_MATRIX_DIAG[r]);
214
215 res
216 }
217
218 fn mds_row_shf_packed_field<
220 F: RichField + Extendable<D>,
221 const D: usize,
222 FE,
223 P,
224 const D2: usize,
225 >(
226 r: usize,
227 v: &[P; SPONGE_WIDTH],
228 ) -> P
229 where
230 FE: FieldExtension<D2, BaseField = F>,
231 P: PackedField<Scalar = FE>,
232 {
233 debug_assert!(r < SPONGE_WIDTH);
234 let mut res = P::ZEROS;
235
236 for i in 0..SPONGE_WIDTH {
237 res +=
238 v[(i + r) % SPONGE_WIDTH] * P::Scalar::from_canonical_u64(Self::MDS_MATRIX_CIRC[i]);
239 }
240 res += v[r] * P::Scalar::from_canonical_u64(Self::MDS_MATRIX_DIAG[r]);
241
242 res
243 }
244
245 fn mds_row_shf_circuit<const D: usize>(
247 builder: &mut CircuitBuilder<Self, D>,
248 r: usize,
249 v: &[ExtensionTarget<D>; SPONGE_WIDTH],
250 ) -> ExtensionTarget<D>
251 where
252 Self: RichField + Extendable<D>,
253 {
254 debug_assert!(r < SPONGE_WIDTH);
255 let mut res = builder.zero_extension();
256
257 for i in 0..SPONGE_WIDTH {
258 let c = Self::from_canonical_u64(<Self as Poseidon>::MDS_MATRIX_CIRC[i]);
259 res = builder.mul_const_add_extension(c, v[(i + r) % SPONGE_WIDTH], res);
260 }
261 {
262 let c = Self::from_canonical_u64(<Self as Poseidon>::MDS_MATRIX_DIAG[r]);
263 res = builder.mul_const_add_extension(c, v[r], res);
264 }
265
266 res
267 }
268
269 #[inline(always)]
270 #[unroll_for_loops]
271 fn mds_layer(state_: &[Self; SPONGE_WIDTH]) -> [Self; SPONGE_WIDTH] {
272 let mut result = [Self::ZERO; SPONGE_WIDTH];
273
274 let mut state = [0u64; SPONGE_WIDTH];
275 for r in 0..SPONGE_WIDTH {
276 state[r] = state_[r].to_noncanonical_u64();
277 }
278
279 for r in 0..12 {
281 if r < SPONGE_WIDTH {
282 let sum = Self::mds_row_shf(r, &state);
283 let sum_lo = sum as u64;
284 let sum_hi = (sum >> 64) as u32;
285 result[r] = Self::from_noncanonical_u96((sum_lo, sum_hi));
286 }
287 }
288
289 result
290 }
291
292 fn mds_layer_field<F: FieldExtension<D, BaseField = Self>, const D: usize>(
294 state: &[F; SPONGE_WIDTH],
295 ) -> [F; SPONGE_WIDTH] {
296 let mut result = [F::ZERO; SPONGE_WIDTH];
297
298 for r in 0..SPONGE_WIDTH {
299 result[r] = Self::mds_row_shf_field(r, state);
300 }
301
302 result
303 }
304
305 fn mds_layer_packed_field<
307 F: RichField + Extendable<D>,
308 const D: usize,
309 FE,
310 P,
311 const D2: usize,
312 >(
313 state: &[P; SPONGE_WIDTH],
314 ) -> [P; SPONGE_WIDTH]
315 where
316 FE: FieldExtension<D2, BaseField = F>,
317 P: PackedField<Scalar = FE>,
318 {
319 let mut result = [P::ZEROS; SPONGE_WIDTH];
320
321 for r in 0..SPONGE_WIDTH {
322 result[r] = Self::mds_row_shf_packed_field(r, state);
323 }
324
325 result
326 }
327
328 fn mds_layer_circuit<const D: usize>(
330 builder: &mut CircuitBuilder<Self, D>,
331 state: &[ExtensionTarget<D>; SPONGE_WIDTH],
332 ) -> [ExtensionTarget<D>; SPONGE_WIDTH]
333 where
334 Self: RichField + Extendable<D>,
335 {
336 let mds_gate = PoseidonMdsGate::<Self, D>::new();
338 if builder.config.num_routed_wires >= mds_gate.num_wires() {
339 let index = builder.add_gate(mds_gate, vec![]);
340 for i in 0..SPONGE_WIDTH {
341 let input_wire = PoseidonMdsGate::<Self, D>::wires_input(i);
342 builder.connect_extension(state[i], ExtensionTarget::from_range(index, input_wire));
343 }
344 (0..SPONGE_WIDTH)
345 .map(|i| {
346 let output_wire = PoseidonMdsGate::<Self, D>::wires_output(i);
347 ExtensionTarget::from_range(index, output_wire)
348 })
349 .collect::<Vec<_>>()
350 .try_into()
351 .unwrap()
352 } else {
353 let mut result = [builder.zero_extension(); SPONGE_WIDTH];
354
355 for r in 0..SPONGE_WIDTH {
356 result[r] = Self::mds_row_shf_circuit(builder, r, state);
357 }
358
359 result
360 }
361 }
362
363 #[inline(always)]
364 #[unroll_for_loops]
365 fn partial_first_constant_layer<F: FieldExtension<D, BaseField = Self>, const D: usize>(
366 state: &mut [F; SPONGE_WIDTH],
367 ) {
368 for i in 0..12 {
369 if i < SPONGE_WIDTH {
370 state[i] += F::from_canonical_u64(Self::FAST_PARTIAL_FIRST_ROUND_CONSTANT[i]);
371 }
372 }
373 }
374
375 #[inline(always)]
377 #[unroll_for_loops]
378 fn partial_first_constant_layer_packed_field<
379 F: RichField + Extendable<D>,
380 const D: usize,
381 FE,
382 P,
383 const D2: usize,
384 >(
385 state: &mut [P; SPONGE_WIDTH],
386 ) where
387 FE: FieldExtension<D2, BaseField = F>,
388 P: PackedField<Scalar = FE>,
389 {
390 for i in 0..12 {
391 if i < SPONGE_WIDTH {
392 state[i] +=
393 P::Scalar::from_canonical_u64(Self::FAST_PARTIAL_FIRST_ROUND_CONSTANT[i]);
394 }
395 }
396 }
397
398 fn partial_first_constant_layer_circuit<const D: usize>(
400 builder: &mut CircuitBuilder<Self, D>,
401 state: &mut [ExtensionTarget<D>; SPONGE_WIDTH],
402 ) where
403 Self: RichField + Extendable<D>,
404 {
405 for i in 0..SPONGE_WIDTH {
406 let c = <Self as Poseidon>::FAST_PARTIAL_FIRST_ROUND_CONSTANT[i];
407 let c = Self::Extension::from_canonical_u64(c);
408 let c = builder.constant_extension(c);
409 state[i] = builder.add_extension(state[i], c);
410 }
411 }
412
413 #[inline(always)]
414 #[unroll_for_loops]
415 fn mds_partial_layer_init<F: FieldExtension<D, BaseField = Self>, const D: usize>(
416 state: &[F; SPONGE_WIDTH],
417 ) -> [F; SPONGE_WIDTH] {
418 let mut result = [F::ZERO; SPONGE_WIDTH];
419
420 result[0] = state[0];
424
425 for r in 1..12 {
426 if r < SPONGE_WIDTH {
427 for c in 1..12 {
428 if c < SPONGE_WIDTH {
429 let t = F::from_canonical_u64(
433 Self::FAST_PARTIAL_ROUND_INITIAL_MATRIX[r - 1][c - 1],
434 );
435 result[c] += state[r] * t;
436 }
437 }
438 }
439 }
440 result
441 }
442
443 #[inline(always)]
445 #[unroll_for_loops]
446 fn mds_partial_layer_init_packed_field<
447 F: RichField + Extendable<D>,
448 const D: usize,
449 FE,
450 P,
451 const D2: usize,
452 >(
453 state: &[P; SPONGE_WIDTH],
454 ) -> [P; SPONGE_WIDTH]
455 where
456 FE: FieldExtension<D2, BaseField = F>,
457 P: PackedField<Scalar = FE>,
458 {
459 let mut result = [P::ZEROS; SPONGE_WIDTH];
460
461 result[0] = state[0];
465
466 for r in 1..12 {
467 if r < SPONGE_WIDTH {
468 for c in 1..12 {
469 if c < SPONGE_WIDTH {
470 let t = P::Scalar::from_canonical_u64(
474 Self::FAST_PARTIAL_ROUND_INITIAL_MATRIX[r - 1][c - 1],
475 );
476 result[c] += state[r] * t;
477 }
478 }
479 }
480 }
481 result
482 }
483 fn mds_partial_layer_init_circuit<const D: usize>(
485 builder: &mut CircuitBuilder<Self, D>,
486 state: &[ExtensionTarget<D>; SPONGE_WIDTH],
487 ) -> [ExtensionTarget<D>; SPONGE_WIDTH]
488 where
489 Self: RichField + Extendable<D>,
490 {
491 let mut result = [builder.zero_extension(); SPONGE_WIDTH];
492
493 result[0] = state[0];
494
495 for r in 1..SPONGE_WIDTH {
496 for c in 1..SPONGE_WIDTH {
497 let t = <Self as Poseidon>::FAST_PARTIAL_ROUND_INITIAL_MATRIX[r - 1][c - 1];
498 let t = Self::Extension::from_canonical_u64(t);
499 let t = builder.constant_extension(t);
500 result[c] = builder.mul_add_extension(t, state[r], result[c]);
501 }
502 }
503 result
504 }
505
506 #[inline(always)]
515 #[unroll_for_loops]
516 fn mds_partial_layer_fast(state: &[Self; SPONGE_WIDTH], r: usize) -> [Self; SPONGE_WIDTH] {
517 let mut d_sum = (0u128, 0u32); for i in 1..12 {
521 if i < SPONGE_WIDTH {
522 let t = Self::FAST_PARTIAL_ROUND_W_HATS[r][i - 1] as u128;
523 let si = state[i].to_noncanonical_u64() as u128;
524 d_sum = add_u160_u128(d_sum, si * t);
525 }
526 }
527 let s0 = state[0].to_noncanonical_u64() as u128;
528 let mds0to0 = (Self::MDS_MATRIX_CIRC[0] + Self::MDS_MATRIX_DIAG[0]) as u128;
529 d_sum = add_u160_u128(d_sum, s0 * mds0to0);
530 let d = reduce_u160::<Self>(d_sum);
531
532 let mut result = [Self::ZERO; SPONGE_WIDTH];
534 result[0] = d;
535 for i in 1..12 {
536 if i < SPONGE_WIDTH {
537 let t = Self::from_canonical_u64(Self::FAST_PARTIAL_ROUND_VS[r][i - 1]);
538 result[i] = state[i].multiply_accumulate(state[0], t);
539 }
540 }
541 result
542 }
543
544 fn mds_partial_layer_fast_field<F: FieldExtension<D, BaseField = Self>, const D: usize>(
546 state: &[F; SPONGE_WIDTH],
547 r: usize,
548 ) -> [F; SPONGE_WIDTH] {
549 let s0 = state[0];
550 let mds0to0 = Self::MDS_MATRIX_CIRC[0] + Self::MDS_MATRIX_DIAG[0];
551 let mut d = s0 * F::from_canonical_u64(mds0to0);
552 for i in 1..SPONGE_WIDTH {
553 let t = F::from_canonical_u64(Self::FAST_PARTIAL_ROUND_W_HATS[r][i - 1]);
554 d += state[i] * t;
555 }
556
557 let mut result = [F::ZERO; SPONGE_WIDTH];
559 result[0] = d;
560 for i in 1..SPONGE_WIDTH {
561 let t = F::from_canonical_u64(Self::FAST_PARTIAL_ROUND_VS[r][i - 1]);
562 result[i] = state[0] * t + state[i];
563 }
564 result
565 }
566
567 fn mds_partial_layer_fast_packed_field<
569 F: RichField + Extendable<D>,
570 const D: usize,
571 FE,
572 P,
573 const D2: usize,
574 >(
575 state: &[P; SPONGE_WIDTH],
576 r: usize,
577 ) -> [P; SPONGE_WIDTH]
578 where
579 FE: FieldExtension<D2, BaseField = F>,
580 P: PackedField<Scalar = FE>,
581 {
582 let s0 = state[0];
583 let mds0to0 = Self::MDS_MATRIX_CIRC[0] + Self::MDS_MATRIX_DIAG[0];
584 let mut d = s0 * P::Scalar::from_canonical_u64(mds0to0);
585 for i in 1..SPONGE_WIDTH {
586 let t = P::Scalar::from_canonical_u64(Self::FAST_PARTIAL_ROUND_W_HATS[r][i - 1]);
587 d += state[i] * t;
588 }
589
590 let mut result = [P::ZEROS; SPONGE_WIDTH];
592 result[0] = d;
593 for i in 1..SPONGE_WIDTH {
594 let t = P::Scalar::from_canonical_u64(Self::FAST_PARTIAL_ROUND_VS[r][i - 1]);
595 result[i] = state[0] * t + state[i];
596 }
597 result
598 }
599
600 fn mds_partial_layer_fast_circuit<const D: usize>(
602 builder: &mut CircuitBuilder<Self, D>,
603 state: &[ExtensionTarget<D>; SPONGE_WIDTH],
604 r: usize,
605 ) -> [ExtensionTarget<D>; SPONGE_WIDTH]
606 where
607 Self: RichField + Extendable<D>,
608 {
609 let s0 = state[0];
610 let mds0to0 = Self::MDS_MATRIX_CIRC[0] + Self::MDS_MATRIX_DIAG[0];
611 let mut d = builder.mul_const_extension(Self::from_canonical_u64(mds0to0), s0);
612 for i in 1..SPONGE_WIDTH {
613 let t = <Self as Poseidon>::FAST_PARTIAL_ROUND_W_HATS[r][i - 1];
614 let t = Self::Extension::from_canonical_u64(t);
615 let t = builder.constant_extension(t);
616 d = builder.mul_add_extension(t, state[i], d);
617 }
618
619 let mut result = [builder.zero_extension(); SPONGE_WIDTH];
620 result[0] = d;
621 for i in 1..SPONGE_WIDTH {
622 let t = <Self as Poseidon>::FAST_PARTIAL_ROUND_VS[r][i - 1];
623 let t = Self::Extension::from_canonical_u64(t);
624 let t = builder.constant_extension(t);
625 result[i] = builder.mul_add_extension(t, state[0], state[i]);
626 }
627 result
628 }
629
630 #[inline(always)]
631 #[unroll_for_loops]
632 fn constant_layer(state: &mut [Self; SPONGE_WIDTH], round_ctr: usize) {
633 for i in 0..12 {
634 if i < SPONGE_WIDTH {
635 let round_constant = ALL_ROUND_CONSTANTS[i + SPONGE_WIDTH * round_ctr];
636 unsafe {
637 state[i] = state[i].add_canonical_u64(round_constant);
638 }
639 }
640 }
641 }
642
643 fn constant_layer_field<F: FieldExtension<D, BaseField = Self>, const D: usize>(
645 state: &mut [F; SPONGE_WIDTH],
646 round_ctr: usize,
647 ) {
648 for i in 0..SPONGE_WIDTH {
649 state[i] += F::from_canonical_u64(ALL_ROUND_CONSTANTS[i + SPONGE_WIDTH * round_ctr]);
650 }
651 }
652
653 fn constant_layer_packed_field<
655 F: RichField + Extendable<D>,
656 const D: usize,
657 FE,
658 P,
659 const D2: usize,
660 >(
661 state: &mut [P; SPONGE_WIDTH],
662 round_ctr: usize,
663 ) where
664 FE: FieldExtension<D2, BaseField = F>,
665 P: PackedField<Scalar = FE>,
666 {
667 for i in 0..SPONGE_WIDTH {
668 state[i] +=
669 P::Scalar::from_canonical_u64(ALL_ROUND_CONSTANTS[i + SPONGE_WIDTH * round_ctr]);
670 }
671 }
672
673 fn constant_layer_circuit<const D: usize>(
675 builder: &mut CircuitBuilder<Self, D>,
676 state: &mut [ExtensionTarget<D>; SPONGE_WIDTH],
677 round_ctr: usize,
678 ) where
679 Self: RichField + Extendable<D>,
680 {
681 for i in 0..SPONGE_WIDTH {
682 let c = ALL_ROUND_CONSTANTS[i + SPONGE_WIDTH * round_ctr];
683 let c = Self::Extension::from_canonical_u64(c);
684 let c = builder.constant_extension(c);
685 state[i] = builder.add_extension(state[i], c);
686 }
687 }
688
689 #[inline(always)]
690 fn sbox_monomial<F: FieldExtension<D, BaseField = Self>, const D: usize>(x: F) -> F {
691 let x2 = x.square();
693 let x4 = x2.square();
694 let x3 = x * x2;
695 x3 * x4
696 }
697
698 fn sbox_monomial_circuit<const D: usize>(
700 builder: &mut CircuitBuilder<Self, D>,
701 x: ExtensionTarget<D>,
702 ) -> ExtensionTarget<D>
703 where
704 Self: RichField + Extendable<D>,
705 {
706 builder.exp_u64_extension(x, 7)
708 }
709
710 #[inline(always)]
711 #[unroll_for_loops]
712 fn sbox_layer(state: &mut [Self; SPONGE_WIDTH]) {
713 for i in 0..12 {
714 if i < SPONGE_WIDTH {
715 state[i] = Self::sbox_monomial(state[i]);
716 }
717 }
718 }
719
720 fn sbox_layer_field<F: FieldExtension<D, BaseField = Self>, const D: usize>(
722 state: &mut [F; SPONGE_WIDTH],
723 ) {
724 for i in 0..SPONGE_WIDTH {
725 state[i] = Self::sbox_monomial(state[i]);
726 }
727 }
728
729 fn sbox_layer_circuit<const D: usize>(
731 builder: &mut CircuitBuilder<Self, D>,
732 state: &mut [ExtensionTarget<D>; SPONGE_WIDTH],
733 ) where
734 Self: RichField + Extendable<D>,
735 {
736 for i in 0..SPONGE_WIDTH {
737 state[i] = <Self as Poseidon>::sbox_monomial_circuit(builder, state[i]);
738 }
739 }
740
741 #[inline]
742 fn full_rounds(state: &mut [Self; SPONGE_WIDTH], round_ctr: &mut usize) {
743 for _ in 0..HALF_N_FULL_ROUNDS {
744 Self::constant_layer(state, *round_ctr);
745 Self::sbox_layer(state);
746 *state = Self::mds_layer(state);
747 *round_ctr += 1;
748 }
749 }
750
751 #[inline]
752 fn partial_rounds(state: &mut [Self; SPONGE_WIDTH], round_ctr: &mut usize) {
753 Self::partial_first_constant_layer(state);
754 *state = Self::mds_partial_layer_init(state);
755
756 for i in 0..N_PARTIAL_ROUNDS {
757 state[0] = Self::sbox_monomial(state[0]);
758 unsafe {
759 state[0] = state[0].add_canonical_u64(Self::FAST_PARTIAL_ROUND_CONSTANTS[i]);
760 }
761 *state = Self::mds_partial_layer_fast(state, i);
762 }
763 *round_ctr += N_PARTIAL_ROUNDS;
764 }
765
766 #[inline]
767 fn poseidon(input: [Self; SPONGE_WIDTH]) -> [Self; SPONGE_WIDTH] {
768 let mut state = input;
769 let mut round_ctr = 0;
770
771 Self::full_rounds(&mut state, &mut round_ctr);
772 Self::partial_rounds(&mut state, &mut round_ctr);
773 Self::full_rounds(&mut state, &mut round_ctr);
774 debug_assert_eq!(round_ctr, N_ROUNDS);
775
776 state
777 }
778
779 #[inline]
781 fn partial_rounds_naive(state: &mut [Self; SPONGE_WIDTH], round_ctr: &mut usize) {
782 for _ in 0..N_PARTIAL_ROUNDS {
783 Self::constant_layer(state, *round_ctr);
784 state[0] = Self::sbox_monomial(state[0]);
785 *state = Self::mds_layer(state);
786 *round_ctr += 1;
787 }
788 }
789
790 #[inline]
791 fn poseidon_naive(input: [Self; SPONGE_WIDTH]) -> [Self; SPONGE_WIDTH] {
792 let mut state = input;
793 let mut round_ctr = 0;
794
795 Self::full_rounds(&mut state, &mut round_ctr);
796 Self::partial_rounds_naive(&mut state, &mut round_ctr);
797 Self::full_rounds(&mut state, &mut round_ctr);
798 debug_assert_eq!(round_ctr, N_ROUNDS);
799
800 state
801 }
802}
803
804#[derive(Copy, Clone, Default, Debug, PartialEq)]
805pub struct PoseidonPermutation<T> {
806 state: [T; SPONGE_WIDTH],
807}
808
809impl<T: Eq> Eq for PoseidonPermutation<T> {}
810
811impl<T> AsRef<[T]> for PoseidonPermutation<T> {
812 fn as_ref(&self) -> &[T] {
813 &self.state
814 }
815}
816
817trait Permuter: Sized {
818 fn permute(input: [Self; SPONGE_WIDTH]) -> [Self; SPONGE_WIDTH];
819}
820
821impl<F: Poseidon> Permuter for F {
822 fn permute(input: [Self; SPONGE_WIDTH]) -> [Self; SPONGE_WIDTH] {
823 <F as Poseidon>::poseidon(input)
824 }
825}
826
827impl Permuter for Target {
828 fn permute(_input: [Self; SPONGE_WIDTH]) -> [Self; SPONGE_WIDTH] {
829 panic!("Call `permute_swapped()` instead of `permute()`");
830 }
831}
832
833impl<T: Copy + Debug + Default + Eq + Permuter + Send + Sync> PlonkyPermutation<T>
834 for PoseidonPermutation<T>
835{
836 const RATE: usize = SPONGE_RATE;
837 const WIDTH: usize = SPONGE_WIDTH;
838
839 fn new<I: IntoIterator<Item = T>>(elts: I) -> Self {
840 let mut perm = Self {
841 state: [T::default(); SPONGE_WIDTH],
842 };
843 perm.set_from_iter(elts, 0);
844 perm
845 }
846
847 fn set_elt(&mut self, elt: T, idx: usize) {
848 self.state[idx] = elt;
849 }
850
851 fn set_from_slice(&mut self, elts: &[T], start_idx: usize) {
852 let begin = start_idx;
853 let end = start_idx + elts.len();
854 self.state[begin..end].copy_from_slice(elts);
855 }
856
857 fn set_from_iter<I: IntoIterator<Item = T>>(&mut self, elts: I, start_idx: usize) {
858 for (s, e) in self.state[start_idx..].iter_mut().zip(elts) {
859 *s = e;
860 }
861 }
862
863 fn permute(&mut self) {
864 self.state = T::permute(self.state);
865 }
866
867 fn squeeze(&self) -> &[T] {
868 &self.state[..Self::RATE]
869 }
870}
871
872#[derive(Copy, Clone, Debug, Eq, PartialEq)]
874pub struct PoseidonHash;
875impl<F: RichField> Hasher<F> for PoseidonHash {
876 const HASH_SIZE: usize = 4 * 8;
877 type Hash = HashOut<F>;
878 type Permutation = PoseidonPermutation<F>;
879
880 fn hash_no_pad(input: &[F]) -> Self::Hash {
881 hash_n_to_hash_no_pad::<F, Self::Permutation>(input)
882 }
883
884 fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash {
885 compress::<F, Self::Permutation>(left, right)
886 }
887}
888
889impl<F: RichField> AlgebraicHasher<F> for PoseidonHash {
890 type AlgebraicPermutation = PoseidonPermutation<Target>;
891
892 fn permute_swapped<const D: usize>(
893 inputs: Self::AlgebraicPermutation,
894 swap: BoolTarget,
895 builder: &mut CircuitBuilder<F, D>,
896 ) -> Self::AlgebraicPermutation
897 where
898 F: RichField + Extendable<D>,
899 {
900 let gate_type = PoseidonGate::<F, D>::new();
901 let gate = builder.add_gate(gate_type, vec![]);
902
903 let swap_wire = PoseidonGate::<F, D>::WIRE_SWAP;
904 let swap_wire = Target::wire(gate, swap_wire);
905 builder.connect(swap.target, swap_wire);
906
907 let inputs = inputs.as_ref();
909 for i in 0..SPONGE_WIDTH {
910 let in_wire = PoseidonGate::<F, D>::wire_input(i);
911 let in_wire = Target::wire(gate, in_wire);
912 builder.connect(inputs[i], in_wire);
913 }
914
915 Self::AlgebraicPermutation::new(
917 (0..SPONGE_WIDTH).map(|i| Target::wire(gate, PoseidonGate::<F, D>::wire_output(i))),
918 )
919 }
920}
921
922#[cfg(test)]
923pub(crate) mod test_helpers {
924 use super::*;
925
926 pub(crate) fn check_test_vectors<F>(
927 test_vectors: Vec<([u64; SPONGE_WIDTH], [u64; SPONGE_WIDTH])>,
928 ) where
929 F: Poseidon,
930 {
931 for (input_, expected_output_) in test_vectors.into_iter() {
932 let mut input = [F::ZERO; SPONGE_WIDTH];
933 for i in 0..SPONGE_WIDTH {
934 input[i] = F::from_canonical_u64(input_[i]);
935 }
936 let output = F::poseidon(input);
937 for i in 0..SPONGE_WIDTH {
938 let ex_output = F::from_canonical_u64(expected_output_[i]);
939 assert_eq!(output[i], ex_output);
940 }
941 }
942 }
943
944 pub(crate) fn check_consistency<F>()
945 where
946 F: Poseidon,
947 {
948 let mut input = [F::ZERO; SPONGE_WIDTH];
949 for i in 0..SPONGE_WIDTH {
950 input[i] = F::from_canonical_u64(i as u64);
951 }
952 let output = F::poseidon(input);
953 let output_naive = F::poseidon_naive(input);
954 for i in 0..SPONGE_WIDTH {
955 assert_eq!(output[i], output_naive[i]);
956 }
957 }
958}