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) {
168 0
169 } else {
170 1
171 }
172 }
173}
174
175pub struct DynamicExpVerifier<F: Field>(ExpClaim<F>);
176
177impl<F: Field> DynamicExpVerifier<F> {
178 pub fn new(claim: &ExpClaim<F>) -> Result<Self, Error> {
179 if claim.static_base.is_some() {
180 bail!(Error::IncorrectWitnessType);
181 }
182
183 Ok(Self(claim.clone()))
184 }
185}
186
187impl<F: Field> ExpVerifier<F> for DynamicExpVerifier<F> {
188 fn exponent_bit_width(&self) -> usize {
189 self.0.exponent_bit_width
190 }
191
192 fn layer_claim_eval_point(&self) -> &[F] {
193 &self.0.eval_point
194 }
195
196 fn finish_layer(
197 &mut self,
198 evaluation_order: EvaluationOrder,
199 layer_no: usize,
200 multilinear_evals: &[F],
201 r: &[F],
202 ) -> Vec<LayerClaim<F>> {
203 let n_vars = self.layer_claim_eval_point().len();
204
205 let eval_point = match evaluation_order {
206 EvaluationOrder::LowToHigh => r[r.len() - n_vars..].to_vec(),
207 EvaluationOrder::HighToLow => r[..n_vars].to_vec(),
208 };
209
210 let mut claims = Vec::with_capacity(2);
211
212 let exponent_bit_eval = multilinear_evals[1];
213
214 let exponent_bit_claim = LayerClaim {
215 eval: exponent_bit_eval,
216 eval_point: eval_point.clone(),
217 };
218
219 claims.push(exponent_bit_claim);
220
221 if self.is_last_layer(layer_no) {
222 let base_eval = multilinear_evals[0];
223
224 let base_claim = LayerClaim {
225 eval: base_eval,
226 eval_point,
227 };
228 claims.push(base_claim)
229 } else {
230 let layer_eval = multilinear_evals[0];
231
232 self.0.eval = layer_eval;
233 self.0.eval_point = eval_point.clone();
234
235 let base_eval = multilinear_evals[2];
236
237 let base_claim = LayerClaim {
238 eval: base_eval,
239 eval_point,
240 };
241
242 claims.push(base_claim)
243 }
244
245 claims
246 }
247
248 fn layer_composite_sum_claim(
249 &self,
250 layer_no: usize,
251 composite_claims_n_multilinears: usize,
252 multilinears_index: usize,
253 ) -> Result<Option<CompositeSumClaim<F, IndexedExpComposition<F>>>, Error> {
254 let composition = if self.is_last_layer(layer_no) {
255 let base_index = multilinears_index;
256 let exponent_bit_index = multilinears_index + 1;
257
258 let composition = IndexComposition::new(
259 composite_claims_n_multilinears,
260 [base_index, exponent_bit_index],
261 ExpCompositions::DynamicBaseLastLayer,
262 )?;
263
264 FixedDimIndexCompositions::Bivariate(composition)
265 } else {
266 let this_layer_input_index = multilinears_index;
267 let exponent_bit_index = multilinears_index + 1;
268 let base_index = multilinears_index + 2;
269
270 let composition = IndexComposition::new(
271 composite_claims_n_multilinears,
272 [this_layer_input_index, exponent_bit_index, base_index],
273 ExpCompositions::DynamicBase,
274 )?;
275
276 FixedDimIndexCompositions::Trivariate(composition)
277 };
278
279 let this_round_composite_claim = CompositeSumClaim {
280 sum: self.0.eval,
281 composition,
282 };
283
284 Ok(Some(this_round_composite_claim))
285 }
286
287 fn layer_n_multilinears(&self, layer_no: usize) -> usize {
288 if self.is_last_layer(layer_no) {
289 2
291 } else {
292 3
294 }
295 }
296
297 fn layer_n_claims(&self, _layer_no: usize) -> usize {
298 1
299 }
300}