cargo_openvm/commands/
setup.rs

1use std::{
2    fs::{create_dir_all, write},
3    path::PathBuf,
4};
5
6use aws_config::{defaults, BehaviorVersion, Region};
7use aws_sdk_s3::Client;
8use clap::Parser;
9use eyre::{eyre, Result};
10use openvm_sdk::{
11    config::DEFAULT_HALO2_VERIFIER_K,
12    fs::{
13        read_object_from_file, write_evm_halo2_verifier_to_folder, write_object_to_file,
14        EVM_HALO2_VERIFIER_BASE_NAME, EVM_HALO2_VERIFIER_INTERFACE_NAME,
15        EVM_HALO2_VERIFIER_PARENT_NAME,
16    },
17    Sdk,
18};
19use static_assertions::const_assert;
20
21use crate::{
22    default::{
23        default_agg_halo2_pk_path, default_agg_stark_pk_path, default_agg_stark_vk_path,
24        default_asm_path, default_evm_halo2_verifier_path, default_params_dir,
25    },
26    util::read_default_agg_and_halo2_pk,
27};
28
29/// The maximum value of `k` to download Halo2 KZG trusted setup parameters for. This depends on the
30/// default verifier circuit and wrapper circuit sizes.
31const MAX_HALO2_VERIFIER_K_FOR_DOWNLOAD: usize = 24;
32
33#[derive(Parser)]
34#[command(
35    name = "setup",
36    about = "Set up for generating EVM proofs. ATTENTION: this requires large amounts of computation and memory. "
37)]
38pub struct SetupCmd {
39    #[arg(
40        long,
41        default_value = "false",
42        help = "use --evm to also generate proving keys for EVM verifier"
43    )]
44    pub evm: bool,
45    #[arg(
46        long,
47        default_value = "false",
48        help = "force keygen even if the proving keys already exist"
49    )]
50    pub force_agg_keygen: bool,
51}
52
53impl SetupCmd {
54    pub async fn run(&self) -> Result<()> {
55        let default_agg_stark_pk_path = default_agg_stark_pk_path();
56        let default_agg_stark_vk_path = default_agg_stark_vk_path();
57        let default_evm_halo2_verifier_path = default_evm_halo2_verifier_path();
58        let default_asm_path = default_asm_path();
59        if !self.evm {
60            if PathBuf::from(&default_agg_stark_pk_path).exists() && !self.force_agg_keygen {
61                println!("Aggregation stark proving key already exists");
62                return Ok(());
63            }
64            // agg keygen does not depend on the app config
65            let sdk = Sdk::standard();
66            let (agg_pk, agg_vk) = sdk.agg_keygen()?;
67
68            println!(
69                "Writing STARK aggregation proving key to {}",
70                &default_agg_stark_pk_path
71            );
72            write_object_to_file(default_agg_stark_pk_path, agg_pk)?;
73            println!(
74                "Writing STARK aggregation verifying key to {}",
75                &default_agg_stark_vk_path
76            );
77            write_object_to_file(default_agg_stark_vk_path, agg_vk)?;
78
79            println!("Generating root verifier ASM...");
80            let root_verifier_asm = sdk.generate_root_verifier_asm();
81
82            println!("Writing root verifier ASM to {}", &default_asm_path);
83            write(&default_asm_path, root_verifier_asm)?;
84        } else {
85            let default_agg_halo2_pk_path = default_agg_halo2_pk_path();
86            if PathBuf::from(&default_agg_stark_pk_path).exists()
87                && PathBuf::from(&default_agg_halo2_pk_path).exists()
88                && PathBuf::from(&default_evm_halo2_verifier_path)
89                    .join(EVM_HALO2_VERIFIER_PARENT_NAME)
90                    .exists()
91                && PathBuf::from(&default_evm_halo2_verifier_path)
92                    .join(EVM_HALO2_VERIFIER_BASE_NAME)
93                    .exists()
94                && PathBuf::from(&default_evm_halo2_verifier_path)
95                    .join("interfaces")
96                    .join(EVM_HALO2_VERIFIER_INTERFACE_NAME)
97                    .exists()
98            {
99                println!("Aggregation proving key and verifier contract already exist");
100                return Ok(());
101            } else if !Self::check_solc_installed() {
102                return Err(eyre!(
103                    "solc is not installed, please install solc to continue"
104                ));
105            }
106
107            const_assert!(DEFAULT_HALO2_VERIFIER_K <= MAX_HALO2_VERIFIER_K_FOR_DOWNLOAD);
108            Self::download_params(10, MAX_HALO2_VERIFIER_K_FOR_DOWNLOAD as u32).await?;
109            // halo2 keygen does not depend on the app config
110            let sdk = Sdk::standard();
111
112            let agg_vk = if !self.force_agg_keygen
113                && PathBuf::from(&default_agg_stark_pk_path).exists()
114                && PathBuf::from(&default_agg_stark_vk_path).exists()
115                && PathBuf::from(&default_agg_halo2_pk_path).exists()
116            {
117                let (agg_pk, halo2_pk) = read_default_agg_and_halo2_pk()?;
118                sdk.set_agg_pk(agg_pk)
119                    .map_err(|_| eyre!("agg_pk already existed"))?;
120                sdk.set_halo2_pk(halo2_pk)
121                    .map_err(|_| eyre!("halo2_pk already existed"))?;
122                read_object_from_file(&default_agg_stark_vk_path)?
123            } else {
124                println!("Generating proving key...");
125                let (_agg_pk, agg_vk) = sdk.agg_keygen()?;
126                let _halo2_pk = sdk.halo2_pk();
127                agg_vk
128            };
129
130            println!("Generating root verifier ASM...");
131            let root_verifier_asm = sdk.generate_root_verifier_asm();
132
133            println!("Generating verifier contract...");
134            let verifier = sdk.generate_halo2_verifier_solidity()?;
135
136            println!("Writing stark proving key to file...");
137            write_object_to_file(&default_agg_stark_pk_path, sdk.agg_pk())?;
138
139            println!("Writing stark verifying key to file...");
140            write_object_to_file(&default_agg_stark_vk_path, agg_vk)?;
141
142            println!("Writing halo2 proving key to file...");
143            write_object_to_file(&default_agg_halo2_pk_path, sdk.halo2_pk())?;
144
145            println!("Writing root verifier ASM to file...");
146            write(&default_asm_path, root_verifier_asm)?;
147
148            println!("Writing verifier contract to file...");
149            write_evm_halo2_verifier_to_folder(verifier, &default_evm_halo2_verifier_path)?;
150        }
151        Ok(())
152    }
153
154    fn check_solc_installed() -> bool {
155        std::process::Command::new("solc")
156            .arg("--version")
157            .output()
158            .is_ok()
159    }
160
161    async fn download_params(min_k: u32, max_k: u32) -> Result<()> {
162        let default_params_dir = default_params_dir();
163        create_dir_all(&default_params_dir)?;
164
165        let config = defaults(BehaviorVersion::latest())
166            .region(Region::new("us-east-1"))
167            .no_credentials()
168            .load()
169            .await;
170        let client = Client::new(&config);
171
172        for k in min_k..=max_k {
173            let file_name = format!("kzg_bn254_{k}.srs");
174            let local_file_path = PathBuf::from(&default_params_dir).join(&file_name);
175            if !local_file_path.exists() {
176                println!("Downloading {file_name}");
177                let key = format!("challenge_0085/{file_name}");
178                let resp = client
179                    .get_object()
180                    .bucket("axiom-crypto")
181                    .key(&key)
182                    .send()
183                    .await?;
184                let data = resp.body.collect().await?;
185                write(local_file_path, data.into_bytes())?;
186            }
187        }
188
189        Ok(())
190    }
191}