1use std::{
2 result::Result,
3 sync::{Arc, Mutex},
4};
5
6use derive_more::derive::From;
7use openvm_circuit::{
8 arch::{
9 AirInventory, AirInventoryError, ChipInventory, ChipInventoryError,
10 ExecutorInventoryBuilder, ExecutorInventoryError, InitFileGenerator, MatrixRecordArena,
11 RowMajorMatrixArena, SystemConfig, VmBuilder, VmChipComplex, VmCircuitExtension,
12 VmExecutionExtension, VmField, VmProverExtension,
13 },
14 system::{memory::SharedMemoryHelper, SystemChipInventory, SystemCpuBuilder, SystemExecutor},
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_cpu_backend::{CpuBackend, CpuDevice};
22use openvm_instructions::LocalOpcode;
23use openvm_rv32im_circuit::{
24 Rv32I, Rv32IExecutor, Rv32ImCpuProverExt, Rv32Io, Rv32IoExecutor, Rv32M, Rv32MExecutor,
25};
26use openvm_sha2_air::{Sha256Config, Sha512Config};
27use openvm_sha2_transpiler::Rv32Sha2Opcode;
28use openvm_stark_backend::{StarkEngine, StarkProtocolConfig, Val};
29use serde::{Deserialize, Serialize};
30
31use crate::{Sha2BlockHasherChip, Sha2BlockHasherVmAir, Sha2MainAir, Sha2MainChip, Sha2VmExecutor};
32
33cfg_if::cfg_if! {
34 if #[cfg(feature = "cuda")] {
35 mod cuda;
36 pub use self::cuda::*;
37 pub use self::cuda::Sha2GpuProverExt as Sha2ProverExt;
38 pub use self::cuda::Sha2Rv32GpuBuilder as Sha2Rv32Builder;
39 } else {
40 pub use self::Sha2CpuProverExt as Sha2ProverExt;
41 pub use self::Sha2Rv32CpuBuilder as Sha2Rv32Builder;
42 }
43}
44
45#[derive(Clone, Debug, VmConfig, derive_new::new, Serialize, Deserialize)]
46pub struct Sha2Rv32Config {
47 #[config(executor = "SystemExecutor<F>")]
48 pub system: SystemConfig,
49 #[extension]
50 pub rv32i: Rv32I,
51 #[extension]
52 pub rv32m: Rv32M,
53 #[extension]
54 pub io: Rv32Io,
55 #[extension]
56 pub sha2: Sha2,
57}
58
59impl Default for Sha2Rv32Config {
60 fn default() -> Self {
61 Self {
62 system: SystemConfig::default(),
63 rv32i: Rv32I,
64 rv32m: Rv32M::default(),
65 io: Rv32Io,
66 sha2: Sha2,
67 }
68 }
69}
70
71impl InitFileGenerator for Sha2Rv32Config {}
73
74#[derive(Clone)]
75pub struct Sha2Rv32CpuBuilder;
76
77impl<E, SC> VmBuilder<E> for Sha2Rv32CpuBuilder
78where
79 SC: StarkProtocolConfig,
80 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
81 Val<SC>: VmField,
82 SC::EF: Ord,
83{
84 type VmConfig = Sha2Rv32Config;
85 type SystemChipInventory = SystemChipInventory<SC>;
86 type RecordArena = MatrixRecordArena<Val<SC>>;
87
88 fn create_chip_complex(
89 &self,
90 config: &Sha2Rv32Config,
91 circuit: AirInventory<SC>,
92 device_ctx: &openvm_stark_backend::EngineDeviceCtx<E>,
93 ) -> Result<
94 VmChipComplex<SC, Self::RecordArena, E::PB, Self::SystemChipInventory>,
95 ChipInventoryError,
96 > {
97 let mut chip_complex = VmBuilder::<E>::create_chip_complex(
98 &SystemCpuBuilder,
99 &config.system,
100 circuit,
101 device_ctx,
102 )?;
103 let inventory = &mut chip_complex.inventory;
104 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.rv32i, inventory)?;
105 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.rv32m, inventory)?;
106 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, &config.io, inventory)?;
107 VmProverExtension::<E, _, _>::extend_prover(&Sha2CpuProverExt, &config.sha2, inventory)?;
108 Ok(chip_complex)
109 }
110}
111
112#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
114pub struct Sha2;
115
116#[derive(Clone, From, AnyEnum, Executor, MeteredExecutor, PreflightExecutor)]
117#[cfg_attr(
118 feature = "aot",
119 derive(
120 openvm_circuit_derive::AotExecutor,
121 openvm_circuit_derive::AotMeteredExecutor
122 )
123)]
124pub enum Sha2Executor {
125 Sha256(Sha2VmExecutor<Sha256Config>),
126 Sha512(Sha2VmExecutor<Sha512Config>),
127}
128
129impl<F> VmExecutionExtension<F> for Sha2 {
130 type Executor = Sha2Executor;
131
132 fn extend_execution(
133 &self,
134 inventory: &mut ExecutorInventoryBuilder<F, Sha2Executor>,
135 ) -> Result<(), ExecutorInventoryError> {
136 let pointer_max_bits = inventory.pointer_max_bits();
137
138 let sha256_executor =
139 Sha2VmExecutor::<Sha256Config>::new(Rv32Sha2Opcode::CLASS_OFFSET, pointer_max_bits);
140 inventory.add_executor(sha256_executor, [Rv32Sha2Opcode::SHA256.global_opcode()])?;
141
142 let sha512_executor =
143 Sha2VmExecutor::<Sha512Config>::new(Rv32Sha2Opcode::CLASS_OFFSET, pointer_max_bits);
144 inventory.add_executor(sha512_executor, [Rv32Sha2Opcode::SHA512.global_opcode()])?;
145
146 Ok(())
147 }
148}
149
150impl<SC: StarkProtocolConfig> VmCircuitExtension<SC> for Sha2 {
151 fn extend_circuit(&self, inventory: &mut AirInventory<SC>) -> Result<(), AirInventoryError> {
152 let bitwise_lu = {
153 let existing_air = inventory.find_air::<BitwiseOperationLookupAir<8>>().next();
154 if let Some(air) = existing_air {
155 air.bus
156 } else {
157 let bus = BitwiseOperationLookupBus::new(inventory.new_bus_idx());
158 let air = BitwiseOperationLookupAir::<8>::new(bus);
159 inventory.add_air(air);
160 air.bus
161 }
162 };
163
164 let sha2_bus_index = inventory.new_bus_idx();
166 let subair_bus_index = inventory.new_bus_idx();
168
169 let sha256_block_hasher_air =
171 Sha2BlockHasherVmAir::<Sha256Config>::new(bitwise_lu, subair_bus_index, sha2_bus_index);
172 inventory.add_air(sha256_block_hasher_air);
173
174 let sha256_main_air = Sha2MainAir::<Sha256Config>::new(
175 inventory.system().port(),
176 bitwise_lu,
177 inventory.pointer_max_bits(),
178 sha2_bus_index,
179 Rv32Sha2Opcode::CLASS_OFFSET,
180 );
181 inventory.add_air(sha256_main_air);
182
183 let sha512_block_hasher_air =
185 Sha2BlockHasherVmAir::<Sha512Config>::new(bitwise_lu, subair_bus_index, sha2_bus_index);
186 inventory.add_air(sha512_block_hasher_air);
187
188 let sha512_main_air = Sha2MainAir::<Sha512Config>::new(
189 inventory.system().port(),
190 bitwise_lu,
191 inventory.pointer_max_bits(),
192 sha2_bus_index,
193 Rv32Sha2Opcode::CLASS_OFFSET,
194 );
195 inventory.add_air(sha512_main_air);
196
197 Ok(())
198 }
199}
200
201pub struct Sha2CpuProverExt;
202impl<E, SC, RA> VmProverExtension<E, RA, Sha2> for Sha2CpuProverExt
205where
206 SC: StarkProtocolConfig,
207 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
208 RA: RowMajorMatrixArena<Val<SC>> + Send + Sync + 'static,
209 Val<SC>: VmField,
210 SC::EF: Ord,
211{
212 fn extend_prover(
213 &self,
214 _: &Sha2,
215 inventory: &mut ChipInventory<SC, RA, CpuBackend<SC>>,
216 ) -> Result<(), ChipInventoryError> {
217 let range_checker = inventory.range_checker()?.clone();
218 let timestamp_max_bits = inventory.timestamp_max_bits();
219 let mem_helper = SharedMemoryHelper::new(range_checker.clone(), timestamp_max_bits);
220 let pointer_max_bits = inventory.airs().pointer_max_bits();
221
222 let bitwise_lu = {
223 let existing_chip = inventory
224 .find_chip::<SharedBitwiseOperationLookupChip<8>>()
225 .next();
226 if let Some(chip) = existing_chip {
227 chip.clone()
228 } else {
229 let air: &BitwiseOperationLookupAir<8> = inventory.next_air()?;
230 let chip = Arc::new(BitwiseOperationLookupChip::new(air.bus));
231 inventory.add_periphery_chip(chip.clone());
232 chip
233 }
234 };
235
236 inventory.next_air::<Sha2BlockHasherVmAir<Sha256Config>>()?;
242 let records = Arc::new(Mutex::new(None));
244 let sha256_block_hasher_chip = Sha2BlockHasherChip::<Val<SC>, Sha256Config>::new(
245 bitwise_lu.clone(),
246 pointer_max_bits,
247 mem_helper.clone(),
248 records.clone(),
249 );
250 inventory.add_periphery_chip(sha256_block_hasher_chip);
251
252 inventory.next_air::<Sha2MainAir<Sha256Config>>()?;
253 let sha256_main_chip = Sha2MainChip::<Val<SC>, Sha256Config>::new(
254 records,
255 bitwise_lu.clone(),
256 pointer_max_bits,
257 mem_helper.clone(),
258 );
259 inventory.add_executor_chip(sha256_main_chip);
260
261 inventory.next_air::<Sha2BlockHasherVmAir<Sha512Config>>()?;
263 let records = Arc::new(Mutex::new(None));
265 let sha512_block_hasher_chip = Sha2BlockHasherChip::<Val<SC>, Sha512Config>::new(
266 bitwise_lu.clone(),
267 pointer_max_bits,
268 mem_helper.clone(),
269 records.clone(),
270 );
271 inventory.add_periphery_chip(sha512_block_hasher_chip);
272
273 inventory.next_air::<Sha2MainAir<Sha512Config>>()?;
274 let sha512_main_chip = Sha2MainChip::<Val<SC>, Sha512Config>::new(
275 records,
276 bitwise_lu.clone(),
277 pointer_max_bits,
278 mem_helper.clone(),
279 );
280 inventory.add_executor_chip(sha512_main_chip);
281
282 Ok(())
283 }
284}