mina_tree/proofs/
util.rs

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