1use std::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, VmField, VmProverExtension,
10 },
11 system::{memory::SharedMemoryHelper, SystemChipInventory, SystemCpuBuilder, SystemExecutor},
12};
13use openvm_circuit_derive::{AnyEnum, Executor, MeteredExecutor, PreflightExecutor, VmConfig};
14use openvm_circuit_primitives::bitwise_op_lookup::{
15 BitwiseOperationLookupAir, BitwiseOperationLookupBus, BitwiseOperationLookupChip,
16 SharedBitwiseOperationLookupChip,
17};
18use openvm_cpu_backend::{CpuBackend, CpuDevice};
19use openvm_deferral_transpiler::DeferralOpcode;
20use openvm_instructions::LocalOpcode;
21use openvm_rv32im_circuit::{
22 Rv32I, Rv32IExecutor, Rv32ImCpuProverExt, Rv32Io, Rv32IoExecutor, Rv32M, Rv32MExecutor,
23};
24use openvm_stark_backend::{StarkEngine, StarkProtocolConfig, Val};
25use serde::{Deserialize, Serialize};
26
27use crate::{
28 call::{
29 DeferralCallAdapterAir, DeferralCallAdapterExecutor, DeferralCallAdapterFiller,
30 DeferralCallAir, DeferralCallChip, DeferralCallCoreAir, DeferralCallCoreFiller,
31 DeferralCallExecutor,
32 },
33 count::{DeferralCircuitCountAir, DeferralCircuitCountBus, DeferralCircuitCountChip},
34 output::{DeferralOutputAir, DeferralOutputChip, DeferralOutputExecutor, DeferralOutputFiller},
35 poseidon2::{
36 deferral_poseidon2_air, deferral_poseidon2_chip, DeferralPoseidon2Air, DeferralPoseidon2Bus,
37 },
38 utils::COMMIT_NUM_BYTES,
39 DeferralFn,
40};
41
42cfg_if::cfg_if! {
43 if #[cfg(feature = "cuda")] {
44 mod cuda;
45 pub use self::cuda::DeferralGpuProverExt as DeferralProverExt;
46 pub use self::cuda::Rv32DeferralGpuBuilder as Rv32DeferralBuilder;
47
48 } else {
49 pub use self::DeferralCpuProverExt as DeferralProverExt;
50 pub use self::Rv32DeferralCpuBuilder as Rv32DeferralBuilder;
51 }
52}
53
54pub(crate) const POSEIDON2_AIR_REL_IDX: usize = 1;
56pub(crate) const CALL_AIR_REL_IDX: usize = 2;
57pub(crate) const OUTPUT_AIR_REL_IDX: usize = 3;
58
59#[derive(Clone, Debug, Default, Serialize, Deserialize, derive_new::new)]
62pub struct DeferralExtension {
63 #[serde(skip)]
64 pub fns: Vec<Arc<DeferralFn>>,
65 pub def_circuit_commits: Vec<[u8; COMMIT_NUM_BYTES]>,
66}
67
68#[derive(Clone, From, AnyEnum, Executor, MeteredExecutor, PreflightExecutor)]
69#[cfg_attr(
70 feature = "aot",
71 derive(
72 openvm_circuit_derive::AotExecutor,
73 openvm_circuit_derive::AotMeteredExecutor
74 )
75)]
76pub enum DeferralExecutor {
77 Call(DeferralCallExecutor),
78 Output(DeferralOutputExecutor),
79}
80
81impl<F: VmField> VmExecutionExtension<F> for DeferralExtension {
82 type Executor = DeferralExecutor;
83
84 fn extend_execution(
85 &self,
86 inventory: &mut ExecutorInventoryBuilder<F, DeferralExecutor>,
87 ) -> Result<(), ExecutorInventoryError> {
88 let call = DeferralCallExecutor::new(DeferralCallAdapterExecutor, self.fns.clone());
89 inventory.add_executor(call, [DeferralOpcode::CALL.global_opcode()])?;
90
91 inventory.add_executor(
92 DeferralOutputExecutor::new(),
93 [DeferralOpcode::OUTPUT.global_opcode()],
94 )?;
95
96 Ok(())
97 }
98}
99
100impl<SC: StarkProtocolConfig> VmCircuitExtension<SC> for DeferralExtension
101where
102 Val<SC>: VmField,
103{
104 fn extend_circuit(&self, inventory: &mut AirInventory<SC>) -> Result<(), AirInventoryError> {
105 let memory_bridge = inventory.system().port().memory_bridge;
106 let execution_bridge = ExecutionBridge::new(
107 inventory.system().port().execution_bus,
108 inventory.system().port().program_bus,
109 );
110
111 let count_bus = DeferralCircuitCountBus::new(inventory.new_bus_idx());
112 let poseidon2_bus = DeferralPoseidon2Bus::new(inventory.new_bus_idx());
113 let bitwise_bus = {
114 let existing_air = inventory.find_air::<BitwiseOperationLookupAir<8>>().next();
115 if let Some(air) = existing_air {
116 air.bus
117 } else {
118 let bus = BitwiseOperationLookupBus::new(inventory.new_bus_idx());
119 let air = BitwiseOperationLookupAir::<8>::new(bus);
120 inventory.add_air(air);
121 air.bus
122 }
123 };
124
125 let base_num_airs = inventory.num_airs();
126 let address_bits = inventory.pointer_max_bits();
127
128 inventory.add_air(DeferralCircuitCountAir::new(count_bus, self.fns.len()));
129
130 assert_eq!(inventory.num_airs() - base_num_airs, POSEIDON2_AIR_REL_IDX);
131 inventory.add_air_ref(Arc::new(deferral_poseidon2_air(poseidon2_bus.0)));
132
133 assert_eq!(inventory.num_airs() - base_num_airs, CALL_AIR_REL_IDX);
134 inventory.add_air(DeferralCallAir::new(
135 DeferralCallAdapterAir::new(execution_bridge, memory_bridge, bitwise_bus, address_bits),
136 DeferralCallCoreAir::new(count_bus, poseidon2_bus, bitwise_bus),
137 ));
138
139 assert_eq!(inventory.num_airs() - base_num_airs, OUTPUT_AIR_REL_IDX);
140 inventory.add_air(DeferralOutputAir::new(
141 execution_bridge,
142 memory_bridge,
143 count_bus,
144 poseidon2_bus,
145 bitwise_bus,
146 address_bits,
147 ));
148
149 Ok(())
150 }
151}
152
153pub struct DeferralCpuProverExt;
154
155impl<SC, E, RA> VmProverExtension<E, RA, DeferralExtension> for DeferralCpuProverExt
156where
157 SC: StarkProtocolConfig,
158 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
159 RA: RowMajorMatrixArena<Val<SC>>,
160 Val<SC>: VmField,
161 SC::EF: Ord,
162{
163 fn extend_prover(
164 &self,
165 extension: &DeferralExtension,
166 inventory: &mut ChipInventory<SC, RA, CpuBackend<SC>>,
167 ) -> Result<(), ChipInventoryError> {
168 let range_checker = inventory.range_checker()?.clone();
169 let timestamp_max_bits = inventory.timestamp_max_bits();
170 let address_bits = inventory.airs().pointer_max_bits();
171 let mem_helper = SharedMemoryHelper::new(range_checker.clone(), timestamp_max_bits);
172 let bitwise_lu = {
173 let existing_chip = inventory
174 .find_chip::<SharedBitwiseOperationLookupChip<8>>()
175 .next();
176 if let Some(chip) = existing_chip {
177 chip.clone()
178 } else {
179 let air: &BitwiseOperationLookupAir<8> = inventory.next_air()?;
180 let chip = Arc::new(BitwiseOperationLookupChip::new(air.bus));
181 inventory.add_periphery_chip(chip.clone());
182 chip
183 }
184 };
185 let count_chip = Arc::new(DeferralCircuitCountChip::new(extension.fns.len()));
186 let poseidon2_chip = Arc::new(deferral_poseidon2_chip());
187
188 inventory.next_air::<DeferralCircuitCountAir>()?;
189 inventory.add_periphery_chip(count_chip.clone());
190
191 inventory.next_air::<DeferralPoseidon2Air<Val<SC>>>()?;
192 inventory.add_periphery_chip(poseidon2_chip.clone());
193
194 inventory.next_air::<DeferralCallAir>()?;
195 inventory.add_executor_chip(DeferralCallChip::new(
196 DeferralCallCoreFiller::new(
197 DeferralCallAdapterFiller::new(bitwise_lu.clone(), address_bits),
198 count_chip.clone(),
199 poseidon2_chip.clone(),
200 bitwise_lu.clone(),
201 address_bits,
202 ),
203 mem_helper.clone(),
204 ));
205
206 inventory.next_air::<DeferralOutputAir>()?;
207 inventory.add_executor_chip(DeferralOutputChip::new(
208 DeferralOutputFiller::new(
209 count_chip.clone(),
210 poseidon2_chip.clone(),
211 bitwise_lu,
212 address_bits,
213 ),
214 mem_helper,
215 ));
216
217 Ok(())
218 }
219}
220
221#[derive(Clone, VmConfig, Serialize, Deserialize)]
224pub struct Rv32DeferralConfig {
225 #[config(executor = "SystemExecutor<F>")]
226 pub system: SystemConfig,
227 #[extension]
228 pub rv32i: Rv32I,
229 #[extension]
230 pub rv32m: Rv32M,
231 #[extension]
232 pub io: Rv32Io,
233 #[serde(skip)]
234 #[extension(executor = "DeferralExecutor")]
235 pub deferral: DeferralExtension,
236}
237
238impl InitFileGenerator for Rv32DeferralConfig {}
239
240#[derive(Clone)]
241pub struct Rv32DeferralCpuBuilder;
242
243impl<SC, E> VmBuilder<E> for Rv32DeferralCpuBuilder
244where
245 SC: StarkProtocolConfig,
246 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
247 Val<SC>: VmField,
248 SC::EF: Ord,
249{
250 type VmConfig = Rv32DeferralConfig;
251 type SystemChipInventory = SystemChipInventory<SC>;
252 type RecordArena = MatrixRecordArena<Val<SC>>;
253
254 fn create_chip_complex(
255 &self,
256 config: &Self::VmConfig,
257 circuit: AirInventory<SC>,
258 device_ctx: &openvm_stark_backend::EngineDeviceCtx<E>,
259 ) -> Result<
260 VmChipComplex<SC, Self::RecordArena, E::PB, Self::SystemChipInventory>,
261 ChipInventoryError,
262 > {
263 let mut chip_complex = VmBuilder::<E>::create_chip_complex(
264 &SystemCpuBuilder,
265 &config.system,
266 circuit,
267 device_ctx,
268 )?;
269 let inventory = &mut chip_complex.inventory;
270 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.rv32i, inventory)?;
271 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.rv32m, inventory)?;
272 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.io, inventory)?;
273 VmProverExtension::<E, _, _>::extend_prover(
274 &DeferralCpuProverExt,
275 &config.deferral,
276 inventory,
277 )?;
278 Ok(chip_complex)
279 }
280}