diff --git a/crates/proof-of-sql/Cargo.toml b/crates/proof-of-sql/Cargo.toml index c2be7d100..1c74d35ec 100644 --- a/crates/proof-of-sql/Cargo.toml +++ b/crates/proof-of-sql/Cargo.toml @@ -30,6 +30,7 @@ blitzar = { workspace = true, optional = true } bumpalo = { workspace = true, features = ["collections"] } bytemuck = { workspace = true } byte-slice-cast = { workspace = true } +clap = { workspace = true, features = ["derive"] } curve25519-dalek = { workspace = true, features = ["serde"] } chrono = { workspace = true, features = ["serde"] } derive_more = { workspace = true } @@ -54,7 +55,6 @@ zerocopy = { workspace = true } alloy-sol-types = { workspace = true } arrow-csv = { workspace = true } blitzar = { workspace = true } -clap = { workspace = true, features = ["derive"] } criterion = { workspace = true, features = ["html_reports"] } merlin = { workspace = true } opentelemetry = { workspace = true } @@ -83,6 +83,10 @@ std = ["snafu/std"] [lints] workspace = true +[[bin]] +name = "commitment-utility" +path = "utils/commitment-utility/main.rs" + [[example]] name = "hello_world" required-features = ["test"] diff --git a/crates/proof-of-sql/utils/commitment-utility/main.rs b/crates/proof-of-sql/utils/commitment-utility/main.rs new file mode 100644 index 000000000..ae44929cb --- /dev/null +++ b/crates/proof-of-sql/utils/commitment-utility/main.rs @@ -0,0 +1,135 @@ +//! Utility to deserialize and print a commitment from a file or stdin. +use clap::{Parser, ValueEnum}; +use curve25519_dalek::ristretto::RistrettoPoint; +use proof_of_sql::{ + base::commitment::TableCommitment, + proof_primitive::dory::{DoryCommitment, DynamicDoryCommitment}, +}; +use snafu::Snafu; +use std::{ + fs::File, + io::{self, Read, Write}, + path::PathBuf, +}; + +#[derive(ValueEnum, Clone, Debug)] +/// Supported commitment schemes. +enum CommitmentScheme { + /// Inner Product Argument (IPA) commitment scheme. + Ipa, + /// Dory commitment scheme. + Dory, + /// Dynamic Dory commitment scheme. + DynamicDory, +} + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Cli { + /// Input file (defaults to None which is stdin) + #[arg(short, long)] + input: Option, + + /// Output file (defaults to None which is stdout) + #[arg(short, long)] + output: Option, + + /// Commitment scheme (e.g. `ipa`, `dynamic_dory`, `dory`) + #[arg(long, value_enum, default_value = "CommitmentScheme::DynamicDory")] + scheme: CommitmentScheme, +} + +#[derive(Debug, Snafu)] +enum CommitUtilityError { + #[snafu(display("Failed to open input file '{:?}'", filename))] + OpenInputFile { filename: PathBuf }, + + #[snafu(display("Failed to read from input file '{:?}'", filename))] + ReadInputFile { filename: PathBuf }, + + #[snafu(display("Failed to read from stdin"))] + ReadStdin, + + #[snafu(display("Failed to create output file '{:?}'", filename))] + CreateOutputFile { filename: PathBuf }, + + #[snafu(display("Failed to write to output file '{:?}'", filename))] + WriteOutputFile { filename: PathBuf }, + + #[snafu(display("Failed to write to stdout"))] + WriteStdout, + + #[snafu(display("Failed to deserialize commitment"))] + DeserializationError, +} + +type CommitUtilityResult = std::result::Result; + +fn main() -> CommitUtilityResult<()> { + let cli = Cli::parse(); + + // Read input data + let input_data = match &cli.input { + Some(input_file) => { + let mut file = + File::open(input_file).map_err(|_| CommitUtilityError::OpenInputFile { + filename: input_file.clone(), + })?; + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer) + .map_err(|_| CommitUtilityError::ReadInputFile { + filename: input_file.clone(), + })?; + buffer + } + None => { + let mut buffer = Vec::new(); + io::stdin() + .read_to_end(&mut buffer) + .map_err(|_| CommitUtilityError::ReadStdin)?; + buffer + } + }; + + // Deserialize commitment based on the scheme + let human_readable = match cli.scheme { + CommitmentScheme::DynamicDory => { + let commitment: TableCommitment = + postcard::from_bytes(&input_data) + .map_err(|_| CommitUtilityError::DeserializationError)?; + format!("{commitment:#?}") + } + CommitmentScheme::Dory => { + let commitment: TableCommitment = postcard::from_bytes(&input_data) + .map_err(|_| CommitUtilityError::DeserializationError)?; + format!("{commitment:#?}") + } + CommitmentScheme::Ipa => { + let commitment: TableCommitment = postcard::from_bytes(&input_data) + .map_err(|_| CommitUtilityError::DeserializationError)?; + format!("{commitment:#?}") + } + }; + + // Write output data + match &cli.output { + Some(output_file) => { + let mut file = + File::create(output_file).map_err(|_| CommitUtilityError::CreateOutputFile { + filename: output_file.clone(), + })?; + file.write_all(human_readable.as_bytes()).map_err(|_| { + CommitUtilityError::WriteOutputFile { + filename: output_file.clone(), + } + })?; + } + None => { + io::stdout() + .write_all(human_readable.as_bytes()) + .map_err(|_| CommitUtilityError::WriteStdout)?; + } + } + + Ok(()) +}