openvm_algebra_circuit/modular_chip/
addsub.rs

1use std::{
2    cell::RefCell,
3    rc::Rc,
4    sync::{Arc, Mutex},
5};
6
7use openvm_algebra_transpiler::Rv32ModularArithmeticOpcode;
8use openvm_circuit::{arch::VmChipWrapper, system::memory::OfflineMemory};
9use openvm_circuit_derive::InstructionExecutor;
10use openvm_circuit_primitives::var_range::{
11    SharedVariableRangeCheckerChip, VariableRangeCheckerBus,
12};
13use openvm_circuit_primitives_derive::{Chip, ChipUsageGetter};
14use openvm_mod_circuit_builder::{
15    ExprBuilder, ExprBuilderConfig, FieldExpr, FieldExpressionCoreChip, FieldVariable,
16};
17use openvm_rv32_adapters::Rv32VecHeapAdapterChip;
18use openvm_stark_backend::p3_field::PrimeField32;
19
20pub fn addsub_expr(
21    config: ExprBuilderConfig,
22    range_bus: VariableRangeCheckerBus,
23) -> (FieldExpr, usize, usize) {
24    config.check_valid();
25    let builder = ExprBuilder::new(config, range_bus.range_max_bits);
26    let builder = Rc::new(RefCell::new(builder));
27
28    let x1 = ExprBuilder::new_input(builder.clone());
29    let x2 = ExprBuilder::new_input(builder.clone());
30    let x3 = x1.clone() + x2.clone();
31    let x4 = x1.clone() - x2.clone();
32    let is_add_flag = builder.borrow_mut().new_flag();
33    let is_sub_flag = builder.borrow_mut().new_flag();
34    let x5 = FieldVariable::select(is_sub_flag, &x4, &x1);
35    let mut x6 = FieldVariable::select(is_add_flag, &x3, &x5);
36    x6.save_output();
37    let builder = builder.borrow().clone();
38
39    (
40        FieldExpr::new(builder, range_bus, true),
41        is_add_flag,
42        is_sub_flag,
43    )
44}
45
46#[derive(Chip, ChipUsageGetter, InstructionExecutor)]
47pub struct ModularAddSubChip<F: PrimeField32, const BLOCKS: usize, const BLOCK_SIZE: usize>(
48    pub  VmChipWrapper<
49        F,
50        Rv32VecHeapAdapterChip<F, 2, BLOCKS, BLOCKS, BLOCK_SIZE, BLOCK_SIZE>,
51        FieldExpressionCoreChip,
52    >,
53);
54
55impl<F: PrimeField32, const BLOCKS: usize, const BLOCK_SIZE: usize>
56    ModularAddSubChip<F, BLOCKS, BLOCK_SIZE>
57{
58    pub fn new(
59        adapter: Rv32VecHeapAdapterChip<F, 2, BLOCKS, BLOCKS, BLOCK_SIZE, BLOCK_SIZE>,
60        config: ExprBuilderConfig,
61        offset: usize,
62        range_checker: SharedVariableRangeCheckerChip,
63        offline_memory: Arc<Mutex<OfflineMemory<F>>>,
64    ) -> Self {
65        let (expr, is_add_flag, is_sub_flag) = addsub_expr(config, range_checker.bus());
66        let core = FieldExpressionCoreChip::new(
67            expr,
68            offset,
69            vec![
70                Rv32ModularArithmeticOpcode::ADD as usize,
71                Rv32ModularArithmeticOpcode::SUB as usize,
72                Rv32ModularArithmeticOpcode::SETUP_ADDSUB as usize,
73            ],
74            vec![is_add_flag, is_sub_flag],
75            range_checker,
76            "ModularAddSub",
77            false,
78        );
79        Self(VmChipWrapper::new(adapter, core, offline_memory))
80    }
81}