From 1ef5db09df10f14a1f7a829a12d1e9da45d43fca Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Mon, 17 Jun 2024 09:22:22 +0900 Subject: [PATCH 01/23] feat: Add initial function stubs and main function structure - Set up the main function outline - Added stubs for implementation functions without details --- .gitignore | 3 +- Cargo.lock | 277 +++++++++++++++++++++++++++++++++- Cargo.toml | 3 + src/commands/commit.rs | 3 + src/commands/generate_data.rs | 1 + src/commands/mod.rs | 4 + src/commands/open.rs | 3 + src/commands/verify.rs | 3 + src/main.rs | 115 ++++++++++++++ 9 files changed, 409 insertions(+), 3 deletions(-) create mode 100644 src/commands/commit.rs create mode 100644 src/commands/generate_data.rs create mode 100644 src/commands/mod.rs create mode 100644 src/commands/open.rs create mode 100644 src/commands/verify.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore index 1de5659..80ddbfc 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -target \ No newline at end of file +target +data diff --git a/Cargo.lock b/Cargo.lock index f4af52d..f73f5ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,55 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -38,9 +87,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -48,6 +97,52 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + [[package]] name = "constant_time_eq" version = "0.3.0" @@ -87,6 +182,9 @@ dependencies = [ name = "frida-poc" version = "0.1.0" dependencies = [ + "clap", + "serde", + "serde_json", "winter-crypto", "winter-fri", "winter-math", @@ -115,6 +213,24 @@ dependencies = [ "wasi", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "keccak" version = "0.1.5" @@ -136,6 +252,24 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.8.5" @@ -166,6 +300,43 @@ dependencies = [ "getrandom", ] +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha3" version = "0.10.8" @@ -176,12 +347,41 @@ dependencies = [ "keccak", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "version_check" version = "0.9.4" @@ -194,6 +394,79 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + [[package]] name = "winter-crypto" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 3171890..22ab551 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +clap = { version = "4.5", features = ["derive"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" winter-crypto = "0.9.0" winter-fri = "0.9.0" winter-math = "0.9.0" diff --git a/src/commands/commit.rs b/src/commands/commit.rs new file mode 100644 index 0000000..ddf4378 --- /dev/null +++ b/src/commands/commit.rs @@ -0,0 +1,3 @@ +use winter_fri::FriOptions; + +pub fn run(data_path: &str, num_queries: usize, options: FriOptions) {} diff --git a/src/commands/generate_data.rs b/src/commands/generate_data.rs new file mode 100644 index 0000000..2c3bf9d --- /dev/null +++ b/src/commands/generate_data.rs @@ -0,0 +1 @@ +pub fn run(size: usize, file_path: &str) {} diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..a8e7fac --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,4 @@ +pub mod commit; +pub mod generate_data; +pub mod open; +pub mod verify; diff --git a/src/commands/open.rs b/src/commands/open.rs new file mode 100644 index 0000000..c5e144e --- /dev/null +++ b/src/commands/open.rs @@ -0,0 +1,3 @@ +use winter_fri::FriOptions; + +pub fn run(proof_path: &str, position: usize, options: FriOptions) {} diff --git a/src/commands/verify.rs b/src/commands/verify.rs new file mode 100644 index 0000000..46a5e24 --- /dev/null +++ b/src/commands/verify.rs @@ -0,0 +1,3 @@ +use winter_fri::FriOptions; + +pub fn run(proof_path: &str, data_path: &str, position: usize, options: FriOptions) {} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3918408 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,115 @@ +use clap::{Parser, Subcommand}; +use serde::Deserialize; +use std::fs; +use winter_fri::FriOptions; + +mod commands; + +#[derive(Parser)] +#[command(name = "frida_cli")] +#[command(about = "A CLI for the Frida Verifier", long_about = None)] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Generate random data + GenerateData { + /// Size of the data + size: usize, + /// Path to the data file + #[arg(long)] + file_path: Option, + }, + /// Commit data and generate a proof + Commit { + /// Path to the data file + data: String, + /// Number of queries to generate + num_queries: usize, + /// Path to the FriOptions file (optional) + #[arg(long)] + fri_options: Option, + }, + /// Open a proof for a given position + Open { + /// Path to the proof file + proof: String, + /// Position to open + position: usize, + /// Path to the FriOptions file (optional) + #[arg(long)] + fri_options: Option, + }, + /// Verify a proof + Verify { + /// Path to the proof file + proof: String, + /// Path to the data file + data: String, + /// Position to verify + position: usize, + /// Path to the FriOptions file (optional) + #[arg(long)] + fri_options: Option, + }, +} + +#[derive(Deserialize)] +struct FriOptionsConfig { + blowup_factor: usize, + folding_factor: usize, + max_remainder_degree: usize, +} + +fn load_fri_options(file_path: Option<&String>) -> FriOptions { + if let Some(path) = file_path { + let file_content = fs::read_to_string(path).expect("Unable to read FriOptions file"); + let config: FriOptionsConfig = + serde_json::from_str(&file_content).expect("Invalid FriOptions file format"); + FriOptions::new( + config.blowup_factor, + config.folding_factor, + config.max_remainder_degree, + ) + } else { + FriOptions::new(8, 2, 7) + } +} + +fn main() { + let cli = Cli::parse(); + + match &cli.command { + Commands::GenerateData { size, file_path } => { + commands::generate_data::run(*size, file_path.as_deref().unwrap_or("data/data.bin")); + } + Commands::Commit { + data, + num_queries, + fri_options, + } => { + let options = load_fri_options(fri_options.as_ref()); + commands::commit::run(data, *num_queries, options); + } + Commands::Open { + proof, + position, + fri_options, + } => { + let options = load_fri_options(fri_options.as_ref()); + commands::open::run(proof, *position, options); + } + Commands::Verify { + proof, + data, + position, + fri_options, + } => { + let options = load_fri_options(fri_options.as_ref()); + commands::verify::run(proof, data, *position, options); + } + } +} From ca7064acefc9a43afd9debffec4786d8f4a23961 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Mon, 17 Jun 2024 09:25:50 +0900 Subject: [PATCH 02/23] feat: Add generate_data --- src/commands/generate_data.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/commands/generate_data.rs b/src/commands/generate_data.rs index 2c3bf9d..1545e52 100644 --- a/src/commands/generate_data.rs +++ b/src/commands/generate_data.rs @@ -1 +1,10 @@ -pub fn run(size: usize, file_path: &str) {} +use std::fs::File; +use std::io::Write; +use winter_rand_utils::rand_vector; + +pub fn run(size: usize, file_path: &str) { + let data = rand_vector::(size); + let mut file = File::create(file_path).expect("Unable to create file"); + file.write_all(&data).expect("Unable to write data"); + println!("Generated data of size {} and saved to {}", size, file_path); +} From a70d1c269c72901d4b8fd57912470b93f5964b41 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Mon, 17 Jun 2024 09:26:15 +0900 Subject: [PATCH 03/23] feat: Add a test for generate_data --- src/commands/generate_data.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/commands/generate_data.rs b/src/commands/generate_data.rs index 1545e52..3ed6113 100644 --- a/src/commands/generate_data.rs +++ b/src/commands/generate_data.rs @@ -8,3 +8,19 @@ pub fn run(size: usize, file_path: &str) { file.write_all(&data).expect("Unable to write data"); println!("Generated data of size {} and saved to {}", size, file_path); } + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + + #[test] + fn test_generate_data() { + let size = 200; + let file_path = "data/data.bin"; + run(size, file_path); + let metadata = fs::metadata(file_path).expect("Unable to read metadata"); + assert!(metadata.is_file()); + assert_eq!(metadata.len(), size as u64); + } +} From 6d8fa26612ec8260856d92cc9da98a438875ec42 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Mon, 17 Jun 2024 09:26:55 +0900 Subject: [PATCH 04/23] feat: Add commit TODO: - Save commitment to the file --- src/commands/commit.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/commands/commit.rs b/src/commands/commit.rs index ddf4378..ee4e8ff 100644 --- a/src/commands/commit.rs +++ b/src/commands/commit.rs @@ -1,3 +1,24 @@ +use frida_poc::{ + frida_prover::{traits::BaseFriProver, FridaProver}, + frida_prover_channel::FridaProverChannel, + frida_random::FridaRandom, +}; +use winter_crypto::hashers::Blake3_256; use winter_fri::FriOptions; +use winter_math::fields::f128::BaseElement; -pub fn run(data_path: &str, num_queries: usize, options: FriOptions) {} +type Blake3 = Blake3_256; +type FridaChannel = + FridaProverChannel>; +type FridaProverType = FridaProver; + +pub fn run(data_path: &str, num_queries: usize, options: FriOptions) { + let data = std::fs::read(data_path).expect("Unable to read data file"); + let mut prover: FridaProverType = FridaProver::new(options.clone()); + + let (commitment, _) = prover.commit(data.clone(), num_queries).unwrap(); + + // TODO: Save commitment to file + + println!("Data committed with commitment: {:?}", commitment); +} From 0234c9ac6a2693b636e8f3bcc196388306e70488 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Mon, 17 Jun 2024 09:28:49 +0900 Subject: [PATCH 05/23] feat: Add a test for commit --- src/commands/commit.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/commands/commit.rs b/src/commands/commit.rs index ee4e8ff..0c3179c 100644 --- a/src/commands/commit.rs +++ b/src/commands/commit.rs @@ -22,3 +22,22 @@ pub fn run(data_path: &str, num_queries: usize, options: FriOptions) { println!("Data committed with commitment: {:?}", commitment); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_commit() { + let data_path = "data/data.bin"; + assert!( + std::path::Path::new(data_path).exists(), + "Test data file does not exist" + ); + + let options = FriOptions::new(8, 2, 7); + run(data_path, 31, options); + + // TODO: Check if the commitment file is correct + } +} From 5e59f6e60315c4601daa8bbd15436de66cee82dc Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Wed, 19 Jun 2024 12:39:58 +0900 Subject: [PATCH 06/23] chore: Refactor fri_options to fri_options_path --- src/main.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3918408..497b0c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,7 +31,7 @@ enum Commands { num_queries: usize, /// Path to the FriOptions file (optional) #[arg(long)] - fri_options: Option, + fri_options_path: Option, }, /// Open a proof for a given position Open { @@ -41,7 +41,7 @@ enum Commands { position: usize, /// Path to the FriOptions file (optional) #[arg(long)] - fri_options: Option, + fri_options_path: Option, }, /// Verify a proof Verify { @@ -53,7 +53,7 @@ enum Commands { position: usize, /// Path to the FriOptions file (optional) #[arg(long)] - fri_options: Option, + fri_options_path: Option, }, } @@ -89,26 +89,26 @@ fn main() { Commands::Commit { data, num_queries, - fri_options, + fri_options_path, } => { - let options = load_fri_options(fri_options.as_ref()); + let options = load_fri_options(fri_options_path.as_ref()); commands::commit::run(data, *num_queries, options); } Commands::Open { proof, position, - fri_options, + fri_options_path, } => { - let options = load_fri_options(fri_options.as_ref()); + let options = load_fri_options(fri_options_path.as_ref()); commands::open::run(proof, *position, options); } Commands::Verify { proof, data, position, - fri_options, + fri_options_path, } => { - let options = load_fri_options(fri_options.as_ref()); + let options = load_fri_options(fri_options_path.as_ref()); commands::verify::run(proof, data, *position, options); } } From 0d971ad4a4bbefbc8928d7fcd5914c16e073ee91 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Wed, 19 Jun 2024 12:42:01 +0900 Subject: [PATCH 07/23] feat: Change default value location to command --- src/commands/commit.rs | 10 ++++++++-- src/main.rs | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/commands/commit.rs b/src/commands/commit.rs index 0c3179c..e1701f2 100644 --- a/src/commands/commit.rs +++ b/src/commands/commit.rs @@ -1,4 +1,5 @@ use frida_poc::{ + frida_data::encoded_data_element_count, frida_prover::{traits::BaseFriProver, FridaProver}, frida_prover_channel::FridaProverChannel, frida_random::FridaRandom, @@ -16,11 +17,16 @@ pub fn run(data_path: &str, num_queries: usize, options: FriOptions) { let data = std::fs::read(data_path).expect("Unable to read data file"); let mut prover: FridaProverType = FridaProver::new(options.clone()); - let (commitment, _) = prover.commit(data.clone(), num_queries).unwrap(); + let encoded_element_count = + encoded_data_element_count::(data.len()).next_power_of_two(); + let (commitment, _) = prover.commit(data.clone(), num_queries).unwrap(); // TODO: Save commitment to file - println!("Data committed with commitment: {:?}", commitment); + println!( + "Data committed with commitment: {:?} and encoded element count: {}", + commitment, encoded_element_count + ); } #[cfg(test)] diff --git a/src/main.rs b/src/main.rs index 497b0c2..35c5f7a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,7 @@ enum Commands { /// Size of the data size: usize, /// Path to the data file - #[arg(long)] + #[arg(long, default_value = "data/data.bin")] file_path: Option, }, /// Commit data and generate a proof @@ -84,7 +84,7 @@ fn main() { match &cli.command { Commands::GenerateData { size, file_path } => { - commands::generate_data::run(*size, file_path.as_deref().unwrap_or("data/data.bin")); + commands::generate_data::run(*size, file_path.as_deref().unwrap()); } Commands::Commit { data, From 520695ca53a24cad142ae46bec3c66e7ff1de74d Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Tue, 25 Jun 2024 18:13:10 +0900 Subject: [PATCH 08/23] feat: Add serialization for Commitment --- Cargo.lock | 40 +++++++++++++++++++-------------------- src/commands/commit.rs | 28 +++++++++++++++++++-------- src/frida_prover/mod.rs | 17 ++++++++++++++++- src/frida_prover/proof.rs | 7 ++++--- 4 files changed, 60 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8b8b4d..f5ddf96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -331,6 +331,26 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "ryu" version = "1.0.18" @@ -368,26 +388,6 @@ dependencies = [ "serde", ] -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "sha3" version = "0.10.8" diff --git a/src/commands/commit.rs b/src/commands/commit.rs index e1701f2..9bd7b88 100644 --- a/src/commands/commit.rs +++ b/src/commands/commit.rs @@ -1,3 +1,6 @@ +use serde_json; +use std::fs; + use frida_poc::{ frida_data::encoded_data_element_count, frida_prover::{traits::BaseFriProver, FridaProver}, @@ -13,20 +16,29 @@ type FridaChannel = FridaProverChannel>; type FridaProverType = FridaProver; -pub fn run(data_path: &str, num_queries: usize, options: FriOptions) { - let data = std::fs::read(data_path).expect("Unable to read data file"); +pub fn run( + data_path: &str, + num_queries: usize, + options: FriOptions, +) -> Result<(), Box> { + let data = fs::read(data_path)?; let mut prover: FridaProverType = FridaProver::new(options.clone()); let encoded_element_count = encoded_data_element_count::(data.len()).next_power_of_two(); let (commitment, _) = prover.commit(data.clone(), num_queries).unwrap(); - // TODO: Save commitment to file - println!( - "Data committed with commitment: {:?} and encoded element count: {}", - commitment, encoded_element_count - ); + let commitment_json = serde_json::to_string(&commitment).unwrap(); + fs::write("data/commitment.json", commitment_json)?; + + println!("Commitment saved to data/commitment.json"); + + fs::write("data/count.txt", encoded_element_count.to_string())?; + + println!("Encoded element count saved to data/count.txt"); + + Ok(()) } #[cfg(test)] @@ -42,7 +54,7 @@ mod tests { ); let options = FriOptions::new(8, 2, 7); - run(data_path, 31, options); + run(data_path, 31, options).expect("Failed to commit data"); // TODO: Check if the commitment file is correct } diff --git a/src/frida_prover/mod.rs b/src/frida_prover/mod.rs index 482e50f..7f23df1 100644 --- a/src/frida_prover/mod.rs +++ b/src/frida_prover/mod.rs @@ -3,8 +3,9 @@ use core::marker::PhantomData; #[cfg(feature = "bench")] use std::time::Instant; +use serde::ser::{Serialize, SerializeStruct, Serializer}; use traits::BaseFriProver; -use winter_crypto::{ElementHasher, Hasher, MerkleTree}; +use winter_crypto::{Digest, ElementHasher, Hasher, MerkleTree}; use winter_math::{FieldElement, StarkField}; use winter_fri::FriOptions; @@ -60,6 +61,20 @@ pub struct Commitment { pub batch_size: usize, } +impl Serialize for Commitment { + fn serialize(&self, serializer: S) -> Result { + let mut state = serializer.serialize_struct("Commitment", 4)?; + state.serialize_field( + "roots", + &self.roots.iter().map(|d| d.as_bytes()).collect::>(), + )?; + state.serialize_field("proof", &self.proof)?; + state.serialize_field("num_queries", &self.num_queries)?; + state.serialize_field("batch_size", &self.batch_size)?; + state.end() + } +} + #[cfg(feature = "bench")] pub mod bench { use std::time::{Duration, Instant}; diff --git a/src/frida_prover/proof.rs b/src/frida_prover/proof.rs index da98e4e..26ea8f1 100644 --- a/src/frida_prover/proof.rs +++ b/src/frida_prover/proof.rs @@ -1,3 +1,4 @@ +use serde::Serialize; use winter_crypto::{BatchMerkleProof, ElementHasher, Hasher}; use winter_math::FieldElement; use winter_utils::{ @@ -6,7 +7,7 @@ use winter_utils::{ // FRI PROOF // ================================================================================================ -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub struct FridaProof { batch_layer: Option, layers: Vec, @@ -270,7 +271,7 @@ impl Deserializable for FridaProof { // FRI PROOF LAYER // ================================================================================================ -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub struct FridaProofLayer { values: Vec, paths: Vec, @@ -412,7 +413,7 @@ impl Deserializable for FridaProofLayer { // FRI PROOF LAYER FOR BATCH LAYER // ================================================================================================ -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub struct FridaProofBatchLayer { values: Vec, paths: Vec, From dbee96622bba20a805f20e1083fa443fc51a0217 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Thu, 27 Jun 2024 09:45:08 +0900 Subject: [PATCH 09/23] feat: Implement Serializable to Commitment --- Cargo.lock | 4 +- src/commands/commit.rs | 117 +++++++++++++++++++++++++++++----- src/commands/generate_data.rs | 40 ++++++++++-- src/frida_prover/mod.rs | 51 +++++++++++---- src/frida_prover/proof.rs | 7 +- src/lib.rs | 1 + src/main.rs | 46 ++++--------- src/utils/mod.rs | 25 ++++++++ 8 files changed, 216 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f5ddf96..0894e72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -379,9 +379,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "itoa", "ryu", diff --git a/src/commands/commit.rs b/src/commands/commit.rs index 9bd7b88..b8e4807 100644 --- a/src/commands/commit.rs +++ b/src/commands/commit.rs @@ -1,42 +1,79 @@ -use serde_json; use std::fs; +use std::fs::File; +use std::io::BufWriter; +use std::io::Write; -use frida_poc::{ +use crate::{ frida_data::encoded_data_element_count, - frida_prover::{traits::BaseFriProver, FridaProver}, + frida_prover::{traits::BaseFriProver, Commitment, FridaProver}, frida_prover_channel::FridaProverChannel, frida_random::FridaRandom, }; use winter_crypto::hashers::Blake3_256; use winter_fri::FriOptions; use winter_math::fields::f128::BaseElement; +use winter_utils::Serializable; type Blake3 = Blake3_256; type FridaChannel = FridaProverChannel>; type FridaProverType = FridaProver; +/// Runs the commitment process, saving the commitment to a file. pub fn run( data_path: &str, + commitment_path: &str, num_queries: usize, options: FriOptions, -) -> Result<(), Box> { +) -> Result<(usize, Commitment), Box> { + // Create commitment from the data file + let (encoded_element_count, commitment) = + create_commitment_from_file(data_path, num_queries, options)?; + + // Write the commitment to the specified file + write_commitment_to_file(encoded_element_count, &commitment, commitment_path)?; + + // Print success message with detail + println!("Commitment created and saved to {}", commitment_path); + + Ok((encoded_element_count, commitment)) +} + +/// Creates a commitment from the data file. +fn create_commitment_from_file( + data_path: &str, + num_queries: usize, + options: FriOptions, +) -> Result<(usize, Commitment), Box> { + // Read data from the file let data = fs::read(data_path)?; let mut prover: FridaProverType = FridaProver::new(options.clone()); + // Calculate the encoded element count let encoded_element_count = encoded_data_element_count::(data.len()).next_power_of_two(); - let (commitment, _) = prover.commit(data.clone(), num_queries).unwrap(); + // Generate the commitment + let (commitment, _) = prover.commit(data, num_queries).unwrap(); - let commitment_json = serde_json::to_string(&commitment).unwrap(); - fs::write("data/commitment.json", commitment_json)?; - - println!("Commitment saved to data/commitment.json"); + Ok((encoded_element_count, commitment)) +} - fs::write("data/count.txt", encoded_element_count.to_string())?; +/// Writes the commitment and encoded element count to a file. +fn write_commitment_to_file( + encoded_element_count: usize, + commitment: &Commitment, + file_path: &str, +) -> Result<(), Box> { + // Serialize the commitment and encoded element count + let commitment_bytes = commitment.to_bytes(); + let encoded_element_count_bytes = encoded_element_count.to_le_bytes(); - println!("Encoded element count saved to data/count.txt"); + // Write to the file + let mut file = File::create(file_path)?; + let mut writer = BufWriter::new(&mut file); + writer.write_all(&encoded_element_count_bytes)?; + writer.write_all(&commitment_bytes)?; Ok(()) } @@ -44,18 +81,64 @@ pub fn run( #[cfg(test)] mod tests { use super::*; + use crate::{commands::generate_data, utils::load_fri_options}; + use std::io::BufReader; + use std::io::Read; + use winter_utils::Deserializable; #[test] fn test_commit() { let data_path = "data/data.bin"; - assert!( - std::path::Path::new(data_path).exists(), - "Test data file does not exist" + let commitment_path = "data/commitment.bin"; + + if !std::path::Path::new(data_path).exists() { + generate_data::run(200, data_path).unwrap(); + } + + let options = load_fri_options(None); + + // Run the commitment process + let (encoded_element_count, commitment) = + run(data_path, commitment_path, 31, options).unwrap(); + + // Read the commitment from the file + let (encoded_element_count_file, commitment_file) = + read_commitment_from_file(commitment_path).unwrap(); + + // Verify the encoded element count + assert_eq!( + encoded_element_count, encoded_element_count_file, + "Encoded element count does not match." ); - let options = FriOptions::new(8, 2, 7); - run(data_path, 31, options).expect("Failed to commit data"); + // Verify the commitment + assert_eq!(commitment, commitment_file, "Commitment does not match."); + + // Cleanup + fs::remove_file(data_path).unwrap(); + fs::remove_file(commitment_path).unwrap(); + } + + /// Reads the commitment and encoded element count from a file. + fn read_commitment_from_file( + file_path: &str, + ) -> Result<(usize, Commitment), Box> { + // Open the file and create a buffered reader + let file = File::open(file_path)?; + let mut reader = BufReader::new(file); + + // Read the encoded element count + let mut encoded_element_count_bytes = [0u8; 8]; + reader.read_exact(&mut encoded_element_count_bytes)?; + let encoded_element_count = usize::from_le_bytes(encoded_element_count_bytes); + + // Read the commitment bytes + let mut commitment_bytes = Vec::new(); + reader.read_to_end(&mut commitment_bytes)?; + + // Deserialize the commitment + let commitment = Commitment::::read_from_bytes(&commitment_bytes).unwrap(); - // TODO: Check if the commitment file is correct + Ok((encoded_element_count, commitment)) } } diff --git a/src/commands/generate_data.rs b/src/commands/generate_data.rs index 3ed6113..26eb079 100644 --- a/src/commands/generate_data.rs +++ b/src/commands/generate_data.rs @@ -1,26 +1,56 @@ +use std::fs; use std::fs::File; use std::io::Write; use winter_rand_utils::rand_vector; -pub fn run(size: usize, file_path: &str) { +pub fn run(size: usize, file_path: &str) -> Result, Box> { + // Generate random data let data = rand_vector::(size); + + // Ensure directory exists + if let Some(parent) = std::path::Path::new(file_path).parent() { + fs::create_dir_all(parent).expect("Unable to create directories"); + } + + // Write data to file let mut file = File::create(file_path).expect("Unable to create file"); file.write_all(&data).expect("Unable to write data"); + + // Print success message println!("Generated data of size {} and saved to {}", size, file_path); + + Ok(data) } #[cfg(test)] mod tests { use super::*; use std::fs; + use std::io::Read; #[test] fn test_generate_data() { let size = 200; let file_path = "data/data.bin"; - run(size, file_path); - let metadata = fs::metadata(file_path).expect("Unable to read metadata"); - assert!(metadata.is_file()); - assert_eq!(metadata.len(), size as u64); + + // Ensure directory exists + if let Some(parent) = std::path::Path::new(file_path).parent() { + fs::create_dir_all(parent).expect("Unable to create directories"); + } + + // Generate data and write to file + let data = run(size, file_path).unwrap(); + + // Read data from file + let mut file = File::open(file_path).expect("Unable to open file"); + let mut file_data = Vec::new(); + file.read_to_end(&mut file_data) + .expect("Unable to read file"); + + // Verify data + assert_eq!(data, file_data); + + // Clean up + fs::remove_file(file_path).expect("Unable to delete file"); } } diff --git a/src/frida_prover/mod.rs b/src/frida_prover/mod.rs index 7f23df1..2105bfa 100644 --- a/src/frida_prover/mod.rs +++ b/src/frida_prover/mod.rs @@ -3,9 +3,8 @@ use core::marker::PhantomData; #[cfg(feature = "bench")] use std::time::Instant; -use serde::ser::{Serialize, SerializeStruct, Serializer}; use traits::BaseFriProver; -use winter_crypto::{Digest, ElementHasher, Hasher, MerkleTree}; +use winter_crypto::{ElementHasher, Hasher, MerkleTree}; use winter_math::{FieldElement, StarkField}; use winter_fri::FriOptions; @@ -16,7 +15,9 @@ use proof::FridaProof; #[cfg(feature = "concurrent")] use winter_utils::iterators::*; -use winter_utils::{iter_mut, uninit_vector}; +use winter_utils::{ + iter_mut, uninit_vector, ByteReader, Deserializable, DeserializationError, Serializable, +}; use crate::{ frida_const, @@ -61,17 +62,39 @@ pub struct Commitment { pub batch_size: usize, } -impl Serialize for Commitment { - fn serialize(&self, serializer: S) -> Result { - let mut state = serializer.serialize_struct("Commitment", 4)?; - state.serialize_field( - "roots", - &self.roots.iter().map(|d| d.as_bytes()).collect::>(), - )?; - state.serialize_field("proof", &self.proof)?; - state.serialize_field("num_queries", &self.num_queries)?; - state.serialize_field("batch_size", &self.batch_size)?; - state.end() +impl Serializable for Commitment +where + HRoot::Digest: Serializable, +{ + fn write_into(&self, target: &mut W) { + self.roots.write_into(target); + self.proof.write_into(target); + self.num_queries.write_into(target); + self.batch_size.write_into(target); + } + + fn get_size_hint(&self) -> usize { + // 24 + 104 + 8 + 8 + 136 + } +} + +impl Deserializable for Commitment +where + HRoot::Digest: Deserializable, +{ + fn read_from(source: &mut R) -> Result { + let roots = Vec::::read_from(source)?; + let proof = FridaProof::read_from(source)?; + let num_queries = usize::read_from(source)?; + let batch_size = usize::read_from(source)?; + + Ok(Commitment { + roots, + proof, + num_queries, + batch_size, + }) } } diff --git a/src/frida_prover/proof.rs b/src/frida_prover/proof.rs index 26ea8f1..da98e4e 100644 --- a/src/frida_prover/proof.rs +++ b/src/frida_prover/proof.rs @@ -1,4 +1,3 @@ -use serde::Serialize; use winter_crypto::{BatchMerkleProof, ElementHasher, Hasher}; use winter_math::FieldElement; use winter_utils::{ @@ -7,7 +6,7 @@ use winter_utils::{ // FRI PROOF // ================================================================================================ -#[derive(Debug, Clone, Eq, PartialEq, Serialize)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct FridaProof { batch_layer: Option, layers: Vec, @@ -271,7 +270,7 @@ impl Deserializable for FridaProof { // FRI PROOF LAYER // ================================================================================================ -#[derive(Debug, Clone, Eq, PartialEq, Serialize)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct FridaProofLayer { values: Vec, paths: Vec, @@ -413,7 +412,7 @@ impl Deserializable for FridaProofLayer { // FRI PROOF LAYER FOR BATCH LAYER // ================================================================================================ -#[derive(Debug, Clone, Eq, PartialEq, Serialize)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct FridaProofBatchLayer { values: Vec, paths: Vec, diff --git a/src/lib.rs b/src/lib.rs index 4f91fdf..696fae5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +pub mod commands; pub mod frida_const; pub mod frida_data; pub mod frida_error; diff --git a/src/main.rs b/src/main.rs index 35c5f7a..c3fca5f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,6 @@ use clap::{Parser, Subcommand}; -use serde::Deserialize; -use std::fs; -use winter_fri::FriOptions; - -mod commands; +use frida_poc::commands; +use frida_poc::utils; #[derive(Parser)] #[command(name = "frida_cli")] @@ -21,12 +18,16 @@ enum Commands { size: usize, /// Path to the data file #[arg(long, default_value = "data/data.bin")] - file_path: Option, + file_path: String, }, /// Commit data and generate a proof Commit { /// Path to the data file + #[arg(long, default_value = "data/data.bin")] data: String, + /// Path to the commitment file + #[arg(long, default_value = "data/commitment.bin")] + commitment_path: String, /// Number of queries to generate num_queries: usize, /// Path to the FriOptions file (optional) @@ -57,49 +58,28 @@ enum Commands { }, } -#[derive(Deserialize)] -struct FriOptionsConfig { - blowup_factor: usize, - folding_factor: usize, - max_remainder_degree: usize, -} - -fn load_fri_options(file_path: Option<&String>) -> FriOptions { - if let Some(path) = file_path { - let file_content = fs::read_to_string(path).expect("Unable to read FriOptions file"); - let config: FriOptionsConfig = - serde_json::from_str(&file_content).expect("Invalid FriOptions file format"); - FriOptions::new( - config.blowup_factor, - config.folding_factor, - config.max_remainder_degree, - ) - } else { - FriOptions::new(8, 2, 7) - } -} - fn main() { let cli = Cli::parse(); match &cli.command { Commands::GenerateData { size, file_path } => { - commands::generate_data::run(*size, file_path.as_deref().unwrap()); + commands::generate_data::run(*size, file_path).unwrap(); } Commands::Commit { data, + commitment_path, num_queries, fri_options_path, } => { - let options = load_fri_options(fri_options_path.as_ref()); - commands::commit::run(data, *num_queries, options); + let options = utils::load_fri_options(fri_options_path.as_ref()); + commands::commit::run(data, commitment_path, *num_queries, options).unwrap(); } Commands::Open { proof, position, fri_options_path, } => { - let options = load_fri_options(fri_options_path.as_ref()); + let options = utils::load_fri_options(fri_options_path.as_ref()); commands::open::run(proof, *position, options); } Commands::Verify { @@ -108,7 +88,7 @@ fn main() { position, fri_options_path, } => { - let options = load_fri_options(fri_options_path.as_ref()); + let options = utils::load_fri_options(fri_options_path.as_ref()); commands::verify::run(proof, data, *position, options); } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 51838d1..955f714 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,3 +1,6 @@ +use serde::Deserialize; +use std::fs; + use winter_crypto::hashers::Blake3_256; use winter_fri::FriOptions; use winter_math::{fft, fields::f128::BaseElement, FieldElement}; @@ -31,3 +34,25 @@ pub fn build_evaluations(trace_length: usize, lde_blowup: usize) -> Vec) -> FriOptions { + if let Some(path) = file_path { + let file_content = fs::read_to_string(path).expect("Unable to read FriOptions file"); + let config: FriOptionsConfig = + serde_json::from_str(&file_content).expect("Invalid FriOptions file format"); + FriOptions::new( + config.blowup_factor, + config.folding_factor, + config.max_remainder_degree, + ) + } else { + FriOptions::new(8, 2, 7) + } +} From d1893cbb135138d39d10b33a16155b0bce8f3a81 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Mon, 1 Jul 2024 06:33:14 +0900 Subject: [PATCH 10/23] feat: Add open command --- src/commands/commit.rs | 62 ++++++++++++++++++++---------------------- src/commands/open.rs | 41 +++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 33 deletions(-) diff --git a/src/commands/commit.rs b/src/commands/commit.rs index b8e4807..12ae2d3 100644 --- a/src/commands/commit.rs +++ b/src/commands/commit.rs @@ -1,18 +1,19 @@ -use std::fs; -use std::fs::File; -use std::io::BufWriter; -use std::io::Write; - use crate::{ frida_data::encoded_data_element_count, frida_prover::{traits::BaseFriProver, Commitment, FridaProver}, frida_prover_channel::FridaProverChannel, frida_random::FridaRandom, }; +use std::fs; +use std::fs::File; +use std::io::BufReader; +use std::io::BufWriter; +use std::io::Read; +use std::io::Write; use winter_crypto::hashers::Blake3_256; use winter_fri::FriOptions; use winter_math::fields::f128::BaseElement; -use winter_utils::Serializable; +use winter_utils::{Deserializable, Serializable}; type Blake3 = Blake3_256; type FridaChannel = @@ -78,13 +79,33 @@ fn write_commitment_to_file( Ok(()) } +/// Reads the commitment and encoded element count from a file. +pub fn read_commitment_from_file( + file_path: &str, +) -> Result<(usize, Commitment), Box> { + // Open the file and create a buffered reader + let file = File::open(file_path)?; + let mut reader = BufReader::new(file); + + // Read the encoded element count + let mut encoded_element_count_bytes = [0u8; 8]; + reader.read_exact(&mut encoded_element_count_bytes)?; + let encoded_element_count = usize::from_le_bytes(encoded_element_count_bytes); + + // Read the commitment bytes + let mut commitment_bytes = Vec::new(); + reader.read_to_end(&mut commitment_bytes)?; + + // Deserialize the commitment + let commitment = Commitment::::read_from_bytes(&commitment_bytes).unwrap(); + + Ok((encoded_element_count, commitment)) +} + #[cfg(test)] mod tests { use super::*; use crate::{commands::generate_data, utils::load_fri_options}; - use std::io::BufReader; - use std::io::Read; - use winter_utils::Deserializable; #[test] fn test_commit() { @@ -118,27 +139,4 @@ mod tests { fs::remove_file(data_path).unwrap(); fs::remove_file(commitment_path).unwrap(); } - - /// Reads the commitment and encoded element count from a file. - fn read_commitment_from_file( - file_path: &str, - ) -> Result<(usize, Commitment), Box> { - // Open the file and create a buffered reader - let file = File::open(file_path)?; - let mut reader = BufReader::new(file); - - // Read the encoded element count - let mut encoded_element_count_bytes = [0u8; 8]; - reader.read_exact(&mut encoded_element_count_bytes)?; - let encoded_element_count = usize::from_le_bytes(encoded_element_count_bytes); - - // Read the commitment bytes - let mut commitment_bytes = Vec::new(); - reader.read_to_end(&mut commitment_bytes)?; - - // Deserialize the commitment - let commitment = Commitment::::read_from_bytes(&commitment_bytes).unwrap(); - - Ok((encoded_element_count, commitment)) - } } diff --git a/src/commands/open.rs b/src/commands/open.rs index c5e144e..d125fe3 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -1,3 +1,42 @@ +use std::fs; +use std::fs::File; +use std::io::BufWriter; +use std::io::Write; + +use crate::{ + commands::commit::read_commitment_from_file, + frida_data::{build_evaluations_from_data, encoded_data_element_count}, + frida_prover::{traits::BaseFriProver, Commitment, FridaProver}, + frida_prover_channel::FridaProverChannel, + frida_random::FridaRandom, +}; +use winter_crypto::hashers::Blake3_256; use winter_fri::FriOptions; +use winter_math::fields::f128::BaseElement; + +type Blake3 = Blake3_256; +type FridaChannel = + FridaProverChannel>; +type FridaProverType = FridaProver; + +pub fn run(proof_path: &str, positions: &[usize], options: FriOptions) { + let data = fs::read("data/data.bin").unwrap(); + let encoded_element_count = + encoded_data_element_count::(data.len()).next_power_of_two(); + let (_, commitment) = read_commitment_from_file("d").expect("Cannot read commitment file"); + + let mut prover: FridaProverType = FridaProver::new(options.clone()); + let open_position = [1]; + let proof = prover.open(&open_position); + + let domain_size = (encoded_element_count - 1).next_power_of_two() * options.blowup_factor(); + let evaluations: Vec = + build_evaluations_from_data(&data, domain_size, options.blowup_factor()).unwrap(); + + let queried_evaluations = open_position + .iter() + .map(|&p| evaluations[p]) + .collect::>(); -pub fn run(proof_path: &str, position: usize, options: FriOptions) {} + // TODO: Save to the file +} From ed85773e2105abad9a30d9384abecd523cac6cac Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Mon, 1 Jul 2024 20:12:43 +0900 Subject: [PATCH 11/23] feat: Initialize prover in the main --- src/commands/commit.rs | 66 +++++++++++-------------------- src/commands/open.rs | 90 ++++++++++++++++++++++++++++++++++++++---- src/commands/verify.rs | 4 +- src/main.rs | 90 ++++++++++++++++++++++++------------------ 4 files changed, 157 insertions(+), 93 deletions(-) diff --git a/src/commands/commit.rs b/src/commands/commit.rs index 12ae2d3..673e2f5 100644 --- a/src/commands/commit.rs +++ b/src/commands/commit.rs @@ -1,6 +1,5 @@ use crate::{ - frida_data::encoded_data_element_count, - frida_prover::{traits::BaseFriProver, Commitment, FridaProver}, + frida_prover::{Commitment, FridaProver}, frida_prover_channel::FridaProverChannel, frida_random::FridaRandom, }; @@ -11,7 +10,6 @@ use std::io::BufWriter; use std::io::Read; use std::io::Write; use winter_crypto::hashers::Blake3_256; -use winter_fri::FriOptions; use winter_math::fields::f128::BaseElement; use winter_utils::{Deserializable, Serializable}; @@ -22,76 +20,62 @@ type FridaProverType = FridaProver Result<(usize, Commitment), Box> { +) -> Result, Box> { // Create commitment from the data file - let (encoded_element_count, commitment) = - create_commitment_from_file(data_path, num_queries, options)?; + let commitment = create_commitment_from_file(prover, num_queries, data_path)?; // Write the commitment to the specified file - write_commitment_to_file(encoded_element_count, &commitment, commitment_path)?; + write_commitment_to_file(&commitment, commitment_path)?; // Print success message with detail println!("Commitment created and saved to {}", commitment_path); - Ok((encoded_element_count, commitment)) + Ok(commitment) } /// Creates a commitment from the data file. fn create_commitment_from_file( - data_path: &str, + prover: &mut FridaProverType, num_queries: usize, - options: FriOptions, -) -> Result<(usize, Commitment), Box> { + data_path: &str, +) -> Result, Box> { // Read data from the file let data = fs::read(data_path)?; - let mut prover: FridaProverType = FridaProver::new(options.clone()); - - // Calculate the encoded element count - let encoded_element_count = - encoded_data_element_count::(data.len()).next_power_of_two(); // Generate the commitment let (commitment, _) = prover.commit(data, num_queries).unwrap(); - Ok((encoded_element_count, commitment)) + Ok(commitment) } -/// Writes the commitment and encoded element count to a file. +/// Writes the commitment to a file. fn write_commitment_to_file( - encoded_element_count: usize, commitment: &Commitment, file_path: &str, ) -> Result<(), Box> { - // Serialize the commitment and encoded element count + // Serialize the commitment let commitment_bytes = commitment.to_bytes(); - let encoded_element_count_bytes = encoded_element_count.to_le_bytes(); // Write to the file let mut file = File::create(file_path)?; let mut writer = BufWriter::new(&mut file); - writer.write_all(&encoded_element_count_bytes)?; writer.write_all(&commitment_bytes)?; Ok(()) } -/// Reads the commitment and encoded element count from a file. +/// Reads the commitment from a file. pub fn read_commitment_from_file( file_path: &str, -) -> Result<(usize, Commitment), Box> { +) -> Result, Box> { // Open the file and create a buffered reader let file = File::open(file_path)?; let mut reader = BufReader::new(file); - // Read the encoded element count - let mut encoded_element_count_bytes = [0u8; 8]; - reader.read_exact(&mut encoded_element_count_bytes)?; - let encoded_element_count = usize::from_le_bytes(encoded_element_count_bytes); - // Read the commitment bytes let mut commitment_bytes = Vec::new(); reader.read_to_end(&mut commitment_bytes)?; @@ -99,13 +83,15 @@ pub fn read_commitment_from_file( // Deserialize the commitment let commitment = Commitment::::read_from_bytes(&commitment_bytes).unwrap(); - Ok((encoded_element_count, commitment)) + Ok(commitment) } #[cfg(test)] mod tests { use super::*; - use crate::{commands::generate_data, utils::load_fri_options}; + use crate::commands::generate_data; + use crate::frida_prover::traits::BaseFriProver; + use winter_fri::FriOptions; #[test] fn test_commit() { @@ -116,21 +102,13 @@ mod tests { generate_data::run(200, data_path).unwrap(); } - let options = load_fri_options(None); + let mut prover = FridaProverType::new(FriOptions::new(8, 2, 7)); // Run the commitment process - let (encoded_element_count, commitment) = - run(data_path, commitment_path, 31, options).unwrap(); + let commitment = run(&mut prover, 31, data_path, commitment_path).unwrap(); // Read the commitment from the file - let (encoded_element_count_file, commitment_file) = - read_commitment_from_file(commitment_path).unwrap(); - - // Verify the encoded element count - assert_eq!( - encoded_element_count, encoded_element_count_file, - "Encoded element count does not match." - ); + let commitment_file = read_commitment_from_file(commitment_path).unwrap(); // Verify the commitment assert_eq!(commitment, commitment_file, "Commitment does not match."); diff --git a/src/commands/open.rs b/src/commands/open.rs index d125fe3..968a4b2 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -4,30 +4,35 @@ use std::io::BufWriter; use std::io::Write; use crate::{ - commands::commit::read_commitment_from_file, frida_data::{build_evaluations_from_data, encoded_data_element_count}, - frida_prover::{traits::BaseFriProver, Commitment, FridaProver}, + frida_prover::{proof::FridaProof, traits::BaseFriProver, FridaProver}, frida_prover_channel::FridaProverChannel, frida_random::FridaRandom, }; use winter_crypto::hashers::Blake3_256; -use winter_fri::FriOptions; use winter_math::fields::f128::BaseElement; +use winter_utils::Serializable; type Blake3 = Blake3_256; type FridaChannel = FridaProverChannel>; type FridaProverType = FridaProver; -pub fn run(proof_path: &str, positions: &[usize], options: FriOptions) { +pub fn run( + prover: &mut FridaProverType, + proof_path: &str, + positions: &[usize], +) -> Result<(FridaProof, Vec), Box> { + let options = prover.options().clone(); + // Read from files let data = fs::read("data/data.bin").unwrap(); + + // Calculate encoded element count let encoded_element_count = encoded_data_element_count::(data.len()).next_power_of_two(); - let (_, commitment) = read_commitment_from_file("d").expect("Cannot read commitment file"); - let mut prover: FridaProverType = FridaProver::new(options.clone()); - let open_position = [1]; - let proof = prover.open(&open_position); + let open_position = positions; + let proof = prover.open(open_position); let domain_size = (encoded_element_count - 1).next_power_of_two() * options.blowup_factor(); let evaluations: Vec = @@ -39,4 +44,73 @@ pub fn run(proof_path: &str, positions: &[usize], options: FriOptions) { .collect::>(); // TODO: Save to the file + let proof_bytes = proof.to_bytes(); + let queried_evaluations_bytes = queried_evaluations.to_bytes(); + + // Write to the file + let mut file = File::create(proof_path)?; + let mut writer = BufWriter::new(&mut file); + writer.write_all(&proof_bytes)?; + writer.write_all(&queried_evaluations_bytes)?; + + Ok((proof, queried_evaluations)) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::commands::generate_data; + use std::fs; + use std::io::Read; + use winter_fri::FriOptions; + + #[test] + fn test_open() { + // Paths + let data_path = "data/data.bin"; + let proof_path = "data/proof.bin"; + + // Prepare data + if !std::path::Path::new(data_path).exists() { + generate_data::run(200, data_path).unwrap(); + } + let data = fs::read(data_path).unwrap(); + let num_queries = 31; + + // Initialize prover + let mut prover = FridaProverType::new(FriOptions::new(8, 2, 7)); + + // Generate the commitment + prover.commit(data, num_queries).unwrap(); + + // Specify positions to open + let positions = vec![0, 5, 10]; + + // Run the opening process + let result = run(&mut prover, proof_path, &positions); + assert!(result.is_ok(), "Failed to generate proof and evaluations."); + + let (proof, queried_evaluations) = result.unwrap(); + + // Verify the contents are written to file + let mut file_contents = Vec::new(); + let mut file = fs::File::open(proof_path).unwrap(); + file.read_to_end(&mut file_contents).unwrap(); + + // Serialize proof and queried evaluations + let mut proof_bytes = proof.to_bytes(); + let queried_evaluations_bytes = queried_evaluations.to_bytes(); + proof_bytes.extend(queried_evaluations_bytes); + + assert_eq!( + file_contents, proof_bytes, + "File contents do not match expected serialized output." + ); + + // Optionally, validate proof with external verification logic here, if available + + // Cleanup + fs::remove_file(data_path).unwrap(); + fs::remove_file(proof_path).unwrap(); + } } diff --git a/src/commands/verify.rs b/src/commands/verify.rs index 46a5e24..b6ad846 100644 --- a/src/commands/verify.rs +++ b/src/commands/verify.rs @@ -1,3 +1 @@ -use winter_fri::FriOptions; - -pub fn run(proof_path: &str, data_path: &str, position: usize, options: FriOptions) {} +pub fn run(commitment_path: &str, positions_path: &str, evaluations_path: &str, proof_path: &str) {} diff --git a/src/main.rs b/src/main.rs index c3fca5f..fb267b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,16 @@ use clap::{Parser, Subcommand}; use frida_poc::commands; +use frida_poc::frida_prover::{traits::BaseFriProver, FridaProver}; use frida_poc::utils; +use winter_crypto::hashers::Blake3_256; +use winter_math::fields::f128::BaseElement; + +use frida_poc::{frida_prover_channel::FridaProverChannel, frida_random::FridaRandom}; + +type Blake3 = Blake3_256; +type FridaChannel = + FridaProverChannel>; +type FridaProverType = FridaProver; #[derive(Parser)] #[command(name = "frida_cli")] @@ -12,6 +22,8 @@ struct Cli { #[derive(Subcommand)] enum Commands { + /// Initialize settings + Init, /// Generate random data GenerateData { /// Size of the data @@ -22,74 +34,76 @@ enum Commands { }, /// Commit data and generate a proof Commit { + /// Number of queries to generate + num_queries: usize, /// Path to the data file #[arg(long, default_value = "data/data.bin")] - data: String, + data_path: String, /// Path to the commitment file #[arg(long, default_value = "data/commitment.bin")] commitment_path: String, - /// Number of queries to generate - num_queries: usize, - /// Path to the FriOptions file (optional) - #[arg(long)] - fri_options_path: Option, }, /// Open a proof for a given position Open { - /// Path to the proof file - proof: String, /// Position to open - position: usize, - /// Path to the FriOptions file (optional) - #[arg(long)] - fri_options_path: Option, + positions: Vec, + /// Path to the proof file + #[arg(long, default_value = "data/proof.bin")] + proof_path: String, }, /// Verify a proof Verify { + /// Path to the commitment file + #[arg(long, default_value = "data/commitment.bin")] + commitment_path: String, + /// Path to the positions file + #[arg(long, default_value = "data/positions.bin")] + positions_path: String, + /// Path to the evaluations file + #[arg(long, default_value = "data/evaluations.bin")] + evaluations_path: String, /// Path to the proof file - proof: String, - /// Path to the data file - data: String, - /// Position to verify - position: usize, - /// Path to the FriOptions file (optional) - #[arg(long)] - fri_options_path: Option, + #[arg(long, default_value = "data/proof.bin")] + proof_path: String, }, } fn main() { let cli = Cli::parse(); + let mut prover = FridaProverType::new(utils::load_fri_options(None)); match &cli.command { + Commands::Init => { + let options = utils::load_fri_options(None); + prover = FridaProverType::new(options); + } Commands::GenerateData { size, file_path } => { - commands::generate_data::run(*size, file_path).unwrap(); + commands::generate_data::run(*size, file_path).expect("Failed to generate data"); } Commands::Commit { - data, + data_path, commitment_path, num_queries, - fri_options_path, } => { - let options = utils::load_fri_options(fri_options_path.as_ref()); - commands::commit::run(data, commitment_path, *num_queries, options).unwrap(); + commands::commit::run(&mut prover, *num_queries, data_path, commitment_path) + .expect("Failed to commit data"); } Commands::Open { - proof, - position, - fri_options_path, + positions, + proof_path, } => { - let options = utils::load_fri_options(fri_options_path.as_ref()); - commands::open::run(proof, *position, options); + commands::open::run(&mut prover, proof_path, positions).expect("Failed to open proof"); } Commands::Verify { - proof, - data, - position, - fri_options_path, - } => { - let options = utils::load_fri_options(fri_options_path.as_ref()); - commands::verify::run(proof, data, *position, options); - } + commitment_path, + positions_path, + evaluations_path, + proof_path, + } => commands::verify::run( + commitment_path, + positions_path, + evaluations_path, + proof_path, + ), } } From 145f4277354b7dd1c85af6ece34aa533aaf44ffd Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Tue, 2 Jul 2024 05:32:22 +0900 Subject: [PATCH 12/23] feat: Complete CLI implementation --- Cargo.lock | 7 ++ Cargo.toml | 1 + src/commands/open.rs | 106 ++++++++++++++++------ src/commands/verify.rs | 115 +++++++++++++++++++++++- src/main.rs | 193 +++++++++++++++++++++++++++++++++-------- 5 files changed, 361 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0894e72..542b6fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,6 +216,7 @@ dependencies = [ "clap", "serde", "serde_json", + "shlex", "winter-crypto", "winter-fri", "winter-math", @@ -398,6 +399,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "strsim" version = "0.11.1" diff --git a/Cargo.toml b/Cargo.toml index 9410ef4..ea11cfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ bench = [] clap = { version = "4.5", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +shlex = "1.3.0" winter-crypto = "0.9.0" winter-fri = "0.9.0" winter-math = "0.9.0" diff --git a/src/commands/open.rs b/src/commands/open.rs index 968a4b2..10c4641 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -1,16 +1,17 @@ -use std::fs; -use std::fs::File; -use std::io::BufWriter; -use std::io::Write; - use crate::{ frida_data::{build_evaluations_from_data, encoded_data_element_count}, frida_prover::{proof::FridaProof, traits::BaseFriProver, FridaProver}, frida_prover_channel::FridaProverChannel, frida_random::FridaRandom, }; +use std::fs; +use std::fs::File; +use std::io::BufWriter; +use std::io::Write; +use std::io::{BufReader, Read}; use winter_crypto::hashers::Blake3_256; use winter_math::fields::f128::BaseElement; +use winter_utils::Deserializable; use winter_utils::Serializable; type Blake3 = Blake3_256; @@ -20,9 +21,11 @@ type FridaProverType = FridaProver Result<(FridaProof, Vec), Box> { + positions_path: &str, + evaluations_path: &str, + proof_path: &str, +) -> Result<(Vec, Vec, FridaProof), Box> { let options = prover.options().clone(); // Read from files let data = fs::read("data/data.bin").unwrap(); @@ -43,31 +46,71 @@ pub fn run( .map(|&p| evaluations[p]) .collect::>(); - // TODO: Save to the file + // Save to separate files let proof_bytes = proof.to_bytes(); let queried_evaluations_bytes = queried_evaluations.to_bytes(); + let positions_bytes = positions.to_bytes(); + + // Write positions to the file + let mut file = File::create(positions_path)?; + let mut writer = BufWriter::new(&mut file); + writer.write_all(&positions_bytes)?; + + // Write queried evaluations to the file + let mut file = File::create(evaluations_path)?; + let mut writer = BufWriter::new(&mut file); + writer.write_all(&queried_evaluations_bytes)?; - // Write to the file + // Write proof to the file let mut file = File::create(proof_path)?; let mut writer = BufWriter::new(&mut file); writer.write_all(&proof_bytes)?; - writer.write_all(&queried_evaluations_bytes)?; - Ok((proof, queried_evaluations)) + Ok((positions.to_vec(), queried_evaluations, proof)) } +pub fn read_and_deserialize_proof( + positions_path: &str, + evaluations_path: &str, + proof_path: &str, +) -> Result<(Vec, Vec, FridaProof), Box> { + // Read positions + let mut file = File::open(positions_path)?; + let mut reader = BufReader::new(&mut file); + let mut positions_bytes = Vec::new(); + reader.read_to_end(&mut positions_bytes)?; + let positions = Vec::::read_from_bytes(&positions_bytes).unwrap(); + + // Read queried evaluations + let mut file = File::open(evaluations_path)?; + let mut reader = BufReader::new(&mut file); + let mut queried_evaluations_bytes = Vec::new(); + reader.read_to_end(&mut queried_evaluations_bytes)?; + let queried_evaluations = + Vec::::read_from_bytes(&queried_evaluations_bytes).unwrap(); + + // Read proof + let mut file = File::open(proof_path)?; + let mut reader = BufReader::new(&mut file); + let mut proof_bytes = Vec::new(); + reader.read_to_end(&mut proof_bytes)?; + let proof = FridaProof::read_from_bytes(&proof_bytes).unwrap(); + + Ok((positions, queried_evaluations, proof)) +} #[cfg(test)] mod tests { use super::*; use crate::commands::generate_data; use std::fs; - use std::io::Read; use winter_fri::FriOptions; #[test] fn test_open() { // Paths let data_path = "data/data.bin"; + let positions_path = "data/positions.bin"; + let evaluations_path = "data/evaluations.bin"; let proof_path = "data/proof.bin"; // Prepare data @@ -87,30 +130,43 @@ mod tests { let positions = vec![0, 5, 10]; // Run the opening process - let result = run(&mut prover, proof_path, &positions); + let result = run( + &mut prover, + &positions, + positions_path, + evaluations_path, + proof_path, + ); assert!(result.is_ok(), "Failed to generate proof and evaluations."); - let (proof, queried_evaluations) = result.unwrap(); + let (positions, queried_evaluations, proof) = result.unwrap(); // Verify the contents are written to file - let mut file_contents = Vec::new(); - let mut file = fs::File::open(proof_path).unwrap(); - file.read_to_end(&mut file_contents).unwrap(); + let deserialized_result = + read_and_deserialize_proof(positions_path, evaluations_path, proof_path); + assert!( + deserialized_result.is_ok(), + "Failed to deserialize proof and evaluations." + ); - // Serialize proof and queried evaluations - let mut proof_bytes = proof.to_bytes(); - let queried_evaluations_bytes = queried_evaluations.to_bytes(); - proof_bytes.extend(queried_evaluations_bytes); + let (deserialized_positions, deserialized_evaluations, deserialized_proof) = + deserialized_result.unwrap(); + assert_eq!(positions, deserialized_positions, "Positions do not match."); assert_eq!( - file_contents, proof_bytes, - "File contents do not match expected serialized output." + queried_evaluations, deserialized_evaluations, + "Queried evaluations do not match." + ); + assert_eq!( + proof.to_bytes(), + deserialized_proof.to_bytes(), + "Proof does not match." ); - - // Optionally, validate proof with external verification logic here, if available // Cleanup fs::remove_file(data_path).unwrap(); fs::remove_file(proof_path).unwrap(); + fs::remove_file(positions_path).unwrap(); + fs::remove_file(evaluations_path).unwrap(); } } diff --git a/src/commands/verify.rs b/src/commands/verify.rs index b6ad846..ae29a47 100644 --- a/src/commands/verify.rs +++ b/src/commands/verify.rs @@ -1 +1,114 @@ -pub fn run(commitment_path: &str, positions_path: &str, evaluations_path: &str, proof_path: &str) {} +use crate::{ + commands::open::read_and_deserialize_proof, + frida_error::FridaError, + frida_prover::Commitment, + frida_random::{FridaRandom, FridaRandomCoin}, + frida_verifier::das::FridaDasVerifier, +}; +use std::fs; +use winter_crypto::hashers::Blake3_256; +use winter_fri::FriOptions; +use winter_math::fields::f128::BaseElement; +use winter_utils::Deserializable; + +pub fn run( + commitment_path: &str, + positions_path: &str, + evaluations_path: &str, + proof_path: &str, + encoded_element_count: usize, + fri_options: FriOptions, +) -> Result<(), FridaError> { + // Read and deserialize + let commitment = + Commitment::>::read_from_bytes(&fs::read(commitment_path).unwrap()) + .unwrap(); + let (positions, evaluations, proof) = + read_and_deserialize_proof(positions_path, evaluations_path, proof_path).unwrap(); + + // Instantiate the verifier + let mut public_coin = + FridaRandom::, Blake3_256, BaseElement>::new(&[123]); + + let verifier = FridaDasVerifier::new( + commitment, + &mut public_coin, + fri_options.clone(), + encoded_element_count - 1, + ) + .unwrap(); + + // Verify the proof + verifier.verify(proof, &evaluations, &positions) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + commands::{commit, generate_data, open}, + frida_data::encoded_data_element_count, + frida_prover::{traits::BaseFriProver, FridaProver}, + frida_prover_channel::FridaProverChannel, + }; + use std::fs; + use winter_fri::FriOptions; + + use winter_crypto::hashers::Blake3_256; + use winter_math::fields::f128::BaseElement; + + type Blake3 = Blake3_256; + type FridaChannel = + FridaProverChannel>; + type FridaProverType = FridaProver; + + #[test] + fn test_verify() { + let data_path = "data/data.bin"; + let commitment_path = "data/commitment.bin"; + let positions_path = "data/positions.bin"; + let evaluations_path = "data/evaluations.bin"; + let proof_path = "data/proof.bin"; + + // Generate data + generate_data::run(200, data_path).unwrap(); + let encoded_element_count = + encoded_data_element_count::(fs::read(data_path).unwrap().len()) + .next_power_of_two(); + + // Initialize prover + let mut prover = FridaProverType::new(FriOptions::new(8, 2, 7)); + + // Commit the data + let num_queries = 31; + commit::run(&mut prover, num_queries, data_path, commitment_path).unwrap(); + + // Open the commitment + let (_, _, _) = open::run( + &mut prover, + &[1, 2, 3], + positions_path, + evaluations_path, + proof_path, + ) + .unwrap(); + + // Verify the proof + let result = run( + commitment_path, + positions_path, + evaluations_path, + proof_path, + encoded_element_count, + prover.options().clone(), + ); + assert!(result.is_ok(), "{:?}", result.err().unwrap()); + + // Clean up + fs::remove_file(data_path).expect("Failed to remove data file"); + fs::remove_file(commitment_path).expect("Failed to remove commitment file"); + fs::remove_file(positions_path).expect("Failed to remove positions file"); + fs::remove_file(evaluations_path).expect("Failed to remove evaluations file"); + fs::remove_file(proof_path).expect("Failed to remove proof file"); + } +} diff --git a/src/main.rs b/src/main.rs index fb267b3..b6f5952 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,12 @@ use clap::{Parser, Subcommand}; use frida_poc::commands; +use frida_poc::frida_data::encoded_data_element_count; use frida_poc::frida_prover::{traits::BaseFriProver, FridaProver}; use frida_poc::utils; +use std::fs; +use std::io::{self, Write}; use winter_crypto::hashers::Blake3_256; +use winter_fri::FriOptions; use winter_math::fields::f128::BaseElement; use frida_poc::{frida_prover_channel::FridaProverChannel, frida_random::FridaRandom}; @@ -20,10 +24,23 @@ struct Cli { command: Commands, } -#[derive(Subcommand)] +#[derive(Subcommand, Debug)] enum Commands { - /// Initialize settings - Init, + /// Initialize the prover and data + Init { + /// Data Path + #[arg(long, default_value = "data/data.bin")] + data_path: String, + /// Blowup factor + #[arg(long, default_value = "8")] + blowup_factor: usize, + /// Folding factor + #[arg(long, default_value = "2")] + folding_factor: usize, + /// Number of layers + #[arg(long, default_value = "7")] + max_remainder_degree: usize, + }, /// Generate random data GenerateData { /// Size of the data @@ -47,6 +64,12 @@ enum Commands { Open { /// Position to open positions: Vec, + /// Path to the positions file + #[arg(long, default_value = "data/positions.bin")] + positions_path: String, + /// Path to the evaluations file + #[arg(long, default_value = "data/evaluations.bin")] + evaluations_path: String, /// Path to the proof file #[arg(long, default_value = "data/proof.bin")] proof_path: String, @@ -69,41 +92,141 @@ enum Commands { } fn main() { - let cli = Cli::parse(); + // Initialize prover with default options let mut prover = FridaProverType::new(utils::load_fri_options(None)); + let mut encoded_element_count: usize = 0; + let mut init_done = false; - match &cli.command { - Commands::Init => { - let options = utils::load_fri_options(None); - prover = FridaProverType::new(options); - } - Commands::GenerateData { size, file_path } => { - commands::generate_data::run(*size, file_path).expect("Failed to generate data"); - } - Commands::Commit { - data_path, - commitment_path, - num_queries, - } => { - commands::commit::run(&mut prover, *num_queries, data_path, commitment_path) - .expect("Failed to commit data"); + loop { + print!("Enter command: "); + io::stdout().flush().unwrap(); + + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); + let input = input.trim(); + + // Allow user to exit the loop + if input.eq_ignore_ascii_case("exit") { + break; } - Commands::Open { - positions, - proof_path, - } => { - commands::open::run(&mut prover, proof_path, positions).expect("Failed to open proof"); + + // Split input into arguments and parse them + let args = match shlex::split(input) { + Some(mut args) => { + args.insert(0, "frida-poc".to_string()); + args + } + None => { + eprintln!("Failed to parse input."); + continue; + } + }; + + let cli = match Cli::try_parse_from(args) { + Ok(cli) => cli, + Err(err) => { + eprintln!("Error: {}", err); + continue; + } + }; + + match &cli.command { + Commands::Init { + data_path, + blowup_factor, + folding_factor, + max_remainder_degree, + } => { + println!( + "Initializing prover with data path: {}, blowup factor: {}, folding factor: {}, max remainder degree: {}", + data_path, blowup_factor, folding_factor, max_remainder_degree + ); + let options = + FriOptions::new(*blowup_factor, *folding_factor, *max_remainder_degree); + prover = FridaProverType::new(options); + if let Err(err) = fs::read(data_path) { + eprintln!( + "Failed to read data file: {}\nUse `generate-data ` command.", + err + ); + continue; + } + encoded_element_count = + encoded_data_element_count::(fs::read(data_path).unwrap().len()) + .next_power_of_two(); + init_done = true; + } + + Commands::GenerateData { size, file_path } => { + if let Err(err) = commands::generate_data::run(*size, file_path) { + eprintln!("Failed to generate data: {}", err); + } + } + + Commands::Commit { + num_queries, + data_path, + commitment_path, + } => { + if !init_done { + eprintln!("Please call the init command first."); + continue; + } + if let Err(err) = + commands::commit::run(&mut prover, *num_queries, data_path, commitment_path) + { + eprintln!("Failed to commit data: {}", err); + } + } + + Commands::Open { + positions, + positions_path, + evaluations_path, + proof_path, + } => { + if !init_done { + eprintln!("Please call the init command first."); + continue; + } + + if let Err(err) = commands::open::run( + &mut prover, + positions, + positions_path, + evaluations_path, + proof_path, + ) { + eprintln!("Failed to open proof: {}", err); + } + } + + Commands::Verify { + commitment_path, + positions_path, + evaluations_path, + proof_path, + } => { + if !init_done { + eprintln!("Please call the init command first."); + continue; + } + + if commands::verify::run( + commitment_path, + positions_path, + evaluations_path, + proof_path, + encoded_element_count, + prover.options().clone(), + ) + .is_err() + { + eprintln!("Verification failed"); + continue; + } + println!("Verification successful"); + } } - Commands::Verify { - commitment_path, - positions_path, - evaluations_path, - proof_path, - } => commands::verify::run( - commitment_path, - positions_path, - evaluations_path, - proof_path, - ), } } From 9df2757f3a67c66de98b368362b4b08bbd8d72e5 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Mon, 15 Jul 2024 16:39:43 +0900 Subject: [PATCH 13/23] refactor: Refactor CLI codes --- src/commands/commit.rs | 75 +++++------------- src/commands/generate_data.rs | 63 ++++++++++----- src/commands/open.rs | 109 ++++++++++---------------- src/commands/verify.rs | 23 +++--- src/frida_error.rs | 41 ++++++++++ src/main.rs | 140 ++++++++++++++++++++++++---------- src/utils/mod.rs | 16 ++++ 7 files changed, 275 insertions(+), 192 deletions(-) diff --git a/src/commands/commit.rs b/src/commands/commit.rs index 673e2f5..84cd988 100644 --- a/src/commands/commit.rs +++ b/src/commands/commit.rs @@ -2,13 +2,8 @@ use crate::{ frida_prover::{Commitment, FridaProver}, frida_prover_channel::FridaProverChannel, frida_random::FridaRandom, + utils::{read_file_to_vec, write_to_file}, }; -use std::fs; -use std::fs::File; -use std::io::BufReader; -use std::io::BufWriter; -use std::io::Read; -use std::io::Write; use winter_crypto::hashers::Blake3_256; use winter_math::fields::f128::BaseElement; use winter_utils::{Deserializable, Serializable}; @@ -25,64 +20,33 @@ pub fn run( data_path: &str, commitment_path: &str, ) -> Result, Box> { - // Create commitment from the data file - let commitment = create_commitment_from_file(prover, num_queries, data_path)?; - - // Write the commitment to the specified file - write_commitment_to_file(&commitment, commitment_path)?; + // Read data from file + let data = read_file_to_vec(data_path)?; + + // Create commitment from data + let (commitment, _) = + prover + .commit(data, num_queries) + .map_err(|e| -> Box { + format!("Prover commit error: {}", e).into() + })?; + + // Write commitment to file + let commitment_bytes = commitment.to_bytes(); + write_to_file(commitment_path, &commitment_bytes)?; - // Print success message with detail println!("Commitment created and saved to {}", commitment_path); - Ok(commitment) } -/// Creates a commitment from the data file. -fn create_commitment_from_file( - prover: &mut FridaProverType, - num_queries: usize, - data_path: &str, -) -> Result, Box> { - // Read data from the file - let data = fs::read(data_path)?; - - // Generate the commitment - let (commitment, _) = prover.commit(data, num_queries).unwrap(); - - Ok(commitment) -} - -/// Writes the commitment to a file. -fn write_commitment_to_file( - commitment: &Commitment, - file_path: &str, -) -> Result<(), Box> { - // Serialize the commitment - let commitment_bytes = commitment.to_bytes(); - - // Write to the file - let mut file = File::create(file_path)?; - let mut writer = BufWriter::new(&mut file); - writer.write_all(&commitment_bytes)?; - - Ok(()) -} - /// Reads the commitment from a file. pub fn read_commitment_from_file( file_path: &str, ) -> Result, Box> { - // Open the file and create a buffered reader - let file = File::open(file_path)?; - let mut reader = BufReader::new(file); - - // Read the commitment bytes - let mut commitment_bytes = Vec::new(); - reader.read_to_end(&mut commitment_bytes)?; - - // Deserialize the commitment - let commitment = Commitment::::read_from_bytes(&commitment_bytes).unwrap(); - + let commitment_bytes = read_file_to_vec(file_path)?; + let commitment = Commitment::::read_from_bytes(&commitment_bytes).map_err( + |e| -> Box { format!("Deserialization error: {}", e).into() }, + )?; Ok(commitment) } @@ -91,6 +55,7 @@ mod tests { use super::*; use crate::commands::generate_data; use crate::frida_prover::traits::BaseFriProver; + use std::fs; use winter_fri::FriOptions; #[test] diff --git a/src/commands/generate_data.rs b/src/commands/generate_data.rs index 26eb079..ed178a0 100644 --- a/src/commands/generate_data.rs +++ b/src/commands/generate_data.rs @@ -1,20 +1,19 @@ +use crate::utils::write_to_file; use std::fs; -use std::fs::File; -use std::io::Write; +use std::io; use winter_rand_utils::rand_vector; -pub fn run(size: usize, file_path: &str) -> Result, Box> { +pub fn run(size: usize, file_path: &str) -> Result, GenerateDataError> { // Generate random data let data = rand_vector::(size); // Ensure directory exists if let Some(parent) = std::path::Path::new(file_path).parent() { - fs::create_dir_all(parent).expect("Unable to create directories"); + fs::create_dir_all(parent).map_err(GenerateDataError::IoError)?; } // Write data to file - let mut file = File::create(file_path).expect("Unable to create file"); - file.write_all(&data).expect("Unable to write data"); + write_to_file(file_path, &data).map_err(GenerateDataError::IoError)?; // Print success message println!("Generated data of size {} and saved to {}", size, file_path); @@ -25,32 +24,56 @@ pub fn run(size: usize, file_path: &str) -> Result, Box Result<(), GenerateDataError> { let size = 200; - let file_path = "data/data.bin"; - - // Ensure directory exists - if let Some(parent) = std::path::Path::new(file_path).parent() { - fs::create_dir_all(parent).expect("Unable to create directories"); - } + let file_path = "data/test_data.bin"; // Generate data and write to file - let data = run(size, file_path).unwrap(); + let data = run(size, file_path)?; // Read data from file - let mut file = File::open(file_path).expect("Unable to open file"); - let mut file_data = Vec::new(); - file.read_to_end(&mut file_data) - .expect("Unable to read file"); + let file_data = read_file_to_vec(file_path).map_err(GenerateDataError::IoError)?; // Verify data assert_eq!(data, file_data); // Clean up - fs::remove_file(file_path).expect("Unable to delete file"); + fs::remove_file(file_path).map_err(GenerateDataError::IoError)?; + + Ok(()) + } +} + +#[derive(Debug)] +pub enum GenerateDataError { + IoError(io::Error), + CustomError(String), +} + +impl std::fmt::Display for GenerateDataError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + GenerateDataError::IoError(ref err) => write!(f, "IO error: {}", err), + GenerateDataError::CustomError(ref err) => write!(f, "Custom error: {}", err), + } + } +} + +impl std::error::Error for GenerateDataError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match *self { + GenerateDataError::IoError(ref err) => Some(err), + GenerateDataError::CustomError(_) => None, + } + } +} + +impl From for GenerateDataError { + fn from(err: io::Error) -> GenerateDataError { + GenerateDataError::IoError(err) } } diff --git a/src/commands/open.rs b/src/commands/open.rs index 10c4641..ae51c63 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -3,16 +3,12 @@ use crate::{ frida_prover::{proof::FridaProof, traits::BaseFriProver, FridaProver}, frida_prover_channel::FridaProverChannel, frida_random::FridaRandom, + utils::{read_file_to_vec, write_to_file}, }; -use std::fs; -use std::fs::File; -use std::io::BufWriter; -use std::io::Write; -use std::io::{BufReader, Read}; + use winter_crypto::hashers::Blake3_256; use winter_math::fields::f128::BaseElement; -use winter_utils::Deserializable; -use winter_utils::Serializable; +use winter_utils::{Deserializable, Serializable}; type Blake3 = Blake3_256; type FridaChannel = @@ -27,44 +23,28 @@ pub fn run( proof_path: &str, ) -> Result<(Vec, Vec, FridaProof), Box> { let options = prover.options().clone(); - // Read from files - let data = fs::read("data/data.bin").unwrap(); - // Calculate encoded element count + // Read data from file + let data = read_file_to_vec("data/data.bin")?; + let encoded_element_count = encoded_data_element_count::(data.len()).next_power_of_two(); - let open_position = positions; - let proof = prover.open(open_position); + // Create proof + let proof = prover.open(positions); let domain_size = (encoded_element_count - 1).next_power_of_two() * options.blowup_factor(); - let evaluations: Vec = - build_evaluations_from_data(&data, domain_size, options.blowup_factor()).unwrap(); - - let queried_evaluations = open_position - .iter() - .map(|&p| evaluations[p]) - .collect::>(); - - // Save to separate files - let proof_bytes = proof.to_bytes(); - let queried_evaluations_bytes = queried_evaluations.to_bytes(); - let positions_bytes = positions.to_bytes(); - - // Write positions to the file - let mut file = File::create(positions_path)?; - let mut writer = BufWriter::new(&mut file); - writer.write_all(&positions_bytes)?; - - // Write queried evaluations to the file - let mut file = File::create(evaluations_path)?; - let mut writer = BufWriter::new(&mut file); - writer.write_all(&queried_evaluations_bytes)?; - - // Write proof to the file - let mut file = File::create(proof_path)?; - let mut writer = BufWriter::new(&mut file); - writer.write_all(&proof_bytes)?; + let evaluations = build_evaluations_from_data(&data, domain_size, options.blowup_factor()) + .map_err(|e| -> Box { + format!("Failed to build evaluations: {}", e).into() + })?; + + let queried_evaluations: Vec = positions.iter().map(|&p| evaluations[p]).collect(); + + // Write positions, evaluations, and proof to files + write_to_file(positions_path, &positions.to_bytes())?; + write_to_file(evaluations_path, &queried_evaluations.to_bytes())?; + write_to_file(proof_path, &proof.to_bytes())?; Ok((positions.to_vec(), queried_evaluations, proof)) } @@ -74,30 +54,29 @@ pub fn read_and_deserialize_proof( evaluations_path: &str, proof_path: &str, ) -> Result<(Vec, Vec, FridaProof), Box> { - // Read positions - let mut file = File::open(positions_path)?; - let mut reader = BufReader::new(&mut file); - let mut positions_bytes = Vec::new(); - reader.read_to_end(&mut positions_bytes)?; - let positions = Vec::::read_from_bytes(&positions_bytes).unwrap(); - - // Read queried evaluations - let mut file = File::open(evaluations_path)?; - let mut reader = BufReader::new(&mut file); - let mut queried_evaluations_bytes = Vec::new(); - reader.read_to_end(&mut queried_evaluations_bytes)?; - let queried_evaluations = - Vec::::read_from_bytes(&queried_evaluations_bytes).unwrap(); - - // Read proof - let mut file = File::open(proof_path)?; - let mut reader = BufReader::new(&mut file); - let mut proof_bytes = Vec::new(); - reader.read_to_end(&mut proof_bytes)?; - let proof = FridaProof::read_from_bytes(&proof_bytes).unwrap(); + // Read and deserialize positions + let positions_bytes = read_file_to_vec(positions_path)?; + let positions = Vec::::read_from_bytes(&positions_bytes).map_err( + |e| -> Box { format!("Deserialization error: {}", e).into() }, + )?; + + // Read and deserialize evaluations + let queried_evaluations_bytes = read_file_to_vec(evaluations_path)?; + let queried_evaluations = Vec::::read_from_bytes(&queried_evaluations_bytes) + .map_err(|e| -> Box { + format!("Deserialization error: {}", e).into() + })?; + + // Read and deserialize proof + let proof_bytes = read_file_to_vec(proof_path)?; + let proof = + FridaProof::read_from_bytes(&proof_bytes).map_err(|e| -> Box { + format!("Deserialization error: {}", e).into() + })?; Ok((positions, queried_evaluations, proof)) } + #[cfg(test)] mod tests { use super::*; @@ -107,29 +86,23 @@ mod tests { #[test] fn test_open() { - // Paths let data_path = "data/data.bin"; let positions_path = "data/positions.bin"; let evaluations_path = "data/evaluations.bin"; let proof_path = "data/proof.bin"; - // Prepare data if !std::path::Path::new(data_path).exists() { generate_data::run(200, data_path).unwrap(); } + let data = fs::read(data_path).unwrap(); let num_queries = 31; - // Initialize prover let mut prover = FridaProverType::new(FriOptions::new(8, 2, 7)); - - // Generate the commitment prover.commit(data, num_queries).unwrap(); - // Specify positions to open let positions = vec![0, 5, 10]; - // Run the opening process let result = run( &mut prover, &positions, @@ -141,7 +114,6 @@ mod tests { let (positions, queried_evaluations, proof) = result.unwrap(); - // Verify the contents are written to file let deserialized_result = read_and_deserialize_proof(positions_path, evaluations_path, proof_path); assert!( @@ -163,7 +135,6 @@ mod tests { "Proof does not match." ); - // Cleanup fs::remove_file(data_path).unwrap(); fs::remove_file(proof_path).unwrap(); fs::remove_file(positions_path).unwrap(); diff --git a/src/commands/verify.rs b/src/commands/verify.rs index ae29a47..0a38561 100644 --- a/src/commands/verify.rs +++ b/src/commands/verify.rs @@ -1,10 +1,10 @@ use crate::{ commands::open::read_and_deserialize_proof, - frida_error::FridaError, frida_prover::Commitment, frida_random::{FridaRandom, FridaRandomCoin}, frida_verifier::das::FridaDasVerifier, }; +use std::error::Error; use std::fs; use winter_crypto::hashers::Blake3_256; use winter_fri::FriOptions; @@ -18,13 +18,14 @@ pub fn run( proof_path: &str, encoded_element_count: usize, fri_options: FriOptions, -) -> Result<(), FridaError> { +) -> Result<(), Box> { // Read and deserialize - let commitment = - Commitment::>::read_from_bytes(&fs::read(commitment_path).unwrap()) - .unwrap(); + let commitment_bytes = fs::read(commitment_path)?; + let commitment = Commitment::>::read_from_bytes(&commitment_bytes) + .map_err(|e| format!("Deserialization error: {}", e))?; + let (positions, evaluations, proof) = - read_and_deserialize_proof(positions_path, evaluations_path, proof_path).unwrap(); + read_and_deserialize_proof(positions_path, evaluations_path, proof_path)?; // Instantiate the verifier let mut public_coin = @@ -36,10 +37,14 @@ pub fn run( fri_options.clone(), encoded_element_count - 1, ) - .unwrap(); + .map_err(|e| format!("Verifier initialization error: {}", e))?; // Verify the proof - verifier.verify(proof, &evaluations, &positions) + verifier + .verify(proof, &evaluations, &positions) + .map_err(|e| format!("Verification error: {}", e))?; + + Ok(()) } #[cfg(test)] @@ -84,7 +89,7 @@ mod tests { commit::run(&mut prover, num_queries, data_path, commitment_path).unwrap(); // Open the commitment - let (_, _, _) = open::run( + open::run( &mut prover, &[1, 2, 3], positions_path, diff --git a/src/frida_error.rs b/src/frida_error.rs index 5276339..c8a49d2 100644 --- a/src/frida_error.rs +++ b/src/frida_error.rs @@ -1,3 +1,5 @@ +use std::fmt; + #[derive(Debug, Clone, PartialEq, Eq)] pub enum FridaError { DeserializationError(), @@ -16,3 +18,42 @@ pub enum FridaError { DegreeTruncation(usize, usize, usize), UnsupportedFoldingFactor(usize), } + +impl fmt::Display for FridaError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + FridaError::DeserializationError() => write!(f, "Deserialization error occurred"), + FridaError::XYCoordinateLengthMismatch() => write!(f, "XY coordinate length mismatch"), + FridaError::NotEnoughDataPoints() => write!(f, "Not enough data points"), + FridaError::BadDataLength() => write!(f, "Bad data length"), + FridaError::NotEnoughEvaluationsForDecoding() => { + write!(f, "Not enough evaluations for decoding") + } + FridaError::DrawError() => write!(f, "Draw error"), + FridaError::FailedToDrawEnoughQueryPoints(required, drawn) => write!( + f, + "Failed to draw enough query points: required {}, drawn {}", + required, drawn + ), + FridaError::FailedToDrawEnoughXi(required, drawn) => write!( + f, + "Failed to draw enough Xi: required {}, drawn {}", + required, drawn + ), + FridaError::DomainSizeTooBig(size) => write!(f, "Domain size too big: {}", size), + FridaError::BadNumQueries(num) => write!(f, "Bad number of queries: {}", num), + FridaError::InvalidDASCommitment => write!(f, "Invalid DAS commitment"), + FridaError::FailToVerify => write!(f, "Failed to verify"), + FridaError::DegreeTruncation(layer, degree, factor) => write!( + f, + "Degree truncation error at layer {}: degree {}, factor {}", + layer, degree, factor + ), + FridaError::UnsupportedFoldingFactor(factor) => { + write!(f, "Unsupported folding factor: {}", factor) + } + } + } +} + +impl std::error::Error for FridaError {} diff --git a/src/main.rs b/src/main.rs index b6f5952..4cab841 100644 --- a/src/main.rs +++ b/src/main.rs @@ -137,30 +137,19 @@ fn main() { folding_factor, max_remainder_degree, } => { - println!( - "Initializing prover with data path: {}, blowup factor: {}, folding factor: {}, max remainder degree: {}", - data_path, blowup_factor, folding_factor, max_remainder_degree + handle_init( + &mut prover, + data_path, + *blowup_factor, + *folding_factor, + *max_remainder_degree, + &mut encoded_element_count, + &mut init_done, ); - let options = - FriOptions::new(*blowup_factor, *folding_factor, *max_remainder_degree); - prover = FridaProverType::new(options); - if let Err(err) = fs::read(data_path) { - eprintln!( - "Failed to read data file: {}\nUse `generate-data ` command.", - err - ); - continue; - } - encoded_element_count = - encoded_data_element_count::(fs::read(data_path).unwrap().len()) - .next_power_of_two(); - init_done = true; } Commands::GenerateData { size, file_path } => { - if let Err(err) = commands::generate_data::run(*size, file_path) { - eprintln!("Failed to generate data: {}", err); - } + handle_generate_data(*size, file_path); } Commands::Commit { @@ -172,11 +161,7 @@ fn main() { eprintln!("Please call the init command first."); continue; } - if let Err(err) = - commands::commit::run(&mut prover, *num_queries, data_path, commitment_path) - { - eprintln!("Failed to commit data: {}", err); - } + handle_commit(&mut prover, *num_queries, data_path, commitment_path); } Commands::Open { @@ -189,16 +174,13 @@ fn main() { eprintln!("Please call the init command first."); continue; } - - if let Err(err) = commands::open::run( + handle_open( &mut prover, positions, positions_path, evaluations_path, proof_path, - ) { - eprintln!("Failed to open proof: {}", err); - } + ); } Commands::Verify { @@ -211,22 +193,102 @@ fn main() { eprintln!("Please call the init command first."); continue; } - - if commands::verify::run( + handle_verify( commitment_path, positions_path, evaluations_path, proof_path, encoded_element_count, prover.options().clone(), - ) - .is_err() - { - eprintln!("Verification failed"); - continue; - } - println!("Verification successful"); + ); } } } } + +fn handle_init( + prover: &mut FridaProverType, + data_path: &str, + blowup_factor: usize, + folding_factor: usize, + max_remainder_degree: usize, + encoded_element_count: &mut usize, + init_done: &mut bool, +) { + println!( + "Initializing prover with data path: {}, blowup factor: {}, folding factor: {}, max remainder degree: {}", + data_path, blowup_factor, folding_factor, max_remainder_degree + ); + let options = FriOptions::new(blowup_factor, folding_factor, max_remainder_degree); + *prover = FridaProverType::new(options); + if let Err(err) = fs::read(data_path) { + eprintln!( + "Failed to read data file: {}\nUse `generate-data ` command.", + err + ); + return; + } + *encoded_element_count = + encoded_data_element_count::(fs::read(data_path).unwrap().len()) + .next_power_of_two(); + *init_done = true; +} + +fn handle_generate_data(size: usize, file_path: &str) { + if let Err(err) = commands::generate_data::run(size, file_path) { + eprintln!("Failed to generate data: {}", err); + } +} + +fn handle_commit( + prover: &mut FridaProverType, + num_queries: usize, + data_path: &str, + commitment_path: &str, +) { + if let Err(err) = commands::commit::run(prover, num_queries, data_path, commitment_path) { + eprintln!("Failed to commit data: {}", err); + } +} + +fn handle_open( + prover: &mut FridaProverType, + positions: &[usize], + positions_path: &str, + evaluations_path: &str, + proof_path: &str, +) { + if let Err(err) = commands::open::run( + prover, + positions, + positions_path, + evaluations_path, + proof_path, + ) { + eprintln!("Failed to open proof: {}", err); + } +} + +fn handle_verify( + commitment_path: &str, + positions_path: &str, + evaluations_path: &str, + proof_path: &str, + encoded_element_count: usize, + options: FriOptions, +) { + if commands::verify::run( + commitment_path, + positions_path, + evaluations_path, + proof_path, + encoded_element_count, + options, + ) + .is_err() + { + eprintln!("Verification failed"); + return; + } + println!("Verification successful"); +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 955f714..1e7439f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,5 +1,7 @@ use serde::Deserialize; use std::fs; +use std::fs::File; +use std::io::{self, BufWriter, Read, Write}; use winter_crypto::hashers::Blake3_256; use winter_fri::FriOptions; @@ -56,3 +58,17 @@ pub fn load_fri_options(file_path: Option<&String>) -> FriOptions { FriOptions::new(8, 2, 7) } } + +pub fn read_file_to_vec(file_path: &str) -> Result, io::Error> { + let mut file = File::open(file_path)?; + let mut data = Vec::new(); + file.read_to_end(&mut data)?; + Ok(data) +} + +pub fn write_to_file(file_path: &str, data: &[u8]) -> Result<(), io::Error> { + let mut file = File::create(file_path)?; + let mut writer = BufWriter::new(&mut file); + writer.write_all(data)?; + Ok(()) +} From 56a3f5c3624f7ffef6cf068adec54815f3ef7992 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Mon, 15 Jul 2024 18:19:31 +0900 Subject: [PATCH 14/23] fix: Fix errors caused by change in commitment struct --- src/commands/verify.rs | 17 +++-------------- src/frida_prover/mod.rs | 7 +++++-- src/main.rs | 9 --------- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/src/commands/verify.rs b/src/commands/verify.rs index 0a38561..8a25314 100644 --- a/src/commands/verify.rs +++ b/src/commands/verify.rs @@ -2,7 +2,7 @@ use crate::{ commands::open::read_and_deserialize_proof, frida_prover::Commitment, frida_random::{FridaRandom, FridaRandomCoin}, - frida_verifier::das::FridaDasVerifier, + frida_verifier::{das::FridaDasVerifier, traits::BaseFridaVerifier}, }; use std::error::Error; use std::fs; @@ -16,7 +16,6 @@ pub fn run( positions_path: &str, evaluations_path: &str, proof_path: &str, - encoded_element_count: usize, fri_options: FriOptions, ) -> Result<(), Box> { // Read and deserialize @@ -31,13 +30,8 @@ pub fn run( let mut public_coin = FridaRandom::, Blake3_256, BaseElement>::new(&[123]); - let verifier = FridaDasVerifier::new( - commitment, - &mut public_coin, - fri_options.clone(), - encoded_element_count - 1, - ) - .map_err(|e| format!("Verifier initialization error: {}", e))?; + let verifier = FridaDasVerifier::new(commitment, &mut public_coin, fri_options.clone()) + .map_err(|e| format!("Verifier initialization error: {}", e))?; // Verify the proof verifier @@ -52,7 +46,6 @@ mod tests { use super::*; use crate::{ commands::{commit, generate_data, open}, - frida_data::encoded_data_element_count, frida_prover::{traits::BaseFriProver, FridaProver}, frida_prover_channel::FridaProverChannel, }; @@ -77,9 +70,6 @@ mod tests { // Generate data generate_data::run(200, data_path).unwrap(); - let encoded_element_count = - encoded_data_element_count::(fs::read(data_path).unwrap().len()) - .next_power_of_two(); // Initialize prover let mut prover = FridaProverType::new(FriOptions::new(8, 2, 7)); @@ -104,7 +94,6 @@ mod tests { positions_path, evaluations_path, proof_path, - encoded_element_count, prover.options().clone(), ); assert!(result.is_ok(), "{:?}", result.err().unwrap()); diff --git a/src/frida_prover/mod.rs b/src/frida_prover/mod.rs index 02fbfc3..8254b57 100644 --- a/src/frida_prover/mod.rs +++ b/src/frida_prover/mod.rs @@ -71,13 +71,14 @@ where fn write_into(&self, target: &mut W) { self.roots.write_into(target); self.proof.write_into(target); + self.domain_size.write_into(target); self.num_queries.write_into(target); self.batch_size.write_into(target); } fn get_size_hint(&self) -> usize { - // 24 + 104 + 8 + 8 - 136 + // 24 + 104 + 8 + 8 + 8 + 152 } } @@ -88,12 +89,14 @@ where fn read_from(source: &mut R) -> Result { let roots = Vec::::read_from(source)?; let proof = FridaProof::read_from(source)?; + let domain_size = usize::read_from(source)?; let num_queries = usize::read_from(source)?; let batch_size = usize::read_from(source)?; Ok(Commitment { roots, proof, + domain_size, num_queries, batch_size, }) diff --git a/src/main.rs b/src/main.rs index 4cab841..7f858ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -94,7 +94,6 @@ enum Commands { fn main() { // Initialize prover with default options let mut prover = FridaProverType::new(utils::load_fri_options(None)); - let mut encoded_element_count: usize = 0; let mut init_done = false; loop { @@ -143,7 +142,6 @@ fn main() { *blowup_factor, *folding_factor, *max_remainder_degree, - &mut encoded_element_count, &mut init_done, ); } @@ -198,7 +196,6 @@ fn main() { positions_path, evaluations_path, proof_path, - encoded_element_count, prover.options().clone(), ); } @@ -212,7 +209,6 @@ fn handle_init( blowup_factor: usize, folding_factor: usize, max_remainder_degree: usize, - encoded_element_count: &mut usize, init_done: &mut bool, ) { println!( @@ -228,9 +224,6 @@ fn handle_init( ); return; } - *encoded_element_count = - encoded_data_element_count::(fs::read(data_path).unwrap().len()) - .next_power_of_two(); *init_done = true; } @@ -274,7 +267,6 @@ fn handle_verify( positions_path: &str, evaluations_path: &str, proof_path: &str, - encoded_element_count: usize, options: FriOptions, ) { if commands::verify::run( @@ -282,7 +274,6 @@ fn handle_verify( positions_path, evaluations_path, proof_path, - encoded_element_count, options, ) .is_err() From 83e22d42c0fc4bbd58bdcc804d085a0b55c7e2ad Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Wed, 17 Jul 2024 14:43:21 +0900 Subject: [PATCH 15/23] refactor: Refactor handle_* functions --- src/main.rs | 280 +++++++++++++++++++++++----------------------------- 1 file changed, 122 insertions(+), 158 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7f858ca..07addbe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,6 @@ use clap::{Parser, Subcommand}; use frida_poc::commands; -use frida_poc::frida_data::encoded_data_element_count; use frida_poc::frida_prover::{traits::BaseFriProver, FridaProver}; -use frida_poc::utils; use std::fs; use std::io::{self, Write}; use winter_crypto::hashers::Blake3_256; @@ -47,7 +45,7 @@ enum Commands { size: usize, /// Path to the data file #[arg(long, default_value = "data/data.bin")] - file_path: String, + data_path: String, }, /// Commit data and generate a proof Commit { @@ -92,194 +90,160 @@ enum Commands { } fn main() { - // Initialize prover with default options - let mut prover = FridaProverType::new(utils::load_fri_options(None)); - let mut init_done = false; + let mut prover: Option = None; loop { - print!("Enter command: "); - io::stdout().flush().unwrap(); - - let mut input = String::new(); - io::stdin().read_line(&mut input).unwrap(); - let input = input.trim(); - - // Allow user to exit the loop - if input.eq_ignore_ascii_case("exit") { - break; - } - - // Split input into arguments and parse them - let args = match shlex::split(input) { - Some(mut args) => { - args.insert(0, "frida-poc".to_string()); - args - } - None => { - eprintln!("Failed to parse input."); - continue; - } - }; - - let cli = match Cli::try_parse_from(args) { - Ok(cli) => cli, + match read_and_parse_command() { + Ok(cli) => match cli.command { + Commands::Init { .. } => { + prover = handle_init(cli.command); + } + Commands::GenerateData { .. } => { + handle_generate_data(cli.command); + } + Commands::Commit { .. } => { + handle_commit(cli.command, &mut prover); + } + Commands::Open { .. } => { + handle_open(cli.command, &mut prover); + } + Commands::Verify { .. } => { + handle_verify(cli.command, &mut prover); + } + }, Err(err) => { eprintln!("Error: {}", err); - continue; - } - }; - - match &cli.command { - Commands::Init { - data_path, - blowup_factor, - folding_factor, - max_remainder_degree, - } => { - handle_init( - &mut prover, - data_path, - *blowup_factor, - *folding_factor, - *max_remainder_degree, - &mut init_done, - ); } + } + } +} - Commands::GenerateData { size, file_path } => { - handle_generate_data(*size, file_path); - } +fn read_and_parse_command() -> Result { + print!("Enter command: "); + io::stdout().flush().unwrap(); - Commands::Commit { - num_queries, - data_path, - commitment_path, - } => { - if !init_done { - eprintln!("Please call the init command first."); - continue; - } - handle_commit(&mut prover, *num_queries, data_path, commitment_path); - } + let mut input = String::new(); + io::stdin() + .read_line(&mut input) + .map_err(|_| "Failed to read input.".to_string())?; + let input = input.trim(); - Commands::Open { - positions, - positions_path, - evaluations_path, - proof_path, - } => { - if !init_done { - eprintln!("Please call the init command first."); - continue; - } - handle_open( - &mut prover, - positions, - positions_path, - evaluations_path, - proof_path, - ); - } + if input.eq_ignore_ascii_case("exit") { + std::process::exit(0); + } - Commands::Verify { - commitment_path, - positions_path, - evaluations_path, - proof_path, - } => { - if !init_done { - eprintln!("Please call the init command first."); - continue; - } - handle_verify( - commitment_path, - positions_path, - evaluations_path, - proof_path, - prover.options().clone(), - ); - } + let args = match shlex::split(input) { + Some(mut args) => { + args.insert(0, "frida-poc".to_string()); + args } - } + None => return Err("Failed to parse input.".to_string()), + }; + + Cli::try_parse_from(args).map_err(|err| err.to_string()) } -fn handle_init( - prover: &mut FridaProverType, - data_path: &str, - blowup_factor: usize, - folding_factor: usize, - max_remainder_degree: usize, - init_done: &mut bool, -) { - println!( - "Initializing prover with data path: {}, blowup factor: {}, folding factor: {}, max remainder degree: {}", - data_path, blowup_factor, folding_factor, max_remainder_degree - ); - let options = FriOptions::new(blowup_factor, folding_factor, max_remainder_degree); - *prover = FridaProverType::new(options); - if let Err(err) = fs::read(data_path) { - eprintln!( - "Failed to read data file: {}\nUse `generate-data ` command.", - err +fn handle_init(cmd: Commands) -> Option { + if let Commands::Init { + data_path, + blowup_factor, + folding_factor, + max_remainder_degree, + } = cmd + { + println!( + "Initializing prover with data path: {}, blowup factor: {}, folding factor: {}, max remainder degree: {}", + data_path, blowup_factor, folding_factor, max_remainder_degree ); - return; + let options = FriOptions::new(blowup_factor, folding_factor, max_remainder_degree); + if let Err(err) = fs::read(&data_path) { + eprintln!( + "Failed to read data file: {}\nUse `generate-data ` command.", + err + ); + return None; + } + Some(FridaProverType::new(options)) + } else { + None } - *init_done = true; } -fn handle_generate_data(size: usize, file_path: &str) { - if let Err(err) = commands::generate_data::run(size, file_path) { - eprintln!("Failed to generate data: {}", err); +fn handle_generate_data(cmd: Commands) { + if let Commands::GenerateData { size, data_path } = cmd { + if let Err(err) = commands::generate_data::run(size, &data_path) { + eprintln!("Failed to generate data: {}", err); + } } } -fn handle_commit( - prover: &mut FridaProverType, - num_queries: usize, - data_path: &str, - commitment_path: &str, -) { - if let Err(err) = commands::commit::run(prover, num_queries, data_path, commitment_path) { - eprintln!("Failed to commit data: {}", err); +fn handle_commit(cmd: Commands, prover: &mut Option) { + let prover = match_prover(prover); + + if let Commands::Commit { + num_queries, + data_path, + commitment_path, + } = cmd + { + if let Err(err) = commands::commit::run(prover, num_queries, &data_path, &commitment_path) { + eprintln!("Failed to commit data: {}", err); + } } } -fn handle_open( - prover: &mut FridaProverType, - positions: &[usize], - positions_path: &str, - evaluations_path: &str, - proof_path: &str, -) { - if let Err(err) = commands::open::run( - prover, +fn handle_open(cmd: Commands, prover: &mut Option) { + let prover = match_prover(prover); + + if let Commands::Open { positions, positions_path, evaluations_path, proof_path, - ) { - eprintln!("Failed to open proof: {}", err); + } = cmd + { + if let Err(err) = commands::open::run( + prover, + &positions, + &positions_path, + &evaluations_path, + &proof_path, + ) { + eprintln!("Failed to open proof: {}", err); + } } } -fn handle_verify( - commitment_path: &str, - positions_path: &str, - evaluations_path: &str, - proof_path: &str, - options: FriOptions, -) { - if commands::verify::run( +fn handle_verify(cmd: Commands, prover: &mut Option) { + let prover = match_prover(prover); + + if let Commands::Verify { commitment_path, positions_path, evaluations_path, proof_path, - options, - ) - .is_err() + } = cmd { - eprintln!("Verification failed"); - return; + if let Err(err) = commands::verify::run( + &commitment_path, + &positions_path, + &evaluations_path, + &proof_path, + prover.options().clone(), + ) { + eprintln!("Failed to verify proof: {}", err); + return; + } + println!("Verification successful"); + } +} + +fn match_prover(prover: &mut Option) -> &mut FridaProverType { + match prover.as_mut() { + Some(prover) => prover, + None => { + eprintln!("Please call the init command first."); + std::process::exit(1); + } } - println!("Verification successful"); } From 820e93a4a6fa9a4c908318b8b7ccfefad64a91c4 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Thu, 18 Jul 2024 00:45:55 +0900 Subject: [PATCH 16/23] refactor: Add CleanupFiles struct and use Path types --- src/commands/commit.rs | 27 +++++++++++------------ src/commands/generate_data.rs | 21 +++++++++--------- src/commands/open.rs | 38 +++++++++++++++++--------------- src/commands/verify.rs | 41 +++++++++++++++++------------------ src/main.rs | 41 ++++++++++++++++++++--------------- src/utils/mod.rs | 35 +++++++++++++++++++++++++----- 6 files changed, 116 insertions(+), 87 deletions(-) diff --git a/src/commands/commit.rs b/src/commands/commit.rs index 84cd988..2f2053a 100644 --- a/src/commands/commit.rs +++ b/src/commands/commit.rs @@ -4,6 +4,7 @@ use crate::{ frida_random::FridaRandom, utils::{read_file_to_vec, write_to_file}, }; +use std::path::Path; use winter_crypto::hashers::Blake3_256; use winter_math::fields::f128::BaseElement; use winter_utils::{Deserializable, Serializable}; @@ -17,8 +18,8 @@ type FridaProverType = FridaProver Result, Box> { // Read data from file let data = read_file_to_vec(data_path)?; @@ -35,13 +36,13 @@ pub fn run( let commitment_bytes = commitment.to_bytes(); write_to_file(commitment_path, &commitment_bytes)?; - println!("Commitment created and saved to {}", commitment_path); + println!("Commitment created and saved to {:?}", commitment_path); Ok(commitment) } /// Reads the commitment from a file. pub fn read_commitment_from_file( - file_path: &str, + file_path: &Path, ) -> Result, Box> { let commitment_bytes = read_file_to_vec(file_path)?; let commitment = Commitment::::read_from_bytes(&commitment_bytes).map_err( @@ -53,17 +54,19 @@ pub fn read_commitment_from_file( #[cfg(test)] mod tests { use super::*; - use crate::commands::generate_data; - use crate::frida_prover::traits::BaseFriProver; - use std::fs; + use crate::{ + commands::generate_data, frida_prover::traits::BaseFriProver, utils::CleanupFiles, + }; use winter_fri::FriOptions; #[test] fn test_commit() { - let data_path = "data/data.bin"; - let commitment_path = "data/commitment.bin"; + let data_path = Path::new("data/data.bin"); + let commitment_path = Path::new("data/commitment.bin"); - if !std::path::Path::new(data_path).exists() { + let _cleanup = CleanupFiles::new(vec![data_path, commitment_path]); + + if !data_path.exists() { generate_data::run(200, data_path).unwrap(); } @@ -77,9 +80,5 @@ mod tests { // Verify the commitment assert_eq!(commitment, commitment_file, "Commitment does not match."); - - // Cleanup - fs::remove_file(data_path).unwrap(); - fs::remove_file(commitment_path).unwrap(); } } diff --git a/src/commands/generate_data.rs b/src/commands/generate_data.rs index ed178a0..575c250 100644 --- a/src/commands/generate_data.rs +++ b/src/commands/generate_data.rs @@ -1,9 +1,8 @@ use crate::utils::write_to_file; -use std::fs; -use std::io; +use std::{fs, io, path::Path}; use winter_rand_utils::rand_vector; -pub fn run(size: usize, file_path: &str) -> Result, GenerateDataError> { +pub fn run(size: usize, file_path: &Path) -> Result, GenerateDataError> { // Generate random data let data = rand_vector::(size); @@ -16,7 +15,11 @@ pub fn run(size: usize, file_path: &str) -> Result, GenerateDataError> { write_to_file(file_path, &data).map_err(GenerateDataError::IoError)?; // Print success message - println!("Generated data of size {} and saved to {}", size, file_path); + println!( + "Generated data of size {} and saved to {}", + size, + file_path.display() + ); Ok(data) } @@ -24,13 +27,14 @@ pub fn run(size: usize, file_path: &str) -> Result, GenerateDataError> { #[cfg(test)] mod tests { use super::*; - use crate::utils::read_file_to_vec; - use std::fs; + use crate::utils::{read_file_to_vec, CleanupFiles}; #[test] fn test_generate_data() -> Result<(), GenerateDataError> { let size = 200; - let file_path = "data/test_data.bin"; + let file_path = Path::new("data/data.bin"); + + let _cleanup = CleanupFiles::new(vec![file_path]); // Generate data and write to file let data = run(size, file_path)?; @@ -41,9 +45,6 @@ mod tests { // Verify data assert_eq!(data, file_data); - // Clean up - fs::remove_file(file_path).map_err(GenerateDataError::IoError)?; - Ok(()) } } diff --git a/src/commands/open.rs b/src/commands/open.rs index ae51c63..0bb94ba 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -5,7 +5,7 @@ use crate::{ frida_random::FridaRandom, utils::{read_file_to_vec, write_to_file}, }; - +use std::path::Path; use winter_crypto::hashers::Blake3_256; use winter_math::fields::f128::BaseElement; use winter_utils::{Deserializable, Serializable}; @@ -18,14 +18,14 @@ type FridaProverType = FridaProver Result<(Vec, Vec, FridaProof), Box> { let options = prover.options().clone(); // Read data from file - let data = read_file_to_vec("data/data.bin")?; + let data = read_file_to_vec(Path::new("data/data.bin"))?; let encoded_element_count = encoded_data_element_count::(data.len()).next_power_of_two(); @@ -50,9 +50,9 @@ pub fn run( } pub fn read_and_deserialize_proof( - positions_path: &str, - evaluations_path: &str, - proof_path: &str, + positions_path: &Path, + evaluations_path: &Path, + proof_path: &Path, ) -> Result<(Vec, Vec, FridaProof), Box> { // Read and deserialize positions let positions_bytes = read_file_to_vec(positions_path)?; @@ -80,16 +80,23 @@ pub fn read_and_deserialize_proof( #[cfg(test)] mod tests { use super::*; - use crate::commands::generate_data; + use crate::{commands::generate_data, utils::CleanupFiles}; use std::fs; use winter_fri::FriOptions; #[test] fn test_open() { - let data_path = "data/data.bin"; - let positions_path = "data/positions.bin"; - let evaluations_path = "data/evaluations.bin"; - let proof_path = "data/proof.bin"; + let data_path = Path::new("data/data.bin"); + let positions_path = Path::new("data/positions.bin"); + let evaluations_path = Path::new("data/evaluations.bin"); + let proof_path = Path::new("data/proof.bin"); + + let _cleanup = CleanupFiles::new(vec![ + data_path, + positions_path, + evaluations_path, + proof_path, + ]); if !std::path::Path::new(data_path).exists() { generate_data::run(200, data_path).unwrap(); @@ -134,10 +141,5 @@ mod tests { deserialized_proof.to_bytes(), "Proof does not match." ); - - fs::remove_file(data_path).unwrap(); - fs::remove_file(proof_path).unwrap(); - fs::remove_file(positions_path).unwrap(); - fs::remove_file(evaluations_path).unwrap(); } } diff --git a/src/commands/verify.rs b/src/commands/verify.rs index 8a25314..c085a1f 100644 --- a/src/commands/verify.rs +++ b/src/commands/verify.rs @@ -4,18 +4,17 @@ use crate::{ frida_random::{FridaRandom, FridaRandomCoin}, frida_verifier::{das::FridaDasVerifier, traits::BaseFridaVerifier}, }; -use std::error::Error; -use std::fs; +use std::{error::Error, fs, path::Path}; use winter_crypto::hashers::Blake3_256; use winter_fri::FriOptions; use winter_math::fields::f128::BaseElement; use winter_utils::Deserializable; pub fn run( - commitment_path: &str, - positions_path: &str, - evaluations_path: &str, - proof_path: &str, + commitment_path: &Path, + positions_path: &Path, + evaluations_path: &Path, + proof_path: &Path, fri_options: FriOptions, ) -> Result<(), Box> { // Read and deserialize @@ -48,11 +47,10 @@ mod tests { commands::{commit, generate_data, open}, frida_prover::{traits::BaseFriProver, FridaProver}, frida_prover_channel::FridaProverChannel, + utils::CleanupFiles, }; - use std::fs; - use winter_fri::FriOptions; - use winter_crypto::hashers::Blake3_256; + use winter_fri::FriOptions; use winter_math::fields::f128::BaseElement; type Blake3 = Blake3_256; @@ -62,11 +60,19 @@ mod tests { #[test] fn test_verify() { - let data_path = "data/data.bin"; - let commitment_path = "data/commitment.bin"; - let positions_path = "data/positions.bin"; - let evaluations_path = "data/evaluations.bin"; - let proof_path = "data/proof.bin"; + let data_path = Path::new("data/data.bin"); + let commitment_path = Path::new("data/commitment.bin"); + let positions_path = Path::new("data/positions.bin"); + let evaluations_path = Path::new("data/evaluations.bin"); + let proof_path = Path::new("data/proof.bin"); + + let _cleanup = CleanupFiles::new(vec![ + data_path, + commitment_path, + positions_path, + evaluations_path, + proof_path, + ]); // Generate data generate_data::run(200, data_path).unwrap(); @@ -97,12 +103,5 @@ mod tests { prover.options().clone(), ); assert!(result.is_ok(), "{:?}", result.err().unwrap()); - - // Clean up - fs::remove_file(data_path).expect("Failed to remove data file"); - fs::remove_file(commitment_path).expect("Failed to remove commitment file"); - fs::remove_file(positions_path).expect("Failed to remove positions file"); - fs::remove_file(evaluations_path).expect("Failed to remove evaluations file"); - fs::remove_file(proof_path).expect("Failed to remove proof file"); } } diff --git a/src/main.rs b/src/main.rs index 07addbe..a88ed0d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,19 @@ use clap::{Parser, Subcommand}; -use frida_poc::commands; -use frida_poc::frida_prover::{traits::BaseFriProver, FridaProver}; -use std::fs; -use std::io::{self, Write}; +use frida_poc::{ + commands, + frida_prover::{traits::BaseFriProver, FridaProver}, + frida_prover_channel::FridaProverChannel, + frida_random::FridaRandom, +}; +use std::{ + fs, + io::{self, Write}, + path::PathBuf, +}; use winter_crypto::hashers::Blake3_256; use winter_fri::FriOptions; use winter_math::fields::f128::BaseElement; -use frida_poc::{frida_prover_channel::FridaProverChannel, frida_random::FridaRandom}; - type Blake3 = Blake3_256; type FridaChannel = FridaProverChannel>; @@ -28,7 +33,7 @@ enum Commands { Init { /// Data Path #[arg(long, default_value = "data/data.bin")] - data_path: String, + data_path: PathBuf, /// Blowup factor #[arg(long, default_value = "8")] blowup_factor: usize, @@ -45,7 +50,7 @@ enum Commands { size: usize, /// Path to the data file #[arg(long, default_value = "data/data.bin")] - data_path: String, + data_path: PathBuf, }, /// Commit data and generate a proof Commit { @@ -53,10 +58,10 @@ enum Commands { num_queries: usize, /// Path to the data file #[arg(long, default_value = "data/data.bin")] - data_path: String, + data_path: PathBuf, /// Path to the commitment file #[arg(long, default_value = "data/commitment.bin")] - commitment_path: String, + commitment_path: PathBuf, }, /// Open a proof for a given position Open { @@ -64,28 +69,28 @@ enum Commands { positions: Vec, /// Path to the positions file #[arg(long, default_value = "data/positions.bin")] - positions_path: String, + positions_path: PathBuf, /// Path to the evaluations file #[arg(long, default_value = "data/evaluations.bin")] - evaluations_path: String, + evaluations_path: PathBuf, /// Path to the proof file #[arg(long, default_value = "data/proof.bin")] - proof_path: String, + proof_path: PathBuf, }, /// Verify a proof Verify { /// Path to the commitment file #[arg(long, default_value = "data/commitment.bin")] - commitment_path: String, + commitment_path: PathBuf, /// Path to the positions file #[arg(long, default_value = "data/positions.bin")] - positions_path: String, + positions_path: PathBuf, /// Path to the evaluations file #[arg(long, default_value = "data/evaluations.bin")] - evaluations_path: String, + evaluations_path: PathBuf, /// Path to the proof file #[arg(long, default_value = "data/proof.bin")] - proof_path: String, + proof_path: PathBuf, }, } @@ -153,7 +158,7 @@ fn handle_init(cmd: Commands) -> Option { { println!( "Initializing prover with data path: {}, blowup factor: {}, folding factor: {}, max remainder degree: {}", - data_path, blowup_factor, folding_factor, max_remainder_degree + data_path.display(), blowup_factor, folding_factor, max_remainder_degree ); let options = FriOptions::new(blowup_factor, folding_factor, max_remainder_degree); if let Err(err) = fs::read(&data_path) { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 1e7439f..75553cf 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,8 +1,9 @@ use serde::Deserialize; -use std::fs; -use std::fs::File; -use std::io::{self, BufWriter, Read, Write}; - +use std::{ + fs::{self, File}, + io::{self, BufWriter, Read, Write}, + path::Path, +}; use winter_crypto::hashers::Blake3_256; use winter_fri::FriOptions; use winter_math::{fft, fields::f128::BaseElement, FieldElement}; @@ -59,16 +60,38 @@ pub fn load_fri_options(file_path: Option<&String>) -> FriOptions { } } -pub fn read_file_to_vec(file_path: &str) -> Result, io::Error> { +pub fn read_file_to_vec(file_path: &Path) -> Result, io::Error> { let mut file = File::open(file_path)?; let mut data = Vec::new(); file.read_to_end(&mut data)?; Ok(data) } -pub fn write_to_file(file_path: &str, data: &[u8]) -> Result<(), io::Error> { +pub fn write_to_file(file_path: &Path, data: &[u8]) -> Result<(), io::Error> { let mut file = File::create(file_path)?; let mut writer = BufWriter::new(&mut file); writer.write_all(data)?; Ok(()) } + +pub struct CleanupFiles<'a> { + pub paths: Vec<&'a Path>, +} + +impl<'a> CleanupFiles<'a> { + pub fn new(paths: Vec<&'a Path>) -> Self { + CleanupFiles { paths } + } +} + +impl Drop for CleanupFiles<'_> { + fn drop(&mut self) { + for path in &self.paths { + if path.exists() { + fs::remove_file(path).unwrap_or_else(|err| { + eprintln!("Failed to remove file {}: {}", path.display(), err); + }); + } + } + } +} From 6edefee241e738379ac7730d2a38e41e92bfba54 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Thu, 18 Jul 2024 01:56:33 +0900 Subject: [PATCH 17/23] refactor: Change deserialization of FriOptions with BP --- src/utils/mod.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 75553cf..a795b6f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -39,27 +39,33 @@ pub fn build_evaluations(trace_length: usize, lde_blowup: usize) -> Vec) -> FriOptions { - if let Some(path) = file_path { - let file_content = fs::read_to_string(path).expect("Unable to read FriOptions file"); - let config: FriOptionsConfig = - serde_json::from_str(&file_content).expect("Invalid FriOptions file format"); +impl From for FriOptions { + fn from(def: FriOptionsDef) -> FriOptions { FriOptions::new( - config.blowup_factor, - config.folding_factor, - config.max_remainder_degree, + def.blowup_factor, + def.folding_factor, + def.remainder_max_degree, ) - } else { - FriOptions::new(8, 2, 7) } } +pub fn load_fri_options(file_path: &Path) -> Result> { + let file_content = fs::read_to_string(file_path)?; + let mut de = serde_json::Deserializer::from_str(&file_content); + let fri_options = FriOptionsDef::deserialize(&mut de)?; + Ok(fri_options) +} + pub fn read_file_to_vec(file_path: &Path) -> Result, io::Error> { let mut file = File::open(file_path)?; let mut data = Vec::new(); From 97bfe52bc72d88ecafebcd2223309099893d46f3 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Mon, 22 Jul 2024 21:47:07 +0900 Subject: [PATCH 18/23] fix: Use .display() instead of {:?} --- src/commands/commit.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/commands/commit.rs b/src/commands/commit.rs index 2f2053a..a7266bf 100644 --- a/src/commands/commit.rs +++ b/src/commands/commit.rs @@ -36,7 +36,10 @@ pub fn run( let commitment_bytes = commitment.to_bytes(); write_to_file(commitment_path, &commitment_bytes)?; - println!("Commitment created and saved to {:?}", commitment_path); + println!( + "Commitment created and saved to {}", + commitment_path.display() + ); Ok(commitment) } From bde35bb8d32bb5e285a63bab2b943acda5bb87a3 Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Tue, 23 Jul 2024 00:33:59 +0900 Subject: [PATCH 19/23] refactor: Refactor error handling --- src/main.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index a88ed0d..2df63fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -130,20 +130,18 @@ fn read_and_parse_command() -> Result { let mut input = String::new(); io::stdin() .read_line(&mut input) - .map_err(|_| "Failed to read input.".to_string())?; + .expect("Failed to read input."); let input = input.trim(); if input.eq_ignore_ascii_case("exit") { std::process::exit(0); } - let args = match shlex::split(input) { - Some(mut args) => { - args.insert(0, "frida-poc".to_string()); - args - } - None => return Err("Failed to parse input.".to_string()), - }; + let args = shlex::split(input) + .ok_or_else(|| "Failed to parse input.".to_string())? + .into_iter() + .chain(Some("frida-poc".to_string())) + .collect::>(); Cli::try_parse_from(args).map_err(|err| err.to_string()) } From b0adee7f1094085c11d037bbc64472ef26f63e6a Mon Sep 17 00:00:00 2001 From: Wonjae Choi Date: Tue, 23 Jul 2024 00:35:44 +0900 Subject: [PATCH 20/23] refactor: Change to unwrap prover on an outer level --- src/main.rs | 74 ++++++++++++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2df63fa..3528ee6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -97,28 +97,38 @@ enum Commands { fn main() { let mut prover: Option = None; - loop { - match read_and_parse_command() { - Ok(cli) => match cli.command { - Commands::Init { .. } => { - prover = handle_init(cli.command); - } - Commands::GenerateData { .. } => { - handle_generate_data(cli.command); - } - Commands::Commit { .. } => { - handle_commit(cli.command, &mut prover); - } - Commands::Open { .. } => { - handle_open(cli.command, &mut prover); - } - Commands::Verify { .. } => { - handle_verify(cli.command, &mut prover); - } - }, - Err(err) => { - eprintln!("Error: {}", err); + fn try_unwrap_mut(prover: &mut Option) -> Result<&mut T, String> { + prover + .as_mut() + .ok_or("Please call the init command first.".to_owned()) + } + + let mut iteration = || -> Result<(), String> { + let cli = read_and_parse_command()?; + + match cli.command { + Commands::Init { .. } => { + prover = handle_init(cli.command); + } + Commands::GenerateData { .. } => { + handle_generate_data(cli.command); } + Commands::Commit { .. } => { + handle_commit(cli.command, try_unwrap_mut(&mut prover)?); + } + Commands::Open { .. } => { + handle_open(cli.command, try_unwrap_mut(&mut prover)?); + } + Commands::Verify { .. } => { + handle_verify(cli.command, try_unwrap_mut(&mut prover)?); + } + } + Ok(()) + }; + + loop { + if let Err(err) = iteration() { + eprintln!("Error: {}", err); } } } @@ -180,9 +190,7 @@ fn handle_generate_data(cmd: Commands) { } } -fn handle_commit(cmd: Commands, prover: &mut Option) { - let prover = match_prover(prover); - +fn handle_commit(cmd: Commands, prover: &mut FridaProverType) { if let Commands::Commit { num_queries, data_path, @@ -195,9 +203,7 @@ fn handle_commit(cmd: Commands, prover: &mut Option) { } } -fn handle_open(cmd: Commands, prover: &mut Option) { - let prover = match_prover(prover); - +fn handle_open(cmd: Commands, prover: &mut FridaProverType) { if let Commands::Open { positions, positions_path, @@ -217,9 +223,7 @@ fn handle_open(cmd: Commands, prover: &mut Option) { } } -fn handle_verify(cmd: Commands, prover: &mut Option) { - let prover = match_prover(prover); - +fn handle_verify(cmd: Commands, prover: &mut FridaProverType) { if let Commands::Verify { commitment_path, positions_path, @@ -240,13 +244,3 @@ fn handle_verify(cmd: Commands, prover: &mut Option) { println!("Verification successful"); } } - -fn match_prover(prover: &mut Option) -> &mut FridaProverType { - match prover.as_mut() { - Some(prover) => prover, - None => { - eprintln!("Please call the init command first."); - std::process::exit(1); - } - } -} From 85e6d63d298f96e7c15cc91de3f9ba9623ce1885 Mon Sep 17 00:00:00 2001 From: Ali <64667466+ali-rezai@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:47:40 +0900 Subject: [PATCH 21/23] fix --- src/frida_prover/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/frida_prover/mod.rs b/src/frida_prover/mod.rs index 596338e..cc334c0 100644 --- a/src/frida_prover/mod.rs +++ b/src/frida_prover/mod.rs @@ -7,7 +7,7 @@ use winter_fri::{FriOptions, ProverChannel}; use winter_fri::folding; use winter_fri::utils::hash_values; use winter_math::{fft, FieldElement}; -use winter_utils::{flatten_vector_elements, group_slice_elements, iter_mut, transpose_slice, uninit_vector}; +use winter_utils::{flatten_vector_elements, group_slice_elements, iter_mut, transpose_slice, uninit_vector, ByteReader, Deserializable, DeserializationError, Serializable}; #[cfg(feature = "concurrent")] use winter_utils::iterators::*; @@ -35,7 +35,7 @@ where E: FieldElement, H: ElementHasher, { - options: FriOptions, + pub(crate) options: FriOptions, _phantom_field_element: PhantomData, _phantom_hasher: PhantomData, } @@ -86,7 +86,7 @@ where self.proof.write_into(target); self.domain_size.write_into(target); self.num_queries.write_into(target); - self.batch_size.write_into(target); + self.poly_count.write_into(target); } fn get_size_hint(&self) -> usize { @@ -104,14 +104,14 @@ where let proof = FridaProof::read_from(source)?; let domain_size = usize::read_from(source)?; let num_queries = usize::read_from(source)?; - let batch_size = usize::read_from(source)?; + let poly_count = usize::read_from(source)?; Ok(Commitment { roots, proof, domain_size, num_queries, - batch_size, + poly_count, }) } } From 41c015fc9ca1cd53c59bba017428350b471dffe3 Mon Sep 17 00:00:00 2001 From: Ali <64667466+ali-rezai@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:57:14 +0900 Subject: [PATCH 22/23] Fix main CLI --- src/frida_prover/mod.rs | 6 +++--- src/lib.rs | 2 +- src/main.rs | 31 +++++++++++++------------------ src/utils/mod.rs | 2 +- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/frida_prover/mod.rs b/src/frida_prover/mod.rs index cc334c0..89f3575 100644 --- a/src/frida_prover/mod.rs +++ b/src/frida_prover/mod.rs @@ -22,10 +22,10 @@ use crate::{ }; // Channel is only exposed to tests -#[cfg(test)] +#[cfg(any(test, feature = "cli"))] pub mod channel; -#[cfg(not(test))] +#[cfg(not(any(test, feature = "cli")))] mod channel; pub mod proof; @@ -35,7 +35,7 @@ where E: FieldElement, H: ElementHasher, { - pub(crate) options: FriOptions, + pub options: FriOptions, _phantom_field_element: PhantomData, _phantom_hasher: PhantomData, } diff --git a/src/lib.rs b/src/lib.rs index 266c4e0..7f1300a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#[cfg(any(test, cli))] +#[cfg(any(test, feature = "cli"))] pub mod commands; pub mod frida_const; pub mod frida_data; diff --git a/src/main.rs b/src/main.rs index 3e27381..7381c48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,5 @@ use clap::{Parser, Subcommand}; -use frida_poc::{ - commands, - frida_prover::{traits::BaseFriProver, FridaProver}, - frida_prover_channel::FridaProverChannel, - frida_random::FridaRandom, -}; +use frida_poc::{commands, frida_prover::FridaProverBuilder}; use std::{ fs, io::{self, Write}, @@ -15,9 +10,7 @@ use winter_fri::FriOptions; use winter_math::fields::f128::BaseElement; type Blake3 = Blake3_256; -type FridaChannel = - FridaProverChannel>; -type FridaProverType = FridaProver; +type FridaProverBuilderType = FridaProverBuilder; #[derive(Parser)] #[command(name = "frida_cli")] @@ -98,7 +91,7 @@ enum Commands { } fn main() { - let mut prover: Option = None; + let mut prover: Option = None; fn try_unwrap_mut(prover: &mut Option) -> Result<&mut T, String> { prover @@ -159,7 +152,7 @@ fn read_and_parse_command() -> Result { Cli::try_parse_from(args).map_err(|err| err.to_string()) } -fn handle_init(cmd: Commands) -> Option { +fn handle_init(cmd: Commands) -> Option { if let Commands::Init { data_path, blowup_factor, @@ -179,7 +172,7 @@ fn handle_init(cmd: Commands) -> Option { ); return None; } - Some(FridaProverType::new(options)) + Some(FridaProverBuilderType::new(options)) } else { None } @@ -193,20 +186,22 @@ fn handle_generate_data(cmd: Commands) { } } -fn handle_commit(cmd: Commands, prover: &mut FridaProverType) { +fn handle_commit(cmd: Commands, prover_builder: &mut FridaProverBuilderType) { if let Commands::Commit { num_queries, data_path, commitment_path, } = cmd { - if let Err(err) = commands::commit::run(prover, num_queries, &data_path, &commitment_path) { + if let Err(err) = + commands::commit::run(prover_builder, num_queries, &data_path, &commitment_path) + { eprintln!("Failed to commit data: {}", err); } } } -fn handle_open(cmd: Commands, prover: &mut FridaProverType) { +fn handle_open(cmd: Commands, prover_builder: &mut FridaProverBuilderType) { if let Commands::Open { positions, positions_path, @@ -216,7 +211,7 @@ fn handle_open(cmd: Commands, prover: &mut FridaProverType) { } = cmd { if let Err(err) = commands::open::run( - prover, + prover_builder, &positions, &positions_path, &evaluations_path, @@ -228,7 +223,7 @@ fn handle_open(cmd: Commands, prover: &mut FridaProverType) { } } -fn handle_verify(cmd: Commands, prover: &mut FridaProverType) { +fn handle_verify(cmd: Commands, prover_builder: &mut FridaProverBuilderType) { if let Commands::Verify { commitment_path, positions_path, @@ -241,7 +236,7 @@ fn handle_verify(cmd: Commands, prover: &mut FridaProverType) { &positions_path, &evaluations_path, &proof_path, - prover.options().clone(), + prover_builder.options.clone(), ) { eprintln!("Failed to verify proof: {}", err); return; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 83ca74f..733786d 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1,2 @@ -#[cfg(any(test, cli))] +#[cfg(any(test, feature = "cli"))] pub mod test_utils; From 4fd065a76e85f22085af82233ba79903d618f323 Mon Sep 17 00:00:00 2001 From: Ali <64667466+ali-rezai@users.noreply.github.com> Date: Mon, 2 Sep 2024 17:09:38 +0900 Subject: [PATCH 23/23] Fix cli sub command issue --- src/main.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7381c48..5da2765 100644 --- a/src/main.rs +++ b/src/main.rs @@ -91,10 +91,10 @@ enum Commands { } fn main() { - let mut prover: Option = None; + let mut prover_builder: Option = None; - fn try_unwrap_mut(prover: &mut Option) -> Result<&mut T, String> { - prover + fn try_unwrap_mut(prover_builder: &mut Option) -> Result<&mut T, String> { + prover_builder .as_mut() .ok_or("Please call the init command first.".to_owned()) } @@ -104,19 +104,19 @@ fn main() { match cli.command { Commands::Init { .. } => { - prover = handle_init(cli.command); + prover_builder = handle_init(cli.command); } Commands::GenerateData { .. } => { handle_generate_data(cli.command); } Commands::Commit { .. } => { - handle_commit(cli.command, try_unwrap_mut(&mut prover)?); + handle_commit(cli.command, try_unwrap_mut(&mut prover_builder)?); } Commands::Open { .. } => { - handle_open(cli.command, try_unwrap_mut(&mut prover)?); + handle_open(cli.command, try_unwrap_mut(&mut prover_builder)?); } Commands::Verify { .. } => { - handle_verify(cli.command, try_unwrap_mut(&mut prover)?); + handle_verify(cli.command, try_unwrap_mut(&mut prover_builder)?); } } Ok(()) @@ -143,10 +143,12 @@ fn read_and_parse_command() -> Result { std::process::exit(0); } - let args = shlex::split(input) - .ok_or_else(|| "Failed to parse input.".to_string())? - .into_iter() - .chain(Some("frida-poc".to_string())) + let args = std::iter::once("frida-poc".to_string()) + .chain( + shlex::split(input) + .ok_or_else(|| "Failed to parse input.".to_string())? + .into_iter(), + ) .collect::>(); Cli::try_parse_from(args).map_err(|err| err.to_string())