halo2_axiom/plonk/lookup/
verifier.rs
1use std::iter;
2
3use super::super::{
4 circuit::Expression, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX,
5};
6use super::Argument;
7use crate::{
8 arithmetic::CurveAffine,
9 plonk::{Error, VerifyingKey},
10 poly::{commitment::MSM, Rotation, VerifierQuery},
11 transcript::{EncodedChallenge, TranscriptRead},
12};
13use ff::Field;
14
15pub struct PermutationCommitments<C: CurveAffine> {
16 permuted_input_commitment: C,
17 permuted_table_commitment: C,
18}
19
20pub struct Committed<C: CurveAffine> {
21 permuted: PermutationCommitments<C>,
22 product_commitment: C,
23}
24
25pub struct Evaluated<C: CurveAffine> {
26 committed: Committed<C>,
27 product_eval: C::Scalar,
28 product_next_eval: C::Scalar,
29 permuted_input_eval: C::Scalar,
30 permuted_input_inv_eval: C::Scalar,
31 permuted_table_eval: C::Scalar,
32}
33
34impl<F: Field> Argument<F> {
35 pub(in crate::plonk) fn read_permuted_commitments<
36 C: CurveAffine,
37 E: EncodedChallenge<C>,
38 T: TranscriptRead<C, E>,
39 >(
40 &self,
41 transcript: &mut T,
42 ) -> Result<PermutationCommitments<C>, Error> {
43 let permuted_input_commitment = transcript.read_point()?;
44 let permuted_table_commitment = transcript.read_point()?;
45
46 Ok(PermutationCommitments {
47 permuted_input_commitment,
48 permuted_table_commitment,
49 })
50 }
51}
52
53impl<C: CurveAffine> PermutationCommitments<C> {
54 pub(in crate::plonk) fn read_product_commitment<
55 E: EncodedChallenge<C>,
56 T: TranscriptRead<C, E>,
57 >(
58 self,
59 transcript: &mut T,
60 ) -> Result<Committed<C>, Error> {
61 let product_commitment = transcript.read_point()?;
62
63 Ok(Committed {
64 permuted: self,
65 product_commitment,
66 })
67 }
68}
69
70impl<C: CurveAffine> Committed<C> {
71 pub(crate) fn evaluate<E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
72 self,
73 transcript: &mut T,
74 ) -> Result<Evaluated<C>, Error> {
75 let product_eval = transcript.read_scalar()?;
76 let product_next_eval = transcript.read_scalar()?;
77 let permuted_input_eval = transcript.read_scalar()?;
78 let permuted_input_inv_eval = transcript.read_scalar()?;
79 let permuted_table_eval = transcript.read_scalar()?;
80
81 Ok(Evaluated {
82 committed: self,
83 product_eval,
84 product_next_eval,
85 permuted_input_eval,
86 permuted_input_inv_eval,
87 permuted_table_eval,
88 })
89 }
90}
91
92impl<C: CurveAffine> Evaluated<C> {
93 #[allow(clippy::too_many_arguments)]
94 pub(in crate::plonk) fn expressions<'a>(
95 &'a self,
96 l_0: C::Scalar,
97 l_last: C::Scalar,
98 l_blind: C::Scalar,
99 argument: &'a Argument<C::Scalar>,
100 theta: ChallengeTheta<C>,
101 beta: ChallengeBeta<C>,
102 gamma: ChallengeGamma<C>,
103 advice_evals: &[C::Scalar],
104 fixed_evals: &[C::Scalar],
105 instance_evals: &[C::Scalar],
106 challenges: &[C::Scalar],
107 ) -> impl Iterator<Item = C::Scalar> + 'a {
108 let active_rows = C::Scalar::ONE - (l_last + l_blind);
109
110 let product_expression = || {
111 let left = self.product_next_eval
114 * &(self.permuted_input_eval + &*beta)
115 * &(self.permuted_table_eval + &*gamma);
116
117 let compress_expressions = |expressions: &[Expression<C::Scalar>]| {
118 expressions
119 .iter()
120 .map(|expression| {
121 expression.evaluate(
122 &|scalar| scalar,
123 &|_| panic!("virtual selectors are removed during optimization"),
124 &|query| fixed_evals[query.index.unwrap()],
125 &|query| advice_evals[query.index.unwrap()],
126 &|query| instance_evals[query.index.unwrap()],
127 &|challenge| challenges[challenge.index()],
128 &|a| -a,
129 &|a, b| a + &b,
130 &|a, b| a * &b,
131 &|a, scalar| a * &scalar,
132 )
133 })
134 .fold(C::Scalar::ZERO, |acc, eval| acc * &*theta + &eval)
135 };
136 let right = self.product_eval
137 * &(compress_expressions(&argument.input_expressions) + &*beta)
138 * &(compress_expressions(&argument.table_expressions) + &*gamma);
139
140 (left - &right) * &active_rows
141 };
142
143 std::iter::empty()
144 .chain(
145 Some(l_0 * &(C::Scalar::ONE - &self.product_eval)),
147 )
148 .chain(
149 Some(l_last * &(self.product_eval.square() - &self.product_eval)),
151 )
152 .chain(
153 Some(product_expression()),
158 )
159 .chain(Some(
160 l_0 * &(self.permuted_input_eval - &self.permuted_table_eval),
162 ))
163 .chain(Some(
164 (self.permuted_input_eval - &self.permuted_table_eval)
166 * &(self.permuted_input_eval - &self.permuted_input_inv_eval)
167 * &active_rows,
168 ))
169 }
170
171 pub(in crate::plonk) fn queries<'r, M: MSM<C> + 'r>(
172 &'r self,
173 vk: &'r VerifyingKey<C>,
174 x: ChallengeX<C>,
175 ) -> impl Iterator<Item = VerifierQuery<'r, C, M>> + Clone {
176 let x_inv = vk.domain.rotate_omega(*x, Rotation::prev());
177 let x_next = vk.domain.rotate_omega(*x, Rotation::next());
178
179 iter::empty()
180 .chain(Some(VerifierQuery::new_commitment(
182 &self.committed.product_commitment,
183 *x,
184 self.product_eval,
185 )))
186 .chain(Some(VerifierQuery::new_commitment(
188 &self.committed.permuted.permuted_input_commitment,
189 *x,
190 self.permuted_input_eval,
191 )))
192 .chain(Some(VerifierQuery::new_commitment(
194 &self.committed.permuted.permuted_table_commitment,
195 *x,
196 self.permuted_table_eval,
197 )))
198 .chain(Some(VerifierQuery::new_commitment(
200 &self.committed.permuted.permuted_input_commitment,
201 x_inv,
202 self.permuted_input_inv_eval,
203 )))
204 .chain(Some(VerifierQuery::new_commitment(
206 &self.committed.product_commitment,
207 x_next,
208 self.product_next_eval,
209 )))
210 }
211}