kimchi/
plonk_sponge.rs

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