diff --git a/circuits/benchmarks/config.json b/circuits/benchmarks/config.json index a4bea2178a..6bedcf83fb 100644 --- a/circuits/benchmarks/config.json +++ b/circuits/benchmarks/config.json @@ -11,8 +11,7 @@ "threshold/pk_generation", "threshold/pk_aggregation", "threshold/share_decryption", - "threshold/decrypted_shares_aggregation_bn", - "threshold/decrypted_shares_aggregation_mod" + "threshold/decrypted_shares_aggregation" ], "oracles": ["default"], "mode": "insecure", diff --git a/circuits/benchmarks/scripts/generate_prover_toml.sh b/circuits/benchmarks/scripts/generate_prover_toml.sh index b4ca4670c5..2b7be187df 100755 --- a/circuits/benchmarks/scripts/generate_prover_toml.sh +++ b/circuits/benchmarks/scripts/generate_prover_toml.sh @@ -80,7 +80,7 @@ get_zk_args() { echo "threshold-share-decryption" return ;; - threshold/decrypted_shares_aggregation_bn|threshold/decrypted_shares_aggregation_mod) + threshold/decrypted_shares_aggregation) echo "decrypted-shares-aggregation" return ;; diff --git a/circuits/benchmarks/scripts/run_benchmarks.sh b/circuits/benchmarks/scripts/run_benchmarks.sh index 49f8a4b5cd..65f29cb78a 100755 --- a/circuits/benchmarks/scripts/run_benchmarks.sh +++ b/circuits/benchmarks/scripts/run_benchmarks.sh @@ -129,7 +129,6 @@ echo " Base Directory: $CIRCUITS_BASE_DIR" echo " Output Directory: ${OUTPUT_DIR}" echo "" -# decrypted_shares_aggregation_mod is for insecure only (Q < 128bit); _bn is for secure (large Q) # Circuit-specific modes come from config.json (e.g. "config" has "modes": ["secure"]); see circuits/benchmarks/config.json RUN_CIRCUITS="" CIRCUIT_MODES=$(jq -r '.circuits[] | (if type == "string" then . else .name end) as $path | (if type == "object" and (.modes != null) then (.modes | join(",")) else "insecure,secure" end) | "\($path)\t\(.)"' "$CONFIG_FILE") @@ -148,14 +147,6 @@ while IFS= read -r line; do continue fi fi - if [ "$MODE" = "secure" ] && [ "$c" = "threshold/decrypted_shares_aggregation_mod" ]; then - echo " Skipping $c (modular variant is insecure-only, Q < 128bit)" - continue - fi - if [ "$MODE" = "insecure" ] && [ "$c" = "threshold/decrypted_shares_aggregation_bn" ]; then - echo " Skipping $c (BigNum variant is for secure/large Q only)" - continue - fi RUN_CIRCUITS="${RUN_CIRCUITS} ${c}" done <<< "$CIRCUIT_MODES" # When --circuit was given but not in config.json, no line matched; run it anyway if path exists (see note above) diff --git a/circuits/bin/threshold/Nargo.toml b/circuits/bin/threshold/Nargo.toml index e303fbe8aa..352848a1ed 100644 --- a/circuits/bin/threshold/Nargo.toml +++ b/circuits/bin/threshold/Nargo.toml @@ -6,7 +6,5 @@ members = [ "user_data_encryption_ct0", "user_data_encryption_ct1", "share_decryption", - "decrypted_shares_aggregation_bn", - "decrypted_shares_aggregation_mod" - + "decrypted_shares_aggregation", ] \ No newline at end of file diff --git a/circuits/bin/threshold/decrypted_shares_aggregation_bn/Nargo.toml b/circuits/bin/threshold/decrypted_shares_aggregation/Nargo.toml similarity index 72% rename from circuits/bin/threshold/decrypted_shares_aggregation_bn/Nargo.toml rename to circuits/bin/threshold/decrypted_shares_aggregation/Nargo.toml index 3c41039fb2..51f6ebf657 100644 --- a/circuits/bin/threshold/decrypted_shares_aggregation_bn/Nargo.toml +++ b/circuits/bin/threshold/decrypted_shares_aggregation/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "decrypted_shares_aggregation_bn" +name = "decrypted_shares_aggregation" type = "bin" authors = ["Gnosis Guild / Enclave"] diff --git a/circuits/bin/threshold/decrypted_shares_aggregation_bn/src/main.nr b/circuits/bin/threshold/decrypted_shares_aggregation/src/main.nr similarity index 87% rename from circuits/bin/threshold/decrypted_shares_aggregation_bn/src/main.nr rename to circuits/bin/threshold/decrypted_shares_aggregation/src/main.nr index 25693a810e..7b2885a4c7 100644 --- a/circuits/bin/threshold/decrypted_shares_aggregation_bn/src/main.nr +++ b/circuits/bin/threshold/decrypted_shares_aggregation/src/main.nr @@ -8,7 +8,7 @@ use lib::configs::default::{MAX_MSG_NON_ZERO_COEFFS, T}; use lib::configs::default::threshold::{ DECRYPTED_SHARES_AGGREGATION_BIT_NOISE, DECRYPTED_SHARES_AGGREGATION_CONFIGS, L, }; -use lib::core::threshold::decrypted_shares_aggregation::DecryptedSharesAggregationBigNum; +use lib::core::threshold::decrypted_shares_aggregation::DecryptedSharesAggregation; use lib::math::polynomial::Polynomial; fn main( @@ -18,7 +18,7 @@ fn main( u_global: Polynomial, crt_quotients: [Polynomial; L], ) { - let decrypted_shares_aggregation: DecryptedSharesAggregationBigNum = DecryptedSharesAggregationBigNum::new( + let decrypted_shares_aggregation: DecryptedSharesAggregation = DecryptedSharesAggregation::new( DECRYPTED_SHARES_AGGREGATION_CONFIGS, decryption_shares, party_ids, diff --git a/circuits/bin/threshold/decrypted_shares_aggregation_bn/README.md b/circuits/bin/threshold/decrypted_shares_aggregation_bn/README.md deleted file mode 100644 index 707a1cdd49..0000000000 --- a/circuits/bin/threshold/decrypted_shares_aggregation_bn/README.md +++ /dev/null @@ -1 +0,0 @@ -instantiation of Decrypted Shares Aggregation circuit with BigNum (for large Q values) (PVSS #7) diff --git a/circuits/bin/threshold/decrypted_shares_aggregation_mod/Nargo.toml b/circuits/bin/threshold/decrypted_shares_aggregation_mod/Nargo.toml deleted file mode 100644 index cf0428de17..0000000000 --- a/circuits/bin/threshold/decrypted_shares_aggregation_mod/Nargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "decrypted_shares_aggregation_mod" -type = "bin" -authors = ["Gnosis Guild / Enclave"] - - -[dependencies] -lib = { path = "../../../lib" } diff --git a/circuits/bin/threshold/decrypted_shares_aggregation_mod/README.md b/circuits/bin/threshold/decrypted_shares_aggregation_mod/README.md deleted file mode 100644 index 05dbe220ab..0000000000 --- a/circuits/bin/threshold/decrypted_shares_aggregation_mod/README.md +++ /dev/null @@ -1,2 +0,0 @@ -instantiation of Decrypted Shares Aggregation circuit with modular arithmetic (for Q < 128bit) (PVSS -#7) diff --git a/circuits/bin/threshold/decrypted_shares_aggregation_mod/src/main.nr b/circuits/bin/threshold/decrypted_shares_aggregation_mod/src/main.nr deleted file mode 100644 index 94e2a695af..0000000000 --- a/circuits/bin/threshold/decrypted_shares_aggregation_mod/src/main.nr +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. - -use lib::configs::default::{MAX_MSG_NON_ZERO_COEFFS, T}; -use lib::configs::default::threshold::{ - DECRYPTED_SHARES_AGGREGATION_BIT_NOISE, DECRYPTED_SHARES_AGGREGATION_CONFIGS, L, -}; -use lib::core::threshold::decrypted_shares_aggregation::DecryptedSharesAggregationModular; -use lib::math::polynomial::Polynomial; - -fn main( - decryption_shares: pub [[Polynomial; L]; T + 1], - party_ids: pub [Field; T + 1], - message: pub Polynomial, - u_global: Polynomial, - crt_quotients: [Polynomial; L], -) { - let decrypted_shares_aggregation: DecryptedSharesAggregationModular = DecryptedSharesAggregationModular::new( - DECRYPTED_SHARES_AGGREGATION_CONFIGS, - decryption_shares, - party_ids, - message, - u_global, - crt_quotients, - ); - - decrypted_shares_aggregation.execute(); -} diff --git a/circuits/lib/src/core/threshold/decrypted_shares_aggregation.nr b/circuits/lib/src/core/threshold/decrypted_shares_aggregation.nr index ff1f2c432d..c6deaff177 100644 --- a/circuits/lib/src/core/threshold/decrypted_shares_aggregation.nr +++ b/circuits/lib/src/core/threshold/decrypted_shares_aggregation.nr @@ -26,14 +26,14 @@ impl Configs { } } -/// Decrypted Shares Aggregation Circuit (Circuit 7) using BigNum -/// for large Q values. +/// Decrypted Shares Aggregation Circuit (Circuit 7). +/// Uses BigNum for Q values (works for both insecure and secure parameter sets). /// /// Verifies: /// 1. Lagrange interpolation to compute u^{(l)} for each CRT basis /// 2. CRT reconstruction: u^{(l)} + r^{(l)} * q_l = u_global /// 3. Decoding verification: message = -Q^{-1} * (t * u_global)_Q mod t -pub struct DecryptedSharesAggregationBigNum { +pub struct DecryptedSharesAggregation { /// Circuit parameters including crypto constants configs: Configs, @@ -53,34 +53,8 @@ pub struct DecryptedSharesAggregationBigNum; L], } -/// Decrypted Shares Aggregation Circuit (Circuit 7) using modular arithmetic -/// -/// Verifies: -/// 1. Lagrange interpolation to compute u^{(l)} for each CRT basis -/// 2. CRT reconstruction: u^{(l)} + r^{(l)} * q_l = u_global -/// 3. Decoding verification: message = -Q^{-1} * (t * u_global)_Q mod t -pub struct DecryptedSharesAggregationModular { - /// Circuit parameters including crypto constants - configs: Configs, - /// Decryption shares from t+1 parties (public witnesses) - decryption_shares: [[Polynomial; L]; T + 1], - - /// Party IDs (x-coordinates) for interpolation (public witnesses) - /// Note: Must be in strictly increasing order for correct Lagrange sign computation - party_ids: [Field; T + 1], - - /// Message polynomial m(x) (public witness) - message: Polynomial, - - /// Global u polynomial (secret witness) - u_global: Polynomial, - - /// CRT quotient polynomials (secret witnesses) - crt_quotients: [Polynomial; L], -} - -impl DecryptedSharesAggregationBigNum { +impl DecryptedSharesAggregation { pub fn new( configs: Configs, decryption_shares: [[Polynomial; L]; T + 1], @@ -89,7 +63,7 @@ impl, crt_quotients: [Polynomial; L], ) -> Self { - DecryptedSharesAggregationBigNum { + DecryptedSharesAggregation { configs, decryption_shares, party_ids, @@ -178,101 +152,6 @@ impl DecryptedSharesAggregationModular { - pub fn new( - configs: Configs, - decryption_shares: [[Polynomial; L]; T + 1], - party_ids: [Field; T + 1], - message: Polynomial, - u_global: Polynomial, - crt_quotients: [Polynomial; L], - ) -> Self { - DecryptedSharesAggregationModular { - configs, - decryption_shares, - party_ids, - message, - u_global, - crt_quotients, - } - } - - /// Alternative verification function using efficient modular arithmetic without BigNum. - /// - /// Uses `ModU128` for decoding verification instead of BigNum. More efficient when - /// Q (the product of all CRT moduli) fits within u128 (e.g., 72 bits for insecure parameter sets). - pub fn execute(self) { - // Step 1: Compute Lagrange coefficients in-circuit - let lagrange_coeffs = compute_all_lagrange_coeffs::(self.configs.qis, self.party_ids); - - // Step 2: Compute u^{(l)} for each CRT basis via Lagrange interpolation - let u_crts = compute_crt_components::( - self.configs.qis, - self.decryption_shares, - lagrange_coeffs, - ); - - // Step 3: Verify CRT reconstruction: u^{(l)} + r^{(l)} * q_l = u_global - verify_crt_reconstruction::( - self.configs.qis, - self.u_global, - self.crt_quotients, - u_crts, - ); - // Step 4: Verify decoding - self.verify_decoding(); - } - - /// Alternative decoding verification using the formula: - /// message = -Q^{-1} * (t * u_global)_Q mod t - fn verify_decoding(self) { - let t: Field = self.configs.plaintext_modulus; - // Compute Q as product of all CRT moduli - let mut q_modulus = 1; - for l in 0..L { - q_modulus *= self.configs.qis[l]; - } - - // For centered arithmetic - let q_half = q_modulus as u128 / 2; - - for coeff_idx in 0..MAX_MSG_NON_ZERO_COEFFS { - // Compute (t * u_global) mod Q using BigNum - let q_mod = ModU128::new(q_modulus); - let t_mod = ModU128::new(t); - - // Compute (t * u_global) mod Q using modular arithmetic functions - let t_times_u_mod_q = q_mod.mul_mod(t, self.u_global.coefficients[coeff_idx]); - let needs_centering = (t_times_u_mod_q as u128) > q_half; - - let computed_message = if needs_centering { - // When (t*u) mod Q >= Q/2: treat as negative in centered form - // Centered value is conceptually negative: (t_times_u_mod_q - Q) - // -Q^{-1} * (negative) = positive result - let centered_positive = q_modulus - t_times_u_mod_q; - let centered_positive_mod_t = t_mod.reduce_mod(centered_positive); - - t_mod.mul_mod(self.configs.q_inverse_mod_t, centered_positive_mod_t) - } else { - // When (t*u) mod Q < Q/2: stays positive in centered form - // -Q^{-1} * (positive) = negative result = t - result - let t_times_u_mod_t = t_mod.reduce_mod(t_times_u_mod_q); - let product = t_mod.mul_mod(self.configs.q_inverse_mod_t, t_times_u_mod_t); - if product == 0 { - 0 - } else { - t - product - } - }; - - // Verify: only check non-zero coefficients - if self.message.coefficients[coeff_idx] != 0 { - assert(computed_message == self.message.coefficients[coeff_idx]); - } - } - } -} - /// Computes all Lagrange coefficients using optimized modular arithmetic pub fn compute_all_lagrange_coeffs( qis: [Field; L], diff --git a/crates/events/src/enclave_event/proof.rs b/crates/events/src/enclave_event/proof.rs index b0052643f8..eb48acc2a7 100644 --- a/crates/events/src/enclave_event/proof.rs +++ b/crates/events/src/enclave_event/proof.rs @@ -93,10 +93,8 @@ pub enum CircuitName { PkAggregation, /// Decryption share proof (C6). ThresholdShareDecryption, - /// Decrypted shares aggregation proof — BigNum variant (C7a). - DecryptedSharesAggregationBn, - /// Decrypted shares aggregation proof — Modular variant (C7b). - DecryptedSharesAggregationMod, + /// Decrypted shares aggregation proof (C7). + DecryptedSharesAggregation, /// Recursive aggregation fold circuit (independent; lives at recursive_aggregation/fold). Fold, } @@ -112,8 +110,7 @@ impl CircuitName { CircuitName::DkgShareDecryption => "share_decryption", CircuitName::PkAggregation => "pk_aggregation", CircuitName::ThresholdShareDecryption => "share_decryption", - CircuitName::DecryptedSharesAggregationBn => "decrypted_shares_aggregation_bn", - CircuitName::DecryptedSharesAggregationMod => "decrypted_shares_aggregation_mod", + CircuitName::DecryptedSharesAggregation => "decrypted_shares_aggregation", CircuitName::Fold => "fold", } } @@ -128,8 +125,7 @@ impl CircuitName { CircuitName::PkGeneration => "threshold", CircuitName::ThresholdShareDecryption => "threshold", CircuitName::PkAggregation => "threshold", - CircuitName::DecryptedSharesAggregationBn => "threshold", - CircuitName::DecryptedSharesAggregationMod => "threshold", + CircuitName::DecryptedSharesAggregation => "threshold", CircuitName::Fold => "recursive_aggregation", } } diff --git a/crates/events/src/enclave_event/signed_proof.rs b/crates/events/src/enclave_event/signed_proof.rs index af8a4c70df..fd7bcbe90d 100644 --- a/crates/events/src/enclave_event/signed_proof.rs +++ b/crates/events/src/enclave_event/signed_proof.rs @@ -61,15 +61,14 @@ impl ProofType { ProofType::C3bESmShareEncryption => vec![CircuitName::ShareEncryption], ProofType::C4DkgShareDecryption => vec![CircuitName::DkgShareDecryption], ProofType::C6ThresholdShareDecryption => vec![CircuitName::ThresholdShareDecryption], - ProofType::C7DecryptedSharesAggregation => vec![ - CircuitName::DecryptedSharesAggregationBn, - CircuitName::DecryptedSharesAggregationMod, - ], + ProofType::C7DecryptedSharesAggregation => { + vec![CircuitName::DecryptedSharesAggregation] + } ProofType::C5PkAggregation => vec![CircuitName::PkAggregation], } } - /// Slash reason identifier for on-chain policies. + /// Slash reason identifier for on-chain policies pub fn slash_reason(&self) -> &'static str { match self { ProofType::C0PkBfv @@ -401,10 +400,7 @@ mod tests { ); assert_eq!( ProofType::C7DecryptedSharesAggregation.circuit_names(), - vec![ - CircuitName::DecryptedSharesAggregationBn, - CircuitName::DecryptedSharesAggregationMod, - ] + vec![CircuitName::DecryptedSharesAggregation] ); } } diff --git a/crates/tests/tests/integration.rs b/crates/tests/tests/integration.rs index 9108c7dc92..6afcd83207 100644 --- a/crates/tests/tests/integration.rs +++ b/crates/tests/tests/integration.rs @@ -198,11 +198,11 @@ async fn setup_test_zk_backend() -> (ZkBackend, tempfile::TempDir) { ".vk_noir_hash", ) .await; - // C7 (decrypted_shares_aggregation_mod) + // C7 (decrypted_shares_aggregation) copy_circuit( &threshold_target, - &rv.join("threshold/decrypted_shares_aggregation_mod"), - "decrypted_shares_aggregation_mod", + &rv.join("threshold/decrypted_shares_aggregation"), + "decrypted_shares_aggregation", ".vk_noir", ".vk_noir_hash", ) @@ -330,11 +330,11 @@ async fn setup_test_zk_backend() -> (ZkBackend, tempfile::TempDir) { ".vk_hash", ) .await; - // C7 (decrypted_shares_aggregation_mod) — EVM-targeted + // C7 (decrypted_shares_aggregation) — EVM-targeted copy_circuit( &threshold_target, - &ev.join("threshold/decrypted_shares_aggregation_mod"), - "decrypted_shares_aggregation_mod", + &ev.join("threshold/decrypted_shares_aggregation"), + "decrypted_shares_aggregation", ".vk", ".vk_hash", ) diff --git a/crates/zk-prover/src/circuits/threshold/decrypted_shares_aggregation.rs b/crates/zk-prover/src/circuits/threshold/decrypted_shares_aggregation.rs index 42d49f41b7..202499dd88 100644 --- a/crates/zk-prover/src/circuits/threshold/decrypted_shares_aggregation.rs +++ b/crates/zk-prover/src/circuits/threshold/decrypted_shares_aggregation.rs @@ -18,22 +18,10 @@ impl Provable for DecryptedSharesAggregationCircuit { type Inputs = Inputs; fn circuit(&self) -> CircuitName { - CircuitName::DecryptedSharesAggregationMod - } - - fn resolve_circuit_name(&self, params: &Self::Params, _input: &Self::Input) -> CircuitName { - match params { - BfvPreset::SecureThreshold8192 | BfvPreset::SecureDkg8192 => { - CircuitName::DecryptedSharesAggregationBn - } - _ => CircuitName::DecryptedSharesAggregationMod, - } + CircuitName::DecryptedSharesAggregation } fn valid_circuits(&self) -> Vec { - vec![ - CircuitName::DecryptedSharesAggregationBn, - CircuitName::DecryptedSharesAggregationMod, - ] + vec![CircuitName::DecryptedSharesAggregation] } } diff --git a/crates/zk-prover/tests/local_e2e_tests.rs b/crates/zk-prover/tests/local_e2e_tests.rs index 641140aed9..27d032148b 100644 --- a/crates/zk-prover/tests/local_e2e_tests.rs +++ b/crates/zk-prover/tests/local_e2e_tests.rs @@ -291,7 +291,7 @@ async fn setup_decrypted_shares_aggregation_test() -> Option<( let bb = find_bb().await?; let (backend, temp) = setup_test_prover(&bb).await; - setup_compiled_circuit(&backend, "threshold", "decrypted_shares_aggregation_mod").await; + setup_compiled_circuit(&backend, "threshold", "decrypted_shares_aggregation").await; let sample = DecryptedSharesAggregationCircuitData::generate_sample(preset, committee).ok()?; let prover = ZkProver::new(&backend); diff --git a/docs/pages/ciphernode-operators/index.mdx b/docs/pages/ciphernode-operators/index.mdx index 6907157c60..47113e127e 100644 --- a/docs/pages/ciphernode-operators/index.mdx +++ b/docs/pages/ciphernode-operators/index.mdx @@ -50,14 +50,15 @@ The Interfold protocol uses several contracts that work together: | EnclaveToken (ENCL) | `0x24b28471AE7BdF1fdBcfDd183c73D13ff0689B99` | 10395612 | | MockUSDC (fee token) | `0x01AbD7D8e6547c943c2fE082C3Ce194fDCe57396` | 10395611 | -Circuit verifiers (C5, C7 BN/Mod, Fold) are deployed with the main flow. See `deployed_contracts.json` for addresses. - -| Verifier | Address | -| -------------------------------------------------------- | -------------------------------------------- | -| ThresholdPkAggregationVerifier (C5) | See `deployed_contracts.json` after deploy | -| ThresholdDecryptedSharesAggregationBnVerifier (C7 BN) | See `deployed_contracts.json` after deploy | -| ThresholdDecryptedSharesAggregationModVerifier (C7 Mod) | See `deployed_contracts.json` after deploy | -| RecursiveAggregationFoldVerifier (Fold) | See `deployed_contracts.json` after deploy | +Circuit verifiers (C5, C7, Fold) are deployed with the main flow. The DecryptedSharesAggregation +circuit (C7) is deployed as a single ThresholdDecryptedSharesAggregationVerifier. See +`deployed_contracts.json` for addresses. + +| Verifier | Address | +| ------------------------------------------------ | ------------------------------------------ | +| ThresholdPkAggregationVerifier (C5) | See `deployed_contracts.json` after deploy | +| ThresholdDecryptedSharesAggregationVerifier (C7) | See `deployed_contracts.json` after deploy | +| RecursiveAggregationFoldVerifier (Fold) | See `deployed_contracts.json` after deploy | > Always verify addresses from `packages/enclave-contracts/deployed_contracts.json` or your > deployment output. Addresses differ per network. diff --git a/docs/pages/noir-circuits.mdx b/docs/pages/noir-circuits.mdx index 8268f38bbb..debf9381c0 100644 --- a/docs/pages/noir-circuits.mdx +++ b/docs/pages/noir-circuits.mdx @@ -29,7 +29,7 @@ circuits/ │ │ # share_encryption, share_decryption) │ ├── threshold/ # threshold sub-circuits (pk_generation, pk_aggregation, │ │ # share_decryption, user_data_encryption_ct0/ct1, -│ │ # decrypted_shares_aggregation_bn, decrypted_shares_aggregation_mod) +│ │ # decrypted_shares_aggregation) │ ├── insecure/ # legacy insecure-parameter circuits for development │ ├── production/ # production-parameter circuits (placeholder) │ └── recursive_aggregation/ # recursive proof aggregation diff --git a/package.json b/package.json index 3851ab9776..42a1b061dc 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "scripts": { "bump:versions": "tsx scripts/bump-versions.ts", "build:circuits": "tsx scripts/build-circuits.ts", - "generate:verifiers": "tsx scripts/generate-verifiers.ts --circuits pk_aggregation,decrypted_shares_aggregation_bn,decrypted_shares_aggregation_mod,fold", + "generate:verifiers": "tsx scripts/generate-verifiers.ts --circuits pk_aggregation,decrypted_shares_aggregation,fold", "store:circuits": "tsx scripts/circuit-artifacts.ts", "clean": "tsx scripts/clean.ts", "compile": "pnpm build:ts && pnpm rust:build", diff --git a/packages/enclave-contracts/.gitignore b/packages/enclave-contracts/.gitignore index 16125844fb..54675c7cfe 100644 --- a/packages/enclave-contracts/.gitignore +++ b/packages/enclave-contracts/.gitignore @@ -41,12 +41,9 @@ !/artifacts/contracts/verifier/ThresholdPkAggregationVerifier.sol/ !/artifacts/contracts/verifier/ThresholdPkAggregationVerifier.sol/ThresholdPkAggregationVerifier.json !/artifacts/contracts/verifier/ThresholdPkAggregationVerifier.sol/ZKTranscriptLib.json -!/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol/ -!/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol/ThresholdDecryptedSharesAggregationBnVerifier.json -!/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol/ZKTranscriptLib.json -!/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol/ -!/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol/ThresholdDecryptedSharesAggregationModVerifier.json -!/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol/ZKTranscriptLib.json +!/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol/ +!/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol/ThresholdDecryptedSharesAggregationVerifier.json +!/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol/ZKTranscriptLib.json !/artifacts/contracts/verifier/RecursiveAggregationFoldVerifier.sol/ !/artifacts/contracts/verifier/RecursiveAggregationFoldVerifier.sol/RecursiveAggregationFoldVerifier.json !/artifacts/contracts/verifier/RecursiveAggregationFoldVerifier.sol/ZKTranscriptLib.json diff --git a/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol/ThresholdDecryptedSharesAggregationBnVerifier.json b/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol/ThresholdDecryptedSharesAggregationBnVerifier.json deleted file mode 100644 index d98f07bf79..0000000000 --- a/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol/ThresholdDecryptedSharesAggregationBnVerifier.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "_format": "hh3-artifact-1", - "contractName": "ThresholdDecryptedSharesAggregationBnVerifier", - "sourceName": "contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol", - "abi": [ - { - "inputs": [], - "name": "ConsistencyCheckFailed", - "type": "error" - }, - { - "inputs": [], - "name": "GeminiChallengeInSubgroup", - "type": "error" - }, - { - "inputs": [], - "name": "ProofLengthWrong", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "logN", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "actualLength", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expectedLength", - "type": "uint256" - } - ], - "name": "ProofLengthWrongWithLogN", - "type": "error" - }, - { - "inputs": [], - "name": "PublicInputsLengthWrong", - "type": "error" - }, - { - "inputs": [], - "name": "ShpleminiFailed", - "type": "error" - }, - { - "inputs": [], - "name": "SumcheckFailed", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "proof", - "type": "bytes" - }, - { - "internalType": "bytes32[]", - "name": "publicInputs", - "type": "bytes32[]" - } - ], - "name": "verify", - "outputs": [ - { - "internalType": "bool", - "name": "verified", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - } - ], - "bytecode": "0x610120604052348015610010575f5ffd5b50620200006080819052601160a08190527f1eb29cc0a26390fad32af3a6275716d347fdcbdcc5f7c7c54c194a0cce5854e060c081905261024360e081905260038361005e6001602461008b565b610068919061008b565b610072919061008b565b61007d90600261008b565b61010052506100b092505050565b808201808211156100aa57634e487b7160e01b5f52601160045260245ffd5b92915050565b60805160a05160c05160e05161010051615cbb61014a5f395f8181610c5401528181610cb90152612ec301525f81816101b001526108ff01525f61018e01525f8181605b01528181609401528181610101015281816101d201528181610a2d01528181610b8e01528181610c2b01528181611523015281816115dd015281816116100152818161181a0152612ba001525f5050615cbb5ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063ea50d0e41461002d575b5f5ffd5b61004061003b3660046154f2565b610054565b604051901515815260200160405180910390f35b5f5f61007f7f00000000000000000000000000000000000000000000000000000000000000006102ee565b905061008c8160206155ca565b85146100ee577f0000000000000000000000000000000000000000000000000000000000000000856100bf8360206155ca565b6040516359895a5360e01b81526004810193909352602483019190915260448201526064015b60405180910390fd5b5f6100f76103fb565b90505f61012588887f0000000000000000000000000000000000000000000000000000000000000000610410565b90506010826040015161013891906155e1565b85146101575760405163fa06659360e01b815260040160405180910390fd5b60405163995bf45760e01b81525f9073__$766c1d4ff1635319bed72d911807c12b70$__9063995bf457906101fa9085908b908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090600401615764565b610be060405180830381865af4158015610216573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061023a9190615a90565b905061028a8787808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050855185516060810151608090910151919350915060016108a9565b815160a0015261029a8282610a10565b6102b7576040516313f8744360e31b815260040160405180910390fd5b6102c2828483610c17565b6102df576040516352ec174560e11b815260040160405180910390fd5b50600198975050505050505050565b5f8060026102fe60016008615b3a565b61030891906155ca565b9050610316600260036155ca565b6103209082615b3a565b9050600161032f6009856155ca565b61033991906155ca565b6103439082615b3a565b90506001610352816029615b3a565b61035c91906155ca565b6103669082615b3a565b9050610374600160026155ca565b61037e9082615b3a565b905061038b6001846155ca565b6103959082615b3a565b90506103a3600160046155ca565b6103ad9082615b3a565b905060026103bc6001856155e1565b6103c691906155ca565b6103d09082615b3a565b90506103dd6002806155ca565b6103e79082615b3a565b90506103f4601082615b3a565b9392505050565b610403615025565b61040b611c14565b905090565b6104186151af565b5f805b601081101561047a57610447868387610435602083615b3a565b9261044293929190615b4d565b61254f565b8351826010811061045a5761045a615b74565b6020020181815250506020826104709190615b3a565b915060010161041b565b5061049e85828661048c604083615b3a565b9261049993929190615b4d565b612562565b60208301526104ae604082615b3a565b90506104c185828661048c604083615b3a565b6040808401919091526104d49082615b3a565b90506104e785828661048c604083615b3a565b60608301526104f7604082615b3a565b905061050a85828661048c604083615b3a565b608083015261051a604082615b3a565b905061052d85828661048c604083615b3a565b60c083015261053d604082615b3a565b905061055085828661048c604083615b3a565b60e0830152610560604082615b3a565b905061057385828661048c604083615b3a565b60a0830152610583604082615b3a565b905061059685828661048c604083615b3a565b6101008301526105a7604082615b3a565b90506105ba85828661048c604083615b3a565b6101208301526105cb604082615b3a565b90506105de85828661048c604083615b3a565b610140830151526105f0604082615b3a565b9050610603858286610435602083615b3a565b610160830152610614602082615b3a565b90505f5b83811015610692575f5b60098110156106895761063c878488610435602083615b3a565b84610180015183601c811061065357610653615b74565b6020020151826009811061066957610669615b74565b60200201818152505060208361067f9190615b3a565b9250600101610622565b50600101610618565b505f5b6106a160016029615b3a565b8110156106f0576106b9868387610435602083615b3a565b836101c0015182602a81106106d0576106d0615b74565b6020020181815250506020826106e69190615b3a565b9150600101610695565b50610702858286610435602083615b3a565b6101a0830152610713602082615b3a565b905061072685828661048c604083615b3a565b6101408301516020015261073b604082615b3a565b905061074e85828661048c604083615b3a565b61014083015160026020020152610766604082615b3a565b90505f5b6107756001856155e1565b8110156107be5761078d86838761048c604083615b3a565b836101e0015182601b81106107a4576107a4615b74565b60200201526107b4604083615b3a565b915060010161076a565b505f5b83811015610811576107da868387610435602083615b3a565b83610200015182601c81106107f1576107f1615b74565b6020020181815250506020826108079190615b3a565b91506001016107c1565b505f5b60048110156108655761082e868387610435602083615b3a565b836102200151826004811061084557610845615b74565b60200201818152505060208261085b9190615b3a565b9150600101610814565b5061087785828661048c604083615b3a565b610240830152610888604082615b3a565b905061089b85828661048c604083615b3a565b610260830152509392505050565b5f600180826108d6866108d1896108cc6108c78a6310000000615b3a565b6125e4565b6125fc565b612617565b90505f6108f4876108ef8a6108cc6108c78b6001615b3a565b612630565b90505f5b61092360107f00000000000000000000000000000000000000000000000000000000000000006155e1565b811015610990575f61094d8c838151811061094057610940615b74565b6020026020010151612658565b905061095d866108cc8684612617565b955061096d856108cc8584612617565b9450610979848b612617565b9350610985838b612630565b9250506001016108f8565b505f5b60108110156109f7575f8a82601081106109af576109af615b74565b602002015190506109c4866108cc8684612617565b95506109d4856108cc8584612617565b94506109e0848b612617565b93506109ec838b612630565b925050600101610993565b50610a02848461266d565b9a9950505050505050505050565b5f5f610a2583606001518561016001516125fc565b905060015f5b7f0000000000000000000000000000000000000000000000000000000000000000811015610b17575f86610180015182601c8110610a6b57610a6b615b74565b602002015180519091505f90610a89908360015b6020020151612617565b9050848114610aab576040516313f8744360e31b815260040160405180910390fd5b5f876080015184601c8110610ac257610ac2615b74565b60200201519050610ad3838261267b565b9550610b07856108cc60016108d1856108cc8e604001518b601c8110610afb57610afb615b74565b60200201516001612630565b9450505050806001019050610a2b565b50610b20615292565b5f5b6029811015610b70576101c0870151610b3c600183615b3a565b602a8110610b4c57610b4c615b74565b6020020151828260298110610b6357610b63615b74565b6020020152600101610b22565b505f610b8582875f0151886020015186612829565b9050600160025b7f0000000000000000000000000000000000000000000000000000000000000000811015610be257610bd882896080015183601c8110610bce57610bce615b74565b60200201516125fc565b9150600101610b8c565b50610c08610bf5836108cc600185612630565b6108d18a6101a001518a606001516125fc565b94909414979650505050505050565b5f610c206152b1565b5f610c4f8460c001517f00000000000000000000000000000000000000000000000000000000000000006128a2565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610c8a57610c8a615941565b604051908082528060200260200182016040528015610cb3578160200160208202803683370190505b5090505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610cef57610cef615941565b604051908082528060200260200182016040528015610d2857816020015b610d15615321565b815260200190600190039081610d0d5790505b509050610d5b610d56876101000151855f81518110610d4957610d49615b74565b6020026020010151612630565b61296b565b84610120018181525050610d90610d56876101000151855f81518110610d8357610d83615b74565b6020026020010151612617565b610140850181905261012085015160e0880151610db1926108d191906125fc565b845260c0860151610de190610dc59061296b565b6108cc8661012001516108ef8a60e001518961014001516125fc565b6020850152815160019083905f90610dfb57610dfb615b74565b602002602001018181525050876102400151815f81518110610e1f57610e1f615b74565b6020908102919091010152600160a08501525f60c08501528351610e42906129db565b60408501526020840151610e55906129db565b606085015260015b610e6960016024615b3a565b8111610f0a57610e8185604001518660a001516125fc565b838281518110610e9357610e93615b74565b602002602001018181525050610edc8560c001516108d18b6101c00151600185610ebd91906155e1565b602a8110610ecd57610ecd615b74565b60200201518860a001516125fc565b60c086015260a08086015190880151610ef591906125fc565b60a0860152610f0381615b88565b9050610e5d565b505f5b6005811015610fe3575f610f22601e83615b3a565b90505f610f3160016024615b3a565b610f3b9084615b3a565b9050610f6c858381518110610f5257610f52615b74565b60200260200101516108d189606001518a60a001516125fc565b858381518110610f7e57610f7e615b74565b602002602001018181525050610fbb8760c001516108d18d6101c0015184602a8110610fac57610fac615b74565b60200201518a60a001516125fc565b60c088015260a080880151908a0151610fd491906125fc565b60a08801525050600101610f0d565b50876020015181600181518110610ffc57610ffc615b74565b602002602001018190525086606001518160028151811061101f5761101f615b74565b602002602001018190525086608001518160038151811061104257611042615b74565b60200260200101819052508660a001518160048151811061106557611065615b74565b60200260200101819052508660c001518160058151811061108857611088615b74565b60200260200101819052508660e00151816006815181106110ab576110ab615b74565b6020026020010181905250866101000151816007815181106110cf576110cf615b74565b6020026020010181905250866101200151816008815181106110f3576110f3615b74565b60200260200101819052508661014001518160098151811061111757611117615b74565b602002602001018190525086610160015181600a8151811061113b5761113b615b74565b6020026020010181905250866101c0015181600b8151811061115f5761115f615b74565b602002602001018190525086610180015181600c8151811061118357611183615b74565b6020026020010181905250866101a0015181600d815181106111a7576111a7615b74565b6020026020010181905250866101e0015181600e815181106111cb576111cb615b74565b602002602001018190525086610200015181600f815181106111ef576111ef615b74565b60200260200101819052508661022001518160108151811061121357611213615b74565b60200260200101819052508661024001518160118151811061123757611237615b74565b60200260200101819052508661026001518160128151811061125b5761125b615b74565b60200260200101819052508661028001518160138151811061127f5761127f615b74565b6020026020010181905250866102a00151816014815181106112a3576112a3615b74565b6020026020010181905250866102c00151816015815181106112c7576112c7615b74565b6020026020010181905250866102e00151816016815181106112eb576112eb615b74565b60200260200101819052508661030001518160178151811061130f5761130f615b74565b60200260200101819052508661032001518160188151811061133357611333615b74565b60200260200101819052508661034001518160198151811061135757611357615b74565b602002602001018190525086610360015181601a8151811061137b5761137b615b74565b602002602001018190525086610380015181601b8151811061139f5761139f615b74565b6020026020010181905250866103a0015181601c815181106113c3576113c3615b74565b6020026020010181905250866103c0015181601d815181106113e7576113e7615b74565b6020026020010181905250876040015181601e8151811061140a5761140a615b74565b6020026020010181905250876060015181601f8151811061142d5761142d615b74565b602002602001018190525087608001518160208151811061145057611450615b74565b60200260200101819052508760a001518160218151811061147357611473615b74565b60200260200101819052508761012001518160228151811061149757611497615b74565b6020026020010181905250876101000151816023815181106114bb576114bb615b74565b60200260200101819052508760c00151816024815181106114de576114de615b74565b60200260200101819052508760e001518160258151811061150157611501615b74565b60200260200101819052505f61154787608001518660c001518b6102000151877f00000000000000000000000000000000000000000000000000000000000000006129ed565b9050611571815f8151811061155e5761155e615b74565b60200260200101518661012001516125fc565b608086018190526102008a01515160e08901516115a292916108d19161159791906125fc565b8861014001516125fc565b608086015260e08701516115b590612b4b565b60a08601525f6115c760016024615b3a565b6115d2906001615b3a565b90505f5b61160160017f00000000000000000000000000000000000000000000000000000000000000006155e1565b811015611812575f61163460017f00000000000000000000000000000000000000000000000000000000000000006155e1565b8210159050806117a357611668610d568b6101000151898560016116589190615b3a565b81518110610d4957610d49615b74565b6101208901526101008a015161169890610d569089611688866001615b3a565b81518110610d8357610d83615b74565b61014089015260a08801516101208901516116b391906125fc565b61016089015260a088015160e08b01516116db916116d0916125fc565b8961014001516125fc565b61018089018190526116fe906116f0906129db565b6108d18a61016001516129db565b866117098486615b3a565b8151811061171957611719615b74565b6020026020010181815250505f6117528961018001518e61020001518560016117429190615b3a565b601c8110610bce57610bce615b74565b905061178c816108d18b61016001518887600161176f9190615b3a565b8151811061177f5761177f615b74565b60200260200101516125fc565b905061179c896080015182612617565b60808a0152505b6117c26117b88960a001518c60e001516125fc565b8b60e001516125fc565b60a08901526101e08c015182601b81106117de576117de615b74565b6020020151856117ee8486615b3a565b815181106117fe576117fe615b74565b6020908102919091010152506001016115d6565b5061183e60017f00000000000000000000000000000000000000000000000000000000000000006155e1565b6118489082615b3a565b90506118686118608961010001518a60c00151612630565b60019061266d565b60e08701515261010088015160c08901516118ac91611860916108ef907f07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76906125fc565b60e0878101805160200192909252815180516040909101529051805160609091015260a0870151908901516118ee916118e4916125fc565b8960e001516125fc565b60a08701525f5b600481101561199c575f6119278860e00151836004811061191857611918615b74565b60200201518960a001516125fc565b9050611932816129db565b886101000151836004811061194957611949615b74565b602002015260a088015160e08b015161196291906125fc565b8860a001818152505061198e88608001516108d1838f61022001518660048110610bce57610bce615b74565b6080890152506001016118f5565b506101008601515184518590839081106119b8576119b8615b74565b602090810291909101810191909152610100870151908101516119dc916002610a7f565b846119e8836001615b3a565b815181106119f8576119f8615b74565b60209081029190910101526101008601516060015184611a19836002615b3a565b81518110611a2957611a29615b74565b60209081029190910101525f5b6003811015611a8b578a61014001518160038110611a5657611a56615b74565b60200201518483611a6681615b88565b945081518110611a7857611a78615b74565b6020908102919091010152600101611a36565b506040518060400160405280600181526020016002815250838281518110611ab557611ab5615b74565b60200260200101819052508560800151848280611ad190615b88565b935081518110611ae357611ae3615b74565b602002602001018181525050611b0d8a61022001518960c001518a608001518d6101a00151612b56565b611b2a5760405163a2a2ac8360e01b815260040160405180910390fd5b5f8a6102600151905080848381518110611b4657611b46615b74565b6020026020010181905250886101000151858381518110611b6957611b69615b74565b602002602001018181525050611b7d615339565b611b878587612eb9565b8152611b9282612fb1565b602082018190528c5182515f92611baa929190612ff7565b90505f5f611bba8f5f0151613088565b91509150611bc782613149565b611bd081613149565b8351611bdd9083856131e8565b84526020840151611bef9082856131e8565b602085018190528451611c0191613217565b9f9e505050505050505050505050505050565b611c1c615025565b50604080516103e081018252620200008152601160208083019190915261024382840152825180840184527f039702f4c2b2b49fd29d82b077cbf9d1df2871e0fbade17241573ca5021603fc81527f03270b3b2673844695842df11cdbabf54acafe03642adfdfbf69834247ed0720818301526060830152825180840184527f1ccb0308d0359b8835480fa7dd829fdbf16b136d57e85c1621efb1679fe1a94c81527f207076fed3c60bbeb2df5f48c86b12f4027c523f9b8e69456ca51643fea3de1d818301526080830152825180840184527f067b40a80be55b95cc17070cf5dc78441e4868acea0ac1e46b5708705151590581527f0792e6c3d76aeeed6ee7d7e443138c813b74dbcd8ce92990e6f6747adc0af0548183015260a0830152825180840184527f148a04387a9e0a8cec6a4a0d90706f5907e8bb257fb04f8a3cfe07c18a7c101481527f225866d9efd4a5be4eb9a00016f902f844e3d81e2768b24dc92ecbd6b34176bd8183015260c0830152825180840184527f0dacf57ed82c686ca051fca3f1820016cb49e91b5d3c4bee7f9fa19800d9ed0681527f22ba5fda41aa14aeb7a3a2731fbfe3a673cf7db1d2217d32db491f44344309058183015260e0830152825180840184527f0f783f69a36c2bac47b9c59ff33ccc583a284a46b282591b9e9bbb85d8b5e5dc81527f029b91609a06e94924f0d83530fc01f3427f5ab729a0959903108c2ccc86825c81830152610100830152825180840184527f11beb2731ab8cf46c0a52666bb457fa74d4b635043bb5689a35a2aee24990b8081527f2f1fba989036c44aedb609d0d3341ccb842c2d1cd7c80cea4a95d0eb4530577081830152610120830152825180840184527f28ae1f7459c3c5d9ca2f80f8e5c28bb301d0245228bade0e2bb962b4bfbe301b81527f0622f7db14381bbecf862e186cfa570588160466ae7d4fed4b35a70d99af914f81830152610140830152825180840184527f233983f621ab48bdce4f7216bdbc54c49463e90d88301b9ab224fca61c93dba081527f265c3834d63be0bc710c9b4a48015e2442a3b9bf63caec9db0064dfb1bd569c481830152610160830152825180840184527f06d21b82f49e04e078d4ad30cd6828eaa66c1bf984bc52b79de8c786fe4dfe7a81527f301aa91e167bbc765996ac6d2889e7d49f0734bc7abb3a4b85900143556a1b3f81830152610180830152825180840184527f1222d34f53e6b36138627277789ad131ea24f79caca2d5f59193c5e3a7dfdde781527f245a380726977d41c9f0a9a0ba33608994eb3660de6a8efba38009df93da679a818301526101a0830152825180840184527f2dfc248e28ad889b5b692077f338d28b2f687c6e909b9693f8e8fd25cefc352881527f16e2cbc305166ea90a426987efff2020827d8c548ea4155c659df296f14f00fd818301526101c0830152825180840184527f0d815a04effc6e57ec95f3ac112f76ab4a9d993d044626ceb54f967c8d77d8e181527f1df4c065a1129d5cbdf244cb9cc2eaf406c2f5fbab4c393347d57ae5e2ab881f818301526101e0830152825180840184527f118733dc1db84685f4160119cb0cd9a51b831cf0643e914daf1c63fc7967297981527f27b63107b52edf239acb1bd47e24c97094422cc2bba51ee0f54b2707946be55681830152610200830152825180840184527f2e7a11cec89df0ad6b730cf80be4246e56e1667f55e35a22c9b39b196226135b81527f0891267297e339bedeef69881477b4e5c19e761e127e3d3772714f92ade80fd381830152610220830152825180840184527f16f90d7d5c3fd7ab9f490dd5d2b94afea698039e2456c1d5f0e22159348d1e0c81527f29ad721b49b02192f5323326fd803b102f7a09b0371c537db998014fa14c307981830152610240830152825180840184527f0a5e4e29375b31024f09dd662b460eb25930835255c62dc74d62d0c983981e4281527f069adf56537452ecad2fcd8cdea1291fbf273d7e752d9ba0812900e7215c8fc081830152610260830152825180840184527f1bd554f207de2e42cbc94e8579154a07e37f3ba9d80832f28e38dffaaccd1ade81527f22261d045539dbaabf26f23773b365b2ddd30af639a8b15a56e777f5607bf43581830152610280830152825180840184527f11769064ef79db1f35b23b8b1e5c118e769e1a41b912f49dfdbffbacf23d056481527f16f17c1721186bbd19d09f1645f968677cb1ad0c6b656c3849a4b7f27d5279d9818301526102a0830152825180840184527f0cad91097e151471556985b94a0188b759472f9bb3295fe6de6846f2d4fe27e181527f042f4a199546b40704a9c4822bfd20a91bc478055dc5676c7347f64545b47f4d818301526102c0830152825180840184527f1286a8beb1993863980820c27dfb00f93f8949f60933042e5aa8275dd48e55f781527f2037878d67d1009eb6dac43c5f6f076f884d456e057b000912d40a2ec440df1f818301526102e0830152825180840184527f1c0413fa3552ba4738b423829d55fcc03c912bf931336778a458e1c25cd4f55881527f190904e6db04c862bd9d7406029e03a1103a513203eb6d8faa010021eedf18d481830152610300830152825180840184527f099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d2681527e15b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f81830152610320830152825180840184527f1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e81527f305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d1981830152610340830152825180840184527f061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d81527f1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e81830152610360830152825180840184527f043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce81527f261522c4089330646aff96736194949330952ae74c573d1686d9cb4a007338548183015261038083015282518084018452600181526002818301526103a083015282518084019093527f0ad44c49c91e4374983e023f10e6256c39d27b2857eb2d2ce82a82b51e02dc3883527f23ad26f46d7b04b00d6ebe50273765d49c59d9db9ae22dd33909bc3c9efc5308908301526103c081019190915290565b5f6103f461255d8385615ba0565b612658565b61256a615321565b60408051808201909152805f516020615c6f5f395f51905f5261259060205f8789615b4d565b61259991615ba0565b6125a39190615bbd565b81526020908101905f516020615c6f5f395f51905f52906125c8906040908789615b4d565b6125d191615ba0565b6125db9190615bbd565b90529392505050565b5f5f516020615c8f5f395f51905f52825b0692915050565b5f5f516020615c8f5f395f51905f5282840990505b92915050565b5f5f516020615c8f5f395f51905f528284089392505050565b5f5f516020615c8f5f395f51905f52825f516020615c8f5f395f51905f520384089392505050565b5f5f516020615c8f5f395f51905f52826125f5565b5f6103f4836108cc8461296b565b5f5f604051806101200160405280619d8081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec5181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31815260200161024081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd3181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec518152602001619d8081525090505f600190505f5f90505b60098110156127745761276a826108cc8784612630565b9150600101612753565b5061277d61534c565b5f5b60098110156127ce576127af610d568583600981106127a0576127a0615b74565b60200201516108cc8985612630565b8282600981106127c1576127c1615b74565b602002015260010161277f565b505f5b60098110156128145761280a856108d18984600981106127f3576127f3615b74565b6020020151858560098110610bce57610bce615b74565b94506001016127d1565b5061281f84836125fc565b9695505050505050565b5f61283261536b565b61283d86828561340b565b612849868683866135b7565b612855868683866137a3565b6128608682856139c8565b61286b868285613bbc565b61287786868386613f05565b6128828682856143b1565b61288d8682856147c3565b612898868285614b84565b61281f8185614e84565b60605f826001600160401b038111156128bd576128bd615941565b6040519080825280602002602001820160405280156128e6578160200160208202803683370190505b50905083815f815181106128fc576128fc615b74565b602090810291909101015260015b838110156129635761293e826129216001846155e1565b8151811061293157612931615b74565b6020026020010151612b4b565b82828151811061295057612950615b74565b602090810291909101015260010161290a565b509392505050565b5f5f8290505f604051602081526020808201526020604082015282606082015260025f516020615c8f5f395f51905f520360808201525f516020615c8f5f395f51905f5260a082015260205f60c08360055afa806129c7575f5ffd5b505f51608091909101604052949350505050565b5f516020615c8f5f395f51905f520390565b60605f826001600160401b03811115612a0857612a08615941565b604051908082528060200260200182016040528015612a31578160200160208202803683370190505b509050825b8015612b40575f85612a496001846155e1565b81518110612a5957612a59615b74565b602002602001015190505f89600184612a7291906155e1565b601c8110612a8257612a82615b74565b602002015190505f612add612aa1612a9a858d6125fc565b60026125fc565b6108ef8b612ab06001896155e1565b601c8110612ac057612ac0615b74565b60200201516108cc612ad7886108cc60018a612630565b87612630565b9050612afe816108cc610d56612af8876108cc600189612630565b86612617565b99508990508085612b106001876155e1565b81518110612b2057612b20615b74565b60200260200101818152505050505080612b3990615bdc565b9050612a36565b509695505050505050565b5f61261182836125fc565b5f600181612b6f612b6987610100614edd565b83612630565b905080612b8f5760405163835eb8f760e01b815260040160405180910390fd5b612b9761538a565b80518390525f5b7f0000000000000000000000000000000000000000000000000000000000000000811015612c80575f612bd28260096155ca565b612bdd906001615b3a565b905084835f0151826101008110612bf657612bf6615b74565b60200201525f612c07826001615b3a565b90505b612c15600983615b3a565b811015612c76578351612c5590612c2d6001846155e1565b6101008110612c3e57612c3e615b74565b60200201518a85601c8110610bce57610bce615b74565b8451826101008110612c6957612c69615b74565b6020020152600101612c0a565b5050600101612b9e565b50608081018390525f602082018190525b610100811015612d9157612cb2612cac83608001518a6125fc565b85612630565b8260a00151826101008110612cc957612cc9615b74565b602002015260a0820151612cf390826101008110612ce957612ce9615b74565b602002015161296b565b8260a00151826101008110612d0a57612d0a615b74565b602002018181525050612d5082602001516108d1845f0151846101008110612d3457612d34615b74565b60200201518560a00151856101008110610bce57610bce615b74565b60208301526080820151612d84907f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d66125fc565b6080830152600101612c91565b505f612da2836108cc61010061296b565b9050612db28260200151826125fc565b602083015260a0820151612dcd905f5b6020020151826125fc565b604083015260a0820151612df990612de860016101006155e1565b6101008110612dc257612dc2615b74565b60608301526040820151612e0f908a6002610bce565b60c08301819052612e6f906108d1612e478b7f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6612630565b60208d015160408e01516108cc91612e5e91612630565b8e5160208901516108ef91906125fc565b60c083018190526060830151612ea491612e98916108d1906108cc8e600260200201518c612630565b6108ef858c6003610bce565b60c08301819052159998505050505050505050565b612ec1615321565b7f00000000000000000000000000000000000000000000000000000000000000005f5b81811015612f1657612f0e858281518110612f0157612f01615b74565b6020026020010151613149565b600101612ee4565b50604051600190815b60018401811015612f7b5760208102870160208202870181515160408501528151602001516060850152805160808501525050604080830160606040850160075afa8316925060408260808460065afa90921691600101612f1f565b5080518452602081015160208501525080612fa9576040516352ec174560e11b815260040160405180910390fd5b505092915050565b612fb9615321565b5f516020615c6f5f395f51905f5282602001515f516020615c6f5f395f51905f52612fe491906155e1565b612fee9190615bbd565b60208301525090565b5f5f5f61300386613088565b9150915061300f6153ce565b82518152602080840151818301528251604080840191909152838201516060840152875160808401528782015160a0840152865160c08401528682015160e08401525161307d9161306291849101615bf1565b60405160208183030381529060405280519060200120612658565b979650505050505050565b613090615321565b613098615321565b82516020808501516040860151606087015160cc90811b608892831b604494851b90961795909517949094178652608087015160a088015160c089015160e08a0151871b90841b91851b9092171717868401526101008701516101208801516101408901516101608a0151871b90841b91851b909217171785526101808701516101a08801516101c08901516101e09099015190951b9790911b9390911b1791909117939093179281019290925291565b805160208201515f5f516020615c6f5f395f51905f528380095f516020615c6f5f395f51905f5260035f516020615c6f5f395f51905f52838709085f516020615c6f5f395f51905f5284850914915050806131e25760405162461bcd60e51b8152602060048201526019602482015278706f696e74206973206e6f74206f6e2074686520637572766560381b60448201526064016100e5565b50505050565b6131f0615321565b6131f8615321565b6132028386614f3e565b905061320e8185614f94565b95945050505050565b81516020808401518351848301516040805194850195909552938301919091527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260608301527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60808301527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b60a08301527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60c083015260e08201526101008101919091527f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c16101208201527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b06101408201527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe46101608201527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101808201525f9081906101a00160405160208183030381529060405290505f5f60086001600160a01b0316836040516133ad9190615c25565b5f60405180830381855afa9150503d805f81146133e5576040519150601f19603f3d011682016040523d82523d5f602084013e6133ea565b606091505b509150915081801561281f57508080602001905181019061281f9190615c3b565b5f613417846007614ff5565b90507f183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f80000005f61347861347261344c856003612630565b6108cc61346761345c8b5f614ff5565b6108cc8c601d614ff5565b6108cc8b601c614ff5565b836125fc565b90506134f96134ee6134d56134bc6134a3856108d16134988d6002614ff5565b6108cc8e601c614ff5565b6108d16134b18c6003614ff5565b6108cc8d601d614ff5565b6108d16134ca8b6004614ff5565b6108cc8c601e614ff5565b6108d16134e38a6005614ff5565b6108cc8b601f614ff5565b6108d1886001614ff5565b9050613518816108d161350d866001612630565b6108cc8a6027614ff5565b905061352481846125fc565b905061353081856125fc565b8552505f905061356a61356061355561354a88601c614ff5565b6108d189601f614ff5565b6108ef886024614ff5565b6108d1875f614ff5565b905061357b816108cc846002612630565b905061358c816108cc846001612630565b905061359881836125fc565b90506135a481846125fc565b9050808460015b60200201525050505050565b5f5f5f6135ed6135e36135cb89601c614ff5565b6108d16135d98b6012614ff5565b8a606001516125fc565b8760800151612617565b9050613626816108cc61361c6136048b601d614ff5565b6108d16136128d6013614ff5565b8c606001516125fc565b8960800151612617565b905061364b816108cc61361c61363d8b601e614ff5565b6108d16136128d6014614ff5565b9050613670816108cc61361c6136628b601f614ff5565b6108d16136128d6015614ff5565b92505f90506136946135e361368689601c614ff5565b6108d16135d98b600e614ff5565b90506136b9816108cc61361c6136ab8b601d614ff5565b6108d16136128d600f614ff5565b90506136de816108cc61361c6136d08b601e614ff5565b6108d16136128d6010614ff5565b9050613703816108cc61361c6136f58b601f614ff5565b6108d16136128d6011614ff5565b91505f905061372a613724613719896020614ff5565b6108d18a601a614ff5565b846125fc565b905061375f816108ef6137596137418b6028614ff5565b6108d161374f8d601b614ff5565b8c60a001516125fc565b856125fc565b905061376b81856125fc565b6040860152505f61378e61375961378389601b614ff5565b6108cc8a6028614ff5565b9050808560035b602002015250505050505050565b5f5f6138016137e96137d16137bc61361c8a6016614ff5565b6108d16137ca8b6017614ff5565b8a516125fc565b6108d16137df8a6018614ff5565b89602001516125fc565b6108d16137f7896019614ff5565b88604001516125fc565b91505f61383861381f61381589601c614ff5565b8860800151612617565b6108d161382d8a6003614ff5565b6108cc8b6024614ff5565b90505f61386161384989601d614ff5565b6108d16138568b5f614ff5565b6108cc8c6025614ff5565b90505f61388b6138728a601e614ff5565b6108d16138808c6001614ff5565b6108cc8d6026614ff5565b90506138ca6138b26138a4856108d1868d5f01516125fc565b6108d1848c602001516125fc565b6108d16138c08c6004614ff5565b8b604001516125fc565b93505050505f6138de613724886021614ff5565b90505f6138ef613724896021614ff5565b90505f61392761390e6139038b6023614ff5565b6108d18c6006614ff5565b6108ef61391c8c6023614ff5565b6108cc8d6006614ff5565b90505f613945612b6961393a87896125fc565b6108cc8d6021614ff5565b905061395181886125fc565b90505f61397961396b6139658d6006614ff5565b876125fc565b6108ef6139658e6022614ff5565b90505f6139878c6023614ff5565b90505f613997612b6983846125fc565b60808c0185905260a08c0184905290506139b1818b6125fc565b8b6006602002015250505050505050505050505050565b5f6139d45f6001612630565b90505f6139e25f6002612630565b90505f6139f05f6003612630565b90505f613a0c613a0188601d614ff5565b6108ef89601c614ff5565b90505f613a28613a1d89601e614ff5565b6108ef8a601d614ff5565b90505f613a44613a398a601f614ff5565b6108ef8b601e614ff5565b90505f613a60613a558b6024614ff5565b6108ef8c601f614ff5565b905083613a71816108cc818b612617565b9050613a81816108cc878a612617565b9050613a91816108cc8789612617565b9050613aa2816108cc8d6008614ff5565b9050613aae818a6125fc565b60e08b01525082613ac3816108cc818b612617565b9050613ad3816108cc868a612617565b9050613ae3816108cc8689612617565b9050613af4816108cc8d6008614ff5565b9050613b00818a6125fc565b6101008b01525081613b16816108cc818b612617565b9050613b26816108cc858a612617565b9050613b36816108cc8589612617565b9050613b47816108cc8d6008614ff5565b9050613b53818a6125fc565b6101208b01525080613b69816108cc818b612617565b9050613b79816108cc848a612617565b9050613b89816108cc8489612617565b9050613b9a816108cc8d6008614ff5565b9050613ba6818a6125fc565b610140909a019990995250505050505050505050565b613bf56040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613c0084601d614ff5565b8152613c0d84601e614ff5565b6020820152613c1d846024614ff5565b6040820152613c2d846027614ff5565b6060820152613c3d846026614ff5565b6080820152613c4d846025614ff5565b60a08201525f613c5e856002614ff5565b90505f613c6b865f614ff5565b90505f613c7f8460400151855f0151612630565b90505f613c94856020015186602001516125fc565b606086015190915086905f90613caa90806125fc565b90505f613cc8613cc289602001518a606001516125fc565b886125fc565b90505f613ce7613ce08a60a001518b60400151612617565b8a51612617565b9050613cf661396582886125fc565b9050613d1d613d17613d11613d0b8487612630565b88612630565b84612617565b83612617565b9050613d45613d3a613d2f83876125fc565b6108cc8f6009614ff5565b6108cc60018a612630565b6101608c015250505050602085015160808601515f91613d6491612617565b90505f613d82613d788860600151886125fc565b8860200151612630565b90505f613da6613d9284876125fc565b6108d16137598b60a001518c5f0151612630565b9050613dce613dc3613db8838c6125fc565b6108cc8e6009614ff5565b6108cc600189612630565b6101808b0152505f9150613def9050613de8836011612617565b87516125fc565b90505f613dfc8384612617565b9050613e088182612617565b90505f613e168360096125fc565b9050613e3f613e39613724613e328b60a001518c5f0151612617565b8b51612617565b82612630565b60c089018190525f90613e5a90613cc290613d2f908d6125fc565b9050613e6d8b600b602002015182612617565b6101608c0152505086515f9250613e949150613de890613e8d9080612617565b8851612617565b90505f613ed4613eaf836108cc8a5f01518b60a00151612630565b60208901516108ef90613ec29080612617565b6108cc8b602001518c60800151612617565b9050613ef189600c60200201516108d1613cc2613d2f858d6125fc565b89600c602002015250505050505050505050565b613f6f604051806101e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613f87613f7d86601e614ff5565b85604001516125fc565b808252613fa6906108d1613f9c88601d614ff5565b87602001516125fc565b808252613fbb906108d1613de888601c614ff5565b808252613fcd906108d1876001614ff5565b80825260208201819052613fe6906108ef87601f614ff5565b8152614001613ff6866024614ff5565b6108ef87601c614ff5565b608082015261401f614014866027614ff5565b6108ef87601f614ff5565b60608201526080810151614038906108cc816001612630565b6101c082015260808101516140789061406e90614067906108cc60015f516020615c8f5f395f51905f526155e1565b6001612617565b82606001516125fc565b60a082018190526140ae906140a0906108cc614095896002614ff5565b6108cc8a6003614ff5565b6108cc61375988600a614ff5565b83600e60200201526101c08101516140d2906140a0906108cc614095896002614ff5565b6101e084015280516140f7906108cc6140ec886002614ff5565b6108cc896003614ff5565b6101208201525f61411661410c87601f614ff5565b8360200151612630565b9050614127816108cc836001612630565b60e083015261414461413a876026614ff5565b86604001516125fc565b60408301819052614167906108d161415d896025614ff5565b88602001516125fc565b60408301819052614187906108d1614180896024614ff5565b88516125fc565b60408301526141a461419a876027614ff5565b8360400151612630565b60408301525f6141c36141b8886026614ff5565b6108ef89601e614ff5565b90506142156141f0613472614067866080015160015f516020615c8f5f395f51905f526108cc91906155e1565b6108cc614067866040015160015f516020615c8f5f395f51905f526108cc91906155e1565b60c084015260408301516142379061422d90806125fc565b8460400151612630565b61010084015260c083015161426390614255906108cc8a6004614ff5565b6108cc6139658a600a614ff5565b6102008601526101c083015161428290614255906108cc8a6004614ff5565b6102208601526101008301516142a190614255906108cc8a6004614ff5565b61024086015260e08301516142bb906108cc896004614ff5565b6101408401526142da6142cf886025614ff5565b6108ef89601d614ff5565b6101608401526080830151614318906141b89061430d90614067906108cc60015f516020615c8f5f395f51905f526155e1565b8561016001516125fc565b61018084018190526101208401516101a0850181905261434f916108d1906108cc6143448c6005614ff5565b6108cc8d6002614ff5565b6101a08401819052835161436f91906108d1906108cc6143448c5f614ff5565b6101a084018190526101408401516143879190612617565b6101a084018190526143a1906108cc6139658a600a614ff5565b6101a0840181905285600d613795565b6143ea6040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61441f6144066143fb86601c614ff5565b6108cc876025614ff5565b6108d1614414876024614ff5565b6108cc88601d614ff5565b815261446461445961444061443587601c614ff5565b6108cc88601f614ff5565b6108d161444e88601d614ff5565b6108cc89601e614ff5565b6108ef866026614ff5565b6040820181905261447990600160441b6125fc565b6040820181905261448f906108ef866027614ff5565b6040820181905281516144a29190612617565b604082018190526144b8906108cc866005614ff5565b604082015280516144cd90600160441b6125fc565b8082526144ed906108d16144e2876024614ff5565b6108cc886025614ff5565b80825260208201819052614514906108ef61450987601e614ff5565b6108d188601f614ff5565b6020820181905261452a906108cc866004614ff5565b6020820152805160608201819052614547906108d186601f614ff5565b6060820181905261456b906108ef614560876026614ff5565b6108d1886027614ff5565b60608201819052614580906108cc865f614ff5565b8160600181815250505f6145a961459f83602001518460400151612617565b8360600151612617565b90506145ba816108cc876003614ff5565b90506145d26145ca866025614ff5565b6140006125fc565b608083018190526145e8906108d1876024614ff5565b608083018190526145fb906140006125fc565b60808301819052614611906108d187601e614ff5565b60808301819052614624906140006125fc565b6080830181905261463a906108d187601d614ff5565b6080830181905261464d906140006125fc565b60808301819052614663906108d187601c614ff5565b60808301819052614679906108ef87601f614ff5565b6080830181905261468f906108cc876005614ff5565b60808301526146a26145ca866026614ff5565b60a083018190526146b8906108d1876025614ff5565b60a083018190526146cb906140006125fc565b60a083018190526146e1906108d1876024614ff5565b60a083018190526146f4906140006125fc565b60a0830181905261470a906108d187601f614ff5565b60a0830181905261471d906140006125fc565b60a08301819052614733906108d187601e614ff5565b60a08301819052614749906108ef876027614ff5565b60a0830181905261475e906108cc875f614ff5565b60a0830181905260808301515f916147769190612617565b9050614787816108cc886004614ff5565b90506147938282612617565b60c084018190526147ac906108cc61396589600b614ff5565b60c084018190528560136020020152505050505050565b6148396040518061022001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61485261484785601c614ff5565b6108d1866002614ff5565b815261486d61486285601d614ff5565b6108d1866003614ff5565b602082015261488b61488085601e614ff5565b6108d1866004614ff5565b60408201526148a961489e85601f614ff5565b6108d1866005614ff5565b606082015280516148db906148d4906148cd906148c690806125fc565b84516125fc565b83516125fc565b82516125fc565b608082015260208101516149199061490f90614905906148fb90806125fc565b84602001516125fc565b83602001516125fc565b82602001516125fc565b60a082015260408101516149579061494d906149439061493990806125fc565b84604001516125fc565b83604001516125fc565b82604001516125fc565b60c0820152606081015161498b9061406e906149819061497790806125fc565b84606001516125fc565b83606001516125fc565b60e0820152608081015160a08201516149a49190612617565b61010082015260c081015160e08201516149be9190612617565b61012082015260a08101516149e2906149d79080612617565b826101200151612617565b61014082015260e0810151614a06906149fb9080612617565b826101000151612617565b610160820152610120810151614a1c9080612617565b6101e08201819052614a3d90614a329080612617565b826101600151612617565b6101e0820152610100810151614a539080612617565b6101a08201819052614a7490614a699080612617565b826101400151612617565b6101a08201819052610160820151614a8b91612617565b6101808201526101408101516101e0820151614aa79190612617565b6101c0820152614abb61347285600c614ff5565b6102008201819052610280840151610180830151614ae6926108d1916108cc906108ef8a6024614ff5565b8360146020020152614b1683601560200201516108d18361020001516108cc856101a001516108ef8a6025614ff5565b8360156020020152614b4683601660200201516108d18361020001516108cc856101c001516108ef8a6026614ff5565b8360166020020152614b7683601760200201516108d18361020001516108cc856101e001516108ef8a6027614ff5565b836017602002015250505050565b614bd66040518061016001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f6040518060800160405280614c0b7f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e76125e4565b8152602001614c397f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b6125e4565b8152602001614c667e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac156125e4565b8152602001614c947f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b6125e4565b90529050614cb1614ca686601c614ff5565b6108d1876002614ff5565b6101208301819052614cf090614ce590614cda90614ccf90806125fc565b8561012001516125fc565b8461012001516125fc565b8361012001516125fc565b8252614cfd85601d614ff5565b6020830152614d0d85601e614ff5565b6040830152614d1d85601f614ff5565b606083015281516020830151614d459161459f91614d3b9190612617565b8460400151612617565b6080830152614d5861372486600d614ff5565b6101408301528151614d7990614d6f90835f610bce565b8360800151612617565b60a0830152614da584601860200201516108d18461014001516108cc8660a001516108ef8b6024614ff5565b6103008501526020820151614dc090614d6f90836001610bce565b60c0830152614dec84601960200201516108d18461014001516108cc8660c001516108ef8b6025614ff5565b6103208501526040820151614e0790614d6f90836002610bce565b60e0830152614e3384601a60200201516108d18461014001516108cc8660e001516108ef8b6026614ff5565b6103408501526060820151614e4e90614d6f90836003610bce565b610100830152614e7c84601b60200201516108d18461014001516108cc8661010001516108ef8b6027614ff5565b84601b6135ab565b815160015b601c811015614ed657614ecc826108d18684601c8110614eab57614eab615b74565b602002015186614ebc6001876155e1565b601b8110610bce57610bce615b74565b9150600101614e89565b5092915050565b5f5f8390505f60405160208152602080820152602060408201528260608201528460808201525f516020615c8f5f395f51905f5260a082015260205f60c08360055afa80614f29575f5ffd5b505f5160809190910160405295945050505050565b614f46615321565b614f4e615321565b604051835181526020840151602082015284604082015260408160608360075afa80614f78575f5ffd5b5080518252602080820151908301526060016040529392505050565b614f9c615321565b614fa4615321565b6040518451815260208501516020820152835160408201526020840151606082015260408160808360065afa80614fd9575f5ffd5b5080518252602080820151908301526080016040529392505050565b5f8282602881111561500957615009615c5a565b6029811061501957615019615b74565b60200201519392505050565b604051806103e001604052805f81526020015f81526020015f815260200161504b615321565b8152602001615058615321565b8152602001615065615321565b8152602001615072615321565b815260200161507f615321565b815260200161508c615321565b8152602001615099615321565b81526020016150a6615321565b81526020016150b3615321565b81526020016150c0615321565b81526020016150cd615321565b81526020016150da615321565b81526020016150e7615321565b81526020016150f4615321565b8152602001615101615321565b815260200161510e615321565b815260200161511b615321565b8152602001615128615321565b8152602001615135615321565b8152602001615142615321565b815260200161514f615321565b815260200161515c615321565b8152602001615169615321565b8152602001615176615321565b8152602001615183615321565b8152602001615190615321565b815260200161519d615321565b81526020016151aa615321565b905290565b6040518061028001604052806151c36153ed565b81526020016151d0615321565b81526020016151dd615321565b81526020016151ea615321565b81526020016151f7615321565b8152602001615204615321565b8152602001615211615321565b815260200161521e615321565b815260200161522b615321565b8152602001615238615321565b815260200161524561540c565b81526020015f8152602001615258615439565b81526020015f815260200161526b615467565b8152602001615278615486565b815260200161528561536b565b81526020016151906154b4565b6040518061052001604052806029906020820280368337509192915050565b604051806101c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020016152ef6154b4565b81526020016152fc6154b4565b81526020015f81526020015f81526020015f81526020015f8152602001606081525090565b60405180604001604052805f81526020015f81525090565b604051806040016040528061519d615321565b6040518061012001604052806009906020820280368337509192915050565b604051806103800160405280601c906020820280368337509192915050565b6040518060e0016040528061539d6154d2565b81526020015f81526020015f81526020015f81526020015f81526020016153c26154d2565b81526020015f81525090565b6040518061010001604052806008906020820280368337509192915050565b6040518061020001604052806010906020820280368337509192915050565b60405180606001604052806003905b615423615321565b81526020019060019003908161541b5790505090565b604051806103800160405280601c905b61545161534c565b8152602001906001900390816154495790505090565b604051806105400160405280602a906020820280368337509192915050565b604051806103600160405280601b905b61549e615321565b8152602001906001900390816154965790505090565b60405180608001604052806004906020820280368337509192915050565b604051806120000160405280610100906020820280368337509192915050565b5f5f5f5f60408587031215615505575f5ffd5b84356001600160401b0381111561551a575f5ffd5b8501601f8101871361552a575f5ffd5b80356001600160401b0381111561553f575f5ffd5b876020828401011115615550575f5ffd5b6020918201955093508501356001600160401b0381111561556f575f5ffd5b8501601f8101871361557f575f5ffd5b80356001600160401b03811115615594575f5ffd5b8760208260051b84010111156155a8575f5ffd5b949793965060200194505050565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417612611576126116155b6565b81810381811115612611576126116155b6565b805f5b60108110156131e25781518452602093840193909101906001016155f7565b805f5b60038110156131e25761563784835180518252602090810151910152565b6040939093019260209190910190600101615619565b805f5b601c8110156131e2578151845f5b600981101561567d57825182526020928301929091019060010161565e565b505050610120939093019260209190910190600101615650565b805f5b602a8110156131e257815184526020938401939091019060010161569a565b805f5b601b8110156131e2576156da84835180518252602090810151910152565b60409390930192602091909101906001016156bc565b805f5b601c8110156131e25781518452602093840193909101906001016156f3565b805f5b60048110156131e2578151845260209384019390910190600101615715565b8183525f6001600160fb1b0383111561574b575f5ffd5b8260051b80836020870137939093016020019392505050565b61576f8188516155f4565b5f602088015161578d61020084018280518252602090810151910152565b5060408801518051610240840152602090810151610260840152606089015180516102808501528101516102a0840152608089015180516102c08501528101516102e084015260a0890151805161030085015281015161032084015260c0890151805161034085015281015161036084015260e089015180516103808501528101516103a084015261010089015180516103c08501528101516103e084015261012089015180516104008501520151610420830152610140880151615856610440840182615616565b5061016088015161050083015261018088015161587761052084018261564d565b506101a08801516124a08301526101c08801516158986124c0840182615697565b506101e08801516158ad612a008401826156b9565b506102008801516158c26130c08401826156f0565b506102208801516158d7613440840182615712565b5061024088015180516134c08401526020908101516134e0840152610260890151805161350085015201516135208301526135c061354083018190526159209083018789615734565b613560830195909552506135808101929092526135a0909101529392505050565b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b038111828210171561597857615978615941565b60405290565b604051601f8201601f191681016001600160401b03811182821017156159a6576159a6615941565b604052919050565b5f60c082840312156159be575f5ffd5b60405160c081016001600160401b03811182821017156159e0576159e0615941565b604090815283518252602080850151908301528381015190820152606080840151908201526080808401519082015260a0928301519281019290925250919050565b5f82601f830112615a31575f5ffd5b5f610360615a3e8161597e565b915083018185821115615a4f575f5ffd5b845b82811015615a69578051825260209182019101615a51565b509195945050505050565b5f82601f830112615a83575f5ffd5b5f610380615a3e8161597e565b5f610be0828403128015615aa2575f5ffd5b50615aab615955565b615ab584846159ae565b8152615ac48460c08501615a22565b6020820152615ad7846104208501615a74565b60408201526107a08301516060820152615af5846107c08501615a74565b6080820152610b4083015160a0820152610b6083015160c0820152610b8083015160e0820152610ba0830151610100820152610bc09092015161012083015250919050565b80820180821115612611576126116155b6565b5f5f85851115615b5b575f5ffd5b83861115615b67575f5ffd5b5050820193919092039150565b634e487b7160e01b5f52603260045260245ffd5b5f60018201615b9957615b996155b6565b5060010190565b80356020831015612611575f19602084900360031b1b1692915050565b5f82615bd757634e487b7160e01b5f52601260045260245ffd5b500690565b5f81615bea57615bea6155b6565b505f190190565b5f8183825b6008811015615c15578151835260209283019290910190600101615bf6565b5050506101008201905092915050565b5f82518060208501845e5f920191825250919050565b5f60208284031215615c4b575f5ffd5b815180151581146103f4575f5ffd5b634e487b7160e01b5f52602160045260245ffdfe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4730644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a164736f6c634300081c000a", - "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063ea50d0e41461002d575b5f5ffd5b61004061003b3660046154f2565b610054565b604051901515815260200160405180910390f35b5f5f61007f7f00000000000000000000000000000000000000000000000000000000000000006102ee565b905061008c8160206155ca565b85146100ee577f0000000000000000000000000000000000000000000000000000000000000000856100bf8360206155ca565b6040516359895a5360e01b81526004810193909352602483019190915260448201526064015b60405180910390fd5b5f6100f76103fb565b90505f61012588887f0000000000000000000000000000000000000000000000000000000000000000610410565b90506010826040015161013891906155e1565b85146101575760405163fa06659360e01b815260040160405180910390fd5b60405163995bf45760e01b81525f9073__$766c1d4ff1635319bed72d911807c12b70$__9063995bf457906101fa9085908b908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090600401615764565b610be060405180830381865af4158015610216573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061023a9190615a90565b905061028a8787808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050855185516060810151608090910151919350915060016108a9565b815160a0015261029a8282610a10565b6102b7576040516313f8744360e31b815260040160405180910390fd5b6102c2828483610c17565b6102df576040516352ec174560e11b815260040160405180910390fd5b50600198975050505050505050565b5f8060026102fe60016008615b3a565b61030891906155ca565b9050610316600260036155ca565b6103209082615b3a565b9050600161032f6009856155ca565b61033991906155ca565b6103439082615b3a565b90506001610352816029615b3a565b61035c91906155ca565b6103669082615b3a565b9050610374600160026155ca565b61037e9082615b3a565b905061038b6001846155ca565b6103959082615b3a565b90506103a3600160046155ca565b6103ad9082615b3a565b905060026103bc6001856155e1565b6103c691906155ca565b6103d09082615b3a565b90506103dd6002806155ca565b6103e79082615b3a565b90506103f4601082615b3a565b9392505050565b610403615025565b61040b611c14565b905090565b6104186151af565b5f805b601081101561047a57610447868387610435602083615b3a565b9261044293929190615b4d565b61254f565b8351826010811061045a5761045a615b74565b6020020181815250506020826104709190615b3a565b915060010161041b565b5061049e85828661048c604083615b3a565b9261049993929190615b4d565b612562565b60208301526104ae604082615b3a565b90506104c185828661048c604083615b3a565b6040808401919091526104d49082615b3a565b90506104e785828661048c604083615b3a565b60608301526104f7604082615b3a565b905061050a85828661048c604083615b3a565b608083015261051a604082615b3a565b905061052d85828661048c604083615b3a565b60c083015261053d604082615b3a565b905061055085828661048c604083615b3a565b60e0830152610560604082615b3a565b905061057385828661048c604083615b3a565b60a0830152610583604082615b3a565b905061059685828661048c604083615b3a565b6101008301526105a7604082615b3a565b90506105ba85828661048c604083615b3a565b6101208301526105cb604082615b3a565b90506105de85828661048c604083615b3a565b610140830151526105f0604082615b3a565b9050610603858286610435602083615b3a565b610160830152610614602082615b3a565b90505f5b83811015610692575f5b60098110156106895761063c878488610435602083615b3a565b84610180015183601c811061065357610653615b74565b6020020151826009811061066957610669615b74565b60200201818152505060208361067f9190615b3a565b9250600101610622565b50600101610618565b505f5b6106a160016029615b3a565b8110156106f0576106b9868387610435602083615b3a565b836101c0015182602a81106106d0576106d0615b74565b6020020181815250506020826106e69190615b3a565b9150600101610695565b50610702858286610435602083615b3a565b6101a0830152610713602082615b3a565b905061072685828661048c604083615b3a565b6101408301516020015261073b604082615b3a565b905061074e85828661048c604083615b3a565b61014083015160026020020152610766604082615b3a565b90505f5b6107756001856155e1565b8110156107be5761078d86838761048c604083615b3a565b836101e0015182601b81106107a4576107a4615b74565b60200201526107b4604083615b3a565b915060010161076a565b505f5b83811015610811576107da868387610435602083615b3a565b83610200015182601c81106107f1576107f1615b74565b6020020181815250506020826108079190615b3a565b91506001016107c1565b505f5b60048110156108655761082e868387610435602083615b3a565b836102200151826004811061084557610845615b74565b60200201818152505060208261085b9190615b3a565b9150600101610814565b5061087785828661048c604083615b3a565b610240830152610888604082615b3a565b905061089b85828661048c604083615b3a565b610260830152509392505050565b5f600180826108d6866108d1896108cc6108c78a6310000000615b3a565b6125e4565b6125fc565b612617565b90505f6108f4876108ef8a6108cc6108c78b6001615b3a565b612630565b90505f5b61092360107f00000000000000000000000000000000000000000000000000000000000000006155e1565b811015610990575f61094d8c838151811061094057610940615b74565b6020026020010151612658565b905061095d866108cc8684612617565b955061096d856108cc8584612617565b9450610979848b612617565b9350610985838b612630565b9250506001016108f8565b505f5b60108110156109f7575f8a82601081106109af576109af615b74565b602002015190506109c4866108cc8684612617565b95506109d4856108cc8584612617565b94506109e0848b612617565b93506109ec838b612630565b925050600101610993565b50610a02848461266d565b9a9950505050505050505050565b5f5f610a2583606001518561016001516125fc565b905060015f5b7f0000000000000000000000000000000000000000000000000000000000000000811015610b17575f86610180015182601c8110610a6b57610a6b615b74565b602002015180519091505f90610a89908360015b6020020151612617565b9050848114610aab576040516313f8744360e31b815260040160405180910390fd5b5f876080015184601c8110610ac257610ac2615b74565b60200201519050610ad3838261267b565b9550610b07856108cc60016108d1856108cc8e604001518b601c8110610afb57610afb615b74565b60200201516001612630565b9450505050806001019050610a2b565b50610b20615292565b5f5b6029811015610b70576101c0870151610b3c600183615b3a565b602a8110610b4c57610b4c615b74565b6020020151828260298110610b6357610b63615b74565b6020020152600101610b22565b505f610b8582875f0151886020015186612829565b9050600160025b7f0000000000000000000000000000000000000000000000000000000000000000811015610be257610bd882896080015183601c8110610bce57610bce615b74565b60200201516125fc565b9150600101610b8c565b50610c08610bf5836108cc600185612630565b6108d18a6101a001518a606001516125fc565b94909414979650505050505050565b5f610c206152b1565b5f610c4f8460c001517f00000000000000000000000000000000000000000000000000000000000000006128a2565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610c8a57610c8a615941565b604051908082528060200260200182016040528015610cb3578160200160208202803683370190505b5090505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610cef57610cef615941565b604051908082528060200260200182016040528015610d2857816020015b610d15615321565b815260200190600190039081610d0d5790505b509050610d5b610d56876101000151855f81518110610d4957610d49615b74565b6020026020010151612630565b61296b565b84610120018181525050610d90610d56876101000151855f81518110610d8357610d83615b74565b6020026020010151612617565b610140850181905261012085015160e0880151610db1926108d191906125fc565b845260c0860151610de190610dc59061296b565b6108cc8661012001516108ef8a60e001518961014001516125fc565b6020850152815160019083905f90610dfb57610dfb615b74565b602002602001018181525050876102400151815f81518110610e1f57610e1f615b74565b6020908102919091010152600160a08501525f60c08501528351610e42906129db565b60408501526020840151610e55906129db565b606085015260015b610e6960016024615b3a565b8111610f0a57610e8185604001518660a001516125fc565b838281518110610e9357610e93615b74565b602002602001018181525050610edc8560c001516108d18b6101c00151600185610ebd91906155e1565b602a8110610ecd57610ecd615b74565b60200201518860a001516125fc565b60c086015260a08086015190880151610ef591906125fc565b60a0860152610f0381615b88565b9050610e5d565b505f5b6005811015610fe3575f610f22601e83615b3a565b90505f610f3160016024615b3a565b610f3b9084615b3a565b9050610f6c858381518110610f5257610f52615b74565b60200260200101516108d189606001518a60a001516125fc565b858381518110610f7e57610f7e615b74565b602002602001018181525050610fbb8760c001516108d18d6101c0015184602a8110610fac57610fac615b74565b60200201518a60a001516125fc565b60c088015260a080880151908a0151610fd491906125fc565b60a08801525050600101610f0d565b50876020015181600181518110610ffc57610ffc615b74565b602002602001018190525086606001518160028151811061101f5761101f615b74565b602002602001018190525086608001518160038151811061104257611042615b74565b60200260200101819052508660a001518160048151811061106557611065615b74565b60200260200101819052508660c001518160058151811061108857611088615b74565b60200260200101819052508660e00151816006815181106110ab576110ab615b74565b6020026020010181905250866101000151816007815181106110cf576110cf615b74565b6020026020010181905250866101200151816008815181106110f3576110f3615b74565b60200260200101819052508661014001518160098151811061111757611117615b74565b602002602001018190525086610160015181600a8151811061113b5761113b615b74565b6020026020010181905250866101c0015181600b8151811061115f5761115f615b74565b602002602001018190525086610180015181600c8151811061118357611183615b74565b6020026020010181905250866101a0015181600d815181106111a7576111a7615b74565b6020026020010181905250866101e0015181600e815181106111cb576111cb615b74565b602002602001018190525086610200015181600f815181106111ef576111ef615b74565b60200260200101819052508661022001518160108151811061121357611213615b74565b60200260200101819052508661024001518160118151811061123757611237615b74565b60200260200101819052508661026001518160128151811061125b5761125b615b74565b60200260200101819052508661028001518160138151811061127f5761127f615b74565b6020026020010181905250866102a00151816014815181106112a3576112a3615b74565b6020026020010181905250866102c00151816015815181106112c7576112c7615b74565b6020026020010181905250866102e00151816016815181106112eb576112eb615b74565b60200260200101819052508661030001518160178151811061130f5761130f615b74565b60200260200101819052508661032001518160188151811061133357611333615b74565b60200260200101819052508661034001518160198151811061135757611357615b74565b602002602001018190525086610360015181601a8151811061137b5761137b615b74565b602002602001018190525086610380015181601b8151811061139f5761139f615b74565b6020026020010181905250866103a0015181601c815181106113c3576113c3615b74565b6020026020010181905250866103c0015181601d815181106113e7576113e7615b74565b6020026020010181905250876040015181601e8151811061140a5761140a615b74565b6020026020010181905250876060015181601f8151811061142d5761142d615b74565b602002602001018190525087608001518160208151811061145057611450615b74565b60200260200101819052508760a001518160218151811061147357611473615b74565b60200260200101819052508761012001518160228151811061149757611497615b74565b6020026020010181905250876101000151816023815181106114bb576114bb615b74565b60200260200101819052508760c00151816024815181106114de576114de615b74565b60200260200101819052508760e001518160258151811061150157611501615b74565b60200260200101819052505f61154787608001518660c001518b6102000151877f00000000000000000000000000000000000000000000000000000000000000006129ed565b9050611571815f8151811061155e5761155e615b74565b60200260200101518661012001516125fc565b608086018190526102008a01515160e08901516115a292916108d19161159791906125fc565b8861014001516125fc565b608086015260e08701516115b590612b4b565b60a08601525f6115c760016024615b3a565b6115d2906001615b3a565b90505f5b61160160017f00000000000000000000000000000000000000000000000000000000000000006155e1565b811015611812575f61163460017f00000000000000000000000000000000000000000000000000000000000000006155e1565b8210159050806117a357611668610d568b6101000151898560016116589190615b3a565b81518110610d4957610d49615b74565b6101208901526101008a015161169890610d569089611688866001615b3a565b81518110610d8357610d83615b74565b61014089015260a08801516101208901516116b391906125fc565b61016089015260a088015160e08b01516116db916116d0916125fc565b8961014001516125fc565b61018089018190526116fe906116f0906129db565b6108d18a61016001516129db565b866117098486615b3a565b8151811061171957611719615b74565b6020026020010181815250505f6117528961018001518e61020001518560016117429190615b3a565b601c8110610bce57610bce615b74565b905061178c816108d18b61016001518887600161176f9190615b3a565b8151811061177f5761177f615b74565b60200260200101516125fc565b905061179c896080015182612617565b60808a0152505b6117c26117b88960a001518c60e001516125fc565b8b60e001516125fc565b60a08901526101e08c015182601b81106117de576117de615b74565b6020020151856117ee8486615b3a565b815181106117fe576117fe615b74565b6020908102919091010152506001016115d6565b5061183e60017f00000000000000000000000000000000000000000000000000000000000000006155e1565b6118489082615b3a565b90506118686118608961010001518a60c00151612630565b60019061266d565b60e08701515261010088015160c08901516118ac91611860916108ef907f07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76906125fc565b60e0878101805160200192909252815180516040909101529051805160609091015260a0870151908901516118ee916118e4916125fc565b8960e001516125fc565b60a08701525f5b600481101561199c575f6119278860e00151836004811061191857611918615b74565b60200201518960a001516125fc565b9050611932816129db565b886101000151836004811061194957611949615b74565b602002015260a088015160e08b015161196291906125fc565b8860a001818152505061198e88608001516108d1838f61022001518660048110610bce57610bce615b74565b6080890152506001016118f5565b506101008601515184518590839081106119b8576119b8615b74565b602090810291909101810191909152610100870151908101516119dc916002610a7f565b846119e8836001615b3a565b815181106119f8576119f8615b74565b60209081029190910101526101008601516060015184611a19836002615b3a565b81518110611a2957611a29615b74565b60209081029190910101525f5b6003811015611a8b578a61014001518160038110611a5657611a56615b74565b60200201518483611a6681615b88565b945081518110611a7857611a78615b74565b6020908102919091010152600101611a36565b506040518060400160405280600181526020016002815250838281518110611ab557611ab5615b74565b60200260200101819052508560800151848280611ad190615b88565b935081518110611ae357611ae3615b74565b602002602001018181525050611b0d8a61022001518960c001518a608001518d6101a00151612b56565b611b2a5760405163a2a2ac8360e01b815260040160405180910390fd5b5f8a6102600151905080848381518110611b4657611b46615b74565b6020026020010181905250886101000151858381518110611b6957611b69615b74565b602002602001018181525050611b7d615339565b611b878587612eb9565b8152611b9282612fb1565b602082018190528c5182515f92611baa929190612ff7565b90505f5f611bba8f5f0151613088565b91509150611bc782613149565b611bd081613149565b8351611bdd9083856131e8565b84526020840151611bef9082856131e8565b602085018190528451611c0191613217565b9f9e505050505050505050505050505050565b611c1c615025565b50604080516103e081018252620200008152601160208083019190915261024382840152825180840184527f039702f4c2b2b49fd29d82b077cbf9d1df2871e0fbade17241573ca5021603fc81527f03270b3b2673844695842df11cdbabf54acafe03642adfdfbf69834247ed0720818301526060830152825180840184527f1ccb0308d0359b8835480fa7dd829fdbf16b136d57e85c1621efb1679fe1a94c81527f207076fed3c60bbeb2df5f48c86b12f4027c523f9b8e69456ca51643fea3de1d818301526080830152825180840184527f067b40a80be55b95cc17070cf5dc78441e4868acea0ac1e46b5708705151590581527f0792e6c3d76aeeed6ee7d7e443138c813b74dbcd8ce92990e6f6747adc0af0548183015260a0830152825180840184527f148a04387a9e0a8cec6a4a0d90706f5907e8bb257fb04f8a3cfe07c18a7c101481527f225866d9efd4a5be4eb9a00016f902f844e3d81e2768b24dc92ecbd6b34176bd8183015260c0830152825180840184527f0dacf57ed82c686ca051fca3f1820016cb49e91b5d3c4bee7f9fa19800d9ed0681527f22ba5fda41aa14aeb7a3a2731fbfe3a673cf7db1d2217d32db491f44344309058183015260e0830152825180840184527f0f783f69a36c2bac47b9c59ff33ccc583a284a46b282591b9e9bbb85d8b5e5dc81527f029b91609a06e94924f0d83530fc01f3427f5ab729a0959903108c2ccc86825c81830152610100830152825180840184527f11beb2731ab8cf46c0a52666bb457fa74d4b635043bb5689a35a2aee24990b8081527f2f1fba989036c44aedb609d0d3341ccb842c2d1cd7c80cea4a95d0eb4530577081830152610120830152825180840184527f28ae1f7459c3c5d9ca2f80f8e5c28bb301d0245228bade0e2bb962b4bfbe301b81527f0622f7db14381bbecf862e186cfa570588160466ae7d4fed4b35a70d99af914f81830152610140830152825180840184527f233983f621ab48bdce4f7216bdbc54c49463e90d88301b9ab224fca61c93dba081527f265c3834d63be0bc710c9b4a48015e2442a3b9bf63caec9db0064dfb1bd569c481830152610160830152825180840184527f06d21b82f49e04e078d4ad30cd6828eaa66c1bf984bc52b79de8c786fe4dfe7a81527f301aa91e167bbc765996ac6d2889e7d49f0734bc7abb3a4b85900143556a1b3f81830152610180830152825180840184527f1222d34f53e6b36138627277789ad131ea24f79caca2d5f59193c5e3a7dfdde781527f245a380726977d41c9f0a9a0ba33608994eb3660de6a8efba38009df93da679a818301526101a0830152825180840184527f2dfc248e28ad889b5b692077f338d28b2f687c6e909b9693f8e8fd25cefc352881527f16e2cbc305166ea90a426987efff2020827d8c548ea4155c659df296f14f00fd818301526101c0830152825180840184527f0d815a04effc6e57ec95f3ac112f76ab4a9d993d044626ceb54f967c8d77d8e181527f1df4c065a1129d5cbdf244cb9cc2eaf406c2f5fbab4c393347d57ae5e2ab881f818301526101e0830152825180840184527f118733dc1db84685f4160119cb0cd9a51b831cf0643e914daf1c63fc7967297981527f27b63107b52edf239acb1bd47e24c97094422cc2bba51ee0f54b2707946be55681830152610200830152825180840184527f2e7a11cec89df0ad6b730cf80be4246e56e1667f55e35a22c9b39b196226135b81527f0891267297e339bedeef69881477b4e5c19e761e127e3d3772714f92ade80fd381830152610220830152825180840184527f16f90d7d5c3fd7ab9f490dd5d2b94afea698039e2456c1d5f0e22159348d1e0c81527f29ad721b49b02192f5323326fd803b102f7a09b0371c537db998014fa14c307981830152610240830152825180840184527f0a5e4e29375b31024f09dd662b460eb25930835255c62dc74d62d0c983981e4281527f069adf56537452ecad2fcd8cdea1291fbf273d7e752d9ba0812900e7215c8fc081830152610260830152825180840184527f1bd554f207de2e42cbc94e8579154a07e37f3ba9d80832f28e38dffaaccd1ade81527f22261d045539dbaabf26f23773b365b2ddd30af639a8b15a56e777f5607bf43581830152610280830152825180840184527f11769064ef79db1f35b23b8b1e5c118e769e1a41b912f49dfdbffbacf23d056481527f16f17c1721186bbd19d09f1645f968677cb1ad0c6b656c3849a4b7f27d5279d9818301526102a0830152825180840184527f0cad91097e151471556985b94a0188b759472f9bb3295fe6de6846f2d4fe27e181527f042f4a199546b40704a9c4822bfd20a91bc478055dc5676c7347f64545b47f4d818301526102c0830152825180840184527f1286a8beb1993863980820c27dfb00f93f8949f60933042e5aa8275dd48e55f781527f2037878d67d1009eb6dac43c5f6f076f884d456e057b000912d40a2ec440df1f818301526102e0830152825180840184527f1c0413fa3552ba4738b423829d55fcc03c912bf931336778a458e1c25cd4f55881527f190904e6db04c862bd9d7406029e03a1103a513203eb6d8faa010021eedf18d481830152610300830152825180840184527f099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d2681527e15b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f81830152610320830152825180840184527f1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e81527f305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d1981830152610340830152825180840184527f061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d81527f1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e81830152610360830152825180840184527f043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce81527f261522c4089330646aff96736194949330952ae74c573d1686d9cb4a007338548183015261038083015282518084018452600181526002818301526103a083015282518084019093527f0ad44c49c91e4374983e023f10e6256c39d27b2857eb2d2ce82a82b51e02dc3883527f23ad26f46d7b04b00d6ebe50273765d49c59d9db9ae22dd33909bc3c9efc5308908301526103c081019190915290565b5f6103f461255d8385615ba0565b612658565b61256a615321565b60408051808201909152805f516020615c6f5f395f51905f5261259060205f8789615b4d565b61259991615ba0565b6125a39190615bbd565b81526020908101905f516020615c6f5f395f51905f52906125c8906040908789615b4d565b6125d191615ba0565b6125db9190615bbd565b90529392505050565b5f5f516020615c8f5f395f51905f52825b0692915050565b5f5f516020615c8f5f395f51905f5282840990505b92915050565b5f5f516020615c8f5f395f51905f528284089392505050565b5f5f516020615c8f5f395f51905f52825f516020615c8f5f395f51905f520384089392505050565b5f5f516020615c8f5f395f51905f52826125f5565b5f6103f4836108cc8461296b565b5f5f604051806101200160405280619d8081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec5181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31815260200161024081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd3181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec518152602001619d8081525090505f600190505f5f90505b60098110156127745761276a826108cc8784612630565b9150600101612753565b5061277d61534c565b5f5b60098110156127ce576127af610d568583600981106127a0576127a0615b74565b60200201516108cc8985612630565b8282600981106127c1576127c1615b74565b602002015260010161277f565b505f5b60098110156128145761280a856108d18984600981106127f3576127f3615b74565b6020020151858560098110610bce57610bce615b74565b94506001016127d1565b5061281f84836125fc565b9695505050505050565b5f61283261536b565b61283d86828561340b565b612849868683866135b7565b612855868683866137a3565b6128608682856139c8565b61286b868285613bbc565b61287786868386613f05565b6128828682856143b1565b61288d8682856147c3565b612898868285614b84565b61281f8185614e84565b60605f826001600160401b038111156128bd576128bd615941565b6040519080825280602002602001820160405280156128e6578160200160208202803683370190505b50905083815f815181106128fc576128fc615b74565b602090810291909101015260015b838110156129635761293e826129216001846155e1565b8151811061293157612931615b74565b6020026020010151612b4b565b82828151811061295057612950615b74565b602090810291909101015260010161290a565b509392505050565b5f5f8290505f604051602081526020808201526020604082015282606082015260025f516020615c8f5f395f51905f520360808201525f516020615c8f5f395f51905f5260a082015260205f60c08360055afa806129c7575f5ffd5b505f51608091909101604052949350505050565b5f516020615c8f5f395f51905f520390565b60605f826001600160401b03811115612a0857612a08615941565b604051908082528060200260200182016040528015612a31578160200160208202803683370190505b509050825b8015612b40575f85612a496001846155e1565b81518110612a5957612a59615b74565b602002602001015190505f89600184612a7291906155e1565b601c8110612a8257612a82615b74565b602002015190505f612add612aa1612a9a858d6125fc565b60026125fc565b6108ef8b612ab06001896155e1565b601c8110612ac057612ac0615b74565b60200201516108cc612ad7886108cc60018a612630565b87612630565b9050612afe816108cc610d56612af8876108cc600189612630565b86612617565b99508990508085612b106001876155e1565b81518110612b2057612b20615b74565b60200260200101818152505050505080612b3990615bdc565b9050612a36565b509695505050505050565b5f61261182836125fc565b5f600181612b6f612b6987610100614edd565b83612630565b905080612b8f5760405163835eb8f760e01b815260040160405180910390fd5b612b9761538a565b80518390525f5b7f0000000000000000000000000000000000000000000000000000000000000000811015612c80575f612bd28260096155ca565b612bdd906001615b3a565b905084835f0151826101008110612bf657612bf6615b74565b60200201525f612c07826001615b3a565b90505b612c15600983615b3a565b811015612c76578351612c5590612c2d6001846155e1565b6101008110612c3e57612c3e615b74565b60200201518a85601c8110610bce57610bce615b74565b8451826101008110612c6957612c69615b74565b6020020152600101612c0a565b5050600101612b9e565b50608081018390525f602082018190525b610100811015612d9157612cb2612cac83608001518a6125fc565b85612630565b8260a00151826101008110612cc957612cc9615b74565b602002015260a0820151612cf390826101008110612ce957612ce9615b74565b602002015161296b565b8260a00151826101008110612d0a57612d0a615b74565b602002018181525050612d5082602001516108d1845f0151846101008110612d3457612d34615b74565b60200201518560a00151856101008110610bce57610bce615b74565b60208301526080820151612d84907f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d66125fc565b6080830152600101612c91565b505f612da2836108cc61010061296b565b9050612db28260200151826125fc565b602083015260a0820151612dcd905f5b6020020151826125fc565b604083015260a0820151612df990612de860016101006155e1565b6101008110612dc257612dc2615b74565b60608301526040820151612e0f908a6002610bce565b60c08301819052612e6f906108d1612e478b7f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6612630565b60208d015160408e01516108cc91612e5e91612630565b8e5160208901516108ef91906125fc565b60c083018190526060830151612ea491612e98916108d1906108cc8e600260200201518c612630565b6108ef858c6003610bce565b60c08301819052159998505050505050505050565b612ec1615321565b7f00000000000000000000000000000000000000000000000000000000000000005f5b81811015612f1657612f0e858281518110612f0157612f01615b74565b6020026020010151613149565b600101612ee4565b50604051600190815b60018401811015612f7b5760208102870160208202870181515160408501528151602001516060850152805160808501525050604080830160606040850160075afa8316925060408260808460065afa90921691600101612f1f565b5080518452602081015160208501525080612fa9576040516352ec174560e11b815260040160405180910390fd5b505092915050565b612fb9615321565b5f516020615c6f5f395f51905f5282602001515f516020615c6f5f395f51905f52612fe491906155e1565b612fee9190615bbd565b60208301525090565b5f5f5f61300386613088565b9150915061300f6153ce565b82518152602080840151818301528251604080840191909152838201516060840152875160808401528782015160a0840152865160c08401528682015160e08401525161307d9161306291849101615bf1565b60405160208183030381529060405280519060200120612658565b979650505050505050565b613090615321565b613098615321565b82516020808501516040860151606087015160cc90811b608892831b604494851b90961795909517949094178652608087015160a088015160c089015160e08a0151871b90841b91851b9092171717868401526101008701516101208801516101408901516101608a0151871b90841b91851b909217171785526101808701516101a08801516101c08901516101e09099015190951b9790911b9390911b1791909117939093179281019290925291565b805160208201515f5f516020615c6f5f395f51905f528380095f516020615c6f5f395f51905f5260035f516020615c6f5f395f51905f52838709085f516020615c6f5f395f51905f5284850914915050806131e25760405162461bcd60e51b8152602060048201526019602482015278706f696e74206973206e6f74206f6e2074686520637572766560381b60448201526064016100e5565b50505050565b6131f0615321565b6131f8615321565b6132028386614f3e565b905061320e8185614f94565b95945050505050565b81516020808401518351848301516040805194850195909552938301919091527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260608301527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60808301527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b60a08301527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60c083015260e08201526101008101919091527f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c16101208201527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b06101408201527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe46101608201527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101808201525f9081906101a00160405160208183030381529060405290505f5f60086001600160a01b0316836040516133ad9190615c25565b5f60405180830381855afa9150503d805f81146133e5576040519150601f19603f3d011682016040523d82523d5f602084013e6133ea565b606091505b509150915081801561281f57508080602001905181019061281f9190615c3b565b5f613417846007614ff5565b90507f183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f80000005f61347861347261344c856003612630565b6108cc61346761345c8b5f614ff5565b6108cc8c601d614ff5565b6108cc8b601c614ff5565b836125fc565b90506134f96134ee6134d56134bc6134a3856108d16134988d6002614ff5565b6108cc8e601c614ff5565b6108d16134b18c6003614ff5565b6108cc8d601d614ff5565b6108d16134ca8b6004614ff5565b6108cc8c601e614ff5565b6108d16134e38a6005614ff5565b6108cc8b601f614ff5565b6108d1886001614ff5565b9050613518816108d161350d866001612630565b6108cc8a6027614ff5565b905061352481846125fc565b905061353081856125fc565b8552505f905061356a61356061355561354a88601c614ff5565b6108d189601f614ff5565b6108ef886024614ff5565b6108d1875f614ff5565b905061357b816108cc846002612630565b905061358c816108cc846001612630565b905061359881836125fc565b90506135a481846125fc565b9050808460015b60200201525050505050565b5f5f5f6135ed6135e36135cb89601c614ff5565b6108d16135d98b6012614ff5565b8a606001516125fc565b8760800151612617565b9050613626816108cc61361c6136048b601d614ff5565b6108d16136128d6013614ff5565b8c606001516125fc565b8960800151612617565b905061364b816108cc61361c61363d8b601e614ff5565b6108d16136128d6014614ff5565b9050613670816108cc61361c6136628b601f614ff5565b6108d16136128d6015614ff5565b92505f90506136946135e361368689601c614ff5565b6108d16135d98b600e614ff5565b90506136b9816108cc61361c6136ab8b601d614ff5565b6108d16136128d600f614ff5565b90506136de816108cc61361c6136d08b601e614ff5565b6108d16136128d6010614ff5565b9050613703816108cc61361c6136f58b601f614ff5565b6108d16136128d6011614ff5565b91505f905061372a613724613719896020614ff5565b6108d18a601a614ff5565b846125fc565b905061375f816108ef6137596137418b6028614ff5565b6108d161374f8d601b614ff5565b8c60a001516125fc565b856125fc565b905061376b81856125fc565b6040860152505f61378e61375961378389601b614ff5565b6108cc8a6028614ff5565b9050808560035b602002015250505050505050565b5f5f6138016137e96137d16137bc61361c8a6016614ff5565b6108d16137ca8b6017614ff5565b8a516125fc565b6108d16137df8a6018614ff5565b89602001516125fc565b6108d16137f7896019614ff5565b88604001516125fc565b91505f61383861381f61381589601c614ff5565b8860800151612617565b6108d161382d8a6003614ff5565b6108cc8b6024614ff5565b90505f61386161384989601d614ff5565b6108d16138568b5f614ff5565b6108cc8c6025614ff5565b90505f61388b6138728a601e614ff5565b6108d16138808c6001614ff5565b6108cc8d6026614ff5565b90506138ca6138b26138a4856108d1868d5f01516125fc565b6108d1848c602001516125fc565b6108d16138c08c6004614ff5565b8b604001516125fc565b93505050505f6138de613724886021614ff5565b90505f6138ef613724896021614ff5565b90505f61392761390e6139038b6023614ff5565b6108d18c6006614ff5565b6108ef61391c8c6023614ff5565b6108cc8d6006614ff5565b90505f613945612b6961393a87896125fc565b6108cc8d6021614ff5565b905061395181886125fc565b90505f61397961396b6139658d6006614ff5565b876125fc565b6108ef6139658e6022614ff5565b90505f6139878c6023614ff5565b90505f613997612b6983846125fc565b60808c0185905260a08c0184905290506139b1818b6125fc565b8b6006602002015250505050505050505050505050565b5f6139d45f6001612630565b90505f6139e25f6002612630565b90505f6139f05f6003612630565b90505f613a0c613a0188601d614ff5565b6108ef89601c614ff5565b90505f613a28613a1d89601e614ff5565b6108ef8a601d614ff5565b90505f613a44613a398a601f614ff5565b6108ef8b601e614ff5565b90505f613a60613a558b6024614ff5565b6108ef8c601f614ff5565b905083613a71816108cc818b612617565b9050613a81816108cc878a612617565b9050613a91816108cc8789612617565b9050613aa2816108cc8d6008614ff5565b9050613aae818a6125fc565b60e08b01525082613ac3816108cc818b612617565b9050613ad3816108cc868a612617565b9050613ae3816108cc8689612617565b9050613af4816108cc8d6008614ff5565b9050613b00818a6125fc565b6101008b01525081613b16816108cc818b612617565b9050613b26816108cc858a612617565b9050613b36816108cc8589612617565b9050613b47816108cc8d6008614ff5565b9050613b53818a6125fc565b6101208b01525080613b69816108cc818b612617565b9050613b79816108cc848a612617565b9050613b89816108cc8489612617565b9050613b9a816108cc8d6008614ff5565b9050613ba6818a6125fc565b610140909a019990995250505050505050505050565b613bf56040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613c0084601d614ff5565b8152613c0d84601e614ff5565b6020820152613c1d846024614ff5565b6040820152613c2d846027614ff5565b6060820152613c3d846026614ff5565b6080820152613c4d846025614ff5565b60a08201525f613c5e856002614ff5565b90505f613c6b865f614ff5565b90505f613c7f8460400151855f0151612630565b90505f613c94856020015186602001516125fc565b606086015190915086905f90613caa90806125fc565b90505f613cc8613cc289602001518a606001516125fc565b886125fc565b90505f613ce7613ce08a60a001518b60400151612617565b8a51612617565b9050613cf661396582886125fc565b9050613d1d613d17613d11613d0b8487612630565b88612630565b84612617565b83612617565b9050613d45613d3a613d2f83876125fc565b6108cc8f6009614ff5565b6108cc60018a612630565b6101608c015250505050602085015160808601515f91613d6491612617565b90505f613d82613d788860600151886125fc565b8860200151612630565b90505f613da6613d9284876125fc565b6108d16137598b60a001518c5f0151612630565b9050613dce613dc3613db8838c6125fc565b6108cc8e6009614ff5565b6108cc600189612630565b6101808b0152505f9150613def9050613de8836011612617565b87516125fc565b90505f613dfc8384612617565b9050613e088182612617565b90505f613e168360096125fc565b9050613e3f613e39613724613e328b60a001518c5f0151612617565b8b51612617565b82612630565b60c089018190525f90613e5a90613cc290613d2f908d6125fc565b9050613e6d8b600b602002015182612617565b6101608c0152505086515f9250613e949150613de890613e8d9080612617565b8851612617565b90505f613ed4613eaf836108cc8a5f01518b60a00151612630565b60208901516108ef90613ec29080612617565b6108cc8b602001518c60800151612617565b9050613ef189600c60200201516108d1613cc2613d2f858d6125fc565b89600c602002015250505050505050505050565b613f6f604051806101e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613f87613f7d86601e614ff5565b85604001516125fc565b808252613fa6906108d1613f9c88601d614ff5565b87602001516125fc565b808252613fbb906108d1613de888601c614ff5565b808252613fcd906108d1876001614ff5565b80825260208201819052613fe6906108ef87601f614ff5565b8152614001613ff6866024614ff5565b6108ef87601c614ff5565b608082015261401f614014866027614ff5565b6108ef87601f614ff5565b60608201526080810151614038906108cc816001612630565b6101c082015260808101516140789061406e90614067906108cc60015f516020615c8f5f395f51905f526155e1565b6001612617565b82606001516125fc565b60a082018190526140ae906140a0906108cc614095896002614ff5565b6108cc8a6003614ff5565b6108cc61375988600a614ff5565b83600e60200201526101c08101516140d2906140a0906108cc614095896002614ff5565b6101e084015280516140f7906108cc6140ec886002614ff5565b6108cc896003614ff5565b6101208201525f61411661410c87601f614ff5565b8360200151612630565b9050614127816108cc836001612630565b60e083015261414461413a876026614ff5565b86604001516125fc565b60408301819052614167906108d161415d896025614ff5565b88602001516125fc565b60408301819052614187906108d1614180896024614ff5565b88516125fc565b60408301526141a461419a876027614ff5565b8360400151612630565b60408301525f6141c36141b8886026614ff5565b6108ef89601e614ff5565b90506142156141f0613472614067866080015160015f516020615c8f5f395f51905f526108cc91906155e1565b6108cc614067866040015160015f516020615c8f5f395f51905f526108cc91906155e1565b60c084015260408301516142379061422d90806125fc565b8460400151612630565b61010084015260c083015161426390614255906108cc8a6004614ff5565b6108cc6139658a600a614ff5565b6102008601526101c083015161428290614255906108cc8a6004614ff5565b6102208601526101008301516142a190614255906108cc8a6004614ff5565b61024086015260e08301516142bb906108cc896004614ff5565b6101408401526142da6142cf886025614ff5565b6108ef89601d614ff5565b6101608401526080830151614318906141b89061430d90614067906108cc60015f516020615c8f5f395f51905f526155e1565b8561016001516125fc565b61018084018190526101208401516101a0850181905261434f916108d1906108cc6143448c6005614ff5565b6108cc8d6002614ff5565b6101a08401819052835161436f91906108d1906108cc6143448c5f614ff5565b6101a084018190526101408401516143879190612617565b6101a084018190526143a1906108cc6139658a600a614ff5565b6101a0840181905285600d613795565b6143ea6040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61441f6144066143fb86601c614ff5565b6108cc876025614ff5565b6108d1614414876024614ff5565b6108cc88601d614ff5565b815261446461445961444061443587601c614ff5565b6108cc88601f614ff5565b6108d161444e88601d614ff5565b6108cc89601e614ff5565b6108ef866026614ff5565b6040820181905261447990600160441b6125fc565b6040820181905261448f906108ef866027614ff5565b6040820181905281516144a29190612617565b604082018190526144b8906108cc866005614ff5565b604082015280516144cd90600160441b6125fc565b8082526144ed906108d16144e2876024614ff5565b6108cc886025614ff5565b80825260208201819052614514906108ef61450987601e614ff5565b6108d188601f614ff5565b6020820181905261452a906108cc866004614ff5565b6020820152805160608201819052614547906108d186601f614ff5565b6060820181905261456b906108ef614560876026614ff5565b6108d1886027614ff5565b60608201819052614580906108cc865f614ff5565b8160600181815250505f6145a961459f83602001518460400151612617565b8360600151612617565b90506145ba816108cc876003614ff5565b90506145d26145ca866025614ff5565b6140006125fc565b608083018190526145e8906108d1876024614ff5565b608083018190526145fb906140006125fc565b60808301819052614611906108d187601e614ff5565b60808301819052614624906140006125fc565b6080830181905261463a906108d187601d614ff5565b6080830181905261464d906140006125fc565b60808301819052614663906108d187601c614ff5565b60808301819052614679906108ef87601f614ff5565b6080830181905261468f906108cc876005614ff5565b60808301526146a26145ca866026614ff5565b60a083018190526146b8906108d1876025614ff5565b60a083018190526146cb906140006125fc565b60a083018190526146e1906108d1876024614ff5565b60a083018190526146f4906140006125fc565b60a0830181905261470a906108d187601f614ff5565b60a0830181905261471d906140006125fc565b60a08301819052614733906108d187601e614ff5565b60a08301819052614749906108ef876027614ff5565b60a0830181905261475e906108cc875f614ff5565b60a0830181905260808301515f916147769190612617565b9050614787816108cc886004614ff5565b90506147938282612617565b60c084018190526147ac906108cc61396589600b614ff5565b60c084018190528560136020020152505050505050565b6148396040518061022001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61485261484785601c614ff5565b6108d1866002614ff5565b815261486d61486285601d614ff5565b6108d1866003614ff5565b602082015261488b61488085601e614ff5565b6108d1866004614ff5565b60408201526148a961489e85601f614ff5565b6108d1866005614ff5565b606082015280516148db906148d4906148cd906148c690806125fc565b84516125fc565b83516125fc565b82516125fc565b608082015260208101516149199061490f90614905906148fb90806125fc565b84602001516125fc565b83602001516125fc565b82602001516125fc565b60a082015260408101516149579061494d906149439061493990806125fc565b84604001516125fc565b83604001516125fc565b82604001516125fc565b60c0820152606081015161498b9061406e906149819061497790806125fc565b84606001516125fc565b83606001516125fc565b60e0820152608081015160a08201516149a49190612617565b61010082015260c081015160e08201516149be9190612617565b61012082015260a08101516149e2906149d79080612617565b826101200151612617565b61014082015260e0810151614a06906149fb9080612617565b826101000151612617565b610160820152610120810151614a1c9080612617565b6101e08201819052614a3d90614a329080612617565b826101600151612617565b6101e0820152610100810151614a539080612617565b6101a08201819052614a7490614a699080612617565b826101400151612617565b6101a08201819052610160820151614a8b91612617565b6101808201526101408101516101e0820151614aa79190612617565b6101c0820152614abb61347285600c614ff5565b6102008201819052610280840151610180830151614ae6926108d1916108cc906108ef8a6024614ff5565b8360146020020152614b1683601560200201516108d18361020001516108cc856101a001516108ef8a6025614ff5565b8360156020020152614b4683601660200201516108d18361020001516108cc856101c001516108ef8a6026614ff5565b8360166020020152614b7683601760200201516108d18361020001516108cc856101e001516108ef8a6027614ff5565b836017602002015250505050565b614bd66040518061016001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f6040518060800160405280614c0b7f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e76125e4565b8152602001614c397f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b6125e4565b8152602001614c667e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac156125e4565b8152602001614c947f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b6125e4565b90529050614cb1614ca686601c614ff5565b6108d1876002614ff5565b6101208301819052614cf090614ce590614cda90614ccf90806125fc565b8561012001516125fc565b8461012001516125fc565b8361012001516125fc565b8252614cfd85601d614ff5565b6020830152614d0d85601e614ff5565b6040830152614d1d85601f614ff5565b606083015281516020830151614d459161459f91614d3b9190612617565b8460400151612617565b6080830152614d5861372486600d614ff5565b6101408301528151614d7990614d6f90835f610bce565b8360800151612617565b60a0830152614da584601860200201516108d18461014001516108cc8660a001516108ef8b6024614ff5565b6103008501526020820151614dc090614d6f90836001610bce565b60c0830152614dec84601960200201516108d18461014001516108cc8660c001516108ef8b6025614ff5565b6103208501526040820151614e0790614d6f90836002610bce565b60e0830152614e3384601a60200201516108d18461014001516108cc8660e001516108ef8b6026614ff5565b6103408501526060820151614e4e90614d6f90836003610bce565b610100830152614e7c84601b60200201516108d18461014001516108cc8661010001516108ef8b6027614ff5565b84601b6135ab565b815160015b601c811015614ed657614ecc826108d18684601c8110614eab57614eab615b74565b602002015186614ebc6001876155e1565b601b8110610bce57610bce615b74565b9150600101614e89565b5092915050565b5f5f8390505f60405160208152602080820152602060408201528260608201528460808201525f516020615c8f5f395f51905f5260a082015260205f60c08360055afa80614f29575f5ffd5b505f5160809190910160405295945050505050565b614f46615321565b614f4e615321565b604051835181526020840151602082015284604082015260408160608360075afa80614f78575f5ffd5b5080518252602080820151908301526060016040529392505050565b614f9c615321565b614fa4615321565b6040518451815260208501516020820152835160408201526020840151606082015260408160808360065afa80614fd9575f5ffd5b5080518252602080820151908301526080016040529392505050565b5f8282602881111561500957615009615c5a565b6029811061501957615019615b74565b60200201519392505050565b604051806103e001604052805f81526020015f81526020015f815260200161504b615321565b8152602001615058615321565b8152602001615065615321565b8152602001615072615321565b815260200161507f615321565b815260200161508c615321565b8152602001615099615321565b81526020016150a6615321565b81526020016150b3615321565b81526020016150c0615321565b81526020016150cd615321565b81526020016150da615321565b81526020016150e7615321565b81526020016150f4615321565b8152602001615101615321565b815260200161510e615321565b815260200161511b615321565b8152602001615128615321565b8152602001615135615321565b8152602001615142615321565b815260200161514f615321565b815260200161515c615321565b8152602001615169615321565b8152602001615176615321565b8152602001615183615321565b8152602001615190615321565b815260200161519d615321565b81526020016151aa615321565b905290565b6040518061028001604052806151c36153ed565b81526020016151d0615321565b81526020016151dd615321565b81526020016151ea615321565b81526020016151f7615321565b8152602001615204615321565b8152602001615211615321565b815260200161521e615321565b815260200161522b615321565b8152602001615238615321565b815260200161524561540c565b81526020015f8152602001615258615439565b81526020015f815260200161526b615467565b8152602001615278615486565b815260200161528561536b565b81526020016151906154b4565b6040518061052001604052806029906020820280368337509192915050565b604051806101c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020016152ef6154b4565b81526020016152fc6154b4565b81526020015f81526020015f81526020015f81526020015f8152602001606081525090565b60405180604001604052805f81526020015f81525090565b604051806040016040528061519d615321565b6040518061012001604052806009906020820280368337509192915050565b604051806103800160405280601c906020820280368337509192915050565b6040518060e0016040528061539d6154d2565b81526020015f81526020015f81526020015f81526020015f81526020016153c26154d2565b81526020015f81525090565b6040518061010001604052806008906020820280368337509192915050565b6040518061020001604052806010906020820280368337509192915050565b60405180606001604052806003905b615423615321565b81526020019060019003908161541b5790505090565b604051806103800160405280601c905b61545161534c565b8152602001906001900390816154495790505090565b604051806105400160405280602a906020820280368337509192915050565b604051806103600160405280601b905b61549e615321565b8152602001906001900390816154965790505090565b60405180608001604052806004906020820280368337509192915050565b604051806120000160405280610100906020820280368337509192915050565b5f5f5f5f60408587031215615505575f5ffd5b84356001600160401b0381111561551a575f5ffd5b8501601f8101871361552a575f5ffd5b80356001600160401b0381111561553f575f5ffd5b876020828401011115615550575f5ffd5b6020918201955093508501356001600160401b0381111561556f575f5ffd5b8501601f8101871361557f575f5ffd5b80356001600160401b03811115615594575f5ffd5b8760208260051b84010111156155a8575f5ffd5b949793965060200194505050565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417612611576126116155b6565b81810381811115612611576126116155b6565b805f5b60108110156131e25781518452602093840193909101906001016155f7565b805f5b60038110156131e25761563784835180518252602090810151910152565b6040939093019260209190910190600101615619565b805f5b601c8110156131e2578151845f5b600981101561567d57825182526020928301929091019060010161565e565b505050610120939093019260209190910190600101615650565b805f5b602a8110156131e257815184526020938401939091019060010161569a565b805f5b601b8110156131e2576156da84835180518252602090810151910152565b60409390930192602091909101906001016156bc565b805f5b601c8110156131e25781518452602093840193909101906001016156f3565b805f5b60048110156131e2578151845260209384019390910190600101615715565b8183525f6001600160fb1b0383111561574b575f5ffd5b8260051b80836020870137939093016020019392505050565b61576f8188516155f4565b5f602088015161578d61020084018280518252602090810151910152565b5060408801518051610240840152602090810151610260840152606089015180516102808501528101516102a0840152608089015180516102c08501528101516102e084015260a0890151805161030085015281015161032084015260c0890151805161034085015281015161036084015260e089015180516103808501528101516103a084015261010089015180516103c08501528101516103e084015261012089015180516104008501520151610420830152610140880151615856610440840182615616565b5061016088015161050083015261018088015161587761052084018261564d565b506101a08801516124a08301526101c08801516158986124c0840182615697565b506101e08801516158ad612a008401826156b9565b506102008801516158c26130c08401826156f0565b506102208801516158d7613440840182615712565b5061024088015180516134c08401526020908101516134e0840152610260890151805161350085015201516135208301526135c061354083018190526159209083018789615734565b613560830195909552506135808101929092526135a0909101529392505050565b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b038111828210171561597857615978615941565b60405290565b604051601f8201601f191681016001600160401b03811182821017156159a6576159a6615941565b604052919050565b5f60c082840312156159be575f5ffd5b60405160c081016001600160401b03811182821017156159e0576159e0615941565b604090815283518252602080850151908301528381015190820152606080840151908201526080808401519082015260a0928301519281019290925250919050565b5f82601f830112615a31575f5ffd5b5f610360615a3e8161597e565b915083018185821115615a4f575f5ffd5b845b82811015615a69578051825260209182019101615a51565b509195945050505050565b5f82601f830112615a83575f5ffd5b5f610380615a3e8161597e565b5f610be0828403128015615aa2575f5ffd5b50615aab615955565b615ab584846159ae565b8152615ac48460c08501615a22565b6020820152615ad7846104208501615a74565b60408201526107a08301516060820152615af5846107c08501615a74565b6080820152610b4083015160a0820152610b6083015160c0820152610b8083015160e0820152610ba0830151610100820152610bc09092015161012083015250919050565b80820180821115612611576126116155b6565b5f5f85851115615b5b575f5ffd5b83861115615b67575f5ffd5b5050820193919092039150565b634e487b7160e01b5f52603260045260245ffd5b5f60018201615b9957615b996155b6565b5060010190565b80356020831015612611575f19602084900360031b1b1692915050565b5f82615bd757634e487b7160e01b5f52601260045260245ffd5b500690565b5f81615bea57615bea6155b6565b505f190190565b5f8183825b6008811015615c15578151835260209283019290910190600101615bf6565b5050506101008201905092915050565b5f82518060208501845e5f920191825250919050565b5f60208284031215615c4b575f5ffd5b815180151581146103f4575f5ffd5b634e487b7160e01b5f52602160045260245ffdfe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4730644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a164736f6c634300081c000a", - "linkReferences": { - "project/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol": { - "ZKTranscriptLib": [ - { - "length": 20, - "start": 690 - } - ] - } - }, - "deployedLinkReferences": { - "project/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol": { - "ZKTranscriptLib": [ - { - "length": 20, - "start": 360 - } - ] - } - }, - "immutableReferences": { - "45189": [ - { - "length": 32, - "start": 91 - }, - { - "length": 32, - "start": 148 - }, - { - "length": 32, - "start": 257 - }, - { - "length": 32, - "start": 466 - }, - { - "length": 32, - "start": 2605 - }, - { - "length": 32, - "start": 2958 - }, - { - "length": 32, - "start": 3115 - }, - { - "length": 32, - "start": 5411 - }, - { - "length": 32, - "start": 5597 - }, - { - "length": 32, - "start": 5648 - }, - { - "length": 32, - "start": 6170 - }, - { - "length": 32, - "start": 11168 - } - ], - "45191": [ - { - "length": 32, - "start": 398 - } - ], - "45193": [ - { - "length": 32, - "start": 432 - }, - { - "length": 32, - "start": 2303 - } - ], - "45195": [ - { - "length": 32, - "start": 3156 - }, - { - "length": 32, - "start": 3257 - }, - { - "length": 32, - "start": 11971 - } - ] - }, - "inputSourceName": "project/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol", - "buildInfoId": "solc-0_8_28-bd46eae6f77be9a8538850385226c1ee4fc57e42" -} \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol/ZKTranscriptLib.json b/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol/ZKTranscriptLib.json deleted file mode 100644 index d222bdae21..0000000000 --- a/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol/ZKTranscriptLib.json +++ /dev/null @@ -1,395 +0,0 @@ -{ - "_format": "hh3-artifact-1", - "contractName": "ZKTranscriptLib", - "sourceName": "contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol", - "abi": [ - { - "inputs": [ - { - "components": [ - { - "internalType": "Fr[16]", - "name": "pairingPointObject", - "type": "uint256[16]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "geminiMaskingPoly", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "w1", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "w2", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "w3", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "w4", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "lookupReadCounts", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "lookupReadTags", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "lookupInverses", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "zPerm", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point[3]", - "name": "libraCommitments", - "type": "tuple[3]" - }, - { - "internalType": "Fr", - "name": "libraSum", - "type": "uint256" - }, - { - "internalType": "Fr[9][28]", - "name": "sumcheckUnivariates", - "type": "uint256[9][28]" - }, - { - "internalType": "Fr", - "name": "libraEvaluation", - "type": "uint256" - }, - { - "internalType": "Fr[42]", - "name": "sumcheckEvaluations", - "type": "uint256[42]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point[27]", - "name": "geminiFoldComms", - "type": "tuple[27]" - }, - { - "internalType": "Fr[28]", - "name": "geminiAEvaluations", - "type": "uint256[28]" - }, - { - "internalType": "Fr[4]", - "name": "libraPolyEvals", - "type": "uint256[4]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "shplonkQ", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "y", - "type": "uint256" - } - ], - "internalType": "struct Honk.G1Point", - "name": "kzgQuotient", - "type": "tuple" - } - ], - "internalType": "struct Honk.ZKProof", - "name": "proof", - "type": "tuple" - }, - { - "internalType": "bytes32[]", - "name": "publicInputs", - "type": "bytes32[]" - }, - { - "internalType": "uint256", - "name": "vkHash", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "publicInputsSize", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "logN", - "type": "uint256" - } - ], - "name": "generateTranscript", - "outputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "Fr", - "name": "eta", - "type": "uint256" - }, - { - "internalType": "Fr", - "name": "etaTwo", - "type": "uint256" - }, - { - "internalType": "Fr", - "name": "etaThree", - "type": "uint256" - }, - { - "internalType": "Fr", - "name": "beta", - "type": "uint256" - }, - { - "internalType": "Fr", - "name": "gamma", - "type": "uint256" - }, - { - "internalType": "Fr", - "name": "publicInputsDelta", - "type": "uint256" - } - ], - "internalType": "struct Honk.RelationParameters", - "name": "relationParameters", - "type": "tuple" - }, - { - "internalType": "Fr[27]", - "name": "alphas", - "type": "uint256[27]" - }, - { - "internalType": "Fr[28]", - "name": "gateChallenges", - "type": "uint256[28]" - }, - { - "internalType": "Fr", - "name": "libraChallenge", - "type": "uint256" - }, - { - "internalType": "Fr[28]", - "name": "sumCheckUChallenges", - "type": "uint256[28]" - }, - { - "internalType": "Fr", - "name": "rho", - "type": "uint256" - }, - { - "internalType": "Fr", - "name": "geminiR", - "type": "uint256" - }, - { - "internalType": "Fr", - "name": "shplonkNu", - "type": "uint256" - }, - { - "internalType": "Fr", - "name": "shplonkZ", - "type": "uint256" - }, - { - "internalType": "Fr", - "name": "publicInputsDelta", - "type": "uint256" - } - ], - "internalType": "struct ZKTranscript", - "name": "t", - "type": "tuple" - } - ], - "stateMutability": "pure", - "type": "function" - } - ], - "bytecode": "0x6116f3610034600b8282823980515f1a607314602857634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c8063995bf45714610038575b5f5ffd5b61004b610046366004611214565b610061565b604051610058919061144a565b60405180910390f35b610069610d76565b5f610078888888888886610128565b9083529050610087818961017c565b6020840191909152905061009b818461026c565b604084019190915290506100af8189610315565b606084019190915290506100c4888285610376565b608084019190915290506100d88882610445565b60a084019190915290506100ed8882856105cb565b60c0840191909152905061010288828561073d565b60e0840191909152905061011688826108bf565b50610100830152509695505050505050565b610130610ddb565b5f61013e88888888886108fc565b60408601919091526020850191909152908352925061015d8389610c6a565b6080850191909152606084019190915291989197509095505050505050565b610184610e0b565b5f61018d610e2a565b8481526101008401805151602080840191909152905181015160408084019190915261012086018051516060850152518201516080840152516101f1916101d69184910161151f565b60405160208183030381529060405280519060200120610cf2565b91505f6101fd83610d18565b50808552905060015b6102126001601c611566565b8110156102625761024385610228600184611566565b601b81106102385761023861150b565b602002015183610d48565b8582601b81106102555761025561150b565b6020020152600101610206565b5050509250929050565b610274610e48565b5f61028b846040516020016101d691815260200190565b935061029684610d18565b50825260015b8381101561030d576102ee836102b3600184611566565b601c81106102c3576102c361150b565b6020020151846102d4600185611566565b601c81106102e4576102e461150b565b6020020151610d48565b8382601c81106103005761030061150b565b602002015260010161029c565b509093915050565b5f5f61031f610e67565b84815261014084018051515160208084019190915290515181015160408084019190915261016086015160608401525161035f916101d691849101611579565b915061036a82610d18565b50959194509092505050565b61037e610e48565b5f805b8381101561043b57610391610e85565b8581525f5b60098110156103fa5787610180015183601c81106103b6576103b661150b565b602002015181600981106103cc576103cc61150b565b6020020151826103dd8360016115ac565b600a81106103ed576103ed61150b565b6020020152600101610396565b5061040f816040516020016101d691906115bf565b955061041a86610d18565b508483601c811061042d5761042d61150b565b602002015250600101610381565b5090949293505050565b5f5f61044f610ea4565b83815260015b610461600160296115ac565b81116104b6576101c0860151610478600183611566565b602a81106104885761048861150b565b602002015182826030811061049f5761049f61150b565b6020020152806104ae816115f3565b915050610455565b856101a001518282603081106104ce576104ce61150b565b60200201526104de6001826115ac565b61014087015160200151519091508282603081106104fe576104fe61150b565b602002015261014086015160016020020151602001518282600161052291906115ac565b603081106105325761053261150b565b60200201526105426002826115ac565b61014087015160400151519091508282603081106105625761056261150b565b602002015261014086015160026020020151602001518282600161058691906115ac565b603081106105965761059661150b565b6020020181815250506105b3826040516020016101d6919061160b565b92506105be83610d18565b5096929550919350505050565b5f80806105d9600185611566565b6105e490600261163f565b6105ef9060016115ac565b6001600160401b0381111561060657610606610eff565b60405190808252806020026020018201604052801561062f578160200160208202803683370190505b50905084815f815181106106455761064561150b565b60209081029190910101525f5b61065d600186611566565b81101561071057866101e0015181601b811061067b5761067b61150b565b6020020151518261068d83600261163f565b6106989060016115ac565b815181106106a8576106a861150b565b602002602001018181525050866101e0015181601b81106106cb576106cb61150b565b602002015160200151828260026106e2919061163f565b6106ed9060026115ac565b815181106106fd576106fd61150b565b6020908102919091010152600101610652565b50610725816040516020016101d69190611656565b915061073082610d18565b5096919550909350505050565b5f808061074b8460016115ac565b6107569060046115ac565b6001600160401b0381111561076d5761076d610eff565b604051908082528060200260200182016040528015610796578160200160208202803683370190505b50905084815f815181106107ac576107ac61150b565b602090810291909101015260015b848111610816576102008701516107d2600183611566565b601c81106107e2576107e261150b565b60200201518282815181106107f9576107f961150b565b60209081029190910101528061080e816115f3565b9150506107ba565b505f806108248660016115ac565b90505b6108328660046115ac565b811161089157876102200151826004811061084f5761084f61150b565b60200201518382815181106108665761086661150b565b60209081029190910101528161087b816115f3565b9250508080610889906115f3565b915050610827565b506108a6826040516020016101d69190611656565b92506108b183610d18565b509792965091945050505050565b5f5f6108c9610ec3565b838152610240850180515160208084019190915290518101516040808401919091525161035f916101d691849101611680565b5f8080808061090c8660016115ac565b6109179060086115ac565b6001600160401b0381111561092e5761092e610eff565b604051908082528060200260200182016040528015610957578160200160208202803683370190505b509050865f1b815f8151811061096f5761096f61150b565b60209081029190910101525f5b610987601088611566565b8110156109d8578989828181106109a0576109a061150b565b90506020020135828260016109b591906115ac565b815181106109c5576109c561150b565b602090810291909101015260010161097c565b505f5b6010811015610a49578a51610a039082601081106109fb576109fb61150b565b602002015190565b82826010610a128b60016115ac565b610a1c9190611566565b610a2691906115ac565b81518110610a3657610a3661150b565b60209081029190910101526001016109db565b5060208a01515181610a5c8860016115ac565b81518110610a6c57610a6c61150b565b6020908102919091018101919091528a810151015181610a8d8860016115ac565b610a989060016115ac565b81518110610aa857610aa861150b565b602090810291909101015260408a01515181610ac58860016115ac565b610ad09060026115ac565b81518110610ae057610ae061150b565b60209081029190910181019190915260408b0151015181610b028860016115ac565b610b0d9060036115ac565b81518110610b1d57610b1d61150b565b602090810291909101015260608a01515181610b3a8860016115ac565b610b459060046115ac565b81518110610b5557610b5561150b565b60209081029190910181019190915260608b0151015181610b778860016115ac565b610b829060056115ac565b81518110610b9257610b9261150b565b602090810291909101015260808a01515181610baf8860016115ac565b610bba9060066115ac565b81518110610bca57610bca61150b565b60209081029190910181019190915260808b0151015181610bec8860016115ac565b610bf79060076115ac565b81518110610c0757610c0761150b565b602002602001018181525050610c27816040516020016101d69190611656565b9150610c3282610d18565b6040805160208101869052929750909550610c4d91016101d6565b9150610c5882610d18565b50809350505095509550955095915050565b5f5f5f610c75610ee1565b85815260c0858101805151602080850191909152905181015160408085019190915260e08801805151606086015251820151608085015260a08089018051519186019190915251820151928401929092529051610cd8916101d6918491016116b3565b9150610ce382610d18565b90979096509194509092505050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001900690565b5f808260016001607f1b038116607f82901c610d3382610cf2565b9450610d3e81610cf2565b9350505050915091565b5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182840990505b92915050565b604051806101400160405280610d8a610ddb565b8152602001610d97610e0b565b8152602001610da4610e48565b81526020015f8152602001610db7610e48565b81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b604051806103600160405280601b906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b604051806103800160405280601c906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b604051806101400160405280600a906020820280368337509192915050565b6040518061060001604052806030906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b6040518060e001604052806007906020820280368337509192915050565b634e487b7160e01b5f52604160045260245ffd5b60405161028081016001600160401b0381118282101715610f3657610f36610eff565b60405290565b604051601f8201601f191681016001600160401b0381118282101715610f6457610f64610eff565b604052919050565b5f82601f830112610f7b575f5ffd5b5f610200610f8881610f3c565b915083018185821115610f99575f5ffd5b845b82811015610fb3578035825260209182019101610f9b565b509195945050505050565b5f60408284031215610fce575f5ffd5b604080519081016001600160401b0381118282101715610ff057610ff0610eff565b604052823581526020928301359281019290925250919050565b5f82601f830112611019575f5ffd5b5f6110246060610f3c565b90508060c0840185811115611037575f5ffd5b845b81811015610fb35761104b8782610fbe565b8352602090920191604001611039565b5f82601f83011261106a575f5ffd5b61038061107681610f3c565b905080611f8084018581111561108a575f5ffd5b845b818110156110ee5786601f8201126110a2575f5ffd5b5f6101206110af81610f3c565b9150820181898211156110c0575f5ffd5b835b828110156110da5780358252602091820191016110c2565b50505084526020909301926101200161108c565b509095945050505050565b5f82601f830112611108575f5ffd5b5f610540610f8881610f3c565b5f82601f830112611124575f5ffd5b5f61036061113181610f3c565b915050806106c0840185811115611146575f5ffd5b845b81811015610fb35761115a8782610fbe565b8352602090920191604001611148565b5f82601f830112611179575f5ffd5b5f610380610f8881610f3c565b5f82601f830112611195575f5ffd5b5f6111a06080610f3c565b90508060808401858111156111b3575f5ffd5b845b81811015610fb35780358352602092830192016111b5565b5f5f83601f8401126111dd575f5ffd5b5081356001600160401b038111156111f3575f5ffd5b6020830191508360208260051b850101111561120d575f5ffd5b9250929050565b5f5f5f5f5f5f8688036135c081121561122b575f5ffd5b613540811215611239575f5ffd5b50611242610f13565b61124c8989610f6c565b815261125c896102008a01610fbe565b602082015261126f896102408a01610fbe565b6040820152611282896102808a01610fbe565b6060820152611295896102c08a01610fbe565b60808201526112a8896103008a01610fbe565b60a08201526112bb896103408a01610fbe565b60c08201526112ce896103808a01610fbe565b60e08201526112e1896103c08a01610fbe565b6101008201526112f5896104008a01610fbe565b610120820152611309896104408a0161100a565b610140820152610500880135610160820152611329896105208a0161105b565b6101808201526124a08801356101a0820152611349896124c08a016110f9565b6101c082015261135d89612a008a01611115565b6101e0820152611371896130c08a0161116a565b610200820152611385896134408a01611186565b610220820152611399896134c08a01610fbe565b6102408201526113ad896135008a01610fbe565b61026082015295506135408701356001600160401b038111156113ce575f5ffd5b6113da89828a016111cd565b979a90995096976135608101359761358082013597506135a09091013595509350505050565b805f5b601b811015611422578151845260209384019390910190600101611403565b50505050565b805f5b601c81101561142257815184526020938401939091019060010161142b565b8151805182526020808201519083015260408082015190830152606080820151908301526080808201519083015260a09081015190820152610be08101602083015161149960c0840182611400565b5060408301516114ad610420840182611428565b5060608301516107a083015260808301516114cc6107c0840182611428565b5060a0830151610b4083015260c0830151610b6083015260e0830151610b80830152610100830151610ba083015261012090920151610bc09091015290565b634e487b7160e01b5f52603260045260245ffd5b5f8183825b6005811015611543578151835260209283019290910190600101611524565b50505060a08201905092915050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610d7057610d70611552565b5f8183825b600481101561159d57815183526020928301929091019060010161157e565b50505060808201905092915050565b80820180821115610d7057610d70611552565b5f8183825b600a8110156115e35781518352602092830192909101906001016115c4565b5050506101408201905092915050565b5f6001820161160457611604611552565b5060010190565b5f8183825b603081101561162f578151835260209283019290910190600101611610565b5050506106008201905092915050565b8082028115828204841417610d7057610d70611552565b81515f90829060208501835b82811015610fb3578151845260209384019390910190600101611662565b5f8183825b60038110156116a4578151835260209283019290910190600101611685565b50505060608201905092915050565b5f8183825b60078110156116d75781518352602092830192909101906001016116b8565b50505060e0820190509291505056fea164736f6c634300081c000a", - "deployedBytecode": "0x7300000000000000000000000000000000000000003014608060405260043610610034575f3560e01c8063995bf45714610038575b5f5ffd5b61004b610046366004611214565b610061565b604051610058919061144a565b60405180910390f35b610069610d76565b5f610078888888888886610128565b9083529050610087818961017c565b6020840191909152905061009b818461026c565b604084019190915290506100af8189610315565b606084019190915290506100c4888285610376565b608084019190915290506100d88882610445565b60a084019190915290506100ed8882856105cb565b60c0840191909152905061010288828561073d565b60e0840191909152905061011688826108bf565b50610100830152509695505050505050565b610130610ddb565b5f61013e88888888886108fc565b60408601919091526020850191909152908352925061015d8389610c6a565b6080850191909152606084019190915291989197509095505050505050565b610184610e0b565b5f61018d610e2a565b8481526101008401805151602080840191909152905181015160408084019190915261012086018051516060850152518201516080840152516101f1916101d69184910161151f565b60405160208183030381529060405280519060200120610cf2565b91505f6101fd83610d18565b50808552905060015b6102126001601c611566565b8110156102625761024385610228600184611566565b601b81106102385761023861150b565b602002015183610d48565b8582601b81106102555761025561150b565b6020020152600101610206565b5050509250929050565b610274610e48565b5f61028b846040516020016101d691815260200190565b935061029684610d18565b50825260015b8381101561030d576102ee836102b3600184611566565b601c81106102c3576102c361150b565b6020020151846102d4600185611566565b601c81106102e4576102e461150b565b6020020151610d48565b8382601c81106103005761030061150b565b602002015260010161029c565b509093915050565b5f5f61031f610e67565b84815261014084018051515160208084019190915290515181015160408084019190915261016086015160608401525161035f916101d691849101611579565b915061036a82610d18565b50959194509092505050565b61037e610e48565b5f805b8381101561043b57610391610e85565b8581525f5b60098110156103fa5787610180015183601c81106103b6576103b661150b565b602002015181600981106103cc576103cc61150b565b6020020151826103dd8360016115ac565b600a81106103ed576103ed61150b565b6020020152600101610396565b5061040f816040516020016101d691906115bf565b955061041a86610d18565b508483601c811061042d5761042d61150b565b602002015250600101610381565b5090949293505050565b5f5f61044f610ea4565b83815260015b610461600160296115ac565b81116104b6576101c0860151610478600183611566565b602a81106104885761048861150b565b602002015182826030811061049f5761049f61150b565b6020020152806104ae816115f3565b915050610455565b856101a001518282603081106104ce576104ce61150b565b60200201526104de6001826115ac565b61014087015160200151519091508282603081106104fe576104fe61150b565b602002015261014086015160016020020151602001518282600161052291906115ac565b603081106105325761053261150b565b60200201526105426002826115ac565b61014087015160400151519091508282603081106105625761056261150b565b602002015261014086015160026020020151602001518282600161058691906115ac565b603081106105965761059661150b565b6020020181815250506105b3826040516020016101d6919061160b565b92506105be83610d18565b5096929550919350505050565b5f80806105d9600185611566565b6105e490600261163f565b6105ef9060016115ac565b6001600160401b0381111561060657610606610eff565b60405190808252806020026020018201604052801561062f578160200160208202803683370190505b50905084815f815181106106455761064561150b565b60209081029190910101525f5b61065d600186611566565b81101561071057866101e0015181601b811061067b5761067b61150b565b6020020151518261068d83600261163f565b6106989060016115ac565b815181106106a8576106a861150b565b602002602001018181525050866101e0015181601b81106106cb576106cb61150b565b602002015160200151828260026106e2919061163f565b6106ed9060026115ac565b815181106106fd576106fd61150b565b6020908102919091010152600101610652565b50610725816040516020016101d69190611656565b915061073082610d18565b5096919550909350505050565b5f808061074b8460016115ac565b6107569060046115ac565b6001600160401b0381111561076d5761076d610eff565b604051908082528060200260200182016040528015610796578160200160208202803683370190505b50905084815f815181106107ac576107ac61150b565b602090810291909101015260015b848111610816576102008701516107d2600183611566565b601c81106107e2576107e261150b565b60200201518282815181106107f9576107f961150b565b60209081029190910101528061080e816115f3565b9150506107ba565b505f806108248660016115ac565b90505b6108328660046115ac565b811161089157876102200151826004811061084f5761084f61150b565b60200201518382815181106108665761086661150b565b60209081029190910101528161087b816115f3565b9250508080610889906115f3565b915050610827565b506108a6826040516020016101d69190611656565b92506108b183610d18565b509792965091945050505050565b5f5f6108c9610ec3565b838152610240850180515160208084019190915290518101516040808401919091525161035f916101d691849101611680565b5f8080808061090c8660016115ac565b6109179060086115ac565b6001600160401b0381111561092e5761092e610eff565b604051908082528060200260200182016040528015610957578160200160208202803683370190505b509050865f1b815f8151811061096f5761096f61150b565b60209081029190910101525f5b610987601088611566565b8110156109d8578989828181106109a0576109a061150b565b90506020020135828260016109b591906115ac565b815181106109c5576109c561150b565b602090810291909101015260010161097c565b505f5b6010811015610a49578a51610a039082601081106109fb576109fb61150b565b602002015190565b82826010610a128b60016115ac565b610a1c9190611566565b610a2691906115ac565b81518110610a3657610a3661150b565b60209081029190910101526001016109db565b5060208a01515181610a5c8860016115ac565b81518110610a6c57610a6c61150b565b6020908102919091018101919091528a810151015181610a8d8860016115ac565b610a989060016115ac565b81518110610aa857610aa861150b565b602090810291909101015260408a01515181610ac58860016115ac565b610ad09060026115ac565b81518110610ae057610ae061150b565b60209081029190910181019190915260408b0151015181610b028860016115ac565b610b0d9060036115ac565b81518110610b1d57610b1d61150b565b602090810291909101015260608a01515181610b3a8860016115ac565b610b459060046115ac565b81518110610b5557610b5561150b565b60209081029190910181019190915260608b0151015181610b778860016115ac565b610b829060056115ac565b81518110610b9257610b9261150b565b602090810291909101015260808a01515181610baf8860016115ac565b610bba9060066115ac565b81518110610bca57610bca61150b565b60209081029190910181019190915260808b0151015181610bec8860016115ac565b610bf79060076115ac565b81518110610c0757610c0761150b565b602002602001018181525050610c27816040516020016101d69190611656565b9150610c3282610d18565b6040805160208101869052929750909550610c4d91016101d6565b9150610c5882610d18565b50809350505095509550955095915050565b5f5f5f610c75610ee1565b85815260c0858101805151602080850191909152905181015160408085019190915260e08801805151606086015251820151608085015260a08089018051519186019190915251820151928401929092529051610cd8916101d6918491016116b3565b9150610ce382610d18565b90979096509194509092505050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001900690565b5f808260016001607f1b038116607f82901c610d3382610cf2565b9450610d3e81610cf2565b9350505050915091565b5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182840990505b92915050565b604051806101400160405280610d8a610ddb565b8152602001610d97610e0b565b8152602001610da4610e48565b81526020015f8152602001610db7610e48565b81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b604051806103600160405280601b906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b604051806103800160405280601c906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b604051806101400160405280600a906020820280368337509192915050565b6040518061060001604052806030906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b6040518060e001604052806007906020820280368337509192915050565b634e487b7160e01b5f52604160045260245ffd5b60405161028081016001600160401b0381118282101715610f3657610f36610eff565b60405290565b604051601f8201601f191681016001600160401b0381118282101715610f6457610f64610eff565b604052919050565b5f82601f830112610f7b575f5ffd5b5f610200610f8881610f3c565b915083018185821115610f99575f5ffd5b845b82811015610fb3578035825260209182019101610f9b565b509195945050505050565b5f60408284031215610fce575f5ffd5b604080519081016001600160401b0381118282101715610ff057610ff0610eff565b604052823581526020928301359281019290925250919050565b5f82601f830112611019575f5ffd5b5f6110246060610f3c565b90508060c0840185811115611037575f5ffd5b845b81811015610fb35761104b8782610fbe565b8352602090920191604001611039565b5f82601f83011261106a575f5ffd5b61038061107681610f3c565b905080611f8084018581111561108a575f5ffd5b845b818110156110ee5786601f8201126110a2575f5ffd5b5f6101206110af81610f3c565b9150820181898211156110c0575f5ffd5b835b828110156110da5780358252602091820191016110c2565b50505084526020909301926101200161108c565b509095945050505050565b5f82601f830112611108575f5ffd5b5f610540610f8881610f3c565b5f82601f830112611124575f5ffd5b5f61036061113181610f3c565b915050806106c0840185811115611146575f5ffd5b845b81811015610fb35761115a8782610fbe565b8352602090920191604001611148565b5f82601f830112611179575f5ffd5b5f610380610f8881610f3c565b5f82601f830112611195575f5ffd5b5f6111a06080610f3c565b90508060808401858111156111b3575f5ffd5b845b81811015610fb35780358352602092830192016111b5565b5f5f83601f8401126111dd575f5ffd5b5081356001600160401b038111156111f3575f5ffd5b6020830191508360208260051b850101111561120d575f5ffd5b9250929050565b5f5f5f5f5f5f8688036135c081121561122b575f5ffd5b613540811215611239575f5ffd5b50611242610f13565b61124c8989610f6c565b815261125c896102008a01610fbe565b602082015261126f896102408a01610fbe565b6040820152611282896102808a01610fbe565b6060820152611295896102c08a01610fbe565b60808201526112a8896103008a01610fbe565b60a08201526112bb896103408a01610fbe565b60c08201526112ce896103808a01610fbe565b60e08201526112e1896103c08a01610fbe565b6101008201526112f5896104008a01610fbe565b610120820152611309896104408a0161100a565b610140820152610500880135610160820152611329896105208a0161105b565b6101808201526124a08801356101a0820152611349896124c08a016110f9565b6101c082015261135d89612a008a01611115565b6101e0820152611371896130c08a0161116a565b610200820152611385896134408a01611186565b610220820152611399896134c08a01610fbe565b6102408201526113ad896135008a01610fbe565b61026082015295506135408701356001600160401b038111156113ce575f5ffd5b6113da89828a016111cd565b979a90995096976135608101359761358082013597506135a09091013595509350505050565b805f5b601b811015611422578151845260209384019390910190600101611403565b50505050565b805f5b601c81101561142257815184526020938401939091019060010161142b565b8151805182526020808201519083015260408082015190830152606080820151908301526080808201519083015260a09081015190820152610be08101602083015161149960c0840182611400565b5060408301516114ad610420840182611428565b5060608301516107a083015260808301516114cc6107c0840182611428565b5060a0830151610b4083015260c0830151610b6083015260e0830151610b80830152610100830151610ba083015261012090920151610bc09091015290565b634e487b7160e01b5f52603260045260245ffd5b5f8183825b6005811015611543578151835260209283019290910190600101611524565b50505060a08201905092915050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610d7057610d70611552565b5f8183825b600481101561159d57815183526020928301929091019060010161157e565b50505060808201905092915050565b80820180821115610d7057610d70611552565b5f8183825b600a8110156115e35781518352602092830192909101906001016115c4565b5050506101408201905092915050565b5f6001820161160457611604611552565b5060010190565b5f8183825b603081101561162f578151835260209283019290910190600101611610565b5050506106008201905092915050565b8082028115828204841417610d7057610d70611552565b81515f90829060208501835b82811015610fb3578151845260209384019390910190600101611662565b5f8183825b60038110156116a4578151835260209283019290910190600101611685565b50505060608201905092915050565b5f8183825b60078110156116d75781518352602092830192909101906001016116b8565b50505060e0820190509291505056fea164736f6c634300081c000a", - "linkReferences": {}, - "deployedLinkReferences": {}, - "immutableReferences": {}, - "inputSourceName": "project/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol", - "buildInfoId": "solc-0_8_28-bd46eae6f77be9a8538850385226c1ee4fc57e42" -} \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol/ThresholdDecryptedSharesAggregationModVerifier.json b/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol/ThresholdDecryptedSharesAggregationVerifier.json similarity index 91% rename from packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol/ThresholdDecryptedSharesAggregationModVerifier.json rename to packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol/ThresholdDecryptedSharesAggregationVerifier.json index 31f8f7e917..f18f207a1a 100644 --- a/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol/ThresholdDecryptedSharesAggregationModVerifier.json +++ b/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol/ThresholdDecryptedSharesAggregationVerifier.json @@ -1,7 +1,7 @@ { "_format": "hh3-artifact-1", - "contractName": "ThresholdDecryptedSharesAggregationModVerifier", - "sourceName": "contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol", + "contractName": "ThresholdDecryptedSharesAggregationVerifier", + "sourceName": "contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol", "abi": [ { "inputs": [], @@ -79,10 +79,10 @@ "type": "function" } ], - "bytecode": "0x610120604052348015610010575f5ffd5b50620200006080819052601160a08190527f0772b20ab0892c5f70111dd5e3e9737a04e02129d3f48fbd7a1079f68d41c3de60c081905261024360e081905260038361005e6001602461008b565b610068919061008b565b610072919061008b565b61007d90600261008b565b61010052506100b092505050565b808201808211156100aa57634e487b7160e01b5f52601160045260245ffd5b92915050565b60805160a05160c05160e05161010051615cba61014a5f395f8181610c5401528181610cb90152612ec201525f81816101b001526108ff01525f61018e01525f8181605b01528181609401528181610101015281816101d201528181610a2d01528181610b8e01528181610c2b01528181611523015281816115dd015281816116100152818161181a0152612b9f01525f5050615cba5ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063ea50d0e41461002d575b5f5ffd5b61004061003b3660046154f1565b610054565b604051901515815260200160405180910390f35b5f5f61007f7f00000000000000000000000000000000000000000000000000000000000000006102ee565b905061008c8160206155c9565b85146100ee577f0000000000000000000000000000000000000000000000000000000000000000856100bf8360206155c9565b6040516359895a5360e01b81526004810193909352602483019190915260448201526064015b60405180910390fd5b5f6100f76103fb565b90505f61012588887f0000000000000000000000000000000000000000000000000000000000000000610410565b90506010826040015161013891906155e0565b85146101575760405163fa06659360e01b815260040160405180910390fd5b60405163995bf45760e01b81525f9073__$2b3697cbc38bc9b2f889ee4ee8a0f41368$__9063995bf457906101fa9085908b908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090600401615763565b610be060405180830381865af4158015610216573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061023a9190615a8f565b905061028a8787808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050855185516060810151608090910151919350915060016108a9565b815160a0015261029a8282610a10565b6102b7576040516313f8744360e31b815260040160405180910390fd5b6102c2828483610c17565b6102df576040516352ec174560e11b815260040160405180910390fd5b50600198975050505050505050565b5f8060026102fe60016008615b39565b61030891906155c9565b9050610316600260036155c9565b6103209082615b39565b9050600161032f6009856155c9565b61033991906155c9565b6103439082615b39565b90506001610352816029615b39565b61035c91906155c9565b6103669082615b39565b9050610374600160026155c9565b61037e9082615b39565b905061038b6001846155c9565b6103959082615b39565b90506103a3600160046155c9565b6103ad9082615b39565b905060026103bc6001856155e0565b6103c691906155c9565b6103d09082615b39565b90506103dd6002806155c9565b6103e79082615b39565b90506103f4601082615b39565b9392505050565b610403615024565b61040b611c14565b905090565b6104186151ae565b5f805b601081101561047a57610447868387610435602083615b39565b9261044293929190615b4c565b61254e565b8351826010811061045a5761045a615b73565b6020020181815250506020826104709190615b39565b915060010161041b565b5061049e85828661048c604083615b39565b9261049993929190615b4c565b612561565b60208301526104ae604082615b39565b90506104c185828661048c604083615b39565b6040808401919091526104d49082615b39565b90506104e785828661048c604083615b39565b60608301526104f7604082615b39565b905061050a85828661048c604083615b39565b608083015261051a604082615b39565b905061052d85828661048c604083615b39565b60c083015261053d604082615b39565b905061055085828661048c604083615b39565b60e0830152610560604082615b39565b905061057385828661048c604083615b39565b60a0830152610583604082615b39565b905061059685828661048c604083615b39565b6101008301526105a7604082615b39565b90506105ba85828661048c604083615b39565b6101208301526105cb604082615b39565b90506105de85828661048c604083615b39565b610140830151526105f0604082615b39565b9050610603858286610435602083615b39565b610160830152610614602082615b39565b90505f5b83811015610692575f5b60098110156106895761063c878488610435602083615b39565b84610180015183601c811061065357610653615b73565b6020020151826009811061066957610669615b73565b60200201818152505060208361067f9190615b39565b9250600101610622565b50600101610618565b505f5b6106a160016029615b39565b8110156106f0576106b9868387610435602083615b39565b836101c0015182602a81106106d0576106d0615b73565b6020020181815250506020826106e69190615b39565b9150600101610695565b50610702858286610435602083615b39565b6101a0830152610713602082615b39565b905061072685828661048c604083615b39565b6101408301516020015261073b604082615b39565b905061074e85828661048c604083615b39565b61014083015160026020020152610766604082615b39565b90505f5b6107756001856155e0565b8110156107be5761078d86838761048c604083615b39565b836101e0015182601b81106107a4576107a4615b73565b60200201526107b4604083615b39565b915060010161076a565b505f5b83811015610811576107da868387610435602083615b39565b83610200015182601c81106107f1576107f1615b73565b6020020181815250506020826108079190615b39565b91506001016107c1565b505f5b60048110156108655761082e868387610435602083615b39565b836102200151826004811061084557610845615b73565b60200201818152505060208261085b9190615b39565b9150600101610814565b5061087785828661048c604083615b39565b610240830152610888604082615b39565b905061089b85828661048c604083615b39565b610260830152509392505050565b5f600180826108d6866108d1896108cc6108c78a6310000000615b39565b6125e3565b6125fb565b612616565b90505f6108f4876108ef8a6108cc6108c78b6001615b39565b61262f565b90505f5b61092360107f00000000000000000000000000000000000000000000000000000000000000006155e0565b811015610990575f61094d8c838151811061094057610940615b73565b6020026020010151612657565b905061095d866108cc8684612616565b955061096d856108cc8584612616565b9450610979848b612616565b9350610985838b61262f565b9250506001016108f8565b505f5b60108110156109f7575f8a82601081106109af576109af615b73565b602002015190506109c4866108cc8684612616565b95506109d4856108cc8584612616565b94506109e0848b612616565b93506109ec838b61262f565b925050600101610993565b50610a02848461266c565b9a9950505050505050505050565b5f5f610a2583606001518561016001516125fb565b905060015f5b7f0000000000000000000000000000000000000000000000000000000000000000811015610b17575f86610180015182601c8110610a6b57610a6b615b73565b602002015180519091505f90610a89908360015b6020020151612616565b9050848114610aab576040516313f8744360e31b815260040160405180910390fd5b5f876080015184601c8110610ac257610ac2615b73565b60200201519050610ad3838261267a565b9550610b07856108cc60016108d1856108cc8e604001518b601c8110610afb57610afb615b73565b6020020151600161262f565b9450505050806001019050610a2b565b50610b20615291565b5f5b6029811015610b70576101c0870151610b3c600183615b39565b602a8110610b4c57610b4c615b73565b6020020151828260298110610b6357610b63615b73565b6020020152600101610b22565b505f610b8582875f0151886020015186612828565b9050600160025b7f0000000000000000000000000000000000000000000000000000000000000000811015610be257610bd882896080015183601c8110610bce57610bce615b73565b60200201516125fb565b9150600101610b8c565b50610c08610bf5836108cc60018561262f565b6108d18a6101a001518a606001516125fb565b94909414979650505050505050565b5f610c206152b0565b5f610c4f8460c001517f00000000000000000000000000000000000000000000000000000000000000006128a1565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610c8a57610c8a615940565b604051908082528060200260200182016040528015610cb3578160200160208202803683370190505b5090505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610cef57610cef615940565b604051908082528060200260200182016040528015610d2857816020015b610d15615320565b815260200190600190039081610d0d5790505b509050610d5b610d56876101000151855f81518110610d4957610d49615b73565b602002602001015161262f565b61296a565b84610120018181525050610d90610d56876101000151855f81518110610d8357610d83615b73565b6020026020010151612616565b610140850181905261012085015160e0880151610db1926108d191906125fb565b845260c0860151610de190610dc59061296a565b6108cc8661012001516108ef8a60e001518961014001516125fb565b6020850152815160019083905f90610dfb57610dfb615b73565b602002602001018181525050876102400151815f81518110610e1f57610e1f615b73565b6020908102919091010152600160a08501525f60c08501528351610e42906129da565b60408501526020840151610e55906129da565b606085015260015b610e6960016024615b39565b8111610f0a57610e8185604001518660a001516125fb565b838281518110610e9357610e93615b73565b602002602001018181525050610edc8560c001516108d18b6101c00151600185610ebd91906155e0565b602a8110610ecd57610ecd615b73565b60200201518860a001516125fb565b60c086015260a08086015190880151610ef591906125fb565b60a0860152610f0381615b87565b9050610e5d565b505f5b6005811015610fe3575f610f22601e83615b39565b90505f610f3160016024615b39565b610f3b9084615b39565b9050610f6c858381518110610f5257610f52615b73565b60200260200101516108d189606001518a60a001516125fb565b858381518110610f7e57610f7e615b73565b602002602001018181525050610fbb8760c001516108d18d6101c0015184602a8110610fac57610fac615b73565b60200201518a60a001516125fb565b60c088015260a080880151908a0151610fd491906125fb565b60a08801525050600101610f0d565b50876020015181600181518110610ffc57610ffc615b73565b602002602001018190525086606001518160028151811061101f5761101f615b73565b602002602001018190525086608001518160038151811061104257611042615b73565b60200260200101819052508660a001518160048151811061106557611065615b73565b60200260200101819052508660c001518160058151811061108857611088615b73565b60200260200101819052508660e00151816006815181106110ab576110ab615b73565b6020026020010181905250866101000151816007815181106110cf576110cf615b73565b6020026020010181905250866101200151816008815181106110f3576110f3615b73565b60200260200101819052508661014001518160098151811061111757611117615b73565b602002602001018190525086610160015181600a8151811061113b5761113b615b73565b6020026020010181905250866101c0015181600b8151811061115f5761115f615b73565b602002602001018190525086610180015181600c8151811061118357611183615b73565b6020026020010181905250866101a0015181600d815181106111a7576111a7615b73565b6020026020010181905250866101e0015181600e815181106111cb576111cb615b73565b602002602001018190525086610200015181600f815181106111ef576111ef615b73565b60200260200101819052508661022001518160108151811061121357611213615b73565b60200260200101819052508661024001518160118151811061123757611237615b73565b60200260200101819052508661026001518160128151811061125b5761125b615b73565b60200260200101819052508661028001518160138151811061127f5761127f615b73565b6020026020010181905250866102a00151816014815181106112a3576112a3615b73565b6020026020010181905250866102c00151816015815181106112c7576112c7615b73565b6020026020010181905250866102e00151816016815181106112eb576112eb615b73565b60200260200101819052508661030001518160178151811061130f5761130f615b73565b60200260200101819052508661032001518160188151811061133357611333615b73565b60200260200101819052508661034001518160198151811061135757611357615b73565b602002602001018190525086610360015181601a8151811061137b5761137b615b73565b602002602001018190525086610380015181601b8151811061139f5761139f615b73565b6020026020010181905250866103a0015181601c815181106113c3576113c3615b73565b6020026020010181905250866103c0015181601d815181106113e7576113e7615b73565b6020026020010181905250876040015181601e8151811061140a5761140a615b73565b6020026020010181905250876060015181601f8151811061142d5761142d615b73565b602002602001018190525087608001518160208151811061145057611450615b73565b60200260200101819052508760a001518160218151811061147357611473615b73565b60200260200101819052508761012001518160228151811061149757611497615b73565b6020026020010181905250876101000151816023815181106114bb576114bb615b73565b60200260200101819052508760c00151816024815181106114de576114de615b73565b60200260200101819052508760e001518160258151811061150157611501615b73565b60200260200101819052505f61154787608001518660c001518b6102000151877f00000000000000000000000000000000000000000000000000000000000000006129ec565b9050611571815f8151811061155e5761155e615b73565b60200260200101518661012001516125fb565b608086018190526102008a01515160e08901516115a292916108d19161159791906125fb565b8861014001516125fb565b608086015260e08701516115b590612b4a565b60a08601525f6115c760016024615b39565b6115d2906001615b39565b90505f5b61160160017f00000000000000000000000000000000000000000000000000000000000000006155e0565b811015611812575f61163460017f00000000000000000000000000000000000000000000000000000000000000006155e0565b8210159050806117a357611668610d568b6101000151898560016116589190615b39565b81518110610d4957610d49615b73565b6101208901526101008a015161169890610d569089611688866001615b39565b81518110610d8357610d83615b73565b61014089015260a08801516101208901516116b391906125fb565b61016089015260a088015160e08b01516116db916116d0916125fb565b8961014001516125fb565b61018089018190526116fe906116f0906129da565b6108d18a61016001516129da565b866117098486615b39565b8151811061171957611719615b73565b6020026020010181815250505f6117528961018001518e61020001518560016117429190615b39565b601c8110610bce57610bce615b73565b905061178c816108d18b61016001518887600161176f9190615b39565b8151811061177f5761177f615b73565b60200260200101516125fb565b905061179c896080015182612616565b60808a0152505b6117c26117b88960a001518c60e001516125fb565b8b60e001516125fb565b60a08901526101e08c015182601b81106117de576117de615b73565b6020020151856117ee8486615b39565b815181106117fe576117fe615b73565b6020908102919091010152506001016115d6565b5061183e60017f00000000000000000000000000000000000000000000000000000000000000006155e0565b6118489082615b39565b90506118686118608961010001518a60c0015161262f565b60019061266c565b60e08701515261010088015160c08901516118ac91611860916108ef907f07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76906125fb565b60e0878101805160200192909252815180516040909101529051805160609091015260a0870151908901516118ee916118e4916125fb565b8960e001516125fb565b60a08701525f5b600481101561199c575f6119278860e00151836004811061191857611918615b73565b60200201518960a001516125fb565b9050611932816129da565b886101000151836004811061194957611949615b73565b602002015260a088015160e08b015161196291906125fb565b8860a001818152505061198e88608001516108d1838f61022001518660048110610bce57610bce615b73565b6080890152506001016118f5565b506101008601515184518590839081106119b8576119b8615b73565b602090810291909101810191909152610100870151908101516119dc916002610a7f565b846119e8836001615b39565b815181106119f8576119f8615b73565b60209081029190910101526101008601516060015184611a19836002615b39565b81518110611a2957611a29615b73565b60209081029190910101525f5b6003811015611a8b578a61014001518160038110611a5657611a56615b73565b60200201518483611a6681615b87565b945081518110611a7857611a78615b73565b6020908102919091010152600101611a36565b506040518060400160405280600181526020016002815250838281518110611ab557611ab5615b73565b60200260200101819052508560800151848280611ad190615b87565b935081518110611ae357611ae3615b73565b602002602001018181525050611b0d8a61022001518960c001518a608001518d6101a00151612b55565b611b2a5760405163a2a2ac8360e01b815260040160405180910390fd5b5f8a6102600151905080848381518110611b4657611b46615b73565b6020026020010181905250886101000151858381518110611b6957611b69615b73565b602002602001018181525050611b7d615338565b611b878587612eb8565b8152611b9282612fb0565b602082018190528c5182515f92611baa929190612ff6565b90505f5f611bba8f5f0151613087565b91509150611bc782613148565b611bd081613148565b8351611bdd9083856131e7565b84526020840151611bef9082856131e7565b602085018190528451611c0191613216565b9f9e505050505050505050505050505050565b611c1c615024565b50604080516103e081018252620200008152601160208083019190915261024382840152825180840184527f3046224394ac0664c5df0bbff473db8485b523993c3378b647785875fbda56e581527f075b8449cf262130cd0d53747c76da002a74053958060ee7c8e930b7f729af4e818301526060830152825180840184527f23f894967a8d0ad87a02976c74accf68659348a280e6c1ab3f99dad7b8cf4bc481527f21acfe5f2f788aee6ca1b87420abfb1b567605edbfc9de6cbff67aa99eb633b8818301526080830152825180840184527f2d8eb0ef0769af9b60944c9c1f9aef88f4458599d8d53d5700e57c463d3d248181527f067d884aca949978f4410a65ef7addb04f9e8a13536c428fbe9d71beb988a3218183015260a0830152825180840184527f04f478772f21c19f23074f73f4cafc722ade3b71fd3e674504df4d488e70844f81527f256ede28a442453cee32d59a1ae23e10ad9765b8cd5aa917f613437e401d03df8183015260c0830152825180840184527f296c0719e6414ccc762949a1eb297b40c46b886179cf2ba5d3660b218aa9a72881527f219d51db4d209022eaa607152a2ddc23b94fb99be6ed4b2f158ed46b21faceb88183015260e0830152825180840184527f0cf55eebb61a0e90c6f9fd68c4839012c6433b88fafff66701ab99c6975e6da381527f1f44b9a9447265fad2e8c326a3cfd26d434ed9eece6c2d5b5586f8232572d76581830152610100830152825180840184527f11beb2731ab8cf46c0a52666bb457fa74d4b635043bb5689a35a2aee24990b8081527f2f1fba989036c44aedb609d0d3341ccb842c2d1cd7c80cea4a95d0eb4530577081830152610120830152825180840184527f2d70068023998c277c75458b7b6eb1fe3c479eb044dec7aa3384d7b5049542c781527f10af4b4ffb3c03f9c906e4dd1cf3c21dc74139881dfa7ad73c25370424f3978181830152610140830152825180840184527f0d07902b3266cd4af955bac93e3579b0bc1bcd754c7b70035cc95877d641376c81527f195d808eeb35965b8df7ea80461dcc033e5d8d0ef25b028a1d429e52b33f3f0d81830152610160830152825180840184527f24ec1ac19b9f052e9e2c4270db9b317502859b163514073401512c675318823881527f28869fd3c9b2ad1ce8a966e9225bed7eac600c656be6891317404dc44726736781830152610180830152825180840184527f201e0e19e72484d21e8136546fe6aaeea2d5b6413019276eada6638ffeb2ce8a81527eba5238e406d8d46f68dc3b00a201ad10d2dc97beed32f5e83d051e742b2642818301526101a0830152825180840184527f2656809e98f3dee7945c4f48c6fff3c0833412aeeae84dada472462112fa8fe981527f2454353d981df4ae6c3fd37c4a7b5114bcb1416f43efc627d55e128449c7c14d818301526101c0830152825180840184527f1fb5e9c3ae41ba815444512a4e882619ac69f0cbb639657adeadb93ed50895b181527f201d42c30be1a478f6c6a28159a335c02fa3dc3e6c6843089c648bfd4dc8c250818301526101e0830152825180840184527f1375207e60c7d651a62aed70d2496e2324a7dc718de86e5887f805f907d4964081527f22a964f903d1faa46e20c6f8902415d61985c86bbeef23a01b6ca1718dfe80c581830152610200830152825180840184527f2a38162537d04323884347c1f31f76b03a04ec2f6f9c4b125d5d322932ff65ba81527f2465da5aac067658f2f98944a8ba1bc9fd81c2220d22f07995746a7b7deccd2981830152610220830152825180840184527f2a12695e6fa7a23c3519eee6d96433bb00d51cd274de90288914e3fb336334b681527f235e728947aff729c4ade5a63ca501273a958075ae1281bb612012f03219601681830152610240830152825180840184527f09e5efa8f84174e74fe0429a76ec404c053a4f8c3e5524d68e3cd4e338a2b4b881527f057873d3cf1d8589310604f6f203386d9a9928d980432f5316522d84e6eecb6181830152610260830152825180840184527f096a6fb164d4a53c869c12d0369ef747bbbd3f40e5dd997c01e32495b64b07cb81527f01198ac63b80d1d160ab5882da3dfc3a8864b70b72c31790e55fec5014c4436281830152610280830152825180840184527f085cbd5bb5a6a7a0407ad624e78b82be37c9c90a9c5de9302004bc406bc1778d81527f2a4cbd271054bf508c73ffeab6e321bba811248126e552f55701993aed192e4b818301526102a0830152825180840184527f1a89bfbff2ee55715a55cf0de0d6a1c62183bbaae9d200a5247b58f170cbbc7c81527f0ae77530f6cad79672428f376996a91ce1358fea5f49180218f18a7918f80bb3818301526102c0830152825180840184527f1faa95912a219c90e3cdbe1e78b25d6f79d4ca8ef1cd9fd3a8a6b87f94d138f281527f22a4b4a860838e96fcc07839e0c9742c2dbe4aa634664da1e24570a1dc4156fd818301526102e0830152825180840184527f1d11efcd01d1170fc229d305654298122dd323cc9ae7e16ad2f0bfa56a0f9e2e81527f225cd914fa8180a343e93ee8a0e87e2d850b8ca6e03267e5281f7ace3dd82ab581830152610300830152825180840184527f099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d2681527e15b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f81830152610320830152825180840184527f1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e81527f305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d1981830152610340830152825180840184527f061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d81527f1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e81830152610360830152825180840184527f043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce81527f261522c4089330646aff96736194949330952ae74c573d1686d9cb4a007338548183015261038083015282518084018452600181526002818301526103a083015282518084019093527f1af84073758283d4c848fed9bc6f055831baf81a643050fceafadf8da1791eec83527f1be165956a9c6a29edc2a4d21793a6fb1f00a6967720f870ebb2f2c6b267e9dd908301526103c081019190915290565b5f6103f461255c8385615b9f565b612657565b612569615320565b60408051808201909152805f516020615c6e5f395f51905f5261258f60205f8789615b4c565b61259891615b9f565b6125a29190615bbc565b81526020908101905f516020615c6e5f395f51905f52906125c7906040908789615b4c565b6125d091615b9f565b6125da9190615bbc565b90529392505050565b5f5f516020615c8e5f395f51905f52825b0692915050565b5f5f516020615c8e5f395f51905f5282840990505b92915050565b5f5f516020615c8e5f395f51905f528284089392505050565b5f5f516020615c8e5f395f51905f52825f516020615c8e5f395f51905f520384089392505050565b5f5f516020615c8e5f395f51905f52826125f4565b5f6103f4836108cc8461296a565b5f5f604051806101200160405280619d8081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec5181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31815260200161024081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd3181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec518152602001619d8081525090505f600190505f5f90505b600981101561277357612769826108cc878461262f565b9150600101612752565b5061277c61534b565b5f5b60098110156127cd576127ae610d5685836009811061279f5761279f615b73565b60200201516108cc898561262f565b8282600981106127c0576127c0615b73565b602002015260010161277e565b505f5b600981101561281357612809856108d18984600981106127f2576127f2615b73565b6020020151858560098110610bce57610bce615b73565b94506001016127d0565b5061281e84836125fb565b9695505050505050565b5f61283161536a565b61283c86828561340a565b612848868683866135b6565b612854868683866137a2565b61285f8682856139c7565b61286a868285613bbb565b61287686868386613f04565b6128818682856143b0565b61288c8682856147c2565b612897868285614b83565b61281e8185614e83565b60605f826001600160401b038111156128bc576128bc615940565b6040519080825280602002602001820160405280156128e5578160200160208202803683370190505b50905083815f815181106128fb576128fb615b73565b602090810291909101015260015b838110156129625761293d826129206001846155e0565b8151811061293057612930615b73565b6020026020010151612b4a565b82828151811061294f5761294f615b73565b6020908102919091010152600101612909565b509392505050565b5f5f8290505f604051602081526020808201526020604082015282606082015260025f516020615c8e5f395f51905f520360808201525f516020615c8e5f395f51905f5260a082015260205f60c08360055afa806129c6575f5ffd5b505f51608091909101604052949350505050565b5f516020615c8e5f395f51905f520390565b60605f826001600160401b03811115612a0757612a07615940565b604051908082528060200260200182016040528015612a30578160200160208202803683370190505b509050825b8015612b3f575f85612a486001846155e0565b81518110612a5857612a58615b73565b602002602001015190505f89600184612a7191906155e0565b601c8110612a8157612a81615b73565b602002015190505f612adc612aa0612a99858d6125fb565b60026125fb565b6108ef8b612aaf6001896155e0565b601c8110612abf57612abf615b73565b60200201516108cc612ad6886108cc60018a61262f565b8761262f565b9050612afd816108cc610d56612af7876108cc60018961262f565b86612616565b99508990508085612b0f6001876155e0565b81518110612b1f57612b1f615b73565b60200260200101818152505050505080612b3890615bdb565b9050612a35565b509695505050505050565b5f61261082836125fb565b5f600181612b6e612b6887610100614edc565b8361262f565b905080612b8e5760405163835eb8f760e01b815260040160405180910390fd5b612b96615389565b80518390525f5b7f0000000000000000000000000000000000000000000000000000000000000000811015612c7f575f612bd18260096155c9565b612bdc906001615b39565b905084835f0151826101008110612bf557612bf5615b73565b60200201525f612c06826001615b39565b90505b612c14600983615b39565b811015612c75578351612c5490612c2c6001846155e0565b6101008110612c3d57612c3d615b73565b60200201518a85601c8110610bce57610bce615b73565b8451826101008110612c6857612c68615b73565b6020020152600101612c09565b5050600101612b9d565b50608081018390525f602082018190525b610100811015612d9057612cb1612cab83608001518a6125fb565b8561262f565b8260a00151826101008110612cc857612cc8615b73565b602002015260a0820151612cf290826101008110612ce857612ce8615b73565b602002015161296a565b8260a00151826101008110612d0957612d09615b73565b602002018181525050612d4f82602001516108d1845f0151846101008110612d3357612d33615b73565b60200201518560a00151856101008110610bce57610bce615b73565b60208301526080820151612d83907f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d66125fb565b6080830152600101612c90565b505f612da1836108cc61010061296a565b9050612db18260200151826125fb565b602083015260a0820151612dcc905f5b6020020151826125fb565b604083015260a0820151612df890612de760016101006155e0565b6101008110612dc157612dc1615b73565b60608301526040820151612e0e908a6002610bce565b60c08301819052612e6e906108d1612e468b7f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d661262f565b60208d015160408e01516108cc91612e5d9161262f565b8e5160208901516108ef91906125fb565b60c083018190526060830151612ea391612e97916108d1906108cc8e600260200201518c61262f565b6108ef858c6003610bce565b60c08301819052159998505050505050505050565b612ec0615320565b7f00000000000000000000000000000000000000000000000000000000000000005f5b81811015612f1557612f0d858281518110612f0057612f00615b73565b6020026020010151613148565b600101612ee3565b50604051600190815b60018401811015612f7a5760208102870160208202870181515160408501528151602001516060850152805160808501525050604080830160606040850160075afa8316925060408260808460065afa90921691600101612f1e565b5080518452602081015160208501525080612fa8576040516352ec174560e11b815260040160405180910390fd5b505092915050565b612fb8615320565b5f516020615c6e5f395f51905f5282602001515f516020615c6e5f395f51905f52612fe391906155e0565b612fed9190615bbc565b60208301525090565b5f5f5f61300286613087565b9150915061300e6153cd565b82518152602080840151818301528251604080840191909152838201516060840152875160808401528782015160a0840152865160c08401528682015160e08401525161307c9161306191849101615bf0565b60405160208183030381529060405280519060200120612657565b979650505050505050565b61308f615320565b613097615320565b82516020808501516040860151606087015160cc90811b608892831b604494851b90961795909517949094178652608087015160a088015160c089015160e08a0151871b90841b91851b9092171717868401526101008701516101208801516101408901516101608a0151871b90841b91851b909217171785526101808701516101a08801516101c08901516101e09099015190951b9790911b9390911b1791909117939093179281019290925291565b805160208201515f5f516020615c6e5f395f51905f528380095f516020615c6e5f395f51905f5260035f516020615c6e5f395f51905f52838709085f516020615c6e5f395f51905f5284850914915050806131e15760405162461bcd60e51b8152602060048201526019602482015278706f696e74206973206e6f74206f6e2074686520637572766560381b60448201526064016100e5565b50505050565b6131ef615320565b6131f7615320565b6132018386614f3d565b905061320d8185614f93565b95945050505050565b81516020808401518351848301516040805194850195909552938301919091527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260608301527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60808301527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b60a08301527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60c083015260e08201526101008101919091527f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c16101208201527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b06101408201527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe46101608201527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101808201525f9081906101a00160405160208183030381529060405290505f5f60086001600160a01b0316836040516133ac9190615c24565b5f60405180830381855afa9150503d805f81146133e4576040519150601f19603f3d011682016040523d82523d5f602084013e6133e9565b606091505b509150915081801561281e57508080602001905181019061281e9190615c3a565b5f613416846007614ff4565b90507f183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f80000005f61347761347161344b85600361262f565b6108cc61346661345b8b5f614ff4565b6108cc8c601d614ff4565b6108cc8b601c614ff4565b836125fb565b90506134f86134ed6134d46134bb6134a2856108d16134978d6002614ff4565b6108cc8e601c614ff4565b6108d16134b08c6003614ff4565b6108cc8d601d614ff4565b6108d16134c98b6004614ff4565b6108cc8c601e614ff4565b6108d16134e28a6005614ff4565b6108cc8b601f614ff4565b6108d1886001614ff4565b9050613517816108d161350c86600161262f565b6108cc8a6027614ff4565b905061352381846125fb565b905061352f81856125fb565b8552505f905061356961355f61355461354988601c614ff4565b6108d189601f614ff4565b6108ef886024614ff4565b6108d1875f614ff4565b905061357a816108cc84600261262f565b905061358b816108cc84600161262f565b905061359781836125fb565b90506135a381846125fb565b9050808460015b60200201525050505050565b5f5f5f6135ec6135e26135ca89601c614ff4565b6108d16135d88b6012614ff4565b8a606001516125fb565b8760800151612616565b9050613625816108cc61361b6136038b601d614ff4565b6108d16136118d6013614ff4565b8c606001516125fb565b8960800151612616565b905061364a816108cc61361b61363c8b601e614ff4565b6108d16136118d6014614ff4565b905061366f816108cc61361b6136618b601f614ff4565b6108d16136118d6015614ff4565b92505f90506136936135e261368589601c614ff4565b6108d16135d88b600e614ff4565b90506136b8816108cc61361b6136aa8b601d614ff4565b6108d16136118d600f614ff4565b90506136dd816108cc61361b6136cf8b601e614ff4565b6108d16136118d6010614ff4565b9050613702816108cc61361b6136f48b601f614ff4565b6108d16136118d6011614ff4565b91505f9050613729613723613718896020614ff4565b6108d18a601a614ff4565b846125fb565b905061375e816108ef6137586137408b6028614ff4565b6108d161374e8d601b614ff4565b8c60a001516125fb565b856125fb565b905061376a81856125fb565b6040860152505f61378d61375861378289601b614ff4565b6108cc8a6028614ff4565b9050808560035b602002015250505050505050565b5f5f6138006137e86137d06137bb61361b8a6016614ff4565b6108d16137c98b6017614ff4565b8a516125fb565b6108d16137de8a6018614ff4565b89602001516125fb565b6108d16137f6896019614ff4565b88604001516125fb565b91505f61383761381e61381489601c614ff4565b8860800151612616565b6108d161382c8a6003614ff4565b6108cc8b6024614ff4565b90505f61386061384889601d614ff4565b6108d16138558b5f614ff4565b6108cc8c6025614ff4565b90505f61388a6138718a601e614ff4565b6108d161387f8c6001614ff4565b6108cc8d6026614ff4565b90506138c96138b16138a3856108d1868d5f01516125fb565b6108d1848c602001516125fb565b6108d16138bf8c6004614ff4565b8b604001516125fb565b93505050505f6138dd613723886021614ff4565b90505f6138ee613723896021614ff4565b90505f61392661390d6139028b6023614ff4565b6108d18c6006614ff4565b6108ef61391b8c6023614ff4565b6108cc8d6006614ff4565b90505f613944612b6861393987896125fb565b6108cc8d6021614ff4565b905061395081886125fb565b90505f61397861396a6139648d6006614ff4565b876125fb565b6108ef6139648e6022614ff4565b90505f6139868c6023614ff4565b90505f613996612b6883846125fb565b60808c0185905260a08c0184905290506139b0818b6125fb565b8b6006602002015250505050505050505050505050565b5f6139d35f600161262f565b90505f6139e15f600261262f565b90505f6139ef5f600361262f565b90505f613a0b613a0088601d614ff4565b6108ef89601c614ff4565b90505f613a27613a1c89601e614ff4565b6108ef8a601d614ff4565b90505f613a43613a388a601f614ff4565b6108ef8b601e614ff4565b90505f613a5f613a548b6024614ff4565b6108ef8c601f614ff4565b905083613a70816108cc818b612616565b9050613a80816108cc878a612616565b9050613a90816108cc8789612616565b9050613aa1816108cc8d6008614ff4565b9050613aad818a6125fb565b60e08b01525082613ac2816108cc818b612616565b9050613ad2816108cc868a612616565b9050613ae2816108cc8689612616565b9050613af3816108cc8d6008614ff4565b9050613aff818a6125fb565b6101008b01525081613b15816108cc818b612616565b9050613b25816108cc858a612616565b9050613b35816108cc8589612616565b9050613b46816108cc8d6008614ff4565b9050613b52818a6125fb565b6101208b01525080613b68816108cc818b612616565b9050613b78816108cc848a612616565b9050613b88816108cc8489612616565b9050613b99816108cc8d6008614ff4565b9050613ba5818a6125fb565b610140909a019990995250505050505050505050565b613bf46040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613bff84601d614ff4565b8152613c0c84601e614ff4565b6020820152613c1c846024614ff4565b6040820152613c2c846027614ff4565b6060820152613c3c846026614ff4565b6080820152613c4c846025614ff4565b60a08201525f613c5d856002614ff4565b90505f613c6a865f614ff4565b90505f613c7e8460400151855f015161262f565b90505f613c93856020015186602001516125fb565b606086015190915086905f90613ca990806125fb565b90505f613cc7613cc189602001518a606001516125fb565b886125fb565b90505f613ce6613cdf8a60a001518b60400151612616565b8a51612616565b9050613cf561396482886125fb565b9050613d1c613d16613d10613d0a848761262f565b8861262f565b84612616565b83612616565b9050613d44613d39613d2e83876125fb565b6108cc8f6009614ff4565b6108cc60018a61262f565b6101608c015250505050602085015160808601515f91613d6391612616565b90505f613d81613d778860600151886125fb565b886020015161262f565b90505f613da5613d9184876125fb565b6108d16137588b60a001518c5f015161262f565b9050613dcd613dc2613db7838c6125fb565b6108cc8e6009614ff4565b6108cc60018961262f565b6101808b0152505f9150613dee9050613de7836011612616565b87516125fb565b90505f613dfb8384612616565b9050613e078182612616565b90505f613e158360096125fb565b9050613e3e613e38613723613e318b60a001518c5f0151612616565b8b51612616565b8261262f565b60c089018190525f90613e5990613cc190613d2e908d6125fb565b9050613e6c8b600b602002015182612616565b6101608c0152505086515f9250613e939150613de790613e8c9080612616565b8851612616565b90505f613ed3613eae836108cc8a5f01518b60a0015161262f565b60208901516108ef90613ec19080612616565b6108cc8b602001518c60800151612616565b9050613ef089600c60200201516108d1613cc1613d2e858d6125fb565b89600c602002015250505050505050505050565b613f6e604051806101e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613f86613f7c86601e614ff4565b85604001516125fb565b808252613fa5906108d1613f9b88601d614ff4565b87602001516125fb565b808252613fba906108d1613de788601c614ff4565b808252613fcc906108d1876001614ff4565b80825260208201819052613fe5906108ef87601f614ff4565b8152614000613ff5866024614ff4565b6108ef87601c614ff4565b608082015261401e614013866027614ff4565b6108ef87601f614ff4565b60608201526080810151614037906108cc81600161262f565b6101c082015260808101516140779061406d90614066906108cc60015f516020615c8e5f395f51905f526155e0565b6001612616565b82606001516125fb565b60a082018190526140ad9061409f906108cc614094896002614ff4565b6108cc8a6003614ff4565b6108cc61375888600a614ff4565b83600e60200201526101c08101516140d19061409f906108cc614094896002614ff4565b6101e084015280516140f6906108cc6140eb886002614ff4565b6108cc896003614ff4565b6101208201525f61411561410b87601f614ff4565b836020015161262f565b9050614126816108cc83600161262f565b60e0830152614143614139876026614ff4565b86604001516125fb565b60408301819052614166906108d161415c896025614ff4565b88602001516125fb565b60408301819052614186906108d161417f896024614ff4565b88516125fb565b60408301526141a3614199876027614ff4565b836040015161262f565b60408301525f6141c26141b7886026614ff4565b6108ef89601e614ff4565b90506142146141ef613471614066866080015160015f516020615c8e5f395f51905f526108cc91906155e0565b6108cc614066866040015160015f516020615c8e5f395f51905f526108cc91906155e0565b60c084015260408301516142369061422c90806125fb565b846040015161262f565b61010084015260c083015161426290614254906108cc8a6004614ff4565b6108cc6139648a600a614ff4565b6102008601526101c083015161428190614254906108cc8a6004614ff4565b6102208601526101008301516142a090614254906108cc8a6004614ff4565b61024086015260e08301516142ba906108cc896004614ff4565b6101408401526142d96142ce886025614ff4565b6108ef89601d614ff4565b6101608401526080830151614317906141b79061430c90614066906108cc60015f516020615c8e5f395f51905f526155e0565b8561016001516125fb565b61018084018190526101208401516101a0850181905261434e916108d1906108cc6143438c6005614ff4565b6108cc8d6002614ff4565b6101a08401819052835161436e91906108d1906108cc6143438c5f614ff4565b6101a084018190526101408401516143869190612616565b6101a084018190526143a0906108cc6139648a600a614ff4565b6101a0840181905285600d613794565b6143e96040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61441e6144056143fa86601c614ff4565b6108cc876025614ff4565b6108d1614413876024614ff4565b6108cc88601d614ff4565b815261446361445861443f61443487601c614ff4565b6108cc88601f614ff4565b6108d161444d88601d614ff4565b6108cc89601e614ff4565b6108ef866026614ff4565b6040820181905261447890600160441b6125fb565b6040820181905261448e906108ef866027614ff4565b6040820181905281516144a19190612616565b604082018190526144b7906108cc866005614ff4565b604082015280516144cc90600160441b6125fb565b8082526144ec906108d16144e1876024614ff4565b6108cc886025614ff4565b80825260208201819052614513906108ef61450887601e614ff4565b6108d188601f614ff4565b60208201819052614529906108cc866004614ff4565b6020820152805160608201819052614546906108d186601f614ff4565b6060820181905261456a906108ef61455f876026614ff4565b6108d1886027614ff4565b6060820181905261457f906108cc865f614ff4565b8160600181815250505f6145a861459e83602001518460400151612616565b8360600151612616565b90506145b9816108cc876003614ff4565b90506145d16145c9866025614ff4565b6140006125fb565b608083018190526145e7906108d1876024614ff4565b608083018190526145fa906140006125fb565b60808301819052614610906108d187601e614ff4565b60808301819052614623906140006125fb565b60808301819052614639906108d187601d614ff4565b6080830181905261464c906140006125fb565b60808301819052614662906108d187601c614ff4565b60808301819052614678906108ef87601f614ff4565b6080830181905261468e906108cc876005614ff4565b60808301526146a16145c9866026614ff4565b60a083018190526146b7906108d1876025614ff4565b60a083018190526146ca906140006125fb565b60a083018190526146e0906108d1876024614ff4565b60a083018190526146f3906140006125fb565b60a08301819052614709906108d187601f614ff4565b60a0830181905261471c906140006125fb565b60a08301819052614732906108d187601e614ff4565b60a08301819052614748906108ef876027614ff4565b60a0830181905261475d906108cc875f614ff4565b60a0830181905260808301515f916147759190612616565b9050614786816108cc886004614ff4565b90506147928282612616565b60c084018190526147ab906108cc61396489600b614ff4565b60c084018190528560136020020152505050505050565b6148386040518061022001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61485161484685601c614ff4565b6108d1866002614ff4565b815261486c61486185601d614ff4565b6108d1866003614ff4565b602082015261488a61487f85601e614ff4565b6108d1866004614ff4565b60408201526148a861489d85601f614ff4565b6108d1866005614ff4565b606082015280516148da906148d3906148cc906148c590806125fb565b84516125fb565b83516125fb565b82516125fb565b608082015260208101516149189061490e90614904906148fa90806125fb565b84602001516125fb565b83602001516125fb565b82602001516125fb565b60a082015260408101516149569061494c906149429061493890806125fb565b84604001516125fb565b83604001516125fb565b82604001516125fb565b60c0820152606081015161498a9061406d906149809061497690806125fb565b84606001516125fb565b83606001516125fb565b60e0820152608081015160a08201516149a39190612616565b61010082015260c081015160e08201516149bd9190612616565b61012082015260a08101516149e1906149d69080612616565b826101200151612616565b61014082015260e0810151614a05906149fa9080612616565b826101000151612616565b610160820152610120810151614a1b9080612616565b6101e08201819052614a3c90614a319080612616565b826101600151612616565b6101e0820152610100810151614a529080612616565b6101a08201819052614a7390614a689080612616565b826101400151612616565b6101a08201819052610160820151614a8a91612616565b6101808201526101408101516101e0820151614aa69190612616565b6101c0820152614aba61347185600c614ff4565b6102008201819052610280840151610180830151614ae5926108d1916108cc906108ef8a6024614ff4565b8360146020020152614b1583601560200201516108d18361020001516108cc856101a001516108ef8a6025614ff4565b8360156020020152614b4583601660200201516108d18361020001516108cc856101c001516108ef8a6026614ff4565b8360166020020152614b7583601760200201516108d18361020001516108cc856101e001516108ef8a6027614ff4565b836017602002015250505050565b614bd56040518061016001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f6040518060800160405280614c0a7f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e76125e3565b8152602001614c387f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b6125e3565b8152602001614c657e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac156125e3565b8152602001614c937f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b6125e3565b90529050614cb0614ca586601c614ff4565b6108d1876002614ff4565b6101208301819052614cef90614ce490614cd990614cce90806125fb565b8561012001516125fb565b8461012001516125fb565b8361012001516125fb565b8252614cfc85601d614ff4565b6020830152614d0c85601e614ff4565b6040830152614d1c85601f614ff4565b606083015281516020830151614d449161459e91614d3a9190612616565b8460400151612616565b6080830152614d5761372386600d614ff4565b6101408301528151614d7890614d6e90835f610bce565b8360800151612616565b60a0830152614da484601860200201516108d18461014001516108cc8660a001516108ef8b6024614ff4565b6103008501526020820151614dbf90614d6e90836001610bce565b60c0830152614deb84601960200201516108d18461014001516108cc8660c001516108ef8b6025614ff4565b6103208501526040820151614e0690614d6e90836002610bce565b60e0830152614e3284601a60200201516108d18461014001516108cc8660e001516108ef8b6026614ff4565b6103408501526060820151614e4d90614d6e90836003610bce565b610100830152614e7b84601b60200201516108d18461014001516108cc8661010001516108ef8b6027614ff4565b84601b6135aa565b815160015b601c811015614ed557614ecb826108d18684601c8110614eaa57614eaa615b73565b602002015186614ebb6001876155e0565b601b8110610bce57610bce615b73565b9150600101614e88565b5092915050565b5f5f8390505f60405160208152602080820152602060408201528260608201528460808201525f516020615c8e5f395f51905f5260a082015260205f60c08360055afa80614f28575f5ffd5b505f5160809190910160405295945050505050565b614f45615320565b614f4d615320565b604051835181526020840151602082015284604082015260408160608360075afa80614f77575f5ffd5b5080518252602080820151908301526060016040529392505050565b614f9b615320565b614fa3615320565b6040518451815260208501516020820152835160408201526020840151606082015260408160808360065afa80614fd8575f5ffd5b5080518252602080820151908301526080016040529392505050565b5f8282602881111561500857615008615c59565b6029811061501857615018615b73565b60200201519392505050565b604051806103e001604052805f81526020015f81526020015f815260200161504a615320565b8152602001615057615320565b8152602001615064615320565b8152602001615071615320565b815260200161507e615320565b815260200161508b615320565b8152602001615098615320565b81526020016150a5615320565b81526020016150b2615320565b81526020016150bf615320565b81526020016150cc615320565b81526020016150d9615320565b81526020016150e6615320565b81526020016150f3615320565b8152602001615100615320565b815260200161510d615320565b815260200161511a615320565b8152602001615127615320565b8152602001615134615320565b8152602001615141615320565b815260200161514e615320565b815260200161515b615320565b8152602001615168615320565b8152602001615175615320565b8152602001615182615320565b815260200161518f615320565b815260200161519c615320565b81526020016151a9615320565b905290565b6040518061028001604052806151c26153ec565b81526020016151cf615320565b81526020016151dc615320565b81526020016151e9615320565b81526020016151f6615320565b8152602001615203615320565b8152602001615210615320565b815260200161521d615320565b815260200161522a615320565b8152602001615237615320565b815260200161524461540b565b81526020015f8152602001615257615438565b81526020015f815260200161526a615466565b8152602001615277615485565b815260200161528461536a565b815260200161518f6154b3565b6040518061052001604052806029906020820280368337509192915050565b604051806101c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020016152ee6154b3565b81526020016152fb6154b3565b81526020015f81526020015f81526020015f81526020015f8152602001606081525090565b60405180604001604052805f81526020015f81525090565b604051806040016040528061519c615320565b6040518061012001604052806009906020820280368337509192915050565b604051806103800160405280601c906020820280368337509192915050565b6040518060e0016040528061539c6154d1565b81526020015f81526020015f81526020015f81526020015f81526020016153c16154d1565b81526020015f81525090565b6040518061010001604052806008906020820280368337509192915050565b6040518061020001604052806010906020820280368337509192915050565b60405180606001604052806003905b615422615320565b81526020019060019003908161541a5790505090565b604051806103800160405280601c905b61545061534b565b8152602001906001900390816154485790505090565b604051806105400160405280602a906020820280368337509192915050565b604051806103600160405280601b905b61549d615320565b8152602001906001900390816154955790505090565b60405180608001604052806004906020820280368337509192915050565b604051806120000160405280610100906020820280368337509192915050565b5f5f5f5f60408587031215615504575f5ffd5b84356001600160401b03811115615519575f5ffd5b8501601f81018713615529575f5ffd5b80356001600160401b0381111561553e575f5ffd5b87602082840101111561554f575f5ffd5b6020918201955093508501356001600160401b0381111561556e575f5ffd5b8501601f8101871361557e575f5ffd5b80356001600160401b03811115615593575f5ffd5b8760208260051b84010111156155a7575f5ffd5b949793965060200194505050565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417612610576126106155b5565b81810381811115612610576126106155b5565b805f5b60108110156131e15781518452602093840193909101906001016155f6565b805f5b60038110156131e15761563684835180518252602090810151910152565b6040939093019260209190910190600101615618565b805f5b601c8110156131e1578151845f5b600981101561567c57825182526020928301929091019060010161565d565b50505061012093909301926020919091019060010161564f565b805f5b602a8110156131e1578151845260209384019390910190600101615699565b805f5b601b8110156131e1576156d984835180518252602090810151910152565b60409390930192602091909101906001016156bb565b805f5b601c8110156131e15781518452602093840193909101906001016156f2565b805f5b60048110156131e1578151845260209384019390910190600101615714565b8183525f6001600160fb1b0383111561574a575f5ffd5b8260051b80836020870137939093016020019392505050565b61576e8188516155f3565b5f602088015161578c61020084018280518252602090810151910152565b5060408801518051610240840152602090810151610260840152606089015180516102808501528101516102a0840152608089015180516102c08501528101516102e084015260a0890151805161030085015281015161032084015260c0890151805161034085015281015161036084015260e089015180516103808501528101516103a084015261010089015180516103c08501528101516103e084015261012089015180516104008501520151610420830152610140880151615855610440840182615615565b5061016088015161050083015261018088015161587661052084018261564c565b506101a08801516124a08301526101c08801516158976124c0840182615696565b506101e08801516158ac612a008401826156b8565b506102008801516158c16130c08401826156ef565b506102208801516158d6613440840182615711565b5061024088015180516134c08401526020908101516134e0840152610260890151805161350085015201516135208301526135c0613540830181905261591f9083018789615733565b613560830195909552506135808101929092526135a0909101529392505050565b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b038111828210171561597757615977615940565b60405290565b604051601f8201601f191681016001600160401b03811182821017156159a5576159a5615940565b604052919050565b5f60c082840312156159bd575f5ffd5b60405160c081016001600160401b03811182821017156159df576159df615940565b604090815283518252602080850151908301528381015190820152606080840151908201526080808401519082015260a0928301519281019290925250919050565b5f82601f830112615a30575f5ffd5b5f610360615a3d8161597d565b915083018185821115615a4e575f5ffd5b845b82811015615a68578051825260209182019101615a50565b509195945050505050565b5f82601f830112615a82575f5ffd5b5f610380615a3d8161597d565b5f610be0828403128015615aa1575f5ffd5b50615aaa615954565b615ab484846159ad565b8152615ac38460c08501615a21565b6020820152615ad6846104208501615a73565b60408201526107a08301516060820152615af4846107c08501615a73565b6080820152610b4083015160a0820152610b6083015160c0820152610b8083015160e0820152610ba0830151610100820152610bc09092015161012083015250919050565b80820180821115612610576126106155b5565b5f5f85851115615b5a575f5ffd5b83861115615b66575f5ffd5b5050820193919092039150565b634e487b7160e01b5f52603260045260245ffd5b5f60018201615b9857615b986155b5565b5060010190565b80356020831015612610575f19602084900360031b1b1692915050565b5f82615bd657634e487b7160e01b5f52601260045260245ffd5b500690565b5f81615be957615be96155b5565b505f190190565b5f8183825b6008811015615c14578151835260209283019290910190600101615bf5565b5050506101008201905092915050565b5f82518060208501845e5f920191825250919050565b5f60208284031215615c4a575f5ffd5b815180151581146103f4575f5ffd5b634e487b7160e01b5f52602160045260245ffdfe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4730644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a164736f6c634300081c000a", - "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063ea50d0e41461002d575b5f5ffd5b61004061003b3660046154f1565b610054565b604051901515815260200160405180910390f35b5f5f61007f7f00000000000000000000000000000000000000000000000000000000000000006102ee565b905061008c8160206155c9565b85146100ee577f0000000000000000000000000000000000000000000000000000000000000000856100bf8360206155c9565b6040516359895a5360e01b81526004810193909352602483019190915260448201526064015b60405180910390fd5b5f6100f76103fb565b90505f61012588887f0000000000000000000000000000000000000000000000000000000000000000610410565b90506010826040015161013891906155e0565b85146101575760405163fa06659360e01b815260040160405180910390fd5b60405163995bf45760e01b81525f9073__$2b3697cbc38bc9b2f889ee4ee8a0f41368$__9063995bf457906101fa9085908b908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090600401615763565b610be060405180830381865af4158015610216573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061023a9190615a8f565b905061028a8787808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050855185516060810151608090910151919350915060016108a9565b815160a0015261029a8282610a10565b6102b7576040516313f8744360e31b815260040160405180910390fd5b6102c2828483610c17565b6102df576040516352ec174560e11b815260040160405180910390fd5b50600198975050505050505050565b5f8060026102fe60016008615b39565b61030891906155c9565b9050610316600260036155c9565b6103209082615b39565b9050600161032f6009856155c9565b61033991906155c9565b6103439082615b39565b90506001610352816029615b39565b61035c91906155c9565b6103669082615b39565b9050610374600160026155c9565b61037e9082615b39565b905061038b6001846155c9565b6103959082615b39565b90506103a3600160046155c9565b6103ad9082615b39565b905060026103bc6001856155e0565b6103c691906155c9565b6103d09082615b39565b90506103dd6002806155c9565b6103e79082615b39565b90506103f4601082615b39565b9392505050565b610403615024565b61040b611c14565b905090565b6104186151ae565b5f805b601081101561047a57610447868387610435602083615b39565b9261044293929190615b4c565b61254e565b8351826010811061045a5761045a615b73565b6020020181815250506020826104709190615b39565b915060010161041b565b5061049e85828661048c604083615b39565b9261049993929190615b4c565b612561565b60208301526104ae604082615b39565b90506104c185828661048c604083615b39565b6040808401919091526104d49082615b39565b90506104e785828661048c604083615b39565b60608301526104f7604082615b39565b905061050a85828661048c604083615b39565b608083015261051a604082615b39565b905061052d85828661048c604083615b39565b60c083015261053d604082615b39565b905061055085828661048c604083615b39565b60e0830152610560604082615b39565b905061057385828661048c604083615b39565b60a0830152610583604082615b39565b905061059685828661048c604083615b39565b6101008301526105a7604082615b39565b90506105ba85828661048c604083615b39565b6101208301526105cb604082615b39565b90506105de85828661048c604083615b39565b610140830151526105f0604082615b39565b9050610603858286610435602083615b39565b610160830152610614602082615b39565b90505f5b83811015610692575f5b60098110156106895761063c878488610435602083615b39565b84610180015183601c811061065357610653615b73565b6020020151826009811061066957610669615b73565b60200201818152505060208361067f9190615b39565b9250600101610622565b50600101610618565b505f5b6106a160016029615b39565b8110156106f0576106b9868387610435602083615b39565b836101c0015182602a81106106d0576106d0615b73565b6020020181815250506020826106e69190615b39565b9150600101610695565b50610702858286610435602083615b39565b6101a0830152610713602082615b39565b905061072685828661048c604083615b39565b6101408301516020015261073b604082615b39565b905061074e85828661048c604083615b39565b61014083015160026020020152610766604082615b39565b90505f5b6107756001856155e0565b8110156107be5761078d86838761048c604083615b39565b836101e0015182601b81106107a4576107a4615b73565b60200201526107b4604083615b39565b915060010161076a565b505f5b83811015610811576107da868387610435602083615b39565b83610200015182601c81106107f1576107f1615b73565b6020020181815250506020826108079190615b39565b91506001016107c1565b505f5b60048110156108655761082e868387610435602083615b39565b836102200151826004811061084557610845615b73565b60200201818152505060208261085b9190615b39565b9150600101610814565b5061087785828661048c604083615b39565b610240830152610888604082615b39565b905061089b85828661048c604083615b39565b610260830152509392505050565b5f600180826108d6866108d1896108cc6108c78a6310000000615b39565b6125e3565b6125fb565b612616565b90505f6108f4876108ef8a6108cc6108c78b6001615b39565b61262f565b90505f5b61092360107f00000000000000000000000000000000000000000000000000000000000000006155e0565b811015610990575f61094d8c838151811061094057610940615b73565b6020026020010151612657565b905061095d866108cc8684612616565b955061096d856108cc8584612616565b9450610979848b612616565b9350610985838b61262f565b9250506001016108f8565b505f5b60108110156109f7575f8a82601081106109af576109af615b73565b602002015190506109c4866108cc8684612616565b95506109d4856108cc8584612616565b94506109e0848b612616565b93506109ec838b61262f565b925050600101610993565b50610a02848461266c565b9a9950505050505050505050565b5f5f610a2583606001518561016001516125fb565b905060015f5b7f0000000000000000000000000000000000000000000000000000000000000000811015610b17575f86610180015182601c8110610a6b57610a6b615b73565b602002015180519091505f90610a89908360015b6020020151612616565b9050848114610aab576040516313f8744360e31b815260040160405180910390fd5b5f876080015184601c8110610ac257610ac2615b73565b60200201519050610ad3838261267a565b9550610b07856108cc60016108d1856108cc8e604001518b601c8110610afb57610afb615b73565b6020020151600161262f565b9450505050806001019050610a2b565b50610b20615291565b5f5b6029811015610b70576101c0870151610b3c600183615b39565b602a8110610b4c57610b4c615b73565b6020020151828260298110610b6357610b63615b73565b6020020152600101610b22565b505f610b8582875f0151886020015186612828565b9050600160025b7f0000000000000000000000000000000000000000000000000000000000000000811015610be257610bd882896080015183601c8110610bce57610bce615b73565b60200201516125fb565b9150600101610b8c565b50610c08610bf5836108cc60018561262f565b6108d18a6101a001518a606001516125fb565b94909414979650505050505050565b5f610c206152b0565b5f610c4f8460c001517f00000000000000000000000000000000000000000000000000000000000000006128a1565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610c8a57610c8a615940565b604051908082528060200260200182016040528015610cb3578160200160208202803683370190505b5090505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610cef57610cef615940565b604051908082528060200260200182016040528015610d2857816020015b610d15615320565b815260200190600190039081610d0d5790505b509050610d5b610d56876101000151855f81518110610d4957610d49615b73565b602002602001015161262f565b61296a565b84610120018181525050610d90610d56876101000151855f81518110610d8357610d83615b73565b6020026020010151612616565b610140850181905261012085015160e0880151610db1926108d191906125fb565b845260c0860151610de190610dc59061296a565b6108cc8661012001516108ef8a60e001518961014001516125fb565b6020850152815160019083905f90610dfb57610dfb615b73565b602002602001018181525050876102400151815f81518110610e1f57610e1f615b73565b6020908102919091010152600160a08501525f60c08501528351610e42906129da565b60408501526020840151610e55906129da565b606085015260015b610e6960016024615b39565b8111610f0a57610e8185604001518660a001516125fb565b838281518110610e9357610e93615b73565b602002602001018181525050610edc8560c001516108d18b6101c00151600185610ebd91906155e0565b602a8110610ecd57610ecd615b73565b60200201518860a001516125fb565b60c086015260a08086015190880151610ef591906125fb565b60a0860152610f0381615b87565b9050610e5d565b505f5b6005811015610fe3575f610f22601e83615b39565b90505f610f3160016024615b39565b610f3b9084615b39565b9050610f6c858381518110610f5257610f52615b73565b60200260200101516108d189606001518a60a001516125fb565b858381518110610f7e57610f7e615b73565b602002602001018181525050610fbb8760c001516108d18d6101c0015184602a8110610fac57610fac615b73565b60200201518a60a001516125fb565b60c088015260a080880151908a0151610fd491906125fb565b60a08801525050600101610f0d565b50876020015181600181518110610ffc57610ffc615b73565b602002602001018190525086606001518160028151811061101f5761101f615b73565b602002602001018190525086608001518160038151811061104257611042615b73565b60200260200101819052508660a001518160048151811061106557611065615b73565b60200260200101819052508660c001518160058151811061108857611088615b73565b60200260200101819052508660e00151816006815181106110ab576110ab615b73565b6020026020010181905250866101000151816007815181106110cf576110cf615b73565b6020026020010181905250866101200151816008815181106110f3576110f3615b73565b60200260200101819052508661014001518160098151811061111757611117615b73565b602002602001018190525086610160015181600a8151811061113b5761113b615b73565b6020026020010181905250866101c0015181600b8151811061115f5761115f615b73565b602002602001018190525086610180015181600c8151811061118357611183615b73565b6020026020010181905250866101a0015181600d815181106111a7576111a7615b73565b6020026020010181905250866101e0015181600e815181106111cb576111cb615b73565b602002602001018190525086610200015181600f815181106111ef576111ef615b73565b60200260200101819052508661022001518160108151811061121357611213615b73565b60200260200101819052508661024001518160118151811061123757611237615b73565b60200260200101819052508661026001518160128151811061125b5761125b615b73565b60200260200101819052508661028001518160138151811061127f5761127f615b73565b6020026020010181905250866102a00151816014815181106112a3576112a3615b73565b6020026020010181905250866102c00151816015815181106112c7576112c7615b73565b6020026020010181905250866102e00151816016815181106112eb576112eb615b73565b60200260200101819052508661030001518160178151811061130f5761130f615b73565b60200260200101819052508661032001518160188151811061133357611333615b73565b60200260200101819052508661034001518160198151811061135757611357615b73565b602002602001018190525086610360015181601a8151811061137b5761137b615b73565b602002602001018190525086610380015181601b8151811061139f5761139f615b73565b6020026020010181905250866103a0015181601c815181106113c3576113c3615b73565b6020026020010181905250866103c0015181601d815181106113e7576113e7615b73565b6020026020010181905250876040015181601e8151811061140a5761140a615b73565b6020026020010181905250876060015181601f8151811061142d5761142d615b73565b602002602001018190525087608001518160208151811061145057611450615b73565b60200260200101819052508760a001518160218151811061147357611473615b73565b60200260200101819052508761012001518160228151811061149757611497615b73565b6020026020010181905250876101000151816023815181106114bb576114bb615b73565b60200260200101819052508760c00151816024815181106114de576114de615b73565b60200260200101819052508760e001518160258151811061150157611501615b73565b60200260200101819052505f61154787608001518660c001518b6102000151877f00000000000000000000000000000000000000000000000000000000000000006129ec565b9050611571815f8151811061155e5761155e615b73565b60200260200101518661012001516125fb565b608086018190526102008a01515160e08901516115a292916108d19161159791906125fb565b8861014001516125fb565b608086015260e08701516115b590612b4a565b60a08601525f6115c760016024615b39565b6115d2906001615b39565b90505f5b61160160017f00000000000000000000000000000000000000000000000000000000000000006155e0565b811015611812575f61163460017f00000000000000000000000000000000000000000000000000000000000000006155e0565b8210159050806117a357611668610d568b6101000151898560016116589190615b39565b81518110610d4957610d49615b73565b6101208901526101008a015161169890610d569089611688866001615b39565b81518110610d8357610d83615b73565b61014089015260a08801516101208901516116b391906125fb565b61016089015260a088015160e08b01516116db916116d0916125fb565b8961014001516125fb565b61018089018190526116fe906116f0906129da565b6108d18a61016001516129da565b866117098486615b39565b8151811061171957611719615b73565b6020026020010181815250505f6117528961018001518e61020001518560016117429190615b39565b601c8110610bce57610bce615b73565b905061178c816108d18b61016001518887600161176f9190615b39565b8151811061177f5761177f615b73565b60200260200101516125fb565b905061179c896080015182612616565b60808a0152505b6117c26117b88960a001518c60e001516125fb565b8b60e001516125fb565b60a08901526101e08c015182601b81106117de576117de615b73565b6020020151856117ee8486615b39565b815181106117fe576117fe615b73565b6020908102919091010152506001016115d6565b5061183e60017f00000000000000000000000000000000000000000000000000000000000000006155e0565b6118489082615b39565b90506118686118608961010001518a60c0015161262f565b60019061266c565b60e08701515261010088015160c08901516118ac91611860916108ef907f07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76906125fb565b60e0878101805160200192909252815180516040909101529051805160609091015260a0870151908901516118ee916118e4916125fb565b8960e001516125fb565b60a08701525f5b600481101561199c575f6119278860e00151836004811061191857611918615b73565b60200201518960a001516125fb565b9050611932816129da565b886101000151836004811061194957611949615b73565b602002015260a088015160e08b015161196291906125fb565b8860a001818152505061198e88608001516108d1838f61022001518660048110610bce57610bce615b73565b6080890152506001016118f5565b506101008601515184518590839081106119b8576119b8615b73565b602090810291909101810191909152610100870151908101516119dc916002610a7f565b846119e8836001615b39565b815181106119f8576119f8615b73565b60209081029190910101526101008601516060015184611a19836002615b39565b81518110611a2957611a29615b73565b60209081029190910101525f5b6003811015611a8b578a61014001518160038110611a5657611a56615b73565b60200201518483611a6681615b87565b945081518110611a7857611a78615b73565b6020908102919091010152600101611a36565b506040518060400160405280600181526020016002815250838281518110611ab557611ab5615b73565b60200260200101819052508560800151848280611ad190615b87565b935081518110611ae357611ae3615b73565b602002602001018181525050611b0d8a61022001518960c001518a608001518d6101a00151612b55565b611b2a5760405163a2a2ac8360e01b815260040160405180910390fd5b5f8a6102600151905080848381518110611b4657611b46615b73565b6020026020010181905250886101000151858381518110611b6957611b69615b73565b602002602001018181525050611b7d615338565b611b878587612eb8565b8152611b9282612fb0565b602082018190528c5182515f92611baa929190612ff6565b90505f5f611bba8f5f0151613087565b91509150611bc782613148565b611bd081613148565b8351611bdd9083856131e7565b84526020840151611bef9082856131e7565b602085018190528451611c0191613216565b9f9e505050505050505050505050505050565b611c1c615024565b50604080516103e081018252620200008152601160208083019190915261024382840152825180840184527f3046224394ac0664c5df0bbff473db8485b523993c3378b647785875fbda56e581527f075b8449cf262130cd0d53747c76da002a74053958060ee7c8e930b7f729af4e818301526060830152825180840184527f23f894967a8d0ad87a02976c74accf68659348a280e6c1ab3f99dad7b8cf4bc481527f21acfe5f2f788aee6ca1b87420abfb1b567605edbfc9de6cbff67aa99eb633b8818301526080830152825180840184527f2d8eb0ef0769af9b60944c9c1f9aef88f4458599d8d53d5700e57c463d3d248181527f067d884aca949978f4410a65ef7addb04f9e8a13536c428fbe9d71beb988a3218183015260a0830152825180840184527f04f478772f21c19f23074f73f4cafc722ade3b71fd3e674504df4d488e70844f81527f256ede28a442453cee32d59a1ae23e10ad9765b8cd5aa917f613437e401d03df8183015260c0830152825180840184527f296c0719e6414ccc762949a1eb297b40c46b886179cf2ba5d3660b218aa9a72881527f219d51db4d209022eaa607152a2ddc23b94fb99be6ed4b2f158ed46b21faceb88183015260e0830152825180840184527f0cf55eebb61a0e90c6f9fd68c4839012c6433b88fafff66701ab99c6975e6da381527f1f44b9a9447265fad2e8c326a3cfd26d434ed9eece6c2d5b5586f8232572d76581830152610100830152825180840184527f11beb2731ab8cf46c0a52666bb457fa74d4b635043bb5689a35a2aee24990b8081527f2f1fba989036c44aedb609d0d3341ccb842c2d1cd7c80cea4a95d0eb4530577081830152610120830152825180840184527f2d70068023998c277c75458b7b6eb1fe3c479eb044dec7aa3384d7b5049542c781527f10af4b4ffb3c03f9c906e4dd1cf3c21dc74139881dfa7ad73c25370424f3978181830152610140830152825180840184527f0d07902b3266cd4af955bac93e3579b0bc1bcd754c7b70035cc95877d641376c81527f195d808eeb35965b8df7ea80461dcc033e5d8d0ef25b028a1d429e52b33f3f0d81830152610160830152825180840184527f24ec1ac19b9f052e9e2c4270db9b317502859b163514073401512c675318823881527f28869fd3c9b2ad1ce8a966e9225bed7eac600c656be6891317404dc44726736781830152610180830152825180840184527f201e0e19e72484d21e8136546fe6aaeea2d5b6413019276eada6638ffeb2ce8a81527eba5238e406d8d46f68dc3b00a201ad10d2dc97beed32f5e83d051e742b2642818301526101a0830152825180840184527f2656809e98f3dee7945c4f48c6fff3c0833412aeeae84dada472462112fa8fe981527f2454353d981df4ae6c3fd37c4a7b5114bcb1416f43efc627d55e128449c7c14d818301526101c0830152825180840184527f1fb5e9c3ae41ba815444512a4e882619ac69f0cbb639657adeadb93ed50895b181527f201d42c30be1a478f6c6a28159a335c02fa3dc3e6c6843089c648bfd4dc8c250818301526101e0830152825180840184527f1375207e60c7d651a62aed70d2496e2324a7dc718de86e5887f805f907d4964081527f22a964f903d1faa46e20c6f8902415d61985c86bbeef23a01b6ca1718dfe80c581830152610200830152825180840184527f2a38162537d04323884347c1f31f76b03a04ec2f6f9c4b125d5d322932ff65ba81527f2465da5aac067658f2f98944a8ba1bc9fd81c2220d22f07995746a7b7deccd2981830152610220830152825180840184527f2a12695e6fa7a23c3519eee6d96433bb00d51cd274de90288914e3fb336334b681527f235e728947aff729c4ade5a63ca501273a958075ae1281bb612012f03219601681830152610240830152825180840184527f09e5efa8f84174e74fe0429a76ec404c053a4f8c3e5524d68e3cd4e338a2b4b881527f057873d3cf1d8589310604f6f203386d9a9928d980432f5316522d84e6eecb6181830152610260830152825180840184527f096a6fb164d4a53c869c12d0369ef747bbbd3f40e5dd997c01e32495b64b07cb81527f01198ac63b80d1d160ab5882da3dfc3a8864b70b72c31790e55fec5014c4436281830152610280830152825180840184527f085cbd5bb5a6a7a0407ad624e78b82be37c9c90a9c5de9302004bc406bc1778d81527f2a4cbd271054bf508c73ffeab6e321bba811248126e552f55701993aed192e4b818301526102a0830152825180840184527f1a89bfbff2ee55715a55cf0de0d6a1c62183bbaae9d200a5247b58f170cbbc7c81527f0ae77530f6cad79672428f376996a91ce1358fea5f49180218f18a7918f80bb3818301526102c0830152825180840184527f1faa95912a219c90e3cdbe1e78b25d6f79d4ca8ef1cd9fd3a8a6b87f94d138f281527f22a4b4a860838e96fcc07839e0c9742c2dbe4aa634664da1e24570a1dc4156fd818301526102e0830152825180840184527f1d11efcd01d1170fc229d305654298122dd323cc9ae7e16ad2f0bfa56a0f9e2e81527f225cd914fa8180a343e93ee8a0e87e2d850b8ca6e03267e5281f7ace3dd82ab581830152610300830152825180840184527f099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d2681527e15b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f81830152610320830152825180840184527f1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e81527f305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d1981830152610340830152825180840184527f061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d81527f1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e81830152610360830152825180840184527f043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce81527f261522c4089330646aff96736194949330952ae74c573d1686d9cb4a007338548183015261038083015282518084018452600181526002818301526103a083015282518084019093527f1af84073758283d4c848fed9bc6f055831baf81a643050fceafadf8da1791eec83527f1be165956a9c6a29edc2a4d21793a6fb1f00a6967720f870ebb2f2c6b267e9dd908301526103c081019190915290565b5f6103f461255c8385615b9f565b612657565b612569615320565b60408051808201909152805f516020615c6e5f395f51905f5261258f60205f8789615b4c565b61259891615b9f565b6125a29190615bbc565b81526020908101905f516020615c6e5f395f51905f52906125c7906040908789615b4c565b6125d091615b9f565b6125da9190615bbc565b90529392505050565b5f5f516020615c8e5f395f51905f52825b0692915050565b5f5f516020615c8e5f395f51905f5282840990505b92915050565b5f5f516020615c8e5f395f51905f528284089392505050565b5f5f516020615c8e5f395f51905f52825f516020615c8e5f395f51905f520384089392505050565b5f5f516020615c8e5f395f51905f52826125f4565b5f6103f4836108cc8461296a565b5f5f604051806101200160405280619d8081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec5181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31815260200161024081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd3181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec518152602001619d8081525090505f600190505f5f90505b600981101561277357612769826108cc878461262f565b9150600101612752565b5061277c61534b565b5f5b60098110156127cd576127ae610d5685836009811061279f5761279f615b73565b60200201516108cc898561262f565b8282600981106127c0576127c0615b73565b602002015260010161277e565b505f5b600981101561281357612809856108d18984600981106127f2576127f2615b73565b6020020151858560098110610bce57610bce615b73565b94506001016127d0565b5061281e84836125fb565b9695505050505050565b5f61283161536a565b61283c86828561340a565b612848868683866135b6565b612854868683866137a2565b61285f8682856139c7565b61286a868285613bbb565b61287686868386613f04565b6128818682856143b0565b61288c8682856147c2565b612897868285614b83565b61281e8185614e83565b60605f826001600160401b038111156128bc576128bc615940565b6040519080825280602002602001820160405280156128e5578160200160208202803683370190505b50905083815f815181106128fb576128fb615b73565b602090810291909101015260015b838110156129625761293d826129206001846155e0565b8151811061293057612930615b73565b6020026020010151612b4a565b82828151811061294f5761294f615b73565b6020908102919091010152600101612909565b509392505050565b5f5f8290505f604051602081526020808201526020604082015282606082015260025f516020615c8e5f395f51905f520360808201525f516020615c8e5f395f51905f5260a082015260205f60c08360055afa806129c6575f5ffd5b505f51608091909101604052949350505050565b5f516020615c8e5f395f51905f520390565b60605f826001600160401b03811115612a0757612a07615940565b604051908082528060200260200182016040528015612a30578160200160208202803683370190505b509050825b8015612b3f575f85612a486001846155e0565b81518110612a5857612a58615b73565b602002602001015190505f89600184612a7191906155e0565b601c8110612a8157612a81615b73565b602002015190505f612adc612aa0612a99858d6125fb565b60026125fb565b6108ef8b612aaf6001896155e0565b601c8110612abf57612abf615b73565b60200201516108cc612ad6886108cc60018a61262f565b8761262f565b9050612afd816108cc610d56612af7876108cc60018961262f565b86612616565b99508990508085612b0f6001876155e0565b81518110612b1f57612b1f615b73565b60200260200101818152505050505080612b3890615bdb565b9050612a35565b509695505050505050565b5f61261082836125fb565b5f600181612b6e612b6887610100614edc565b8361262f565b905080612b8e5760405163835eb8f760e01b815260040160405180910390fd5b612b96615389565b80518390525f5b7f0000000000000000000000000000000000000000000000000000000000000000811015612c7f575f612bd18260096155c9565b612bdc906001615b39565b905084835f0151826101008110612bf557612bf5615b73565b60200201525f612c06826001615b39565b90505b612c14600983615b39565b811015612c75578351612c5490612c2c6001846155e0565b6101008110612c3d57612c3d615b73565b60200201518a85601c8110610bce57610bce615b73565b8451826101008110612c6857612c68615b73565b6020020152600101612c09565b5050600101612b9d565b50608081018390525f602082018190525b610100811015612d9057612cb1612cab83608001518a6125fb565b8561262f565b8260a00151826101008110612cc857612cc8615b73565b602002015260a0820151612cf290826101008110612ce857612ce8615b73565b602002015161296a565b8260a00151826101008110612d0957612d09615b73565b602002018181525050612d4f82602001516108d1845f0151846101008110612d3357612d33615b73565b60200201518560a00151856101008110610bce57610bce615b73565b60208301526080820151612d83907f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d66125fb565b6080830152600101612c90565b505f612da1836108cc61010061296a565b9050612db18260200151826125fb565b602083015260a0820151612dcc905f5b6020020151826125fb565b604083015260a0820151612df890612de760016101006155e0565b6101008110612dc157612dc1615b73565b60608301526040820151612e0e908a6002610bce565b60c08301819052612e6e906108d1612e468b7f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d661262f565b60208d015160408e01516108cc91612e5d9161262f565b8e5160208901516108ef91906125fb565b60c083018190526060830151612ea391612e97916108d1906108cc8e600260200201518c61262f565b6108ef858c6003610bce565b60c08301819052159998505050505050505050565b612ec0615320565b7f00000000000000000000000000000000000000000000000000000000000000005f5b81811015612f1557612f0d858281518110612f0057612f00615b73565b6020026020010151613148565b600101612ee3565b50604051600190815b60018401811015612f7a5760208102870160208202870181515160408501528151602001516060850152805160808501525050604080830160606040850160075afa8316925060408260808460065afa90921691600101612f1e565b5080518452602081015160208501525080612fa8576040516352ec174560e11b815260040160405180910390fd5b505092915050565b612fb8615320565b5f516020615c6e5f395f51905f5282602001515f516020615c6e5f395f51905f52612fe391906155e0565b612fed9190615bbc565b60208301525090565b5f5f5f61300286613087565b9150915061300e6153cd565b82518152602080840151818301528251604080840191909152838201516060840152875160808401528782015160a0840152865160c08401528682015160e08401525161307c9161306191849101615bf0565b60405160208183030381529060405280519060200120612657565b979650505050505050565b61308f615320565b613097615320565b82516020808501516040860151606087015160cc90811b608892831b604494851b90961795909517949094178652608087015160a088015160c089015160e08a0151871b90841b91851b9092171717868401526101008701516101208801516101408901516101608a0151871b90841b91851b909217171785526101808701516101a08801516101c08901516101e09099015190951b9790911b9390911b1791909117939093179281019290925291565b805160208201515f5f516020615c6e5f395f51905f528380095f516020615c6e5f395f51905f5260035f516020615c6e5f395f51905f52838709085f516020615c6e5f395f51905f5284850914915050806131e15760405162461bcd60e51b8152602060048201526019602482015278706f696e74206973206e6f74206f6e2074686520637572766560381b60448201526064016100e5565b50505050565b6131ef615320565b6131f7615320565b6132018386614f3d565b905061320d8185614f93565b95945050505050565b81516020808401518351848301516040805194850195909552938301919091527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260608301527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60808301527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b60a08301527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60c083015260e08201526101008101919091527f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c16101208201527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b06101408201527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe46101608201527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101808201525f9081906101a00160405160208183030381529060405290505f5f60086001600160a01b0316836040516133ac9190615c24565b5f60405180830381855afa9150503d805f81146133e4576040519150601f19603f3d011682016040523d82523d5f602084013e6133e9565b606091505b509150915081801561281e57508080602001905181019061281e9190615c3a565b5f613416846007614ff4565b90507f183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f80000005f61347761347161344b85600361262f565b6108cc61346661345b8b5f614ff4565b6108cc8c601d614ff4565b6108cc8b601c614ff4565b836125fb565b90506134f86134ed6134d46134bb6134a2856108d16134978d6002614ff4565b6108cc8e601c614ff4565b6108d16134b08c6003614ff4565b6108cc8d601d614ff4565b6108d16134c98b6004614ff4565b6108cc8c601e614ff4565b6108d16134e28a6005614ff4565b6108cc8b601f614ff4565b6108d1886001614ff4565b9050613517816108d161350c86600161262f565b6108cc8a6027614ff4565b905061352381846125fb565b905061352f81856125fb565b8552505f905061356961355f61355461354988601c614ff4565b6108d189601f614ff4565b6108ef886024614ff4565b6108d1875f614ff4565b905061357a816108cc84600261262f565b905061358b816108cc84600161262f565b905061359781836125fb565b90506135a381846125fb565b9050808460015b60200201525050505050565b5f5f5f6135ec6135e26135ca89601c614ff4565b6108d16135d88b6012614ff4565b8a606001516125fb565b8760800151612616565b9050613625816108cc61361b6136038b601d614ff4565b6108d16136118d6013614ff4565b8c606001516125fb565b8960800151612616565b905061364a816108cc61361b61363c8b601e614ff4565b6108d16136118d6014614ff4565b905061366f816108cc61361b6136618b601f614ff4565b6108d16136118d6015614ff4565b92505f90506136936135e261368589601c614ff4565b6108d16135d88b600e614ff4565b90506136b8816108cc61361b6136aa8b601d614ff4565b6108d16136118d600f614ff4565b90506136dd816108cc61361b6136cf8b601e614ff4565b6108d16136118d6010614ff4565b9050613702816108cc61361b6136f48b601f614ff4565b6108d16136118d6011614ff4565b91505f9050613729613723613718896020614ff4565b6108d18a601a614ff4565b846125fb565b905061375e816108ef6137586137408b6028614ff4565b6108d161374e8d601b614ff4565b8c60a001516125fb565b856125fb565b905061376a81856125fb565b6040860152505f61378d61375861378289601b614ff4565b6108cc8a6028614ff4565b9050808560035b602002015250505050505050565b5f5f6138006137e86137d06137bb61361b8a6016614ff4565b6108d16137c98b6017614ff4565b8a516125fb565b6108d16137de8a6018614ff4565b89602001516125fb565b6108d16137f6896019614ff4565b88604001516125fb565b91505f61383761381e61381489601c614ff4565b8860800151612616565b6108d161382c8a6003614ff4565b6108cc8b6024614ff4565b90505f61386061384889601d614ff4565b6108d16138558b5f614ff4565b6108cc8c6025614ff4565b90505f61388a6138718a601e614ff4565b6108d161387f8c6001614ff4565b6108cc8d6026614ff4565b90506138c96138b16138a3856108d1868d5f01516125fb565b6108d1848c602001516125fb565b6108d16138bf8c6004614ff4565b8b604001516125fb565b93505050505f6138dd613723886021614ff4565b90505f6138ee613723896021614ff4565b90505f61392661390d6139028b6023614ff4565b6108d18c6006614ff4565b6108ef61391b8c6023614ff4565b6108cc8d6006614ff4565b90505f613944612b6861393987896125fb565b6108cc8d6021614ff4565b905061395081886125fb565b90505f61397861396a6139648d6006614ff4565b876125fb565b6108ef6139648e6022614ff4565b90505f6139868c6023614ff4565b90505f613996612b6883846125fb565b60808c0185905260a08c0184905290506139b0818b6125fb565b8b6006602002015250505050505050505050505050565b5f6139d35f600161262f565b90505f6139e15f600261262f565b90505f6139ef5f600361262f565b90505f613a0b613a0088601d614ff4565b6108ef89601c614ff4565b90505f613a27613a1c89601e614ff4565b6108ef8a601d614ff4565b90505f613a43613a388a601f614ff4565b6108ef8b601e614ff4565b90505f613a5f613a548b6024614ff4565b6108ef8c601f614ff4565b905083613a70816108cc818b612616565b9050613a80816108cc878a612616565b9050613a90816108cc8789612616565b9050613aa1816108cc8d6008614ff4565b9050613aad818a6125fb565b60e08b01525082613ac2816108cc818b612616565b9050613ad2816108cc868a612616565b9050613ae2816108cc8689612616565b9050613af3816108cc8d6008614ff4565b9050613aff818a6125fb565b6101008b01525081613b15816108cc818b612616565b9050613b25816108cc858a612616565b9050613b35816108cc8589612616565b9050613b46816108cc8d6008614ff4565b9050613b52818a6125fb565b6101208b01525080613b68816108cc818b612616565b9050613b78816108cc848a612616565b9050613b88816108cc8489612616565b9050613b99816108cc8d6008614ff4565b9050613ba5818a6125fb565b610140909a019990995250505050505050505050565b613bf46040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613bff84601d614ff4565b8152613c0c84601e614ff4565b6020820152613c1c846024614ff4565b6040820152613c2c846027614ff4565b6060820152613c3c846026614ff4565b6080820152613c4c846025614ff4565b60a08201525f613c5d856002614ff4565b90505f613c6a865f614ff4565b90505f613c7e8460400151855f015161262f565b90505f613c93856020015186602001516125fb565b606086015190915086905f90613ca990806125fb565b90505f613cc7613cc189602001518a606001516125fb565b886125fb565b90505f613ce6613cdf8a60a001518b60400151612616565b8a51612616565b9050613cf561396482886125fb565b9050613d1c613d16613d10613d0a848761262f565b8861262f565b84612616565b83612616565b9050613d44613d39613d2e83876125fb565b6108cc8f6009614ff4565b6108cc60018a61262f565b6101608c015250505050602085015160808601515f91613d6391612616565b90505f613d81613d778860600151886125fb565b886020015161262f565b90505f613da5613d9184876125fb565b6108d16137588b60a001518c5f015161262f565b9050613dcd613dc2613db7838c6125fb565b6108cc8e6009614ff4565b6108cc60018961262f565b6101808b0152505f9150613dee9050613de7836011612616565b87516125fb565b90505f613dfb8384612616565b9050613e078182612616565b90505f613e158360096125fb565b9050613e3e613e38613723613e318b60a001518c5f0151612616565b8b51612616565b8261262f565b60c089018190525f90613e5990613cc190613d2e908d6125fb565b9050613e6c8b600b602002015182612616565b6101608c0152505086515f9250613e939150613de790613e8c9080612616565b8851612616565b90505f613ed3613eae836108cc8a5f01518b60a0015161262f565b60208901516108ef90613ec19080612616565b6108cc8b602001518c60800151612616565b9050613ef089600c60200201516108d1613cc1613d2e858d6125fb565b89600c602002015250505050505050505050565b613f6e604051806101e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613f86613f7c86601e614ff4565b85604001516125fb565b808252613fa5906108d1613f9b88601d614ff4565b87602001516125fb565b808252613fba906108d1613de788601c614ff4565b808252613fcc906108d1876001614ff4565b80825260208201819052613fe5906108ef87601f614ff4565b8152614000613ff5866024614ff4565b6108ef87601c614ff4565b608082015261401e614013866027614ff4565b6108ef87601f614ff4565b60608201526080810151614037906108cc81600161262f565b6101c082015260808101516140779061406d90614066906108cc60015f516020615c8e5f395f51905f526155e0565b6001612616565b82606001516125fb565b60a082018190526140ad9061409f906108cc614094896002614ff4565b6108cc8a6003614ff4565b6108cc61375888600a614ff4565b83600e60200201526101c08101516140d19061409f906108cc614094896002614ff4565b6101e084015280516140f6906108cc6140eb886002614ff4565b6108cc896003614ff4565b6101208201525f61411561410b87601f614ff4565b836020015161262f565b9050614126816108cc83600161262f565b60e0830152614143614139876026614ff4565b86604001516125fb565b60408301819052614166906108d161415c896025614ff4565b88602001516125fb565b60408301819052614186906108d161417f896024614ff4565b88516125fb565b60408301526141a3614199876027614ff4565b836040015161262f565b60408301525f6141c26141b7886026614ff4565b6108ef89601e614ff4565b90506142146141ef613471614066866080015160015f516020615c8e5f395f51905f526108cc91906155e0565b6108cc614066866040015160015f516020615c8e5f395f51905f526108cc91906155e0565b60c084015260408301516142369061422c90806125fb565b846040015161262f565b61010084015260c083015161426290614254906108cc8a6004614ff4565b6108cc6139648a600a614ff4565b6102008601526101c083015161428190614254906108cc8a6004614ff4565b6102208601526101008301516142a090614254906108cc8a6004614ff4565b61024086015260e08301516142ba906108cc896004614ff4565b6101408401526142d96142ce886025614ff4565b6108ef89601d614ff4565b6101608401526080830151614317906141b79061430c90614066906108cc60015f516020615c8e5f395f51905f526155e0565b8561016001516125fb565b61018084018190526101208401516101a0850181905261434e916108d1906108cc6143438c6005614ff4565b6108cc8d6002614ff4565b6101a08401819052835161436e91906108d1906108cc6143438c5f614ff4565b6101a084018190526101408401516143869190612616565b6101a084018190526143a0906108cc6139648a600a614ff4565b6101a0840181905285600d613794565b6143e96040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61441e6144056143fa86601c614ff4565b6108cc876025614ff4565b6108d1614413876024614ff4565b6108cc88601d614ff4565b815261446361445861443f61443487601c614ff4565b6108cc88601f614ff4565b6108d161444d88601d614ff4565b6108cc89601e614ff4565b6108ef866026614ff4565b6040820181905261447890600160441b6125fb565b6040820181905261448e906108ef866027614ff4565b6040820181905281516144a19190612616565b604082018190526144b7906108cc866005614ff4565b604082015280516144cc90600160441b6125fb565b8082526144ec906108d16144e1876024614ff4565b6108cc886025614ff4565b80825260208201819052614513906108ef61450887601e614ff4565b6108d188601f614ff4565b60208201819052614529906108cc866004614ff4565b6020820152805160608201819052614546906108d186601f614ff4565b6060820181905261456a906108ef61455f876026614ff4565b6108d1886027614ff4565b6060820181905261457f906108cc865f614ff4565b8160600181815250505f6145a861459e83602001518460400151612616565b8360600151612616565b90506145b9816108cc876003614ff4565b90506145d16145c9866025614ff4565b6140006125fb565b608083018190526145e7906108d1876024614ff4565b608083018190526145fa906140006125fb565b60808301819052614610906108d187601e614ff4565b60808301819052614623906140006125fb565b60808301819052614639906108d187601d614ff4565b6080830181905261464c906140006125fb565b60808301819052614662906108d187601c614ff4565b60808301819052614678906108ef87601f614ff4565b6080830181905261468e906108cc876005614ff4565b60808301526146a16145c9866026614ff4565b60a083018190526146b7906108d1876025614ff4565b60a083018190526146ca906140006125fb565b60a083018190526146e0906108d1876024614ff4565b60a083018190526146f3906140006125fb565b60a08301819052614709906108d187601f614ff4565b60a0830181905261471c906140006125fb565b60a08301819052614732906108d187601e614ff4565b60a08301819052614748906108ef876027614ff4565b60a0830181905261475d906108cc875f614ff4565b60a0830181905260808301515f916147759190612616565b9050614786816108cc886004614ff4565b90506147928282612616565b60c084018190526147ab906108cc61396489600b614ff4565b60c084018190528560136020020152505050505050565b6148386040518061022001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61485161484685601c614ff4565b6108d1866002614ff4565b815261486c61486185601d614ff4565b6108d1866003614ff4565b602082015261488a61487f85601e614ff4565b6108d1866004614ff4565b60408201526148a861489d85601f614ff4565b6108d1866005614ff4565b606082015280516148da906148d3906148cc906148c590806125fb565b84516125fb565b83516125fb565b82516125fb565b608082015260208101516149189061490e90614904906148fa90806125fb565b84602001516125fb565b83602001516125fb565b82602001516125fb565b60a082015260408101516149569061494c906149429061493890806125fb565b84604001516125fb565b83604001516125fb565b82604001516125fb565b60c0820152606081015161498a9061406d906149809061497690806125fb565b84606001516125fb565b83606001516125fb565b60e0820152608081015160a08201516149a39190612616565b61010082015260c081015160e08201516149bd9190612616565b61012082015260a08101516149e1906149d69080612616565b826101200151612616565b61014082015260e0810151614a05906149fa9080612616565b826101000151612616565b610160820152610120810151614a1b9080612616565b6101e08201819052614a3c90614a319080612616565b826101600151612616565b6101e0820152610100810151614a529080612616565b6101a08201819052614a7390614a689080612616565b826101400151612616565b6101a08201819052610160820151614a8a91612616565b6101808201526101408101516101e0820151614aa69190612616565b6101c0820152614aba61347185600c614ff4565b6102008201819052610280840151610180830151614ae5926108d1916108cc906108ef8a6024614ff4565b8360146020020152614b1583601560200201516108d18361020001516108cc856101a001516108ef8a6025614ff4565b8360156020020152614b4583601660200201516108d18361020001516108cc856101c001516108ef8a6026614ff4565b8360166020020152614b7583601760200201516108d18361020001516108cc856101e001516108ef8a6027614ff4565b836017602002015250505050565b614bd56040518061016001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f6040518060800160405280614c0a7f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e76125e3565b8152602001614c387f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b6125e3565b8152602001614c657e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac156125e3565b8152602001614c937f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b6125e3565b90529050614cb0614ca586601c614ff4565b6108d1876002614ff4565b6101208301819052614cef90614ce490614cd990614cce90806125fb565b8561012001516125fb565b8461012001516125fb565b8361012001516125fb565b8252614cfc85601d614ff4565b6020830152614d0c85601e614ff4565b6040830152614d1c85601f614ff4565b606083015281516020830151614d449161459e91614d3a9190612616565b8460400151612616565b6080830152614d5761372386600d614ff4565b6101408301528151614d7890614d6e90835f610bce565b8360800151612616565b60a0830152614da484601860200201516108d18461014001516108cc8660a001516108ef8b6024614ff4565b6103008501526020820151614dbf90614d6e90836001610bce565b60c0830152614deb84601960200201516108d18461014001516108cc8660c001516108ef8b6025614ff4565b6103208501526040820151614e0690614d6e90836002610bce565b60e0830152614e3284601a60200201516108d18461014001516108cc8660e001516108ef8b6026614ff4565b6103408501526060820151614e4d90614d6e90836003610bce565b610100830152614e7b84601b60200201516108d18461014001516108cc8661010001516108ef8b6027614ff4565b84601b6135aa565b815160015b601c811015614ed557614ecb826108d18684601c8110614eaa57614eaa615b73565b602002015186614ebb6001876155e0565b601b8110610bce57610bce615b73565b9150600101614e88565b5092915050565b5f5f8390505f60405160208152602080820152602060408201528260608201528460808201525f516020615c8e5f395f51905f5260a082015260205f60c08360055afa80614f28575f5ffd5b505f5160809190910160405295945050505050565b614f45615320565b614f4d615320565b604051835181526020840151602082015284604082015260408160608360075afa80614f77575f5ffd5b5080518252602080820151908301526060016040529392505050565b614f9b615320565b614fa3615320565b6040518451815260208501516020820152835160408201526020840151606082015260408160808360065afa80614fd8575f5ffd5b5080518252602080820151908301526080016040529392505050565b5f8282602881111561500857615008615c59565b6029811061501857615018615b73565b60200201519392505050565b604051806103e001604052805f81526020015f81526020015f815260200161504a615320565b8152602001615057615320565b8152602001615064615320565b8152602001615071615320565b815260200161507e615320565b815260200161508b615320565b8152602001615098615320565b81526020016150a5615320565b81526020016150b2615320565b81526020016150bf615320565b81526020016150cc615320565b81526020016150d9615320565b81526020016150e6615320565b81526020016150f3615320565b8152602001615100615320565b815260200161510d615320565b815260200161511a615320565b8152602001615127615320565b8152602001615134615320565b8152602001615141615320565b815260200161514e615320565b815260200161515b615320565b8152602001615168615320565b8152602001615175615320565b8152602001615182615320565b815260200161518f615320565b815260200161519c615320565b81526020016151a9615320565b905290565b6040518061028001604052806151c26153ec565b81526020016151cf615320565b81526020016151dc615320565b81526020016151e9615320565b81526020016151f6615320565b8152602001615203615320565b8152602001615210615320565b815260200161521d615320565b815260200161522a615320565b8152602001615237615320565b815260200161524461540b565b81526020015f8152602001615257615438565b81526020015f815260200161526a615466565b8152602001615277615485565b815260200161528461536a565b815260200161518f6154b3565b6040518061052001604052806029906020820280368337509192915050565b604051806101c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020016152ee6154b3565b81526020016152fb6154b3565b81526020015f81526020015f81526020015f81526020015f8152602001606081525090565b60405180604001604052805f81526020015f81525090565b604051806040016040528061519c615320565b6040518061012001604052806009906020820280368337509192915050565b604051806103800160405280601c906020820280368337509192915050565b6040518060e0016040528061539c6154d1565b81526020015f81526020015f81526020015f81526020015f81526020016153c16154d1565b81526020015f81525090565b6040518061010001604052806008906020820280368337509192915050565b6040518061020001604052806010906020820280368337509192915050565b60405180606001604052806003905b615422615320565b81526020019060019003908161541a5790505090565b604051806103800160405280601c905b61545061534b565b8152602001906001900390816154485790505090565b604051806105400160405280602a906020820280368337509192915050565b604051806103600160405280601b905b61549d615320565b8152602001906001900390816154955790505090565b60405180608001604052806004906020820280368337509192915050565b604051806120000160405280610100906020820280368337509192915050565b5f5f5f5f60408587031215615504575f5ffd5b84356001600160401b03811115615519575f5ffd5b8501601f81018713615529575f5ffd5b80356001600160401b0381111561553e575f5ffd5b87602082840101111561554f575f5ffd5b6020918201955093508501356001600160401b0381111561556e575f5ffd5b8501601f8101871361557e575f5ffd5b80356001600160401b03811115615593575f5ffd5b8760208260051b84010111156155a7575f5ffd5b949793965060200194505050565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417612610576126106155b5565b81810381811115612610576126106155b5565b805f5b60108110156131e15781518452602093840193909101906001016155f6565b805f5b60038110156131e15761563684835180518252602090810151910152565b6040939093019260209190910190600101615618565b805f5b601c8110156131e1578151845f5b600981101561567c57825182526020928301929091019060010161565d565b50505061012093909301926020919091019060010161564f565b805f5b602a8110156131e1578151845260209384019390910190600101615699565b805f5b601b8110156131e1576156d984835180518252602090810151910152565b60409390930192602091909101906001016156bb565b805f5b601c8110156131e15781518452602093840193909101906001016156f2565b805f5b60048110156131e1578151845260209384019390910190600101615714565b8183525f6001600160fb1b0383111561574a575f5ffd5b8260051b80836020870137939093016020019392505050565b61576e8188516155f3565b5f602088015161578c61020084018280518252602090810151910152565b5060408801518051610240840152602090810151610260840152606089015180516102808501528101516102a0840152608089015180516102c08501528101516102e084015260a0890151805161030085015281015161032084015260c0890151805161034085015281015161036084015260e089015180516103808501528101516103a084015261010089015180516103c08501528101516103e084015261012089015180516104008501520151610420830152610140880151615855610440840182615615565b5061016088015161050083015261018088015161587661052084018261564c565b506101a08801516124a08301526101c08801516158976124c0840182615696565b506101e08801516158ac612a008401826156b8565b506102008801516158c16130c08401826156ef565b506102208801516158d6613440840182615711565b5061024088015180516134c08401526020908101516134e0840152610260890151805161350085015201516135208301526135c0613540830181905261591f9083018789615733565b613560830195909552506135808101929092526135a0909101529392505050565b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b038111828210171561597757615977615940565b60405290565b604051601f8201601f191681016001600160401b03811182821017156159a5576159a5615940565b604052919050565b5f60c082840312156159bd575f5ffd5b60405160c081016001600160401b03811182821017156159df576159df615940565b604090815283518252602080850151908301528381015190820152606080840151908201526080808401519082015260a0928301519281019290925250919050565b5f82601f830112615a30575f5ffd5b5f610360615a3d8161597d565b915083018185821115615a4e575f5ffd5b845b82811015615a68578051825260209182019101615a50565b509195945050505050565b5f82601f830112615a82575f5ffd5b5f610380615a3d8161597d565b5f610be0828403128015615aa1575f5ffd5b50615aaa615954565b615ab484846159ad565b8152615ac38460c08501615a21565b6020820152615ad6846104208501615a73565b60408201526107a08301516060820152615af4846107c08501615a73565b6080820152610b4083015160a0820152610b6083015160c0820152610b8083015160e0820152610ba0830151610100820152610bc09092015161012083015250919050565b80820180821115612610576126106155b5565b5f5f85851115615b5a575f5ffd5b83861115615b66575f5ffd5b5050820193919092039150565b634e487b7160e01b5f52603260045260245ffd5b5f60018201615b9857615b986155b5565b5060010190565b80356020831015612610575f19602084900360031b1b1692915050565b5f82615bd657634e487b7160e01b5f52601260045260245ffd5b500690565b5f81615be957615be96155b5565b505f190190565b5f8183825b6008811015615c14578151835260209283019290910190600101615bf5565b5050506101008201905092915050565b5f82518060208501845e5f920191825250919050565b5f60208284031215615c4a575f5ffd5b815180151581146103f4575f5ffd5b634e487b7160e01b5f52602160045260245ffdfe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4730644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a164736f6c634300081c000a", + "bytecode": "0x610120604052348015610010575f5ffd5b50620200006080819052601160a08190527f1a888222f07de9fba8c8456b3e25b3abe8f5a37ba2fb1cb1e5c24a19dcb8977f60c08190526101a260e081905260038361005e6001602461008b565b610068919061008b565b610072919061008b565b61007d90600261008b565b61010052506100b092505050565b808201808211156100aa57634e487b7160e01b5f52601160045260245ffd5b92915050565b60805160a05160c05160e05161010051615cba61014a5f395f8181610c5401528181610cb90152612ec201525f81816101b001526108ff01525f61018e01525f8181605b01528181609401528181610101015281816101d201528181610a2d01528181610b8e01528181610c2b01528181611523015281816115dd015281816116100152818161181a0152612b9f01525f5050615cba5ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063ea50d0e41461002d575b5f5ffd5b61004061003b3660046154f1565b610054565b604051901515815260200160405180910390f35b5f5f61007f7f00000000000000000000000000000000000000000000000000000000000000006102ee565b905061008c8160206155c9565b85146100ee577f0000000000000000000000000000000000000000000000000000000000000000856100bf8360206155c9565b6040516359895a5360e01b81526004810193909352602483019190915260448201526064015b60405180910390fd5b5f6100f76103fb565b90505f61012588887f0000000000000000000000000000000000000000000000000000000000000000610410565b90506010826040015161013891906155e0565b85146101575760405163fa06659360e01b815260040160405180910390fd5b60405163995bf45760e01b81525f9073__$d0188790065ac172f94fde8676855b6381$__9063995bf457906101fa9085908b908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090600401615763565b610be060405180830381865af4158015610216573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061023a9190615a8f565b905061028a8787808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050855185516060810151608090910151919350915060016108a9565b815160a0015261029a8282610a10565b6102b7576040516313f8744360e31b815260040160405180910390fd5b6102c2828483610c17565b6102df576040516352ec174560e11b815260040160405180910390fd5b50600198975050505050505050565b5f8060026102fe60016008615b39565b61030891906155c9565b9050610316600260036155c9565b6103209082615b39565b9050600161032f6009856155c9565b61033991906155c9565b6103439082615b39565b90506001610352816029615b39565b61035c91906155c9565b6103669082615b39565b9050610374600160026155c9565b61037e9082615b39565b905061038b6001846155c9565b6103959082615b39565b90506103a3600160046155c9565b6103ad9082615b39565b905060026103bc6001856155e0565b6103c691906155c9565b6103d09082615b39565b90506103dd6002806155c9565b6103e79082615b39565b90506103f4601082615b39565b9392505050565b610403615024565b61040b611c14565b905090565b6104186151ae565b5f805b601081101561047a57610447868387610435602083615b39565b9261044293929190615b4c565b61254e565b8351826010811061045a5761045a615b73565b6020020181815250506020826104709190615b39565b915060010161041b565b5061049e85828661048c604083615b39565b9261049993929190615b4c565b612561565b60208301526104ae604082615b39565b90506104c185828661048c604083615b39565b6040808401919091526104d49082615b39565b90506104e785828661048c604083615b39565b60608301526104f7604082615b39565b905061050a85828661048c604083615b39565b608083015261051a604082615b39565b905061052d85828661048c604083615b39565b60c083015261053d604082615b39565b905061055085828661048c604083615b39565b60e0830152610560604082615b39565b905061057385828661048c604083615b39565b60a0830152610583604082615b39565b905061059685828661048c604083615b39565b6101008301526105a7604082615b39565b90506105ba85828661048c604083615b39565b6101208301526105cb604082615b39565b90506105de85828661048c604083615b39565b610140830151526105f0604082615b39565b9050610603858286610435602083615b39565b610160830152610614602082615b39565b90505f5b83811015610692575f5b60098110156106895761063c878488610435602083615b39565b84610180015183601c811061065357610653615b73565b6020020151826009811061066957610669615b73565b60200201818152505060208361067f9190615b39565b9250600101610622565b50600101610618565b505f5b6106a160016029615b39565b8110156106f0576106b9868387610435602083615b39565b836101c0015182602a81106106d0576106d0615b73565b6020020181815250506020826106e69190615b39565b9150600101610695565b50610702858286610435602083615b39565b6101a0830152610713602082615b39565b905061072685828661048c604083615b39565b6101408301516020015261073b604082615b39565b905061074e85828661048c604083615b39565b61014083015160026020020152610766604082615b39565b90505f5b6107756001856155e0565b8110156107be5761078d86838761048c604083615b39565b836101e0015182601b81106107a4576107a4615b73565b60200201526107b4604083615b39565b915060010161076a565b505f5b83811015610811576107da868387610435602083615b39565b83610200015182601c81106107f1576107f1615b73565b6020020181815250506020826108079190615b39565b91506001016107c1565b505f5b60048110156108655761082e868387610435602083615b39565b836102200151826004811061084557610845615b73565b60200201818152505060208261085b9190615b39565b9150600101610814565b5061087785828661048c604083615b39565b610240830152610888604082615b39565b905061089b85828661048c604083615b39565b610260830152509392505050565b5f600180826108d6866108d1896108cc6108c78a6310000000615b39565b6125e3565b6125fb565b612616565b90505f6108f4876108ef8a6108cc6108c78b6001615b39565b61262f565b90505f5b61092360107f00000000000000000000000000000000000000000000000000000000000000006155e0565b811015610990575f61094d8c838151811061094057610940615b73565b6020026020010151612657565b905061095d866108cc8684612616565b955061096d856108cc8584612616565b9450610979848b612616565b9350610985838b61262f565b9250506001016108f8565b505f5b60108110156109f7575f8a82601081106109af576109af615b73565b602002015190506109c4866108cc8684612616565b95506109d4856108cc8584612616565b94506109e0848b612616565b93506109ec838b61262f565b925050600101610993565b50610a02848461266c565b9a9950505050505050505050565b5f5f610a2583606001518561016001516125fb565b905060015f5b7f0000000000000000000000000000000000000000000000000000000000000000811015610b17575f86610180015182601c8110610a6b57610a6b615b73565b602002015180519091505f90610a89908360015b6020020151612616565b9050848114610aab576040516313f8744360e31b815260040160405180910390fd5b5f876080015184601c8110610ac257610ac2615b73565b60200201519050610ad3838261267a565b9550610b07856108cc60016108d1856108cc8e604001518b601c8110610afb57610afb615b73565b6020020151600161262f565b9450505050806001019050610a2b565b50610b20615291565b5f5b6029811015610b70576101c0870151610b3c600183615b39565b602a8110610b4c57610b4c615b73565b6020020151828260298110610b6357610b63615b73565b6020020152600101610b22565b505f610b8582875f0151886020015186612828565b9050600160025b7f0000000000000000000000000000000000000000000000000000000000000000811015610be257610bd882896080015183601c8110610bce57610bce615b73565b60200201516125fb565b9150600101610b8c565b50610c08610bf5836108cc60018561262f565b6108d18a6101a001518a606001516125fb565b94909414979650505050505050565b5f610c206152b0565b5f610c4f8460c001517f00000000000000000000000000000000000000000000000000000000000000006128a1565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610c8a57610c8a615940565b604051908082528060200260200182016040528015610cb3578160200160208202803683370190505b5090505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610cef57610cef615940565b604051908082528060200260200182016040528015610d2857816020015b610d15615320565b815260200190600190039081610d0d5790505b509050610d5b610d56876101000151855f81518110610d4957610d49615b73565b602002602001015161262f565b61296a565b84610120018181525050610d90610d56876101000151855f81518110610d8357610d83615b73565b6020026020010151612616565b610140850181905261012085015160e0880151610db1926108d191906125fb565b845260c0860151610de190610dc59061296a565b6108cc8661012001516108ef8a60e001518961014001516125fb565b6020850152815160019083905f90610dfb57610dfb615b73565b602002602001018181525050876102400151815f81518110610e1f57610e1f615b73565b6020908102919091010152600160a08501525f60c08501528351610e42906129da565b60408501526020840151610e55906129da565b606085015260015b610e6960016024615b39565b8111610f0a57610e8185604001518660a001516125fb565b838281518110610e9357610e93615b73565b602002602001018181525050610edc8560c001516108d18b6101c00151600185610ebd91906155e0565b602a8110610ecd57610ecd615b73565b60200201518860a001516125fb565b60c086015260a08086015190880151610ef591906125fb565b60a0860152610f0381615b87565b9050610e5d565b505f5b6005811015610fe3575f610f22601e83615b39565b90505f610f3160016024615b39565b610f3b9084615b39565b9050610f6c858381518110610f5257610f52615b73565b60200260200101516108d189606001518a60a001516125fb565b858381518110610f7e57610f7e615b73565b602002602001018181525050610fbb8760c001516108d18d6101c0015184602a8110610fac57610fac615b73565b60200201518a60a001516125fb565b60c088015260a080880151908a0151610fd491906125fb565b60a08801525050600101610f0d565b50876020015181600181518110610ffc57610ffc615b73565b602002602001018190525086606001518160028151811061101f5761101f615b73565b602002602001018190525086608001518160038151811061104257611042615b73565b60200260200101819052508660a001518160048151811061106557611065615b73565b60200260200101819052508660c001518160058151811061108857611088615b73565b60200260200101819052508660e00151816006815181106110ab576110ab615b73565b6020026020010181905250866101000151816007815181106110cf576110cf615b73565b6020026020010181905250866101200151816008815181106110f3576110f3615b73565b60200260200101819052508661014001518160098151811061111757611117615b73565b602002602001018190525086610160015181600a8151811061113b5761113b615b73565b6020026020010181905250866101c0015181600b8151811061115f5761115f615b73565b602002602001018190525086610180015181600c8151811061118357611183615b73565b6020026020010181905250866101a0015181600d815181106111a7576111a7615b73565b6020026020010181905250866101e0015181600e815181106111cb576111cb615b73565b602002602001018190525086610200015181600f815181106111ef576111ef615b73565b60200260200101819052508661022001518160108151811061121357611213615b73565b60200260200101819052508661024001518160118151811061123757611237615b73565b60200260200101819052508661026001518160128151811061125b5761125b615b73565b60200260200101819052508661028001518160138151811061127f5761127f615b73565b6020026020010181905250866102a00151816014815181106112a3576112a3615b73565b6020026020010181905250866102c00151816015815181106112c7576112c7615b73565b6020026020010181905250866102e00151816016815181106112eb576112eb615b73565b60200260200101819052508661030001518160178151811061130f5761130f615b73565b60200260200101819052508661032001518160188151811061133357611333615b73565b60200260200101819052508661034001518160198151811061135757611357615b73565b602002602001018190525086610360015181601a8151811061137b5761137b615b73565b602002602001018190525086610380015181601b8151811061139f5761139f615b73565b6020026020010181905250866103a0015181601c815181106113c3576113c3615b73565b6020026020010181905250866103c0015181601d815181106113e7576113e7615b73565b6020026020010181905250876040015181601e8151811061140a5761140a615b73565b6020026020010181905250876060015181601f8151811061142d5761142d615b73565b602002602001018190525087608001518160208151811061145057611450615b73565b60200260200101819052508760a001518160218151811061147357611473615b73565b60200260200101819052508761012001518160228151811061149757611497615b73565b6020026020010181905250876101000151816023815181106114bb576114bb615b73565b60200260200101819052508760c00151816024815181106114de576114de615b73565b60200260200101819052508760e001518160258151811061150157611501615b73565b60200260200101819052505f61154787608001518660c001518b6102000151877f00000000000000000000000000000000000000000000000000000000000000006129ec565b9050611571815f8151811061155e5761155e615b73565b60200260200101518661012001516125fb565b608086018190526102008a01515160e08901516115a292916108d19161159791906125fb565b8861014001516125fb565b608086015260e08701516115b590612b4a565b60a08601525f6115c760016024615b39565b6115d2906001615b39565b90505f5b61160160017f00000000000000000000000000000000000000000000000000000000000000006155e0565b811015611812575f61163460017f00000000000000000000000000000000000000000000000000000000000000006155e0565b8210159050806117a357611668610d568b6101000151898560016116589190615b39565b81518110610d4957610d49615b73565b6101208901526101008a015161169890610d569089611688866001615b39565b81518110610d8357610d83615b73565b61014089015260a08801516101208901516116b391906125fb565b61016089015260a088015160e08b01516116db916116d0916125fb565b8961014001516125fb565b61018089018190526116fe906116f0906129da565b6108d18a61016001516129da565b866117098486615b39565b8151811061171957611719615b73565b6020026020010181815250505f6117528961018001518e61020001518560016117429190615b39565b601c8110610bce57610bce615b73565b905061178c816108d18b61016001518887600161176f9190615b39565b8151811061177f5761177f615b73565b60200260200101516125fb565b905061179c896080015182612616565b60808a0152505b6117c26117b88960a001518c60e001516125fb565b8b60e001516125fb565b60a08901526101e08c015182601b81106117de576117de615b73565b6020020151856117ee8486615b39565b815181106117fe576117fe615b73565b6020908102919091010152506001016115d6565b5061183e60017f00000000000000000000000000000000000000000000000000000000000000006155e0565b6118489082615b39565b90506118686118608961010001518a60c0015161262f565b60019061266c565b60e08701515261010088015160c08901516118ac91611860916108ef907f07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76906125fb565b60e0878101805160200192909252815180516040909101529051805160609091015260a0870151908901516118ee916118e4916125fb565b8960e001516125fb565b60a08701525f5b600481101561199c575f6119278860e00151836004811061191857611918615b73565b60200201518960a001516125fb565b9050611932816129da565b886101000151836004811061194957611949615b73565b602002015260a088015160e08b015161196291906125fb565b8860a001818152505061198e88608001516108d1838f61022001518660048110610bce57610bce615b73565b6080890152506001016118f5565b506101008601515184518590839081106119b8576119b8615b73565b602090810291909101810191909152610100870151908101516119dc916002610a7f565b846119e8836001615b39565b815181106119f8576119f8615b73565b60209081029190910101526101008601516060015184611a19836002615b39565b81518110611a2957611a29615b73565b60209081029190910101525f5b6003811015611a8b578a61014001518160038110611a5657611a56615b73565b60200201518483611a6681615b87565b945081518110611a7857611a78615b73565b6020908102919091010152600101611a36565b506040518060400160405280600181526020016002815250838281518110611ab557611ab5615b73565b60200260200101819052508560800151848280611ad190615b87565b935081518110611ae357611ae3615b73565b602002602001018181525050611b0d8a61022001518960c001518a608001518d6101a00151612b55565b611b2a5760405163a2a2ac8360e01b815260040160405180910390fd5b5f8a6102600151905080848381518110611b4657611b46615b73565b6020026020010181905250886101000151858381518110611b6957611b69615b73565b602002602001018181525050611b7d615338565b611b878587612eb8565b8152611b9282612fb0565b602082018190528c5182515f92611baa929190612ff6565b90505f5f611bba8f5f0151613087565b91509150611bc782613148565b611bd081613148565b8351611bdd9083856131e7565b84526020840151611bef9082856131e7565b602085018190528451611c0191613216565b9f9e505050505050505050505050505050565b611c1c615024565b50604080516103e08101825262020000815260116020808301919091526101a282840152825180840184527f13637737c33db244a3712ce1f84f4a6400935882acd540419ff5fc19166ea61881527f15e894c35784b66acc688f1d787868569692c5761fa71b84ab52a3b2c1dd41a8818301526060830152825180840184527f16daf8e28d24b787f5a311fc0930d1d495f74cb0eba1780ae0d36610a1ab587081527f220aa4f565987b5544214f4aa9477fd03cbb82e8a57a2aeaa21968038c2af3a5818301526080830152825180840184527f2c0c47eac6980c002be7c5f4633a8bd6d5d0fc9e6651e541b141fc02557ca48d81527f1ca159a1bbe1a8c82eb796fba79bcdff36d3fb98c986996878fdf102d6a12ab98183015260a0830152825180840184527f1c05ee47a359c77501f8bb557929e27f64523630d83a818cd364994cadcaf8c581527f2f8e9947f0eab4542b5e684bbc807466bc192c42d7fce467125769936b4536f58183015260c0830152825180840184527f082a6fc7457baf2a604ae295f701031e54ede6a34d88f93f5e7aaeb2a213312181527f20ecb56a891971bc2cf9bc98cdc00fc8ec720de344999055300f979e749ec93d8183015260e0830152825180840184527f265c425247eed132b40b111b5a7c14d7d9db56aefbf71eeec0b2cc09dd66a6b381527f3054e4ee825da9852d2fc5172b24c4ffbdfd315f13fce4b498379c566604897e81830152610100830152825180840184527f163a3285e23ec78bb34d3c6122f47c770ee1f228ed2dda996542bade7a8bc2e481527f188245f34ba632acb17885f4be308c9551dbfd5095069e7077281d144e55044b81830152610120830152825180840184527f1913712d01550fa30bf15a28a13902738529edfc1ddc730c5bc57c00514fd3b481527f1f125db8f6315e55f2b20ba6863482eac90d77f6c6289efb0d6a6c740be172cd81830152610140830152825180840184527f26ce5fb2dc4d867f0f6957729e6158fe7d6924445514b4c485f0b093195cff4881527f102d0d1aa8a400a6f7e233d512ed7205fcb3eb0ba5c0d54041f23b25f58a4c5781830152610160830152825180840184527f0ff4dd20d4821b5ca6738a69881d693c04c892bade4b929a311c6612d94ffbc281527f19fcce46268bf02b94f4486494e361d2c126372f35e0583d55825134c2ee88cc81830152610180830152825180840184527f018d6d017a26c5c223931a63ee8ad0ef37f9f9f0caba099d8d8482e95b6f46e881527f0ed38b925edf5f9b54e2b5289074d64999010264d2a4eae8fc53b8e38fc10b6b818301526101a0830152825180840184527f1a08892e26c7c33a003d075a86a9edd8cdf253009e26fa7b2ac7f4339ca07ce381527f09383a35fb9f67045a070c939b0d947454f64cd92bcf90838b2163bc0e071b58818301526101c0830152825180840184527f0d2f53319bc2e321ef88e47d0a3a35b0f35728ed7b7790dd357ecda4ea55a57b81527f074497f78eec311b533ca170dc19e81c0cf5a22dce7bdf938841ff71e8cbdc8d818301526101e0830152825180840184527f0cde2682ddd264dcac5b0e5626164271411bca898cd8beb4c98536534ffe3e6981527f20f8bfa3f9ed612f481072d20715601f08415ecbb5092b8dae96a15c583ac77081830152610200830152825180840184527f2dc45f069a801ce507391a5d369024e6c0a8f508426efa10efec079f652943fd81527f0ca193ecd89783532ab900689868dfa9713a57dd313c222bfa2d1ee92c5a1ec981830152610220830152825180840184527f18f0b7ba3135bb08f1e312928b750b6bacb9776a9e8a3d30d1da58873083baa681527f1ed01d844f4aee867147b3eb571130d0e37c0686151a13106aeb40936713c09381830152610240830152825180840184527f2787d437215fba393c1bb6e8bc91cdf1f5c75cb93b1eb8b522819a6cfc71507c81527f027ea99429a3d006c4d01411577bf6ac562f7811b4d64e7ff060351468d63b6b81830152610260830152825180840184527f0d0f4f0fa40d68989657a0feee08deed1f08355b066c778578bfbf430cc2d22b81527f2d9d81c8732bf6991afa6657818d09e17fe8bfb40f59301a7b992fc8f2a9d1e981830152610280830152825180840184527ea673368cf560b1069debee688c082cda349df8fbacc711f845dc7960acdeba81527f0234d1b5f65d17aaf71d51ae744b28b6a024bface3333ea19ef58c8c2fc38595818301526102a0830152825180840184527f29353e7eeeae9d8cf7bc6bac6961a44a69fe7b38396fc4b07d416b226fbecc3d81527f012d0615aad587261d1403ca95322f67b6e64382ac7346503bb61ee8ff465ffd818301526102c0830152825180840184527f0dddb0066cbe44ac884fe3658ad6c24943d3329fd839b8dd47b37e0b334f3efc81527f1a54ecfb49945a189bd28fa28103f9ad98d08107f8d68167d96417d95297903f818301526102e0830152825180840184527f271c4df54fa64ddca42889abf3e4559c2aa59525ea5a1858fadae4b6eb6f140681527f06f10a564e9397fc800ffbb6b4c887df1d1e4eeb6dd8cd4f789916e31836f19781830152610300830152825180840184527f099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d2681527e15b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f81830152610320830152825180840184527f1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e81527f305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d1981830152610340830152825180840184527f061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d81527f1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e81830152610360830152825180840184527f043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce81527f261522c4089330646aff96736194949330952ae74c573d1686d9cb4a007338548183015261038083015282518084018452600181526002818301526103a083015282518084019093527f0602bc9d2460bf21b73d27154ff5f8919350545f3cb6dc7f40dae014613bc4c683527f1df576b5b16064433355e8bad62265096027978ab6496527059305dbd8708565908301526103c081019190915290565b5f6103f461255c8385615b9f565b612657565b612569615320565b60408051808201909152805f516020615c6e5f395f51905f5261258f60205f8789615b4c565b61259891615b9f565b6125a29190615bbc565b81526020908101905f516020615c6e5f395f51905f52906125c7906040908789615b4c565b6125d091615b9f565b6125da9190615bbc565b90529392505050565b5f5f516020615c8e5f395f51905f52825b0692915050565b5f5f516020615c8e5f395f51905f5282840990505b92915050565b5f5f516020615c8e5f395f51905f528284089392505050565b5f5f516020615c8e5f395f51905f52825f516020615c8e5f395f51905f520384089392505050565b5f5f516020615c8e5f395f51905f52826125f4565b5f6103f4836108cc8461296a565b5f5f604051806101200160405280619d8081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec5181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31815260200161024081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd3181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec518152602001619d8081525090505f600190505f5f90505b600981101561277357612769826108cc878461262f565b9150600101612752565b5061277c61534b565b5f5b60098110156127cd576127ae610d5685836009811061279f5761279f615b73565b60200201516108cc898561262f565b8282600981106127c0576127c0615b73565b602002015260010161277e565b505f5b600981101561281357612809856108d18984600981106127f2576127f2615b73565b6020020151858560098110610bce57610bce615b73565b94506001016127d0565b5061281e84836125fb565b9695505050505050565b5f61283161536a565b61283c86828561340a565b612848868683866135b6565b612854868683866137a2565b61285f8682856139c7565b61286a868285613bbb565b61287686868386613f04565b6128818682856143b0565b61288c8682856147c2565b612897868285614b83565b61281e8185614e83565b60605f826001600160401b038111156128bc576128bc615940565b6040519080825280602002602001820160405280156128e5578160200160208202803683370190505b50905083815f815181106128fb576128fb615b73565b602090810291909101015260015b838110156129625761293d826129206001846155e0565b8151811061293057612930615b73565b6020026020010151612b4a565b82828151811061294f5761294f615b73565b6020908102919091010152600101612909565b509392505050565b5f5f8290505f604051602081526020808201526020604082015282606082015260025f516020615c8e5f395f51905f520360808201525f516020615c8e5f395f51905f5260a082015260205f60c08360055afa806129c6575f5ffd5b505f51608091909101604052949350505050565b5f516020615c8e5f395f51905f520390565b60605f826001600160401b03811115612a0757612a07615940565b604051908082528060200260200182016040528015612a30578160200160208202803683370190505b509050825b8015612b3f575f85612a486001846155e0565b81518110612a5857612a58615b73565b602002602001015190505f89600184612a7191906155e0565b601c8110612a8157612a81615b73565b602002015190505f612adc612aa0612a99858d6125fb565b60026125fb565b6108ef8b612aaf6001896155e0565b601c8110612abf57612abf615b73565b60200201516108cc612ad6886108cc60018a61262f565b8761262f565b9050612afd816108cc610d56612af7876108cc60018961262f565b86612616565b99508990508085612b0f6001876155e0565b81518110612b1f57612b1f615b73565b60200260200101818152505050505080612b3890615bdb565b9050612a35565b509695505050505050565b5f61261082836125fb565b5f600181612b6e612b6887610100614edc565b8361262f565b905080612b8e5760405163835eb8f760e01b815260040160405180910390fd5b612b96615389565b80518390525f5b7f0000000000000000000000000000000000000000000000000000000000000000811015612c7f575f612bd18260096155c9565b612bdc906001615b39565b905084835f0151826101008110612bf557612bf5615b73565b60200201525f612c06826001615b39565b90505b612c14600983615b39565b811015612c75578351612c5490612c2c6001846155e0565b6101008110612c3d57612c3d615b73565b60200201518a85601c8110610bce57610bce615b73565b8451826101008110612c6857612c68615b73565b6020020152600101612c09565b5050600101612b9d565b50608081018390525f602082018190525b610100811015612d9057612cb1612cab83608001518a6125fb565b8561262f565b8260a00151826101008110612cc857612cc8615b73565b602002015260a0820151612cf290826101008110612ce857612ce8615b73565b602002015161296a565b8260a00151826101008110612d0957612d09615b73565b602002018181525050612d4f82602001516108d1845f0151846101008110612d3357612d33615b73565b60200201518560a00151856101008110610bce57610bce615b73565b60208301526080820151612d83907f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d66125fb565b6080830152600101612c90565b505f612da1836108cc61010061296a565b9050612db18260200151826125fb565b602083015260a0820151612dcc905f5b6020020151826125fb565b604083015260a0820151612df890612de760016101006155e0565b6101008110612dc157612dc1615b73565b60608301526040820151612e0e908a6002610bce565b60c08301819052612e6e906108d1612e468b7f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d661262f565b60208d015160408e01516108cc91612e5d9161262f565b8e5160208901516108ef91906125fb565b60c083018190526060830151612ea391612e97916108d1906108cc8e600260200201518c61262f565b6108ef858c6003610bce565b60c08301819052159998505050505050505050565b612ec0615320565b7f00000000000000000000000000000000000000000000000000000000000000005f5b81811015612f1557612f0d858281518110612f0057612f00615b73565b6020026020010151613148565b600101612ee3565b50604051600190815b60018401811015612f7a5760208102870160208202870181515160408501528151602001516060850152805160808501525050604080830160606040850160075afa8316925060408260808460065afa90921691600101612f1e565b5080518452602081015160208501525080612fa8576040516352ec174560e11b815260040160405180910390fd5b505092915050565b612fb8615320565b5f516020615c6e5f395f51905f5282602001515f516020615c6e5f395f51905f52612fe391906155e0565b612fed9190615bbc565b60208301525090565b5f5f5f61300286613087565b9150915061300e6153cd565b82518152602080840151818301528251604080840191909152838201516060840152875160808401528782015160a0840152865160c08401528682015160e08401525161307c9161306191849101615bf0565b60405160208183030381529060405280519060200120612657565b979650505050505050565b61308f615320565b613097615320565b82516020808501516040860151606087015160cc90811b608892831b604494851b90961795909517949094178652608087015160a088015160c089015160e08a0151871b90841b91851b9092171717868401526101008701516101208801516101408901516101608a0151871b90841b91851b909217171785526101808701516101a08801516101c08901516101e09099015190951b9790911b9390911b1791909117939093179281019290925291565b805160208201515f5f516020615c6e5f395f51905f528380095f516020615c6e5f395f51905f5260035f516020615c6e5f395f51905f52838709085f516020615c6e5f395f51905f5284850914915050806131e15760405162461bcd60e51b8152602060048201526019602482015278706f696e74206973206e6f74206f6e2074686520637572766560381b60448201526064016100e5565b50505050565b6131ef615320565b6131f7615320565b6132018386614f3d565b905061320d8185614f93565b95945050505050565b81516020808401518351848301516040805194850195909552938301919091527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260608301527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60808301527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b60a08301527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60c083015260e08201526101008101919091527f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c16101208201527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b06101408201527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe46101608201527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101808201525f9081906101a00160405160208183030381529060405290505f5f60086001600160a01b0316836040516133ac9190615c24565b5f60405180830381855afa9150503d805f81146133e4576040519150601f19603f3d011682016040523d82523d5f602084013e6133e9565b606091505b509150915081801561281e57508080602001905181019061281e9190615c3a565b5f613416846007614ff4565b90507f183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f80000005f61347761347161344b85600361262f565b6108cc61346661345b8b5f614ff4565b6108cc8c601d614ff4565b6108cc8b601c614ff4565b836125fb565b90506134f86134ed6134d46134bb6134a2856108d16134978d6002614ff4565b6108cc8e601c614ff4565b6108d16134b08c6003614ff4565b6108cc8d601d614ff4565b6108d16134c98b6004614ff4565b6108cc8c601e614ff4565b6108d16134e28a6005614ff4565b6108cc8b601f614ff4565b6108d1886001614ff4565b9050613517816108d161350c86600161262f565b6108cc8a6027614ff4565b905061352381846125fb565b905061352f81856125fb565b8552505f905061356961355f61355461354988601c614ff4565b6108d189601f614ff4565b6108ef886024614ff4565b6108d1875f614ff4565b905061357a816108cc84600261262f565b905061358b816108cc84600161262f565b905061359781836125fb565b90506135a381846125fb565b9050808460015b60200201525050505050565b5f5f5f6135ec6135e26135ca89601c614ff4565b6108d16135d88b6012614ff4565b8a606001516125fb565b8760800151612616565b9050613625816108cc61361b6136038b601d614ff4565b6108d16136118d6013614ff4565b8c606001516125fb565b8960800151612616565b905061364a816108cc61361b61363c8b601e614ff4565b6108d16136118d6014614ff4565b905061366f816108cc61361b6136618b601f614ff4565b6108d16136118d6015614ff4565b92505f90506136936135e261368589601c614ff4565b6108d16135d88b600e614ff4565b90506136b8816108cc61361b6136aa8b601d614ff4565b6108d16136118d600f614ff4565b90506136dd816108cc61361b6136cf8b601e614ff4565b6108d16136118d6010614ff4565b9050613702816108cc61361b6136f48b601f614ff4565b6108d16136118d6011614ff4565b91505f9050613729613723613718896020614ff4565b6108d18a601a614ff4565b846125fb565b905061375e816108ef6137586137408b6028614ff4565b6108d161374e8d601b614ff4565b8c60a001516125fb565b856125fb565b905061376a81856125fb565b6040860152505f61378d61375861378289601b614ff4565b6108cc8a6028614ff4565b9050808560035b602002015250505050505050565b5f5f6138006137e86137d06137bb61361b8a6016614ff4565b6108d16137c98b6017614ff4565b8a516125fb565b6108d16137de8a6018614ff4565b89602001516125fb565b6108d16137f6896019614ff4565b88604001516125fb565b91505f61383761381e61381489601c614ff4565b8860800151612616565b6108d161382c8a6003614ff4565b6108cc8b6024614ff4565b90505f61386061384889601d614ff4565b6108d16138558b5f614ff4565b6108cc8c6025614ff4565b90505f61388a6138718a601e614ff4565b6108d161387f8c6001614ff4565b6108cc8d6026614ff4565b90506138c96138b16138a3856108d1868d5f01516125fb565b6108d1848c602001516125fb565b6108d16138bf8c6004614ff4565b8b604001516125fb565b93505050505f6138dd613723886021614ff4565b90505f6138ee613723896021614ff4565b90505f61392661390d6139028b6023614ff4565b6108d18c6006614ff4565b6108ef61391b8c6023614ff4565b6108cc8d6006614ff4565b90505f613944612b6861393987896125fb565b6108cc8d6021614ff4565b905061395081886125fb565b90505f61397861396a6139648d6006614ff4565b876125fb565b6108ef6139648e6022614ff4565b90505f6139868c6023614ff4565b90505f613996612b6883846125fb565b60808c0185905260a08c0184905290506139b0818b6125fb565b8b6006602002015250505050505050505050505050565b5f6139d35f600161262f565b90505f6139e15f600261262f565b90505f6139ef5f600361262f565b90505f613a0b613a0088601d614ff4565b6108ef89601c614ff4565b90505f613a27613a1c89601e614ff4565b6108ef8a601d614ff4565b90505f613a43613a388a601f614ff4565b6108ef8b601e614ff4565b90505f613a5f613a548b6024614ff4565b6108ef8c601f614ff4565b905083613a70816108cc818b612616565b9050613a80816108cc878a612616565b9050613a90816108cc8789612616565b9050613aa1816108cc8d6008614ff4565b9050613aad818a6125fb565b60e08b01525082613ac2816108cc818b612616565b9050613ad2816108cc868a612616565b9050613ae2816108cc8689612616565b9050613af3816108cc8d6008614ff4565b9050613aff818a6125fb565b6101008b01525081613b15816108cc818b612616565b9050613b25816108cc858a612616565b9050613b35816108cc8589612616565b9050613b46816108cc8d6008614ff4565b9050613b52818a6125fb565b6101208b01525080613b68816108cc818b612616565b9050613b78816108cc848a612616565b9050613b88816108cc8489612616565b9050613b99816108cc8d6008614ff4565b9050613ba5818a6125fb565b610140909a019990995250505050505050505050565b613bf46040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613bff84601d614ff4565b8152613c0c84601e614ff4565b6020820152613c1c846024614ff4565b6040820152613c2c846027614ff4565b6060820152613c3c846026614ff4565b6080820152613c4c846025614ff4565b60a08201525f613c5d856002614ff4565b90505f613c6a865f614ff4565b90505f613c7e8460400151855f015161262f565b90505f613c93856020015186602001516125fb565b606086015190915086905f90613ca990806125fb565b90505f613cc7613cc189602001518a606001516125fb565b886125fb565b90505f613ce6613cdf8a60a001518b60400151612616565b8a51612616565b9050613cf561396482886125fb565b9050613d1c613d16613d10613d0a848761262f565b8861262f565b84612616565b83612616565b9050613d44613d39613d2e83876125fb565b6108cc8f6009614ff4565b6108cc60018a61262f565b6101608c015250505050602085015160808601515f91613d6391612616565b90505f613d81613d778860600151886125fb565b886020015161262f565b90505f613da5613d9184876125fb565b6108d16137588b60a001518c5f015161262f565b9050613dcd613dc2613db7838c6125fb565b6108cc8e6009614ff4565b6108cc60018961262f565b6101808b0152505f9150613dee9050613de7836011612616565b87516125fb565b90505f613dfb8384612616565b9050613e078182612616565b90505f613e158360096125fb565b9050613e3e613e38613723613e318b60a001518c5f0151612616565b8b51612616565b8261262f565b60c089018190525f90613e5990613cc190613d2e908d6125fb565b9050613e6c8b600b602002015182612616565b6101608c0152505086515f9250613e939150613de790613e8c9080612616565b8851612616565b90505f613ed3613eae836108cc8a5f01518b60a0015161262f565b60208901516108ef90613ec19080612616565b6108cc8b602001518c60800151612616565b9050613ef089600c60200201516108d1613cc1613d2e858d6125fb565b89600c602002015250505050505050505050565b613f6e604051806101e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613f86613f7c86601e614ff4565b85604001516125fb565b808252613fa5906108d1613f9b88601d614ff4565b87602001516125fb565b808252613fba906108d1613de788601c614ff4565b808252613fcc906108d1876001614ff4565b80825260208201819052613fe5906108ef87601f614ff4565b8152614000613ff5866024614ff4565b6108ef87601c614ff4565b608082015261401e614013866027614ff4565b6108ef87601f614ff4565b60608201526080810151614037906108cc81600161262f565b6101c082015260808101516140779061406d90614066906108cc60015f516020615c8e5f395f51905f526155e0565b6001612616565b82606001516125fb565b60a082018190526140ad9061409f906108cc614094896002614ff4565b6108cc8a6003614ff4565b6108cc61375888600a614ff4565b83600e60200201526101c08101516140d19061409f906108cc614094896002614ff4565b6101e084015280516140f6906108cc6140eb886002614ff4565b6108cc896003614ff4565b6101208201525f61411561410b87601f614ff4565b836020015161262f565b9050614126816108cc83600161262f565b60e0830152614143614139876026614ff4565b86604001516125fb565b60408301819052614166906108d161415c896025614ff4565b88602001516125fb565b60408301819052614186906108d161417f896024614ff4565b88516125fb565b60408301526141a3614199876027614ff4565b836040015161262f565b60408301525f6141c26141b7886026614ff4565b6108ef89601e614ff4565b90506142146141ef613471614066866080015160015f516020615c8e5f395f51905f526108cc91906155e0565b6108cc614066866040015160015f516020615c8e5f395f51905f526108cc91906155e0565b60c084015260408301516142369061422c90806125fb565b846040015161262f565b61010084015260c083015161426290614254906108cc8a6004614ff4565b6108cc6139648a600a614ff4565b6102008601526101c083015161428190614254906108cc8a6004614ff4565b6102208601526101008301516142a090614254906108cc8a6004614ff4565b61024086015260e08301516142ba906108cc896004614ff4565b6101408401526142d96142ce886025614ff4565b6108ef89601d614ff4565b6101608401526080830151614317906141b79061430c90614066906108cc60015f516020615c8e5f395f51905f526155e0565b8561016001516125fb565b61018084018190526101208401516101a0850181905261434e916108d1906108cc6143438c6005614ff4565b6108cc8d6002614ff4565b6101a08401819052835161436e91906108d1906108cc6143438c5f614ff4565b6101a084018190526101408401516143869190612616565b6101a084018190526143a0906108cc6139648a600a614ff4565b6101a0840181905285600d613794565b6143e96040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61441e6144056143fa86601c614ff4565b6108cc876025614ff4565b6108d1614413876024614ff4565b6108cc88601d614ff4565b815261446361445861443f61443487601c614ff4565b6108cc88601f614ff4565b6108d161444d88601d614ff4565b6108cc89601e614ff4565b6108ef866026614ff4565b6040820181905261447890600160441b6125fb565b6040820181905261448e906108ef866027614ff4565b6040820181905281516144a19190612616565b604082018190526144b7906108cc866005614ff4565b604082015280516144cc90600160441b6125fb565b8082526144ec906108d16144e1876024614ff4565b6108cc886025614ff4565b80825260208201819052614513906108ef61450887601e614ff4565b6108d188601f614ff4565b60208201819052614529906108cc866004614ff4565b6020820152805160608201819052614546906108d186601f614ff4565b6060820181905261456a906108ef61455f876026614ff4565b6108d1886027614ff4565b6060820181905261457f906108cc865f614ff4565b8160600181815250505f6145a861459e83602001518460400151612616565b8360600151612616565b90506145b9816108cc876003614ff4565b90506145d16145c9866025614ff4565b6140006125fb565b608083018190526145e7906108d1876024614ff4565b608083018190526145fa906140006125fb565b60808301819052614610906108d187601e614ff4565b60808301819052614623906140006125fb565b60808301819052614639906108d187601d614ff4565b6080830181905261464c906140006125fb565b60808301819052614662906108d187601c614ff4565b60808301819052614678906108ef87601f614ff4565b6080830181905261468e906108cc876005614ff4565b60808301526146a16145c9866026614ff4565b60a083018190526146b7906108d1876025614ff4565b60a083018190526146ca906140006125fb565b60a083018190526146e0906108d1876024614ff4565b60a083018190526146f3906140006125fb565b60a08301819052614709906108d187601f614ff4565b60a0830181905261471c906140006125fb565b60a08301819052614732906108d187601e614ff4565b60a08301819052614748906108ef876027614ff4565b60a0830181905261475d906108cc875f614ff4565b60a0830181905260808301515f916147759190612616565b9050614786816108cc886004614ff4565b90506147928282612616565b60c084018190526147ab906108cc61396489600b614ff4565b60c084018190528560136020020152505050505050565b6148386040518061022001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61485161484685601c614ff4565b6108d1866002614ff4565b815261486c61486185601d614ff4565b6108d1866003614ff4565b602082015261488a61487f85601e614ff4565b6108d1866004614ff4565b60408201526148a861489d85601f614ff4565b6108d1866005614ff4565b606082015280516148da906148d3906148cc906148c590806125fb565b84516125fb565b83516125fb565b82516125fb565b608082015260208101516149189061490e90614904906148fa90806125fb565b84602001516125fb565b83602001516125fb565b82602001516125fb565b60a082015260408101516149569061494c906149429061493890806125fb565b84604001516125fb565b83604001516125fb565b82604001516125fb565b60c0820152606081015161498a9061406d906149809061497690806125fb565b84606001516125fb565b83606001516125fb565b60e0820152608081015160a08201516149a39190612616565b61010082015260c081015160e08201516149bd9190612616565b61012082015260a08101516149e1906149d69080612616565b826101200151612616565b61014082015260e0810151614a05906149fa9080612616565b826101000151612616565b610160820152610120810151614a1b9080612616565b6101e08201819052614a3c90614a319080612616565b826101600151612616565b6101e0820152610100810151614a529080612616565b6101a08201819052614a7390614a689080612616565b826101400151612616565b6101a08201819052610160820151614a8a91612616565b6101808201526101408101516101e0820151614aa69190612616565b6101c0820152614aba61347185600c614ff4565b6102008201819052610280840151610180830151614ae5926108d1916108cc906108ef8a6024614ff4565b8360146020020152614b1583601560200201516108d18361020001516108cc856101a001516108ef8a6025614ff4565b8360156020020152614b4583601660200201516108d18361020001516108cc856101c001516108ef8a6026614ff4565b8360166020020152614b7583601760200201516108d18361020001516108cc856101e001516108ef8a6027614ff4565b836017602002015250505050565b614bd56040518061016001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f6040518060800160405280614c0a7f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e76125e3565b8152602001614c387f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b6125e3565b8152602001614c657e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac156125e3565b8152602001614c937f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b6125e3565b90529050614cb0614ca586601c614ff4565b6108d1876002614ff4565b6101208301819052614cef90614ce490614cd990614cce90806125fb565b8561012001516125fb565b8461012001516125fb565b8361012001516125fb565b8252614cfc85601d614ff4565b6020830152614d0c85601e614ff4565b6040830152614d1c85601f614ff4565b606083015281516020830151614d449161459e91614d3a9190612616565b8460400151612616565b6080830152614d5761372386600d614ff4565b6101408301528151614d7890614d6e90835f610bce565b8360800151612616565b60a0830152614da484601860200201516108d18461014001516108cc8660a001516108ef8b6024614ff4565b6103008501526020820151614dbf90614d6e90836001610bce565b60c0830152614deb84601960200201516108d18461014001516108cc8660c001516108ef8b6025614ff4565b6103208501526040820151614e0690614d6e90836002610bce565b60e0830152614e3284601a60200201516108d18461014001516108cc8660e001516108ef8b6026614ff4565b6103408501526060820151614e4d90614d6e90836003610bce565b610100830152614e7b84601b60200201516108d18461014001516108cc8661010001516108ef8b6027614ff4565b84601b6135aa565b815160015b601c811015614ed557614ecb826108d18684601c8110614eaa57614eaa615b73565b602002015186614ebb6001876155e0565b601b8110610bce57610bce615b73565b9150600101614e88565b5092915050565b5f5f8390505f60405160208152602080820152602060408201528260608201528460808201525f516020615c8e5f395f51905f5260a082015260205f60c08360055afa80614f28575f5ffd5b505f5160809190910160405295945050505050565b614f45615320565b614f4d615320565b604051835181526020840151602082015284604082015260408160608360075afa80614f77575f5ffd5b5080518252602080820151908301526060016040529392505050565b614f9b615320565b614fa3615320565b6040518451815260208501516020820152835160408201526020840151606082015260408160808360065afa80614fd8575f5ffd5b5080518252602080820151908301526080016040529392505050565b5f8282602881111561500857615008615c59565b6029811061501857615018615b73565b60200201519392505050565b604051806103e001604052805f81526020015f81526020015f815260200161504a615320565b8152602001615057615320565b8152602001615064615320565b8152602001615071615320565b815260200161507e615320565b815260200161508b615320565b8152602001615098615320565b81526020016150a5615320565b81526020016150b2615320565b81526020016150bf615320565b81526020016150cc615320565b81526020016150d9615320565b81526020016150e6615320565b81526020016150f3615320565b8152602001615100615320565b815260200161510d615320565b815260200161511a615320565b8152602001615127615320565b8152602001615134615320565b8152602001615141615320565b815260200161514e615320565b815260200161515b615320565b8152602001615168615320565b8152602001615175615320565b8152602001615182615320565b815260200161518f615320565b815260200161519c615320565b81526020016151a9615320565b905290565b6040518061028001604052806151c26153ec565b81526020016151cf615320565b81526020016151dc615320565b81526020016151e9615320565b81526020016151f6615320565b8152602001615203615320565b8152602001615210615320565b815260200161521d615320565b815260200161522a615320565b8152602001615237615320565b815260200161524461540b565b81526020015f8152602001615257615438565b81526020015f815260200161526a615466565b8152602001615277615485565b815260200161528461536a565b815260200161518f6154b3565b6040518061052001604052806029906020820280368337509192915050565b604051806101c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020016152ee6154b3565b81526020016152fb6154b3565b81526020015f81526020015f81526020015f81526020015f8152602001606081525090565b60405180604001604052805f81526020015f81525090565b604051806040016040528061519c615320565b6040518061012001604052806009906020820280368337509192915050565b604051806103800160405280601c906020820280368337509192915050565b6040518060e0016040528061539c6154d1565b81526020015f81526020015f81526020015f81526020015f81526020016153c16154d1565b81526020015f81525090565b6040518061010001604052806008906020820280368337509192915050565b6040518061020001604052806010906020820280368337509192915050565b60405180606001604052806003905b615422615320565b81526020019060019003908161541a5790505090565b604051806103800160405280601c905b61545061534b565b8152602001906001900390816154485790505090565b604051806105400160405280602a906020820280368337509192915050565b604051806103600160405280601b905b61549d615320565b8152602001906001900390816154955790505090565b60405180608001604052806004906020820280368337509192915050565b604051806120000160405280610100906020820280368337509192915050565b5f5f5f5f60408587031215615504575f5ffd5b84356001600160401b03811115615519575f5ffd5b8501601f81018713615529575f5ffd5b80356001600160401b0381111561553e575f5ffd5b87602082840101111561554f575f5ffd5b6020918201955093508501356001600160401b0381111561556e575f5ffd5b8501601f8101871361557e575f5ffd5b80356001600160401b03811115615593575f5ffd5b8760208260051b84010111156155a7575f5ffd5b949793965060200194505050565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417612610576126106155b5565b81810381811115612610576126106155b5565b805f5b60108110156131e15781518452602093840193909101906001016155f6565b805f5b60038110156131e15761563684835180518252602090810151910152565b6040939093019260209190910190600101615618565b805f5b601c8110156131e1578151845f5b600981101561567c57825182526020928301929091019060010161565d565b50505061012093909301926020919091019060010161564f565b805f5b602a8110156131e1578151845260209384019390910190600101615699565b805f5b601b8110156131e1576156d984835180518252602090810151910152565b60409390930192602091909101906001016156bb565b805f5b601c8110156131e15781518452602093840193909101906001016156f2565b805f5b60048110156131e1578151845260209384019390910190600101615714565b8183525f6001600160fb1b0383111561574a575f5ffd5b8260051b80836020870137939093016020019392505050565b61576e8188516155f3565b5f602088015161578c61020084018280518252602090810151910152565b5060408801518051610240840152602090810151610260840152606089015180516102808501528101516102a0840152608089015180516102c08501528101516102e084015260a0890151805161030085015281015161032084015260c0890151805161034085015281015161036084015260e089015180516103808501528101516103a084015261010089015180516103c08501528101516103e084015261012089015180516104008501520151610420830152610140880151615855610440840182615615565b5061016088015161050083015261018088015161587661052084018261564c565b506101a08801516124a08301526101c08801516158976124c0840182615696565b506101e08801516158ac612a008401826156b8565b506102008801516158c16130c08401826156ef565b506102208801516158d6613440840182615711565b5061024088015180516134c08401526020908101516134e0840152610260890151805161350085015201516135208301526135c0613540830181905261591f9083018789615733565b613560830195909552506135808101929092526135a0909101529392505050565b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b038111828210171561597757615977615940565b60405290565b604051601f8201601f191681016001600160401b03811182821017156159a5576159a5615940565b604052919050565b5f60c082840312156159bd575f5ffd5b60405160c081016001600160401b03811182821017156159df576159df615940565b604090815283518252602080850151908301528381015190820152606080840151908201526080808401519082015260a0928301519281019290925250919050565b5f82601f830112615a30575f5ffd5b5f610360615a3d8161597d565b915083018185821115615a4e575f5ffd5b845b82811015615a68578051825260209182019101615a50565b509195945050505050565b5f82601f830112615a82575f5ffd5b5f610380615a3d8161597d565b5f610be0828403128015615aa1575f5ffd5b50615aaa615954565b615ab484846159ad565b8152615ac38460c08501615a21565b6020820152615ad6846104208501615a73565b60408201526107a08301516060820152615af4846107c08501615a73565b6080820152610b4083015160a0820152610b6083015160c0820152610b8083015160e0820152610ba0830151610100820152610bc09092015161012083015250919050565b80820180821115612610576126106155b5565b5f5f85851115615b5a575f5ffd5b83861115615b66575f5ffd5b5050820193919092039150565b634e487b7160e01b5f52603260045260245ffd5b5f60018201615b9857615b986155b5565b5060010190565b80356020831015612610575f19602084900360031b1b1692915050565b5f82615bd657634e487b7160e01b5f52601260045260245ffd5b500690565b5f81615be957615be96155b5565b505f190190565b5f8183825b6008811015615c14578151835260209283019290910190600101615bf5565b5050506101008201905092915050565b5f82518060208501845e5f920191825250919050565b5f60208284031215615c4a575f5ffd5b815180151581146103f4575f5ffd5b634e487b7160e01b5f52602160045260245ffdfe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4730644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a164736f6c634300081c000a", + "deployedBytecode": "0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063ea50d0e41461002d575b5f5ffd5b61004061003b3660046154f1565b610054565b604051901515815260200160405180910390f35b5f5f61007f7f00000000000000000000000000000000000000000000000000000000000000006102ee565b905061008c8160206155c9565b85146100ee577f0000000000000000000000000000000000000000000000000000000000000000856100bf8360206155c9565b6040516359895a5360e01b81526004810193909352602483019190915260448201526064015b60405180910390fd5b5f6100f76103fb565b90505f61012588887f0000000000000000000000000000000000000000000000000000000000000000610410565b90506010826040015161013891906155e0565b85146101575760405163fa06659360e01b815260040160405180910390fd5b60405163995bf45760e01b81525f9073__$d0188790065ac172f94fde8676855b6381$__9063995bf457906101fa9085908b908b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090600401615763565b610be060405180830381865af4158015610216573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061023a9190615a8f565b905061028a8787808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050855185516060810151608090910151919350915060016108a9565b815160a0015261029a8282610a10565b6102b7576040516313f8744360e31b815260040160405180910390fd5b6102c2828483610c17565b6102df576040516352ec174560e11b815260040160405180910390fd5b50600198975050505050505050565b5f8060026102fe60016008615b39565b61030891906155c9565b9050610316600260036155c9565b6103209082615b39565b9050600161032f6009856155c9565b61033991906155c9565b6103439082615b39565b90506001610352816029615b39565b61035c91906155c9565b6103669082615b39565b9050610374600160026155c9565b61037e9082615b39565b905061038b6001846155c9565b6103959082615b39565b90506103a3600160046155c9565b6103ad9082615b39565b905060026103bc6001856155e0565b6103c691906155c9565b6103d09082615b39565b90506103dd6002806155c9565b6103e79082615b39565b90506103f4601082615b39565b9392505050565b610403615024565b61040b611c14565b905090565b6104186151ae565b5f805b601081101561047a57610447868387610435602083615b39565b9261044293929190615b4c565b61254e565b8351826010811061045a5761045a615b73565b6020020181815250506020826104709190615b39565b915060010161041b565b5061049e85828661048c604083615b39565b9261049993929190615b4c565b612561565b60208301526104ae604082615b39565b90506104c185828661048c604083615b39565b6040808401919091526104d49082615b39565b90506104e785828661048c604083615b39565b60608301526104f7604082615b39565b905061050a85828661048c604083615b39565b608083015261051a604082615b39565b905061052d85828661048c604083615b39565b60c083015261053d604082615b39565b905061055085828661048c604083615b39565b60e0830152610560604082615b39565b905061057385828661048c604083615b39565b60a0830152610583604082615b39565b905061059685828661048c604083615b39565b6101008301526105a7604082615b39565b90506105ba85828661048c604083615b39565b6101208301526105cb604082615b39565b90506105de85828661048c604083615b39565b610140830151526105f0604082615b39565b9050610603858286610435602083615b39565b610160830152610614602082615b39565b90505f5b83811015610692575f5b60098110156106895761063c878488610435602083615b39565b84610180015183601c811061065357610653615b73565b6020020151826009811061066957610669615b73565b60200201818152505060208361067f9190615b39565b9250600101610622565b50600101610618565b505f5b6106a160016029615b39565b8110156106f0576106b9868387610435602083615b39565b836101c0015182602a81106106d0576106d0615b73565b6020020181815250506020826106e69190615b39565b9150600101610695565b50610702858286610435602083615b39565b6101a0830152610713602082615b39565b905061072685828661048c604083615b39565b6101408301516020015261073b604082615b39565b905061074e85828661048c604083615b39565b61014083015160026020020152610766604082615b39565b90505f5b6107756001856155e0565b8110156107be5761078d86838761048c604083615b39565b836101e0015182601b81106107a4576107a4615b73565b60200201526107b4604083615b39565b915060010161076a565b505f5b83811015610811576107da868387610435602083615b39565b83610200015182601c81106107f1576107f1615b73565b6020020181815250506020826108079190615b39565b91506001016107c1565b505f5b60048110156108655761082e868387610435602083615b39565b836102200151826004811061084557610845615b73565b60200201818152505060208261085b9190615b39565b9150600101610814565b5061087785828661048c604083615b39565b610240830152610888604082615b39565b905061089b85828661048c604083615b39565b610260830152509392505050565b5f600180826108d6866108d1896108cc6108c78a6310000000615b39565b6125e3565b6125fb565b612616565b90505f6108f4876108ef8a6108cc6108c78b6001615b39565b61262f565b90505f5b61092360107f00000000000000000000000000000000000000000000000000000000000000006155e0565b811015610990575f61094d8c838151811061094057610940615b73565b6020026020010151612657565b905061095d866108cc8684612616565b955061096d856108cc8584612616565b9450610979848b612616565b9350610985838b61262f565b9250506001016108f8565b505f5b60108110156109f7575f8a82601081106109af576109af615b73565b602002015190506109c4866108cc8684612616565b95506109d4856108cc8584612616565b94506109e0848b612616565b93506109ec838b61262f565b925050600101610993565b50610a02848461266c565b9a9950505050505050505050565b5f5f610a2583606001518561016001516125fb565b905060015f5b7f0000000000000000000000000000000000000000000000000000000000000000811015610b17575f86610180015182601c8110610a6b57610a6b615b73565b602002015180519091505f90610a89908360015b6020020151612616565b9050848114610aab576040516313f8744360e31b815260040160405180910390fd5b5f876080015184601c8110610ac257610ac2615b73565b60200201519050610ad3838261267a565b9550610b07856108cc60016108d1856108cc8e604001518b601c8110610afb57610afb615b73565b6020020151600161262f565b9450505050806001019050610a2b565b50610b20615291565b5f5b6029811015610b70576101c0870151610b3c600183615b39565b602a8110610b4c57610b4c615b73565b6020020151828260298110610b6357610b63615b73565b6020020152600101610b22565b505f610b8582875f0151886020015186612828565b9050600160025b7f0000000000000000000000000000000000000000000000000000000000000000811015610be257610bd882896080015183601c8110610bce57610bce615b73565b60200201516125fb565b9150600101610b8c565b50610c08610bf5836108cc60018561262f565b6108d18a6101a001518a606001516125fb565b94909414979650505050505050565b5f610c206152b0565b5f610c4f8460c001517f00000000000000000000000000000000000000000000000000000000000000006128a1565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610c8a57610c8a615940565b604051908082528060200260200182016040528015610cb3578160200160208202803683370190505b5090505f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b03811115610cef57610cef615940565b604051908082528060200260200182016040528015610d2857816020015b610d15615320565b815260200190600190039081610d0d5790505b509050610d5b610d56876101000151855f81518110610d4957610d49615b73565b602002602001015161262f565b61296a565b84610120018181525050610d90610d56876101000151855f81518110610d8357610d83615b73565b6020026020010151612616565b610140850181905261012085015160e0880151610db1926108d191906125fb565b845260c0860151610de190610dc59061296a565b6108cc8661012001516108ef8a60e001518961014001516125fb565b6020850152815160019083905f90610dfb57610dfb615b73565b602002602001018181525050876102400151815f81518110610e1f57610e1f615b73565b6020908102919091010152600160a08501525f60c08501528351610e42906129da565b60408501526020840151610e55906129da565b606085015260015b610e6960016024615b39565b8111610f0a57610e8185604001518660a001516125fb565b838281518110610e9357610e93615b73565b602002602001018181525050610edc8560c001516108d18b6101c00151600185610ebd91906155e0565b602a8110610ecd57610ecd615b73565b60200201518860a001516125fb565b60c086015260a08086015190880151610ef591906125fb565b60a0860152610f0381615b87565b9050610e5d565b505f5b6005811015610fe3575f610f22601e83615b39565b90505f610f3160016024615b39565b610f3b9084615b39565b9050610f6c858381518110610f5257610f52615b73565b60200260200101516108d189606001518a60a001516125fb565b858381518110610f7e57610f7e615b73565b602002602001018181525050610fbb8760c001516108d18d6101c0015184602a8110610fac57610fac615b73565b60200201518a60a001516125fb565b60c088015260a080880151908a0151610fd491906125fb565b60a08801525050600101610f0d565b50876020015181600181518110610ffc57610ffc615b73565b602002602001018190525086606001518160028151811061101f5761101f615b73565b602002602001018190525086608001518160038151811061104257611042615b73565b60200260200101819052508660a001518160048151811061106557611065615b73565b60200260200101819052508660c001518160058151811061108857611088615b73565b60200260200101819052508660e00151816006815181106110ab576110ab615b73565b6020026020010181905250866101000151816007815181106110cf576110cf615b73565b6020026020010181905250866101200151816008815181106110f3576110f3615b73565b60200260200101819052508661014001518160098151811061111757611117615b73565b602002602001018190525086610160015181600a8151811061113b5761113b615b73565b6020026020010181905250866101c0015181600b8151811061115f5761115f615b73565b602002602001018190525086610180015181600c8151811061118357611183615b73565b6020026020010181905250866101a0015181600d815181106111a7576111a7615b73565b6020026020010181905250866101e0015181600e815181106111cb576111cb615b73565b602002602001018190525086610200015181600f815181106111ef576111ef615b73565b60200260200101819052508661022001518160108151811061121357611213615b73565b60200260200101819052508661024001518160118151811061123757611237615b73565b60200260200101819052508661026001518160128151811061125b5761125b615b73565b60200260200101819052508661028001518160138151811061127f5761127f615b73565b6020026020010181905250866102a00151816014815181106112a3576112a3615b73565b6020026020010181905250866102c00151816015815181106112c7576112c7615b73565b6020026020010181905250866102e00151816016815181106112eb576112eb615b73565b60200260200101819052508661030001518160178151811061130f5761130f615b73565b60200260200101819052508661032001518160188151811061133357611333615b73565b60200260200101819052508661034001518160198151811061135757611357615b73565b602002602001018190525086610360015181601a8151811061137b5761137b615b73565b602002602001018190525086610380015181601b8151811061139f5761139f615b73565b6020026020010181905250866103a0015181601c815181106113c3576113c3615b73565b6020026020010181905250866103c0015181601d815181106113e7576113e7615b73565b6020026020010181905250876040015181601e8151811061140a5761140a615b73565b6020026020010181905250876060015181601f8151811061142d5761142d615b73565b602002602001018190525087608001518160208151811061145057611450615b73565b60200260200101819052508760a001518160218151811061147357611473615b73565b60200260200101819052508761012001518160228151811061149757611497615b73565b6020026020010181905250876101000151816023815181106114bb576114bb615b73565b60200260200101819052508760c00151816024815181106114de576114de615b73565b60200260200101819052508760e001518160258151811061150157611501615b73565b60200260200101819052505f61154787608001518660c001518b6102000151877f00000000000000000000000000000000000000000000000000000000000000006129ec565b9050611571815f8151811061155e5761155e615b73565b60200260200101518661012001516125fb565b608086018190526102008a01515160e08901516115a292916108d19161159791906125fb565b8861014001516125fb565b608086015260e08701516115b590612b4a565b60a08601525f6115c760016024615b39565b6115d2906001615b39565b90505f5b61160160017f00000000000000000000000000000000000000000000000000000000000000006155e0565b811015611812575f61163460017f00000000000000000000000000000000000000000000000000000000000000006155e0565b8210159050806117a357611668610d568b6101000151898560016116589190615b39565b81518110610d4957610d49615b73565b6101208901526101008a015161169890610d569089611688866001615b39565b81518110610d8357610d83615b73565b61014089015260a08801516101208901516116b391906125fb565b61016089015260a088015160e08b01516116db916116d0916125fb565b8961014001516125fb565b61018089018190526116fe906116f0906129da565b6108d18a61016001516129da565b866117098486615b39565b8151811061171957611719615b73565b6020026020010181815250505f6117528961018001518e61020001518560016117429190615b39565b601c8110610bce57610bce615b73565b905061178c816108d18b61016001518887600161176f9190615b39565b8151811061177f5761177f615b73565b60200260200101516125fb565b905061179c896080015182612616565b60808a0152505b6117c26117b88960a001518c60e001516125fb565b8b60e001516125fb565b60a08901526101e08c015182601b81106117de576117de615b73565b6020020151856117ee8486615b39565b815181106117fe576117fe615b73565b6020908102919091010152506001016115d6565b5061183e60017f00000000000000000000000000000000000000000000000000000000000000006155e0565b6118489082615b39565b90506118686118608961010001518a60c0015161262f565b60019061266c565b60e08701515261010088015160c08901516118ac91611860916108ef907f07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76906125fb565b60e0878101805160200192909252815180516040909101529051805160609091015260a0870151908901516118ee916118e4916125fb565b8960e001516125fb565b60a08701525f5b600481101561199c575f6119278860e00151836004811061191857611918615b73565b60200201518960a001516125fb565b9050611932816129da565b886101000151836004811061194957611949615b73565b602002015260a088015160e08b015161196291906125fb565b8860a001818152505061198e88608001516108d1838f61022001518660048110610bce57610bce615b73565b6080890152506001016118f5565b506101008601515184518590839081106119b8576119b8615b73565b602090810291909101810191909152610100870151908101516119dc916002610a7f565b846119e8836001615b39565b815181106119f8576119f8615b73565b60209081029190910101526101008601516060015184611a19836002615b39565b81518110611a2957611a29615b73565b60209081029190910101525f5b6003811015611a8b578a61014001518160038110611a5657611a56615b73565b60200201518483611a6681615b87565b945081518110611a7857611a78615b73565b6020908102919091010152600101611a36565b506040518060400160405280600181526020016002815250838281518110611ab557611ab5615b73565b60200260200101819052508560800151848280611ad190615b87565b935081518110611ae357611ae3615b73565b602002602001018181525050611b0d8a61022001518960c001518a608001518d6101a00151612b55565b611b2a5760405163a2a2ac8360e01b815260040160405180910390fd5b5f8a6102600151905080848381518110611b4657611b46615b73565b6020026020010181905250886101000151858381518110611b6957611b69615b73565b602002602001018181525050611b7d615338565b611b878587612eb8565b8152611b9282612fb0565b602082018190528c5182515f92611baa929190612ff6565b90505f5f611bba8f5f0151613087565b91509150611bc782613148565b611bd081613148565b8351611bdd9083856131e7565b84526020840151611bef9082856131e7565b602085018190528451611c0191613216565b9f9e505050505050505050505050505050565b611c1c615024565b50604080516103e08101825262020000815260116020808301919091526101a282840152825180840184527f13637737c33db244a3712ce1f84f4a6400935882acd540419ff5fc19166ea61881527f15e894c35784b66acc688f1d787868569692c5761fa71b84ab52a3b2c1dd41a8818301526060830152825180840184527f16daf8e28d24b787f5a311fc0930d1d495f74cb0eba1780ae0d36610a1ab587081527f220aa4f565987b5544214f4aa9477fd03cbb82e8a57a2aeaa21968038c2af3a5818301526080830152825180840184527f2c0c47eac6980c002be7c5f4633a8bd6d5d0fc9e6651e541b141fc02557ca48d81527f1ca159a1bbe1a8c82eb796fba79bcdff36d3fb98c986996878fdf102d6a12ab98183015260a0830152825180840184527f1c05ee47a359c77501f8bb557929e27f64523630d83a818cd364994cadcaf8c581527f2f8e9947f0eab4542b5e684bbc807466bc192c42d7fce467125769936b4536f58183015260c0830152825180840184527f082a6fc7457baf2a604ae295f701031e54ede6a34d88f93f5e7aaeb2a213312181527f20ecb56a891971bc2cf9bc98cdc00fc8ec720de344999055300f979e749ec93d8183015260e0830152825180840184527f265c425247eed132b40b111b5a7c14d7d9db56aefbf71eeec0b2cc09dd66a6b381527f3054e4ee825da9852d2fc5172b24c4ffbdfd315f13fce4b498379c566604897e81830152610100830152825180840184527f163a3285e23ec78bb34d3c6122f47c770ee1f228ed2dda996542bade7a8bc2e481527f188245f34ba632acb17885f4be308c9551dbfd5095069e7077281d144e55044b81830152610120830152825180840184527f1913712d01550fa30bf15a28a13902738529edfc1ddc730c5bc57c00514fd3b481527f1f125db8f6315e55f2b20ba6863482eac90d77f6c6289efb0d6a6c740be172cd81830152610140830152825180840184527f26ce5fb2dc4d867f0f6957729e6158fe7d6924445514b4c485f0b093195cff4881527f102d0d1aa8a400a6f7e233d512ed7205fcb3eb0ba5c0d54041f23b25f58a4c5781830152610160830152825180840184527f0ff4dd20d4821b5ca6738a69881d693c04c892bade4b929a311c6612d94ffbc281527f19fcce46268bf02b94f4486494e361d2c126372f35e0583d55825134c2ee88cc81830152610180830152825180840184527f018d6d017a26c5c223931a63ee8ad0ef37f9f9f0caba099d8d8482e95b6f46e881527f0ed38b925edf5f9b54e2b5289074d64999010264d2a4eae8fc53b8e38fc10b6b818301526101a0830152825180840184527f1a08892e26c7c33a003d075a86a9edd8cdf253009e26fa7b2ac7f4339ca07ce381527f09383a35fb9f67045a070c939b0d947454f64cd92bcf90838b2163bc0e071b58818301526101c0830152825180840184527f0d2f53319bc2e321ef88e47d0a3a35b0f35728ed7b7790dd357ecda4ea55a57b81527f074497f78eec311b533ca170dc19e81c0cf5a22dce7bdf938841ff71e8cbdc8d818301526101e0830152825180840184527f0cde2682ddd264dcac5b0e5626164271411bca898cd8beb4c98536534ffe3e6981527f20f8bfa3f9ed612f481072d20715601f08415ecbb5092b8dae96a15c583ac77081830152610200830152825180840184527f2dc45f069a801ce507391a5d369024e6c0a8f508426efa10efec079f652943fd81527f0ca193ecd89783532ab900689868dfa9713a57dd313c222bfa2d1ee92c5a1ec981830152610220830152825180840184527f18f0b7ba3135bb08f1e312928b750b6bacb9776a9e8a3d30d1da58873083baa681527f1ed01d844f4aee867147b3eb571130d0e37c0686151a13106aeb40936713c09381830152610240830152825180840184527f2787d437215fba393c1bb6e8bc91cdf1f5c75cb93b1eb8b522819a6cfc71507c81527f027ea99429a3d006c4d01411577bf6ac562f7811b4d64e7ff060351468d63b6b81830152610260830152825180840184527f0d0f4f0fa40d68989657a0feee08deed1f08355b066c778578bfbf430cc2d22b81527f2d9d81c8732bf6991afa6657818d09e17fe8bfb40f59301a7b992fc8f2a9d1e981830152610280830152825180840184527ea673368cf560b1069debee688c082cda349df8fbacc711f845dc7960acdeba81527f0234d1b5f65d17aaf71d51ae744b28b6a024bface3333ea19ef58c8c2fc38595818301526102a0830152825180840184527f29353e7eeeae9d8cf7bc6bac6961a44a69fe7b38396fc4b07d416b226fbecc3d81527f012d0615aad587261d1403ca95322f67b6e64382ac7346503bb61ee8ff465ffd818301526102c0830152825180840184527f0dddb0066cbe44ac884fe3658ad6c24943d3329fd839b8dd47b37e0b334f3efc81527f1a54ecfb49945a189bd28fa28103f9ad98d08107f8d68167d96417d95297903f818301526102e0830152825180840184527f271c4df54fa64ddca42889abf3e4559c2aa59525ea5a1858fadae4b6eb6f140681527f06f10a564e9397fc800ffbb6b4c887df1d1e4eeb6dd8cd4f789916e31836f19781830152610300830152825180840184527f099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d2681527e15b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f81830152610320830152825180840184527f1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e81527f305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d1981830152610340830152825180840184527f061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d81527f1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e81830152610360830152825180840184527f043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce81527f261522c4089330646aff96736194949330952ae74c573d1686d9cb4a007338548183015261038083015282518084018452600181526002818301526103a083015282518084019093527f0602bc9d2460bf21b73d27154ff5f8919350545f3cb6dc7f40dae014613bc4c683527f1df576b5b16064433355e8bad62265096027978ab6496527059305dbd8708565908301526103c081019190915290565b5f6103f461255c8385615b9f565b612657565b612569615320565b60408051808201909152805f516020615c6e5f395f51905f5261258f60205f8789615b4c565b61259891615b9f565b6125a29190615bbc565b81526020908101905f516020615c6e5f395f51905f52906125c7906040908789615b4c565b6125d091615b9f565b6125da9190615bbc565b90529392505050565b5f5f516020615c8e5f395f51905f52825b0692915050565b5f5f516020615c8e5f395f51905f5282840990505b92915050565b5f5f516020615c8e5f395f51905f528284089392505050565b5f5f516020615c8e5f395f51905f52825f516020615c8e5f395f51905f520384089392505050565b5f5f516020615c8e5f395f51905f52826125f4565b5f6103f4836108cc8461296a565b5f5f604051806101200160405280619d8081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec5181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31815260200161024081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd3181526020016105a081526020017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec518152602001619d8081525090505f600190505f5f90505b600981101561277357612769826108cc878461262f565b9150600101612752565b5061277c61534b565b5f5b60098110156127cd576127ae610d5685836009811061279f5761279f615b73565b60200201516108cc898561262f565b8282600981106127c0576127c0615b73565b602002015260010161277e565b505f5b600981101561281357612809856108d18984600981106127f2576127f2615b73565b6020020151858560098110610bce57610bce615b73565b94506001016127d0565b5061281e84836125fb565b9695505050505050565b5f61283161536a565b61283c86828561340a565b612848868683866135b6565b612854868683866137a2565b61285f8682856139c7565b61286a868285613bbb565b61287686868386613f04565b6128818682856143b0565b61288c8682856147c2565b612897868285614b83565b61281e8185614e83565b60605f826001600160401b038111156128bc576128bc615940565b6040519080825280602002602001820160405280156128e5578160200160208202803683370190505b50905083815f815181106128fb576128fb615b73565b602090810291909101015260015b838110156129625761293d826129206001846155e0565b8151811061293057612930615b73565b6020026020010151612b4a565b82828151811061294f5761294f615b73565b6020908102919091010152600101612909565b509392505050565b5f5f8290505f604051602081526020808201526020604082015282606082015260025f516020615c8e5f395f51905f520360808201525f516020615c8e5f395f51905f5260a082015260205f60c08360055afa806129c6575f5ffd5b505f51608091909101604052949350505050565b5f516020615c8e5f395f51905f520390565b60605f826001600160401b03811115612a0757612a07615940565b604051908082528060200260200182016040528015612a30578160200160208202803683370190505b509050825b8015612b3f575f85612a486001846155e0565b81518110612a5857612a58615b73565b602002602001015190505f89600184612a7191906155e0565b601c8110612a8157612a81615b73565b602002015190505f612adc612aa0612a99858d6125fb565b60026125fb565b6108ef8b612aaf6001896155e0565b601c8110612abf57612abf615b73565b60200201516108cc612ad6886108cc60018a61262f565b8761262f565b9050612afd816108cc610d56612af7876108cc60018961262f565b86612616565b99508990508085612b0f6001876155e0565b81518110612b1f57612b1f615b73565b60200260200101818152505050505080612b3890615bdb565b9050612a35565b509695505050505050565b5f61261082836125fb565b5f600181612b6e612b6887610100614edc565b8361262f565b905080612b8e5760405163835eb8f760e01b815260040160405180910390fd5b612b96615389565b80518390525f5b7f0000000000000000000000000000000000000000000000000000000000000000811015612c7f575f612bd18260096155c9565b612bdc906001615b39565b905084835f0151826101008110612bf557612bf5615b73565b60200201525f612c06826001615b39565b90505b612c14600983615b39565b811015612c75578351612c5490612c2c6001846155e0565b6101008110612c3d57612c3d615b73565b60200201518a85601c8110610bce57610bce615b73565b8451826101008110612c6857612c68615b73565b6020020152600101612c09565b5050600101612b9d565b50608081018390525f602082018190525b610100811015612d9057612cb1612cab83608001518a6125fb565b8561262f565b8260a00151826101008110612cc857612cc8615b73565b602002015260a0820151612cf290826101008110612ce857612ce8615b73565b602002015161296a565b8260a00151826101008110612d0957612d09615b73565b602002018181525050612d4f82602001516108d1845f0151846101008110612d3357612d33615b73565b60200201518560a00151856101008110610bce57610bce615b73565b60208301526080820151612d83907f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d66125fb565b6080830152600101612c90565b505f612da1836108cc61010061296a565b9050612db18260200151826125fb565b602083015260a0820151612dcc905f5b6020020151826125fb565b604083015260a0820151612df890612de760016101006155e0565b6101008110612dc157612dc1615b73565b60608301526040820151612e0e908a6002610bce565b60c08301819052612e6e906108d1612e468b7f204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d661262f565b60208d015160408e01516108cc91612e5d9161262f565b8e5160208901516108ef91906125fb565b60c083018190526060830151612ea391612e97916108d1906108cc8e600260200201518c61262f565b6108ef858c6003610bce565b60c08301819052159998505050505050505050565b612ec0615320565b7f00000000000000000000000000000000000000000000000000000000000000005f5b81811015612f1557612f0d858281518110612f0057612f00615b73565b6020026020010151613148565b600101612ee3565b50604051600190815b60018401811015612f7a5760208102870160208202870181515160408501528151602001516060850152805160808501525050604080830160606040850160075afa8316925060408260808460065afa90921691600101612f1e565b5080518452602081015160208501525080612fa8576040516352ec174560e11b815260040160405180910390fd5b505092915050565b612fb8615320565b5f516020615c6e5f395f51905f5282602001515f516020615c6e5f395f51905f52612fe391906155e0565b612fed9190615bbc565b60208301525090565b5f5f5f61300286613087565b9150915061300e6153cd565b82518152602080840151818301528251604080840191909152838201516060840152875160808401528782015160a0840152865160c08401528682015160e08401525161307c9161306191849101615bf0565b60405160208183030381529060405280519060200120612657565b979650505050505050565b61308f615320565b613097615320565b82516020808501516040860151606087015160cc90811b608892831b604494851b90961795909517949094178652608087015160a088015160c089015160e08a0151871b90841b91851b9092171717868401526101008701516101208801516101408901516101608a0151871b90841b91851b909217171785526101808701516101a08801516101c08901516101e09099015190951b9790911b9390911b1791909117939093179281019290925291565b805160208201515f5f516020615c6e5f395f51905f528380095f516020615c6e5f395f51905f5260035f516020615c6e5f395f51905f52838709085f516020615c6e5f395f51905f5284850914915050806131e15760405162461bcd60e51b8152602060048201526019602482015278706f696e74206973206e6f74206f6e2074686520637572766560381b60448201526064016100e5565b50505050565b6131ef615320565b6131f7615320565b6132018386614f3d565b905061320d8185614f93565b95945050505050565b81516020808401518351848301516040805194850195909552938301919091527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260608301527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60808301527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b60a08301527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60c083015260e08201526101008101919091527f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c16101208201527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b06101408201527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe46101608201527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101808201525f9081906101a00160405160208183030381529060405290505f5f60086001600160a01b0316836040516133ac9190615c24565b5f60405180830381855afa9150503d805f81146133e4576040519150601f19603f3d011682016040523d82523d5f602084013e6133e9565b606091505b509150915081801561281e57508080602001905181019061281e9190615c3a565b5f613416846007614ff4565b90507f183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f80000005f61347761347161344b85600361262f565b6108cc61346661345b8b5f614ff4565b6108cc8c601d614ff4565b6108cc8b601c614ff4565b836125fb565b90506134f86134ed6134d46134bb6134a2856108d16134978d6002614ff4565b6108cc8e601c614ff4565b6108d16134b08c6003614ff4565b6108cc8d601d614ff4565b6108d16134c98b6004614ff4565b6108cc8c601e614ff4565b6108d16134e28a6005614ff4565b6108cc8b601f614ff4565b6108d1886001614ff4565b9050613517816108d161350c86600161262f565b6108cc8a6027614ff4565b905061352381846125fb565b905061352f81856125fb565b8552505f905061356961355f61355461354988601c614ff4565b6108d189601f614ff4565b6108ef886024614ff4565b6108d1875f614ff4565b905061357a816108cc84600261262f565b905061358b816108cc84600161262f565b905061359781836125fb565b90506135a381846125fb565b9050808460015b60200201525050505050565b5f5f5f6135ec6135e26135ca89601c614ff4565b6108d16135d88b6012614ff4565b8a606001516125fb565b8760800151612616565b9050613625816108cc61361b6136038b601d614ff4565b6108d16136118d6013614ff4565b8c606001516125fb565b8960800151612616565b905061364a816108cc61361b61363c8b601e614ff4565b6108d16136118d6014614ff4565b905061366f816108cc61361b6136618b601f614ff4565b6108d16136118d6015614ff4565b92505f90506136936135e261368589601c614ff4565b6108d16135d88b600e614ff4565b90506136b8816108cc61361b6136aa8b601d614ff4565b6108d16136118d600f614ff4565b90506136dd816108cc61361b6136cf8b601e614ff4565b6108d16136118d6010614ff4565b9050613702816108cc61361b6136f48b601f614ff4565b6108d16136118d6011614ff4565b91505f9050613729613723613718896020614ff4565b6108d18a601a614ff4565b846125fb565b905061375e816108ef6137586137408b6028614ff4565b6108d161374e8d601b614ff4565b8c60a001516125fb565b856125fb565b905061376a81856125fb565b6040860152505f61378d61375861378289601b614ff4565b6108cc8a6028614ff4565b9050808560035b602002015250505050505050565b5f5f6138006137e86137d06137bb61361b8a6016614ff4565b6108d16137c98b6017614ff4565b8a516125fb565b6108d16137de8a6018614ff4565b89602001516125fb565b6108d16137f6896019614ff4565b88604001516125fb565b91505f61383761381e61381489601c614ff4565b8860800151612616565b6108d161382c8a6003614ff4565b6108cc8b6024614ff4565b90505f61386061384889601d614ff4565b6108d16138558b5f614ff4565b6108cc8c6025614ff4565b90505f61388a6138718a601e614ff4565b6108d161387f8c6001614ff4565b6108cc8d6026614ff4565b90506138c96138b16138a3856108d1868d5f01516125fb565b6108d1848c602001516125fb565b6108d16138bf8c6004614ff4565b8b604001516125fb565b93505050505f6138dd613723886021614ff4565b90505f6138ee613723896021614ff4565b90505f61392661390d6139028b6023614ff4565b6108d18c6006614ff4565b6108ef61391b8c6023614ff4565b6108cc8d6006614ff4565b90505f613944612b6861393987896125fb565b6108cc8d6021614ff4565b905061395081886125fb565b90505f61397861396a6139648d6006614ff4565b876125fb565b6108ef6139648e6022614ff4565b90505f6139868c6023614ff4565b90505f613996612b6883846125fb565b60808c0185905260a08c0184905290506139b0818b6125fb565b8b6006602002015250505050505050505050505050565b5f6139d35f600161262f565b90505f6139e15f600261262f565b90505f6139ef5f600361262f565b90505f613a0b613a0088601d614ff4565b6108ef89601c614ff4565b90505f613a27613a1c89601e614ff4565b6108ef8a601d614ff4565b90505f613a43613a388a601f614ff4565b6108ef8b601e614ff4565b90505f613a5f613a548b6024614ff4565b6108ef8c601f614ff4565b905083613a70816108cc818b612616565b9050613a80816108cc878a612616565b9050613a90816108cc8789612616565b9050613aa1816108cc8d6008614ff4565b9050613aad818a6125fb565b60e08b01525082613ac2816108cc818b612616565b9050613ad2816108cc868a612616565b9050613ae2816108cc8689612616565b9050613af3816108cc8d6008614ff4565b9050613aff818a6125fb565b6101008b01525081613b15816108cc818b612616565b9050613b25816108cc858a612616565b9050613b35816108cc8589612616565b9050613b46816108cc8d6008614ff4565b9050613b52818a6125fb565b6101208b01525080613b68816108cc818b612616565b9050613b78816108cc848a612616565b9050613b88816108cc8489612616565b9050613b99816108cc8d6008614ff4565b9050613ba5818a6125fb565b610140909a019990995250505050505050505050565b613bf46040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613bff84601d614ff4565b8152613c0c84601e614ff4565b6020820152613c1c846024614ff4565b6040820152613c2c846027614ff4565b6060820152613c3c846026614ff4565b6080820152613c4c846025614ff4565b60a08201525f613c5d856002614ff4565b90505f613c6a865f614ff4565b90505f613c7e8460400151855f015161262f565b90505f613c93856020015186602001516125fb565b606086015190915086905f90613ca990806125fb565b90505f613cc7613cc189602001518a606001516125fb565b886125fb565b90505f613ce6613cdf8a60a001518b60400151612616565b8a51612616565b9050613cf561396482886125fb565b9050613d1c613d16613d10613d0a848761262f565b8861262f565b84612616565b83612616565b9050613d44613d39613d2e83876125fb565b6108cc8f6009614ff4565b6108cc60018a61262f565b6101608c015250505050602085015160808601515f91613d6391612616565b90505f613d81613d778860600151886125fb565b886020015161262f565b90505f613da5613d9184876125fb565b6108d16137588b60a001518c5f015161262f565b9050613dcd613dc2613db7838c6125fb565b6108cc8e6009614ff4565b6108cc60018961262f565b6101808b0152505f9150613dee9050613de7836011612616565b87516125fb565b90505f613dfb8384612616565b9050613e078182612616565b90505f613e158360096125fb565b9050613e3e613e38613723613e318b60a001518c5f0151612616565b8b51612616565b8261262f565b60c089018190525f90613e5990613cc190613d2e908d6125fb565b9050613e6c8b600b602002015182612616565b6101608c0152505086515f9250613e939150613de790613e8c9080612616565b8851612616565b90505f613ed3613eae836108cc8a5f01518b60a0015161262f565b60208901516108ef90613ec19080612616565b6108cc8b602001518c60800151612616565b9050613ef089600c60200201516108d1613cc1613d2e858d6125fb565b89600c602002015250505050505050505050565b613f6e604051806101e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b613f86613f7c86601e614ff4565b85604001516125fb565b808252613fa5906108d1613f9b88601d614ff4565b87602001516125fb565b808252613fba906108d1613de788601c614ff4565b808252613fcc906108d1876001614ff4565b80825260208201819052613fe5906108ef87601f614ff4565b8152614000613ff5866024614ff4565b6108ef87601c614ff4565b608082015261401e614013866027614ff4565b6108ef87601f614ff4565b60608201526080810151614037906108cc81600161262f565b6101c082015260808101516140779061406d90614066906108cc60015f516020615c8e5f395f51905f526155e0565b6001612616565b82606001516125fb565b60a082018190526140ad9061409f906108cc614094896002614ff4565b6108cc8a6003614ff4565b6108cc61375888600a614ff4565b83600e60200201526101c08101516140d19061409f906108cc614094896002614ff4565b6101e084015280516140f6906108cc6140eb886002614ff4565b6108cc896003614ff4565b6101208201525f61411561410b87601f614ff4565b836020015161262f565b9050614126816108cc83600161262f565b60e0830152614143614139876026614ff4565b86604001516125fb565b60408301819052614166906108d161415c896025614ff4565b88602001516125fb565b60408301819052614186906108d161417f896024614ff4565b88516125fb565b60408301526141a3614199876027614ff4565b836040015161262f565b60408301525f6141c26141b7886026614ff4565b6108ef89601e614ff4565b90506142146141ef613471614066866080015160015f516020615c8e5f395f51905f526108cc91906155e0565b6108cc614066866040015160015f516020615c8e5f395f51905f526108cc91906155e0565b60c084015260408301516142369061422c90806125fb565b846040015161262f565b61010084015260c083015161426290614254906108cc8a6004614ff4565b6108cc6139648a600a614ff4565b6102008601526101c083015161428190614254906108cc8a6004614ff4565b6102208601526101008301516142a090614254906108cc8a6004614ff4565b61024086015260e08301516142ba906108cc896004614ff4565b6101408401526142d96142ce886025614ff4565b6108ef89601d614ff4565b6101608401526080830151614317906141b79061430c90614066906108cc60015f516020615c8e5f395f51905f526155e0565b8561016001516125fb565b61018084018190526101208401516101a0850181905261434e916108d1906108cc6143438c6005614ff4565b6108cc8d6002614ff4565b6101a08401819052835161436e91906108d1906108cc6143438c5f614ff4565b6101a084018190526101408401516143869190612616565b6101a084018190526143a0906108cc6139648a600a614ff4565b6101a0840181905285600d613794565b6143e96040518060e001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61441e6144056143fa86601c614ff4565b6108cc876025614ff4565b6108d1614413876024614ff4565b6108cc88601d614ff4565b815261446361445861443f61443487601c614ff4565b6108cc88601f614ff4565b6108d161444d88601d614ff4565b6108cc89601e614ff4565b6108ef866026614ff4565b6040820181905261447890600160441b6125fb565b6040820181905261448e906108ef866027614ff4565b6040820181905281516144a19190612616565b604082018190526144b7906108cc866005614ff4565b604082015280516144cc90600160441b6125fb565b8082526144ec906108d16144e1876024614ff4565b6108cc886025614ff4565b80825260208201819052614513906108ef61450887601e614ff4565b6108d188601f614ff4565b60208201819052614529906108cc866004614ff4565b6020820152805160608201819052614546906108d186601f614ff4565b6060820181905261456a906108ef61455f876026614ff4565b6108d1886027614ff4565b6060820181905261457f906108cc865f614ff4565b8160600181815250505f6145a861459e83602001518460400151612616565b8360600151612616565b90506145b9816108cc876003614ff4565b90506145d16145c9866025614ff4565b6140006125fb565b608083018190526145e7906108d1876024614ff4565b608083018190526145fa906140006125fb565b60808301819052614610906108d187601e614ff4565b60808301819052614623906140006125fb565b60808301819052614639906108d187601d614ff4565b6080830181905261464c906140006125fb565b60808301819052614662906108d187601c614ff4565b60808301819052614678906108ef87601f614ff4565b6080830181905261468e906108cc876005614ff4565b60808301526146a16145c9866026614ff4565b60a083018190526146b7906108d1876025614ff4565b60a083018190526146ca906140006125fb565b60a083018190526146e0906108d1876024614ff4565b60a083018190526146f3906140006125fb565b60a08301819052614709906108d187601f614ff4565b60a0830181905261471c906140006125fb565b60a08301819052614732906108d187601e614ff4565b60a08301819052614748906108ef876027614ff4565b60a0830181905261475d906108cc875f614ff4565b60a0830181905260808301515f916147759190612616565b9050614786816108cc886004614ff4565b90506147928282612616565b60c084018190526147ab906108cc61396489600b614ff4565b60c084018190528560136020020152505050505050565b6148386040518061022001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b61485161484685601c614ff4565b6108d1866002614ff4565b815261486c61486185601d614ff4565b6108d1866003614ff4565b602082015261488a61487f85601e614ff4565b6108d1866004614ff4565b60408201526148a861489d85601f614ff4565b6108d1866005614ff4565b606082015280516148da906148d3906148cc906148c590806125fb565b84516125fb565b83516125fb565b82516125fb565b608082015260208101516149189061490e90614904906148fa90806125fb565b84602001516125fb565b83602001516125fb565b82602001516125fb565b60a082015260408101516149569061494c906149429061493890806125fb565b84604001516125fb565b83604001516125fb565b82604001516125fb565b60c0820152606081015161498a9061406d906149809061497690806125fb565b84606001516125fb565b83606001516125fb565b60e0820152608081015160a08201516149a39190612616565b61010082015260c081015160e08201516149bd9190612616565b61012082015260a08101516149e1906149d69080612616565b826101200151612616565b61014082015260e0810151614a05906149fa9080612616565b826101000151612616565b610160820152610120810151614a1b9080612616565b6101e08201819052614a3c90614a319080612616565b826101600151612616565b6101e0820152610100810151614a529080612616565b6101a08201819052614a7390614a689080612616565b826101400151612616565b6101a08201819052610160820151614a8a91612616565b6101808201526101408101516101e0820151614aa69190612616565b6101c0820152614aba61347185600c614ff4565b6102008201819052610280840151610180830151614ae5926108d1916108cc906108ef8a6024614ff4565b8360146020020152614b1583601560200201516108d18361020001516108cc856101a001516108ef8a6025614ff4565b8360156020020152614b4583601660200201516108d18361020001516108cc856101c001516108ef8a6026614ff4565b8360166020020152614b7583601760200201516108d18361020001516108cc856101e001516108ef8a6027614ff4565b836017602002015250505050565b614bd56040518061016001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f6040518060800160405280614c0a7f10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e76125e3565b8152602001614c387f0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b6125e3565b8152602001614c657e544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac156125e3565b8152602001614c937f222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b6125e3565b90529050614cb0614ca586601c614ff4565b6108d1876002614ff4565b6101208301819052614cef90614ce490614cd990614cce90806125fb565b8561012001516125fb565b8461012001516125fb565b8361012001516125fb565b8252614cfc85601d614ff4565b6020830152614d0c85601e614ff4565b6040830152614d1c85601f614ff4565b606083015281516020830151614d449161459e91614d3a9190612616565b8460400151612616565b6080830152614d5761372386600d614ff4565b6101408301528151614d7890614d6e90835f610bce565b8360800151612616565b60a0830152614da484601860200201516108d18461014001516108cc8660a001516108ef8b6024614ff4565b6103008501526020820151614dbf90614d6e90836001610bce565b60c0830152614deb84601960200201516108d18461014001516108cc8660c001516108ef8b6025614ff4565b6103208501526040820151614e0690614d6e90836002610bce565b60e0830152614e3284601a60200201516108d18461014001516108cc8660e001516108ef8b6026614ff4565b6103408501526060820151614e4d90614d6e90836003610bce565b610100830152614e7b84601b60200201516108d18461014001516108cc8661010001516108ef8b6027614ff4565b84601b6135aa565b815160015b601c811015614ed557614ecb826108d18684601c8110614eaa57614eaa615b73565b602002015186614ebb6001876155e0565b601b8110610bce57610bce615b73565b9150600101614e88565b5092915050565b5f5f8390505f60405160208152602080820152602060408201528260608201528460808201525f516020615c8e5f395f51905f5260a082015260205f60c08360055afa80614f28575f5ffd5b505f5160809190910160405295945050505050565b614f45615320565b614f4d615320565b604051835181526020840151602082015284604082015260408160608360075afa80614f77575f5ffd5b5080518252602080820151908301526060016040529392505050565b614f9b615320565b614fa3615320565b6040518451815260208501516020820152835160408201526020840151606082015260408160808360065afa80614fd8575f5ffd5b5080518252602080820151908301526080016040529392505050565b5f8282602881111561500857615008615c59565b6029811061501857615018615b73565b60200201519392505050565b604051806103e001604052805f81526020015f81526020015f815260200161504a615320565b8152602001615057615320565b8152602001615064615320565b8152602001615071615320565b815260200161507e615320565b815260200161508b615320565b8152602001615098615320565b81526020016150a5615320565b81526020016150b2615320565b81526020016150bf615320565b81526020016150cc615320565b81526020016150d9615320565b81526020016150e6615320565b81526020016150f3615320565b8152602001615100615320565b815260200161510d615320565b815260200161511a615320565b8152602001615127615320565b8152602001615134615320565b8152602001615141615320565b815260200161514e615320565b815260200161515b615320565b8152602001615168615320565b8152602001615175615320565b8152602001615182615320565b815260200161518f615320565b815260200161519c615320565b81526020016151a9615320565b905290565b6040518061028001604052806151c26153ec565b81526020016151cf615320565b81526020016151dc615320565b81526020016151e9615320565b81526020016151f6615320565b8152602001615203615320565b8152602001615210615320565b815260200161521d615320565b815260200161522a615320565b8152602001615237615320565b815260200161524461540b565b81526020015f8152602001615257615438565b81526020015f815260200161526a615466565b8152602001615277615485565b815260200161528461536a565b815260200161518f6154b3565b6040518061052001604052806029906020820280368337509192915050565b604051806101c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020016152ee6154b3565b81526020016152fb6154b3565b81526020015f81526020015f81526020015f81526020015f8152602001606081525090565b60405180604001604052805f81526020015f81525090565b604051806040016040528061519c615320565b6040518061012001604052806009906020820280368337509192915050565b604051806103800160405280601c906020820280368337509192915050565b6040518060e0016040528061539c6154d1565b81526020015f81526020015f81526020015f81526020015f81526020016153c16154d1565b81526020015f81525090565b6040518061010001604052806008906020820280368337509192915050565b6040518061020001604052806010906020820280368337509192915050565b60405180606001604052806003905b615422615320565b81526020019060019003908161541a5790505090565b604051806103800160405280601c905b61545061534b565b8152602001906001900390816154485790505090565b604051806105400160405280602a906020820280368337509192915050565b604051806103600160405280601b905b61549d615320565b8152602001906001900390816154955790505090565b60405180608001604052806004906020820280368337509192915050565b604051806120000160405280610100906020820280368337509192915050565b5f5f5f5f60408587031215615504575f5ffd5b84356001600160401b03811115615519575f5ffd5b8501601f81018713615529575f5ffd5b80356001600160401b0381111561553e575f5ffd5b87602082840101111561554f575f5ffd5b6020918201955093508501356001600160401b0381111561556e575f5ffd5b8501601f8101871361557e575f5ffd5b80356001600160401b03811115615593575f5ffd5b8760208260051b84010111156155a7575f5ffd5b949793965060200194505050565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417612610576126106155b5565b81810381811115612610576126106155b5565b805f5b60108110156131e15781518452602093840193909101906001016155f6565b805f5b60038110156131e15761563684835180518252602090810151910152565b6040939093019260209190910190600101615618565b805f5b601c8110156131e1578151845f5b600981101561567c57825182526020928301929091019060010161565d565b50505061012093909301926020919091019060010161564f565b805f5b602a8110156131e1578151845260209384019390910190600101615699565b805f5b601b8110156131e1576156d984835180518252602090810151910152565b60409390930192602091909101906001016156bb565b805f5b601c8110156131e15781518452602093840193909101906001016156f2565b805f5b60048110156131e1578151845260209384019390910190600101615714565b8183525f6001600160fb1b0383111561574a575f5ffd5b8260051b80836020870137939093016020019392505050565b61576e8188516155f3565b5f602088015161578c61020084018280518252602090810151910152565b5060408801518051610240840152602090810151610260840152606089015180516102808501528101516102a0840152608089015180516102c08501528101516102e084015260a0890151805161030085015281015161032084015260c0890151805161034085015281015161036084015260e089015180516103808501528101516103a084015261010089015180516103c08501528101516103e084015261012089015180516104008501520151610420830152610140880151615855610440840182615615565b5061016088015161050083015261018088015161587661052084018261564c565b506101a08801516124a08301526101c08801516158976124c0840182615696565b506101e08801516158ac612a008401826156b8565b506102008801516158c16130c08401826156ef565b506102208801516158d6613440840182615711565b5061024088015180516134c08401526020908101516134e0840152610260890151805161350085015201516135208301526135c0613540830181905261591f9083018789615733565b613560830195909552506135808101929092526135a0909101529392505050565b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b038111828210171561597757615977615940565b60405290565b604051601f8201601f191681016001600160401b03811182821017156159a5576159a5615940565b604052919050565b5f60c082840312156159bd575f5ffd5b60405160c081016001600160401b03811182821017156159df576159df615940565b604090815283518252602080850151908301528381015190820152606080840151908201526080808401519082015260a0928301519281019290925250919050565b5f82601f830112615a30575f5ffd5b5f610360615a3d8161597d565b915083018185821115615a4e575f5ffd5b845b82811015615a68578051825260209182019101615a50565b509195945050505050565b5f82601f830112615a82575f5ffd5b5f610380615a3d8161597d565b5f610be0828403128015615aa1575f5ffd5b50615aaa615954565b615ab484846159ad565b8152615ac38460c08501615a21565b6020820152615ad6846104208501615a73565b60408201526107a08301516060820152615af4846107c08501615a73565b6080820152610b4083015160a0820152610b6083015160c0820152610b8083015160e0820152610ba0830151610100820152610bc09092015161012083015250919050565b80820180821115612610576126106155b5565b5f5f85851115615b5a575f5ffd5b83861115615b66575f5ffd5b5050820193919092039150565b634e487b7160e01b5f52603260045260245ffd5b5f60018201615b9857615b986155b5565b5060010190565b80356020831015612610575f19602084900360031b1b1692915050565b5f82615bd657634e487b7160e01b5f52601260045260245ffd5b500690565b5f81615be957615be96155b5565b505f190190565b5f8183825b6008811015615c14578151835260209283019290910190600101615bf5565b5050506101008201905092915050565b5f82518060208501845e5f920191825250919050565b5f60208284031215615c4a575f5ffd5b815180151581146103f4575f5ffd5b634e487b7160e01b5f52602160045260245ffdfe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4730644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a164736f6c634300081c000a", "linkReferences": { - "project/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol": { + "project/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol": { "ZKTranscriptLib": [ { "length": 20, @@ -92,7 +92,7 @@ } }, "deployedLinkReferences": { - "project/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol": { + "project/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol": { "ZKTranscriptLib": [ { "length": 20, @@ -102,7 +102,7 @@ } }, "immutableReferences": { - "55298": [ + "7752": [ { "length": 32, "start": 91 @@ -152,13 +152,13 @@ "start": 11167 } ], - "55300": [ + "7754": [ { "length": 32, "start": 398 } ], - "55302": [ + "7756": [ { "length": 32, "start": 432 @@ -168,7 +168,7 @@ "start": 2303 } ], - "55304": [ + "7758": [ { "length": 32, "start": 3156 @@ -183,6 +183,6 @@ } ] }, - "inputSourceName": "project/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol", - "buildInfoId": "solc-0_8_28-bd46eae6f77be9a8538850385226c1ee4fc57e42" + "inputSourceName": "project/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol", + "buildInfoId": "solc-0_8_28-ea784e9448f647a2ad29ccdb24e4cacb8fdc4660" } \ No newline at end of file diff --git a/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol/ZKTranscriptLib.json b/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol/ZKTranscriptLib.json similarity index 99% rename from packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol/ZKTranscriptLib.json rename to packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol/ZKTranscriptLib.json index 07540b1e68..c534800666 100644 --- a/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol/ZKTranscriptLib.json +++ b/packages/enclave-contracts/artifacts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol/ZKTranscriptLib.json @@ -1,7 +1,7 @@ { "_format": "hh3-artifact-1", "contractName": "ZKTranscriptLib", - "sourceName": "contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol", + "sourceName": "contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol", "abi": [ { "inputs": [ @@ -390,6 +390,6 @@ "linkReferences": {}, "deployedLinkReferences": {}, "immutableReferences": {}, - "inputSourceName": "project/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol", - "buildInfoId": "solc-0_8_28-bd46eae6f77be9a8538850385226c1ee4fc57e42" + "inputSourceName": "project/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol", + "buildInfoId": "solc-0_8_28-ea784e9448f647a2ad29ccdb24e4cacb8fdc4660" } \ No newline at end of file diff --git a/packages/enclave-contracts/contracts/verifier/RecursiveAggregationFoldVerifier.sol b/packages/enclave-contracts/contracts/verifier/RecursiveAggregationFoldVerifier.sol index dad00f9ba6..c4f6834eeb 100644 --- a/packages/enclave-contracts/contracts/verifier/RecursiveAggregationFoldVerifier.sol +++ b/packages/enclave-contracts/contracts/verifier/RecursiveAggregationFoldVerifier.sol @@ -10,122 +10,238 @@ uint256 constant LOG_N = 21; uint256 constant NUMBER_OF_PUBLIC_INPUTS = 18; uint256 constant VK_HASH = 0x0c0bf44aa8d9785b43e16005da8fc455d330c7ff959979a9c7cc876703453859; library HonkVerificationKey { - function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { + function loadVerificationKey() + internal + pure + returns (Honk.VerificationKey memory) + { Honk.VerificationKey memory vk = Honk.VerificationKey({ circuitSize: uint256(2097152), logCircuitSize: uint256(21), publicInputsSize: uint256(18), - ql: Honk.G1Point({ - x: uint256(0x04874f63e091441575d7f87163ad2d04fa3e4b49cee4cde183081c90e13ff17f), - y: uint256(0x1547db64a1675f5ab99f4dc4cf2af5cfd0ef1fbdb68977d8abc8f7112e88bf80) + ql: Honk.G1Point({ + x: uint256( + 0x04874f63e091441575d7f87163ad2d04fa3e4b49cee4cde183081c90e13ff17f + ), + y: uint256( + 0x1547db64a1675f5ab99f4dc4cf2af5cfd0ef1fbdb68977d8abc8f7112e88bf80 + ) }), - qr: Honk.G1Point({ - x: uint256(0x17094eb4ca2210abcb1b4d41cf1355b04dd66b014d42345e6eadf8407a74ed1a), - y: uint256(0x2228aebc15e7852110c94a633f8fb944d71cb1a5cff1b5127d0e4eecf1a7726f) + qr: Honk.G1Point({ + x: uint256( + 0x17094eb4ca2210abcb1b4d41cf1355b04dd66b014d42345e6eadf8407a74ed1a + ), + y: uint256( + 0x2228aebc15e7852110c94a633f8fb944d71cb1a5cff1b5127d0e4eecf1a7726f + ) }), - qo: Honk.G1Point({ - x: uint256(0x15cfc9a869b9c86a839a67ab04b780b3049b2d5f10a901055f85d4717428f6dc), - y: uint256(0x2aec2a8cee64e9da3981b9d6f9f00faffbe2ece25cd4f57d80b8552d81c716b5) + qo: Honk.G1Point({ + x: uint256( + 0x15cfc9a869b9c86a839a67ab04b780b3049b2d5f10a901055f85d4717428f6dc + ), + y: uint256( + 0x2aec2a8cee64e9da3981b9d6f9f00faffbe2ece25cd4f57d80b8552d81c716b5 + ) }), - q4: Honk.G1Point({ - x: uint256(0x232463dd05273276d135bcdfe18a8b299585d6e0fe220dfafe63a54293476dfe), - y: uint256(0x17f763713bb623ce792152d0aabd32b83ca5a6abecb97ece41dc00a1bb6296ad) + q4: Honk.G1Point({ + x: uint256( + 0x232463dd05273276d135bcdfe18a8b299585d6e0fe220dfafe63a54293476dfe + ), + y: uint256( + 0x17f763713bb623ce792152d0aabd32b83ca5a6abecb97ece41dc00a1bb6296ad + ) }), - qm: Honk.G1Point({ - x: uint256(0x286493b1bc5a9674ed3d063c79269512944b6dfb58b880361d36fce8a61c9814), - y: uint256(0x1ef073ead7f7fd307a1a357548e4d8c9f5d03d5a7191cea80b2ba0cf03d18d29) + qm: Honk.G1Point({ + x: uint256( + 0x286493b1bc5a9674ed3d063c79269512944b6dfb58b880361d36fce8a61c9814 + ), + y: uint256( + 0x1ef073ead7f7fd307a1a357548e4d8c9f5d03d5a7191cea80b2ba0cf03d18d29 + ) }), - qc: Honk.G1Point({ - x: uint256(0x216ae5e3bf2a41f792d13f7028ec70fb78ac8d5fa4834341acad58d3453bf123), - y: uint256(0x2ef50ace63f2e23d4b2a184ce511e1b7781287457bcc135459c5c56de1877b93) + qc: Honk.G1Point({ + x: uint256( + 0x216ae5e3bf2a41f792d13f7028ec70fb78ac8d5fa4834341acad58d3453bf123 + ), + y: uint256( + 0x2ef50ace63f2e23d4b2a184ce511e1b7781287457bcc135459c5c56de1877b93 + ) }), - qLookup: Honk.G1Point({ - x: uint256(0x1ad0852ae1f831506b33a76a4968849abaf87e068b8e00ba462e190ff4dc0ff9), - y: uint256(0x2b782e70b28e331338317e348ecb3d3ee69c0cb7b1ca634b32395b5349605a93) + qLookup: Honk.G1Point({ + x: uint256( + 0x1ad0852ae1f831506b33a76a4968849abaf87e068b8e00ba462e190ff4dc0ff9 + ), + y: uint256( + 0x2b782e70b28e331338317e348ecb3d3ee69c0cb7b1ca634b32395b5349605a93 + ) }), - qArith: Honk.G1Point({ - x: uint256(0x1a03cf866e6a54045329039071909e3129fefe1a3f380a5db12e3156f6bed47e), - y: uint256(0x1bdf1ec93f5b5962d4aac343eaa211a5b8021546f0dc225d03f39cb465546d5a) + qArith: Honk.G1Point({ + x: uint256( + 0x1a03cf866e6a54045329039071909e3129fefe1a3f380a5db12e3156f6bed47e + ), + y: uint256( + 0x1bdf1ec93f5b5962d4aac343eaa211a5b8021546f0dc225d03f39cb465546d5a + ) }), - qDeltaRange: Honk.G1Point({ - x: uint256(0x1940cce3f764969daf23bd6cf6d09ecd7e50392878ce2ba3a0a30c88f619cd37), - y: uint256(0x06d183a757a5b2294f8e3b10d3304744bc4d7b68246b01563c48dfd3ab443842) + qDeltaRange: Honk.G1Point({ + x: uint256( + 0x1940cce3f764969daf23bd6cf6d09ecd7e50392878ce2ba3a0a30c88f619cd37 + ), + y: uint256( + 0x06d183a757a5b2294f8e3b10d3304744bc4d7b68246b01563c48dfd3ab443842 + ) }), - qElliptic: Honk.G1Point({ - x: uint256(0x1b5b7f1276e5867eef1d033df65d003c591c16bf64bd2d4cb89bccc1a98ab3dd), - y: uint256(0x28f55668465e42d873d91d75906232c6f05bf37be890e4d4c0ef6a1d5df8c211) + qElliptic: Honk.G1Point({ + x: uint256( + 0x1b5b7f1276e5867eef1d033df65d003c591c16bf64bd2d4cb89bccc1a98ab3dd + ), + y: uint256( + 0x28f55668465e42d873d91d75906232c6f05bf37be890e4d4c0ef6a1d5df8c211 + ) }), - qMemory: Honk.G1Point({ - x: uint256(0x11a96a0fb134b4ad2a3ac7b54fc7989a18ada93ac73e0e7bfb7134f334854c55), - y: uint256(0x166911402df98ab7053779cb1f431384018e058cbe2ac79d1d5ff020ce5474d9) + qMemory: Honk.G1Point({ + x: uint256( + 0x11a96a0fb134b4ad2a3ac7b54fc7989a18ada93ac73e0e7bfb7134f334854c55 + ), + y: uint256( + 0x166911402df98ab7053779cb1f431384018e058cbe2ac79d1d5ff020ce5474d9 + ) }), - qNnf: Honk.G1Point({ - x: uint256(0x11b342da18e6325f40bddb950e3ba058fe013e0a6757512f022a0d9961d3d468), - y: uint256(0x04225227552dcaa71ff7c4571eebd04ca40091a33ff91d1b220af458dffca289) + qNnf: Honk.G1Point({ + x: uint256( + 0x11b342da18e6325f40bddb950e3ba058fe013e0a6757512f022a0d9961d3d468 + ), + y: uint256( + 0x04225227552dcaa71ff7c4571eebd04ca40091a33ff91d1b220af458dffca289 + ) }), - qPoseidon2External: Honk.G1Point({ - x: uint256(0x18ae1c0c284757fd6a6bcf60413a8e2334fcb46562ea30b9cb9444a663493463), - y: uint256(0x1cade59f171ec1d94348309a02e1642067d6e6b43eb254837e703c1488dff221) + qPoseidon2External: Honk.G1Point({ + x: uint256( + 0x18ae1c0c284757fd6a6bcf60413a8e2334fcb46562ea30b9cb9444a663493463 + ), + y: uint256( + 0x1cade59f171ec1d94348309a02e1642067d6e6b43eb254837e703c1488dff221 + ) }), - qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x2537fc03ae8cfc49498d0a04704d77e10d6477d6b7c5e515cf24dadab0dee874), - y: uint256(0x0850d14d62e2c194a69110f3aefa10d6caea9bf6ff940331877c5f49e41e5fa7) + qPoseidon2Internal: Honk.G1Point({ + x: uint256( + 0x2537fc03ae8cfc49498d0a04704d77e10d6477d6b7c5e515cf24dadab0dee874 + ), + y: uint256( + 0x0850d14d62e2c194a69110f3aefa10d6caea9bf6ff940331877c5f49e41e5fa7 + ) }), - s1: Honk.G1Point({ - x: uint256(0x02f24bc3b670a81abc44133de34592b13bb3a5ea67cdaa1d73ad35965b8abe49), - y: uint256(0x0c62df1ee51bfbaeba2a75c1cc8aa8a2ea3222f21bc0b8958bd43c3aa749e963) + s1: Honk.G1Point({ + x: uint256( + 0x02f24bc3b670a81abc44133de34592b13bb3a5ea67cdaa1d73ad35965b8abe49 + ), + y: uint256( + 0x0c62df1ee51bfbaeba2a75c1cc8aa8a2ea3222f21bc0b8958bd43c3aa749e963 + ) }), - s2: Honk.G1Point({ - x: uint256(0x21ac9dc80bd7f54e6817d224b7650c4176407a1109f92567c05676ac1fe0973c), - y: uint256(0x2d325ad91e20be879c716023bcde84d469c4f7867c12bb321c387e4a1036f86d) + s2: Honk.G1Point({ + x: uint256( + 0x21ac9dc80bd7f54e6817d224b7650c4176407a1109f92567c05676ac1fe0973c + ), + y: uint256( + 0x2d325ad91e20be879c716023bcde84d469c4f7867c12bb321c387e4a1036f86d + ) }), - s3: Honk.G1Point({ - x: uint256(0x25b123800356ccc6d7a609989a0e4fc132bf757389ca25f0c1db7612bbec2349), - y: uint256(0x03832b0106e3581612f83d158277886cc9e5637790fccabde84b3218220f2a48) + s3: Honk.G1Point({ + x: uint256( + 0x25b123800356ccc6d7a609989a0e4fc132bf757389ca25f0c1db7612bbec2349 + ), + y: uint256( + 0x03832b0106e3581612f83d158277886cc9e5637790fccabde84b3218220f2a48 + ) }), - s4: Honk.G1Point({ - x: uint256(0x25962cb0996ebaeea7b01f8860fde2547f8bb738291e53c7f25a4ac80af4fd2e), - y: uint256(0x22ec82955d2dc95fddc9cf9fd4f7aa555635abb02cf6eeb7ac3df225c8b62d52) + s4: Honk.G1Point({ + x: uint256( + 0x25962cb0996ebaeea7b01f8860fde2547f8bb738291e53c7f25a4ac80af4fd2e + ), + y: uint256( + 0x22ec82955d2dc95fddc9cf9fd4f7aa555635abb02cf6eeb7ac3df225c8b62d52 + ) }), - t1: Honk.G1Point({ - x: uint256(0x099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d26), - y: uint256(0x0015b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f) + t1: Honk.G1Point({ + x: uint256( + 0x099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d26 + ), + y: uint256( + 0x0015b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f + ) }), - t2: Honk.G1Point({ - x: uint256(0x1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e), - y: uint256(0x305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d19) + t2: Honk.G1Point({ + x: uint256( + 0x1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e + ), + y: uint256( + 0x305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d19 + ) }), - t3: Honk.G1Point({ - x: uint256(0x061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d), - y: uint256(0x1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e) + t3: Honk.G1Point({ + x: uint256( + 0x061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d + ), + y: uint256( + 0x1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e + ) }), - t4: Honk.G1Point({ - x: uint256(0x043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce), - y: uint256(0x261522c4089330646aff96736194949330952ae74c573d1686d9cb4a00733854) + t4: Honk.G1Point({ + x: uint256( + 0x043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce + ), + y: uint256( + 0x261522c4089330646aff96736194949330952ae74c573d1686d9cb4a00733854 + ) }), - id1: Honk.G1Point({ - x: uint256(0x1332d280da268502ba2d853e14e53baf604c7a6a41b7e70bdf2e861cc6a59821), - y: uint256(0x0d14761f5281d5dc1209b25146d92d9e5692294f818c8c3468c9921f7a7cce79) + id1: Honk.G1Point({ + x: uint256( + 0x1332d280da268502ba2d853e14e53baf604c7a6a41b7e70bdf2e861cc6a59821 + ), + y: uint256( + 0x0d14761f5281d5dc1209b25146d92d9e5692294f818c8c3468c9921f7a7cce79 + ) }), - id2: Honk.G1Point({ - x: uint256(0x1b215ab72c8af91207dee6f8ac01f0e0d51895a9f670d7173c7b6d5b80a39085), - y: uint256(0x04ee544edd280fa185c8d9886c9e19832ef71d67fab5093eadeec49ccc5a34b1) + id2: Honk.G1Point({ + x: uint256( + 0x1b215ab72c8af91207dee6f8ac01f0e0d51895a9f670d7173c7b6d5b80a39085 + ), + y: uint256( + 0x04ee544edd280fa185c8d9886c9e19832ef71d67fab5093eadeec49ccc5a34b1 + ) }), - id3: Honk.G1Point({ - x: uint256(0x11005f2ce25b6f954b89343fa059782ab8ecdc84d411c828cc7dfd54f796b6f6), - y: uint256(0x0c68694f3595aecaaffdff52c0fa5f1d05fa8c7ba651da1220634fa4b8867ba7) + id3: Honk.G1Point({ + x: uint256( + 0x11005f2ce25b6f954b89343fa059782ab8ecdc84d411c828cc7dfd54f796b6f6 + ), + y: uint256( + 0x0c68694f3595aecaaffdff52c0fa5f1d05fa8c7ba651da1220634fa4b8867ba7 + ) }), - id4: Honk.G1Point({ - x: uint256(0x1145c2f8face74c268cc68c772d99c59587659cbd594a1aef32a36ab556621e2), - y: uint256(0x1ffa60a61a074aa68c8412fd9f3b4ae61437cf3ff3f0497e1244ba56370d7b91) + id4: Honk.G1Point({ + x: uint256( + 0x1145c2f8face74c268cc68c772d99c59587659cbd594a1aef32a36ab556621e2 + ), + y: uint256( + 0x1ffa60a61a074aa68c8412fd9f3b4ae61437cf3ff3f0497e1244ba56370d7b91 + ) }), - lagrangeFirst: Honk.G1Point({ - x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), - y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) + lagrangeFirst: Honk.G1Point({ + x: uint256( + 0x0000000000000000000000000000000000000000000000000000000000000001 + ), + y: uint256( + 0x0000000000000000000000000000000000000000000000000000000000000002 + ) }), - lagrangeLast: Honk.G1Point({ - x: uint256(0x1f0071e7d3b9be4c8376ff230b3b8b242585d403d25463022d38e574cb0b5754), - y: uint256(0x19cb572dac34151573e3024878327a8ea7febb3d76c6171b10d1e3f2f2907584) + lagrangeLast: Honk.G1Point({ + x: uint256( + 0x1f0071e7d3b9be4c8376ff230b3b8b242585d403d25463022d38e574cb0b5754 + ), + y: uint256( + 0x19cb572dac34151573e3024878327a8ea7febb3d76c6171b10d1e3f2f2907584 + ) }) }); return vk; @@ -135,24 +251,31 @@ library HonkVerificationKey { pragma solidity ^0.8.27; interface IVerifier { - function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external returns (bool); + function verify( + bytes calldata _proof, + bytes32[] calldata _publicInputs + ) external returns (bool); } type Fr is uint256; -using {add as +} for Fr global; -using {sub as -} for Fr global; -using {mul as *} for Fr global; +using { add as + } for Fr global; +using { sub as - } for Fr global; +using { mul as * } for Fr global; -using {exp as ^} for Fr global; -using {notEqual as !=} for Fr global; -using {equal as ==} for Fr global; +using { exp as ^ } for Fr global; +using { notEqual as != } for Fr global; +using { equal as == } for Fr global; uint256 constant SUBGROUP_SIZE = 256; uint256 constant MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order uint256 constant P = MODULUS; -Fr constant SUBGROUP_GENERATOR = Fr.wrap(0x07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76); -Fr constant SUBGROUP_GENERATOR_INVERSE = Fr.wrap(0x204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6); +Fr constant SUBGROUP_GENERATOR = Fr.wrap( + 0x07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76 +); +Fr constant SUBGROUP_GENERATOR_INVERSE = Fr.wrap( + 0x204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6 +); Fr constant MINUS_ONE = Fr.wrap(MODULUS - 1); Fr constant ONE = Fr.wrap(1); Fr constant ZERO = Fr.wrap(0); @@ -298,9 +421,11 @@ uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9; uint256 constant NUMBER_OF_ENTITIES = 41; // The number of entities added for ZK (gemini_masking_poly) uint256 constant NUM_MASKING_POLYNOMIALS = 1; -uint256 constant NUMBER_OF_ENTITIES_ZK = NUMBER_OF_ENTITIES + NUM_MASKING_POLYNOMIALS; +uint256 constant NUMBER_OF_ENTITIES_ZK = NUMBER_OF_ENTITIES + + NUM_MASKING_POLYNOMIALS; uint256 constant NUMBER_UNSHIFTED = 36; -uint256 constant NUMBER_UNSHIFTED_ZK = NUMBER_UNSHIFTED + NUM_MASKING_POLYNOMIALS; +uint256 constant NUMBER_UNSHIFTED_ZK = NUMBER_UNSHIFTED + + NUM_MASKING_POLYNOMIALS; uint256 constant NUMBER_TO_BE_SHIFTED = 5; uint256 constant PAIRING_POINTS_SIZE = 16; @@ -496,26 +621,63 @@ library ZKTranscriptLib { uint256 logN ) external pure returns (ZKTranscript memory t) { Fr previousChallenge; - (t.relationParameters, previousChallenge) = - generateRelationParametersChallenges(proof, publicInputs, vkHash, publicInputsSize, previousChallenge); + ( + t.relationParameters, + previousChallenge + ) = generateRelationParametersChallenges( + proof, + publicInputs, + vkHash, + publicInputsSize, + previousChallenge + ); - (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof); + (t.alphas, previousChallenge) = generateAlphaChallenges( + previousChallenge, + proof + ); - (t.gateChallenges, previousChallenge) = generateGateChallenges(previousChallenge, logN); - (t.libraChallenge, previousChallenge) = generateLibraChallenge(previousChallenge, proof); - (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges(proof, previousChallenge, logN); + (t.gateChallenges, previousChallenge) = generateGateChallenges( + previousChallenge, + logN + ); + (t.libraChallenge, previousChallenge) = generateLibraChallenge( + previousChallenge, + proof + ); + (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges( + proof, + previousChallenge, + logN + ); - (t.rho, previousChallenge) = generateRhoChallenge(proof, previousChallenge); + (t.rho, previousChallenge) = generateRhoChallenge( + proof, + previousChallenge + ); - (t.geminiR, previousChallenge) = generateGeminiRChallenge(proof, previousChallenge, logN); + (t.geminiR, previousChallenge) = generateGeminiRChallenge( + proof, + previousChallenge, + logN + ); - (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge(proof, previousChallenge, logN); + (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge( + proof, + previousChallenge, + logN + ); - (t.shplonkZ, previousChallenge) = generateShplonkZChallenge(proof, previousChallenge); + (t.shplonkZ, previousChallenge) = generateShplonkZChallenge( + proof, + previousChallenge + ); return t; } - function splitChallenge(Fr challenge) internal pure returns (Fr first, Fr second) { + function splitChallenge( + Fr challenge + ) internal pure returns (Fr first, Fr second) { uint256 challengeU256 = uint256(Fr.unwrap(challenge)); // Split into two equal 127-bit chunks (254/2) uint256 lo = challengeU256 & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // 127 bits @@ -530,11 +692,23 @@ library ZKTranscriptLib { uint256 vkHash, uint256 publicInputsSize, Fr previousChallenge - ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { - (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = - generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize); + ) + internal + pure + returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) + { + ( + rp.eta, + rp.etaTwo, + rp.etaThree, + previousChallenge + ) = generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize); - (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); + ( + rp.beta, + rp.gamma, + nextPreviousChallenge + ) = generateBetaAndGammaChallenges(previousChallenge, proof); } function generateEtaChallenge( @@ -542,7 +716,11 @@ library ZKTranscriptLib { bytes32[] calldata publicInputs, uint256 vkHash, uint256 publicInputsSize - ) internal pure returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) { + ) + internal + pure + returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) + { // Size: 1 (vkHash) + publicInputsSize + 8 (geminiMask(2) + 3 wires(6)) bytes32[] memory round0 = new bytes32[](1 + publicInputsSize + 8); round0[0] = bytes32(vkHash); @@ -551,7 +729,8 @@ library ZKTranscriptLib { round0[1 + i] = bytes32(publicInputs[i]); } for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { - round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]); + round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib + .toBytes32(proof.pairingPointObject[i]); } // For ZK flavors: hash the gemini masking poly commitment (sent right after public inputs) @@ -567,18 +746,21 @@ library ZKTranscriptLib { round0[1 + publicInputsSize + 6] = bytes32(proof.w3.x); round0[1 + publicInputsSize + 7] = bytes32(proof.w3.y); - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round0))); + previousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(round0)) + ); (eta, etaTwo) = splitChallenge(previousChallenge); - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))); + previousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))) + ); - (etaThree,) = splitChallenge(previousChallenge); + (etaThree, ) = splitChallenge(previousChallenge); } - function generateBetaAndGammaChallenges(Fr previousChallenge, Honk.ZKProof memory proof) - internal - pure - returns (Fr beta, Fr gamma, Fr nextPreviousChallenge) - { + function generateBetaAndGammaChallenges( + Fr previousChallenge, + Honk.ZKProof memory proof + ) internal pure returns (Fr beta, Fr gamma, Fr nextPreviousChallenge) { bytes32[7] memory round1; round1[0] = FrLib.toBytes32(previousChallenge); round1[1] = bytes32(proof.lookupReadCounts.x); @@ -588,12 +770,17 @@ library ZKTranscriptLib { round1[5] = bytes32(proof.w4.x); round1[6] = bytes32(proof.w4.y); - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round1))); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(round1)) + ); (beta, gamma) = splitChallenge(nextPreviousChallenge); } // Alpha challenges non-linearise the gate contributions - function generateAlphaChallenges(Fr previousChallenge, Honk.ZKProof memory proof) + function generateAlphaChallenges( + Fr previousChallenge, + Honk.ZKProof memory proof + ) internal pure returns (Fr[NUMBER_OF_ALPHAS] memory alphas, Fr nextPreviousChallenge) @@ -606,9 +793,11 @@ library ZKTranscriptLib { alpha0[3] = proof.zPerm.x; alpha0[4] = proof.zPerm.y; - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(alpha0))); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(alpha0)) + ); Fr alpha; - (alpha,) = splitChallenge(nextPreviousChallenge); + (alpha, ) = splitChallenge(nextPreviousChallenge); // Compute powers of alpha for batching subrelations alphas[0] = alpha; @@ -617,38 +806,54 @@ library ZKTranscriptLib { } } - function generateGateChallenges(Fr previousChallenge, uint256 logN) + function generateGateChallenges( + Fr previousChallenge, + uint256 logN + ) internal pure - returns (Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, Fr nextPreviousChallenge) + returns ( + Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, + Fr nextPreviousChallenge + ) { - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))); - (gateChallenges[0],) = splitChallenge(previousChallenge); + previousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))) + ); + (gateChallenges[0], ) = splitChallenge(previousChallenge); for (uint256 i = 1; i < logN; i++) { gateChallenges[i] = gateChallenges[i - 1] * gateChallenges[i - 1]; } nextPreviousChallenge = previousChallenge; } - function generateLibraChallenge(Fr previousChallenge, Honk.ZKProof memory proof) - internal - pure - returns (Fr libraChallenge, Fr nextPreviousChallenge) - { + function generateLibraChallenge( + Fr previousChallenge, + Honk.ZKProof memory proof + ) internal pure returns (Fr libraChallenge, Fr nextPreviousChallenge) { // 2 comm, 1 sum, 1 challenge uint256[4] memory challengeData; challengeData[0] = Fr.unwrap(previousChallenge); challengeData[1] = proof.libraCommitments[0].x; challengeData[2] = proof.libraCommitments[0].y; challengeData[3] = Fr.unwrap(proof.libraSum); - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(challengeData))); - (libraChallenge,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(challengeData)) + ); + (libraChallenge, ) = splitChallenge(nextPreviousChallenge); } - function generateSumcheckChallenges(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) + function generateSumcheckChallenges( + Honk.ZKProof memory proof, + Fr prevChallenge, + uint256 logN + ) internal pure - returns (Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, Fr nextPreviousChallenge) + returns ( + Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, + Fr nextPreviousChallenge + ) { for (uint256 i = 0; i < logN; i++) { Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH + 1] memory univariateChal; @@ -657,24 +862,27 @@ library ZKTranscriptLib { for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) { univariateChal[j + 1] = proof.sumcheckUnivariates[i][j]; } - prevChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(univariateChal))); + prevChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(univariateChal)) + ); - (sumcheckChallenges[i],) = splitChallenge(prevChallenge); + (sumcheckChallenges[i], ) = splitChallenge(prevChallenge); } nextPreviousChallenge = prevChallenge; } // We add Libra claimed eval + 2 libra commitments (grand_sum, quotient) - function generateRhoChallenge(Honk.ZKProof memory proof, Fr prevChallenge) - internal - pure - returns (Fr rho, Fr nextPreviousChallenge) - { + function generateRhoChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge + ) internal pure returns (Fr rho, Fr nextPreviousChallenge) { uint256[NUMBER_OF_ENTITIES_ZK + 6] memory rhoChallengeElements; rhoChallengeElements[0] = Fr.unwrap(prevChallenge); uint256 i; for (i = 1; i <= NUMBER_OF_ENTITIES_ZK; i++) { - rhoChallengeElements[i] = Fr.unwrap(proof.sumcheckEvaluations[i - 1]); + rhoChallengeElements[i] = Fr.unwrap( + proof.sumcheckEvaluations[i - 1] + ); } rhoChallengeElements[i] = Fr.unwrap(proof.libraEvaluation); i += 1; @@ -684,15 +892,17 @@ library ZKTranscriptLib { rhoChallengeElements[i] = proof.libraCommitments[2].x; rhoChallengeElements[i + 1] = proof.libraCommitments[2].y; - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(rhoChallengeElements))); - (rho,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(rhoChallengeElements)) + ); + (rho, ) = splitChallenge(nextPreviousChallenge); } - function generateGeminiRChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) - internal - pure - returns (Fr geminiR, Fr nextPreviousChallenge) - { + function generateGeminiRChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge, + uint256 logN + ) internal pure returns (Fr geminiR, Fr nextPreviousChallenge) { uint256[] memory gR = new uint256[]((logN - 1) * 2 + 1); gR[0] = Fr.unwrap(prevChallenge); @@ -701,59 +911,77 @@ library ZKTranscriptLib { gR[2 + i * 2] = proof.geminiFoldComms[i].y; } - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(gR))); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(gR)) + ); - (geminiR,) = splitChallenge(nextPreviousChallenge); + (geminiR, ) = splitChallenge(nextPreviousChallenge); } - function generateShplonkNuChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) - internal - pure - returns (Fr shplonkNu, Fr nextPreviousChallenge) - { - uint256[] memory shplonkNuChallengeElements = new uint256[](logN + 1 + 4); + function generateShplonkNuChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge, + uint256 logN + ) internal pure returns (Fr shplonkNu, Fr nextPreviousChallenge) { + uint256[] memory shplonkNuChallengeElements = new uint256[]( + logN + 1 + 4 + ); shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge); for (uint256 i = 1; i <= logN; i++) { - shplonkNuChallengeElements[i] = Fr.unwrap(proof.geminiAEvaluations[i - 1]); + shplonkNuChallengeElements[i] = Fr.unwrap( + proof.geminiAEvaluations[i - 1] + ); } uint256 libraIdx = 0; for (uint256 i = logN + 1; i <= logN + 4; i++) { - shplonkNuChallengeElements[i] = Fr.unwrap(proof.libraPolyEvals[libraIdx]); + shplonkNuChallengeElements[i] = Fr.unwrap( + proof.libraPolyEvals[libraIdx] + ); libraIdx++; } - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkNuChallengeElements))); - (shplonkNu,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(shplonkNuChallengeElements)) + ); + (shplonkNu, ) = splitChallenge(nextPreviousChallenge); } - function generateShplonkZChallenge(Honk.ZKProof memory proof, Fr prevChallenge) - internal - pure - returns (Fr shplonkZ, Fr nextPreviousChallenge) - { + function generateShplonkZChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge + ) internal pure returns (Fr shplonkZ, Fr nextPreviousChallenge) { uint256[3] memory shplonkZChallengeElements; shplonkZChallengeElements[0] = Fr.unwrap(prevChallenge); shplonkZChallengeElements[1] = proof.shplonkQ.x; shplonkZChallengeElements[2] = proof.shplonkQ.y; - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkZChallengeElements))); - (shplonkZ,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(shplonkZChallengeElements)) + ); + (shplonkZ, ) = splitChallenge(nextPreviousChallenge); } - function loadProof(bytes calldata proof, uint256 logN) internal pure returns (Honk.ZKProof memory p) { + function loadProof( + bytes calldata proof, + uint256 logN + ) internal pure returns (Honk.ZKProof memory p) { uint256 boundary = 0x0; // Pairing point object for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { - p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.pairingPointObject[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } // Gemini masking polynomial commitment (sent first in ZK flavors, right after pairing points) - p.geminiMaskingPoly = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.geminiMaskingPoly = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; // Commitments @@ -765,17 +993,25 @@ library ZKTranscriptLib { boundary += GROUP_ELEMENT_SIZE; // Lookup / Permutation Helper Commitments - p.lookupReadCounts = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupReadCounts = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; - p.lookupReadTags = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupReadTags = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; p.w4 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); boundary += GROUP_ELEMENT_SIZE; - p.lookupInverses = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupInverses = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; p.zPerm = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); boundary += GROUP_ELEMENT_SIZE; - p.libraCommitments[0] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.libraCommitments[0] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; p.libraSum = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); @@ -783,48 +1019,68 @@ library ZKTranscriptLib { // Sumcheck univariates for (uint256 i = 0; i < logN; i++) { for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) { - p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.sumcheckUnivariates[i][j] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } } // Sumcheck evaluations (includes gemini_masking_poly eval at index 0 for ZK flavors) for (uint256 i = 0; i < NUMBER_OF_ENTITIES_ZK; i++) { - p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.sumcheckEvaluations[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } - p.libraEvaluation = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.libraEvaluation = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; - p.libraCommitments[1] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.libraCommitments[1] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; - p.libraCommitments[2] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.libraCommitments[2] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; // Gemini // Read gemini fold univariates for (uint256 i = 0; i < logN - 1; i++) { - p.geminiFoldComms[i] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.geminiFoldComms[i] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; } // Read gemini a evaluations for (uint256 i = 0; i < logN; i++) { - p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.geminiAEvaluations[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } for (uint256 i = 0; i < 4; i++) { - p.libraPolyEvals[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.libraPolyEvals[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } // Shplonk - p.shplonkQ = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.shplonkQ = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; // KZG - p.kzgQuotient = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.kzgQuotient = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); } } @@ -842,18 +1098,60 @@ library RelationsLib { Fr[NUMBER_OF_SUBRELATIONS] memory evaluations; // Accumulate all relations in Ultra Honk - each with varying number of subrelations - accumulateArithmeticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePermutationRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateLogDerivativeLookupRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateDeltaRangeRelation(purportedEvaluations, evaluations, powPartialEval); - accumulateEllipticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulateMemoryRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateNnfRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval); + accumulateArithmeticRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulatePermutationRelation( + purportedEvaluations, + rp, + evaluations, + powPartialEval + ); + accumulateLogDerivativeLookupRelation( + purportedEvaluations, + rp, + evaluations, + powPartialEval + ); + accumulateDeltaRangeRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulateEllipticRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulateMemoryRelation( + purportedEvaluations, + rp, + evaluations, + powPartialEval + ); + accumulateNnfRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulatePoseidonExternalRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulatePoseidonInternalRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); // batch the subrelations with the precomputed alpha powers to obtain the full honk relation - accumulator = scaleAndBatchSubrelations(evaluations, subrelationChallenges); + accumulator = scaleAndBatchSubrelations( + evaluations, + subrelationChallenges + ); } /** @@ -861,11 +1159,15 @@ library RelationsLib { * the relation checking code being cluttered with uint256 type casting, which is often a different colour in code * editors, and thus is noisy. */ - function wire(Fr[NUMBER_OF_ENTITIES] memory p, WIRE _wire) internal pure returns (Fr) { + function wire( + Fr[NUMBER_OF_ENTITIES] memory p, + WIRE _wire + ) internal pure returns (Fr) { return p[uint256(_wire)]; } - uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; + uint256 internal constant NEG_HALF_MODULO_P = + 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; /** * Ultra Arithmetic Relation * @@ -881,9 +1183,16 @@ library RelationsLib { { Fr neg_half = Fr.wrap(NEG_HALF_MODULO_P); - Fr accum = (q_arith - Fr.wrap(3)) * (wire(p, WIRE.Q_M) * wire(p, WIRE.W_R) * wire(p, WIRE.W_L)) * neg_half; - accum = accum + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R)) - + (wire(p, WIRE.Q_O) * wire(p, WIRE.W_O)) + (wire(p, WIRE.Q_4) * wire(p, WIRE.W_4)) + wire(p, WIRE.Q_C); + Fr accum = (q_arith - Fr.wrap(3)) * + (wire(p, WIRE.Q_M) * wire(p, WIRE.W_R) * wire(p, WIRE.W_L)) * + neg_half; + accum = + accum + + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R)) + + (wire(p, WIRE.Q_O) * wire(p, WIRE.W_O)) + + (wire(p, WIRE.Q_4) * wire(p, WIRE.W_4)) + + wire(p, WIRE.Q_C); accum = accum + (q_arith - ONE) * wire(p, WIRE.W_4_SHIFT); accum = accum * q_arith; accum = accum * domainSep; @@ -892,7 +1201,10 @@ library RelationsLib { // Relation 1 { - Fr accum = wire(p, WIRE.W_L) + wire(p, WIRE.W_4) - wire(p, WIRE.W_L_SHIFT) + wire(p, WIRE.Q_M); + Fr accum = wire(p, WIRE.W_L) + + wire(p, WIRE.W_4) - + wire(p, WIRE.W_L_SHIFT) + + wire(p, WIRE.Q_M); accum = accum * (q_arith - Fr.wrap(2)); accum = accum * (q_arith - ONE); accum = accum * q_arith; @@ -911,36 +1223,67 @@ library RelationsLib { Fr grand_product_denominator; { - Fr num = wire(p, WIRE.W_L) + wire(p, WIRE.ID_1) * rp.beta + rp.gamma; - num = num * (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma); - num = num * (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma); - num = num * (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma); + Fr num = wire(p, WIRE.W_L) + + wire(p, WIRE.ID_1) * + rp.beta + + rp.gamma; + num = + num * + (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma); + num = + num * + (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma); + num = + num * + (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma); grand_product_numerator = num; } { - Fr den = wire(p, WIRE.W_L) + wire(p, WIRE.SIGMA_1) * rp.beta + rp.gamma; - den = den * (wire(p, WIRE.W_R) + wire(p, WIRE.SIGMA_2) * rp.beta + rp.gamma); - den = den * (wire(p, WIRE.W_O) + wire(p, WIRE.SIGMA_3) * rp.beta + rp.gamma); - den = den * (wire(p, WIRE.W_4) + wire(p, WIRE.SIGMA_4) * rp.beta + rp.gamma); + Fr den = wire(p, WIRE.W_L) + + wire(p, WIRE.SIGMA_1) * + rp.beta + + rp.gamma; + den = + den * + (wire(p, WIRE.W_R) + + wire(p, WIRE.SIGMA_2) * + rp.beta + + rp.gamma); + den = + den * + (wire(p, WIRE.W_O) + + wire(p, WIRE.SIGMA_3) * + rp.beta + + rp.gamma); + den = + den * + (wire(p, WIRE.W_4) + + wire(p, WIRE.SIGMA_4) * + rp.beta + + rp.gamma); grand_product_denominator = den; } // Contribution 2 { - Fr acc = (wire(p, WIRE.Z_PERM) + wire(p, WIRE.LAGRANGE_FIRST)) * grand_product_numerator; - - acc = acc - - ((wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) - * grand_product_denominator); + Fr acc = (wire(p, WIRE.Z_PERM) + wire(p, WIRE.LAGRANGE_FIRST)) * + grand_product_numerator; + + acc = + acc - + ((wire(p, WIRE.Z_PERM_SHIFT) + + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) * + grand_product_denominator); acc = acc * domainSep; evals[2] = acc; } // Contribution 3 { - Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; + Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * + wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; evals[3] = acc; } } @@ -956,33 +1299,52 @@ library RelationsLib { // Calculate the write term (the table accumulation) { - write_term = wire(p, WIRE.TABLE_1) + rp.gamma + (wire(p, WIRE.TABLE_2) * rp.eta) - + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + (wire(p, WIRE.TABLE_4) * rp.etaThree); + write_term = + wire(p, WIRE.TABLE_1) + + rp.gamma + + (wire(p, WIRE.TABLE_2) * rp.eta) + + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + + (wire(p, WIRE.TABLE_4) * rp.etaThree); } // Calculate the write term { - Fr derived_entry_1 = wire(p, WIRE.W_L) + rp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); - Fr derived_entry_2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_M) * wire(p, WIRE.W_R_SHIFT); - Fr derived_entry_3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_C) * wire(p, WIRE.W_O_SHIFT); - - read_term = derived_entry_1 + (derived_entry_2 * rp.eta) + (derived_entry_3 * rp.etaTwo) - + (wire(p, WIRE.Q_O) * rp.etaThree); + Fr derived_entry_1 = wire(p, WIRE.W_L) + + rp.gamma + + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); + Fr derived_entry_2 = wire(p, WIRE.W_R) + + wire(p, WIRE.Q_M) * + wire(p, WIRE.W_R_SHIFT); + Fr derived_entry_3 = wire(p, WIRE.W_O) + + wire(p, WIRE.Q_C) * + wire(p, WIRE.W_O_SHIFT); + + read_term = + derived_entry_1 + + (derived_entry_2 * rp.eta) + + (derived_entry_3 * rp.etaTwo) + + (wire(p, WIRE.Q_O) * rp.etaThree); } Fr read_inverse = wire(p, WIRE.LOOKUP_INVERSES) * write_term; Fr write_inverse = wire(p, WIRE.LOOKUP_INVERSES) * read_term; - Fr inverse_exists_xor = - wire(p, WIRE.LOOKUP_READ_TAGS) + wire(p, WIRE.Q_LOOKUP) - - (wire(p, WIRE.LOOKUP_READ_TAGS) * wire(p, WIRE.Q_LOOKUP)); + Fr inverse_exists_xor = wire(p, WIRE.LOOKUP_READ_TAGS) + + wire(p, WIRE.Q_LOOKUP) - + (wire(p, WIRE.LOOKUP_READ_TAGS) * wire(p, WIRE.Q_LOOKUP)); // Inverse calculated correctly relation - Fr accumulatorNone = read_term * write_term * wire(p, WIRE.LOOKUP_INVERSES) - inverse_exists_xor; + Fr accumulatorNone = read_term * + write_term * + wire(p, WIRE.LOOKUP_INVERSES) - + inverse_exists_xor; accumulatorNone = accumulatorNone * domainSep; // Inverse - Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * read_inverse - wire(p, WIRE.LOOKUP_READ_COUNTS) * write_inverse; + Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * + read_inverse - + wire(p, WIRE.LOOKUP_READ_COUNTS) * + write_inverse; Fr read_tag = wire(p, WIRE.LOOKUP_READ_TAGS); @@ -1096,7 +1458,11 @@ library RelationsLib { x_add_identity = x_add_identity * x_diff * x_diff; x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2; - evals[11] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + evals[11] = + x_add_identity * + partialEval * + wire(p, WIRE.Q_ELLIPTIC) * + (ONE - q_is_double); } // Contribution 11 point addition, x-coordinate check @@ -1104,8 +1470,15 @@ library RelationsLib { { Fr y1_plus_y3 = ep.y_1 + ep.y_3; Fr y_diff = ep.y_2 * q_sign - ep.y_1; - Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff; - evals[12] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + Fr y_add_identity = y1_plus_y3 * + x_diff + + (ep.x_3 - ep.x_1) * + y_diff; + evals[12] = + y_add_identity * + domainSep * + wire(p, WIRE.Q_ELLIPTIC) * + (ONE - q_is_double); } // Contribution 10 point doubling, x-coordinate check @@ -1118,9 +1491,15 @@ library RelationsLib { Fr x1_pow_4_mul_9 = x_pow_4 * Fr.wrap(9); // NOTE: pushed into memory (stack >:'( ) - ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9; - - Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + ep.x_double_identity = + (ep.x_3 + ep.x_1 + ep.x_1) * + y1_sqr_mul_4 - + x1_pow_4_mul_9; + + Fr acc = ep.x_double_identity * + domainSep * + wire(p, WIRE.Q_ELLIPTIC) * + q_is_double; evals[11] = evals[11] + acc; } @@ -1128,8 +1507,16 @@ library RelationsLib { // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0 { Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1; - Fr y_double_identity = x1_sqr_mul_3 * (ep.x_1 - ep.x_3) - (ep.y_1 + ep.y_1) * (ep.y_1 + ep.y_3); - evals[12] = evals[12] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + Fr y_double_identity = x1_sqr_mul_3 * + (ep.x_1 - ep.x_3) - + (ep.y_1 + ep.y_1) * + (ep.y_1 + ep.y_3); + evals[12] = + evals[12] + + y_double_identity * + domainSep * + wire(p, WIRE.Q_ELLIPTIC) * + q_is_double; } } @@ -1203,8 +1590,12 @@ library RelationsLib { * For ROM gates, qc = 0 */ ap.memory_record_check = wire(p, WIRE.W_O) * rp.etaThree; - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * rp.etaTwo); - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * rp.eta); + ap.memory_record_check = + ap.memory_record_check + + (wire(p, WIRE.W_R) * rp.etaTwo); + ap.memory_record_check = + ap.memory_record_check + + (wire(p, WIRE.W_L) * rp.eta); ap.memory_record_check = ap.memory_record_check + wire(p, WIRE.Q_C); ap.partial_record_check = ap.memory_record_check; // used in RAM consistency check; deg 1 or 4 ap.memory_record_check = ap.memory_record_check - wire(p, WIRE.W_4); @@ -1228,16 +1619,26 @@ library RelationsLib { ap.index_delta = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_L); ap.record_delta = wire(p, WIRE.W_4_SHIFT) - wire(p, WIRE.W_4); - ap.index_is_monotonically_increasing = ap.index_delta * (ap.index_delta - Fr.wrap(1)); // deg 2 + ap.index_is_monotonically_increasing = + ap.index_delta * + (ap.index_delta - Fr.wrap(1)); // deg 2 - ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + ONE) * ap.record_delta; // deg 2 + ap.adjacent_values_match_if_adjacent_indices_match = + (ap.index_delta * MINUS_ONE + ONE) * + ap.record_delta; // deg 2 - evals[14] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) - * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - evals[15] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) - * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 + evals[14] = + ap.adjacent_values_match_if_adjacent_indices_match * + (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 + evals[15] = + ap.index_is_monotonically_increasing * + (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 + ap.ROM_consistency_check_identity = + ap.memory_record_check * + (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 /** * Contributions 15,16,17 @@ -1264,13 +1665,22 @@ library RelationsLib { // reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta // deg 1 or 4 ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree; - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta); - ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type; + ap.next_gate_access_type = + ap.next_gate_access_type + + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); + ap.next_gate_access_type = + ap.next_gate_access_type + + (wire(p, WIRE.W_L_SHIFT) * rp.eta); + ap.next_gate_access_type = + wire(p, WIRE.W_4_SHIFT) - + ap.next_gate_access_type; Fr value_delta = wire(p, WIRE.W_O_SHIFT) - wire(p, WIRE.W_O); - ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = - (ap.index_delta * MINUS_ONE + ONE) * value_delta * (ap.next_gate_access_type * MINUS_ONE + ONE); // deg 3 or 6 + ap + .adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = + (ap.index_delta * MINUS_ONE + ONE) * + value_delta * + (ap.next_gate_access_type * MINUS_ONE + ONE); // deg 3 or 6 // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't @@ -1278,15 +1688,28 @@ library RelationsLib { // type is correct, to cover this edge case // deg 2 or 4 ap.next_gate_access_type_is_boolean = - ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type; + ap.next_gate_access_type * + ap.next_gate_access_type - + ap.next_gate_access_type; // Putting it all together... - evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation - * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 - evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 - evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 - - ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9 + evals[16] = + ap + .adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * + (wire(p, WIRE.Q_O)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 + evals[17] = + ap.index_is_monotonically_increasing * + (wire(p, WIRE.Q_O)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 + evals[18] = + ap.next_gate_access_type_is_boolean * + (wire(p, WIRE.Q_O)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 + + ap.RAM_consistency_check_identity = + ap.access_check * + (wire(p, WIRE.Q_O)); // deg 3 or 9 /** * RAM Timestamp Consistency Check @@ -1300,7 +1723,10 @@ library RelationsLib { * Else timestamp_check = 0 */ ap.timestamp_delta = wire(p, WIRE.W_R_SHIFT) - wire(p, WIRE.W_R); - ap.RAM_timestamp_check_identity = (ap.index_delta * MINUS_ONE + ONE) * ap.timestamp_delta - wire(p, WIRE.W_O); // deg 3 + ap.RAM_timestamp_check_identity = + (ap.index_delta * MINUS_ONE + ONE) * + ap.timestamp_delta - + wire(p, WIRE.W_O); // deg 3 /** * Complete Contribution 12 @@ -1309,12 +1735,21 @@ library RelationsLib { */ ap.memory_identity = ap.ROM_consistency_check_identity; // deg 3 or 6 ap.memory_identity = - ap.memory_identity + ap.RAM_timestamp_check_identity * (wire(p, WIRE.Q_4) * wire(p, WIRE.Q_L)); // deg 4 - ap.memory_identity = ap.memory_identity + ap.memory_record_check * (wire(p, WIRE.Q_M) * wire(p, WIRE.Q_L)); // deg 3 or 6 - ap.memory_identity = ap.memory_identity + ap.RAM_consistency_check_identity; // deg 3 or 9 + ap.memory_identity + + ap.RAM_timestamp_check_identity * + (wire(p, WIRE.Q_4) * wire(p, WIRE.Q_L)); // deg 4 + ap.memory_identity = + ap.memory_identity + + ap.memory_record_check * + (wire(p, WIRE.Q_M) * wire(p, WIRE.Q_L)); // deg 3 or 6 + ap.memory_identity = + ap.memory_identity + + ap.RAM_consistency_check_identity; // deg 3 or 9 // (deg 3 or 9) + (deg 4) + (deg 3) - ap.memory_identity = ap.memory_identity * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10 + ap.memory_identity = + ap.memory_identity * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10 evals[13] = ap.memory_identity; } @@ -1353,28 +1788,56 @@ library RelationsLib { * * */ - ap.limb_subproduct = wire(p, WIRE.W_L) * wire(p, WIRE.W_R_SHIFT) + wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R); - ap.non_native_field_gate_2 = - (wire(p, WIRE.W_L) * wire(p, WIRE.W_4) + wire(p, WIRE.W_R) * wire(p, WIRE.W_O) - wire(p, WIRE.W_O_SHIFT)); + ap.limb_subproduct = + wire(p, WIRE.W_L) * + wire(p, WIRE.W_R_SHIFT) + + wire(p, WIRE.W_L_SHIFT) * + wire(p, WIRE.W_R); + ap.non_native_field_gate_2 = (wire(p, WIRE.W_L) * + wire(p, WIRE.W_4) + + wire(p, WIRE.W_R) * + wire(p, WIRE.W_O) - + wire(p, WIRE.W_O_SHIFT)); ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * LIMB_SIZE; - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 - wire(p, WIRE.W_4_SHIFT); - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 + ap.limb_subproduct; - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * wire(p, WIRE.Q_4); + ap.non_native_field_gate_2 = + ap.non_native_field_gate_2 - + wire(p, WIRE.W_4_SHIFT); + ap.non_native_field_gate_2 = + ap.non_native_field_gate_2 + + ap.limb_subproduct; + ap.non_native_field_gate_2 = + ap.non_native_field_gate_2 * + wire(p, WIRE.Q_4); ap.limb_subproduct = ap.limb_subproduct * LIMB_SIZE; - ap.limb_subproduct = ap.limb_subproduct + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT)); + ap.limb_subproduct = + ap.limb_subproduct + + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT)); ap.non_native_field_gate_1 = ap.limb_subproduct; - ap.non_native_field_gate_1 = ap.non_native_field_gate_1 - (wire(p, WIRE.W_O) + wire(p, WIRE.W_4)); - ap.non_native_field_gate_1 = ap.non_native_field_gate_1 * wire(p, WIRE.Q_O); + ap.non_native_field_gate_1 = + ap.non_native_field_gate_1 - + (wire(p, WIRE.W_O) + wire(p, WIRE.W_4)); + ap.non_native_field_gate_1 = + ap.non_native_field_gate_1 * + wire(p, WIRE.Q_O); ap.non_native_field_gate_3 = ap.limb_subproduct; - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 + wire(p, WIRE.W_4); - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 - (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT)); - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 * wire(p, WIRE.Q_M); - - Fr non_native_field_identity = - ap.non_native_field_gate_1 + ap.non_native_field_gate_2 + ap.non_native_field_gate_3; - non_native_field_identity = non_native_field_identity * wire(p, WIRE.Q_R); + ap.non_native_field_gate_3 = + ap.non_native_field_gate_3 + + wire(p, WIRE.W_4); + ap.non_native_field_gate_3 = + ap.non_native_field_gate_3 - + (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT)); + ap.non_native_field_gate_3 = + ap.non_native_field_gate_3 * + wire(p, WIRE.Q_M); + + Fr non_native_field_identity = ap.non_native_field_gate_1 + + ap.non_native_field_gate_2 + + ap.non_native_field_gate_3; + non_native_field_identity = + non_native_field_identity * + wire(p, WIRE.Q_R); // ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * qm // deg 2 @@ -1402,8 +1865,11 @@ library RelationsLib { ap.limb_accumulator_2 = ap.limb_accumulator_2 - wire(p, WIRE.W_4_SHIFT); ap.limb_accumulator_2 = ap.limb_accumulator_2 * wire(p, WIRE.Q_M); - Fr limb_accumulator_identity = ap.limb_accumulator_1 + ap.limb_accumulator_2; - limb_accumulator_identity = limb_accumulator_identity * wire(p, WIRE.Q_O); // deg 3 + Fr limb_accumulator_identity = ap.limb_accumulator_1 + + ap.limb_accumulator_2; + limb_accumulator_identity = + limb_accumulator_identity * + wire(p, WIRE.Q_O); // deg 3 ap.nnf_identity = non_native_field_identity + limb_accumulator_identity; ap.nnf_identity = ap.nnf_identity * (wire(p, WIRE.Q_NNF) * domainSep); @@ -1463,13 +1929,25 @@ library RelationsLib { ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4 ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep; - evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[20] = + evals[20] + + ep.q_pos_by_scaling * + (ep.v1 - wire(p, WIRE.W_L_SHIFT)); - evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[21] = + evals[21] + + ep.q_pos_by_scaling * + (ep.v2 - wire(p, WIRE.W_R_SHIFT)); - evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[22] = + evals[22] + + ep.q_pos_by_scaling * + (ep.v3 - wire(p, WIRE.W_O_SHIFT)); - evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[23] = + evals[23] + + ep.q_pos_by_scaling * + (ep.v4 - wire(p, WIRE.W_4_SHIFT)); } struct PoseidonInternalParams { @@ -1494,10 +1972,18 @@ library RelationsLib { PoseidonInternalParams memory ip; Fr[4] memory INTERNAL_MATRIX_DIAGONAL = [ - FrLib.from(0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7), - FrLib.from(0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b), - FrLib.from(0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15), - FrLib.from(0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b) + FrLib.from( + 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7 + ), + FrLib.from( + 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b + ), + FrLib.from( + 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15 + ), + FrLib.from( + 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b + ) ]; // add round constants @@ -1515,16 +2001,28 @@ library RelationsLib { ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep; ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum; - evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[24] = + evals[24] + + ip.q_pos_by_scaling * + (ip.v1 - wire(p, WIRE.W_L_SHIFT)); ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum; - evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[25] = + evals[25] + + ip.q_pos_by_scaling * + (ip.v2 - wire(p, WIRE.W_R_SHIFT)); ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum; - evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[26] = + evals[26] + + ip.q_pos_by_scaling * + (ip.v3 - wire(p, WIRE.W_O_SHIFT)); ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum; - evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[27] = + evals[27] + + ip.q_pos_by_scaling * + (ip.v4 - wire(p, WIRE.W_4_SHIFT)); } // Batch subrelation evaluations using precomputed powers of alpha @@ -1536,7 +2034,10 @@ library RelationsLib { accumulator = evaluations[0]; for (uint256 i = 1; i < NUMBER_OF_SUBRELATIONS; ++i) { - accumulator = accumulator + evaluations[i] * subrelationChallenges[i - 1]; + accumulator = + accumulator + + evaluations[i] * + subrelationChallenges[i - 1]; } } } @@ -1572,7 +2073,10 @@ library CommitmentSchemeLib { Fr[] foldPosEvaluations; } - function computeSquares(Fr r, uint256 logN) internal pure returns (Fr[] memory) { + function computeSquares( + Fr r, + uint256 logN + ) internal pure returns (Fr[] memory) { Fr[] memory squares = new Fr[](logN); squares[0] = r; for (uint256 i = 1; i < logN; ++i) { @@ -1594,10 +2098,15 @@ library CommitmentSchemeLib { Fr challengePower = geminiEvalChallengePowers[i - 1]; Fr u = sumcheckUChallenges[i - 1]; - Fr batchedEvalRoundAcc = ((challengePower * batchedEvalAccumulator * Fr.wrap(2)) - geminiEvaluations[i - 1] - * (challengePower * (ONE - u) - u)); + Fr batchedEvalRoundAcc = ((challengePower * + batchedEvalAccumulator * + Fr.wrap(2)) - + geminiEvaluations[i - 1] * + (challengePower * (ONE - u) - u)); // Divide by the denominator - batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (ONE - u) + u).invert(); + batchedEvalRoundAcc = + batchedEvalRoundAcc * + (challengePower * (ONE - u) + u).invert(); batchedEvalAccumulator = batchedEvalRoundAcc; foldPosEvaluations[i - 1] = batchedEvalRoundAcc; @@ -1628,13 +2137,18 @@ function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) { } // EC Point utilities -function bytesToG1Point(bytes calldata proofSection) pure returns (Honk.G1Point memory point) { +function bytesToG1Point( + bytes calldata proofSection +) pure returns (Honk.G1Point memory point) { point = Honk.G1Point({ - x: uint256(bytes32(proofSection[0x00:0x20])) % Q, y: uint256(bytes32(proofSection[0x20:0x40])) % Q + x: uint256(bytes32(proofSection[0x00:0x20])) % Q, + y: uint256(bytes32(proofSection[0x20:0x40])) % Q }); } -function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) { +function negateInplace( + Honk.G1Point memory point +) pure returns (Honk.G1Point memory) { point.y = (Q - point.y) % Q; return point; } @@ -1651,10 +2165,9 @@ function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point mem * @return lhs * @return rhs */ -function convertPairingPointsToG1(Fr[PAIRING_POINTS_SIZE] memory pairingPoints) - pure - returns (Honk.G1Point memory lhs, Honk.G1Point memory rhs) -{ +function convertPairingPointsToG1( + Fr[PAIRING_POINTS_SIZE] memory pairingPoints +) pure returns (Honk.G1Point memory lhs, Honk.G1Point memory rhs) { uint256 lhsX = Fr.unwrap(pairingPoints[0]); lhsX |= Fr.unwrap(pairingPoints[1]) << 68; lhsX |= Fr.unwrap(pairingPoints[2]) << 136; @@ -1698,7 +2211,10 @@ function generateRecursionSeparator( // hash the accum X // hash the accum Y - (Honk.G1Point memory proofLhs, Honk.G1Point memory proofRhs) = convertPairingPointsToG1(proofPairingPoints); + ( + Honk.G1Point memory proofLhs, + Honk.G1Point memory proofRhs + ) = convertPairingPointsToG1(proofPairingPoints); uint256[8] memory recursionSeparatorElements; @@ -1714,7 +2230,9 @@ function generateRecursionSeparator( recursionSeparatorElements[6] = accRhs.x; recursionSeparatorElements[7] = accRhs.y; - recursionSeparator = FrLib.fromBytes32(keccak256(abi.encodePacked(recursionSeparatorElements))); + recursionSeparator = FrLib.fromBytes32( + keccak256(abi.encodePacked(recursionSeparatorElements)) + ); } /** @@ -1726,10 +2244,11 @@ function generateRecursionSeparator( * @param recursionSeperator The separator to use for the multiplication. * @return `(recursionSeperator * basePoint) + other`. */ -function mulWithSeperator(Honk.G1Point memory basePoint, Honk.G1Point memory other, Fr recursionSeperator) - view - returns (Honk.G1Point memory) -{ +function mulWithSeperator( + Honk.G1Point memory basePoint, + Honk.G1Point memory other, + Fr recursionSeperator +) view returns (Honk.G1Point memory) { Honk.G1Point memory result; result = ecMul(recursionSeperator, basePoint); @@ -1746,7 +2265,10 @@ function mulWithSeperator(Honk.G1Point memory basePoint, Honk.G1Point memory oth * @param point The point to multiply. * @return result The result of the multiplication. */ -function ecMul(Fr value, Honk.G1Point memory point) view returns (Honk.G1Point memory) { +function ecMul( + Fr value, + Honk.G1Point memory point +) view returns (Honk.G1Point memory) { Honk.G1Point memory result; assembly { @@ -1792,7 +2314,10 @@ function ecMul(Fr value, Honk.G1Point memory point) view returns (Honk.G1Point m * @param rhs The right hand side of the addition. * @return result The result of the addition. */ -function ecAdd(Honk.G1Point memory lhs, Honk.G1Point memory rhs) view returns (Honk.G1Point memory) { +function ecAdd( + Honk.G1Point memory lhs, + Honk.G1Point memory rhs +) view returns (Honk.G1Point memory) { Honk.G1Point memory result; assembly { @@ -1816,7 +2341,9 @@ function ecAdd(Honk.G1Point memory lhs, Honk.G1Point memory rhs) view returns (H // Call the ecAdd precompile, it takes in the following // [lhs.x, lhs.y, rhs.x, rhs.y], and returns their addition back into the free memory location. let success := staticcall(gas(), 0x06, free, 0x80, free, 0x40) - if iszero(success) { revert(0, 0) } + if iszero(success) { + revert(0, 0) + } // Copy the result of the addition back into the result memory location. // Memory layout: @@ -1845,22 +2372,41 @@ function validateOnCurve(Honk.G1Point memory point) pure { require(success, "point is not on the curve"); } -function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns (bool decodedResult) { +function pairing( + Honk.G1Point memory rhs, + Honk.G1Point memory lhs +) view returns (bool decodedResult) { bytes memory input = abi.encodePacked( rhs.x, rhs.y, // Fixed G2 point - uint256(0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2), - uint256(0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed), - uint256(0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b), - uint256(0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa), + uint256( + 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2 + ), + uint256( + 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed + ), + uint256( + 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b + ), + uint256( + 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa + ), lhs.x, lhs.y, // G2 point from VK - uint256(0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1), - uint256(0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0), - uint256(0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4), - uint256(0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) + uint256( + 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1 + ), + uint256( + 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0 + ), + uint256( + 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4 + ), + uint256( + 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55 + ) ); (bool success, bytes memory result) = address(0x08).staticcall(input); @@ -1869,9 +2415,6 @@ function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns // Field arithmetic libraries - prevent littering the code with modmul / addmul - - - abstract contract BaseZKHonkVerifier is IVerifier { using FrLib for Fr; @@ -1881,7 +2424,12 @@ abstract contract BaseZKHonkVerifier is IVerifier { uint256 immutable $NUM_PUBLIC_INPUTS; uint256 immutable $MSMSize; - constructor(uint256 _N, uint256 _logN, uint256 _vkHash, uint256 _numPublicInputs) { + constructor( + uint256 _N, + uint256 _logN, + uint256 _vkHash, + uint256 _numPublicInputs + ) { $N = _N; $LOG_N = _logN; $VK_HASH = _vkHash; @@ -1891,7 +2439,11 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Errors error ProofLengthWrong(); - error ProofLengthWrongWithLogN(uint256 logN, uint256 actualLength, uint256 expectedLength); + error ProofLengthWrongWithLogN( + uint256 logN, + uint256 actualLength, + uint256 expectedLength + ); error PublicInputsLengthWrong(); error SumcheckFailed(); error ShpleminiFailed(); @@ -1911,7 +2463,10 @@ abstract contract BaseZKHonkVerifier is IVerifier { proofLength += NUM_ELEMENTS_COMM * 3; // Libra concat, grand sum, quotient comms + Gemini masking // Sumcheck - proofLength += logN * ZK_BATCHED_RELATION_PARTIAL_LENGTH * NUM_ELEMENTS_FR; // sumcheck univariates + proofLength += + logN * + ZK_BATCHED_RELATION_PARTIAL_LENGTH * + NUM_ELEMENTS_FR; // sumcheck univariates proofLength += NUMBER_OF_ENTITIES_ZK * NUM_ELEMENTS_FR; // sumcheck evaluations // Libra and Gemini @@ -1931,20 +2486,26 @@ abstract contract BaseZKHonkVerifier is IVerifier { uint256 constant SHIFTED_COMMITMENTS_START = 30; - function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory); + function loadVerificationKey() + internal + pure + virtual + returns (Honk.VerificationKey memory); - function verify(bytes calldata proof, bytes32[] calldata publicInputs) - public - view - override - returns (bool verified) - { + function verify( + bytes calldata proof, + bytes32[] calldata publicInputs + ) public view override returns (bool verified) { // Calculate expected proof size based on $LOG_N uint256 expectedProofSize = calculateProofSize($LOG_N); // Check the received proof is the expected size where each field element is 32 bytes if (proof.length != expectedProofSize * 32) { - revert ProofLengthWrongWithLogN($LOG_N, proof.length, expectedProofSize * 32); + revert ProofLengthWrongWithLogN( + $LOG_N, + proof.length, + expectedProofSize * 32 + ); } Honk.VerificationKey memory vk = loadVerificationKey(); @@ -1955,15 +2516,20 @@ abstract contract BaseZKHonkVerifier is IVerifier { } // Generate the fiat shamir challenges for the whole protocol - ZKTranscript memory t = - ZKTranscriptLib.generateTranscript(p, publicInputs, $VK_HASH, $NUM_PUBLIC_INPUTS, $LOG_N); + ZKTranscript memory t = ZKTranscriptLib.generateTranscript( + p, + publicInputs, + $VK_HASH, + $NUM_PUBLIC_INPUTS, + $LOG_N + ); // Derive public input delta t.relationParameters.publicInputsDelta = computePublicInputDelta( publicInputs, p.pairingPointObject, t.relationParameters.beta, - t.relationParameters.gamma, /*pubInputsOffset=*/ + t.relationParameters.gamma /*pubInputsOffset=*/, 1 ); @@ -1987,11 +2553,16 @@ abstract contract BaseZKHonkVerifier is IVerifier { Fr numerator = Fr.wrap(1); Fr denominator = Fr.wrap(1); - Fr numeratorAcc = gamma + (beta * FrLib.from(PERMUTATION_ARGUMENT_VALUE_SEPARATOR + offset)); + Fr numeratorAcc = gamma + + (beta * FrLib.from(PERMUTATION_ARGUMENT_VALUE_SEPARATOR + offset)); Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); { - for (uint256 i = 0; i < $NUM_PUBLIC_INPUTS - PAIRING_POINTS_SIZE; i++) { + for ( + uint256 i = 0; + i < $NUM_PUBLIC_INPUTS - PAIRING_POINTS_SIZE; + i++ + ) { Fr pubInput = FrLib.fromBytes32(publicInputs[i]); numerator = numerator * (numeratorAcc + pubInput); @@ -2016,22 +2587,32 @@ abstract contract BaseZKHonkVerifier is IVerifier { publicInputDelta = FrLib.div(numerator, denominator); } - function verifySumcheck(Honk.ZKProof memory proof, ZKTranscript memory tp) internal view returns (bool verified) { + function verifySumcheck( + Honk.ZKProof memory proof, + ZKTranscript memory tp + ) internal view returns (bool verified) { Fr roundTargetSum = tp.libraChallenge * proof.libraSum; // default 0 Fr powPartialEvaluation = Fr.wrap(1); // We perform sumcheck reductions over log n rounds ( the multivariate degree ) for (uint256 round; round < $LOG_N; ++round) { - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate = proof.sumcheckUnivariates[round]; + Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] + memory roundUnivariate = proof.sumcheckUnivariates[round]; Fr totalSum = roundUnivariate[0] + roundUnivariate[1]; if (totalSum != roundTargetSum) revert SumcheckFailed(); Fr roundChallenge = tp.sumCheckUChallenges[round]; // Update the round target for the next rounf - roundTargetSum = computeNextTargetSum(roundUnivariate, roundChallenge); + roundTargetSum = computeNextTargetSum( + roundUnivariate, + roundChallenge + ); powPartialEvaluation = - powPartialEvaluation * (Fr.wrap(1) + roundChallenge * (tp.gateChallenges[round] - Fr.wrap(1))); + powPartialEvaluation * + (Fr.wrap(1) + + roundChallenge * + (tp.gateChallenges[round] - Fr.wrap(1))); } // Last round @@ -2039,10 +2620,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Index 0 is gemini_masking_poly, indices 1-41 are the regular entities used in relations Fr[NUMBER_OF_ENTITIES] memory relationsEvaluations; for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { - relationsEvaluations[i] = proof.sumcheckEvaluations[i + NUM_MASKING_POLYNOMIALS]; // Skip gemini_masking_poly at index 0 + relationsEvaluations[i] = proof.sumcheckEvaluations[ + i + NUM_MASKING_POLYNOMIALS + ]; // Skip gemini_masking_poly at index 0 } Fr grandHonkRelationSum = RelationsLib.accumulateRelationEvaluations( - relationsEvaluations, tp.relationParameters, tp.alphas, powPartialEvaluation + relationsEvaluations, + tp.relationParameters, + tp.alphas, + powPartialEvaluation ); Fr evaluation = Fr.wrap(1); @@ -2051,27 +2637,48 @@ abstract contract BaseZKHonkVerifier is IVerifier { } grandHonkRelationSum = - grandHonkRelationSum * (Fr.wrap(1) - evaluation) + proof.libraEvaluation * tp.libraChallenge; + grandHonkRelationSum * + (Fr.wrap(1) - evaluation) + + proof.libraEvaluation * + tp.libraChallenge; verified = (grandHonkRelationSum == roundTargetSum); } // Return the new target sum for the next sumcheck round - function computeNextTargetSum(Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, Fr roundChallenge) - internal - view - returns (Fr targetSum) - { - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [ - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51), - Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31), - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000000240), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31), - Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51), - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80) - ]; + function computeNextTargetSum( + Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, + Fr roundChallenge + ) internal view returns (Fr targetSum) { + Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] + memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [ + Fr.wrap( + 0x0000000000000000000000000000000000000000000000000000000000009d80 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51 + ), + Fr.wrap( + 0x00000000000000000000000000000000000000000000000000000000000005a0 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31 + ), + Fr.wrap( + 0x0000000000000000000000000000000000000000000000000000000000000240 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31 + ), + Fr.wrap( + 0x00000000000000000000000000000000000000000000000000000000000005a0 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51 + ), + Fr.wrap( + 0x0000000000000000000000000000000000000000000000000000000000009d80 + ) + ]; // To compute the next target sum, we evaluate the given univariate at a point u (challenge). @@ -2084,11 +2691,17 @@ abstract contract BaseZKHonkVerifier is IVerifier { Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory denominatorInverses; for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) { - denominatorInverses[i] = FrLib.invert(BARYCENTRIC_LAGRANGE_DENOMINATORS[i] * (roundChallenge - Fr.wrap(i))); + denominatorInverses[i] = FrLib.invert( + BARYCENTRIC_LAGRANGE_DENOMINATORS[i] * + (roundChallenge - Fr.wrap(i)) + ); } for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) { - targetSum = targetSum + roundUnivariates[i] * denominatorInverses[i]; + targetSum = + targetSum + + roundUnivariates[i] * + denominatorInverses[i]; } // Scale the sum by the value of B(x) @@ -2104,56 +2717,63 @@ abstract contract BaseZKHonkVerifier is IVerifier { Honk.G1Point P_1; } - function verifyShplemini(Honk.ZKProof memory proof, Honk.VerificationKey memory vk, ZKTranscript memory tp) - internal - view - returns (bool verified) - { + function verifyShplemini( + Honk.ZKProof memory proof, + Honk.VerificationKey memory vk, + ZKTranscript memory tp + ) internal view returns (bool verified) { CommitmentSchemeLib.ShpleminiIntermediates memory mem; // stack // - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size - Fr[] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR, $LOG_N); + Fr[] memory powers_of_evaluation_challenge = CommitmentSchemeLib + .computeSquares(tp.geminiR, $LOG_N); // Arrays hold values that will be linearly combined for the gemini and shplonk batch openings Fr[] memory scalars = new Fr[]($MSMSize); Honk.G1Point[] memory commitments = new Honk.G1Point[]($MSMSize); - mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); - mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); + mem.posInvertedDenominator = (tp.shplonkZ - + powers_of_evaluation_challenge[0]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + + powers_of_evaluation_challenge[0]).invert(); - mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator); + mem.unshiftedScalar = + mem.posInvertedDenominator + + (tp.shplonkNu * mem.negInvertedDenominator); mem.shiftedScalar = - tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator)); + tp.geminiR.invert() * + (mem.posInvertedDenominator - + (tp.shplonkNu * mem.negInvertedDenominator)); scalars[0] = Fr.wrap(1); commitments[0] = proof.shplonkQ; /* Batch multivariate opening claims, shifted and unshifted - * The vector of scalars is populated as follows: - * \f[ - * \left( - * - \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), - * \ldots, - * - \rho^{i+k-1} \times \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), - * - \rho^{i+k} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right), - * \ldots, - * - \rho^{k+m-1} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right) - * \right) - * \f] - * - * The following vector is concatenated to the vector of commitments: - * \f[ - * f_0, \ldots, f_{m-1}, f_{\text{shift}, 0}, \ldots, f_{\text{shift}, k-1} - * \f] - * - * Simultaneously, the evaluation of the multilinear polynomial - * \f[ - * \sum \rho^i \cdot f_i + \sum \rho^{i+k} \cdot f_{\text{shift}, i} - * \f] - * at the challenge point \f$ (u_0,\ldots, u_{n-1}) \f$ is computed. - * - * This approach minimizes the number of iterations over the commitments to multilinear polynomials - * and eliminates the need to store the powers of \f$ \rho \f$. - */ + * The vector of scalars is populated as follows: + * \f[ + * \left( + * - \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), + * \ldots, + * - \rho^{i+k-1} \times \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), + * - \rho^{i+k} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right), + * \ldots, + * - \rho^{k+m-1} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right) + * \right) + * \f] + * + * The following vector is concatenated to the vector of commitments: + * \f[ + * f_0, \ldots, f_{m-1}, f_{\text{shift}, 0}, \ldots, f_{\text{shift}, k-1} + * \f] + * + * Simultaneously, the evaluation of the multilinear polynomial + * \f[ + * \sum \rho^i \cdot f_i + \sum \rho^{i+k} \cdot f_{\text{shift}, i} + * \f] + * at the challenge point \f$ (u_0,\ldots, u_{n-1}) \f$ is computed. + * + * This approach minimizes the number of iterations over the commitments to multilinear polynomials + * and eliminates the need to store the powers of \f$ \rho \f$. + */ // For ZK flavors: evaluations array is [gemini_masking_poly, qm, qc, ql, qr, ...] // Start batching challenge at 1, not rho, to match non-ZK pattern mem.batchingChallenge = Fr.wrap(1); @@ -2165,8 +2785,10 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Process all NUMBER_UNSHIFTED_ZK evaluations (includes gemini_masking_poly at index 0) for (uint256 i = 1; i <= NUMBER_UNSHIFTED_ZK; ++i) { scalars[i] = mem.unshiftedScalarNeg * mem.batchingChallenge; - mem.batchedEvaluation = mem.batchedEvaluation - + (proof.sumcheckEvaluations[i - NUM_MASKING_POLYNOMIALS] * mem.batchingChallenge); + mem.batchedEvaluation = + mem.batchedEvaluation + + (proof.sumcheckEvaluations[i - NUM_MASKING_POLYNOMIALS] * + mem.batchingChallenge); mem.batchingChallenge = mem.batchingChallenge * tp.rho; } // g commitments are accumulated at r @@ -2179,9 +2801,13 @@ abstract contract BaseZKHonkVerifier is IVerifier { uint256 scalarOff = i + SHIFTED_COMMITMENTS_START; uint256 evaluationOff = i + NUMBER_UNSHIFTED_ZK; - scalars[scalarOff] = scalars[scalarOff] + (mem.shiftedScalarNeg * mem.batchingChallenge); + scalars[scalarOff] = + scalars[scalarOff] + + (mem.shiftedScalarNeg * mem.batchingChallenge); mem.batchedEvaluation = - mem.batchedEvaluation + (proof.sumcheckEvaluations[evaluationOff] * mem.batchingChallenge); + mem.batchedEvaluation + + (proof.sumcheckEvaluations[evaluationOff] * + mem.batchingChallenge); mem.batchingChallenge = mem.batchingChallenge * tp.rho; } @@ -2234,15 +2860,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { * \f[ * \left( \text{com}(A_1), \text{com}(A_2), \ldots, \text{com}(A_{n-1}) \right) * \f] - * to the 'commitments' vector. - * - * 2. Computes the scalars: - * \f[ - * \frac{\nu^{2}}{z + r^2}, \frac{\nu^3}{z + r^4}, \ldots, \frac{\nu^{n-1}}{z + r^{2^{n-1}}} - * \f] - * and places them into the 'scalars' vector. - * - * 3. Accumulates the summands of the constant term: + * to the 'commitments' vector. + * + * 2. Computes the scalars: + * \f[ + * \frac{\nu^{2}}{z + r^2}, \frac{\nu^3}{z + r^4}, \ldots, \frac{\nu^{n-1}}{z + r^{2^{n-1}}} + * \f] + * and places them into the 'scalars' vector. + * + * 3. Accumulates the summands of the constant term: * \f[ * \sum_{i=2}^{n-1} \frac{\nu^{i} \cdot A_i(-r^{2^i})}{z + r^{2^i}} * \f] @@ -2251,17 +2877,23 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., $LOG_N - 1 - Fr[] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations( - tp.sumCheckUChallenges, - mem.batchedEvaluation, - proof.geminiAEvaluations, - powers_of_evaluation_challenge, - $LOG_N - ); + Fr[] memory foldPosEvaluations = CommitmentSchemeLib + .computeFoldPosEvaluations( + tp.sumCheckUChallenges, + mem.batchedEvaluation, + proof.geminiAEvaluations, + powers_of_evaluation_challenge, + $LOG_N + ); - mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; mem.constantTermAccumulator = - mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); + foldPosEvaluations[0] * + mem.posInvertedDenominator; + mem.constantTermAccumulator = + mem.constantTermAccumulator + + (proof.geminiAEvaluations[0] * + tp.shplonkNu * + mem.negInvertedDenominator); mem.batchingChallenge = tp.shplonkNu.sqr(); uint256 boundary = NUMBER_UNSHIFTED_ZK + 1; @@ -2273,22 +2905,40 @@ abstract contract BaseZKHonkVerifier is IVerifier { if (!dummy_round) { // Update inverted denominators - mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); - mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + mem.posInvertedDenominator = (tp.shplonkZ - + powers_of_evaluation_challenge[i + 1]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + + powers_of_evaluation_challenge[i + 1]).invert(); // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ] - mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; - mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; - scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + mem.scalingFactorPos = + mem.batchingChallenge * + mem.posInvertedDenominator; + mem.scalingFactorNeg = + mem.batchingChallenge * + tp.shplonkNu * + mem.negInvertedDenominator; + scalars[boundary + i] = + mem.scalingFactorNeg.neg() + + mem.scalingFactorPos.neg(); // Accumulate the const term contribution given by // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l}) - Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; - accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; - mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; + Fr accumContribution = mem.scalingFactorNeg * + proof.geminiAEvaluations[i + 1]; + accumContribution = + accumContribution + + mem.scalingFactorPos * + foldPosEvaluations[i + 1]; + mem.constantTermAccumulator = + mem.constantTermAccumulator + + accumContribution; } // Update the running power of v - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + mem.batchingChallenge = + mem.batchingChallenge * + tp.shplonkNu * + tp.shplonkNu; commitments[boundary + i] = proof.geminiFoldComms[i]; } @@ -2297,16 +2947,24 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Finalize the batch opening claim mem.denominators[0] = Fr.wrap(1).div(tp.shplonkZ - tp.geminiR); - mem.denominators[1] = Fr.wrap(1).div(tp.shplonkZ - SUBGROUP_GENERATOR * tp.geminiR); + mem.denominators[1] = Fr.wrap(1).div( + tp.shplonkZ - SUBGROUP_GENERATOR * tp.geminiR + ); mem.denominators[2] = mem.denominators[0]; mem.denominators[3] = mem.denominators[0]; - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + mem.batchingChallenge = + mem.batchingChallenge * + tp.shplonkNu * + tp.shplonkNu; for (uint256 i = 0; i < LIBRA_EVALUATIONS; i++) { Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge; mem.batchingScalars[i] = scalingFactor.neg(); mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; - mem.constantTermAccumulator = mem.constantTermAccumulator + scalingFactor * proof.libraPolyEvals[i]; + mem.constantTermAccumulator = + mem.constantTermAccumulator + + scalingFactor * + proof.libraPolyEvals[i]; } scalars[boundary] = mem.batchingScalars[0]; scalars[boundary + 1] = mem.batchingScalars[1] + mem.batchingScalars[2]; @@ -2316,10 +2974,17 @@ abstract contract BaseZKHonkVerifier is IVerifier { commitments[boundary++] = proof.libraCommitments[i]; } - commitments[boundary] = Honk.G1Point({x: 1, y: 2}); + commitments[boundary] = Honk.G1Point({ x: 1, y: 2 }); scalars[boundary++] = mem.constantTermAccumulator; - if (!checkEvalsConsistency(proof.libraPolyEvals, tp.geminiR, tp.sumCheckUChallenges, proof.libraEvaluation)) { + if ( + !checkEvalsConsistency( + proof.libraPolyEvals, + tp.geminiR, + tp.sumCheckUChallenges, + proof.libraEvaluation + ) + ) { revert ConsistencyCheckFailed(); } @@ -2333,9 +2998,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { pair.P_1 = negateInplace(quotient_commitment); // Aggregate pairing points - Fr recursionSeparator = generateRecursionSeparator(proof.pairingPointObject, pair.P_0, pair.P_1); - (Honk.G1Point memory P_0_other, Honk.G1Point memory P_1_other) = - convertPairingPointsToG1(proof.pairingPointObject); + Fr recursionSeparator = generateRecursionSeparator( + proof.pairingPointObject, + pair.P_0, + pair.P_1 + ); + ( + Honk.G1Point memory P_0_other, + Honk.G1Point memory P_1_other + ) = convertPairingPointsToG1(proof.pairingPointObject); // Validate the points from the proof are on the curve validateOnCurve(P_0_other); @@ -2375,8 +3046,14 @@ abstract contract BaseZKHonkVerifier is IVerifier { for (uint256 round = 0; round < $LOG_N; round++) { uint256 currIdx = 1 + LIBRA_UNIVARIATES_LENGTH * round; mem.challengePolyLagrange[currIdx] = one; - for (uint256 idx = currIdx + 1; idx < currIdx + LIBRA_UNIVARIATES_LENGTH; idx++) { - mem.challengePolyLagrange[idx] = mem.challengePolyLagrange[idx - 1] * uChallenges[round]; + for ( + uint256 idx = currIdx + 1; + idx < currIdx + LIBRA_UNIVARIATES_LENGTH; + idx++ + ) { + mem.challengePolyLagrange[idx] = + mem.challengePolyLagrange[idx - 1] * + uChallenges[round]; } } @@ -2385,7 +3062,10 @@ abstract contract BaseZKHonkVerifier is IVerifier { for (uint256 idx = 0; idx < SUBGROUP_SIZE; idx++) { mem.denominators[idx] = mem.rootPower * geminiR - one; mem.denominators[idx] = mem.denominators[idx].invert(); - mem.challengePolyEval = mem.challengePolyEval + mem.challengePolyLagrange[idx] * mem.denominators[idx]; + mem.challengePolyEval = + mem.challengePolyEval + + mem.challengePolyLagrange[idx] * + mem.denominators[idx]; mem.rootPower = mem.rootPower * SUBGROUP_GENERATOR_INVERSE; } @@ -2396,19 +3076,28 @@ abstract contract BaseZKHonkVerifier is IVerifier { mem.diff = mem.lagrangeFirst * libraPolyEvals[2]; - mem.diff = mem.diff + (geminiR - SUBGROUP_GENERATOR_INVERSE) - * (libraPolyEvals[1] - libraPolyEvals[2] - libraPolyEvals[0] * mem.challengePolyEval); - mem.diff = mem.diff + mem.lagrangeLast * (libraPolyEvals[2] - libraEval) - vanishingPolyEval * libraPolyEvals[3]; + mem.diff = + mem.diff + + (geminiR - SUBGROUP_GENERATOR_INVERSE) * + (libraPolyEvals[1] - + libraPolyEvals[2] - + libraPolyEvals[0] * + mem.challengePolyEval); + mem.diff = + mem.diff + + mem.lagrangeLast * + (libraPolyEvals[2] - libraEval) - + vanishingPolyEval * + libraPolyEvals[3]; check = mem.diff == Fr.wrap(0); } // This implementation is the same as above with different constants - function batchMul(Honk.G1Point[] memory base, Fr[] memory scalars) - internal - view - returns (Honk.G1Point memory result) - { + function batchMul( + Honk.G1Point[] memory base, + Fr[] memory scalars + ) internal view returns (Honk.G1Point memory result) { uint256 limit = $MSMSize; // Validate all points are on the curve @@ -2421,7 +3110,9 @@ abstract contract BaseZKHonkVerifier is IVerifier { let free := mload(0x40) let count := 0x01 - for {} lt(count, add(limit, 1)) { count := add(count, 1) } { + for {} lt(count, add(limit, 1)) { + count := add(count, 1) + } { // Get loop offsets let base_base := add(base, mul(count, 0x20)) let scalar_base := add(scalars, mul(count, 0x20)) @@ -2431,9 +3122,22 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Add scalar mstore(add(free, 0x80), mload(scalar_base)) - success := and(success, staticcall(gas(), 7, add(free, 0x40), 0x60, add(free, 0x40), 0x40)) + success := and( + success, + staticcall( + gas(), + 7, + add(free, 0x40), + 0x60, + add(free, 0x40), + 0x40 + ) + ) // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, free, 0x80, free, 0x40)) + success := and( + success, + staticcall(gas(), 6, free, 0x80, free, 0x40) + ) } // Return the result @@ -2445,8 +3149,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { } } -contract RecursiveAggregationFoldVerifier is BaseZKHonkVerifier(N, LOG_N, VK_HASH, NUMBER_OF_PUBLIC_INPUTS) { - function loadVerificationKey() internal pure override returns (Honk.VerificationKey memory) { - return HonkVerificationKey.loadVerificationKey(); +contract RecursiveAggregationFoldVerifier is + BaseZKHonkVerifier(N, LOG_N, VK_HASH, NUMBER_OF_PUBLIC_INPUTS) +{ + function loadVerificationKey() + internal + pure + override + returns (Honk.VerificationKey memory) + { + return HonkVerificationKey.loadVerificationKey(); } } diff --git a/packages/enclave-contracts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol b/packages/enclave-contracts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol deleted file mode 100644 index d7bd687db4..0000000000 --- a/packages/enclave-contracts/contracts/verifier/ThresholdDecryptedSharesAggregationBnVerifier.sol +++ /dev/null @@ -1,2452 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. -pragma solidity >=0.8.21; - -uint256 constant N = 131072; -uint256 constant LOG_N = 17; -uint256 constant NUMBER_OF_PUBLIC_INPUTS = 579; -uint256 constant VK_HASH = 0x1eb29cc0a26390fad32af3a6275716d347fdcbdcc5f7c7c54c194a0cce5854e0; -library HonkVerificationKey { - function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { - Honk.VerificationKey memory vk = Honk.VerificationKey({ - circuitSize: uint256(131072), - logCircuitSize: uint256(17), - publicInputsSize: uint256(579), - ql: Honk.G1Point({ - x: uint256(0x067b40a80be55b95cc17070cf5dc78441e4868acea0ac1e46b57087051515905), - y: uint256(0x0792e6c3d76aeeed6ee7d7e443138c813b74dbcd8ce92990e6f6747adc0af054) - }), - qr: Honk.G1Point({ - x: uint256(0x148a04387a9e0a8cec6a4a0d90706f5907e8bb257fb04f8a3cfe07c18a7c1014), - y: uint256(0x225866d9efd4a5be4eb9a00016f902f844e3d81e2768b24dc92ecbd6b34176bd) - }), - qo: Honk.G1Point({ - x: uint256(0x0dacf57ed82c686ca051fca3f1820016cb49e91b5d3c4bee7f9fa19800d9ed06), - y: uint256(0x22ba5fda41aa14aeb7a3a2731fbfe3a673cf7db1d2217d32db491f4434430905) - }), - q4: Honk.G1Point({ - x: uint256(0x0f783f69a36c2bac47b9c59ff33ccc583a284a46b282591b9e9bbb85d8b5e5dc), - y: uint256(0x029b91609a06e94924f0d83530fc01f3427f5ab729a0959903108c2ccc86825c) - }), - qm: Honk.G1Point({ - x: uint256(0x039702f4c2b2b49fd29d82b077cbf9d1df2871e0fbade17241573ca5021603fc), - y: uint256(0x03270b3b2673844695842df11cdbabf54acafe03642adfdfbf69834247ed0720) - }), - qc: Honk.G1Point({ - x: uint256(0x1ccb0308d0359b8835480fa7dd829fdbf16b136d57e85c1621efb1679fe1a94c), - y: uint256(0x207076fed3c60bbeb2df5f48c86b12f4027c523f9b8e69456ca51643fea3de1d) - }), - qLookup: Honk.G1Point({ - x: uint256(0x11beb2731ab8cf46c0a52666bb457fa74d4b635043bb5689a35a2aee24990b80), - y: uint256(0x2f1fba989036c44aedb609d0d3341ccb842c2d1cd7c80cea4a95d0eb45305770) - }), - qArith: Honk.G1Point({ - x: uint256(0x28ae1f7459c3c5d9ca2f80f8e5c28bb301d0245228bade0e2bb962b4bfbe301b), - y: uint256(0x0622f7db14381bbecf862e186cfa570588160466ae7d4fed4b35a70d99af914f) - }), - qDeltaRange: Honk.G1Point({ - x: uint256(0x233983f621ab48bdce4f7216bdbc54c49463e90d88301b9ab224fca61c93dba0), - y: uint256(0x265c3834d63be0bc710c9b4a48015e2442a3b9bf63caec9db0064dfb1bd569c4) - }), - qElliptic: Honk.G1Point({ - x: uint256(0x2dfc248e28ad889b5b692077f338d28b2f687c6e909b9693f8e8fd25cefc3528), - y: uint256(0x16e2cbc305166ea90a426987efff2020827d8c548ea4155c659df296f14f00fd) - }), - qMemory: Honk.G1Point({ - x: uint256(0x06d21b82f49e04e078d4ad30cd6828eaa66c1bf984bc52b79de8c786fe4dfe7a), - y: uint256(0x301aa91e167bbc765996ac6d2889e7d49f0734bc7abb3a4b85900143556a1b3f) - }), - qNnf: Honk.G1Point({ - x: uint256(0x1222d34f53e6b36138627277789ad131ea24f79caca2d5f59193c5e3a7dfdde7), - y: uint256(0x245a380726977d41c9f0a9a0ba33608994eb3660de6a8efba38009df93da679a) - }), - qPoseidon2External: Honk.G1Point({ - x: uint256(0x0d815a04effc6e57ec95f3ac112f76ab4a9d993d044626ceb54f967c8d77d8e1), - y: uint256(0x1df4c065a1129d5cbdf244cb9cc2eaf406c2f5fbab4c393347d57ae5e2ab881f) - }), - qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x118733dc1db84685f4160119cb0cd9a51b831cf0643e914daf1c63fc79672979), - y: uint256(0x27b63107b52edf239acb1bd47e24c97094422cc2bba51ee0f54b2707946be556) - }), - s1: Honk.G1Point({ - x: uint256(0x2e7a11cec89df0ad6b730cf80be4246e56e1667f55e35a22c9b39b196226135b), - y: uint256(0x0891267297e339bedeef69881477b4e5c19e761e127e3d3772714f92ade80fd3) - }), - s2: Honk.G1Point({ - x: uint256(0x16f90d7d5c3fd7ab9f490dd5d2b94afea698039e2456c1d5f0e22159348d1e0c), - y: uint256(0x29ad721b49b02192f5323326fd803b102f7a09b0371c537db998014fa14c3079) - }), - s3: Honk.G1Point({ - x: uint256(0x0a5e4e29375b31024f09dd662b460eb25930835255c62dc74d62d0c983981e42), - y: uint256(0x069adf56537452ecad2fcd8cdea1291fbf273d7e752d9ba0812900e7215c8fc0) - }), - s4: Honk.G1Point({ - x: uint256(0x1bd554f207de2e42cbc94e8579154a07e37f3ba9d80832f28e38dffaaccd1ade), - y: uint256(0x22261d045539dbaabf26f23773b365b2ddd30af639a8b15a56e777f5607bf435) - }), - t1: Honk.G1Point({ - x: uint256(0x099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d26), - y: uint256(0x0015b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f) - }), - t2: Honk.G1Point({ - x: uint256(0x1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e), - y: uint256(0x305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d19) - }), - t3: Honk.G1Point({ - x: uint256(0x061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d), - y: uint256(0x1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e) - }), - t4: Honk.G1Point({ - x: uint256(0x043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce), - y: uint256(0x261522c4089330646aff96736194949330952ae74c573d1686d9cb4a00733854) - }), - id1: Honk.G1Point({ - x: uint256(0x11769064ef79db1f35b23b8b1e5c118e769e1a41b912f49dfdbffbacf23d0564), - y: uint256(0x16f17c1721186bbd19d09f1645f968677cb1ad0c6b656c3849a4b7f27d5279d9) - }), - id2: Honk.G1Point({ - x: uint256(0x0cad91097e151471556985b94a0188b759472f9bb3295fe6de6846f2d4fe27e1), - y: uint256(0x042f4a199546b40704a9c4822bfd20a91bc478055dc5676c7347f64545b47f4d) - }), - id3: Honk.G1Point({ - x: uint256(0x1286a8beb1993863980820c27dfb00f93f8949f60933042e5aa8275dd48e55f7), - y: uint256(0x2037878d67d1009eb6dac43c5f6f076f884d456e057b000912d40a2ec440df1f) - }), - id4: Honk.G1Point({ - x: uint256(0x1c0413fa3552ba4738b423829d55fcc03c912bf931336778a458e1c25cd4f558), - y: uint256(0x190904e6db04c862bd9d7406029e03a1103a513203eb6d8faa010021eedf18d4) - }), - lagrangeFirst: Honk.G1Point({ - x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), - y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) - }), - lagrangeLast: Honk.G1Point({ - x: uint256(0x0ad44c49c91e4374983e023f10e6256c39d27b2857eb2d2ce82a82b51e02dc38), - y: uint256(0x23ad26f46d7b04b00d6ebe50273765d49c59d9db9ae22dd33909bc3c9efc5308) - }) - }); - return vk; - } -} - -pragma solidity ^0.8.27; - -interface IVerifier { - function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external returns (bool); -} - -type Fr is uint256; - -using {add as +} for Fr global; -using {sub as -} for Fr global; -using {mul as *} for Fr global; - -using {exp as ^} for Fr global; -using {notEqual as !=} for Fr global; -using {equal as ==} for Fr global; - -uint256 constant SUBGROUP_SIZE = 256; -uint256 constant MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order -uint256 constant P = MODULUS; -Fr constant SUBGROUP_GENERATOR = Fr.wrap(0x07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76); -Fr constant SUBGROUP_GENERATOR_INVERSE = Fr.wrap(0x204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6); -Fr constant MINUS_ONE = Fr.wrap(MODULUS - 1); -Fr constant ONE = Fr.wrap(1); -Fr constant ZERO = Fr.wrap(0); -// Instantiation - -library FrLib { - function from(uint256 value) internal pure returns (Fr) { - unchecked { - return Fr.wrap(value % MODULUS); - } - } - - function fromBytes32(bytes32 value) internal pure returns (Fr) { - unchecked { - return Fr.wrap(uint256(value) % MODULUS); - } - } - - function toBytes32(Fr value) internal pure returns (bytes32) { - unchecked { - return bytes32(Fr.unwrap(value)); - } - } - - function invert(Fr value) internal view returns (Fr) { - uint256 v = Fr.unwrap(value); - uint256 result; - - // Call the modexp precompile to invert in the field - assembly { - let free := mload(0x40) - mstore(free, 0x20) - mstore(add(free, 0x20), 0x20) - mstore(add(free, 0x40), 0x20) - mstore(add(free, 0x60), v) - mstore(add(free, 0x80), sub(MODULUS, 2)) - mstore(add(free, 0xa0), MODULUS) - let success := staticcall(gas(), 0x05, free, 0xc0, 0x00, 0x20) - if iszero(success) { - revert(0, 0) - } - result := mload(0x00) - mstore(0x40, add(free, 0x80)) - } - - return Fr.wrap(result); - } - - function pow(Fr base, uint256 v) internal view returns (Fr) { - uint256 b = Fr.unwrap(base); - uint256 result; - - // Call the modexp precompile to invert in the field - assembly { - let free := mload(0x40) - mstore(free, 0x20) - mstore(add(free, 0x20), 0x20) - mstore(add(free, 0x40), 0x20) - mstore(add(free, 0x60), b) - mstore(add(free, 0x80), v) - mstore(add(free, 0xa0), MODULUS) - let success := staticcall(gas(), 0x05, free, 0xc0, 0x00, 0x20) - if iszero(success) { - revert(0, 0) - } - result := mload(0x00) - mstore(0x40, add(free, 0x80)) - } - - return Fr.wrap(result); - } - - function div(Fr numerator, Fr denominator) internal view returns (Fr) { - unchecked { - return numerator * invert(denominator); - } - } - - function sqr(Fr value) internal pure returns (Fr) { - unchecked { - return value * value; - } - } - - function unwrap(Fr value) internal pure returns (uint256) { - unchecked { - return Fr.unwrap(value); - } - } - - function neg(Fr value) internal pure returns (Fr) { - unchecked { - return Fr.wrap(MODULUS - Fr.unwrap(value)); - } - } -} - -// Free functions -function add(Fr a, Fr b) pure returns (Fr) { - unchecked { - return Fr.wrap(addmod(Fr.unwrap(a), Fr.unwrap(b), MODULUS)); - } -} - -function mul(Fr a, Fr b) pure returns (Fr) { - unchecked { - return Fr.wrap(mulmod(Fr.unwrap(a), Fr.unwrap(b), MODULUS)); - } -} - -function sub(Fr a, Fr b) pure returns (Fr) { - unchecked { - return Fr.wrap(addmod(Fr.unwrap(a), MODULUS - Fr.unwrap(b), MODULUS)); - } -} - -function exp(Fr base, Fr exponent) pure returns (Fr) { - if (Fr.unwrap(exponent) == 0) return Fr.wrap(1); - // Implement exponent with a loop as we will overflow otherwise - for (uint256 i = 1; i < Fr.unwrap(exponent); i += i) { - base = base * base; - } - return base; -} - -function notEqual(Fr a, Fr b) pure returns (bool) { - unchecked { - return Fr.unwrap(a) != Fr.unwrap(b); - } -} - -function equal(Fr a, Fr b) pure returns (bool) { - unchecked { - return Fr.unwrap(a) == Fr.unwrap(b); - } -} - -uint256 constant CONST_PROOF_SIZE_LOG_N = 28; - -uint256 constant NUMBER_OF_SUBRELATIONS = 28; -uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8; -uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9; -uint256 constant NUMBER_OF_ENTITIES = 41; -// The number of entities added for ZK (gemini_masking_poly) -uint256 constant NUM_MASKING_POLYNOMIALS = 1; -uint256 constant NUMBER_OF_ENTITIES_ZK = NUMBER_OF_ENTITIES + NUM_MASKING_POLYNOMIALS; -uint256 constant NUMBER_UNSHIFTED = 36; -uint256 constant NUMBER_UNSHIFTED_ZK = NUMBER_UNSHIFTED + NUM_MASKING_POLYNOMIALS; -uint256 constant NUMBER_TO_BE_SHIFTED = 5; -uint256 constant PAIRING_POINTS_SIZE = 16; - -uint256 constant FIELD_ELEMENT_SIZE = 0x20; -uint256 constant GROUP_ELEMENT_SIZE = 0x40; - -// Powers of alpha used to batch subrelations (alpha, alpha^2, ..., alpha^(NUM_SUBRELATIONS-1)) -uint256 constant NUMBER_OF_ALPHAS = NUMBER_OF_SUBRELATIONS - 1; - -// ENUM FOR WIRES -enum WIRE { - Q_M, - Q_C, - Q_L, - Q_R, - Q_O, - Q_4, - Q_LOOKUP, - Q_ARITH, - Q_RANGE, - Q_ELLIPTIC, - Q_MEMORY, - Q_NNF, - Q_POSEIDON2_EXTERNAL, - Q_POSEIDON2_INTERNAL, - SIGMA_1, - SIGMA_2, - SIGMA_3, - SIGMA_4, - ID_1, - ID_2, - ID_3, - ID_4, - TABLE_1, - TABLE_2, - TABLE_3, - TABLE_4, - LAGRANGE_FIRST, - LAGRANGE_LAST, - W_L, - W_R, - W_O, - W_4, - Z_PERM, - LOOKUP_INVERSES, - LOOKUP_READ_COUNTS, - LOOKUP_READ_TAGS, - W_L_SHIFT, - W_R_SHIFT, - W_O_SHIFT, - W_4_SHIFT, - Z_PERM_SHIFT -} - -library Honk { - struct G1Point { - uint256 x; - uint256 y; - } - - struct VerificationKey { - // Misc Params - uint256 circuitSize; - uint256 logCircuitSize; - uint256 publicInputsSize; - // Selectors - G1Point qm; - G1Point qc; - G1Point ql; - G1Point qr; - G1Point qo; - G1Point q4; - G1Point qLookup; // Lookup - G1Point qArith; // Arithmetic widget - G1Point qDeltaRange; // Delta Range sort - G1Point qMemory; // Memory - G1Point qNnf; // Non-native Field - G1Point qElliptic; // Auxillary - G1Point qPoseidon2External; - G1Point qPoseidon2Internal; - // Copy constraints - G1Point s1; - G1Point s2; - G1Point s3; - G1Point s4; - // Copy identity - G1Point id1; - G1Point id2; - G1Point id3; - G1Point id4; - // Precomputed lookup table - G1Point t1; - G1Point t2; - G1Point t3; - G1Point t4; - // Fixed first and last - G1Point lagrangeFirst; - G1Point lagrangeLast; - } - - struct RelationParameters { - // challenges - Fr eta; - Fr etaTwo; - Fr etaThree; - Fr beta; - Fr gamma; - // derived - Fr publicInputsDelta; - } - - struct Proof { - // Pairing point object - Fr[PAIRING_POINTS_SIZE] pairingPointObject; - // Free wires - G1Point w1; - G1Point w2; - G1Point w3; - G1Point w4; - // Lookup helpers - Permutations - G1Point zPerm; - // Lookup helpers - logup - G1Point lookupReadCounts; - G1Point lookupReadTags; - G1Point lookupInverses; - // Sumcheck - Fr[BATCHED_RELATION_PARTIAL_LENGTH][CONST_PROOF_SIZE_LOG_N] sumcheckUnivariates; - Fr[NUMBER_OF_ENTITIES] sumcheckEvaluations; - // Shplemini - G1Point[CONST_PROOF_SIZE_LOG_N - 1] geminiFoldComms; - Fr[CONST_PROOF_SIZE_LOG_N] geminiAEvaluations; - G1Point shplonkQ; - G1Point kzgQuotient; - } - - /// forge-lint: disable-next-item(pascal-case-struct) - struct ZKProof { - // Pairing point object - Fr[PAIRING_POINTS_SIZE] pairingPointObject; - // ZK: Gemini masking polynomial commitment (sent first, right after public inputs) - G1Point geminiMaskingPoly; - // Commitments to wire polynomials - G1Point w1; - G1Point w2; - G1Point w3; - G1Point w4; - // Commitments to logup witness polynomials - G1Point lookupReadCounts; - G1Point lookupReadTags; - G1Point lookupInverses; - // Commitment to grand permutation polynomial - G1Point zPerm; - G1Point[3] libraCommitments; - // Sumcheck - Fr libraSum; - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH][CONST_PROOF_SIZE_LOG_N] sumcheckUnivariates; - Fr libraEvaluation; - Fr[NUMBER_OF_ENTITIES_ZK] sumcheckEvaluations; // Includes gemini_masking_poly eval at index 0 (first position) - // Shplemini - G1Point[CONST_PROOF_SIZE_LOG_N - 1] geminiFoldComms; - Fr[CONST_PROOF_SIZE_LOG_N] geminiAEvaluations; - Fr[4] libraPolyEvals; - G1Point shplonkQ; - G1Point kzgQuotient; - } -} - -// ZKTranscript library to generate fiat shamir challenges, the ZK transcript only differest -/// forge-lint: disable-next-item(pascal-case-struct) -struct ZKTranscript { - // Oink - Honk.RelationParameters relationParameters; - Fr[NUMBER_OF_ALPHAS] alphas; // Powers of alpha: [alpha, alpha^2, ..., alpha^(NUM_SUBRELATIONS-1)] - Fr[CONST_PROOF_SIZE_LOG_N] gateChallenges; - // Sumcheck - Fr libraChallenge; - Fr[CONST_PROOF_SIZE_LOG_N] sumCheckUChallenges; - // Shplemini - Fr rho; - Fr geminiR; - Fr shplonkNu; - Fr shplonkZ; - // Derived - Fr publicInputsDelta; -} - -library ZKTranscriptLib { - function generateTranscript( - Honk.ZKProof memory proof, - bytes32[] calldata publicInputs, - uint256 vkHash, - uint256 publicInputsSize, - uint256 logN - ) external pure returns (ZKTranscript memory t) { - Fr previousChallenge; - (t.relationParameters, previousChallenge) = - generateRelationParametersChallenges(proof, publicInputs, vkHash, publicInputsSize, previousChallenge); - - (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof); - - (t.gateChallenges, previousChallenge) = generateGateChallenges(previousChallenge, logN); - (t.libraChallenge, previousChallenge) = generateLibraChallenge(previousChallenge, proof); - (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges(proof, previousChallenge, logN); - - (t.rho, previousChallenge) = generateRhoChallenge(proof, previousChallenge); - - (t.geminiR, previousChallenge) = generateGeminiRChallenge(proof, previousChallenge, logN); - - (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge(proof, previousChallenge, logN); - - (t.shplonkZ, previousChallenge) = generateShplonkZChallenge(proof, previousChallenge); - return t; - } - - function splitChallenge(Fr challenge) internal pure returns (Fr first, Fr second) { - uint256 challengeU256 = uint256(Fr.unwrap(challenge)); - // Split into two equal 127-bit chunks (254/2) - uint256 lo = challengeU256 & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // 127 bits - uint256 hi = challengeU256 >> 127; - first = FrLib.fromBytes32(bytes32(lo)); - second = FrLib.fromBytes32(bytes32(hi)); - } - - function generateRelationParametersChallenges( - Honk.ZKProof memory proof, - bytes32[] calldata publicInputs, - uint256 vkHash, - uint256 publicInputsSize, - Fr previousChallenge - ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { - (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = - generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize); - - (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); - } - - function generateEtaChallenge( - Honk.ZKProof memory proof, - bytes32[] calldata publicInputs, - uint256 vkHash, - uint256 publicInputsSize - ) internal pure returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) { - // Size: 1 (vkHash) + publicInputsSize + 8 (geminiMask(2) + 3 wires(6)) - bytes32[] memory round0 = new bytes32[](1 + publicInputsSize + 8); - round0[0] = bytes32(vkHash); - - for (uint256 i = 0; i < publicInputsSize - PAIRING_POINTS_SIZE; i++) { - round0[1 + i] = bytes32(publicInputs[i]); - } - for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { - round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]); - } - - // For ZK flavors: hash the gemini masking poly commitment (sent right after public inputs) - round0[1 + publicInputsSize] = bytes32(proof.geminiMaskingPoly.x); - round0[1 + publicInputsSize + 1] = bytes32(proof.geminiMaskingPoly.y); - - // Create the first challenge - // Note: w4 is added to the challenge later on - round0[1 + publicInputsSize + 2] = bytes32(proof.w1.x); - round0[1 + publicInputsSize + 3] = bytes32(proof.w1.y); - round0[1 + publicInputsSize + 4] = bytes32(proof.w2.x); - round0[1 + publicInputsSize + 5] = bytes32(proof.w2.y); - round0[1 + publicInputsSize + 6] = bytes32(proof.w3.x); - round0[1 + publicInputsSize + 7] = bytes32(proof.w3.y); - - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round0))); - (eta, etaTwo) = splitChallenge(previousChallenge); - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))); - - (etaThree,) = splitChallenge(previousChallenge); - } - - function generateBetaAndGammaChallenges(Fr previousChallenge, Honk.ZKProof memory proof) - internal - pure - returns (Fr beta, Fr gamma, Fr nextPreviousChallenge) - { - bytes32[7] memory round1; - round1[0] = FrLib.toBytes32(previousChallenge); - round1[1] = bytes32(proof.lookupReadCounts.x); - round1[2] = bytes32(proof.lookupReadCounts.y); - round1[3] = bytes32(proof.lookupReadTags.x); - round1[4] = bytes32(proof.lookupReadTags.y); - round1[5] = bytes32(proof.w4.x); - round1[6] = bytes32(proof.w4.y); - - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round1))); - (beta, gamma) = splitChallenge(nextPreviousChallenge); - } - - // Alpha challenges non-linearise the gate contributions - function generateAlphaChallenges(Fr previousChallenge, Honk.ZKProof memory proof) - internal - pure - returns (Fr[NUMBER_OF_ALPHAS] memory alphas, Fr nextPreviousChallenge) - { - // Generate the original sumcheck alpha 0 by hashing zPerm and zLookup - uint256[5] memory alpha0; - alpha0[0] = Fr.unwrap(previousChallenge); - alpha0[1] = proof.lookupInverses.x; - alpha0[2] = proof.lookupInverses.y; - alpha0[3] = proof.zPerm.x; - alpha0[4] = proof.zPerm.y; - - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(alpha0))); - Fr alpha; - (alpha,) = splitChallenge(nextPreviousChallenge); - - // Compute powers of alpha for batching subrelations - alphas[0] = alpha; - for (uint256 i = 1; i < NUMBER_OF_ALPHAS; i++) { - alphas[i] = alphas[i - 1] * alpha; - } - } - - function generateGateChallenges(Fr previousChallenge, uint256 logN) - internal - pure - returns (Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, Fr nextPreviousChallenge) - { - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))); - (gateChallenges[0],) = splitChallenge(previousChallenge); - for (uint256 i = 1; i < logN; i++) { - gateChallenges[i] = gateChallenges[i - 1] * gateChallenges[i - 1]; - } - nextPreviousChallenge = previousChallenge; - } - - function generateLibraChallenge(Fr previousChallenge, Honk.ZKProof memory proof) - internal - pure - returns (Fr libraChallenge, Fr nextPreviousChallenge) - { - // 2 comm, 1 sum, 1 challenge - uint256[4] memory challengeData; - challengeData[0] = Fr.unwrap(previousChallenge); - challengeData[1] = proof.libraCommitments[0].x; - challengeData[2] = proof.libraCommitments[0].y; - challengeData[3] = Fr.unwrap(proof.libraSum); - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(challengeData))); - (libraChallenge,) = splitChallenge(nextPreviousChallenge); - } - - function generateSumcheckChallenges(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) - internal - pure - returns (Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, Fr nextPreviousChallenge) - { - for (uint256 i = 0; i < logN; i++) { - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH + 1] memory univariateChal; - univariateChal[0] = prevChallenge; - - for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) { - univariateChal[j + 1] = proof.sumcheckUnivariates[i][j]; - } - prevChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(univariateChal))); - - (sumcheckChallenges[i],) = splitChallenge(prevChallenge); - } - nextPreviousChallenge = prevChallenge; - } - - // We add Libra claimed eval + 2 libra commitments (grand_sum, quotient) - function generateRhoChallenge(Honk.ZKProof memory proof, Fr prevChallenge) - internal - pure - returns (Fr rho, Fr nextPreviousChallenge) - { - uint256[NUMBER_OF_ENTITIES_ZK + 6] memory rhoChallengeElements; - rhoChallengeElements[0] = Fr.unwrap(prevChallenge); - uint256 i; - for (i = 1; i <= NUMBER_OF_ENTITIES_ZK; i++) { - rhoChallengeElements[i] = Fr.unwrap(proof.sumcheckEvaluations[i - 1]); - } - rhoChallengeElements[i] = Fr.unwrap(proof.libraEvaluation); - i += 1; - rhoChallengeElements[i] = proof.libraCommitments[1].x; - rhoChallengeElements[i + 1] = proof.libraCommitments[1].y; - i += 2; - rhoChallengeElements[i] = proof.libraCommitments[2].x; - rhoChallengeElements[i + 1] = proof.libraCommitments[2].y; - - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(rhoChallengeElements))); - (rho,) = splitChallenge(nextPreviousChallenge); - } - - function generateGeminiRChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) - internal - pure - returns (Fr geminiR, Fr nextPreviousChallenge) - { - uint256[] memory gR = new uint256[]((logN - 1) * 2 + 1); - gR[0] = Fr.unwrap(prevChallenge); - - for (uint256 i = 0; i < logN - 1; i++) { - gR[1 + i * 2] = proof.geminiFoldComms[i].x; - gR[2 + i * 2] = proof.geminiFoldComms[i].y; - } - - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(gR))); - - (geminiR,) = splitChallenge(nextPreviousChallenge); - } - - function generateShplonkNuChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) - internal - pure - returns (Fr shplonkNu, Fr nextPreviousChallenge) - { - uint256[] memory shplonkNuChallengeElements = new uint256[](logN + 1 + 4); - shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge); - - for (uint256 i = 1; i <= logN; i++) { - shplonkNuChallengeElements[i] = Fr.unwrap(proof.geminiAEvaluations[i - 1]); - } - - uint256 libraIdx = 0; - for (uint256 i = logN + 1; i <= logN + 4; i++) { - shplonkNuChallengeElements[i] = Fr.unwrap(proof.libraPolyEvals[libraIdx]); - libraIdx++; - } - - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkNuChallengeElements))); - (shplonkNu,) = splitChallenge(nextPreviousChallenge); - } - - function generateShplonkZChallenge(Honk.ZKProof memory proof, Fr prevChallenge) - internal - pure - returns (Fr shplonkZ, Fr nextPreviousChallenge) - { - uint256[3] memory shplonkZChallengeElements; - shplonkZChallengeElements[0] = Fr.unwrap(prevChallenge); - - shplonkZChallengeElements[1] = proof.shplonkQ.x; - shplonkZChallengeElements[2] = proof.shplonkQ.y; - - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkZChallengeElements))); - (shplonkZ,) = splitChallenge(nextPreviousChallenge); - } - - function loadProof(bytes calldata proof, uint256 logN) internal pure returns (Honk.ZKProof memory p) { - uint256 boundary = 0x0; - - // Pairing point object - for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { - p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); - boundary += FIELD_ELEMENT_SIZE; - } - - // Gemini masking polynomial commitment (sent first in ZK flavors, right after pairing points) - p.geminiMaskingPoly = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - - // Commitments - p.w1 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - p.w2 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - p.w3 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - - // Lookup / Permutation Helper Commitments - p.lookupReadCounts = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - p.lookupReadTags = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - p.w4 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - p.lookupInverses = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - p.zPerm = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - p.libraCommitments[0] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - - p.libraSum = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); - boundary += FIELD_ELEMENT_SIZE; - // Sumcheck univariates - for (uint256 i = 0; i < logN; i++) { - for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) { - p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); - boundary += FIELD_ELEMENT_SIZE; - } - } - - // Sumcheck evaluations (includes gemini_masking_poly eval at index 0 for ZK flavors) - for (uint256 i = 0; i < NUMBER_OF_ENTITIES_ZK; i++) { - p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); - boundary += FIELD_ELEMENT_SIZE; - } - - p.libraEvaluation = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); - boundary += FIELD_ELEMENT_SIZE; - - p.libraCommitments[1] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - p.libraCommitments[2] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - - // Gemini - // Read gemini fold univariates - for (uint256 i = 0; i < logN - 1; i++) { - p.geminiFoldComms[i] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - } - - // Read gemini a evaluations - for (uint256 i = 0; i < logN; i++) { - p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); - boundary += FIELD_ELEMENT_SIZE; - } - - for (uint256 i = 0; i < 4; i++) { - p.libraPolyEvals[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); - boundary += FIELD_ELEMENT_SIZE; - } - - // Shplonk - p.shplonkQ = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - boundary += GROUP_ELEMENT_SIZE; - // KZG - p.kzgQuotient = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); - } -} - -// Field arithmetic libraries - -library RelationsLib { - Fr internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = Fr.wrap(17); // -(-17) - - function accumulateRelationEvaluations( - Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations, - Honk.RelationParameters memory rp, - Fr[NUMBER_OF_ALPHAS] memory subrelationChallenges, - Fr powPartialEval - ) internal pure returns (Fr accumulator) { - Fr[NUMBER_OF_SUBRELATIONS] memory evaluations; - - // Accumulate all relations in Ultra Honk - each with varying number of subrelations - accumulateArithmeticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePermutationRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateLogDerivativeLookupRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateDeltaRangeRelation(purportedEvaluations, evaluations, powPartialEval); - accumulateEllipticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulateMemoryRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateNnfRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval); - - // batch the subrelations with the precomputed alpha powers to obtain the full honk relation - accumulator = scaleAndBatchSubrelations(evaluations, subrelationChallenges); - } - - /** - * Aesthetic helper function that is used to index by enum into proof.sumcheckEvaluations, it avoids - * the relation checking code being cluttered with uint256 type casting, which is often a different colour in code - * editors, and thus is noisy. - */ - function wire(Fr[NUMBER_OF_ENTITIES] memory p, WIRE _wire) internal pure returns (Fr) { - return p[uint256(_wire)]; - } - - uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; - /** - * Ultra Arithmetic Relation - * - */ - - function accumulateArithmeticRelation( - Fr[NUMBER_OF_ENTITIES] memory p, - Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep - ) internal pure { - // Relation 0 - Fr q_arith = wire(p, WIRE.Q_ARITH); - { - Fr neg_half = Fr.wrap(NEG_HALF_MODULO_P); - - Fr accum = (q_arith - Fr.wrap(3)) * (wire(p, WIRE.Q_M) * wire(p, WIRE.W_R) * wire(p, WIRE.W_L)) * neg_half; - accum = accum + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R)) - + (wire(p, WIRE.Q_O) * wire(p, WIRE.W_O)) + (wire(p, WIRE.Q_4) * wire(p, WIRE.W_4)) + wire(p, WIRE.Q_C); - accum = accum + (q_arith - ONE) * wire(p, WIRE.W_4_SHIFT); - accum = accum * q_arith; - accum = accum * domainSep; - evals[0] = accum; - } - - // Relation 1 - { - Fr accum = wire(p, WIRE.W_L) + wire(p, WIRE.W_4) - wire(p, WIRE.W_L_SHIFT) + wire(p, WIRE.Q_M); - accum = accum * (q_arith - Fr.wrap(2)); - accum = accum * (q_arith - ONE); - accum = accum * q_arith; - accum = accum * domainSep; - evals[1] = accum; - } - } - - function accumulatePermutationRelation( - Fr[NUMBER_OF_ENTITIES] memory p, - Honk.RelationParameters memory rp, - Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep - ) internal pure { - Fr grand_product_numerator; - Fr grand_product_denominator; - - { - Fr num = wire(p, WIRE.W_L) + wire(p, WIRE.ID_1) * rp.beta + rp.gamma; - num = num * (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma); - num = num * (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma); - num = num * (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma); - - grand_product_numerator = num; - } - { - Fr den = wire(p, WIRE.W_L) + wire(p, WIRE.SIGMA_1) * rp.beta + rp.gamma; - den = den * (wire(p, WIRE.W_R) + wire(p, WIRE.SIGMA_2) * rp.beta + rp.gamma); - den = den * (wire(p, WIRE.W_O) + wire(p, WIRE.SIGMA_3) * rp.beta + rp.gamma); - den = den * (wire(p, WIRE.W_4) + wire(p, WIRE.SIGMA_4) * rp.beta + rp.gamma); - - grand_product_denominator = den; - } - - // Contribution 2 - { - Fr acc = (wire(p, WIRE.Z_PERM) + wire(p, WIRE.LAGRANGE_FIRST)) * grand_product_numerator; - - acc = acc - - ((wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) - * grand_product_denominator); - acc = acc * domainSep; - evals[2] = acc; - } - - // Contribution 3 - { - Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; - evals[3] = acc; - } - } - - function accumulateLogDerivativeLookupRelation( - Fr[NUMBER_OF_ENTITIES] memory p, - Honk.RelationParameters memory rp, - Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep - ) internal pure { - Fr write_term; - Fr read_term; - - // Calculate the write term (the table accumulation) - { - write_term = wire(p, WIRE.TABLE_1) + rp.gamma + (wire(p, WIRE.TABLE_2) * rp.eta) - + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + (wire(p, WIRE.TABLE_4) * rp.etaThree); - } - - // Calculate the write term - { - Fr derived_entry_1 = wire(p, WIRE.W_L) + rp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); - Fr derived_entry_2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_M) * wire(p, WIRE.W_R_SHIFT); - Fr derived_entry_3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_C) * wire(p, WIRE.W_O_SHIFT); - - read_term = derived_entry_1 + (derived_entry_2 * rp.eta) + (derived_entry_3 * rp.etaTwo) - + (wire(p, WIRE.Q_O) * rp.etaThree); - } - - Fr read_inverse = wire(p, WIRE.LOOKUP_INVERSES) * write_term; - Fr write_inverse = wire(p, WIRE.LOOKUP_INVERSES) * read_term; - - Fr inverse_exists_xor = - wire(p, WIRE.LOOKUP_READ_TAGS) + wire(p, WIRE.Q_LOOKUP) - - (wire(p, WIRE.LOOKUP_READ_TAGS) * wire(p, WIRE.Q_LOOKUP)); - - // Inverse calculated correctly relation - Fr accumulatorNone = read_term * write_term * wire(p, WIRE.LOOKUP_INVERSES) - inverse_exists_xor; - accumulatorNone = accumulatorNone * domainSep; - - // Inverse - Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * read_inverse - wire(p, WIRE.LOOKUP_READ_COUNTS) * write_inverse; - - Fr read_tag = wire(p, WIRE.LOOKUP_READ_TAGS); - - Fr read_tag_boolean_relation = read_tag * read_tag - read_tag; - - evals[4] = accumulatorNone; - evals[5] = accumulatorOne; - evals[6] = read_tag_boolean_relation * domainSep; - } - - function accumulateDeltaRangeRelation( - Fr[NUMBER_OF_ENTITIES] memory p, - Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep - ) internal pure { - Fr minus_one = ZERO - ONE; - Fr minus_two = ZERO - Fr.wrap(2); - Fr minus_three = ZERO - Fr.wrap(3); - - // Compute wire differences - Fr delta_1 = wire(p, WIRE.W_R) - wire(p, WIRE.W_L); - Fr delta_2 = wire(p, WIRE.W_O) - wire(p, WIRE.W_R); - Fr delta_3 = wire(p, WIRE.W_4) - wire(p, WIRE.W_O); - Fr delta_4 = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_4); - - // Contribution 6 - { - Fr acc = delta_1; - acc = acc * (delta_1 + minus_one); - acc = acc * (delta_1 + minus_two); - acc = acc * (delta_1 + minus_three); - acc = acc * wire(p, WIRE.Q_RANGE); - acc = acc * domainSep; - evals[7] = acc; - } - - // Contribution 7 - { - Fr acc = delta_2; - acc = acc * (delta_2 + minus_one); - acc = acc * (delta_2 + minus_two); - acc = acc * (delta_2 + minus_three); - acc = acc * wire(p, WIRE.Q_RANGE); - acc = acc * domainSep; - evals[8] = acc; - } - - // Contribution 8 - { - Fr acc = delta_3; - acc = acc * (delta_3 + minus_one); - acc = acc * (delta_3 + minus_two); - acc = acc * (delta_3 + minus_three); - acc = acc * wire(p, WIRE.Q_RANGE); - acc = acc * domainSep; - evals[9] = acc; - } - - // Contribution 9 - { - Fr acc = delta_4; - acc = acc * (delta_4 + minus_one); - acc = acc * (delta_4 + minus_two); - acc = acc * (delta_4 + minus_three); - acc = acc * wire(p, WIRE.Q_RANGE); - acc = acc * domainSep; - evals[10] = acc; - } - } - - struct EllipticParams { - // Points - Fr x_1; - Fr y_1; - Fr x_2; - Fr y_2; - Fr y_3; - Fr x_3; - // push accumulators into memory - Fr x_double_identity; - } - - function accumulateEllipticRelation( - Fr[NUMBER_OF_ENTITIES] memory p, - Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep - ) internal pure { - EllipticParams memory ep; - ep.x_1 = wire(p, WIRE.W_R); - ep.y_1 = wire(p, WIRE.W_O); - - ep.x_2 = wire(p, WIRE.W_L_SHIFT); - ep.y_2 = wire(p, WIRE.W_4_SHIFT); - ep.y_3 = wire(p, WIRE.W_O_SHIFT); - ep.x_3 = wire(p, WIRE.W_R_SHIFT); - - Fr q_sign = wire(p, WIRE.Q_L); - Fr q_is_double = wire(p, WIRE.Q_M); - - // Contribution 10 point addition, x-coordinate check - // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0 - Fr x_diff = (ep.x_2 - ep.x_1); - Fr y1_sqr = (ep.y_1 * ep.y_1); - { - // Move to top - Fr partialEval = domainSep; - - Fr y2_sqr = (ep.y_2 * ep.y_2); - Fr y1y2 = ep.y_1 * ep.y_2 * q_sign; - Fr x_add_identity = (ep.x_3 + ep.x_2 + ep.x_1); - x_add_identity = x_add_identity * x_diff * x_diff; - x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2; - - evals[11] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); - } - - // Contribution 11 point addition, x-coordinate check - // q_elliptic * (q_sign * y1 + y3)(x2 - x1) + (x3 - x1)(y2 - q_sign * y1) = 0 - { - Fr y1_plus_y3 = ep.y_1 + ep.y_3; - Fr y_diff = ep.y_2 * q_sign - ep.y_1; - Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff; - evals[12] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); - } - - // Contribution 10 point doubling, x-coordinate check - // (x3 + x1 + x1) (4y1*y1) - 9 * x1 * x1 * x1 * x1 = 0 - // N.B. we're using the equivalence x1*x1*x1 === y1*y1 - curve_b to reduce degree by 1 - { - Fr x_pow_4 = (y1_sqr + GRUMPKIN_CURVE_B_PARAMETER_NEGATED) * ep.x_1; - Fr y1_sqr_mul_4 = y1_sqr + y1_sqr; - y1_sqr_mul_4 = y1_sqr_mul_4 + y1_sqr_mul_4; - Fr x1_pow_4_mul_9 = x_pow_4 * Fr.wrap(9); - - // NOTE: pushed into memory (stack >:'( ) - ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9; - - Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; - evals[11] = evals[11] + acc; - } - - // Contribution 11 point doubling, y-coordinate check - // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0 - { - Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1; - Fr y_double_identity = x1_sqr_mul_3 * (ep.x_1 - ep.x_3) - (ep.y_1 + ep.y_1) * (ep.y_1 + ep.y_3); - evals[12] = evals[12] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; - } - } - - // Parameters used within the Memory Relation - // A struct is used to work around stack too deep. This relation has alot of variables - struct MemParams { - Fr memory_record_check; - Fr partial_record_check; - Fr next_gate_access_type; - Fr record_delta; - Fr index_delta; - Fr adjacent_values_match_if_adjacent_indices_match; - Fr adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; - Fr access_check; - Fr next_gate_access_type_is_boolean; - Fr ROM_consistency_check_identity; - Fr RAM_consistency_check_identity; - Fr timestamp_delta; - Fr RAM_timestamp_check_identity; - Fr memory_identity; - Fr index_is_monotonically_increasing; - } - - function accumulateMemoryRelation( - Fr[NUMBER_OF_ENTITIES] memory p, - Honk.RelationParameters memory rp, - Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep - ) internal pure { - MemParams memory ap; - - /** - * MEMORY - * - * A RAM memory record contains a tuple of the following fields: - * * i: `index` of memory cell being accessed - * * t: `timestamp` of memory cell being accessed (used for RAM, set to 0 for ROM) - * * v: `value` of memory cell being accessed - * * a: `access` type of record. read: 0 = read, 1 = write - * * r: `record` of memory cell. record = access + index * eta + timestamp * eta_two + value * eta_three - * - * A ROM memory record contains a tuple of the following fields: - * * i: `index` of memory cell being accessed - * * v: `value1` of memory cell being accessed (ROM tables can store up to 2 values per index) - * * v2:`value2` of memory cell being accessed (ROM tables can store up to 2 values per index) - * * r: `record` of memory cell. record = index * eta + value2 * eta_two + value1 * eta_three - * - * When performing a read/write access, the values of i, t, v, v2, a, r are stored in the following wires + - * selectors, depending on whether the gate is a RAM read/write or a ROM read - * - * | gate type | i | v2/t | v | a | r | - * | --------- | -- | ----- | -- | -- | -- | - * | ROM | w1 | w2 | w3 | -- | w4 | - * | RAM | w1 | w2 | w3 | qc | w4 | - * - * (for accesses where `index` is a circuit constant, it is assumed the circuit will apply a copy constraint on - * `w2` to fix its value) - * - * - */ - - /** - * Memory Record Check - * Partial degree: 1 - * Total degree: 4 - * - * A ROM/ROM access gate can be evaluated with the identity: - * - * qc + w1 \eta + w2 \eta_two + w3 \eta_three - w4 = 0 - * - * For ROM gates, qc = 0 - */ - ap.memory_record_check = wire(p, WIRE.W_O) * rp.etaThree; - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * rp.etaTwo); - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * rp.eta); - ap.memory_record_check = ap.memory_record_check + wire(p, WIRE.Q_C); - ap.partial_record_check = ap.memory_record_check; // used in RAM consistency check; deg 1 or 4 - ap.memory_record_check = ap.memory_record_check - wire(p, WIRE.W_4); - - /** - * Contribution 13 & 14 - * ROM Consistency Check - * Partial degree: 1 - * Total degree: 4 - * - * For every ROM read, a set equivalence check is applied between the record witnesses, and a second set of - * records that are sorted. - * - * We apply the following checks for the sorted records: - * - * 1. w1, w2, w3 correctly map to 'index', 'v1, 'v2' for a given record value at w4 - * 2. index values for adjacent records are monotonically increasing - * 3. if, at gate i, index_i == index_{i + 1}, then value1_i == value1_{i + 1} and value2_i == value2_{i + 1} - * - */ - ap.index_delta = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_L); - ap.record_delta = wire(p, WIRE.W_4_SHIFT) - wire(p, WIRE.W_4); - - ap.index_is_monotonically_increasing = ap.index_delta * (ap.index_delta - Fr.wrap(1)); // deg 2 - - ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + ONE) * ap.record_delta; // deg 2 - - evals[14] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) - * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - evals[15] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) - * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - - ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 - - /** - * Contributions 15,16,17 - * RAM Consistency Check - * - * The 'access' type of the record is extracted with the expression `w_4 - ap.partial_record_check` - * (i.e. for an honest Prover `w1 * eta + w2 * eta^2 + w3 * eta^3 - w4 = access`. - * This is validated by requiring `access` to be boolean - * - * For two adjacent entries in the sorted list if _both_ - * A) index values match - * B) adjacent access value is 0 (i.e. next gate is a READ) - * then - * C) both values must match. - * The gate boolean check is - * (A && B) => C === !(A && B) || C === !A || !B || C - * - * N.B. it is the responsibility of the circuit writer to ensure that every RAM cell is initialized - * with a WRITE operation. - */ - Fr access_type = (wire(p, WIRE.W_4) - ap.partial_record_check); // will be 0 or 1 for honest Prover; deg 1 or 4 - ap.access_check = access_type * (access_type - Fr.wrap(1)); // check value is 0 or 1; deg 2 or 8 - - // reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta - // deg 1 or 4 - ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree; - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta); - ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type; - - Fr value_delta = wire(p, WIRE.W_O_SHIFT) - wire(p, WIRE.W_O); - ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = - (ap.index_delta * MINUS_ONE + ONE) * value_delta * (ap.next_gate_access_type * MINUS_ONE + ONE); // deg 3 or 6 - - // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the - // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't - // do with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access - // type is correct, to cover this edge case - // deg 2 or 4 - ap.next_gate_access_type_is_boolean = - ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type; - - // Putting it all together... - evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation - * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 - evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 - evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 - - ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9 - - /** - * RAM Timestamp Consistency Check - * - * | w1 | w2 | w3 | w4 | - * | index | timestamp | timestamp_check | -- | - * - * Let delta_index = index_{i + 1} - index_{i} - * - * Iff delta_index == 0, timestamp_check = timestamp_{i + 1} - timestamp_i - * Else timestamp_check = 0 - */ - ap.timestamp_delta = wire(p, WIRE.W_R_SHIFT) - wire(p, WIRE.W_R); - ap.RAM_timestamp_check_identity = (ap.index_delta * MINUS_ONE + ONE) * ap.timestamp_delta - wire(p, WIRE.W_O); // deg 3 - - /** - * Complete Contribution 12 - * The complete RAM/ROM memory identity - * Partial degree: - */ - ap.memory_identity = ap.ROM_consistency_check_identity; // deg 3 or 6 - ap.memory_identity = - ap.memory_identity + ap.RAM_timestamp_check_identity * (wire(p, WIRE.Q_4) * wire(p, WIRE.Q_L)); // deg 4 - ap.memory_identity = ap.memory_identity + ap.memory_record_check * (wire(p, WIRE.Q_M) * wire(p, WIRE.Q_L)); // deg 3 or 6 - ap.memory_identity = ap.memory_identity + ap.RAM_consistency_check_identity; // deg 3 or 9 - - // (deg 3 or 9) + (deg 4) + (deg 3) - ap.memory_identity = ap.memory_identity * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10 - evals[13] = ap.memory_identity; - } - - // Constants for the Non-native Field relation - Fr constant LIMB_SIZE = Fr.wrap(uint256(1) << 68); - Fr constant SUBLIMB_SHIFT = Fr.wrap(uint256(1) << 14); - - // Parameters used within the Non-Native Field Relation - // A struct is used to work around stack too deep. This relation has alot of variables - struct NnfParams { - Fr limb_subproduct; - Fr non_native_field_gate_1; - Fr non_native_field_gate_2; - Fr non_native_field_gate_3; - Fr limb_accumulator_1; - Fr limb_accumulator_2; - Fr nnf_identity; - } - - function accumulateNnfRelation( - Fr[NUMBER_OF_ENTITIES] memory p, - Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep - ) internal pure { - NnfParams memory ap; - - /** - * Contribution 12 - * Non native field arithmetic gate 2 - * deg 4 - * - * _ _ - * / _ _ _ 14 \ - * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 | - * \_ _/ - * - * - */ - ap.limb_subproduct = wire(p, WIRE.W_L) * wire(p, WIRE.W_R_SHIFT) + wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R); - ap.non_native_field_gate_2 = - (wire(p, WIRE.W_L) * wire(p, WIRE.W_4) + wire(p, WIRE.W_R) * wire(p, WIRE.W_O) - wire(p, WIRE.W_O_SHIFT)); - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * LIMB_SIZE; - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 - wire(p, WIRE.W_4_SHIFT); - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 + ap.limb_subproduct; - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * wire(p, WIRE.Q_4); - - ap.limb_subproduct = ap.limb_subproduct * LIMB_SIZE; - ap.limb_subproduct = ap.limb_subproduct + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT)); - ap.non_native_field_gate_1 = ap.limb_subproduct; - ap.non_native_field_gate_1 = ap.non_native_field_gate_1 - (wire(p, WIRE.W_O) + wire(p, WIRE.W_4)); - ap.non_native_field_gate_1 = ap.non_native_field_gate_1 * wire(p, WIRE.Q_O); - - ap.non_native_field_gate_3 = ap.limb_subproduct; - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 + wire(p, WIRE.W_4); - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 - (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT)); - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 * wire(p, WIRE.Q_M); - - Fr non_native_field_identity = - ap.non_native_field_gate_1 + ap.non_native_field_gate_2 + ap.non_native_field_gate_3; - non_native_field_identity = non_native_field_identity * wire(p, WIRE.Q_R); - - // ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * qm - // deg 2 - ap.limb_accumulator_1 = wire(p, WIRE.W_R_SHIFT) * SUBLIMB_SHIFT; - ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L_SHIFT); - ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT; - ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_O); - ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT; - ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_R); - ap.limb_accumulator_1 = ap.limb_accumulator_1 * SUBLIMB_SHIFT; - ap.limb_accumulator_1 = ap.limb_accumulator_1 + wire(p, WIRE.W_L); - ap.limb_accumulator_1 = ap.limb_accumulator_1 - wire(p, WIRE.W_4); - ap.limb_accumulator_1 = ap.limb_accumulator_1 * wire(p, WIRE.Q_4); - - // ((((w3' * 2^14 + w2') * 2^14 + w1') * 2^14 + w4) * 2^14 + w3 - w4') * qm - // deg 2 - ap.limb_accumulator_2 = wire(p, WIRE.W_O_SHIFT) * SUBLIMB_SHIFT; - ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_R_SHIFT); - ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT; - ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_L_SHIFT); - ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT; - ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_4); - ap.limb_accumulator_2 = ap.limb_accumulator_2 * SUBLIMB_SHIFT; - ap.limb_accumulator_2 = ap.limb_accumulator_2 + wire(p, WIRE.W_O); - ap.limb_accumulator_2 = ap.limb_accumulator_2 - wire(p, WIRE.W_4_SHIFT); - ap.limb_accumulator_2 = ap.limb_accumulator_2 * wire(p, WIRE.Q_M); - - Fr limb_accumulator_identity = ap.limb_accumulator_1 + ap.limb_accumulator_2; - limb_accumulator_identity = limb_accumulator_identity * wire(p, WIRE.Q_O); // deg 3 - - ap.nnf_identity = non_native_field_identity + limb_accumulator_identity; - ap.nnf_identity = ap.nnf_identity * (wire(p, WIRE.Q_NNF) * domainSep); - evals[19] = ap.nnf_identity; - } - - struct PoseidonExternalParams { - Fr s1; - Fr s2; - Fr s3; - Fr s4; - Fr u1; - Fr u2; - Fr u3; - Fr u4; - Fr t0; - Fr t1; - Fr t2; - Fr t3; - Fr v1; - Fr v2; - Fr v3; - Fr v4; - Fr q_pos_by_scaling; - } - - function accumulatePoseidonExternalRelation( - Fr[NUMBER_OF_ENTITIES] memory p, - Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep - ) internal pure { - PoseidonExternalParams memory ep; - - ep.s1 = wire(p, WIRE.W_L) + wire(p, WIRE.Q_L); - ep.s2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_R); - ep.s3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_O); - ep.s4 = wire(p, WIRE.W_4) + wire(p, WIRE.Q_4); - - ep.u1 = ep.s1 * ep.s1 * ep.s1 * ep.s1 * ep.s1; - ep.u2 = ep.s2 * ep.s2 * ep.s2 * ep.s2 * ep.s2; - ep.u3 = ep.s3 * ep.s3 * ep.s3 * ep.s3 * ep.s3; - ep.u4 = ep.s4 * ep.s4 * ep.s4 * ep.s4 * ep.s4; - // matrix mul v = M_E * u with 14 additions - ep.t0 = ep.u1 + ep.u2; // u_1 + u_2 - ep.t1 = ep.u3 + ep.u4; // u_3 + u_4 - ep.t2 = ep.u2 + ep.u2 + ep.t1; // 2u_2 - // ep.t2 += ep.t1; // 2u_2 + u_3 + u_4 - ep.t3 = ep.u4 + ep.u4 + ep.t0; // 2u_4 - // ep.t3 += ep.t0; // u_1 + u_2 + 2u_4 - ep.v4 = ep.t1 + ep.t1; - ep.v4 = ep.v4 + ep.v4 + ep.t3; - // ep.v4 += ep.t3; // u_1 + u_2 + 4u_3 + 6u_4 - ep.v2 = ep.t0 + ep.t0; - ep.v2 = ep.v2 + ep.v2 + ep.t2; - // ep.v2 += ep.t2; // 4u_1 + 6u_2 + u_3 + u_4 - ep.v1 = ep.t3 + ep.v2; // 5u_1 + 7u_2 + u_3 + 3u_4 - ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4 - - ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep; - evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); - - evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); - - evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); - - evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); - } - - struct PoseidonInternalParams { - Fr u1; - Fr u2; - Fr u3; - Fr u4; - Fr u_sum; - Fr v1; - Fr v2; - Fr v3; - Fr v4; - Fr s1; - Fr q_pos_by_scaling; - } - - function accumulatePoseidonInternalRelation( - Fr[NUMBER_OF_ENTITIES] memory p, - Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep - ) internal pure { - PoseidonInternalParams memory ip; - - Fr[4] memory INTERNAL_MATRIX_DIAGONAL = [ - FrLib.from(0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7), - FrLib.from(0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b), - FrLib.from(0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15), - FrLib.from(0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b) - ]; - - // add round constants - ip.s1 = wire(p, WIRE.W_L) + wire(p, WIRE.Q_L); - - // apply s-box round - ip.u1 = ip.s1 * ip.s1 * ip.s1 * ip.s1 * ip.s1; - ip.u2 = wire(p, WIRE.W_R); - ip.u3 = wire(p, WIRE.W_O); - ip.u4 = wire(p, WIRE.W_4); - - // matrix mul with v = M_I * u 4 muls and 7 additions - ip.u_sum = ip.u1 + ip.u2 + ip.u3 + ip.u4; - - ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep; - - ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum; - evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); - - ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum; - evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); - - ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum; - evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); - - ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum; - evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); - } - - // Batch subrelation evaluations using precomputed powers of alpha - // First subrelation is implicitly scaled by 1, subsequent ones use powers from the subrelationChallenges array - function scaleAndBatchSubrelations( - Fr[NUMBER_OF_SUBRELATIONS] memory evaluations, - Fr[NUMBER_OF_ALPHAS] memory subrelationChallenges - ) internal pure returns (Fr accumulator) { - accumulator = evaluations[0]; - - for (uint256 i = 1; i < NUMBER_OF_SUBRELATIONS; ++i) { - accumulator = accumulator + evaluations[i] * subrelationChallenges[i - 1]; - } - } -} - -// Field arithmetic libraries - prevent littering the code with modmul / addmul - -library CommitmentSchemeLib { - using FrLib for Fr; - - // Avoid stack too deep - struct ShpleminiIntermediates { - Fr unshiftedScalar; - Fr shiftedScalar; - Fr unshiftedScalarNeg; - Fr shiftedScalarNeg; - // Scalar to be multiplied by [1]₁ - Fr constantTermAccumulator; - // Accumulator for powers of rho - Fr batchingChallenge; - // Linear combination of multilinear (sumcheck) evaluations and powers of rho - Fr batchedEvaluation; - Fr[4] denominators; - Fr[4] batchingScalars; - // 1/(z - r^{2^i}) for i = 0, ..., logSize, dynamically updated - Fr posInvertedDenominator; - // 1/(z + r^{2^i}) for i = 0, ..., logSize, dynamically updated - Fr negInvertedDenominator; - // ν^{2i} * 1/(z - r^{2^i}) - Fr scalingFactorPos; - // ν^{2i+1} * 1/(z + r^{2^i}) - Fr scalingFactorNeg; - // Fold_i(r^{2^i}) reconstructed by Verifier - Fr[] foldPosEvaluations; - } - - function computeSquares(Fr r, uint256 logN) internal pure returns (Fr[] memory) { - Fr[] memory squares = new Fr[](logN); - squares[0] = r; - for (uint256 i = 1; i < logN; ++i) { - squares[i] = squares[i - 1].sqr(); - } - return squares; - } - // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., m-1 - - function computeFoldPosEvaluations( - Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckUChallenges, - Fr batchedEvalAccumulator, - Fr[CONST_PROOF_SIZE_LOG_N] memory geminiEvaluations, - Fr[] memory geminiEvalChallengePowers, - uint256 logSize - ) internal view returns (Fr[] memory) { - Fr[] memory foldPosEvaluations = new Fr[](logSize); - for (uint256 i = logSize; i > 0; --i) { - Fr challengePower = geminiEvalChallengePowers[i - 1]; - Fr u = sumcheckUChallenges[i - 1]; - - Fr batchedEvalRoundAcc = ((challengePower * batchedEvalAccumulator * Fr.wrap(2)) - geminiEvaluations[i - 1] - * (challengePower * (ONE - u) - u)); - // Divide by the denominator - batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (ONE - u) + u).invert(); - - batchedEvalAccumulator = batchedEvalRoundAcc; - foldPosEvaluations[i - 1] = batchedEvalRoundAcc; - } - return foldPosEvaluations; - } -} - -uint256 constant Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // EC group order. F_q - -function bytes32ToString(bytes32 value) pure returns (string memory result) { - bytes memory alphabet = "0123456789abcdef"; - - bytes memory str = new bytes(66); - str[0] = "0"; - str[1] = "x"; - for (uint256 i = 0; i < 32; i++) { - str[2 + i * 2] = alphabet[uint8(value[i] >> 4)]; - str[3 + i * 2] = alphabet[uint8(value[i] & 0x0f)]; - } - result = string(str); -} - -// Fr utility - -function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) { - scalar = FrLib.fromBytes32(bytes32(proofSection)); -} - -// EC Point utilities -function bytesToG1Point(bytes calldata proofSection) pure returns (Honk.G1Point memory point) { - point = Honk.G1Point({ - x: uint256(bytes32(proofSection[0x00:0x20])) % Q, y: uint256(bytes32(proofSection[0x20:0x40])) % Q - }); -} - -function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) { - point.y = (Q - point.y) % Q; - return point; -} - -/** - * Convert the pairing points to G1 points. - * - * The pairing points are serialised as an array of 68 bit limbs representing two points - * The lhs of a pairing operation and the rhs of a pairing operation - * - * There are 4 fields for each group element, leaving 8 fields for each side of the pairing. - * - * @param pairingPoints The pairing points to convert. - * @return lhs - * @return rhs - */ -function convertPairingPointsToG1(Fr[PAIRING_POINTS_SIZE] memory pairingPoints) - pure - returns (Honk.G1Point memory lhs, Honk.G1Point memory rhs) -{ - uint256 lhsX = Fr.unwrap(pairingPoints[0]); - lhsX |= Fr.unwrap(pairingPoints[1]) << 68; - lhsX |= Fr.unwrap(pairingPoints[2]) << 136; - lhsX |= Fr.unwrap(pairingPoints[3]) << 204; - lhs.x = lhsX; - - uint256 lhsY = Fr.unwrap(pairingPoints[4]); - lhsY |= Fr.unwrap(pairingPoints[5]) << 68; - lhsY |= Fr.unwrap(pairingPoints[6]) << 136; - lhsY |= Fr.unwrap(pairingPoints[7]) << 204; - lhs.y = lhsY; - - uint256 rhsX = Fr.unwrap(pairingPoints[8]); - rhsX |= Fr.unwrap(pairingPoints[9]) << 68; - rhsX |= Fr.unwrap(pairingPoints[10]) << 136; - rhsX |= Fr.unwrap(pairingPoints[11]) << 204; - rhs.x = rhsX; - - uint256 rhsY = Fr.unwrap(pairingPoints[12]); - rhsY |= Fr.unwrap(pairingPoints[13]) << 68; - rhsY |= Fr.unwrap(pairingPoints[14]) << 136; - rhsY |= Fr.unwrap(pairingPoints[15]) << 204; - rhs.y = rhsY; -} - -/** - * Hash the pairing inputs from the present verification context with those extracted from the public inputs. - * - * @param proofPairingPoints Pairing points from the proof - (public inputs). - * @param accLhs Accumulator point for the left side - result of shplemini. - * @param accRhs Accumulator point for the right side - result of shplemini. - * @return recursionSeparator The recursion separator - generated from hashing the above. - */ -function generateRecursionSeparator( - Fr[PAIRING_POINTS_SIZE] memory proofPairingPoints, - Honk.G1Point memory accLhs, - Honk.G1Point memory accRhs -) pure returns (Fr recursionSeparator) { - // hash the proof aggregated X - // hash the proof aggregated Y - // hash the accum X - // hash the accum Y - - (Honk.G1Point memory proofLhs, Honk.G1Point memory proofRhs) = convertPairingPointsToG1(proofPairingPoints); - - uint256[8] memory recursionSeparatorElements; - - // Proof points - recursionSeparatorElements[0] = proofLhs.x; - recursionSeparatorElements[1] = proofLhs.y; - recursionSeparatorElements[2] = proofRhs.x; - recursionSeparatorElements[3] = proofRhs.y; - - // Accumulator points - recursionSeparatorElements[4] = accLhs.x; - recursionSeparatorElements[5] = accLhs.y; - recursionSeparatorElements[6] = accRhs.x; - recursionSeparatorElements[7] = accRhs.y; - - recursionSeparator = FrLib.fromBytes32(keccak256(abi.encodePacked(recursionSeparatorElements))); -} - -/** - * G1 Mul with Separator - * Using the ecAdd and ecMul precompiles - * - * @param basePoint The point to multiply. - * @param other The other point to add. - * @param recursionSeperator The separator to use for the multiplication. - * @return `(recursionSeperator * basePoint) + other`. - */ -function mulWithSeperator(Honk.G1Point memory basePoint, Honk.G1Point memory other, Fr recursionSeperator) - view - returns (Honk.G1Point memory) -{ - Honk.G1Point memory result; - - result = ecMul(recursionSeperator, basePoint); - result = ecAdd(result, other); - - return result; -} - -/** - * G1 Mul - * Takes a Fr value and a G1 point and uses the ecMul precompile to return the result. - * - * @param value The value to multiply the point by. - * @param point The point to multiply. - * @return result The result of the multiplication. - */ -function ecMul(Fr value, Honk.G1Point memory point) view returns (Honk.G1Point memory) { - Honk.G1Point memory result; - - assembly { - let free := mload(0x40) - // Write the point into memory (two 32 byte words) - // Memory layout: - // Address | value - // free | point.x - // free + 0x20| point.y - mstore(free, mload(point)) - mstore(add(free, 0x20), mload(add(point, 0x20))) - // Write the scalar into memory (one 32 byte word) - // Memory layout: - // Address | value - // free + 0x40| value - mstore(add(free, 0x40), value) - - // Call the ecMul precompile, it takes in the following - // [point.x, point.y, scalar], and returns the result back into the free memory location. - let success := staticcall(gas(), 0x07, free, 0x60, free, 0x40) - if iszero(success) { - revert(0, 0) - } - // Copy the result of the multiplication back into the result memory location. - // Memory layout: - // Address | value - // result | result.x - // result + 0x20| result.y - mstore(result, mload(free)) - mstore(add(result, 0x20), mload(add(free, 0x20))) - - mstore(0x40, add(free, 0x60)) - } - - return result; -} - -/** - * G1 Add - * Takes two G1 points and uses the ecAdd precompile to return the result. - * - * @param lhs The left hand side of the addition. - * @param rhs The right hand side of the addition. - * @return result The result of the addition. - */ -function ecAdd(Honk.G1Point memory lhs, Honk.G1Point memory rhs) view returns (Honk.G1Point memory) { - Honk.G1Point memory result; - - assembly { - let free := mload(0x40) - // Write lhs into memory (two 32 byte words) - // Memory layout: - // Address | value - // free | lhs.x - // free + 0x20| lhs.y - mstore(free, mload(lhs)) - mstore(add(free, 0x20), mload(add(lhs, 0x20))) - - // Write rhs into memory (two 32 byte words) - // Memory layout: - // Address | value - // free + 0x40| rhs.x - // free + 0x60| rhs.y - mstore(add(free, 0x40), mload(rhs)) - mstore(add(free, 0x60), mload(add(rhs, 0x20))) - - // Call the ecAdd precompile, it takes in the following - // [lhs.x, lhs.y, rhs.x, rhs.y], and returns their addition back into the free memory location. - let success := staticcall(gas(), 0x06, free, 0x80, free, 0x40) - if iszero(success) { revert(0, 0) } - - // Copy the result of the addition back into the result memory location. - // Memory layout: - // Address | value - // result | result.x - // result + 0x20| result.y - mstore(result, mload(free)) - mstore(add(result, 0x20), mload(add(free, 0x20))) - - mstore(0x40, add(free, 0x80)) - } - - return result; -} - -function validateOnCurve(Honk.G1Point memory point) pure { - uint256 x = point.x; - uint256 y = point.y; - - bool success = false; - assembly { - let xx := mulmod(x, x, Q) - success := eq(mulmod(y, y, Q), addmod(mulmod(x, xx, Q), 3, Q)) - } - - require(success, "point is not on the curve"); -} - -function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns (bool decodedResult) { - bytes memory input = abi.encodePacked( - rhs.x, - rhs.y, - // Fixed G2 point - uint256(0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2), - uint256(0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed), - uint256(0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b), - uint256(0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa), - lhs.x, - lhs.y, - // G2 point from VK - uint256(0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1), - uint256(0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0), - uint256(0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4), - uint256(0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) - ); - - (bool success, bytes memory result) = address(0x08).staticcall(input); - decodedResult = success && abi.decode(result, (bool)); -} - -// Field arithmetic libraries - prevent littering the code with modmul / addmul - - - - -abstract contract BaseZKHonkVerifier is IVerifier { - using FrLib for Fr; - - uint256 immutable $N; - uint256 immutable $LOG_N; - uint256 immutable $VK_HASH; - uint256 immutable $NUM_PUBLIC_INPUTS; - uint256 immutable $MSMSize; - - constructor(uint256 _N, uint256 _logN, uint256 _vkHash, uint256 _numPublicInputs) { - $N = _N; - $LOG_N = _logN; - $VK_HASH = _vkHash; - $NUM_PUBLIC_INPUTS = _numPublicInputs; - $MSMSize = NUMBER_UNSHIFTED_ZK + _logN + LIBRA_COMMITMENTS + 2; - } - - // Errors - error ProofLengthWrong(); - error ProofLengthWrongWithLogN(uint256 logN, uint256 actualLength, uint256 expectedLength); - error PublicInputsLengthWrong(); - error SumcheckFailed(); - error ShpleminiFailed(); - error GeminiChallengeInSubgroup(); - error ConsistencyCheckFailed(); - - // Constants for proof length calculation (matching UltraKeccakZKFlavor) - uint256 constant NUM_WITNESS_ENTITIES = 8 + NUM_MASKING_POLYNOMIALS; - uint256 constant NUM_ELEMENTS_COMM = 2; // uint256 elements for curve points - uint256 constant NUM_ELEMENTS_FR = 1; // uint256 elements for field elements - uint256 constant NUM_LIBRA_EVALUATIONS = 4; // libra evaluations - - // Calculate proof size based on log_n (matching UltraKeccakZKFlavor formula) - function calculateProofSize(uint256 logN) internal pure returns (uint256) { - // Witness and Libra commitments - uint256 proofLength = NUM_WITNESS_ENTITIES * NUM_ELEMENTS_COMM; // witness commitments - proofLength += NUM_ELEMENTS_COMM * 3; // Libra concat, grand sum, quotient comms + Gemini masking - - // Sumcheck - proofLength += logN * ZK_BATCHED_RELATION_PARTIAL_LENGTH * NUM_ELEMENTS_FR; // sumcheck univariates - proofLength += NUMBER_OF_ENTITIES_ZK * NUM_ELEMENTS_FR; // sumcheck evaluations - - // Libra and Gemini - proofLength += NUM_ELEMENTS_FR * 2; // Libra sum, claimed eval - proofLength += logN * NUM_ELEMENTS_FR; // Gemini a evaluations - proofLength += NUM_LIBRA_EVALUATIONS * NUM_ELEMENTS_FR; // libra evaluations - - // PCS commitments - proofLength += (logN - 1) * NUM_ELEMENTS_COMM; // Gemini Fold commitments - proofLength += NUM_ELEMENTS_COMM * 2; // Shplonk Q and KZG W commitments - - // Pairing points - proofLength += PAIRING_POINTS_SIZE; // pairing inputs carried on public inputs - - return proofLength; - } - - uint256 constant SHIFTED_COMMITMENTS_START = 30; - - function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory); - - function verify(bytes calldata proof, bytes32[] calldata publicInputs) - public - view - override - returns (bool verified) - { - // Calculate expected proof size based on $LOG_N - uint256 expectedProofSize = calculateProofSize($LOG_N); - - // Check the received proof is the expected size where each field element is 32 bytes - if (proof.length != expectedProofSize * 32) { - revert ProofLengthWrongWithLogN($LOG_N, proof.length, expectedProofSize * 32); - } - - Honk.VerificationKey memory vk = loadVerificationKey(); - Honk.ZKProof memory p = ZKTranscriptLib.loadProof(proof, $LOG_N); - - if (publicInputs.length != vk.publicInputsSize - PAIRING_POINTS_SIZE) { - revert PublicInputsLengthWrong(); - } - - // Generate the fiat shamir challenges for the whole protocol - ZKTranscript memory t = - ZKTranscriptLib.generateTranscript(p, publicInputs, $VK_HASH, $NUM_PUBLIC_INPUTS, $LOG_N); - - // Derive public input delta - t.relationParameters.publicInputsDelta = computePublicInputDelta( - publicInputs, - p.pairingPointObject, - t.relationParameters.beta, - t.relationParameters.gamma, /*pubInputsOffset=*/ - 1 - ); - - // Sumcheck - if (!verifySumcheck(p, t)) revert SumcheckFailed(); - - if (!verifyShplemini(p, vk, t)) revert ShpleminiFailed(); - - verified = true; - } - - uint256 constant PERMUTATION_ARGUMENT_VALUE_SEPARATOR = 1 << 28; - - function computePublicInputDelta( - bytes32[] memory publicInputs, - Fr[PAIRING_POINTS_SIZE] memory pairingPointObject, - Fr beta, - Fr gamma, - uint256 offset - ) internal view returns (Fr publicInputDelta) { - Fr numerator = Fr.wrap(1); - Fr denominator = Fr.wrap(1); - - Fr numeratorAcc = gamma + (beta * FrLib.from(PERMUTATION_ARGUMENT_VALUE_SEPARATOR + offset)); - Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); - - { - for (uint256 i = 0; i < $NUM_PUBLIC_INPUTS - PAIRING_POINTS_SIZE; i++) { - Fr pubInput = FrLib.fromBytes32(publicInputs[i]); - - numerator = numerator * (numeratorAcc + pubInput); - denominator = denominator * (denominatorAcc + pubInput); - - numeratorAcc = numeratorAcc + beta; - denominatorAcc = denominatorAcc - beta; - } - - for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { - Fr pubInput = pairingPointObject[i]; - - numerator = numerator * (numeratorAcc + pubInput); - denominator = denominator * (denominatorAcc + pubInput); - - numeratorAcc = numeratorAcc + beta; - denominatorAcc = denominatorAcc - beta; - } - } - - // Fr delta = numerator / denominator; // TOOO: batch invert later? - publicInputDelta = FrLib.div(numerator, denominator); - } - - function verifySumcheck(Honk.ZKProof memory proof, ZKTranscript memory tp) internal view returns (bool verified) { - Fr roundTargetSum = tp.libraChallenge * proof.libraSum; // default 0 - Fr powPartialEvaluation = Fr.wrap(1); - - // We perform sumcheck reductions over log n rounds ( the multivariate degree ) - for (uint256 round; round < $LOG_N; ++round) { - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate = proof.sumcheckUnivariates[round]; - Fr totalSum = roundUnivariate[0] + roundUnivariate[1]; - if (totalSum != roundTargetSum) revert SumcheckFailed(); - - Fr roundChallenge = tp.sumCheckUChallenges[round]; - - // Update the round target for the next rounf - roundTargetSum = computeNextTargetSum(roundUnivariate, roundChallenge); - powPartialEvaluation = - powPartialEvaluation * (Fr.wrap(1) + roundChallenge * (tp.gateChallenges[round] - Fr.wrap(1))); - } - - // Last round - // For ZK flavors: sumcheckEvaluations has 42 elements - // Index 0 is gemini_masking_poly, indices 1-41 are the regular entities used in relations - Fr[NUMBER_OF_ENTITIES] memory relationsEvaluations; - for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { - relationsEvaluations[i] = proof.sumcheckEvaluations[i + NUM_MASKING_POLYNOMIALS]; // Skip gemini_masking_poly at index 0 - } - Fr grandHonkRelationSum = RelationsLib.accumulateRelationEvaluations( - relationsEvaluations, tp.relationParameters, tp.alphas, powPartialEvaluation - ); - - Fr evaluation = Fr.wrap(1); - for (uint256 i = 2; i < $LOG_N; i++) { - evaluation = evaluation * tp.sumCheckUChallenges[i]; - } - - grandHonkRelationSum = - grandHonkRelationSum * (Fr.wrap(1) - evaluation) + proof.libraEvaluation * tp.libraChallenge; - verified = (grandHonkRelationSum == roundTargetSum); - } - - // Return the new target sum for the next sumcheck round - function computeNextTargetSum(Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, Fr roundChallenge) - internal - view - returns (Fr targetSum) - { - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [ - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51), - Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31), - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000000240), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31), - Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51), - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80) - ]; - - // To compute the next target sum, we evaluate the given univariate at a point u (challenge). - - // Performing Barycentric evaluations - // Compute B(x) - Fr numeratorValue = Fr.wrap(1); - for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) { - numeratorValue = numeratorValue * (roundChallenge - Fr.wrap(i)); - } - - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory denominatorInverses; - for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) { - denominatorInverses[i] = FrLib.invert(BARYCENTRIC_LAGRANGE_DENOMINATORS[i] * (roundChallenge - Fr.wrap(i))); - } - - for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) { - targetSum = targetSum + roundUnivariates[i] * denominatorInverses[i]; - } - - // Scale the sum by the value of B(x) - targetSum = targetSum * numeratorValue; - } - - uint256 constant LIBRA_COMMITMENTS = 3; - uint256 constant LIBRA_EVALUATIONS = 4; - uint256 constant LIBRA_UNIVARIATES_LENGTH = 9; - - struct PairingInputs { - Honk.G1Point P_0; - Honk.G1Point P_1; - } - - function verifyShplemini(Honk.ZKProof memory proof, Honk.VerificationKey memory vk, ZKTranscript memory tp) - internal - view - returns (bool verified) - { - CommitmentSchemeLib.ShpleminiIntermediates memory mem; // stack - - // - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size - Fr[] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR, $LOG_N); - // Arrays hold values that will be linearly combined for the gemini and shplonk batch openings - Fr[] memory scalars = new Fr[]($MSMSize); - Honk.G1Point[] memory commitments = new Honk.G1Point[]($MSMSize); - - mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); - mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); - - mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator); - mem.shiftedScalar = - tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator)); - - scalars[0] = Fr.wrap(1); - commitments[0] = proof.shplonkQ; - - /* Batch multivariate opening claims, shifted and unshifted - * The vector of scalars is populated as follows: - * \f[ - * \left( - * - \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), - * \ldots, - * - \rho^{i+k-1} \times \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), - * - \rho^{i+k} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right), - * \ldots, - * - \rho^{k+m-1} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right) - * \right) - * \f] - * - * The following vector is concatenated to the vector of commitments: - * \f[ - * f_0, \ldots, f_{m-1}, f_{\text{shift}, 0}, \ldots, f_{\text{shift}, k-1} - * \f] - * - * Simultaneously, the evaluation of the multilinear polynomial - * \f[ - * \sum \rho^i \cdot f_i + \sum \rho^{i+k} \cdot f_{\text{shift}, i} - * \f] - * at the challenge point \f$ (u_0,\ldots, u_{n-1}) \f$ is computed. - * - * This approach minimizes the number of iterations over the commitments to multilinear polynomials - * and eliminates the need to store the powers of \f$ \rho \f$. - */ - // For ZK flavors: evaluations array is [gemini_masking_poly, qm, qc, ql, qr, ...] - // Start batching challenge at 1, not rho, to match non-ZK pattern - mem.batchingChallenge = Fr.wrap(1); - mem.batchedEvaluation = Fr.wrap(0); - - mem.unshiftedScalarNeg = mem.unshiftedScalar.neg(); - mem.shiftedScalarNeg = mem.shiftedScalar.neg(); - - // Process all NUMBER_UNSHIFTED_ZK evaluations (includes gemini_masking_poly at index 0) - for (uint256 i = 1; i <= NUMBER_UNSHIFTED_ZK; ++i) { - scalars[i] = mem.unshiftedScalarNeg * mem.batchingChallenge; - mem.batchedEvaluation = mem.batchedEvaluation - + (proof.sumcheckEvaluations[i - NUM_MASKING_POLYNOMIALS] * mem.batchingChallenge); - mem.batchingChallenge = mem.batchingChallenge * tp.rho; - } - // g commitments are accumulated at r - // For each of the to be shifted commitments perform the shift in place by - // adding to the unshifted value. - // We do so, as the values are to be used in batchMul later, and as - // `a * c + b * c = (a + b) * c` this will allow us to reduce memory and compute. - // Applied to w1, w2, w3, w4 and zPerm - for (uint256 i = 0; i < NUMBER_TO_BE_SHIFTED; ++i) { - uint256 scalarOff = i + SHIFTED_COMMITMENTS_START; - uint256 evaluationOff = i + NUMBER_UNSHIFTED_ZK; - - scalars[scalarOff] = scalars[scalarOff] + (mem.shiftedScalarNeg * mem.batchingChallenge); - mem.batchedEvaluation = - mem.batchedEvaluation + (proof.sumcheckEvaluations[evaluationOff] * mem.batchingChallenge); - mem.batchingChallenge = mem.batchingChallenge * tp.rho; - } - - commitments[1] = proof.geminiMaskingPoly; - - commitments[2] = vk.qm; - commitments[3] = vk.qc; - commitments[4] = vk.ql; - commitments[5] = vk.qr; - commitments[6] = vk.qo; - commitments[7] = vk.q4; - commitments[8] = vk.qLookup; - commitments[9] = vk.qArith; - commitments[10] = vk.qDeltaRange; - commitments[11] = vk.qElliptic; - commitments[12] = vk.qMemory; - commitments[13] = vk.qNnf; - commitments[14] = vk.qPoseidon2External; - commitments[15] = vk.qPoseidon2Internal; - commitments[16] = vk.s1; - commitments[17] = vk.s2; - commitments[18] = vk.s3; - commitments[19] = vk.s4; - commitments[20] = vk.id1; - commitments[21] = vk.id2; - commitments[22] = vk.id3; - commitments[23] = vk.id4; - commitments[24] = vk.t1; - commitments[25] = vk.t2; - commitments[26] = vk.t3; - commitments[27] = vk.t4; - commitments[28] = vk.lagrangeFirst; - commitments[29] = vk.lagrangeLast; - - // Accumulate proof points - commitments[30] = proof.w1; - commitments[31] = proof.w2; - commitments[32] = proof.w3; - commitments[33] = proof.w4; - commitments[34] = proof.zPerm; - commitments[35] = proof.lookupInverses; - commitments[36] = proof.lookupReadCounts; - commitments[37] = proof.lookupReadTags; - - /* Batch gemini claims from the prover - * place the commitments to gemini aᵢ to the vector of commitments, compute the contributions from - * aᵢ(−r²ⁱ) for i=1, … , n−1 to the constant term accumulator, add corresponding scalars - * - * 1. Moves the vector - * \f[ - * \left( \text{com}(A_1), \text{com}(A_2), \ldots, \text{com}(A_{n-1}) \right) - * \f] - * to the 'commitments' vector. - * - * 2. Computes the scalars: - * \f[ - * \frac{\nu^{2}}{z + r^2}, \frac{\nu^3}{z + r^4}, \ldots, \frac{\nu^{n-1}}{z + r^{2^{n-1}}} - * \f] - * and places them into the 'scalars' vector. - * - * 3. Accumulates the summands of the constant term: - * \f[ - * \sum_{i=2}^{n-1} \frac{\nu^{i} \cdot A_i(-r^{2^i})}{z + r^{2^i}} - * \f] - * and adds them to the 'constant_term_accumulator'. - */ - - // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: - // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., $LOG_N - 1 - Fr[] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations( - tp.sumCheckUChallenges, - mem.batchedEvaluation, - proof.geminiAEvaluations, - powers_of_evaluation_challenge, - $LOG_N - ); - - mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; - mem.constantTermAccumulator = - mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); - - mem.batchingChallenge = tp.shplonkNu.sqr(); - uint256 boundary = NUMBER_UNSHIFTED_ZK + 1; - - // Compute Shplonk constant term contributions from Aₗ(± r^{2ˡ}) for l = 1, ..., m-1; - // Compute scalar multipliers for each fold commitment - for (uint256 i = 0; i < $LOG_N - 1; ++i) { - bool dummy_round = i >= ($LOG_N - 1); - - if (!dummy_round) { - // Update inverted denominators - mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); - mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); - - // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ] - mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; - mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; - scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); - - // Accumulate the const term contribution given by - // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l}) - Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; - accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; - mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; - } - // Update the running power of v - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; - - commitments[boundary + i] = proof.geminiFoldComms[i]; - } - - boundary += $LOG_N - 1; - - // Finalize the batch opening claim - mem.denominators[0] = Fr.wrap(1).div(tp.shplonkZ - tp.geminiR); - mem.denominators[1] = Fr.wrap(1).div(tp.shplonkZ - SUBGROUP_GENERATOR * tp.geminiR); - mem.denominators[2] = mem.denominators[0]; - mem.denominators[3] = mem.denominators[0]; - - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; - for (uint256 i = 0; i < LIBRA_EVALUATIONS; i++) { - Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge; - mem.batchingScalars[i] = scalingFactor.neg(); - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; - mem.constantTermAccumulator = mem.constantTermAccumulator + scalingFactor * proof.libraPolyEvals[i]; - } - scalars[boundary] = mem.batchingScalars[0]; - scalars[boundary + 1] = mem.batchingScalars[1] + mem.batchingScalars[2]; - scalars[boundary + 2] = mem.batchingScalars[3]; - - for (uint256 i = 0; i < LIBRA_COMMITMENTS; i++) { - commitments[boundary++] = proof.libraCommitments[i]; - } - - commitments[boundary] = Honk.G1Point({x: 1, y: 2}); - scalars[boundary++] = mem.constantTermAccumulator; - - if (!checkEvalsConsistency(proof.libraPolyEvals, tp.geminiR, tp.sumCheckUChallenges, proof.libraEvaluation)) { - revert ConsistencyCheckFailed(); - } - - Honk.G1Point memory quotient_commitment = proof.kzgQuotient; - - commitments[boundary] = quotient_commitment; - scalars[boundary] = tp.shplonkZ; // evaluation challenge - - PairingInputs memory pair; - pair.P_0 = batchMul(commitments, scalars); - pair.P_1 = negateInplace(quotient_commitment); - - // Aggregate pairing points - Fr recursionSeparator = generateRecursionSeparator(proof.pairingPointObject, pair.P_0, pair.P_1); - (Honk.G1Point memory P_0_other, Honk.G1Point memory P_1_other) = - convertPairingPointsToG1(proof.pairingPointObject); - - // Validate the points from the proof are on the curve - validateOnCurve(P_0_other); - validateOnCurve(P_1_other); - - // accumulate with aggregate points in proof - pair.P_0 = mulWithSeperator(pair.P_0, P_0_other, recursionSeparator); - pair.P_1 = mulWithSeperator(pair.P_1, P_1_other, recursionSeparator); - - return pairing(pair.P_0, pair.P_1); - } - - struct SmallSubgroupIpaIntermediates { - Fr[SUBGROUP_SIZE] challengePolyLagrange; - Fr challengePolyEval; - Fr lagrangeFirst; - Fr lagrangeLast; - Fr rootPower; - Fr[SUBGROUP_SIZE] denominators; // this has to disappear - Fr diff; - } - - function checkEvalsConsistency( - Fr[LIBRA_EVALUATIONS] memory libraPolyEvals, - Fr geminiR, - Fr[CONST_PROOF_SIZE_LOG_N] memory uChallenges, - Fr libraEval - ) internal view returns (bool check) { - Fr one = Fr.wrap(1); - Fr vanishingPolyEval = geminiR.pow(SUBGROUP_SIZE) - one; - if (vanishingPolyEval == Fr.wrap(0)) { - revert GeminiChallengeInSubgroup(); - } - - SmallSubgroupIpaIntermediates memory mem; - mem.challengePolyLagrange[0] = one; - for (uint256 round = 0; round < $LOG_N; round++) { - uint256 currIdx = 1 + LIBRA_UNIVARIATES_LENGTH * round; - mem.challengePolyLagrange[currIdx] = one; - for (uint256 idx = currIdx + 1; idx < currIdx + LIBRA_UNIVARIATES_LENGTH; idx++) { - mem.challengePolyLagrange[idx] = mem.challengePolyLagrange[idx - 1] * uChallenges[round]; - } - } - - mem.rootPower = one; - mem.challengePolyEval = Fr.wrap(0); - for (uint256 idx = 0; idx < SUBGROUP_SIZE; idx++) { - mem.denominators[idx] = mem.rootPower * geminiR - one; - mem.denominators[idx] = mem.denominators[idx].invert(); - mem.challengePolyEval = mem.challengePolyEval + mem.challengePolyLagrange[idx] * mem.denominators[idx]; - mem.rootPower = mem.rootPower * SUBGROUP_GENERATOR_INVERSE; - } - - Fr numerator = vanishingPolyEval * Fr.wrap(SUBGROUP_SIZE).invert(); - mem.challengePolyEval = mem.challengePolyEval * numerator; - mem.lagrangeFirst = mem.denominators[0] * numerator; - mem.lagrangeLast = mem.denominators[SUBGROUP_SIZE - 1] * numerator; - - mem.diff = mem.lagrangeFirst * libraPolyEvals[2]; - - mem.diff = mem.diff + (geminiR - SUBGROUP_GENERATOR_INVERSE) - * (libraPolyEvals[1] - libraPolyEvals[2] - libraPolyEvals[0] * mem.challengePolyEval); - mem.diff = mem.diff + mem.lagrangeLast * (libraPolyEvals[2] - libraEval) - vanishingPolyEval * libraPolyEvals[3]; - - check = mem.diff == Fr.wrap(0); - } - - // This implementation is the same as above with different constants - function batchMul(Honk.G1Point[] memory base, Fr[] memory scalars) - internal - view - returns (Honk.G1Point memory result) - { - uint256 limit = $MSMSize; - - // Validate all points are on the curve - for (uint256 i = 0; i < limit; ++i) { - validateOnCurve(base[i]); - } - - bool success = true; - assembly { - let free := mload(0x40) - - let count := 0x01 - for {} lt(count, add(limit, 1)) { count := add(count, 1) } { - // Get loop offsets - let base_base := add(base, mul(count, 0x20)) - let scalar_base := add(scalars, mul(count, 0x20)) - - mstore(add(free, 0x40), mload(mload(base_base))) - mstore(add(free, 0x60), mload(add(0x20, mload(base_base)))) - // Add scalar - mstore(add(free, 0x80), mload(scalar_base)) - - success := and(success, staticcall(gas(), 7, add(free, 0x40), 0x60, add(free, 0x40), 0x40)) - // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, free, 0x80, free, 0x40)) - } - - // Return the result - mstore(result, mload(free)) - mstore(add(result, 0x20), mload(add(free, 0x20))) - } - - require(success, ShpleminiFailed()); - } -} - -contract ThresholdDecryptedSharesAggregationBnVerifier is BaseZKHonkVerifier(N, LOG_N, VK_HASH, NUMBER_OF_PUBLIC_INPUTS) { - function loadVerificationKey() internal pure override returns (Honk.VerificationKey memory) { - return HonkVerificationKey.loadVerificationKey(); - } -} diff --git a/packages/enclave-contracts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol b/packages/enclave-contracts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol similarity index 60% rename from packages/enclave-contracts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol rename to packages/enclave-contracts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol index a2b3bc0533..ea737d3870 100644 --- a/packages/enclave-contracts/contracts/verifier/ThresholdDecryptedSharesAggregationModVerifier.sol +++ b/packages/enclave-contracts/contracts/verifier/ThresholdDecryptedSharesAggregationVerifier.sol @@ -7,125 +7,241 @@ pragma solidity >=0.8.21; uint256 constant N = 131072; uint256 constant LOG_N = 17; -uint256 constant NUMBER_OF_PUBLIC_INPUTS = 579; -uint256 constant VK_HASH = 0x0772b20ab0892c5f70111dd5e3e9737a04e02129d3f48fbd7a1079f68d41c3de; +uint256 constant NUMBER_OF_PUBLIC_INPUTS = 418; +uint256 constant VK_HASH = 0x1a888222f07de9fba8c8456b3e25b3abe8f5a37ba2fb1cb1e5c24a19dcb8977f; library HonkVerificationKey { - function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { + function loadVerificationKey() + internal + pure + returns (Honk.VerificationKey memory) + { Honk.VerificationKey memory vk = Honk.VerificationKey({ circuitSize: uint256(131072), logCircuitSize: uint256(17), - publicInputsSize: uint256(579), - ql: Honk.G1Point({ - x: uint256(0x2d8eb0ef0769af9b60944c9c1f9aef88f4458599d8d53d5700e57c463d3d2481), - y: uint256(0x067d884aca949978f4410a65ef7addb04f9e8a13536c428fbe9d71beb988a321) + publicInputsSize: uint256(418), + ql: Honk.G1Point({ + x: uint256( + 0x2c0c47eac6980c002be7c5f4633a8bd6d5d0fc9e6651e541b141fc02557ca48d + ), + y: uint256( + 0x1ca159a1bbe1a8c82eb796fba79bcdff36d3fb98c986996878fdf102d6a12ab9 + ) }), - qr: Honk.G1Point({ - x: uint256(0x04f478772f21c19f23074f73f4cafc722ade3b71fd3e674504df4d488e70844f), - y: uint256(0x256ede28a442453cee32d59a1ae23e10ad9765b8cd5aa917f613437e401d03df) + qr: Honk.G1Point({ + x: uint256( + 0x1c05ee47a359c77501f8bb557929e27f64523630d83a818cd364994cadcaf8c5 + ), + y: uint256( + 0x2f8e9947f0eab4542b5e684bbc807466bc192c42d7fce467125769936b4536f5 + ) }), - qo: Honk.G1Point({ - x: uint256(0x296c0719e6414ccc762949a1eb297b40c46b886179cf2ba5d3660b218aa9a728), - y: uint256(0x219d51db4d209022eaa607152a2ddc23b94fb99be6ed4b2f158ed46b21faceb8) + qo: Honk.G1Point({ + x: uint256( + 0x082a6fc7457baf2a604ae295f701031e54ede6a34d88f93f5e7aaeb2a2133121 + ), + y: uint256( + 0x20ecb56a891971bc2cf9bc98cdc00fc8ec720de344999055300f979e749ec93d + ) }), - q4: Honk.G1Point({ - x: uint256(0x0cf55eebb61a0e90c6f9fd68c4839012c6433b88fafff66701ab99c6975e6da3), - y: uint256(0x1f44b9a9447265fad2e8c326a3cfd26d434ed9eece6c2d5b5586f8232572d765) + q4: Honk.G1Point({ + x: uint256( + 0x265c425247eed132b40b111b5a7c14d7d9db56aefbf71eeec0b2cc09dd66a6b3 + ), + y: uint256( + 0x3054e4ee825da9852d2fc5172b24c4ffbdfd315f13fce4b498379c566604897e + ) }), - qm: Honk.G1Point({ - x: uint256(0x3046224394ac0664c5df0bbff473db8485b523993c3378b647785875fbda56e5), - y: uint256(0x075b8449cf262130cd0d53747c76da002a74053958060ee7c8e930b7f729af4e) + qm: Honk.G1Point({ + x: uint256( + 0x13637737c33db244a3712ce1f84f4a6400935882acd540419ff5fc19166ea618 + ), + y: uint256( + 0x15e894c35784b66acc688f1d787868569692c5761fa71b84ab52a3b2c1dd41a8 + ) }), - qc: Honk.G1Point({ - x: uint256(0x23f894967a8d0ad87a02976c74accf68659348a280e6c1ab3f99dad7b8cf4bc4), - y: uint256(0x21acfe5f2f788aee6ca1b87420abfb1b567605edbfc9de6cbff67aa99eb633b8) + qc: Honk.G1Point({ + x: uint256( + 0x16daf8e28d24b787f5a311fc0930d1d495f74cb0eba1780ae0d36610a1ab5870 + ), + y: uint256( + 0x220aa4f565987b5544214f4aa9477fd03cbb82e8a57a2aeaa21968038c2af3a5 + ) }), - qLookup: Honk.G1Point({ - x: uint256(0x11beb2731ab8cf46c0a52666bb457fa74d4b635043bb5689a35a2aee24990b80), - y: uint256(0x2f1fba989036c44aedb609d0d3341ccb842c2d1cd7c80cea4a95d0eb45305770) + qLookup: Honk.G1Point({ + x: uint256( + 0x163a3285e23ec78bb34d3c6122f47c770ee1f228ed2dda996542bade7a8bc2e4 + ), + y: uint256( + 0x188245f34ba632acb17885f4be308c9551dbfd5095069e7077281d144e55044b + ) }), - qArith: Honk.G1Point({ - x: uint256(0x2d70068023998c277c75458b7b6eb1fe3c479eb044dec7aa3384d7b5049542c7), - y: uint256(0x10af4b4ffb3c03f9c906e4dd1cf3c21dc74139881dfa7ad73c25370424f39781) + qArith: Honk.G1Point({ + x: uint256( + 0x1913712d01550fa30bf15a28a13902738529edfc1ddc730c5bc57c00514fd3b4 + ), + y: uint256( + 0x1f125db8f6315e55f2b20ba6863482eac90d77f6c6289efb0d6a6c740be172cd + ) }), - qDeltaRange: Honk.G1Point({ - x: uint256(0x0d07902b3266cd4af955bac93e3579b0bc1bcd754c7b70035cc95877d641376c), - y: uint256(0x195d808eeb35965b8df7ea80461dcc033e5d8d0ef25b028a1d429e52b33f3f0d) + qDeltaRange: Honk.G1Point({ + x: uint256( + 0x26ce5fb2dc4d867f0f6957729e6158fe7d6924445514b4c485f0b093195cff48 + ), + y: uint256( + 0x102d0d1aa8a400a6f7e233d512ed7205fcb3eb0ba5c0d54041f23b25f58a4c57 + ) }), - qElliptic: Honk.G1Point({ - x: uint256(0x2656809e98f3dee7945c4f48c6fff3c0833412aeeae84dada472462112fa8fe9), - y: uint256(0x2454353d981df4ae6c3fd37c4a7b5114bcb1416f43efc627d55e128449c7c14d) + qElliptic: Honk.G1Point({ + x: uint256( + 0x1a08892e26c7c33a003d075a86a9edd8cdf253009e26fa7b2ac7f4339ca07ce3 + ), + y: uint256( + 0x09383a35fb9f67045a070c939b0d947454f64cd92bcf90838b2163bc0e071b58 + ) }), - qMemory: Honk.G1Point({ - x: uint256(0x24ec1ac19b9f052e9e2c4270db9b317502859b163514073401512c6753188238), - y: uint256(0x28869fd3c9b2ad1ce8a966e9225bed7eac600c656be6891317404dc447267367) + qMemory: Honk.G1Point({ + x: uint256( + 0x0ff4dd20d4821b5ca6738a69881d693c04c892bade4b929a311c6612d94ffbc2 + ), + y: uint256( + 0x19fcce46268bf02b94f4486494e361d2c126372f35e0583d55825134c2ee88cc + ) }), - qNnf: Honk.G1Point({ - x: uint256(0x201e0e19e72484d21e8136546fe6aaeea2d5b6413019276eada6638ffeb2ce8a), - y: uint256(0x00ba5238e406d8d46f68dc3b00a201ad10d2dc97beed32f5e83d051e742b2642) + qNnf: Honk.G1Point({ + x: uint256( + 0x018d6d017a26c5c223931a63ee8ad0ef37f9f9f0caba099d8d8482e95b6f46e8 + ), + y: uint256( + 0x0ed38b925edf5f9b54e2b5289074d64999010264d2a4eae8fc53b8e38fc10b6b + ) }), - qPoseidon2External: Honk.G1Point({ - x: uint256(0x1fb5e9c3ae41ba815444512a4e882619ac69f0cbb639657adeadb93ed50895b1), - y: uint256(0x201d42c30be1a478f6c6a28159a335c02fa3dc3e6c6843089c648bfd4dc8c250) + qPoseidon2External: Honk.G1Point({ + x: uint256( + 0x0d2f53319bc2e321ef88e47d0a3a35b0f35728ed7b7790dd357ecda4ea55a57b + ), + y: uint256( + 0x074497f78eec311b533ca170dc19e81c0cf5a22dce7bdf938841ff71e8cbdc8d + ) }), - qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x1375207e60c7d651a62aed70d2496e2324a7dc718de86e5887f805f907d49640), - y: uint256(0x22a964f903d1faa46e20c6f8902415d61985c86bbeef23a01b6ca1718dfe80c5) + qPoseidon2Internal: Honk.G1Point({ + x: uint256( + 0x0cde2682ddd264dcac5b0e5626164271411bca898cd8beb4c98536534ffe3e69 + ), + y: uint256( + 0x20f8bfa3f9ed612f481072d20715601f08415ecbb5092b8dae96a15c583ac770 + ) }), - s1: Honk.G1Point({ - x: uint256(0x2a38162537d04323884347c1f31f76b03a04ec2f6f9c4b125d5d322932ff65ba), - y: uint256(0x2465da5aac067658f2f98944a8ba1bc9fd81c2220d22f07995746a7b7deccd29) + s1: Honk.G1Point({ + x: uint256( + 0x2dc45f069a801ce507391a5d369024e6c0a8f508426efa10efec079f652943fd + ), + y: uint256( + 0x0ca193ecd89783532ab900689868dfa9713a57dd313c222bfa2d1ee92c5a1ec9 + ) }), - s2: Honk.G1Point({ - x: uint256(0x2a12695e6fa7a23c3519eee6d96433bb00d51cd274de90288914e3fb336334b6), - y: uint256(0x235e728947aff729c4ade5a63ca501273a958075ae1281bb612012f032196016) + s2: Honk.G1Point({ + x: uint256( + 0x18f0b7ba3135bb08f1e312928b750b6bacb9776a9e8a3d30d1da58873083baa6 + ), + y: uint256( + 0x1ed01d844f4aee867147b3eb571130d0e37c0686151a13106aeb40936713c093 + ) }), - s3: Honk.G1Point({ - x: uint256(0x09e5efa8f84174e74fe0429a76ec404c053a4f8c3e5524d68e3cd4e338a2b4b8), - y: uint256(0x057873d3cf1d8589310604f6f203386d9a9928d980432f5316522d84e6eecb61) + s3: Honk.G1Point({ + x: uint256( + 0x2787d437215fba393c1bb6e8bc91cdf1f5c75cb93b1eb8b522819a6cfc71507c + ), + y: uint256( + 0x027ea99429a3d006c4d01411577bf6ac562f7811b4d64e7ff060351468d63b6b + ) }), - s4: Honk.G1Point({ - x: uint256(0x096a6fb164d4a53c869c12d0369ef747bbbd3f40e5dd997c01e32495b64b07cb), - y: uint256(0x01198ac63b80d1d160ab5882da3dfc3a8864b70b72c31790e55fec5014c44362) + s4: Honk.G1Point({ + x: uint256( + 0x0d0f4f0fa40d68989657a0feee08deed1f08355b066c778578bfbf430cc2d22b + ), + y: uint256( + 0x2d9d81c8732bf6991afa6657818d09e17fe8bfb40f59301a7b992fc8f2a9d1e9 + ) }), - t1: Honk.G1Point({ - x: uint256(0x099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d26), - y: uint256(0x0015b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f) + t1: Honk.G1Point({ + x: uint256( + 0x099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d26 + ), + y: uint256( + 0x0015b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f + ) }), - t2: Honk.G1Point({ - x: uint256(0x1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e), - y: uint256(0x305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d19) + t2: Honk.G1Point({ + x: uint256( + 0x1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e + ), + y: uint256( + 0x305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d19 + ) }), - t3: Honk.G1Point({ - x: uint256(0x061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d), - y: uint256(0x1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e) + t3: Honk.G1Point({ + x: uint256( + 0x061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d + ), + y: uint256( + 0x1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e + ) }), - t4: Honk.G1Point({ - x: uint256(0x043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce), - y: uint256(0x261522c4089330646aff96736194949330952ae74c573d1686d9cb4a00733854) + t4: Honk.G1Point({ + x: uint256( + 0x043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce + ), + y: uint256( + 0x261522c4089330646aff96736194949330952ae74c573d1686d9cb4a00733854 + ) }), - id1: Honk.G1Point({ - x: uint256(0x085cbd5bb5a6a7a0407ad624e78b82be37c9c90a9c5de9302004bc406bc1778d), - y: uint256(0x2a4cbd271054bf508c73ffeab6e321bba811248126e552f55701993aed192e4b) + id1: Honk.G1Point({ + x: uint256( + 0x00a673368cf560b1069debee688c082cda349df8fbacc711f845dc7960acdeba + ), + y: uint256( + 0x0234d1b5f65d17aaf71d51ae744b28b6a024bface3333ea19ef58c8c2fc38595 + ) }), - id2: Honk.G1Point({ - x: uint256(0x1a89bfbff2ee55715a55cf0de0d6a1c62183bbaae9d200a5247b58f170cbbc7c), - y: uint256(0x0ae77530f6cad79672428f376996a91ce1358fea5f49180218f18a7918f80bb3) + id2: Honk.G1Point({ + x: uint256( + 0x29353e7eeeae9d8cf7bc6bac6961a44a69fe7b38396fc4b07d416b226fbecc3d + ), + y: uint256( + 0x012d0615aad587261d1403ca95322f67b6e64382ac7346503bb61ee8ff465ffd + ) }), - id3: Honk.G1Point({ - x: uint256(0x1faa95912a219c90e3cdbe1e78b25d6f79d4ca8ef1cd9fd3a8a6b87f94d138f2), - y: uint256(0x22a4b4a860838e96fcc07839e0c9742c2dbe4aa634664da1e24570a1dc4156fd) + id3: Honk.G1Point({ + x: uint256( + 0x0dddb0066cbe44ac884fe3658ad6c24943d3329fd839b8dd47b37e0b334f3efc + ), + y: uint256( + 0x1a54ecfb49945a189bd28fa28103f9ad98d08107f8d68167d96417d95297903f + ) }), - id4: Honk.G1Point({ - x: uint256(0x1d11efcd01d1170fc229d305654298122dd323cc9ae7e16ad2f0bfa56a0f9e2e), - y: uint256(0x225cd914fa8180a343e93ee8a0e87e2d850b8ca6e03267e5281f7ace3dd82ab5) + id4: Honk.G1Point({ + x: uint256( + 0x271c4df54fa64ddca42889abf3e4559c2aa59525ea5a1858fadae4b6eb6f1406 + ), + y: uint256( + 0x06f10a564e9397fc800ffbb6b4c887df1d1e4eeb6dd8cd4f789916e31836f197 + ) }), - lagrangeFirst: Honk.G1Point({ - x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), - y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) + lagrangeFirst: Honk.G1Point({ + x: uint256( + 0x0000000000000000000000000000000000000000000000000000000000000001 + ), + y: uint256( + 0x0000000000000000000000000000000000000000000000000000000000000002 + ) }), - lagrangeLast: Honk.G1Point({ - x: uint256(0x1af84073758283d4c848fed9bc6f055831baf81a643050fceafadf8da1791eec), - y: uint256(0x1be165956a9c6a29edc2a4d21793a6fb1f00a6967720f870ebb2f2c6b267e9dd) + lagrangeLast: Honk.G1Point({ + x: uint256( + 0x0602bc9d2460bf21b73d27154ff5f8919350545f3cb6dc7f40dae014613bc4c6 + ), + y: uint256( + 0x1df576b5b16064433355e8bad62265096027978ab6496527059305dbd8708565 + ) }) }); return vk; @@ -135,24 +251,31 @@ library HonkVerificationKey { pragma solidity ^0.8.27; interface IVerifier { - function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external returns (bool); + function verify( + bytes calldata _proof, + bytes32[] calldata _publicInputs + ) external returns (bool); } type Fr is uint256; -using {add as +} for Fr global; -using {sub as -} for Fr global; -using {mul as *} for Fr global; +using { add as + } for Fr global; +using { sub as - } for Fr global; +using { mul as * } for Fr global; -using {exp as ^} for Fr global; -using {notEqual as !=} for Fr global; -using {equal as ==} for Fr global; +using { exp as ^ } for Fr global; +using { notEqual as != } for Fr global; +using { equal as == } for Fr global; uint256 constant SUBGROUP_SIZE = 256; uint256 constant MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order uint256 constant P = MODULUS; -Fr constant SUBGROUP_GENERATOR = Fr.wrap(0x07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76); -Fr constant SUBGROUP_GENERATOR_INVERSE = Fr.wrap(0x204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6); +Fr constant SUBGROUP_GENERATOR = Fr.wrap( + 0x07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76 +); +Fr constant SUBGROUP_GENERATOR_INVERSE = Fr.wrap( + 0x204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6 +); Fr constant MINUS_ONE = Fr.wrap(MODULUS - 1); Fr constant ONE = Fr.wrap(1); Fr constant ZERO = Fr.wrap(0); @@ -298,9 +421,11 @@ uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9; uint256 constant NUMBER_OF_ENTITIES = 41; // The number of entities added for ZK (gemini_masking_poly) uint256 constant NUM_MASKING_POLYNOMIALS = 1; -uint256 constant NUMBER_OF_ENTITIES_ZK = NUMBER_OF_ENTITIES + NUM_MASKING_POLYNOMIALS; +uint256 constant NUMBER_OF_ENTITIES_ZK = NUMBER_OF_ENTITIES + + NUM_MASKING_POLYNOMIALS; uint256 constant NUMBER_UNSHIFTED = 36; -uint256 constant NUMBER_UNSHIFTED_ZK = NUMBER_UNSHIFTED + NUM_MASKING_POLYNOMIALS; +uint256 constant NUMBER_UNSHIFTED_ZK = NUMBER_UNSHIFTED + + NUM_MASKING_POLYNOMIALS; uint256 constant NUMBER_TO_BE_SHIFTED = 5; uint256 constant PAIRING_POINTS_SIZE = 16; @@ -496,26 +621,63 @@ library ZKTranscriptLib { uint256 logN ) external pure returns (ZKTranscript memory t) { Fr previousChallenge; - (t.relationParameters, previousChallenge) = - generateRelationParametersChallenges(proof, publicInputs, vkHash, publicInputsSize, previousChallenge); + ( + t.relationParameters, + previousChallenge + ) = generateRelationParametersChallenges( + proof, + publicInputs, + vkHash, + publicInputsSize, + previousChallenge + ); - (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof); + (t.alphas, previousChallenge) = generateAlphaChallenges( + previousChallenge, + proof + ); - (t.gateChallenges, previousChallenge) = generateGateChallenges(previousChallenge, logN); - (t.libraChallenge, previousChallenge) = generateLibraChallenge(previousChallenge, proof); - (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges(proof, previousChallenge, logN); + (t.gateChallenges, previousChallenge) = generateGateChallenges( + previousChallenge, + logN + ); + (t.libraChallenge, previousChallenge) = generateLibraChallenge( + previousChallenge, + proof + ); + (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges( + proof, + previousChallenge, + logN + ); - (t.rho, previousChallenge) = generateRhoChallenge(proof, previousChallenge); + (t.rho, previousChallenge) = generateRhoChallenge( + proof, + previousChallenge + ); - (t.geminiR, previousChallenge) = generateGeminiRChallenge(proof, previousChallenge, logN); + (t.geminiR, previousChallenge) = generateGeminiRChallenge( + proof, + previousChallenge, + logN + ); - (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge(proof, previousChallenge, logN); + (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge( + proof, + previousChallenge, + logN + ); - (t.shplonkZ, previousChallenge) = generateShplonkZChallenge(proof, previousChallenge); + (t.shplonkZ, previousChallenge) = generateShplonkZChallenge( + proof, + previousChallenge + ); return t; } - function splitChallenge(Fr challenge) internal pure returns (Fr first, Fr second) { + function splitChallenge( + Fr challenge + ) internal pure returns (Fr first, Fr second) { uint256 challengeU256 = uint256(Fr.unwrap(challenge)); // Split into two equal 127-bit chunks (254/2) uint256 lo = challengeU256 & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // 127 bits @@ -530,11 +692,23 @@ library ZKTranscriptLib { uint256 vkHash, uint256 publicInputsSize, Fr previousChallenge - ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { - (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = - generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize); + ) + internal + pure + returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) + { + ( + rp.eta, + rp.etaTwo, + rp.etaThree, + previousChallenge + ) = generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize); - (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); + ( + rp.beta, + rp.gamma, + nextPreviousChallenge + ) = generateBetaAndGammaChallenges(previousChallenge, proof); } function generateEtaChallenge( @@ -542,7 +716,11 @@ library ZKTranscriptLib { bytes32[] calldata publicInputs, uint256 vkHash, uint256 publicInputsSize - ) internal pure returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) { + ) + internal + pure + returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) + { // Size: 1 (vkHash) + publicInputsSize + 8 (geminiMask(2) + 3 wires(6)) bytes32[] memory round0 = new bytes32[](1 + publicInputsSize + 8); round0[0] = bytes32(vkHash); @@ -551,7 +729,8 @@ library ZKTranscriptLib { round0[1 + i] = bytes32(publicInputs[i]); } for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { - round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]); + round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib + .toBytes32(proof.pairingPointObject[i]); } // For ZK flavors: hash the gemini masking poly commitment (sent right after public inputs) @@ -567,18 +746,21 @@ library ZKTranscriptLib { round0[1 + publicInputsSize + 6] = bytes32(proof.w3.x); round0[1 + publicInputsSize + 7] = bytes32(proof.w3.y); - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round0))); + previousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(round0)) + ); (eta, etaTwo) = splitChallenge(previousChallenge); - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))); + previousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))) + ); - (etaThree,) = splitChallenge(previousChallenge); + (etaThree, ) = splitChallenge(previousChallenge); } - function generateBetaAndGammaChallenges(Fr previousChallenge, Honk.ZKProof memory proof) - internal - pure - returns (Fr beta, Fr gamma, Fr nextPreviousChallenge) - { + function generateBetaAndGammaChallenges( + Fr previousChallenge, + Honk.ZKProof memory proof + ) internal pure returns (Fr beta, Fr gamma, Fr nextPreviousChallenge) { bytes32[7] memory round1; round1[0] = FrLib.toBytes32(previousChallenge); round1[1] = bytes32(proof.lookupReadCounts.x); @@ -588,12 +770,17 @@ library ZKTranscriptLib { round1[5] = bytes32(proof.w4.x); round1[6] = bytes32(proof.w4.y); - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round1))); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(round1)) + ); (beta, gamma) = splitChallenge(nextPreviousChallenge); } // Alpha challenges non-linearise the gate contributions - function generateAlphaChallenges(Fr previousChallenge, Honk.ZKProof memory proof) + function generateAlphaChallenges( + Fr previousChallenge, + Honk.ZKProof memory proof + ) internal pure returns (Fr[NUMBER_OF_ALPHAS] memory alphas, Fr nextPreviousChallenge) @@ -606,9 +793,11 @@ library ZKTranscriptLib { alpha0[3] = proof.zPerm.x; alpha0[4] = proof.zPerm.y; - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(alpha0))); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(alpha0)) + ); Fr alpha; - (alpha,) = splitChallenge(nextPreviousChallenge); + (alpha, ) = splitChallenge(nextPreviousChallenge); // Compute powers of alpha for batching subrelations alphas[0] = alpha; @@ -617,38 +806,54 @@ library ZKTranscriptLib { } } - function generateGateChallenges(Fr previousChallenge, uint256 logN) + function generateGateChallenges( + Fr previousChallenge, + uint256 logN + ) internal pure - returns (Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, Fr nextPreviousChallenge) + returns ( + Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, + Fr nextPreviousChallenge + ) { - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))); - (gateChallenges[0],) = splitChallenge(previousChallenge); + previousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))) + ); + (gateChallenges[0], ) = splitChallenge(previousChallenge); for (uint256 i = 1; i < logN; i++) { gateChallenges[i] = gateChallenges[i - 1] * gateChallenges[i - 1]; } nextPreviousChallenge = previousChallenge; } - function generateLibraChallenge(Fr previousChallenge, Honk.ZKProof memory proof) - internal - pure - returns (Fr libraChallenge, Fr nextPreviousChallenge) - { + function generateLibraChallenge( + Fr previousChallenge, + Honk.ZKProof memory proof + ) internal pure returns (Fr libraChallenge, Fr nextPreviousChallenge) { // 2 comm, 1 sum, 1 challenge uint256[4] memory challengeData; challengeData[0] = Fr.unwrap(previousChallenge); challengeData[1] = proof.libraCommitments[0].x; challengeData[2] = proof.libraCommitments[0].y; challengeData[3] = Fr.unwrap(proof.libraSum); - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(challengeData))); - (libraChallenge,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(challengeData)) + ); + (libraChallenge, ) = splitChallenge(nextPreviousChallenge); } - function generateSumcheckChallenges(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) + function generateSumcheckChallenges( + Honk.ZKProof memory proof, + Fr prevChallenge, + uint256 logN + ) internal pure - returns (Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, Fr nextPreviousChallenge) + returns ( + Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, + Fr nextPreviousChallenge + ) { for (uint256 i = 0; i < logN; i++) { Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH + 1] memory univariateChal; @@ -657,24 +862,27 @@ library ZKTranscriptLib { for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) { univariateChal[j + 1] = proof.sumcheckUnivariates[i][j]; } - prevChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(univariateChal))); + prevChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(univariateChal)) + ); - (sumcheckChallenges[i],) = splitChallenge(prevChallenge); + (sumcheckChallenges[i], ) = splitChallenge(prevChallenge); } nextPreviousChallenge = prevChallenge; } // We add Libra claimed eval + 2 libra commitments (grand_sum, quotient) - function generateRhoChallenge(Honk.ZKProof memory proof, Fr prevChallenge) - internal - pure - returns (Fr rho, Fr nextPreviousChallenge) - { + function generateRhoChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge + ) internal pure returns (Fr rho, Fr nextPreviousChallenge) { uint256[NUMBER_OF_ENTITIES_ZK + 6] memory rhoChallengeElements; rhoChallengeElements[0] = Fr.unwrap(prevChallenge); uint256 i; for (i = 1; i <= NUMBER_OF_ENTITIES_ZK; i++) { - rhoChallengeElements[i] = Fr.unwrap(proof.sumcheckEvaluations[i - 1]); + rhoChallengeElements[i] = Fr.unwrap( + proof.sumcheckEvaluations[i - 1] + ); } rhoChallengeElements[i] = Fr.unwrap(proof.libraEvaluation); i += 1; @@ -684,15 +892,17 @@ library ZKTranscriptLib { rhoChallengeElements[i] = proof.libraCommitments[2].x; rhoChallengeElements[i + 1] = proof.libraCommitments[2].y; - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(rhoChallengeElements))); - (rho,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(rhoChallengeElements)) + ); + (rho, ) = splitChallenge(nextPreviousChallenge); } - function generateGeminiRChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) - internal - pure - returns (Fr geminiR, Fr nextPreviousChallenge) - { + function generateGeminiRChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge, + uint256 logN + ) internal pure returns (Fr geminiR, Fr nextPreviousChallenge) { uint256[] memory gR = new uint256[]((logN - 1) * 2 + 1); gR[0] = Fr.unwrap(prevChallenge); @@ -701,59 +911,77 @@ library ZKTranscriptLib { gR[2 + i * 2] = proof.geminiFoldComms[i].y; } - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(gR))); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(gR)) + ); - (geminiR,) = splitChallenge(nextPreviousChallenge); + (geminiR, ) = splitChallenge(nextPreviousChallenge); } - function generateShplonkNuChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) - internal - pure - returns (Fr shplonkNu, Fr nextPreviousChallenge) - { - uint256[] memory shplonkNuChallengeElements = new uint256[](logN + 1 + 4); + function generateShplonkNuChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge, + uint256 logN + ) internal pure returns (Fr shplonkNu, Fr nextPreviousChallenge) { + uint256[] memory shplonkNuChallengeElements = new uint256[]( + logN + 1 + 4 + ); shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge); for (uint256 i = 1; i <= logN; i++) { - shplonkNuChallengeElements[i] = Fr.unwrap(proof.geminiAEvaluations[i - 1]); + shplonkNuChallengeElements[i] = Fr.unwrap( + proof.geminiAEvaluations[i - 1] + ); } uint256 libraIdx = 0; for (uint256 i = logN + 1; i <= logN + 4; i++) { - shplonkNuChallengeElements[i] = Fr.unwrap(proof.libraPolyEvals[libraIdx]); + shplonkNuChallengeElements[i] = Fr.unwrap( + proof.libraPolyEvals[libraIdx] + ); libraIdx++; } - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkNuChallengeElements))); - (shplonkNu,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(shplonkNuChallengeElements)) + ); + (shplonkNu, ) = splitChallenge(nextPreviousChallenge); } - function generateShplonkZChallenge(Honk.ZKProof memory proof, Fr prevChallenge) - internal - pure - returns (Fr shplonkZ, Fr nextPreviousChallenge) - { + function generateShplonkZChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge + ) internal pure returns (Fr shplonkZ, Fr nextPreviousChallenge) { uint256[3] memory shplonkZChallengeElements; shplonkZChallengeElements[0] = Fr.unwrap(prevChallenge); shplonkZChallengeElements[1] = proof.shplonkQ.x; shplonkZChallengeElements[2] = proof.shplonkQ.y; - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkZChallengeElements))); - (shplonkZ,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(shplonkZChallengeElements)) + ); + (shplonkZ, ) = splitChallenge(nextPreviousChallenge); } - function loadProof(bytes calldata proof, uint256 logN) internal pure returns (Honk.ZKProof memory p) { + function loadProof( + bytes calldata proof, + uint256 logN + ) internal pure returns (Honk.ZKProof memory p) { uint256 boundary = 0x0; // Pairing point object for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { - p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.pairingPointObject[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } // Gemini masking polynomial commitment (sent first in ZK flavors, right after pairing points) - p.geminiMaskingPoly = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.geminiMaskingPoly = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; // Commitments @@ -765,17 +993,25 @@ library ZKTranscriptLib { boundary += GROUP_ELEMENT_SIZE; // Lookup / Permutation Helper Commitments - p.lookupReadCounts = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupReadCounts = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; - p.lookupReadTags = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupReadTags = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; p.w4 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); boundary += GROUP_ELEMENT_SIZE; - p.lookupInverses = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupInverses = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; p.zPerm = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); boundary += GROUP_ELEMENT_SIZE; - p.libraCommitments[0] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.libraCommitments[0] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; p.libraSum = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); @@ -783,48 +1019,68 @@ library ZKTranscriptLib { // Sumcheck univariates for (uint256 i = 0; i < logN; i++) { for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) { - p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.sumcheckUnivariates[i][j] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } } // Sumcheck evaluations (includes gemini_masking_poly eval at index 0 for ZK flavors) for (uint256 i = 0; i < NUMBER_OF_ENTITIES_ZK; i++) { - p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.sumcheckEvaluations[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } - p.libraEvaluation = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.libraEvaluation = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; - p.libraCommitments[1] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.libraCommitments[1] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; - p.libraCommitments[2] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.libraCommitments[2] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; // Gemini // Read gemini fold univariates for (uint256 i = 0; i < logN - 1; i++) { - p.geminiFoldComms[i] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.geminiFoldComms[i] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; } // Read gemini a evaluations for (uint256 i = 0; i < logN; i++) { - p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.geminiAEvaluations[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } for (uint256 i = 0; i < 4; i++) { - p.libraPolyEvals[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.libraPolyEvals[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } // Shplonk - p.shplonkQ = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.shplonkQ = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; // KZG - p.kzgQuotient = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.kzgQuotient = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); } } @@ -842,18 +1098,60 @@ library RelationsLib { Fr[NUMBER_OF_SUBRELATIONS] memory evaluations; // Accumulate all relations in Ultra Honk - each with varying number of subrelations - accumulateArithmeticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePermutationRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateLogDerivativeLookupRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateDeltaRangeRelation(purportedEvaluations, evaluations, powPartialEval); - accumulateEllipticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulateMemoryRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateNnfRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval); + accumulateArithmeticRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulatePermutationRelation( + purportedEvaluations, + rp, + evaluations, + powPartialEval + ); + accumulateLogDerivativeLookupRelation( + purportedEvaluations, + rp, + evaluations, + powPartialEval + ); + accumulateDeltaRangeRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulateEllipticRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulateMemoryRelation( + purportedEvaluations, + rp, + evaluations, + powPartialEval + ); + accumulateNnfRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulatePoseidonExternalRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulatePoseidonInternalRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); // batch the subrelations with the precomputed alpha powers to obtain the full honk relation - accumulator = scaleAndBatchSubrelations(evaluations, subrelationChallenges); + accumulator = scaleAndBatchSubrelations( + evaluations, + subrelationChallenges + ); } /** @@ -861,11 +1159,15 @@ library RelationsLib { * the relation checking code being cluttered with uint256 type casting, which is often a different colour in code * editors, and thus is noisy. */ - function wire(Fr[NUMBER_OF_ENTITIES] memory p, WIRE _wire) internal pure returns (Fr) { + function wire( + Fr[NUMBER_OF_ENTITIES] memory p, + WIRE _wire + ) internal pure returns (Fr) { return p[uint256(_wire)]; } - uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; + uint256 internal constant NEG_HALF_MODULO_P = + 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; /** * Ultra Arithmetic Relation * @@ -881,9 +1183,16 @@ library RelationsLib { { Fr neg_half = Fr.wrap(NEG_HALF_MODULO_P); - Fr accum = (q_arith - Fr.wrap(3)) * (wire(p, WIRE.Q_M) * wire(p, WIRE.W_R) * wire(p, WIRE.W_L)) * neg_half; - accum = accum + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R)) - + (wire(p, WIRE.Q_O) * wire(p, WIRE.W_O)) + (wire(p, WIRE.Q_4) * wire(p, WIRE.W_4)) + wire(p, WIRE.Q_C); + Fr accum = (q_arith - Fr.wrap(3)) * + (wire(p, WIRE.Q_M) * wire(p, WIRE.W_R) * wire(p, WIRE.W_L)) * + neg_half; + accum = + accum + + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R)) + + (wire(p, WIRE.Q_O) * wire(p, WIRE.W_O)) + + (wire(p, WIRE.Q_4) * wire(p, WIRE.W_4)) + + wire(p, WIRE.Q_C); accum = accum + (q_arith - ONE) * wire(p, WIRE.W_4_SHIFT); accum = accum * q_arith; accum = accum * domainSep; @@ -892,7 +1201,10 @@ library RelationsLib { // Relation 1 { - Fr accum = wire(p, WIRE.W_L) + wire(p, WIRE.W_4) - wire(p, WIRE.W_L_SHIFT) + wire(p, WIRE.Q_M); + Fr accum = wire(p, WIRE.W_L) + + wire(p, WIRE.W_4) - + wire(p, WIRE.W_L_SHIFT) + + wire(p, WIRE.Q_M); accum = accum * (q_arith - Fr.wrap(2)); accum = accum * (q_arith - ONE); accum = accum * q_arith; @@ -911,36 +1223,67 @@ library RelationsLib { Fr grand_product_denominator; { - Fr num = wire(p, WIRE.W_L) + wire(p, WIRE.ID_1) * rp.beta + rp.gamma; - num = num * (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma); - num = num * (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma); - num = num * (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma); + Fr num = wire(p, WIRE.W_L) + + wire(p, WIRE.ID_1) * + rp.beta + + rp.gamma; + num = + num * + (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma); + num = + num * + (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma); + num = + num * + (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma); grand_product_numerator = num; } { - Fr den = wire(p, WIRE.W_L) + wire(p, WIRE.SIGMA_1) * rp.beta + rp.gamma; - den = den * (wire(p, WIRE.W_R) + wire(p, WIRE.SIGMA_2) * rp.beta + rp.gamma); - den = den * (wire(p, WIRE.W_O) + wire(p, WIRE.SIGMA_3) * rp.beta + rp.gamma); - den = den * (wire(p, WIRE.W_4) + wire(p, WIRE.SIGMA_4) * rp.beta + rp.gamma); + Fr den = wire(p, WIRE.W_L) + + wire(p, WIRE.SIGMA_1) * + rp.beta + + rp.gamma; + den = + den * + (wire(p, WIRE.W_R) + + wire(p, WIRE.SIGMA_2) * + rp.beta + + rp.gamma); + den = + den * + (wire(p, WIRE.W_O) + + wire(p, WIRE.SIGMA_3) * + rp.beta + + rp.gamma); + den = + den * + (wire(p, WIRE.W_4) + + wire(p, WIRE.SIGMA_4) * + rp.beta + + rp.gamma); grand_product_denominator = den; } // Contribution 2 { - Fr acc = (wire(p, WIRE.Z_PERM) + wire(p, WIRE.LAGRANGE_FIRST)) * grand_product_numerator; - - acc = acc - - ((wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) - * grand_product_denominator); + Fr acc = (wire(p, WIRE.Z_PERM) + wire(p, WIRE.LAGRANGE_FIRST)) * + grand_product_numerator; + + acc = + acc - + ((wire(p, WIRE.Z_PERM_SHIFT) + + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) * + grand_product_denominator); acc = acc * domainSep; evals[2] = acc; } // Contribution 3 { - Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; + Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * + wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; evals[3] = acc; } } @@ -956,33 +1299,52 @@ library RelationsLib { // Calculate the write term (the table accumulation) { - write_term = wire(p, WIRE.TABLE_1) + rp.gamma + (wire(p, WIRE.TABLE_2) * rp.eta) - + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + (wire(p, WIRE.TABLE_4) * rp.etaThree); + write_term = + wire(p, WIRE.TABLE_1) + + rp.gamma + + (wire(p, WIRE.TABLE_2) * rp.eta) + + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + + (wire(p, WIRE.TABLE_4) * rp.etaThree); } // Calculate the write term { - Fr derived_entry_1 = wire(p, WIRE.W_L) + rp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); - Fr derived_entry_2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_M) * wire(p, WIRE.W_R_SHIFT); - Fr derived_entry_3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_C) * wire(p, WIRE.W_O_SHIFT); - - read_term = derived_entry_1 + (derived_entry_2 * rp.eta) + (derived_entry_3 * rp.etaTwo) - + (wire(p, WIRE.Q_O) * rp.etaThree); + Fr derived_entry_1 = wire(p, WIRE.W_L) + + rp.gamma + + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); + Fr derived_entry_2 = wire(p, WIRE.W_R) + + wire(p, WIRE.Q_M) * + wire(p, WIRE.W_R_SHIFT); + Fr derived_entry_3 = wire(p, WIRE.W_O) + + wire(p, WIRE.Q_C) * + wire(p, WIRE.W_O_SHIFT); + + read_term = + derived_entry_1 + + (derived_entry_2 * rp.eta) + + (derived_entry_3 * rp.etaTwo) + + (wire(p, WIRE.Q_O) * rp.etaThree); } Fr read_inverse = wire(p, WIRE.LOOKUP_INVERSES) * write_term; Fr write_inverse = wire(p, WIRE.LOOKUP_INVERSES) * read_term; - Fr inverse_exists_xor = - wire(p, WIRE.LOOKUP_READ_TAGS) + wire(p, WIRE.Q_LOOKUP) - - (wire(p, WIRE.LOOKUP_READ_TAGS) * wire(p, WIRE.Q_LOOKUP)); + Fr inverse_exists_xor = wire(p, WIRE.LOOKUP_READ_TAGS) + + wire(p, WIRE.Q_LOOKUP) - + (wire(p, WIRE.LOOKUP_READ_TAGS) * wire(p, WIRE.Q_LOOKUP)); // Inverse calculated correctly relation - Fr accumulatorNone = read_term * write_term * wire(p, WIRE.LOOKUP_INVERSES) - inverse_exists_xor; + Fr accumulatorNone = read_term * + write_term * + wire(p, WIRE.LOOKUP_INVERSES) - + inverse_exists_xor; accumulatorNone = accumulatorNone * domainSep; // Inverse - Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * read_inverse - wire(p, WIRE.LOOKUP_READ_COUNTS) * write_inverse; + Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * + read_inverse - + wire(p, WIRE.LOOKUP_READ_COUNTS) * + write_inverse; Fr read_tag = wire(p, WIRE.LOOKUP_READ_TAGS); @@ -1096,7 +1458,11 @@ library RelationsLib { x_add_identity = x_add_identity * x_diff * x_diff; x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2; - evals[11] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + evals[11] = + x_add_identity * + partialEval * + wire(p, WIRE.Q_ELLIPTIC) * + (ONE - q_is_double); } // Contribution 11 point addition, x-coordinate check @@ -1104,8 +1470,15 @@ library RelationsLib { { Fr y1_plus_y3 = ep.y_1 + ep.y_3; Fr y_diff = ep.y_2 * q_sign - ep.y_1; - Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff; - evals[12] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + Fr y_add_identity = y1_plus_y3 * + x_diff + + (ep.x_3 - ep.x_1) * + y_diff; + evals[12] = + y_add_identity * + domainSep * + wire(p, WIRE.Q_ELLIPTIC) * + (ONE - q_is_double); } // Contribution 10 point doubling, x-coordinate check @@ -1118,9 +1491,15 @@ library RelationsLib { Fr x1_pow_4_mul_9 = x_pow_4 * Fr.wrap(9); // NOTE: pushed into memory (stack >:'( ) - ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9; - - Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + ep.x_double_identity = + (ep.x_3 + ep.x_1 + ep.x_1) * + y1_sqr_mul_4 - + x1_pow_4_mul_9; + + Fr acc = ep.x_double_identity * + domainSep * + wire(p, WIRE.Q_ELLIPTIC) * + q_is_double; evals[11] = evals[11] + acc; } @@ -1128,8 +1507,16 @@ library RelationsLib { // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0 { Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1; - Fr y_double_identity = x1_sqr_mul_3 * (ep.x_1 - ep.x_3) - (ep.y_1 + ep.y_1) * (ep.y_1 + ep.y_3); - evals[12] = evals[12] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + Fr y_double_identity = x1_sqr_mul_3 * + (ep.x_1 - ep.x_3) - + (ep.y_1 + ep.y_1) * + (ep.y_1 + ep.y_3); + evals[12] = + evals[12] + + y_double_identity * + domainSep * + wire(p, WIRE.Q_ELLIPTIC) * + q_is_double; } } @@ -1203,8 +1590,12 @@ library RelationsLib { * For ROM gates, qc = 0 */ ap.memory_record_check = wire(p, WIRE.W_O) * rp.etaThree; - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * rp.etaTwo); - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * rp.eta); + ap.memory_record_check = + ap.memory_record_check + + (wire(p, WIRE.W_R) * rp.etaTwo); + ap.memory_record_check = + ap.memory_record_check + + (wire(p, WIRE.W_L) * rp.eta); ap.memory_record_check = ap.memory_record_check + wire(p, WIRE.Q_C); ap.partial_record_check = ap.memory_record_check; // used in RAM consistency check; deg 1 or 4 ap.memory_record_check = ap.memory_record_check - wire(p, WIRE.W_4); @@ -1228,16 +1619,26 @@ library RelationsLib { ap.index_delta = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_L); ap.record_delta = wire(p, WIRE.W_4_SHIFT) - wire(p, WIRE.W_4); - ap.index_is_monotonically_increasing = ap.index_delta * (ap.index_delta - Fr.wrap(1)); // deg 2 + ap.index_is_monotonically_increasing = + ap.index_delta * + (ap.index_delta - Fr.wrap(1)); // deg 2 - ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + ONE) * ap.record_delta; // deg 2 + ap.adjacent_values_match_if_adjacent_indices_match = + (ap.index_delta * MINUS_ONE + ONE) * + ap.record_delta; // deg 2 - evals[14] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) - * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - evals[15] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) - * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 + evals[14] = + ap.adjacent_values_match_if_adjacent_indices_match * + (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 + evals[15] = + ap.index_is_monotonically_increasing * + (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 + ap.ROM_consistency_check_identity = + ap.memory_record_check * + (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 /** * Contributions 15,16,17 @@ -1264,13 +1665,22 @@ library RelationsLib { // reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta // deg 1 or 4 ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree; - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta); - ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type; + ap.next_gate_access_type = + ap.next_gate_access_type + + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); + ap.next_gate_access_type = + ap.next_gate_access_type + + (wire(p, WIRE.W_L_SHIFT) * rp.eta); + ap.next_gate_access_type = + wire(p, WIRE.W_4_SHIFT) - + ap.next_gate_access_type; Fr value_delta = wire(p, WIRE.W_O_SHIFT) - wire(p, WIRE.W_O); - ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = - (ap.index_delta * MINUS_ONE + ONE) * value_delta * (ap.next_gate_access_type * MINUS_ONE + ONE); // deg 3 or 6 + ap + .adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = + (ap.index_delta * MINUS_ONE + ONE) * + value_delta * + (ap.next_gate_access_type * MINUS_ONE + ONE); // deg 3 or 6 // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't @@ -1278,15 +1688,28 @@ library RelationsLib { // type is correct, to cover this edge case // deg 2 or 4 ap.next_gate_access_type_is_boolean = - ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type; + ap.next_gate_access_type * + ap.next_gate_access_type - + ap.next_gate_access_type; // Putting it all together... - evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation - * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 - evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 - evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 - - ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9 + evals[16] = + ap + .adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * + (wire(p, WIRE.Q_O)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 + evals[17] = + ap.index_is_monotonically_increasing * + (wire(p, WIRE.Q_O)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 + evals[18] = + ap.next_gate_access_type_is_boolean * + (wire(p, WIRE.Q_O)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 + + ap.RAM_consistency_check_identity = + ap.access_check * + (wire(p, WIRE.Q_O)); // deg 3 or 9 /** * RAM Timestamp Consistency Check @@ -1300,7 +1723,10 @@ library RelationsLib { * Else timestamp_check = 0 */ ap.timestamp_delta = wire(p, WIRE.W_R_SHIFT) - wire(p, WIRE.W_R); - ap.RAM_timestamp_check_identity = (ap.index_delta * MINUS_ONE + ONE) * ap.timestamp_delta - wire(p, WIRE.W_O); // deg 3 + ap.RAM_timestamp_check_identity = + (ap.index_delta * MINUS_ONE + ONE) * + ap.timestamp_delta - + wire(p, WIRE.W_O); // deg 3 /** * Complete Contribution 12 @@ -1309,12 +1735,21 @@ library RelationsLib { */ ap.memory_identity = ap.ROM_consistency_check_identity; // deg 3 or 6 ap.memory_identity = - ap.memory_identity + ap.RAM_timestamp_check_identity * (wire(p, WIRE.Q_4) * wire(p, WIRE.Q_L)); // deg 4 - ap.memory_identity = ap.memory_identity + ap.memory_record_check * (wire(p, WIRE.Q_M) * wire(p, WIRE.Q_L)); // deg 3 or 6 - ap.memory_identity = ap.memory_identity + ap.RAM_consistency_check_identity; // deg 3 or 9 + ap.memory_identity + + ap.RAM_timestamp_check_identity * + (wire(p, WIRE.Q_4) * wire(p, WIRE.Q_L)); // deg 4 + ap.memory_identity = + ap.memory_identity + + ap.memory_record_check * + (wire(p, WIRE.Q_M) * wire(p, WIRE.Q_L)); // deg 3 or 6 + ap.memory_identity = + ap.memory_identity + + ap.RAM_consistency_check_identity; // deg 3 or 9 // (deg 3 or 9) + (deg 4) + (deg 3) - ap.memory_identity = ap.memory_identity * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10 + ap.memory_identity = + ap.memory_identity * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10 evals[13] = ap.memory_identity; } @@ -1353,28 +1788,56 @@ library RelationsLib { * * */ - ap.limb_subproduct = wire(p, WIRE.W_L) * wire(p, WIRE.W_R_SHIFT) + wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R); - ap.non_native_field_gate_2 = - (wire(p, WIRE.W_L) * wire(p, WIRE.W_4) + wire(p, WIRE.W_R) * wire(p, WIRE.W_O) - wire(p, WIRE.W_O_SHIFT)); + ap.limb_subproduct = + wire(p, WIRE.W_L) * + wire(p, WIRE.W_R_SHIFT) + + wire(p, WIRE.W_L_SHIFT) * + wire(p, WIRE.W_R); + ap.non_native_field_gate_2 = (wire(p, WIRE.W_L) * + wire(p, WIRE.W_4) + + wire(p, WIRE.W_R) * + wire(p, WIRE.W_O) - + wire(p, WIRE.W_O_SHIFT)); ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * LIMB_SIZE; - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 - wire(p, WIRE.W_4_SHIFT); - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 + ap.limb_subproduct; - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * wire(p, WIRE.Q_4); + ap.non_native_field_gate_2 = + ap.non_native_field_gate_2 - + wire(p, WIRE.W_4_SHIFT); + ap.non_native_field_gate_2 = + ap.non_native_field_gate_2 + + ap.limb_subproduct; + ap.non_native_field_gate_2 = + ap.non_native_field_gate_2 * + wire(p, WIRE.Q_4); ap.limb_subproduct = ap.limb_subproduct * LIMB_SIZE; - ap.limb_subproduct = ap.limb_subproduct + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT)); + ap.limb_subproduct = + ap.limb_subproduct + + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT)); ap.non_native_field_gate_1 = ap.limb_subproduct; - ap.non_native_field_gate_1 = ap.non_native_field_gate_1 - (wire(p, WIRE.W_O) + wire(p, WIRE.W_4)); - ap.non_native_field_gate_1 = ap.non_native_field_gate_1 * wire(p, WIRE.Q_O); + ap.non_native_field_gate_1 = + ap.non_native_field_gate_1 - + (wire(p, WIRE.W_O) + wire(p, WIRE.W_4)); + ap.non_native_field_gate_1 = + ap.non_native_field_gate_1 * + wire(p, WIRE.Q_O); ap.non_native_field_gate_3 = ap.limb_subproduct; - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 + wire(p, WIRE.W_4); - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 - (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT)); - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 * wire(p, WIRE.Q_M); - - Fr non_native_field_identity = - ap.non_native_field_gate_1 + ap.non_native_field_gate_2 + ap.non_native_field_gate_3; - non_native_field_identity = non_native_field_identity * wire(p, WIRE.Q_R); + ap.non_native_field_gate_3 = + ap.non_native_field_gate_3 + + wire(p, WIRE.W_4); + ap.non_native_field_gate_3 = + ap.non_native_field_gate_3 - + (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT)); + ap.non_native_field_gate_3 = + ap.non_native_field_gate_3 * + wire(p, WIRE.Q_M); + + Fr non_native_field_identity = ap.non_native_field_gate_1 + + ap.non_native_field_gate_2 + + ap.non_native_field_gate_3; + non_native_field_identity = + non_native_field_identity * + wire(p, WIRE.Q_R); // ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * qm // deg 2 @@ -1402,8 +1865,11 @@ library RelationsLib { ap.limb_accumulator_2 = ap.limb_accumulator_2 - wire(p, WIRE.W_4_SHIFT); ap.limb_accumulator_2 = ap.limb_accumulator_2 * wire(p, WIRE.Q_M); - Fr limb_accumulator_identity = ap.limb_accumulator_1 + ap.limb_accumulator_2; - limb_accumulator_identity = limb_accumulator_identity * wire(p, WIRE.Q_O); // deg 3 + Fr limb_accumulator_identity = ap.limb_accumulator_1 + + ap.limb_accumulator_2; + limb_accumulator_identity = + limb_accumulator_identity * + wire(p, WIRE.Q_O); // deg 3 ap.nnf_identity = non_native_field_identity + limb_accumulator_identity; ap.nnf_identity = ap.nnf_identity * (wire(p, WIRE.Q_NNF) * domainSep); @@ -1463,13 +1929,25 @@ library RelationsLib { ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4 ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep; - evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[20] = + evals[20] + + ep.q_pos_by_scaling * + (ep.v1 - wire(p, WIRE.W_L_SHIFT)); - evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[21] = + evals[21] + + ep.q_pos_by_scaling * + (ep.v2 - wire(p, WIRE.W_R_SHIFT)); - evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[22] = + evals[22] + + ep.q_pos_by_scaling * + (ep.v3 - wire(p, WIRE.W_O_SHIFT)); - evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[23] = + evals[23] + + ep.q_pos_by_scaling * + (ep.v4 - wire(p, WIRE.W_4_SHIFT)); } struct PoseidonInternalParams { @@ -1494,10 +1972,18 @@ library RelationsLib { PoseidonInternalParams memory ip; Fr[4] memory INTERNAL_MATRIX_DIAGONAL = [ - FrLib.from(0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7), - FrLib.from(0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b), - FrLib.from(0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15), - FrLib.from(0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b) + FrLib.from( + 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7 + ), + FrLib.from( + 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b + ), + FrLib.from( + 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15 + ), + FrLib.from( + 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b + ) ]; // add round constants @@ -1515,16 +2001,28 @@ library RelationsLib { ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep; ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum; - evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[24] = + evals[24] + + ip.q_pos_by_scaling * + (ip.v1 - wire(p, WIRE.W_L_SHIFT)); ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum; - evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[25] = + evals[25] + + ip.q_pos_by_scaling * + (ip.v2 - wire(p, WIRE.W_R_SHIFT)); ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum; - evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[26] = + evals[26] + + ip.q_pos_by_scaling * + (ip.v3 - wire(p, WIRE.W_O_SHIFT)); ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum; - evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[27] = + evals[27] + + ip.q_pos_by_scaling * + (ip.v4 - wire(p, WIRE.W_4_SHIFT)); } // Batch subrelation evaluations using precomputed powers of alpha @@ -1536,7 +2034,10 @@ library RelationsLib { accumulator = evaluations[0]; for (uint256 i = 1; i < NUMBER_OF_SUBRELATIONS; ++i) { - accumulator = accumulator + evaluations[i] * subrelationChallenges[i - 1]; + accumulator = + accumulator + + evaluations[i] * + subrelationChallenges[i - 1]; } } } @@ -1572,7 +2073,10 @@ library CommitmentSchemeLib { Fr[] foldPosEvaluations; } - function computeSquares(Fr r, uint256 logN) internal pure returns (Fr[] memory) { + function computeSquares( + Fr r, + uint256 logN + ) internal pure returns (Fr[] memory) { Fr[] memory squares = new Fr[](logN); squares[0] = r; for (uint256 i = 1; i < logN; ++i) { @@ -1594,10 +2098,15 @@ library CommitmentSchemeLib { Fr challengePower = geminiEvalChallengePowers[i - 1]; Fr u = sumcheckUChallenges[i - 1]; - Fr batchedEvalRoundAcc = ((challengePower * batchedEvalAccumulator * Fr.wrap(2)) - geminiEvaluations[i - 1] - * (challengePower * (ONE - u) - u)); + Fr batchedEvalRoundAcc = ((challengePower * + batchedEvalAccumulator * + Fr.wrap(2)) - + geminiEvaluations[i - 1] * + (challengePower * (ONE - u) - u)); // Divide by the denominator - batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (ONE - u) + u).invert(); + batchedEvalRoundAcc = + batchedEvalRoundAcc * + (challengePower * (ONE - u) + u).invert(); batchedEvalAccumulator = batchedEvalRoundAcc; foldPosEvaluations[i - 1] = batchedEvalRoundAcc; @@ -1628,13 +2137,18 @@ function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) { } // EC Point utilities -function bytesToG1Point(bytes calldata proofSection) pure returns (Honk.G1Point memory point) { +function bytesToG1Point( + bytes calldata proofSection +) pure returns (Honk.G1Point memory point) { point = Honk.G1Point({ - x: uint256(bytes32(proofSection[0x00:0x20])) % Q, y: uint256(bytes32(proofSection[0x20:0x40])) % Q + x: uint256(bytes32(proofSection[0x00:0x20])) % Q, + y: uint256(bytes32(proofSection[0x20:0x40])) % Q }); } -function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) { +function negateInplace( + Honk.G1Point memory point +) pure returns (Honk.G1Point memory) { point.y = (Q - point.y) % Q; return point; } @@ -1651,10 +2165,9 @@ function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point mem * @return lhs * @return rhs */ -function convertPairingPointsToG1(Fr[PAIRING_POINTS_SIZE] memory pairingPoints) - pure - returns (Honk.G1Point memory lhs, Honk.G1Point memory rhs) -{ +function convertPairingPointsToG1( + Fr[PAIRING_POINTS_SIZE] memory pairingPoints +) pure returns (Honk.G1Point memory lhs, Honk.G1Point memory rhs) { uint256 lhsX = Fr.unwrap(pairingPoints[0]); lhsX |= Fr.unwrap(pairingPoints[1]) << 68; lhsX |= Fr.unwrap(pairingPoints[2]) << 136; @@ -1698,7 +2211,10 @@ function generateRecursionSeparator( // hash the accum X // hash the accum Y - (Honk.G1Point memory proofLhs, Honk.G1Point memory proofRhs) = convertPairingPointsToG1(proofPairingPoints); + ( + Honk.G1Point memory proofLhs, + Honk.G1Point memory proofRhs + ) = convertPairingPointsToG1(proofPairingPoints); uint256[8] memory recursionSeparatorElements; @@ -1714,7 +2230,9 @@ function generateRecursionSeparator( recursionSeparatorElements[6] = accRhs.x; recursionSeparatorElements[7] = accRhs.y; - recursionSeparator = FrLib.fromBytes32(keccak256(abi.encodePacked(recursionSeparatorElements))); + recursionSeparator = FrLib.fromBytes32( + keccak256(abi.encodePacked(recursionSeparatorElements)) + ); } /** @@ -1726,10 +2244,11 @@ function generateRecursionSeparator( * @param recursionSeperator The separator to use for the multiplication. * @return `(recursionSeperator * basePoint) + other`. */ -function mulWithSeperator(Honk.G1Point memory basePoint, Honk.G1Point memory other, Fr recursionSeperator) - view - returns (Honk.G1Point memory) -{ +function mulWithSeperator( + Honk.G1Point memory basePoint, + Honk.G1Point memory other, + Fr recursionSeperator +) view returns (Honk.G1Point memory) { Honk.G1Point memory result; result = ecMul(recursionSeperator, basePoint); @@ -1746,7 +2265,10 @@ function mulWithSeperator(Honk.G1Point memory basePoint, Honk.G1Point memory oth * @param point The point to multiply. * @return result The result of the multiplication. */ -function ecMul(Fr value, Honk.G1Point memory point) view returns (Honk.G1Point memory) { +function ecMul( + Fr value, + Honk.G1Point memory point +) view returns (Honk.G1Point memory) { Honk.G1Point memory result; assembly { @@ -1792,7 +2314,10 @@ function ecMul(Fr value, Honk.G1Point memory point) view returns (Honk.G1Point m * @param rhs The right hand side of the addition. * @return result The result of the addition. */ -function ecAdd(Honk.G1Point memory lhs, Honk.G1Point memory rhs) view returns (Honk.G1Point memory) { +function ecAdd( + Honk.G1Point memory lhs, + Honk.G1Point memory rhs +) view returns (Honk.G1Point memory) { Honk.G1Point memory result; assembly { @@ -1816,7 +2341,9 @@ function ecAdd(Honk.G1Point memory lhs, Honk.G1Point memory rhs) view returns (H // Call the ecAdd precompile, it takes in the following // [lhs.x, lhs.y, rhs.x, rhs.y], and returns their addition back into the free memory location. let success := staticcall(gas(), 0x06, free, 0x80, free, 0x40) - if iszero(success) { revert(0, 0) } + if iszero(success) { + revert(0, 0) + } // Copy the result of the addition back into the result memory location. // Memory layout: @@ -1845,22 +2372,41 @@ function validateOnCurve(Honk.G1Point memory point) pure { require(success, "point is not on the curve"); } -function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns (bool decodedResult) { +function pairing( + Honk.G1Point memory rhs, + Honk.G1Point memory lhs +) view returns (bool decodedResult) { bytes memory input = abi.encodePacked( rhs.x, rhs.y, // Fixed G2 point - uint256(0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2), - uint256(0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed), - uint256(0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b), - uint256(0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa), + uint256( + 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2 + ), + uint256( + 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed + ), + uint256( + 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b + ), + uint256( + 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa + ), lhs.x, lhs.y, // G2 point from VK - uint256(0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1), - uint256(0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0), - uint256(0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4), - uint256(0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) + uint256( + 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1 + ), + uint256( + 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0 + ), + uint256( + 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4 + ), + uint256( + 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55 + ) ); (bool success, bytes memory result) = address(0x08).staticcall(input); @@ -1869,9 +2415,6 @@ function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns // Field arithmetic libraries - prevent littering the code with modmul / addmul - - - abstract contract BaseZKHonkVerifier is IVerifier { using FrLib for Fr; @@ -1881,7 +2424,12 @@ abstract contract BaseZKHonkVerifier is IVerifier { uint256 immutable $NUM_PUBLIC_INPUTS; uint256 immutable $MSMSize; - constructor(uint256 _N, uint256 _logN, uint256 _vkHash, uint256 _numPublicInputs) { + constructor( + uint256 _N, + uint256 _logN, + uint256 _vkHash, + uint256 _numPublicInputs + ) { $N = _N; $LOG_N = _logN; $VK_HASH = _vkHash; @@ -1891,7 +2439,11 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Errors error ProofLengthWrong(); - error ProofLengthWrongWithLogN(uint256 logN, uint256 actualLength, uint256 expectedLength); + error ProofLengthWrongWithLogN( + uint256 logN, + uint256 actualLength, + uint256 expectedLength + ); error PublicInputsLengthWrong(); error SumcheckFailed(); error ShpleminiFailed(); @@ -1911,7 +2463,10 @@ abstract contract BaseZKHonkVerifier is IVerifier { proofLength += NUM_ELEMENTS_COMM * 3; // Libra concat, grand sum, quotient comms + Gemini masking // Sumcheck - proofLength += logN * ZK_BATCHED_RELATION_PARTIAL_LENGTH * NUM_ELEMENTS_FR; // sumcheck univariates + proofLength += + logN * + ZK_BATCHED_RELATION_PARTIAL_LENGTH * + NUM_ELEMENTS_FR; // sumcheck univariates proofLength += NUMBER_OF_ENTITIES_ZK * NUM_ELEMENTS_FR; // sumcheck evaluations // Libra and Gemini @@ -1931,20 +2486,26 @@ abstract contract BaseZKHonkVerifier is IVerifier { uint256 constant SHIFTED_COMMITMENTS_START = 30; - function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory); + function loadVerificationKey() + internal + pure + virtual + returns (Honk.VerificationKey memory); - function verify(bytes calldata proof, bytes32[] calldata publicInputs) - public - view - override - returns (bool verified) - { + function verify( + bytes calldata proof, + bytes32[] calldata publicInputs + ) public view override returns (bool verified) { // Calculate expected proof size based on $LOG_N uint256 expectedProofSize = calculateProofSize($LOG_N); // Check the received proof is the expected size where each field element is 32 bytes if (proof.length != expectedProofSize * 32) { - revert ProofLengthWrongWithLogN($LOG_N, proof.length, expectedProofSize * 32); + revert ProofLengthWrongWithLogN( + $LOG_N, + proof.length, + expectedProofSize * 32 + ); } Honk.VerificationKey memory vk = loadVerificationKey(); @@ -1955,15 +2516,20 @@ abstract contract BaseZKHonkVerifier is IVerifier { } // Generate the fiat shamir challenges for the whole protocol - ZKTranscript memory t = - ZKTranscriptLib.generateTranscript(p, publicInputs, $VK_HASH, $NUM_PUBLIC_INPUTS, $LOG_N); + ZKTranscript memory t = ZKTranscriptLib.generateTranscript( + p, + publicInputs, + $VK_HASH, + $NUM_PUBLIC_INPUTS, + $LOG_N + ); // Derive public input delta t.relationParameters.publicInputsDelta = computePublicInputDelta( publicInputs, p.pairingPointObject, t.relationParameters.beta, - t.relationParameters.gamma, /*pubInputsOffset=*/ + t.relationParameters.gamma /*pubInputsOffset=*/, 1 ); @@ -1987,11 +2553,16 @@ abstract contract BaseZKHonkVerifier is IVerifier { Fr numerator = Fr.wrap(1); Fr denominator = Fr.wrap(1); - Fr numeratorAcc = gamma + (beta * FrLib.from(PERMUTATION_ARGUMENT_VALUE_SEPARATOR + offset)); + Fr numeratorAcc = gamma + + (beta * FrLib.from(PERMUTATION_ARGUMENT_VALUE_SEPARATOR + offset)); Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); { - for (uint256 i = 0; i < $NUM_PUBLIC_INPUTS - PAIRING_POINTS_SIZE; i++) { + for ( + uint256 i = 0; + i < $NUM_PUBLIC_INPUTS - PAIRING_POINTS_SIZE; + i++ + ) { Fr pubInput = FrLib.fromBytes32(publicInputs[i]); numerator = numerator * (numeratorAcc + pubInput); @@ -2016,22 +2587,32 @@ abstract contract BaseZKHonkVerifier is IVerifier { publicInputDelta = FrLib.div(numerator, denominator); } - function verifySumcheck(Honk.ZKProof memory proof, ZKTranscript memory tp) internal view returns (bool verified) { + function verifySumcheck( + Honk.ZKProof memory proof, + ZKTranscript memory tp + ) internal view returns (bool verified) { Fr roundTargetSum = tp.libraChallenge * proof.libraSum; // default 0 Fr powPartialEvaluation = Fr.wrap(1); // We perform sumcheck reductions over log n rounds ( the multivariate degree ) for (uint256 round; round < $LOG_N; ++round) { - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate = proof.sumcheckUnivariates[round]; + Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] + memory roundUnivariate = proof.sumcheckUnivariates[round]; Fr totalSum = roundUnivariate[0] + roundUnivariate[1]; if (totalSum != roundTargetSum) revert SumcheckFailed(); Fr roundChallenge = tp.sumCheckUChallenges[round]; // Update the round target for the next rounf - roundTargetSum = computeNextTargetSum(roundUnivariate, roundChallenge); + roundTargetSum = computeNextTargetSum( + roundUnivariate, + roundChallenge + ); powPartialEvaluation = - powPartialEvaluation * (Fr.wrap(1) + roundChallenge * (tp.gateChallenges[round] - Fr.wrap(1))); + powPartialEvaluation * + (Fr.wrap(1) + + roundChallenge * + (tp.gateChallenges[round] - Fr.wrap(1))); } // Last round @@ -2039,10 +2620,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Index 0 is gemini_masking_poly, indices 1-41 are the regular entities used in relations Fr[NUMBER_OF_ENTITIES] memory relationsEvaluations; for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { - relationsEvaluations[i] = proof.sumcheckEvaluations[i + NUM_MASKING_POLYNOMIALS]; // Skip gemini_masking_poly at index 0 + relationsEvaluations[i] = proof.sumcheckEvaluations[ + i + NUM_MASKING_POLYNOMIALS + ]; // Skip gemini_masking_poly at index 0 } Fr grandHonkRelationSum = RelationsLib.accumulateRelationEvaluations( - relationsEvaluations, tp.relationParameters, tp.alphas, powPartialEvaluation + relationsEvaluations, + tp.relationParameters, + tp.alphas, + powPartialEvaluation ); Fr evaluation = Fr.wrap(1); @@ -2051,27 +2637,48 @@ abstract contract BaseZKHonkVerifier is IVerifier { } grandHonkRelationSum = - grandHonkRelationSum * (Fr.wrap(1) - evaluation) + proof.libraEvaluation * tp.libraChallenge; + grandHonkRelationSum * + (Fr.wrap(1) - evaluation) + + proof.libraEvaluation * + tp.libraChallenge; verified = (grandHonkRelationSum == roundTargetSum); } // Return the new target sum for the next sumcheck round - function computeNextTargetSum(Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, Fr roundChallenge) - internal - view - returns (Fr targetSum) - { - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [ - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51), - Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31), - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000000240), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31), - Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51), - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80) - ]; + function computeNextTargetSum( + Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, + Fr roundChallenge + ) internal view returns (Fr targetSum) { + Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] + memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [ + Fr.wrap( + 0x0000000000000000000000000000000000000000000000000000000000009d80 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51 + ), + Fr.wrap( + 0x00000000000000000000000000000000000000000000000000000000000005a0 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31 + ), + Fr.wrap( + 0x0000000000000000000000000000000000000000000000000000000000000240 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31 + ), + Fr.wrap( + 0x00000000000000000000000000000000000000000000000000000000000005a0 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51 + ), + Fr.wrap( + 0x0000000000000000000000000000000000000000000000000000000000009d80 + ) + ]; // To compute the next target sum, we evaluate the given univariate at a point u (challenge). @@ -2084,11 +2691,17 @@ abstract contract BaseZKHonkVerifier is IVerifier { Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory denominatorInverses; for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) { - denominatorInverses[i] = FrLib.invert(BARYCENTRIC_LAGRANGE_DENOMINATORS[i] * (roundChallenge - Fr.wrap(i))); + denominatorInverses[i] = FrLib.invert( + BARYCENTRIC_LAGRANGE_DENOMINATORS[i] * + (roundChallenge - Fr.wrap(i)) + ); } for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) { - targetSum = targetSum + roundUnivariates[i] * denominatorInverses[i]; + targetSum = + targetSum + + roundUnivariates[i] * + denominatorInverses[i]; } // Scale the sum by the value of B(x) @@ -2104,56 +2717,63 @@ abstract contract BaseZKHonkVerifier is IVerifier { Honk.G1Point P_1; } - function verifyShplemini(Honk.ZKProof memory proof, Honk.VerificationKey memory vk, ZKTranscript memory tp) - internal - view - returns (bool verified) - { + function verifyShplemini( + Honk.ZKProof memory proof, + Honk.VerificationKey memory vk, + ZKTranscript memory tp + ) internal view returns (bool verified) { CommitmentSchemeLib.ShpleminiIntermediates memory mem; // stack // - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size - Fr[] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR, $LOG_N); + Fr[] memory powers_of_evaluation_challenge = CommitmentSchemeLib + .computeSquares(tp.geminiR, $LOG_N); // Arrays hold values that will be linearly combined for the gemini and shplonk batch openings Fr[] memory scalars = new Fr[]($MSMSize); Honk.G1Point[] memory commitments = new Honk.G1Point[]($MSMSize); - mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); - mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); + mem.posInvertedDenominator = (tp.shplonkZ - + powers_of_evaluation_challenge[0]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + + powers_of_evaluation_challenge[0]).invert(); - mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator); + mem.unshiftedScalar = + mem.posInvertedDenominator + + (tp.shplonkNu * mem.negInvertedDenominator); mem.shiftedScalar = - tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator)); + tp.geminiR.invert() * + (mem.posInvertedDenominator - + (tp.shplonkNu * mem.negInvertedDenominator)); scalars[0] = Fr.wrap(1); commitments[0] = proof.shplonkQ; /* Batch multivariate opening claims, shifted and unshifted - * The vector of scalars is populated as follows: - * \f[ - * \left( - * - \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), - * \ldots, - * - \rho^{i+k-1} \times \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), - * - \rho^{i+k} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right), - * \ldots, - * - \rho^{k+m-1} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right) - * \right) - * \f] - * - * The following vector is concatenated to the vector of commitments: - * \f[ - * f_0, \ldots, f_{m-1}, f_{\text{shift}, 0}, \ldots, f_{\text{shift}, k-1} - * \f] - * - * Simultaneously, the evaluation of the multilinear polynomial - * \f[ - * \sum \rho^i \cdot f_i + \sum \rho^{i+k} \cdot f_{\text{shift}, i} - * \f] - * at the challenge point \f$ (u_0,\ldots, u_{n-1}) \f$ is computed. - * - * This approach minimizes the number of iterations over the commitments to multilinear polynomials - * and eliminates the need to store the powers of \f$ \rho \f$. - */ + * The vector of scalars is populated as follows: + * \f[ + * \left( + * - \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), + * \ldots, + * - \rho^{i+k-1} \times \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), + * - \rho^{i+k} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right), + * \ldots, + * - \rho^{k+m-1} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right) + * \right) + * \f] + * + * The following vector is concatenated to the vector of commitments: + * \f[ + * f_0, \ldots, f_{m-1}, f_{\text{shift}, 0}, \ldots, f_{\text{shift}, k-1} + * \f] + * + * Simultaneously, the evaluation of the multilinear polynomial + * \f[ + * \sum \rho^i \cdot f_i + \sum \rho^{i+k} \cdot f_{\text{shift}, i} + * \f] + * at the challenge point \f$ (u_0,\ldots, u_{n-1}) \f$ is computed. + * + * This approach minimizes the number of iterations over the commitments to multilinear polynomials + * and eliminates the need to store the powers of \f$ \rho \f$. + */ // For ZK flavors: evaluations array is [gemini_masking_poly, qm, qc, ql, qr, ...] // Start batching challenge at 1, not rho, to match non-ZK pattern mem.batchingChallenge = Fr.wrap(1); @@ -2165,8 +2785,10 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Process all NUMBER_UNSHIFTED_ZK evaluations (includes gemini_masking_poly at index 0) for (uint256 i = 1; i <= NUMBER_UNSHIFTED_ZK; ++i) { scalars[i] = mem.unshiftedScalarNeg * mem.batchingChallenge; - mem.batchedEvaluation = mem.batchedEvaluation - + (proof.sumcheckEvaluations[i - NUM_MASKING_POLYNOMIALS] * mem.batchingChallenge); + mem.batchedEvaluation = + mem.batchedEvaluation + + (proof.sumcheckEvaluations[i - NUM_MASKING_POLYNOMIALS] * + mem.batchingChallenge); mem.batchingChallenge = mem.batchingChallenge * tp.rho; } // g commitments are accumulated at r @@ -2179,9 +2801,13 @@ abstract contract BaseZKHonkVerifier is IVerifier { uint256 scalarOff = i + SHIFTED_COMMITMENTS_START; uint256 evaluationOff = i + NUMBER_UNSHIFTED_ZK; - scalars[scalarOff] = scalars[scalarOff] + (mem.shiftedScalarNeg * mem.batchingChallenge); + scalars[scalarOff] = + scalars[scalarOff] + + (mem.shiftedScalarNeg * mem.batchingChallenge); mem.batchedEvaluation = - mem.batchedEvaluation + (proof.sumcheckEvaluations[evaluationOff] * mem.batchingChallenge); + mem.batchedEvaluation + + (proof.sumcheckEvaluations[evaluationOff] * + mem.batchingChallenge); mem.batchingChallenge = mem.batchingChallenge * tp.rho; } @@ -2234,15 +2860,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { * \f[ * \left( \text{com}(A_1), \text{com}(A_2), \ldots, \text{com}(A_{n-1}) \right) * \f] - * to the 'commitments' vector. - * - * 2. Computes the scalars: - * \f[ - * \frac{\nu^{2}}{z + r^2}, \frac{\nu^3}{z + r^4}, \ldots, \frac{\nu^{n-1}}{z + r^{2^{n-1}}} - * \f] - * and places them into the 'scalars' vector. - * - * 3. Accumulates the summands of the constant term: + * to the 'commitments' vector. + * + * 2. Computes the scalars: + * \f[ + * \frac{\nu^{2}}{z + r^2}, \frac{\nu^3}{z + r^4}, \ldots, \frac{\nu^{n-1}}{z + r^{2^{n-1}}} + * \f] + * and places them into the 'scalars' vector. + * + * 3. Accumulates the summands of the constant term: * \f[ * \sum_{i=2}^{n-1} \frac{\nu^{i} \cdot A_i(-r^{2^i})}{z + r^{2^i}} * \f] @@ -2251,17 +2877,23 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., $LOG_N - 1 - Fr[] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations( - tp.sumCheckUChallenges, - mem.batchedEvaluation, - proof.geminiAEvaluations, - powers_of_evaluation_challenge, - $LOG_N - ); + Fr[] memory foldPosEvaluations = CommitmentSchemeLib + .computeFoldPosEvaluations( + tp.sumCheckUChallenges, + mem.batchedEvaluation, + proof.geminiAEvaluations, + powers_of_evaluation_challenge, + $LOG_N + ); - mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; mem.constantTermAccumulator = - mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); + foldPosEvaluations[0] * + mem.posInvertedDenominator; + mem.constantTermAccumulator = + mem.constantTermAccumulator + + (proof.geminiAEvaluations[0] * + tp.shplonkNu * + mem.negInvertedDenominator); mem.batchingChallenge = tp.shplonkNu.sqr(); uint256 boundary = NUMBER_UNSHIFTED_ZK + 1; @@ -2273,22 +2905,40 @@ abstract contract BaseZKHonkVerifier is IVerifier { if (!dummy_round) { // Update inverted denominators - mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); - mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + mem.posInvertedDenominator = (tp.shplonkZ - + powers_of_evaluation_challenge[i + 1]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + + powers_of_evaluation_challenge[i + 1]).invert(); // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ] - mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; - mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; - scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + mem.scalingFactorPos = + mem.batchingChallenge * + mem.posInvertedDenominator; + mem.scalingFactorNeg = + mem.batchingChallenge * + tp.shplonkNu * + mem.negInvertedDenominator; + scalars[boundary + i] = + mem.scalingFactorNeg.neg() + + mem.scalingFactorPos.neg(); // Accumulate the const term contribution given by // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l}) - Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; - accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; - mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; + Fr accumContribution = mem.scalingFactorNeg * + proof.geminiAEvaluations[i + 1]; + accumContribution = + accumContribution + + mem.scalingFactorPos * + foldPosEvaluations[i + 1]; + mem.constantTermAccumulator = + mem.constantTermAccumulator + + accumContribution; } // Update the running power of v - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + mem.batchingChallenge = + mem.batchingChallenge * + tp.shplonkNu * + tp.shplonkNu; commitments[boundary + i] = proof.geminiFoldComms[i]; } @@ -2297,16 +2947,24 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Finalize the batch opening claim mem.denominators[0] = Fr.wrap(1).div(tp.shplonkZ - tp.geminiR); - mem.denominators[1] = Fr.wrap(1).div(tp.shplonkZ - SUBGROUP_GENERATOR * tp.geminiR); + mem.denominators[1] = Fr.wrap(1).div( + tp.shplonkZ - SUBGROUP_GENERATOR * tp.geminiR + ); mem.denominators[2] = mem.denominators[0]; mem.denominators[3] = mem.denominators[0]; - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + mem.batchingChallenge = + mem.batchingChallenge * + tp.shplonkNu * + tp.shplonkNu; for (uint256 i = 0; i < LIBRA_EVALUATIONS; i++) { Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge; mem.batchingScalars[i] = scalingFactor.neg(); mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; - mem.constantTermAccumulator = mem.constantTermAccumulator + scalingFactor * proof.libraPolyEvals[i]; + mem.constantTermAccumulator = + mem.constantTermAccumulator + + scalingFactor * + proof.libraPolyEvals[i]; } scalars[boundary] = mem.batchingScalars[0]; scalars[boundary + 1] = mem.batchingScalars[1] + mem.batchingScalars[2]; @@ -2316,10 +2974,17 @@ abstract contract BaseZKHonkVerifier is IVerifier { commitments[boundary++] = proof.libraCommitments[i]; } - commitments[boundary] = Honk.G1Point({x: 1, y: 2}); + commitments[boundary] = Honk.G1Point({ x: 1, y: 2 }); scalars[boundary++] = mem.constantTermAccumulator; - if (!checkEvalsConsistency(proof.libraPolyEvals, tp.geminiR, tp.sumCheckUChallenges, proof.libraEvaluation)) { + if ( + !checkEvalsConsistency( + proof.libraPolyEvals, + tp.geminiR, + tp.sumCheckUChallenges, + proof.libraEvaluation + ) + ) { revert ConsistencyCheckFailed(); } @@ -2333,9 +2998,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { pair.P_1 = negateInplace(quotient_commitment); // Aggregate pairing points - Fr recursionSeparator = generateRecursionSeparator(proof.pairingPointObject, pair.P_0, pair.P_1); - (Honk.G1Point memory P_0_other, Honk.G1Point memory P_1_other) = - convertPairingPointsToG1(proof.pairingPointObject); + Fr recursionSeparator = generateRecursionSeparator( + proof.pairingPointObject, + pair.P_0, + pair.P_1 + ); + ( + Honk.G1Point memory P_0_other, + Honk.G1Point memory P_1_other + ) = convertPairingPointsToG1(proof.pairingPointObject); // Validate the points from the proof are on the curve validateOnCurve(P_0_other); @@ -2375,8 +3046,14 @@ abstract contract BaseZKHonkVerifier is IVerifier { for (uint256 round = 0; round < $LOG_N; round++) { uint256 currIdx = 1 + LIBRA_UNIVARIATES_LENGTH * round; mem.challengePolyLagrange[currIdx] = one; - for (uint256 idx = currIdx + 1; idx < currIdx + LIBRA_UNIVARIATES_LENGTH; idx++) { - mem.challengePolyLagrange[idx] = mem.challengePolyLagrange[idx - 1] * uChallenges[round]; + for ( + uint256 idx = currIdx + 1; + idx < currIdx + LIBRA_UNIVARIATES_LENGTH; + idx++ + ) { + mem.challengePolyLagrange[idx] = + mem.challengePolyLagrange[idx - 1] * + uChallenges[round]; } } @@ -2385,7 +3062,10 @@ abstract contract BaseZKHonkVerifier is IVerifier { for (uint256 idx = 0; idx < SUBGROUP_SIZE; idx++) { mem.denominators[idx] = mem.rootPower * geminiR - one; mem.denominators[idx] = mem.denominators[idx].invert(); - mem.challengePolyEval = mem.challengePolyEval + mem.challengePolyLagrange[idx] * mem.denominators[idx]; + mem.challengePolyEval = + mem.challengePolyEval + + mem.challengePolyLagrange[idx] * + mem.denominators[idx]; mem.rootPower = mem.rootPower * SUBGROUP_GENERATOR_INVERSE; } @@ -2396,19 +3076,28 @@ abstract contract BaseZKHonkVerifier is IVerifier { mem.diff = mem.lagrangeFirst * libraPolyEvals[2]; - mem.diff = mem.diff + (geminiR - SUBGROUP_GENERATOR_INVERSE) - * (libraPolyEvals[1] - libraPolyEvals[2] - libraPolyEvals[0] * mem.challengePolyEval); - mem.diff = mem.diff + mem.lagrangeLast * (libraPolyEvals[2] - libraEval) - vanishingPolyEval * libraPolyEvals[3]; + mem.diff = + mem.diff + + (geminiR - SUBGROUP_GENERATOR_INVERSE) * + (libraPolyEvals[1] - + libraPolyEvals[2] - + libraPolyEvals[0] * + mem.challengePolyEval); + mem.diff = + mem.diff + + mem.lagrangeLast * + (libraPolyEvals[2] - libraEval) - + vanishingPolyEval * + libraPolyEvals[3]; check = mem.diff == Fr.wrap(0); } // This implementation is the same as above with different constants - function batchMul(Honk.G1Point[] memory base, Fr[] memory scalars) - internal - view - returns (Honk.G1Point memory result) - { + function batchMul( + Honk.G1Point[] memory base, + Fr[] memory scalars + ) internal view returns (Honk.G1Point memory result) { uint256 limit = $MSMSize; // Validate all points are on the curve @@ -2421,7 +3110,9 @@ abstract contract BaseZKHonkVerifier is IVerifier { let free := mload(0x40) let count := 0x01 - for {} lt(count, add(limit, 1)) { count := add(count, 1) } { + for {} lt(count, add(limit, 1)) { + count := add(count, 1) + } { // Get loop offsets let base_base := add(base, mul(count, 0x20)) let scalar_base := add(scalars, mul(count, 0x20)) @@ -2431,9 +3122,22 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Add scalar mstore(add(free, 0x80), mload(scalar_base)) - success := and(success, staticcall(gas(), 7, add(free, 0x40), 0x60, add(free, 0x40), 0x40)) + success := and( + success, + staticcall( + gas(), + 7, + add(free, 0x40), + 0x60, + add(free, 0x40), + 0x40 + ) + ) // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, free, 0x80, free, 0x40)) + success := and( + success, + staticcall(gas(), 6, free, 0x80, free, 0x40) + ) } // Return the result @@ -2445,8 +3149,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { } } -contract ThresholdDecryptedSharesAggregationModVerifier is BaseZKHonkVerifier(N, LOG_N, VK_HASH, NUMBER_OF_PUBLIC_INPUTS) { - function loadVerificationKey() internal pure override returns (Honk.VerificationKey memory) { - return HonkVerificationKey.loadVerificationKey(); +contract ThresholdDecryptedSharesAggregationVerifier is + BaseZKHonkVerifier(N, LOG_N, VK_HASH, NUMBER_OF_PUBLIC_INPUTS) +{ + function loadVerificationKey() + internal + pure + override + returns (Honk.VerificationKey memory) + { + return HonkVerificationKey.loadVerificationKey(); } } diff --git a/packages/enclave-contracts/contracts/verifier/ThresholdPkAggregationVerifier.sol b/packages/enclave-contracts/contracts/verifier/ThresholdPkAggregationVerifier.sol index 4448f656df..4635c66da2 100644 --- a/packages/enclave-contracts/contracts/verifier/ThresholdPkAggregationVerifier.sol +++ b/packages/enclave-contracts/contracts/verifier/ThresholdPkAggregationVerifier.sol @@ -10,122 +10,238 @@ uint256 constant LOG_N = 18; uint256 constant NUMBER_OF_PUBLIC_INPUTS = 22; uint256 constant VK_HASH = 0x02306f0575881d3ddf6f0b9e8dac79af163672a144640cdf2a6ed6942ee4c6aa; library HonkVerificationKey { - function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { + function loadVerificationKey() + internal + pure + returns (Honk.VerificationKey memory) + { Honk.VerificationKey memory vk = Honk.VerificationKey({ circuitSize: uint256(262144), logCircuitSize: uint256(18), publicInputsSize: uint256(22), - ql: Honk.G1Point({ - x: uint256(0x131fd9af41c938c8b1b6e0086eb4f08ba4075a71288d83449d8d5eac6247099a), - y: uint256(0x072066e82cbf467dd3c411fdaf6242d1ca23f1b37710849520bf2cd4b714e795) + ql: Honk.G1Point({ + x: uint256( + 0x131fd9af41c938c8b1b6e0086eb4f08ba4075a71288d83449d8d5eac6247099a + ), + y: uint256( + 0x072066e82cbf467dd3c411fdaf6242d1ca23f1b37710849520bf2cd4b714e795 + ) }), - qr: Honk.G1Point({ - x: uint256(0x02f04c8042c961b5c40c8617efb47c118b71d76c64259724eb802e8efdada48f), - y: uint256(0x266704b76a579143a49d75c18ad41e4c8664833a345240b18787c26e832b2c2e) + qr: Honk.G1Point({ + x: uint256( + 0x02f04c8042c961b5c40c8617efb47c118b71d76c64259724eb802e8efdada48f + ), + y: uint256( + 0x266704b76a579143a49d75c18ad41e4c8664833a345240b18787c26e832b2c2e + ) }), - qo: Honk.G1Point({ - x: uint256(0x0efe5ef9accef9728a562f5e9ea4fd60b0957f6e559689936896c9d7e94823ba), - y: uint256(0x280a5dfe9d34183e42c5f275391576ae8e2891ab077920340756a44d9131ca70) + qo: Honk.G1Point({ + x: uint256( + 0x0efe5ef9accef9728a562f5e9ea4fd60b0957f6e559689936896c9d7e94823ba + ), + y: uint256( + 0x280a5dfe9d34183e42c5f275391576ae8e2891ab077920340756a44d9131ca70 + ) }), - q4: Honk.G1Point({ - x: uint256(0x2ecfda953e756b07faf8e3954fe5012494ee0237dea45538b88e34d949a516f9), - y: uint256(0x0677e9dcbd562e682c44632da1d4b5ffecdc6c9129adb89089c020384a34d281) + q4: Honk.G1Point({ + x: uint256( + 0x2ecfda953e756b07faf8e3954fe5012494ee0237dea45538b88e34d949a516f9 + ), + y: uint256( + 0x0677e9dcbd562e682c44632da1d4b5ffecdc6c9129adb89089c020384a34d281 + ) }), - qm: Honk.G1Point({ - x: uint256(0x1c34241ed7bd1ea35de9fe54f11e3deca92247eda67d756489374539ed080828), - y: uint256(0x1fa29ca2f59dfccf9e71342fe789ae8e2aa41079798daf79b8e02d06a510a4b7) + qm: Honk.G1Point({ + x: uint256( + 0x1c34241ed7bd1ea35de9fe54f11e3deca92247eda67d756489374539ed080828 + ), + y: uint256( + 0x1fa29ca2f59dfccf9e71342fe789ae8e2aa41079798daf79b8e02d06a510a4b7 + ) }), - qc: Honk.G1Point({ - x: uint256(0x147ff414795e16dd9d8ad7758205875dcbb2feca77004005326a37295450902e), - y: uint256(0x2ce19f89d76fc3a0e68df64342ecb603eb7743838eaab9cad94f597ff49c3d52) + qc: Honk.G1Point({ + x: uint256( + 0x147ff414795e16dd9d8ad7758205875dcbb2feca77004005326a37295450902e + ), + y: uint256( + 0x2ce19f89d76fc3a0e68df64342ecb603eb7743838eaab9cad94f597ff49c3d52 + ) }), - qLookup: Honk.G1Point({ - x: uint256(0x15729599ef3888a89db8f52912b65cdfc12205eb78f54bd9f4742df51d35d9d2), - y: uint256(0x1890a0e4fb04b07215d2034d92fc6ad93cb3670761c8c93df420b3a7d89baefa) + qLookup: Honk.G1Point({ + x: uint256( + 0x15729599ef3888a89db8f52912b65cdfc12205eb78f54bd9f4742df51d35d9d2 + ), + y: uint256( + 0x1890a0e4fb04b07215d2034d92fc6ad93cb3670761c8c93df420b3a7d89baefa + ) }), - qArith: Honk.G1Point({ - x: uint256(0x2aa5463c894b45d28a4b5ea9bed212fc3dd803ce12033d85358d4432a0655c6a), - y: uint256(0x1397cec5342f4f86432b983400c0e56ceb029e78abeba47fc958779df917e1d7) + qArith: Honk.G1Point({ + x: uint256( + 0x2aa5463c894b45d28a4b5ea9bed212fc3dd803ce12033d85358d4432a0655c6a + ), + y: uint256( + 0x1397cec5342f4f86432b983400c0e56ceb029e78abeba47fc958779df917e1d7 + ) }), - qDeltaRange: Honk.G1Point({ - x: uint256(0x1617218df444678e9120d0de7f480a6d0bf6098c6e77009e8cc81a5bb0e820fc), - y: uint256(0x1f03683cfa36530952dc9494533856af2e1487bed9e76f07b4afda82f3afb129) + qDeltaRange: Honk.G1Point({ + x: uint256( + 0x1617218df444678e9120d0de7f480a6d0bf6098c6e77009e8cc81a5bb0e820fc + ), + y: uint256( + 0x1f03683cfa36530952dc9494533856af2e1487bed9e76f07b4afda82f3afb129 + ) }), - qElliptic: Honk.G1Point({ - x: uint256(0x2229994889f103841fc6d5f7a4b209e045992468aec5a30800606e5c1918007c), - y: uint256(0x016891f753e67c0d4349565eaeb8c02d828793eb835c20c532e771ec6918702f) + qElliptic: Honk.G1Point({ + x: uint256( + 0x2229994889f103841fc6d5f7a4b209e045992468aec5a30800606e5c1918007c + ), + y: uint256( + 0x016891f753e67c0d4349565eaeb8c02d828793eb835c20c532e771ec6918702f + ) }), - qMemory: Honk.G1Point({ - x: uint256(0x161d4f65fef69c1bbc2a671569c92da155e9374fabef1d260eb8776142c73bd8), - y: uint256(0x268e5909d8cab6c89c8064ee0fc25a7fc541a3238f93dea808d9fda942421132) + qMemory: Honk.G1Point({ + x: uint256( + 0x161d4f65fef69c1bbc2a671569c92da155e9374fabef1d260eb8776142c73bd8 + ), + y: uint256( + 0x268e5909d8cab6c89c8064ee0fc25a7fc541a3238f93dea808d9fda942421132 + ) }), - qNnf: Honk.G1Point({ - x: uint256(0x26be72a59de37228c424b5ffc3149b2489578d0f09ba433097d9c8596473da5f), - y: uint256(0x1e1d0abff71ff2bf7e0833e32af3baff87b41a17a2cf187367c04ced7bc5ff7a) + qNnf: Honk.G1Point({ + x: uint256( + 0x26be72a59de37228c424b5ffc3149b2489578d0f09ba433097d9c8596473da5f + ), + y: uint256( + 0x1e1d0abff71ff2bf7e0833e32af3baff87b41a17a2cf187367c04ced7bc5ff7a + ) }), - qPoseidon2External: Honk.G1Point({ - x: uint256(0x099ba64dd88f156dc06f527c2bac7b2c7c86d903e24ac09e47f833cfd6f903b8), - y: uint256(0x067f7914c30e0ca5dab695d46a6b6644f048d04e0938eea01c282d7ba0f043cc) + qPoseidon2External: Honk.G1Point({ + x: uint256( + 0x099ba64dd88f156dc06f527c2bac7b2c7c86d903e24ac09e47f833cfd6f903b8 + ), + y: uint256( + 0x067f7914c30e0ca5dab695d46a6b6644f048d04e0938eea01c282d7ba0f043cc + ) }), - qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x281fd5754fbb77ac2ef58f72fe142cf865a329c0611b38919dd1a36feb994360), - y: uint256(0x15f7f262eba8a9b6df7a0928493a1399b33b1f765cb31c934d1cbde777c3bdfd) + qPoseidon2Internal: Honk.G1Point({ + x: uint256( + 0x281fd5754fbb77ac2ef58f72fe142cf865a329c0611b38919dd1a36feb994360 + ), + y: uint256( + 0x15f7f262eba8a9b6df7a0928493a1399b33b1f765cb31c934d1cbde777c3bdfd + ) }), - s1: Honk.G1Point({ - x: uint256(0x04ff10ec802daeb081f77ae5a048da6c5695f760c4b705fa2d0ae3cd5e76a9ae), - y: uint256(0x1242b0b182171f1a737e13750ff2ff10762a6fcb1d4280ce14b5b3a43295610d) + s1: Honk.G1Point({ + x: uint256( + 0x04ff10ec802daeb081f77ae5a048da6c5695f760c4b705fa2d0ae3cd5e76a9ae + ), + y: uint256( + 0x1242b0b182171f1a737e13750ff2ff10762a6fcb1d4280ce14b5b3a43295610d + ) }), - s2: Honk.G1Point({ - x: uint256(0x20bb81a1dc9b0c8d3cbcc2761b6f6751e08be09b384efd9b56bd5f81ca29c136), - y: uint256(0x10d80cf403b8ff3de754a57331c5dd143cb0ae9e0382550efd8f20b353e274b5) + s2: Honk.G1Point({ + x: uint256( + 0x20bb81a1dc9b0c8d3cbcc2761b6f6751e08be09b384efd9b56bd5f81ca29c136 + ), + y: uint256( + 0x10d80cf403b8ff3de754a57331c5dd143cb0ae9e0382550efd8f20b353e274b5 + ) }), - s3: Honk.G1Point({ - x: uint256(0x047c3bf9b1df8256aa780ba25fac792e3a8de5e460d9cb3e41bf8686653a2b83), - y: uint256(0x1f13e4fa50f1ff9430c4f58316e6c3f1ccdcf87540d6a19add847606138d93bf) + s3: Honk.G1Point({ + x: uint256( + 0x047c3bf9b1df8256aa780ba25fac792e3a8de5e460d9cb3e41bf8686653a2b83 + ), + y: uint256( + 0x1f13e4fa50f1ff9430c4f58316e6c3f1ccdcf87540d6a19add847606138d93bf + ) }), - s4: Honk.G1Point({ - x: uint256(0x087819484fd402168d10636c0e1ff16095086cfebb16fa72ecd905faa77611e2), - y: uint256(0x061b92f2194d55921ff02e4362fe5b4f59eac905edb027e656700a56806a5e89) + s4: Honk.G1Point({ + x: uint256( + 0x087819484fd402168d10636c0e1ff16095086cfebb16fa72ecd905faa77611e2 + ), + y: uint256( + 0x061b92f2194d55921ff02e4362fe5b4f59eac905edb027e656700a56806a5e89 + ) }), - t1: Honk.G1Point({ - x: uint256(0x099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d26), - y: uint256(0x0015b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f) + t1: Honk.G1Point({ + x: uint256( + 0x099e3bd5a0a00ab7fe18040105b9b395b5d8b7b4a63b05df652b0d10ef146d26 + ), + y: uint256( + 0x0015b8d2515d76e2ccec99dcd194592129af3a637f5a622a32440f860d1e2a7f + ) }), - t2: Honk.G1Point({ - x: uint256(0x1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e), - y: uint256(0x305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d19) + t2: Honk.G1Point({ + x: uint256( + 0x1b917517920bad3d8bc01c9595092a222b888108dc25d1aa450e0b4bc212c37e + ), + y: uint256( + 0x305e8992b148eedb22e6e992077a84482141c7ebe42000a1d58ccb74381f6d19 + ) }), - t3: Honk.G1Point({ - x: uint256(0x061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d), - y: uint256(0x1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e) + t3: Honk.G1Point({ + x: uint256( + 0x061f64497996e8915722501e9e367938ed8da2375186b518c7345c60b1134b2d + ), + y: uint256( + 0x1b84d38339321f405ebaf6a2f830842ad3d7cb59792e11c0d2691f317fd50e6e + ) }), - t4: Honk.G1Point({ - x: uint256(0x043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce), - y: uint256(0x261522c4089330646aff96736194949330952ae74c573d1686d9cb4a00733854) + t4: Honk.G1Point({ + x: uint256( + 0x043d063b130adfb37342af45d0155a28edd1a7e46c840d9c943fdf45521c64ce + ), + y: uint256( + 0x261522c4089330646aff96736194949330952ae74c573d1686d9cb4a00733854 + ) }), - id1: Honk.G1Point({ - x: uint256(0x30302f92d6b476ab0407ba6570e2c869057a534fafc859946c315715fd37397d), - y: uint256(0x2bccc49a1f124a8ea4933e1f65cd744c4ef91d17b429bc27f44ed533ff179ad9) + id1: Honk.G1Point({ + x: uint256( + 0x30302f92d6b476ab0407ba6570e2c869057a534fafc859946c315715fd37397d + ), + y: uint256( + 0x2bccc49a1f124a8ea4933e1f65cd744c4ef91d17b429bc27f44ed533ff179ad9 + ) }), - id2: Honk.G1Point({ - x: uint256(0x2fa778d2df483e2c7535aa5b015aba244987291fe5d0f78655332f35dbb983a2), - y: uint256(0x0eaaa6e5c290180d0979a51caf8592f4014402d09f8fdee08e2d2b98596b1743) + id2: Honk.G1Point({ + x: uint256( + 0x2fa778d2df483e2c7535aa5b015aba244987291fe5d0f78655332f35dbb983a2 + ), + y: uint256( + 0x0eaaa6e5c290180d0979a51caf8592f4014402d09f8fdee08e2d2b98596b1743 + ) }), - id3: Honk.G1Point({ - x: uint256(0x035d549bad95f400a2d94f6032216957b08b7ab07ab972d8403663454ecb46e4), - y: uint256(0x02512a1a401fd0832cea115ea34675373aa09faa59149b8ffd71fe76be90c306) + id3: Honk.G1Point({ + x: uint256( + 0x035d549bad95f400a2d94f6032216957b08b7ab07ab972d8403663454ecb46e4 + ), + y: uint256( + 0x02512a1a401fd0832cea115ea34675373aa09faa59149b8ffd71fe76be90c306 + ) }), - id4: Honk.G1Point({ - x: uint256(0x07377ddbcd535099c7600f69e539e1d41cdfd8705405334687c4f5b741226da8), - y: uint256(0x06608b7e3be5235cc0368ce844f8c822b118e54f993626431efa578a881b1e01) + id4: Honk.G1Point({ + x: uint256( + 0x07377ddbcd535099c7600f69e539e1d41cdfd8705405334687c4f5b741226da8 + ), + y: uint256( + 0x06608b7e3be5235cc0368ce844f8c822b118e54f993626431efa578a881b1e01 + ) }), - lagrangeFirst: Honk.G1Point({ - x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), - y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) + lagrangeFirst: Honk.G1Point({ + x: uint256( + 0x0000000000000000000000000000000000000000000000000000000000000001 + ), + y: uint256( + 0x0000000000000000000000000000000000000000000000000000000000000002 + ) }), - lagrangeLast: Honk.G1Point({ - x: uint256(0x1280735205fd7e4a58ee8493d273e5afa2f13bfb7879873c4095a5cbfc646a41), - y: uint256(0x155c3c102286dfdbfe78f876a3c74b9c36a02bb8197154c7d9fedb371f55b779) + lagrangeLast: Honk.G1Point({ + x: uint256( + 0x1280735205fd7e4a58ee8493d273e5afa2f13bfb7879873c4095a5cbfc646a41 + ), + y: uint256( + 0x155c3c102286dfdbfe78f876a3c74b9c36a02bb8197154c7d9fedb371f55b779 + ) }) }); return vk; @@ -135,24 +251,31 @@ library HonkVerificationKey { pragma solidity ^0.8.27; interface IVerifier { - function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external returns (bool); + function verify( + bytes calldata _proof, + bytes32[] calldata _publicInputs + ) external returns (bool); } type Fr is uint256; -using {add as +} for Fr global; -using {sub as -} for Fr global; -using {mul as *} for Fr global; +using { add as + } for Fr global; +using { sub as - } for Fr global; +using { mul as * } for Fr global; -using {exp as ^} for Fr global; -using {notEqual as !=} for Fr global; -using {equal as ==} for Fr global; +using { exp as ^ } for Fr global; +using { notEqual as != } for Fr global; +using { equal as == } for Fr global; uint256 constant SUBGROUP_SIZE = 256; uint256 constant MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Prime field order uint256 constant P = MODULUS; -Fr constant SUBGROUP_GENERATOR = Fr.wrap(0x07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76); -Fr constant SUBGROUP_GENERATOR_INVERSE = Fr.wrap(0x204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6); +Fr constant SUBGROUP_GENERATOR = Fr.wrap( + 0x07b0c561a6148404f086204a9f36ffb0617942546750f230c893619174a57a76 +); +Fr constant SUBGROUP_GENERATOR_INVERSE = Fr.wrap( + 0x204bd3277422fad364751ad938e2b5e6a54cf8c68712848a692c553d0329f5d6 +); Fr constant MINUS_ONE = Fr.wrap(MODULUS - 1); Fr constant ONE = Fr.wrap(1); Fr constant ZERO = Fr.wrap(0); @@ -298,9 +421,11 @@ uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9; uint256 constant NUMBER_OF_ENTITIES = 41; // The number of entities added for ZK (gemini_masking_poly) uint256 constant NUM_MASKING_POLYNOMIALS = 1; -uint256 constant NUMBER_OF_ENTITIES_ZK = NUMBER_OF_ENTITIES + NUM_MASKING_POLYNOMIALS; +uint256 constant NUMBER_OF_ENTITIES_ZK = NUMBER_OF_ENTITIES + + NUM_MASKING_POLYNOMIALS; uint256 constant NUMBER_UNSHIFTED = 36; -uint256 constant NUMBER_UNSHIFTED_ZK = NUMBER_UNSHIFTED + NUM_MASKING_POLYNOMIALS; +uint256 constant NUMBER_UNSHIFTED_ZK = NUMBER_UNSHIFTED + + NUM_MASKING_POLYNOMIALS; uint256 constant NUMBER_TO_BE_SHIFTED = 5; uint256 constant PAIRING_POINTS_SIZE = 16; @@ -496,26 +621,63 @@ library ZKTranscriptLib { uint256 logN ) external pure returns (ZKTranscript memory t) { Fr previousChallenge; - (t.relationParameters, previousChallenge) = - generateRelationParametersChallenges(proof, publicInputs, vkHash, publicInputsSize, previousChallenge); + ( + t.relationParameters, + previousChallenge + ) = generateRelationParametersChallenges( + proof, + publicInputs, + vkHash, + publicInputsSize, + previousChallenge + ); - (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof); + (t.alphas, previousChallenge) = generateAlphaChallenges( + previousChallenge, + proof + ); - (t.gateChallenges, previousChallenge) = generateGateChallenges(previousChallenge, logN); - (t.libraChallenge, previousChallenge) = generateLibraChallenge(previousChallenge, proof); - (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges(proof, previousChallenge, logN); + (t.gateChallenges, previousChallenge) = generateGateChallenges( + previousChallenge, + logN + ); + (t.libraChallenge, previousChallenge) = generateLibraChallenge( + previousChallenge, + proof + ); + (t.sumCheckUChallenges, previousChallenge) = generateSumcheckChallenges( + proof, + previousChallenge, + logN + ); - (t.rho, previousChallenge) = generateRhoChallenge(proof, previousChallenge); + (t.rho, previousChallenge) = generateRhoChallenge( + proof, + previousChallenge + ); - (t.geminiR, previousChallenge) = generateGeminiRChallenge(proof, previousChallenge, logN); + (t.geminiR, previousChallenge) = generateGeminiRChallenge( + proof, + previousChallenge, + logN + ); - (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge(proof, previousChallenge, logN); + (t.shplonkNu, previousChallenge) = generateShplonkNuChallenge( + proof, + previousChallenge, + logN + ); - (t.shplonkZ, previousChallenge) = generateShplonkZChallenge(proof, previousChallenge); + (t.shplonkZ, previousChallenge) = generateShplonkZChallenge( + proof, + previousChallenge + ); return t; } - function splitChallenge(Fr challenge) internal pure returns (Fr first, Fr second) { + function splitChallenge( + Fr challenge + ) internal pure returns (Fr first, Fr second) { uint256 challengeU256 = uint256(Fr.unwrap(challenge)); // Split into two equal 127-bit chunks (254/2) uint256 lo = challengeU256 & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // 127 bits @@ -530,11 +692,23 @@ library ZKTranscriptLib { uint256 vkHash, uint256 publicInputsSize, Fr previousChallenge - ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { - (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = - generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize); + ) + internal + pure + returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) + { + ( + rp.eta, + rp.etaTwo, + rp.etaThree, + previousChallenge + ) = generateEtaChallenge(proof, publicInputs, vkHash, publicInputsSize); - (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); + ( + rp.beta, + rp.gamma, + nextPreviousChallenge + ) = generateBetaAndGammaChallenges(previousChallenge, proof); } function generateEtaChallenge( @@ -542,7 +716,11 @@ library ZKTranscriptLib { bytes32[] calldata publicInputs, uint256 vkHash, uint256 publicInputsSize - ) internal pure returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) { + ) + internal + pure + returns (Fr eta, Fr etaTwo, Fr etaThree, Fr previousChallenge) + { // Size: 1 (vkHash) + publicInputsSize + 8 (geminiMask(2) + 3 wires(6)) bytes32[] memory round0 = new bytes32[](1 + publicInputsSize + 8); round0[0] = bytes32(vkHash); @@ -551,7 +729,8 @@ library ZKTranscriptLib { round0[1 + i] = bytes32(publicInputs[i]); } for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { - round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]); + round0[1 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib + .toBytes32(proof.pairingPointObject[i]); } // For ZK flavors: hash the gemini masking poly commitment (sent right after public inputs) @@ -567,18 +746,21 @@ library ZKTranscriptLib { round0[1 + publicInputsSize + 6] = bytes32(proof.w3.x); round0[1 + publicInputsSize + 7] = bytes32(proof.w3.y); - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round0))); + previousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(round0)) + ); (eta, etaTwo) = splitChallenge(previousChallenge); - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))); + previousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))) + ); - (etaThree,) = splitChallenge(previousChallenge); + (etaThree, ) = splitChallenge(previousChallenge); } - function generateBetaAndGammaChallenges(Fr previousChallenge, Honk.ZKProof memory proof) - internal - pure - returns (Fr beta, Fr gamma, Fr nextPreviousChallenge) - { + function generateBetaAndGammaChallenges( + Fr previousChallenge, + Honk.ZKProof memory proof + ) internal pure returns (Fr beta, Fr gamma, Fr nextPreviousChallenge) { bytes32[7] memory round1; round1[0] = FrLib.toBytes32(previousChallenge); round1[1] = bytes32(proof.lookupReadCounts.x); @@ -588,12 +770,17 @@ library ZKTranscriptLib { round1[5] = bytes32(proof.w4.x); round1[6] = bytes32(proof.w4.y); - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(round1))); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(round1)) + ); (beta, gamma) = splitChallenge(nextPreviousChallenge); } // Alpha challenges non-linearise the gate contributions - function generateAlphaChallenges(Fr previousChallenge, Honk.ZKProof memory proof) + function generateAlphaChallenges( + Fr previousChallenge, + Honk.ZKProof memory proof + ) internal pure returns (Fr[NUMBER_OF_ALPHAS] memory alphas, Fr nextPreviousChallenge) @@ -606,9 +793,11 @@ library ZKTranscriptLib { alpha0[3] = proof.zPerm.x; alpha0[4] = proof.zPerm.y; - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(alpha0))); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(alpha0)) + ); Fr alpha; - (alpha,) = splitChallenge(nextPreviousChallenge); + (alpha, ) = splitChallenge(nextPreviousChallenge); // Compute powers of alpha for batching subrelations alphas[0] = alpha; @@ -617,38 +806,54 @@ library ZKTranscriptLib { } } - function generateGateChallenges(Fr previousChallenge, uint256 logN) + function generateGateChallenges( + Fr previousChallenge, + uint256 logN + ) internal pure - returns (Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, Fr nextPreviousChallenge) + returns ( + Fr[CONST_PROOF_SIZE_LOG_N] memory gateChallenges, + Fr nextPreviousChallenge + ) { - previousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(Fr.unwrap(previousChallenge)))); - (gateChallenges[0],) = splitChallenge(previousChallenge); + previousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(Fr.unwrap(previousChallenge))) + ); + (gateChallenges[0], ) = splitChallenge(previousChallenge); for (uint256 i = 1; i < logN; i++) { gateChallenges[i] = gateChallenges[i - 1] * gateChallenges[i - 1]; } nextPreviousChallenge = previousChallenge; } - function generateLibraChallenge(Fr previousChallenge, Honk.ZKProof memory proof) - internal - pure - returns (Fr libraChallenge, Fr nextPreviousChallenge) - { + function generateLibraChallenge( + Fr previousChallenge, + Honk.ZKProof memory proof + ) internal pure returns (Fr libraChallenge, Fr nextPreviousChallenge) { // 2 comm, 1 sum, 1 challenge uint256[4] memory challengeData; challengeData[0] = Fr.unwrap(previousChallenge); challengeData[1] = proof.libraCommitments[0].x; challengeData[2] = proof.libraCommitments[0].y; challengeData[3] = Fr.unwrap(proof.libraSum); - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(challengeData))); - (libraChallenge,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(challengeData)) + ); + (libraChallenge, ) = splitChallenge(nextPreviousChallenge); } - function generateSumcheckChallenges(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) + function generateSumcheckChallenges( + Honk.ZKProof memory proof, + Fr prevChallenge, + uint256 logN + ) internal pure - returns (Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, Fr nextPreviousChallenge) + returns ( + Fr[CONST_PROOF_SIZE_LOG_N] memory sumcheckChallenges, + Fr nextPreviousChallenge + ) { for (uint256 i = 0; i < logN; i++) { Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH + 1] memory univariateChal; @@ -657,24 +862,27 @@ library ZKTranscriptLib { for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) { univariateChal[j + 1] = proof.sumcheckUnivariates[i][j]; } - prevChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(univariateChal))); + prevChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(univariateChal)) + ); - (sumcheckChallenges[i],) = splitChallenge(prevChallenge); + (sumcheckChallenges[i], ) = splitChallenge(prevChallenge); } nextPreviousChallenge = prevChallenge; } // We add Libra claimed eval + 2 libra commitments (grand_sum, quotient) - function generateRhoChallenge(Honk.ZKProof memory proof, Fr prevChallenge) - internal - pure - returns (Fr rho, Fr nextPreviousChallenge) - { + function generateRhoChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge + ) internal pure returns (Fr rho, Fr nextPreviousChallenge) { uint256[NUMBER_OF_ENTITIES_ZK + 6] memory rhoChallengeElements; rhoChallengeElements[0] = Fr.unwrap(prevChallenge); uint256 i; for (i = 1; i <= NUMBER_OF_ENTITIES_ZK; i++) { - rhoChallengeElements[i] = Fr.unwrap(proof.sumcheckEvaluations[i - 1]); + rhoChallengeElements[i] = Fr.unwrap( + proof.sumcheckEvaluations[i - 1] + ); } rhoChallengeElements[i] = Fr.unwrap(proof.libraEvaluation); i += 1; @@ -684,15 +892,17 @@ library ZKTranscriptLib { rhoChallengeElements[i] = proof.libraCommitments[2].x; rhoChallengeElements[i + 1] = proof.libraCommitments[2].y; - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(rhoChallengeElements))); - (rho,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(rhoChallengeElements)) + ); + (rho, ) = splitChallenge(nextPreviousChallenge); } - function generateGeminiRChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) - internal - pure - returns (Fr geminiR, Fr nextPreviousChallenge) - { + function generateGeminiRChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge, + uint256 logN + ) internal pure returns (Fr geminiR, Fr nextPreviousChallenge) { uint256[] memory gR = new uint256[]((logN - 1) * 2 + 1); gR[0] = Fr.unwrap(prevChallenge); @@ -701,59 +911,77 @@ library ZKTranscriptLib { gR[2 + i * 2] = proof.geminiFoldComms[i].y; } - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(gR))); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(gR)) + ); - (geminiR,) = splitChallenge(nextPreviousChallenge); + (geminiR, ) = splitChallenge(nextPreviousChallenge); } - function generateShplonkNuChallenge(Honk.ZKProof memory proof, Fr prevChallenge, uint256 logN) - internal - pure - returns (Fr shplonkNu, Fr nextPreviousChallenge) - { - uint256[] memory shplonkNuChallengeElements = new uint256[](logN + 1 + 4); + function generateShplonkNuChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge, + uint256 logN + ) internal pure returns (Fr shplonkNu, Fr nextPreviousChallenge) { + uint256[] memory shplonkNuChallengeElements = new uint256[]( + logN + 1 + 4 + ); shplonkNuChallengeElements[0] = Fr.unwrap(prevChallenge); for (uint256 i = 1; i <= logN; i++) { - shplonkNuChallengeElements[i] = Fr.unwrap(proof.geminiAEvaluations[i - 1]); + shplonkNuChallengeElements[i] = Fr.unwrap( + proof.geminiAEvaluations[i - 1] + ); } uint256 libraIdx = 0; for (uint256 i = logN + 1; i <= logN + 4; i++) { - shplonkNuChallengeElements[i] = Fr.unwrap(proof.libraPolyEvals[libraIdx]); + shplonkNuChallengeElements[i] = Fr.unwrap( + proof.libraPolyEvals[libraIdx] + ); libraIdx++; } - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkNuChallengeElements))); - (shplonkNu,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(shplonkNuChallengeElements)) + ); + (shplonkNu, ) = splitChallenge(nextPreviousChallenge); } - function generateShplonkZChallenge(Honk.ZKProof memory proof, Fr prevChallenge) - internal - pure - returns (Fr shplonkZ, Fr nextPreviousChallenge) - { + function generateShplonkZChallenge( + Honk.ZKProof memory proof, + Fr prevChallenge + ) internal pure returns (Fr shplonkZ, Fr nextPreviousChallenge) { uint256[3] memory shplonkZChallengeElements; shplonkZChallengeElements[0] = Fr.unwrap(prevChallenge); shplonkZChallengeElements[1] = proof.shplonkQ.x; shplonkZChallengeElements[2] = proof.shplonkQ.y; - nextPreviousChallenge = FrLib.fromBytes32(keccak256(abi.encodePacked(shplonkZChallengeElements))); - (shplonkZ,) = splitChallenge(nextPreviousChallenge); + nextPreviousChallenge = FrLib.fromBytes32( + keccak256(abi.encodePacked(shplonkZChallengeElements)) + ); + (shplonkZ, ) = splitChallenge(nextPreviousChallenge); } - function loadProof(bytes calldata proof, uint256 logN) internal pure returns (Honk.ZKProof memory p) { + function loadProof( + bytes calldata proof, + uint256 logN + ) internal pure returns (Honk.ZKProof memory p) { uint256 boundary = 0x0; // Pairing point object for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { - p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.pairingPointObject[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } // Gemini masking polynomial commitment (sent first in ZK flavors, right after pairing points) - p.geminiMaskingPoly = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.geminiMaskingPoly = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; // Commitments @@ -765,17 +993,25 @@ library ZKTranscriptLib { boundary += GROUP_ELEMENT_SIZE; // Lookup / Permutation Helper Commitments - p.lookupReadCounts = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupReadCounts = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; - p.lookupReadTags = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupReadTags = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; p.w4 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); boundary += GROUP_ELEMENT_SIZE; - p.lookupInverses = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupInverses = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; p.zPerm = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); boundary += GROUP_ELEMENT_SIZE; - p.libraCommitments[0] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.libraCommitments[0] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; p.libraSum = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); @@ -783,48 +1019,68 @@ library ZKTranscriptLib { // Sumcheck univariates for (uint256 i = 0; i < logN; i++) { for (uint256 j = 0; j < ZK_BATCHED_RELATION_PARTIAL_LENGTH; j++) { - p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.sumcheckUnivariates[i][j] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } } // Sumcheck evaluations (includes gemini_masking_poly eval at index 0 for ZK flavors) for (uint256 i = 0; i < NUMBER_OF_ENTITIES_ZK; i++) { - p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.sumcheckEvaluations[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } - p.libraEvaluation = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.libraEvaluation = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; - p.libraCommitments[1] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.libraCommitments[1] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; - p.libraCommitments[2] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.libraCommitments[2] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; // Gemini // Read gemini fold univariates for (uint256 i = 0; i < logN - 1; i++) { - p.geminiFoldComms[i] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.geminiFoldComms[i] = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; } // Read gemini a evaluations for (uint256 i = 0; i < logN; i++) { - p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.geminiAEvaluations[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } for (uint256 i = 0; i < 4; i++) { - p.libraPolyEvals[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.libraPolyEvals[i] = bytesToFr( + proof[boundary:boundary + FIELD_ELEMENT_SIZE] + ); boundary += FIELD_ELEMENT_SIZE; } // Shplonk - p.shplonkQ = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.shplonkQ = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); boundary += GROUP_ELEMENT_SIZE; // KZG - p.kzgQuotient = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.kzgQuotient = bytesToG1Point( + proof[boundary:boundary + GROUP_ELEMENT_SIZE] + ); } } @@ -842,18 +1098,60 @@ library RelationsLib { Fr[NUMBER_OF_SUBRELATIONS] memory evaluations; // Accumulate all relations in Ultra Honk - each with varying number of subrelations - accumulateArithmeticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePermutationRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateLogDerivativeLookupRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateDeltaRangeRelation(purportedEvaluations, evaluations, powPartialEval); - accumulateEllipticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulateMemoryRelation(purportedEvaluations, rp, evaluations, powPartialEval); - accumulateNnfRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval); + accumulateArithmeticRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulatePermutationRelation( + purportedEvaluations, + rp, + evaluations, + powPartialEval + ); + accumulateLogDerivativeLookupRelation( + purportedEvaluations, + rp, + evaluations, + powPartialEval + ); + accumulateDeltaRangeRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulateEllipticRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulateMemoryRelation( + purportedEvaluations, + rp, + evaluations, + powPartialEval + ); + accumulateNnfRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulatePoseidonExternalRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); + accumulatePoseidonInternalRelation( + purportedEvaluations, + evaluations, + powPartialEval + ); // batch the subrelations with the precomputed alpha powers to obtain the full honk relation - accumulator = scaleAndBatchSubrelations(evaluations, subrelationChallenges); + accumulator = scaleAndBatchSubrelations( + evaluations, + subrelationChallenges + ); } /** @@ -861,11 +1159,15 @@ library RelationsLib { * the relation checking code being cluttered with uint256 type casting, which is often a different colour in code * editors, and thus is noisy. */ - function wire(Fr[NUMBER_OF_ENTITIES] memory p, WIRE _wire) internal pure returns (Fr) { + function wire( + Fr[NUMBER_OF_ENTITIES] memory p, + WIRE _wire + ) internal pure returns (Fr) { return p[uint256(_wire)]; } - uint256 internal constant NEG_HALF_MODULO_P = 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; + uint256 internal constant NEG_HALF_MODULO_P = + 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000; /** * Ultra Arithmetic Relation * @@ -881,9 +1183,16 @@ library RelationsLib { { Fr neg_half = Fr.wrap(NEG_HALF_MODULO_P); - Fr accum = (q_arith - Fr.wrap(3)) * (wire(p, WIRE.Q_M) * wire(p, WIRE.W_R) * wire(p, WIRE.W_L)) * neg_half; - accum = accum + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R)) - + (wire(p, WIRE.Q_O) * wire(p, WIRE.W_O)) + (wire(p, WIRE.Q_4) * wire(p, WIRE.W_4)) + wire(p, WIRE.Q_C); + Fr accum = (q_arith - Fr.wrap(3)) * + (wire(p, WIRE.Q_M) * wire(p, WIRE.W_R) * wire(p, WIRE.W_L)) * + neg_half; + accum = + accum + + (wire(p, WIRE.Q_L) * wire(p, WIRE.W_L)) + + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_R)) + + (wire(p, WIRE.Q_O) * wire(p, WIRE.W_O)) + + (wire(p, WIRE.Q_4) * wire(p, WIRE.W_4)) + + wire(p, WIRE.Q_C); accum = accum + (q_arith - ONE) * wire(p, WIRE.W_4_SHIFT); accum = accum * q_arith; accum = accum * domainSep; @@ -892,7 +1201,10 @@ library RelationsLib { // Relation 1 { - Fr accum = wire(p, WIRE.W_L) + wire(p, WIRE.W_4) - wire(p, WIRE.W_L_SHIFT) + wire(p, WIRE.Q_M); + Fr accum = wire(p, WIRE.W_L) + + wire(p, WIRE.W_4) - + wire(p, WIRE.W_L_SHIFT) + + wire(p, WIRE.Q_M); accum = accum * (q_arith - Fr.wrap(2)); accum = accum * (q_arith - ONE); accum = accum * q_arith; @@ -911,36 +1223,67 @@ library RelationsLib { Fr grand_product_denominator; { - Fr num = wire(p, WIRE.W_L) + wire(p, WIRE.ID_1) * rp.beta + rp.gamma; - num = num * (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma); - num = num * (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma); - num = num * (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma); + Fr num = wire(p, WIRE.W_L) + + wire(p, WIRE.ID_1) * + rp.beta + + rp.gamma; + num = + num * + (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma); + num = + num * + (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma); + num = + num * + (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma); grand_product_numerator = num; } { - Fr den = wire(p, WIRE.W_L) + wire(p, WIRE.SIGMA_1) * rp.beta + rp.gamma; - den = den * (wire(p, WIRE.W_R) + wire(p, WIRE.SIGMA_2) * rp.beta + rp.gamma); - den = den * (wire(p, WIRE.W_O) + wire(p, WIRE.SIGMA_3) * rp.beta + rp.gamma); - den = den * (wire(p, WIRE.W_4) + wire(p, WIRE.SIGMA_4) * rp.beta + rp.gamma); + Fr den = wire(p, WIRE.W_L) + + wire(p, WIRE.SIGMA_1) * + rp.beta + + rp.gamma; + den = + den * + (wire(p, WIRE.W_R) + + wire(p, WIRE.SIGMA_2) * + rp.beta + + rp.gamma); + den = + den * + (wire(p, WIRE.W_O) + + wire(p, WIRE.SIGMA_3) * + rp.beta + + rp.gamma); + den = + den * + (wire(p, WIRE.W_4) + + wire(p, WIRE.SIGMA_4) * + rp.beta + + rp.gamma); grand_product_denominator = den; } // Contribution 2 { - Fr acc = (wire(p, WIRE.Z_PERM) + wire(p, WIRE.LAGRANGE_FIRST)) * grand_product_numerator; - - acc = acc - - ((wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) - * grand_product_denominator); + Fr acc = (wire(p, WIRE.Z_PERM) + wire(p, WIRE.LAGRANGE_FIRST)) * + grand_product_numerator; + + acc = + acc - + ((wire(p, WIRE.Z_PERM_SHIFT) + + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) * + grand_product_denominator); acc = acc * domainSep; evals[2] = acc; } // Contribution 3 { - Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; + Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * + wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; evals[3] = acc; } } @@ -956,33 +1299,52 @@ library RelationsLib { // Calculate the write term (the table accumulation) { - write_term = wire(p, WIRE.TABLE_1) + rp.gamma + (wire(p, WIRE.TABLE_2) * rp.eta) - + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + (wire(p, WIRE.TABLE_4) * rp.etaThree); + write_term = + wire(p, WIRE.TABLE_1) + + rp.gamma + + (wire(p, WIRE.TABLE_2) * rp.eta) + + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + + (wire(p, WIRE.TABLE_4) * rp.etaThree); } // Calculate the write term { - Fr derived_entry_1 = wire(p, WIRE.W_L) + rp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); - Fr derived_entry_2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_M) * wire(p, WIRE.W_R_SHIFT); - Fr derived_entry_3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_C) * wire(p, WIRE.W_O_SHIFT); - - read_term = derived_entry_1 + (derived_entry_2 * rp.eta) + (derived_entry_3 * rp.etaTwo) - + (wire(p, WIRE.Q_O) * rp.etaThree); + Fr derived_entry_1 = wire(p, WIRE.W_L) + + rp.gamma + + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); + Fr derived_entry_2 = wire(p, WIRE.W_R) + + wire(p, WIRE.Q_M) * + wire(p, WIRE.W_R_SHIFT); + Fr derived_entry_3 = wire(p, WIRE.W_O) + + wire(p, WIRE.Q_C) * + wire(p, WIRE.W_O_SHIFT); + + read_term = + derived_entry_1 + + (derived_entry_2 * rp.eta) + + (derived_entry_3 * rp.etaTwo) + + (wire(p, WIRE.Q_O) * rp.etaThree); } Fr read_inverse = wire(p, WIRE.LOOKUP_INVERSES) * write_term; Fr write_inverse = wire(p, WIRE.LOOKUP_INVERSES) * read_term; - Fr inverse_exists_xor = - wire(p, WIRE.LOOKUP_READ_TAGS) + wire(p, WIRE.Q_LOOKUP) - - (wire(p, WIRE.LOOKUP_READ_TAGS) * wire(p, WIRE.Q_LOOKUP)); + Fr inverse_exists_xor = wire(p, WIRE.LOOKUP_READ_TAGS) + + wire(p, WIRE.Q_LOOKUP) - + (wire(p, WIRE.LOOKUP_READ_TAGS) * wire(p, WIRE.Q_LOOKUP)); // Inverse calculated correctly relation - Fr accumulatorNone = read_term * write_term * wire(p, WIRE.LOOKUP_INVERSES) - inverse_exists_xor; + Fr accumulatorNone = read_term * + write_term * + wire(p, WIRE.LOOKUP_INVERSES) - + inverse_exists_xor; accumulatorNone = accumulatorNone * domainSep; // Inverse - Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * read_inverse - wire(p, WIRE.LOOKUP_READ_COUNTS) * write_inverse; + Fr accumulatorOne = wire(p, WIRE.Q_LOOKUP) * + read_inverse - + wire(p, WIRE.LOOKUP_READ_COUNTS) * + write_inverse; Fr read_tag = wire(p, WIRE.LOOKUP_READ_TAGS); @@ -1096,7 +1458,11 @@ library RelationsLib { x_add_identity = x_add_identity * x_diff * x_diff; x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2; - evals[11] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + evals[11] = + x_add_identity * + partialEval * + wire(p, WIRE.Q_ELLIPTIC) * + (ONE - q_is_double); } // Contribution 11 point addition, x-coordinate check @@ -1104,8 +1470,15 @@ library RelationsLib { { Fr y1_plus_y3 = ep.y_1 + ep.y_3; Fr y_diff = ep.y_2 * q_sign - ep.y_1; - Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff; - evals[12] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + Fr y_add_identity = y1_plus_y3 * + x_diff + + (ep.x_3 - ep.x_1) * + y_diff; + evals[12] = + y_add_identity * + domainSep * + wire(p, WIRE.Q_ELLIPTIC) * + (ONE - q_is_double); } // Contribution 10 point doubling, x-coordinate check @@ -1118,9 +1491,15 @@ library RelationsLib { Fr x1_pow_4_mul_9 = x_pow_4 * Fr.wrap(9); // NOTE: pushed into memory (stack >:'( ) - ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9; - - Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + ep.x_double_identity = + (ep.x_3 + ep.x_1 + ep.x_1) * + y1_sqr_mul_4 - + x1_pow_4_mul_9; + + Fr acc = ep.x_double_identity * + domainSep * + wire(p, WIRE.Q_ELLIPTIC) * + q_is_double; evals[11] = evals[11] + acc; } @@ -1128,8 +1507,16 @@ library RelationsLib { // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0 { Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1; - Fr y_double_identity = x1_sqr_mul_3 * (ep.x_1 - ep.x_3) - (ep.y_1 + ep.y_1) * (ep.y_1 + ep.y_3); - evals[12] = evals[12] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + Fr y_double_identity = x1_sqr_mul_3 * + (ep.x_1 - ep.x_3) - + (ep.y_1 + ep.y_1) * + (ep.y_1 + ep.y_3); + evals[12] = + evals[12] + + y_double_identity * + domainSep * + wire(p, WIRE.Q_ELLIPTIC) * + q_is_double; } } @@ -1203,8 +1590,12 @@ library RelationsLib { * For ROM gates, qc = 0 */ ap.memory_record_check = wire(p, WIRE.W_O) * rp.etaThree; - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * rp.etaTwo); - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * rp.eta); + ap.memory_record_check = + ap.memory_record_check + + (wire(p, WIRE.W_R) * rp.etaTwo); + ap.memory_record_check = + ap.memory_record_check + + (wire(p, WIRE.W_L) * rp.eta); ap.memory_record_check = ap.memory_record_check + wire(p, WIRE.Q_C); ap.partial_record_check = ap.memory_record_check; // used in RAM consistency check; deg 1 or 4 ap.memory_record_check = ap.memory_record_check - wire(p, WIRE.W_4); @@ -1228,16 +1619,26 @@ library RelationsLib { ap.index_delta = wire(p, WIRE.W_L_SHIFT) - wire(p, WIRE.W_L); ap.record_delta = wire(p, WIRE.W_4_SHIFT) - wire(p, WIRE.W_4); - ap.index_is_monotonically_increasing = ap.index_delta * (ap.index_delta - Fr.wrap(1)); // deg 2 + ap.index_is_monotonically_increasing = + ap.index_delta * + (ap.index_delta - Fr.wrap(1)); // deg 2 - ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + ONE) * ap.record_delta; // deg 2 + ap.adjacent_values_match_if_adjacent_indices_match = + (ap.index_delta * MINUS_ONE + ONE) * + ap.record_delta; // deg 2 - evals[14] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) - * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - evals[15] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) - * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 + evals[14] = + ap.adjacent_values_match_if_adjacent_indices_match * + (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 + evals[15] = + ap.index_is_monotonically_increasing * + (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 + ap.ROM_consistency_check_identity = + ap.memory_record_check * + (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 /** * Contributions 15,16,17 @@ -1264,13 +1665,22 @@ library RelationsLib { // reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta // deg 1 or 4 ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree; - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta); - ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type; + ap.next_gate_access_type = + ap.next_gate_access_type + + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); + ap.next_gate_access_type = + ap.next_gate_access_type + + (wire(p, WIRE.W_L_SHIFT) * rp.eta); + ap.next_gate_access_type = + wire(p, WIRE.W_4_SHIFT) - + ap.next_gate_access_type; Fr value_delta = wire(p, WIRE.W_O_SHIFT) - wire(p, WIRE.W_O); - ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = - (ap.index_delta * MINUS_ONE + ONE) * value_delta * (ap.next_gate_access_type * MINUS_ONE + ONE); // deg 3 or 6 + ap + .adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = + (ap.index_delta * MINUS_ONE + ONE) * + value_delta * + (ap.next_gate_access_type * MINUS_ONE + ONE); // deg 3 or 6 // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the // next gate would make the identity fail). We need to validate that its 'access type' bool is correct. Can't @@ -1278,15 +1688,28 @@ library RelationsLib { // type is correct, to cover this edge case // deg 2 or 4 ap.next_gate_access_type_is_boolean = - ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type; + ap.next_gate_access_type * + ap.next_gate_access_type - + ap.next_gate_access_type; // Putting it all together... - evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation - * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 - evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 - evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 - - ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9 + evals[16] = + ap + .adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * + (wire(p, WIRE.Q_O)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 + evals[17] = + ap.index_is_monotonically_increasing * + (wire(p, WIRE.Q_O)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 + evals[18] = + ap.next_gate_access_type_is_boolean * + (wire(p, WIRE.Q_O)) * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 + + ap.RAM_consistency_check_identity = + ap.access_check * + (wire(p, WIRE.Q_O)); // deg 3 or 9 /** * RAM Timestamp Consistency Check @@ -1300,7 +1723,10 @@ library RelationsLib { * Else timestamp_check = 0 */ ap.timestamp_delta = wire(p, WIRE.W_R_SHIFT) - wire(p, WIRE.W_R); - ap.RAM_timestamp_check_identity = (ap.index_delta * MINUS_ONE + ONE) * ap.timestamp_delta - wire(p, WIRE.W_O); // deg 3 + ap.RAM_timestamp_check_identity = + (ap.index_delta * MINUS_ONE + ONE) * + ap.timestamp_delta - + wire(p, WIRE.W_O); // deg 3 /** * Complete Contribution 12 @@ -1309,12 +1735,21 @@ library RelationsLib { */ ap.memory_identity = ap.ROM_consistency_check_identity; // deg 3 or 6 ap.memory_identity = - ap.memory_identity + ap.RAM_timestamp_check_identity * (wire(p, WIRE.Q_4) * wire(p, WIRE.Q_L)); // deg 4 - ap.memory_identity = ap.memory_identity + ap.memory_record_check * (wire(p, WIRE.Q_M) * wire(p, WIRE.Q_L)); // deg 3 or 6 - ap.memory_identity = ap.memory_identity + ap.RAM_consistency_check_identity; // deg 3 or 9 + ap.memory_identity + + ap.RAM_timestamp_check_identity * + (wire(p, WIRE.Q_4) * wire(p, WIRE.Q_L)); // deg 4 + ap.memory_identity = + ap.memory_identity + + ap.memory_record_check * + (wire(p, WIRE.Q_M) * wire(p, WIRE.Q_L)); // deg 3 or 6 + ap.memory_identity = + ap.memory_identity + + ap.RAM_consistency_check_identity; // deg 3 or 9 // (deg 3 or 9) + (deg 4) + (deg 3) - ap.memory_identity = ap.memory_identity * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10 + ap.memory_identity = + ap.memory_identity * + (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10 evals[13] = ap.memory_identity; } @@ -1353,28 +1788,56 @@ library RelationsLib { * * */ - ap.limb_subproduct = wire(p, WIRE.W_L) * wire(p, WIRE.W_R_SHIFT) + wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R); - ap.non_native_field_gate_2 = - (wire(p, WIRE.W_L) * wire(p, WIRE.W_4) + wire(p, WIRE.W_R) * wire(p, WIRE.W_O) - wire(p, WIRE.W_O_SHIFT)); + ap.limb_subproduct = + wire(p, WIRE.W_L) * + wire(p, WIRE.W_R_SHIFT) + + wire(p, WIRE.W_L_SHIFT) * + wire(p, WIRE.W_R); + ap.non_native_field_gate_2 = (wire(p, WIRE.W_L) * + wire(p, WIRE.W_4) + + wire(p, WIRE.W_R) * + wire(p, WIRE.W_O) - + wire(p, WIRE.W_O_SHIFT)); ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * LIMB_SIZE; - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 - wire(p, WIRE.W_4_SHIFT); - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 + ap.limb_subproduct; - ap.non_native_field_gate_2 = ap.non_native_field_gate_2 * wire(p, WIRE.Q_4); + ap.non_native_field_gate_2 = + ap.non_native_field_gate_2 - + wire(p, WIRE.W_4_SHIFT); + ap.non_native_field_gate_2 = + ap.non_native_field_gate_2 + + ap.limb_subproduct; + ap.non_native_field_gate_2 = + ap.non_native_field_gate_2 * + wire(p, WIRE.Q_4); ap.limb_subproduct = ap.limb_subproduct * LIMB_SIZE; - ap.limb_subproduct = ap.limb_subproduct + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT)); + ap.limb_subproduct = + ap.limb_subproduct + + (wire(p, WIRE.W_L_SHIFT) * wire(p, WIRE.W_R_SHIFT)); ap.non_native_field_gate_1 = ap.limb_subproduct; - ap.non_native_field_gate_1 = ap.non_native_field_gate_1 - (wire(p, WIRE.W_O) + wire(p, WIRE.W_4)); - ap.non_native_field_gate_1 = ap.non_native_field_gate_1 * wire(p, WIRE.Q_O); + ap.non_native_field_gate_1 = + ap.non_native_field_gate_1 - + (wire(p, WIRE.W_O) + wire(p, WIRE.W_4)); + ap.non_native_field_gate_1 = + ap.non_native_field_gate_1 * + wire(p, WIRE.Q_O); ap.non_native_field_gate_3 = ap.limb_subproduct; - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 + wire(p, WIRE.W_4); - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 - (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT)); - ap.non_native_field_gate_3 = ap.non_native_field_gate_3 * wire(p, WIRE.Q_M); - - Fr non_native_field_identity = - ap.non_native_field_gate_1 + ap.non_native_field_gate_2 + ap.non_native_field_gate_3; - non_native_field_identity = non_native_field_identity * wire(p, WIRE.Q_R); + ap.non_native_field_gate_3 = + ap.non_native_field_gate_3 + + wire(p, WIRE.W_4); + ap.non_native_field_gate_3 = + ap.non_native_field_gate_3 - + (wire(p, WIRE.W_O_SHIFT) + wire(p, WIRE.W_4_SHIFT)); + ap.non_native_field_gate_3 = + ap.non_native_field_gate_3 * + wire(p, WIRE.Q_M); + + Fr non_native_field_identity = ap.non_native_field_gate_1 + + ap.non_native_field_gate_2 + + ap.non_native_field_gate_3; + non_native_field_identity = + non_native_field_identity * + wire(p, WIRE.Q_R); // ((((w2' * 2^14 + w1') * 2^14 + w3) * 2^14 + w2) * 2^14 + w1 - w4) * qm // deg 2 @@ -1402,8 +1865,11 @@ library RelationsLib { ap.limb_accumulator_2 = ap.limb_accumulator_2 - wire(p, WIRE.W_4_SHIFT); ap.limb_accumulator_2 = ap.limb_accumulator_2 * wire(p, WIRE.Q_M); - Fr limb_accumulator_identity = ap.limb_accumulator_1 + ap.limb_accumulator_2; - limb_accumulator_identity = limb_accumulator_identity * wire(p, WIRE.Q_O); // deg 3 + Fr limb_accumulator_identity = ap.limb_accumulator_1 + + ap.limb_accumulator_2; + limb_accumulator_identity = + limb_accumulator_identity * + wire(p, WIRE.Q_O); // deg 3 ap.nnf_identity = non_native_field_identity + limb_accumulator_identity; ap.nnf_identity = ap.nnf_identity * (wire(p, WIRE.Q_NNF) * domainSep); @@ -1463,13 +1929,25 @@ library RelationsLib { ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4 ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep; - evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[20] = + evals[20] + + ep.q_pos_by_scaling * + (ep.v1 - wire(p, WIRE.W_L_SHIFT)); - evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[21] = + evals[21] + + ep.q_pos_by_scaling * + (ep.v2 - wire(p, WIRE.W_R_SHIFT)); - evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[22] = + evals[22] + + ep.q_pos_by_scaling * + (ep.v3 - wire(p, WIRE.W_O_SHIFT)); - evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[23] = + evals[23] + + ep.q_pos_by_scaling * + (ep.v4 - wire(p, WIRE.W_4_SHIFT)); } struct PoseidonInternalParams { @@ -1494,10 +1972,18 @@ library RelationsLib { PoseidonInternalParams memory ip; Fr[4] memory INTERNAL_MATRIX_DIAGONAL = [ - FrLib.from(0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7), - FrLib.from(0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b), - FrLib.from(0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15), - FrLib.from(0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b) + FrLib.from( + 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7 + ), + FrLib.from( + 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740b + ), + FrLib.from( + 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15 + ), + FrLib.from( + 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428b + ) ]; // add round constants @@ -1515,16 +2001,28 @@ library RelationsLib { ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep; ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum; - evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[24] = + evals[24] + + ip.q_pos_by_scaling * + (ip.v1 - wire(p, WIRE.W_L_SHIFT)); ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum; - evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[25] = + evals[25] + + ip.q_pos_by_scaling * + (ip.v2 - wire(p, WIRE.W_R_SHIFT)); ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum; - evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[26] = + evals[26] + + ip.q_pos_by_scaling * + (ip.v3 - wire(p, WIRE.W_O_SHIFT)); ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum; - evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[27] = + evals[27] + + ip.q_pos_by_scaling * + (ip.v4 - wire(p, WIRE.W_4_SHIFT)); } // Batch subrelation evaluations using precomputed powers of alpha @@ -1536,7 +2034,10 @@ library RelationsLib { accumulator = evaluations[0]; for (uint256 i = 1; i < NUMBER_OF_SUBRELATIONS; ++i) { - accumulator = accumulator + evaluations[i] * subrelationChallenges[i - 1]; + accumulator = + accumulator + + evaluations[i] * + subrelationChallenges[i - 1]; } } } @@ -1572,7 +2073,10 @@ library CommitmentSchemeLib { Fr[] foldPosEvaluations; } - function computeSquares(Fr r, uint256 logN) internal pure returns (Fr[] memory) { + function computeSquares( + Fr r, + uint256 logN + ) internal pure returns (Fr[] memory) { Fr[] memory squares = new Fr[](logN); squares[0] = r; for (uint256 i = 1; i < logN; ++i) { @@ -1594,10 +2098,15 @@ library CommitmentSchemeLib { Fr challengePower = geminiEvalChallengePowers[i - 1]; Fr u = sumcheckUChallenges[i - 1]; - Fr batchedEvalRoundAcc = ((challengePower * batchedEvalAccumulator * Fr.wrap(2)) - geminiEvaluations[i - 1] - * (challengePower * (ONE - u) - u)); + Fr batchedEvalRoundAcc = ((challengePower * + batchedEvalAccumulator * + Fr.wrap(2)) - + geminiEvaluations[i - 1] * + (challengePower * (ONE - u) - u)); // Divide by the denominator - batchedEvalRoundAcc = batchedEvalRoundAcc * (challengePower * (ONE - u) + u).invert(); + batchedEvalRoundAcc = + batchedEvalRoundAcc * + (challengePower * (ONE - u) + u).invert(); batchedEvalAccumulator = batchedEvalRoundAcc; foldPosEvaluations[i - 1] = batchedEvalRoundAcc; @@ -1628,13 +2137,18 @@ function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) { } // EC Point utilities -function bytesToG1Point(bytes calldata proofSection) pure returns (Honk.G1Point memory point) { +function bytesToG1Point( + bytes calldata proofSection +) pure returns (Honk.G1Point memory point) { point = Honk.G1Point({ - x: uint256(bytes32(proofSection[0x00:0x20])) % Q, y: uint256(bytes32(proofSection[0x20:0x40])) % Q + x: uint256(bytes32(proofSection[0x00:0x20])) % Q, + y: uint256(bytes32(proofSection[0x20:0x40])) % Q }); } -function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) { +function negateInplace( + Honk.G1Point memory point +) pure returns (Honk.G1Point memory) { point.y = (Q - point.y) % Q; return point; } @@ -1651,10 +2165,9 @@ function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point mem * @return lhs * @return rhs */ -function convertPairingPointsToG1(Fr[PAIRING_POINTS_SIZE] memory pairingPoints) - pure - returns (Honk.G1Point memory lhs, Honk.G1Point memory rhs) -{ +function convertPairingPointsToG1( + Fr[PAIRING_POINTS_SIZE] memory pairingPoints +) pure returns (Honk.G1Point memory lhs, Honk.G1Point memory rhs) { uint256 lhsX = Fr.unwrap(pairingPoints[0]); lhsX |= Fr.unwrap(pairingPoints[1]) << 68; lhsX |= Fr.unwrap(pairingPoints[2]) << 136; @@ -1698,7 +2211,10 @@ function generateRecursionSeparator( // hash the accum X // hash the accum Y - (Honk.G1Point memory proofLhs, Honk.G1Point memory proofRhs) = convertPairingPointsToG1(proofPairingPoints); + ( + Honk.G1Point memory proofLhs, + Honk.G1Point memory proofRhs + ) = convertPairingPointsToG1(proofPairingPoints); uint256[8] memory recursionSeparatorElements; @@ -1714,7 +2230,9 @@ function generateRecursionSeparator( recursionSeparatorElements[6] = accRhs.x; recursionSeparatorElements[7] = accRhs.y; - recursionSeparator = FrLib.fromBytes32(keccak256(abi.encodePacked(recursionSeparatorElements))); + recursionSeparator = FrLib.fromBytes32( + keccak256(abi.encodePacked(recursionSeparatorElements)) + ); } /** @@ -1726,10 +2244,11 @@ function generateRecursionSeparator( * @param recursionSeperator The separator to use for the multiplication. * @return `(recursionSeperator * basePoint) + other`. */ -function mulWithSeperator(Honk.G1Point memory basePoint, Honk.G1Point memory other, Fr recursionSeperator) - view - returns (Honk.G1Point memory) -{ +function mulWithSeperator( + Honk.G1Point memory basePoint, + Honk.G1Point memory other, + Fr recursionSeperator +) view returns (Honk.G1Point memory) { Honk.G1Point memory result; result = ecMul(recursionSeperator, basePoint); @@ -1746,7 +2265,10 @@ function mulWithSeperator(Honk.G1Point memory basePoint, Honk.G1Point memory oth * @param point The point to multiply. * @return result The result of the multiplication. */ -function ecMul(Fr value, Honk.G1Point memory point) view returns (Honk.G1Point memory) { +function ecMul( + Fr value, + Honk.G1Point memory point +) view returns (Honk.G1Point memory) { Honk.G1Point memory result; assembly { @@ -1792,7 +2314,10 @@ function ecMul(Fr value, Honk.G1Point memory point) view returns (Honk.G1Point m * @param rhs The right hand side of the addition. * @return result The result of the addition. */ -function ecAdd(Honk.G1Point memory lhs, Honk.G1Point memory rhs) view returns (Honk.G1Point memory) { +function ecAdd( + Honk.G1Point memory lhs, + Honk.G1Point memory rhs +) view returns (Honk.G1Point memory) { Honk.G1Point memory result; assembly { @@ -1816,7 +2341,9 @@ function ecAdd(Honk.G1Point memory lhs, Honk.G1Point memory rhs) view returns (H // Call the ecAdd precompile, it takes in the following // [lhs.x, lhs.y, rhs.x, rhs.y], and returns their addition back into the free memory location. let success := staticcall(gas(), 0x06, free, 0x80, free, 0x40) - if iszero(success) { revert(0, 0) } + if iszero(success) { + revert(0, 0) + } // Copy the result of the addition back into the result memory location. // Memory layout: @@ -1845,22 +2372,41 @@ function validateOnCurve(Honk.G1Point memory point) pure { require(success, "point is not on the curve"); } -function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns (bool decodedResult) { +function pairing( + Honk.G1Point memory rhs, + Honk.G1Point memory lhs +) view returns (bool decodedResult) { bytes memory input = abi.encodePacked( rhs.x, rhs.y, // Fixed G2 point - uint256(0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2), - uint256(0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed), - uint256(0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b), - uint256(0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa), + uint256( + 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2 + ), + uint256( + 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed + ), + uint256( + 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b + ), + uint256( + 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa + ), lhs.x, lhs.y, // G2 point from VK - uint256(0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1), - uint256(0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0), - uint256(0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4), - uint256(0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) + uint256( + 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1 + ), + uint256( + 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0 + ), + uint256( + 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4 + ), + uint256( + 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55 + ) ); (bool success, bytes memory result) = address(0x08).staticcall(input); @@ -1869,9 +2415,6 @@ function pairing(Honk.G1Point memory rhs, Honk.G1Point memory lhs) view returns // Field arithmetic libraries - prevent littering the code with modmul / addmul - - - abstract contract BaseZKHonkVerifier is IVerifier { using FrLib for Fr; @@ -1881,7 +2424,12 @@ abstract contract BaseZKHonkVerifier is IVerifier { uint256 immutable $NUM_PUBLIC_INPUTS; uint256 immutable $MSMSize; - constructor(uint256 _N, uint256 _logN, uint256 _vkHash, uint256 _numPublicInputs) { + constructor( + uint256 _N, + uint256 _logN, + uint256 _vkHash, + uint256 _numPublicInputs + ) { $N = _N; $LOG_N = _logN; $VK_HASH = _vkHash; @@ -1891,7 +2439,11 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Errors error ProofLengthWrong(); - error ProofLengthWrongWithLogN(uint256 logN, uint256 actualLength, uint256 expectedLength); + error ProofLengthWrongWithLogN( + uint256 logN, + uint256 actualLength, + uint256 expectedLength + ); error PublicInputsLengthWrong(); error SumcheckFailed(); error ShpleminiFailed(); @@ -1911,7 +2463,10 @@ abstract contract BaseZKHonkVerifier is IVerifier { proofLength += NUM_ELEMENTS_COMM * 3; // Libra concat, grand sum, quotient comms + Gemini masking // Sumcheck - proofLength += logN * ZK_BATCHED_RELATION_PARTIAL_LENGTH * NUM_ELEMENTS_FR; // sumcheck univariates + proofLength += + logN * + ZK_BATCHED_RELATION_PARTIAL_LENGTH * + NUM_ELEMENTS_FR; // sumcheck univariates proofLength += NUMBER_OF_ENTITIES_ZK * NUM_ELEMENTS_FR; // sumcheck evaluations // Libra and Gemini @@ -1931,20 +2486,26 @@ abstract contract BaseZKHonkVerifier is IVerifier { uint256 constant SHIFTED_COMMITMENTS_START = 30; - function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory); + function loadVerificationKey() + internal + pure + virtual + returns (Honk.VerificationKey memory); - function verify(bytes calldata proof, bytes32[] calldata publicInputs) - public - view - override - returns (bool verified) - { + function verify( + bytes calldata proof, + bytes32[] calldata publicInputs + ) public view override returns (bool verified) { // Calculate expected proof size based on $LOG_N uint256 expectedProofSize = calculateProofSize($LOG_N); // Check the received proof is the expected size where each field element is 32 bytes if (proof.length != expectedProofSize * 32) { - revert ProofLengthWrongWithLogN($LOG_N, proof.length, expectedProofSize * 32); + revert ProofLengthWrongWithLogN( + $LOG_N, + proof.length, + expectedProofSize * 32 + ); } Honk.VerificationKey memory vk = loadVerificationKey(); @@ -1955,15 +2516,20 @@ abstract contract BaseZKHonkVerifier is IVerifier { } // Generate the fiat shamir challenges for the whole protocol - ZKTranscript memory t = - ZKTranscriptLib.generateTranscript(p, publicInputs, $VK_HASH, $NUM_PUBLIC_INPUTS, $LOG_N); + ZKTranscript memory t = ZKTranscriptLib.generateTranscript( + p, + publicInputs, + $VK_HASH, + $NUM_PUBLIC_INPUTS, + $LOG_N + ); // Derive public input delta t.relationParameters.publicInputsDelta = computePublicInputDelta( publicInputs, p.pairingPointObject, t.relationParameters.beta, - t.relationParameters.gamma, /*pubInputsOffset=*/ + t.relationParameters.gamma /*pubInputsOffset=*/, 1 ); @@ -1987,11 +2553,16 @@ abstract contract BaseZKHonkVerifier is IVerifier { Fr numerator = Fr.wrap(1); Fr denominator = Fr.wrap(1); - Fr numeratorAcc = gamma + (beta * FrLib.from(PERMUTATION_ARGUMENT_VALUE_SEPARATOR + offset)); + Fr numeratorAcc = gamma + + (beta * FrLib.from(PERMUTATION_ARGUMENT_VALUE_SEPARATOR + offset)); Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); { - for (uint256 i = 0; i < $NUM_PUBLIC_INPUTS - PAIRING_POINTS_SIZE; i++) { + for ( + uint256 i = 0; + i < $NUM_PUBLIC_INPUTS - PAIRING_POINTS_SIZE; + i++ + ) { Fr pubInput = FrLib.fromBytes32(publicInputs[i]); numerator = numerator * (numeratorAcc + pubInput); @@ -2016,22 +2587,32 @@ abstract contract BaseZKHonkVerifier is IVerifier { publicInputDelta = FrLib.div(numerator, denominator); } - function verifySumcheck(Honk.ZKProof memory proof, ZKTranscript memory tp) internal view returns (bool verified) { + function verifySumcheck( + Honk.ZKProof memory proof, + ZKTranscript memory tp + ) internal view returns (bool verified) { Fr roundTargetSum = tp.libraChallenge * proof.libraSum; // default 0 Fr powPartialEvaluation = Fr.wrap(1); // We perform sumcheck reductions over log n rounds ( the multivariate degree ) for (uint256 round; round < $LOG_N; ++round) { - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariate = proof.sumcheckUnivariates[round]; + Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] + memory roundUnivariate = proof.sumcheckUnivariates[round]; Fr totalSum = roundUnivariate[0] + roundUnivariate[1]; if (totalSum != roundTargetSum) revert SumcheckFailed(); Fr roundChallenge = tp.sumCheckUChallenges[round]; // Update the round target for the next rounf - roundTargetSum = computeNextTargetSum(roundUnivariate, roundChallenge); + roundTargetSum = computeNextTargetSum( + roundUnivariate, + roundChallenge + ); powPartialEvaluation = - powPartialEvaluation * (Fr.wrap(1) + roundChallenge * (tp.gateChallenges[round] - Fr.wrap(1))); + powPartialEvaluation * + (Fr.wrap(1) + + roundChallenge * + (tp.gateChallenges[round] - Fr.wrap(1))); } // Last round @@ -2039,10 +2620,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Index 0 is gemini_masking_poly, indices 1-41 are the regular entities used in relations Fr[NUMBER_OF_ENTITIES] memory relationsEvaluations; for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { - relationsEvaluations[i] = proof.sumcheckEvaluations[i + NUM_MASKING_POLYNOMIALS]; // Skip gemini_masking_poly at index 0 + relationsEvaluations[i] = proof.sumcheckEvaluations[ + i + NUM_MASKING_POLYNOMIALS + ]; // Skip gemini_masking_poly at index 0 } Fr grandHonkRelationSum = RelationsLib.accumulateRelationEvaluations( - relationsEvaluations, tp.relationParameters, tp.alphas, powPartialEvaluation + relationsEvaluations, + tp.relationParameters, + tp.alphas, + powPartialEvaluation ); Fr evaluation = Fr.wrap(1); @@ -2051,27 +2637,48 @@ abstract contract BaseZKHonkVerifier is IVerifier { } grandHonkRelationSum = - grandHonkRelationSum * (Fr.wrap(1) - evaluation) + proof.libraEvaluation * tp.libraChallenge; + grandHonkRelationSum * + (Fr.wrap(1) - evaluation) + + proof.libraEvaluation * + tp.libraChallenge; verified = (grandHonkRelationSum == roundTargetSum); } // Return the new target sum for the next sumcheck round - function computeNextTargetSum(Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, Fr roundChallenge) - internal - view - returns (Fr targetSum) - { - Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [ - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51), - Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31), - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000000240), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31), - Fr.wrap(0x00000000000000000000000000000000000000000000000000000000000005a0), - Fr.wrap(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51), - Fr.wrap(0x0000000000000000000000000000000000000000000000000000000000009d80) - ]; + function computeNextTargetSum( + Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory roundUnivariates, + Fr roundChallenge + ) internal view returns (Fr targetSum) { + Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] + memory BARYCENTRIC_LAGRANGE_DENOMINATORS = [ + Fr.wrap( + 0x0000000000000000000000000000000000000000000000000000000000009d80 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51 + ), + Fr.wrap( + 0x00000000000000000000000000000000000000000000000000000000000005a0 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31 + ), + Fr.wrap( + 0x0000000000000000000000000000000000000000000000000000000000000240 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffd31 + ), + Fr.wrap( + 0x00000000000000000000000000000000000000000000000000000000000005a0 + ), + Fr.wrap( + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffec51 + ), + Fr.wrap( + 0x0000000000000000000000000000000000000000000000000000000000009d80 + ) + ]; // To compute the next target sum, we evaluate the given univariate at a point u (challenge). @@ -2084,11 +2691,17 @@ abstract contract BaseZKHonkVerifier is IVerifier { Fr[ZK_BATCHED_RELATION_PARTIAL_LENGTH] memory denominatorInverses; for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) { - denominatorInverses[i] = FrLib.invert(BARYCENTRIC_LAGRANGE_DENOMINATORS[i] * (roundChallenge - Fr.wrap(i))); + denominatorInverses[i] = FrLib.invert( + BARYCENTRIC_LAGRANGE_DENOMINATORS[i] * + (roundChallenge - Fr.wrap(i)) + ); } for (uint256 i = 0; i < ZK_BATCHED_RELATION_PARTIAL_LENGTH; ++i) { - targetSum = targetSum + roundUnivariates[i] * denominatorInverses[i]; + targetSum = + targetSum + + roundUnivariates[i] * + denominatorInverses[i]; } // Scale the sum by the value of B(x) @@ -2104,56 +2717,63 @@ abstract contract BaseZKHonkVerifier is IVerifier { Honk.G1Point P_1; } - function verifyShplemini(Honk.ZKProof memory proof, Honk.VerificationKey memory vk, ZKTranscript memory tp) - internal - view - returns (bool verified) - { + function verifyShplemini( + Honk.ZKProof memory proof, + Honk.VerificationKey memory vk, + ZKTranscript memory tp + ) internal view returns (bool verified) { CommitmentSchemeLib.ShpleminiIntermediates memory mem; // stack // - Compute vector (r, r², ... , r²⁽ⁿ⁻¹⁾), where n = log_circuit_size - Fr[] memory powers_of_evaluation_challenge = CommitmentSchemeLib.computeSquares(tp.geminiR, $LOG_N); + Fr[] memory powers_of_evaluation_challenge = CommitmentSchemeLib + .computeSquares(tp.geminiR, $LOG_N); // Arrays hold values that will be linearly combined for the gemini and shplonk batch openings Fr[] memory scalars = new Fr[]($MSMSize); Honk.G1Point[] memory commitments = new Honk.G1Point[]($MSMSize); - mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[0]).invert(); - mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[0]).invert(); + mem.posInvertedDenominator = (tp.shplonkZ - + powers_of_evaluation_challenge[0]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + + powers_of_evaluation_challenge[0]).invert(); - mem.unshiftedScalar = mem.posInvertedDenominator + (tp.shplonkNu * mem.negInvertedDenominator); + mem.unshiftedScalar = + mem.posInvertedDenominator + + (tp.shplonkNu * mem.negInvertedDenominator); mem.shiftedScalar = - tp.geminiR.invert() * (mem.posInvertedDenominator - (tp.shplonkNu * mem.negInvertedDenominator)); + tp.geminiR.invert() * + (mem.posInvertedDenominator - + (tp.shplonkNu * mem.negInvertedDenominator)); scalars[0] = Fr.wrap(1); commitments[0] = proof.shplonkQ; /* Batch multivariate opening claims, shifted and unshifted - * The vector of scalars is populated as follows: - * \f[ - * \left( - * - \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), - * \ldots, - * - \rho^{i+k-1} \times \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), - * - \rho^{i+k} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right), - * \ldots, - * - \rho^{k+m-1} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right) - * \right) - * \f] - * - * The following vector is concatenated to the vector of commitments: - * \f[ - * f_0, \ldots, f_{m-1}, f_{\text{shift}, 0}, \ldots, f_{\text{shift}, k-1} - * \f] - * - * Simultaneously, the evaluation of the multilinear polynomial - * \f[ - * \sum \rho^i \cdot f_i + \sum \rho^{i+k} \cdot f_{\text{shift}, i} - * \f] - * at the challenge point \f$ (u_0,\ldots, u_{n-1}) \f$ is computed. - * - * This approach minimizes the number of iterations over the commitments to multilinear polynomials - * and eliminates the need to store the powers of \f$ \rho \f$. - */ + * The vector of scalars is populated as follows: + * \f[ + * \left( + * - \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), + * \ldots, + * - \rho^{i+k-1} \times \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right), + * - \rho^{i+k} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right), + * \ldots, + * - \rho^{k+m-1} \times \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right) + * \right) + * \f] + * + * The following vector is concatenated to the vector of commitments: + * \f[ + * f_0, \ldots, f_{m-1}, f_{\text{shift}, 0}, \ldots, f_{\text{shift}, k-1} + * \f] + * + * Simultaneously, the evaluation of the multilinear polynomial + * \f[ + * \sum \rho^i \cdot f_i + \sum \rho^{i+k} \cdot f_{\text{shift}, i} + * \f] + * at the challenge point \f$ (u_0,\ldots, u_{n-1}) \f$ is computed. + * + * This approach minimizes the number of iterations over the commitments to multilinear polynomials + * and eliminates the need to store the powers of \f$ \rho \f$. + */ // For ZK flavors: evaluations array is [gemini_masking_poly, qm, qc, ql, qr, ...] // Start batching challenge at 1, not rho, to match non-ZK pattern mem.batchingChallenge = Fr.wrap(1); @@ -2165,8 +2785,10 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Process all NUMBER_UNSHIFTED_ZK evaluations (includes gemini_masking_poly at index 0) for (uint256 i = 1; i <= NUMBER_UNSHIFTED_ZK; ++i) { scalars[i] = mem.unshiftedScalarNeg * mem.batchingChallenge; - mem.batchedEvaluation = mem.batchedEvaluation - + (proof.sumcheckEvaluations[i - NUM_MASKING_POLYNOMIALS] * mem.batchingChallenge); + mem.batchedEvaluation = + mem.batchedEvaluation + + (proof.sumcheckEvaluations[i - NUM_MASKING_POLYNOMIALS] * + mem.batchingChallenge); mem.batchingChallenge = mem.batchingChallenge * tp.rho; } // g commitments are accumulated at r @@ -2179,9 +2801,13 @@ abstract contract BaseZKHonkVerifier is IVerifier { uint256 scalarOff = i + SHIFTED_COMMITMENTS_START; uint256 evaluationOff = i + NUMBER_UNSHIFTED_ZK; - scalars[scalarOff] = scalars[scalarOff] + (mem.shiftedScalarNeg * mem.batchingChallenge); + scalars[scalarOff] = + scalars[scalarOff] + + (mem.shiftedScalarNeg * mem.batchingChallenge); mem.batchedEvaluation = - mem.batchedEvaluation + (proof.sumcheckEvaluations[evaluationOff] * mem.batchingChallenge); + mem.batchedEvaluation + + (proof.sumcheckEvaluations[evaluationOff] * + mem.batchingChallenge); mem.batchingChallenge = mem.batchingChallenge * tp.rho; } @@ -2234,15 +2860,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { * \f[ * \left( \text{com}(A_1), \text{com}(A_2), \ldots, \text{com}(A_{n-1}) \right) * \f] - * to the 'commitments' vector. - * - * 2. Computes the scalars: - * \f[ - * \frac{\nu^{2}}{z + r^2}, \frac{\nu^3}{z + r^4}, \ldots, \frac{\nu^{n-1}}{z + r^{2^{n-1}}} - * \f] - * and places them into the 'scalars' vector. - * - * 3. Accumulates the summands of the constant term: + * to the 'commitments' vector. + * + * 2. Computes the scalars: + * \f[ + * \frac{\nu^{2}}{z + r^2}, \frac{\nu^3}{z + r^4}, \ldots, \frac{\nu^{n-1}}{z + r^{2^{n-1}}} + * \f] + * and places them into the 'scalars' vector. + * + * 3. Accumulates the summands of the constant term: * \f[ * \sum_{i=2}^{n-1} \frac{\nu^{i} \cdot A_i(-r^{2^i})}{z + r^{2^i}} * \f] @@ -2251,17 +2877,23 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Add contributions from A₀(r) and A₀(-r) to constant_term_accumulator: // Compute the evaluations Aₗ(r^{2ˡ}) for l = 0, ..., $LOG_N - 1 - Fr[] memory foldPosEvaluations = CommitmentSchemeLib.computeFoldPosEvaluations( - tp.sumCheckUChallenges, - mem.batchedEvaluation, - proof.geminiAEvaluations, - powers_of_evaluation_challenge, - $LOG_N - ); + Fr[] memory foldPosEvaluations = CommitmentSchemeLib + .computeFoldPosEvaluations( + tp.sumCheckUChallenges, + mem.batchedEvaluation, + proof.geminiAEvaluations, + powers_of_evaluation_challenge, + $LOG_N + ); - mem.constantTermAccumulator = foldPosEvaluations[0] * mem.posInvertedDenominator; mem.constantTermAccumulator = - mem.constantTermAccumulator + (proof.geminiAEvaluations[0] * tp.shplonkNu * mem.negInvertedDenominator); + foldPosEvaluations[0] * + mem.posInvertedDenominator; + mem.constantTermAccumulator = + mem.constantTermAccumulator + + (proof.geminiAEvaluations[0] * + tp.shplonkNu * + mem.negInvertedDenominator); mem.batchingChallenge = tp.shplonkNu.sqr(); uint256 boundary = NUMBER_UNSHIFTED_ZK + 1; @@ -2273,22 +2905,40 @@ abstract contract BaseZKHonkVerifier is IVerifier { if (!dummy_round) { // Update inverted denominators - mem.posInvertedDenominator = (tp.shplonkZ - powers_of_evaluation_challenge[i + 1]).invert(); - mem.negInvertedDenominator = (tp.shplonkZ + powers_of_evaluation_challenge[i + 1]).invert(); + mem.posInvertedDenominator = (tp.shplonkZ - + powers_of_evaluation_challenge[i + 1]).invert(); + mem.negInvertedDenominator = (tp.shplonkZ + + powers_of_evaluation_challenge[i + 1]).invert(); // Compute the scalar multipliers for Aₗ(± r^{2ˡ}) and [Aₗ] - mem.scalingFactorPos = mem.batchingChallenge * mem.posInvertedDenominator; - mem.scalingFactorNeg = mem.batchingChallenge * tp.shplonkNu * mem.negInvertedDenominator; - scalars[boundary + i] = mem.scalingFactorNeg.neg() + mem.scalingFactorPos.neg(); + mem.scalingFactorPos = + mem.batchingChallenge * + mem.posInvertedDenominator; + mem.scalingFactorNeg = + mem.batchingChallenge * + tp.shplonkNu * + mem.negInvertedDenominator; + scalars[boundary + i] = + mem.scalingFactorNeg.neg() + + mem.scalingFactorPos.neg(); // Accumulate the const term contribution given by // v^{2l} * Aₗ(r^{2ˡ}) /(z-r^{2^l}) + v^{2l+1} * Aₗ(-r^{2ˡ}) /(z+ r^{2^l}) - Fr accumContribution = mem.scalingFactorNeg * proof.geminiAEvaluations[i + 1]; - accumContribution = accumContribution + mem.scalingFactorPos * foldPosEvaluations[i + 1]; - mem.constantTermAccumulator = mem.constantTermAccumulator + accumContribution; + Fr accumContribution = mem.scalingFactorNeg * + proof.geminiAEvaluations[i + 1]; + accumContribution = + accumContribution + + mem.scalingFactorPos * + foldPosEvaluations[i + 1]; + mem.constantTermAccumulator = + mem.constantTermAccumulator + + accumContribution; } // Update the running power of v - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + mem.batchingChallenge = + mem.batchingChallenge * + tp.shplonkNu * + tp.shplonkNu; commitments[boundary + i] = proof.geminiFoldComms[i]; } @@ -2297,16 +2947,24 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Finalize the batch opening claim mem.denominators[0] = Fr.wrap(1).div(tp.shplonkZ - tp.geminiR); - mem.denominators[1] = Fr.wrap(1).div(tp.shplonkZ - SUBGROUP_GENERATOR * tp.geminiR); + mem.denominators[1] = Fr.wrap(1).div( + tp.shplonkZ - SUBGROUP_GENERATOR * tp.geminiR + ); mem.denominators[2] = mem.denominators[0]; mem.denominators[3] = mem.denominators[0]; - mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu * tp.shplonkNu; + mem.batchingChallenge = + mem.batchingChallenge * + tp.shplonkNu * + tp.shplonkNu; for (uint256 i = 0; i < LIBRA_EVALUATIONS; i++) { Fr scalingFactor = mem.denominators[i] * mem.batchingChallenge; mem.batchingScalars[i] = scalingFactor.neg(); mem.batchingChallenge = mem.batchingChallenge * tp.shplonkNu; - mem.constantTermAccumulator = mem.constantTermAccumulator + scalingFactor * proof.libraPolyEvals[i]; + mem.constantTermAccumulator = + mem.constantTermAccumulator + + scalingFactor * + proof.libraPolyEvals[i]; } scalars[boundary] = mem.batchingScalars[0]; scalars[boundary + 1] = mem.batchingScalars[1] + mem.batchingScalars[2]; @@ -2316,10 +2974,17 @@ abstract contract BaseZKHonkVerifier is IVerifier { commitments[boundary++] = proof.libraCommitments[i]; } - commitments[boundary] = Honk.G1Point({x: 1, y: 2}); + commitments[boundary] = Honk.G1Point({ x: 1, y: 2 }); scalars[boundary++] = mem.constantTermAccumulator; - if (!checkEvalsConsistency(proof.libraPolyEvals, tp.geminiR, tp.sumCheckUChallenges, proof.libraEvaluation)) { + if ( + !checkEvalsConsistency( + proof.libraPolyEvals, + tp.geminiR, + tp.sumCheckUChallenges, + proof.libraEvaluation + ) + ) { revert ConsistencyCheckFailed(); } @@ -2333,9 +2998,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { pair.P_1 = negateInplace(quotient_commitment); // Aggregate pairing points - Fr recursionSeparator = generateRecursionSeparator(proof.pairingPointObject, pair.P_0, pair.P_1); - (Honk.G1Point memory P_0_other, Honk.G1Point memory P_1_other) = - convertPairingPointsToG1(proof.pairingPointObject); + Fr recursionSeparator = generateRecursionSeparator( + proof.pairingPointObject, + pair.P_0, + pair.P_1 + ); + ( + Honk.G1Point memory P_0_other, + Honk.G1Point memory P_1_other + ) = convertPairingPointsToG1(proof.pairingPointObject); // Validate the points from the proof are on the curve validateOnCurve(P_0_other); @@ -2375,8 +3046,14 @@ abstract contract BaseZKHonkVerifier is IVerifier { for (uint256 round = 0; round < $LOG_N; round++) { uint256 currIdx = 1 + LIBRA_UNIVARIATES_LENGTH * round; mem.challengePolyLagrange[currIdx] = one; - for (uint256 idx = currIdx + 1; idx < currIdx + LIBRA_UNIVARIATES_LENGTH; idx++) { - mem.challengePolyLagrange[idx] = mem.challengePolyLagrange[idx - 1] * uChallenges[round]; + for ( + uint256 idx = currIdx + 1; + idx < currIdx + LIBRA_UNIVARIATES_LENGTH; + idx++ + ) { + mem.challengePolyLagrange[idx] = + mem.challengePolyLagrange[idx - 1] * + uChallenges[round]; } } @@ -2385,7 +3062,10 @@ abstract contract BaseZKHonkVerifier is IVerifier { for (uint256 idx = 0; idx < SUBGROUP_SIZE; idx++) { mem.denominators[idx] = mem.rootPower * geminiR - one; mem.denominators[idx] = mem.denominators[idx].invert(); - mem.challengePolyEval = mem.challengePolyEval + mem.challengePolyLagrange[idx] * mem.denominators[idx]; + mem.challengePolyEval = + mem.challengePolyEval + + mem.challengePolyLagrange[idx] * + mem.denominators[idx]; mem.rootPower = mem.rootPower * SUBGROUP_GENERATOR_INVERSE; } @@ -2396,19 +3076,28 @@ abstract contract BaseZKHonkVerifier is IVerifier { mem.diff = mem.lagrangeFirst * libraPolyEvals[2]; - mem.diff = mem.diff + (geminiR - SUBGROUP_GENERATOR_INVERSE) - * (libraPolyEvals[1] - libraPolyEvals[2] - libraPolyEvals[0] * mem.challengePolyEval); - mem.diff = mem.diff + mem.lagrangeLast * (libraPolyEvals[2] - libraEval) - vanishingPolyEval * libraPolyEvals[3]; + mem.diff = + mem.diff + + (geminiR - SUBGROUP_GENERATOR_INVERSE) * + (libraPolyEvals[1] - + libraPolyEvals[2] - + libraPolyEvals[0] * + mem.challengePolyEval); + mem.diff = + mem.diff + + mem.lagrangeLast * + (libraPolyEvals[2] - libraEval) - + vanishingPolyEval * + libraPolyEvals[3]; check = mem.diff == Fr.wrap(0); } // This implementation is the same as above with different constants - function batchMul(Honk.G1Point[] memory base, Fr[] memory scalars) - internal - view - returns (Honk.G1Point memory result) - { + function batchMul( + Honk.G1Point[] memory base, + Fr[] memory scalars + ) internal view returns (Honk.G1Point memory result) { uint256 limit = $MSMSize; // Validate all points are on the curve @@ -2421,7 +3110,9 @@ abstract contract BaseZKHonkVerifier is IVerifier { let free := mload(0x40) let count := 0x01 - for {} lt(count, add(limit, 1)) { count := add(count, 1) } { + for {} lt(count, add(limit, 1)) { + count := add(count, 1) + } { // Get loop offsets let base_base := add(base, mul(count, 0x20)) let scalar_base := add(scalars, mul(count, 0x20)) @@ -2431,9 +3122,22 @@ abstract contract BaseZKHonkVerifier is IVerifier { // Add scalar mstore(add(free, 0x80), mload(scalar_base)) - success := and(success, staticcall(gas(), 7, add(free, 0x40), 0x60, add(free, 0x40), 0x40)) + success := and( + success, + staticcall( + gas(), + 7, + add(free, 0x40), + 0x60, + add(free, 0x40), + 0x40 + ) + ) // accumulator = accumulator + accumulator_2 - success := and(success, staticcall(gas(), 6, free, 0x80, free, 0x40)) + success := and( + success, + staticcall(gas(), 6, free, 0x80, free, 0x40) + ) } // Return the result @@ -2445,8 +3149,15 @@ abstract contract BaseZKHonkVerifier is IVerifier { } } -contract ThresholdPkAggregationVerifier is BaseZKHonkVerifier(N, LOG_N, VK_HASH, NUMBER_OF_PUBLIC_INPUTS) { - function loadVerificationKey() internal pure override returns (Honk.VerificationKey memory) { - return HonkVerificationKey.loadVerificationKey(); +contract ThresholdPkAggregationVerifier is + BaseZKHonkVerifier(N, LOG_N, VK_HASH, NUMBER_OF_PUBLIC_INPUTS) +{ + function loadVerificationKey() + internal + pure + override + returns (Honk.VerificationKey memory) + { + return HonkVerificationKey.loadVerificationKey(); } } diff --git a/packages/enclave-contracts/deployed_contracts.json b/packages/enclave-contracts/deployed_contracts.json index 56b719a0ba..311f2b3b69 100644 --- a/packages/enclave-contracts/deployed_contracts.json +++ b/packages/enclave-contracts/deployed_contracts.json @@ -129,38 +129,38 @@ }, "localhost": { "PoseidonT3": { - "blockNumber": 5, + "blockNumber": 422, "address": "0x3333333C0A88F9BE4fd23ed0536F9B6c427e3B93" }, "MockUSDC": { "constructorArgs": { "initialSupply": "1000000" }, - "blockNumber": 6, - "address": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" + "blockNumber": 423, + "address": "0x21dF544947ba3E8b3c32561399E88B52Dc8b2823" }, "EnclaveToken": { "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 7, - "address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + "blockNumber": 424, + "address": "0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2" }, "EnclaveTicketToken": { "constructorArgs": { - "baseToken": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "baseToken": "0x21dF544947ba3E8b3c32561399E88B52Dc8b2823", "registry": "0x0000000000000000000000000000000000000001", "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 9, - "address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9" + "blockNumber": 426, + "address": "0xDC11f7E700A4c898AE5CAddB1082cFfa76512aDD" }, "SlashingManager": { "constructorArgs": { "admin": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, - "blockNumber": 10, - "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" + "blockNumber": 427, + "address": "0x51A1ceB83B83F1985a81C295d1fF28Afef186E02" }, "CiphernodeRegistryOwnable": { "constructorArgs": { @@ -170,19 +170,19 @@ "proxyRecords": { "initData": "0xcd6dc687000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000000000000000000000000000000000000000000a", "initialOwner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "proxyAddress": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", - "proxyAdminAddress": "0x9bd03768a7DCc129555dE410FF8E85528A4F88b5", - "implementationAddress": "0x0165878A594ca255338adfa4d48449f69242Eb8F" + "proxyAddress": "0x8198f5d8F8CfFE8f9C413d98a0A55aEB8ab9FbB7", + "proxyAdminAddress": "0x5971B98C0066517Bae7D44021f42e50B77cfe1F9", + "implementationAddress": "0x36b58F5C1969B7b6591D752ea6F5486D069010AB" }, - "blockNumber": 11, - "address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853" + "blockNumber": 428, + "address": "0x8198f5d8F8CfFE8f9C413d98a0A55aEB8ab9FbB7" }, "BondingRegistry": { "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "ticketToken": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", - "licenseToken": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", - "registry": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", + "ticketToken": "0xDC11f7E700A4c898AE5CAddB1082cFfa76512aDD", + "licenseToken": "0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2", + "registry": "0x8198f5d8F8CfFE8f9C413d98a0A55aEB8ab9FbB7", "slashedFundsTreasury": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "ticketPrice": "10000000", "licenseRequiredBond": "100000000000000000000", @@ -190,22 +190,22 @@ "exitDelay": "604800" }, "proxyRecords": { - "initData": "0x7333fa82000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000dc64a140aa3e981100a9beca4e685f962f0cf6c90000000000000000000000009fe46736679d2d9a65f0992f2272de9f3c7fa6e0000000000000000000000000a513e6e4b8f2a923d98304ec87f64353c4d5c853000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000009896800000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000093a80", + "initData": "0x7333fa82000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000dc11f7e700a4c898ae5caddb1082cffa76512add0000000000000000000000002e2ed0cfd3ad2f1d34481277b3204d807ca2f8c20000000000000000000000008198f5d8f8cffe8f9c413d98a0a55aeb8ab9fbb7000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000009896800000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000093a80", "initialOwner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "proxyAddress": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", - "proxyAdminAddress": "0x8aCd85898458400f7Db866d53FCFF6f0D49741FF", - "implementationAddress": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" + "proxyAddress": "0x202CCe504e04bEd6fC0521238dDf04Bc9E8E15aB", + "proxyAdminAddress": "0x6C3d502f1a97d4470b881015b83D9Dd1062172e1", + "implementationAddress": "0x0355B7B8cb128fA5692729Ab3AAa199C1753f726" }, - "blockNumber": 12, - "address": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" + "blockNumber": 429, + "address": "0x202CCe504e04bEd6fC0521238dDf04Bc9E8E15aB" }, "Enclave": { "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "registry": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", - "bondingRegistry": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", + "registry": "0x8198f5d8F8CfFE8f9C413d98a0A55aEB8ab9FbB7", + "bondingRegistry": "0x202CCe504e04bEd6fC0521238dDf04Bc9E8E15aB", "e3RefundManager": "0x0000000000000000000000000000000000000001", - "feeToken": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", + "feeToken": "0x21dF544947ba3E8b3c32561399E88B52Dc8b2823", "maxDuration": "2592000", "timeoutConfig": "{\"committeeFormationWindow\":3600,\"dkgWindow\":7200,\"computeWindow\":86400,\"decryptionWindow\":3600}", "params": [ @@ -213,94 +213,58 @@ ] }, "proxyRecords": { - "initData": "0x01d12f1c000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000a513e6e4b8f2a923d98304ec87f64353c4d5c8530000000000000000000000008a791620dd6260079bf849dc5567adc3f2fdc3180000000000000000000000000000000000000000000000000000000000000001000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f05120000000000000000000000000000000000000000000000000000000000278d000000000000000000000000000000000000000000000000000000000000001c2000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000000e100000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000ffffee0010000000000000000000000000000000000000000000000000000000ffffc400100000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000", + "initData": "0x01d12f1c000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000008198f5d8f8cffe8f9c413d98a0a55aeb8ab9fbb7000000000000000000000000202cce504e04bed6fc0521238ddf04bc9e8e15ab000000000000000000000000000000000000000000000000000000000000000100000000000000000000000021df544947ba3e8b3c32561399e88b52dc8b28230000000000000000000000000000000000000000000000000000000000278d000000000000000000000000000000000000000000000000000000000000001c2000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000000e100000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000ffffee0010000000000000000000000000000000000000000000000000000000ffffc400100000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000", "initialOwner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "proxyAddress": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e", - "proxyAdminAddress": "0x8dAF17A20c9DBA35f005b6324F493785D239719d", - "implementationAddress": "0x610178dA211FEF7D417bC0e6FeD39F05609AD788" + "proxyAddress": "0x172076E0166D1F9Cc711C77Adf8488051744980C", + "proxyAdminAddress": "0xD3F77aFa1aA264da7Ef6eB4cEfB91a486dd61bA2", + "implementationAddress": "0xf4B146FbA71F41E0592668ffbF264F1D186b2Ca8" }, - "blockNumber": 15, - "address": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e" + "blockNumber": 432, + "address": "0x172076E0166D1F9Cc711C77Adf8488051744980C" }, "E3RefundManager": { "constructorArgs": { "owner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "enclave": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e", + "enclave": "0x172076E0166D1F9Cc711C77Adf8488051744980C", "treasury": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }, "proxyRecords": { - "initData": "0xc0c53b8b000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000b7f8bc63bbcad18155201308c8f3540b07f84f5e000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "initData": "0xc0c53b8b000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000172076e0166d1f9cc711c77adf8488051744980c000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266", "initialOwner": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "proxyAddress": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82", - "proxyAdminAddress": "0x32467b43BFa67273FC7dDda0999Ee9A12F2AaA08", - "implementationAddress": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0" + "proxyAddress": "0xBEc49fA140aCaA83533fB00A2BB19bDdd0290f25", + "proxyAdminAddress": "0x0CF67A3b6Edd8AC9F13BE276661371Bb699bDBb9", + "implementationAddress": "0x4EE6eCAD1c2Dae9f525404De8555724e3c35d07B" }, - "blockNumber": 17, - "address": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82" + "blockNumber": 434, + "address": "0xBEc49fA140aCaA83533fB00A2BB19bDdd0290f25" }, "MockComputeProvider": { - "blockNumber": 19, - "address": "0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E" + "blockNumber": 436, + "address": "0x720472c8ce72c2A2D711333e064ABD3E6BbEAdd3" }, "MockDecryptionVerifier": { - "blockNumber": 20, - "address": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690" + "blockNumber": 437, + "address": "0xe8D2A1E88c91DCd5433208d4152Cc4F399a7e91d" }, "MockE3Program": { - "blockNumber": 21, - "address": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB" + "blockNumber": 438, + "address": "0x5067457698Fd6Fa1C6964e416b3f42713513B3dD" }, "ZKTranscriptLib": { - "blockNumber": 24, - "address": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8" - }, - "DkgESmShareComputationVerifier": { - "blockNumber": 25, - "address": "0x851356ae760d987E095750cCeb3bC6014560891C" - }, - "DkgShareDecryptionVerifier": { - "blockNumber": 26, - "address": "0xf5059a5D33d5853360D16C683c16e67980206f36" - }, - "DkgShareEncryptionVerifier": { - "blockNumber": 27, - "address": "0x95401dc811bb5740090279Ba06cfA8fcF6113778" - }, - "DkgSkShareComputationVerifier": { - "blockNumber": 28, - "address": "0x998abeb3E57409262aE5b751f60747921B33613E" + "blockNumber": 441, + "address": "0xCace1b78160AE76398F486c8a18044da0d66d86D" }, "RecursiveAggregationFoldVerifier": { - "blockNumber": 29, - "address": "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49" - }, - "ThresholdDecryptedSharesAggregationBnVerifier": { - "blockNumber": 30, - "address": "0x4826533B4897376654Bb4d4AD88B7faFD0C98528" + "blockNumber": 442, + "address": "0xD5ac451B0c50B9476107823Af206eD814a2e2580" }, - "ThresholdDecryptedSharesAggregationModVerifier": { - "blockNumber": 31, - "address": "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf" + "ThresholdDecryptedSharesAggregationVerifier": { + "blockNumber": 443, + "address": "0xF8e31cb472bc70500f08Cd84917E5A1912Ec8397" }, "ThresholdPkAggregationVerifier": { - "blockNumber": 32, - "address": "0x0E801D84Fa97b50751Dbf25036d067dCf18858bF" - }, - "ThresholdPkGenerationVerifier": { - "blockNumber": 33, - "address": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf" - }, - "ThresholdShareDecryptionVerifier": { - "blockNumber": 34, - "address": "0x9d4454B023096f34B160D6B654540c56A1F81688" - }, - "ThresholdUserDataEncryptionCt0Verifier": { - "blockNumber": 35, - "address": "0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00" - }, - "ThresholdUserDataEncryptionCt1Verifier": { - "blockNumber": 36, - "address": "0x36C02dA8a0983159322a80FFE9F24b1acfF8B570" + "blockNumber": 444, + "address": "0xc0F115A19107322cFBf1cDBC7ea011C19EbDB4F8" } } } \ No newline at end of file diff --git a/packages/enclave-contracts/ignition/modules/recursiveAggregationFoldVerifier.ts b/packages/enclave-contracts/ignition/modules/recursiveAggregationFoldVerifier.ts index dafc719d49..fb48071a68 100644 --- a/packages/enclave-contracts/ignition/modules/recursiveAggregationFoldVerifier.ts +++ b/packages/enclave-contracts/ignition/modules/recursiveAggregationFoldVerifier.ts @@ -6,7 +6,9 @@ import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; export default buildModule("RecursiveAggregationFoldVerifier", (m) => { - const recursiveAggregationFoldVerifier = m.contract("RecursiveAggregationFoldVerifier"); + const recursiveAggregationFoldVerifier = m.contract( + "RecursiveAggregationFoldVerifier", + ); return { recursiveAggregationFoldVerifier }; }) as any; diff --git a/packages/enclave-contracts/ignition/modules/thresholdDecryptedSharesAggregationBnVerifier.ts b/packages/enclave-contracts/ignition/modules/thresholdDecryptedSharesAggregationBnVerifier.ts deleted file mode 100644 index 5ec1c542a8..0000000000 --- a/packages/enclave-contracts/ignition/modules/thresholdDecryptedSharesAggregationBnVerifier.ts +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. -import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; - -export default buildModule("ThresholdDecryptedSharesAggregationBnVerifier", (m) => { - const thresholdDecryptedSharesAggregationBnVerifier = m.contract( - "ThresholdDecryptedSharesAggregationBnVerifier", - ); - - return { thresholdDecryptedSharesAggregationBnVerifier }; -}) as any; diff --git a/packages/enclave-contracts/ignition/modules/thresholdDecryptedSharesAggregationModVerifier.ts b/packages/enclave-contracts/ignition/modules/thresholdDecryptedSharesAggregationModVerifier.ts deleted file mode 100644 index 44e6cdfe77..0000000000 --- a/packages/enclave-contracts/ignition/modules/thresholdDecryptedSharesAggregationModVerifier.ts +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// -// This file is provided WITHOUT ANY WARRANTY; -// without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. -import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; - -export default buildModule("ThresholdDecryptedSharesAggregationModVerifier", (m) => { - const thresholdDecryptedSharesAggregationModVerifier = m.contract( - "ThresholdDecryptedSharesAggregationModVerifier", - ); - - return { thresholdDecryptedSharesAggregationModVerifier }; -}) as any; diff --git a/packages/enclave-contracts/ignition/modules/thresholdDecryptedSharesAggregationVerifier.ts b/packages/enclave-contracts/ignition/modules/thresholdDecryptedSharesAggregationVerifier.ts new file mode 100644 index 0000000000..f890339413 --- /dev/null +++ b/packages/enclave-contracts/ignition/modules/thresholdDecryptedSharesAggregationVerifier.ts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: LGPL-3.0-only +// +// This file is provided WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. +import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; + +export default buildModule( + "ThresholdDecryptedSharesAggregationVerifier", + (m) => { + const thresholdDecryptedSharesAggregationVerifier = m.contract( + "ThresholdDecryptedSharesAggregationVerifier", + ); + + return { thresholdDecryptedSharesAggregationVerifier }; + }, +) as any; diff --git a/packages/enclave-contracts/ignition/modules/thresholdPkAggregationVerifier.ts b/packages/enclave-contracts/ignition/modules/thresholdPkAggregationVerifier.ts index 2ced20e7ca..7e8fd4c3f1 100644 --- a/packages/enclave-contracts/ignition/modules/thresholdPkAggregationVerifier.ts +++ b/packages/enclave-contracts/ignition/modules/thresholdPkAggregationVerifier.ts @@ -6,7 +6,9 @@ import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; export default buildModule("ThresholdPkAggregationVerifier", (m) => { - const thresholdPkAggregationVerifier = m.contract("ThresholdPkAggregationVerifier"); + const thresholdPkAggregationVerifier = m.contract( + "ThresholdPkAggregationVerifier", + ); return { thresholdPkAggregationVerifier }; }) as any; diff --git a/packages/enclave-contracts/test/fixtures/attestation.ts b/packages/enclave-contracts/test/fixtures/attestation.ts index 8740f304e2..ed3702670c 100644 --- a/packages/enclave-contracts/test/fixtures/attestation.ts +++ b/packages/enclave-contracts/test/fixtures/attestation.ts @@ -3,7 +3,6 @@ // This file is provided WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. - // Shared attestation helpers for committee-based slashing tests. import type { Signer } from "ethers"; import { network } from "hardhat"; diff --git a/packages/enclave-contracts/test/fixtures/operators.ts b/packages/enclave-contracts/test/fixtures/operators.ts index e600c08c77..473f2e402e 100644 --- a/packages/enclave-contracts/test/fixtures/operators.ts +++ b/packages/enclave-contracts/test/fixtures/operators.ts @@ -3,7 +3,6 @@ // This file is provided WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. - // Shared operator setup helpers for sortition-based tests. import type { Signer } from "ethers"; import { network } from "hardhat"; diff --git a/scripts/README.md b/scripts/README.md index 60749563dd..18bd518205 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -278,8 +278,8 @@ Automates the full pipeline from Noir circuits to on-chain Solidity verifiers: 3. **Generates verification keys** using `bb write_vk -t evm` 4. **Generates Solidity verifiers** using `bb write_solidity_verifier` 5. **Post-processes** the generated Solidity: - - Renames contract from `HonkVerifier` to descriptive name (e.g., `ThresholdPkAggregationVerifier`, - `ThresholdPkGenerationVerifier`) + - Renames contract from `HonkVerifier` to descriptive name (e.g., + `ThresholdPkAggregationVerifier`, `ThresholdPkGenerationVerifier`) - Replaces Apache-2.0 license header with LGPL-3.0-only 6. **Outputs** to `packages/enclave-contracts/contracts/verifier/` @@ -307,8 +307,7 @@ The `generate:verifiers` script in package.json passes `--circuits` with the on- Found 4 circuit(s) ✓ threshold/pk_aggregation → ThresholdPkAggregationVerifier.sol - ✓ threshold/decrypted_shares_aggregation_bn → ThresholdDecryptedSharesAggregationBnVerifier.sol - ✓ threshold/decrypted_shares_aggregation_mod → ThresholdDecryptedSharesAggregationModVerifier.sol + ✓ threshold/decrypted_shares_aggregation → ThresholdDecryptedSharesAggregationVerifier.sol ✓ recursive_aggregation/fold → RecursiveAggregationFoldVerifier.sol ✅ Generated 4 Solidity verifier(s) in: diff --git a/scripts/generate-verifiers.ts b/scripts/generate-verifiers.ts index 4a2a8a8d7c..17beb4a71b 100644 --- a/scripts/generate-verifiers.ts +++ b/scripts/generate-verifiers.ts @@ -399,7 +399,7 @@ Options: -h, --help Show this help message Examples: - pnpm generate:verifiers --circuits pk,pk_aggregation,decrypted_shares_aggregation_bn,decrypted_shares_aggregation_mod,fold + pnpm generate:verifiers --circuits pk,pk_aggregation,decrypted_shares_aggregation,fold pnpm generate:verifiers --circuits pk --clean `) }