Skip to main content

kimchi/
plonk_sponge.rs

1use alloc::{vec, vec::Vec};
2use ark_ff::{Field, PrimeField};
3use mina_poseidon::{
4    constants::PlonkSpongeConstantsKimchi as SC,
5    poseidon::Sponge,
6    sponge::{DefaultFrSponge, ScalarChallenge},
7};
8
9use crate::proof::{PointEvaluations, ProofEvaluations};
10
11/// Abstracts a sponge that operates on the scalar field of an
12/// elliptic curve. Unlike the [`FqSponge`](mina_poseidon::FqSponge)
13/// it cannot absorb or digest base field elements. However, the
14/// [`FqSponge`](mina_poseidon::FqSponge) can *also* operate on the
15/// scalar field by the means of a specific encoding technique.
16pub trait FrSponge<Fr: Field> {
17    /// Absorbs the field element into the sponge.
18    fn absorb(&mut self, x: &Fr);
19
20    /// Absorbs a slice of field elements into the sponge.
21    fn absorb_multiple(&mut self, x: &[Fr]);
22
23    /// Creates a [`ScalarChallenge`] by squeezing the sponge.
24    fn challenge(&mut self) -> ScalarChallenge<Fr>;
25
26    /// Consumes the sponge and returns the current digest, by squeezing.
27    fn digest(self) -> Fr;
28
29    /// Absorbs the given evaluations into the sponge.
30    // TODO: IMO this function should be inlined in prover/verifier
31    fn absorb_evaluations(&mut self, e: &ProofEvaluations<PointEvaluations<Vec<Fr>>>);
32}
33
34impl<const FULL_ROUNDS: usize, Fr: PrimeField> FrSponge<Fr>
35    for DefaultFrSponge<Fr, SC, FULL_ROUNDS>
36{
37    fn absorb(&mut self, x: &Fr) {
38        self.last_squeezed = vec![];
39        self.sponge.absorb(&[*x]);
40    }
41
42    fn absorb_multiple(&mut self, x: &[Fr]) {
43        self.last_squeezed = vec![];
44        self.sponge.absorb(x);
45    }
46
47    fn challenge(&mut self) -> ScalarChallenge<Fr> {
48        ScalarChallenge::new(self.squeeze(mina_poseidon::sponge::CHALLENGE_LENGTH_IN_LIMBS))
49    }
50
51    fn digest(mut self) -> Fr {
52        self.sponge.squeeze()
53    }
54
55    // We absorb all evaluations of the same polynomial at the same time
56    fn absorb_evaluations(&mut self, e: &ProofEvaluations<PointEvaluations<Vec<Fr>>>) {
57        self.last_squeezed = vec![];
58
59        let ProofEvaluations {
60            public: _, // Must be absorbed first manually for now, to handle Mina annoyances
61            w,
62            z,
63            s,
64            coefficients,
65            generic_selector,
66            poseidon_selector,
67            complete_add_selector,
68            mul_selector,
69            emul_selector,
70            endomul_scalar_selector,
71            range_check0_selector,
72            range_check1_selector,
73            foreign_field_add_selector,
74            foreign_field_mul_selector,
75            xor_selector,
76            rot_selector,
77            lookup_aggregation,
78            lookup_table,
79            lookup_sorted,
80            runtime_lookup_table,
81            runtime_lookup_table_selector,
82            xor_lookup_selector,
83            lookup_gate_lookup_selector,
84            range_check_lookup_selector,
85            foreign_field_mul_lookup_selector,
86        } = e;
87
88        let mut points = vec![
89            z,
90            generic_selector,
91            poseidon_selector,
92            complete_add_selector,
93            mul_selector,
94            emul_selector,
95            endomul_scalar_selector,
96        ];
97        w.iter().for_each(|w_i| points.push(w_i));
98        coefficients.iter().for_each(|c_i| points.push(c_i));
99        s.iter().for_each(|s_i| points.push(s_i));
100
101        // Optional gates
102
103        if let Some(range_check0_selector) = range_check0_selector.as_ref() {
104            points.push(range_check0_selector)
105        }
106        if let Some(range_check1_selector) = range_check1_selector.as_ref() {
107            points.push(range_check1_selector)
108        }
109        if let Some(foreign_field_add_selector) = foreign_field_add_selector.as_ref() {
110            points.push(foreign_field_add_selector)
111        }
112        if let Some(foreign_field_mul_selector) = foreign_field_mul_selector.as_ref() {
113            points.push(foreign_field_mul_selector)
114        }
115        if let Some(xor_selector) = xor_selector.as_ref() {
116            points.push(xor_selector)
117        }
118        if let Some(rot_selector) = rot_selector.as_ref() {
119            points.push(rot_selector)
120        }
121        if let Some(lookup_aggregation) = lookup_aggregation.as_ref() {
122            points.push(lookup_aggregation)
123        }
124        if let Some(lookup_table) = lookup_table.as_ref() {
125            points.push(lookup_table)
126        }
127        for lookup_sorted in lookup_sorted {
128            if let Some(lookup_sorted) = lookup_sorted.as_ref() {
129                points.push(lookup_sorted)
130            }
131        }
132        if let Some(runtime_lookup_table) = runtime_lookup_table.as_ref() {
133            points.push(runtime_lookup_table)
134        }
135        if let Some(runtime_lookup_table_selector) = runtime_lookup_table_selector.as_ref() {
136            points.push(runtime_lookup_table_selector)
137        }
138        if let Some(xor_lookup_selector) = xor_lookup_selector.as_ref() {
139            points.push(xor_lookup_selector)
140        }
141        if let Some(lookup_gate_lookup_selector) = lookup_gate_lookup_selector.as_ref() {
142            points.push(lookup_gate_lookup_selector)
143        }
144        if let Some(range_check_lookup_selector) = range_check_lookup_selector.as_ref() {
145            points.push(range_check_lookup_selector)
146        }
147        if let Some(foreign_field_mul_lookup_selector) = foreign_field_mul_lookup_selector.as_ref()
148        {
149            points.push(foreign_field_mul_lookup_selector)
150        }
151
152        points.into_iter().for_each(|p| {
153            self.sponge.absorb(&p.zeta);
154            self.sponge.absorb(&p.zeta_omega);
155        })
156    }
157}