openvm_ecc_circuit/weierstrass_chip/add_ne/
mod.rs

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