1use openvm_circuit::{
7 arch::{
8 AdapterAirContext, AdapterTraceExecutor, BasicAdapterInterface, ImmInstruction,
9 MinimalInstruction, VecHeapAdapterInterface, VecHeapBranchAdapterInterface, VmAdapterAir,
10 VmAdapterInterface,
11 },
12 system::memory::online::TracingMemory,
13};
14use openvm_circuit_primitives::ColumnsAir;
15use openvm_instructions::instruction::Instruction;
16use openvm_stark_backend::{
17 interaction::InteractionBuilder, p3_air::BaseAir, p3_field::PrimeField32,
18 BaseAirWithPublicValues,
19};
20
21#[derive(Clone, Copy, Debug, derive_new::new)]
39pub struct VecToFlatAluAdapterAir<
40 A,
41 const NUM_READS: usize,
42 const BLOCKS_PER_READ: usize,
43 const BLOCKS_PER_WRITE: usize,
44 const BLOCK_SIZE: usize,
45 const TOTAL_READ_SIZE: usize,
46 const TOTAL_WRITE_SIZE: usize,
47>(pub A);
48
49impl<
50 F,
51 A,
52 const NUM_READS: usize,
53 const BLOCKS_PER_READ: usize,
54 const BLOCKS_PER_WRITE: usize,
55 const BLOCK_SIZE: usize,
56 const TOTAL_READ_SIZE: usize,
57 const TOTAL_WRITE_SIZE: usize,
58 > BaseAir<F>
59 for VecToFlatAluAdapterAir<
60 A,
61 NUM_READS,
62 BLOCKS_PER_READ,
63 BLOCKS_PER_WRITE,
64 BLOCK_SIZE,
65 TOTAL_READ_SIZE,
66 TOTAL_WRITE_SIZE,
67 >
68where
69 A: BaseAir<F>,
70{
71 fn width(&self) -> usize {
72 self.0.width()
73 }
74}
75
76impl<
77 A,
78 const NUM_READS: usize,
79 const BLOCKS_PER_READ: usize,
80 const BLOCKS_PER_WRITE: usize,
81 const BLOCK_SIZE: usize,
82 const TOTAL_READ_SIZE: usize,
83 const TOTAL_WRITE_SIZE: usize,
84 > ColumnsAir
85 for VecToFlatAluAdapterAir<
86 A,
87 NUM_READS,
88 BLOCKS_PER_READ,
89 BLOCKS_PER_WRITE,
90 BLOCK_SIZE,
91 TOTAL_READ_SIZE,
92 TOTAL_WRITE_SIZE,
93 >
94where
95 A: ColumnsAir,
96{
97 fn columns(&self) -> Option<Vec<String>> {
98 self.0.columns()
99 }
100}
101
102impl<
103 AB,
104 A,
105 const NUM_READS: usize,
106 const BLOCKS_PER_READ: usize,
107 const BLOCKS_PER_WRITE: usize,
108 const BLOCK_SIZE: usize,
109 const TOTAL_READ_SIZE: usize,
110 const TOTAL_WRITE_SIZE: usize,
111 > VmAdapterAir<AB>
112 for VecToFlatAluAdapterAir<
113 A,
114 NUM_READS,
115 BLOCKS_PER_READ,
116 BLOCKS_PER_WRITE,
117 BLOCK_SIZE,
118 TOTAL_READ_SIZE,
119 TOTAL_WRITE_SIZE,
120 >
121where
122 AB: InteractionBuilder,
123 A: VmAdapterAir<
124 AB,
125 Interface = VecHeapAdapterInterface<
126 AB::Expr,
127 NUM_READS,
128 BLOCKS_PER_READ,
129 BLOCKS_PER_WRITE,
130 BLOCK_SIZE,
131 BLOCK_SIZE,
132 >,
133 >,
134{
135 type Interface = BasicAdapterInterface<
136 AB::Expr,
137 MinimalInstruction<AB::Expr>,
138 NUM_READS,
139 1,
140 TOTAL_READ_SIZE,
141 TOTAL_WRITE_SIZE,
142 >;
143
144 fn eval(
145 &self,
146 builder: &mut AB,
147 local: &[AB::Var],
148 ctx: AdapterAirContext<AB::Expr, Self::Interface>,
149 ) {
150 assert_eq!(
152 TOTAL_READ_SIZE,
153 BLOCKS_PER_READ * BLOCK_SIZE,
154 "TOTAL_READ_SIZE must equal BLOCKS_PER_READ * BLOCK_SIZE"
155 );
156 assert_eq!(
157 TOTAL_WRITE_SIZE,
158 BLOCKS_PER_WRITE * BLOCK_SIZE,
159 "TOTAL_WRITE_SIZE must equal BLOCKS_PER_WRITE * BLOCK_SIZE"
160 );
161
162 type InnerI<T, const NR: usize, const BPR: usize, const BPW: usize, const BS: usize> =
163 VecHeapAdapterInterface<T, NR, BPR, BPW, BS, BS>;
164
165 let inner_reads: <InnerI<
166 AB::Expr,
167 NUM_READS,
168 BLOCKS_PER_READ,
169 BLOCKS_PER_WRITE,
170 BLOCK_SIZE,
171 > as VmAdapterInterface<AB::Expr>>::Reads = core::array::from_fn(|read_i| {
172 core::array::from_fn(|block_i| {
173 core::array::from_fn(|in_block_i| {
174 let byte_i = block_i * BLOCK_SIZE + in_block_i;
175 ctx.reads[read_i][byte_i].clone()
176 })
177 })
178 });
179
180 let inner_writes: <InnerI<
181 AB::Expr,
182 NUM_READS,
183 BLOCKS_PER_READ,
184 BLOCKS_PER_WRITE,
185 BLOCK_SIZE,
186 > as VmAdapterInterface<AB::Expr>>::Writes = core::array::from_fn(|block_i| {
187 core::array::from_fn(|in_block_i| {
188 let byte_i = block_i * BLOCK_SIZE + in_block_i;
189 ctx.writes[0][byte_i].clone()
190 })
191 });
192
193 let inner_ctx: AdapterAirContext<
194 AB::Expr,
195 InnerI<AB::Expr, NUM_READS, BLOCKS_PER_READ, BLOCKS_PER_WRITE, BLOCK_SIZE>,
196 > = AdapterAirContext {
197 to_pc: ctx.to_pc,
198 reads: inner_reads,
199 writes: inner_writes,
200 instruction: ctx.instruction,
201 };
202
203 self.0.eval(builder, local, inner_ctx)
204 }
205
206 fn get_from_pc(&self, local: &[AB::Var]) -> AB::Var {
207 self.0.get_from_pc(local)
208 }
209}
210
211impl<
212 F,
213 A,
214 const NUM_READS: usize,
215 const BLOCKS_PER_READ: usize,
216 const BLOCKS_PER_WRITE: usize,
217 const BLOCK_SIZE: usize,
218 const TOTAL_READ_SIZE: usize,
219 const TOTAL_WRITE_SIZE: usize,
220 > BaseAirWithPublicValues<F>
221 for VecToFlatAluAdapterAir<
222 A,
223 NUM_READS,
224 BLOCKS_PER_READ,
225 BLOCKS_PER_WRITE,
226 BLOCK_SIZE,
227 TOTAL_READ_SIZE,
228 TOTAL_WRITE_SIZE,
229 >
230where
231 A: BaseAirWithPublicValues<F>,
232{
233 fn num_public_values(&self) -> usize {
234 self.0.num_public_values()
235 }
236}
237
238#[derive(Clone, Copy, Debug, derive_new::new)]
240pub struct VecToFlatAluAdapterExecutor<
241 A,
242 const NUM_READS: usize,
243 const BLOCKS_PER_READ: usize,
244 const BLOCKS_PER_WRITE: usize,
245 const BLOCK_SIZE: usize,
246 const TOTAL_READ_SIZE: usize,
247 const TOTAL_WRITE_SIZE: usize,
248>(pub A);
249
250impl<
251 F,
252 A,
253 const NUM_READS: usize,
254 const BLOCKS_PER_READ: usize,
255 const BLOCKS_PER_WRITE: usize,
256 const BLOCK_SIZE: usize,
257 const TOTAL_READ_SIZE: usize,
258 const TOTAL_WRITE_SIZE: usize,
259 > AdapterTraceExecutor<F>
260 for VecToFlatAluAdapterExecutor<
261 A,
262 NUM_READS,
263 BLOCKS_PER_READ,
264 BLOCKS_PER_WRITE,
265 BLOCK_SIZE,
266 TOTAL_READ_SIZE,
267 TOTAL_WRITE_SIZE,
268 >
269where
270 F: PrimeField32,
271 A: AdapterTraceExecutor<
272 F,
273 ReadData = [[[u8; BLOCK_SIZE]; BLOCKS_PER_READ]; NUM_READS],
274 WriteData = [[u8; BLOCK_SIZE]; BLOCKS_PER_WRITE],
275 >,
276{
277 const WIDTH: usize = A::WIDTH;
278 type ReadData = [[u8; TOTAL_READ_SIZE]; NUM_READS];
279 type WriteData = [[u8; TOTAL_WRITE_SIZE]; 1];
280 type RecordMut<'a>
281 = A::RecordMut<'a>
282 where
283 Self: 'a;
284
285 #[inline(always)]
286 fn start(pc: u32, memory: &TracingMemory, record: &mut Self::RecordMut<'_>) {
287 A::start(pc, memory, record);
288 }
289
290 #[inline(always)]
291 fn read(
292 &self,
293 memory: &mut TracingMemory,
294 instruction: &Instruction<F>,
295 record: &mut Self::RecordMut<'_>,
296 ) -> Self::ReadData {
297 let data_inner = <A as AdapterTraceExecutor<F>>::read(&self.0, memory, instruction, record);
298
299 core::array::from_fn(|i| {
300 let mut out = [0u8; TOTAL_READ_SIZE];
301 for (block_idx, block) in data_inner[i].iter().enumerate() {
302 let start = block_idx * BLOCK_SIZE;
303 out[start..start + BLOCK_SIZE].copy_from_slice(&block[..]);
304 }
305 out
306 })
307 }
308
309 #[inline(always)]
310 fn write(
311 &self,
312 memory: &mut TracingMemory,
313 instruction: &Instruction<F>,
314 data: Self::WriteData,
315 record: &mut Self::RecordMut<'_>,
316 ) {
317 let data_inner: <A as AdapterTraceExecutor<F>>::WriteData = core::array::from_fn(|i| {
318 let start = i * BLOCK_SIZE;
319 data[0][start..start + BLOCK_SIZE]
320 .try_into()
321 .expect("slice length matches BLOCK_SIZE")
322 });
323
324 <A as AdapterTraceExecutor<F>>::write(&self.0, memory, instruction, data_inner, record);
325 }
326}
327
328#[derive(Clone, Copy, Debug, derive_new::new)]
345pub struct VecToFlatBranchAdapterAir<
346 A,
347 const NUM_READS: usize,
348 const BLOCKS_PER_READ: usize,
349 const BLOCK_SIZE: usize,
350 const TOTAL_READ_SIZE: usize,
351>(pub A);
352
353impl<
354 F,
355 A,
356 const NUM_READS: usize,
357 const BLOCKS_PER_READ: usize,
358 const BLOCK_SIZE: usize,
359 const TOTAL_READ_SIZE: usize,
360 > BaseAir<F>
361 for VecToFlatBranchAdapterAir<A, NUM_READS, BLOCKS_PER_READ, BLOCK_SIZE, TOTAL_READ_SIZE>
362where
363 A: BaseAir<F>,
364{
365 fn width(&self) -> usize {
366 self.0.width()
367 }
368}
369
370impl<
371 A,
372 const NUM_READS: usize,
373 const BLOCKS_PER_READ: usize,
374 const BLOCK_SIZE: usize,
375 const TOTAL_READ_SIZE: usize,
376 > ColumnsAir
377 for VecToFlatBranchAdapterAir<A, NUM_READS, BLOCKS_PER_READ, BLOCK_SIZE, TOTAL_READ_SIZE>
378where
379 A: ColumnsAir,
380{
381 fn columns(&self) -> Option<Vec<String>> {
382 self.0.columns()
383 }
384}
385
386impl<
387 AB,
388 A,
389 const NUM_READS: usize,
390 const BLOCKS_PER_READ: usize,
391 const BLOCK_SIZE: usize,
392 const TOTAL_READ_SIZE: usize,
393 > VmAdapterAir<AB>
394 for VecToFlatBranchAdapterAir<A, NUM_READS, BLOCKS_PER_READ, BLOCK_SIZE, TOTAL_READ_SIZE>
395where
396 AB: InteractionBuilder,
397 A: VmAdapterAir<
398 AB,
399 Interface = VecHeapBranchAdapterInterface<AB::Expr, NUM_READS, BLOCKS_PER_READ, BLOCK_SIZE>,
400 >,
401{
402 type Interface =
403 BasicAdapterInterface<AB::Expr, ImmInstruction<AB::Expr>, NUM_READS, 0, TOTAL_READ_SIZE, 0>;
404
405 fn eval(
406 &self,
407 builder: &mut AB,
408 local: &[AB::Var],
409 ctx: AdapterAirContext<AB::Expr, Self::Interface>,
410 ) {
411 assert_eq!(
413 TOTAL_READ_SIZE,
414 BLOCKS_PER_READ * BLOCK_SIZE,
415 "TOTAL_READ_SIZE must equal BLOCKS_PER_READ * BLOCK_SIZE"
416 );
417
418 type InnerI<T, const NR: usize, const BPR: usize, const BS: usize> =
419 VecHeapBranchAdapterInterface<T, NR, BPR, BS>;
420
421 let inner_reads: <InnerI<AB::Expr, NUM_READS, BLOCKS_PER_READ, BLOCK_SIZE> as VmAdapterInterface<AB::Expr>>::Reads =
422 core::array::from_fn(|read_i| {
423 core::array::from_fn(|block_i| {
424 core::array::from_fn(|in_block_i| {
425 let byte_i = block_i * BLOCK_SIZE + in_block_i;
426 ctx.reads[read_i][byte_i].clone()
427 })
428 })
429 });
430
431 let inner_ctx: AdapterAirContext<
432 AB::Expr,
433 InnerI<AB::Expr, NUM_READS, BLOCKS_PER_READ, BLOCK_SIZE>,
434 > = AdapterAirContext {
435 to_pc: ctx.to_pc,
436 reads: inner_reads,
437 writes: (),
438 instruction: ctx.instruction,
439 };
440
441 self.0.eval(builder, local, inner_ctx)
442 }
443
444 fn get_from_pc(&self, local: &[AB::Var]) -> AB::Var {
445 self.0.get_from_pc(local)
446 }
447}
448
449impl<
450 F,
451 A,
452 const NUM_READS: usize,
453 const BLOCKS_PER_READ: usize,
454 const BLOCK_SIZE: usize,
455 const TOTAL_READ_SIZE: usize,
456 > BaseAirWithPublicValues<F>
457 for VecToFlatBranchAdapterAir<A, NUM_READS, BLOCKS_PER_READ, BLOCK_SIZE, TOTAL_READ_SIZE>
458where
459 A: BaseAirWithPublicValues<F>,
460{
461 fn num_public_values(&self) -> usize {
462 self.0.num_public_values()
463 }
464}
465
466#[derive(Clone, Copy, Debug, derive_new::new)]
469pub struct VecToFlatBranchAdapterExecutor<
470 A,
471 const NUM_READS: usize,
472 const BLOCKS_PER_READ: usize,
473 const BLOCK_SIZE: usize,
474 const TOTAL_READ_SIZE: usize,
475>(pub A);
476
477impl<
478 F,
479 A,
480 const NUM_READS: usize,
481 const BLOCKS_PER_READ: usize,
482 const BLOCK_SIZE: usize,
483 const TOTAL_READ_SIZE: usize,
484 > AdapterTraceExecutor<F>
485 for VecToFlatBranchAdapterExecutor<A, NUM_READS, BLOCKS_PER_READ, BLOCK_SIZE, TOTAL_READ_SIZE>
486where
487 F: PrimeField32,
488 A: AdapterTraceExecutor<
489 F,
490 ReadData = [[[u8; BLOCK_SIZE]; BLOCKS_PER_READ]; NUM_READS],
491 WriteData = (),
492 >,
493{
494 const WIDTH: usize = A::WIDTH;
495 type ReadData = [[u8; TOTAL_READ_SIZE]; NUM_READS];
496 type WriteData = ();
497 type RecordMut<'a>
498 = A::RecordMut<'a>
499 where
500 Self: 'a;
501
502 #[inline(always)]
503 fn start(pc: u32, memory: &TracingMemory, record: &mut Self::RecordMut<'_>) {
504 A::start(pc, memory, record);
505 }
506
507 #[inline(always)]
508 fn read(
509 &self,
510 memory: &mut TracingMemory,
511 instruction: &Instruction<F>,
512 record: &mut Self::RecordMut<'_>,
513 ) -> Self::ReadData {
514 let data_inner = <A as AdapterTraceExecutor<F>>::read(&self.0, memory, instruction, record);
515
516 core::array::from_fn(|i| {
517 let mut out = [0u8; TOTAL_READ_SIZE];
518 for (block_idx, block) in data_inner[i].iter().enumerate() {
519 let start = block_idx * BLOCK_SIZE;
520 out[start..start + BLOCK_SIZE].copy_from_slice(&block[..]);
521 }
522 out
523 })
524 }
525
526 #[inline(always)]
527 fn write(
528 &self,
529 _memory: &mut TracingMemory,
530 _instruction: &Instruction<F>,
531 _data: Self::WriteData,
532 _record: &mut Self::RecordMut<'_>,
533 ) {
534 }
536}