diff --git a/src/kzg_proof.rs b/src/kzg_proof.rs new file mode 100644 index 0000000..ae163e3 --- /dev/null +++ b/src/kzg_proof.rs @@ -0,0 +1,122 @@ +use crate::dtypes::*; +use crate::enums::KzgError; +use crate::trusted_setup::KzgSettings; +use alloc::vec::Vec; +use bls12_381::{pairing, G1Affine, G2Affine, Scalar}; + +fn safe_g1_affine_from_bytes(bytes: &Bytes48) -> Result { + let g1 = G1Affine::from_compressed(&(bytes.clone().into())); + if g1.is_none().into() { + return Err(KzgError::BadArgs( + "Failed to parse G1Affine from bytes".to_string(), + )); + } + Ok(g1.unwrap()) +} + +fn safe_scalar_affine_from_bytes(bytes: &Bytes32) -> Result { + let lendian: [u8; 32] = Into::<[u8; 32]>::into(bytes.clone()) + .iter() + .rev() + .map(|&x| x) + .collect::>() + .try_into() + .unwrap(); + let scalar = Scalar::from_bytes(&lendian); + if scalar.is_none().into() { + return Err(KzgError::BadArgs( + "Failed to parse G1Affine from bytes".to_string(), + )); + } + Ok(scalar.unwrap()) +} + +pub struct KzgProof {} + +impl KzgProof { + pub fn verify_kzg_proof( + commitment_bytes: &Bytes48, + z_bytes: &Bytes32, + y_bytes: &Bytes32, + proof_bytes: &Bytes48, + kzg_settings: &KzgSettings, + ) -> Result { + let z = match safe_scalar_affine_from_bytes(z_bytes) { + Ok(z) => z, + Err(e) => { + return Err(e); + } + }; + let y = match safe_scalar_affine_from_bytes(y_bytes) { + Ok(y) => y, + Err(e) => { + return Err(e); + } + }; + let commitment = match safe_g1_affine_from_bytes(commitment_bytes) { + Ok(g1) => g1, + Err(e) => { + return Err(e); + } + }; + let proof = match safe_g1_affine_from_bytes(proof_bytes) { + Ok(g1) => g1, + Err(e) => { + return Err(e); + } + }; + + let g2_x = G2Affine::generator() * z; + let x_minus_z = kzg_settings.g2_values[1] - g2_x; + + let g1_y = G1Affine::generator() * y; + let p_minus_y = commitment - g1_y; + + Ok( + pairing(&p_minus_y.into(), &G2Affine::generator()) + == pairing(&proof, &x_minus_z.into()), + ) + } +} + +#[cfg(test)] +mod tests { + use std::{fs, path::PathBuf}; + + use crate::{test_format::Test, trusted_setup::KzgSettings, KzgProof}; + + const VERIFY_KZG_PROOF_TESTS: &str = "tests/verify_kzg_proof/*/*"; + + #[test] + fn test_verify_kzg_proof() { + let kzg_settings = KzgSettings::load_trusted_setup_file().unwrap(); + let test_files: Vec = glob::glob(VERIFY_KZG_PROOF_TESTS) + .unwrap() + .map(|x| x.unwrap()) + .collect(); + for test_file in test_files { + let yaml_data = fs::read_to_string(test_file.clone()).unwrap(); + let test: Test = serde_yaml::from_str(&yaml_data).unwrap(); + let (Ok(commitment), Ok(z), Ok(y), Ok(proof)) = ( + test.input.get_commitment(), + test.input.get_z(), + test.input.get_y(), + test.input.get_proof(), + ) else { + assert!(test.get_output().is_none()); + continue; + }; + + let result = KzgProof::verify_kzg_proof(&commitment, &z, &y, &proof, &kzg_settings); + match result { + Ok(result) => { + assert_eq!(result, test.get_output().unwrap_or_else(|| false)); + } + Err(e) => { + assert!(test.get_output().is_none()); + eprintln!("Error: {:?}", e); + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index e74079d..af4cc6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,134 +10,17 @@ use enums::KzgError; pub mod consts; pub mod dtypes; pub mod enums; +pub mod kzg_proof; pub mod test_format; pub mod trusted_setup; pub use consts::*; pub use dtypes::*; +pub use kzg_proof::KzgProof; pub use trusted_setup::*; -use alloc::vec::Vec; - -fn safe_g1_affine_from_bytes(bytes: &Bytes48) -> Result { - let g1 = G1Affine::from_compressed(&(bytes.clone().into())); - if g1.is_none().into() { - return Err(KzgError::BadArgs( - "Failed to parse G1Affine from bytes".to_string(), - )); - } - Ok(g1.unwrap()) -} - -fn safe_scalar_affine_from_bytes(bytes: &Bytes32) -> Result { - let lendian: [u8; 32] = Into::<[u8; 32]>::into(bytes.clone()) - .iter() - .rev() - .map(|&x| x) - .collect::>() - .try_into() - .unwrap(); - let scalar = Scalar::from_bytes(&lendian); - if scalar.is_none().into() { - return Err(KzgError::BadArgs( - "Failed to parse G1Affine from bytes".to_string(), - )); - } - Ok(scalar.unwrap()) -} - -pub struct KzgProof {} - -impl KzgProof { - pub fn verify_kzg_proof( - commitment_bytes: &Bytes48, - z_bytes: &Bytes32, - y_bytes: &Bytes32, - proof_bytes: &Bytes48, - kzg_settings: &KzgSettings, - ) -> Result { - let z = match safe_scalar_affine_from_bytes(z_bytes) { - Ok(z) => z, - Err(e) => { - return Err(e); - } - }; - let y = match safe_scalar_affine_from_bytes(y_bytes) { - Ok(y) => y, - Err(e) => { - return Err(e); - } - }; - let commitment = match safe_g1_affine_from_bytes(commitment_bytes) { - Ok(g1) => g1, - Err(e) => { - return Err(e); - } - }; - let proof = match safe_g1_affine_from_bytes(proof_bytes) { - Ok(g1) => g1, - Err(e) => { - return Err(e); - } - }; - - let g2_x = G2Affine::generator() * z; - let x_minus_z = kzg_settings.g2_values[1] - g2_x; - - let g1_y = G1Affine::generator() * y; - let p_minus_y = commitment - g1_y; - - Ok( - pairing(&p_minus_y.into(), &G2Affine::generator()) - == pairing(&proof, &x_minus_z.into()), - ) - } -} - pub(crate) fn hex_to_bytes(hex_str: &str) -> Result, KzgError> { let trimmed_str = hex_str.strip_prefix("0x").unwrap_or(hex_str); hex::decode(trimmed_str) .map_err(|e| KzgError::InvalidHexFormat(format!("Failed to decode hex: {}", e))) } - -#[cfg(test)] -mod tests { - use std::{fs, path::PathBuf}; - - use crate::{test_format::Test, trusted_setup::KzgSettings, KzgProof}; - - const VERIFY_KZG_PROOF_TESTS: &str = "tests/verify_kzg_proof/*/*"; - - #[test] - fn test_verify_kzg_proof() { - let kzg_settings = KzgSettings::load_trusted_setup_file().unwrap(); - let test_files: Vec = glob::glob(VERIFY_KZG_PROOF_TESTS) - .unwrap() - .map(|x| x.unwrap()) - .collect(); - for test_file in test_files { - let yaml_data = fs::read_to_string(test_file.clone()).unwrap(); - let test: Test = serde_yaml::from_str(&yaml_data).unwrap(); - let (Ok(commitment), Ok(z), Ok(y), Ok(proof)) = ( - test.input.get_commitment(), - test.input.get_z(), - test.input.get_y(), - test.input.get_proof(), - ) else { - assert!(test.get_output().is_none()); - continue; - }; - - let result = KzgProof::verify_kzg_proof(&commitment, &z, &y, &proof, &kzg_settings); - match result { - Ok(result) => { - assert_eq!(result, test.get_output().unwrap_or_else(|| false)); - } - Err(e) => { - assert!(test.get_output().is_none()); - eprintln!("Error: {:?}", e); - } - } - } - } -}