mina_tree/proofs/
util.rs

1use std::fmt::Debug;
2
3use ark_ff::{BigInteger256, Field};
4use kimchi::proof::{PointEvaluations, ProofEvaluations};
5use mina_p2p_messages::{
6    bigint::{BigInt, InvalidBigInt},
7    pseq::PaddedSeq,
8    v2::PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2A,
9};
10
11use crate::proofs::field::{field, Boolean, FieldWitness};
12
13use super::{
14    public_input::scalar_challenge::ScalarChallenge,
15    step::{Opt, OptFlag},
16    transaction::InnerCurve,
17    witness::Witness,
18};
19
20pub fn extract_polynomial_commitment<
21    'a,
22    F: FieldWitness,
23    I: IntoIterator<Item = &'a (BigInt, BigInt)>,
24>(
25    curves: I,
26) -> Result<Vec<InnerCurve<F>>, InvalidBigInt> {
27    curves
28        .into_iter()
29        .map(|curve| {
30            Ok(InnerCurve::from((
31                curve.0.to_field::<F>()?,
32                curve.1.to_field()?,
33            )))
34        })
35        .collect()
36}
37
38pub fn extract_bulletproof<
39    'a,
40    F: FieldWitness,
41    I: IntoIterator<
42        Item = &'a PaddedSeq<
43            PicklesReducedMessagesForNextProofOverSameFieldWrapChallengesVectorStableV2A,
44            N,
45        >,
46    >,
47    const N: usize,
48>(
49    v: I,
50) -> Vec<[F; N]> {
51    v.into_iter()
52        .map(|old| {
53            old.each_ref().map(|old| {
54                let prechallenge = old.prechallenge.inner.each_ref().map(|v| v.as_u64());
55                ScalarChallenge::limbs_to_field(&prechallenge)
56            })
57        })
58        .collect()
59}
60
61pub fn four_u64_to_field<F, E>(v: &[u64; 4]) -> Result<F, InvalidBigInt>
62where
63    F: Field + TryFrom<BigInteger256, Error = E>,
64{
65    let mut bigint: [u64; 4] = [0; 4];
66    bigint[..4].copy_from_slice(v);
67
68    let bigint = BigInteger256::new(bigint);
69    F::try_from(bigint).map_err(|_| InvalidBigInt)
70}
71
72pub fn two_u64_to_field<F, E>(v: &[u64; 2]) -> F
73where
74    F: Field + TryFrom<BigInteger256, Error = E>,
75    E: Debug,
76{
77    let mut bigint: [u64; 4] = [0; 4];
78    bigint[..2].copy_from_slice(v);
79
80    let bigint = BigInteger256::new(bigint);
81    F::try_from(bigint).unwrap() // Never fail with 2 limbs
82}
83
84/// <https://github.com/MinaProtocol/mina/blob/bfd1009abdbee78979ff0343cc73a3480e862f58/src/lib/pickles/wrap_verifier.ml#L16>
85pub fn challenge_polynomial<F: FieldWitness>(chals: &[F]) -> impl Fn(F) -> F + '_ {
86    |pt: F| {
87        let k = chals.len();
88        let pow_two_pows = {
89            let mut res = vec![pt; k];
90            for i in 1..k {
91                let y = res[i - 1];
92                res[i] = y * y;
93            }
94            res
95        };
96        fn prod<F: FieldWitness>(k: usize, fun: impl Fn(usize) -> F) -> F {
97            let mut r = fun(0);
98            for i in 1..k {
99                r = fun(i) * r;
100            }
101            r
102        }
103        prod::<F>(k, |i| F::one() + (chals[i] * pow_two_pows[k - 1 - i]))
104    }
105}
106
107/// <https://github.com/MinaProtocol/mina/blob/bfd1009abdbee78979ff0343cc73a3480e862f58/src/lib/pickles/wrap_verifier.ml#L16>
108pub fn challenge_polynomial_checked<F: FieldWitness>(
109    chals: &[F],
110) -> impl Fn(F, &mut Witness<F>) -> F + '_ {
111    |pt: F, w: &mut Witness<F>| {
112        let k = chals.len();
113        let pow_two_pows = {
114            let mut res = vec![pt; k];
115            for i in 1..k {
116                let y = res[i - 1];
117                res[i] = field::mul(y, y, w);
118            }
119            res
120        };
121        fn prod<F: FieldWitness>(
122            k: usize,
123            fun: impl Fn(usize, &mut Witness<F>) -> F,
124            w: &mut Witness<F>,
125        ) -> F {
126            let mut r = fun(0, w);
127            for i in 1..k {
128                r = field::mul(fun(i, w), r, w);
129            }
130            r
131        }
132        prod(
133            k,
134            |i, w| F::one() + field::mul(chals[i], pow_two_pows[k - 1 - i], w),
135            w,
136        )
137    }
138}
139
140/// Note: Outdated URL
141/// Note: Different than `to_absorption_sequence`
142/// <https://github.com/MinaProtocol/mina/blob/4af0c229548bc96d76678f11b6842999de5d3b0b/src/lib/pickles_types/plonk_types.ml#L611>
143pub fn proof_evaluation_to_list<F: FieldWitness>(
144    e: &ProofEvaluations<PointEvaluations<Vec<F>>>,
145) -> Vec<&PointEvaluations<Vec<F>>> {
146    let ProofEvaluations::<PointEvaluations<Vec<F>>> {
147        public: _,
148        w,
149        z,
150        s,
151        coefficients,
152        generic_selector,
153        poseidon_selector,
154        complete_add_selector,
155        mul_selector,
156        emul_selector,
157        endomul_scalar_selector,
158        range_check0_selector,
159        range_check1_selector,
160        foreign_field_add_selector,
161        foreign_field_mul_selector,
162        xor_selector,
163        rot_selector,
164        lookup_aggregation,
165        lookup_table,
166        lookup_sorted,
167        runtime_lookup_table,
168        runtime_lookup_table_selector,
169        xor_lookup_selector,
170        lookup_gate_lookup_selector,
171        range_check_lookup_selector,
172        foreign_field_mul_lookup_selector,
173    } = e;
174
175    let mut list = vec![
176        z,
177        generic_selector,
178        poseidon_selector,
179        complete_add_selector,
180        mul_selector,
181        emul_selector,
182        endomul_scalar_selector,
183    ];
184
185    list.extend(w);
186    list.extend(coefficients);
187    list.extend(s);
188
189    let optional_gates = [
190        range_check0_selector,
191        range_check1_selector,
192        foreign_field_add_selector,
193        foreign_field_mul_selector,
194        xor_selector,
195        rot_selector,
196    ];
197
198    list.extend(optional_gates.iter().filter_map(|v| (*v).as_ref()));
199    list.extend(lookup_sorted.iter().filter_map(|v| v.as_ref()));
200    list.extend(
201        [
202            lookup_aggregation,
203            lookup_table,
204            runtime_lookup_table,
205            runtime_lookup_table_selector,
206            xor_lookup_selector,
207            lookup_gate_lookup_selector,
208            range_check_lookup_selector,
209            foreign_field_mul_lookup_selector,
210        ]
211        .iter()
212        .filter_map(|v| (*v).as_ref()),
213    );
214
215    list
216}
217
218pub fn proof_evaluation_to_absorption_sequence<F: FieldWitness>(
219    e: &ProofEvaluations<PointEvaluations<Vec<F>>>,
220) -> Vec<&PointEvaluations<Vec<F>>> {
221    let ProofEvaluations {
222        public: _,
223        w,
224        coefficients,
225        z,
226        s,
227        generic_selector,
228        poseidon_selector,
229        complete_add_selector,
230        mul_selector,
231        emul_selector,
232        endomul_scalar_selector,
233        range_check0_selector,
234        range_check1_selector,
235        foreign_field_add_selector,
236        foreign_field_mul_selector,
237        xor_selector,
238        rot_selector,
239        lookup_aggregation,
240        lookup_table,
241        lookup_sorted,
242        runtime_lookup_table,
243        runtime_lookup_table_selector,
244        xor_lookup_selector,
245        lookup_gate_lookup_selector,
246        range_check_lookup_selector,
247        foreign_field_mul_lookup_selector,
248    } = e;
249
250    let mut list = vec![
251        z,
252        generic_selector,
253        poseidon_selector,
254        complete_add_selector,
255        mul_selector,
256        emul_selector,
257        endomul_scalar_selector,
258    ];
259
260    list.extend(w.iter());
261    list.extend(coefficients.iter());
262    list.extend(s.iter());
263
264    list.extend(
265        [
266            range_check0_selector,
267            range_check1_selector,
268            foreign_field_add_selector,
269            foreign_field_mul_selector,
270            xor_selector,
271            rot_selector,
272            lookup_aggregation,
273            lookup_table,
274        ]
275        .into_iter()
276        .filter_map(|v| v.as_ref()),
277    );
278
279    list.extend(lookup_sorted.iter().filter_map(|v| v.as_ref()));
280
281    list.extend(
282        [
283            runtime_lookup_table,
284            runtime_lookup_table_selector,
285            xor_lookup_selector,
286            lookup_gate_lookup_selector,
287            range_check_lookup_selector,
288            foreign_field_mul_lookup_selector,
289        ]
290        .into_iter()
291        .filter_map(|v| v.as_ref()),
292    );
293
294    #[allow(clippy::iter_cloned_collect)]
295    list.iter().cloned().collect()
296}
297
298/// <https://github.com/MinaProtocol/mina/blob/4af0c229548bc96d76678f11b6842999de5d3b0b/src/lib/pickles_types/plonk_types.ml#L611>
299pub fn proof_evaluation_to_list_opt<F: FieldWitness>(
300    e: &ProofEvaluations<PointEvaluations<Vec<F>>>,
301    hack_feature_flags: OptFlag,
302) -> Vec<Opt<PointEvaluations<Vec<F>>>> {
303    let ProofEvaluations {
304        public: _,
305        w,
306        z,
307        s,
308        coefficients,
309        generic_selector,
310        poseidon_selector,
311        complete_add_selector,
312        mul_selector,
313        emul_selector,
314        endomul_scalar_selector,
315        range_check0_selector,
316        range_check1_selector,
317        foreign_field_add_selector,
318        foreign_field_mul_selector,
319        xor_selector,
320        rot_selector,
321        lookup_aggregation,
322        lookup_table,
323        lookup_sorted,
324        runtime_lookup_table,
325        runtime_lookup_table_selector,
326        xor_lookup_selector,
327        lookup_gate_lookup_selector,
328        range_check_lookup_selector,
329        foreign_field_mul_lookup_selector,
330    } = e;
331
332    let mut list = vec![
333        Opt::Some(z.clone()),
334        Opt::Some(generic_selector.clone()),
335        Opt::Some(poseidon_selector.clone()),
336        Opt::Some(complete_add_selector.clone()),
337        Opt::Some(mul_selector.clone()),
338        Opt::Some(emul_selector.clone()),
339        Opt::Some(endomul_scalar_selector.clone()),
340    ];
341
342    list.extend(w.iter().cloned().map(Opt::Some));
343    list.extend(coefficients.iter().cloned().map(Opt::Some));
344    list.extend(s.iter().cloned().map(Opt::Some));
345
346    let zero = || PointEvaluations {
347        zeta: vec![F::zero()],
348        zeta_omega: vec![F::zero()],
349    };
350    let to_opt = |v: &Option<PointEvaluations<Vec<F>>>| {
351        if let OptFlag::Maybe = hack_feature_flags {
352            match v {
353                Some(v) => Opt::Maybe(Boolean::True, v.clone()),
354                None => Opt::Maybe(Boolean::False, zero()),
355            }
356        } else {
357            match v {
358                Some(v) => Opt::Some(v.clone()),
359                None => Opt::No,
360            }
361        }
362    };
363
364    let optional_gates = [
365        range_check0_selector,
366        range_check1_selector,
367        foreign_field_add_selector,
368        foreign_field_mul_selector,
369        xor_selector,
370        rot_selector,
371    ];
372
373    list.extend(optional_gates.into_iter().map(to_opt));
374    list.extend(lookup_sorted.iter().map(to_opt));
375
376    list.extend(
377        [
378            lookup_aggregation,
379            lookup_table,
380            runtime_lookup_table,
381            runtime_lookup_table_selector,
382            xor_lookup_selector,
383            lookup_gate_lookup_selector,
384            range_check_lookup_selector,
385            foreign_field_mul_lookup_selector,
386        ]
387        .into_iter()
388        .map(to_opt),
389    );
390
391    list
392}
393
394/// <https://github.com/MinaProtocol/mina/blob/4af0c229548bc96d76678f11b6842999de5d3b0b/src/lib/pickles_types/plonk_types.ml#L674>
395pub fn to_absorption_sequence_opt<F: FieldWitness>(
396    evals: &ProofEvaluations<PointEvaluations<Vec<F>>>,
397    hack_feature_flags: OptFlag,
398) -> Vec<Opt<PointEvaluations<Vec<F>>>> {
399    let ProofEvaluations {
400        public: _,
401        w,
402        coefficients,
403        z,
404        s,
405        generic_selector,
406        poseidon_selector,
407        complete_add_selector,
408        mul_selector,
409        emul_selector,
410        endomul_scalar_selector,
411        range_check0_selector,
412        range_check1_selector,
413        foreign_field_add_selector,
414        foreign_field_mul_selector,
415        xor_selector,
416        rot_selector,
417        lookup_aggregation,
418        lookup_table,
419        lookup_sorted,
420        runtime_lookup_table,
421        runtime_lookup_table_selector,
422        xor_lookup_selector,
423        lookup_gate_lookup_selector,
424        range_check_lookup_selector,
425        foreign_field_mul_lookup_selector,
426    } = evals;
427
428    let mut list = vec![
429        Opt::Some(z.clone()),
430        Opt::Some(generic_selector.clone()),
431        Opt::Some(poseidon_selector.clone()),
432        Opt::Some(complete_add_selector.clone()),
433        Opt::Some(mul_selector.clone()),
434        Opt::Some(emul_selector.clone()),
435        Opt::Some(endomul_scalar_selector.clone()),
436    ];
437
438    list.extend(w.iter().cloned().map(Opt::Some));
439    list.extend(coefficients.iter().cloned().map(Opt::Some));
440    list.extend(s.iter().cloned().map(Opt::Some));
441
442    let zero = || PointEvaluations {
443        zeta: vec![F::zero()],
444        zeta_omega: vec![F::zero()],
445    };
446    let to_opt = |v: &Option<PointEvaluations<Vec<F>>>| {
447        if let OptFlag::Maybe = hack_feature_flags {
448            match v {
449                Some(v) => Opt::Maybe(Boolean::True, v.clone()),
450                None => Opt::Maybe(Boolean::False, zero()),
451            }
452        } else {
453            match v {
454                Some(v) => Opt::Some(v.clone()),
455                None => Opt::No,
456            }
457        }
458    };
459
460    list.extend(
461        [
462            range_check0_selector,
463            range_check1_selector,
464            foreign_field_add_selector,
465            foreign_field_mul_selector,
466            xor_selector,
467            rot_selector,
468            lookup_aggregation,
469            lookup_table,
470        ]
471        .iter()
472        .map(|e| to_opt(e)),
473    );
474
475    list.extend(lookup_sorted.iter().map(to_opt));
476
477    list.extend(
478        [
479            runtime_lookup_table,
480            runtime_lookup_table_selector,
481            xor_lookup_selector,
482            lookup_gate_lookup_selector,
483            range_check_lookup_selector,
484            foreign_field_mul_lookup_selector,
485        ]
486        .into_iter()
487        .map(to_opt),
488    );
489
490    list
491}
492
493pub fn sha256_sum(s: &[u8]) -> String {
494    use sha2::Digest;
495    let mut hasher = sha2::Sha256::new();
496    hasher.update(s);
497    hex::encode(hasher.finalize())
498}
499
500pub fn field_of_bits<F: FieldWitness, const N: usize>(bs: &[bool; N]) -> F {
501    bs.iter().rev().fold(F::zero(), |acc, b| {
502        let acc = acc + acc;
503        if *b {
504            acc + F::one()
505        } else {
506            acc
507        }
508    })
509}