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_instructions::{program::DEFAULT_PC_STEP, LocalOpcode};
29use openvm_rv32im_circuit::Rv32ImCpuProverExt;
30use openvm_stark_backend::{
31 config::{StarkGenericConfig, Val},
32 engine::StarkEngine,
33 p3_field::PrimeField32,
34 prover::cpu::{CpuBackend, CpuDevice},
35};
36use serde::{Deserialize, Serialize};
37
38use crate::*;
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 Rv32HeapAdapterExecutor::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 Rv32HeapAdapterExecutor::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(
114 Rv32HeapBranchAdapterExecutor::new(pointer_max_bits),
115 Rv32BranchEqual256Opcode::CLASS_OFFSET,
116 DEFAULT_PC_STEP,
117 );
118 inventory.add_executor(
119 beq,
120 Rv32BranchEqual256Opcode::iter().map(|x| x.global_opcode()),
121 )?;
122
123 let blt = Rv32BranchLessThan256Executor::new(
124 Rv32HeapBranchAdapterExecutor::new(pointer_max_bits),
125 Rv32BranchLessThan256Opcode::CLASS_OFFSET,
126 );
127 inventory.add_executor(
128 blt,
129 Rv32BranchLessThan256Opcode::iter().map(|x| x.global_opcode()),
130 )?;
131
132 let mult = Rv32Multiplication256Executor::new(
133 Rv32HeapAdapterExecutor::new(pointer_max_bits),
134 Rv32Mul256Opcode::CLASS_OFFSET,
135 );
136 inventory.add_executor(mult, Rv32Mul256Opcode::iter().map(|x| x.global_opcode()))?;
137
138 let shift = Rv32Shift256Executor::new(
139 Rv32HeapAdapterExecutor::new(pointer_max_bits),
140 Rv32Shift256Opcode::CLASS_OFFSET,
141 );
142 inventory.add_executor(shift, Rv32Shift256Opcode::iter().map(|x| x.global_opcode()))?;
143
144 Ok(())
145 }
146}
147
148impl<SC: StarkGenericConfig> VmCircuitExtension<SC> for Int256 {
149 fn extend_circuit(&self, inventory: &mut AirInventory<SC>) -> Result<(), AirInventoryError> {
150 let SystemPort {
151 execution_bus,
152 program_bus,
153 memory_bridge,
154 } = inventory.system().port();
155
156 let exec_bridge = ExecutionBridge::new(execution_bus, program_bus);
157 let range_checker = inventory.range_checker().bus;
158 let pointer_max_bits = inventory.pointer_max_bits();
159
160 let bitwise_lu = {
161 let existing_air = inventory.find_air::<BitwiseOperationLookupAir<8>>().next();
163 if let Some(air) = existing_air {
164 air.bus
165 } else {
166 let bus = BitwiseOperationLookupBus::new(inventory.new_bus_idx());
167 let air = BitwiseOperationLookupAir::<8>::new(bus);
168 inventory.add_air(air);
169 air.bus
170 }
171 };
172
173 let range_tuple_checker = {
174 let existing_air = inventory.find_air::<RangeTupleCheckerAir<2>>().find(|c| {
175 c.bus.sizes[0] >= self.range_tuple_checker_sizes[0]
176 && c.bus.sizes[1] >= self.range_tuple_checker_sizes[1]
177 });
178 if let Some(air) = existing_air {
179 air.bus
180 } else {
181 let bus = RangeTupleCheckerBus::new(
182 inventory.new_bus_idx(),
183 self.range_tuple_checker_sizes,
184 );
185 let air = RangeTupleCheckerAir { bus };
186 inventory.add_air(air);
187 air.bus
188 }
189 };
190
191 let alu = Rv32BaseAlu256Air::new(
192 Rv32HeapAdapterAir::new(exec_bridge, memory_bridge, bitwise_lu, pointer_max_bits),
193 BaseAluCoreAir::new(bitwise_lu, Rv32BaseAlu256Opcode::CLASS_OFFSET),
194 );
195 inventory.add_air(alu);
196
197 let lt = Rv32LessThan256Air::new(
198 Rv32HeapAdapterAir::new(exec_bridge, memory_bridge, bitwise_lu, pointer_max_bits),
199 LessThanCoreAir::new(bitwise_lu, Rv32LessThan256Opcode::CLASS_OFFSET),
200 );
201 inventory.add_air(lt);
202
203 let beq = Rv32BranchEqual256Air::new(
204 Rv32HeapBranchAdapterAir::new(exec_bridge, memory_bridge, bitwise_lu, pointer_max_bits),
205 BranchEqualCoreAir::new(Rv32BranchEqual256Opcode::CLASS_OFFSET, DEFAULT_PC_STEP),
206 );
207 inventory.add_air(beq);
208
209 let blt = Rv32BranchLessThan256Air::new(
210 Rv32HeapBranchAdapterAir::new(exec_bridge, memory_bridge, bitwise_lu, pointer_max_bits),
211 BranchLessThanCoreAir::new(bitwise_lu, Rv32BranchLessThan256Opcode::CLASS_OFFSET),
212 );
213 inventory.add_air(blt);
214
215 let mult = Rv32Multiplication256Air::new(
216 Rv32HeapAdapterAir::new(exec_bridge, memory_bridge, bitwise_lu, pointer_max_bits),
217 MultiplicationCoreAir::new(range_tuple_checker, Rv32Mul256Opcode::CLASS_OFFSET),
218 );
219 inventory.add_air(mult);
220
221 let shift = Rv32Shift256Air::new(
222 Rv32HeapAdapterAir::new(exec_bridge, memory_bridge, bitwise_lu, pointer_max_bits),
223 ShiftCoreAir::new(bitwise_lu, range_checker, Rv32Shift256Opcode::CLASS_OFFSET),
224 );
225 inventory.add_air(shift);
226
227 Ok(())
228 }
229}
230
231pub struct Int256CpuProverExt;
232impl<E, SC, RA> VmProverExtension<E, RA, Int256> for Int256CpuProverExt
235where
236 SC: StarkGenericConfig,
237 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
238 RA: RowMajorMatrixArena<Val<SC>>,
239 Val<SC>: PrimeField32,
240{
241 fn extend_prover(
242 &self,
243 extension: &Int256,
244 inventory: &mut ChipInventory<SC, RA, CpuBackend<SC>>,
245 ) -> Result<(), ChipInventoryError> {
246 let range_checker = inventory.range_checker()?.clone();
247 let timestamp_max_bits = inventory.timestamp_max_bits();
248 let mem_helper = SharedMemoryHelper::new(range_checker.clone(), timestamp_max_bits);
249 let pointer_max_bits = inventory.airs().config().memory_config.pointer_max_bits;
250
251 let bitwise_lu = {
252 let existing_chip = inventory
253 .find_chip::<SharedBitwiseOperationLookupChip<8>>()
254 .next();
255 if let Some(chip) = existing_chip {
256 chip.clone()
257 } else {
258 let air: &BitwiseOperationLookupAir<8> = inventory.next_air()?;
259 let chip = Arc::new(BitwiseOperationLookupChip::new(air.bus));
260 inventory.add_periphery_chip(chip.clone());
261 chip
262 }
263 };
264
265 let range_tuple_checker = {
266 let existing_chip = inventory
267 .find_chip::<SharedRangeTupleCheckerChip<2>>()
268 .find(|c| {
269 c.bus().sizes[0] >= extension.range_tuple_checker_sizes[0]
270 && c.bus().sizes[1] >= extension.range_tuple_checker_sizes[1]
271 });
272 if let Some(chip) = existing_chip {
273 chip.clone()
274 } else {
275 let air: &RangeTupleCheckerAir<2> = inventory.next_air()?;
276 let chip = SharedRangeTupleCheckerChip::new(RangeTupleCheckerChip::new(air.bus));
277 inventory.add_periphery_chip(chip.clone());
278 chip
279 }
280 };
281
282 inventory.next_air::<Rv32BaseAlu256Air>()?;
283 let alu = Rv32BaseAlu256Chip::new(
284 BaseAluFiller::new(
285 Rv32HeapAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
286 bitwise_lu.clone(),
287 Rv32BaseAlu256Opcode::CLASS_OFFSET,
288 ),
289 mem_helper.clone(),
290 );
291 inventory.add_executor_chip(alu);
292
293 inventory.next_air::<Rv32LessThan256Air>()?;
294 let lt = Rv32LessThan256Chip::new(
295 LessThanFiller::new(
296 Rv32HeapAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
297 bitwise_lu.clone(),
298 Rv32LessThan256Opcode::CLASS_OFFSET,
299 ),
300 mem_helper.clone(),
301 );
302 inventory.add_executor_chip(lt);
303
304 inventory.next_air::<Rv32BranchEqual256Air>()?;
305 let beq = Rv32BranchEqual256Chip::new(
306 BranchEqualFiller::new(
307 Rv32HeapBranchAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
308 Rv32BranchEqual256Opcode::CLASS_OFFSET,
309 DEFAULT_PC_STEP,
310 ),
311 mem_helper.clone(),
312 );
313 inventory.add_executor_chip(beq);
314
315 inventory.next_air::<Rv32BranchLessThan256Air>()?;
316 let blt = Rv32BranchLessThan256Chip::new(
317 BranchLessThanFiller::new(
318 Rv32HeapBranchAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
319 bitwise_lu.clone(),
320 Rv32BranchLessThan256Opcode::CLASS_OFFSET,
321 ),
322 mem_helper.clone(),
323 );
324 inventory.add_executor_chip(blt);
325
326 inventory.next_air::<Rv32Multiplication256Air>()?;
327 let mult = Rv32Multiplication256Chip::new(
328 MultiplicationFiller::new(
329 Rv32HeapAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
330 range_tuple_checker.clone(),
331 Rv32Mul256Opcode::CLASS_OFFSET,
332 ),
333 mem_helper.clone(),
334 );
335 inventory.add_executor_chip(mult);
336
337 inventory.next_air::<Rv32Shift256Air>()?;
338 let shift = Rv32Shift256Chip::new(
339 ShiftFiller::new(
340 Rv32HeapAdapterFiller::new(pointer_max_bits, bitwise_lu.clone()),
341 bitwise_lu.clone(),
342 range_checker.clone(),
343 Rv32Shift256Opcode::CLASS_OFFSET,
344 ),
345 mem_helper.clone(),
346 );
347 inventory.add_executor_chip(shift);
348 Ok(())
349 }
350}
351
352#[derive(Clone)]
353pub struct Int256Rv32CpuBuilder;
354
355impl<E, SC> VmBuilder<E> for Int256Rv32CpuBuilder
356where
357 SC: StarkGenericConfig,
358 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
359 Val<SC>: VmField,
360{
361 type VmConfig = Int256Rv32Config;
362 type SystemChipInventory = SystemChipInventory<SC>;
363 type RecordArena = MatrixRecordArena<Val<SC>>;
364
365 fn create_chip_complex(
366 &self,
367 config: &Int256Rv32Config,
368 circuit: AirInventory<E::SC>,
369 ) -> Result<
370 VmChipComplex<E::SC, Self::RecordArena, E::PB, Self::SystemChipInventory>,
371 ChipInventoryError,
372 > {
373 let mut chip_complex =
374 VmBuilder::<E>::create_chip_complex(&SystemCpuBuilder, &config.system, circuit)?;
375 let inventory = &mut chip_complex.inventory;
376 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.rv32i, inventory)?;
377 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.rv32m, inventory)?;
378 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.io, inventory)?;
379 VmProverExtension::<E, _, _>::extend_prover(
380 &Int256CpuProverExt,
381 &config.bigint,
382 inventory,
383 )?;
384 Ok(chip_complex)
385 }
386}