openvm_keccak256_transpiler/
lib.rs1use core::panic;
2
3use openvm_instructions::{riscv::RV32_MEMORY_AS, LocalOpcode};
4use openvm_instructions_derive::LocalOpcode;
5use openvm_keccak256_guest::{KECCAKF_FUNCT7, OPCODE, XORIN_FUNCT3, XORIN_FUNCT7};
6use openvm_stark_backend::p3_field::PrimeField32;
7use openvm_transpiler::{util::from_r_type, TranspilerExtension, TranspilerOutput};
8use rrs_lib::instruction_formats::RType;
9use strum::{EnumCount, EnumIter, FromRepr};
10
11#[derive(
12 Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EnumCount, EnumIter, FromRepr, LocalOpcode,
13)]
14#[opcode_offset = 0x310]
15#[repr(usize)]
16pub enum KeccakfOpcode {
17 KECCAKF,
18}
19
20#[derive(
21 Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EnumCount, EnumIter, FromRepr, LocalOpcode,
22)]
23#[opcode_offset = 0x311]
24#[repr(usize)]
25pub enum XorinOpcode {
26 XORIN,
27}
28
29#[derive(Default)]
30pub struct Keccak256TranspilerExtension;
31
32impl<F: PrimeField32> TranspilerExtension<F> for Keccak256TranspilerExtension {
33 fn process_custom(&self, instruction_stream: &[u32]) -> Option<TranspilerOutput<F>> {
34 if instruction_stream.is_empty() {
35 return None;
36 }
37 let instruction_u32 = instruction_stream[0];
38 let opcode = (instruction_u32 & 0x7f) as u8;
39 let funct3 = ((instruction_u32 >> 12) & 0b111) as u8;
40
41 if (opcode, funct3) != (OPCODE, XORIN_FUNCT3) {
43 return None;
44 }
45
46 let dec_insn = RType::new(instruction_u32);
47
48 if dec_insn.funct7 != XORIN_FUNCT7 as u32 && dec_insn.funct7 != KECCAKF_FUNCT7 as u32 {
49 return None;
50 }
51
52 let instruction = if dec_insn.funct7 == XORIN_FUNCT7 as u32 {
53 from_r_type(
54 XorinOpcode::XORIN.global_opcode().as_usize(),
55 RV32_MEMORY_AS as usize,
56 &dec_insn,
57 true,
58 )
59 } else {
60 from_r_type(
61 KeccakfOpcode::KECCAKF.global_opcode().as_usize(),
62 RV32_MEMORY_AS as usize,
63 &dec_insn,
64 true,
65 )
66 };
67
68 Some(TranspilerOutput::one_to_one(instruction))
69 }
70}