1use std::{mem::size_of, sync::Arc};
2
3use derive_new::new;
4use openvm_circuit::{
5 arch::{DenseRecordArena, DEFAULT_BLOCK_SIZE},
6 utils::next_power_of_two_or_zero,
7};
8use openvm_circuit_primitives::{
9 bitwise_op_lookup::BitwiseOperationLookupChipGPU, cuda_abi::UInt2,
10 range_tuple::RangeTupleCheckerChipGPU, var_range::VariableRangeCheckerChipGPU, Chip,
11};
12use openvm_cuda_backend::{base::DeviceMatrix, prelude::F, GpuBackend};
13use openvm_cuda_common::copy::MemCopyH2D;
14use openvm_rv32_adapters::{
15 Rv32VecHeapAdapterCols, Rv32VecHeapAdapterRecord, Rv32VecHeapBranchAdapterCols,
16 Rv32VecHeapBranchAdapterRecord,
17};
18use openvm_rv32im_circuit::{
19 adapters::{INT256_NUM_LIMBS, RV32_CELL_BITS},
20 BaseAluCoreCols, BaseAluCoreRecord, BranchEqualCoreCols, BranchEqualCoreRecord,
21 BranchLessThanCoreCols, BranchLessThanCoreRecord, LessThanCoreCols, LessThanCoreRecord,
22 MultiplicationCoreCols, MultiplicationCoreRecord, ShiftCoreCols, ShiftCoreRecord,
23};
24use openvm_stark_backend::prover::AirProvingContext;
25
26mod cuda_abi;
27
28use crate::INT256_NUM_BLOCKS;
29
30pub type BaseAlu256AdapterRecord = Rv32VecHeapAdapterRecord<
34 2,
35 INT256_NUM_BLOCKS,
36 INT256_NUM_BLOCKS,
37 DEFAULT_BLOCK_SIZE,
38 DEFAULT_BLOCK_SIZE,
39>;
40pub type BaseAlu256CoreRecord = BaseAluCoreRecord<INT256_NUM_LIMBS>;
41
42#[derive(new)]
43pub struct BaseAlu256ChipGpu {
44 pub range_checker: Arc<VariableRangeCheckerChipGPU>,
45 pub bitwise_lookup: Arc<BitwiseOperationLookupChipGPU<RV32_CELL_BITS>>,
46 pub pointer_max_bits: usize,
47 pub timestamp_max_bits: usize,
48}
49
50impl Chip<DenseRecordArena, GpuBackend> for BaseAlu256ChipGpu {
51 fn generate_proving_ctx(&self, arena: DenseRecordArena) -> AirProvingContext<GpuBackend> {
52 const RECORD_SIZE: usize = size_of::<(BaseAlu256AdapterRecord, BaseAlu256CoreRecord)>();
53 let records = arena.allocated();
54 if records.is_empty() {
55 return AirProvingContext::simple_no_pis(DeviceMatrix::dummy());
56 }
57 debug_assert_eq!(records.len() % RECORD_SIZE, 0);
58
59 let trace_width = BaseAluCoreCols::<F, INT256_NUM_LIMBS, RV32_CELL_BITS>::width()
60 + Rv32VecHeapAdapterCols::<
61 F,
62 2,
63 INT256_NUM_BLOCKS,
64 INT256_NUM_BLOCKS,
65 DEFAULT_BLOCK_SIZE,
66 DEFAULT_BLOCK_SIZE,
67 >::width();
68 let trace_height = next_power_of_two_or_zero(records.len() / RECORD_SIZE);
69 let device_ctx = &self.range_checker.device_ctx;
70
71 let d_records = records.to_device_on(device_ctx).unwrap();
72 let d_trace = DeviceMatrix::<F>::with_capacity_on(trace_height, trace_width, device_ctx);
73
74 unsafe {
75 cuda_abi::alu256::tracegen(
76 d_trace.buffer(),
77 trace_height,
78 &d_records,
79 &self.range_checker.count,
80 &self.bitwise_lookup.count,
81 RV32_CELL_BITS,
82 self.pointer_max_bits as u32,
83 self.timestamp_max_bits as u32,
84 device_ctx.stream.as_raw(),
85 )
86 .unwrap();
87 }
88
89 AirProvingContext::simple_no_pis(d_trace)
90 }
91}
92
93pub type BranchEqual256AdapterRecord =
97 Rv32VecHeapBranchAdapterRecord<2, INT256_NUM_BLOCKS, DEFAULT_BLOCK_SIZE>;
98pub type BranchEqual256CoreRecord = BranchEqualCoreRecord<INT256_NUM_LIMBS>;
99
100#[derive(new)]
101pub struct BranchEqual256ChipGpu {
102 pub range_checker: Arc<VariableRangeCheckerChipGPU>,
103 pub bitwise_lookup: Arc<BitwiseOperationLookupChipGPU<RV32_CELL_BITS>>,
104 pub pointer_max_bits: usize,
105 pub timestamp_max_bits: usize,
106}
107
108impl Chip<DenseRecordArena, GpuBackend> for BranchEqual256ChipGpu {
109 fn generate_proving_ctx(&self, arena: DenseRecordArena) -> AirProvingContext<GpuBackend> {
110 const RECORD_SIZE: usize =
111 size_of::<(BranchEqual256AdapterRecord, BranchEqual256CoreRecord)>();
112 let records = arena.allocated();
113 if records.is_empty() {
114 return AirProvingContext::simple_no_pis(DeviceMatrix::dummy());
115 }
116 debug_assert_eq!(records.len() % RECORD_SIZE, 0);
117
118 let trace_width = BranchEqualCoreCols::<F, INT256_NUM_LIMBS>::width()
119 + Rv32VecHeapBranchAdapterCols::<F, 2, INT256_NUM_BLOCKS, DEFAULT_BLOCK_SIZE>::width();
120 let trace_height = next_power_of_two_or_zero(records.len() / RECORD_SIZE);
121 let device_ctx = &self.range_checker.device_ctx;
122
123 let d_records = records.to_device_on(device_ctx).unwrap();
124 let d_trace = DeviceMatrix::<F>::with_capacity_on(trace_height, trace_width, device_ctx);
125
126 unsafe {
127 cuda_abi::beq256::tracegen(
128 d_trace.buffer(),
129 trace_height,
130 &d_records,
131 &self.range_checker.count,
132 &self.bitwise_lookup.count,
133 RV32_CELL_BITS,
134 self.pointer_max_bits as u32,
135 self.timestamp_max_bits as u32,
136 device_ctx.stream.as_raw(),
137 )
138 .unwrap();
139 }
140
141 AirProvingContext::simple_no_pis(d_trace)
142 }
143}
144
145pub type LessThan256AdapterRecord = Rv32VecHeapAdapterRecord<
149 2,
150 INT256_NUM_BLOCKS,
151 INT256_NUM_BLOCKS,
152 DEFAULT_BLOCK_SIZE,
153 DEFAULT_BLOCK_SIZE,
154>;
155pub type LessThan256CoreRecord = LessThanCoreRecord<INT256_NUM_LIMBS, RV32_CELL_BITS>;
156
157#[derive(new)]
158pub struct LessThan256ChipGpu {
159 pub range_checker: Arc<VariableRangeCheckerChipGPU>,
160 pub bitwise_lookup: Arc<BitwiseOperationLookupChipGPU<RV32_CELL_BITS>>,
161 pub pointer_max_bits: usize,
162 pub timestamp_max_bits: usize,
163}
164
165impl Chip<DenseRecordArena, GpuBackend> for LessThan256ChipGpu {
166 fn generate_proving_ctx(&self, arena: DenseRecordArena) -> AirProvingContext<GpuBackend> {
167 const RECORD_SIZE: usize = size_of::<(LessThan256AdapterRecord, LessThan256CoreRecord)>();
168 let records = arena.allocated();
169 if records.is_empty() {
170 return AirProvingContext::simple_no_pis(DeviceMatrix::dummy());
171 }
172 debug_assert_eq!(records.len() % RECORD_SIZE, 0);
173
174 let trace_width = LessThanCoreCols::<F, INT256_NUM_LIMBS, RV32_CELL_BITS>::width()
175 + Rv32VecHeapAdapterCols::<
176 F,
177 2,
178 INT256_NUM_BLOCKS,
179 INT256_NUM_BLOCKS,
180 DEFAULT_BLOCK_SIZE,
181 DEFAULT_BLOCK_SIZE,
182 >::width();
183 let trace_height = next_power_of_two_or_zero(records.len() / RECORD_SIZE);
184 let device_ctx = &self.range_checker.device_ctx;
185
186 let d_records = records.to_device_on(device_ctx).unwrap();
187 let d_trace = DeviceMatrix::<F>::with_capacity_on(trace_height, trace_width, device_ctx);
188
189 unsafe {
190 cuda_abi::lt256::tracegen(
191 d_trace.buffer(),
192 trace_height,
193 &d_records,
194 &self.range_checker.count,
195 &self.bitwise_lookup.count,
196 RV32_CELL_BITS,
197 self.pointer_max_bits as u32,
198 self.timestamp_max_bits as u32,
199 device_ctx.stream.as_raw(),
200 )
201 .unwrap();
202 }
203
204 AirProvingContext::simple_no_pis(d_trace)
205 }
206}
207
208pub type BranchLessThan256AdapterRecord =
212 Rv32VecHeapBranchAdapterRecord<2, INT256_NUM_BLOCKS, DEFAULT_BLOCK_SIZE>;
213pub type BranchLessThan256CoreRecord = BranchLessThanCoreRecord<INT256_NUM_LIMBS, RV32_CELL_BITS>;
214
215#[derive(new)]
216pub struct BranchLessThan256ChipGpu {
217 pub range_checker: Arc<VariableRangeCheckerChipGPU>,
218 pub bitwise_lookup: Arc<BitwiseOperationLookupChipGPU<RV32_CELL_BITS>>,
219 pub pointer_max_bits: usize,
220 pub timestamp_max_bits: usize,
221}
222
223impl Chip<DenseRecordArena, GpuBackend> for BranchLessThan256ChipGpu {
224 fn generate_proving_ctx(&self, arena: DenseRecordArena) -> AirProvingContext<GpuBackend> {
225 const RECORD_SIZE: usize =
226 size_of::<(BranchLessThan256AdapterRecord, BranchLessThan256CoreRecord)>();
227 let records = arena.allocated();
228 if records.is_empty() {
229 return AirProvingContext::simple_no_pis(DeviceMatrix::dummy());
230 }
231 debug_assert_eq!(records.len() % RECORD_SIZE, 0);
232
233 let trace_width = BranchLessThanCoreCols::<F, INT256_NUM_LIMBS, RV32_CELL_BITS>::width()
234 + Rv32VecHeapBranchAdapterCols::<F, 2, INT256_NUM_BLOCKS, DEFAULT_BLOCK_SIZE>::width();
235 let trace_height = next_power_of_two_or_zero(records.len() / RECORD_SIZE);
236 let device_ctx = &self.range_checker.device_ctx;
237
238 let d_records = records.to_device_on(device_ctx).unwrap();
239 let d_trace = DeviceMatrix::<F>::with_capacity_on(trace_height, trace_width, device_ctx);
240
241 unsafe {
242 cuda_abi::blt256::tracegen(
243 d_trace.buffer(),
244 trace_height,
245 &d_records,
246 &self.range_checker.count,
247 &self.bitwise_lookup.count,
248 RV32_CELL_BITS,
249 self.pointer_max_bits as u32,
250 self.timestamp_max_bits as u32,
251 device_ctx.stream.as_raw(),
252 )
253 .unwrap();
254 }
255
256 AirProvingContext::simple_no_pis(d_trace)
257 }
258}
259
260pub type Shift256AdapterRecord = Rv32VecHeapAdapterRecord<
264 2,
265 INT256_NUM_BLOCKS,
266 INT256_NUM_BLOCKS,
267 DEFAULT_BLOCK_SIZE,
268 DEFAULT_BLOCK_SIZE,
269>;
270pub type Shift256CoreRecord = ShiftCoreRecord<INT256_NUM_LIMBS, RV32_CELL_BITS>;
271
272#[derive(new)]
273pub struct Shift256ChipGpu {
274 pub range_checker: Arc<VariableRangeCheckerChipGPU>,
275 pub bitwise_lookup: Arc<BitwiseOperationLookupChipGPU<RV32_CELL_BITS>>,
276 pub pointer_max_bits: usize,
277 pub timestamp_max_bits: usize,
278}
279
280impl Chip<DenseRecordArena, GpuBackend> for Shift256ChipGpu {
281 fn generate_proving_ctx(&self, arena: DenseRecordArena) -> AirProvingContext<GpuBackend> {
282 const RECORD_SIZE: usize = size_of::<(Shift256AdapterRecord, Shift256CoreRecord)>();
283 let records = arena.allocated();
284 if records.is_empty() {
285 return AirProvingContext::simple_no_pis(DeviceMatrix::dummy());
286 }
287 debug_assert_eq!(records.len() % RECORD_SIZE, 0);
288
289 let trace_width = ShiftCoreCols::<F, INT256_NUM_LIMBS, RV32_CELL_BITS>::width()
290 + Rv32VecHeapAdapterCols::<
291 F,
292 2,
293 INT256_NUM_BLOCKS,
294 INT256_NUM_BLOCKS,
295 DEFAULT_BLOCK_SIZE,
296 DEFAULT_BLOCK_SIZE,
297 >::width();
298 let trace_height = next_power_of_two_or_zero(records.len() / RECORD_SIZE);
299 let device_ctx = &self.range_checker.device_ctx;
300
301 let d_records = records.to_device_on(device_ctx).unwrap();
302 let d_trace = DeviceMatrix::<F>::with_capacity_on(trace_height, trace_width, device_ctx);
303
304 unsafe {
305 cuda_abi::shift256::tracegen(
306 d_trace.buffer(),
307 trace_height,
308 &d_records,
309 &self.range_checker.count,
310 &self.bitwise_lookup.count,
311 RV32_CELL_BITS,
312 self.pointer_max_bits as u32,
313 self.timestamp_max_bits as u32,
314 device_ctx.stream.as_raw(),
315 )
316 .unwrap();
317 }
318
319 AirProvingContext::simple_no_pis(d_trace)
320 }
321}
322
323pub type Multiplication256AdapterRecord = Rv32VecHeapAdapterRecord<
327 2,
328 INT256_NUM_BLOCKS,
329 INT256_NUM_BLOCKS,
330 DEFAULT_BLOCK_SIZE,
331 DEFAULT_BLOCK_SIZE,
332>;
333pub type Multiplication256CoreRecord = MultiplicationCoreRecord<INT256_NUM_LIMBS, RV32_CELL_BITS>;
334
335#[derive(new)]
336pub struct Multiplication256ChipGpu {
337 pub range_checker: Arc<VariableRangeCheckerChipGPU>,
338 pub bitwise_lookup: Arc<BitwiseOperationLookupChipGPU<RV32_CELL_BITS>>,
339 pub range_tuple_checker: Arc<RangeTupleCheckerChipGPU<2>>,
340 pub pointer_max_bits: usize,
341 pub timestamp_max_bits: usize,
342}
343
344impl Chip<DenseRecordArena, GpuBackend> for Multiplication256ChipGpu {
345 fn generate_proving_ctx(&self, arena: DenseRecordArena) -> AirProvingContext<GpuBackend> {
346 const RECORD_SIZE: usize =
347 size_of::<(Multiplication256AdapterRecord, Multiplication256CoreRecord)>();
348 let records = arena.allocated();
349 if records.is_empty() {
350 return AirProvingContext::simple_no_pis(DeviceMatrix::dummy());
351 }
352 debug_assert_eq!(records.len() % RECORD_SIZE, 0);
353
354 let trace_width = MultiplicationCoreCols::<F, INT256_NUM_LIMBS, RV32_CELL_BITS>::width()
355 + Rv32VecHeapAdapterCols::<
356 F,
357 2,
358 INT256_NUM_BLOCKS,
359 INT256_NUM_BLOCKS,
360 DEFAULT_BLOCK_SIZE,
361 DEFAULT_BLOCK_SIZE,
362 >::width();
363 let trace_height = next_power_of_two_or_zero(records.len() / RECORD_SIZE);
364 let device_ctx = &self.range_checker.device_ctx;
365
366 let d_records = records.to_device_on(device_ctx).unwrap();
367 let d_trace = DeviceMatrix::<F>::with_capacity_on(trace_height, trace_width, device_ctx);
368
369 let sizes = self.range_tuple_checker.sizes;
370 let d_sizes = UInt2 {
371 x: sizes[0],
372 y: sizes[1],
373 };
374 unsafe {
375 cuda_abi::mul256::tracegen(
376 d_trace.buffer(),
377 trace_height,
378 &d_records,
379 &self.range_checker.count,
380 &self.bitwise_lookup.count,
381 RV32_CELL_BITS,
382 &self.range_tuple_checker.count,
383 d_sizes,
384 self.pointer_max_bits as u32,
385 self.timestamp_max_bits as u32,
386 device_ctx.stream.as_raw(),
387 )
388 .unwrap();
389 }
390
391 AirProvingContext::simple_no_pis(d_trace)
392 }
393}