cargo_openvm/commands/
keygen.rs

1use std::{
2    fs::{copy, create_dir_all},
3    path::{Path, PathBuf},
4};
5
6use clap::Parser;
7use eyre::Result;
8use openvm_sdk::{fs::write_object_to_file, Sdk};
9
10use crate::{
11    default::{DEFAULT_APP_PK_NAME, DEFAULT_APP_VK_NAME},
12    util::{
13        get_app_pk_path, get_app_vk_path, get_manifest_path_and_dir, get_target_dir,
14        read_config_toml_or_default,
15    },
16};
17
18#[derive(Parser)]
19#[command(name = "keygen", about = "Generate an application proving key")]
20pub struct KeygenCmd {
21    #[arg(
22        long,
23        help = "Path to the OpenVM config .toml file that specifies the VM extensions, by default will search for the file at ${manifest_dir}/openvm.toml",
24        help_heading = "OpenVM Options"
25    )]
26    config: Option<PathBuf>,
27
28    #[arg(
29        long,
30        help = "Output directory that OpenVM proving artifacts will be copied to",
31        help_heading = "OpenVM Options"
32    )]
33    output_dir: Option<PathBuf>,
34
35    #[command(flatten)]
36    cargo_args: KeygenCargoArgs,
37}
38
39#[derive(Parser)]
40pub struct KeygenCargoArgs {
41    #[arg(
42        long,
43        value_name = "DIR",
44        help = "Directory for all Cargo-generated artifacts and intermediate files",
45        help_heading = "Cargo Options"
46    )]
47    pub(crate) target_dir: Option<PathBuf>,
48
49    #[arg(
50        long,
51        value_name = "PATH",
52        help = "Path to the Cargo.toml file, by default searches for the file in the current or any parent directory",
53        help_heading = "Cargo Options"
54    )]
55    pub(crate) manifest_path: Option<PathBuf>,
56}
57
58impl KeygenCmd {
59    pub fn run(&self) -> Result<()> {
60        let (manifest_path, manifest_dir) =
61            get_manifest_path_and_dir(&self.cargo_args.manifest_path)?;
62        let target_dir = get_target_dir(&self.cargo_args.target_dir, &manifest_path);
63        let app_pk_path = get_app_pk_path(&target_dir);
64        let app_vk_path = get_app_vk_path(&target_dir);
65
66        keygen(
67            self.config
68                .to_owned()
69                .unwrap_or_else(|| manifest_dir.join("openvm.toml")),
70            &app_pk_path,
71            &app_vk_path,
72            self.output_dir.as_ref(),
73        )?;
74        println!(
75            "Successfully generated app pk and vk in {}",
76            if let Some(output_dir) = self.output_dir.as_ref() {
77                output_dir.display()
78            } else {
79                app_pk_path.parent().unwrap().display()
80            }
81        );
82        Ok(())
83    }
84}
85
86pub(crate) fn keygen(
87    config: impl AsRef<Path>,
88    app_pk_path: impl AsRef<Path>,
89    app_vk_path: impl AsRef<Path>,
90    output_dir: Option<impl AsRef<Path>>,
91) -> Result<()> {
92    let app_config = read_config_toml_or_default(config)?;
93    let (app_pk, app_vk) = Sdk::new(app_config)?.app_keygen();
94    write_object_to_file(&app_vk_path, app_vk)?;
95    write_object_to_file(&app_pk_path, app_pk)?;
96
97    if let Some(output_dir) = output_dir {
98        let output_dir = output_dir.as_ref();
99        create_dir_all(output_dir)?;
100        copy(&app_pk_path, output_dir.join(DEFAULT_APP_PK_NAME))?;
101        copy(&app_vk_path, output_dir.join(DEFAULT_APP_VK_NAME))?;
102    }
103
104    Ok(())
105}