1use alloc::vec::Vec;
2use core::ops::{
3 Add,
4 Mul,
5 Sub,
6};
7
8use lib_q_stark_field::{
9 Algebra,
10 ExtensionField,
11 Field,
12 PrimeCharacteristicRing,
13};
14use lib_q_stark_matrix::dense::{
15 RowMajorMatrix,
16 RowMajorMatrixView,
17};
18
19pub trait WindowAccess<T> {
24 fn current_slice(&self) -> &[T];
25 fn next_slice(&self) -> &[T];
26
27 #[inline]
28 fn current(&self, i: usize) -> Option<T>
29 where
30 T: Clone,
31 {
32 self.current_slice().get(i).cloned()
33 }
34
35 #[inline]
36 fn next(&self, i: usize) -> Option<T>
37 where
38 T: Clone,
39 {
40 self.next_slice().get(i).cloned()
41 }
42}
43
44#[derive(Debug, Clone, Copy)]
49pub struct RowWindow<'a, T> {
50 current: &'a [T],
51 next: &'a [T],
52}
53
54impl<'a, T> RowWindow<'a, T> {
55 #[inline]
62 pub fn from_view(view: &RowMajorMatrixView<'a, T>) -> Self {
63 let width = view.width;
64 assert_eq!(
65 view.values.len(),
66 2 * width,
67 "RowWindow::from_view: expected 2 rows (2*{width} elements), got {}",
68 view.values.len()
69 );
70 let (current, next) = view.values.split_at(width);
71 Self { current, next }
72 }
73
74 #[inline]
80 pub fn from_two_rows(current: &'a [T], next: &'a [T]) -> Self {
81 debug_assert_eq!(
82 current.len(),
83 next.len(),
84 "RowWindow::from_two_rows: row lengths differ ({} vs {})",
85 current.len(),
86 next.len()
87 );
88 Self { current, next }
89 }
90}
91
92impl<T> WindowAccess<T> for RowWindow<'_, T> {
93 #[inline]
94 fn current_slice(&self) -> &[T] {
95 self.current
96 }
97
98 #[inline]
99 fn next_slice(&self) -> &[T] {
100 self.next
101 }
102}
103
104pub trait BaseAir<F>: Sync {
106 fn width(&self) -> usize;
108
109 fn preprocessed_trace(&self) -> Option<RowMajorMatrix<F>> {
111 None
112 }
113
114 fn main_next_row_columns(&self) -> Vec<usize> {
124 (0..self.width()).collect()
125 }
126
127 fn preprocessed_next_row_columns(&self) -> Vec<usize> {
129 self.preprocessed_trace()
130 .map(|t| (0..t.width).collect())
131 .unwrap_or_default()
132 }
133
134 fn num_constraints(&self) -> Option<usize> {
137 None
138 }
139
140 fn max_constraint_degree(&self) -> Option<usize> {
143 None
144 }
145
146 fn num_public_values(&self) -> usize {
148 0
149 }
150}
151
152pub trait Air<AB: AirBuilder>: BaseAir<AB::F> {
157 fn eval(&self, builder: &mut AB);
158}
159
160pub trait AirBuilder: Sized {
166 type F: PrimeCharacteristicRing + Sync;
168
169 type Expr: Algebra<Self::F> + Algebra<Self::Var>;
171
172 type Var: Into<Self::Expr>
174 + Copy
175 + Send
176 + Sync
177 + Add<Self::F, Output = Self::Expr>
178 + Add<Self::Var, Output = Self::Expr>
179 + Add<Self::Expr, Output = Self::Expr>
180 + Sub<Self::F, Output = Self::Expr>
181 + Sub<Self::Var, Output = Self::Expr>
182 + Sub<Self::Expr, Output = Self::Expr>
183 + Mul<Self::F, Output = Self::Expr>
184 + Mul<Self::Var, Output = Self::Expr>
185 + Mul<Self::Expr, Output = Self::Expr>;
186
187 type PreprocessedWindow: WindowAccess<Self::Var> + Clone;
189
190 type MainWindow: WindowAccess<Self::Var> + Clone;
192
193 type PublicVar: Into<Self::Expr> + Copy;
195
196 fn main(&self) -> Self::MainWindow;
198
199 fn preprocessed(&self) -> &Self::PreprocessedWindow;
201
202 fn is_first_row(&self) -> Self::Expr;
204
205 fn is_last_row(&self) -> Self::Expr;
207
208 fn is_transition(&self) -> Self::Expr {
210 self.is_transition_window(2)
211 }
212
213 fn is_transition_window(&self, size: usize) -> Self::Expr;
215
216 fn when<I: Into<Self::Expr>>(&mut self, condition: I) -> FilteredAirBuilder<'_, Self> {
218 FilteredAirBuilder {
219 inner: self,
220 condition: condition.into(),
221 }
222 }
223
224 fn when_ne<I1: Into<Self::Expr>, I2: Into<Self::Expr>>(
226 &mut self,
227 x: I1,
228 y: I2,
229 ) -> FilteredAirBuilder<'_, Self> {
230 self.when(x.into() - y.into())
231 }
232
233 fn when_first_row(&mut self) -> FilteredAirBuilder<'_, Self> {
235 self.when(self.is_first_row())
236 }
237
238 fn when_last_row(&mut self) -> FilteredAirBuilder<'_, Self> {
240 self.when(self.is_last_row())
241 }
242
243 fn when_transition(&mut self) -> FilteredAirBuilder<'_, Self> {
245 self.when(self.is_transition())
246 }
247
248 fn when_transition_window(&mut self, size: usize) -> FilteredAirBuilder<'_, Self> {
250 self.when(self.is_transition_window(size))
251 }
252
253 fn assert_zero<I: Into<Self::Expr>>(&mut self, x: I);
255
256 fn assert_zeros<const N: usize, I: Into<Self::Expr>>(&mut self, array: [I; N]) {
258 for elem in array {
259 self.assert_zero(elem);
260 }
261 }
262
263 fn assert_bools<const N: usize, I: Into<Self::Expr>>(&mut self, array: [I; N]) {
265 let zero_array = array.map(|x| x.into().bool_check());
266 self.assert_zeros(zero_array);
267 }
268
269 fn assert_one<I: Into<Self::Expr>>(&mut self, x: I) {
271 self.assert_zero(x.into() - Self::Expr::ONE);
272 }
273
274 fn assert_eq<I1: Into<Self::Expr>, I2: Into<Self::Expr>>(&mut self, x: I1, y: I2) {
276 self.assert_zero(x.into() - y.into());
277 }
278
279 fn public_values(&self) -> &[Self::PublicVar] {
281 &[]
282 }
283
284 fn assert_bool<I: Into<Self::Expr>>(&mut self, x: I) {
286 self.assert_zero(x.into().bool_check());
287 }
288}
289
290pub trait PeriodicAirBuilder: AirBuilder {
292 type PeriodicVar: Into<Self::Expr> + Copy;
293 fn periodic_values(&self) -> &[Self::PeriodicVar];
294}
295
296pub trait AirBuilderWithContext: AirBuilder {
298 type EvalContext;
299 fn eval_context(&self) -> &Self::EvalContext;
300}
301
302pub trait ExtensionBuilder: AirBuilder<F: Field> {
304 type EF: ExtensionField<Self::F>;
306
307 type ExprEF: Algebra<Self::Expr> + Algebra<Self::EF>;
309
310 type VarEF: Into<Self::ExprEF> + Copy + Send + Sync;
312
313 fn assert_zero_ext<I>(&mut self, x: I)
315 where
316 I: Into<Self::ExprEF>;
317
318 fn assert_eq_ext<I1, I2>(&mut self, x: I1, y: I2)
320 where
321 I1: Into<Self::ExprEF>,
322 I2: Into<Self::ExprEF>,
323 {
324 self.assert_zero_ext(x.into() - y.into());
325 }
326
327 fn assert_one_ext<I>(&mut self, x: I)
329 where
330 I: Into<Self::ExprEF>,
331 {
332 self.assert_eq_ext(x, Self::ExprEF::ONE);
333 }
334}
335
336pub trait PermutationAirBuilder: ExtensionBuilder {
338 type MP: WindowAccess<Self::VarEF>;
340
341 type RandomVar: Into<Self::ExprEF> + Copy;
343
344 type PermutationVar: Into<Self::ExprEF> + Clone;
346
347 fn permutation(&self) -> Self::MP;
349
350 fn permutation_randomness(&self) -> &[Self::RandomVar];
352
353 fn permutation_values(&self) -> &[Self::PermutationVar];
355}
356
357#[derive(Debug)]
360pub struct FilteredAirBuilder<'a, AB: AirBuilder> {
361 pub inner: &'a mut AB,
362 condition: AB::Expr,
363}
364
365impl<AB: AirBuilder> FilteredAirBuilder<'_, AB> {
366 pub fn condition(&self) -> AB::Expr {
367 self.condition.clone()
368 }
369}
370
371impl<AB: AirBuilder> AirBuilder for FilteredAirBuilder<'_, AB> {
372 type F = AB::F;
373 type Expr = AB::Expr;
374 type Var = AB::Var;
375 type PreprocessedWindow = AB::PreprocessedWindow;
376 type MainWindow = AB::MainWindow;
377 type PublicVar = AB::PublicVar;
378
379 fn main(&self) -> Self::MainWindow {
380 self.inner.main()
381 }
382
383 fn preprocessed(&self) -> &Self::PreprocessedWindow {
384 self.inner.preprocessed()
385 }
386
387 fn is_first_row(&self) -> Self::Expr {
388 self.inner.is_first_row()
389 }
390
391 fn is_last_row(&self) -> Self::Expr {
392 self.inner.is_last_row()
393 }
394
395 fn is_transition(&self) -> Self::Expr {
396 self.inner.is_transition()
397 }
398
399 fn is_transition_window(&self, size: usize) -> Self::Expr {
400 self.inner.is_transition_window(size)
401 }
402
403 fn assert_zero<I: Into<Self::Expr>>(&mut self, x: I) {
404 self.inner.assert_zero(self.condition() * x.into());
405 }
406
407 fn public_values(&self) -> &[Self::PublicVar] {
408 self.inner.public_values()
409 }
410}
411
412impl<AB: PeriodicAirBuilder> PeriodicAirBuilder for FilteredAirBuilder<'_, AB> {
413 type PeriodicVar = AB::PeriodicVar;
414
415 fn periodic_values(&self) -> &[Self::PeriodicVar] {
416 self.inner.periodic_values()
417 }
418}
419
420impl<AB: ExtensionBuilder> ExtensionBuilder for FilteredAirBuilder<'_, AB> {
421 type EF = AB::EF;
422 type ExprEF = AB::ExprEF;
423 type VarEF = AB::VarEF;
424
425 fn assert_zero_ext<I>(&mut self, x: I)
426 where
427 I: Into<Self::ExprEF>,
428 {
429 let ext_x: Self::ExprEF = x.into();
430 let condition: AB::Expr = self.condition();
431 self.inner.assert_zero_ext(ext_x * condition);
432 }
433}
434
435impl<AB: PermutationAirBuilder> PermutationAirBuilder for FilteredAirBuilder<'_, AB> {
436 type MP = AB::MP;
437 type RandomVar = AB::RandomVar;
438 type PermutationVar = AB::PermutationVar;
439
440 fn permutation(&self) -> Self::MP {
441 self.inner.permutation()
442 }
443
444 fn permutation_randomness(&self) -> &[Self::RandomVar] {
445 self.inner.permutation_randomness()
446 }
447
448 fn permutation_values(&self) -> &[Self::PermutationVar] {
449 self.inner.permutation_values()
450 }
451}
452
453impl<AB: AirBuilderWithContext> AirBuilderWithContext for FilteredAirBuilder<'_, AB> {
454 type EvalContext = AB::EvalContext;
455
456 fn eval_context(&self) -> &Self::EvalContext {
457 self.inner.eval_context()
458 }
459}