../../.cargo/katex-header.html

plonky2/hash/
poseidon.rs

1//! Implementation of the Poseidon hash function, as described in
2//! <https://eprint.iacr.org/2019/458.pdf>
3
4#[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
27// The number of full rounds and partial rounds is given by the
28// calc_round_numbers.py script. They happen to be the same for both
29// width 8 and width 12 with s-box x^7.
30//
31// NB: Changing any of these values will require regenerating all of
32// the precomputed constant arrays in this file.
33pub 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; // we only have width 8 and 12, and 12 is bigger. :)
38
39#[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/// Note that these work for the Goldilocks field, but not necessarily others. See
56/// `generate_constants` about how these were generated. We include enough for a width of 12;
57/// smaller widths just use a subset.
58#[rustfmt::skip]
59pub const ALL_ROUND_CONSTANTS: [u64; MAX_WIDTH * N_ROUNDS]  = [
60    // WARNING: The AVX2 Goldilocks specialization relies on all round constants being in
61    // 0..0xfffeeac900011537. If these constants are randomly regenerated, there is a ~.6% chance
62    // that this condition will no longer hold.
63    //
64    // WARNING: If these are changed in any way, then all the
65    // implementations of Poseidon must be regenerated. See comments
66    // in `poseidon_goldilocks.rs`.
67    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    // Total number of round constants required: width of the input
161    // times number of rounds.
162    const N_ROUND_CONSTANTS: usize = SPONGE_WIDTH * N_ROUNDS;
163
164    // The MDS matrix we use is C + D, where C is the circulant matrix whose first
165    // row is given by `MDS_MATRIX_CIRC`, and D is the diagonal matrix whose
166    // diagonal is given by `MDS_MATRIX_DIAG`.
167    const MDS_MATRIX_CIRC: [u64; SPONGE_WIDTH];
168    const MDS_MATRIX_DIAG: [u64; SPONGE_WIDTH];
169
170    // Precomputed constants for the fast Poseidon calculation. See
171    // the paper.
172    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        // The values of `MDS_MATRIX_CIRC` and `MDS_MATRIX_DIAG` are
183        // known to be small, so we can accumulate all the products for
184        // each row and reduce just once at the end (done by the
185        // caller).
186
187        // NB: Unrolling this, calculating each term independently, and
188        // summing at the end, didn't improve performance for me.
189        let mut res = 0u128;
190
191        // This is a hacky way of fully unrolling the loop.
192        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    /// Same as `mds_row_shf` for field extensions of `Self`.
203    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    /// Same as `mds_row_shf` for `PackedField`.
219    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    /// Recursive version of `mds_row_shf`.
246    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        // This is a hacky way of fully unrolling the loop.
280        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    /// Same as `mds_layer` for field extensions of `Self`.
293    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    /// Same as `mds_layer` for `PackedField`.
306    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    /// Recursive version of `mds_layer`.
329    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        // If we have enough routed wires, we will use PoseidonMdsGate.
337        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    /// Same as `partial_first_constant_layer` for `PackedField`.
376    #[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    /// Recursive version of `partial_first_constant_layer`.
399    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        // Initial matrix has first row/column = [1, 0, ..., 0];
421
422        // c = 0
423        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                        // NB: FAST_PARTIAL_ROUND_INITIAL_MATRIX is stored in
430                        // row-major order so that this dot product is cache
431                        // friendly.
432                        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    /// Same as `mds_partial_layer_init` for `PackedField`.
444    #[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        // Initial matrix has first row/column = [1, 0, ..., 0];
462
463        // c = 0
464        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                        // NB: FAST_PARTIAL_ROUND_INITIAL_MATRIX is stored in
471                        // row-major order so that this dot product is cache
472                        // friendly.
473                        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    /// Recursive version of `mds_partial_layer_init`.
484    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    /// Computes s*A where s is the state row vector and A is the matrix
507    ///
508    ///    [ M_00  | v  ]
509    ///    [ ------+--- ]
510    ///    [ w_hat | Id ]
511    ///
512    /// M_00 is a scalar, v is 1x(t-1), w_hat is (t-1)x1 and Id is the
513    /// (t-1)x(t-1) identity matrix.
514    #[inline(always)]
515    #[unroll_for_loops]
516    fn mds_partial_layer_fast(state: &[Self; SPONGE_WIDTH], r: usize) -> [Self; SPONGE_WIDTH] {
517        // Set d = [M_00 | w^] dot [state]
518
519        let mut d_sum = (0u128, 0u32); // u160 accumulator
520        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        // result = [d] concat [state[0] * v + state[shift up by 1]]
533        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    /// Same as `mds_partial_layer_fast` for field extensions of `Self`.
545    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        // result = [d] concat [state[0] * v + state[shift up by 1]]
558        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    /// Same as `mds_partial_layer_fast` for `PackedField.
568    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        // result = [d] concat [state[0] * v + state[shift up by 1]]
591        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    /// Recursive version of `mds_partial_layer_fast`.
601    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    /// Same as `constant_layer` for field extensions of `Self`.
644    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    /// Same as `constant_layer` for PackedFields.
654    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    /// Recursive version of `constant_layer`.
674    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        // x |--> x^7
692        let x2 = x.square();
693        let x4 = x2.square();
694        let x3 = x * x2;
695        x3 * x4
696    }
697
698    /// Recursive version of `sbox_monomial`.
699    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        // x |--> x^7
707        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    /// Same as `sbox_layer` for field extensions of `Self`.
721    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    /// Recursive version of `sbox_layer`.
730    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    // For testing only, to ensure that various tricks are correct.
780    #[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/// Poseidon hash function.
873#[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        // Route input wires.
908        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        // Collect output wires.
916        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}