Skip to content

Commit

Permalink
Step and Rotate with same update (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
ec2 authored Jan 8, 2024
1 parent 9fd8b7d commit d354dd0
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 26 deletions.
7 changes: 5 additions & 2 deletions contract-tests/tests/step_input_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl<Spec: eth_types::Spec> From<SyncStepArgs<Spec>> for SyncStepInput {
participation,
finalized_header_root,
execution_payload_root,
accumulator: Default::default()
accumulator: Default::default(),
}
}
}
Expand All @@ -68,7 +68,10 @@ async fn test_step_instance_commitment_evm_equivalence(
let contract = SyncStepExternal::deploy(ethclient, ())?.send().await?;

let result = contract
.to_public_inputs(SyncStepInput::from(witness), U256::from_little_endian(&instance[0][1].to_bytes()))
.to_public_inputs(
SyncStepInput::from(witness),
U256::from_little_endian(&instance[0][1].to_bytes()),
)
.call()
.await?;
let result_decoded = decode_solidity_u256_array(&result);
Expand Down
8 changes: 4 additions & 4 deletions lightclient-circuits/src/poseidon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ const R_P: usize = N_ROUNDS_PC[T - 2];
const R_F: usize = 8;

/// Generates Poseidon hash commitment to a list of BLS12-381 Fq elements.
///
///
/// Fields elements are initially represented as `NUM_LIMBS` limbs of `LIMB_BITS` bits each.
/// By composing element two limbs in one, we reduce the number of inputs to Poseidon in half.
///
///
/// Each Poseidon sponge absorbs `POSEIDON_SIZE`-2 elements and previos sponge output if it's not the first batch, ie. onion commitment.
///
///
/// Assumes that LIMB_BITS * 2 < 254 (BN254).
pub fn fq_array_poseidon<'a, F: Field>(
ctx: &mut Context<F>,
Expand Down Expand Up @@ -74,7 +74,7 @@ pub fn fq_array_poseidon<'a, F: Field>(
}

/// Generates Poseidon hash commitment to a list of BLS12-381 Fq elements.
///
///
/// This is the off-circuit analog of `fq_array_poseidon`.
pub fn poseidon_hash_fq_array<F: Field>(elems: impl Iterator<Item = Fq>, limb_bits: usize) -> F {
let limbs = elems
Expand Down
1 change: 0 additions & 1 deletion lightclient-circuits/src/sync_step_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,6 @@ impl<S: Spec> AppCircuit for StepCircuit<S, bn256::Fr> {
}
}


#[cfg(test)]
mod tests {
use std::fs;
Expand Down
3 changes: 2 additions & 1 deletion lightclient-circuits/src/util/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ pub trait AppCircuit {
) -> ProvingKey<G1Affine> {
let pinning = Self::Pinning::from_path(pinning_path);
let circuit =
Self::create_circuit(CircuitBuilderStage::Keygen, Some(pinning), witness, params).unwrap();
Self::create_circuit(CircuitBuilderStage::Keygen, Some(pinning), witness, params)
.unwrap();
custom_read_pk(path, &circuit)
}

Expand Down
2 changes: 1 addition & 1 deletion lightclient-circuits/src/witness/rotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use sha2::{Digest, Sha256};
use std::{iter, marker::PhantomData};

/// Input datum for the `CommitteeUpdateCircuit` to map next sync committee SSZ root in the finalized state root to the corresponding Poseidon commitment to the public keys.
///
///
/// Assumes that public keys are BLS12-381 points on G1; `sync_committee_branch` is exactly `S::SYNC_COMMITTEE_PUBKEYS_DEPTH` hashes in lenght.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommitteeUpdateArgs<S: Spec> {
Expand Down
12 changes: 4 additions & 8 deletions lightclient-circuits/src/witness/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use super::mock_root;

/// Input datum for the `StepCircuit` to verify `attested_header` singed by the lightclient sync committee,
/// and the `execution_payload_root` via Merkle `finality_branch` against the `finalized_header` root.
///
///
/// Assumes that aggregated BLS signarure is represented as a compressed G2 point and the public keys are uncompressed G1 points;
/// `pariticipation_bits` vector has exactly `S::SYNC_COMMITTEE_SIZE`` bits;
/// `finality_branch` and `execution_payload_branch` are exactly `S::FINALIZED_HEADER_DEPTH` and `S::EXECUTION_STATE_ROOT_DEPTH` long respectively.
Expand Down Expand Up @@ -138,13 +138,9 @@ mod tests {
const K: u32 = 20;
let witness = SyncStepArgs::<Testnet>::default();

let circuit = StepCircuit::<Testnet, Fr>::mock_circuit(
CircuitBuilderStage::Mock,
None,
&witness,
K,
)
.unwrap();
let circuit =
StepCircuit::<Testnet, Fr>::mock_circuit(CircuitBuilderStage::Mock, None, &witness, K)
.unwrap();

let prover = MockProver::<Fr>::run(K, &circuit, circuit.instances()).unwrap();
prover.assert_satisfied_par();
Expand Down
169 changes: 166 additions & 3 deletions preprocessor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ use beacon_api_client::{BlockId, Client, ClientTypes, Value, VersionedValue};
use eth_types::Spec;
use ethereum_consensus_types::bls::BlsSignature;
use ethereum_consensus_types::{
BeaconBlockHeader, LightClientBootstrap, LightClientFinalityUpdate, LightClientUpdateCapella,
Root,
BeaconBlockHeader, BlsPublicKey, ByteVector, LightClientBootstrap, LightClientFinalityUpdate,
LightClientUpdateCapella, Root,
};

use itertools::Itertools;
use lightclient_circuits::witness::{CommitteeUpdateArgs, SyncStepArgs};
pub use rotation::*;
use serde::{Deserialize, Serialize};
use ssz_rs::Node;
use ssz_rs::{Node, Vector};
pub use step::*;

pub async fn get_light_client_update_at_period<S: Spec, C: ClientTypes>(
Expand Down Expand Up @@ -122,3 +124,164 @@ pub async fn get_block_header<C: ClientTypes>(
let block: BeaconHeaderSummary = client.get::<Value<_>>(&route).await?.data;
Ok(block.header.message)
}

pub async fn light_client_update_to_args<S: Spec>(
update: &mut LightClientUpdateCapella<
{ S::SYNC_COMMITTEE_SIZE },
{ S::SYNC_COMMITTEE_ROOT_INDEX },
{ S::SYNC_COMMITTEE_DEPTH },
{ S::FINALIZED_HEADER_INDEX },
{ S::FINALIZED_HEADER_DEPTH },
{ S::BYTES_PER_LOGS_BLOOM },
{ S::MAX_EXTRA_DATA_BYTES },
>,
pubkeys_compressed: Vector<BlsPublicKey, { S::SYNC_COMMITTEE_SIZE }>,
domain: [u8; 32],
) -> eyre::Result<(SyncStepArgs<S>, CommitteeUpdateArgs<S>)>
where
[(); S::SYNC_COMMITTEE_SIZE]:,
[(); S::FINALIZED_HEADER_DEPTH]:,
[(); S::BYTES_PER_LOGS_BLOOM]:,
[(); S::MAX_EXTRA_DATA_BYTES]:,
[(); S::SYNC_COMMITTEE_ROOT_INDEX]:,
[(); S::SYNC_COMMITTEE_DEPTH]:,
[(); S::FINALIZED_HEADER_INDEX]:,
{
let finality_update = LightClientFinalityUpdate {
attested_header: update.attested_header.clone(),
finalized_header: update.finalized_header.clone(),
finality_branch: Vector::try_from(
update
.finality_branch
.iter()
.map(|v| ByteVector(Vector::try_from(v.to_vec()).unwrap()))
.collect_vec(),
)
.unwrap(),
sync_aggregate: update.sync_aggregate.clone(),
signature_slot: update.signature_slot,
};

let rotation_args = rotation::rotation_args_from_update(update).await?;

let sync_args =
step::step_args_from_finality_update(finality_update, pubkeys_compressed, domain).await?;

Ok((sync_args, rotation_args))
}

#[cfg(test)]
mod tests {
use beacon_api_client::StateId;
use eth_types::Testnet;
use ethereum_consensus_types::signing::{compute_domain, DomainType};
use ethereum_consensus_types::ForkData;
use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit;
use lightclient_circuits::halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr};
use lightclient_circuits::util::{Eth2ConfigPinning, Halo2ConfigPinning};
use lightclient_circuits::{
halo2_base::gates::circuit::CircuitBuilderStage, sync_step_circuit::StepCircuit,
util::AppCircuit,
};
use snark_verifier_sdk::CircuitExt;

use super::*;
use beacon_api_client::mainnet::Client as MainnetClient;
use reqwest::Url;

#[tokio::test]
async fn test_both_circuit_sepolia() {
const K: u32 = 21;
let client =
MainnetClient::new(Url::parse("https://lodestar-sepolia.chainsafe.io").unwrap());

let block = get_block_header(&client, BlockId::Finalized).await.unwrap();
let slot = block.slot;
let period = slot / (32 * 256);

println!(
"Fetching light client update at current Slot: {} at Period: {}",
slot, period
);

// Fetch light client update and create circuit arguments
let (s, mut c) = {
let mut update = get_light_client_update_at_period(&client, period)
.await
.unwrap();

let block_root = client
.get_beacon_block_root(BlockId::Slot(slot))
.await
.unwrap();

let bootstrap = get_light_client_bootstrap(&client, block_root)
.await
.unwrap();

let pubkeys_compressed = bootstrap.current_sync_committee.pubkeys;

let fork_version = client
.get_fork(StateId::Head)
.await
.unwrap()
.current_version;
let genesis_validators_root = client
.get_genesis_details()
.await
.unwrap()
.genesis_validators_root;
let fork_data = ForkData {
genesis_validators_root,
fork_version,
};
let domain = compute_domain(DomainType::SyncCommittee, &fork_data).unwrap();
light_client_update_to_args::<Testnet>(&mut update, pubkeys_compressed, domain)
.await
.unwrap()
};

let mut finalized_sync_committee_branch = {
let block_root = client
.get_beacon_block_root(BlockId::Slot(s.finalized_header.slot))
.await
.unwrap();

get_light_client_bootstrap::<Testnet, _>(&client, block_root)
.await
.unwrap()
.current_sync_committee_branch
.iter()
.map(|n| n.to_vec())
.collect_vec()
};

// Magic swap of sync committee branch
finalized_sync_committee_branch.insert(0, c.sync_committee_branch[0].clone());
finalized_sync_committee_branch[1] = c.sync_committee_branch[1].clone();
c.sync_committee_branch = finalized_sync_committee_branch;
// Replaces the attested header with step circuits finalized header
c.finalized_header = s.finalized_header.clone();

let circuit =
StepCircuit::<Testnet, Fr>::mock_circuit(CircuitBuilderStage::Mock, None, &s, K)
.unwrap();

let prover = MockProver::<Fr>::run(K, &circuit, circuit.instances()).unwrap();
prover.assert_satisfied_par();

const CONFIG_PATH: &str = "../lightclient-circuits/config/committee_update_testnet.json";

let pinning = Eth2ConfigPinning::from_path(CONFIG_PATH);
let circuit = CommitteeUpdateCircuit::<Testnet, Fr>::mock_circuit(
CircuitBuilderStage::Mock,
Some(pinning),
&c,
K,
)
.unwrap();

let prover = MockProver::<Fr>::run(K, &circuit, circuit.instances()).unwrap();
prover.assert_satisfied_par();
}
}
7 changes: 4 additions & 3 deletions preprocessor/src/rotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ where

/// Converts a [`LightClientUpdateCapella`] to a [`CommitteeUpdateArgs`] witness.
pub async fn rotation_args_from_update<S: Spec>(
update: &mut LightClientUpdateCapella<
update: &LightClientUpdateCapella<
{ S::SYNC_COMMITTEE_SIZE },
{ S::SYNC_COMMITTEE_ROOT_INDEX },
{ S::SYNC_COMMITTEE_DEPTH },
Expand All @@ -60,6 +60,7 @@ where
[(); S::SYNC_COMMITTEE_DEPTH]:,
[(); S::FINALIZED_HEADER_INDEX]:,
{
let mut update = update.clone();
let pubkeys_compressed = update
.next_sync_committee
.pubkeys
Expand Down Expand Up @@ -94,7 +95,7 @@ where

let args = CommitteeUpdateArgs::<S> {
pubkeys_compressed,
finalized_header: update.attested_header.beacon.clone(),
finalized_header: update.finalized_header.beacon.clone(),
sync_committee_branch: sync_committee_branch
.into_iter()
.map(|n| n.to_vec())
Expand All @@ -121,7 +122,7 @@ mod tests {

#[tokio::test]
async fn test_rotation_circuit_sepolia() {
const CONFIG_PATH: &str = "../lightclient-circuits/config/committee_update.json";
const CONFIG_PATH: &str = "../lightclient-circuits/config/committee_update_testnet.json";
const K: u32 = 21;
let client =
MainnetClient::new(Url::parse("https://lodestar-sepolia.chainsafe.io").unwrap());
Expand Down
5 changes: 3 additions & 2 deletions prover/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize};
use url::Url;

use crate::rpc_api::{
CommitteeUpdateEvmProofResult, GenProofStepParams, SyncStepCompressedEvmProofResult,
RPC_EVM_PROOF_COMMITTEE_UPDATE_CIRCUIT_COMPRESSED, RPC_EVM_PROOF_STEP_CIRCUIT_COMPRESSED, GenProofCommitteeUpdateParams,
CommitteeUpdateEvmProofResult, GenProofCommitteeUpdateParams, GenProofStepParams,
SyncStepCompressedEvmProofResult, RPC_EVM_PROOF_COMMITTEE_UPDATE_CIRCUIT_COMPRESSED,
RPC_EVM_PROOF_STEP_CIRCUIT_COMPRESSED,
};

/// Error object in a response
Expand Down
2 changes: 1 addition & 1 deletion prover/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Code: https://github.com/ChainSafe/Spectre
// SPDX-License-Identifier: LGPL-3.0-only

use std::{env, ops::Deref, sync::Arc};
use std::{ops::Deref, sync::Arc};

use beacon_api_client::{BlockId, VersionedValue};
use ethereum_consensus_types::LightClientBootstrap;
Expand Down

0 comments on commit d354dd0

Please sign in to comment.