1use std::sync::Arc;
2
3use derive_more::derive::From;
4use openvm_bigint_transpiler::{
5 Rv32BaseAlu256Opcode, Rv32BranchEqual256Opcode, Rv32BranchLessThan256Opcode,
6 Rv32LessThan256Opcode, Rv32Mul256Opcode, Rv32Shift256Opcode,
7};
8use openvm_circuit::{
9 arch::{
10 AirInventory, AirInventoryError, ChipInventory, ChipInventoryError, ExecutionBridge,
11 ExecutorInventoryBuilder, ExecutorInventoryError, MatrixRecordArena, RowMajorMatrixArena,
12 VmBuilder, VmChipComplex, VmCircuitExtension, VmExecutionExtension, VmField,
13 VmProverExtension,
14 },
15 system::{memory::SharedMemoryHelper, SystemChipInventory, SystemCpuBuilder, SystemPort},
16};
17use openvm_circuit_derive::{AnyEnum, Executor, MeteredExecutor, PreflightExecutor};
18use openvm_circuit_primitives::{
19 bitwise_op_lookup::{
20 BitwiseOperationLookupAir, BitwiseOperationLookupBus, BitwiseOperationLookupChip,
21 SharedBitwiseOperationLookupChip,
22 },
23 range_tuple::{
24 RangeTupleCheckerAir, RangeTupleCheckerBus, RangeTupleCheckerChip,
25 SharedRangeTupleCheckerChip,
26 },
27};
28use openvm_cpu_backend::{CpuBackend, CpuDevice};
29use openvm_instructions::{program::DEFAULT_PC_STEP, LocalOpcode};
30use openvm_rv32_adapters::{
31 Rv32VecHeapAdapterAir, Rv32VecHeapAdapterExecutor, Rv32VecHeapAdapterFiller,
32 Rv32VecHeapBranchAdapterAir, Rv32VecHeapBranchAdapterExecutor, Rv32VecHeapBranchAdapterFiller,
33};
34use openvm_rv32im_circuit::Rv32ImCpuProverExt;
35use openvm_stark_backend::{p3_field::PrimeField32, StarkEngine, StarkProtocolConfig, Val};
36use serde::{Deserialize, Serialize};
37
38use crate::{AluAdapterAir, AluAdapterExecutor, BranchAdapterAir, BranchAdapterExecutor, *};
39
40cfg_if::cfg_if! {
41 if #[cfg(feature = "cuda")] {
42 mod cuda;
43 pub use self::cuda::*;
44 pub use self::cuda::{
45 Int256GpuProverExt as Int256ProverExt,
46 Int256Rv32GpuBuilder as Int256Rv32Builder,
47 };
48 } else {
49 pub use self::{
50 Int256CpuProverExt as Int256ProverExt,
51 Int256Rv32CpuBuilder as Int256Rv32Builder,
52 };
53 }
54}
55
56#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
58pub struct Int256 {
59 #[serde(default = "default_range_tuple_checker_sizes")]
60 pub range_tuple_checker_sizes: [u32; 2],
61}
62
63impl Default for Int256 {
64 fn default() -> Self {
65 Self {
66 range_tuple_checker_sizes: default_range_tuple_checker_sizes(),
67 }
68 }
69}
70
71fn default_range_tuple_checker_sizes() -> [u32; 2] {
72 [1 << 8, 32 * (1 << 8)]
73}
74
75#[derive(Clone, From, AnyEnum, Executor, MeteredExecutor, PreflightExecutor)]
76#[cfg_attr(
77 feature = "aot",
78 derive(
79 openvm_circuit_derive::AotExecutor,
80 openvm_circuit_derive::AotMeteredExecutor
81 )
82)]
83pub enum Int256Executor {
84 BaseAlu256(Rv32BaseAlu256Executor),
85 LessThan256(Rv32LessThan256Executor),
86 BranchEqual256(Rv32BranchEqual256Executor),
87 BranchLessThan256(Rv32BranchLessThan256Executor),
88 Multiplication256(Rv32Multiplication256Executor),
89 Shift256(Rv32Shift256Executor),
90}
91
92impl<F: PrimeField32> VmExecutionExtension<F> for Int256 {
93 type Executor = Int256Executor;
94
95 fn extend_execution(
96 &self,
97 inventory: &mut ExecutorInventoryBuilder<F, Int256Executor>,
98 ) -> Result<(), ExecutorInventoryError> {
99 let pointer_max_bits = inventory.pointer_max_bits();
100
101 let alu = Rv32BaseAlu256Executor::new(
102 AluAdapterExecutor::new(Rv32VecHeapAdapterExecutor::new(pointer_max_bits)),
103 Rv32BaseAlu256Opcode::CLASS_OFFSET,
104 );
105 inventory.add_executor(alu, Rv32BaseAlu256Opcode::iter().map(|x| x.global_opcode()))?;
106
107 let lt = Rv32LessThan256Executor::new(
108 AluAdapterExecutor::new(Rv32VecHeapAdapterExecutor::new(pointer_max_bits)),
109 Rv32LessThan256Opcode::CLASS_OFFSET,
110 );
111 inventory.add_executor(lt, Rv32LessThan256Opcode::iter().map(|x| x.global_opcode()))?;
112
113 let beq = Rv32BranchEqual256Executor::new(
117 BranchAdapterExecutor::new(Rv32VecHeapBranchAdapterExecutor::new(pointer_max_bits)),
118 Rv32BranchEqual256Opcode::CLASS_OFFSET,
119 DEFAULT_PC_STEP,
120 );
121 inventory.add_executor(
122 beq,
123 Rv32BranchEqual256Opcode::iter().map(|x| x.global_opcode()),
124 )?;
125
126 let blt = Rv32BranchLessThan256Executor::new(
127 BranchAdapterExecutor::new(Rv32VecHeapBranchAdapterExecutor::new(pointer_max_bits)),
128 Rv32BranchLessThan256Opcode::CLASS_OFFSET,
129 );
130 inventory.add_executor(
131 blt,
132 Rv32BranchLessThan256Opcode::iter().map(|x| x.global_opcode()),
133 )?;
134
135 let mult = Rv32Multiplication256Executor::new(
136 AluAdapterExecutor::new(Rv32VecHeapAdapterExecutor::new(pointer_max_bits)),
137 Rv32Mul256Opcode::CLASS_OFFSET,
138 );
139 inventory.add_executor(mult, Rv32Mul256Opcode::iter().map(|x| x.global_opcode()))?;
140
141 let shift = Rv32Shift256Executor::new(
142 AluAdapterExecutor::new(Rv32VecHeapAdapterExecutor::new(pointer_max_bits)),
143 Rv32Shift256Opcode::CLASS_OFFSET,
144 );
145 inventory.add_executor(shift, Rv32Shift256Opcode::iter().map(|x| x.global_opcode()))?;
146
147 Ok(())
148 }
149}
150
151impl<SC: StarkProtocolConfig> VmCircuitExtension<SC> for Int256 {
152 fn extend_circuit(&self, inventory: &mut AirInventory<SC>) -> Result<(), AirInventoryError> {
153 let SystemPort {
154 execution_bus,
155 program_bus,
156 memory_bridge,
157 } = inventory.system().port();
158
159 let exec_bridge = ExecutionBridge::new(execution_bus, program_bus);
160 let range_checker = inventory.range_checker().bus;
161 let pointer_max_bits = inventory.pointer_max_bits();
162
163 let bitwise_lu = {
164 let existing_air = inventory.find_air::<BitwiseOperationLookupAir<8>>().next();
166 if let Some(air) = existing_air {
167 air.bus
168 } else {
169 let bus = BitwiseOperationLookupBus::new(inventory.new_bus_idx());
170 let air = BitwiseOperationLookupAir::<8>::new(bus);
171 inventory.add_air(air);
172 air.bus
173 }
174 };
175
176 let range_tuple_checker = {
177 let existing_air = inventory.find_air::<RangeTupleCheckerAir<2>>().find(|c| {
178 c.bus.sizes[0] >= self.range_tuple_checker_sizes[0]
179 && c.bus.sizes[1] >= self.range_tuple_checker_sizes[1]
180 });
181 if let Some(air) = existing_air {
182 air.bus
183 } else {
184 let bus = RangeTupleCheckerBus::new(
185 inventory.new_bus_idx(),
186 self.range_tuple_checker_sizes,
187 );
188 let air = RangeTupleCheckerAir { bus };
189 inventory.add_air(air);
190 air.bus
191 }
192 };
193
194 let alu = Rv32BaseAlu256Air::new(
195 AluAdapterAir::new(Rv32VecHeapAdapterAir::new(
196 exec_bridge,
197 memory_bridge,
198 bitwise_lu,
199 pointer_max_bits,
200 )),
201 BaseAluCoreAir::new(bitwise_lu, Rv32BaseAlu256Opcode::CLASS_OFFSET),
202 );
203 inventory.add_air(alu);
204
205 let lt = Rv32LessThan256Air::new(
206 AluAdapterAir::new(Rv32VecHeapAdapterAir::new(
207 exec_bridge,
208 memory_bridge,
209 bitwise_lu,
210 pointer_max_bits,
211 )),
212 LessThanCoreAir::new(bitwise_lu, Rv32LessThan256Opcode::CLASS_OFFSET),
213 );
214 inventory.add_air(lt);
215
216 let beq = Rv32BranchEqual256Air::new(
217 BranchAdapterAir::new(Rv32VecHeapBranchAdapterAir::new(
218 exec_bridge,
219 memory_bridge,
220 bitwise_lu,
221 pointer_max_bits,
222 )),
223 BranchEqualCoreAir::new(Rv32BranchEqual256Opcode::CLASS_OFFSET, DEFAULT_PC_STEP),
224 );
225 inventory.add_air(beq);
226
227 let blt = Rv32BranchLessThan256Air::new(
228 BranchAdapterAir::new(Rv32VecHeapBranchAdapterAir::new(
229 exec_bridge,
230 memory_bridge,
231 bitwise_lu,
232 pointer_max_bits,
233 )),
234 BranchLessThanCoreAir::new(bitwise_lu, Rv32BranchLessThan256Opcode::CLASS_OFFSET),
235 );
236 inventory.add_air(blt);
237
238 let mult = Rv32Multiplication256Air::new(
239 AluAdapterAir::new(Rv32VecHeapAdapterAir::new(
240 exec_bridge,
241 memory_bridge,
242 bitwise_lu,
243 pointer_max_bits,
244 )),
245 MultiplicationCoreAir::new(range_tuple_checker, Rv32Mul256Opcode::CLASS_OFFSET),
246 );
247 inventory.add_air(mult);
248
249 let shift = Rv32Shift256Air::new(
250 AluAdapterAir::new(Rv32VecHeapAdapterAir::new(
251 exec_bridge,
252 memory_bridge,
253 bitwise_lu,
254 pointer_max_bits,
255 )),
256 ShiftCoreAir::new(bitwise_lu, range_checker, Rv32Shift256Opcode::CLASS_OFFSET),
257 );
258 inventory.add_air(shift);
259
260 Ok(())
261 }
262}
263
264pub struct Int256CpuProverExt;
265impl<SC, E, RA> VmProverExtension<E, RA, Int256> for Int256CpuProverExt
268where
269 SC: StarkProtocolConfig,
270 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
271 RA: RowMajorMatrixArena<Val<SC>>,
272 Val<SC>: PrimeField32,
273 SC::EF: Ord,
274{
275 fn extend_prover(
276 &self,
277 extension: &Int256,
278 inventory: &mut ChipInventory<SC, RA, CpuBackend<SC>>,
279 ) -> Result<(), ChipInventoryError> {
280 let range_checker = inventory.range_checker()?.clone();
281 let timestamp_max_bits = inventory.timestamp_max_bits();
282 let mem_helper = SharedMemoryHelper::new(range_checker.clone(), timestamp_max_bits);
283 let pointer_max_bits = inventory.airs().config().memory_config.pointer_max_bits;
284
285 let bitwise_lu = {
286 let existing_chip = inventory
287 .find_chip::<SharedBitwiseOperationLookupChip<8>>()
288 .next();
289 if let Some(chip) = existing_chip {
290 chip.clone()
291 } else {
292 let air: &BitwiseOperationLookupAir<8> = inventory.next_air()?;
293 let chip = Arc::new(BitwiseOperationLookupChip::new(air.bus));
294 inventory.add_periphery_chip(chip.clone());
295 chip
296 }
297 };
298
299 let range_tuple_checker = {
300 let existing_chip = inventory
301 .find_chip::<SharedRangeTupleCheckerChip<2>>()
302 .find(|c| {
303 c.bus().sizes[0] >= extension.range_tuple_checker_sizes[0]
304 && c.bus().sizes[1] >= extension.range_tuple_checker_sizes[1]
305 });
306 if let Some(chip) = existing_chip {
307 chip.clone()
308 } else {
309 let air: &RangeTupleCheckerAir<2> = inventory.next_air()?;
310 let chip = SharedRangeTupleCheckerChip::new(RangeTupleCheckerChip::new(air.bus));
311 inventory.add_periphery_chip(chip.clone());
312 chip
313 }
314 };
315
316 inventory.next_air::<Rv32BaseAlu256Air>()?;
317 let alu = Rv32BaseAlu256Chip::new(
318 BaseAluFiller::new(
319 Rv32VecHeapAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
320 bitwise_lu.clone(),
321 Rv32BaseAlu256Opcode::CLASS_OFFSET,
322 ),
323 mem_helper.clone(),
324 );
325 inventory.add_executor_chip(alu);
326
327 inventory.next_air::<Rv32LessThan256Air>()?;
328 let lt = Rv32LessThan256Chip::new(
329 LessThanFiller::new(
330 Rv32VecHeapAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
331 bitwise_lu.clone(),
332 Rv32LessThan256Opcode::CLASS_OFFSET,
333 ),
334 mem_helper.clone(),
335 );
336 inventory.add_executor_chip(lt);
337
338 inventory.next_air::<Rv32BranchEqual256Air>()?;
339 let beq = Rv32BranchEqual256Chip::new(
340 BranchEqualFiller::new(
341 Rv32VecHeapBranchAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
342 Rv32BranchEqual256Opcode::CLASS_OFFSET,
343 DEFAULT_PC_STEP,
344 ),
345 mem_helper.clone(),
346 );
347 inventory.add_executor_chip(beq);
348
349 inventory.next_air::<Rv32BranchLessThan256Air>()?;
350 let blt = Rv32BranchLessThan256Chip::new(
351 BranchLessThanFiller::new(
352 Rv32VecHeapBranchAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
353 bitwise_lu.clone(),
354 Rv32BranchLessThan256Opcode::CLASS_OFFSET,
355 ),
356 mem_helper.clone(),
357 );
358 inventory.add_executor_chip(blt);
359
360 inventory.next_air::<Rv32Multiplication256Air>()?;
361 let mult = Rv32Multiplication256Chip::new(
362 MultiplicationFiller::new(
363 Rv32VecHeapAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
364 range_tuple_checker.clone(),
365 Rv32Mul256Opcode::CLASS_OFFSET,
366 ),
367 mem_helper.clone(),
368 );
369 inventory.add_executor_chip(mult);
370
371 inventory.next_air::<Rv32Shift256Air>()?;
372 let shift = Rv32Shift256Chip::new(
373 ShiftFiller::new(
374 Rv32VecHeapAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
375 bitwise_lu.clone(),
376 range_checker.clone(),
377 Rv32Shift256Opcode::CLASS_OFFSET,
378 ),
379 mem_helper.clone(),
380 );
381 inventory.add_executor_chip(shift);
382 Ok(())
383 }
384}
385
386#[derive(Clone)]
387pub struct Int256Rv32CpuBuilder;
388
389impl<SC, E> VmBuilder<E> for Int256Rv32CpuBuilder
390where
391 SC: StarkProtocolConfig,
392 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
393 Val<SC>: VmField,
394 SC::EF: Ord,
395{
396 type VmConfig = Int256Rv32Config;
397 type SystemChipInventory = SystemChipInventory<SC>;
398 type RecordArena = MatrixRecordArena<Val<SC>>;
399
400 fn create_chip_complex(
401 &self,
402 config: &Int256Rv32Config,
403 circuit: AirInventory<E::SC>,
404 device_ctx: &openvm_stark_backend::EngineDeviceCtx<E>,
405 ) -> Result<
406 VmChipComplex<E::SC, Self::RecordArena, E::PB, Self::SystemChipInventory>,
407 ChipInventoryError,
408 > {
409 let mut chip_complex = VmBuilder::<E>::create_chip_complex(
410 &SystemCpuBuilder,
411 &config.system,
412 circuit,
413 device_ctx,
414 )?;
415 let inventory = &mut chip_complex.inventory;
416 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.rv32i, inventory)?;
417 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.rv32m, inventory)?;
418 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.io, inventory)?;
419 VmProverExtension::<E, _, _>::extend_prover(
420 &Int256CpuProverExt,
421 &config.bigint,
422 inventory,
423 )?;
424 Ok(chip_complex)
425 }
426}