@@ -29,99 +29,134 @@ template <typename FF_> class Poseidon2ExternalRelationImpl {
2929 }
3030
3131 /* *
32- * @brief Expression for the poseidon2 external round relation, based on E_i in Section 6 of
32+ * @brief Expression for the poseidon2 external round relation, based on \f$ E_i \f$ in Section 6 of
3333 * https://eprint.iacr.org/2023/323.pdf.
34- * @details This relation is defined as C(in(X)...) :=
35- * q_poseidon2_external * ( (v1 - w_1_shift) + \alpha * (v2 - w_2_shift) +
36- * \alpha^2 * (v3 - w_3_shift) + \alpha^3 * (v4 - w_4_shift) ) = 0 where:
37- * u1 := (w_1 + q_1)^5
38- * u2 := (w_2 + q_2)^5
39- * u3 := (w_3 + q_3)^5
40- * u4 := (w_4 + q_4)^5
41- * t0 := u1 + u2 (1, 1, 0, 0)
42- * t1 := u3 + u4 (0, 0, 1, 1)
43- * t2 := 2 * u2 + t1 = 2 * u2 + u3 + u4 (0, 2, 1, 1)
44- * t3 := 2 * u4 + t0 = u1 + u2 + 2 * u4 (1, 1, 0, 2)
45- * v4 := 4 * t1 + t3 = u1 + u2 + 4 * u3 + 6 * u4 (1, 1, 4, 6)
46- * v2 := 4 * t0 + t2 = 4 * u1 + 6 * u2 + u3 + u4 (4, 6, 1, 1)
47- * v1 := t3 + v2 = 5 * u1 + 7 * u2 + 1 * u3 + 3 * u4 (5, 7, 1, 3)
48- * v3 := t2 + v4 (1, 3, 5, 7)
34+ * @details For state \f$ \mathbf{u} = (u_1, u_2, u_3, u_4)\f$ with \f$ u_i = \big(w_i + c_i^{(i)}\big)^5 \f$, the
35+ * external round computes \f$ \mathbf{v} = M_E \cdot \mathbf{u}^{\top}\f$, where \f$M_E\f$ is the external round
36+ * matrix defined as follows:
37+ *
38+ * \f[
39+ * M_E =
40+ * \begin{bmatrix}
41+ * 5 & 7 & 1 & 3 \\
42+ * 4 & 6 & 1 & 1 \\
43+ * 1 & 3 & 5 & 7 \\
44+ * 1 & 1 & 4 & 6
45+ * \end{bmatrix}
46+ * \f]
47+ *
48+ * i.e.
49+ * \f{align}{
50+ * v_1 &= 5u_1 + 7u_2 + u_3 + 3u_4 \\
51+ * v_2 &= 4u_1 + 6u_2 + u_3 + u_4 \\
52+ * v_3 &= u_1 + 3u_2 + 5u_3 + 7u_4 \\
53+ * v_4 &= u_1 + u_2 + 4u_3 + 6u_4
54+ * \f}
55+ *
56+ * The relation enforces \f$ v_k = w_{k,shift}\f$ for \f$ k \in \{1,2,3,4\}\f$.
57+ * Concretely, the relation is encoded as four independent constraints multiplied by the
58+ * \f$\text{q_poseidon2_external}\f$ selector and the scaling factor \f$\hat{g}\f$ arising from the
59+ * `GateSeparatorPolynomial`. These contributions are added to the corresponding univariate accumulator \f$ A_i
60+ * \f$:
61+ * \f{align}{
62+ * A_1 &\;\mathrel{+}= \text{q_poseidon2_internal}\cdot \big(v_1 - w_{1,\text{shift}}\big) \cdot \hat{g} \\
63+ * A_2 &\;\mathrel{+}= \text{q_poseidon2_internal}\cdot \big(v_1 - w_{1,\text{shift}}\big) \cdot \hat{g} \\
64+ * A_3 &\;\mathrel{+}= \text{q_poseidon2_internal}\cdot \big(v_3 - w_{3,\text{shift}}\big) \cdot \hat{g} \\
65+ * A_4 &\;\mathrel{+}= \text{q_poseidon2_internal}\cdot \big(v_4 - w_{4,\text{shift}}\big) \cdot \hat{g}
66+ * \f}
67+ * At the end of each Sumcheck Round, the subrelation accumulators are aggregated with independent challenges
68+ * \f$\alpha_{i} = \alpha_{i, \text{Poseidon2Ext}}\f$ taken from the array of `SubrelationSeparators`
69+ * \f[
70+ * \alpha_{0} A_1 +
71+ * \alpha_{1} A_2 +
72+ * \alpha_{2} A_3 +
73+ * \alpha_{3} A_4
74+ * \f]
75+ * and multiplied by the linear factor of the `GateSeparatorPolynomial`.
76+ *
77+ * @param evals a tuple of tuples of univariate accumulators, the subtuple corresponding to this relation consists
78+ * of \f$ [A_0, A_1, A_2, A_3]\f$ , such that
79+ * \f$ \deg(A_i) = \text{SUBRELATION_PARTIAL_LENGTHS}[i] - 1 \f$.
80+ * @param in In round \f$ k \f$ of Sumcheck at the point \f$i_{>k} = (i_{k+1}, \ldots, i_{d-1})\f$ on the
81+ * \f$d-k-1\f$-dimensional hypercube, given by an array containing the restrictions of the prover polynomials
82+ * \f$ P_i(u_{<k}, X_k, i_{>k}) \f$.
83+ * @param parameters Not used in this relation
84+ * @param scaling_factor scaling term coming from `GateSeparatorPolynomial`.
4985 *
50- * @param evals transformed to `evals + C(in(X)...)*scaling_factor`
51- * @param in an std::array containing the fully extended Univariate edges.
52- * @param parameters contains beta, gamma, and public_input_delta, ....
53- * @param scaling_factor optional term to scale the evaluation before adding to evals.
5486 */
5587 template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
5688 void static accumulate (ContainerOverSubrelations& evals,
5789 const AllEntities& in,
5890 const Parameters&,
5991 const FF& scaling_factor)
6092 {
93+ // Univariates of degree 6 represented in Lagrange basis
6194 using Accumulator = std::tuple_element_t <0 , ContainerOverSubrelations>;
95+ // Low-degree univariates represented in monomial basis
6296 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
63- auto w_l = CoefficientAccumulator (in.w_l );
64- auto w_r = CoefficientAccumulator (in.w_r );
65- auto w_o = CoefficientAccumulator (in.w_o );
66- auto w_4 = CoefficientAccumulator (in.w_4 );
67- auto w_l_shift = CoefficientAccumulator (in.w_l_shift );
68- auto w_r_shift = CoefficientAccumulator (in.w_r_shift );
69- auto w_o_shift = CoefficientAccumulator (in.w_o_shift );
70- auto w_4_shift = CoefficientAccumulator (in.w_4_shift );
71- auto q_l = CoefficientAccumulator (in.q_l );
72- auto q_r = CoefficientAccumulator (in.q_r );
73- auto q_o = CoefficientAccumulator (in.q_o );
74- auto q_4 = CoefficientAccumulator (in.q_4 );
75- auto q_poseidon2_external = CoefficientAccumulator (in.q_poseidon2_external );
97+
98+ // Current state
99+ const auto w_1 = CoefficientAccumulator (in.w_l );
100+ const auto w_2 = CoefficientAccumulator (in.w_r );
101+ const auto w_3 = CoefficientAccumulator (in.w_o );
102+ const auto w_4 = CoefficientAccumulator (in.w_4 );
103+ // Expected state, contained in the next row
104+ const auto w_1_shift = CoefficientAccumulator (in.w_l_shift );
105+ const auto w_2_shift = CoefficientAccumulator (in.w_r_shift );
106+ const auto w_3_shift = CoefficientAccumulator (in.w_o_shift );
107+ const auto w_4_shift = CoefficientAccumulator (in.w_4_shift );
108+ // i-th external round constants
109+ const auto c_1 = CoefficientAccumulator (in.q_l );
110+ const auto c_2 = CoefficientAccumulator (in.q_r );
111+ const auto c_3 = CoefficientAccumulator (in.q_o );
112+ const auto c_4 = CoefficientAccumulator (in.q_4 );
113+ // Poseidon2 external relation selector
114+ const auto q_poseidon2_external = CoefficientAccumulator (in.q_poseidon2_external );
76115
77116 // add round constants which are loaded in selectors
78- auto s1 = Accumulator (w_l + q_l);
79- auto s2 = Accumulator (w_r + q_r);
80- auto s3 = Accumulator (w_o + q_o);
81- auto s4 = Accumulator (w_4 + q_4);
82117
118+ auto sbox = [](const Accumulator& x) {
119+ auto t2 = x.sqr (); // x^2
120+ auto t4 = t2.sqr (); // x^4
121+ return t4 * x; // x^5
122+ };
83123 // apply s-box round
84- auto u1 = s1.sqr ();
85- u1 = u1.sqr ();
86- u1 *= s1;
87- auto u2 = s2.sqr ();
88- u2 = u2.sqr ();
89- u2 *= s2;
90- auto u3 = s3.sqr ();
91- u3 = u3.sqr ();
92- u3 *= s3;
93- auto u4 = s4.sqr ();
94- u4 = u4.sqr ();
95- u4 *= s4;
96-
97- // matrix mul v = M_E * u with 14 additions
124+ auto u1 = sbox (Accumulator (w_1 + c_1));
125+ auto u2 = sbox (Accumulator (w_2 + c_2));
126+ auto u3 = sbox (Accumulator (w_3 + c_3));
127+ auto u4 = sbox (Accumulator (w_4 + c_4));
128+ // Matrix mul v = M_E * u with 14 additions.
129+ // Precompute common summands.
98130 auto t0 = u1 + u2; // u_1 + u_2
99131 auto t1 = u3 + u4; // u_3 + u_4
100132 auto t2 = u2 + u2; // 2u_2
101133 t2 += t1; // 2u_2 + u_3 + u_4
102134 auto t3 = u4 + u4; // 2u_4
103135 t3 += t0; // u_1 + u_2 + 2u_4
136+
137+ // Row 4: u_1 + u_2 + 4u_3 + 6u_4
104138 auto v4 = t1 + t1;
105139 v4 += v4;
106- v4 += t3; // u_1 + u_2 + 4u_3 + 6u_4
140+ v4 += t3;
141+
142+ // Row 2: 4u_1 + 6u_2 + u_3 + u_4
107143 auto v2 = t0 + t0;
108144 v2 += v2;
109- v2 += t2; // 4u_1 + 6u_2 + u_3 + u_4
110- auto v1 = t3 + v2; // 5u_1 + 7u_2 + u_3 + 3u_4
111- auto v3 = t2 + v4; // u_1 + 3u_2 + 5u_3 + 7u_4
145+ v2 += t2;
146+ // Row 1: 5u_1 + 7u_2 + u_3 + 3u_4
147+ auto v1 = t3 + v2;
148+
149+ // Row 3: u_1 + 3u_2 + 5u_3 + 7u_4
150+ auto v3 = t2 + v4;
112151
113152 auto q_pos_by_scaling = Accumulator (q_poseidon2_external * scaling_factor);
114- auto tmp = q_pos_by_scaling * (v1 - Accumulator (w_l_shift));
115- std::get<0 >(evals) += tmp;
153+ std::get<0 >(evals) += q_pos_by_scaling * (v1 - Accumulator (w_1_shift));
116154
117- tmp = q_pos_by_scaling * (v2 - Accumulator (w_r_shift));
118- std::get<1 >(evals) += tmp;
155+ std::get<1 >(evals) += q_pos_by_scaling * (v2 - Accumulator (w_2_shift));
119156
120- tmp = q_pos_by_scaling * (v3 - Accumulator (w_o_shift));
121- std::get<2 >(evals) += tmp;
157+ std::get<2 >(evals) += q_pos_by_scaling * (v3 - Accumulator (w_3_shift));
122158
123- tmp = q_pos_by_scaling * (v4 - Accumulator (w_4_shift));
124- std::get<3 >(evals) += tmp;
159+ std::get<3 >(evals) += q_pos_by_scaling * (v4 - Accumulator (w_4_shift));
125160 };
126161};
127162
0 commit comments