diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 9e26090eac..ed05db902e 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -53,7 +53,7 @@ impl ConstraintSynthesizer for Compiler { self, cs: &mut CS, ) -> Result<(), SynthesisError> { - self.evaluate_program(cs); + self.evaluate_program(cs).expect("error compiling program"); Ok(()) } } diff --git a/leo/commands/mod.rs b/leo/commands/mod.rs index 9a7bff1df7..1d6e030267 100644 --- a/leo/commands/mod.rs +++ b/leo/commands/mod.rs @@ -7,6 +7,9 @@ pub use self::init::*; pub mod new; pub use self::new::*; +pub mod prove; +pub use self::prove::*; + pub mod run; pub use self::run::*; diff --git a/leo/commands/prove.rs b/leo/commands/prove.rs new file mode 100644 index 0000000000..2fd6eb2975 --- /dev/null +++ b/leo/commands/prove.rs @@ -0,0 +1,57 @@ +use crate::{cli::*, cli_types::*}; +use crate::commands::SetupCommand; +use crate::errors::CLIError; +use crate::files::ProofFile; +use crate::manifest::Manifest; + +use snarkos_algorithms::snark::{create_random_proof, Proof}; +use snarkos_curves::bls12_377::Bls12_377; + +use clap::ArgMatches; +use rand::thread_rng; +use std::convert::TryFrom; +use std::env::current_dir; +use std::time::Instant; + +#[derive(Debug)] +pub struct ProveCommand; + +impl CLI for ProveCommand { + type Options = (); + type Output = Proof; + + const NAME: NameType = "prove"; + const ABOUT: AboutType = "Run the program and produce a proof"; + const ARGUMENTS: &'static [ArgumentType] = &[]; + const FLAGS: &'static [FlagType] = &[]; + const OPTIONS: &'static [OptionType] = &[]; + const SUBCOMMANDS: &'static [SubCommandType] = &[]; + + #[cfg_attr(tarpaulin, skip)] + fn parse(_arguments: &ArgMatches) -> Result { + Ok(()) + } + + #[cfg_attr(tarpaulin, skip)] + fn output(options: Self::Options) -> Result { + let (program, parameters, _) = SetupCommand::output(options)?; + + // Get the package name + let path = current_dir()?; + let package_name = Manifest::try_from(&path)?.get_package_name(); + + let start = Instant::now(); + + let rng = &mut thread_rng(); + let program_proof = create_random_proof(program, ¶meters, rng).unwrap(); + + log::info!("Prover completed in {:?} milliseconds", start.elapsed().as_millis()); + + // Write the proof file to the outputs directory + let mut proof = vec![]; + program_proof.write(&mut proof)?; + ProofFile::new(&package_name).write_to(&path, &proof)?; + + Ok(program_proof) + } +} diff --git a/leo/commands/run.rs b/leo/commands/run.rs index 720f134ff3..f8997b68f4 100644 --- a/leo/commands/run.rs +++ b/leo/commands/run.rs @@ -1,11 +1,10 @@ -use crate::commands::SetupCommand; +use crate::commands::{SetupCommand, ProveCommand}; use crate::errors::CLIError; use crate::{cli::*, cli_types::*}; -use snarkos_algorithms::snark::{create_random_proof, verify_proof}; +use snarkos_algorithms::snark::verify_proof; use clap::ArgMatches; -use rand::thread_rng; use std::time::{Duration, Instant}; #[derive(Debug)] @@ -29,18 +28,11 @@ impl CLI for RunCommand { #[cfg_attr(tarpaulin, skip)] fn output(options: Self::Options) -> Result<(), CLIError> { - let (program, parameters, prepared_verifying_key) = SetupCommand::output(options)?; + let (_program, _parameters, prepared_verifying_key) = SetupCommand::output(options)?; + let proof = ProveCommand::output(options)?; - let rng = &mut thread_rng(); - - let mut proving = Duration::new(0, 0); let mut verifying = Duration::new(0, 0); - let start = Instant::now(); - let proof = create_random_proof(program, ¶meters, rng).unwrap(); - - proving += start.elapsed(); - // let _inputs: Vec<_> = [1u32; 1].to_vec(); let start = Instant::now(); @@ -50,7 +42,6 @@ impl CLI for RunCommand { verifying += start.elapsed(); println!(" "); - println!(" Prover time : {:?} milliseconds", proving.as_millis()); println!( " Verifier time : {:?} milliseconds", verifying.as_millis() diff --git a/leo/commands/setup.rs b/leo/commands/setup.rs index fd93b6bb3d..bac6eedc5b 100644 --- a/leo/commands/setup.rs +++ b/leo/commands/setup.rs @@ -59,12 +59,12 @@ impl CLI for SetupCommand { // Write the proving key file to the inputs directory let mut proving_key = vec![]; - parameters.write(&mut proving_key); + parameters.write(&mut proving_key)?; ProvingKeyFile::new(&package_name).write_to(&path, &proving_key)?; // Write the proving key file to the inputs directory let mut verification_key = vec![]; - prepared_verifying_key.write(&mut verification_key); + prepared_verifying_key.write(&mut verification_key)?; VerificationKeyFile::new(&package_name).write_to(&path, &verification_key)?; Ok((program, parameters, prepared_verifying_key)) diff --git a/leo/errors/cli.rs b/leo/errors/cli.rs index 965c2a7b14..54fa1deb3b 100644 --- a/leo/errors/cli.rs +++ b/leo/errors/cli.rs @@ -26,6 +26,9 @@ pub enum CLIError { #[fail(display = "{}", _0)] OutputsDirectoryError(OutputsDirectoryError), + #[fail(display = "{}", _0)] + ProofFileError(ProofFileError), + #[fail(display = "{}", _0)] ProvingKeyFileError(ProvingKeyFileError), @@ -81,6 +84,12 @@ impl From for CLIError { } } +impl From for CLIError { + fn from(error: ProofFileError) -> Self { + CLIError::ProofFileError(error) + } +} + impl From for CLIError { fn from(error: ProvingKeyFileError) -> Self { CLIError::ProvingKeyFileError(error) diff --git a/leo/errors/files/mod.rs b/leo/errors/files/mod.rs index f5555f95ba..abb181bb3e 100644 --- a/leo/errors/files/mod.rs +++ b/leo/errors/files/mod.rs @@ -1,6 +1,9 @@ pub mod main; pub use self::main::*; +pub mod proof; +pub use self::proof::*; + pub mod proving_key; pub use self::proving_key::*; diff --git a/leo/errors/files/proof.rs b/leo/errors/files/proof.rs new file mode 100644 index 0000000000..a8a3c62e86 --- /dev/null +++ b/leo/errors/files/proof.rs @@ -0,0 +1,19 @@ +use std::io; + +#[derive(Debug, Fail)] +pub enum ProofFileError { + #[fail(display = "{}: {}", _0, _1)] + Crate(&'static str, String), + + #[fail(display = "creating: {}", _0)] + Creating(io::Error), + + #[fail(display = "writing: {}", _0)] + Writing(io::Error), +} + +impl From for ProofFileError { + fn from(error: std::io::Error) -> Self { + ProofFileError::Crate("std::io", format!("{}", error)) + } +} diff --git a/leo/files/mod.rs b/leo/files/mod.rs index f5555f95ba..abb181bb3e 100644 --- a/leo/files/mod.rs +++ b/leo/files/mod.rs @@ -1,6 +1,9 @@ pub mod main; pub use self::main::*; +pub mod proof; +pub use self::proof::*; + pub mod proving_key; pub use self::proving_key::*; diff --git a/leo/files/proof.rs b/leo/files/proof.rs new file mode 100644 index 0000000000..49e7a99879 --- /dev/null +++ b/leo/files/proof.rs @@ -0,0 +1,52 @@ +//! The `main.leo` file. + +use crate::directories::outputs::OUTPUTS_DIRECTORY_NAME; +use crate::errors::ProofFileError; + +use serde::Deserialize; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +pub static PROOF_FILE_EXTENSION: &str = ".leo.proof"; + +#[derive(Deserialize)] +pub struct ProofFile { + pub package_name: String, +} + +impl ProofFile { + pub fn new(package_name: &str) -> Self { + Self { + package_name: package_name.to_string(), + } + } + + pub fn exists_at(self, path: &PathBuf) -> bool { + let mut path = path.to_owned(); + if path.is_dir() { + if !path.ends_with(OUTPUTS_DIRECTORY_NAME) { + path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME)); + } + path.push(PathBuf::from(format!("{}{}", self.package_name, PROOF_FILE_EXTENSION))); + } + path.exists() + } + + pub fn write_to(self, path: &PathBuf, proof: &[u8]) -> Result<(), ProofFileError> { + let mut path = path.to_owned(); + if path.is_dir() { + if !path.ends_with(OUTPUTS_DIRECTORY_NAME) { + path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME)); + } + path.push(PathBuf::from(format!("{}{}", self.package_name, PROOF_FILE_EXTENSION))); + } + + let mut file = File::create(&path)?; + file.write_all(proof)?; + + log::info!("Proof stored in {:?}", path); + + Ok(()) + } +} diff --git a/leo/main.rs b/leo/main.rs index 47ac498d52..ffcfcf81d4 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -23,6 +23,7 @@ fn main() -> Result<(), CLIError> { InitCommand::new(), BuildCommand::new(), SetupCommand::new(), + ProveCommand::new(), RunCommand::new(), ]) .set_term_width(0) @@ -39,6 +40,10 @@ fn main() -> Result<(), CLIError> { SetupCommand::output(SetupCommand::parse(arguments)?)?; Ok(()) } + ("prove", Some(arguments)) => { + ProveCommand::output(ProveCommand::parse(arguments)?)?; + Ok(()) + } ("run", Some(arguments)) => RunCommand::output(RunCommand::parse(arguments)?), _ => unreachable!(), }