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