diff --git a/Cargo.lock b/Cargo.lock index 0fbbcce..364ba29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,12 +17,54 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anstream" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + [[package]] name = "anstyle" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.75" @@ -130,28 +172,49 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", + "clap_derive", ] [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ + "anstream", "anstyle", "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "console" @@ -282,6 +345,29 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e7cf40684ae96ade6232ed84582f40ce0a66efcd43a5117aef610534f8e0b8" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -314,14 +400,17 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" name = "fhe" version = "0.1.0-beta.8" dependencies = [ + "clap", "console", "criterion", "doc-comment", + "env_logger", "fhe-math", "fhe-traits", "fhe-util", "indicatif", "itertools 0.12.1", + "log", "ndarray", "num-bigint", "num-traits", @@ -441,6 +530,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "indexmap" version = "2.0.2" @@ -1050,6 +1145,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "2.0.46" @@ -1128,6 +1229,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 0d6734b..947a717 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,15 @@ license = "MIT" rust-version = "1.73" [workspace.dependencies] +clap = { version = "^4.4.18", features = ["derive"] } console = "^0.15.8" criterion = "^0.5.1" doc-comment = "^0.3.3" +env_logger = "^0.11.1" ethnum = "^1.5.0" indicatif = "^0.17.7" itertools = "^0.12.1" +log = "^0.4.20" ndarray = "^0.15.6" num-bigint = "^0.4.4" num-bigint-dig = "^0.8.4" diff --git a/crates/fhe/Cargo.toml b/crates/fhe/Cargo.toml index a881531..bae86fb 100644 --- a/crates/fhe/Cargo.toml +++ b/crates/fhe/Cargo.toml @@ -33,12 +33,15 @@ thiserror.workspace = true prost-build.workspace = true [dev-dependencies] +clap.workspace = true +console.workspace = true criterion.workspace = true +env_logger.workspace = true indicatif.workspace = true itertools.workspace = true +log.workspace = true ndarray.workspace = true rand.workspace = true -console.workspace = true [[bench]] name = "bfv" @@ -58,8 +61,5 @@ name = "mulpir" [[example]] name = "sealpir" -[[example]] -name = "util" - [[example]] name = "voting" diff --git a/crates/fhe/examples/mulpir.rs b/crates/fhe/examples/mulpir.rs index 2e351d9..9f81f05 100644 --- a/crates/fhe/examples/mulpir.rs +++ b/crates/fhe/examples/mulpir.rs @@ -6,9 +6,10 @@ // We use the same parameters as in the paper to enable an apple-to-apple // comparison. +mod pir; mod util; -use console::style; +use clap::Parser; use fhe::bfv; use fhe_traits::{ DeserializeParametrized, FheDecoder, FheDecrypter, FheEncoder, FheEncrypter, Serialize, @@ -16,94 +17,29 @@ use fhe_traits::{ use fhe_util::{inverse, transcode_to_bytes}; use indicatif::HumanBytes; use rand::{rngs::OsRng, thread_rng, RngCore}; -use std::{env, error::Error, process::exit, time::Instant}; +use std::{error::Error, time::Instant}; use util::{ encode_database, generate_database, number_elements_per_plaintext, timeit::{timeit, timeit_n}, }; -fn print_notice_and_exit(max_element_size: usize, error: Option) { - println!( - "{} MulPIR with fhe.rs", - style(" overview:").magenta().bold() - ); - println!( - "{} mulpir- [-h] [--help] [--database_size=] [--element_size=]", - style(" usage:").magenta().bold() - ); - println!( - "{} {} must be at least 1, and {} must be between 1 and {}", - style("constraints:").magenta().bold(), - style("database_size").blue(), - style("element_size").blue(), - max_element_size - ); - if let Some(error) = error { - println!("{} {}", style(" error:").red().bold(), error); - } - exit(0); -} - fn main() -> Result<(), Box> { // We use the parameters reported in Table 1 of https://eprint.iacr.org/2019/1483.pdf. let degree = 8192; let plaintext_modulus: u64 = (1 << 20) + (1 << 19) + (1 << 17) + (1 << 16) + (1 << 14) + 1; let moduli_sizes = [50, 55, 55]; + let args = pir::Cli::parse(); + let database_size = args.database_size; + let elements_size = args.element_size; + // Compute what is the maximum byte-length of an element to fit within one // ciphertext. Each coefficient of the ciphertext polynomial can contain // floor(log2(plaintext_modulus)) bits. let max_element_size = ((plaintext_modulus.ilog2() as usize) * degree) / 8; - - // This executable is a command line tool which enables to specify different - // database and element sizes. - let args: Vec = env::args().skip(1).collect(); - - // Print the help if requested. - if args.contains(&"-h".to_string()) || args.contains(&"--help".to_string()) { - print_notice_and_exit(max_element_size, None) - } - - // Use the default values from . - let mut database_size = 1 << 20; - let mut elements_size = 288; - - // Update the database size and/or element size depending on the arguments - // provided. - for arg in &args { - if arg.starts_with("--database_size") { - let a: Vec<&str> = arg.rsplit('=').collect(); - if a.len() != 2 || a[0].parse::().is_err() { - print_notice_and_exit( - max_element_size, - Some("Invalid `--database_size` command".to_string()), - ) - } else { - database_size = a[0].parse::()? - } - } else if arg.starts_with("--element_size") { - let a: Vec<&str> = arg.rsplit('=').collect(); - if a.len() != 2 || a[0].parse::().is_err() { - print_notice_and_exit( - max_element_size, - Some("Invalid `--element_size` command".to_string()), - ) - } else { - elements_size = a[0].parse::()? - } - } else { - print_notice_and_exit( - max_element_size, - Some(format!("Unrecognized command: {arg}")), - ) - } - } - if elements_size > max_element_size || elements_size == 0 || database_size == 0 { - print_notice_and_exit( - max_element_size, - Some("Element or database sizes out of bound".to_string()), - ) + log::error!("Invalid parameters: database_size = {database_size}, elements_size = {elements_size}. The maximum element size if {max_element_size}."); + clap::Error::new(clap::error::ErrorKind::InvalidValue).exit(); } // The parameters are within bound, let's go! Let's first display some diff --git a/crates/fhe/examples/pir.rs b/crates/fhe/examples/pir.rs new file mode 100644 index 0000000..1fa1821 --- /dev/null +++ b/crates/fhe/examples/pir.rs @@ -0,0 +1,21 @@ +use clap::Parser; + +#[derive(Parser)] +pub struct Cli { + #[arg( + long, + help = "The number of elements in the database", + default_value = "65536" + )] + pub database_size: usize, + + #[arg( + long, + help = "The size of each database element", + default_value = "1024" + )] + pub element_size: usize, +} + +#[allow(dead_code)] +fn main() {} diff --git a/crates/fhe/examples/sealpir.rs b/crates/fhe/examples/sealpir.rs index 271301e..d1a824a 100644 --- a/crates/fhe/examples/sealpir.rs +++ b/crates/fhe/examples/sealpir.rs @@ -6,9 +6,10 @@ // We use the same parameters as in Microsoft's public implementation // to enable an apple-to-apple comparison. +mod pir; mod util; -use console::style; +use clap::Parser; use fhe::bfv; use fhe_math::rq::{traits::TryConvertFrom, Context, Poly, Representation}; use fhe_traits::{ @@ -19,92 +20,30 @@ use fhe_util::{inverse, transcode_bidirectional, transcode_to_bytes}; use indicatif::HumanBytes; use itertools::Itertools; use rand::{rngs::OsRng, thread_rng, RngCore}; -use std::{env, error::Error, process::exit, sync::Arc}; +use std::{error::Error, sync::Arc}; use util::{ encode_database, generate_database, number_elements_per_plaintext, timeit::{timeit, timeit_n}, }; -fn print_notice_and_exit(max_element_size: usize, error: Option) { - println!( - "{} SealPIR with fhe.rs", - style(" overview:").magenta().bold() - ); - println!( - "{} sealpir [-h] [--help] [--database_size=] [--element_size=]", - style(" usage:").magenta().bold() - ); - println!( - "{} {} must be at least 1, and {} must be between 1 and {}", - style("constraints:").magenta().bold(), - style("database_size").blue(), - style("element_size").blue(), - max_element_size - ); - if let Some(error) = error { - println!("{} {}", style(" error:").red().bold(), error); - } - exit(0); -} - fn main() -> Result<(), Box> { + env_logger::init(); + let degree = 4096usize; let plaintext_modulus = 2056193u64; let moduli_sizes = [36, 36, 37]; + let args = pir::Cli::parse(); + let database_size = args.database_size; + let elements_size = args.element_size; + // Compute what is the maximum byte-length of an element to fit within one // ciphertext. Each coefficient of the ciphertext polynomial can contain // floor(log2(plaintext_modulus)) bits. let max_element_size = ((plaintext_modulus.ilog2() as usize) * degree) / 8; - - // This executable is a command line tool which enables to specify different - // database and element sizes. - let args: Vec = env::args().skip(1).collect(); - - // Print the help if requested. - if args.contains(&"-h".to_string()) || args.contains(&"--help".to_string()) { - print_notice_and_exit(max_element_size, None) - } - - // Use the default values from . - let mut database_size = 1 << 16; - let mut elements_size = 1024; - - // Update the database size and/or element size depending on the arguments - // provided. - for arg in &args { - if arg.starts_with("--database_size") { - let a: Vec<&str> = arg.rsplit('=').collect(); - if a.len() != 2 || a[0].parse::().is_err() { - print_notice_and_exit( - max_element_size, - Some("Invalid `--database_size` command".to_string()), - ) - } else { - database_size = a[0].parse::()? - } - } else if arg.starts_with("--element_size") { - let a: Vec<&str> = arg.rsplit('=').collect(); - if a.len() != 2 || a[0].parse::().is_err() { - print_notice_and_exit( - max_element_size, - Some("Invalid `--element_size` command".to_string()), - ) - } else { - elements_size = a[0].parse::()? - } - } else { - print_notice_and_exit( - max_element_size, - Some(format!("Unrecognized command: {arg}")), - ) - } - } if elements_size > max_element_size || elements_size == 0 || database_size == 0 { - print_notice_and_exit( - max_element_size, - Some("Element or database sizes out of bound".to_string()), - ) + log::error!("Invalid parameters: database_size = {database_size}, elements_size = {elements_size}. The maximum element size if {max_element_size}."); + clap::Error::new(clap::error::ErrorKind::InvalidValue).exit(); } // The parameters are within bound, let's go! Let's first display some