mina_tree/proofs/public_input/
scalars.rs

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