From 085bff7539a51248510a2a57fef8d392598669d6 Mon Sep 17 00:00:00 2001 From: jonas pauli Date: Mon, 7 Oct 2024 15:46:45 +0200 Subject: [PATCH 1/5] fix workspace --- Cargo.toml | 2 -- contract-tests/Cargo.toml | 2 +- contracts | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) delete mode 160000 contracts diff --git a/Cargo.toml b/Cargo.toml index bdd14a06..125c86cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ members = [ "eth-types", "contract-tests", "test-utils", - "contracts", ] resolver = "2" @@ -36,7 +35,6 @@ lightclient-circuits = { path = "lightclient-circuits" } test-utils = { path = "test-utils" } eth-types = { path = "eth-types" } -contracts = { path = "contracts" } preprocessor = { path = "preprocessor" } diff --git a/contract-tests/Cargo.toml b/contract-tests/Cargo.toml index 61800d7a..c565f9d6 100644 --- a/contract-tests/Cargo.toml +++ b/contract-tests/Cargo.toml @@ -19,4 +19,4 @@ eth-types = { workspace = true } ssz_rs = { workspace = true } halo2-base = { workspace = true } snark-verifier-sdk = { workspace = true } -contracts = { workspace = true } +contracts = { git = "https://github.com/jonas089/spectre-contracts" } diff --git a/contracts b/contracts deleted file mode 160000 index a430caeb..00000000 --- a/contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a430caeb3678582b73e3ee73b6f001bd9d1e75ca From 1f89e375bd6c0fba084776e86e0ea7d5154b9a1f Mon Sep 17 00:00:00 2001 From: jonas pauli Date: Mon, 7 Oct 2024 17:51:53 +0200 Subject: [PATCH 2/5] hide contract integration tests behind a feature --- Cargo.toml | 3 ++- contract-tests/Cargo.toml | 6 +++++- contract-tests/tests/spectre.rs | 6 ++++++ contract-tests/tests/step_input_encoding.rs | 3 +++ contracts/Cargo.toml | 8 ++++++++ contracts/src/lib.rs | 1 + 6 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 contracts/Cargo.toml create mode 100644 contracts/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 125c86cb..5e4952e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = [ "preprocessor", "eth-types", "contract-tests", - "test-utils", + "test-utils", "contracts", ] resolver = "2" @@ -35,6 +35,7 @@ lightclient-circuits = { path = "lightclient-circuits" } test-utils = { path = "test-utils" } eth-types = { path = "eth-types" } +contracts = { path = "contracts" } preprocessor = { path = "preprocessor" } diff --git a/contract-tests/Cargo.toml b/contract-tests/Cargo.toml index c565f9d6..130fd89a 100644 --- a/contract-tests/Cargo.toml +++ b/contract-tests/Cargo.toml @@ -6,6 +6,11 @@ edition = "2021" [dependencies] ethers = "2.0.10" lightclient-circuits = { workspace = true } +contracts = { path = "../contracts", optional = true } + +[features] +contracts = ["dep:contracts"] + [dev-dependencies] rstest = "0.18.2" @@ -19,4 +24,3 @@ eth-types = { workspace = true } ssz_rs = { workspace = true } halo2-base = { workspace = true } snark-verifier-sdk = { workspace = true } -contracts = { git = "https://github.com/jonas089/spectre-contracts" } diff --git a/contract-tests/tests/spectre.rs b/contract-tests/tests/spectre.rs index a4a316e2..e7a7c2fa 100644 --- a/contract-tests/tests/spectre.rs +++ b/contract-tests/tests/spectre.rs @@ -10,6 +10,7 @@ use std::path::PathBuf; use std::sync::Arc; use contract_tests::make_client; +#[cfg(feature = "contracts")] use contracts::{MockVerifier, Spectre}; use eth_types::{Minimal, LIMB_BITS}; use ethers::core::types::U256; @@ -25,6 +26,8 @@ const SLOTS_PER_SYNC_COMMITTEE_PERIOD: usize = EPOCHS_PER_SYNC_COMMITTEE_PERIOD const FINALITY_THRESHOLD: usize = 20; // ~ 2/3 of 32 #[tokio::test] +#[cfg(feature = "contracts")] + async fn test_deploy_spectre() -> anyhow::Result<()> { let (_anvil_instance, ethclient) = make_client(); let _contract = deploy_spectre_mock_verifiers(ethclient, 0, U256::zero(), 0).await?; @@ -33,6 +36,8 @@ async fn test_deploy_spectre() -> anyhow::Result<()> { #[rstest] #[tokio::test] +#[cfg(feature = "contracts")] + async fn test_contract_initialization_and_first_step( #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] #[exclude("deneb*")] @@ -86,6 +91,7 @@ async fn test_contract_initialization_and_first_step( /// Deploy the Spectre contract using the given ethclient /// Also deploys the step verifier and the update verifier contracts /// and passes their addresses along with the other params to the constructor +#[cfg(feature = "contracts")] async fn deploy_spectre_mock_verifiers( ethclient: Arc, initial_sync_period: usize, diff --git a/contract-tests/tests/step_input_encoding.rs b/contract-tests/tests/step_input_encoding.rs index cf2c2e6c..c929a481 100644 --- a/contract-tests/tests/step_input_encoding.rs +++ b/contract-tests/tests/step_input_encoding.rs @@ -14,11 +14,13 @@ use rstest::rstest; use ssz_rs::Merkleized; use test_utils::read_test_files_and_gen_witness; +#[cfg(feature = "contracts")] abigen!( StepExternal, "../contracts/out/StepExternal.sol/StepExternal.json"; ); +#[cfg(feature = "contracts")] // SyncStepInput type produced by abigen macro matches the solidity struct type impl From> for StepInput { fn from(args: SyncStepArgs) -> Self { @@ -51,6 +53,7 @@ impl From> for StepInput { #[rstest] #[tokio::test] +#[cfg(feature = "contracts")] async fn test_step_instance_commitment_evm_equivalence( #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] #[exclude("deneb*")] diff --git a/contracts/Cargo.toml b/contracts/Cargo.toml new file mode 100644 index 00000000..0002efbc --- /dev/null +++ b/contracts/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "contracts" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/contracts/src/lib.rs b/contracts/src/lib.rs new file mode 100644 index 00000000..f6451284 --- /dev/null +++ b/contracts/src/lib.rs @@ -0,0 +1 @@ +// replace this crate with the actual contracts crate to run integration tests From 5bf07bb68eb82a0360b4d82774861d88c3a454cd Mon Sep 17 00:00:00 2001 From: jonas pauli Date: Mon, 7 Oct 2024 17:55:58 +0200 Subject: [PATCH 3/5] improved crate structure --- contract-tests/tests/spectre.rs | 38 ++++++++++----------- contract-tests/tests/step_input_encoding.rs | 23 +++++++------ contracts/README.md | 4 +++ 3 files changed, 36 insertions(+), 29 deletions(-) create mode 100644 contracts/README.md diff --git a/contract-tests/tests/spectre.rs b/contract-tests/tests/spectre.rs index e7a7c2fa..8d1ae38d 100644 --- a/contract-tests/tests/spectre.rs +++ b/contract-tests/tests/spectre.rs @@ -6,28 +6,30 @@ * These are the highest level integration tests for the Spectre protocol * They treat the Spectre contract as an ethereum light-client and test against the spec */ -use std::path::PathBuf; -use std::sync::Arc; -use contract_tests::make_client; #[cfg(feature = "contracts")] -use contracts::{MockVerifier, Spectre}; -use eth_types::{Minimal, LIMB_BITS}; -use ethers::core::types::U256; -use ethers::providers::Middleware; -use halo2_base::halo2_proofs::halo2curves::bn256::Fr; -use lightclient_circuits::sync_step_circuit::StepCircuit; -use rstest::rstest; -use test_utils::{get_initial_sync_committee_poseidon, read_test_files_and_gen_witness}; - -const SLOTS_PER_EPOCH: usize = 8; -const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: usize = 8; -const SLOTS_PER_SYNC_COMMITTEE_PERIOD: usize = EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH; -const FINALITY_THRESHOLD: usize = 20; // ~ 2/3 of 32 +mod contract_integration { + use std::path::PathBuf; + use std::sync::Arc; + + use contract_tests::make_client; + use contracts::{MockVerifier, Spectre}; + use eth_types::{Minimal, LIMB_BITS}; + use ethers::core::types::U256; + use ethers::providers::Middleware; + use halo2_base::halo2_proofs::halo2curves::bn256::Fr; + use lightclient_circuits::sync_step_circuit::StepCircuit; + use rstest::rstest; + use test_utils::{get_initial_sync_committee_poseidon, read_test_files_and_gen_witness}; + const SLOTS_PER_EPOCH: usize = 8; + const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: usize = 8; + const SLOTS_PER_SYNC_COMMITTEE_PERIOD: usize = + EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH; + const FINALITY_THRESHOLD: usize = 20; // ~ 2/3 of 32 +} #[tokio::test] #[cfg(feature = "contracts")] - async fn test_deploy_spectre() -> anyhow::Result<()> { let (_anvil_instance, ethclient) = make_client(); let _contract = deploy_spectre_mock_verifiers(ethclient, 0, U256::zero(), 0).await?; @@ -37,7 +39,6 @@ async fn test_deploy_spectre() -> anyhow::Result<()> { #[rstest] #[tokio::test] #[cfg(feature = "contracts")] - async fn test_contract_initialization_and_first_step( #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] #[exclude("deneb*")] @@ -82,7 +83,6 @@ async fn test_contract_initialization_and_first_step( contract.execution_payload_roots(head).call().await?, step_input.execution_payload_root ); - Ok(()) } diff --git a/contract-tests/tests/step_input_encoding.rs b/contract-tests/tests/step_input_encoding.rs index c929a481..26be4dfc 100644 --- a/contract-tests/tests/step_input_encoding.rs +++ b/contract-tests/tests/step_input_encoding.rs @@ -2,17 +2,20 @@ // Code: https://github.com/ChainSafe/Spectre // SPDX-License-Identifier: LGPL-3.0-only -use std::ops::Deref; -use std::path::PathBuf; +#[cfg(feature = "contracts")] +mod contract_integration { + use std::ops::Deref; + use std::path::PathBuf; -use contract_tests::make_client; -use eth_types::{Minimal, LIMB_BITS}; -use ethers::contract::abigen; -use lightclient_circuits::halo2_proofs::halo2curves::bn256; -use lightclient_circuits::witness::SyncStepArgs; -use rstest::rstest; -use ssz_rs::Merkleized; -use test_utils::read_test_files_and_gen_witness; + use contract_tests::make_client; + use eth_types::{Minimal, LIMB_BITS}; + use ethers::contract::abigen; + use lightclient_circuits::halo2_proofs::halo2curves::bn256; + use lightclient_circuits::witness::SyncStepArgs; + use rstest::rstest; + use ssz_rs::Merkleized; + use test_utils::read_test_files_and_gen_witness; +} #[cfg(feature = "contracts")] abigen!( diff --git a/contracts/README.md b/contracts/README.md new file mode 100644 index 00000000..8d1dd211 --- /dev/null +++ b/contracts/README.md @@ -0,0 +1,4 @@ +# Running smart contract integration tests +When running the Spectre smart contract integration tests, replace this crate with [this crate](https://github.com/ChainSafe/spectre-contracts/tree/a430caeb3678582b73e3ee73b6f001bd9d1e75ca) + +Additionally make sure to enable the `contracts` feature when running tests against the real contracts crate. \ No newline at end of file From 589b7c2ca44816b7d4126b73a9d236a021309218 Mon Sep 17 00:00:00 2001 From: jonas pauli Date: Tue, 15 Oct 2024 20:46:27 +0200 Subject: [PATCH 4/5] fix deps --- Cargo.toml | 31 +--- lightclient-circuits/Cargo.toml | 3 +- .../config/committee_update_20.json | 2 +- lightclient-circuits/proof.txt | Bin 0 -> 23624 bytes .../src/committee_update_circuit.rs | 174 +++++++++++++++--- lightclient-circuits/vk.txt | Bin 0 -> 263631 bytes 6 files changed, 157 insertions(+), 53 deletions(-) create mode 100644 lightclient-circuits/proof.txt create mode 100644 lightclient-circuits/vk.txt diff --git a/Cargo.toml b/Cargo.toml index 5e4952e4..290d9b51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,8 @@ members = [ "preprocessor", "eth-types", "contract-tests", - "test-utils", "contracts", + "test-utils", + "contracts", ] resolver = "2" @@ -38,18 +39,13 @@ eth-types = { path = "eth-types" } contracts = { path = "contracts" } preprocessor = { path = "preprocessor" } - -# halo2 -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", tag = "v0.4.1", default-features = false, features = [ - "halo2-pse", - "display", - "jemallocator", -] } -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", tag = "v0.4.1", default-features = false } -zkevm-hashes = { git = "https://github.com/axiom-crypto/halo2-lib", tag = "v0.4.1", default-features = false } - halo2curves = { package = "halo2curves-axiom", version = "=0.5.2" } +ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } +halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } + # verifier SDK snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.7-git", default-features = false, features = [ "display", @@ -68,7 +64,6 @@ snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git # ethereum types ethereum-consensus-types = { git = "https://github.com/ChainSafe/ethereum-consensus-types", branch = "capella" } beacon-api-client = { git = "https://github.com/ralexstokes/ethereum-consensus.git", rev = "f3bff52e9c43866f231ec40c8ab0e34125a8957f" } -ssz_rs = "0.9" # crypto group = "0.13" @@ -86,15 +81,3 @@ getset = "0.1.2" log = "0.4.14" hex = "0.4" ark-std = { version = "0.4.0", features = ["print-trace"] } - - -[patch.crates-io] -ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } -halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } -halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } -zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } - -[patch."https://github.com/axiom-crypto/halo2-lib"] -halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } -halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } -zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } diff --git a/lightclient-circuits/Cargo.toml b/lightclient-circuits/Cargo.toml index fa18d720..4083ce3e 100644 --- a/lightclient-circuits/Cargo.toml +++ b/lightclient-circuits/Cargo.toml @@ -26,7 +26,7 @@ pse-poseidon = { git = "https://github.com/axiom-crypto/pse-poseidon.git" } # ethereum ssz_rs = { workspace = true, features = ["serde"] } -ethereum-consensus-types ={ workspace = true, features = ["serde"] } +ethereum-consensus-types = { workspace = true, features = ["serde"] } # local eth-types.workspace = true @@ -46,6 +46,7 @@ rand = "0.8" lazy_static = "1.4" getset = "0.1.2" rand_chacha = "0.3.0" +bincode = "1.3.3" [dev-dependencies] rstest = "0.18.2" diff --git a/lightclient-circuits/config/committee_update_20.json b/lightclient-circuits/config/committee_update_20.json index 4bea29b8..0b9df49b 100644 --- a/lightclient-circuits/config/committee_update_20.json +++ b/lightclient-circuits/config/committee_update_20.json @@ -6,7 +6,7 @@ ], "num_fixed": 1, "num_lookup_advice_per_phase": [ - 1, + 0, 0, 0 ], diff --git a/lightclient-circuits/proof.txt b/lightclient-circuits/proof.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c15d6449accc93ff0044ca0940d85ef963e6013 GIT binary patch literal 23624 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 fBNiw;N3iFI_jK#!dTeNdol { _f: PhantomData, @@ -268,25 +268,57 @@ impl AppCircuit for CommitteeUpdateCircuit { #[cfg(test)] mod tests { - use std::fs; + fn write_struct_to_file(data: &T, file_path: &str) -> IoResult<()> { + let encoded: Vec = bincode::serialize(data).expect("Failed to serialize"); + let mut file = File::create(file_path)?; + file.write_all(&encoded)?; + Ok(()) + } + + fn read_struct_from_file Deserialize<'de>>(file_path: &str) -> IoResult { + let mut file = File::open(file_path)?; + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer)?; + + // Deserialization can use the buffer's data, no lifetime issue + let decoded: T = bincode::deserialize(&buffer) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?; + + Ok(decoded) + } + use std::{fs, io::Cursor}; use crate::{ - aggregation_circuit::AggregationConfigPinning, util::Halo2ConfigPinning, - witness::CommitteeUpdateArgs, + aggregation_circuit::AggregationConfigPinning, gadget::crypto::ShaFlexGateManager, + util::Halo2ConfigPinning, witness::CommitteeUpdateArgs, }; use super::*; - use ark_std::{end_timer, start_timer}; + use bn256::G1Affine; use eth_types::Testnet; + use ff::Field; use halo2_base::{ + gates::circuit::{builder::BaseCircuitBuilder, BaseCircuitParams}, halo2_proofs::{ - dev::MockProver, halo2curves::bn256::Fr, - plonk::ProvingKey, - poly::{commitment::Params, kzg::commitment::ParamsKZG}, + plonk::{create_proof, keygen_vk, verify_proof, Circuit, ProvingKey, VerifyingKey}, + poly::{ + commitment::Params, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + VerificationStrategy, + }, + transcript::{ + Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, + TranscriptWriterBuffer, + }, }, utils::fs::gen_srs, }; + use rand::rngs::OsRng; use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk}; use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, CircuitExt, Snark}; @@ -311,25 +343,113 @@ mod tests { } #[test] - fn test_committee_update_circuit() { + fn test_prove_and_verify_plonk() { const K: u32 = 20; + let mut file = File::open("./params/kzg_bn254_20.srs").expect("Failed to open params!"); + + let mut buffer = Vec::new(); + + file.read_to_end(&mut buffer) + .expect("Failed to read params!"); + + let params: ParamsKZG = + ParamsKZG::read(&mut Cursor::new(&buffer)).expect("Failed to read buffer :("); + + const PINNING_PATH: &str = "./config/committee_update_20.json"; + const PKEY_PATH: &str = "../build/committee_update_20.pkey"; + + let pk = CommitteeUpdateCircuit::::create_pk( + ¶ms, + PKEY_PATH, + PINNING_PATH, + &CommitteeUpdateArgs::::default(), + None, + ); + + println!("[Ok] Proving Key"); + let witness = load_circuit_args(); - let params: ParamsKZG = gen_srs(K); let circuit = CommitteeUpdateCircuit::::create_circuit( - CircuitBuilderStage::Mock, - None, + CircuitBuilderStage::Prover, + Some(Eth2ConfigPinning::from_path(PINNING_PATH)), &witness, ¶ms, ) - .unwrap(); + .expect("Failed to construct circuit"); + + println!("[Ok] Construct Circuit"); + + let reader: Vec = vec![]; + let mut transcript_writer: Blake2bWrite, G1Affine, Challenge255> = + Blake2bWrite::init(reader); + println!("[Ok] Read Transcript"); + + let vk: &VerifyingKey = pk.get_vk(); + + let circuit_params = circuit.params(); + //let vk_serialized = vk.to_bytes(halo2_base::halo2_proofs::SerdeFormat::RawBytes); + + let witness_serialized = bincode::serialize(&witness).unwrap(); + let witness_deserialized: CommitteeUpdateArgs = + bincode::deserialize(&witness_serialized).unwrap(); + + /* + let instances = circuit.instances(); + let instances_ref: Vec<&[Fr]> = instances.iter().map(|inner| inner.as_slice()).collect(); + let instances_nested_ref: Vec<&[&[Fr]]> = instances_ref + .iter() + .map(|inner| std::slice::from_ref(inner)) + .collect(); + + create_proof::< + KZGCommitmentScheme, + ProverSHPLONK, + Challenge255, + OsRng, + Blake2bWrite, G1Affine, Challenge255>, + _, + >( + ¶ms, + &pk, + &[circuit], + &instances_nested_ref, + OsRng, + &mut transcript_writer, + ) + .expect("Failed to generate proof!"); + + let reader_final = transcript_writer.finalize(); - let instance = CommitteeUpdateCircuit::::get_instances(&witness, LIMB_BITS); + println!("[Ok] Proof"); + + let mut transcript_reader = Blake2bRead::init(&reader_final[..]); + + write_struct_to_file(&reader_final, "proof.txt").expect("Failed to write proof"); + write_struct_to_file(&instances, "instances.txt").expect("Failed to write instances"); + write_struct_to_file( + &vk.to_bytes(halo2_base::halo2_proofs::SerdeFormat::RawBytes), + "vk.txt", + ) + .expect("Failed to write vk"); + + verify_proof::< + _, + VerifierSHPLONK, + Challenge255, + Blake2bRead<_, G1Affine, Challenge255>, + SingleStrategy, + >( + ¶ms, + &vk, + SingleStrategy::new(¶ms), + &instances_nested_ref, + &mut transcript_reader, + ) + .expect("Failed to verify!"); - let timer = start_timer!(|| "committee_update mock prover"); - let prover = MockProver::::run(K, &circuit, instance).unwrap(); - prover.assert_satisfied(); - end_timer!(timer); + println!("[Yippie]"); + */ } #[test] diff --git a/lightclient-circuits/vk.txt b/lightclient-circuits/vk.txt new file mode 100644 index 0000000000000000000000000000000000000000..81ae5bae2acdb69e803238c785c59c47c9f861f1 GIT binary patch literal 263631 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%0Ap)(mU4>1oh4}E{^r>+k}q%--(|tnn6p zU&}?QId>2uQKz3;@%>Cb^U#?VvhDTNGw_8eLQNwk11Kg#Eb8=AE54sOKG!8glVK?z zreKWJ9fZyAD{K&x1v#!H7f^VqY6pwAmwGp6x37#>`>TPk-QsMd0;oaK4+--S^ANq~ za!sh)e?vm~YKP2?j5w@3WaXh0h@#@Tvm=$(RLCjpX1Ex;#aGs6`dkT2I>MqfSnPZd zlfv>|h#sf-PMr}cj)e3j7>z*1{tg$+L+2V`9!6-AwL`^iMFUW4bXjM~f{K^)IK_AB zj7Z5pB+NtSI?FD}S82jL6fhmOkre>;5CSq(O|&7Q6v4?;6)!$hK#$~Ww>TT=aZ*5M zVjep4fR%?d(V=gm4J~HJf{M6?iYCtm_6R+D$f+7C8LVeh zn6gqoH_XFC2$Wz&3tyUu665ka<{{?cA)O;LnL?y9F%KO&IOG&i7aa3Yh>B3DrgSL> zC8nT^Kq1nZIhiKgi{DuGwW^CXqbVw}L(L470*55e#U%qVc4vk>GdgHG=%Qa>mqN3} z$fhu5rG9e7C5nugpZuJOxtZEaMutGGpln7v@s?A{+5BN+qkQN04~u`!&&ZH(nO;;a zn*2{Kr1>}Fhx>g)*_^14BTG^^dF`Z!Ag`QvRd@#h5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH O0T2KI5CDPHLf}87gJY=x literal 0 HcmV?d00001 From 7b9c8fe169386049479719a977ab91a92a0c26f5 Mon Sep 17 00:00:00 2001 From: jonas pauli Date: Fri, 18 Oct 2024 22:12:58 +0200 Subject: [PATCH 5/5] revert unwanted changes --- Cargo.toml | 28 ++- contracts/src/lib.rs | 12 +- lightclient-circuits/proof.txt | Bin 23624 -> 0 bytes .../src/committee_update_circuit.rs | 174 +++--------------- lightclient-circuits/vk.txt | Bin 263631 -> 0 bytes 5 files changed, 61 insertions(+), 153 deletions(-) delete mode 100644 lightclient-circuits/proof.txt delete mode 100644 lightclient-circuits/vk.txt diff --git a/Cargo.toml b/Cargo.toml index 290d9b51..bdd14a06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,12 +39,17 @@ eth-types = { path = "eth-types" } contracts = { path = "contracts" } preprocessor = { path = "preprocessor" } -halo2curves = { package = "halo2curves-axiom", version = "=0.5.2" } -ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } -halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } -halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } -zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +# halo2 +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", tag = "v0.4.1", default-features = false, features = [ + "halo2-pse", + "display", + "jemallocator", +] } +halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", tag = "v0.4.1", default-features = false } +zkevm-hashes = { git = "https://github.com/axiom-crypto/halo2-lib", tag = "v0.4.1", default-features = false } + +halo2curves = { package = "halo2curves-axiom", version = "=0.5.2" } # verifier SDK snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.7-git", default-features = false, features = [ @@ -64,6 +69,7 @@ snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git # ethereum types ethereum-consensus-types = { git = "https://github.com/ChainSafe/ethereum-consensus-types", branch = "capella" } beacon-api-client = { git = "https://github.com/ralexstokes/ethereum-consensus.git", rev = "f3bff52e9c43866f231ec40c8ab0e34125a8957f" } +ssz_rs = "0.9" # crypto group = "0.13" @@ -81,3 +87,15 @@ getset = "0.1.2" log = "0.4.14" hex = "0.4" ark-std = { version = "0.4.0", features = ["print-trace"] } + + +[patch.crates-io] +ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } +halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } + +[patch."https://github.com/axiom-crypto/halo2-lib"] +halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } diff --git a/contracts/src/lib.rs b/contracts/src/lib.rs index f6451284..97ff96c1 100644 --- a/contracts/src/lib.rs +++ b/contracts/src/lib.rs @@ -1 +1,11 @@ -// replace this crate with the actual contracts crate to run integration tests +/* + As a user looking to run contract integration tests it is recommended + that you delete this crate (the 'contracts' crate) and replace it with + the contracts crate found here: + + https://github.com/ChainSafe/spectre-contracts/tree/a430caeb3678582b73e3ee73b6f001bd9d1e75ca + + To run the contract integration tests afterwards, run: + + cargo test -- --features contracts +*/ diff --git a/lightclient-circuits/proof.txt b/lightclient-circuits/proof.txt deleted file mode 100644 index 0c15d6449accc93ff0044ca0940d85ef963e6013..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23624 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 fBNiw;N3iFI_jK#!dTeNdol { _f: PhantomData, @@ -268,57 +268,25 @@ impl AppCircuit for CommitteeUpdateCircuit { #[cfg(test)] mod tests { - fn write_struct_to_file(data: &T, file_path: &str) -> IoResult<()> { - let encoded: Vec = bincode::serialize(data).expect("Failed to serialize"); - let mut file = File::create(file_path)?; - file.write_all(&encoded)?; - Ok(()) - } - - fn read_struct_from_file Deserialize<'de>>(file_path: &str) -> IoResult { - let mut file = File::open(file_path)?; - let mut buffer = Vec::new(); - file.read_to_end(&mut buffer)?; - - // Deserialization can use the buffer's data, no lifetime issue - let decoded: T = bincode::deserialize(&buffer) - .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?; - - Ok(decoded) - } - use std::{fs, io::Cursor}; + use std::fs; use crate::{ - aggregation_circuit::AggregationConfigPinning, gadget::crypto::ShaFlexGateManager, - util::Halo2ConfigPinning, witness::CommitteeUpdateArgs, + aggregation_circuit::AggregationConfigPinning, util::Halo2ConfigPinning, + witness::CommitteeUpdateArgs, }; use super::*; - use bn256::G1Affine; + use ark_std::{end_timer, start_timer}; use eth_types::Testnet; - use ff::Field; use halo2_base::{ - gates::circuit::{builder::BaseCircuitBuilder, BaseCircuitParams}, halo2_proofs::{ + dev::MockProver, halo2curves::bn256::Fr, - plonk::{create_proof, keygen_vk, verify_proof, Circuit, ProvingKey, VerifyingKey}, - poly::{ - commitment::Params, - kzg::{ - commitment::{KZGCommitmentScheme, ParamsKZG}, - multiopen::{ProverSHPLONK, VerifierSHPLONK}, - strategy::SingleStrategy, - }, - VerificationStrategy, - }, - transcript::{ - Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, - TranscriptWriterBuffer, - }, + plonk::ProvingKey, + poly::{commitment::Params, kzg::commitment::ParamsKZG}, }, utils::fs::gen_srs, }; - use rand::rngs::OsRng; use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk}; use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, CircuitExt, Snark}; @@ -343,113 +311,25 @@ mod tests { } #[test] - fn test_prove_and_verify_plonk() { + fn test_committee_update_circuit() { const K: u32 = 20; - let mut file = File::open("./params/kzg_bn254_20.srs").expect("Failed to open params!"); - - let mut buffer = Vec::new(); - - file.read_to_end(&mut buffer) - .expect("Failed to read params!"); - - let params: ParamsKZG = - ParamsKZG::read(&mut Cursor::new(&buffer)).expect("Failed to read buffer :("); - - const PINNING_PATH: &str = "./config/committee_update_20.json"; - const PKEY_PATH: &str = "../build/committee_update_20.pkey"; - - let pk = CommitteeUpdateCircuit::::create_pk( - ¶ms, - PKEY_PATH, - PINNING_PATH, - &CommitteeUpdateArgs::::default(), - None, - ); - - println!("[Ok] Proving Key"); - let witness = load_circuit_args(); + let params: ParamsKZG = gen_srs(K); let circuit = CommitteeUpdateCircuit::::create_circuit( - CircuitBuilderStage::Prover, - Some(Eth2ConfigPinning::from_path(PINNING_PATH)), + CircuitBuilderStage::Mock, + None, &witness, ¶ms, ) - .expect("Failed to construct circuit"); - - println!("[Ok] Construct Circuit"); - - let reader: Vec = vec![]; - let mut transcript_writer: Blake2bWrite, G1Affine, Challenge255> = - Blake2bWrite::init(reader); - println!("[Ok] Read Transcript"); - - let vk: &VerifyingKey = pk.get_vk(); - - let circuit_params = circuit.params(); - //let vk_serialized = vk.to_bytes(halo2_base::halo2_proofs::SerdeFormat::RawBytes); - - let witness_serialized = bincode::serialize(&witness).unwrap(); - let witness_deserialized: CommitteeUpdateArgs = - bincode::deserialize(&witness_serialized).unwrap(); - - /* - let instances = circuit.instances(); - let instances_ref: Vec<&[Fr]> = instances.iter().map(|inner| inner.as_slice()).collect(); - let instances_nested_ref: Vec<&[&[Fr]]> = instances_ref - .iter() - .map(|inner| std::slice::from_ref(inner)) - .collect(); - - create_proof::< - KZGCommitmentScheme, - ProverSHPLONK, - Challenge255, - OsRng, - Blake2bWrite, G1Affine, Challenge255>, - _, - >( - ¶ms, - &pk, - &[circuit], - &instances_nested_ref, - OsRng, - &mut transcript_writer, - ) - .expect("Failed to generate proof!"); - - let reader_final = transcript_writer.finalize(); - - println!("[Ok] Proof"); - - let mut transcript_reader = Blake2bRead::init(&reader_final[..]); + .unwrap(); - write_struct_to_file(&reader_final, "proof.txt").expect("Failed to write proof"); - write_struct_to_file(&instances, "instances.txt").expect("Failed to write instances"); - write_struct_to_file( - &vk.to_bytes(halo2_base::halo2_proofs::SerdeFormat::RawBytes), - "vk.txt", - ) - .expect("Failed to write vk"); - - verify_proof::< - _, - VerifierSHPLONK, - Challenge255, - Blake2bRead<_, G1Affine, Challenge255>, - SingleStrategy, - >( - ¶ms, - &vk, - SingleStrategy::new(¶ms), - &instances_nested_ref, - &mut transcript_reader, - ) - .expect("Failed to verify!"); + let instance = CommitteeUpdateCircuit::::get_instances(&witness, LIMB_BITS); - println!("[Yippie]"); - */ + let timer = start_timer!(|| "committee_update mock prover"); + let prover = MockProver::::run(K, &circuit, instance).unwrap(); + prover.assert_satisfied(); + end_timer!(timer); } #[test] diff --git a/lightclient-circuits/vk.txt b/lightclient-circuits/vk.txt deleted file mode 100644 index 81ae5bae2acdb69e803238c785c59c47c9f861f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 263631 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%0Ap)(mU4>1oh4}E{^r>+k}q%--(|tnn6p zU&}?QId>2uQKz3;@%>Cb^U#?VvhDTNGw_8eLQNwk11Kg#Eb8=AE54sOKG!8glVK?z zreKWJ9fZyAD{K&x1v#!H7f^VqY6pwAmwGp6x37#>`>TPk-QsMd0;oaK4+--S^ANq~ za!sh)e?vm~YKP2?j5w@3WaXh0h@#@Tvm=$(RLCjpX1Ex;#aGs6`dkT2I>MqfSnPZd zlfv>|h#sf-PMr}cj)e3j7>z*1{tg$+L+2V`9!6-AwL`^iMFUW4bXjM~f{K^)IK_AB zj7Z5pB+NtSI?FD}S82jL6fhmOkre>;5CSq(O|&7Q6v4?;6)!$hK#$~Ww>TT=aZ*5M zVjep4fR%?d(V=gm4J~HJf{M6?iYCtm_6R+D$f+7C8LVeh zn6gqoH_XFC2$Wz&3tyUu665ka<{{?cA)O;LnL?y9F%KO&IOG&i7aa3Yh>B3DrgSL> zC8nT^Kq1nZIhiKgi{DuGwW^CXqbVw}L(L470*55e#U%qVc4vk>GdgHG=%Qa>mqN3} z$fhu5rG9e7C5nugpZuJOxtZEaMutGGpln7v@s?A{+5BN+qkQN04~u`!&&ZH(nO;;a zn*2{Kr1>}Fhx>g)*_^14BTG^^dF`Z!Ag`QvRd@#h5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH O0T2KI5CDPHLf}87gJY=x