openvm_bigint_circuit/
extension.rs

1use derive_more::derive::From;
2use openvm_bigint_transpiler::{
3    Rv32BaseAlu256Opcode, Rv32BranchEqual256Opcode, Rv32BranchLessThan256Opcode,
4    Rv32LessThan256Opcode, Rv32Mul256Opcode, Rv32Shift256Opcode,
5};
6use openvm_circuit::{
7    arch::{
8        SystemConfig, SystemPort, VmExtension, VmInventory, VmInventoryBuilder, VmInventoryError,
9    },
10    system::phantom::PhantomChip,
11};
12use openvm_circuit_derive::{AnyEnum, InstructionExecutor, VmConfig};
13use openvm_circuit_primitives::{
14    bitwise_op_lookup::{BitwiseOperationLookupBus, SharedBitwiseOperationLookupChip},
15    range_tuple::{RangeTupleCheckerBus, SharedRangeTupleCheckerChip},
16};
17use openvm_circuit_primitives_derive::{Chip, ChipUsageGetter};
18use openvm_instructions::{program::DEFAULT_PC_STEP, LocalOpcode};
19use openvm_rv32im_circuit::{
20    Rv32I, Rv32IExecutor, Rv32IPeriphery, Rv32Io, Rv32IoExecutor, Rv32IoPeriphery, Rv32M,
21    Rv32MExecutor, Rv32MPeriphery,
22};
23use openvm_stark_backend::p3_field::PrimeField32;
24use serde::{Deserialize, Serialize};
25
26use crate::*;
27
28#[derive(Clone, Debug, VmConfig, derive_new::new, Serialize, Deserialize)]
29pub struct Int256Rv32Config {
30    #[system]
31    pub system: SystemConfig,
32    #[extension]
33    pub rv32i: Rv32I,
34    #[extension]
35    pub rv32m: Rv32M,
36    #[extension]
37    pub io: Rv32Io,
38    #[extension]
39    pub bigint: Int256,
40}
41
42impl Default for Int256Rv32Config {
43    fn default() -> Self {
44        Self {
45            system: SystemConfig::default().with_continuations(),
46            rv32i: Rv32I,
47            rv32m: Rv32M::default(),
48            io: Rv32Io,
49            bigint: Int256::default(),
50        }
51    }
52}
53
54#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
55pub struct Int256 {
56    #[serde(default = "default_range_tuple_checker_sizes")]
57    pub range_tuple_checker_sizes: [u32; 2],
58}
59
60impl Default for Int256 {
61    fn default() -> Self {
62        Self {
63            range_tuple_checker_sizes: default_range_tuple_checker_sizes(),
64        }
65    }
66}
67
68fn default_range_tuple_checker_sizes() -> [u32; 2] {
69    [1 << 8, 32 * (1 << 8)]
70}
71
72#[derive(ChipUsageGetter, Chip, InstructionExecutor, From, AnyEnum)]
73pub enum Int256Executor<F: PrimeField32> {
74    BaseAlu256(Rv32BaseAlu256Chip<F>),
75    LessThan256(Rv32LessThan256Chip<F>),
76    BranchEqual256(Rv32BranchEqual256Chip<F>),
77    BranchLessThan256(Rv32BranchLessThan256Chip<F>),
78    Multiplication256(Rv32Multiplication256Chip<F>),
79    Shift256(Rv32Shift256Chip<F>),
80}
81
82#[derive(From, ChipUsageGetter, Chip, AnyEnum)]
83pub enum Int256Periphery<F: PrimeField32> {
84    BitwiseOperationLookup(SharedBitwiseOperationLookupChip<8>),
85    /// Only needed for multiplication extension
86    RangeTupleChecker(SharedRangeTupleCheckerChip<2>),
87    Phantom(PhantomChip<F>),
88}
89
90impl<F: PrimeField32> VmExtension<F> for Int256 {
91    type Executor = Int256Executor<F>;
92    type Periphery = Int256Periphery<F>;
93
94    fn build(
95        &self,
96        builder: &mut VmInventoryBuilder<F>,
97    ) -> Result<VmInventory<Self::Executor, Self::Periphery>, VmInventoryError> {
98        let mut inventory = VmInventory::new();
99        let SystemPort {
100            execution_bus,
101            program_bus,
102            memory_bridge,
103        } = builder.system_port();
104        let range_checker_chip = builder.system_base().range_checker_chip.clone();
105        let bitwise_lu_chip = if let Some(&chip) = builder
106            .find_chip::<SharedBitwiseOperationLookupChip<8>>()
107            .first()
108        {
109            chip.clone()
110        } else {
111            let bitwise_lu_bus = BitwiseOperationLookupBus::new(builder.new_bus_idx());
112            let chip = SharedBitwiseOperationLookupChip::new(bitwise_lu_bus);
113            inventory.add_periphery_chip(chip.clone());
114            chip
115        };
116        let offline_memory = builder.system_base().offline_memory();
117        let address_bits = builder.system_config().memory_config.pointer_max_bits;
118
119        let range_tuple_chip = if let Some(chip) = builder
120            .find_chip::<SharedRangeTupleCheckerChip<2>>()
121            .into_iter()
122            .find(|c| {
123                c.bus().sizes[0] >= self.range_tuple_checker_sizes[0]
124                    && c.bus().sizes[1] >= self.range_tuple_checker_sizes[1]
125            }) {
126            chip.clone()
127        } else {
128            let range_tuple_bus =
129                RangeTupleCheckerBus::new(builder.new_bus_idx(), self.range_tuple_checker_sizes);
130            let chip = SharedRangeTupleCheckerChip::new(range_tuple_bus);
131            inventory.add_periphery_chip(chip.clone());
132            chip
133        };
134
135        let base_alu_chip = Rv32BaseAlu256Chip::new(
136            Rv32HeapAdapterChip::new(
137                execution_bus,
138                program_bus,
139                memory_bridge,
140                address_bits,
141                bitwise_lu_chip.clone(),
142            ),
143            BaseAluCoreChip::new(bitwise_lu_chip.clone(), Rv32BaseAlu256Opcode::CLASS_OFFSET),
144            offline_memory.clone(),
145        );
146        inventory.add_executor(
147            base_alu_chip,
148            Rv32BaseAlu256Opcode::iter().map(|x| x.global_opcode()),
149        )?;
150
151        let less_than_chip = Rv32LessThan256Chip::new(
152            Rv32HeapAdapterChip::new(
153                execution_bus,
154                program_bus,
155                memory_bridge,
156                address_bits,
157                bitwise_lu_chip.clone(),
158            ),
159            LessThanCoreChip::new(bitwise_lu_chip.clone(), Rv32LessThan256Opcode::CLASS_OFFSET),
160            offline_memory.clone(),
161        );
162        inventory.add_executor(
163            less_than_chip,
164            Rv32LessThan256Opcode::iter().map(|x| x.global_opcode()),
165        )?;
166
167        let branch_equal_chip = Rv32BranchEqual256Chip::new(
168            Rv32HeapBranchAdapterChip::new(
169                execution_bus,
170                program_bus,
171                memory_bridge,
172                address_bits,
173                bitwise_lu_chip.clone(),
174            ),
175            BranchEqualCoreChip::new(Rv32BranchEqual256Opcode::CLASS_OFFSET, DEFAULT_PC_STEP),
176            offline_memory.clone(),
177        );
178        inventory.add_executor(
179            branch_equal_chip,
180            Rv32BranchEqual256Opcode::iter().map(|x| x.global_opcode()),
181        )?;
182
183        let branch_less_than_chip = Rv32BranchLessThan256Chip::new(
184            Rv32HeapBranchAdapterChip::new(
185                execution_bus,
186                program_bus,
187                memory_bridge,
188                address_bits,
189                bitwise_lu_chip.clone(),
190            ),
191            BranchLessThanCoreChip::new(
192                bitwise_lu_chip.clone(),
193                Rv32BranchLessThan256Opcode::CLASS_OFFSET,
194            ),
195            offline_memory.clone(),
196        );
197        inventory.add_executor(
198            branch_less_than_chip,
199            Rv32BranchLessThan256Opcode::iter().map(|x| x.global_opcode()),
200        )?;
201
202        let multiplication_chip = Rv32Multiplication256Chip::new(
203            Rv32HeapAdapterChip::new(
204                execution_bus,
205                program_bus,
206                memory_bridge,
207                address_bits,
208                bitwise_lu_chip.clone(),
209            ),
210            MultiplicationCoreChip::new(range_tuple_chip, Rv32Mul256Opcode::CLASS_OFFSET),
211            offline_memory.clone(),
212        );
213        inventory.add_executor(
214            multiplication_chip,
215            Rv32Mul256Opcode::iter().map(|x| x.global_opcode()),
216        )?;
217
218        let shift_chip = Rv32Shift256Chip::new(
219            Rv32HeapAdapterChip::new(
220                execution_bus,
221                program_bus,
222                memory_bridge,
223                address_bits,
224                bitwise_lu_chip.clone(),
225            ),
226            ShiftCoreChip::new(
227                bitwise_lu_chip.clone(),
228                range_checker_chip,
229                Rv32Shift256Opcode::CLASS_OFFSET,
230            ),
231            offline_memory.clone(),
232        );
233        inventory.add_executor(
234            shift_chip,
235            Rv32Shift256Opcode::iter().map(|x| x.global_opcode()),
236        )?;
237
238        Ok(inventory)
239    }
240}