37 { C::poseidon2_perm_B_4_0, C::poseidon2_perm_B_4_1, C::poseidon2_perm_B_4_2, C::poseidon2_perm_B_4_3 },
38 { C::poseidon2_perm_B_5_0, C::poseidon2_perm_B_5_1, C::poseidon2_perm_B_5_2, C::poseidon2_perm_B_5_3 },
39 { C::poseidon2_perm_B_6_0, C::poseidon2_perm_B_6_1, C::poseidon2_perm_B_6_2, C::poseidon2_perm_B_6_3 },
40 { C::poseidon2_perm_B_7_0, C::poseidon2_perm_B_7_1, C::poseidon2_perm_B_7_2, C::poseidon2_perm_B_7_3 },
41 { C::poseidon2_perm_B_8_0, C::poseidon2_perm_B_8_1, C::poseidon2_perm_B_8_2, C::poseidon2_perm_B_8_3 },
42 { C::poseidon2_perm_B_9_0, C::poseidon2_perm_B_9_1, C::poseidon2_perm_B_9_2, C::poseidon2_perm_B_9_3 },
43 { C::poseidon2_perm_B_10_0, C::poseidon2_perm_B_10_1, C::poseidon2_perm_B_10_2, C::poseidon2_perm_B_10_3 },
44 { C::poseidon2_perm_B_11_0, C::poseidon2_perm_B_11_1, C::poseidon2_perm_B_11_2, C::poseidon2_perm_B_11_3 },
45 { C::poseidon2_perm_B_12_0, C::poseidon2_perm_B_12_1, C::poseidon2_perm_B_12_2, C::poseidon2_perm_B_12_3 },
46 { C::poseidon2_perm_B_13_0, C::poseidon2_perm_B_13_1, C::poseidon2_perm_B_13_2, C::poseidon2_perm_B_13_3 },
47 { C::poseidon2_perm_B_14_0, C::poseidon2_perm_B_14_1, C::poseidon2_perm_B_14_2, C::poseidon2_perm_B_14_3 },
48 { C::poseidon2_perm_B_15_0, C::poseidon2_perm_B_15_1, C::poseidon2_perm_B_15_2, C::poseidon2_perm_B_15_3 },
49 { C::poseidon2_perm_B_16_0, C::poseidon2_perm_B_16_1, C::poseidon2_perm_B_16_2, C::poseidon2_perm_B_16_3 },
50 { C::poseidon2_perm_B_17_0, C::poseidon2_perm_B_17_1, C::poseidon2_perm_B_17_2, C::poseidon2_perm_B_17_3 },
51 { C::poseidon2_perm_B_18_0, C::poseidon2_perm_B_18_1, C::poseidon2_perm_B_18_2, C::poseidon2_perm_B_18_3 },
52 { C::poseidon2_perm_B_19_0, C::poseidon2_perm_B_19_1, C::poseidon2_perm_B_19_2, C::poseidon2_perm_B_19_3 },
53 { C::poseidon2_perm_B_20_0, C::poseidon2_perm_B_20_1, C::poseidon2_perm_B_20_2, C::poseidon2_perm_B_20_3 },
54 { C::poseidon2_perm_B_21_0, C::poseidon2_perm_B_21_1, C::poseidon2_perm_B_21_2, C::poseidon2_perm_B_21_3 },
55 { C::poseidon2_perm_B_22_0, C::poseidon2_perm_B_22_1, C::poseidon2_perm_B_22_2, C::poseidon2_perm_B_22_3 },
56 { C::poseidon2_perm_B_23_0, C::poseidon2_perm_B_23_1, C::poseidon2_perm_B_23_2, C::poseidon2_perm_B_23_3 },
57 { C::poseidon2_perm_B_24_0, C::poseidon2_perm_B_24_1, C::poseidon2_perm_B_24_2, C::poseidon2_perm_B_24_3 },
58 { C::poseidon2_perm_B_25_0, C::poseidon2_perm_B_25_1, C::poseidon2_perm_B_25_2, C::poseidon2_perm_B_25_3 },
59 { C::poseidon2_perm_B_26_0, C::poseidon2_perm_B_26_1, C::poseidon2_perm_B_26_2, C::poseidon2_perm_B_26_3 },
60 { C::poseidon2_perm_B_27_0, C::poseidon2_perm_B_27_1, C::poseidon2_perm_B_27_2, C::poseidon2_perm_B_27_3 },
61 { C::poseidon2_perm_B_28_0, C::poseidon2_perm_B_28_1, C::poseidon2_perm_B_28_2, C::poseidon2_perm_B_28_3 },
62 { C::poseidon2_perm_B_29_0, C::poseidon2_perm_B_29_1, C::poseidon2_perm_B_29_2, C::poseidon2_perm_B_29_3 },
63 { C::poseidon2_perm_B_30_0, C::poseidon2_perm_B_30_1, C::poseidon2_perm_B_30_2, C::poseidon2_perm_B_30_3 },
64 { C::poseidon2_perm_B_31_0, C::poseidon2_perm_B_31_1, C::poseidon2_perm_B_31_2, C::poseidon2_perm_B_31_3 },
65 { C::poseidon2_perm_B_32_0, C::poseidon2_perm_B_32_1, C::poseidon2_perm_B_32_2, C::poseidon2_perm_B_32_3 },
66 { C::poseidon2_perm_B_33_0, C::poseidon2_perm_B_33_1, C::poseidon2_perm_B_33_2, C::poseidon2_perm_B_33_3 },
67 { C::poseidon2_perm_B_34_0, C::poseidon2_perm_B_34_1, C::poseidon2_perm_B_34_2, C::poseidon2_perm_B_34_3 },
68 { C::poseidon2_perm_B_35_0, C::poseidon2_perm_B_35_1, C::poseidon2_perm_B_35_2, C::poseidon2_perm_B_35_3 },
69 { C::poseidon2_perm_B_36_0, C::poseidon2_perm_B_36_1, C::poseidon2_perm_B_36_2, C::poseidon2_perm_B_36_3 },
70 { C::poseidon2_perm_B_37_0, C::poseidon2_perm_B_37_1, C::poseidon2_perm_B_37_2, C::poseidon2_perm_B_37_3 },
71 { C::poseidon2_perm_B_38_0, C::poseidon2_perm_B_38_1, C::poseidon2_perm_B_38_2, C::poseidon2_perm_B_38_3 },
72 { C::poseidon2_perm_B_39_0, C::poseidon2_perm_B_39_1, C::poseidon2_perm_B_39_2, C::poseidon2_perm_B_39_3 },
73 { C::poseidon2_perm_B_40_0, C::poseidon2_perm_B_40_1, C::poseidon2_perm_B_40_2, C::poseidon2_perm_B_40_3 },
74 { C::poseidon2_perm_B_41_0, C::poseidon2_perm_B_41_1, C::poseidon2_perm_B_41_2, C::poseidon2_perm_B_41_3 },
75 { C::poseidon2_perm_B_42_0, C::poseidon2_perm_B_42_1, C::poseidon2_perm_B_42_2, C::poseidon2_perm_B_42_3 },
76 { C::poseidon2_perm_B_43_0, C::poseidon2_perm_B_43_1, C::poseidon2_perm_B_43_2, C::poseidon2_perm_B_43_3 },
77 { C::poseidon2_perm_B_44_0, C::poseidon2_perm_B_44_1, C::poseidon2_perm_B_44_2, C::poseidon2_perm_B_44_3 },
78 { C::poseidon2_perm_B_45_0, C::poseidon2_perm_B_45_1, C::poseidon2_perm_B_45_2, C::poseidon2_perm_B_45_3 },
79 { C::poseidon2_perm_B_46_0, C::poseidon2_perm_B_46_1, C::poseidon2_perm_B_46_2, C::poseidon2_perm_B_46_3 },
80 { C::poseidon2_perm_B_47_0, C::poseidon2_perm_B_47_1, C::poseidon2_perm_B_47_2, C::poseidon2_perm_B_47_3 },
81 { C::poseidon2_perm_B_48_0, C::poseidon2_perm_B_48_1, C::poseidon2_perm_B_48_2, C::poseidon2_perm_B_48_3 },
82 { C::poseidon2_perm_B_49_0, C::poseidon2_perm_B_49_1, C::poseidon2_perm_B_49_2, C::poseidon2_perm_B_49_3 },
83 { C::poseidon2_perm_B_50_0, C::poseidon2_perm_B_50_1, C::poseidon2_perm_B_50_2, C::poseidon2_perm_B_50_3 },
84 { C::poseidon2_perm_B_51_0, C::poseidon2_perm_B_51_1, C::poseidon2_perm_B_51_2, C::poseidon2_perm_B_51_3 },
85 { C::poseidon2_perm_B_52_0, C::poseidon2_perm_B_52_1, C::poseidon2_perm_B_52_2, C::poseidon2_perm_B_52_3 },
86 { C::poseidon2_perm_B_53_0, C::poseidon2_perm_B_53_1, C::poseidon2_perm_B_53_2, C::poseidon2_perm_B_53_3 },
87 { C::poseidon2_perm_B_54_0, C::poseidon2_perm_B_54_1, C::poseidon2_perm_B_54_2, C::poseidon2_perm_B_54_3 },
88 { C::poseidon2_perm_B_55_0, C::poseidon2_perm_B_55_1, C::poseidon2_perm_B_55_2, C::poseidon2_perm_B_55_3 },
89 { C::poseidon2_perm_B_56_0, C::poseidon2_perm_B_56_1, C::poseidon2_perm_B_56_2, C::poseidon2_perm_B_56_3 },
90 { C::poseidon2_perm_B_57_0, C::poseidon2_perm_B_57_1, C::poseidon2_perm_B_57_2, C::poseidon2_perm_B_57_3 },
91 { C::poseidon2_perm_B_58_0, C::poseidon2_perm_B_58_1, C::poseidon2_perm_B_58_2, C::poseidon2_perm_B_58_3 },
92 { C::poseidon2_perm_B_59_0, C::poseidon2_perm_B_59_1, C::poseidon2_perm_B_59_2, C::poseidon2_perm_B_59_3 },
96 { C::poseidon2_perm_T_60_4, C::poseidon2_perm_T_60_5, C::poseidon2_perm_T_60_6, C::poseidon2_perm_T_60_7 },
97 { C::poseidon2_perm_T_61_4, C::poseidon2_perm_T_61_5, C::poseidon2_perm_T_61_6, C::poseidon2_perm_T_61_7 },
98 { C::poseidon2_perm_T_62_4, C::poseidon2_perm_T_62_5, C::poseidon2_perm_T_62_6, C::poseidon2_perm_T_62_7 },
99 { C::poseidon2_perm_T_63_4, C::poseidon2_perm_T_63_5, C::poseidon2_perm_T_63_6, C::poseidon2_perm_T_63_7 },
105 const auto full_round_add_constant = []<
typename T,
typename U>(
std::array<T, 4>& state,
115 state[0] = state[0] * state[0] * state[0] * state[0] * state[0];
116 state[1] = state[1] * state[1] * state[1] * state[1] * state[1];
117 state[2] = state[2] * state[2] * state[2] * state[2] * state[2];
118 state[3] = state[3] * state[3] * state[3] * state[3] * state[3];
123 auto t0 = state[0] + state[1];
124 auto t1 = state[2] + state[3];
125 auto t2 =
FF(2) * state[1] + t1;
126 auto t3 =
FF(2) * state[3] + t0;
127 auto t4 =
FF(4) * t1 + t3;
128 auto t5 =
FF(4) * t0 + t2;
138 const auto partial_round_add_constant = []<
typename T,
typename U>(
std::array<T, 4>& state,
const U& rc) {
144 state[0] = state[0] * state[0] * state[0] * state[0] * state[0];
148 const auto internal_matrix_mul = []<
typename T,
typename U>(
std::array<T, 4>& state,
150 auto sum = state[0] + state[1] + state[2] + state[3];
151 for (
size_t i = 0; i < 4; ++i) {
152 state[i] = state[i] * internal_matrix_diagonal[i] +
sum;
161 auto tmp = in.get(C::poseidon2_perm_sel) * (
FF(1) - in.get(C::poseidon2_perm_sel));
162 tmp *= scaling_factor;
163 std::get<0>(evals) +=
typename Accumulator::View(tmp);
167 auto state = std::array{
168 in.get(C::poseidon2_perm_a_0),
169 in.get(C::poseidon2_perm_a_1),
170 in.get(C::poseidon2_perm_a_2),
171 in.get(C::poseidon2_perm_a_3),
183 external_matrix_mul(state);
187 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(C::poseidon2_perm_EXT_LAYER_4) - state[3]);
188 tmp *= scaling_factor;
189 std::get<1>(evals) +=
typename Accumulator::View(tmp);
193 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(C::poseidon2_perm_EXT_LAYER_5) - state[1]);
194 tmp *= scaling_factor;
195 std::get<2>(evals) +=
typename Accumulator::View(tmp);
199 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(C::poseidon2_perm_EXT_LAYER_6) - state[0]);
200 tmp *= scaling_factor;
201 std::get<3>(evals) +=
typename Accumulator::View(tmp);
205 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(C::poseidon2_perm_EXT_LAYER_7) - state[2]);
206 tmp *= scaling_factor;
207 std::get<4>(evals) +=
typename Accumulator::View(tmp);
211 constexpr size_t START_RELATION_OF_PERM = 5;
215 in.get(C::poseidon2_perm_EXT_LAYER_6),
216 in.get(C::poseidon2_perm_EXT_LAYER_5),
217 in.get(C::poseidon2_perm_EXT_LAYER_7),
218 in.get(C::poseidon2_perm_EXT_LAYER_4),
222 constexpr_for<0, 4, 1>([&]<
size_t i>() {
223 constexpr size_t relation_offset = START_RELATION_OF_PERM + (i * 4);
224 full_round_add_constant(state, Poseidon2Params::round_constants[i]);
225 full_round_s_box(state);
226 external_matrix_mul(state);
230 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][0]) - state[3]);
231 tmp *= scaling_factor;
237 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][1]) - state[1]);
238 tmp *= scaling_factor;
244 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][2]) - state[0]);
245 tmp *= scaling_factor;
251 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][3]) - state[2]);
252 tmp *= scaling_factor;
258 in.get(round_cols[i][2]),
259 in.get(round_cols[i][1]),
260 in.get(round_cols[i][3]),
261 in.get(round_cols[i][0]),
266 constexpr_for<4, 60, 1>([&]<
size_t i>() {
267 constexpr size_t relation_offset = START_RELATION_OF_PERM + (i * 4);
268 partial_round_add_constant(state, Poseidon2Params::round_constants[i][0]);
269 partial_round_s_box(state);
270 internal_matrix_mul(state, Poseidon2Params::internal_matrix_diagonal);
274 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][0]) - state[0]);
275 tmp *= scaling_factor;
281 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][1]) - state[1]);
282 tmp *= scaling_factor;
288 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][2]) - state[2]);
289 tmp *= scaling_factor;
295 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][3]) - state[3]);
296 tmp *= scaling_factor;
302 in.get(round_cols[i][0]),
303 in.get(round_cols[i][1]),
304 in.get(round_cols[i][2]),
305 in.get(round_cols[i][3]),
310 constexpr_for<60, 64, 1>([&]<
size_t i>() {
311 constexpr size_t relation_offset = START_RELATION_OF_PERM + (i * 4);
312 full_round_add_constant(state, Poseidon2Params::round_constants[i]);
313 full_round_s_box(state);
314 external_matrix_mul(state);
318 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][0]) - state[3]);
319 tmp *= scaling_factor;
325 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][1]) - state[1]);
326 tmp *= scaling_factor;
332 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][2]) - state[0]);
333 tmp *= scaling_factor;
339 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(round_cols[i][3]) - state[2]);
340 tmp *= scaling_factor;
346 in.get(round_cols[i][2]),
347 in.get(round_cols[i][1]),
348 in.get(round_cols[i][3]),
349 in.get(round_cols[i][0]),
356 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(C::poseidon2_perm_b_0) - in.get(C::poseidon2_perm_T_63_6));
357 tmp *= scaling_factor;
362 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(C::poseidon2_perm_b_1) - in.get(C::poseidon2_perm_T_63_5));
363 tmp *= scaling_factor;
368 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(C::poseidon2_perm_b_2) - in.get(C::poseidon2_perm_T_63_7));
369 tmp *= scaling_factor;
374 auto tmp = in.get(C::poseidon2_perm_sel) * (in.get(C::poseidon2_perm_b_3) - in.get(C::poseidon2_perm_T_63_4));
375 tmp *= scaling_factor;