kimchi/
plonk_sponge.rs

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