mina_tree/proofs/public_input/
scalars.rs

1use ark_ff::{fields::arithmetic::InvalidBigInt, BigInteger256, Field, FromBytes};
2use kimchi::proof::ProofEvaluations;
3use mina_curves::pasta::{Fp, Fq};
4
5use crate::proofs::field::FieldWitness;
6
7use super::plonk_checks::NPOWERS_OF_ALPHA;
8
9pub enum CurrOrNext {
10    Curr,
11    Next,
12}
13
14pub enum Column {
15    Witness(usize),
16    // Poseidon, // unused for now
17}
18
19// Helpers methods
20
21fn square<F>(field: F) -> F
22where
23    F: Field,
24{
25    field * field
26}
27
28fn cell<T>(v: T) -> T {
29    v
30}
31
32fn double<F>(fp: F) -> F
33where
34    F: Field,
35{
36    fp.double()
37}
38
39pub fn field_from_hex<F>(mut s: &str) -> F
40where
41    F: Field + TryFrom<BigInteger256, Error = InvalidBigInt>,
42{
43    if s.starts_with("0x") {
44        s = &s[2..];
45    }
46
47    let mut bytes = <[u8; 32]>::default();
48    hex::decode_to_slice(s, &mut bytes).unwrap();
49    bytes.reverse();
50
51    let bigint = BigInteger256::read(&bytes[..]).unwrap();
52    bigint.try_into().unwrap() // Never fail, we hardcode them with string literals
53}
54
55fn field<F: FieldWitness>(s: &str) -> F {
56    field_from_hex(s)
57}
58
59/// <https://github.com/MinaProtocol/mina/blob/aebd4e552b8b4bcd78d1e24523169e8778794857/src/lib/pickles/plonk_checks/plonk_checks.ml#L97-L130>
60fn get_var<F>(evals: &ProofEvaluations<[F; 2]>) -> impl Fn(Column, CurrOrNext) -> F + '_
61where
62    F: Field,
63{
64    use Column::*;
65    use CurrOrNext::*;
66
67    // Use a closure to capture `evals`
68    |col: Column, row: CurrOrNext| match (col, row) {
69        (Witness(i), Curr) => evals.w[i][0],
70        (Witness(i), Next) => evals.w[i][1],
71        // (Poseidon, Curr) => evals.poseidon_selector[0],
72        // (Poseidon, Next) => evals.poseidon_selector[1],
73    }
74}
75
76// Actual methods
77
78#[allow(clippy::double_parens)]
79#[allow(unused_parens)]
80pub fn complete_add<F: FieldWitness>(
81    evals: &ProofEvaluations<[F; 2]>,
82    powers_of_alpha: &[F; NPOWERS_OF_ALPHA],
83) -> F {
84    use Column::*;
85    use CurrOrNext::*;
86
87    let var = get_var(evals);
88    let alpha_pow = |i: usize| powers_of_alpha[i];
89    let field = field::<F>;
90
91    // Auto-generated code with the test `generate_plonk`
92    let x_0 = { (cell(var(Witness(2), Curr)) - cell(var(Witness(0), Curr))) };
93    let x_1 = { (cell(var(Witness(3), Curr)) - cell(var(Witness(1), Curr))) };
94    let x_2 = { (cell(var(Witness(0), Curr)) * cell(var(Witness(0), Curr))) };
95    ((((((((cell(var(Witness(10), Curr)) * x_0)
96        - (field("0x0000000000000000000000000000000000000000000000000000000000000001")
97            - cell(var(Witness(7), Curr))))
98        + (alpha_pow(1) * (cell(var(Witness(7), Curr)) * x_0)))
99        + (alpha_pow(2)
100            * ((cell(var(Witness(7), Curr))
101                * (((double(cell(var(Witness(8), Curr))) * cell(var(Witness(1), Curr)))
102                    - double(x_2))
103                    - x_2))
104                + ((field(
105                    "0x0000000000000000000000000000000000000000000000000000000000000001",
106                ) - cell(var(Witness(7), Curr)))
107                    * ((x_0 * cell(var(Witness(8), Curr))) - x_1)))))
108        + (alpha_pow(3)
109            * (((cell(var(Witness(0), Curr)) + cell(var(Witness(2), Curr)))
110                + cell(var(Witness(4), Curr)))
111                - (cell(var(Witness(8), Curr)) * cell(var(Witness(8), Curr))))))
112        + (alpha_pow(4)
113            * (((cell(var(Witness(8), Curr))
114                * (cell(var(Witness(0), Curr)) - cell(var(Witness(4), Curr))))
115                - cell(var(Witness(1), Curr)))
116                - cell(var(Witness(5), Curr)))))
117        + (alpha_pow(5) * (x_1 * (cell(var(Witness(7), Curr)) - cell(var(Witness(6), Curr))))))
118        + (alpha_pow(6) * ((x_1 * cell(var(Witness(9), Curr))) - cell(var(Witness(6), Curr)))))
119}
120
121#[allow(clippy::double_parens)]
122#[allow(unused_parens)]
123pub fn var_base_mul<F: FieldWitness>(
124    evals: &ProofEvaluations<[F; 2]>,
125    powers_of_alpha: &[F; NPOWERS_OF_ALPHA],
126) -> F {
127    use Column::*;
128    use CurrOrNext::*;
129
130    let var = get_var(evals);
131    let alpha_pow = |i: usize| powers_of_alpha[i];
132    let field = field::<F>;
133
134    // Auto-generated code with the test `generate_plonk`
135    let x_0 = { (cell(var(Witness(7), Next)) * cell(var(Witness(7), Next))) };
136    let x_1 = {
137        let x_0 = { (cell(var(Witness(7), Next)) * cell(var(Witness(7), Next))) };
138        (cell(var(Witness(2), Curr))
139            - ((x_0 - cell(var(Witness(2), Curr))) - cell(var(Witness(0), Curr))))
140    };
141    let x_2 = {
142        let x_1 = {
143            let x_0 = { (cell(var(Witness(7), Next)) * cell(var(Witness(7), Next))) };
144            (cell(var(Witness(2), Curr))
145                - ((x_0 - cell(var(Witness(2), Curr))) - cell(var(Witness(0), Curr))))
146        };
147        (double(cell(var(Witness(3), Curr))) - (x_1 * cell(var(Witness(7), Next))))
148    };
149    let x_3 = { (cell(var(Witness(8), Next)) * cell(var(Witness(8), Next))) };
150    let x_4 = {
151        let x_3 = { (cell(var(Witness(8), Next)) * cell(var(Witness(8), Next))) };
152        (cell(var(Witness(7), Curr))
153            - ((x_3 - cell(var(Witness(7), Curr))) - cell(var(Witness(0), Curr))))
154    };
155    let x_5 = {
156        let x_4 = {
157            let x_3 = { (cell(var(Witness(8), Next)) * cell(var(Witness(8), Next))) };
158            (cell(var(Witness(7), Curr))
159                - ((x_3 - cell(var(Witness(7), Curr))) - cell(var(Witness(0), Curr))))
160        };
161        (double(cell(var(Witness(8), Curr))) - (x_4 * cell(var(Witness(8), Next))))
162    };
163    let x_6 = { (cell(var(Witness(9), Next)) * cell(var(Witness(9), Next))) };
164    let x_7 = {
165        let x_6 = { (cell(var(Witness(9), Next)) * cell(var(Witness(9), Next))) };
166        (cell(var(Witness(9), Curr))
167            - ((x_6 - cell(var(Witness(9), Curr))) - cell(var(Witness(0), Curr))))
168    };
169    let x_8 = {
170        let x_7 = {
171            let x_6 = { (cell(var(Witness(9), Next)) * cell(var(Witness(9), Next))) };
172            (cell(var(Witness(9), Curr))
173                - ((x_6 - cell(var(Witness(9), Curr))) - cell(var(Witness(0), Curr))))
174        };
175        (double(cell(var(Witness(10), Curr))) - (x_7 * cell(var(Witness(9), Next))))
176    };
177    let x_9 = { (cell(var(Witness(10), Next)) * cell(var(Witness(10), Next))) };
178    let x_10 = {
179        let x_9 = { (cell(var(Witness(10), Next)) * cell(var(Witness(10), Next))) };
180        (cell(var(Witness(11), Curr))
181            - ((x_9 - cell(var(Witness(11), Curr))) - cell(var(Witness(0), Curr))))
182    };
183    let x_11 = {
184        let x_10 = {
185            let x_9 = { (cell(var(Witness(10), Next)) * cell(var(Witness(10), Next))) };
186            (cell(var(Witness(11), Curr))
187                - ((x_9 - cell(var(Witness(11), Curr))) - cell(var(Witness(0), Curr))))
188        };
189        (double(cell(var(Witness(12), Curr))) - (x_10 * cell(var(Witness(10), Next))))
190    };
191    let x_12 = { (cell(var(Witness(11), Next)) * cell(var(Witness(11), Next))) };
192    let x_13 = {
193        let x_12 = { (cell(var(Witness(11), Next)) * cell(var(Witness(11), Next))) };
194        (cell(var(Witness(13), Curr))
195            - ((x_12 - cell(var(Witness(13), Curr))) - cell(var(Witness(0), Curr))))
196    };
197    let x_14 = {
198        let x_13 = {
199            let x_12 = { (cell(var(Witness(11), Next)) * cell(var(Witness(11), Next))) };
200            (cell(var(Witness(13), Curr))
201                - ((x_12 - cell(var(Witness(13), Curr))) - cell(var(Witness(0), Curr))))
202        };
203        (double(cell(var(Witness(14), Curr))) - (x_13 * cell(var(Witness(11), Next))))
204    };
205    (((((((((((((((((((((cell(var(Witness(5), Curr))
206        - (cell(var(Witness(6), Next))
207            + double(
208                (cell(var(Witness(5), Next))
209                    + double(
210                        (cell(var(Witness(4), Next))
211                            + double(
212                                (cell(var(Witness(3), Next))
213                                    + double(
214                                        (cell(var(Witness(2), Next))
215                                            + double(cell(var(Witness(4), Curr)))),
216                                    )),
217                            )),
218                    )),
219            )))
220        + (alpha_pow(1)
221            * (square(cell(var(Witness(2), Next)))
222                - cell(var(Witness(2), Next)))))
223        + (alpha_pow(2)
224            * (((cell(var(Witness(2), Curr)) - cell(var(Witness(0), Curr)))
225                * cell(var(Witness(7), Next)))
226                - (cell(var(Witness(3), Curr))
227                    - ((double(cell(var(Witness(2), Next)))
228                        - field(
229                            "0x0000000000000000000000000000000000000000000000000000000000000001",
230                        ))
231                        * cell(var(Witness(1), Curr)))))))
232        + (alpha_pow(3)
233            * ((x_2 * x_2)
234                - ((x_1 * x_1)
235                    * ((cell(var(Witness(7), Curr))
236                        - cell(var(Witness(0), Curr)))
237                        + x_0)))))
238        + (alpha_pow(4)
239            * (((cell(var(Witness(8), Curr)) + cell(var(Witness(3), Curr)))
240                * x_1)
241                - ((cell(var(Witness(2), Curr)) - cell(var(Witness(7), Curr)))
242                    * x_2))))
243        + (alpha_pow(5)
244            * (square(cell(var(Witness(3), Next))) - cell(var(Witness(3), Next)))))
245        + (alpha_pow(6)
246            * (((cell(var(Witness(7), Curr)) - cell(var(Witness(0), Curr)))
247                * cell(var(Witness(8), Next)))
248                - (cell(var(Witness(8), Curr))
249                    - ((double(cell(var(Witness(3), Next)))
250                        - field(
251                            "0x0000000000000000000000000000000000000000000000000000000000000001",
252                        ))
253                        * cell(var(Witness(1), Curr)))))))
254        + (alpha_pow(7)
255            * ((x_5 * x_5)
256                - ((x_4 * x_4)
257                    * ((cell(var(Witness(9), Curr)) - cell(var(Witness(0), Curr)))
258                        + x_3)))))
259        + (alpha_pow(8)
260            * (((cell(var(Witness(10), Curr)) + cell(var(Witness(8), Curr))) * x_4)
261                - ((cell(var(Witness(7), Curr)) - cell(var(Witness(9), Curr))) * x_5))))
262        + (alpha_pow(9)
263            * (square(cell(var(Witness(4), Next))) - cell(var(Witness(4), Next)))))
264        + (alpha_pow(10)
265            * (((cell(var(Witness(9), Curr)) - cell(var(Witness(0), Curr)))
266                * cell(var(Witness(9), Next)))
267                - (cell(var(Witness(10), Curr))
268                    - ((double(cell(var(Witness(4), Next)))
269                        - field(
270                            "0x0000000000000000000000000000000000000000000000000000000000000001",
271                        ))
272                        * cell(var(Witness(1), Curr)))))))
273        + (alpha_pow(11)
274            * ((x_8 * x_8)
275                - ((x_7 * x_7)
276                    * ((cell(var(Witness(11), Curr)) - cell(var(Witness(0), Curr)))
277                        + x_6)))))
278        + (alpha_pow(12)
279            * (((cell(var(Witness(12), Curr)) + cell(var(Witness(10), Curr))) * x_7)
280                - ((cell(var(Witness(9), Curr)) - cell(var(Witness(11), Curr))) * x_8))))
281        + (alpha_pow(13)
282            * (square(cell(var(Witness(5), Next))) - cell(var(Witness(5), Next)))))
283        + (alpha_pow(14)
284            * (((cell(var(Witness(11), Curr)) - cell(var(Witness(0), Curr)))
285                * cell(var(Witness(10), Next)))
286                - (cell(var(Witness(12), Curr))
287                    - ((double(cell(var(Witness(5), Next)))
288                        - field(
289                            "0x0000000000000000000000000000000000000000000000000000000000000001",
290                        ))
291                        * cell(var(Witness(1), Curr)))))))
292        + (alpha_pow(15)
293            * ((x_11 * x_11)
294                - ((x_10 * x_10)
295                    * ((cell(var(Witness(13), Curr)) - cell(var(Witness(0), Curr))) + x_9)))))
296        + (alpha_pow(16)
297            * (((cell(var(Witness(14), Curr)) + cell(var(Witness(12), Curr))) * x_10)
298                - ((cell(var(Witness(11), Curr)) - cell(var(Witness(13), Curr))) * x_11))))
299        + (alpha_pow(17) * (square(cell(var(Witness(6), Next))) - cell(var(Witness(6), Next)))))
300        + (alpha_pow(18)
301            * (((cell(var(Witness(13), Curr)) - cell(var(Witness(0), Curr)))
302                * cell(var(Witness(11), Next)))
303                - (cell(var(Witness(14), Curr))
304                    - ((double(cell(var(Witness(6), Next)))
305                        - field(
306                            "0x0000000000000000000000000000000000000000000000000000000000000001",
307                        ))
308                        * cell(var(Witness(1), Curr)))))))
309        + (alpha_pow(19)
310            * ((x_14 * x_14)
311                - ((x_13 * x_13)
312                    * ((cell(var(Witness(0), Next)) - cell(var(Witness(0), Curr))) + x_12)))))
313        + (alpha_pow(20)
314            * (((cell(var(Witness(1), Next)) + cell(var(Witness(14), Curr))) * x_13)
315                - ((cell(var(Witness(13), Curr)) - cell(var(Witness(0), Next))) * x_14))))
316}
317
318#[allow(clippy::double_parens)]
319#[allow(unused_parens)]
320pub fn endo_mul<F: FieldWitness>(
321    evals: &ProofEvaluations<[F; 2]>,
322    powers_of_alpha: &[F; NPOWERS_OF_ALPHA],
323) -> F {
324    use Column::*;
325    use CurrOrNext::*;
326
327    let var = get_var(evals);
328    let alpha_pow = |i: usize| powers_of_alpha[i];
329    let endo_coefficient: F = mina_poseidon::sponge::endo_coefficient();
330    let field = field::<F>;
331
332    // Auto-generated code with the test `generate_plonk`
333    let x_0 = {
334        ((field("0x0000000000000000000000000000000000000000000000000000000000000001")
335            + (cell(var(Witness(11), Curr))
336                * (endo_coefficient
337                    - field(
338                        "0x0000000000000000000000000000000000000000000000000000000000000001",
339                    ))))
340            * cell(var(Witness(0), Curr)))
341    };
342    let x_1 = {
343        ((field("0x0000000000000000000000000000000000000000000000000000000000000001")
344            + (cell(var(Witness(13), Curr))
345                * (endo_coefficient
346                    - field(
347                        "0x0000000000000000000000000000000000000000000000000000000000000001",
348                    ))))
349            * cell(var(Witness(0), Curr)))
350    };
351    let x_2 = { square(cell(var(Witness(9), Curr))) };
352    let x_3 = { square(cell(var(Witness(10), Curr))) };
353    let x_4 = { (cell(var(Witness(4), Curr)) - cell(var(Witness(7), Curr))) };
354    let x_5 = { (cell(var(Witness(7), Curr)) - cell(var(Witness(4), Next))) };
355    let x_6 = { (cell(var(Witness(5), Next)) + cell(var(Witness(8), Curr))) };
356    let x_7 = { (cell(var(Witness(8), Curr)) + cell(var(Witness(5), Curr))) };
357    (((((((((((square(cell(var(Witness(11), Curr))) - cell(var(Witness(11), Curr)))
358        + (alpha_pow(1)
359            * (square(cell(var(Witness(12), Curr))) - cell(var(Witness(12), Curr)))))
360        + (alpha_pow(2)
361            * (square(cell(var(Witness(13), Curr))) - cell(var(Witness(13), Curr)))))
362        + (alpha_pow(3)
363            * (square(cell(var(Witness(14), Curr))) - cell(var(Witness(14), Curr)))))
364        + (alpha_pow(4)
365            * (((x_0 - cell(var(Witness(4), Curr))) * cell(var(Witness(9), Curr)))
366                - (((double(cell(var(Witness(12), Curr)))
367                    - field(
368                        "0x0000000000000000000000000000000000000000000000000000000000000001",
369                    ))
370                    * cell(var(Witness(1), Curr)))
371                    - cell(var(Witness(5), Curr))))))
372        + (alpha_pow(5)
373            * ((((double(cell(var(Witness(4), Curr))) - x_2) + x_0)
374                * ((x_4 * cell(var(Witness(9), Curr))) + x_7))
375                - (double(cell(var(Witness(5), Curr))) * x_4))))
376        + (alpha_pow(6)
377            * (square(x_7) - (square(x_4) * ((x_2 - x_0) + cell(var(Witness(7), Curr)))))))
378        + (alpha_pow(7)
379            * (((x_1 - cell(var(Witness(7), Curr))) * cell(var(Witness(10), Curr)))
380                - (((double(cell(var(Witness(14), Curr)))
381                    - field(
382                        "0x0000000000000000000000000000000000000000000000000000000000000001",
383                    ))
384                    * cell(var(Witness(1), Curr)))
385                    - cell(var(Witness(8), Curr))))))
386        + (alpha_pow(8)
387            * ((((double(cell(var(Witness(7), Curr))) - x_3) + x_1)
388                * ((x_5 * cell(var(Witness(10), Curr))) + x_6))
389                - (double(cell(var(Witness(8), Curr))) * x_5))))
390        + (alpha_pow(9)
391            * (square(x_6) - (square(x_5) * ((x_3 - x_1) + cell(var(Witness(4), Next)))))))
392        + (alpha_pow(10)
393            * ((double(
394                (double(
395                    (double((double(cell(var(Witness(6), Curr))) + cell(var(Witness(11), Curr))))
396                        + cell(var(Witness(12), Curr))),
397                ) + cell(var(Witness(13), Curr))),
398            ) + cell(var(Witness(14), Curr)))
399                - cell(var(Witness(6), Next)))))
400}
401
402pub fn endo_mul_scalar<F: FieldWitness>(
403    evals: &ProofEvaluations<[F; 2]>,
404    powers_of_alpha: &[F; NPOWERS_OF_ALPHA],
405) -> F {
406    use std::any::TypeId;
407
408    // TODO: Might use a Trait here
409    if TypeId::of::<F>() == TypeId::of::<Fp>() {
410        endo_mul_scalar_fp(evals, powers_of_alpha)
411    } else if TypeId::of::<F>() == TypeId::of::<Fq>() {
412        endo_mul_scalar_fq(evals, powers_of_alpha)
413    } else {
414        unimplemented!()
415    }
416}
417
418#[allow(clippy::double_parens)]
419#[allow(unused_parens)]
420#[rustfmt::skip] // See below
421fn endo_mul_scalar_fp<F: FieldWitness>(
422    evals: &ProofEvaluations<[F; 2]>,
423    powers_of_alpha: &[F; NPOWERS_OF_ALPHA]
424) -> F {
425    use Column::*;
426    use CurrOrNext::*;
427
428    let var = get_var(evals);
429    let alpha_pow = |i: usize| powers_of_alpha[i];
430    let field = field::<F>;
431
432    // Auto-generated code with the test `generate_plonk`
433    let x_0 = {
434        (((((field("0x1555555555555555555555555555555560C232FEADC45309330F104F00000001")
435            * cell(var(Witness(6), Curr)))
436            + field("0x2000000000000000000000000000000011234C7E04A67C8DCC9698767FFFFFFE"))
437            * cell(var(Witness(6), Curr)))
438            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56E229849987882780000002"))
439            * cell(var(Witness(6), Curr)))
440    };
441    let x_1 = {
442        (((((field("0x1555555555555555555555555555555560C232FEADC45309330F104F00000001")
443            * cell(var(Witness(7), Curr)))
444            + field("0x2000000000000000000000000000000011234C7E04A67C8DCC9698767FFFFFFE"))
445            * cell(var(Witness(7), Curr)))
446            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56E229849987882780000002"))
447            * cell(var(Witness(7), Curr)))
448    };
449    let x_2 = {
450        (((((field("0x1555555555555555555555555555555560C232FEADC45309330F104F00000001")
451            * cell(var(Witness(8), Curr)))
452            + field("0x2000000000000000000000000000000011234C7E04A67C8DCC9698767FFFFFFE"))
453            * cell(var(Witness(8), Curr)))
454            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56E229849987882780000002"))
455            * cell(var(Witness(8), Curr)))
456    };
457    let x_3 = {
458        (((((field("0x1555555555555555555555555555555560C232FEADC45309330F104F00000001")
459            * cell(var(Witness(9), Curr)))
460            + field("0x2000000000000000000000000000000011234C7E04A67C8DCC9698767FFFFFFE"))
461            * cell(var(Witness(9), Curr)))
462            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56E229849987882780000002"))
463            * cell(var(Witness(9), Curr)))
464    };
465    let x_4 = {
466        (((((field("0x1555555555555555555555555555555560C232FEADC45309330F104F00000001")
467            * cell(var(Witness(10), Curr)))
468            + field("0x2000000000000000000000000000000011234C7E04A67C8DCC9698767FFFFFFE"))
469            * cell(var(Witness(10), Curr)))
470            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56E229849987882780000002"))
471            * cell(var(Witness(10), Curr)))
472    };
473    let x_5 = {
474        (((((field("0x1555555555555555555555555555555560C232FEADC45309330F104F00000001")
475            * cell(var(Witness(11), Curr)))
476            + field("0x2000000000000000000000000000000011234C7E04A67C8DCC9698767FFFFFFE"))
477            * cell(var(Witness(11), Curr)))
478            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56E229849987882780000002"))
479            * cell(var(Witness(11), Curr)))
480    };
481    let x_6 = {
482        (((((field("0x1555555555555555555555555555555560C232FEADC45309330F104F00000001")
483            * cell(var(Witness(12), Curr)))
484            + field("0x2000000000000000000000000000000011234C7E04A67C8DCC9698767FFFFFFE"))
485            * cell(var(Witness(12), Curr)))
486            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56E229849987882780000002"))
487            * cell(var(Witness(12), Curr)))
488    };
489    let x_7 = {
490        (((((field("0x1555555555555555555555555555555560C232FEADC45309330F104F00000001")
491            * cell(var(Witness(13), Curr)))
492            + field("0x2000000000000000000000000000000011234C7E04A67C8DCC9698767FFFFFFE"))
493            * cell(var(Witness(13), Curr)))
494            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56E229849987882780000002"))
495            * cell(var(Witness(13), Curr)))
496    };
497    // Note: `rustfmt` is not able to format that, it runs undefinitely
498    ((((((((((((double(double((double(double((double(double((double(double((double(double(
499    (double(double((double(double((double(double(cell(var(Witness(0), Curr))))
500     + cell(var(Witness(6), Curr))))) + cell(var(Witness(7), Curr)))))
501     + cell(var(Witness(8), Curr))))) + cell(var(Witness(9), Curr)))))
502     + cell(var(Witness(10), Curr))))) + cell(var(Witness(11), Curr)))))
503     + cell(var(Witness(12), Curr))))) + cell(var(Witness(13), Curr)))
504     - cell(var(Witness(1), Curr))) + (alpha_pow(1) * ((double((double((double((double(
505     (double((double((double((double(cell(var(Witness(2), Curr))) + x_0)) + x_1)) + x_2))
506     + x_3)) + x_4)) + x_5)) + x_6)) + x_7) - cell(var(Witness(4), Curr))))) + (alpha_pow(2)
507     * ((double((double((double((double((double((double((double((double(cell
508     (var(Witness(3), Curr))) + (x_0
509     + ((((field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")
510     * cell(var(Witness(6), Curr)))
511     + field("0x0000000000000000000000000000000000000000000000000000000000000003"))
512     * cell(var(Witness(6), Curr)))
513     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")))))
514     + (x_1 + ((((field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")
515     * cell(var(Witness(7), Curr)))
516     + field("0x0000000000000000000000000000000000000000000000000000000000000003"))
517     * cell(var(Witness(7), Curr)))
518     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")))))
519     + (x_2 + ((((field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")
520     * cell(var(Witness(8), Curr)))
521     + field("0x0000000000000000000000000000000000000000000000000000000000000003"))
522     * cell(var(Witness(8), Curr)))
523     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")))))
524     + (x_3 + ((((field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")
525     * cell(var(Witness(9), Curr)))
526     + field("0x0000000000000000000000000000000000000000000000000000000000000003"))
527     * cell(var(Witness(9), Curr)))
528     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")))))
529     + (x_4 + ((((field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")
530     * cell(var(Witness(10), Curr)))
531     + field("0x0000000000000000000000000000000000000000000000000000000000000003"))
532     * cell(var(Witness(10), Curr)))
533     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")))))
534     + (x_5 + ((((field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")
535     * cell(var(Witness(11), Curr)))
536     + field("0x0000000000000000000000000000000000000000000000000000000000000003"))
537     * cell(var(Witness(11), Curr)))
538     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")))))
539     + (x_6 + ((((field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")
540     * cell(var(Witness(12), Curr)))
541     + field("0x0000000000000000000000000000000000000000000000000000000000000003"))
542     * cell(var(Witness(12), Curr)))
543     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")))))
544     + (x_7 + ((((field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000")
545     * cell(var(Witness(13), Curr)))
546     + field("0x0000000000000000000000000000000000000000000000000000000000000003"))
547     * cell(var(Witness(13), Curr)))
548     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ED00000000"))))
549     - cell(var(Witness(5), Curr))))) + (alpha_pow(3) * ((((((cell(var(Witness(6), Curr))
550     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
551     * cell(var(Witness(6), Curr)))
552     + field("0x000000000000000000000000000000000000000000000000000000000000000B"))
553     * cell(var(Witness(6), Curr)))
554     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
555     * cell(var(Witness(6), Curr))))) + (alpha_pow(4) * ((((((cell(var(Witness(7), Curr))
556     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
557     * cell(var(Witness(7), Curr)))
558     + field("0x000000000000000000000000000000000000000000000000000000000000000B"))
559     * cell(var(Witness(7), Curr)))
560     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
561     * cell(var(Witness(7), Curr))))) + (alpha_pow(5) * ((((((cell(var(Witness(8), Curr))
562     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
563     * cell(var(Witness(8), Curr)))
564     + field("0x000000000000000000000000000000000000000000000000000000000000000B"))
565     * cell(var(Witness(8), Curr)))
566     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
567     * cell(var(Witness(8), Curr))))) + (alpha_pow(6) * ((((((cell(var(Witness(9), Curr))
568     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
569     * cell(var(Witness(9), Curr)))
570     + field("0x000000000000000000000000000000000000000000000000000000000000000B"))
571     * cell(var(Witness(9), Curr)))
572     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
573     * cell(var(Witness(9), Curr))))) + (alpha_pow(7) * ((((((cell(var(Witness(10), Curr))
574     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
575     * cell(var(Witness(10), Curr)))
576     + field("0x000000000000000000000000000000000000000000000000000000000000000B"))
577     * cell(var(Witness(10), Curr)))
578     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
579     * cell(var(Witness(10), Curr))))) + (alpha_pow(8) * ((((((cell(var(Witness(11), Curr))
580     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
581     * cell(var(Witness(11), Curr)))
582     + field("0x000000000000000000000000000000000000000000000000000000000000000B"))
583     * cell(var(Witness(11), Curr)))
584     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
585     * cell(var(Witness(11), Curr))))) + (alpha_pow(9) * ((((((cell(var(Witness(12), Curr))
586     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
587     * cell(var(Witness(12), Curr)))
588     + field("0x000000000000000000000000000000000000000000000000000000000000000B"))
589     * cell(var(Witness(12), Curr)))
590     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
591     * cell(var(Witness(12), Curr))))) + (alpha_pow(10) * ((((((cell(var(Witness(13), Curr))
592     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
593     * cell(var(Witness(13), Curr)))
594     + field("0x000000000000000000000000000000000000000000000000000000000000000B"))
595     * cell(var(Witness(13), Curr)))
596     + field("0x40000000000000000000000000000000224698FC094CF91B992D30ECFFFFFFFB"))
597     * cell(var(Witness(13), Curr)))))
598}
599
600#[allow(clippy::double_parens)]
601#[allow(unused_parens)]
602#[rustfmt::skip] // See below
603fn endo_mul_scalar_fq<F: FieldWitness>(
604    evals: &ProofEvaluations<[F; 2]>,
605    powers_of_alpha: &[F; NPOWERS_OF_ALPHA],
606) -> F {
607    use Column::*;
608    use CurrOrNext::*;
609
610    let var = get_var(evals);
611    let alpha_pow = |i: usize| powers_of_alpha[i];
612    let field = field::<F>;
613
614    // Auto-generated code with the test `generate_plonk`
615    let x_0 = {
616        (((((field("0x1555555555555555555555555555555560C232FEADDC3849D96CF90B00000001")
617            * cell(var(Witness(6), Curr)))
618            + field("0x2000000000000000000000000000000011234C7E04CA546EC62375907FFFFFFE"))
619            * cell(var(Witness(6), Curr)))
620            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56EE1C24ECB67C8580000002"))
621            * cell(var(Witness(6), Curr)))
622    };
623    let x_1 = {
624        (((((field("0x1555555555555555555555555555555560C232FEADDC3849D96CF90B00000001")
625            * cell(var(Witness(7), Curr)))
626            + field("0x2000000000000000000000000000000011234C7E04CA546EC62375907FFFFFFE"))
627            * cell(var(Witness(7), Curr)))
628            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56EE1C24ECB67C8580000002"))
629            * cell(var(Witness(7), Curr)))
630    };
631    let x_2 = {
632        (((((field("0x1555555555555555555555555555555560C232FEADDC3849D96CF90B00000001")
633            * cell(var(Witness(8), Curr)))
634            + field("0x2000000000000000000000000000000011234C7E04CA546EC62375907FFFFFFE"))
635            * cell(var(Witness(8), Curr)))
636            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56EE1C24ECB67C8580000002"))
637            * cell(var(Witness(8), Curr)))
638    };
639    let x_3 = {
640        (((((field("0x1555555555555555555555555555555560C232FEADDC3849D96CF90B00000001")
641            * cell(var(Witness(9), Curr)))
642            + field("0x2000000000000000000000000000000011234C7E04CA546EC62375907FFFFFFE"))
643            * cell(var(Witness(9), Curr)))
644            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56EE1C24ECB67C8580000002"))
645            * cell(var(Witness(9), Curr)))
646    };
647    let x_4 = {
648        (((((field("0x1555555555555555555555555555555560C232FEADDC3849D96CF90B00000001")
649            * cell(var(Witness(10), Curr)))
650            + field("0x2000000000000000000000000000000011234C7E04CA546EC62375907FFFFFFE"))
651            * cell(var(Witness(10), Curr)))
652            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56EE1C24ECB67C8580000002"))
653            * cell(var(Witness(10), Curr)))
654    };
655    let x_5 = {
656        (((((field("0x1555555555555555555555555555555560C232FEADDC3849D96CF90B00000001")
657            * cell(var(Witness(11), Curr)))
658            + field("0x2000000000000000000000000000000011234C7E04CA546EC62375907FFFFFFE"))
659            * cell(var(Witness(11), Curr)))
660            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56EE1C24ECB67C8580000002"))
661            * cell(var(Witness(11), Curr)))
662    };
663    let x_6 = {
664        (((((field("0x1555555555555555555555555555555560C232FEADDC3849D96CF90B00000001")
665            * cell(var(Witness(12), Curr)))
666            + field("0x2000000000000000000000000000000011234C7E04CA546EC62375907FFFFFFE"))
667            * cell(var(Witness(12), Curr)))
668            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56EE1C24ECB67C8580000002"))
669            * cell(var(Witness(12), Curr)))
670    };
671    let x_7 = {
672        (((((field("0x1555555555555555555555555555555560C232FEADDC3849D96CF90B00000001")
673            * cell(var(Witness(13), Curr)))
674            + field("0x2000000000000000000000000000000011234C7E04CA546EC62375907FFFFFFE"))
675            * cell(var(Witness(13), Curr)))
676            + field("0x0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB061197F56EE1C24ECB67C8580000002"))
677            * cell(var(Witness(13), Curr)))
678    };
679
680    // Note: `rustfmt` is not able to format that, it runs undefinitely
681    ((((((((((((double(double((double(double((double(double((double(double((double(double((double(double((double(double((double(double(cell(var(Witness(0), Curr)))) + cell(var(Witness(6), Curr))))) + cell(var(Witness(7), Curr))))) + cell(var(Witness(8), Curr))))) + cell(var(Witness(9), Curr))))) + cell(var(Witness(10), Curr))))) + cell(var(Witness(11), Curr))))) + cell(var(Witness(12), Curr))))) + cell(var(Witness(13), Curr))) - cell(var(Witness(1), Curr))) + (alpha_pow(1) * ((double((double((double((double((double((double((double((double(cell(var(Witness(2), Curr))) + x_0)) + x_1)) + x_2)) + x_3)) + x_4)) + x_5)) + x_6)) + x_7) - cell(var(Witness(4), Curr))))) + (alpha_pow(2) * ((double((double((double((double((double((double((double((double(cell(var(Witness(3), Curr))) + (x_0 + ((((field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000") * cell(var(Witness(6), Curr))) + field("0x0000000000000000000000000000000000000000000000000000000000000003")) * cell(var(Witness(6), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000"))))) + (x_1 + ((((field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000") * cell(var(Witness(7), Curr))) + field("0x0000000000000000000000000000000000000000000000000000000000000003")) * cell(var(Witness(7), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000"))))) + (x_2 + ((((field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000") * cell(var(Witness(8), Curr))) + field("0x0000000000000000000000000000000000000000000000000000000000000003")) * cell(var(Witness(8), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000"))))) + (x_3 + ((((field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000") * cell(var(Witness(9), Curr))) + field("0x0000000000000000000000000000000000000000000000000000000000000003")) * cell(var(Witness(9), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000"))))) + (x_4 + ((((field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000") * cell(var(Witness(10), Curr))) + field("0x0000000000000000000000000000000000000000000000000000000000000003")) * cell(var(Witness(10), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000"))))) + (x_5 + ((((field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000") * cell(var(Witness(11), Curr))) + field("0x0000000000000000000000000000000000000000000000000000000000000003")) * cell(var(Witness(11), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000"))))) + (x_6 + ((((field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000") * cell(var(Witness(12), Curr))) + field("0x0000000000000000000000000000000000000000000000000000000000000003")) * cell(var(Witness(12), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000"))))) + (x_7 + ((((field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000") * cell(var(Witness(13), Curr))) + field("0x0000000000000000000000000000000000000000000000000000000000000003")) * cell(var(Witness(13), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB2100000000")))) - cell(var(Witness(5), Curr))))) + (alpha_pow(3) * ((((((cell(var(Witness(6), Curr)) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(6), Curr))) + field("0x000000000000000000000000000000000000000000000000000000000000000B")) * cell(var(Witness(6), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(6), Curr))))) + (alpha_pow(4) * ((((((cell(var(Witness(7), Curr)) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(7), Curr))) + field("0x000000000000000000000000000000000000000000000000000000000000000B")) * cell(var(Witness(7), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(7), Curr))))) + (alpha_pow(5) * ((((((cell(var(Witness(8), Curr)) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(8), Curr))) + field("0x000000000000000000000000000000000000000000000000000000000000000B")) * cell(var(Witness(8), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(8), Curr))))) + (alpha_pow(6) * ((((((cell(var(Witness(9), Curr)) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(9), Curr))) + field("0x000000000000000000000000000000000000000000000000000000000000000B")) * cell(var(Witness(9), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(9), Curr))))) + (alpha_pow(7) * ((((((cell(var(Witness(10), Curr)) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(10), Curr))) + field("0x000000000000000000000000000000000000000000000000000000000000000B")) * cell(var(Witness(10), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(10), Curr))))) + (alpha_pow(8) * ((((((cell(var(Witness(11), Curr)) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(11), Curr))) + field("0x000000000000000000000000000000000000000000000000000000000000000B")) * cell(var(Witness(11), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(11), Curr))))) + (alpha_pow(9) * ((((((cell(var(Witness(12), Curr)) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(12), Curr))) + field("0x000000000000000000000000000000000000000000000000000000000000000B")) * cell(var(Witness(12), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(12), Curr))))) + (alpha_pow(10) * ((((((cell(var(Witness(13), Curr)) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(13), Curr))) + field("0x000000000000000000000000000000000000000000000000000000000000000B")) * cell(var(Witness(13), Curr))) + field("0x40000000000000000000000000000000224698FC0994A8DD8C46EB20FFFFFFFB")) * cell(var(Witness(13), Curr)))))
682}
683
684#[cfg(test)]
685mod tests {
686    use kimchi::{
687        circuits::expr::Linearization,
688        linearization::{constraints_expr, linearization_columns},
689    };
690    use mina_curves::pasta::{Fp, Fq};
691    use sha2::{Digest, Sha256};
692    #[cfg(target_family = "wasm")]
693    use wasm_bindgen_test::wasm_bindgen_test as test;
694
695    /// Code originally used to generate OCaml code
696    /// We use the same method to generate our Rust code
697    ///
698    /// <https://github.com/MinaProtocol/mina/blob/0b63498e271575dbffe2b31f3ab8be293490b1ac/src/lib/crypto/kimchi_bindings/stubs/src/linearization.rs#L11>
699    // #[test]
700    fn generate_plonk() {
701        let lookup_configuration = None;
702        let fp_evaluated_cols = linearization_columns::<Fp>(lookup_configuration);
703        let (fp_linearization, _powers_of_alpha) = constraints_expr::<Fp>(None, true);
704
705        let Linearization {
706            constant_term: _,
707            index_terms: mut index_terms_fp,
708        } = fp_linearization.linearize(fp_evaluated_cols).unwrap();
709
710        // HashMap deliberately uses an unstable order; here we sort to ensure that the output is
711        // consistent when printing.
712        index_terms_fp.sort_by(|(x, _), (y, _)| x.cmp(y));
713
714        let fp_other_terms: Vec<(String, String)> = index_terms_fp
715            .iter()
716            .map(|(col, expr)| (format!("{:?}", col), expr.ocaml_str()))
717            .collect();
718
719        let sum = |s: &str| {
720            let mut hasher = Sha256::new();
721            hasher.update(s.as_bytes());
722            hex::encode(hasher.finalize())
723        };
724
725        // Convert to Rust code
726        for (v, terms) in &fp_other_terms {
727            println!("value={:?} sum=\n{}\n", v, sum(terms));
728
729            // Replace "let a = b in " with "let a = { b };", to make the output a Rust syntax
730            let terms = terms.replace(" in ", "};");
731            let terms = terms.replace('=', "={");
732
733            // Code is copy/paste from this output
734            println!("value={:?} code=\n{}\n", v, terms);
735        }
736
737        // Make sure the generated code doesn't change if we update the `proof-systems` dependency
738
739        let value_of = |s: &str| &fp_other_terms.iter().find(|(v, _)| v == s).unwrap().1;
740
741        let fp_sum_complete_add = sum(value_of("Index(CompleteAdd)"));
742        assert_eq!(
743            fp_sum_complete_add,
744            "c478727783cc551528384c6f05c26414bf64bbd1dc6a0c47c30eb917a825b9a0"
745        );
746
747        let fp_sum_var_base_mul = sum(value_of("Index(VarBaseMul)"));
748        assert_eq!(
749            fp_sum_var_base_mul,
750            "4437fea516a70ff606b11eda22cfde29e2d95b86154010b5886b3510909d2ab2"
751        );
752
753        let fp_sum_endomul = sum(value_of("Index(EndoMul)"));
754        assert_eq!(
755            fp_sum_endomul,
756            "561f3c95177dc76aa596d506be6e1dd5530dd3a9f44d25d2f5e4e9ad1c89176e"
757        );
758
759        let fp_sum_endomul_scalar = sum(value_of("Index(EndoMulScalar)"));
760        assert_eq!(
761            fp_sum_endomul_scalar,
762            "d56e30e8015f38922a7069cc87daaf21ffb15d96cc80fdd9b257e3267145b919"
763        );
764
765        // Same but for `Fq`. EndoMulScalar is different
766
767        let fq_evaluated_cols = linearization_columns::<Fq>(lookup_configuration);
768        let (fq_linearization, _powers_of_alpha) = constraints_expr::<Fq>(None, true);
769
770        let Linearization {
771            constant_term,
772            index_terms: mut index_terms_fq,
773        } = fq_linearization.linearize(fq_evaluated_cols).unwrap();
774
775        dbg!(constant_term.ocaml_str());
776
777        // HashMap deliberately uses an unstable order; here we sort to ensure that the output is
778        // consistent when printing.
779        index_terms_fq.sort_by(|(x, _), (y, _)| x.cmp(y));
780
781        // dbg!(index_terms_fq)
782
783        let fq_other_terms: Vec<(String, String)> = index_terms_fq
784            .iter()
785            .map(|(col, expr)| (format!("{:?}", col), expr.ocaml_str()))
786            .collect();
787
788        let value_of = |s: &str| &fq_other_terms.iter().find(|(v, _)| v == s).unwrap().1;
789
790        let fq_sum_complete_add = sum(value_of("Index(CompleteAdd)"));
791        assert_eq!(fq_sum_complete_add, fp_sum_complete_add);
792
793        let fq_sum_var_base_mul = sum(value_of("Index(VarBaseMul)"));
794        assert_eq!(fq_sum_var_base_mul, fp_sum_var_base_mul);
795
796        let fq_sum_endomul = sum(value_of("Index(EndoMul)"));
797        assert_eq!(fq_sum_endomul, fp_sum_endomul);
798
799        let fq_sum_endomul_scalar = sum(value_of("Index(EndoMulScalar)"));
800        assert_ne!(fq_sum_endomul_scalar, fp_sum_endomul_scalar);
801        assert_eq!(
802            fq_sum_endomul_scalar,
803            "bcf65a903f377ad4c115d4357817a7129381b42ff3a23e41f4fc2c735943db0f"
804        );
805    }
806}