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