1use bon::Builder;
2use openvm_algebra_circuit::{
3 AlgebraCpuProverExt, Fp2Extension, Fp2ExtensionExecutor, ModularExtension,
4 ModularExtensionExecutor,
5};
6use openvm_algebra_transpiler::{Fp2TranspilerExtension, ModularTranspilerExtension};
7use openvm_bigint_circuit::{Int256, Int256CpuProverExt, Int256Executor};
8use openvm_bigint_transpiler::Int256TranspilerExtension;
9use openvm_circuit::{
10 arch::{instructions::NATIVE_AS, *},
11 derive::VmConfig,
12 system::{SystemChipInventory, SystemCpuBuilder, SystemExecutor},
13};
14use openvm_ecc_circuit::{
15 EccCpuProverExt, WeierstrassExtension, WeierstrassExtensionExecutor, P256_CONFIG,
16 SECP256K1_CONFIG,
17};
18use openvm_ecc_transpiler::EccTranspilerExtension;
19use openvm_keccak256_circuit::{Keccak256, Keccak256CpuProverExt, Keccak256Executor};
20use openvm_keccak256_transpiler::Keccak256TranspilerExtension;
21use openvm_native_circuit::{
22 CastFExtension, CastFExtensionExecutor, Native, NativeCpuProverExt, NativeExecutor,
23};
24use openvm_native_transpiler::LongFormTranspilerExtension;
25use openvm_pairing_circuit::{
26 PairingCurve, PairingExtension, PairingExtensionExecutor, PairingProverExt,
27 BLS12_381_COMPLEX_STRUCT_NAME, BN254_COMPLEX_STRUCT_NAME,
28};
29use openvm_pairing_transpiler::PairingTranspilerExtension;
30use openvm_rv32im_circuit::{
31 Rv32I, Rv32IExecutor, Rv32ImCpuProverExt, Rv32Io, Rv32IoExecutor, Rv32M, Rv32MExecutor,
32};
33use openvm_rv32im_transpiler::{
34 Rv32ITranspilerExtension, Rv32IoTranspilerExtension, Rv32MTranspilerExtension,
35};
36use openvm_sha256_circuit::{Sha256, Sha256Executor, Sha2CpuProverExt};
37use openvm_sha256_transpiler::Sha256TranspilerExtension;
38use openvm_stark_backend::{
39 config::{StarkGenericConfig, Val},
40 engine::StarkEngine,
41 p3_field::{Field, PrimeField32},
42 prover::cpu::{CpuBackend, CpuDevice},
43};
44use openvm_transpiler::transpiler::Transpiler;
45use serde::{Deserialize, Serialize};
46cfg_if::cfg_if! {
47 if #[cfg(feature = "cuda")] {
48 use openvm_algebra_circuit::AlgebraProverExt;
49 use openvm_bigint_circuit::Int256GpuProverExt;
50 use openvm_circuit::system::cuda::{extensions::SystemGpuBuilder, SystemChipInventoryGPU};
51 use openvm_cuda_backend::{
52 engine::GpuBabyBearPoseidon2Engine, prover_backend::GpuBackend, types::SC,
53 };
54 use openvm_ecc_circuit::EccProverExt;
55 use openvm_keccak256_circuit::Keccak256GpuProverExt;
56 use openvm_native_circuit::NativeGpuProverExt;
57 use openvm_rv32im_circuit::Rv32ImGpuProverExt;
58 use openvm_sha256_circuit::Sha256GpuProverExt;
59 pub use SdkVmGpuBuilder as SdkVmBuilder;
60 } else {
61 pub use SdkVmCpuBuilder as SdkVmBuilder;
62 }
63}
64
65use super::AppFriParams;
66use crate::{
67 config::{AppConfig, TranspilerConfig},
68 F,
69};
70
71#[derive(Builder, Clone, Debug, Serialize, Deserialize)]
78#[serde(from = "SdkVmConfigWithDefaultDeser")]
79pub struct SdkVmConfig {
80 pub system: SdkSystemConfig,
81 pub rv32i: Option<UnitStruct>,
82 pub io: Option<UnitStruct>,
83 pub keccak: Option<UnitStruct>,
84 pub sha256: Option<UnitStruct>,
85 pub native: Option<UnitStruct>,
86 pub castf: Option<UnitStruct>,
87
88 pub rv32m: Option<Rv32M>,
92 pub bigint: Option<Int256>,
96 pub modular: Option<ModularExtension>,
97 pub fp2: Option<Fp2Extension>,
98 pub pairing: Option<PairingExtension>,
99 pub ecc: Option<WeierstrassExtension>,
100}
101
102impl SdkVmConfig {
103 #[doc = include_str!("openvm_standard.toml")]
111 pub fn standard() -> SdkVmConfig {
113 let bn_config = PairingCurve::Bn254.curve_config();
114 let bls_config = PairingCurve::Bls12_381.curve_config();
115 SdkVmConfig::builder()
116 .system(Default::default())
117 .rv32i(Default::default())
118 .rv32m(Default::default())
119 .io(Default::default())
120 .keccak(Default::default())
121 .sha256(Default::default())
122 .bigint(Default::default())
123 .modular(ModularExtension::new(vec![
124 bn_config.modulus.clone(),
125 bn_config.scalar.clone(),
126 SECP256K1_CONFIG.modulus.clone(),
127 SECP256K1_CONFIG.scalar.clone(),
128 P256_CONFIG.modulus.clone(),
129 P256_CONFIG.scalar.clone(),
130 bls_config.modulus.clone(),
131 bls_config.scalar.clone(),
132 ]))
133 .fp2(Fp2Extension::new(vec![
134 (
135 BN254_COMPLEX_STRUCT_NAME.to_string(),
136 bn_config.modulus.clone(),
137 ),
138 (
139 BLS12_381_COMPLEX_STRUCT_NAME.to_string(),
140 bls_config.modulus.clone(),
141 ),
142 ]))
143 .ecc(WeierstrassExtension::new(vec![
144 bn_config.clone(),
145 SECP256K1_CONFIG.clone(),
146 P256_CONFIG.clone(),
147 bls_config.clone(),
148 ]))
149 .pairing(PairingExtension::new(vec![
150 PairingCurve::Bn254,
151 PairingCurve::Bls12_381,
152 ]))
153 .build()
154 .optimize()
155 }
156
157 #[doc = include_str!("openvm_riscv32.toml")]
163 pub fn riscv32() -> Self {
165 SdkVmConfig::builder()
166 .system(Default::default())
167 .rv32i(Default::default())
168 .rv32m(Default::default())
169 .io(Default::default())
170 .build()
171 .optimize()
172 }
173
174 pub fn from_toml(openvm_toml: &str) -> Result<AppConfig<Self>, toml::de::Error> {
176 toml::from_str(openvm_toml)
177 }
178}
179
180impl AppConfig<SdkVmConfig> {
181 pub fn standard() -> Self {
182 Self::new(AppFriParams::default().fri_params, SdkVmConfig::standard())
183 }
184
185 pub fn riscv32() -> Self {
186 Self::new(AppFriParams::default().fri_params, SdkVmConfig::riscv32())
187 }
188}
189
190impl TranspilerConfig<F> for SdkVmConfig {
191 fn transpiler(&self) -> Transpiler<F> {
192 let mut transpiler = Transpiler::default();
193 if self.rv32i.is_some() {
194 transpiler = transpiler.with_extension(Rv32ITranspilerExtension);
195 }
196 if self.io.is_some() {
197 transpiler = transpiler.with_extension(Rv32IoTranspilerExtension);
198 }
199 if self.keccak.is_some() {
200 transpiler = transpiler.with_extension(Keccak256TranspilerExtension);
201 }
202 if self.sha256.is_some() {
203 transpiler = transpiler.with_extension(Sha256TranspilerExtension);
204 }
205 if self.native.is_some() {
206 transpiler = transpiler.with_extension(LongFormTranspilerExtension);
207 }
208 if self.rv32m.is_some() {
209 transpiler = transpiler.with_extension(Rv32MTranspilerExtension);
210 }
211 if self.bigint.is_some() {
212 transpiler = transpiler.with_extension(Int256TranspilerExtension);
213 }
214 if self.modular.is_some() {
215 transpiler = transpiler.with_extension(ModularTranspilerExtension);
216 }
217 if self.fp2.is_some() {
218 transpiler = transpiler.with_extension(Fp2TranspilerExtension);
219 }
220 if self.pairing.is_some() {
221 transpiler = transpiler.with_extension(PairingTranspilerExtension);
222 }
223 if self.ecc.is_some() {
224 transpiler = transpiler.with_extension(EccTranspilerExtension);
225 }
226 transpiler
227 }
228}
229
230impl AsRef<SystemConfig> for SdkVmConfig {
231 fn as_ref(&self) -> &SystemConfig {
232 &self.system.config
233 }
234}
235
236impl AsMut<SystemConfig> for SdkVmConfig {
237 fn as_mut(&mut self) -> &mut SystemConfig {
238 &mut self.system.config
239 }
240}
241
242impl SdkVmConfig {
243 pub fn optimize(mut self) -> Self {
244 self.apply_optimizations();
245 self
246 }
247
248 pub fn apply_optimizations(&mut self) {
250 if self.native.is_none() && self.castf.is_none() {
251 self.system.config.memory_config.addr_spaces[NATIVE_AS as usize].num_cells = 0;
254 }
255 let rv32m = self.rv32m.as_mut();
256 let bigint = self.bigint.as_mut();
257 if let (Some(bigint), Some(rv32m)) = (bigint, rv32m) {
258 rv32m.range_tuple_checker_sizes[0] =
259 rv32m.range_tuple_checker_sizes[0].max(bigint.range_tuple_checker_sizes[0]);
260 rv32m.range_tuple_checker_sizes[1] =
261 rv32m.range_tuple_checker_sizes[1].max(bigint.range_tuple_checker_sizes[1]);
262 bigint.range_tuple_checker_sizes = rv32m.range_tuple_checker_sizes;
263 }
264 }
265
266 pub fn to_inner(&self) -> SdkVmConfigInner {
267 let config = self.clone().optimize();
268 let system = config.system.config.clone();
269 let rv32i = config.rv32i.map(|_| Rv32I);
270 let io = config.io.map(|_| Rv32Io);
271 let keccak = config.keccak.map(|_| Keccak256);
272 let sha256 = config.sha256.map(|_| Sha256);
273 let native = config.native.map(|_| Native);
274 let castf = config.castf.map(|_| CastFExtension);
275 let rv32m = config.rv32m;
276 let bigint = config.bigint;
277 let modular = config.modular.clone();
278 let fp2 = config.fp2.clone();
279 let pairing = config.pairing.clone();
280 let ecc = config.ecc.clone();
281
282 SdkVmConfigInner {
283 system,
284 rv32i,
285 io,
286 keccak,
287 sha256,
288 native,
289 castf,
290 rv32m,
291 bigint,
292 modular,
293 fp2,
294 pairing,
295 ecc,
296 }
297 }
298}
299
300#[derive(Copy, Clone, Default)]
304pub struct SdkVmCpuBuilder;
305
306#[derive(Clone, Debug, VmConfig, Serialize, Deserialize)]
309pub struct SdkVmConfigInner {
310 #[config(executor = "SystemExecutor<F>")]
311 pub system: SystemConfig,
312 #[extension(executor = "Rv32IExecutor")]
313 pub rv32i: Option<Rv32I>,
314 #[extension(executor = "Rv32IoExecutor")]
315 pub io: Option<Rv32Io>,
316 #[extension(executor = "Keccak256Executor")]
317 pub keccak: Option<Keccak256>,
318 #[extension(executor = "Sha256Executor")]
319 pub sha256: Option<Sha256>,
320 #[extension(executor = "NativeExecutor<F>")]
321 pub native: Option<Native>,
322 #[extension(executor = "CastFExtensionExecutor")]
323 pub castf: Option<CastFExtension>,
324
325 #[extension(executor = "Rv32MExecutor")]
326 pub rv32m: Option<Rv32M>,
327 #[extension(executor = "Int256Executor")]
328 pub bigint: Option<Int256>,
329 #[extension(executor = "ModularExtensionExecutor")]
330 pub modular: Option<ModularExtension>,
331 #[extension(executor = "Fp2ExtensionExecutor")]
332 pub fp2: Option<Fp2Extension>,
333 #[extension(executor = "PairingExtensionExecutor<F>")]
334 pub pairing: Option<PairingExtension>,
335 #[extension(executor = "WeierstrassExtensionExecutor")]
336 pub ecc: Option<WeierstrassExtension>,
337}
338
339pub type SdkVmConfigExecutor<F> = SdkVmConfigInnerExecutor<F>;
341
342impl<F: Field> VmExecutionConfig<F> for SdkVmConfig
343where
344 SdkVmConfigInner: VmExecutionConfig<F>,
345{
346 type Executor = <SdkVmConfigInner as VmExecutionConfig<F>>::Executor;
347
348 fn create_executors(
349 &self,
350 ) -> Result<ExecutorInventory<Self::Executor>, ExecutorInventoryError> {
351 self.to_inner().create_executors()
352 }
353}
354
355impl<SC: StarkGenericConfig> VmCircuitConfig<SC> for SdkVmConfig
356where
357 SdkVmConfigInner: VmCircuitConfig<SC>,
358{
359 fn create_airs(&self) -> Result<AirInventory<SC>, AirInventoryError> {
360 self.to_inner().create_airs()
361 }
362}
363
364impl<E, SC> VmBuilder<E> for SdkVmCpuBuilder
365where
366 SC: StarkGenericConfig,
367 E: StarkEngine<SC = SC, PB = CpuBackend<SC>, PD = CpuDevice<SC>>,
368 Val<SC>: PrimeField32,
369{
370 type VmConfig = SdkVmConfig;
371 type SystemChipInventory = SystemChipInventory<SC>;
372 type RecordArena = MatrixRecordArena<Val<SC>>;
373
374 fn create_chip_complex(
375 &self,
376 config: &SdkVmConfig,
377 circuit: AirInventory<SC>,
378 ) -> Result<
379 VmChipComplex<SC, Self::RecordArena, E::PB, Self::SystemChipInventory>,
380 ChipInventoryError,
381 > {
382 let config = config.to_inner();
383 let mut chip_complex =
384 VmBuilder::<E>::create_chip_complex(&SystemCpuBuilder, &config.system, circuit)?;
385 let inventory = &mut chip_complex.inventory;
386 if let Some(rv32i) = &config.rv32i {
387 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, rv32i, inventory)?;
388 }
389 if let Some(io) = &config.io {
390 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, io, inventory)?;
391 }
392 if let Some(keccak) = &config.keccak {
393 VmProverExtension::<E, _, _>::extend_prover(&Keccak256CpuProverExt, keccak, inventory)?;
394 }
395 if let Some(sha256) = &config.sha256 {
396 VmProverExtension::<E, _, _>::extend_prover(&Sha2CpuProverExt, sha256, inventory)?;
397 }
398 if let Some(native) = &config.native {
399 VmProverExtension::<E, _, _>::extend_prover(&NativeCpuProverExt, native, inventory)?;
400 }
401 if let Some(castf) = &config.castf {
402 VmProverExtension::<E, _, _>::extend_prover(&NativeCpuProverExt, castf, inventory)?;
403 }
404 if let Some(rv32m) = &config.rv32m {
405 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImCpuProverExt, rv32m, inventory)?;
406 }
407 if let Some(bigint) = &config.bigint {
408 VmProverExtension::<E, _, _>::extend_prover(&Int256CpuProverExt, bigint, inventory)?;
409 }
410 if let Some(modular) = &config.modular {
411 VmProverExtension::<E, _, _>::extend_prover(&AlgebraCpuProverExt, modular, inventory)?;
412 }
413 if let Some(fp2) = &config.fp2 {
414 VmProverExtension::<E, _, _>::extend_prover(&AlgebraCpuProverExt, fp2, inventory)?;
415 }
416 if let Some(pairing) = &config.pairing {
417 VmProverExtension::<E, _, _>::extend_prover(&PairingProverExt, pairing, inventory)?;
418 }
419 if let Some(ecc) = &config.ecc {
420 VmProverExtension::<E, _, _>::extend_prover(&EccCpuProverExt, ecc, inventory)?;
421 }
422 Ok(chip_complex)
423 }
424}
425
426#[cfg(feature = "cuda")]
427#[derive(Copy, Clone, Default)]
428pub struct SdkVmGpuBuilder;
429
430#[cfg(feature = "cuda")]
431impl VmBuilder<GpuBabyBearPoseidon2Engine> for SdkVmGpuBuilder {
432 type VmConfig = SdkVmConfig;
433 type SystemChipInventory = SystemChipInventoryGPU;
434 type RecordArena = DenseRecordArena;
435
436 fn create_chip_complex(
437 &self,
438 config: &SdkVmConfig,
439 circuit: AirInventory<SC>,
440 ) -> Result<
441 VmChipComplex<SC, Self::RecordArena, GpuBackend, Self::SystemChipInventory>,
442 ChipInventoryError,
443 > {
444 type E = GpuBabyBearPoseidon2Engine;
445
446 let config = config.to_inner();
447 let mut chip_complex =
448 VmBuilder::<E>::create_chip_complex(&SystemGpuBuilder, &config.system, circuit)?;
449 let inventory = &mut chip_complex.inventory;
450 if let Some(rv32i) = &config.rv32i {
451 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImGpuProverExt, rv32i, inventory)?;
452 }
453 if let Some(io) = &config.io {
454 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImGpuProverExt, io, inventory)?;
455 }
456 if let Some(keccak) = &config.keccak {
457 VmProverExtension::<E, _, _>::extend_prover(&Keccak256GpuProverExt, keccak, inventory)?;
458 }
459 if let Some(sha256) = &config.sha256 {
460 VmProverExtension::<E, _, _>::extend_prover(&Sha256GpuProverExt, sha256, inventory)?;
461 }
462 if let Some(native) = &config.native {
463 VmProverExtension::<E, _, _>::extend_prover(&NativeGpuProverExt, native, inventory)?;
464 }
465 if let Some(castf) = &config.castf {
466 VmProverExtension::<E, _, _>::extend_prover(&NativeGpuProverExt, castf, inventory)?;
467 }
468 if let Some(rv32m) = &config.rv32m {
469 VmProverExtension::<E, _, _>::extend_prover(&Rv32ImGpuProverExt, rv32m, inventory)?;
470 }
471 if let Some(bigint) = &config.bigint {
472 VmProverExtension::<E, _, _>::extend_prover(&Int256GpuProverExt, bigint, inventory)?;
473 }
474 if let Some(modular) = &config.modular {
475 VmProverExtension::<E, _, _>::extend_prover(&AlgebraProverExt, modular, inventory)?;
476 }
477 if let Some(fp2) = &config.fp2 {
478 VmProverExtension::<E, _, _>::extend_prover(&AlgebraProverExt, fp2, inventory)?;
479 }
480 if let Some(pairing) = &config.pairing {
481 VmProverExtension::<E, _, _>::extend_prover(&PairingProverExt, pairing, inventory)?;
482 }
483 if let Some(ecc) = &config.ecc {
484 VmProverExtension::<E, _, _>::extend_prover(&EccProverExt, ecc, inventory)?;
485 }
486 Ok(chip_complex)
487 }
488}
489
490impl InitFileGenerator for SdkVmConfig {
493 fn generate_init_file_contents(&self) -> Option<String> {
494 self.to_inner().generate_init_file_contents()
495 }
496}
497impl InitFileGenerator for SdkVmConfigInner {
498 fn generate_init_file_contents(&self) -> Option<String> {
499 if self.modular.is_some() || self.fp2.is_some() || self.ecc.is_some() {
500 let mut contents = String::new();
501 contents.push_str(
502 "// This file is automatically generated by cargo openvm. Do not rename or edit.\n",
503 );
504
505 if let Some(modular_config) = &self.modular {
506 contents.push_str(&modular_config.generate_moduli_init());
507 contents.push('\n');
508 }
509
510 if let Some(fp2_config) = &self.fp2 {
511 assert!(
512 self.modular.is_some(),
513 "ModularExtension is required for Fp2Extension"
514 );
515 let modular_config = self.modular.as_ref().unwrap();
516 contents.push_str(&fp2_config.generate_complex_init(modular_config));
517 contents.push('\n');
518 }
519
520 if let Some(ecc_config) = &self.ecc {
521 contents.push_str(&ecc_config.generate_sw_init());
522 contents.push('\n');
523 }
524
525 Some(contents)
526 } else {
527 None
528 }
529 }
530}
531
532#[derive(Clone, Debug, Default, Serialize, Deserialize)]
533pub struct SdkSystemConfig {
534 pub config: SystemConfig,
535}
536
537impl InitFileGenerator for SdkSystemConfig {}
539
540impl From<SystemConfig> for SdkSystemConfig {
541 fn from(config: SystemConfig) -> Self {
542 Self { config }
543 }
544}
545
546#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
549pub struct UnitStruct {}
550
551impl From<Rv32I> for UnitStruct {
552 fn from(_: Rv32I) -> Self {
553 UnitStruct {}
554 }
555}
556
557impl From<Rv32Io> for UnitStruct {
558 fn from(_: Rv32Io) -> Self {
559 UnitStruct {}
560 }
561}
562
563impl From<Keccak256> for UnitStruct {
564 fn from(_: Keccak256) -> Self {
565 UnitStruct {}
566 }
567}
568
569impl From<Sha256> for UnitStruct {
570 fn from(_: Sha256) -> Self {
571 UnitStruct {}
572 }
573}
574
575impl From<Native> for UnitStruct {
576 fn from(_: Native) -> Self {
577 UnitStruct {}
578 }
579}
580
581impl From<CastFExtension> for UnitStruct {
582 fn from(_: CastFExtension) -> Self {
583 UnitStruct {}
584 }
585}
586
587#[derive(Deserialize)]
588struct SdkVmConfigWithDefaultDeser {
589 #[serde(default)]
590 pub system: SdkSystemConfig,
591
592 pub rv32i: Option<UnitStruct>,
593 pub io: Option<UnitStruct>,
594 pub keccak: Option<UnitStruct>,
595 pub sha256: Option<UnitStruct>,
596 pub native: Option<UnitStruct>,
597 pub castf: Option<UnitStruct>,
598
599 pub rv32m: Option<Rv32M>,
600 pub bigint: Option<Int256>,
601 pub modular: Option<ModularExtension>,
602 pub fp2: Option<Fp2Extension>,
603 pub pairing: Option<PairingExtension>,
604 pub ecc: Option<WeierstrassExtension>,
605}
606
607impl From<SdkVmConfigWithDefaultDeser> for SdkVmConfig {
608 fn from(config: SdkVmConfigWithDefaultDeser) -> Self {
609 let ret = Self {
610 system: config.system,
611 rv32i: config.rv32i,
612 io: config.io,
613 keccak: config.keccak,
614 sha256: config.sha256,
615 native: config.native,
616 castf: config.castf,
617 rv32m: config.rv32m,
618 bigint: config.bigint,
619 modular: config.modular,
620 fp2: config.fp2,
621 pairing: config.pairing,
622 ecc: config.ecc,
623 };
624 ret.optimize()
625 }
626}
627
628#[cfg(test)]
629mod tests {
630 use itertools::zip_eq;
631
632 use super::*;
633
634 #[test]
635 fn test_app_config_consistency() {
636 let toml_config = SdkVmConfig::from_toml(include_str!("./openvm_standard.toml")).unwrap();
637 for (line1, line2) in zip_eq(
638 toml::to_string_pretty(&AppConfig::standard())
639 .unwrap()
640 .lines(),
641 toml::to_string_pretty(&toml_config).unwrap().lines(),
642 ) {
643 assert_eq!(line1, line2);
644 }
645
646 let toml_config = SdkVmConfig::from_toml(include_str!("./openvm_riscv32.toml")).unwrap();
647 for (line1, line2) in zip_eq(
648 toml::to_string_pretty(&AppConfig::riscv32())
649 .unwrap()
650 .lines(),
651 toml::to_string_pretty(&toml_config).unwrap().lines(),
652 ) {
653 assert_eq!(line1, line2);
654 }
655 }
656}