Skip to content

Commit

Permalink
feat: move KzgProof to standalone file
Browse files Browse the repository at this point in the history
  • Loading branch information
0xWOLAND committed Jun 19, 2024
1 parent c3c574e commit 58d6bc8
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 119 deletions.
122 changes: 122 additions & 0 deletions src/kzg_proof.rs
Original file line number Diff line number Diff line change
@@ -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<G1Affine, KzgError> {
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<Scalar, KzgError> {
let lendian: [u8; 32] = Into::<[u8; 32]>::into(bytes.clone())
.iter()
.rev()
.map(|&x| x)
.collect::<Vec<u8>>()
.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<bool, KzgError> {
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<PathBuf> = 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);
}
}
}
}
}
121 changes: 2 additions & 119 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<G1Affine, KzgError> {
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<Scalar, KzgError> {
let lendian: [u8; 32] = Into::<[u8; 32]>::into(bytes.clone())
.iter()
.rev()
.map(|&x| x)
.collect::<Vec<u8>>()
.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<bool, KzgError> {
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<Vec<u8>, 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<PathBuf> = 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);
}
}
}
}
}

0 comments on commit 58d6bc8

Please sign in to comment.