From 222f0b529009769bfb3bae5cd2485a98ab752408 Mon Sep 17 00:00:00 2001 From: timofey Date: Wed, 29 Nov 2023 12:37:32 +0100 Subject: [PATCH] Use `zkevm-sha256` gates for `Sha256Wide` chip (#33) * 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 * cargo fix --- Cargo.toml | 21 +- .../tests/rotation_input_encoding.rs | 6 +- contracts/rust-abi/lib.rs | 5 +- eth-types/src/lib.rs | 3 +- lightclient-circuits/Cargo.toml | 2 +- ...e_update.json => committee_update_18.json} | 20 +- .../config/committee_update_20.json | 23 - .../config/committee_update_aggregation.json | 21 - .../config/committee_update_verifier_25.json | 12 + .../{sync_step.json => sync_step_22.json} | 0 .../src/committee_update_circuit.rs | 179 +--- lightclient-circuits/src/gadget/common.rs | 285 +----- .../src/gadget/crypto/builder.rs | 3 +- lightclient-circuits/src/gadget/crypto/mod.rs | 6 - .../src/gadget/crypto/sha256_flex.rs | 25 +- .../src/gadget/crypto/sha256_flex/gate.rs | 12 +- .../src/gadget/crypto/sha256_flex/spread.rs | 10 +- .../src/gadget/crypto/sha256_wide.rs | 230 ++--- .../src/gadget/crypto/sha256_wide/config.rs | 910 ------------------ .../src/gadget/crypto/sha256_wide/gate.rs | 202 ++-- .../src/gadget/crypto/sha256_wide/util.rs | 151 --- .../src/gadget/crypto/sha256_wide/witness.rs | 292 ------ lightclient-circuits/src/lib.rs | 3 +- lightclient-circuits/src/ssz_merkle.rs | 255 +---- lightclient-circuits/src/sync_step_circuit.rs | 56 +- lightclient-circuits/src/util.rs | 45 - lightclient-circuits/src/util/circuit.rs | 4 +- lightclient-circuits/src/util/common.rs | 107 +- .../src/util/constraint_builder.rs | 186 ---- lightclient-circuits/src/witness/rotation.rs | 10 +- lightclient-circuits/tests/step.rs | 17 +- preprocessor/src/lib.rs | 6 +- preprocessor/src/rotation.rs | 23 +- preprocessor/src/sync.rs | 4 +- prover/src/rpc.rs | 6 +- test-utils/src/conversions.rs | 2 +- test-utils/src/lib.rs | 7 +- 37 files changed, 365 insertions(+), 2784 deletions(-) rename lightclient-circuits/config/{committee_update.json => committee_update_18.json} (57%) delete mode 100644 lightclient-circuits/config/committee_update_20.json delete mode 100644 lightclient-circuits/config/committee_update_aggregation.json create mode 100644 lightclient-circuits/config/committee_update_verifier_25.json rename lightclient-circuits/config/{sync_step.json => sync_step_22.json} (100%) delete mode 100644 lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs delete mode 100644 lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs delete mode 100644 lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs delete mode 100644 lightclient-circuits/src/util/constraint_builder.rs diff --git a/Cargo.toml b/Cargo.toml index e2c9c6af..b72e7da0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,9 @@ halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "comm "jemallocator" ] } halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } -halo2curves = { git = "https://github.com/axiom-crypto/halo2curves", version = "0.4.0" } +zkevm-hashes = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } + +halo2curves = { package = "halo2curves-axiom", version = "0.4.2" } # verifier SDK @@ -73,7 +75,6 @@ ff = "0.12" sha2 = { version = "0.10.6", features = ["compress"] } uint = "0.9.1" ark-std = { version = "0.4.0", features = ["print-trace"] } -poseidon_native = { git = "https://github.com/axiom-crypto/halo2.git", branch = "axiom/dev", package = "poseidon" } # misc itertools = "0.11.0" @@ -82,21 +83,22 @@ serde_json = "1.0.78" log = "0.4.14" hex = "0.4" -[patch."https://github.com/axiom-crypto/halo2curves"] -halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "support_bls12-381" } -# halo2curves = { path = "../halo2curves" } +[patch.crates-io] +halo2curves = { git = "https://github.com/timoftime/halo2curves", package = "halo2curves-axiom", rev = "f3bb3f5a7d3a8ca806368f185c112283a73a94cb" } +ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } [patch."https://github.com/axiom-crypto/halo2-lib"] -halo2-base = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ +halo2-base = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/zkevm-sha256-builder", default-features = false, features = [ "halo2-pse", "display", "jemallocator" ] } -halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ +halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/zkevm-sha256-builder", default-features = false, features = [ "halo2-pse", "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 = [ # "halo2-pse", # "display", @@ -104,12 +106,11 @@ halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls # halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false, features = [ # "halo2-pse", # ] } +# zkevm-hashes = { path = "../halo2-lib/hashes/zkevm", default-features = false } + [patch."https://github.com/axiom-crypto/snark-verifier.git"] snark-verifier = { git = "https://github.com/timoftime/snark-verifier", branch = "halo2-pse-fix", default-features = false } snark-verifier-sdk = { git = "https://github.com/timoftime/snark-verifier", branch = "halo2-pse-fix", default-features = false } # snark-verifier = { path = "../snark-verifier/snark-verifier" } # snark-verifier-sdk = { path = "../snark-verifier/snark-verifier-sdk" } - -[patch.crates-io] -ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } diff --git a/contract-tests/tests/rotation_input_encoding.rs b/contract-tests/tests/rotation_input_encoding.rs index 569ee89a..14543727 100644 --- a/contract-tests/tests/rotation_input_encoding.rs +++ b/contract-tests/tests/rotation_input_encoding.rs @@ -9,7 +9,7 @@ use eth_types::LIMB_BITS; use ethers::contract::abigen; use itertools::Itertools; use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; -use lightclient_circuits::halo2_proofs::halo2curves::bn256::{self, Fr}; +use lightclient_circuits::halo2_proofs::halo2curves::bn256; use lightclient_circuits::poseidon::poseidon_committee_commitment_from_compressed; use lightclient_circuits::witness::CommitteeRotationArgs; use rstest::rstest; @@ -24,11 +24,11 @@ abigen!( ); // CommitteeRotationArgs type produced by abigen macro matches the solidity struct type -impl From> for RotateInput +impl From> for RotateInput where [(); Spec::SYNC_COMMITTEE_SIZE]:, { - fn from(args: CommitteeRotationArgs) -> Self { + fn from(args: CommitteeRotationArgs) -> Self { let poseidon_commitment_le = poseidon_committee_commitment_from_compressed( &args.pubkeys_compressed.iter().cloned().collect_vec(), ) diff --git a/contracts/rust-abi/lib.rs b/contracts/rust-abi/lib.rs index 6a090ac6..ca7cc0e5 100644 --- a/contracts/rust-abi/lib.rs +++ b/contracts/rust-abi/lib.rs @@ -1,7 +1,6 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs)] use ethers::contract::abigen; -use halo2curves::bn256::Fr; use itertools::Itertools; use lightclient_circuits::{ poseidon::poseidon_committee_commitment_from_compressed, @@ -57,11 +56,11 @@ impl From> for SyncStepInput { } // CommitteeRotationArgs type produced by abigen macro matches the solidity struct type -impl From> for RotateInput +impl From> for RotateInput where [(); Spec::SYNC_COMMITTEE_SIZE]:, { - fn from(args: CommitteeRotationArgs) -> Self { + fn from(args: CommitteeRotationArgs) -> Self { let poseidon_commitment_le = poseidon_committee_commitment_from_compressed( &args.pubkeys_compressed.iter().cloned().collect_vec(), ) diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index 735d57ec..12cb69e3 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -5,9 +5,10 @@ #![feature(trait_alias)] mod spec; use halo2_base::utils::BigPrimeField; +use halo2curves::ff::PrimeField; pub use spec::{Mainnet, Minimal, Spec, Testnet}; pub const NUM_LIMBS: usize = 4; pub const LIMB_BITS: usize = 112; -pub trait Field = BigPrimeField; +pub trait Field = BigPrimeField + PrimeField; diff --git a/lightclient-circuits/Cargo.toml b/lightclient-circuits/Cargo.toml index 76ee3dfa..c1dc9ce3 100644 --- a/lightclient-circuits/Cargo.toml +++ b/lightclient-circuits/Cargo.toml @@ -10,6 +10,7 @@ license = "MIT OR Apache-2.0" halo2curves.workspace = true halo2-base.workspace = true halo2-ecc.workspace = true +zkevm-hashes.workspace = true # verifier SDK snark-verifier.workspace = true @@ -37,7 +38,6 @@ serde_json.workspace = true itertools.workspace = true log.workspace = true hex.workspace = true -poseidon_native.workspace = true rayon = "1.7.0" array-init = "2.0.0" strum = "0.25" diff --git a/lightclient-circuits/config/committee_update.json b/lightclient-circuits/config/committee_update_18.json similarity index 57% rename from lightclient-circuits/config/committee_update.json rename to lightclient-circuits/config/committee_update_18.json index e0ff3c54..0bfba944 100644 --- a/lightclient-circuits/config/committee_update.json +++ b/lightclient-circuits/config/committee_update_18.json @@ -1,8 +1,8 @@ { "params": { - "k": 20, + "k": 18, "num_advice_per_phase": [ - 4 + 12 ], "num_fixed": 1, "num_lookup_advice_per_phase": [ @@ -15,9 +15,17 @@ }, "break_points": [ [ - 1048564, - 1048566, - 1048565 + 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_20.json b/lightclient-circuits/config/committee_update_20.json deleted file mode 100644 index e0ff3c54..00000000 --- a/lightclient-circuits/config/committee_update_20.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "params": { - "k": 20, - "num_advice_per_phase": [ - 4 - ], - "num_fixed": 1, - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "lookup_bits": 8, - "num_instance_columns": 1 - }, - "break_points": [ - [ - 1048564, - 1048566, - 1048565 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_aggregation.json b/lightclient-circuits/config/committee_update_aggregation.json deleted file mode 100644 index c2ab190d..00000000 --- a/lightclient-circuits/config/committee_update_aggregation.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "params": { - "degree": 22, - "num_advice": 9, - "num_lookup_advice": 2, - "num_fixed": 1, - "lookup_bits": 8 - }, - "break_points": [ - [ - 4194292, - 4194294, - 4194292, - 4194293, - 4194293, - 4194293, - 4194293, - 4194294 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_verifier_25.json b/lightclient-circuits/config/committee_update_verifier_25.json new file mode 100644 index 00000000..9d724c53 --- /dev/null +++ b/lightclient-circuits/config/committee_update_verifier_25.json @@ -0,0 +1,12 @@ +{ + "params": { + "degree": 25, + "num_advice": 1, + "num_lookup_advice": 1, + "num_fixed": 1, + "lookup_bits": 8 + }, + "break_points": [ + [] + ] + } diff --git a/lightclient-circuits/config/sync_step.json b/lightclient-circuits/config/sync_step_22.json similarity index 100% rename from lightclient-circuits/config/sync_step.json rename to lightclient-circuits/config/sync_step_22.json diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 7222f85c..0c5736a6 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -36,11 +36,11 @@ impl CommitteeUpdateCircuit { fn synthesize( builder: &mut ShaCircuitBuilder>, fp_chip: &FpChip, - args: &witness::CommitteeRotationArgs, + args: &witness::CommitteeRotationArgs, ) -> Result>, Error> { let range = fp_chip.range(); - let sha256_chip = Sha256ChipWide::new(range, args.randomness); + let sha256_chip = Sha256ChipWide::new(range); let compressed_encodings = args .pubkeys_compressed @@ -83,6 +83,7 @@ impl CommitteeUpdateCircuit { args.finalized_header.body_root.as_ref().into_witness(), ], )?; + // Verify that the sync committee root is in the finalized state root verify_merkle_proof( builder, @@ -149,7 +150,7 @@ impl CommitteeUpdateCircuit { .pad_using(64, |_| builder.main().load_zero()) .into(); hasher - .digest::<64>(builder, HashInput::Single(input), false) + .digest(builder, HashInput::Single(input)) .map(|r| r.into_iter().collect_vec().into()) }) .collect::, _>>()?; @@ -157,7 +158,7 @@ impl CommitteeUpdateCircuit { } pub fn instance( - args: &witness::CommitteeRotationArgs, + args: &witness::CommitteeRotationArgs, limb_bits: usize, ) -> Vec> where @@ -201,12 +202,12 @@ impl CommitteeUpdateCircuit { impl AppCircuit for CommitteeUpdateCircuit { type Pinning = Eth2ConfigPinning; - type Witness = witness::CommitteeRotationArgs; + type Witness = witness::CommitteeRotationArgs; fn create_circuit( stage: CircuitBuilderStage, pinning: Option, - witness: &witness::CommitteeRotationArgs, + witness: &witness::CommitteeRotationArgs, k: u32, ) -> Result, Error> { let mut builder = Eth2CircuitBuilder::>::from_stage(stage) @@ -244,8 +245,8 @@ mod tests { use std::fs; use crate::{ - aggregation::AggregationConfigPinning, gadget::crypto::constant_randomness, - util::Halo2ConfigPinning, witness::CommitteeRotationArgs, + aggregation::AggregationConfigPinning, util::Halo2ConfigPinning, + witness::CommitteeRotationArgs, }; use super::*; @@ -264,7 +265,7 @@ mod tests { use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk}; use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, CircuitExt, Snark}; - fn load_circuit_args() -> CommitteeRotationArgs { + fn load_circuit_args() -> CommitteeRotationArgs { #[derive(serde::Deserialize)] struct ArgsJson { finalized_header: BeaconBlockHeader, @@ -280,7 +281,6 @@ mod tests { CommitteeRotationArgs { pubkeys_compressed, - randomness: constant_randomness(), _spec: PhantomData, finalized_header, sync_committee_branch: committee_root_branch, @@ -290,7 +290,7 @@ mod tests { fn gen_application_snark( params: &ParamsKZG, pk: &ProvingKey, - witness: &CommitteeRotationArgs, + witness: &CommitteeRotationArgs, pinning_path: &str, ) -> Snark { CommitteeUpdateCircuit::::gen_snark_shplonk( @@ -310,7 +310,7 @@ mod tests { let witness = load_circuit_args(); - let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); + let pinning = Eth2ConfigPinning::from_path("./config/committee_update_18.json"); let circuit = CommitteeUpdateCircuit::::create_circuit( CircuitBuilderStage::Mock, Some(pinning), @@ -338,7 +338,7 @@ mod tests { PKEY_PATH, PINNING_PATH, false, - &CommitteeRotationArgs::::default(), + &CommitteeRotationArgs::::default(), ); let witness = load_circuit_args(); @@ -353,58 +353,20 @@ mod tests { } #[test] - fn test_circuit_aggregation_proofgen() { - const APP_PINNING_PATH: &str = "./config/committee_update_20.json"; - const APP_PK_PATH: &str = "../build/committee_update_20.pkey"; - const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; - const APP_K: u32 = 20; + fn test_committee_update_aggregation_evm() { + const APP_K: u32 = 18; + const APP_PK_PATH: &str = "../build/committee_update_18.pkey"; + const APP_PINNING_PATH: &str = "./config/committee_update_18.json"; + const AGG_CONFIG_PATH: &str = "./config/committee_update_verifier_25.json"; let params_app = gen_srs(APP_K); - const AGG_K: u32 = 22; + const AGG_K: u32 = 25; let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( ¶ms_app, APP_PK_PATH, APP_PINNING_PATH, false, - &CommitteeRotationArgs::::default(), - ); - let witness = load_circuit_args(); - let snark = gen_application_snark(¶ms_app, &pk_app, &witness, APP_PINNING_PATH); - - let params = gen_srs(AGG_K); - println!("agg_params k: {:?}", params.k()); - - let pk = AggregationCircuit::read_or_create_pk( - ¶ms, - "../build/committee_update_aggregation_22.pkey", - AGG_CONFIG_PATH, - false, - &vec![snark.clone()], - ); - - let _ = AggregationCircuit::gen_proof_shplonk( - ¶ms, - &pk, - AGG_CONFIG_PATH, - &vec![snark.clone()], - ) - .expect("proof generation & verification should not fail"); - } - - #[test] - fn test_circuit_aggregation_evm() { - const APP_K: u32 = 21; - const APP_PINNING_PATH: &str = "./config/committee_update_21.json"; - const AGG_CONFIG_PATH: &str = "./config/committee_update_a.json"; - let params_app = gen_srs(APP_K); - - const AGG_K: u32 = 23; - let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( - ¶ms_app, - APP_PINNING_PATH, - APP_PINNING_PATH, - false, - &CommitteeRotationArgs::::default(), + &CommitteeRotationArgs::::default(), ); let witness = load_circuit_args(); @@ -415,7 +377,7 @@ mod tests { let pk = AggregationCircuit::read_or_create_pk( ¶ms, - "../build/aggregation.pkey", + "../build/committee_update_verifier_25.pkey", AGG_CONFIG_PATH, false, &vec![snark.clone()], @@ -442,108 +404,11 @@ mod tests { let deployment_code = AggregationCircuit::gen_evm_verifier_shplonk( ¶ms, &pk, - Some("contractyul"), + None::, &vec![snark], ) .unwrap(); println!("deployment_code size: {}", deployment_code.len()); evm_verify(deployment_code, instances, proof); } - - // #[test] - // fn test_circuit_aggregation_2_evm() { - // const K0: u32 = 20; - // const K1: u32 = 24; - // const K2: u32 = 24; - - // const APP_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; - // const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation_1.json"; - // const AGG_FINAL_CONFIG_PATH: &str = "./config/committee_update_aggregation_2.json"; - - // // Layer 0 snark gen - // let l0_snark = { - // let p0 = gen_srs(K0); - // let pk_l0 = CommitteeUpdateCircuit::::read_or_create_pk( - // &p0, - // "../build/committee_update.pkey", - // APP_CONFIG_PATH, - // false, - // &CommitteeRotationArgs::::default(), - // ); - // let witness = load_circuit_args(); - // let snark = gen_application_snark(&p0, &pk_l0, &witness); - // println!( - // "L0 num instances: {:?}", - // snark.instances.iter().map(|i| i.len()).collect_vec() - // ); - // println!("L0 snark size: {}", snark.proof.len()); - // snark - // }; - - // // Layer 1 snark gen - // let l1_snark = { - // let p1 = gen_srs(K1); - // let pk_l1 = AggregationCircuit::read_or_create_pk( - // &p1, - // "./build/l1_aggregation.pkey", - // AGG_CONFIG_PATH, - // false, - // &vec![l0_snark.clone()], - // ); - - // let pinning = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); - // let lookup_bits = K1 as usize - 1; - // let circuit = AggregationCircuit::create_circuit( - // CircuitBuilderStage::Prover, - // Some(pinning), - // &vec![l0_snark.clone()], - // K1, - // ) - // .unwrap(); - - // println!("L1 Prover num_instances: {:?}", circuit.num_instance()); - // let snark = gen_snark_shplonk(&p1, &pk_l1, circuit, None::); - // println!("L1 snark size: {}", snark.proof.len()); - - // snark - // }; - - // // Layer 2 snark gen - // let (proof, deployment_code, instances) = { - // let p2 = gen_srs(K2); - // let pk_l2 = AggregationCircuit::read_or_create_pk( - // &p2, - // "./build/l2_aggregation.pkey", - // AGG_FINAL_CONFIG_PATH, - // false, - // &vec![l0_snark.clone()], - // ); - // let pinning = AggregationConfigPinning::from_path(AGG_FINAL_CONFIG_PATH); - - // let mut circuit = AggregationCircuit::create_circuit( - // CircuitBuilderStage::Prover, - // Some(pinning), - // &vec![l1_snark.clone()], - // K2, - // ) - // .unwrap(); - // let num_instances = circuit.num_instance(); - - // let deployment_code = gen_evm_verifier_shplonk::( - // &p2, - // pk_l2.get_vk(), - // vec![65], - // Some(&PathBuf::from("contractyul")), - // ); - // let instances = circuit.instances(); - // println!("L2 Prover num_instances: {:?}", num_instances); - - // let proof = gen_evm_proof_shplonk(&p2, &pk_l2, circuit, instances.clone()); - // println!("L2 proof size: {}", proof.len()); - // println!("L2 Deployment Code Size: {}", deployment_code.len()); - // (proof, deployment_code, instances) - // }; - - // evm_verify(deployment_code, instances, proof); - // } } diff --git a/lightclient-circuits/src/gadget/common.rs b/lightclient-circuits/src/gadget/common.rs index f75351c2..b1f5dbc1 100644 --- a/lightclient-circuits/src/gadget/common.rs +++ b/lightclient-circuits/src/gadget/common.rs @@ -1,263 +1,28 @@ //! Utility traits, functions used in the crate. use eth_types::Field; -use halo2_base::halo2_proofs::plonk::Expression; - -/// Returns the sum of the passed in cells -pub mod sum { - use super::{Expr, Expression, Field}; - - /// Returns an expression for the sum of the list of expressions. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { - inputs - .into_iter() - .fold(0.expr(), |acc, input| acc + input.expr()) - } - - /// Returns the sum of the given list of values within the field. - pub fn value(values: &[u8]) -> F { - values - .iter() - .fold(F::ZERO, |acc, value| acc + F::from(*value as u64)) - } -} - -/// Returns `1` when `expr[0] && expr[1] && ... == 1`, and returns `0` -/// otherwise. Inputs need to be boolean -pub mod and { - use super::{Expr, Expression, Field}; - - /// Returns an expression that evaluates to 1 only if all the expressions in - /// the given list are 1, else returns 0. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { - inputs - .into_iter() - .fold(1.expr(), |acc, input| acc * input.expr()) - } - - /// Returns the product of all given values. - pub fn value(inputs: Vec) -> F { - inputs.iter().fold(F::ONE, |acc, input| acc * input) - } -} - -/// Returns `1` when `expr[0] || expr[1] || ... == 1`, and returns `0` -/// otherwise. Inputs need to be boolean -pub mod or { - use super::{and, not}; - use super::{Expr, Expression, Field}; - - /// Returns an expression that evaluates to 1 if any expression in the given - /// list is 1. Returns 0 if all the expressions were 0. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { - not::expr(and::expr(inputs.into_iter().map(not::expr))) - } - - /// Returns the value after passing all given values through the OR gate. - pub fn value(inputs: Vec) -> F { - not::value(and::value(inputs.into_iter().map(not::value).collect())) - } -} - -/// Returns `1` when `b == 0`, and returns `0` otherwise. -/// `b` needs to be boolean -pub mod not { - use super::{Expr, Expression, Field}; - - /// Returns an expression that represents the NOT of the given expression. - pub fn expr>(b: E) -> Expression { - 1.expr() - b.expr() - } - - /// Returns a value that represents the NOT of the given value. - pub fn value(b: F) -> F { - F::ONE - b - } -} - -/// Returns `a ^ b`. -/// `a` and `b` needs to be boolean -pub mod xor { - use super::{Expr, Expression, Field}; - - /// Returns an expression that represents the XOR of the given expression. - pub fn expr>(a: E, b: E) -> Expression { - a.expr() + b.expr() - 2.expr() * a.expr() * b.expr() - } - - /// Returns a value that represents the XOR of the given value. - pub fn value(a: F, b: F) -> F { - a + b - F::from(2u64) * a * b - } -} - -/// Returns `when_true` when `selector == 1`, and returns `when_false` when -/// `selector == 0`. `selector` needs to be boolean. -pub mod select { - use super::{Expr, Expression, Field}; - - /// Returns the `when_true` expression when the selector is true, else - /// returns the `when_false` expression. - pub fn expr( - selector: Expression, - when_true: Expression, - when_false: Expression, - ) -> Expression { - selector.clone() * when_true + (1.expr() - selector) * when_false - } - - /// Returns the `when_true` value when the selector is true, else returns - /// the `when_false` value. - pub fn value(selector: F, when_true: F, when_false: F) -> F { - selector * when_true + (F::ONE - selector) * when_false - } - - /// Returns the `when_true` word when selector is true, else returns the - /// `when_false` word. - pub fn value_word( - selector: F, - when_true: [u8; 32], - when_false: [u8; 32], - ) -> [u8; 32] { - if selector == F::ONE { - when_true - } else { - when_false - } - } -} - -/// Trait that implements functionality to get a constant expression from -/// commonly used types. -pub trait Expr { - /// Returns an expression for the type. - fn expr(&self) -> Expression; -} - -/// Implementation trait `Expr` for type able to be casted to u64 -#[macro_export] -macro_rules! impl_expr { - ($type:ty) => { - impl Expr for $type { - #[inline] - fn expr(&self) -> Expression { - Expression::Constant(F::from(*self as u64)) - } - } - }; - ($type:ty, $method:path) => { - impl $super::Expr for $type { - #[inline] - fn expr(&self) -> Expression { - Expression::Constant(F::from($method(self) as u64)) - } - } - }; -} - -impl_expr!(bool); -impl_expr!(u8); -impl_expr!(u64); -impl_expr!(usize); - -impl Expr for Expression { - #[inline] - fn expr(&self) -> Expression { - self.clone() - } -} - -impl Expr for &Expression { - #[inline] - fn expr(&self) -> Expression { - (*self).clone() - } -} - -impl Expr for i32 { - #[inline] - fn expr(&self) -> Expression { - Expression::Constant( - F::from(self.unsigned_abs() as u64) * if self.is_negative() { -F::ONE } else { F::ONE }, - ) - } -} - -/// Given a bytes-representation of an expression, it computes and returns the -/// single expression. -pub fn expr_from_bytes>(bytes: &[E]) -> Expression { - let mut value = 0.expr(); - let mut multiplier = F::ONE; - for byte in bytes.iter() { - value = value + byte.expr() * multiplier; - multiplier *= F::from(256); - } - value -} - -/// Returns the random linear combination of the inputs. -/// Encoding is done as follows: v_0 * R^0 + v_1 * R^1 + ... -pub mod rlc { - use std::ops::{Add, Mul}; - - use super::{Expr, Expression, Field}; - use halo2_base::{gates::GateInstructions, AssignedValue, Context, QuantumCell}; - - /// Returns an expression that represents the random linear combination. - pub fn expr>(expressions: &[E], randomness: E) -> Expression { - if !expressions.is_empty() { - generic(expressions.iter().map(|e| e.expr()), randomness.expr()) - } else { - 0.expr() - } - } - - /// Returns the random linear combination of the inputs. - pub fn value<'a, F: Field, I>(values: I, randomness: F) -> F - where - I: IntoIterator, - ::IntoIter: DoubleEndedIterator, - { - let values = values - .into_iter() - .map(|v| F::from(*v as u64)) - .collect::>(); - if !values.is_empty() { - generic(values, randomness) - } else { - F::ZERO - } - } - - /// Returns the random linear combination of the halo2-lib assigned values. - pub fn assigned_value( - values: &[AssignedValue], - randomness: &QuantumCell, - gate: &impl GateInstructions, - ctx: &mut Context, - ) -> AssignedValue { - if !values.is_empty() { - let mut values = values.iter(); - let init = values.next().expect("values should not be empty"); - - values.fold(*init, |acc, value| { - gate.mul_add(ctx, acc, *randomness, *value) - }) - } else { - ctx.load_zero() - } - } - - fn generic(values: I, randomness: R) -> V - where - I: IntoIterator, - ::IntoIter: DoubleEndedIterator, - V: Clone + Add + Add + Mul, - R: Clone, - { - // we don't reverse bytes because https://github.com/ChainSafe/Banshee/issues/72 - let mut values = values.into_iter(); - let init = values.next().expect("values should not be empty"); - - values.fold(init, |acc, value| acc * randomness.clone() + value) - } +use halo2_base::{gates::GateInstructions, AssignedValue, Context, QuantumCell}; +use itertools::Itertools; + +pub fn to_bytes_le( + a: &AssignedValue, + gate: &impl GateInstructions, + ctx: &mut Context, +) -> Vec> { + let byte_bases = (0..MAX_BYTES) + .map(|i| QuantumCell::Constant(gate.pow_of_two()[i * 8])) + .collect_vec(); + + let assigned_bytes = a + .value() + .to_bytes_le() + .into_iter() + .take(MAX_BYTES) + .map(|v| ctx.load_witness(F::from(v as u64))) + .collect_vec(); + + // Constrain poseidon bytes to be equal to the recovered checksum + let checksum = gate.inner_product(ctx, assigned_bytes.clone(), byte_bases); + ctx.constrain_equal(a, &checksum); + + assigned_bytes } diff --git a/lightclient-circuits/src/gadget/crypto/builder.rs b/lightclient-circuits/src/gadget/crypto/builder.rs index 4c22cb6d..26aca908 100644 --- a/lightclient-circuits/src/gadget/crypto/builder.rs +++ b/lightclient-circuits/src/gadget/crypto/builder.rs @@ -18,7 +18,6 @@ use halo2_base::{ circuit::{Layouter, SimpleFloorPlanner}, plonk::{Circuit, ConstraintSystem, Error}, }, - utils::BigPrimeField, AssignedValue, Context, }; use itertools::Itertools; @@ -32,7 +31,7 @@ pub struct SHAConfig> { pub base: BaseConfig, } -impl> SHAConfig { +impl> SHAConfig { pub fn configure(meta: &mut ConstraintSystem, params: BaseCircuitParams) -> Self { let base = BaseConfig::configure(meta, params); let compression = GateConfig::configure(meta); diff --git a/lightclient-circuits/src/gadget/crypto/mod.rs b/lightclient-circuits/src/gadget/crypto/mod.rs index 46fc5610..69e2f05b 100644 --- a/lightclient-circuits/src/gadget/crypto/mod.rs +++ b/lightclient-circuits/src/gadget/crypto/mod.rs @@ -5,7 +5,6 @@ mod sha256_flex; mod sha256_wide; pub use builder::{SHAConfig, ShaCircuitBuilder}; -use eth_types::Field; use halo2_ecc::{ bigint::ProperCrtUint, bls12_381::{Fp2Chip, Fp2Point, FpChip}, @@ -26,8 +25,3 @@ pub type G1Chip<'chip, F> = EccChip<'chip, F, FpChip<'chip, F>>; pub type G2Chip<'chip, F> = EccChip<'chip, F, Fp2Chip<'chip, F>>; pub use halo2_ecc::ecc::hash_to_curve::HashInstructions; - -// This is a temporary measure. TODO: use challenges API. -pub fn constant_randomness() -> F { - F::from_u128(0xca9d6022267d3bd658bf) -} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs index d32d4bc8..a9138abc 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs @@ -35,14 +35,14 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { type CircuitBuilder = ShaCircuitBuilder>; type Output = Vec>; - fn digest( + fn digest_varlen( &self, builder: &mut Self::CircuitBuilder, input: impl IntoIterator>, - strict: bool, + max_len: usize, ) -> Result>, Error> { let max_processed_bytes = { - let mut max_bytes = MAX_INPUT_SIZE + 9; + let mut max_bytes = max_len + 9; let remainder = max_bytes % 64; if remainder != 0 { max_bytes += 64 - remainder; @@ -62,10 +62,11 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { let input_byte_size = assigned_input_bytes.len(); let input_byte_size_with_9 = input_byte_size + 9; - assert!(input_byte_size <= MAX_INPUT_SIZE); let range = self.spread.range(); let gate = &range.gate; + assert!(input_byte_size <= max_len); + let one_round_size = Self::BLOCK_SIZE; let num_round = if input_byte_size_with_9 % one_round_size == 0 { @@ -100,12 +101,6 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { // assigned_input_bytes.push(assign_byte(0u8)); // } - if strict { - for &assigned in assigned_input_bytes.iter() { - range.range_check(builder.main(), assigned, 8); - } - } - let assigned_num_round = builder.main().load_witness(F::from(num_round as u64)); // compute an initial state from the precomputed_input. @@ -171,6 +166,16 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { Ok(output_digest_bytes) } + + fn digest( + &self, + ctx: &mut Self::CircuitBuilder, + input: impl IntoIterator>, + ) -> Result { + let input = input.into_iter().collect_vec(); + let input_len = input.len(); + self.digest_varlen(ctx, input, input_len) + } } impl<'a, F: Field> Sha256Chip<'a, F> { diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs index b5264411..6f1b902e 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs @@ -1,9 +1,9 @@ use std::any::TypeId; +use eth_types::Field; use getset::CopyGetters; use halo2_base::{ halo2_proofs::circuit::{Region, Value}, - utils::BigPrimeField, virtual_region::{ copy_constraints::{CopyConstraintManager, SharedCopyConstraintManager}, manager::VirtualRegionManager, @@ -22,7 +22,7 @@ struct Dence; struct Spread; #[derive(Clone, Debug, Default, CopyGetters)] -pub struct ShaFlexGateManager { +pub struct ShaFlexGateManager { #[getset(get_copy = "pub")] witness_gen_only: bool, /// The `unknown` flag is used during key generation. If true, during key generation witness [Value]s are replaced with Value::unknown() for safety. @@ -38,7 +38,7 @@ pub struct ShaFlexGateManager { pub type ShaContexts<'a, F> = (&'a mut Context, &'a mut Context); -impl ShaFlexGateManager { +impl ShaFlexGateManager { /// Mutates `self` to use the given copy manager everywhere, including in all threads. pub fn set_copy_manager(&mut self, copy_manager: SharedCopyConstraintManager) { self.copy_manager = copy_manager.clone(); @@ -79,7 +79,7 @@ impl ShaFlexGateManager { // } } -impl CommonGateManager for ShaFlexGateManager { +impl CommonGateManager for ShaFlexGateManager { type CustomContext<'a> = ShaContexts<'a, F>; fn new(witness_gen_only: bool) -> Self { @@ -116,7 +116,7 @@ impl CommonGateManager for ShaFlexGateManager { } } -impl VirtualRegionManager for ShaFlexGateManager { +impl VirtualRegionManager for ShaFlexGateManager { type Config = SpreadConfig; fn assign_raw(&self, spread: &Self::Config, region: &mut Region) { @@ -149,7 +149,7 @@ impl VirtualRegionManager for ShaFlexGateManager { /// Pure advice witness assignment in a single phase. Uses preprocessed `break_points` to determine when /// to split a thread into a new column. #[allow(clippy::type_complexity)] -pub fn assign_threads_sha( +pub fn assign_threads_sha( threads_dense: &[Context], threads_spread: &[Context], spread: &SpreadConfig, diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs index 439db355..0d670aba 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs @@ -1,3 +1,4 @@ +use eth_types::Field; use halo2_base::utils::{decompose, ScalarField}; use halo2_base::QuantumCell; use halo2_base::{ @@ -7,7 +8,6 @@ use halo2_base::{ plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, poly::Rotation, }, - utils::BigPrimeField, }; use halo2_base::{ gates::{flex_gate::threads::CommonCircuitBuilder, GateInstructions, RangeInstructions}, @@ -23,7 +23,7 @@ use super::util::{bits_le_to_fe, fe_to_bits_le}; use super::ShaFlexGateManager; #[derive(Debug, Clone)] -pub struct SpreadConfig { +pub struct SpreadConfig { pub denses: Vec>, pub spreads: Vec>, pub table_dense: TableColumn, @@ -33,7 +33,7 @@ pub struct SpreadConfig { _f: PhantomData, } -impl SpreadConfig { +impl SpreadConfig { pub fn configure( meta: &mut ConstraintSystem, num_bits_lookup: usize, @@ -77,7 +77,7 @@ impl SpreadConfig { } } -impl GateBuilderConfig for SpreadConfig { +impl GateBuilderConfig for SpreadConfig { fn configure(meta: &mut ConstraintSystem) -> Self { Self::configure(meta, 8, 1) // todo: configure } @@ -129,7 +129,7 @@ pub struct SpreadChip<'a, F: ScalarField> { range: &'a RangeChip, } -impl<'a, F: BigPrimeField> SpreadChip<'a, F> { +impl<'a, F: Field> SpreadChip<'a, F> { pub fn new(range: &'a RangeChip) -> Self { debug_assert_eq!(16 % range.lookup_bits(), 0); diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs index d638c1a5..8dea7a84 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs @@ -1,47 +1,23 @@ -mod config; mod gate; -mod util; -mod witness; use eth_types::Field; -use halo2_base::gates::flex_gate::threads::CommonCircuitBuilder; use halo2_base::gates::RangeChip; +use halo2_base::{gates::flex_gate::threads::CommonCircuitBuilder, Context}; use itertools::Itertools; +use zkevm_hashes::sha256::vanilla::param::NUM_WORDS_TO_ABSORB; +use zkevm_hashes::sha256::vanilla::util::get_num_sha2_blocks; +use zkevm_hashes::{sha256::vanilla::witness::generate_witnesses_sha256, util::word::Word}; -use crate::gadget::crypto::sha256_wide::util::Sha256AssignedRows; -use crate::gadget::crypto::sha256_wide::witness::multi_sha256; -use crate::gadget::rlc; use crate::witness::HashInput; - -use halo2_base::{ - gates::{GateInstructions, RangeInstructions}, - halo2_proofs::plonk::Error, - AssignedValue, QuantumCell, -}; +use halo2_base::{gates::GateInstructions, halo2_proofs::plonk::Error, AssignedValue, QuantumCell}; pub use self::gate::ShaBitGateManager; -use self::util::{NUM_BYTES_FINAL_HASH, NUM_WORDS_TO_ABSORB}; - use super::{HashInstructions, ShaCircuitBuilder}; +use crate::gadget::common::to_bytes_le; #[derive(Debug)] pub struct Sha256ChipWide<'a, F: Field> { range: &'a RangeChip, - randomness: F, -} - -#[derive(Clone, Debug)] -pub struct AssignedSha256Round { - /// Whether the row is final. - pub is_final: AssignedValue, - /// Input length at the row. - pub input_len: AssignedValue, - /// Input words at the row. - pub input_rlcs: [AssignedValue; NUM_WORDS_TO_ABSORB], - /// Whether the row is padding. - pub padding_selectors: [[AssignedValue; 4]; NUM_WORDS_TO_ABSORB], - /// Output words at the row. - pub output_rlc: AssignedValue, } impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { @@ -51,13 +27,12 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { type CircuitBuilder = ShaCircuitBuilder>; type Output = Vec>; - fn digest( + fn digest( &self, builder: &mut Self::CircuitBuilder, input: impl IntoIterator>, - _strict: bool, ) -> Result>, Error> { - let assigned_input = input + let assigned_bytes = input .into_iter() .map(|cell| match cell { QuantumCell::Existing(v) => v, @@ -68,172 +43,79 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { .collect_vec(); let binary_input: HashInput = HashInput::Single( - assigned_input + assigned_bytes .iter() .map(|av| av.value().get_lower_32() as u8) .collect_vec() .into(), ); - let mut assigned_input_bytes = assigned_input.to_vec(); - let rnd = QuantumCell::Constant(self.randomness); - let input_byte_size = assigned_input_bytes.len(); - let max_byte_size = MAX_INPUT_SIZE; - assert!(input_byte_size <= max_byte_size); - let range = &self.range; + let input_len = assigned_bytes.len(); + let range = self.range; let gate = &range.gate; - assert!(assigned_input_bytes.len() <= MAX_INPUT_SIZE); - - let mut assigned_rounds = vec![]; - let assigned_output = - self.load_digest::(builder, binary_input, &mut assigned_rounds)?; + let mut virtual_rows = vec![]; + let input_bytes = binary_input.to_vec(); - let one_round_size = Self::BLOCK_SIZE; + generate_witnesses_sha256(&mut virtual_rows, &input_bytes); + let blocks = builder.sha.load_virtual_rows(virtual_rows); - let num_round = if input_byte_size % one_round_size == 0 { - input_byte_size / one_round_size - } else { - input_byte_size / one_round_size + 1 - }; - let padded_size = one_round_size * num_round; - let zero_padding_byte_size = padded_size - input_byte_size; - let max_round = max_byte_size / one_round_size; + let num_rounds = get_num_sha2_blocks(input_len); - let mut assign_byte = |byte: u8| builder.main().load_witness(F::from(byte as u64)); + let num_input_words = (input_len + 3) / 4; + let num_input_rounds = num_input_words.div_ceil(NUM_WORDS_TO_ABSORB); - for _ in 0..zero_padding_byte_size { - assigned_input_bytes.push(assign_byte(0u8)); - } - - assert_eq!(assigned_input_bytes.len(), num_round * one_round_size); - - for &assigned in assigned_input_bytes.iter() { - range.range_check(builder.main(), assigned, 8); - } + let byte_bases = (0..4) + .map(|i| QuantumCell::Constant(gate.pow_of_two()[i * 8])) + .collect_vec(); - let zero = builder.main().load_zero(); - let mut full_input_len = zero; - - let mut cur_input_rlc = zero; - let ctx_gate = builder.main(); - for round_idx in 0..max_round { - full_input_len = { - let muled = gate.mul( - ctx_gate, - assigned_rounds[round_idx].is_final, - assigned_rounds[round_idx].input_len, - ); - gate.add(ctx_gate, full_input_len, muled) - }; - - for word_idx in 0..NUM_WORDS_TO_ABSORB { - let offset_in = 64 * round_idx + 4 * word_idx; - let assigned_input_u32 = &assigned_input_bytes[offset_in..(offset_in + 4)]; - - for (idx, &assigned_byte) in assigned_input_u32.iter().enumerate() { - let tmp = gate.mul_add(ctx_gate, cur_input_rlc, rnd, assigned_byte); - cur_input_rlc = gate.select( - ctx_gate, - cur_input_rlc, - tmp, - assigned_rounds[round_idx].padding_selectors[word_idx][idx], - ); - } - - ctx_gate.constrain_equal( - &cur_input_rlc, - &assigned_rounds[round_idx].input_rlcs[word_idx], + for r in 0..num_input_rounds { + for w in 0..(num_input_words - r * NUM_WORDS_TO_ABSORB) { + let i = (r * NUM_WORDS_TO_ABSORB + w) * 4; + let checksum = gate.inner_product( + builder.main(), + assigned_bytes[i..i + 4].to_vec(), + byte_bases.clone(), ); + builder + .main() + .constrain_equal(&checksum, &blocks[r].word_values[w]); } - - let hash_rlc = rlc::assigned_value(&assigned_output, &rnd, gate, ctx_gate); - ctx_gate.constrain_equal(&hash_rlc, &assigned_rounds[round_idx].output_rlc); } - Ok(assigned_output.to_vec()) - } -} + let mut hash_bytes = word_to_bytes_le(blocks[num_rounds - 1].hash, gate, builder.main()); + hash_bytes.reverse(); -impl<'a, F: Field> Sha256ChipWide<'a, F> { - pub fn new(range: &'a RangeChip, randomness: F) -> Self { - Self { range, randomness } + Ok(hash_bytes) } - pub fn load_digest( + fn digest_varlen( &self, - builder: &mut ShaCircuitBuilder>, - input: HashInput, - assigned_rounds: &mut Vec>, - ) -> Result<[AssignedValue; NUM_BYTES_FINAL_HASH], Error> { - let max_round = MAX_INPUT_SIZE / Self::BLOCK_SIZE; - - let mut assigned_rows = Sha256AssignedRows::new(); - let witness = multi_sha256(&[input], self.randomness); - let vec_vecs = witness - .iter() - .map(|sha256_row| { - builder - .sha - .sha_contexts() - .load_sha256_row(sha256_row, &mut assigned_rows) - }) - .collect::, Error>>()?; - let hashes: Vec<[_; NUM_BYTES_FINAL_HASH]> = vec_vecs - .into_iter() - .filter_map(|hash_bytes| { - (!hash_bytes.is_empty()).then(|| hash_bytes.try_into().unwrap()) - }) - .collect(); - - assert_eq!(hashes.len(), 1); - - let hash_sha = hashes[0]; - - let ctx_gate = builder.main(); - - let mut reassign_to_gate = |val_sha: AssignedValue| -> AssignedValue { - let val_gate = ctx_gate.load_witness(*val_sha.value()); - ctx_gate.constrain_equal(&val_sha, &val_gate); - val_gate - }; - - for round_idx in 0..max_round { - let input_len = reassign_to_gate(assigned_rows.input_len[round_idx]); - - let input_rlcs = assigned_rows.input_rlc[16 * round_idx..16 * (round_idx + 1)] - .iter() - .map(|v| reassign_to_gate(*v)) - .collect_vec() - .try_into() - .unwrap(); - - let padding_selectors = assigned_rows.padding_selectors - [16 * round_idx..16 * (round_idx + 1)] - .iter() - .map(|values| values.map(&mut reassign_to_gate)) - .collect_vec() - .try_into() - .unwrap(); - - let is_final = reassign_to_gate(assigned_rows.is_enabled[round_idx]); - let output_rlc = reassign_to_gate(assigned_rows.output_rlc[0]); - - assigned_rounds.push(AssignedSha256Round { - is_final, - input_len, - input_rlcs, - padding_selectors, - output_rlc, - }) - } - - let hash_gate = hash_sha.map(reassign_to_gate); + _ctx: &mut Self::CircuitBuilder, + _input: impl IntoIterator>, + _max_input_len: usize, + ) -> Result { + unimplemented!() + } +} - Ok(hash_gate) +impl<'a, F: Field> Sha256ChipWide<'a, F> { + pub fn new(range: &'a RangeChip) -> Self { + Self { range } } } +pub fn word_to_bytes_le( + word: Word>, + gate: &impl GateInstructions, + ctx: &mut Context, +) -> Vec> { + to_bytes_le::<_, 16>(&word.lo(), gate, ctx) + .into_iter() + .chain(to_bytes_le::<_, 16>(&word.hi(), gate, ctx)) + .collect() +} + // #[cfg(test)] // mod test { // use std::env::var; diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs deleted file mode 100644 index b8c5715b..00000000 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs +++ /dev/null @@ -1,910 +0,0 @@ -//! The circuit for SHA256 hash function. -//! This implementation is based on: -//! - https://github.com/SoraSuegami/zkevm-circuits/blob/main/zkevm-circuits/src/sha256_circuit/sha256_bit.rs - -use super::{util::*, witness::ShaRow}; -use crate::gadget::crypto::constant_randomness; -use crate::gadget::{and, not, rlc, select, sum, xor, Expr}; -use crate::util::BaseConstraintBuilder; -use crate::util::GateBuilderConfig; -use eth_types::Field; -use halo2_base::virtual_region::copy_constraints::CopyConstraintManager; -use halo2_base::{ - halo2_proofs::{ - circuit::{Layouter, Region, Value}, - plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, - poly::Rotation, - }, - AssignedValue, Context, ContextCell, QuantumCell, -}; -use itertools::Itertools; -use log::debug; -use std::iter; -use std::marker::PhantomData; - -/// Configuration for [`Sha256WideChip`]. -#[derive(Clone, Debug)] -pub struct Sha256BitConfig, CA = Column> { - pub q_enable: CF, - pub q_first: CF, - pub q_extend: CF, - pub q_start: CF, - pub q_compression: CF, - pub q_end: CF, - pub q_padding: CF, - pub q_padding_last: CF, - pub q_squeeze: CF, - pub q_final_word: CF, - pub word_w: [CA; NUM_BITS_PER_WORD_W], - pub word_a: [CA; NUM_BITS_PER_WORD_EXT], - pub word_e: [CA; NUM_BITS_PER_WORD_EXT], - pub is_final: CA, - pub is_paddings: [CA; ABSORB_WIDTH_PER_ROW_BYTES], - pub data_rlcs: [CA; ABSORB_WIDTH_PER_ROW_BYTES], - pub round_cst: CF, - pub h_a: CF, - pub h_e: CF, - - // True when the row is enabled - pub is_enabled: CA, - // The columns for bytes of hash results - pub input_rlc: CA, - // Length of first+second inputs - pub input_len: CA, - // RLC of the hash result - pub hash_rlc: CA, - // Output bytes - pub final_hash_bytes: [CA; NUM_BYTES_FINAL_HASH], - - pub _f: PhantomData, - - pub offset: usize, -} - -impl GateBuilderConfig for Sha256BitConfig { - fn configure(meta: &mut ConstraintSystem) -> Self { - let r: F = constant_randomness(); // TODO: use challenges API - let q_enable = meta.fixed_column(); - let q_first = meta.fixed_column(); - let q_extend = meta.fixed_column(); - let q_start = meta.fixed_column(); - let q_compression = meta.fixed_column(); - let q_end = meta.fixed_column(); - let q_padding = meta.fixed_column(); - let q_padding_last = meta.fixed_column(); - let q_squeeze = meta.fixed_column(); - let q_final_word = meta.fixed_column(); - let word_w = array_init::array_init(|_| meta.advice_column()); - let word_a = array_init::array_init(|_| meta.advice_column()); - let word_e = array_init::array_init(|_| meta.advice_column()); - let is_final = meta.advice_column(); - - let is_paddings = array_init::array_init(|_| meta.advice_column()); - is_paddings - .iter() - .for_each(|&col| meta.enable_equality(col)); - let data_rlcs = array_init::array_init(|_| meta.advice_column()); - - let round_cst = meta.fixed_column(); - let h_a = meta.fixed_column(); - meta.enable_equality(h_a); - let h_e = meta.fixed_column(); - meta.enable_equality(h_e); - - let is_enabled = meta.advice_column(); - meta.enable_equality(is_enabled); - let input_len = meta.advice_column(); - meta.enable_equality(input_len); - let input_rlc = meta.advice_column(); - meta.enable_equality(input_rlc); - let hash_rlc = meta.advice_column(); - meta.enable_equality(hash_rlc); - - let final_hash_bytes = array_init::array_init(|_| meta.advice_column()); - for col in final_hash_bytes.into_iter() { - meta.enable_equality(col); - } - // State bits - let mut w_ext = vec![0u64.expr(); NUM_BITS_PER_WORD_W]; - let mut w_2 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut w_7 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut w_15 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut w_16 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut a = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut b = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut c = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut d = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut e = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut f = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut g = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut h = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut d_64 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut h_64 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut new_a_ext = vec![0u64.expr(); NUM_BITS_PER_WORD_EXT]; - let mut new_e_ext = vec![0u64.expr(); NUM_BITS_PER_WORD_EXT]; - - meta.create_gate("Query state bits", |meta| { - for k in 0..NUM_BITS_PER_WORD_W { - w_ext[k] = meta.query_advice(word_w[k], Rotation(-0)); - } - for i in 0..NUM_BITS_PER_WORD { - let k = i + NUM_BITS_PER_WORD_W - NUM_BITS_PER_WORD; - w_2[i] = meta.query_advice(word_w[k], Rotation(-2)); - w_7[i] = meta.query_advice(word_w[k], Rotation(-7)); - w_15[i] = meta.query_advice(word_w[k], Rotation(-15)); - w_16[i] = meta.query_advice(word_w[k], Rotation(-16)); - let k = i + NUM_BITS_PER_WORD_EXT - NUM_BITS_PER_WORD; - a[i] = meta.query_advice(word_a[k], Rotation(-1)); - b[i] = meta.query_advice(word_a[k], Rotation(-2)); - c[i] = meta.query_advice(word_a[k], Rotation(-3)); - d[i] = meta.query_advice(word_a[k], Rotation(-4)); - e[i] = meta.query_advice(word_e[k], Rotation(-1)); - f[i] = meta.query_advice(word_e[k], Rotation(-2)); - g[i] = meta.query_advice(word_e[k], Rotation(-3)); - h[i] = meta.query_advice(word_e[k], Rotation(-4)); - d_64[i] = meta.query_advice(word_a[k], Rotation(-((NUM_ROUNDS + 4) as i32))); - h_64[i] = meta.query_advice(word_e[k], Rotation(-((NUM_ROUNDS + 4) as i32))); - } - for k in 0..NUM_BITS_PER_WORD_EXT { - new_a_ext[k] = meta.query_advice(word_a[k], Rotation(0)); - new_e_ext[k] = meta.query_advice(word_e[k], Rotation(0)); - } - vec![0u64.expr()] - }); - let w = &w_ext[NUM_BITS_PER_WORD_W - NUM_BITS_PER_WORD..NUM_BITS_PER_WORD_W]; - let new_a = &new_a_ext[NUM_BITS_PER_WORD_EXT - NUM_BITS_PER_WORD..NUM_BITS_PER_WORD_EXT]; - let new_e = &new_e_ext[NUM_BITS_PER_WORD_EXT - NUM_BITS_PER_WORD..NUM_BITS_PER_WORD_EXT]; - - let xor = |a: &[Expression], b: &[Expression]| { - debug_assert_eq!(a.len(), b.len(), "invalid length"); - let mut c = vec![0.expr(); a.len()]; - for (idx, (a, b)) in a.iter().zip(b.iter()).enumerate() { - c[idx] = xor::expr(a, b); - } - c - }; - - let select = - |c: &[Expression], when_true: &[Expression], when_false: &[Expression]| { - debug_assert_eq!(c.len(), when_true.len(), "invalid length"); - debug_assert_eq!(c.len(), when_false.len(), "invalid length"); - let mut r = vec![0.expr(); c.len()]; - for (idx, (c, (when_true, when_false))) in c - .iter() - .zip(when_true.iter().zip(when_false.iter())) - .enumerate() - { - r[idx] = select::expr(c.clone(), when_true.clone(), when_false.clone()); - } - r - }; - - meta.create_gate("input checks", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - for w in w_ext.iter() { - cb.require_boolean("w bit boolean", w.clone()); - } - for a in new_a_ext.iter() { - cb.require_boolean("a bit boolean", a.clone()); - } - for e in new_e_ext.iter() { - cb.require_boolean("e bit boolean", e.clone()); - } - cb.gate(meta.query_fixed(q_enable, Rotation::cur())) - }); - - meta.create_gate("w extend", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let s0 = xor( - &rotate::expr(&w_15, 7), - &xor(&rotate::expr(&w_15, 18), &shift::expr(&w_15, 3)), - ); - let s1 = xor( - &rotate::expr(&w_2, 17), - &xor(&rotate::expr(&w_2, 19), &shift::expr(&w_2, 10)), - ); - let new_w = - decode::expr(&w_16) + decode::expr(&s0) + decode::expr(&w_7) + decode::expr(&s1); - cb.require_equal("w", new_w, decode::expr(&w_ext)); - cb.gate(meta.query_fixed(q_extend, Rotation::cur())) - }); - - meta.create_gate("compression", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let s1 = xor( - &rotate::expr(&e, 6), - &xor(&rotate::expr(&e, 11), &rotate::expr(&e, 25)), - ); - let ch = select(&e, &f, &g); - let temp1 = decode::expr(&h) - + decode::expr(&s1) - + decode::expr(&ch) - + meta.query_fixed(round_cst, Rotation::cur()) - + decode::expr(w); - - let s0 = xor( - &rotate::expr(&a, 2), - &xor(&rotate::expr(&a, 13), &rotate::expr(&a, 22)), - ); - let maj = select(&xor(&b, &c), &a, &b); - let temp2 = decode::expr(&s0) + decode::expr(&maj); - cb.require_equal( - "compress a", - decode::expr(&new_a_ext), - temp1.clone() + temp2, - ); - cb.require_equal( - "compress e", - decode::expr(&new_e_ext), - decode::expr(&d) + temp1, - ); - cb.gate(meta.query_fixed(q_compression, Rotation::cur())) - }); - - meta.create_gate("start", |meta| { - let is_final = meta.query_advice(is_final, Rotation::cur()); - let h_a = meta.query_fixed(h_a, Rotation::cur()); - let h_e = meta.query_fixed(h_e, Rotation::cur()); - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - cb.require_equal( - "start a", - decode::expr(&new_a_ext), - select::expr(is_final.expr(), h_a, decode::expr(&d)), - ); - cb.require_equal( - "start e", - decode::expr(&new_e_ext), - select::expr(is_final.expr(), h_e, decode::expr(&h)), - ); - cb.gate(meta.query_fixed(q_start, Rotation::cur())) - }); - - meta.create_gate("end", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - cb.require_equal( - "end a", - decode::expr(&new_a_ext), - decode::expr(&d) + decode::expr(&d_64), - ); - cb.require_equal( - "end e", - decode::expr(&new_e_ext), - decode::expr(&h) + decode::expr(&h_64), - ); - cb.gate(meta.query_fixed(q_end, Rotation::cur())) - }); - - // Enforce logic for when this block is the last block for a hash - meta.create_gate("is final", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let is_padding = meta.query_advice( - *is_paddings.last().unwrap(), - Rotation(-((NUM_END_ROWS + NUM_ROUNDS - NUM_WORDS_TO_ABSORB) as i32) - 2), - ); - let is_final_prev = meta.query_advice(is_final, Rotation::prev()); - let is_final = meta.query_advice(is_final, Rotation::cur()); - // On the first row is_final needs to be enabled - cb.condition(meta.query_fixed(q_first, Rotation::cur()), |cb| { - cb.require_equal( - "is_final needs to remain the same", - is_final.expr(), - 1.expr(), - ); - }); - // Get the correct is_final state from the padding selector - cb.condition(meta.query_fixed(q_squeeze, Rotation::cur()), |cb| { - cb.require_equal( - "is_final needs to match the padding selector", - is_final.expr(), - is_padding, - ); - }); - // Copy the is_final state to the q_start rows - cb.condition( - meta.query_fixed(q_start, Rotation::cur()) - - meta.query_fixed(q_first, Rotation::cur()), - |cb| { - cb.require_equal( - "is_final needs to remain the same", - is_final.expr(), - is_final_prev, - ); - }, - ); - cb.gate(1.expr()) - }); - - meta.create_gate("is enabled", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let q_squeeze = meta.query_fixed(q_squeeze, Rotation::cur()); - let is_final = meta.query_advice(is_final, Rotation::cur()); - let is_enabled = meta.query_advice(is_enabled, Rotation::cur()); - // Only set is_enabled to true when is_final is true and it's a squeeze row - cb.require_equal( - "is_enabled := q_squeeze && is_final", - is_enabled.expr(), - and::expr(&[q_squeeze.expr(), is_final.expr()]), - ); - cb.gate(meta.query_fixed(q_enable, Rotation::cur())) - }); - - let start_new_hash = |meta: &mut VirtualCells| { - // A new hash is started when the previous hash is done or on the first row - meta.query_advice(is_final, Rotation::cur()) - }; - - // Create bytes from input bits - let input_bytes = to_le_bytes::expr(w); - - // Padding - meta.create_gate("padding", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let prev_is_padding = meta.query_advice(*is_paddings.last().unwrap(), Rotation::prev()); - let q_padding = meta.query_fixed(q_padding, Rotation::cur()); - let q_padding_last = meta.query_fixed(q_padding_last, Rotation::cur()); - let length = meta.query_advice(input_len, Rotation::cur()); - let is_final_padding_row = - meta.query_advice(*is_paddings.last().unwrap(), Rotation(-2)); - // All padding selectors need to be boolean - for is_padding in is_paddings.iter() { - let is_padding = meta.query_advice(*is_padding, Rotation::cur()); - cb.condition(meta.query_fixed(q_enable, Rotation::cur()), |cb| { - cb.require_boolean("is_padding boolean", is_padding); - }); - } - // Now for each padding selector - for idx in 0..is_paddings.len() { - // Previous padding selector can be on the previous row - let is_padding_prev = if idx == 0 { - prev_is_padding.expr() - } else { - meta.query_advice(is_paddings[idx - 1], Rotation::cur()) - }; - let is_padding = meta.query_advice(is_paddings[idx], Rotation::cur()); - let is_first_padding = is_padding.clone() - is_padding_prev.clone(); - // Check padding transition 0 -> 1 done only once - cb.condition(q_padding.expr(), |cb| { - cb.require_boolean("padding step boolean", is_first_padding.clone()); - }); - // Padding start/intermediate byte, all padding rows except the last one - cb.condition( - and::expr([ - (q_padding.expr() - q_padding_last.expr()), - is_padding.expr(), - ]), - |cb| { - // Input bytes need to be zero, or 128 if this is the first padding byte - cb.require_equal( - "padding start/intermediate byte", - input_bytes[idx].clone(), - is_first_padding.expr() * 128.expr(), - ); - }, - ); - // Padding start/intermediate byte, last padding row but not in the final block - cb.condition( - and::expr([ - q_padding_last.expr(), - is_padding.expr(), - not::expr(is_final_padding_row.expr()), - ]), - |cb| { - // Input bytes need to be zero, or 128 if this is the first padding byte - cb.require_equal( - "padding start/intermediate byte", - input_bytes[idx].clone(), - is_first_padding.expr() * 128.expr(), - ); - }, - ); - } - // The last row containing input/padding data in the final block needs to - // contain the length in bits (Only input lengths up to 2**32 - 1 - // bits are supported, which is lower than the spec of 2**64 - 1 bits) - cb.condition( - and::expr([q_padding_last.expr(), is_final_padding_row.expr()]), - |cb| { - cb.require_equal("padding length", decode::expr(w), length.expr() * 8.expr()); - }, - ); - cb.gate(1.expr()) - }); - - // Length and input data rlc - meta.create_gate("length and data rlc", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let q_padding = meta.query_fixed(q_padding, Rotation::cur()); - let start_new_hash = start_new_hash(meta); - let length_prev = meta.query_advice(input_len, Rotation::prev()); - let length = meta.query_advice(input_len, Rotation::cur()); - let data_rlc_prev = meta.query_advice(input_rlc, Rotation::prev()); - let data_rlc = meta.query_advice(input_rlc, Rotation::cur()); - - // Update the length/data_rlc on rows where we absorb data - cb.condition(q_padding.expr(), |cb| { - // Length increases by the number of bytes that aren't padding - // In a new block we have to start from 0 if the previous block was the final - // one - cb.require_equal( - "update length", - length.clone(), - length_prev.clone() * not::expr(start_new_hash.expr()) - + sum::expr(is_paddings.iter().map(|is_padding| { - not::expr(meta.query_advice(*is_padding, Rotation::cur())) - })), - ); - - // Use intermediate cells to keep the degree low - let mut new_data_rlc = data_rlc_prev.clone() * not::expr(start_new_hash.expr()); - - cb.require_equal( - "initial data rlc", - meta.query_advice(data_rlcs[0], Rotation::cur()), - new_data_rlc, - ); - new_data_rlc = meta.query_advice(data_rlcs[0], Rotation::cur()); - - for (idx, (byte, is_padding)) in - input_bytes.iter().zip(is_paddings.iter()).enumerate() - { - new_data_rlc = select::expr( - meta.query_advice(*is_padding, Rotation::cur()), - new_data_rlc.clone(), - new_data_rlc.clone() * r + byte.clone(), - ); - if idx < data_rlcs.len() - 1 { - let next_data_rlc = meta.query_advice(data_rlcs[idx + 1], Rotation::cur()); - cb.require_equal( - "intermediate data rlc", - next_data_rlc.clone(), - new_data_rlc, - ); - new_data_rlc = next_data_rlc; - } - } - - cb.require_equal("update data rlc", data_rlc.clone(), new_data_rlc); - }); - cb.gate(1.expr()) - }); - - // Make sure data is consistent between blocks - meta.create_gate("cross block data consistency", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let start_new_hash = start_new_hash(meta); - let to_const = - |value: &String| -> &'static str { Box::leak(value.clone().into_boxed_str()) }; - let mut add = |name: &'static str, column| { - let last_rot = - Rotation(-((NUM_END_ROWS + NUM_ROUNDS - NUM_WORDS_TO_ABSORB) as i32)); - let value_to_copy = meta.query_advice(column, last_rot); - let prev_value = meta.query_advice(column, Rotation::prev()); - let cur_value = meta.query_advice(column, Rotation::cur()); - // On squeeze rows fetch the last used value - cb.condition(meta.query_fixed(q_squeeze, Rotation::cur()), |cb| { - cb.require_equal( - to_const(&format!("{} copy check", name)), - cur_value.expr(), - value_to_copy.expr(), - ); - }); - // On first rows keep the length the same, or reset the length when starting a - // new hash - cb.condition( - meta.query_fixed(q_start, Rotation::cur()) - - meta.query_fixed(q_first, Rotation::cur()), - |cb| { - cb.require_equal( - to_const(&format!("{} equality check", name)), - cur_value.expr(), - prev_value.expr() * not::expr(start_new_hash.expr()), - ); - }, - ); - // Set the value to zero on the first row - cb.condition(meta.query_fixed(q_first, Rotation::cur()), |cb| { - cb.require_equal( - to_const(&format!("{} initialized to 0", name)), - cur_value.clone(), - 0.expr(), - ); - }); - }; - add("length", input_len); - add("data_rlc", input_rlc); - add("last padding", *is_paddings.last().unwrap()); - - cb.gate(1.expr()) - }); - - // Squeeze - meta.create_gate("squeeze", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - // Squeeze out the hash - let hash_parts = [new_a, &a, &b, &c, new_e, &e, &f, &g]; - let hash_bytes = hash_parts - .iter() - .flat_map(|part| to_le_bytes::expr(part)) - .collect::>(); - let rlc = rlc::expr(&hash_bytes, Expression::Constant(r)); - cb.condition(start_new_hash(meta), |cb| { - cb.require_equal( - "hash rlc check", - rlc, - meta.query_advice(hash_rlc, Rotation::cur()), - ); - }); - cb.gate(meta.query_fixed(q_squeeze, Rotation::cur())) - }); - - meta.create_gate("final_hash_words", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let q_condition = meta.query_fixed(q_final_word, Rotation::cur()); - - let final_word_exprs = (0..NUM_BYTES_FINAL_HASH) - .map(|i| { - meta.query_advice(final_hash_bytes[i], Rotation::cur()) - .expr() - }) - .collect::>>(); - let rlc = rlc::expr(&final_word_exprs, Expression::Constant(r)); - cb.condition(q_condition.clone(), |cb| { - cb.require_equal( - "final hash rlc check", - rlc, - meta.query_advice(hash_rlc, Rotation::cur()), - ); - }); - cb.gate(q_condition) - }); - - debug!("sha256 circuit degree: {}", meta.degree()); - debug!("minimum rows: {}", meta.minimum_rows()); - - Sha256BitConfig { - q_enable, - q_first, - q_extend, - q_start, - q_compression, - q_end, - q_padding, - q_padding_last, - q_squeeze, - q_final_word, - word_w, - word_a, - word_e, - is_final, - is_paddings, - data_rlcs, - round_cst, - h_a, - h_e, - is_enabled, - input_len, - input_rlc, - hash_rlc, - final_hash_bytes, - _f: PhantomData, - offset: Default::default(), - } - } - - fn annotate_columns_in_region(&self, region: &mut Region) { - self.annotations().iter().for_each(|(column, name)| { - region.name_column(|| name, *column); - }); - } - - fn load(&self, _layouter: &mut impl Layouter) -> Result<(), Error> { - Ok(()) - } -} - -impl Sha256BitConfig { - pub fn annotations(&self) -> Vec<(Column, String)> { - let mut annotations = vec![ - (self.q_enable.into(), "q_enabled".to_string()), - (self.q_first.into(), "q_first".to_string()), - (self.q_extend.into(), "q_extend".to_string()), - (self.q_start.into(), "q_start".to_string()), - (self.q_compression.into(), "q_compression".to_string()), - (self.q_end.into(), "q_end".to_string()), - (self.q_padding.into(), "q_padding".to_string()), - (self.q_padding_last.into(), "q_padding_last".to_string()), - (self.q_squeeze.into(), "q_squeeze".to_string()), - (self.q_final_word.into(), "q_final_word".to_string()), - (self.is_final.into(), "is_final".to_string()), - (self.round_cst.into(), "round_cst".to_string()), - (self.h_a.into(), "h_a".to_string()), - (self.h_e.into(), "h_e".to_string()), - (self.is_enabled.into(), "is_enabled".to_string()), - (self.input_len.into(), "input_len".to_string()), - (self.input_rlc.into(), "input_rlc".to_string()), - (self.hash_rlc.into(), "hash_rlc".to_string()), - ]; - - for (i, col) in self.word_w.iter().copied().enumerate() { - annotations.push((col.into(), format!("word_w_{}", i))); - } - for (i, col) in self.word_a.iter().copied().enumerate() { - annotations.push((col.into(), format!("word_a_{}", i))); - } - for (i, col) in self.word_e.iter().copied().enumerate() { - annotations.push((col.into(), format!("word_e_{}", i))); - } - for (i, col) in self.is_paddings.iter().copied().enumerate() { - annotations.push((col.into(), format!("is_paddings_{}", i))); - } - for (i, col) in self.data_rlcs.iter().copied().enumerate() { - annotations.push((col.into(), format!("data_rlcs_{}", i))); - } - for (i, col) in self.final_hash_bytes.iter().copied().enumerate() { - annotations.push((col.into(), format!("final_hash_bytes_{}", i))); - } - - annotations - } -} - -impl Sha256BitConfig, Context> { - pub fn load_sha256_row( - &mut self, - row: &ShaRow, - assigned_rows: &mut Sha256AssignedRows, - ) -> Result>, Error> { - let offset = self.offset; - self.offset += 1; - let round = offset % (NUM_ROUNDS + 8); - // Fixed values - for (ctx, value) in [ - (&mut self.q_enable, F::from(true)), - (&mut self.q_first, F::from(offset == 0)), - ( - &mut self.q_extend, - F::from((4 + 16..4 + NUM_ROUNDS).contains(&round)), - ), - (&mut self.q_start, F::from(round < 4)), - ( - &mut self.q_compression, - F::from((4..NUM_ROUNDS + 4).contains(&round)), - ), - (&mut self.q_end, F::from(round >= NUM_ROUNDS + 4)), - (&mut self.q_padding, F::from((4..20).contains(&round))), - (&mut self.q_padding_last, F::from(round == 19)), - (&mut self.q_squeeze, F::from(round == NUM_ROUNDS + 7)), - ( - &mut self.q_final_word, - F::from(row.is_final && round == NUM_ROUNDS + 7), - ), - ( - &mut self.round_cst, - F::from(if (4..NUM_ROUNDS + 4).contains(&round) { - ROUND_CST[round - 4] as u64 - } else { - 0 - }), - ), - ( - &mut self.h_a, - F::from(if round < 4 { H[3 - round] } else { 0 }), - ), - ( - &mut self.h_e, - F::from(if round < 4 { H[7 - round] } else { 0 }), - ), - ] { - ctx.assign_cell(QuantumCell::Constant(value)); - } - - // Advice values - for (ctxs, values) in [ - ( - self.word_w.iter_mut().collect::>(), - row.w.as_slice(), - ), - ( - self.word_a.iter_mut().collect::>(), - row.a.as_slice(), - ), - ( - self.word_e.iter_mut().collect::>(), - row.e.as_slice(), - ), - (vec![&mut self.is_final], [row.is_final].as_slice()), - ] { - for (value, ctx) in values.iter().zip(ctxs) { - ctx.assign_cell(QuantumCell::Witness(F::from(*value))); - } - } - - let padding_selectors = self - .is_paddings - .iter_mut() - .zip(row.is_paddings) - .map(|(ctx, val)| ctx.load_witness(F::from(val))) - .collect_vec() - .try_into() - .unwrap(); - - // Intermediary data rlcs - for (ctx, data_rlc) in self.data_rlcs.iter_mut().zip(row.intermediary_data_rlcs) { - ctx.assign_cell(QuantumCell::Witness(data_rlc)); - } - - // Hash data - let [is_enabled, input_rlc, input_len, output_rlc] = [ - ( - &mut self.is_enabled, - F::from(row.is_final && round == NUM_ROUNDS + 7), - ), - (&mut self.input_rlc, row.data_rlc), - (&mut self.input_len, F::from(row.length as u64)), - (&mut self.hash_rlc, row.hash_rlc), - ] - .map(|(ctx, value)| ctx.load_witness(value)); - - if (4..20).contains(&round) { - assigned_rows.padding_selectors.push(padding_selectors); - assigned_rows.input_rlc.push(input_rlc); - } - - if row.is_final && round == NUM_ROUNDS + 7 { - assigned_rows.output_rlc.push(output_rlc); - } - - if round == NUM_ROUNDS + 7 { - assigned_rows.is_enabled.push(is_enabled); - assigned_rows.input_len.push(input_len); - } - - if !row.is_final || round != NUM_ROUNDS + 7 { - self.final_hash_bytes - .iter_mut() - .zip(iter::repeat(F::from(0u64))) - .for_each(|(ctx, byte)| { - ctx.assign_cell(QuantumCell::Witness(byte)); - }); - - return Ok(vec![]); - } - - let assigned_hash_bytes = self - .final_hash_bytes - .iter_mut() - .zip(row.final_hash_bytes) - .map(|(ctx, byte)| ctx.load_witness(byte)) - .collect_vec(); - - Ok(assigned_hash_bytes) - } - - #[allow(clippy::type_complexity)] - pub fn assign_in_region( - &self, - region: &mut Region, - config: &Sha256BitConfig, - use_unknown: bool, - mut copy_manager: Option<&mut CopyConstraintManager>, - ) -> Result<(), Error> { - // Fixed values - for (name, column, ctx) in [ - ("q_enable", &config.q_enable, &self.q_enable), - ("q_first", &config.q_first, &self.q_first), - ("q_extend", &config.q_extend, &self.q_extend), - ("q_start", &config.q_start, &self.q_start), - ("q_compression", &config.q_compression, &self.q_compression), - ("q_end", &config.q_end, &self.q_end), - ("q_padding", &config.q_padding, &self.q_padding), - ( - "q_padding_last", - &config.q_padding_last, - &self.q_padding_last, - ), - ("q_squeeze", &config.q_squeeze, &self.q_squeeze), - ("q_final_word", &config.q_final_word, &self.q_final_word), - ("round_cst", &config.round_cst, &self.round_cst), - ("h_a", &config.h_a, &self.h_a), - ("h_e", &config.h_e, &self.h_e), - ] { - for (offset, &val) in ctx.advice.iter().enumerate() { - let cell = region - .assign_fixed(|| name, *column, offset, || Value::known(val))? - .cell(); - - if let Some(copy_manager) = copy_manager.as_mut() { - copy_manager - .assigned_advices - .insert(ContextCell::new(ctx.type_id(), ctx.id(), offset), cell); - } - } - } - - // Advice values - - for (name, column, ctx) in [ - ("is_enabled", &config.is_enabled, &self.is_enabled), - ("input_len", &config.input_len, &self.input_len), - ("input_rlc", &config.input_rlc, &self.input_rlc), - ("hash_rlc", &config.hash_rlc, &self.hash_rlc), - ] { - for (offset, &val) in ctx.advice.iter().enumerate() { - let value = if use_unknown { - Value::unknown() - } else { - Value::known(val) - }; - let cell = region - .assign_advice(|| name, *column, offset, || value)? - .cell(); - - if let Some(copy_manager) = copy_manager.as_mut() { - copy_manager - .assigned_advices - .insert(ContextCell::new(ctx.type_id(), ctx.id(), offset), cell); - } - } - } - - let _ = itertools::multizip(( - config.is_paddings.iter(), - self.is_paddings.iter(), - iter::repeat("is_paddings"), - )) - .chain(itertools::multizip(( - config.data_rlcs.iter(), - self.data_rlcs.iter(), - iter::repeat("data_rlcs"), - ))) - .chain(itertools::multizip(( - config.word_w.iter(), - self.word_w.iter(), - iter::repeat("w word"), - ))) - .chain(itertools::multizip(( - config.word_a.iter(), - self.word_a.iter(), - iter::repeat("a word"), - ))) - .chain(itertools::multizip(( - config.word_e.iter(), - self.word_e.iter(), - iter::repeat("e word"), - ))) - .chain(iter::once((&config.is_final, &self.is_final, "is final"))) - .chain(itertools::multizip(( - config.final_hash_bytes.iter(), - self.final_hash_bytes.iter(), - iter::repeat("final hash bytes"), - ))) - .map(|(column, ctx, name)| { - for (offset, &val) in ctx.advice.iter().enumerate() { - let value = if use_unknown { - Value::unknown() - } else { - Value::known(val) - }; - - let cell = match region.assign_advice(|| name, *column, offset, || value) { - Ok(cell) => cell, - Err(e) => { - return Err(e); - } - } - .cell(); - - if let Some(copy_manager) = copy_manager.as_mut() { - copy_manager - .assigned_advices - .insert(ContextCell::new(ctx.type_id(), ctx.id(), offset), cell); - } - } - - Ok::<_, Error>(()) - }) - .collect::, _>>()?; - - Ok(()) - } -} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs index 7ef6ac4d..047145ad 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs @@ -1,20 +1,25 @@ -use super::config::Sha256BitConfig; use crate::util::{CommonGateManager, GateBuilderConfig}; use eth_types::Field; use getset::CopyGetters; use halo2_base::{ gates::circuit::CircuitBuilderStage, - halo2_proofs::circuit::Region, + halo2_proofs::{circuit::Region, plonk::Error}, virtual_region::{ copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, }, - Context, }; -use std::any::TypeId; - -pub const FIRST_PHASE: usize = 0; - -pub type Sha256BitContexts = Sha256BitConfig, Context>; +use itertools::Itertools; +use zkevm_hashes::{ + sha256::{ + component::circuit::LoadedSha256, + vanilla::{ + columns::Sha256CircuitConfig, + param::{NUM_START_ROWS, NUM_WORDS_TO_ABSORB, SHA256_NUM_ROWS}, + witness::VirtualShaRow, + }, + }, + util::word::Word, +}; #[derive(Clone, Debug, CopyGetters)] pub struct ShaBitGateManager { @@ -25,66 +30,26 @@ pub struct ShaBitGateManager { pub(crate) use_unknown: bool, /// Threads for spread table assignment. - sha_contexts: Sha256BitContexts, + virtual_rows: Vec, + loaded_blocks: Vec>, pub copy_manager: SharedCopyConstraintManager, } impl CommonGateManager for ShaBitGateManager { - type CustomContext<'a> = &'a mut Sha256BitContexts; + type CustomContext<'a> = (); fn new(witness_gen_only: bool) -> Self { - let copy_manager = SharedCopyConstraintManager::default(); - let mut context_id = 0; - let mut new_context = || { - context_id += 1; - Context::new( - witness_gen_only, - FIRST_PHASE, - TypeId::of::(), - context_id, - copy_manager.clone(), - ) - }; - Self { witness_gen_only, use_unknown: false, - sha_contexts: Sha256BitConfig { - q_enable: new_context(), - q_first: new_context(), - q_extend: new_context(), - q_start: new_context(), - q_compression: new_context(), - q_end: new_context(), - q_padding: new_context(), - q_padding_last: new_context(), - q_squeeze: new_context(), - q_final_word: new_context(), - word_w: array_init::array_init(|_| new_context()), - word_a: array_init::array_init(|_| new_context()), - word_e: array_init::array_init(|_| new_context()), - is_final: new_context(), - is_paddings: array_init::array_init(|_| new_context()), - data_rlcs: array_init::array_init(|_| new_context()), - round_cst: new_context(), - h_a: new_context(), - h_e: new_context(), - is_enabled: new_context(), - input_rlc: new_context(), - input_len: new_context(), - hash_rlc: new_context(), - final_hash_bytes: array_init::array_init(|_| new_context()), - _f: std::marker::PhantomData, - offset: 0, - }, + virtual_rows: Vec::new(), + loaded_blocks: Vec::new(), copy_manager: SharedCopyConstraintManager::default(), } } - fn custom_context(&mut self) -> Self::CustomContext<'_> { - self.sha_contexts() - } + fn custom_context(&mut self) -> Self::CustomContext<'_> {} fn from_stage(stage: CircuitBuilderStage) -> Self { Self::new(stage == CircuitBuilderStage::Prover) @@ -103,27 +68,111 @@ impl CommonGateManager for ShaBitGateManager { } impl VirtualRegionManager for ShaBitGateManager { - type Config = Sha256BitConfig; + type Config = Sha256CircuitConfig; fn assign_raw(&self, config: &Self::Config, region: &mut Region) { - config.annotate_columns_in_region(region); - - if self.witness_gen_only() { - self.sha_contexts - .assign_in_region(region, config, false, None) - .unwrap(); - } else { - let mut copy_manager = self.copy_manager.lock().unwrap(); - self.sha_contexts - .assign_in_region(region, config, self.use_unknown(), Some(&mut copy_manager)) - .unwrap(); - } + // config.annotate_columns_in_region(region); + let mut copy_manager = self.copy_manager.lock().unwrap(); + + config + .assign_sha256_rows(region, self.virtual_rows.clone(), None, 0) + .into_iter() + .zip(&self.loaded_blocks) + .for_each(|(vanilla, loaded)| { + copy_manager + .assigned_advices + .insert(loaded.is_final.cell.unwrap(), vanilla.is_final().cell()); + copy_manager + .assigned_advices + .insert(loaded.hash.lo().cell.unwrap(), vanilla.output().lo().cell()); + copy_manager + .assigned_advices + .insert(loaded.hash.hi().cell.unwrap(), vanilla.output().hi().cell()); + vanilla + .word_values() + .iter() + .zip(loaded.word_values) + .for_each(|(vanilla_input_word, loaded_input_word)| { + copy_manager + .assigned_advices + .insert(loaded_input_word.cell.unwrap(), vanilla_input_word.cell()); + }); + }); + + // if self.witness_gen_only() { + // config + // .assign_in_region(region, config, false, None) + // .unwrap(); + // } else { + // let mut copy_manager = self.copy_manager.lock().unwrap(); + // config.assign_sha256_rows(region, config, self.use_unknown(), Some(&mut copy_manager)) + // .unwrap(); + // } } } impl ShaBitGateManager { - pub fn sha_contexts(&mut self) -> &mut Sha256BitContexts { - &mut self.sha_contexts + pub fn load_virtual_rows(&mut self, virtual_rows: Vec) -> Vec> { + struct UnassignedShaTableRow { + is_final: F, + io: F, + // length: F, + } + let table_rows = virtual_rows + .iter() + .enumerate() + .map(|(offset, row)| { + let round = offset % SHA256_NUM_ROWS; + let q_input = + (NUM_START_ROWS..NUM_START_ROWS + NUM_WORDS_TO_ABSORB).contains(&round); + + let io_value = if q_input { + F::from(row.word_value as u64) + } else if round >= SHA256_NUM_ROWS - 2 { + F::from_u128(row.hash_limb) + } else { + F::ZERO + }; + + UnassignedShaTableRow { + is_final: F::from(row.is_final), + io: io_value, + // length: F::from(row.length as u64), + } + }) + // .enumerate() + .collect_vec(); + debug_assert_eq!(table_rows.len() % SHA256_NUM_ROWS, 0); + self.virtual_rows.extend(virtual_rows); + let mut copy_manager = self.copy_manager.lock().unwrap(); + + let loaded_blocks = table_rows + .chunks_exact(SHA256_NUM_ROWS) + .map(|rows| { + let last_row = rows.last().unwrap(); // rows[SHA256_NUM_ROWS - 1] + let is_final = copy_manager.mock_external_assigned(last_row.is_final); + let output_lo = copy_manager.mock_external_assigned(last_row.io); + let output_hi = copy_manager.mock_external_assigned(rows[SHA256_NUM_ROWS - 2].io); + let input_rows = &rows[NUM_START_ROWS..NUM_START_ROWS + NUM_WORDS_TO_ABSORB]; + let word_values: [_; NUM_WORDS_TO_ABSORB] = input_rows + .iter() + .map(|row| copy_manager.mock_external_assigned(row.io)) + .collect::>() + .try_into() + .unwrap(); + // let length = + // copy_manager.mock_external_assigned(input_rows.last().unwrap().1.length); + LoadedSha256 { + is_final, + hash: Word::new([output_lo, output_hi]), + word_values, + } + }) + .collect_vec(); + + self.loaded_blocks.extend(loaded_blocks.clone()); + + loaded_blocks } /// Mutates `self` to use the given copy manager everywhere, including in all threads. @@ -132,3 +181,18 @@ impl ShaBitGateManager { // TODO: set to `self.sha_contexts`. } } + +impl GateBuilderConfig for Sha256CircuitConfig { + fn configure(meta: &mut halo2_base::halo2_proofs::plonk::ConstraintSystem) -> Self { + Sha256CircuitConfig::new(meta) + } + + fn load( + &self, + _: &mut impl halo2_base::halo2_proofs::circuit::Layouter, + ) -> Result<(), Error> { + Ok(()) + } + + fn annotate_columns_in_region(&self, _: &mut Region) {} +} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs deleted file mode 100644 index 0cbb3edd..00000000 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs +++ /dev/null @@ -1,151 +0,0 @@ -use eth_types::Field; -use halo2_base::AssignedValue; - -pub(crate) const NUM_BITS_PER_BYTE: usize = 8; -pub(crate) const NUM_BYTES_PER_WORD: usize = 4; -pub(crate) const NUM_BITS_PER_WORD: usize = NUM_BYTES_PER_WORD * NUM_BITS_PER_BYTE; -pub(crate) const NUM_BITS_PER_WORD_W: usize = NUM_BITS_PER_WORD + 2; -pub(crate) const NUM_BITS_PER_WORD_EXT: usize = NUM_BITS_PER_WORD + 3; -pub(crate) const NUM_ROUNDS: usize = 64; -pub(crate) const RATE: usize = 16 * NUM_BYTES_PER_WORD; -pub(crate) const RATE_IN_BITS: usize = RATE * NUM_BITS_PER_BYTE; -pub(crate) const NUM_WORDS_TO_ABSORB: usize = 16; -pub(crate) const ABSORB_WIDTH_PER_ROW_BYTES: usize = 4; -pub(crate) const NUM_BITS_PADDING_LENGTH: usize = 64; -pub(crate) const NUM_END_ROWS: usize = 4; -pub(crate) const NUM_BYTES_FINAL_HASH: usize = 32; -pub(crate) const MAX_DEGREE: usize = 5; - -pub(crate) const ROUND_CST: [u32; NUM_ROUNDS] = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, -]; - -/// Init h_in parameters. -pub const H: [u64; 8] = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, -]; - -/// Assigned values for each row. -#[derive(Clone, Debug, Default)] -pub struct Sha256AssignedRows { - // /// Offset of the row. - // pub offset: usize, - /// Input length at the row. - pub input_len: Vec>, - /// Input words at the row. - pub input_rlc: Vec>, - /// Whether the output word is enabled at the row. - pub is_enabled: Vec>, - /// Whether the row is padding. - pub padding_selectors: Vec<[AssignedValue; 4]>, - /// Output words at the row. - pub output_rlc: Vec>, -} - -impl Sha256AssignedRows { - pub fn new() -> Self { - Self { - ..Default::default() - } - } -} - -/// Decodes be bits -pub mod decode { - use eth_types::Field; - use halo2_base::halo2_proofs::plonk::Expression; - - use crate::gadget::Expr; - - pub(crate) fn expr(bits: &[Expression]) -> Expression { - let mut value = 0.expr(); - let mut multiplier = F::ONE; - for bit in bits.iter().rev() { - value = value + bit.expr() * multiplier; - multiplier *= F::from(2); - } - value - } - - pub(crate) fn value(bits: &[u8]) -> u64 { - let mut value = 0u64; - for (idx, &bit) in bits.iter().rev().enumerate() { - value += (bit as u64) << idx; - } - value - } -} - -/// Rotates bits to the right -pub mod rotate { - use eth_types::Field; - use halo2_base::halo2_proofs::plonk::Expression; - - pub(crate) fn expr(bits: &[Expression], count: usize) -> Vec> { - let mut rotated = bits.to_vec(); - rotated.rotate_right(count); - rotated - } - - pub(crate) fn value(value: u64, count: u32) -> u64 { - ((value as u32).rotate_right(count)) as u64 - } -} - -/// Shifts bits to the right -pub mod shift { - use crate::gadget::Expr; - - use super::NUM_BITS_PER_WORD; - use eth_types::Field; - use halo2_base::halo2_proofs::plonk::Expression; - - pub(crate) fn expr(bits: &[Expression], count: usize) -> Vec> { - let mut res = vec![0.expr(); count]; - res.extend_from_slice(&bits[0..NUM_BITS_PER_WORD - count]); - res - } - - pub(crate) fn value(value: u64, count: u32) -> u64 { - ((value as u32) >> count) as u64 - } -} - -/// Convert be bits to le bytes -pub mod to_le_bytes { - use crate::util::to_bytes; - use eth_types::Field; - use halo2_base::halo2_proofs::plonk::Expression; - - pub(crate) fn expr(bits: &[Expression]) -> Vec> { - to_bytes::expr(&bits.iter().rev().cloned().collect::>()) - .into_iter() - .rev() - .collect::>() - } - - pub(crate) fn value(bits: &[u8]) -> Vec { - to_bytes::value(&bits.iter().rev().copied().collect::>()) - .into_iter() - .rev() - .collect::>() - } -} - -/// Converts bytes into bits -pub(crate) fn into_bits(bytes: &[u8]) -> Vec { - let mut bits: Vec = vec![0; bytes.len() * 8]; - for (byte_idx, byte) in bytes.iter().enumerate() { - for idx in 0u64..8 { - bits[byte_idx * 8 + (idx as usize)] = (*byte >> (7 - idx)) & 1; - } - } - bits -} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs deleted file mode 100644 index 34342d99..00000000 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs +++ /dev/null @@ -1,292 +0,0 @@ -use super::util::*; -use crate::{gadget::rlc, witness::HashInput}; -use eth_types::Field; -use itertools::Itertools; -use log::debug; - -#[derive(Clone, Debug, PartialEq)] -pub struct ShaRow { - pub(crate) w: [bool; NUM_BITS_PER_WORD_W], - pub(crate) a: [bool; NUM_BITS_PER_WORD_EXT], - pub(crate) e: [bool; NUM_BITS_PER_WORD_EXT], - pub(crate) is_final: bool, - pub(crate) length: usize, - pub(crate) data_rlc: F, - pub(crate) hash_rlc: F, - pub(crate) is_paddings: [bool; ABSORB_WIDTH_PER_ROW_BYTES], - pub(crate) intermediary_data_rlcs: [F; ABSORB_WIDTH_PER_ROW_BYTES], - pub(crate) final_hash_bytes: [F; NUM_BYTES_FINAL_HASH], -} - -pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F) { - let left_bits = into_bits(inputs[0]); - let right_bits = into_bits(inputs[1]); - let input_len = inputs[0].len() + inputs[1].len(); - let mut bits = left_bits.iter().copied().chain(right_bits).collect_vec(); - - // Padding - let length = bits.len(); - let mut length_in_bits = into_bits(&(length as u64).to_be_bytes()); - assert!(length_in_bits.len() == NUM_BITS_PADDING_LENGTH); - bits.push(1); - while (bits.len() + NUM_BITS_PADDING_LENGTH) % RATE_IN_BITS != 0 { - bits.push(0); - } - bits.append(&mut length_in_bits); - assert!(bits.len() % RATE_IN_BITS == 0); - - // Set the initial state - let mut hs: [u64; 8] = H.to_vec().try_into().unwrap(); - let mut length = 0usize; - let mut data_rlc = F::ZERO; - - let mut in_padding = false; - - // Process each block - let chunks = bits.chunks(RATE_IN_BITS); - let num_chunks = chunks.len(); - for (idx, chunk) in chunks.enumerate() { - // Adds a row - let mut add_row = |w: u64, - a: u64, - e: u64, - is_final, - length, - data_rlc, - hash_rlc, - is_paddings, - intermediary_data_rlcs, - final_hash_bytes| { - let word_to_bits = |value: u64, num_bits: usize| { - into_bits(&value.to_be_bytes())[64 - num_bits..64] - .iter() - .map(|b| *b != 0) - .collect::>() - }; - - rows.push(ShaRow { - w: word_to_bits(w, NUM_BITS_PER_WORD_W).try_into().unwrap(), - a: word_to_bits(a, NUM_BITS_PER_WORD_EXT).try_into().unwrap(), - e: word_to_bits(e, NUM_BITS_PER_WORD_EXT).try_into().unwrap(), - is_final, - length, - data_rlc, - hash_rlc, - is_paddings, - intermediary_data_rlcs, - final_hash_bytes, - }); - }; - - // Last block for this hash - let is_final_block = idx == num_chunks - 1; - - // Set the state - let (mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h) = - (hs[0], hs[1], hs[2], hs[3], hs[4], hs[5], hs[6], hs[7]); - - // Add start rows - let mut add_row_start = |a: u64, e: u64, is_final| { - add_row( - 0, - a, - e, - is_final, - length, - data_rlc, - F::ZERO, - [false, false, false, in_padding], - [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES], - [F::ZERO; NUM_BYTES_FINAL_HASH], - ) - }; - add_row_start(d, h, idx == 0); - add_row_start(c, g, idx == 0); - add_row_start(b, f, idx == 0); - add_row_start(a, e, idx == 0); - - let mut ws = Vec::new(); - for (round, round_cst) in ROUND_CST.iter().enumerate() { - // Padding/Length/Data rlc - let mut is_paddings = [false; ABSORB_WIDTH_PER_ROW_BYTES]; - let mut inter_data_rlcs = [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES]; - if round < NUM_WORDS_TO_ABSORB { - // padding/length - for is_padding in is_paddings.iter_mut() { - *is_padding = if length == input_len { - true - } else { - length += 1; - false - }; - } - // data rlc - let input_bytes = to_le_bytes::value(&chunk[round * 32..(round + 1) * 32]); - inter_data_rlcs[0] = data_rlc; - for (idx, (byte, padding)) in input_bytes.iter().zip(is_paddings.iter()).enumerate() - { - if !*padding { - data_rlc = data_rlc * rnd + F::from(*byte as u64); - } - if idx < inter_data_rlcs.len() - 1 { - inter_data_rlcs[idx + 1] = data_rlc; - } - } - in_padding = *is_paddings.last().unwrap(); - } - - // w - let w_ext = if round < NUM_WORDS_TO_ABSORB { - decode::value(&chunk[round * 32..(round + 1) * 32]) - } else { - let get_w = |offset: usize| ws[ws.len() - offset] & 0xFFFFFFFF; - let s0 = rotate::value(get_w(15), 7) - ^ rotate::value(get_w(15), 18) - ^ shift::value(get_w(15), 3); - let s1 = rotate::value(get_w(2), 17) - ^ rotate::value(get_w(2), 19) - ^ shift::value(get_w(2), 10); - get_w(16) + s0 + get_w(7) + s1 - }; - let w = w_ext & 0xFFFFFFFF; - ws.push(w); - - // compression - let s1 = rotate::value(e, 6) ^ rotate::value(e, 11) ^ rotate::value(e, 25); - let ch = (e & f) ^ (!e & g); - let temp1 = h + s1 + ch + (*round_cst as u64) + w; - let s0 = rotate::value(a, 2) ^ rotate::value(a, 13) ^ rotate::value(a, 22); - let maj = (a & b) ^ (a & c) ^ (b & c); - let temp2 = s0 + maj; - - h = g; - g = f; - f = e; - e = d + temp1; - d = c; - c = b; - b = a; - a = temp1 + temp2; - - // Add the row - add_row( - w_ext, - a, - e, - false, - if round < NUM_WORDS_TO_ABSORB { - length - } else { - 0 - }, - if round < NUM_WORDS_TO_ABSORB { - data_rlc - } else { - F::ZERO - }, - F::ZERO, - is_paddings, - inter_data_rlcs, - [F::ZERO; NUM_BYTES_FINAL_HASH], - ); - - // Truncate the newly calculated values - a &= 0xFFFFFFFF; - e &= 0xFFFFFFFF; - } - - // Accumulate - hs[0] += a; - hs[1] += b; - hs[2] += c; - hs[3] += d; - hs[4] += e; - hs[5] += f; - hs[6] += g; - hs[7] += h; - - // Squeeze - - let hash_rlc = if is_final_block { - let hash_bytes = hs - .iter() - .flat_map(|h| (*h as u32).to_be_bytes()) - .collect::>(); - rlc::value(&hash_bytes, rnd) - } else { - F::ZERO - }; - - let final_hash_bytes = if is_final_block { - let mut bytes = [F::ZERO; NUM_BYTES_FINAL_HASH]; - for (i, h) in hs.iter().enumerate() { - for (j, byte) in (*h as u32).to_be_bytes().into_iter().enumerate() { - bytes[4 * i + j] = F::from(byte as u64); - } - } - bytes - } else { - [F::ZERO; NUM_BYTES_FINAL_HASH] - }; - - // Add end rows - let mut add_row_end = |a: u64, e: u64| { - add_row( - 0, - a, - e, - false, - 0, - F::ZERO, - F::ZERO, - [false; ABSORB_WIDTH_PER_ROW_BYTES], - [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES], - [F::ZERO; NUM_BYTES_FINAL_HASH], - ) - }; - add_row_end(hs[3], hs[7]); - add_row_end(hs[2], hs[6]); - add_row_end(hs[1], hs[5]); - - add_row( - 0, - hs[0], - hs[4], - is_final_block, - length, - data_rlc, - hash_rlc, - [false, false, false, in_padding], - [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES], - final_hash_bytes, - ); - - // Now truncate the results - for h in hs.iter_mut() { - *h &= 0xFFFFFFFF; - } - } - - let hash_bytes = hs - .iter() - .flat_map(|h| (*h as u32).to_be_bytes()) - .collect::>(); - - debug!("hash: {:x?}", &hash_bytes); - debug!("data rlc: {:x?}", data_rlc); -} - -pub fn multi_sha256(inputs: &[HashInput], rnd: F) -> Vec> { - let inputs = inputs - .iter() - .map(|input| match input { - HashInput::Single(inner) => [inner.bytes.as_slice(), &[]], - HashInput::TwoToOne(left, right) => [left.bytes.as_slice(), right.bytes.as_slice()], - }) - .collect_vec(); - let mut rows: Vec> = Vec::new(); - for bytes in inputs { - sha256(&mut rows, &bytes, rnd); - } - rows -} diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 48c2dded..50a15e00 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -7,6 +7,7 @@ #![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; @@ -20,8 +21,8 @@ mod ssz_merkle; pub use halo2_base; pub use halo2_base::halo2_proofs; - use halo2_base::halo2_proofs::halo2curves::bn256; + #[allow(type_alias_bounds)] pub type Eth2CircuitBuilder> = gadget::crypto::ShaCircuitBuilder; diff --git a/lightclient-circuits/src/ssz_merkle.rs b/lightclient-circuits/src/ssz_merkle.rs index 76267080..3a877ac4 100644 --- a/lightclient-circuits/src/ssz_merkle.rs +++ b/lightclient-circuits/src/ssz_merkle.rs @@ -31,7 +31,7 @@ pub fn ssz_merkleize_chunks>( .tuples() .map(|(left, right)| { hasher - .digest::<64>(builder, HashInput::TwoToOne(left, right), false) + .digest(builder, HashInput::TwoToOne(left, right)) .map(|res| res.into()) }) .collect::, _>>()?; @@ -59,14 +59,13 @@ pub fn verify_merkle_proof>( for witness in proof.into_iter() { computed_hash = hasher - .digest::<64>( + .digest( builder, if gindex % 2 == 0 { HashInput::TwoToOne(computed_hash, witness) } else { HashInput::TwoToOne(witness, computed_hash) }, - false, )? .into(); gindex /= 2; @@ -84,258 +83,10 @@ pub fn verify_merkle_proof>( Ok(()) } -pub const ZERO_HASHES: [[u8; 32]; 64] = [ +pub const ZERO_HASHES: [[u8; 32]; 2] = [ [0; 32], [ 245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169, 39, 89, 251, 75, ], - [ - 219, 86, 17, 78, 0, 253, 212, 193, 248, 92, 137, 43, 243, 90, 201, 168, 146, 137, 170, 236, - 177, 235, 208, 169, 108, 222, 96, 106, 116, 139, 93, 113, - ], - [ - 199, 128, 9, 253, 240, 127, 197, 106, 17, 241, 34, 55, 6, 88, 163, 83, 170, 165, 66, 237, - 99, 228, 76, 75, 193, 95, 244, 205, 16, 90, 179, 60, - ], - [ - 83, 109, 152, 131, 127, 45, 209, 101, 165, 93, 94, 234, 233, 20, 133, 149, 68, 114, 213, - 111, 36, 109, 242, 86, 191, 60, 174, 25, 53, 42, 18, 60, - ], - [ - 158, 253, 224, 82, 170, 21, 66, 159, 174, 5, 186, 212, 208, 177, 215, 198, 77, 166, 77, 3, - 215, 161, 133, 74, 88, 140, 44, 184, 67, 12, 13, 48, - ], - [ - 216, 141, 223, 238, 212, 0, 168, 117, 85, 150, 178, 25, 66, 193, 73, 126, 17, 76, 48, 46, - 97, 24, 41, 15, 145, 230, 119, 41, 118, 4, 31, 161, - ], - [ - 135, 235, 13, 219, 165, 126, 53, 246, 210, 134, 103, 56, 2, 164, 175, 89, 117, 226, 37, 6, - 199, 207, 76, 100, 187, 107, 229, 238, 17, 82, 127, 44, - ], - [ - 38, 132, 100, 118, 253, 95, 197, 74, 93, 67, 56, 81, 103, 201, 81, 68, 242, 100, 63, 83, - 60, 200, 91, 185, 209, 107, 120, 47, 141, 125, 177, 147, - ], - [ - 80, 109, 134, 88, 45, 37, 36, 5, 184, 64, 1, 135, 146, 202, 210, 191, 18, 89, 241, 239, 90, - 165, 248, 135, 225, 60, 178, 240, 9, 79, 81, 225, - ], - [ - 255, 255, 10, 215, 230, 89, 119, 47, 149, 52, 193, 149, 200, 21, 239, 196, 1, 78, 241, 225, - 218, 237, 68, 4, 192, 99, 133, 209, 17, 146, 233, 43, - ], - [ - 108, 240, 65, 39, 219, 5, 68, 28, 216, 51, 16, 122, 82, 190, 133, 40, 104, 137, 14, 67, 23, - 230, 160, 42, 180, 118, 131, 170, 117, 150, 66, 32, - ], - [ - 183, 208, 95, 135, 95, 20, 0, 39, 239, 81, 24, 162, 36, 123, 187, 132, 206, 143, 47, 15, - 17, 35, 98, 48, 133, 218, 247, 150, 12, 50, 159, 95, - ], - [ - 223, 106, 245, 245, 187, 219, 107, 233, 239, 138, 166, 24, 228, 191, 128, 115, 150, 8, 103, - 23, 30, 41, 103, 111, 139, 40, 77, 234, 106, 8, 168, 94, - ], - [ - 181, 141, 144, 15, 94, 24, 46, 60, 80, 239, 116, 150, 158, 161, 108, 119, 38, 197, 73, 117, - 124, 194, 53, 35, 195, 105, 88, 125, 167, 41, 55, 132, - ], - [ - 212, 154, 117, 2, 255, 207, 176, 52, 11, 29, 120, 133, 104, 133, 0, 202, 48, 129, 97, 167, - 249, 107, 98, 223, 157, 8, 59, 113, 252, 200, 242, 187, - ], - [ - 143, 230, 177, 104, 146, 86, 192, 211, 133, 244, 47, 91, 190, 32, 39, 162, 44, 25, 150, - 225, 16, 186, 151, 193, 113, 211, 229, 148, 141, 233, 43, 235, - ], - [ - 141, 13, 99, 195, 158, 186, 222, 133, 9, 224, 174, 60, 156, 56, 118, 251, 95, 161, 18, 190, - 24, 249, 5, 236, 172, 254, 203, 146, 5, 118, 3, 171, - ], - [ - 149, 238, 200, 178, 229, 65, 202, 212, 233, 29, 227, 131, 133, 242, 224, 70, 97, 159, 84, - 73, 108, 35, 130, 203, 108, 172, 213, 185, 140, 38, 245, 164, - ], - [ - 248, 147, 233, 8, 145, 119, 117, 182, 43, 255, 35, 41, 77, 187, 227, 161, 205, 142, 108, - 193, 195, 91, 72, 1, 136, 123, 100, 106, 111, 129, 241, 127, - ], - [ - 205, 219, 167, 181, 146, 227, 19, 51, 147, 193, 97, 148, 250, 199, 67, 26, 191, 47, 84, - 133, 237, 113, 29, 178, 130, 24, 60, 129, 158, 8, 235, 170, - ], - [ - 138, 141, 127, 227, 175, 140, 170, 8, 90, 118, 57, 168, 50, 0, 20, 87, 223, 185, 18, 138, - 128, 97, 20, 42, 208, 51, 86, 41, 255, 35, 255, 156, - ], - [ - 254, 179, 195, 55, 215, 165, 26, 111, 191, 0, 185, 227, 76, 82, 225, 201, 25, 92, 150, 155, - 212, 231, 160, 191, 213, 29, 92, 91, 237, 156, 17, 103, - ], - [ - 231, 31, 10, 168, 60, 195, 46, 223, 190, 250, 159, 77, 62, 1, 116, 202, 133, 24, 46, 236, - 159, 58, 9, 246, 166, 192, 223, 99, 119, 165, 16, 215, - ], - [ - 49, 32, 111, 168, 10, 80, 187, 106, 190, 41, 8, 80, 88, 241, 98, 18, 33, 42, 96, 238, 200, - 240, 73, 254, 203, 146, 216, 200, 224, 168, 75, 192, - ], - [ - 33, 53, 43, 254, 203, 237, 221, 233, 147, 131, 159, 97, 76, 61, 172, 10, 62, 227, 117, 67, - 249, 180, 18, 177, 97, 153, 220, 21, 142, 35, 181, 68, - ], - [ - 97, 158, 49, 39, 36, 187, 109, 124, 49, 83, 237, 157, 231, 145, 215, 100, 163, 102, 179, - 137, 175, 19, 197, 139, 248, 168, 217, 4, 129, 164, 103, 101, - ], - [ - 124, 221, 41, 134, 38, 130, 80, 98, 141, 12, 16, 227, 133, 197, 140, 97, 145, 230, 251, - 224, 81, 145, 188, 192, 79, 19, 63, 44, 234, 114, 193, 196, - ], - [ - 132, 137, 48, 189, 123, 168, 202, 197, 70, 97, 7, 33, 19, 251, 39, 136, 105, 224, 123, 184, - 88, 127, 145, 57, 41, 51, 55, 77, 1, 123, 203, 225, - ], - [ - 136, 105, 255, 44, 34, 178, 140, 193, 5, 16, 217, 133, 50, 146, 128, 51, 40, 190, 79, 176, - 232, 4, 149, 232, 187, 141, 39, 31, 91, 136, 150, 54, - ], - [ - 181, 254, 40, 231, 159, 27, 133, 15, 134, 88, 36, 108, 233, 182, 161, 231, 180, 159, 192, - 109, 183, 20, 62, 143, 224, 180, 242, 176, 197, 82, 58, 92, - ], - [ - 152, 94, 146, 159, 112, 175, 40, 208, 189, 209, 169, 10, 128, 143, 151, 127, 89, 124, 124, - 119, 140, 72, 158, 152, 211, 189, 137, 16, 211, 26, 192, 247, - ], - [ - 198, 246, 126, 2, 230, 228, 225, 189, 239, 185, 148, 198, 9, 137, 83, 243, 70, 54, 186, 43, - 108, 162, 10, 71, 33, 210, 178, 106, 136, 103, 34, 255, - ], - [ - 28, 154, 126, 95, 241, 207, 72, 180, 173, 21, 130, 211, 244, 228, 161, 0, 79, 59, 32, 216, - 197, 162, 183, 19, 135, 164, 37, 74, 217, 51, 235, 197, - ], - [ - 47, 7, 90, 226, 41, 100, 107, 111, 106, 237, 25, 165, 227, 114, 207, 41, 80, 129, 64, 30, - 184, 147, 255, 89, 155, 63, 154, 204, 12, 13, 62, 125, - ], - [ - 50, 137, 33, 222, 181, 150, 18, 7, 104, 1, 232, 205, 97, 89, 33, 7, 181, 198, 124, 121, - 184, 70, 89, 92, 198, 50, 12, 57, 91, 70, 54, 44, - ], - [ - 191, 185, 9, 253, 178, 54, 173, 36, 17, 180, 228, 136, 56, 16, 160, 116, 184, 64, 70, 70, - 137, 152, 108, 63, 138, 128, 145, 130, 126, 23, 195, 39, - ], - [ - 85, 216, 251, 54, 135, 186, 59, 164, 159, 52, 44, 119, 245, 161, 248, 155, 236, 131, 216, - 17, 68, 110, 26, 70, 113, 57, 33, 61, 100, 11, 106, 116, - ], - [ - 247, 33, 13, 79, 142, 126, 16, 57, 121, 14, 123, 244, 239, 162, 7, 85, 90, 16, 166, 219, - 29, 212, 185, 93, 163, 19, 170, 168, 139, 136, 254, 118, - ], - [ - 173, 33, 181, 22, 203, 198, 69, 255, 227, 74, 181, 222, 28, 138, 239, 140, 212, 231, 248, - 210, 181, 30, 142, 20, 86, 173, 199, 86, 60, 218, 32, 111, - ], - [ - 107, 254, 141, 43, 204, 66, 55, 183, 74, 80, 71, 5, 142, 244, 85, 51, 158, 205, 115, 96, - 203, 99, 191, 187, 142, 229, 68, 142, 100, 48, 186, 4, - ], - [ - 167, 242, 60, 233, 24, 23, 64, 220, 34, 12, 129, 71, 130, 101, 79, 238, 106, 206, 185, 241, - 236, 146, 34, 196, 226, 70, 125, 10, 177, 104, 8, 55, - ], - [ - 174, 249, 71, 108, 137, 89, 10, 44, 140, 201, 179, 183, 79, 73, 103, 199, 87, 196, 157, - 152, 102, 164, 75, 172, 242, 31, 162, 237, 103, 93, 223, 162, - ], - [ - 154, 66, 188, 173, 130, 246, 169, 228, 18, 132, 216, 8, 234, 211, 25, 242, 159, 59, 8, 32, - 157, 104, 15, 14, 44, 231, 21, 16, 208, 113, 226, 5, - ], - [ - 209, 166, 109, 53, 74, 103, 185, 207, 23, 149, 113, 216, 229, 249, 119, 146, 113, 110, 141, - 212, 236, 68, 25, 104, 57, 163, 247, 198, 183, 79, 139, 172, - ], - [ - 250, 250, 48, 37, 242, 248, 149, 9, 194, 199, 28, 116, 251, 160, 205, 146, 133, 142, 244, - 155, 7, 128, 251, 84, 121, 116, 108, 138, 155, 252, 179, 70, - ], - [ - 51, 52, 167, 193, 231, 246, 112, 90, 166, 1, 26, 106, 148, 150, 69, 1, 109, 180, 172, 222, - 12, 169, 171, 214, 109, 199, 157, 130, 102, 66, 48, 86, - ], - [ - 7, 150, 253, 117, 102, 79, 174, 247, 68, 238, 78, 82, 215, 39, 30, 43, 187, 118, 159, 145, - 237, 111, 155, 116, 216, 182, 148, 245, 102, 6, 133, 44, - ], - [ - 123, 163, 174, 74, 65, 127, 232, 84, 91, 20, 43, 200, 159, 74, 220, 215, 174, 19, 148, 28, - 186, 183, 117, 11, 131, 233, 240, 166, 109, 22, 190, 100, - ], - [ - 120, 143, 175, 204, 74, 165, 32, 57, 154, 219, 174, 209, 149, 248, 177, 44, 78, 179, 30, - 193, 1, 104, 229, 10, 171, 198, 89, 166, 174, 165, 22, 220, - ], - [ - 232, 51, 215, 166, 113, 96, 230, 139, 244, 201, 4, 74, 83, 7, 125, 242, 114, 122, 208, 12, - 243, 111, 73, 73, 199, 182, 129, 169, 18, 20, 12, 187, - ], - [ - 48, 158, 171, 240, 149, 220, 103, 20, 249, 244, 216, 100, 187, 165, 175, 250, 224, 179, 90, - 226, 245, 227, 86, 91, 204, 58, 71, 178, 18, 118, 119, 1, - ], - [ - 34, 106, 142, 190, 250, 40, 134, 101, 166, 68, 165, 2, 115, 51, 94, 251, 182, 16, 81, 15, - 36, 27, 91, 114, 12, 138, 54, 141, 89, 166, 154, 93, - ], - [ - 65, 171, 253, 153, 84, 37, 130, 118, 37, 147, 129, 49, 175, 12, 79, 51, 254, 11, 212, 104, - 140, 34, 44, 33, 250, 157, 168, 232, 156, 170, 3, 248, - ], - [ - 68, 44, 100, 46, 245, 15, 161, 166, 103, 166, 230, 209, 5, 199, 124, 92, 195, 254, 200, - 215, 170, 37, 112, 207, 26, 48, 119, 181, 3, 195, 128, 105, - ], - [ - 160, 160, 141, 252, 155, 66, 217, 108, 45, 225, 155, 109, 18, 123, 138, 225, 54, 221, 207, - 62, 90, 208, 220, 228, 34, 196, 90, 86, 246, 31, 106, 116, - ], - [ - 125, 52, 131, 130, 175, 9, 109, 190, 11, 240, 134, 199, 187, 57, 178, 162, 192, 188, 54, - 182, 33, 171, 12, 115, 142, 152, 133, 215, 49, 216, 23, 64, - ], - [ - 58, 177, 52, 117, 29, 25, 18, 105, 2, 108, 134, 153, 78, 170, 139, 67, 168, 59, 74, 209, - 246, 208, 231, 115, 129, 196, 226, 151, 74, 251, 200, 246, - ], - [ - 154, 116, 82, 97, 29, 178, 210, 62, 174, 38, 249, 189, 187, 136, 149, 142, 244, 76, 100, - 208, 254, 152, 123, 233, 247, 38, 173, 249, 56, 245, 15, 108, - ], - [ - 114, 92, 127, 129, 96, 55, 191, 228, 82, 205, 30, 123, 163, 90, 196, 126, 220, 180, 154, - 154, 43, 39, 174, 202, 112, 220, 228, 131, 203, 125, 237, 31, - ], - [ - 44, 234, 26, 245, 31, 178, 139, 98, 136, 124, 57, 153, 138, 201, 254, 244, 223, 222, 218, - 31, 7, 224, 113, 186, 85, 138, 23, 58, 253, 6, 203, 195, - ], - [ - 255, 29, 89, 249, 139, 108, 85, 29, 149, 8, 147, 87, 5, 125, 92, 139, 226, 100, 2, 39, 158, - 157, 240, 177, 223, 26, 16, 183, 43, 243, 146, 127, - ], - [ - 47, 138, 24, 31, 124, 153, 221, 33, 90, 117, 41, 191, 226, 150, 169, 96, 58, 20, 70, 115, - 113, 134, 210, 26, 235, 139, 199, 174, 89, 225, 253, 33, - ], - [ - 236, 197, 2, 201, 177, 20, 95, 57, 80, 203, 125, 62, 56, 66, 68, 111, 129, 164, 240, 223, - 29, 245, 55, 206, 225, 57, 239, 100, 234, 152, 75, 217, - ], ]; diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 986400e5..5d0a3e80 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -1,7 +1,10 @@ use crate::{ - gadget::crypto::{ - calculate_ysquared, G1Chip, G1Point, G2Chip, HashInstructions, Sha256Chip, - ShaCircuitBuilder, ShaFlexGateManager, + gadget::{ + crypto::{ + calculate_ysquared, G1Chip, G1Point, G2Chip, HashInstructions, Sha256Chip, + ShaCircuitBuilder, ShaFlexGateManager, + }, + to_bytes_le, }, poseidon::{fq_array_poseidon, fq_array_poseidon_native}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, @@ -132,10 +135,9 @@ impl StepCircuit { ], )?; - let signing_root = sha256_chip.digest::<64>( + let signing_root = sha256_chip.digest( builder, HashInput::TwoToOne(attested_header.into(), args.domain.to_vec().into_witness()), - false, )?; let signature = @@ -174,9 +176,9 @@ impl StepCircuit { )?; // Public Input Commitment - let participation_sum_le = to_bytes_le::<_, 8>(builder.main(), gate, &participation_sum); + let participation_sum_le = to_bytes_le::<_, 8>(&participation_sum, gate, builder.main()); - let poseidon_commit_le = to_bytes_le::<_, 32>(builder.main(), gate, &poseidon_commit); + let poseidon_commit_le = to_bytes_le::<_, 32>(&poseidon_commit, gate, builder.main()); // See "Onion hashing vs. Input concatenation" in https://github.com/ChainSafe/Spectre/issues/17#issuecomment-1740965182 let public_inputs_concat = itertools::chain![ @@ -196,7 +198,7 @@ impl StepCircuit { .collect_vec(); let pi_hash_bytes = sha256_chip - .digest::<{ 8 * 3 + 32 * 3 }>(builder, public_inputs_concat, false)? + .digest(builder, public_inputs_concat)? .try_into() .unwrap(); @@ -303,30 +305,6 @@ pub fn clear_3_bits( range.div_mod(ctx, b_shifted, BigUint::from(8u64), 8).0 } -pub fn to_bytes_le( - ctx: &mut Context, - gate: &impl GateInstructions, - a: &AssignedValue, -) -> Vec> { - let byte_bases = (0..MAX_BYTES) - .map(|i| QuantumCell::Constant(gate.pow_of_two()[i * 8])) - .collect_vec(); - - let assigned_bytes = a - .value() - .to_bytes_le() - .into_iter() - .take(MAX_BYTES) - .map(|v| ctx.load_witness(F::from(v as u64))) - .collect_vec(); - - // Constrain poseidon bytes to be equal to the recovered checksum - let checksum = gate.inner_product(ctx, assigned_bytes.clone(), byte_bases); - ctx.constrain_equal(&checksum, &checksum); - - assigned_bytes -} - impl StepCircuit { fn assign_signature( ctx: &mut Context, @@ -461,7 +439,7 @@ mod tests { const K: u32 = 21; let witness = load_circuit_args(); - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + let pinning = Eth2ConfigPinning::from_path("./config/sync_step_21.json"); let circuit = StepCircuit::::create_circuit( CircuitBuilderStage::Mock, @@ -486,8 +464,8 @@ mod tests { let pk = StepCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", - "./config/sync_step.json", + "../build/sync_step_22.pkey", + "./config/sync_step_22.json", false, &SyncStepArgs::::default(), ); @@ -497,7 +475,7 @@ mod tests { let _ = StepCircuit::::gen_proof_shplonk( ¶ms, &pk, - "./config/sync_step.json", + "./config/sync_step_22.json", &witness, ) .expect("proof generation & verification should not fail"); @@ -510,15 +488,15 @@ mod tests { let pk = StepCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", - "./config/sync_step.json", + "../build/sync_step_22.pkey", + "./config/sync_step_22.json", false, &SyncStepArgs::::default(), ); let witness = load_circuit_args(); - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + let pinning = Eth2ConfigPinning::from_path("./config/sync_step_22.json"); let circuit = StepCircuit::::create_circuit( CircuitBuilderStage::Prover, diff --git a/lightclient-circuits/src/util.rs b/lightclient-circuits/src/util.rs index 4ae8e821..2782f3d1 100644 --- a/lightclient-circuits/src/util.rs +++ b/lightclient-circuits/src/util.rs @@ -3,9 +3,6 @@ mod common; pub use common::*; -mod constraint_builder; -pub(crate) use constraint_builder::*; - mod conversion; pub(crate) use conversion::*; @@ -17,48 +14,6 @@ pub use circuit::*; use eth_types::*; -/// Helper trait that implements functionality to represent a generic type as -/// array of N-bits. -pub trait AsBits { - /// Return the bits of self, starting from the most significant. - fn as_bits(&self) -> [bool; N]; -} - -/// Packs bits into bytes -pub mod to_bytes { - use crate::gadget::Expr; - use eth_types::Field; - use halo2_base::halo2_proofs::plonk::Expression; - - pub(crate) fn expr(bits: &[Expression]) -> Vec> { - debug_assert!(bits.len() % 8 == 0, "bits not a multiple of 8"); - let mut bytes = Vec::new(); - for byte_bits in bits.chunks(8) { - let mut value = 0.expr(); - let mut multiplier = F::ONE; - for byte in byte_bits.iter() { - value = value + byte.expr() * multiplier; - multiplier *= F::from(2); - } - bytes.push(value); - } - bytes - } - - pub(crate) fn value(bits: &[u8]) -> Vec { - debug_assert!(bits.len() % 8 == 0, "bits not a multiple of 8"); - let mut bytes = Vec::new(); - for byte_bits in bits.chunks(8) { - let mut value = 0u8; - for (idx, bit) in byte_bits.iter().enumerate() { - value += *bit << idx; - } - bytes.push(value); - } - bytes - } -} - pub fn bigint_to_le_bytes( limbs: impl IntoIterator, limb_bits: usize, diff --git a/lightclient-circuits/src/util/circuit.rs b/lightclient-circuits/src/util/circuit.rs index 8c25ca39..126dcb4f 100644 --- a/lightclient-circuits/src/util/circuit.rs +++ b/lightclient-circuits/src/util/circuit.rs @@ -2,6 +2,7 @@ use std::env::{set_var, var}; use std::fs; use std::{fs::File, path::Path}; +use eth_types::Field; use halo2_base::gates::circuit::{BaseCircuitParams, CircuitBuilderStage}; use halo2_base::gates::flex_gate::MultiPhaseThreadBreakPoints; use halo2_base::halo2_proofs::{ @@ -11,7 +12,6 @@ use halo2_base::halo2_proofs::{ poly::commitment::Params, poly::kzg::commitment::ParamsKZG, }; -use halo2_base::utils::BigPrimeField; use serde::{Deserialize, Serialize}; use snark_verifier_sdk::evm::{ encode_calldata, evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk, @@ -79,7 +79,7 @@ impl Halo2ConfigPinning for Eth2ConfigPinning { } } -pub trait PinnableCircuit: CircuitExt { +pub trait PinnableCircuit: CircuitExt { type Pinning: Halo2ConfigPinning; fn break_points(&self) -> ::BreakPoints; diff --git a/lightclient-circuits/src/util/common.rs b/lightclient-circuits/src/util/common.rs index 32e18aaf..aa481ec6 100644 --- a/lightclient-circuits/src/util/common.rs +++ b/lightclient-circuits/src/util/common.rs @@ -1,119 +1,16 @@ #![allow(dead_code)] -use crate::gadget::Expr; use eth_types::*; use halo2_base::{ gates::circuit::CircuitBuilderStage, halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, - poly::Rotation, + circuit::{Layouter, Region}, + plonk::{ConstraintSystem, Error}, }, virtual_region::{ copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, }, }; -use std::hash::Hash; - -#[derive(Clone, Debug)] -pub struct Cell { - // expression for constraint - expression: Expression, - column: Column, - // relative position to selector for synthesis - rotation: usize, - cell_column_index: usize, -} - -impl Cell { - pub(crate) fn new( - meta: &mut VirtualCells, - column: Column, - rotation: usize, - cell_column_index: usize, - ) -> Self { - Self { - expression: meta.query_advice(column, Rotation(rotation as i32)), - column, - rotation, - cell_column_index, - } - } - - pub(crate) fn assign( - &self, - region: &mut Region<'_, F>, - offset: usize, - value: Value, - ) -> Result, Error> { - region.assign_advice( - || { - format!( - "Cell column: {:?} and rotation: {}", - self.column, self.rotation - ) - }, - self.column, - offset + self.rotation, - || value, - ) - } -} - -impl Expr for Cell { - fn expr(&self) -> Expression { - self.expression.clone() - } -} - -impl Expr for &Cell { - fn expr(&self) -> Expression { - self.expression.clone() - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum CellType { - StoragePhase1, - StoragePhase2, - StoragePermutation, - LookupByte, - // Lookup(Table), -} - -impl CellType { - // The phase that given `Expression` becomes evaluateable. - fn expr_phase(expr: &Expression) -> u8 { - use Expression::*; - match expr { - Challenge(challenge) => challenge.phase() + 1, - Advice(query) => query.phase(), - Constant(_) | Selector(_) | Fixed(_) | Instance(_) => 0, - Negated(a) | Expression::Scaled(a, _) => Self::expr_phase(a), - Sum(a, b) | Product(a, b) => std::cmp::max(Self::expr_phase(a), Self::expr_phase(b)), - } - } - - /// Return the storage phase of phase - pub(crate) fn storage_for_phase(phase: u8) -> CellType { - match phase { - 0 => CellType::StoragePhase1, - 1 => CellType::StoragePhase2, - _ => unreachable!(), - } - } - - /// Return the storage cell of the expression - pub(crate) fn storage_for_expr(expr: &Expression) -> CellType { - Self::storage_for_phase(Self::expr_phase::(expr)) - } - - /// Return the storage cell of the advice column - pub(crate) fn storage_for_column(col: &Column) -> CellType { - Self::storage_for_phase(col.column_type().phase()) - } -} - pub trait GateBuilderConfig: Clone + Sized { fn configure(meta: &mut ConstraintSystem) -> Self; diff --git a/lightclient-circuits/src/util/constraint_builder.rs b/lightclient-circuits/src/util/constraint_builder.rs deleted file mode 100644 index b62b6e70..00000000 --- a/lightclient-circuits/src/util/constraint_builder.rs +++ /dev/null @@ -1,186 +0,0 @@ -use crate::gadget::Expr; -use eth_types::Field; -use halo2_base::halo2_proofs::plonk::Expression; - -use super::{Cell, CellType}; - -pub(crate) trait ConstrainBuilderCommon { - fn add_constraint(&mut self, name: &'static str, constraint: Expression); - - fn require_zero(&mut self, name: &'static str, constraint: Expression) { - self.add_constraint(name, constraint); - } - - fn require_equal(&mut self, name: &'static str, lhs: Expression, rhs: Expression) { - self.add_constraint(name, lhs - rhs); - } - - fn require_boolean(&mut self, name: &'static str, value: Expression) { - self.add_constraint(name, value.clone() * (1.expr() - value)); - } - - fn require_true(&mut self, name: &'static str, e: Expression) { - self.require_equal(name, e, 1.expr()); - } - - fn require_in_set( - &mut self, - name: &'static str, - value: Expression, - set: Vec>, - ) { - self.add_constraint( - name, - set.iter() - .fold(1.expr(), |acc, item| acc * (value.clone() - item.clone())), - ); - } - - fn add_constraints(&mut self, constraints: Vec<(&'static str, Expression)>) { - for (name, constraint) in constraints { - self.add_constraint(name, constraint); - } - } - - fn condition( - &mut self, - condition: Expression, - constraint: impl FnOnce(&mut Self) -> R, - ) -> R; - - fn query_bool(&mut self) -> Cell { - let cell = self.query_cell(); - self.require_boolean("Constrain cell to be a bool", cell.expr()); - cell - } - - fn query_bytes(&mut self) -> [Cell; N] { - self.query_bytes_dyn(N).try_into().unwrap() - } - - fn query_bytes_dyn(&mut self, count: usize) -> Vec> { - self.query_cells(CellType::LookupByte, count) - } - - fn query_cell(&mut self) -> Cell { - self.query_cell_with_type(CellType::StoragePhase1) - } - - fn query_cell_phase2(&mut self) -> Cell { - self.query_cell_with_type(CellType::StoragePhase2) - } - - fn query_copy_cell(&mut self) -> Cell { - self.query_cell_with_type(CellType::StoragePermutation) - } - - fn query_cell_with_type(&mut self, cell_type: CellType) -> Cell { - self.query_cells(cell_type, 1).first().unwrap().clone() - } - - fn query_cells(&mut self, cell_type: CellType, count: usize) -> Vec>; -} - -#[derive(Default)] -pub struct BaseConstraintBuilder { - pub constraints: Vec<(&'static str, Expression)>, - pub max_degree: usize, - pub condition: Option>, -} - -impl BaseConstraintBuilder { - pub(crate) fn new(max_degree: usize) -> Self { - BaseConstraintBuilder { - constraints: Vec::new(), - max_degree, - condition: None, - } - } - - #[allow(dead_code)] - pub(crate) fn require_zero(&mut self, name: &'static str, constraint: Expression) { - self.add_constraint(name, constraint); - } - - pub(crate) fn require_equal( - &mut self, - name: &'static str, - lhs: Expression, - rhs: Expression, - ) { - self.add_constraint(name, lhs - rhs); - } - - pub(crate) fn require_boolean(&mut self, name: &'static str, value: Expression) { - self.add_constraint(name, value.clone() * (1.expr() - value)); - } - - #[allow(dead_code)] - pub(crate) fn require_in_set( - &mut self, - name: &'static str, - value: Expression, - set: Vec>, - ) { - self.add_constraint( - name, - set.iter() - .fold(1.expr(), |acc, item| acc * (value.clone() - item.clone())), - ); - } - - pub(crate) fn condition( - &mut self, - condition: Expression, - constraint: impl FnOnce(&mut Self) -> R, - ) -> R { - debug_assert!( - self.condition.is_none(), - "Nested condition is not supported" - ); - self.condition = Some(condition); - let ret = constraint(self); - self.condition = None; - ret - } - - #[allow(dead_code)] - pub(crate) fn add_constraints(&mut self, constraints: Vec<(&'static str, Expression)>) { - for (name, constraint) in constraints { - self.add_constraint(name, constraint); - } - } - - pub(crate) fn add_constraint(&mut self, name: &'static str, constraint: Expression) { - let constraint = match &self.condition { - Some(condition) => condition.clone() * constraint, - None => constraint, - }; - self.validate_degree(constraint.degree(), name); - self.constraints.push((name, constraint)); - } - - pub(crate) fn validate_degree(&self, degree: usize, name: &'static str) { - if self.max_degree > 0 { - debug_assert!( - degree <= self.max_degree, - "Expression {} degree too high: {} > {}", - name, - degree, - self.max_degree, - ); - } - } - - pub(crate) fn gate(&self, selector: Expression) -> Vec<(&'static str, Expression)> { - self.constraints - .clone() - .into_iter() - .map(|(name, constraint)| (name, selector.clone() * constraint)) - .filter(|(name, constraint)| { - self.validate_degree(constraint.degree(), name); - true - }) - .collect() - } -} diff --git a/lightclient-circuits/src/witness/rotation.rs b/lightclient-circuits/src/witness/rotation.rs index 5efb889e..309e7a91 100644 --- a/lightclient-circuits/src/witness/rotation.rs +++ b/lightclient-circuits/src/witness/rotation.rs @@ -1,24 +1,21 @@ -use crate::gadget::crypto::constant_randomness; -use eth_types::{Field, Spec}; +use eth_types::Spec; use ethereum_consensus_types::BeaconBlockHeader; use itertools::Itertools; use serde::{Deserialize, Serialize}; use std::{iter, marker::PhantomData}; #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CommitteeRotationArgs { +pub struct CommitteeRotationArgs { pub pubkeys_compressed: Vec>, pub finalized_header: BeaconBlockHeader, pub sync_committee_branch: Vec>, - pub randomness: F, - pub _spec: PhantomData, } -impl Default for CommitteeRotationArgs { +impl Default for CommitteeRotationArgs { fn default() -> Self { let dummy_x_bytes = iter::once(192).pad_using(48, |_| 0).rev().collect(); @@ -29,7 +26,6 @@ impl Default for CommitteeRotationArgs { .take(S::SYNC_COMMITTEE_SIZE) .collect_vec(), sync_committee_branch, - randomness: constant_randomness(), finalized_header: Default::default(), _spec: PhantomData, } diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index 553535b1..bbba9385 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -39,7 +39,7 @@ fn run_test_eth2_spec_mock(path: PathB let rotation_circuit = { let pinning: Eth2ConfigPinning = - Eth2ConfigPinning::from_path("./config/committee_update.json"); + Eth2ConfigPinning::from_path(format!("./config/committee_update_{K_ROTATION}.json")); CommitteeUpdateCircuit::::create_circuit( CircuitBuilderStage::Mock, @@ -61,7 +61,8 @@ fn run_test_eth2_spec_mock(path: PathB end_timer!(timer); let sync_circuit = { - let pinning: Eth2ConfigPinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + let pinning: Eth2ConfigPinning = + Eth2ConfigPinning::from_path(format!("./config/sync_step_{K_SYNC}.json")); StepCircuit::::create_circuit( CircuitBuilderStage::Mock, @@ -94,8 +95,8 @@ fn test_eth2_spec_proofgen( let params = gen_srs(K); let pk = StepCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", - "./config/sync_step.json", + "../build/sync_step_20.pkey", + "./config/sync_step_20.json", false, &SyncStepArgs::::default(), ); @@ -103,7 +104,7 @@ fn test_eth2_spec_proofgen( let _ = StepCircuit::::gen_proof_shplonk( ¶ms, &pk, - "./config/sync_step.json", + "./config/sync_step_20.json", &witness, ) .expect("proof generation & verification should not fail"); @@ -120,15 +121,15 @@ fn test_eth2_spec_evm_verify( let pk = StepCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", - "./config/sync_step.json", + "../build/sync_step_21.pkey", + "./config/sync_step_21.json", false, &SyncStepArgs::::default(), ); let (witness, _) = read_test_files_and_gen_witness(&path); - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + let pinning = Eth2ConfigPinning::from_path("./config/sync_step_21.json"); let circuit = StepCircuit::::create_circuit( CircuitBuilderStage::Prover, diff --git a/preprocessor/src/lib.rs b/preprocessor/src/lib.rs index 97594a12..56475ff4 100644 --- a/preprocessor/src/lib.rs +++ b/preprocessor/src/lib.rs @@ -2,7 +2,6 @@ #![feature(generic_const_exprs)] mod sync; -use std::ops::Deref; use beacon_api_client::{BlockId, Client, ClientTypes, Value, VersionedValue}; use eth_types::Spec; @@ -11,15 +10,16 @@ use ethereum_consensus_types::{ LightClientUpdateCapella, Root, }; use itertools::Itertools; -use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use lightclient_circuits::witness::{CommitteeRotationArgs, SyncStepArgs}; use serde::{Deserialize, Serialize}; use ssz_rs::{Node, Vector}; +use std::ops::Deref; pub use sync::*; mod rotation; 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 }, @@ -32,7 +32,7 @@ pub async fn light_client_update_to_args( >, pubkeys_compressed: Vector, domain: [u8; 32], -) -> eyre::Result<(SyncStepArgs, CommitteeRotationArgs)> +) -> eyre::Result<(SyncStepArgs, CommitteeRotationArgs)> where [(); S::SYNC_COMMITTEE_SIZE]:, [(); S::FINALIZED_HEADER_DEPTH]:, diff --git a/preprocessor/src/rotation.rs b/preprocessor/src/rotation.rs index d295aab2..82458d3b 100644 --- a/preprocessor/src/rotation.rs +++ b/preprocessor/src/rotation.rs @@ -4,8 +4,7 @@ use beacon_api_client::{BlockId, Client, ClientTypes}; use eth_types::Spec; use ethereum_consensus_types::{BeaconBlockHeader, LightClientUpdateCapella}; use itertools::Itertools; -use lightclient_circuits::halo2_base::halo2_proofs::halo2curves::bn256::Fr; -use lightclient_circuits::{gadget::crypto, witness::CommitteeRotationArgs}; +use lightclient_circuits::witness::CommitteeRotationArgs; use log::debug; use ssz_rs::Merkleized; use tokio::fs; @@ -14,7 +13,7 @@ use crate::{get_block_header, get_light_client_update_at_period}; pub async fn fetch_rotation_args( client: &Client, -) -> eyre::Result> +) -> eyre::Result> where [(); S::SYNC_COMMITTEE_SIZE]:, [(); S::FINALIZED_HEADER_DEPTH]:, @@ -46,7 +45,7 @@ pub async fn rotation_args_from_update( { S::BYTES_PER_LOGS_BLOOM }, { S::MAX_EXTRA_DATA_BYTES }, >, -) -> eyre::Result> +) -> eyre::Result> where [(); S::SYNC_COMMITTEE_SIZE]:, [(); S::FINALIZED_HEADER_DEPTH]:, @@ -88,9 +87,8 @@ where "Execution payload merkle proof verification failed" ); - let args = CommitteeRotationArgs:: { + let args = CommitteeRotationArgs:: { pubkeys_compressed, - randomness: crypto::constant_randomness(), finalized_header: update.attested_header.beacon.clone(), sync_committee_branch: sync_committee_branch .into_iter() @@ -101,9 +99,7 @@ where Ok(args) } -pub async fn read_rotation_args( - path: String, -) -> eyre::Result> { +pub async fn read_rotation_args(path: String) -> eyre::Result> { #[derive(serde::Deserialize)] struct ArgsJson { finalized_header: BeaconBlockHeader, @@ -122,9 +118,8 @@ pub async fn read_rotation_args( ) .map_err(|e| eyre::eyre!("Error decoding witness {}", e))?; - Ok(CommitteeRotationArgs:: { + Ok(CommitteeRotationArgs:: { pubkeys_compressed, - randomness: crypto::constant_randomness(), finalized_header, sync_committee_branch: committee_root_branch, _spec: PhantomData, @@ -167,16 +162,16 @@ mod tests { #[tokio::test] async fn test_rotation_step_snark_sepolia() { - const CONFIG_PATH: &str = "../lightclient-circuits/config/committee_update.json"; + const CONFIG_PATH: &str = "../lightclient-circuits/config/committee_update_18.json"; const K: u32 = 21; let params = gen_srs(K); let pk = CommitteeUpdateCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", + "../build/sync_step_21.pkey", CONFIG_PATH, false, - &CommitteeRotationArgs::::default(), + &CommitteeRotationArgs::::default(), ); let client = MainnetClient::new(Url::parse("http://65.109.55.120:9596").unwrap()); let witness = fetch_rotation_args::(&client).await.unwrap(); diff --git a/preprocessor/src/sync.rs b/preprocessor/src/sync.rs index 6c8a6c05..82c598e3 100644 --- a/preprocessor/src/sync.rs +++ b/preprocessor/src/sync.rs @@ -199,13 +199,13 @@ mod tests { #[tokio::test] async fn test_sync_step_snark_sepolia() { - const CONFIG_PATH: &str = "../lightclient-circuits/config/sync_step.json"; + const CONFIG_PATH: &str = "../lightclient-circuits/config/sync_step_21.json"; const K: u32 = 21; let params = gen_srs(K); let pk = StepCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", + "../build/sync_step_21.pkey", CONFIG_PATH, false, &SyncStepArgs::::default(), diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index 8fcc4b82..57e988dd 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -98,10 +98,8 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_handler( 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< - eth_types::Minimal, - Fr, - > = fetch_rotation_args(&client).await?; + let witness: lightclient_circuits::witness::CommitteeRotationArgs = + fetch_rotation_args(&client).await?; gen_app_snark::(app_config_path, app_pk_path, witness)? } Spec::Testnet => { diff --git a/test-utils/src/conversions.rs b/test-utils/src/conversions.rs index 753b45d2..cea03da9 100644 --- a/test-utils/src/conversions.rs +++ b/test-utils/src/conversions.rs @@ -33,7 +33,7 @@ pub fn sync_input_from_args(args: SyncStepArgs) -> } pub fn rotate_input_from_args( - args: CommitteeRotationArgs, + args: CommitteeRotationArgs, ) -> RotateInput where [(); Spec::SYNC_COMMITTEE_SIZE]:, diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index 1e8f1529..52563073 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -10,8 +10,6 @@ use ethereum_consensus_types::BeaconBlockHeader; use ethereum_consensus_types::{ForkData, Root}; use itertools::Itertools; use light_client_verifier::ZiplineUpdateWitnessCapella; -use lightclient_circuits::gadget::crypto; -use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use lightclient_circuits::poseidon::{ poseidon_committee_commitment_from_compressed, poseidon_committee_commitment_from_uncompressed, }; @@ -82,7 +80,7 @@ pub fn valid_updates_from_test_path( pub fn read_test_files_and_gen_witness( path: &Path, -) -> (SyncStepArgs, CommitteeRotationArgs) { +) -> (SyncStepArgs, CommitteeRotationArgs) { let bootstrap: LightClientBootstrap = load_snappy_ssz(path.join("bootstrap.ssz_snappy").to_str().unwrap()).unwrap(); @@ -113,7 +111,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:: { + let rotation_wit = CommitteeRotationArgs:: { pubkeys_compressed: zipline_witness .light_client_update .next_sync_committee @@ -122,7 +120,6 @@ pub fn read_test_files_and_gen_witness( .cloned() .map(|pk| pk.to_bytes().to_vec()) .collect_vec(), - randomness: crypto::constant_randomness(), finalized_header: sync_wit.attested_header.clone(), sync_committee_branch, _spec: Default::default(),