openvm_keccak256_circuit/extension/
mod.rs1use std::{result::Result, sync::Arc};
2
3use derive_more::derive::From;
4use openvm_circuit::{
5 arch::{
6 AirInventory, AirInventoryError, ChipInventory, ChipInventoryError, ExecutionBridge,
7 ExecutorInventoryBuilder, ExecutorInventoryError, InitFileGenerator, MatrixRecordArena,
8 RowMajorMatrixArena, SystemConfig, VmBuilder, VmChipComplex, VmCircuitExtension,
9 VmExecutionExtension, VmProverExtension,
10 },
11 system::{
12 memory::SharedMemoryHelper, SystemChipInventory, SystemCpuBuilder, SystemExecutor,
13 SystemPort,
14 },
15};
16use openvm_circuit_derive::{AnyEnum, Executor, MeteredExecutor, PreflightExecutor, VmConfig};
17use openvm_circuit_primitives::bitwise_op_lookup::{
18 BitwiseOperationLookupAir, BitwiseOperationLookupBus, BitwiseOperationLookupChip,
19 SharedBitwiseOperationLookupChip,
20};
21use openvm_instructions::*;
22use openvm_keccak256_transpiler::Rv32KeccakOpcode;
23use openvm_rv32im_circuit::{
24 Rv32I, Rv32IExecutor, Rv32ImCpuProverExt, Rv32Io, Rv32IoExecutor, Rv32M, Rv32MExecutor,
25};
26use openvm_stark_backend::{
27 config::{StarkGenericConfig, Val},
28 p3_field::PrimeField32,
29 prover::cpu::{CpuBackend, CpuDevice},
30};
31use openvm_stark_sdk::engine::StarkEngine;
32use serde::{Deserialize, Serialize};
33use strum::IntoEnumIterator;
34
35use crate::{KeccakVmAir, KeccakVmChip, KeccakVmExecutor, KeccakVmFiller};
36
37cfg_if::cfg_if! {
38 if #[cfg(feature = "cuda")] {
39 mod cuda;
40 pub use cuda::*;
41 pub use cuda::{
42 Keccak256GpuProverExt as Keccak256ProverExt,
43 Keccak256Rv32GpuBuilder as Keccak256Rv32Builder,
44 };
45 } else {
46 pub use self::{
47 Keccak256CpuProverExt as Keccak256ProverExt,
48 Keccak256Rv32CpuBuilder as Keccak256Rv32Builder,
49 };
50 }
51}
52
53#[derive(Clone, Debug, VmConfig, derive_new::new, Serialize, Deserialize)]
54pub struct Keccak256Rv32Config {
55 #[config(executor = "SystemExecutor<F>")]
56 pub system: SystemConfig,
57 #[extension]
58 pub rv32i: Rv32I,
59 #[extension]
60 pub rv32m: Rv32M,
61 #[extension]
62 pub io: Rv32Io,
63 #[extension]
64 pub keccak: Keccak256,
65}
66
67impl Default for Keccak256Rv32Config {
68 fn default() -> Self {
69 Self {
70 system: SystemConfig::default(),
71 rv32i: Rv32I,
72 rv32m: Rv32M::default(),
73 io: Rv32Io,
74 keccak: Keccak256,
75 }
76 }
77}
78
79impl InitFileGenerator for Keccak256Rv32Config {}
81
82#[derive(Clone)]
83pub struct Keccak256Rv32CpuBuilder;
84
85impl<E, SC> VmBuilder<E> for Keccak256Rv32CpuBuilder
86where
87 SC: StarkGenericConfig,
88 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
89 Val<SC>: PrimeField32,
90{
91 type VmConfig = Keccak256Rv32Config;
92 type SystemChipInventory = SystemChipInventory<SC>;
93 type RecordArena = MatrixRecordArena<Val<SC>>;
94
95 fn create_chip_complex(
96 &self,
97 config: &Keccak256Rv32Config,
98 circuit: AirInventory<SC>,
99 ) -> Result<
100 VmChipComplex<SC, Self::RecordArena, E::PB, Self::SystemChipInventory>,
101 ChipInventoryError,
102 > {
103 let mut chip_complex =
104 VmBuilder::<E>::create_chip_complex(&SystemCpuBuilder, &config.system, circuit)?;
105 let inventory = &mut chip_complex.inventory;
106 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.rv32i, inventory)?;
107 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.rv32m, inventory)?;
108 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.io, inventory)?;
109 VmProverExtension::<E, _, _>::extend_prover(
110 &Keccak256CpuProverExt,
111 &config.keccak,
112 inventory,
113 )?;
114 Ok(chip_complex)
115 }
116}
117
118#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
120pub struct Keccak256;
121
122#[derive(Clone, Copy, From, AnyEnum, Executor, MeteredExecutor, PreflightExecutor)]
123pub enum Keccak256Executor {
124 Keccak256(KeccakVmExecutor),
125}
126
127impl<F> VmExecutionExtension<F> for Keccak256 {
128 type Executor = Keccak256Executor;
129
130 fn extend_execution(
131 &self,
132 inventory: &mut ExecutorInventoryBuilder<F, Keccak256Executor>,
133 ) -> Result<(), ExecutorInventoryError> {
134 let pointer_max_bits = inventory.pointer_max_bits();
135 let keccak_step = KeccakVmExecutor::new(Rv32KeccakOpcode::CLASS_OFFSET, pointer_max_bits);
136 inventory.add_executor(
137 keccak_step,
138 Rv32KeccakOpcode::iter().map(|x| x.global_opcode()),
139 )?;
140
141 Ok(())
142 }
143}
144
145impl<SC: StarkGenericConfig> VmCircuitExtension<SC> for Keccak256 {
146 fn extend_circuit(&self, inventory: &mut AirInventory<SC>) -> Result<(), AirInventoryError> {
147 let SystemPort {
148 execution_bus,
149 program_bus,
150 memory_bridge,
151 } = inventory.system().port();
152
153 let exec_bridge = ExecutionBridge::new(execution_bus, program_bus);
154 let pointer_max_bits = inventory.pointer_max_bits();
155
156 let bitwise_lu = {
157 let existing_air = inventory.find_air::<BitwiseOperationLookupAir<8>>().next();
158 if let Some(air) = existing_air {
159 air.bus
160 } else {
161 let bus = BitwiseOperationLookupBus::new(inventory.new_bus_idx());
162 let air = BitwiseOperationLookupAir::<8>::new(bus);
163 inventory.add_air(air);
164 air.bus
165 }
166 };
167
168 let keccak = KeccakVmAir::new(
169 exec_bridge,
170 memory_bridge,
171 bitwise_lu,
172 pointer_max_bits,
173 Rv32KeccakOpcode::CLASS_OFFSET,
174 );
175 inventory.add_air(keccak);
176
177 Ok(())
178 }
179}
180
181pub struct Keccak256CpuProverExt;
182impl<E, SC, RA> VmProverExtension<E, RA, Keccak256> for Keccak256CpuProverExt
185where
186 SC: StarkGenericConfig,
187 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
188 RA: RowMajorMatrixArena<Val<SC>>,
189 Val<SC>: PrimeField32,
190{
191 fn extend_prover(
192 &self,
193 _: &Keccak256,
194 inventory: &mut ChipInventory<SC, RA, CpuBackend<SC>>,
195 ) -> Result<(), ChipInventoryError> {
196 let range_checker = inventory.range_checker()?.clone();
197 let timestamp_max_bits = inventory.timestamp_max_bits();
198 let mem_helper = SharedMemoryHelper::new(range_checker.clone(), timestamp_max_bits);
199 let pointer_max_bits = inventory.airs().pointer_max_bits();
200
201 let bitwise_lu = {
202 let existing_chip = inventory
203 .find_chip::<SharedBitwiseOperationLookupChip<8>>()
204 .next();
205 if let Some(chip) = existing_chip {
206 chip.clone()
207 } else {
208 let air: &BitwiseOperationLookupAir<8> = inventory.next_air()?;
209 let chip = Arc::new(BitwiseOperationLookupChip::new(air.bus));
210 inventory.add_periphery_chip(chip.clone());
211 chip
212 }
213 };
214
215 inventory.next_air::<KeccakVmAir>()?;
216 let keccak = KeccakVmChip::new(
217 KeccakVmFiller::new(bitwise_lu, pointer_max_bits),
218 mem_helper,
219 );
220 inventory.add_executor_chip(keccak);
221
222 Ok(())
223 }
224}