Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements kzg tests #364

Merged
merged 27 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
54ecfac
Create boiler plate for kzg runner
EchoAlice Mar 28, 2024
e478927
Boilerplate for handlers. Create (wip) `BlobToKzgCommitmentTestCase`
EchoAlice Mar 29, 2024
56a5f70
Attempts to create `blob_to_kzg_commitment()` test case. (Test fails…
EchoAlice Apr 2, 2024
fc96134
Create `blob_to_kzg_commitment()` handler. Passes "valid blob" tests
EchoAlice Apr 2, 2024
e5155d2
Implements `blob_to_kzg_commitment()` handler
EchoAlice Apr 2, 2024
b67f3d5
Create `compute_kzg_proof` handler
EchoAlice Apr 3, 2024
37f7bb7
Iterate on feedback
EchoAlice Apr 3, 2024
184a709
Implements happy case to kzg proof verification. WIP for unhappy cases
EchoAlice Apr 5, 2024
ccba416
Create "verify_kzg_proof" handler. (All tests pass)
EchoAlice Apr 5, 2024
fbea38c
Place testing logic within internal `run` functions
EchoAlice Apr 5, 2024
a902107
refactor `run_verify_kzg_proof_test` to simplify deserialization
ralexstokes Apr 6, 2024
9a921b6
Add semicolons (formatter told me to)
EchoAlice Apr 6, 2024
318dd20
Create "compute_blob_kzg_proof" handler
EchoAlice Apr 9, 2024
a969b2e
Fix formatting warnings
EchoAlice Apr 9, 2024
8040acb
`unwrap()` on all outputs
EchoAlice Apr 9, 2024
aa997fd
Creates "verify_blob_kzg_proof" handler. (WIP) Test cases with inval…
EchoAlice Apr 9, 2024
d2f0af9
Create "verify_blob_kzg_proof" handler
EchoAlice Apr 10, 2024
00e2848
Removes ice file. Removes LightClient and MerkleProof test runners fr…
EchoAlice Apr 10, 2024
fb2d1b0
Convert all handler logic to deserialize input before handling test o…
EchoAlice Apr 10, 2024
490a790
Create "verify_blob_kzg_proof_batch" handler. All kzg tests pass!
EchoAlice Apr 11, 2024
9983d2e
Remove unnecessary `return` statements
EchoAlice Apr 11, 2024
b69723c
Iterates on feedback from Alex
EchoAlice Apr 11, 2024
dc36dab
Accesses `KZGSettings` via `.context()` within test runner
EchoAlice Apr 15, 2024
9c911cd
Fixes Clippy warnings
EchoAlice Apr 15, 2024
12bd779
Remove semicolons after `return` from main.rs
EchoAlice Apr 16, 2024
8c6c803
Changes `if let Some` logic for handlers
EchoAlice Apr 16, 2024
cffaeb8
Apply suggestions from code review
ralexstokes Apr 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ethereum-consensus/src/deneb/polynomial_commitments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub enum Error {
InvalidProof,
}

#[derive(Debug, PartialEq, Eq)]
pub struct ProofAndEvaluation {
pub proof: KzgProof,
pub evaluation: FieldElement,
Expand Down
4 changes: 2 additions & 2 deletions spec-tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fn visit_dir(
} else {
if entries.is_empty() {
// some spurious test dirs exist
return Ok(())
return Ok(());
}
let test_case_paths = entries
.iter()
Expand All @@ -87,7 +87,7 @@ fn visit_dir(

let test_case = parse_test_case(&test_case_paths, path_mask, context.clone());
if test_case.meta.should_skip() {
return Ok(())
return Ok(());
}
let name = test_case.name();
let should_ignore = test_case.meta.should_ignore();
Expand Down
325 changes: 325 additions & 0 deletions spec-tests/runners/kzg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
use crate::{
test_case::TestCase,
test_utils::{load_yaml, Error},
};
use ethereum_consensus::deneb::{
mainnet::Blob,
polynomial_commitments::{
blob_to_kzg_commitment, compute_blob_kzg_proof, compute_kzg_proof, verify_blob_kzg_proof,
verify_blob_kzg_proof_batch, verify_kzg_proof, FieldElement, KzgCommitment, KzgProof,
KzgSettings, ProofAndEvaluation,
},
};

pub fn dispatch(test: &TestCase) -> Result<(), Error> {
let kzg_settings = &test.context().kzg_settings;

match test.meta.handler.0.as_str() {
"blob_to_kzg_commitment" => run_blob_to_kzg_commitment_test(test, kzg_settings),
"compute_kzg_proof" => run_compute_kzg_proof_test(test, kzg_settings),
"verify_kzg_proof" => run_verify_kzg_proof_test(test, kzg_settings),
"compute_blob_kzg_proof" => run_compute_blob_kzg_proof_test(test, kzg_settings),
"verify_blob_kzg_proof" => run_verify_blob_kzg_proof_test(test, kzg_settings),
"verify_blob_kzg_proof_batch" => run_verify_blob_kzg_proof_batch_test(test, kzg_settings),
handler => unreachable!("no tests for {handler}"),
}
}

fn run_blob_to_kzg_commitment_test(
test: &TestCase,
kzg_settings: &KzgSettings,
) -> Result<(), Error> {
let path = &test.data_path;
// Load test case ----
let path = path.to_string() + "/data.yaml";
let test_data: serde_yaml::Value = load_yaml(&path);
let input_yaml = test_data.get("input").unwrap();
let blob_yaml = input_yaml.get("blob").unwrap();
let output_yaml = test_data.get("output").unwrap();
let output: Option<KzgCommitment> = serde_yaml::from_value(output_yaml.clone()).unwrap();

// Check the deserialization of input(s)
let blob: Blob = match serde_yaml::from_value(blob_yaml.clone()) {
Ok(blob) => blob,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let result = blob_to_kzg_commitment(&blob, kzg_settings);
if let Some(expected_commitment) = output {
// some `output` was present, use inner value to determine if the spec code should succeed
// or fail
match result {
Ok(commitment) => {
assert_eq!(commitment, expected_commitment);
Ok(())
}
Err(_) => Ok(()),
EchoAlice marked this conversation as resolved.
Show resolved Hide resolved
}
} else {
// `output` is `null`, implying the spec code should always fail
let result = blob_to_kzg_commitment(&blob, kzg_settings);
ralexstokes marked this conversation as resolved.
Show resolved Hide resolved
assert!(result.is_err());
Ok(())
}
}

fn run_compute_kzg_proof_test(test: &TestCase, kzg_settings: &KzgSettings) -> Result<(), Error> {
let path = &test.data_path;
let path = path.to_string() + "/data.yaml";
let test_data: serde_yaml::Value = load_yaml(&path);
let input_yaml = test_data.get("input").unwrap();
let blob_yaml = input_yaml.get("blob").unwrap();
let z_yaml = input_yaml.get("z").unwrap();
let output_yaml = test_data.get("output").unwrap();
let output: Option<(KzgProof, FieldElement)> =
serde_yaml::from_value(output_yaml.clone()).unwrap();

let blob: Blob = match serde_yaml::from_value(blob_yaml.clone()) {
Ok(blob) => blob,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let z = match serde_yaml::from_value(z_yaml.clone()) {
Ok(z) => z,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let result = compute_kzg_proof(&blob, &z, kzg_settings);
if let Some(expected_proof_and_evaluation) = output {
match result {
EchoAlice marked this conversation as resolved.
Show resolved Hide resolved
Ok(proof_and_evaluation) => {
let expected_proof_and_evaluation = ProofAndEvaluation {
proof: expected_proof_and_evaluation.0,
evaluation: expected_proof_and_evaluation.1,
};
EchoAlice marked this conversation as resolved.
Show resolved Hide resolved
assert_eq!(proof_and_evaluation, expected_proof_and_evaluation);
Ok(())
}
Err(_) => Ok(()),
}
} else {
let result = compute_kzg_proof(&blob, &z, kzg_settings);
ralexstokes marked this conversation as resolved.
Show resolved Hide resolved
assert!(result.is_err());
Ok(())
}
}

fn run_verify_kzg_proof_test(test: &TestCase, kzg_settings: &KzgSettings) -> Result<(), Error> {
let path = &test.data_path;
let path = path.to_string() + "/data.yaml";
let test_data: serde_yaml::Value = load_yaml(&path);
let input_yaml = test_data.get("input").unwrap();
let commitment_yaml = input_yaml.get("commitment").unwrap();
let z_yaml = input_yaml.get("z").unwrap();
let y_yaml = input_yaml.get("y").unwrap();
let proof_yaml = input_yaml.get("proof").unwrap();
let output_yaml = test_data.get("output").unwrap();
let output: Option<bool> = serde_yaml::from_value(output_yaml.clone()).unwrap();

let commitment = match serde_yaml::from_value(commitment_yaml.clone()) {
Ok(commitment) => commitment,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let z = match serde_yaml::from_value(z_yaml.clone()) {
Ok(z) => z,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let y = match serde_yaml::from_value(y_yaml.clone()) {
Ok(y) => y,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let proof = match serde_yaml::from_value(proof_yaml.clone()) {
Ok(proof) => proof,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let result = verify_kzg_proof(&commitment, &z, &y, &proof, kzg_settings);
if let Some(expected_validity) = output {
if expected_validity {
assert!(result.is_ok());
Ok(())
} else {
assert!(result.is_err());
Ok(())
}
} else {
let result = verify_kzg_proof(&commitment, &z, &y, &proof, kzg_settings);
ralexstokes marked this conversation as resolved.
Show resolved Hide resolved
assert!(result.is_err());
Ok(())
}
}

fn run_compute_blob_kzg_proof_test(
test: &TestCase,
kzg_settings: &KzgSettings,
) -> Result<(), Error> {
let path = &test.data_path;
let path = path.to_string() + "/data.yaml";
let test_data: serde_yaml::Value = load_yaml(&path);
let input_yaml = test_data.get("input").unwrap();
let blob_yaml = input_yaml.get("blob").unwrap();
let commitment_yaml = input_yaml.get("commitment").unwrap();
let output_yaml = test_data.get("output").unwrap();
let output: Option<KzgProof> = serde_yaml::from_value(output_yaml.clone()).unwrap();

let blob: Blob = match serde_yaml::from_value(blob_yaml.clone()) {
Ok(blob) => blob,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let commitment = match serde_yaml::from_value(commitment_yaml.clone()) {
Ok(commitment) => commitment,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let result = compute_blob_kzg_proof(&blob, &commitment, kzg_settings);
if let Some(expected_proof) = output {
match result {
ralexstokes marked this conversation as resolved.
Show resolved Hide resolved
Ok(proof) => {
assert_eq!(proof, expected_proof);
Ok(())
}
Err(_) => Ok(()),
}
} else {
let result = compute_blob_kzg_proof(&blob, &commitment, kzg_settings);
ralexstokes marked this conversation as resolved.
Show resolved Hide resolved
assert!(result.is_err());
Ok(())
}
}

fn run_verify_blob_kzg_proof_test(
test: &TestCase,
kzg_settings: &KzgSettings,
) -> Result<(), Error> {
let path = &test.data_path;
let path = path.to_string() + "/data.yaml";
let test_data: serde_yaml::Value = load_yaml(&path);
let input_yaml = test_data.get("input").unwrap();
let blob_yaml = input_yaml.get("blob").unwrap();
let commitment_yaml = input_yaml.get("commitment").unwrap();
let proof_yaml = input_yaml.get("proof").unwrap();
let output_yaml = test_data.get("output").unwrap();
let output: Option<bool> = serde_yaml::from_value(output_yaml.clone()).unwrap();

let blob: Blob = match serde_yaml::from_value(blob_yaml.clone()) {
ralexstokes marked this conversation as resolved.
Show resolved Hide resolved
Ok(blob) => blob,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let commitment = match serde_yaml::from_value(commitment_yaml.clone()) {
Ok(commitment) => commitment,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let proof = match serde_yaml::from_value(proof_yaml.clone()) {
Ok(proof) => proof,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let result = verify_blob_kzg_proof(&blob, &commitment, &proof, kzg_settings);
if let Some(expected_validity) = output {
if expected_validity {
assert!(result.is_ok());
Ok(())
} else {
assert!(result.is_err());
Ok(())
}
} else {
let result = verify_blob_kzg_proof(&blob, &commitment, &proof, kzg_settings);
ralexstokes marked this conversation as resolved.
Show resolved Hide resolved
assert!(result.is_err());
Ok(())
}
}

fn run_verify_blob_kzg_proof_batch_test(
test: &TestCase,
kzg_settings: &KzgSettings,
) -> Result<(), Error> {
let path = &test.data_path;
let path = path.to_string() + "/data.yaml";
let test_data: serde_yaml::Value = load_yaml(&path);
let input_yaml = test_data.get("input").unwrap();
let blobs_yaml = input_yaml.get("blobs").unwrap();
let commitments_yaml = input_yaml.get("commitments").unwrap();
let proofs_yaml = input_yaml.get("proofs").unwrap();
let output_yaml = test_data.get("output").unwrap();
let output: Option<bool> = serde_yaml::from_value(output_yaml.clone()).unwrap();

let blobs: Vec<Blob> = match serde_yaml::from_value(blobs_yaml.clone()) {
Ok(blobs) => blobs,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};
let commitments: Vec<KzgCommitment> = match serde_yaml::from_value(commitments_yaml.clone()) {
Ok(commitments) => commitments,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};
let proofs: Vec<KzgProof> = match serde_yaml::from_value(proofs_yaml.clone()) {
Ok(proofs) => proofs,
Err(_) => {
assert!(output.is_none());
return Ok(());
}
};

let result = verify_blob_kzg_proof_batch(&blobs, &commitments, &proofs, kzg_settings);
if let Some(expected_validity) = output {
if expected_validity {
assert!(result.is_ok());
Ok(())
} else {
assert!(result.is_err());
Ok(())
}
} else {
let result = verify_blob_kzg_proof_batch(&blobs, &commitments, &proofs, kzg_settings);
ralexstokes marked this conversation as resolved.
Show resolved Hide resolved
assert!(result.is_err());
Ok(())
}
}
1 change: 1 addition & 0 deletions spec-tests/runners/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod epoch_processing;
pub mod finality;
pub mod fork;
pub mod genesis;
pub mod kzg;
pub mod light_client;
pub mod merkle_proof;
pub mod operations;
Expand Down
8 changes: 4 additions & 4 deletions spec-tests/test_case.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
runners::{
bls, epoch_processing, finality, fork, genesis, light_client, merkle_proof, operations,
random, rewards, sanity, shuffling, ssz_static, transition,
bls, epoch_processing, finality, fork, genesis, kzg, light_client, merkle_proof,
operations, random, rewards, sanity, shuffling, ssz_static, transition,
},
test_meta::TestMeta,
Config, Context,
Expand Down Expand Up @@ -29,7 +29,7 @@ impl TestCase {
match self.meta.config {
Config::Mainnet => &self.context.mainnet,
Config::Minimal => &self.context.minimal,
_ => unreachable!(),
Config::General => &self.context.mainnet,
ralexstokes marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -48,8 +48,8 @@ impl TestCase {
Shuffling => shuffling::dispatch(self),
SszStatic => ssz_static::dispatch(self),
Transition => transition::dispatch(self),
Kzg => todo!(),
LightClient => light_client::dispatch(self),
Kzg => kzg::dispatch(self),
MerkleProof => merkle_proof::dispatch(self),
Sync => todo!(),
SszGeneric => unreachable!(),
Expand Down
2 changes: 1 addition & 1 deletion spec-tests/test_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub enum Runner {

impl Runner {
pub fn should_ignore(&self) -> bool {
matches!(self, Self::ForkChoice | Self::Kzg | Self::Sync)
matches!(self, Self::ForkChoice | Self::Sync)
}

// Do not collect these tests.
Expand Down
Loading