Skip to main content

openvm_ecc_circuit/weierstrass_chip/add_ne/
mod.rs

1use std::{
2    cell::RefCell,
3    ops::{Deref, DerefMut},
4    rc::Rc,
5};
6
7use openvm_algebra_circuit::fields::{get_field_type, FieldType};
8use openvm_circuit::{
9    arch::*,
10    system::memory::{offline_checker::MemoryBridge, SharedMemoryHelper},
11};
12use openvm_circuit_primitives::{
13    bitwise_op_lookup::{BitwiseOperationLookupBus, SharedBitwiseOperationLookupChip},
14    var_range::{SharedVariableRangeCheckerChip, VariableRangeCheckerBus},
15};
16use openvm_ecc_transpiler::Rv32WeierstrassOpcode;
17use openvm_instructions::riscv::RV32_CELL_BITS;
18use openvm_mod_circuit_builder::{
19    ExprBuilder, ExprBuilderConfig, FieldExpr, FieldExpressionCoreAir, FieldExpressionExecutor,
20    FieldExpressionFiller,
21};
22use openvm_rv32_adapters::{
23    Rv32VecHeapAdapterAir, Rv32VecHeapAdapterExecutor, Rv32VecHeapAdapterFiller,
24};
25
26use super::{WeierstrassAir, WeierstrassChip};
27
28mod execution;
29
30// Assumes that (x1, y1), (x2, y2) both lie on the curve and are not the identity point.
31// Further assumes that x1, x2 are not equal in the coordinate field.
32pub fn ec_add_ne_expr(
33    config: ExprBuilderConfig, // The coordinate field.
34    range_bus: VariableRangeCheckerBus,
35) -> FieldExpr {
36    config.check_valid();
37    let builder = ExprBuilder::new(config, range_bus.range_max_bits);
38    let builder = Rc::new(RefCell::new(builder));
39
40    let x1 = ExprBuilder::new_input(builder.clone());
41    let y1 = ExprBuilder::new_input(builder.clone());
42    let x2 = ExprBuilder::new_input(builder.clone());
43    let y2 = ExprBuilder::new_input(builder.clone());
44    let mut lambda = (y2 - y1.clone()) / (x2.clone() - x1.clone());
45    let mut x3 = lambda.square() - x1.clone() - x2;
46    x3.save_output();
47    let mut y3 = lambda * (x1 - x3.clone()) - y1;
48    y3.save_output();
49
50    let builder = (*builder).borrow().clone();
51    FieldExpr::new(builder, range_bus, true)
52}
53
54/// BLOCK_SIZE: how many cells do we read at a time, must be a power of 2.
55/// BLOCKS: how many blocks do we need to represent one input or output
56/// For example, for bls12_381, BLOCK_SIZE = 16, each element has 3 blocks and with two elements per
57/// input AffinePoint, BLOCKS = 6. For secp256k1, BLOCK_SIZE = 32, BLOCKS = 2.
58// Note: PreflightExecutor is implemented manually in preflight.rs with fast native arithmetic
59#[derive(Clone)]
60pub struct EcAddNeExecutor<const BLOCKS: usize, const BLOCK_SIZE: usize> {
61    pub(crate) inner: FieldExpressionExecutor<
62        Rv32VecHeapAdapterExecutor<2, BLOCKS, BLOCKS, BLOCK_SIZE, BLOCK_SIZE>,
63    >,
64    pub(crate) cached_field_type: Option<FieldType>,
65}
66
67impl<const BLOCKS: usize, const BLOCK_SIZE: usize> EcAddNeExecutor<BLOCKS, BLOCK_SIZE> {
68    pub fn new(
69        inner: FieldExpressionExecutor<
70            Rv32VecHeapAdapterExecutor<2, BLOCKS, BLOCKS, BLOCK_SIZE, BLOCK_SIZE>,
71        >,
72    ) -> Self {
73        let cached_field_type = get_field_type(&inner.expr.prime);
74        Self {
75            inner,
76            cached_field_type,
77        }
78    }
79}
80
81impl<const BLOCKS: usize, const BLOCK_SIZE: usize> Deref for EcAddNeExecutor<BLOCKS, BLOCK_SIZE> {
82    type Target = FieldExpressionExecutor<
83        Rv32VecHeapAdapterExecutor<2, BLOCKS, BLOCKS, BLOCK_SIZE, BLOCK_SIZE>,
84    >;
85
86    fn deref(&self) -> &Self::Target {
87        &self.inner
88    }
89}
90
91impl<const BLOCKS: usize, const BLOCK_SIZE: usize> DerefMut
92    for EcAddNeExecutor<BLOCKS, BLOCK_SIZE>
93{
94    fn deref_mut(&mut self) -> &mut Self::Target {
95        &mut self.inner
96    }
97}
98
99fn gen_base_expr(
100    config: ExprBuilderConfig,
101    range_checker_bus: VariableRangeCheckerBus,
102) -> (FieldExpr, Vec<usize>) {
103    let expr = ec_add_ne_expr(config, range_checker_bus);
104
105    let local_opcode_idx = vec![
106        Rv32WeierstrassOpcode::EC_ADD_NE as usize,
107        Rv32WeierstrassOpcode::SETUP_EC_ADD_NE as usize,
108    ];
109
110    (expr, local_opcode_idx)
111}
112
113pub fn get_ec_addne_air<const BLOCKS: usize, const BLOCK_SIZE: usize>(
114    exec_bridge: ExecutionBridge,
115    mem_bridge: MemoryBridge,
116    config: ExprBuilderConfig,
117    range_checker_bus: VariableRangeCheckerBus,
118    bitwise_lookup_bus: BitwiseOperationLookupBus,
119    pointer_max_bits: usize,
120    offset: usize,
121) -> WeierstrassAir<2, BLOCKS, BLOCK_SIZE> {
122    let (expr, local_opcode_idx) = gen_base_expr(config, range_checker_bus);
123    WeierstrassAir::new(
124        Rv32VecHeapAdapterAir::new(
125            exec_bridge,
126            mem_bridge,
127            bitwise_lookup_bus,
128            pointer_max_bits,
129        ),
130        FieldExpressionCoreAir::new(expr.clone(), offset, local_opcode_idx.clone(), vec![]),
131    )
132}
133
134pub fn get_ec_addne_executor<const BLOCKS: usize, const BLOCK_SIZE: usize>(
135    config: ExprBuilderConfig,
136    range_checker_bus: VariableRangeCheckerBus,
137    pointer_max_bits: usize,
138    offset: usize,
139) -> EcAddNeExecutor<BLOCKS, BLOCK_SIZE> {
140    let (expr, local_opcode_idx) = gen_base_expr(config, range_checker_bus);
141    EcAddNeExecutor::new(FieldExpressionExecutor::new(
142        Rv32VecHeapAdapterExecutor::new(pointer_max_bits),
143        expr,
144        offset,
145        local_opcode_idx,
146        vec![],
147        "EcAddNe",
148    ))
149}
150
151pub fn get_ec_addne_chip<F, const BLOCKS: usize, const BLOCK_SIZE: usize>(
152    config: ExprBuilderConfig,
153    mem_helper: SharedMemoryHelper<F>,
154    range_checker: SharedVariableRangeCheckerChip,
155    bitwise_lookup_chip: SharedBitwiseOperationLookupChip<RV32_CELL_BITS>,
156    pointer_max_bits: usize,
157) -> WeierstrassChip<F, 2, BLOCKS, BLOCK_SIZE> {
158    let (expr, local_opcode_idx) = gen_base_expr(config, range_checker.bus());
159    WeierstrassChip::new(
160        FieldExpressionFiller::new(
161            Rv32VecHeapAdapterFiller::new(pointer_max_bits, bitwise_lookup_chip),
162            expr,
163            local_opcode_idx,
164            vec![],
165            range_checker,
166            false,
167        ),
168        mem_helper,
169    )
170}