openvm_bigint_transpiler/
lib.rs

1use openvm_bigint_guest::{Int256Funct7, BEQ256_FUNCT3, INT256_FUNCT3, OPCODE};
2use openvm_instructions::{
3    instruction::Instruction, riscv::RV32_REGISTER_NUM_LIMBS, utils::isize_to_field, LocalOpcode,
4    VmOpcode,
5};
6use openvm_instructions_derive::LocalOpcode;
7use openvm_rv32im_transpiler::{
8    BaseAluOpcode, BranchEqualOpcode, BranchLessThanOpcode, LessThanOpcode, MulOpcode, ShiftOpcode,
9};
10use openvm_stark_backend::p3_field::PrimeField32;
11use openvm_transpiler::{util::from_r_type, TranspilerExtension, TranspilerOutput};
12use rrs_lib::instruction_formats::{BType, RType};
13use strum::IntoEnumIterator;
14
15// =================================================================================================
16// Intrinsics: 256-bit Integers
17// =================================================================================================
18
19#[derive(Copy, Clone, Debug, LocalOpcode)]
20#[opcode_offset = 0x400]
21pub struct Rv32BaseAlu256Opcode(pub BaseAluOpcode);
22
23impl Rv32BaseAlu256Opcode {
24    pub fn iter() -> impl Iterator<Item = Self> {
25        BaseAluOpcode::iter().map(Self)
26    }
27}
28
29#[derive(Copy, Clone, Debug, LocalOpcode)]
30#[opcode_offset = 0x405]
31pub struct Rv32Shift256Opcode(pub ShiftOpcode);
32
33impl Rv32Shift256Opcode {
34    pub fn iter() -> impl Iterator<Item = Self> {
35        ShiftOpcode::iter().map(Self)
36    }
37}
38
39#[derive(Copy, Clone, Debug, LocalOpcode)]
40#[opcode_offset = 0x408]
41pub struct Rv32LessThan256Opcode(pub LessThanOpcode);
42
43impl Rv32LessThan256Opcode {
44    pub fn iter() -> impl Iterator<Item = Self> {
45        LessThanOpcode::iter().map(Self)
46    }
47}
48
49#[derive(Copy, Clone, Debug, LocalOpcode)]
50#[opcode_offset = 0x420]
51pub struct Rv32BranchEqual256Opcode(pub BranchEqualOpcode);
52
53impl Rv32BranchEqual256Opcode {
54    pub fn iter() -> impl Iterator<Item = Self> {
55        BranchEqualOpcode::iter().map(Self)
56    }
57}
58
59#[derive(Copy, Clone, Debug, LocalOpcode)]
60#[opcode_offset = 0x425]
61pub struct Rv32BranchLessThan256Opcode(pub BranchLessThanOpcode);
62
63impl Rv32BranchLessThan256Opcode {
64    pub fn iter() -> impl Iterator<Item = Self> {
65        BranchLessThanOpcode::iter().map(Self)
66    }
67}
68
69#[derive(Copy, Clone, Debug, LocalOpcode)]
70#[opcode_offset = 0x450]
71pub struct Rv32Mul256Opcode(pub MulOpcode);
72
73impl Rv32Mul256Opcode {
74    pub fn iter() -> impl Iterator<Item = Self> {
75        MulOpcode::iter().map(Self)
76    }
77}
78
79#[derive(Default)]
80pub struct Int256TranspilerExtension;
81
82impl<F: PrimeField32> TranspilerExtension<F> for Int256TranspilerExtension {
83    fn process_custom(&self, instruction_stream: &[u32]) -> Option<TranspilerOutput<F>> {
84        if instruction_stream.is_empty() {
85            return None;
86        }
87        let instruction_u32 = instruction_stream[0];
88        let opcode = (instruction_u32 & 0x7f) as u8;
89        let funct3 = ((instruction_u32 >> 12) & 0b111) as u8;
90
91        if opcode != OPCODE {
92            return None;
93        }
94        if funct3 != INT256_FUNCT3 && funct3 != BEQ256_FUNCT3 {
95            return None;
96        }
97
98        let dec_insn = RType::new(instruction_u32);
99        let instruction = match funct3 {
100            INT256_FUNCT3 => {
101                let global_opcode = match Int256Funct7::from_repr(dec_insn.funct7 as u8) {
102                    Some(Int256Funct7::Add) => {
103                        BaseAluOpcode::ADD as usize + Rv32BaseAlu256Opcode::CLASS_OFFSET
104                    }
105                    Some(Int256Funct7::Sub) => {
106                        BaseAluOpcode::SUB as usize + Rv32BaseAlu256Opcode::CLASS_OFFSET
107                    }
108                    Some(Int256Funct7::Xor) => {
109                        BaseAluOpcode::XOR as usize + Rv32BaseAlu256Opcode::CLASS_OFFSET
110                    }
111                    Some(Int256Funct7::Or) => {
112                        BaseAluOpcode::OR as usize + Rv32BaseAlu256Opcode::CLASS_OFFSET
113                    }
114                    Some(Int256Funct7::And) => {
115                        BaseAluOpcode::AND as usize + Rv32BaseAlu256Opcode::CLASS_OFFSET
116                    }
117                    Some(Int256Funct7::Sll) => {
118                        ShiftOpcode::SLL as usize + Rv32Shift256Opcode::CLASS_OFFSET
119                    }
120                    Some(Int256Funct7::Srl) => {
121                        ShiftOpcode::SRL as usize + Rv32Shift256Opcode::CLASS_OFFSET
122                    }
123                    Some(Int256Funct7::Sra) => {
124                        ShiftOpcode::SRA as usize + Rv32Shift256Opcode::CLASS_OFFSET
125                    }
126                    Some(Int256Funct7::Slt) => {
127                        LessThanOpcode::SLT as usize + Rv32LessThan256Opcode::CLASS_OFFSET
128                    }
129                    Some(Int256Funct7::Sltu) => {
130                        LessThanOpcode::SLTU as usize + Rv32LessThan256Opcode::CLASS_OFFSET
131                    }
132                    Some(Int256Funct7::Mul) => {
133                        MulOpcode::MUL as usize + Rv32Mul256Opcode::CLASS_OFFSET
134                    }
135                    _ => unimplemented!(),
136                };
137                Some(from_r_type(global_opcode, 2, &dec_insn, true))
138            }
139            BEQ256_FUNCT3 => {
140                let dec_insn = BType::new(instruction_u32);
141                Some(Instruction::new(
142                    VmOpcode::from_usize(
143                        BranchEqualOpcode::BEQ.local_usize()
144                            + Rv32BranchEqual256Opcode::CLASS_OFFSET,
145                    ),
146                    F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs1),
147                    F::from_canonical_usize(RV32_REGISTER_NUM_LIMBS * dec_insn.rs2),
148                    isize_to_field(dec_insn.imm as isize),
149                    F::ONE,
150                    F::TWO,
151                    F::ZERO,
152                    F::ZERO,
153                ))
154            }
155            _ => None,
156        };
157        instruction.map(TranspilerOutput::one_to_one)
158    }
159}