From 915a593db38da25fec3f3831ede93c4188f4e298 Mon Sep 17 00:00:00 2001 From: timofey Date: Thu, 30 Nov 2023 15:46:48 +0100 Subject: [PATCH] Fix RPC handlers (#34) * WIP * update version in circuits crate * fix step circuit * fix sha wide chip gate * fix prover * fix proofgen * fix instance gen & refactor * fix prover rpc * fix some tests * switch to remote deps * rename circuit files * refactor * rename circuit files back (to merge main) * post merge fixes * fixes * fmt * wip * remove redundant * fix endianness * remove redundant tests * cargo fix + fmt * rename config files * fix * cargo fmt * switch to https://github.com/ChainSafe/ethereum-consensus-types (#35) * CLI wip * add requirements to readme * simplify cli * fix CI tests * fix paths * fmt + fix --- Cargo.toml | 23 +- README.md | 3 + justfile | 14 +- .../config/committee_update_testnet.json | 31 ++ .../committee_update_verifier_testnet.json | 12 + lightclient-circuits/config/sync_step_20.json | 40 ++ .../config/sync_step_testnet.json | 25 ++ lightclient-circuits/src/lib.rs | 3 +- lightclient-circuits/src/witness/rotation.rs | 58 ++- lightclient-circuits/src/witness/sync.rs | 21 +- lightclient-circuits/tests/step.rs | 11 +- preprocessor/Cargo.toml | 3 +- preprocessor/src/lib.rs | 5 +- preprocessor/src/sync.rs | 2 +- prover/src/args.rs | 109 +++--- prover/src/cli.rs | 340 ++++++----------- prover/src/main.rs | 53 +-- prover/src/rpc.rs | 344 ++++++++---------- prover/src/rpc_api.rs | 6 - prover/src/rpc_client.rs | 4 +- test-utils/Cargo.toml | 7 +- test-utils/src/lib.rs | 116 ++---- 22 files changed, 557 insertions(+), 673 deletions(-) create mode 100644 lightclient-circuits/config/committee_update_testnet.json create mode 100644 lightclient-circuits/config/committee_update_verifier_testnet.json create mode 100644 lightclient-circuits/config/sync_step_20.json create mode 100644 lightclient-circuits/config/sync_step_testnet.json diff --git a/Cargo.toml b/Cargo.toml index b72e7da0..9ff504ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,13 @@ [workspace] -members = ["lightclient-circuits", "prover", "preprocessor", "eth-types", "contract-tests", "test-utils", "contracts"] +members = [ + "lightclient-circuits", + "prover", + "preprocessor", + "eth-types", + "contract-tests", + "test-utils", + "contracts", +] resolver = "2" @@ -36,7 +44,7 @@ preprocessor = { path = "preprocessor" } halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false, features = [ "halo2-pse", "display", - "jemallocator" + "jemallocator", ] } halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } zkevm-hashes = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } @@ -60,10 +68,7 @@ snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git halo2_solidity_verifier = { git = "https://github.com/privacy-scaling-explorations/halo2-solidity-verifier", branch = "ac/initial-verifier-PR" } # ethereum types -ethereum-consensus-types = { git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "5ecf28d24690862814a7ebc5385c7e5c2eeb6e3d" } -zipline-test-utils = { package = "test-utils", git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "5ecf28d24690862814a7ebc5385c7e5c2eeb6e3d" } -zipline-cryptography = { package = "cryptography", git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "5ecf28d24690862814a7ebc5385c7e5c2eeb6e3d" } -light-client-verifier = { git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "5ecf28d24690862814a7ebc5385c7e5c2eeb6e3d" } +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" @@ -84,7 +89,7 @@ log = "0.4.14" hex = "0.4" [patch.crates-io] -halo2curves = { git = "https://github.com/timoftime/halo2curves", package = "halo2curves-axiom", rev = "f3bb3f5a7d3a8ca806368f185c112283a73a94cb" } +halo2curves = { git = "https://github.com/timoftime/halo2curves", package = "halo2curves-axiom", rev = "f3bb3f5a7d3a8ca806368f185c112283a73a94cb" } ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } @@ -92,11 +97,11 @@ ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa0 halo2-base = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/zkevm-sha256-builder", default-features = false, features = [ "halo2-pse", "display", - "jemallocator" + "jemallocator", ] } halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/zkevm-sha256-builder", default-features = false, features = [ "halo2-pse", - "jemallocator" + "jemallocator", ] } zkevm-hashes = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/zkevm-sha256-builder", default-features = false } # halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ diff --git a/README.md b/README.md index 78d7ab73..489fbabe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # Spectre Spectre is a ZK-based block header oracle protocol based on Altair fork light-client sync protocol. +## Requirements +- `build-essential clang pkg-config libssl-dev` + ## Deploying contracts Just scripts are provided to deploy the contracts either to a local testnet, or public networks. diff --git a/justfile b/justfile index 3773303f..fd77373a 100644 --- a/justfile +++ b/justfile @@ -13,14 +13,12 @@ check: lint: fmt cargo clippy --all-targets --all-features --workspace -setup-step-circuit: - cargo run -r -- circuit sync-step -c ./lightclient-circuits/config/sync_step.json -o artifacts -k 22 - -setup-rotation-circuit: - cargo run -r -- circuit committee-update -c ./lightclient-circuits/config/committee_update.json -o artifacts -k 18 - # TODO: generate committee-update snark - cargo run -r -- circuit aggregation -c ./lightclient-circuits/config/aggregation.json --app-pk-path \ - ./build/committee_update.pkey --app-config-path ./lightclient-circuits/config/committee_update.json -i ./rotation -o artifacts -k 22 +setup-step network: + cargo run -r -- circuit sync-step -p ./build/sync_step_$1.pkey -k 22 setup + +setup-committee-update network: + cargo run -r -- circuit committee-update -p ./build/committee_update_$1.pkey -k 18 \ + --verifier-k 25 --verifier-pk-path ./build/committee_update_verifier_$1.pkey setup gen-step-evm-verifier: cargo run -r -- circuit sync-step -c ./lightclient-circuits/config/sync_step.json -o evm-verifier ./contracts/snark-verifiers/sync_step.yul diff --git a/lightclient-circuits/config/committee_update_testnet.json b/lightclient-circuits/config/committee_update_testnet.json new file mode 100644 index 00000000..f4f64d68 --- /dev/null +++ b/lightclient-circuits/config/committee_update_testnet.json @@ -0,0 +1,31 @@ +{ + "params": { + "k": 18, + "num_advice_per_phase": [ + 12 + ], + "num_fixed": 1, + "num_lookup_advice_per_phase": [ + 1, + 0, + 0 + ], + "lookup_bits": 8, + "num_instance_columns": 1 + }, + "break_points": [ + [ + 262134, + 262132, + 262134, + 262132, + 262133, + 262132, + 262132, + 262133, + 262132, + 262134, + 262133 + ] + ] +} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_verifier_testnet.json b/lightclient-circuits/config/committee_update_verifier_testnet.json new file mode 100644 index 00000000..88107546 --- /dev/null +++ b/lightclient-circuits/config/committee_update_verifier_testnet.json @@ -0,0 +1,12 @@ +{ + "params": { + "degree": 25, + "num_advice": 1, + "num_lookup_advice": 1, + "num_fixed": 1, + "lookup_bits": 8 + }, + "break_points": [ + [] + ] +} \ No newline at end of file diff --git a/lightclient-circuits/config/sync_step_20.json b/lightclient-circuits/config/sync_step_20.json new file mode 100644 index 00000000..5e5db520 --- /dev/null +++ b/lightclient-circuits/config/sync_step_20.json @@ -0,0 +1,40 @@ +{ + "params": { + "k": 20, + "num_advice_per_phase": [ + 21 + ], + "num_fixed": 1, + "num_lookup_advice_per_phase": [ + 3, + 0, + 0 + ], + "lookup_bits": 8, + "num_instance_columns": 1 + }, + "break_points": [ + [ + 1048565, + 1048564, + 1048566, + 1048565, + 1048565, + 1048566, + 1048566, + 1048566, + 1048564, + 1048565, + 1048566, + 1048564, + 1048566, + 1048566, + 1048564, + 1048564, + 1048566, + 1048564, + 1048566, + 1048566 + ] + ] +} \ No newline at end of file diff --git a/lightclient-circuits/config/sync_step_testnet.json b/lightclient-circuits/config/sync_step_testnet.json new file mode 100644 index 00000000..c430ae66 --- /dev/null +++ b/lightclient-circuits/config/sync_step_testnet.json @@ -0,0 +1,25 @@ +{ + "params": { + "k": 22, + "num_advice_per_phase": [ + 6 + ], + "num_fixed": 1, + "num_lookup_advice_per_phase": [ + 1, + 0, + 0 + ], + "lookup_bits": 8, + "num_instance_columns": 1 + }, + "break_points": [ + [ + 4194292, + 4194294, + 4194292, + 4194293, + 4194293 + ] + ] +} \ No newline at end of file diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 50a15e00..48c2dded 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -7,7 +7,6 @@ #![feature(generic_arg_infer)] #![feature(return_position_impl_trait_in_trait)] #![allow(clippy::needless_range_loop)] - pub mod gadget; pub mod util; pub mod witness; @@ -21,8 +20,8 @@ mod ssz_merkle; pub use halo2_base; pub use halo2_base::halo2_proofs; -use halo2_base::halo2_proofs::halo2curves::bn256; +use halo2_base::halo2_proofs::halo2curves::bn256; #[allow(type_alias_bounds)] pub type Eth2CircuitBuilder> = gadget::crypto::ShaCircuitBuilder; diff --git a/lightclient-circuits/src/witness/rotation.rs b/lightclient-circuits/src/witness/rotation.rs index 309e7a91..72545055 100644 --- a/lightclient-circuits/src/witness/rotation.rs +++ b/lightclient-circuits/src/witness/rotation.rs @@ -2,6 +2,7 @@ use eth_types::Spec; use ethereum_consensus_types::BeaconBlockHeader; use itertools::Itertools; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; use std::{iter, marker::PhantomData}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -17,17 +18,68 @@ pub struct CommitteeRotationArgs { impl Default for CommitteeRotationArgs { fn default() -> Self { - let dummy_x_bytes = iter::once(192).pad_using(48, |_| 0).rev().collect(); + let dummy_x_bytes = iter::once(192).pad_using(48, |_| 0).rev().collect_vec(); - let sync_committee_branch = vec![vec![0; 32]; S::SYNC_COMMITTEE_DEPTH + 1]; + let sync_committee_branch = vec![vec![0; 32]; S::SYNC_COMMITTEE_PUBKEYS_DEPTH]; + + let hashed_pk = sha2::Sha256::digest( + dummy_x_bytes + .iter() + .copied() + .pad_using(64, |_| 0) + .collect_vec(), + ) + .to_vec(); + + assert!(S::SYNC_COMMITTEE_SIZE.is_power_of_two()); + + let mut chunks = vec![hashed_pk; S::SYNC_COMMITTEE_SIZE]; + + while chunks.len() > 1 { + chunks = chunks + .into_iter() + .tuples() + .map(|(left, right)| sha2::Sha256::digest([left, right].concat()).to_vec()) + .collect(); + } + + let committee_root = chunks.pop().unwrap(); + + let state_root = mock_root( + committee_root, + &sync_committee_branch, + S::SYNC_COMMITTEE_PUBKEYS_ROOT_INDEX, + ); Self { pubkeys_compressed: iter::repeat(dummy_x_bytes) .take(S::SYNC_COMMITTEE_SIZE) .collect_vec(), sync_committee_branch, - finalized_header: Default::default(), + finalized_header: BeaconBlockHeader { + state_root: state_root.as_slice().try_into().unwrap(), + ..Default::default() + }, _spec: PhantomData, } } } + +pub(crate) fn mock_root(leaf: Vec, branch: &[Vec], mut gindex: usize) -> Vec { + let mut last_hash = leaf; + + for i in 0..branch.len() { + last_hash = Sha256::digest( + if gindex % 2 == 0 { + [last_hash, branch[i].clone()] + } else { + [branch[i].clone(), last_hash] + } + .concat(), + ) + .to_vec(); + gindex /= 2; + } + + last_hash +} diff --git a/lightclient-circuits/src/witness/sync.rs b/lightclient-circuits/src/witness/sync.rs index dd1d19ad..84400c6c 100644 --- a/lightclient-circuits/src/witness/sync.rs +++ b/lightclient-circuits/src/witness/sync.rs @@ -1,13 +1,13 @@ use eth_types::Spec; -use ethereum_consensus_types; use ethereum_consensus_types::BeaconBlockHeader; use itertools::Itertools; use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; use ssz_rs::Node; use std::iter; use std::marker::PhantomData; +use super::mock_root; + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SyncStepArgs { pub signature_compressed: Vec, @@ -41,20 +41,13 @@ impl Default for SyncStepArgs { .take(S::FINALIZED_HEADER_DEPTH) .collect_vec(); - let compute_root = |leaf: Vec, branch: &[Vec]| -> Vec { - let mut last_hash = Sha256::digest([leaf, branch[0].clone()].concat()).to_vec(); - - for i in 1..branch.len() { - last_hash = Sha256::digest([last_hash, branch[i].clone()].concat()).to_vec(); - } - - last_hash - }; - let execution_state_root = vec![0; 32]; let execution_merkle_branch = vec![vec![0; 32]; S::EXECUTION_STATE_ROOT_DEPTH]; - let beacon_block_body_root = - compute_root(execution_state_root.clone(), &state_merkle_branch); + let beacon_block_body_root = mock_root( + execution_state_root.clone(), + &state_merkle_branch, + S::EXECUTION_STATE_ROOT_INDEX, + ); let finalized_block = BeaconBlockHeader { body_root: Node::try_from(beacon_block_body_root.as_slice()).unwrap(), diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index bbba9385..299f38e7 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -22,16 +22,7 @@ fn test_eth2_spec_mock_1( #[exclude("deneb*")] path: PathBuf, ) { - run_test_eth2_spec_mock::<16, 20>(path) -} - -#[rstest] -fn test_eth2_spec_mock_3( - #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] - #[exclude("deneb*")] - path: PathBuf, -) { - run_test_eth2_spec_mock::<17, 20>(path) + run_test_eth2_spec_mock::<18, 20>(path) } fn run_test_eth2_spec_mock(path: PathBuf) { diff --git a/preprocessor/Cargo.toml b/preprocessor/Cargo.toml index 6f202ba7..4f675c46 100644 --- a/preprocessor/Cargo.toml +++ b/preprocessor/Cargo.toml @@ -11,7 +11,7 @@ beacon-api-client.workspace = true # misc eyre = "0.6" -tokio = { version = "1", features = ["full"]} +tokio = { version = "1", features = ["full"] } hex.workspace = true log.workspace = true @@ -19,7 +19,6 @@ itertools.workspace = true serde_json.workspace = true serde.workspace = true ethereum-consensus-types.workspace = true -zipline-cryptography = { workspace = true, features = ["serde"] } # local eth-types.workspace = true lightclient-circuits.workspace = true diff --git a/preprocessor/src/lib.rs b/preprocessor/src/lib.rs index 56475ff4..136282d3 100644 --- a/preprocessor/src/lib.rs +++ b/preprocessor/src/lib.rs @@ -16,10 +16,9 @@ use ssz_rs::{Node, Vector}; use std::ops::Deref; pub use sync::*; mod rotation; +use ethereum_consensus_types::bls::BlsPublicKey; +use ethereum_consensus_types::bls::BlsSignature; pub use rotation::*; -use zipline_cryptography::bls::BlsPublicKey; -use zipline_cryptography::bls::BlsSignature; - pub async fn light_client_update_to_args( update: &mut LightClientUpdateCapella< { S::SYNC_COMMITTEE_SIZE }, diff --git a/preprocessor/src/sync.rs b/preprocessor/src/sync.rs index 82c598e3..266b8fdc 100644 --- a/preprocessor/src/sync.rs +++ b/preprocessor/src/sync.rs @@ -3,6 +3,7 @@ use std::marker::PhantomData; use beacon_api_client::Client; use beacon_api_client::{BlockId, ClientTypes, StateId}; use eth_types::Spec; +use ethereum_consensus_types::bls::BlsPublicKey; use ethereum_consensus_types::signing::{compute_domain, DomainType}; use ethereum_consensus_types::{ForkData, LightClientBootstrap, LightClientFinalityUpdate}; use itertools::Itertools; @@ -10,7 +11,6 @@ use lightclient_circuits::witness::SyncStepArgs; use ssz_rs::Vector; use ssz_rs::{Merkleized, Node}; use tokio::fs; -use zipline_cryptography::bls::BlsPublicKey; use crate::{get_light_client_bootstrap, get_light_client_finality_update}; diff --git a/prover/src/args.rs b/prover/src/args.rs index 1a984ef0..3f10c823 100644 --- a/prover/src/args.rs +++ b/prover/src/args.rs @@ -8,11 +8,21 @@ use strum::EnumString; #[command(about = "Spectre prover", long_about = None)] pub struct Cli { #[command(subcommand)] - pub subcommand: Subcommands, + pub subcommand: BaseCmd, + + #[clap(flatten)] + pub args: BaseArgs, +} + +#[derive(Clone, clap::Args)] +pub struct BaseArgs { + #[clap(long, short, default_value = "./lightclient-circuits/config")] + pub config_dir: PathBuf, } + #[derive(Clone, clap::Parser)] #[allow(clippy::large_enum_variant)] -pub enum Subcommands { +pub enum BaseCmd { Rpc(RpcOptions), Circuit(CircuitOptions), } @@ -25,87 +35,52 @@ pub struct RpcOptions { #[derive(Clone, clap::Parser)] pub struct CircuitOptions { #[command(subcommand)] - pub proof: Proof, + pub proof: ProofCmd, #[clap(long, short, default_value = "mainnet")] pub spec: Spec, } #[derive(Clone, clap::Subcommand)] -pub enum Proof { - CommitteeUpdate(Args), - SyncStep(Args), - Aggregation(AggregationArgs), -} +pub enum ProofCmd { + SyncStep { + #[command(subcommand)] + operation: OperationCmd, -#[derive(Clone, clap::Args)] -pub struct Args { - #[clap(long, short, default_value = "snark")] - pub out: Out, + #[clap(long, short, default_value = "22")] + k: u32, - #[clap(long, short)] - pub k: Option, + #[clap(long, short)] + pk_path: PathBuf, + }, + CommitteeUpdate { + #[command(subcommand)] + operation: OperationCmd, - #[clap( - long, - short, - default_value = "./lightclient-circuits/config/sync_step.json" - )] - pub config_path: PathBuf, + #[clap(long, short, default_value = "18")] + k: u32, - #[clap(long, short, default_value = "./build")] - pub build_dir: PathBuf, + #[clap(long, short)] + pk_path: PathBuf, - #[clap(long, short)] - pub input_path: Option, - - #[clap( - long, - short = 'n', - help = "Beacon node URL", - default_value = "http://127.0.0.1:5052" - )] - pub beacon_api_url: String, - - #[clap( - long, - short, - help = "Ethereum RPC", - default_value = "http://127.0.0.1:8545" - )] - pub ethereum_rpc: String, + #[clap(long, default_value = "25")] + verifier_k: u32, - #[clap(long, short)] - pub verifier_address: Option, - - #[clap(index = 1, help = "path to output", default_value = ".")] - pub path_out: PathBuf, + #[clap(long)] + verifier_pk_path: PathBuf, + }, } -#[derive(Clone, clap::Args)] -pub struct AggregationArgs { - #[clap(flatten)] - pub aggregation: Args, - - #[clap(long)] - pub app_pk_path: PathBuf, - - #[clap(long)] - pub app_config_path: PathBuf, +#[derive(Clone, clap::Subcommand)] +pub enum OperationCmd { + Setup, + GenVerifier(VerifierGenArgs), } -#[derive(Clone, Debug, PartialEq, EnumString)] -pub enum Out { - #[strum(serialize = "snark")] - Snark, - #[strum(serialize = "artifacts")] - Artifacts, - #[strum(serialize = "evm-verifier")] - EvmVerifier, - #[strum(serialize = "calldata")] - Calldata, - #[strum(serialize = "tx")] - Tx, +#[derive(Clone, clap::Args)] +pub struct VerifierGenArgs { + #[clap(long, short)] + pub solidity_out: PathBuf, } #[derive(Clone, Debug, PartialEq, EnumString, Serialize, Deserialize)] diff --git a/prover/src/cli.rs b/prover/src/cli.rs index 442fae6f..ce2c696c 100644 --- a/prover/src/cli.rs +++ b/prover/src/cli.rs @@ -1,34 +1,17 @@ -use crate::args::{Args, Out, Proof}; +use crate::args::BaseArgs; +use crate::args::{OperationCmd, ProofCmd}; -use beacon_api_client::Client; -use beacon_api_client::ClientTypes; -use ethers::abi::Address; -use ethers::providers::{Http, Provider}; -use itertools::Itertools; use lightclient_circuits::{ committee_update_circuit::CommitteeUpdateCircuit, - halo2_proofs::halo2curves::bn256::{Bn256, Fr, G1Affine}, + halo2_proofs::halo2curves::bn256::{Bn256, Fr}, sync_step_circuit::StepCircuit, util::{gen_srs, AppCircuit}, }; -use preprocessor::{fetch_rotation_args, fetch_step_args}; -use primitive_types::U256; -use snark_verifier::{ - loader::halo2::halo2_ecc::halo2_base::halo2_proofs::{ - plonk::VerifyingKey, poly::kzg::commitment::ParamsKZG, - }, - system::halo2::Config, -}; -use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, read_instances, Snark}; -use std::str::FromStr; -use std::{ - fs::{self, File}, - future::Future, - io::Write, - path::Path, - sync::Arc, -}; -use url::Url; +use snark_verifier::loader::halo2::halo2_ecc::halo2_base::halo2_proofs::poly::kzg::commitment::ParamsKZG; +use snark_verifier_sdk::halo2::aggregation::AggregationCircuit; +use std::path::PathBuf; +use std::{fs::File, future::Future, io::Write, path::Path}; + ethers::contract::abigen!( SnarkVerifierSol, r#"[ @@ -50,7 +33,10 @@ where type Output = Fut::Output; } -pub(crate) async fn spec_app(proof: &Proof) -> eyre::Result<()> +pub(crate) async fn spec_app( + proof: ProofCmd, + base_args: &BaseArgs, +) -> eyre::Result<()> where [(); S::SYNC_COMMITTEE_SIZE]:, [(); S::FINALIZED_HEADER_DEPTH]:, @@ -61,225 +47,109 @@ where [(); S::FINALIZED_HEADER_INDEX]:, { match proof { - Proof::CommitteeUpdate(args) => { - let client: Client = Client::new(Url::parse(&args.beacon_api_url).unwrap()); - - generic_circuit_cli::, C, _>( - args, - client, - fetch_rotation_args, - "committee_update", - as AppCircuit>::Witness::default(), - ) - .await?; + ProofCmd::SyncStep { + operation, + k, + pk_path, + } => { + let params = gen_srs(k); + let cfg_path = get_config_path(&pk_path, &base_args.config_dir); + + match operation { + OperationCmd::Setup => { + StepCircuit::::create_pk( + ¶ms, + &pk_path, + cfg_path, + &Default::default(), + ); + + Ok(()) + } + OperationCmd::GenVerifier(args) => { + gen_evm_verifier::>(¶ms, &pk_path, args.solidity_out) + } + } } - Proof::SyncStep(args) => { - let client: Client = Client::new(Url::parse(&args.beacon_api_url).unwrap()); - - generic_circuit_cli::, C, _>( - args, - client, - fetch_step_args, - "step_circuit_testnet", - as AppCircuit>::Witness::default(), - ) - .await?; - } - Proof::Aggregation(args) => { - let client: Client = Client::new(Url::parse("").unwrap()); - - let params = gen_srs(CommitteeUpdateCircuit::::get_degree( - &args.app_config_path, - )); - - let app_pk = CommitteeUpdateCircuit::::read_pk( - ¶ms, - &args.app_pk_path, - & as AppCircuit>::Witness::default(), - ); - - let snark = read_snark( - ¶ms, - app_pk.get_vk(), - args.aggregation - .input_path - .as_ref() - .expect("path to SNARK is required"), - )?; - let snark_clone = snark.clone(); - let get_args = move |_client: &Client| async { Ok(vec![snark_clone]) }; - generic_circuit_cli::( - &args.aggregation, - client, - get_args, - "aggregation", - vec![snark], - ) - .await?; + ProofCmd::CommitteeUpdate { + operation, + k, + verifier_k, + verifier_pk_path, + pk_path, + } => { + let params = gen_srs(k); + let cfg_path = get_config_path(&pk_path, &base_args.config_dir); + match operation { + OperationCmd::Setup => { + let pk = CommitteeUpdateCircuit::::create_pk( + ¶ms, + &pk_path, + &cfg_path, + &Default::default(), + ); + + let dummy_snark = CommitteeUpdateCircuit::::gen_snark_shplonk( + ¶ms, + &pk, + &cfg_path, + None::, + &Default::default(), + ) + .map_err(|e| eyre::eyre!("Failed to generate proof: {}", e))?; + + let verifier_params = gen_srs(verifier_k); + let verifier_cfg_path = + get_config_path(&verifier_pk_path, &base_args.config_dir); + + AggregationCircuit::create_pk( + &verifier_params, + &verifier_pk_path, + verifier_cfg_path, + &vec![dummy_snark], + ); + + Ok(()) + } + OperationCmd::GenVerifier(args) => { + gen_evm_verifier::>(¶ms, &pk_path, args.solidity_out) + } + } } } - Ok(()) } -pub(crate) async fn generic_circuit_cli( - args: &Args, - client: Client, - fetch: FnFetch, - name: &str, - default_witness: Circuit::Witness, +fn get_config_path(pk_path: &Path, config_dir: &Path) -> PathBuf { + let circuit_configuration = pk_path + .file_stem() + .expect("config file is required") + .to_str() + .unwrap(); + config_dir.join(format!("{}.json", circuit_configuration)) +} + +fn gen_evm_verifier( + params: &ParamsKZG, + pk_path: &Path, + mut path_out: PathBuf, ) -> eyre::Result<()> where - for<'a> FnFetch: FetchFn<&'a Client, Output = eyre::Result>, + Circuit::Witness: Default, { - let k = args - .k - .unwrap_or_else(|| Circuit::get_degree(&args.config_path)); - let params = gen_srs(k); - let pk_filename = format!("{}.pkey", name); - // let client = Client::new(Url::parse(&args.beacon_api_url).unwrap()); - match args.out { - Out::Snark => { - let pk = Circuit::read_or_create_pk( - ¶ms, - args.build_dir.join(&pk_filename), - &args.config_path, - true, - &default_witness, - ); - let witness = fetch(&client).await?; - Circuit::gen_snark_shplonk( - ¶ms, - &pk, - &args.config_path, - Some(&args.path_out), - &witness, - ) - .map_err(|e| eyre::eyre!("Failed to generate proof: {}", e))?; - } - Out::Artifacts => { - Circuit::create_pk( - ¶ms, - args.build_dir.join(&pk_filename), - &args.config_path, - &default_witness, - ); - } - Out::EvmVerifier => { - let pk = Circuit::read_or_create_pk( - ¶ms, - args.build_dir.join(&pk_filename), - &args.config_path, - true, - &default_witness, - ); - let deplyment_code = Circuit::gen_evm_verifier_shplonk( - ¶ms, - &pk, - Some(&args.path_out), - &default_witness, - ) - .map_err(|e| eyre::eyre!("Failed to EVM verifier: {}", e))?; - println!("yul size: {}", deplyment_code.len()); - let sol_contract = halo2_solidity_verifier::fix_verifier_sol(args.path_out.clone(), 1) - .map_err(|e| eyre::eyre!("Failed to generate Solidity verifier: {}", e))?; - let mut sol_contract_path = args.path_out.clone(); - sol_contract_path.set_extension("sol"); - let mut f = File::create(sol_contract_path).unwrap(); - f.write(sol_contract.as_bytes()) - .map_err(|e| eyre::eyre!("Failed to write Solidity verifier: {}", e))?; - } - Out::Calldata => { - let pk = Circuit::read_or_create_pk( - ¶ms, - args.build_dir.join(&pk_filename), - &args.config_path, - true, - &default_witness, - ); - - let witness = fetch(&client).await?; - - let deplyment_code = - Circuit::gen_evm_verifier_shplonk(¶ms, &pk, None::<&Path>, &default_witness) - .map_err(|e| eyre::eyre!("Failed to EVM verifier: {}", e))?; - - Circuit::gen_calldata( - ¶ms, - &pk, - &args.config_path, - &args.path_out, - Some(deplyment_code), - &witness, - ) - .map_err(|e| eyre::eyre!("Failed to generate calldata: {}", e))?; - } - Out::Tx => { - let provider = Arc::new(Provider::new(Http::new( - args.ethereum_rpc.parse::().unwrap(), - ))); + let pk = Circuit::read_pk(params, pk_path, &Default::default()); - let pk = Circuit::read_or_create_pk( - ¶ms, - args.build_dir.join(&pk_filename), - &args.config_path, - true, - &default_witness, - ); - let witness = fetch(&client).await?; - - let (proof, instances) = - Circuit::gen_evm_proof_shplonk(¶ms, &pk, &args.config_path, None, &witness) - .map_err(|e| eyre::eyre!("Failed to generate calldata: {}", e))?; - - let public_inputs = instances[0] - .iter() - .map(|pi| U256::from_little_endian(&pi.to_bytes())) - .collect_vec() - .try_into() - .unwrap(); - - let contract_addr = Address::from_str( - args.verifier_address - .as_ref() - .expect("verifier address is required"), - ) - .unwrap(); - let snark_verifier = SnarkVerifierSol::new(contract_addr, provider); + let deplyment_code = + Circuit::gen_evm_verifier_shplonk(params, &pk, Some(path_out.clone()), &Default::default()) + .map_err(|e| eyre::eyre!("Failed to EVM verifier: {}", e))?; + println!("yul size: {}", deplyment_code.len()); + path_out.set_extension("yul"); - let result = snark_verifier - .verify(public_inputs, proof.into()) - .await - .unwrap(); + let sol_contract = halo2_solidity_verifier::fix_verifier_sol(path_out.clone(), 1) + .map_err(|e| eyre::eyre!("Failed to generate Solidity verifier: {}", e))?; + path_out.set_extension("sol"); + let mut f = File::create(path_out).unwrap(); + f.write(sol_contract.as_bytes()) + .map_err(|e| eyre::eyre!("Failed to write Solidity verifier: {}", e))?; - assert!(result); - } - } Ok(()) } - -fn read_snark( - params: &ParamsKZG, - vk: &VerifyingKey, - path: &Path, -) -> eyre::Result { - let path_str = path.to_str().unwrap(); - - let proof = fs::read(format!("{path_str}.proof")) - .map_err(|e| eyre::eyre!("Error reading proof file: {}", e))?; - let instances = read_instances(format!("{path_str}.instances")) - .map_err(|e| eyre::eyre!("Error reading instances file: {}", e))?; - - let protocol = snark_verifier::system::halo2::compile( - params, - vk, - Config::kzg() - .with_num_instance(instances.iter().map(|i| i.len()).collect()) - .with_accumulator_indices(None), // FIXME: use >::accumulator_indices() - ); - - Ok(Snark { - protocol, - proof, - instances, - }) -} diff --git a/prover/src/main.rs b/prover/src/main.rs index dc6ff2bf..350fbb1a 100644 --- a/prover/src/main.rs +++ b/prover/src/main.rs @@ -6,49 +6,30 @@ mod rpc; mod rpc_api; pub mod rpc_client; +use crate::args::RpcOptions; +use crate::{cli::spec_app, rpc::run_rpc}; use args::Cli; -use axum::{response::IntoResponse, routing::post, Router}; -use beacon_api_client::{mainnet::MainnetClientTypes, minimal::MinimalClientTypes}; use cli_batteries::version; -use http::StatusCode; -use jsonrpc_v2::{MapRouter as JsonRpcMapRouter, Server as JsonRpcServer}; - -use crate::{cli::spec_app, rpc::jsonrpc_server}; -use std::{net::TcpListener, sync::Arc}; mod args; -use jsonrpc_v2::RequestObject as JsonRpcRequestObject; - -use crate::args::RpcOptions; -pub type JsonRpcServerState = Arc>; async fn app(options: Cli) -> eyre::Result<()> { match options.subcommand { - args::Subcommands::Rpc(op) => { + args::BaseCmd::Rpc(op) => { let RpcOptions { port } = op; - let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", port)).unwrap(); - let rpc_server = Arc::new(jsonrpc_server()); - let router = Router::new() - .route("/rpc", post(handler)) - .with_state(rpc_server); - - log::info!("Ready for RPC connections"); - let server = axum::Server::from_tcp(tcp_listener) - .unwrap() - .serve(router.into_make_service()); - server.await.unwrap(); + run_rpc(port.parse().unwrap()).await.unwrap(); log::info!("Stopped accepting RPC connections"); } - args::Subcommands::Circuit(op) => match op.spec { - args::Spec::Minimal => spec_app::(&op.proof) + args::BaseCmd::Circuit(op) => match op.spec { + args::Spec::Minimal => spec_app::(op.proof, &options.args) .await .unwrap(), - args::Spec::Testnet => spec_app::(&op.proof) + args::Spec::Testnet => spec_app::(op.proof, &options.args) .await .unwrap(), - args::Spec::Mainnet => spec_app::(&op.proof) + args::Spec::Mainnet => spec_app::(op.proof, &options.args) .await .unwrap(), }, @@ -56,24 +37,6 @@ async fn app(options: Cli) -> eyre::Result<()> { Ok(()) } -async fn handler( - axum::extract::State(rpc_server): axum::extract::State, - axum::Json(rpc_call): axum::Json, -) -> impl IntoResponse { - let response_headers = [("content-type", "application/json-rpc;charset=utf-8")]; - let response = rpc_server.handle(rpc_call).await; - - let response_str = serde_json::to_string(&response); - match response_str { - Ok(result) => (StatusCode::OK, response_headers, result), - Err(err) => ( - StatusCode::INTERNAL_SERVER_ERROR, - response_headers, - err.to_string(), - ), - } -} - fn main() { cli_batteries::run(version!(), app); } diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index 57e988dd..f9ba2357 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -1,6 +1,11 @@ use super::args::Spec; +use axum::response::IntoResponse; +use axum::routing::post; +use axum::Router; use ethers::prelude::*; +use http::StatusCode; use itertools::Itertools; +use jsonrpc_v2::RequestObject as JsonRpcRequestObject; use jsonrpc_v2::{Error as JsonRpcError, Params}; use jsonrpc_v2::{MapRouter as JsonRpcMapRouter, Server as JsonRpcServer}; use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; @@ -13,8 +18,11 @@ use preprocessor::{ fetch_rotation_args, fetch_step_args, rotation_args_from_update, step_args_from_finality_update, }; use snark_verifier_sdk::{evm::evm_verify, halo2::aggregation::AggregationCircuit, Snark}; -use std::path::PathBuf; +use std::net::TcpListener; +use std::path::{Path, PathBuf}; +use std::sync::Arc; use url::Url; +pub type JsonRpcServerState = Arc>; use crate::rpc_api::{ EvmProofResult, GenProofRotationParams, GenProofRotationWithWitnessParams, GenProofStepParams, @@ -24,126 +32,114 @@ use crate::rpc_api::{ SYNC_COMMITTEE_POSEIDON_UNCOMPRESSED, }; -fn gen_app_snark( - app_config_path: PathBuf, - app_pk_path: PathBuf, +fn gen_committee_update_snark( + config_path: PathBuf, + pk_path: PathBuf, witness: as AppCircuit>::Witness, ) -> eyre::Result { - let params = gen_srs(CommitteeUpdateCircuit::::get_degree( - &app_config_path, - )); + let params = gen_srs(CommitteeUpdateCircuit::::get_degree(&config_path)); - let app_pk = CommitteeUpdateCircuit::::create_pk( + let app_pk = CommitteeUpdateCircuit::::read_pk( ¶ms, - app_pk_path, - &app_config_path, + pk_path, & as AppCircuit>::Witness::default(), ); Ok(CommitteeUpdateCircuit::::gen_snark_shplonk( ¶ms, &app_pk, - app_config_path, + config_path, None::, &witness, )?) } fn gen_evm_proof( - k: Option, - build_dir: PathBuf, - pk_filename: String, + pk_path: impl AsRef, config_path: PathBuf, witness: C::Witness, + yul_path_if_verify: Option>, ) -> (Vec, Vec>) { - let k = k.unwrap_or_else(|| C::get_degree(&config_path)); + let k = C::get_degree(&config_path); let params = gen_srs(k); - let pk = C::create_pk(¶ms, build_dir.join(pk_filename), &config_path, &witness); + let pk = C::read_pk(¶ms, pk_path, &witness); let (proof, instances) = C::gen_evm_proof_shplonk(¶ms, &pk, &config_path, None, &witness) .map_err(|e| eyre::eyre!("Failed to generate calldata: {}", e)) .unwrap(); println!("Proof size: {}", proof.len()); - let deployment_code = - C::gen_evm_verifier_shplonk(¶ms, &pk, Some("contractyul"), &witness).unwrap(); - println!("deployment_code size: {}", deployment_code.len()); - evm_verify(deployment_code, instances.clone(), proof.clone()); - println!("Gen evm proof done"); + if let Some(deployment_code_path) = yul_path_if_verify { + let deployment_code = + C::gen_evm_verifier_shplonk(¶ms, &pk, Some(deployment_code_path), &witness) + .unwrap(); + println!("Deployment code size: {}", deployment_code.len()); + evm_verify(deployment_code, instances.clone(), proof.clone()); + } (proof, instances) } pub(crate) async fn gen_evm_proof_rotation_circuit_handler( Params(params): Params, ) -> Result { - let GenProofRotationParams { - spec, - k, - beacon_api, - } = params; + let GenProofRotationParams { spec, beacon_api } = params; // TODO: use config/build paths from CLI flags - let app_config_path = PathBuf::from("../lightclient-circuits/config/committee_update.json"); - let agg_l2_pk_path = PathBuf::from("./build/step_agg_l2.pkey"); - let agg_l1_pk_path = PathBuf::from("./build/step_agg_l1.pkey"); - - let agg_l2_config_path = - PathBuf::from("../lightclient-circuits/config/committee_update_aggregation_2.json"); - let agg_l1_config_path = - PathBuf::from("../lightclient-circuits/config/committee_update_aggregation_1.json"); - - let l0_snark = match spec { + let (snark, verifier_filename) = match spec { Spec::Minimal => { - let app_pk_path = PathBuf::from("./build/committee_update_circuit_minimal.pkey"); let client = beacon_api_client::minimal::Client::new(Url::parse(&beacon_api)?); - let witness: lightclient_circuits::witness::CommitteeRotationArgs = - fetch_rotation_args(&client).await?; - gen_app_snark::(app_config_path, app_pk_path, witness)? + let witness = fetch_rotation_args(&client).await?; + let snark = gen_committee_update_snark::( + PathBuf::from("./lightclient-circuits/config/committee_update_minimal.json"), + PathBuf::from("./build/committee_update_minimal.pkey"), + witness, + )?; + + (snark, "committee_update_verifier_minimal") } Spec::Testnet => { - let app_pk_path = PathBuf::from("./build/committee_update_circuit_testnet.pkey"); let client = beacon_api_client::mainnet::Client::new(Url::parse(&beacon_api)?); let witness = fetch_rotation_args(&client).await?; - gen_app_snark::(app_config_path, app_pk_path, witness)? + let snark = gen_committee_update_snark::( + PathBuf::from("./lightclient-circuits/config/committee_update_testnet.json"), + PathBuf::from("./build/committee_update_testnet.pkey"), + witness, + )?; + + (snark, "committee_update_verifier_testnet") } Spec::Mainnet => { - let app_pk_path = PathBuf::from("./build/committee_update_circuit_mainnet.pkey"); let client = beacon_api_client::mainnet::Client::new(Url::parse(&beacon_api)?); let witness = fetch_rotation_args(&client).await?; - gen_app_snark::(app_config_path, app_pk_path, witness)? + let snark = gen_committee_update_snark::( + PathBuf::from("./lightclient-circuits/config/committee_update_mainnet.json"), + PathBuf::from("./build/committee_update_mainnet.pkey"), + witness, + )?; + + (snark, "committee_update_verifier_mainnet") } }; - let l1_snark = { - let k = k.unwrap_or(24); - let p1 = gen_srs(k); - let pk_l1 = AggregationCircuit::read_pk(&p1, agg_l1_pk_path, &vec![l0_snark.clone()]); - - let snark = AggregationCircuit::gen_snark_shplonk( - &p1, - &pk_l1, - agg_l1_config_path, - None::, - &vec![l0_snark.clone()], - ) - .map_err(JsonRpcError::internal)?; - println!("L1 snark size: {}", snark.proof.len()); + let (proof, instances) = { + let pinning_path = format!("./lightclient-circuits/config/{verifier_filename}.json"); - snark - }; + let agg_k = AggregationCircuit::get_degree(&pinning_path); + let params_agg = gen_srs(agg_k); + let pk_agg = AggregationCircuit::read_pk( + ¶ms_agg, + format!("./build/{verifier_filename}.pkey"), + &vec![snark.clone()], + ); - let (proof, instances) = { - let k = k.unwrap_or(24); - let p2 = gen_srs(k); - let pk_l2 = AggregationCircuit::read_pk(&p2, agg_l2_pk_path, &vec![l1_snark.clone()]); AggregationCircuit::gen_evm_proof_shplonk( - &p2, - &pk_l2, - agg_l2_config_path, + ¶ms_agg, + &pk_agg, + pinning_path, None, - &vec![l1_snark.clone()], + &vec![snark.clone()], ) .map_err(JsonRpcError::internal)? }; @@ -152,6 +148,7 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_handler( .iter() .map(|pi| U256::from_little_endian(&pi.to_bytes())) .collect(); + Ok(EvmProofResult { proof, public_inputs, @@ -163,84 +160,65 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_with_witness_handler( ) -> Result { let GenProofRotationWithWitnessParams { spec, - k, light_client_update, } = params; // TODO: use config/build paths from CLI flags - let app_config_path = PathBuf::from("../lightclient-circuits/config/committee_update.json"); - let agg_l2_pk_path = PathBuf::from("./build/step_agg_l2.pkey"); - let agg_l1_pk_path = PathBuf::from("./build/step_agg_l1.pkey"); - let agg_l2_config_path = - PathBuf::from("../lightclient-circuits/config/committee_update_aggregation_2.json"); - let agg_l1_config_path = - PathBuf::from("../lightclient-circuits/config/committee_update_aggregation_1.json"); - let _build_dir = PathBuf::from("./build"); - - let (l0_snark, _pk_filename) = match spec { + let (snark, verifier_filename) = match spec { Spec::Minimal => { let mut update = serde_json::from_slice(&light_client_update).unwrap(); - let app_pk_path = PathBuf::from("./build/committee_update_circuit_minimal.pkey"); - let witness = rotation_args_from_update(&mut update).await.unwrap(); - ( - gen_app_snark::(app_config_path, app_pk_path, witness)?, - "agg_rotation_circuit_minimal.pkey", - ) + let snark = gen_committee_update_snark::( + PathBuf::from("./lightclient-circuits/config/committee_update_minimal.json"), + PathBuf::from("./build/committee_update_minimal.pkey"), + witness, + )?; + + (snark, "committee_update_verifier_minimal") } Spec::Testnet => { let mut update = serde_json::from_slice(&light_client_update).unwrap(); - let app_pk_path = PathBuf::from("./build/committee_update_circuit_testnet.pkey"); - let witness = rotation_args_from_update(&mut update).await.unwrap(); + let snark = gen_committee_update_snark::( + PathBuf::from("./lightclient-circuits/config/committee_update_testnet.json"), + PathBuf::from("./build/committee_update_testnet.pkey"), + witness, + )?; - ( - gen_app_snark::(app_config_path, app_pk_path, witness)?, - "agg_rotation_circuit_testnet.pkey", - ) + (snark, "committee_update_verifier_testnet") } Spec::Mainnet => { let mut update = serde_json::from_slice(&light_client_update).unwrap(); - let app_pk_path = PathBuf::from("./build/committee_update_circuit_mainnet.pkey"); - let witness = rotation_args_from_update(&mut update).await.unwrap(); + let snark = gen_committee_update_snark::( + PathBuf::from("./lightclient-circuits/config/committee_update_mainnet.json"), + PathBuf::from("./build/committee_update_mainnet.pkey"), + witness, + )?; - ( - gen_app_snark::(app_config_path, app_pk_path, witness)?, - "agg_rotation_circuit_mainnet.pkey", - ) + (snark, "committee_update_verifier_mainnet") } }; - let l1_snark = { - let k = k.unwrap_or(24); - let p1 = gen_srs(k); - let pk_l1 = AggregationCircuit::read_pk(&p1, agg_l1_pk_path, &vec![l0_snark.clone()]); - - let snark = AggregationCircuit::gen_snark_shplonk( - &p1, - &pk_l1, - agg_l1_config_path, - None::, - &vec![l0_snark.clone()], - ) - .map_err(JsonRpcError::internal)?; - println!("L1 snark size: {}", snark.proof.len()); + let (proof, instances) = { + let pinning_path = format!("./lightclient-circuits/config/{verifier_filename}.json"); - snark - }; + // Circuits of all specs have the same pinning type so we can just use Mainnet spec. + let agg_k = AggregationCircuit::get_degree(&pinning_path); + let params_agg = gen_srs(agg_k); + let pk_agg = AggregationCircuit::read_pk( + ¶ms_agg, + format!("./build/{verifier_filename}.pkey"), + &vec![snark.clone()], + ); - let (proof, instances) = { - let k = k.unwrap_or(24); - let p2 = gen_srs(k); - let pk_l2 = AggregationCircuit::read_pk(&p2, agg_l2_pk_path, &vec![l1_snark.clone()]); AggregationCircuit::gen_evm_proof_shplonk( - &p2, - &pk_l2, - agg_l2_config_path, + ¶ms_agg, + &pk_agg, + pinning_path, None, - &vec![l1_snark.clone()], + &vec![snark.clone()], ) .map_err(JsonRpcError::internal)? }; @@ -258,55 +236,40 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_with_witness_handler( pub(crate) async fn gen_evm_proof_step_circuit_handler( Params(params): Params, ) -> Result { - let GenProofStepParams { - spec, - k, - beacon_api, - } = params.clone(); - - let config_path = PathBuf::from("../lightclient-circuits/config/sync_step.json"); - let build_dir = PathBuf::from("./build"); + let GenProofStepParams { spec, beacon_api } = params.clone(); let (proof, instances) = match spec { Spec::Minimal => { - let pk_filename = format!("step_circuit_minimal.pkey"); let client = beacon_api_client::minimal::Client::new(Url::parse(&beacon_api)?); - let witness = fetch_step_args(&client).await.unwrap(); + gen_evm_proof::>( - k, - build_dir, - pk_filename, - config_path, + PathBuf::from("./build/sync_step_minimal.pkey"), + PathBuf::from("./lightclient-circuits/config/sync_step_minimal.json"), witness, + None::, ) } Spec::Testnet => { - let pk_filename = format!("step_circuit_testnet.pkey"); let client = beacon_api_client::mainnet::Client::new(Url::parse(&beacon_api)?); - let witness = fetch_step_args(&client).await.unwrap(); gen_evm_proof::>( - k, - build_dir, - pk_filename, - config_path, + PathBuf::from("./build/sync_step_testnet.pkey"), + PathBuf::from("./lightclient-circuits/config/sync_step_testnet.json"), witness, + None::, ) } Spec::Mainnet => { - let pk_filename = format!("step_circuit_mainnet.pkey"); let client = beacon_api_client::mainnet::Client::new(Url::parse(&beacon_api)?); - let witness = fetch_step_args(&client).await.unwrap(); gen_evm_proof::>( - k, - build_dir, - pk_filename, - config_path, + PathBuf::from("./build/sync_step_mainnet.pkey"), + PathBuf::from("./lightclient-circuits/config/sync_step_mainnet.json"), witness, + None::, ) } }; @@ -315,6 +278,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_handler( .iter() .map(|pi| U256::from_little_endian(&pi.to_bytes())) .collect(); + Ok(EvmProofResult { proof, public_inputs, @@ -326,63 +290,52 @@ pub(crate) async fn gen_evm_proof_step_circuit_with_witness_handler( ) -> Result { let GenProofStepWithWitnessParams { spec, - k, light_client_finality_update, domain, pubkeys, } = params; - let config_path = PathBuf::from("../lightclient-circuits/config/sync_step.json"); - let build_dir = PathBuf::from("./build"); - let (proof, instances) = match spec { Spec::Minimal => { - let pk_filename = format!("step_circuit_minimal.pkey"); - let update = serde_json::from_slice(&light_client_finality_update).unwrap(); let pubkeys = serde_json::from_slice(&pubkeys).unwrap(); - let witness = step_args_from_finality_update(update, pubkeys, domain) .await .unwrap(); + gen_evm_proof::>( - k, - build_dir, - pk_filename, - config_path, + PathBuf::from("./build/sync_step_minimal.pkey"), + PathBuf::from("./lightclient-circuits/config/sync_step_minimal.json"), witness, + None::, ) } Spec::Testnet => { - let pk_filename = format!("step_circuit_testnet.pkey"); let update = serde_json::from_slice(&light_client_finality_update).unwrap(); let pubkeys = serde_json::from_slice(&pubkeys).unwrap(); - let witness = step_args_from_finality_update(update, pubkeys, domain) .await .unwrap(); + gen_evm_proof::>( - k, - build_dir, - pk_filename, - config_path, + PathBuf::from("./build/sync_step_testnet.pkey"), + PathBuf::from("./lightclient-circuits/config/sync_step_testnet.json"), witness, + None::, ) } Spec::Mainnet => { - let pk_filename = format!("step_circuit_mainnet.pkey"); let update = serde_json::from_slice(&light_client_finality_update).unwrap(); let pubkeys = serde_json::from_slice(&pubkeys).unwrap(); - let witness = step_args_from_finality_update(update, pubkeys, domain) .await .unwrap(); + gen_evm_proof::>( - k, - build_dir, - pk_filename, - config_path, + PathBuf::from("./build/sync_step_mainnet.pkey"), + PathBuf::from("./lightclient-circuits/config/sync_step_mainnet.json"), witness, + None::, ) } }; @@ -391,6 +344,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_with_witness_handler( .iter() .map(|pi| U256::from_little_endian(&pi.to_bytes())) .collect(); + Ok(EvmProofResult { proof, public_inputs, @@ -402,13 +356,7 @@ pub(crate) async fn sync_committee_poseidon_compressed_handler( ) -> Result { let SyncCommitteePoseidonParams { pubkeys } = params; - let pubkeys = pubkeys - .into_iter() - .map(|mut b| { - b.reverse(); - b - }) - .collect_vec(); + let pubkeys = pubkeys.into_iter().collect_vec(); let commitment = lightclient_circuits::poseidon::poseidon_committee_commitment_from_compressed( pubkeys.as_slice(), @@ -421,13 +369,7 @@ pub(crate) async fn sync_committee_poseidon_uncompressed_handler( ) -> Result { let SyncCommitteePoseidonParams { pubkeys } = params; - let pubkeys = pubkeys - .into_iter() - .map(|mut b| { - b.reverse(); - b - }) - .collect_vec(); + let pubkeys = pubkeys.into_iter().collect_vec(); let commitment = lightclient_circuits::poseidon::poseidon_committee_commitment_from_uncompressed( @@ -462,3 +404,37 @@ pub(crate) fn jsonrpc_server() -> JsonRpcServer { ) .finish_unwrapped() } + +pub async fn run_rpc(port: usize) -> Result<(), eyre::Error> { + let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", port)).unwrap(); + let rpc_server = Arc::new(jsonrpc_server()); + let router = Router::new() + .route("/rpc", post(handler)) + .with_state(rpc_server); + + log::info!("Ready for RPC connections"); + let server = axum::Server::from_tcp(tcp_listener) + .unwrap() + .serve(router.into_make_service()); + server + .await + .map_err(|e| eyre::eyre!("RPC server error: {}", e)) +} + +async fn handler( + axum::extract::State(rpc_server): axum::extract::State, + axum::Json(rpc_call): axum::Json, +) -> impl IntoResponse { + let response_headers = [("content-type", "application/json-rpc;charset=utf-8")]; + let response = rpc_server.handle(rpc_call).await; + + let response_str = serde_json::to_string(&response); + match response_str { + Ok(result) => (StatusCode::OK, response_headers, result), + Err(err) => ( + StatusCode::INTERNAL_SERVER_ERROR, + response_headers, + err.to_string(), + ), + } +} diff --git a/prover/src/rpc_api.rs b/prover/src/rpc_api.rs index be02958a..1f92264c 100644 --- a/prover/src/rpc_api.rs +++ b/prover/src/rpc_api.rs @@ -6,7 +6,6 @@ use serde::{Deserialize, Serialize}; pub struct GenProofRotationParams { pub spec: args::Spec, - pub k: Option, #[serde(default = "default_beacon_api")] pub beacon_api: String, } @@ -15,7 +14,6 @@ pub struct GenProofRotationParams { pub struct GenProofStepParams { pub spec: args::Spec, - pub k: Option, #[serde(default = "default_beacon_api")] pub beacon_api: String, } @@ -24,8 +22,6 @@ pub struct GenProofStepParams { pub struct GenProofStepWithWitnessParams { pub spec: args::Spec, - pub k: Option, - // Serializing as Vec so that we can differentiate between Mainnet, Testnet, Minimal at runtime pub light_client_finality_update: Vec, pub pubkeys: Vec, @@ -37,8 +33,6 @@ pub struct GenProofStepWithWitnessParams { pub struct GenProofRotationWithWitnessParams { pub spec: args::Spec, - pub k: Option, - // Serializing as Vec so that we can differentiate between Mainnet, Testnet, Minimal at runtime pub light_client_update: Vec, } diff --git a/prover/src/rpc_client.rs b/prover/src/rpc_client.rs index 4b85c4ba..cbf94c95 100644 --- a/prover/src/rpc_client.rs +++ b/prover/src/rpc_client.rs @@ -134,9 +134,9 @@ mod test { let p = GenProofStepParams { spec: args::Spec::Testnet, - k: Some(21), - beacon_api: String::from("http://3.128.78.74:5052"), + beacon_api: String::from("http://65.109.55.120:9596"), }; + let r = client.gen_evm_proof_step_circuit(p).await; match r { diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index 96038aee..70977df2 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -9,8 +9,6 @@ ethereum-consensus-types = { workspace = true } eth-types = { workspace = true } contracts = { workspace = true } ssz_rs = { workspace = true } -zipline-test-utils = { workspace = true } -light-client-verifier = { workspace = true } halo2curves = { workspace = true } halo2-base = { workspace = true } @@ -19,3 +17,8 @@ hex = "0.4.3" serde = { version = "1.0.130", features = ["derive"] } anyhow = "1.0.75" ethers = "2.0.10" + +test-utils = { git = "https://github.com/ChainSafe/ethereum-consensus-types", branch = "capella" } + +snap = "1.1.0" +serde_yaml = "0.9.19" diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index 52563073..f6f686ba 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -1,15 +1,20 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs)] +pub mod conversions; +mod execution_payload_header; +mod test_types; + use crate::execution_payload_header::ExecutionPayloadHeader; use crate::test_types::{ByteVector, TestMeta, TestStep}; use eth_types::Minimal; -use ethereum_consensus_types::presets::minimal::{LightClientBootstrap, LightClientUpdateCapella}; +use ethereum_consensus_types::presets::minimal::{ + LightClientBootstrap, LightClientUpdateCapella, BYTES_PER_LOGS_BLOOM, MAX_EXTRA_DATA_BYTES, +}; use ethereum_consensus_types::signing::{compute_domain, DomainType}; -use ethereum_consensus_types::BeaconBlockHeader; +use ethereum_consensus_types::{BeaconBlockHeader, SyncCommittee}; use ethereum_consensus_types::{ForkData, Root}; use itertools::Itertools; -use light_client_verifier::ZiplineUpdateWitnessCapella; use lightclient_circuits::poseidon::{ poseidon_committee_commitment_from_compressed, poseidon_committee_commitment_from_uncompressed, }; @@ -18,10 +23,7 @@ use ssz_rs::prelude::*; use ssz_rs::Merkleized; use std::ops::Deref; use std::path::Path; -use zipline_test_utils::{load_snappy_ssz, load_yaml}; -pub mod conversions; -mod execution_payload_header; -mod test_types; +use test_utils::{load_snappy_ssz, load_yaml}; pub(crate) const U256_BYTE_COUNT: usize = 32; @@ -87,21 +89,19 @@ pub fn read_test_files_and_gen_witness( let genesis_validators_root = validators_root_from_test_path(path); let updates = valid_updates_from_test_path(path); - let zipline_witness = light_client_verifier::ZiplineUpdateWitnessCapella { - committee: bootstrap.current_sync_committee, - light_client_update: updates[0].clone(), - }; - let sync_wit = to_sync_ciruit_witness(&zipline_witness, genesis_validators_root); + let sync_wit = to_sync_ciruit_witness( + bootstrap.current_sync_committee, + &updates[0], + genesis_validators_root, + ); - let mut sync_committee_branch = zipline_witness - .light_client_update + let mut sync_committee_branch = updates[0] .next_sync_committee_branch .iter() .map(|n| n.deref().to_vec()) .collect_vec(); - let agg_pubkeys_compressed = zipline_witness - .light_client_update + let agg_pubkeys_compressed = updates[0] .next_sync_committee .aggregate_pubkey .to_bytes() @@ -112,8 +112,7 @@ pub fn read_test_files_and_gen_witness( sync_committee_branch.insert(0, agg_pk.hash_tree_root().unwrap().deref().to_vec()); let rotation_wit = CommitteeRotationArgs:: { - pubkeys_compressed: zipline_witness - .light_client_update + pubkeys_compressed: updates[0] .next_sync_committee .pubkeys .iter() @@ -127,29 +126,13 @@ pub fn read_test_files_and_gen_witness( (sync_wit, rotation_wit) } -fn to_sync_ciruit_witness< - const SYNC_COMMITTEE_SIZE: usize, - const NEXT_SYNC_COMMITTEE_GINDEX: usize, - const NEXT_SYNC_COMMITTEE_PROOF_SIZE: usize, - const FINALIZED_ROOT_GINDEX: usize, - const FINALIZED_ROOT_PROOF_SIZE: usize, - const BYTES_PER_LOGS_BLOOM: usize, - const MAX_EXTRA_DATA_BYTES: usize, ->( - zipline_witness: &ZiplineUpdateWitnessCapella< - SYNC_COMMITTEE_SIZE, - NEXT_SYNC_COMMITTEE_GINDEX, - NEXT_SYNC_COMMITTEE_PROOF_SIZE, - FINALIZED_ROOT_GINDEX, - FINALIZED_ROOT_PROOF_SIZE, - BYTES_PER_LOGS_BLOOM, - MAX_EXTRA_DATA_BYTES, - >, +fn to_sync_ciruit_witness( + committee: SyncCommittee, + light_client_update: &LightClientUpdateCapella, genesis_validators_root: Root, ) -> SyncStepArgs { let mut args = SyncStepArgs:: { - signature_compressed: zipline_witness - .light_client_update + signature_compressed: light_client_update .sync_aggregate .sync_committee_signature .to_bytes() @@ -157,34 +140,23 @@ fn to_sync_ciruit_witness< ..Default::default() }; - let pubkeys_uncompressed = zipline_witness - .committee + let pubkeys_uncompressed = committee .pubkeys .iter() .map(|pk| pk.decompressed_bytes()) .collect_vec(); args.pubkeys_uncompressed = pubkeys_uncompressed; - args.pariticipation_bits = zipline_witness - .light_client_update + args.pariticipation_bits = light_client_update .sync_aggregate .sync_committee_bits .iter() .map(|b| *b) .collect(); args.attested_header = BeaconBlockHeader { - slot: zipline_witness - .light_client_update - .attested_header - .beacon - .slot, - proposer_index: zipline_witness - .light_client_update - .attested_header - .beacon - .proposer_index, + slot: light_client_update.attested_header.beacon.slot, + proposer_index: light_client_update.attested_header.beacon.proposer_index, parent_root: Node::try_from( - zipline_witness - .light_client_update + light_client_update .attested_header .beacon .parent_root @@ -192,8 +164,7 @@ fn to_sync_ciruit_witness< ) .unwrap(), state_root: Node::try_from( - zipline_witness - .light_client_update + light_client_update .attested_header .beacon .state_root @@ -201,8 +172,7 @@ fn to_sync_ciruit_witness< ) .unwrap(), body_root: Node::try_from( - zipline_witness - .light_client_update + light_client_update .attested_header .beacon .body_root @@ -211,19 +181,10 @@ fn to_sync_ciruit_witness< .unwrap(), }; args.finalized_header = BeaconBlockHeader { - slot: zipline_witness - .light_client_update - .finalized_header - .beacon - .slot, - proposer_index: zipline_witness - .light_client_update - .finalized_header - .beacon - .proposer_index, + slot: light_client_update.finalized_header.beacon.slot, + proposer_index: light_client_update.finalized_header.beacon.proposer_index, parent_root: Node::try_from( - zipline_witness - .light_client_update + light_client_update .finalized_header .beacon .parent_root @@ -231,8 +192,7 @@ fn to_sync_ciruit_witness< ) .unwrap(), state_root: Node::try_from( - zipline_witness - .light_client_update + light_client_update .finalized_header .beacon .state_root @@ -240,8 +200,7 @@ fn to_sync_ciruit_witness< ) .unwrap(), body_root: Node::try_from( - zipline_witness - .light_client_update + light_client_update .finalized_header .beacon .body_root @@ -255,8 +214,7 @@ fn to_sync_ciruit_witness< }; let signing_domain = compute_domain(DomainType::SyncCommittee, &fork_data).unwrap(); args.domain = signing_domain; - args.execution_payload_branch = zipline_witness - .light_client_update + args.execution_payload_branch = light_client_update .finalized_header .execution_branch .iter() @@ -266,8 +224,7 @@ fn to_sync_ciruit_witness< let mut execution_payload_header: ExecutionPayloadHeader< BYTES_PER_LOGS_BLOOM, MAX_EXTRA_DATA_BYTES, - > = zipline_witness - .light_client_update + > = light_client_update .finalized_header .execution .clone() @@ -279,8 +236,7 @@ fn to_sync_ciruit_witness< .deref() .to_vec() }; - args.finality_branch = zipline_witness - .light_client_update + args.finality_branch = light_client_update .finality_branch .iter() .map(|b| b.deref().to_vec())