binius_core/protocols/gkr_exp/
verifiers.rs1use binius_field::{BinaryField, Field, PackedField};
4use binius_math::EvaluationOrder;
5use binius_utils::bail;
6
7use super::{
8 common::{ExpClaim, LayerClaim},
9 compositions::{ExpCompositions, IndexedExpComposition},
10 error::Error,
11 utils::first_layer_inverse,
12};
13use crate::{
14 composition::{FixedDimIndexCompositions, IndexComposition},
15 protocols::sumcheck::CompositeSumClaim,
16};
17
18pub trait ExpVerifier<F: Field> {
19 fn exponent_bit_width(&self) -> usize;
20
21 fn is_last_layer(&self, layer_no: usize) -> bool {
22 self.exponent_bit_width() - 1 - layer_no == 0
23 }
24
25 fn layer_claim_eval_point(&self) -> &[F];
27
28 fn layer_composite_sum_claim(
32 &self,
33 layer_no: usize,
34 composite_claims_n_multilinears: usize,
35 multilinears_index: usize,
36 ) -> Result<Option<CompositeSumClaim<F, IndexedExpComposition<F>>>, Error>;
37
38 fn layer_n_multilinears(&self, layer_no: usize) -> usize;
40
41 fn layer_n_claims(&self, layer_no: usize) -> usize;
43
44 fn finish_layer(
47 &mut self,
48 evaluation_order: EvaluationOrder,
49 layer_no: usize,
50 multilinear_evals: &[F],
51 r: &[F],
52 ) -> Vec<LayerClaim<F>>;
53}
54
55pub struct StaticBaseExpVerifier<F: Field>(ExpClaim<F>);
56
57impl<F: Field> StaticBaseExpVerifier<F> {
58 pub fn new(claim: &ExpClaim<F>) -> Result<Self, Error> {
59 if claim.static_base.is_none() {
60 bail!(Error::IncorrectWitnessType);
61 }
62
63 Ok(Self(claim.clone()))
64 }
65}
66
67impl<F> ExpVerifier<F> for StaticBaseExpVerifier<F>
68where
69 F: BinaryField,
70{
71 fn exponent_bit_width(&self) -> usize {
72 self.0.exponent_bit_width
73 }
74
75 fn layer_claim_eval_point(&self) -> &[F] {
76 &self.0.eval_point
77 }
78
79 fn finish_layer(
80 &mut self,
81 evaluation_order: EvaluationOrder,
82 layer_no: usize,
83 multilinear_evals: &[F],
84 r: &[F],
85 ) -> Vec<LayerClaim<F>> {
86 let exponent_bit_claim = if self.is_last_layer(layer_no) {
87 let base = self.0.static_base.expect("static_base exist");
91
92 LayerClaim {
93 eval_point: self.0.eval_point.clone(),
94 eval: first_layer_inverse(self.0.eval, base),
95 }
96 } else {
97 let n_vars = self.layer_claim_eval_point().len();
98
99 let layer_eval = multilinear_evals[0];
100
101 let exponent_bit_eval = multilinear_evals[1];
102
103 let eval_point = match evaluation_order {
104 EvaluationOrder::LowToHigh => r[r.len() - n_vars..].to_vec(),
105 EvaluationOrder::HighToLow => r[..n_vars].to_vec(),
106 };
107
108 if !self.is_last_layer(layer_no) {
109 self.0.eval = layer_eval;
110 self.0.eval_point = eval_point.clone();
111 }
112
113 LayerClaim {
114 eval: exponent_bit_eval,
115 eval_point,
116 }
117 };
118
119 vec![exponent_bit_claim]
120 }
121
122 fn layer_composite_sum_claim(
123 &self,
124 layer_no: usize,
125 composite_claims_n_multilinears: usize,
126 multilinears_index: usize,
127 ) -> Result<Option<CompositeSumClaim<F, IndexedExpComposition<F>>>, Error> {
128 if self.is_last_layer(layer_no) {
129 Ok(None)
130 } else {
131 let internal_layer_index = self.exponent_bit_width() - 1 - layer_no;
132
133 let base_power_static = self
134 .0
135 .static_base
136 .expect("static_base exist")
137 .pow(1 << internal_layer_index);
138
139 let this_layer_input_index = multilinears_index;
140 let exponent_bit_index = multilinears_index + 1;
141
142 let composition = IndexComposition::new(
143 composite_claims_n_multilinears,
144 [this_layer_input_index, exponent_bit_index],
145 ExpCompositions::StaticBase { base_power_static },
146 )?;
147
148 let this_round_composite_claim = CompositeSumClaim {
149 sum: self.0.eval,
150 composition: FixedDimIndexCompositions::Bivariate(composition),
151 };
152
153 Ok(Some(this_round_composite_claim))
154 }
155 }
156
157 fn layer_n_multilinears(&self, layer_no: usize) -> usize {
158 if self.is_last_layer(layer_no) {
159 0
160 } else {
161 2
163 }
164 }
165
166 fn layer_n_claims(&self, layer_no: usize) -> usize {
167 if self.is_last_layer(layer_no) { 0 } else { 1 }
168 }
169}
170
171pub struct DynamicExpVerifier<F: Field>(ExpClaim<F>);
172
173impl<F: Field> DynamicExpVerifier<F> {
174 pub fn new(claim: &ExpClaim<F>) -> Result<Self, Error> {
175 if claim.static_base.is_some() {
176 bail!(Error::IncorrectWitnessType);
177 }
178
179 Ok(Self(claim.clone()))
180 }
181}
182
183impl<F: Field> ExpVerifier<F> for DynamicExpVerifier<F> {
184 fn exponent_bit_width(&self) -> usize {
185 self.0.exponent_bit_width
186 }
187
188 fn layer_claim_eval_point(&self) -> &[F] {
189 &self.0.eval_point
190 }
191
192 fn finish_layer(
193 &mut self,
194 evaluation_order: EvaluationOrder,
195 layer_no: usize,
196 multilinear_evals: &[F],
197 r: &[F],
198 ) -> Vec<LayerClaim<F>> {
199 let n_vars = self.layer_claim_eval_point().len();
200
201 let eval_point = match evaluation_order {
202 EvaluationOrder::LowToHigh => r[r.len() - n_vars..].to_vec(),
203 EvaluationOrder::HighToLow => r[..n_vars].to_vec(),
204 };
205
206 let mut claims = Vec::with_capacity(2);
207
208 let exponent_bit_eval = multilinear_evals[1];
209
210 let exponent_bit_claim = LayerClaim {
211 eval: exponent_bit_eval,
212 eval_point: eval_point.clone(),
213 };
214
215 claims.push(exponent_bit_claim);
216
217 if self.is_last_layer(layer_no) {
218 let base_eval = multilinear_evals[0];
219
220 let base_claim = LayerClaim {
221 eval: base_eval,
222 eval_point,
223 };
224 claims.push(base_claim)
225 } else {
226 let layer_eval = multilinear_evals[0];
227
228 self.0.eval = layer_eval;
229 self.0.eval_point = eval_point.clone();
230
231 let base_eval = multilinear_evals[2];
232
233 let base_claim = LayerClaim {
234 eval: base_eval,
235 eval_point,
236 };
237
238 claims.push(base_claim)
239 }
240
241 claims
242 }
243
244 fn layer_composite_sum_claim(
245 &self,
246 layer_no: usize,
247 composite_claims_n_multilinears: usize,
248 multilinears_index: usize,
249 ) -> Result<Option<CompositeSumClaim<F, IndexedExpComposition<F>>>, Error> {
250 let composition = if self.is_last_layer(layer_no) {
251 let base_index = multilinears_index;
252 let exponent_bit_index = multilinears_index + 1;
253
254 let composition = IndexComposition::new(
255 composite_claims_n_multilinears,
256 [base_index, exponent_bit_index],
257 ExpCompositions::DynamicBaseLastLayer,
258 )?;
259
260 FixedDimIndexCompositions::Bivariate(composition)
261 } else {
262 let this_layer_input_index = multilinears_index;
263 let exponent_bit_index = multilinears_index + 1;
264 let base_index = multilinears_index + 2;
265
266 let composition = IndexComposition::new(
267 composite_claims_n_multilinears,
268 [this_layer_input_index, exponent_bit_index, base_index],
269 ExpCompositions::DynamicBase,
270 )?;
271
272 FixedDimIndexCompositions::Trivariate(composition)
273 };
274
275 let this_round_composite_claim = CompositeSumClaim {
276 sum: self.0.eval,
277 composition,
278 };
279
280 Ok(Some(this_round_composite_claim))
281 }
282
283 fn layer_n_multilinears(&self, layer_no: usize) -> usize {
284 if self.is_last_layer(layer_no) {
285 2
287 } else {
288 3
290 }
291 }
292
293 fn layer_n_claims(&self, _layer_no: usize) -> usize {
294 1
295 }
296}