From 286847fdbcafa01483f32711cdd306813b173faf Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Thu, 12 Oct 2023 18:03:12 +0200 Subject: [PATCH 01/23] WIP --- Cargo.toml | 40 +- eth-types/Cargo.toml | 10 +- eth-types/src/curve.rs | 341 ----------------- eth-types/src/lib.rs | 106 +++--- lightclient-circuits/Cargo.toml | 21 +- lightclient-circuits/src/builder.rs | 10 +- lightclient-circuits/src/gadget/common.rs | 32 +- .../src/gadget/crypto/builder.rs | 238 ++++++------ lightclient-circuits/src/gadget/crypto/ecc.rs | 6 +- .../src/gadget/crypto/hash2curve.rs | 14 +- lightclient-circuits/src/gadget/crypto/mod.rs | 36 +- .../src/gadget/crypto/sha256_flex.rs | 141 ++++--- .../src/gadget/crypto/sha256_flex/builder.rs | 268 ------------- .../gadget/crypto/sha256_flex/compression.rs | 16 +- .../src/gadget/crypto/sha256_flex/gate.rs | 240 ++++++++++++ .../src/gadget/crypto/sha256_flex/spread.rs | 73 ++-- .../src/gadget/crypto/sha256_flex/util.rs | 1 - .../src/gadget/crypto/sha256_wide.rs | 75 ++-- .../sha256_wide/{builder.rs => gate.rs} | 0 .../src/gadget/crypto/util.rs | 110 ------ lightclient-circuits/src/lib.rs | 12 +- lightclient-circuits/src/poseidon.rs | 18 +- lightclient-circuits/src/ssz_merkle.rs | 10 +- lightclient-circuits/src/sync_step_circuit.rs | 352 +++++++++--------- lightclient-circuits/src/util.rs | 104 +----- lightclient-circuits/src/util/circuit.rs | 14 +- lightclient-circuits/src/util/common.rs | 116 +++--- .../src/util/constraint_builder.rs | 2 +- lightclient-circuits/src/util/proof.rs | 22 +- lightclient-circuits/src/witness/rotation.rs | 1 - preprocessor/Cargo.toml | 4 +- prover/Cargo.toml | 4 +- rust-toolchain | 2 +- 33 files changed, 900 insertions(+), 1539 deletions(-) delete mode 100644 lightclient-circuits/src/gadget/crypto/sha256_flex/builder.rs create mode 100644 lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs rename lightclient-circuits/src/gadget/crypto/sha256_wide/{builder.rs => gate.rs} (100%) delete mode 100644 lightclient-circuits/src/gadget/crypto/util.rs diff --git a/Cargo.toml b/Cargo.toml index 98e3ec19..305e2c3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["lightclient-circuits", "prover", "preprocessor", "eth-types"] +members = ["lightclient-circuits", "preprocessor", "eth-types"] # Definition of benchmarks profile to use. [profile.bench] @@ -21,32 +21,34 @@ rpath = false lto = "thin" incremental = true -[patch."https://github.com/privacy-scaling-explorations/halo2curves"] -halo2curves = { git = "https://github.com/sygmaprotocol/halo2curves", branch = "dev/bls12_381" } -# halo2curves = { path = "../halo2curves" } +[patch."https://github.com/axiom-crypto/halo2curves"] +halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "bls12-381/hash_to_curve" } +# halo2curves = { path = "../halo2curves" [patch."https://github.com/axiom-crypto/halo2-lib"] -halo2-base = { git = "https://github.com/timoftime/halo2-lib", rev = "95bf9a5ce6b62a3f28b163748a7494281d814496", default-features = false, features = [ - "halo2-pse", - "display", -] } -halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", rev = "95bf9a5ce6b62a3f28b163748a7494281d814496", default-features = false } -poseidon = { git = "https://github.com/timoftime/halo2-lib", rev = "95bf9a5ce6b62a3f28b163748a7494281d814496", default-features = false } - - -# halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ +# halo2-base = { git = "https://github.com/timoftime/halo2-lib", rev = "765f52c", default-features = false, features = [ # "halo2-pse", # "display", # ] } -# halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false } +# halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", rev = "765f52c", default-features = false, features = [ +# "halo2-pse", +# ] } + + +halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ + "halo2-axiom", + "display", +] } +halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false, features = [ + "halo2-axiom", +] } # poseidon = { path = "../halo2-lib/hashes/poseidon", default-features = false } [patch."https://github.com/axiom-crypto/snark-verifier.git"] -snark-verifier = { git = "https://github.com/timoftime/snark-verifier", branch = "timoftime/bump-revm", default-features = false } -snark-verifier-sdk = { git = "https://github.com/timoftime/snark-verifier", branch = "timoftime/bump-revm", default-features = false } - -# [patch."https://github.com/timoftime/halo2curves"] -# halo2curves = { path = "../halo2curves" } +# snark-verifier = { git = "https://github.com/timoftime/snark-verifier", branch = "timoftime/bump-revm", default-features = false } +# snark-verifier-sdk = { git = "https://github.com/timoftime/snark-verifier", branch = "timoftime/bump-revm", default-features = false } +# snark-verifier = { path = "../snark-verifier/snark-verifier", default-features = false } +# snark-verifier-sdk = { path = "../snark-verifier/snark-verifier-sdk", default-features = false } [patch."https://github.com/ralexstokes/ssz-rs"] ssz-rs = { git = "https://github.com/polytope-labs/ssz-rs", branch = "main", default-features = false } diff --git a/eth-types/Cargo.toml b/eth-types/Cargo.toml index aaf27db1..243cf95c 100644 --- a/eth-types/Cargo.toml +++ b/eth-types/Cargo.toml @@ -8,10 +8,13 @@ license = "MIT OR Apache-2.0" [dependencies] hex = "0.4" lazy_static = "1.4" -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false, features = [ + "halo2-axiom", +] } +# halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } +halo2curves = { git = "https://github.com/axiom-crypto/halo2curves" } regex = "1.5.4" -serde = {version = "1.0.130", features = ["derive"] } +serde = { version = "1.0.130", features = ["derive"] } serde_json = "1.0.66" # serde_with = "1.12" uint = "0.9.1" @@ -21,5 +24,4 @@ num = "0.4" num-bigint = { version = "0.4" } strum_macros = "0.24" strum = "0.24" -halo2curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.1" } pasta_curves = "0.4.1" diff --git a/eth-types/src/curve.rs b/eth-types/src/curve.rs index 9bafa717..87697a6d 100644 --- a/eth-types/src/curve.rs +++ b/eth-types/src/curve.rs @@ -49,24 +49,6 @@ pub trait AppCurveExt: CurveExt { } } -pub trait HashCurveExt: AppCurveExt { - const BLS_X: u64; - - const SWU_A: Self::Fq; - const SWU_B: Self::Fq; - const SWU_Z: Self::Fq; - - const ISO_XNUM: [Self::Fq; 4]; - const ISO_XDEN: [Self::Fq; 3]; - const ISO_YNUM: [Self::Fq; 4]; - const ISO_YDEN: [Self::Fq; 4]; - - const PSI_X: Self::Fq; - const PSI_Y: Self::Fq; - const PSI2_X: Self::Fq; - - fn get_fq(v: impl IntoIterator>) -> Self::Fq; -} mod bls12_381 { use super::*; @@ -107,327 +89,4 @@ mod bls12_381 { G2Affine::generator() } } - - impl HashCurveExt for G2 { - const BLS_X: u64 = 0xd201000000010000; - - const SWU_A: Self::Fq = Self::Fq { - c0: Fq::zero(), - c1: Fq::from_raw_unchecked([ - 0xe53a_0000_0313_5242, - 0x0108_0c0f_def8_0285, - 0xe788_9edb_e340_f6bd, - 0x0b51_3751_2631_0601, - 0x02d6_9857_17c7_44ab, - 0x1220_b4e9_79ea_5467, - ]), - }; - - const SWU_B: Self::Fq = Self::Fq { - c0: Fq::from_raw_unchecked([ - 0x22ea_0000_0cf8_9db2, - 0x6ec8_32df_7138_0aa4, - 0x6e1b_9440_3db5_a66e, - 0x75bf_3c53_a794_73ba, - 0x3dd3_a569_412c_0a34, - 0x125c_db5e_74dc_4fd1, - ]), - c1: Fq::from_raw_unchecked([ - 0x22ea_0000_0cf8_9db2, - 0x6ec8_32df_7138_0aa4, - 0x6e1b_9440_3db5_a66e, - 0x75bf_3c53_a794_73ba, - 0x3dd3_a569_412c_0a34, - 0x125c_db5e_74dc_4fd1, - ]), - }; - - const SWU_Z: Self::Fq = Self::Fq { - c0: Fq::from_raw_unchecked([ - 0x87eb_ffff_fff9_555c, - 0x656f_ffe5_da8f_fffa, - 0x0fd0_7493_45d3_3ad2, - 0xd951_e663_0665_76f4, - 0xde29_1a3d_41e9_80d3, - 0x0815_664c_7dfe_040d, - ]), - c1: Fq::from_raw_unchecked([ - 0x43f5_ffff_fffc_aaae, - 0x32b7_fff2_ed47_fffd, - 0x07e8_3a49_a2e9_9d69, - 0xeca8_f331_8332_bb7a, - 0xef14_8d1e_a0f4_c069, - 0x040a_b326_3eff_0206, - ]), - }; - - /// Coefficients of the 3-isogeny x map's numerator - const ISO_XNUM: [Self::Fq; 4] = [ - Self::Fq { - c0: Fq::from_raw_unchecked([ - 0x40aa_c71c_71c7_25ed, - 0x1909_5555_7a84_e38e, - 0xd817_050a_8f41_abc3, - 0xd864_85d4_c87f_6fb1, - 0x696e_b479_f885_d059, - 0x198e_1a74_3280_02d2, - ]), - c1: Fq::zero(), - }, - Self::Fq { - c0: Fq::from_raw_unchecked([ - 0x0a0c_5555_5559_71c3, - 0xdb0c_0010_1f9e_aaae, - 0xb1fb_2f94_1d79_7997, - 0xd396_0742_ef41_6e1c, - 0xb700_40e2_c205_56f4, - 0x149d_7861_e581_393b, - ]), - c1: Fq::from_raw_unchecked([ - 0xaff2_aaaa_aaa6_38e8, - 0x439f_ffee_91b5_5551, - 0xb535_a30c_d937_7c8c, - 0x90e1_4442_0443_a4a2, - 0x941b_66d3_8146_55e2, - 0x0563_9988_53fe_ad5e, - ]), - }, - Self::Fq { - c0: Fq::zero(), - c1: Fq::from_raw_unchecked([ - 0x5fe5_5555_554c_71d0, - 0x873f_ffdd_236a_aaa3, - 0x6a6b_4619_b26e_f918, - 0x21c2_8884_0887_4945, - 0x2836_cda7_028c_abc5, - 0x0ac7_3310_a7fd_5abd, - ]), - }, - Self::Fq { - c0: Fq::from_raw_unchecked([ - 0x47f6_71c7_1ce0_5e62, - 0x06dd_5707_1206_393e, - 0x7c80_cd2a_f3fd_71a2, - 0x0481_03ea_9e6c_d062, - 0xc545_16ac_c8d0_37f6, - 0x1380_8f55_0920_ea41, - ]), - c1: Fq::from_raw_unchecked([ - 0x47f6_71c7_1ce0_5e62, - 0x06dd_5707_1206_393e, - 0x7c80_cd2a_f3fd_71a2, - 0x0481_03ea_9e6c_d062, - 0xc545_16ac_c8d0_37f6, - 0x1380_8f55_0920_ea41, - ]), - }, - ]; - - /// Coefficients of the 3-isogeny x map's denominator - const ISO_XDEN: [Self::Fq; 3] = [ - // Self::Fp::zero(), - Self::Fq { - c0: Fq::one(), - c1: Fq::zero(), - }, - Self::Fq { - c0: Fq::from_raw_unchecked([ - 0x4476_0000_0027_552e, - 0xdcb8_009a_4348_0020, - 0x6f7e_e9ce_4a6e_8b59, - 0xb103_30b7_c0a9_5bc6, - 0x6140_b1fc_fb1e_54b7, - 0x0381_be09_7f0b_b4e1, - ]), - c1: Fq::from_raw_unchecked([ - 0x7588_ffff_ffd8_557d, - 0x41f3_ff64_6e0b_ffdf, - 0xf7b1_e8d2_ac42_6aca, - 0xb374_1acd_32db_b6f8, - 0xe9da_f5b9_482d_581f, - 0x167f_53e0_ba74_31b8, - ]), - }, - Self::Fq { - c0: Fq::zero(), - c1: Fq::from_raw_unchecked([ - 0x1f3a_ffff_ff13_ab97, - 0xf25b_fc61_1da3_ff3e, - 0xca37_57cb_3819_b208, - 0x3e64_2736_6f8c_ec18, - 0x0397_7bc8_6095_b089, - 0x04f6_9db1_3f39_a952, - ]), - }, - ]; - - /// Coefficients of the 3-isogeny y map's numerator - const ISO_YNUM: [Self::Fq; 4] = [ - Self::Fq { - c0: Fq::from_raw_unchecked([ - 0xa470_bda1_2f67_f35c, - 0xc0fe_38e2_3327_b425, - 0xc9d3_d0f2_c6f0_678d, - 0x1c55_c993_5b5a_982e, - 0x27f6_c0e2_f074_6764, - 0x117c_5e6e_28aa_9054, - ]), - c1: Fq::zero(), - }, - Self::Fq { - c0: Fq::from_raw_unchecked([ - 0xd7f9_5555_5553_1c74, - 0x21cf_fff7_48da_aaa8, - 0x5a9a_d186_6c9b_be46, - 0x4870_a221_0221_d251, - 0x4a0d_b369_c0a3_2af1, - 0x02b1_ccc4_29ff_56af, - ]), - c1: Fq::from_raw_unchecked([ - 0xe205_aaaa_aaac_8e37, - 0xfcdc_0007_6879_5556, - 0x0c96_011a_8a15_37dd, - 0x1c06_a963_f163_406e, - 0x010d_f44c_82a8_81e6, - 0x174f_4526_0f80_8feb, - ]), - }, - Self::Fq { - c0: Fq::zero(), - c1: Fq::from_raw_unchecked([ - 0xbf0a_71c7_1c91_b406, - 0x4d6d_55d2_8b76_38fd, - 0x9d82_f98e_5f20_5aee, - 0xa27a_a27b_1d1a_18d5, - 0x02c3_b2b2_d293_8e86, - 0x0c7d_1342_0b09_807f, - ]), - }, - Self::Fq { - c0: Fq::from_raw_unchecked([ - 0x96d8_f684_bdfc_77be, - 0xb530_e4f4_3b66_d0e2, - 0x184a_88ff_3796_52fd, - 0x57cb_23ec_fae8_04e1, - 0x0fd2_e39e_ada3_eba9, - 0x08c8_055e_31c5_d5c3, - ]), - c1: Fq::from_raw_unchecked([ - 0x96d8_f684_bdfc_77be, - 0xb530_e4f4_3b66_d0e2, - 0x184a_88ff_3796_52fd, - 0x57cb_23ec_fae8_04e1, - 0x0fd2_e39e_ada3_eba9, - 0x08c8_055e_31c5_d5c3, - ]), - }, - ]; - - /// Coefficients of the 3-isogeny y map's denominator - const ISO_YDEN: [Self::Fq; 4] = [ - Self::Fq { - c0: Fq::one(), - c1: Fq::zero(), - }, - Self::Fq { - c0: Fq::from_raw_unchecked([ - 0x66b1_0000_003a_ffc5, - 0xcb14_00e7_64ec_0030, - 0xa73e_5eb5_6fa5_d106, - 0x8984_c913_a0fe_09a9, - 0x11e1_0afb_78ad_7f13, - 0x0542_9d0e_3e91_8f52, - ]), - c1: Fq::from_raw_unchecked([ - 0x534d_ffff_ffc4_aae6, - 0x5397_ff17_4c67_ffcf, - 0xbff2_73eb_870b_251d, - 0xdaf2_8271_5287_0915, - 0x393a_9cba_ca9e_2dc3, - 0x14be_74db_faee_5748, - ]), - }, - Self::Fq { - c0: Fq::zero(), - c1: Fq::from_raw_unchecked([ - 0x5db0_ffff_fd3b_02c5, - 0xd713_f523_58eb_fdba, - 0x5ea6_0761_a84d_161a, - 0xbb2c_75a3_4ea6_c44a, - 0x0ac6_7359_21c1_119b, - 0x0ee3_d913_bdac_fbf6, - ]), - }, - Self::Fq { - c0: Fq::from_raw_unchecked([ - 0x0162_ffff_fa76_5adf, - 0x8f7b_ea48_0083_fb75, - 0x561b_3c22_59e9_3611, - 0x11e1_9fc1_a9c8_75d5, - 0xca71_3efc_0036_7660, - 0x03c6_a03d_41da_1151, - ]), - c1: Fq::from_raw_unchecked([ - 0x0162_ffff_fa76_5adf, - 0x8f7b_ea48_0083_fb75, - 0x561b_3c22_59e9_3611, - 0x11e1_9fc1_a9c8_75d5, - 0xca71_3efc_0036_7660, - 0x03c6_a03d_41da_1151, - ]), - }, - ]; - - const PSI_X: Self::Fq = Self::Fq { - c0: Fq::zero(), - c1: Fq::from_raw_unchecked([ - 0x890dc9e4867545c3, - 0x2af322533285a5d5, - 0x50880866309b7e2c, - 0xa20d1b8c7e881024, - 0x14e4f04fe2db9068, - 0x14e56d3f1564853a, - ]), - }; - - const PSI_Y: Self::Fq = Self::Fq { - c0: Fq::from_raw_unchecked([ - 0x3e2f585da55c9ad1, - 0x4294213d86c18183, - 0x382844c88b623732, - 0x92ad2afd19103e18, - 0x1d794e4fac7cf0b9, - 0x0bd592fc7d825ec8, - ]), - c1: Fq::from_raw_unchecked([ - 0x7bcfa7a25aa30fda, - 0xdc17dec12a927e7c, - 0x2f088dd86b4ebef1, - 0xd1ca2087da74d4a7, - 0x2da2596696cebc1d, - 0x0e2b7eedbbfd87d2, - ]), - }; - - const PSI2_X: Self::Fq = Fq2 { - c0: Fq::from_raw_unchecked([ - 0xcd03c9e48671f071, - 0x5dab22461fcda5d2, - 0x587042afd3851b95, - 0x8eb60ebe01bacb9e, - 0x03f97d6e83d050d2, - 0x18f0206554638741, - ]), - c1: Fq::zero(), - }; - - fn get_fq(v: impl IntoIterator>) -> Self::Fq { - let (c0, c1) = v - .into_iter() - .map(|c| Fq::from_bytes(&c.try_into().unwrap()).unwrap()) - .collect_tuple() - .unwrap(); - Fq2 { c0, c1 } - } - } } diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index 297afd5c..3a62d97f 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -2,65 +2,69 @@ #![feature(associated_type_bounds)] #![feature(associated_type_defaults)] #![feature(generic_const_exprs)] +#![feature(trait_alias)] mod spec; +use halo2_base::utils::BigPrimeField; pub use spec::{Mainnet, Minimal, Spec, Testnet}; -mod curve; -pub use curve::{AppCurveExt, HashCurveExt}; +// mod curve; +// pub use curve::{AppCurveExt}; -use core::hash::Hash; -use halo2_proofs::{ - arithmetic::{Field as Halo2Field, FieldExt}, - halo2curves::{ - bn256::{Fq, Fr}, - group::ff::PrimeField, - }, -}; +// use core::hash::Hash; +// use halo2_proofs::{ +// arithmetic::{Field as Halo2Field, FieldExt}, +// halo2curves::{ +// bn256::{Fq, Fr}, +// group::ff::PrimeField, +// }, +// }; -/// Trait used to reduce verbosity with the declaration of the [`PrimeField`] -/// trait and its repr. -pub trait Field: - FieldExt + Halo2Field + PrimeField + Hash + Ord + halo2_ecc::fields::PrimeField -{ - fn pow_const(&self, mut exp: usize) -> Self { - if exp == 0 { - return Self::one(); - } +pub trait Field = BigPrimeField; - let mut base = *self; +// /// Trait used to reduce verbosity with the declaration of the [`PrimeField`] +// /// trait and its repr. +// pub trait Field: +// FieldExt + Halo2Field + Hash + Ord + halo2_ecc::fields::PrimeField +// { +// fn pow_const(&self, mut exp: usize) -> Self { +// if exp == 0 { +// return Self::one(); +// } - while exp & 1 == 0 { - base = base.square(); - exp >>= 1; - } +// let mut base = *self; - let mut acc = base; - while exp > 1 { - exp >>= 1; - base = base.square(); - if exp & 1 == 1 { - acc *= &base; - } - } - acc - } +// while exp & 1 == 0 { +// base = base.square(); +// exp >>= 1; +// } - /// Composes a field element from a little endian byte representation. - /// WARNING: CAN OVERFLOW. - fn from_bytes_le_unsecure<'a, I: IntoIterator>(bytes: I) -> Self { - let two = Self::from(2); - let mut value = Self::zero(); - for (i, byte) in bytes.into_iter().enumerate() { - value += Self::from(*byte as u64) * two.pow_const(8 * i); - } - value - } -} +// let mut acc = base; +// while exp > 1 { +// exp >>= 1; +// base = base.square(); +// if exp & 1 == 1 { +// acc *= &base; +// } +// } +// acc +// } -// Impl custom `Field` trait for BN256 Fr to be used and consistent with the -// rest of the workspace. -impl Field for Fr {} +// /// Composes a field element from a little endian byte representation. +// /// WARNING: CAN OVERFLOW. +// fn from_bytes_le_unsecure<'a, I: IntoIterator>(bytes: I) -> Self { +// let two = Self::from(2); +// let mut value = Self::zero(); +// for (i, byte) in bytes.into_iter().enumerate() { +// value += Self::from(*byte as u64) * two.pow_const(8 * i); +// } +// value +// } +// } -// Impl custom `Field` trait for BN256 Frq to be used and consistent with the -// rest of the workspace. -impl Field for Fq {} +// // Impl custom `Field` trait for BN256 Fr to be used and consistent with the +// // rest of the workspace. +// impl Field for Fr {} + +// // Impl custom `Field` trait for BN256 Frq to be used and consistent with the +// // rest of the workspace. +// impl Field for Fq {} diff --git a/lightclient-circuits/Cargo.toml b/lightclient-circuits/Cargo.toml index f7810f6c..45eaa105 100644 --- a/lightclient-circuits/Cargo.toml +++ b/lightclient-circuits/Cargo.toml @@ -7,29 +7,29 @@ license = "MIT OR Apache-2.0" [dependencies] # halo2 -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02", features = [ - "dev-graph", -] } -halo2curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.1" } +# halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02", features = [ +# "dev-graph", +# ] } +halo2curves = { git = "https://github.com/axiom-crypto/halo2curves" } halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false, features = [ - "halo2-pse", + "halo2-axiom", "display", ] } halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } -poseidon = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } +# poseidon = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } # verifier SDK -snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "community-edition", default-features = false, features = [ +snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "develop", default-features = false, features = [ "display", "loader_halo2", "loader_evm", - "halo2-pse" + "halo2-axiom" ] } -snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "community-edition", default-features = false, features = [ +snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "develop", default-features = false, features = [ "display", "loader_halo2", "loader_evm", - "halo2-pse", + "halo2-axiom" ] } # crypto num-bigint = { version = "0.4", features = ["rand"] } @@ -58,6 +58,7 @@ log = "0.4" hex = "0.4" rayon = "1.7.0" ark-std = { version = "0.4.0", features = ["print-trace"] } +getset="0.1.2" poseidon_native = { git = "https://github.com/axiom-crypto/halo2.git", branch = "axiom/dev", package = "poseidon" } [dev-dependencies] diff --git a/lightclient-circuits/src/builder.rs b/lightclient-circuits/src/builder.rs index 5687b390..d6530a17 100644 --- a/lightclient-circuits/src/builder.rs +++ b/lightclient-circuits/src/builder.rs @@ -1,11 +1,11 @@ use eth_types::Field; use halo2_base::{ - gates::builder::{CircuitBuilderStage, FlexGateConfigParams, MultiPhaseThreadBreakPoints}, + gates::{CircuitBuilderStage, FlexGateConfigParams, MultiPhaseThreadBreakPoints}, AssignedValue, -}; -use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - plonk::{Circuit, Column, ConstraintSystem, Error, Instance}, + halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + plonk::{Circuit, Column, ConstraintSystem, Error, Instance}, + } }; use log::debug; diff --git a/lightclient-circuits/src/gadget/common.rs b/lightclient-circuits/src/gadget/common.rs index 4f5417be..3b9d9e0a 100644 --- a/lightclient-circuits/src/gadget/common.rs +++ b/lightclient-circuits/src/gadget/common.rs @@ -1,12 +1,10 @@ //! Utility traits, functions used in the crate. use eth_types::Field; -use halo2_proofs::plonk::Expression; +use halo2_base::halo2_proofs::plonk::Expression; /// Returns the sum of the passed in cells pub mod sum { - use super::Expr; - use eth_types::Field; - use halo2_proofs::plonk::Expression; + use super::{Expr, Expression, Field}; /// Returns an expression for the sum of the list of expressions. pub fn expr, I: IntoIterator>(inputs: I) -> Expression { @@ -26,9 +24,7 @@ pub mod sum { /// Returns `1` when `expr[0] && expr[1] && ... == 1`, and returns `0` /// otherwise. Inputs need to be boolean pub mod and { - use super::Expr; - use eth_types::Field; - use halo2_proofs::plonk::Expression; + use super::{Expr, Expression, Field}; /// Returns an expression that evaluates to 1 only if all the expressions in /// the given list are 1, else returns 0. @@ -47,10 +43,8 @@ pub mod and { /// Returns `1` when `expr[0] || expr[1] || ... == 1`, and returns `0` /// otherwise. Inputs need to be boolean pub mod or { - use super::Expr; use super::{and, not}; - use eth_types::Field; - use halo2_proofs::plonk::Expression; + use super::{Expr, Expression, Field}; /// Returns an expression that evaluates to 1 if any expression in the given /// list is 1. Returns 0 if all the expressions were 0. @@ -67,9 +61,7 @@ pub mod or { /// Returns `1` when `b == 0`, and returns `0` otherwise. /// `b` needs to be boolean pub mod not { - use super::Expr; - use eth_types::Field; - use halo2_proofs::plonk::Expression; + use super::{Expr, Expression, Field}; /// Returns an expression that represents the NOT of the given expression. pub fn expr>(b: E) -> Expression { @@ -85,9 +77,7 @@ pub mod not { /// Returns `a ^ b`. /// `a` and `b` needs to be boolean pub mod xor { - use super::Expr; - use eth_types::Field; - use halo2_proofs::plonk::Expression; + use super::{Expr, Expression, Field}; /// Returns an expression that represents the XOR of the given expression. pub fn expr>(a: E, b: E) -> Expression { @@ -103,9 +93,7 @@ pub mod xor { /// Returns `when_true` when `selector == 1`, and returns `when_false` when /// `selector == 0`. `selector` needs to be boolean. pub mod select { - use super::Expr; - use eth_types::Field; - use halo2_proofs::plonk::Expression; + use super::{Expr, Expression, Field}; /// Returns the `when_true` expression when the selector is true, else /// returns the `when_false` expression. @@ -221,10 +209,8 @@ pub fn pow_of_two(by: usize) -> F { pub mod rlc { use std::ops::{Add, Mul}; - use super::Expr; - use eth_types::Field; - use halo2_base::{safe_types::GateInstructions, AssignedValue, Context, QuantumCell}; - use halo2_proofs::plonk::Expression; + use super::{Expr, Expression, Field}; + use halo2_base::{AssignedValue, Context, QuantumCell, gates::GateInstructions}; /// Returns an expression that represents the random linear combination. pub fn expr>(expressions: &[E], randomness: E) -> Expression { diff --git a/lightclient-circuits/src/gadget/crypto/builder.rs b/lightclient-circuits/src/gadget/crypto/builder.rs index d0177c35..ebb1ec20 100644 --- a/lightclient-circuits/src/gadget/crypto/builder.rs +++ b/lightclient-circuits/src/gadget/crypto/builder.rs @@ -1,183 +1,193 @@ use std::{cell::RefCell, collections::HashMap, env::set_var, marker::PhantomData, mem}; use eth_types::Field; +use getset::Getters; use halo2_base::{ gates::{ - builder::{ - assign_threads_in, CircuitBuilderStage, FlexGateConfigParams, KeygenAssignments, - MultiPhaseThreadBreakPoints, ThreadBreakPoints, + circuit::{ + builder::BaseCircuitBuilder, BaseCircuitParams, BaseConfig, CircuitBuilderStage, }, - range::{RangeConfig, RangeStrategy}, + flex_gate::threads::SinglePhaseCoreManager, + RangeChip, }, - safe_types::RangeChip, - SKIP_FIRST_PASS, -}; -use halo2_proofs::{ - circuit::{self, Layouter, SimpleFloorPlanner}, - plonk::{Circuit, ConstraintSystem, Error}, + halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + plonk::{Circuit, ConstraintSystem, Error}, + }, + utils::BigPrimeField, + virtual_region::manager::VirtualRegionManager, + Context, }; -use snark_verifier_sdk::CircuitExt; use crate::{ gadget::crypto::{Sha256Chip, ShaThreadBuilder}, - util::{ThreadBuilderBase, ThreadBuilderConfigBase}, + util::ThreadBuilderBase, }; use super::sha256_flex::{assign_threads_sha, SpreadConfig, FIRST_PHASE}; #[derive(Debug, Clone)] -pub struct SHAConfig> { - pub compression: CustomConfig, - pub range: RangeConfig, +pub struct SHAConfig { + pub compression: SpreadConfig, + pub base: BaseConfig, } -impl> SHAConfig { - pub fn configure(meta: &mut ConstraintSystem, params: FlexGateConfigParams) -> Self { - let degree = params.k; - let mut range = RangeConfig::configure( - meta, - RangeStrategy::Vertical, - ¶ms.num_advice_per_phase, - ¶ms.num_lookup_advice_per_phase, - params.num_fixed, - params.k - 1, - degree, - ); - let compression = CustomConfig::configure(meta, params); - - range.gate.max_rows = (1 << degree) - meta.minimum_rows(); - Self { range, compression } +impl SHAConfig { + pub fn configure(meta: &mut ConstraintSystem, params: BaseCircuitParams) -> Self { + let base = BaseConfig::configure(meta, params); + let compression = SpreadConfig::configure(meta, 8, 1); + + Self { base, compression } } } +#[derive(Getters)] pub struct ShaCircuitBuilder> { - pub builder: RefCell, - pub break_points: RefCell, // `RefCell` allows the circuit to record break points in a keygen call of `synthesize` for use in later witness gen - _f: PhantomData, + #[getset(get = "pub", get_mut = "pub")] + pub(crate) sha: ThreadBuilder, + #[getset(get = "pub", get_mut = "pub")] + pub(crate) base: BaseCircuitBuilder, } impl> ShaCircuitBuilder { - pub fn new(builder: ThreadBuilder, break_points: Option) -> Self { + pub fn new(witness_gen_only: bool) -> Self { + let base = BaseCircuitBuilder::new(witness_gen_only); Self { - builder: RefCell::new(builder), - break_points: RefCell::new(break_points.unwrap_or_default()), - _f: PhantomData, + sha: ShaThreadBuilder::new(witness_gen_only) + .use_copy_manager(base.core().phase_manager[FIRST_PHASE].copy_manager.clone()), + base, } } - pub fn from_stage( - builder: ThreadBuilder, - break_points: Option, - stage: CircuitBuilderStage, - ) -> Self { - Self::new( - builder.unknown(stage == CircuitBuilderStage::Keygen), - break_points, - ) + pub fn from_stage(stage: CircuitBuilderStage) -> Self { + Self::new(stage == CircuitBuilderStage::Prover) + .unknown(stage == CircuitBuilderStage::Keygen) + } + + pub fn unknown(mut self, use_unknown: bool) -> Self { + self.sha = self.sha.unknown(use_unknown); + self.base = self.base.unknown(use_unknown); + self } /// Creates a new [ShaCircuitBuilder] with `use_unknown` of [ShaThreadBuilder] set to true. - pub fn keygen(builder: ThreadBuilder) -> Self { - Self::new(builder.unknown(true), None) + pub fn keygen() -> Self { + Self::from_stage(CircuitBuilderStage::Keygen) } /// Creates a new [ShaCircuitBuilder] with `use_unknown` of [GateThreadBuilder] set to false. - pub fn mock(builder: ThreadBuilder) -> Self { - Self::new(builder.unknown(false), None) + pub fn mock() -> Self { + Self::from_stage(CircuitBuilderStage::Mock) } /// Creates a new [ShaCircuitBuilder]. - pub fn prover(builder: ThreadBuilder, break_points: MultiPhaseThreadBreakPoints) -> Self { - Self::new(builder.unknown(false), Some(break_points)) + pub fn prover() -> Self { + Self::from_stage(CircuitBuilderStage::Prover) } - pub fn config(&self, k: usize, minimum_rows: Option) -> FlexGateConfigParams { - // clone everything so we don't alter the circuit in any way for later calls - let mut builder = self.builder.borrow().clone(); - builder.config(k, minimum_rows) + /// The log_2 size of the lookup table, if using. + pub fn lookup_bits(&self) -> Option { + self.base.lookup_bits() } - // re-usable function for synthesize - #[allow(clippy::type_complexity)] - pub fn sub_synthesize( - &self, - config: &SHAConfig, - layouter: &mut impl Layouter, - ) -> Result, Error> { - config - .range - .load_lookup_table(layouter) - .expect("load range lookup table"); + /// Set lookup bits + pub fn set_lookup_bits(&mut self, lookup_bits: usize) { + self.base.set_lookup_bits(lookup_bits); + } - let mut first_pass = SKIP_FIRST_PASS; - let witness_gen_only = self.builder.borrow().witness_gen_only(); + /// Returns new with lookup bits + pub fn use_lookup_bits(mut self, lookup_bits: usize) -> Self { + self.set_lookup_bits(lookup_bits); + self + } - let mut assigned_advices = HashMap::new(); + /// Sets new `k` = log2 of domain + pub fn set_k(&mut self, k: usize) { + self.base.set_k(k); + } - config.compression.load(layouter)?; + /// Returns new with `k` set + pub fn use_k(mut self, k: usize) -> Self { + self.set_k(k); + self + } - layouter.assign_region( - || "ShaCircuitBuilder generated circuit", - |mut region| { - if first_pass { - first_pass = false; - return Ok(()); - } - - if !witness_gen_only { - let mut builder = self.builder.borrow().clone(); - - let assignments = builder.assign_all( - &config.range.gate, - &config.range.lookup_advice, - &config.range.q_lookup, - &config.compression, - &mut region, - Default::default(), - )?; - *self.break_points.borrow_mut() = assignments.break_points.clone(); - assigned_advices = assignments.assigned_advices; - } else { - let builder = &mut self.builder.borrow_mut(); - let break_points = &mut self.break_points.borrow_mut(); - - builder.assign_witnesses( - &config.range.gate, - &config.range.lookup_advice, - &config.compression, - &mut region, - break_points, - )?; - } - Ok(()) - }, - )?; - Ok(assigned_advices) + /// Set config params + pub fn set_params(&mut self, params: BaseCircuitParams) { + self.base.set_params(params) + } + + /// Returns new with config params + pub fn use_params(mut self, params: BaseCircuitParams) -> Self { + self.set_params(params); + self + } + + /// Returns a mutable reference to the [Context] of a gate thread. Spawns a new thread for the given phase, if none exists. + /// * `phase`: The challenge phase (as an index) of the gate thread. + pub fn main(&mut self) -> &mut Context { + self.base.main(0) + } + + /// Returns [SinglePhaseCoreManager] with the virtual region with all core threads in the given phase. + pub fn pool(&mut self, phase: usize) -> &mut SinglePhaseCoreManager { + self.base.pool(phase) + } + + pub fn calculate_params(&mut self, minimum_rows: Option) -> BaseCircuitParams { + self.base.calculate_params(minimum_rows) + } + + pub fn sha_contexts_pair(&mut self) -> (&mut Context, &mut ThreadBuilder::CustomContext) { + (self.base.main(0), self.sha.custom_context()) + } + + pub fn range_chip(&mut self, lookup_bits: usize) -> RangeChip { + self.base.set_lookup_bits(lookup_bits); + self.base.range_chip() } } impl> Circuit for ShaCircuitBuilder { - type Config = SHAConfig; + type Config = SHAConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = BaseCircuitParams; + + fn params(&self) -> Self::Params { + self.base.config_params.clone() + } fn without_witnesses(&self) -> Self { unimplemented!() } - fn configure(meta: &mut ConstraintSystem) -> SHAConfig { - let params: FlexGateConfigParams = - serde_json::from_str(&std::env::var("FLEX_GATE_CONFIG_PARAMS").unwrap()).unwrap(); + fn configure_with_params(meta: &mut ConstraintSystem, params: Self::Params) -> Self::Config { SHAConfig::configure(meta, params) } + fn configure(_meta: &mut ConstraintSystem) -> SHAConfig { + unreachable!("You must use configure_with_params"); + } + fn synthesize( &self, config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - self.sub_synthesize(&config, &mut layouter)?; + config.compression.load(&mut layouter)?; + + layouter.assign_region( + || "ShaCircuitBuilder generated circuit", + |mut region| { + self.sha.assign_raw(&config.compression, &mut region); + Ok(()) + }, + )?; + + self.base.synthesize(config.base.clone(), layouter)?; + Ok(()) } } diff --git a/lightclient-circuits/src/gadget/crypto/ecc.rs b/lightclient-circuits/src/gadget/crypto/ecc.rs index 1423508f..50b50203 100644 --- a/lightclient-circuits/src/gadget/crypto/ecc.rs +++ b/lightclient-circuits/src/gadget/crypto/ecc.rs @@ -1,9 +1,9 @@ -use eth_types::{AppCurveExt, Field}; +use eth_types::Field; use halo2_base::Context; use halo2_ecc::{bigint::ProperCrtUint, bls12_381::FpChip, fields::FieldChip}; // Calculates y^2 = x^3 + 4 (the curve equation) -pub fn calculate_ysquared( +pub fn calculate_ysquared( ctx: &mut Context, field_chip: &FpChip<'_, F>, x: ProperCrtUint, @@ -11,6 +11,6 @@ pub fn calculate_ysquared( let x_squared = field_chip.mul(ctx, x.clone(), x.clone()); let x_cubed = field_chip.mul(ctx, x_squared, x); - let plus_b = field_chip.add_constant_no_carry(ctx, x_cubed, C::B.into()); + let plus_b = field_chip.add_constant_no_carry(ctx, x_cubed, 4.into()); field_chip.carry_mod(ctx, plus_b) } diff --git a/lightclient-circuits/src/gadget/crypto/hash2curve.rs b/lightclient-circuits/src/gadget/crypto/hash2curve.rs index 778fbbfe..c20792ec 100644 --- a/lightclient-circuits/src/gadget/crypto/hash2curve.rs +++ b/lightclient-circuits/src/gadget/crypto/hash2curve.rs @@ -90,7 +90,6 @@ impl<'a, S: Spec, F: Field, HC: HashInstructions + 'a> HashToCurveChip<'a, S, msg: HashInput>, cache: &mut HashToCurveCache, ) -> Result<[Fp2Point; 2], Error> { - // let range = self.hash_chip.range(); let gate = range.gate(); let safe_types = SafeTypeChip::new(range); @@ -660,6 +659,7 @@ mod test { let h2c_chip = HashToCurveChip::::new(&sha256); let fp_chip = halo2_ecc::bls12_381::FpChip::::new(&range, G2::LIMB_BITS, G2::NUM_LIMBS); + let fp2_chip = halo2_ecc::bls12_381::Fp2Chip::new(&fp_chip); for input in input_vector { let mut cache = HashToCurveCache::::default(); @@ -670,8 +670,16 @@ mod test { &mut cache, )?; - print_fq2_dev::(hp.x(), "res_p.x"); - print_fq2_dev::(hp.y(), "res_p.y"); + // print_fq2_dev::(hp.x(), "res_p.x"); + // print_fq2_dev::(hp.y(), "res_p.y"); + + println!( + "msghash: {:?}", + ( + fp2_chip.get_assigned_value(&hp.x.into()), + fp2_chip.get_assigned_value(&hp.y.into()) + ) + ); } builder.config(k, None); diff --git a/lightclient-circuits/src/gadget/crypto/mod.rs b/lightclient-circuits/src/gadget/crypto/mod.rs index 2bba9c67..93d53ad7 100644 --- a/lightclient-circuits/src/gadget/crypto/mod.rs +++ b/lightclient-circuits/src/gadget/crypto/mod.rs @@ -1,30 +1,25 @@ mod builder; mod ecc; -mod hash2curve; +// mod hash2curve; mod sha256_flex; -mod sha256_wide; -mod util; +// mod sha256_wide; pub use builder::{SHAConfig, ShaCircuitBuilder}; -use eth_types::{AppCurveExt, Field, HashCurveExt}; -use halo2_base::{safe_types::RangeChip, AssignedValue, QuantumCell}; +use eth_types::Field; +use halo2_base::{AssignedValue, QuantumCell}; use halo2_ecc::{ bigint::ProperCrtUint, - bls12_381::{Fp2Chip, FpChip}, + bls12_381::{Fp2Chip, Fp2Point, FpChip}, ecc::{EcPoint, EccChip}, fields::{fp2, vector::FieldVector, FieldExtConstructor}, }; -use halo2_proofs::plonk::Error; -pub use hash2curve::{HashToCurveCache, HashToCurveChip}; use lazy_static::lazy_static; pub use sha256_flex::{Sha256Chip, ShaContexts, ShaThreadBuilder}; -pub use sha256_wide::{Sha256ChipWide, ShaBitThreadBuilder}; +// pub use sha256_wide::{Sha256ChipWide, ShaBitThreadBuilder}; pub use ecc::calculate_ysquared; -use crate::{util::ThreadBuilderBase, witness::HashInput}; -pub type FpPoint = ProperCrtUint; -pub type Fp2Point = FieldVector>; +use crate::witness::HashInput; pub type G1Point = EcPoint>; pub type G2Point = EcPoint>; @@ -34,22 +29,7 @@ pub type G1Chip<'chip, F> = EccChip<'chip, F, FpChip<'chip, F>>; #[allow(type_alias_bounds)] pub type G2Chip<'chip, F> = EccChip<'chip, F, Fp2Chip<'chip, F>>; -pub trait HashInstructions = ShaThreadBuilder> { - const BLOCK_SIZE: usize; - const DIGEST_SIZE: usize; - - /// Digests input using hash function and returns finilized output. - /// `MAX_INPUT_SIZE` is the maximum size of input that can be processed by the hash function. - /// `strict` flag indicates whether to perform range check on input bytes. - fn digest( - &self, - thread_pool: &mut ThreadBuilder, - input: HashInput>, - strict: bool, - ) -> Result, Error>; - - fn range(&self) -> &RangeChip; -} +pub use halo2_ecc::ecc::hash_to_curve::HashInstructions; #[derive(Debug, Clone)] pub struct AssignedHashResult { diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs index e395e215..26f4203f 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs @@ -1,15 +1,14 @@ -mod builder; mod compression; +mod gate; mod spread; mod util; -pub use builder::ShaThreadBuilder; +pub use gate::ShaThreadBuilder; +use halo2_base::gates::RangeChip; pub use spread::SpreadConfig; use eth_types::Field; use ff::PrimeField; -use halo2_base::gates::builder::KeygenAssignments; -use halo2_proofs::circuit::Value; use itertools::Itertools; use sha2::compress256; use sha2::digest::generic_array::GenericArray; @@ -17,22 +16,23 @@ use std::collections::HashMap; use std::{cell::RefCell, char::MAX}; use crate::gadget::crypto::sha256_flex::compression::{sha256_compression, INIT_STATE}; -use crate::util::{AssignedValueCell, ThreadBuilderBase}; use crate::witness::HashInput; -use halo2_base::safe_types::RangeChip; use halo2_base::QuantumCell; use halo2_base::{ gates::{GateInstructions, RangeInstructions}, AssignedValue, Context, }; -use halo2_base::{utils::value_to_option, ContextCell}; -use halo2_proofs::{ - circuit::{self, AssignedCell, Region}, - plonk::{Assigned, Error}, +use halo2_base::{ + halo2_proofs::{ + circuit::{self, AssignedCell, Region}, + plonk::{Assigned, Error}, + }, + utils::value_to_option, + ContextCell, }; -pub use self::builder::ShaContexts; -pub(super) use self::builder::{assign_threads_sha, FIRST_PHASE}; +pub use self::gate::ShaContexts; +pub(super) use self::gate::{assign_threads_sha, FIRST_PHASE}; pub use self::spread::SpreadChip; use super::{AssignedHashResult, HashInstructions}; @@ -42,10 +42,13 @@ pub struct Sha256Chip<'a, F: Field> { spread: SpreadChip<'a, F>, } -impl<'a, F: Field> HashInstructions> for Sha256Chip<'a, F> { +impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { const BLOCK_SIZE: usize = 64; const DIGEST_SIZE: usize = 32; + type ThreadManager = ShaThreadBuilder; + type Output = AssignedHashResult; + fn digest( &self, thread_pool: &mut ShaThreadBuilder, @@ -188,10 +191,6 @@ impl<'a, F: Field> HashInstructions> for Sha256Chip<'a, F }; Ok(result) } - - fn range(&self) -> &RangeChip { - self.spread.range() - } } impl<'a, F: Field> Sha256Chip<'a, F> { @@ -214,83 +213,79 @@ mod test { use super::*; use ark_std::{end_timer, start_timer}; use eth_types::Testnet; - use halo2_base::gates::builder::FlexGateConfigParams; use halo2_base::gates::range::RangeConfig; + use halo2_base::halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + dev::MockProver, + halo2curves::bn256::Fr, + plonk::{Circuit, ConstraintSystem}, + }; use halo2_base::utils::fs::gen_srs; use halo2_base::SKIP_FIRST_PASS; - use halo2_base::{ - gates::{builder::GateThreadBuilder, range::RangeStrategy}, - halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::MockProver, - halo2curves::bn256::Fr, - plonk::{Circuit, ConstraintSystem}, - }, - }; use sha2::{Digest, Sha256}; - fn test_circuit( - k: usize, - mut builder: ShaThreadBuilder, - input_vector: &[Vec], - ) -> Result>, Error> { - let range = RangeChip::default(8); - let sha256 = Sha256Chip::new(&range); + // fn test_circuit( + // k: usize, + // mut builder: ShaThreadBuilder, + // input_vector: &[Vec], + // ) -> Result>, Error> { + // let range = RangeChip::default(8); + // let sha256 = Sha256Chip::new(&range); - for input in input_vector { - let _ = sha256.digest::<64>(&mut builder, input.as_slice().into_witness(), false)?; - } + // for input in input_vector { + // let _ = sha256.digest::<64>(&mut builder, input.as_slice().into_witness(), false)?; + // } - builder.config(k, None); - Ok(ShaCircuitBuilder::mock(builder)) - } + // builder.config(k, None); + // Ok(ShaCircuitBuilder::mock(builder)) + // } - #[test] - fn test_sha256_chip_constant_size() { - let k = 15; + // #[test] + // fn test_sha256_chip_constant_size() { + // let k = 15; - let test_input = vec![0u8; 64]; + // let test_input = vec![0u8; 64]; - let builder = ShaThreadBuilder::::mock(); + // let builder = ShaThreadBuilder::::mock(); - let circuit = test_circuit(k, builder, &[test_input]); - let prover = MockProver::run(k as u32, &circuit.unwrap(), vec![]).unwrap(); + // let circuit = test_circuit(k, builder, &[test_input]); + // let prover = MockProver::run(k as u32, &circuit.unwrap(), vec![]).unwrap(); - prover.assert_satisfied_par(); - } + // prover.assert_satisfied_par(); + // } - #[test] - fn test_sha256_params_gen() { - let k = 15; - let test_input = vec![0u8; 64]; - let builder = ShaThreadBuilder::::keygen(); + // #[test] + // fn test_sha256_params_gen() { + // let k = 15; + // let test_input = vec![0u8; 64]; + // let builder = ShaThreadBuilder::::keygen(); - let circuit = test_circuit(k, builder, &[test_input]).unwrap(); + // let circuit = test_circuit(k, builder, &[test_input]).unwrap(); - let params = gen_srs(k as u32); - let pk = gen_pkey(|| "sha256_chip", ¶ms, None, &circuit).unwrap(); - } + // let params = gen_srs(k as u32); + // let pk = gen_pkey(|| "sha256_chip", ¶ms, None, &circuit).unwrap(); + // } - #[test] - fn test_sha256_proof_gen() { - let k = 15; - let test_input = vec![0u8; 64]; - let builder = ShaThreadBuilder::::keygen(); + // #[test] + // fn test_sha256_proof_gen() { + // let k = 15; + // let test_input = vec![0u8; 64]; + // let builder = ShaThreadBuilder::::keygen(); - let circuit = test_circuit(k, builder, &[test_input.clone()]).unwrap(); + // let circuit = test_circuit(k, builder, &[test_input.clone()]).unwrap(); - let params = gen_srs(k as u32); - let pk = gen_pkey(|| "sha256_chip", ¶ms, None, &circuit).unwrap(); + // let params = gen_srs(k as u32); + // let pk = gen_pkey(|| "sha256_chip", ¶ms, None, &circuit).unwrap(); - let break_points = circuit.break_points.take(); + // let break_points = circuit.break_points.take(); - let builder = ShaThreadBuilder::::prover(); + // let builder = ShaThreadBuilder::::prover(); - let circuit = test_circuit(k, builder, &[test_input]).unwrap(); + // let circuit = test_circuit(k, builder, &[test_input]).unwrap(); - let proof = full_prover(¶ms, &pk, circuit, vec![]); + // let proof = full_prover(¶ms, &pk, circuit, vec![]); - let is_valid = full_verifier(¶ms, pk.get_vk(), proof, vec![]); - assert!(is_valid); - } + // let is_valid = full_verifier(¶ms, pk.get_vk(), proof, vec![]); + // assert!(is_valid); + // } } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/builder.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/builder.rs deleted file mode 100644 index 63f42b80..00000000 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/builder.rs +++ /dev/null @@ -1,268 +0,0 @@ -use std::{cell::RefCell, collections::HashMap, iter, mem}; - -use eth_types::Field; -use halo2_base::{ - gates::{ - builder::{ - assign_threads_in, CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, - KeygenAssignments, MultiPhaseThreadBreakPoints, ThreadBreakPoints, - }, - flex_gate::FlexGateConfig, - range, - }, - utils::ScalarField, - Context, -}; -use halo2_proofs::{ - circuit::{self, Region, Value}, - plonk::{Advice, Column, Error, Selector}, -}; -use itertools::Itertools; - -use crate::util::ThreadBuilderBase; - -use super::SpreadConfig; - -pub const FIRST_PHASE: usize = 0; - -#[derive(Clone, Debug, Default)] -pub struct ShaThreadBuilder { - /// Threads for spread table assignment. - pub threads_dense: Vec>, - /// Threads for spread table assignment. - pub threads_spread: Vec>, - /// [`GateThreadBuilder`] with threads for basic gate; also in charge of thread IDs - pub gate_builder: GateThreadBuilder, -} - -pub type ShaContexts<'a, F> = (&'a mut Context, &'a mut Context); - -impl ThreadBuilderBase for ShaThreadBuilder { - type Config = SpreadConfig; - - fn new(mut witness_gen_only: bool) -> Self { - Self { - threads_spread: Vec::new(), - threads_dense: Vec::new(), - gate_builder: GateThreadBuilder::new(witness_gen_only), - } - } - - fn from_stage(stage: CircuitBuilderStage) -> Self { - Self::new(stage == CircuitBuilderStage::Prover) - .unknown(stage == CircuitBuilderStage::Keygen) - } - - fn unknown(mut self, use_unknown: bool) -> Self { - self.gate_builder = self.gate_builder.unknown(use_unknown); - self - } - - fn main(&mut self) -> &mut Context { - self.gate_builder.main(FIRST_PHASE) - } - - fn witness_gen_only(&self) -> bool { - self.gate_builder.witness_gen_only() - } - - fn use_unknown(&self) -> bool { - self.gate_builder.use_unknown() - } - - fn thread_count(&self) -> usize { - self.gate_builder.thread_count() - } - - fn get_new_thread_id(&mut self) -> usize { - self.gate_builder.get_new_thread_id() - } - - fn config(&self, k: usize, minimum_rows: Option) -> FlexGateConfigParams { - self.gate_builder.config(k, minimum_rows) - } - - fn assign_all( - &mut self, - gate: &FlexGateConfig, - lookup_advice: &[Vec>], - q_lookup: &[Option], - spread: &SpreadConfig, - region: &mut Region, - KeygenAssignments { - mut assigned_advices, - assigned_constants, - mut break_points, - }: KeygenAssignments, - ) -> Result, Error> { - assert!(!self.witness_gen_only()); - - assign_threads_sha( - &self.threads_dense, - &self.threads_spread, - spread, - region, - self.use_unknown(), - Some(&mut assigned_advices), - ); - // in order to constrain equalities and assign constants, we copy the Spread/Dense equality constraints into the gate builder (it doesn't matter which context the equalities are in), so `GateThreadBuilder::assign_all` can take care of it - // the phase doesn't matter for equality constraints, so we use phase 0 since we're sure there's a main context there - let main_ctx = self.gate_builder.main(0); - for ctx in self - .threads_spread - .iter_mut() - .chain(self.threads_dense.iter_mut()) - { - main_ctx - .advice_equality_constraints - .append(&mut ctx.advice_equality_constraints); - main_ctx - .constant_equality_constraints - .append(&mut ctx.constant_equality_constraints); - } - - Ok(self.gate_builder.assign_all( - gate, - lookup_advice, - q_lookup, - region, - KeygenAssignments { - assigned_advices, - assigned_constants, - break_points, - }, - )) - } - - fn assign_witnesses( - &mut self, - gate: &FlexGateConfig, - lookup_advice: &[Vec>], - spread: &SpreadConfig, - region: &mut Region, - break_points: &mut MultiPhaseThreadBreakPoints, - ) -> Result<(), Error> { - let break_points_gate = mem::take(&mut break_points[FIRST_PHASE]); - // warning: we currently take all contexts from phase 0, which means you can't read the values - // from these contexts later in phase 1. If we want to read, should clone here - let threads = mem::take(&mut self.gate_builder.threads[FIRST_PHASE]); - - assign_threads_in( - FIRST_PHASE, - threads, - gate, - &lookup_advice[FIRST_PHASE], - region, - break_points_gate, - ); - - let threads_dense = mem::take(&mut self.threads_dense); - let threads_spread = mem::take(&mut self.threads_spread); - - assign_threads_sha(&threads_dense, &threads_spread, spread, region, false, None); - - Ok(()) - } -} - -impl ShaThreadBuilder { - pub fn sha_contexts_pair(&mut self) -> (&mut Context, ShaContexts) { - if self.threads_dense.is_empty() { - self.new_thread_dense(); - } - if self.threads_spread.is_empty() { - self.new_thread_spread(); - } - ( - self.gate_builder.main(FIRST_PHASE), - ( - self.threads_dense.last_mut().unwrap(), - self.threads_spread.last_mut().unwrap(), - ), - ) - } - - pub fn new_thread_dense(&mut self) -> &mut Context { - let thread_id = self.get_new_thread_id(); - self.threads_dense - .push(Context::new(self.witness_gen_only(), thread_id)); - self.threads_dense.last_mut().unwrap() - } - - pub fn new_thread_spread(&mut self) -> &mut Context { - let thread_id = self.get_new_thread_id(); - self.threads_spread - .push(Context::new(self.witness_gen_only(), thread_id)); - self.threads_spread.last_mut().unwrap() - } -} - -/// Pure advice witness assignment in a single phase. Uses preprocessed `break_points` to determine when -/// to split a thread into a new column. -#[allow(clippy::type_complexity)] -pub fn assign_threads_sha( - threads_dense: &[Context], - threads_spread: &[Context], - spread: &SpreadConfig, - region: &mut Region, - use_unknown: bool, - mut assigned_advices: Option<&mut HashMap<(usize, usize), (circuit::Cell, usize)>>, -) { - let mut num_limb_sum = 0; - let mut row_offset = 0; - for (ctx_dense, ctx_spread) in threads_dense.iter().zip_eq(threads_spread.iter()) { - for (i, (&advice_dense, &advice_spread)) in ctx_dense - .advice - .iter() - .zip_eq(ctx_spread.advice.iter()) - .enumerate() - { - let column_idx = num_limb_sum % spread.num_advice_columns; - let value_dense = if use_unknown { - Value::unknown() - } else { - Value::known(advice_dense) - }; - - let cell_dense = region - .assign_advice( - || "dense", - spread.denses[column_idx], - row_offset, - || value_dense, - ) - .unwrap() - .cell(); - - if let Some(assigned_advices) = assigned_advices.as_mut() { - assigned_advices.insert((ctx_dense.context_id, i), (cell_dense, row_offset)); - } - - let value_spread = if use_unknown { - Value::unknown() - } else { - Value::known(advice_spread) - }; - - let cell_spread = region - .assign_advice( - || "spread", - spread.spreads[column_idx], - row_offset, - || Value::known(advice_spread), - ) - .unwrap() - .cell(); - - if let Some(assigned_advices) = assigned_advices.as_mut() { - assigned_advices.insert((ctx_spread.context_id, i), (cell_spread, row_offset)); - } - - num_limb_sum += 1; - if column_idx == spread.num_advice_columns - 1 { - row_offset += 1; - } - row_offset += 1; - } - } -} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs index 60b3cf23..ee9750ec 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs @@ -1,13 +1,13 @@ use std::cell::RefMut; +use crate::gadget::crypto::ShaCircuitBuilder; use crate::util::ThreadBuilderBase; -use super::builder::ShaContexts; +use super::gate::ShaContexts; use super::spread::{self, SpreadChip, SpreadConfig}; use super::util::{bits_le_to_fe, fe_to_bits_le}; use super::ShaThreadBuilder; use eth_types::Field; -use halo2_base::halo2_proofs::halo2curves::FieldExt; use halo2_base::halo2_proofs::{ circuit::{AssignedCell, Cell, Layouter, Region, SimpleFloorPlanner, Value}, plonk::{ @@ -56,7 +56,7 @@ pub const INIT_STATE: [u32; NUM_STATE_WORD] = [ pub type SpreadU32<'a, F> = (AssignedValue, AssignedValue); pub fn sha256_compression<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, assigned_input_bytes: &[AssignedValue], pre_state_words: &[AssignedValue], @@ -249,7 +249,7 @@ pub fn sha256_compression<'a, 'b: 'a, F: Field>( } fn state_to_spread_u32<'a, F: Field>( - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x: &AssignedValue, ) -> Result, Error> { @@ -292,7 +292,7 @@ fn mod_u32<'a, 'b: 'a, F: Field>( } fn ch<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x: &SpreadU32<'a, F>, y: &SpreadU32<'a, F>, @@ -402,7 +402,7 @@ fn ch<'a, 'b: 'a, F: Field>( } fn maj<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x: &SpreadU32<'a, F>, y: &SpreadU32<'a, F>, @@ -524,7 +524,7 @@ fn sigma_upper1<'a, 'b: 'a, F: Field>( } fn sigma_lower0<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x_spread: &SpreadU32, ) -> Result, Error> { @@ -575,7 +575,7 @@ fn sigma_lower1<'a, 'b: 'a, F: Field>( #[allow(clippy::too_many_arguments)] fn sigma_generic<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x_spread: &SpreadU32, starts: &[usize; 4], diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs new file mode 100644 index 00000000..547ce382 --- /dev/null +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs @@ -0,0 +1,240 @@ +use std::any::TypeId; + +use getset::CopyGetters; +use halo2_base::{ + gates::circuit::CircuitBuilderStage, + halo2_proofs::circuit::{Region, Value}, + utils::BigPrimeField, + virtual_region::{ + copy_constraints::{CopyConstraintManager, SharedCopyConstraintManager}, + manager::VirtualRegionManager, + }, + Context, ContextCell, +}; +use itertools::Itertools; + +use super::SpreadConfig; + +pub const FIRST_PHASE: usize = 0; + +struct Dence; +struct Spread; + +#[derive(Clone, Debug, Default, CopyGetters)] +pub struct ShaThreadBuilder { + #[getset(get_copy = "pub")] + witness_gen_only: bool, + /// The `unknown` flag is used during key generation. If true, during key generation witness [Value]s are replaced with Value::unknown() for safety. + #[getset(get_copy = "pub")] + pub(crate) use_unknown: bool, + /// Threads for spread table assignment. + pub threads_dense: Vec>, + /// Threads for spread table assignment. + pub threads_spread: Vec>, + + pub copy_manager: SharedCopyConstraintManager, +} + +pub type ShaContexts<'a, F> = (&'a mut Context, &'a mut Context); + +impl ShaThreadBuilder { + pub fn new(witness_gen_only: bool) -> Self { + Self { + witness_gen_only, + use_unknown: false, + threads_spread: Vec::new(), + threads_dense: Vec::new(), + copy_manager: SharedCopyConstraintManager::default(), + } + } + + pub fn mock() -> Self { + Self::new(false) + } + + pub fn keygen() -> Self { + Self::new(false).unknown(true) + } + + pub fn prover() -> Self { + Self::new(true) + } + + pub fn from_stage(stage: CircuitBuilderStage) -> Self { + Self::new(stage == CircuitBuilderStage::Prover) + .unknown(stage == CircuitBuilderStage::Keygen) + } + + /// Mutates `self` to use the given copy manager everywhere, including in all threads. + pub fn set_copy_manager(&mut self, copy_manager: SharedCopyConstraintManager) { + self.copy_manager = copy_manager.clone(); + for ctx in &mut self.threads_dense { + ctx.copy_manager = copy_manager.clone(); + } + for ctx in &mut self.threads_spread { + ctx.copy_manager = copy_manager.clone(); + } + } + + /// Returns `self` with a given copy manager + pub fn use_copy_manager(mut self, copy_manager: SharedCopyConstraintManager) -> Self { + self.set_copy_manager(copy_manager); + self + } + + pub fn unknown(mut self, use_unknown: bool) -> Self { + self.use_unknown = use_unknown; + self + } + + pub fn contexts_pair(&mut self) -> ShaContexts { + if self.threads_dense.is_empty() { + self.new_thread_dense(); + } + if self.threads_spread.is_empty() { + self.new_thread_spread(); + } + ( + self.threads_dense.last_mut().unwrap(), + self.threads_spread.last_mut().unwrap(), + ) + } + + pub fn new_thread_dense(&mut self) -> &mut Context { + let thread_id = self.threads_dense.len(); + self.threads_dense.push(Context::new( + self.witness_gen_only(), + FIRST_PHASE, + TypeId::of::<(Self, Dence)>(), + thread_id, + self.copy_manager.clone(), + )); + self.threads_dense.last_mut().unwrap() + } + + pub fn new_thread_spread(&mut self) -> &mut Context { + let thread_id = self.threads_spread.len(); + self.threads_spread.push(Context::new( + self.witness_gen_only(), + FIRST_PHASE, + TypeId::of::<(Self, Spread)>(), + thread_id, + self.copy_manager.clone(), + )); + self.threads_spread.last_mut().unwrap() + } + + // pub fn thread_count(&self) -> usize { + // self.core.thread_count() + // } + + // pub fn get_new_thread_id(&mut self) -> usize { + // self.core.thread_count() + // } +} + +impl VirtualRegionManager for ShaThreadBuilder { + type Config = SpreadConfig; + + fn assign_raw(&self, spread: &Self::Config, region: &mut Region) { + spread.annotate_columns_in_region(region); + + if self.witness_gen_only() { + assign_threads_sha( + &self.threads_dense, + &self.threads_spread, + spread, + region, + false, + None, + ); + } else { + let mut copy_manager = self.copy_manager.lock().unwrap(); + + assign_threads_sha( + &self.threads_dense, + &self.threads_spread, + spread, + region, + self.use_unknown(), + Some(&mut copy_manager), + ); + } + } +} + +/// Pure advice witness assignment in a single phase. Uses preprocessed `break_points` to determine when +/// to split a thread into a new column. +#[allow(clippy::type_complexity)] +pub fn assign_threads_sha( + threads_dense: &[Context], + threads_spread: &[Context], + spread: &SpreadConfig, + region: &mut Region, + use_unknown: bool, + mut copy_manager: Option<&mut CopyConstraintManager>, +) { + let mut num_limb_sum = 0; + let mut row_offset = 0; + for (ctx_dense, ctx_spread) in threads_dense.iter().zip_eq(threads_spread.iter()) { + for (i, (&advice_dense, &advice_spread)) in ctx_dense + .advice + .iter() + .zip_eq(ctx_spread.advice.iter()) + .enumerate() + { + let column_idx = num_limb_sum % spread.num_advice_columns; + let value_dense = if use_unknown { + Value::unknown() + } else { + Value::known(advice_dense) + }; + + let cell_dense = region + .assign_advice( + || "dense", + spread.denses[column_idx], + row_offset, + || value_dense, + ) + .unwrap() + .cell(); + + if let Some(copy_manager) = copy_manager.as_mut() { + copy_manager.assigned_advices.insert( + ContextCell::new(ctx_dense.type_id(), ctx_dense.id(), i), + cell_dense, + ); + } + + let value_spread = if use_unknown { + Value::unknown() + } else { + Value::known(advice_spread) + }; + + let cell_spread = region + .assign_advice( + || "spread", + spread.spreads[column_idx], + row_offset, + || value_spread, + ) + .unwrap() + .cell(); + + if let Some(copy_manager) = copy_manager.as_mut() { + copy_manager.assigned_advices.insert( + ContextCell::new(ctx_spread.type_id(), ctx_spread.id(), i), + cell_spread, + ); + } + + num_limb_sum += 1; + if column_idx == spread.num_advice_columns - 1 { + row_offset += 1; + } + row_offset += 1; + } + } +} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs index c1ad00a1..e59dc550 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs @@ -1,35 +1,29 @@ use std::marker::PhantomData; -use crate::util::{ThreadBuilderBase, ThreadBuilderConfigBase}; - -use super::builder::ShaContexts; -use super::ShaThreadBuilder; -use super::{compression::SpreadU32, util::*}; -use eth_types::Field; -use halo2_base::gates::builder::FlexGateConfigParams; -use halo2_base::halo2_proofs::halo2curves::FieldExt; -use halo2_base::halo2_proofs::{ - circuit::{AssignedCell, Cell, Layouter, Region, SimpleFloorPlanner, Value}, - plonk::{ - Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, Selector, TableColumn, - VirtualCells, +use halo2_base::utils::{decompose, ScalarField}; +use halo2_base::QuantumCell; +use halo2_base::{ + gates::RangeChip, + halo2_proofs::{ + circuit::{Layouter, Region, Value}, + plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, + poly::Rotation, }, - poly::Rotation, + utils::BigPrimeField, }; -use halo2_base::safe_types::RangeChip; -use halo2_base::utils::decompose; -use halo2_base::QuantumCell; use halo2_base::{ - gates::{flex_gate::FlexGateConfig, range::RangeConfig, GateInstructions, RangeInstructions}, - utils::{bigint_to_fe, biguint_to_fe, fe_to_biguint, modulus}, + gates::{GateInstructions, RangeInstructions}, AssignedValue, Context, }; -use halo2_proofs::plonk::Any; use itertools::Itertools; -use num_bigint::BigUint; + +use crate::gadget::crypto::ShaCircuitBuilder; + +use super::ShaThreadBuilder; +use super::util::{fe_to_bits_le, bits_le_to_fe}; #[derive(Debug, Clone)] -pub struct SpreadConfig { +pub struct SpreadConfig { pub denses: Vec>, pub spreads: Vec>, pub table_dense: TableColumn, @@ -39,7 +33,7 @@ pub struct SpreadConfig { _f: PhantomData, } -impl SpreadConfig { +impl SpreadConfig { pub fn configure( meta: &mut ConstraintSystem, num_bits_lookup: usize, @@ -64,7 +58,7 @@ impl SpreadConfig { let table_dense = meta.lookup_table_column(); let table_spread = meta.lookup_table_column(); - for (idx, (dense, spread)) in denses.iter().zip(spreads.iter()).enumerate() { + for (dense, spread) in denses.iter().zip(spreads.iter()) { meta.lookup("spread lookup", |meta| { let dense = meta.query_advice(*dense, Rotation::cur()); let spread = meta.query_advice(*spread, Rotation::cur()); @@ -82,22 +76,7 @@ impl SpreadConfig { } } - pub fn annotate_columns_in_region(&self, region: &mut Region) { - for (i, col) in self.denses.iter().copied().enumerate() { - region.name_column(|| format!("dense_{}", i), col); - } - for (i, col) in self.spreads.iter().copied().enumerate() { - region.name_column(|| format!("spread_{}", i), col); - } - } -} - -impl ThreadBuilderConfigBase for SpreadConfig { - fn configure(meta: &mut ConstraintSystem, params: FlexGateConfigParams) -> Self { - Self::configure(meta, 8, 1) // TODO configure num_advice_columns - } - - fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { layouter.assign_table( || "spread table", |mut table| { @@ -128,7 +107,7 @@ impl ThreadBuilderConfigBase for SpreadConfig { Ok(()) } - fn annotate_columns_in_region(&self, region: &mut Region) { + pub fn annotate_columns_in_region(&self, region: &mut Region) { for (i, &column) in self.spreads.iter().enumerate() { region.name_column(|| format!("spread_{i}"), column); } @@ -140,11 +119,11 @@ impl ThreadBuilderConfigBase for SpreadConfig { } #[derive(Debug, Clone)] -pub struct SpreadChip<'a, F: Field> { +pub struct SpreadChip<'a, F: ScalarField> { range: &'a RangeChip, } -impl<'a, F: Field> SpreadChip<'a, F> { +impl<'a, F: BigPrimeField> SpreadChip<'a, F> { pub fn new(range: &'a RangeChip) -> Self { debug_assert_eq!(16 % range.lookup_bits(), 0); @@ -152,7 +131,7 @@ impl<'a, F: Field> SpreadChip<'a, F> { } pub fn spread( &self, - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, dense: &AssignedValue, ) -> Result, Error> { let gate = self.range.gate(); @@ -205,7 +184,7 @@ impl<'a, F: Field> SpreadChip<'a, F> { fn spread_limb( &self, - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, limb: &AssignedValue, ) -> Result, Error> { let (ctx_base, (ctx_dense, ctx_spread)) = thread_pool.sha_contexts_pair(); @@ -222,9 +201,7 @@ impl<'a, F: Field> SpreadChip<'a, F> { let assigned_spread = ctx_base.load_witness(spread_value); let assigned_spread_vanila = ctx_spread.load_witness(*assigned_spread.value()); - thread_pool - .main() - .constrain_equal(&assigned_spread_vanila, &assigned_spread); + ctx_base.constrain_equal(&assigned_spread_vanila, &assigned_spread); Ok(assigned_spread) } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs index 3d63c22e..0415286f 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs @@ -1,6 +1,5 @@ use eth_types::Field; use halo2_base::utils::{biguint_to_fe, fe_to_biguint}; -use halo2_proofs::circuit::AssignedCell; use itertools::Itertools; use num_bigint::BigUint; diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs index 58391755..98a597d6 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs @@ -1,4 +1,4 @@ -mod builder; +mod gate; mod config; mod util; mod witness; @@ -31,7 +31,7 @@ use halo2_proofs::{ plonk::{Assigned, Error}, }; -pub use self::builder::ShaBitThreadBuilder; +pub use self::gate::ShaBitThreadBuilder; use self::config::Sha256BitConfig; use self::util::{NUM_BYTES_FINAL_HASH, NUM_WORDS_TO_ABSORB}; @@ -59,10 +59,13 @@ pub struct AssignedSha256Round { pub output_rlc: AssignedValue, } -impl<'a, F: Field> HashInstructions> for Sha256ChipWide<'a, F> { +impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { const BLOCK_SIZE: usize = 64; const DIGEST_SIZE: usize = 32; + type ThreadManager = ShaBitThreadBuilder; + type Output = AssignedHashResult; + fn digest( &self, thread_pool: &mut ShaBitThreadBuilder, @@ -268,51 +271,51 @@ mod test { }; use sha2::{Digest, Sha256}; - fn test_circuit( - k: usize, - builder: &mut ShaBitThreadBuilder, - input_vector: &[Vec], - ) -> Result<(), Error> { - let range = RangeChip::default(8); - let sha256 = Sha256ChipWide::new(&range, constant_randomness()); + // fn test_circuit( + // k: usize, + // builder: &mut ShaBitThreadBuilder, + // input_vector: &[Vec], + // ) -> Result<(), Error> { + // let range = RangeChip::default(8); + // let sha256 = Sha256ChipWide::new(&range, constant_randomness()); - for input in input_vector { - let _ = sha256.digest::<64>(builder, input.as_slice().into_witness(), false)?; - } + // for input in input_vector { + // let _ = sha256.digest::<64>(builder, input.as_slice().into_witness(), false)?; + // } - builder.config(k, None); + // builder.config(k, None); - Ok(()) - } + // Ok(()) + // } - #[test] - fn test_sha256_chip_constant_size() { - let k = 10; + // #[test] + // fn test_sha256_chip_constant_size() { + // let k = 10; - let test_input = vec![0u8; 64]; + // let test_input = vec![0u8; 64]; - let mut builder = ShaBitThreadBuilder::::mock(); + // let mut builder = ShaBitThreadBuilder::::mock(); - test_circuit(k, &mut builder, &[test_input]).unwrap(); + // test_circuit(k, &mut builder, &[test_input]).unwrap(); - let circuit = ShaCircuitBuilder::mock(builder); + // let circuit = ShaCircuitBuilder::mock(builder); - let prover = MockProver::run(k as u32, &circuit, vec![]).unwrap(); + // let prover = MockProver::run(k as u32, &circuit, vec![]).unwrap(); - prover.assert_satisfied_par(); - } + // prover.assert_satisfied_par(); + // } - #[test] - fn test_sha256_wide_params_gen() { - let k = 10; - let test_input = vec![1u8; 64]; - let mut builder = ShaBitThreadBuilder::::keygen(); + // #[test] + // fn test_sha256_wide_params_gen() { + // let k = 10; + // let test_input = vec![1u8; 64]; + // let mut builder = ShaBitThreadBuilder::::keygen(); - test_circuit(k, &mut builder, &[test_input]).unwrap(); + // test_circuit(k, &mut builder, &[test_input]).unwrap(); - let circuit = ShaCircuitBuilder::keygen(builder); + // let circuit = ShaCircuitBuilder::keygen(builder); - let params = gen_srs(k as u32); - let pk = gen_pkey(|| "sha256_wide_chip", ¶ms, None, &circuit).unwrap(); - } + // let params = gen_srs(k as u32); + // let pk = gen_pkey(|| "sha256_wide_chip", ¶ms, None, &circuit).unwrap(); + // } } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/builder.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs similarity index 100% rename from lightclient-circuits/src/gadget/crypto/sha256_wide/builder.rs rename to lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs diff --git a/lightclient-circuits/src/gadget/crypto/util.rs b/lightclient-circuits/src/gadget/crypto/util.rs deleted file mode 100644 index cd233589..00000000 --- a/lightclient-circuits/src/gadget/crypto/util.rs +++ /dev/null @@ -1,110 +0,0 @@ -use super::{hash2curve::HashToCurveCache, Fp2Point, FpPoint}; -use eth_types::{AppCurveExt, Field, HashCurveExt}; -use halo2_base::{ - safe_types::{GateInstructions, RangeInstructions}, - utils::ScalarField, - AssignedValue, Context, QuantumCell, -}; -use halo2_ecc::{ - bigint::ProperCrtUint, - ecc::EcPoint, - fields::{fp::FpChip, vector::FieldVector, FieldChip, FieldExtConstructor, PrimeField}, -}; -use itertools::Itertools; -use num_bigint::BigUint; - -pub fn fp2_sgn0( - x: Fp2Point, - ctx: &mut Context, - fp_chip: &FpChip, -) -> AssignedValue { - let gate = fp_chip.gate(); - let c0 = x.0[0].clone(); - let c1 = x.0[1].clone(); - - let c0_zero = fp_chip.is_zero(ctx, &c0); - let c0_sgn = fp_sgn0::(c0, ctx, fp_chip); - let c1_sgn = fp_sgn0::(c1, ctx, fp_chip); - let sgn = gate.select(ctx, c1_sgn, c0_sgn, c0_zero); - gate.assert_bit(ctx, sgn); - sgn -} - -pub fn fp_sgn0( - x: FpPoint, - ctx: &mut Context, - fp_chip: &FpChip, -) -> AssignedValue { - let range = fp_chip.range(); - let gate = range.gate(); - - let msl = x.limbs()[0]; // most significant limb - - let lsb = range - .div_mod(ctx, msl, BigUint::from(256u64), C::LIMB_BITS) - .1; // get least significant *byte* - range.div_mod(ctx, lsb, BigUint::from(2u64), 8).1 // sgn0 = lsb % 2 -} - -/// Integer to Octet Stream (numberToBytesBE) -pub fn i2osp( - mut value: u128, - length: usize, - mut f: impl FnMut(F) -> AssignedValue, -) -> Vec> { - let mut octet_string = vec![0; length]; - for i in (0..length).rev() { - octet_string[i] = value & 0xff; - value >>= 8; - } - octet_string - .into_iter() - .map(|b| f(F::from(b as u64))) - .collect() -} - -pub fn strxor( - a: impl IntoIterator>, - b: impl IntoIterator>, - gate: &impl GateInstructions, - ctx: &mut Context, -) -> Vec> { - a.into_iter() - .zip(b.into_iter()) - .map(|(a, b)| bitwise_xor::<_, 8>(a, b, gate, ctx)) - .collect() -} - -pub fn bitwise_xor( - a: AssignedValue, - b: AssignedValue, - gate: &impl GateInstructions, - ctx: &mut Context, -) -> AssignedValue { - let one = ctx.load_constant(F::one()); - let mut a_bits = gate.num_to_bits(ctx, a, BITS); - let mut b_bits = gate.num_to_bits(ctx, b, BITS); - - let xor_bits = a_bits - .into_iter() - .zip(b_bits.into_iter()) - .map(|(a, b)| gate.xor(ctx, a, b)) - .collect_vec(); - - bits_to_num(gate, ctx, xor_bits) -} - -pub fn bits_to_num>>( - gate: &impl GateInstructions, - ctx: &mut Context, - bits: I, -) -> AssignedValue -where - I::IntoIter: DoubleEndedIterator + ExactSizeIterator, -{ - let bits_iter = bits.into_iter(); - assert!(bits_iter.len() <= F::NUM_BITS as usize); - bits_iter.rev().fold(ctx.load_zero(), |acc, bit| { - gate.mul_add(ctx, acc, QuantumCell::Constant(F::from(2u64)), bit) - }) -} diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index e5c22d70..eb505fbb 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -2,8 +2,6 @@ #![feature(int_roundings)] #![feature(associated_type_bounds)] #![feature(generic_const_exprs)] -#![feature(const_cmp)] -#![feature(array_zip)] #![feature(stmt_expr_attributes)] #![feature(trait_alias)] #![feature(generic_arg_infer)] @@ -13,12 +11,12 @@ pub mod gadget; pub mod util; pub mod witness; -pub mod aggregation; -pub mod committee_update_circuit; +// pub mod aggregation; +// pub mod committee_update_circuit; pub mod sync_step_circuit; -pub mod builder; -pub mod poseidon; +// pub mod builder; +mod poseidon; mod ssz_merkle; -pub use halo2_base::gates::builder::FlexGateConfigParams; +pub use halo2_base::gates::flex_gate::FlexGateConfigParams; diff --git a/lightclient-circuits/src/poseidon.rs b/lightclient-circuits/src/poseidon.rs index c2f83e04..38cac8f3 100644 --- a/lightclient-circuits/src/poseidon.rs +++ b/lightclient-circuits/src/poseidon.rs @@ -1,13 +1,12 @@ use crate::gadget::crypto::G1Point; -use eth_types::{AppCurveExt, Field, Spec}; -use halo2_base::safe_types::ScalarField; -use halo2_base::{safe_types::GateInstructions, AssignedValue, Context}; +use eth_types::{Field, Spec}; +use halo2_base::{ + gates::GateInstructions, halo2_proofs::plonk::Error, poseidon::PoseidonChip, AssignedValue, + Context, +}; use halo2_ecc::bigint::{ProperCrtUint, ProperUint}; -use halo2_proofs::plonk::Error; -use halo2curves::bls12_381::G1; -use halo2curves::bls12_381::{self, G1Affine}; +use halo2curves::bls12_381::{Fq, G1Affine, G1}; use itertools::Itertools; -use poseidon::PoseidonChip; use poseidon_native::Poseidon as PoseidonNative; const POSEIDON_SIZE: usize = 16; @@ -43,13 +42,14 @@ pub fn fq_array_poseidon<'a, F: Field>( } pub fn fq_array_poseidon_native( - elems: impl Iterator, + elems: impl Iterator, + limb_bits: usize, ) -> Result { let limbs = elems // Converts Fq elements to Fr limbs. .flat_map(|x| { x.to_bytes_le() - .chunks(bls12_381::G1::LIMB_BITS / 8) + .chunks(limb_bits / 8) .map(F::from_bytes_le) .collect_vec() }) diff --git a/lightclient-circuits/src/ssz_merkle.rs b/lightclient-circuits/src/ssz_merkle.rs index a69b1dc8..419728d9 100644 --- a/lightclient-circuits/src/ssz_merkle.rs +++ b/lightclient-circuits/src/ssz_merkle.rs @@ -1,8 +1,10 @@ use std::os::unix::thread; use eth_types::Field; -use halo2_base::{AssignedValue, Context, QuantumCell}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_base::{ + halo2_proofs::{circuit::Region, plonk::Error}, + AssignedValue, Context, QuantumCell, +}; use itertools::Itertools; use crate::{ @@ -13,7 +15,7 @@ use crate::{ pub fn ssz_merkleize_chunks>( thread_pool: &mut ThreadBuilder, - hasher: &impl HashInstructions, + hasher: &impl HashInstructions, chunks: impl IntoIterator>>, ) -> Result>, Error> { let mut chunks = chunks.into_iter().collect_vec(); @@ -50,7 +52,7 @@ pub fn ssz_merkleize_chunks>( pub fn verify_merkle_proof>( thread_pool: &mut ThreadBuilder, - hasher: &impl HashInstructions, + hasher: &impl HashInstructions, proof: impl IntoIterator>>, leaf: HashInputChunk>, root: &[AssignedValue], diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index cacc6b2d..0647a03c 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -13,47 +13,39 @@ use std::{ }; use crate::{ - builder::Eth2CircuitBuilder, gadget::crypto::{ - calculate_ysquared, Fp2Point, FpPoint, G1Chip, G1Point, G2Chip, G2Point, HashInstructions, - HashToCurveCache, HashToCurveChip, Sha256Chip, ShaCircuitBuilder, ShaThreadBuilder, + calculate_ysquared, G1Chip, G1Point, G2Chip, G2Point, HashInstructions, Sha256Chip, + ShaCircuitBuilder, ShaThreadBuilder, }, poseidon::{fq_array_poseidon, fq_array_poseidon_native, poseidon_sponge}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, util::{ - decode_into_field, gen_pkey, AppCircuit, AssignedValueCell, Challenges, Eth2ConfigPinning, - IntoWitness, ThreadBuilderBase, + gen_pkey, AppCircuit, AssignedValueCell, Challenges, Eth2ConfigPinning, IntoWitness, + ThreadBuilderBase, }, witness::{self, HashInput, HashInputChunk, SyncStepArgs}, }; -use eth_types::{AppCurveExt, Field, Spec}; +use eth_types::{Field, Spec}; use ff::PrimeField; use group::UncompressedEncoding; use halo2_base::{ - gates::{ - builder::{ - CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, - MultiPhaseThreadBreakPoints, RangeCircuitBuilder, - }, - flex_gate::GateStrategy, - range::{RangeConfig, RangeStrategy}, + gates::{range::RangeConfig, RangeChip, RangeInstructions, GateInstructions, circuit::CircuitBuilderStage}, + halo2_proofs::{ + circuit::{Layouter, Region, SimpleFloorPlanner, Value}, + dev::MockProver, + plonk::{Circuit, Column, ConstraintSystem, Error, Instance, ProvingKey}, + poly::{commitment::Params, kzg::commitment::ParamsKZG}, }, - safe_types::{GateInstructions, RangeChip, RangeInstructions}, + poseidon::PoseidonChip, utils::{decompose, fe_to_bigint, fe_to_biguint, fs::gen_srs, CurveAffineExt, ScalarField}, AssignedValue, Context, QuantumCell::{self, Witness}, }; use halo2_ecc::{ bigint::ProperCrtUint, - bls12_381::{bls_signature, pairing::PairingChip, Fp12Chip, Fp2Chip, FpChip}, - ecc::{bls_signature::BlsSignatureChip, EcPoint, EccChip}, - fields::{fp12, vector::FieldVector, FieldChip, FieldExtConstructor}, -}; -use halo2_proofs::{ - circuit::{Layouter, Region, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, Column, ConstraintSystem, Error, Instance, ProvingKey}, - poly::{commitment::Params, kzg::commitment::ParamsKZG}, + bls12_381::{bls_signature::{self, BlsSignatureChip}, pairing::PairingChip, Fp12Chip, Fp2Chip, FpChip, Fp2Point}, + ecc::{hash_to_curve::HashToCurveChip, EcPoint, EccChip}, + fields::{fp12, fp2, vector::FieldVector, FieldChip, FieldExtConstructor}, }; use halo2curves::{ bls12_381::{Fq, Fq12, Fr, G1Affine, G2Affine, G2Prepared, G1, G2}, @@ -63,9 +55,7 @@ use itertools::Itertools; use lazy_static::__Deref; use num_bigint::BigUint; use pasta_curves::group::{ff, GroupEncoding}; -use poseidon::PoseidonChip; -use sha2::{Digest, Sha256}; -use snark_verifier_sdk::{evm::gen_evm_verifier_shplonk, CircuitExt}; +// use snark_verifier_sdk::{evm::gen_evm_verifier_shplonk, CircuitExt}; use ssz_rs::{Merkleized, Node}; #[allow(type_alias_bounds)] @@ -94,8 +84,8 @@ impl SyncStepCircuit { let g2_chip = EccChip::new(&fp2_chip); let fp12_chip = Fp12Chip::::new(fp2_chip.fp_chip()); let pairing_chip = PairingChip::new(&fp_chip); - let bls_chip = bls_signature::BlsSignatureChip::new(&fp_chip, pairing_chip); - let h2c_chip = HashToCurveChip::::new(&sha256_chip); + let bls_chip = BlsSignatureChip::new(&fp_chip, &pairing_chip); + let h2c_chip = HashToCurveChip::::new(&sha256_chip, &fp2_chip); let execution_payload_root: HashInputChunk> = args.execution_payload_root.clone().into_witness(); @@ -128,7 +118,6 @@ impl SyncStepCircuit { use ff::Field; fp12_chip.load_constant(thread_pool.main(), Fq12::one()) }; - let mut h2c_cache = HashToCurveCache::::default(); // Verify attestted header let attested_slot_bytes: HashInputChunk<_> = args.attested_header.slot.into_witness(); @@ -196,7 +185,6 @@ impl SyncStepCircuit { thread_pool, &fp_chip, signing_root.into(), - &mut h2c_cache, )?; let res = @@ -308,7 +296,7 @@ impl SyncStepCircuit { }) .collect_vec(); let poseidon_commitment = - fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x)).unwrap(); + fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x), todo!()).unwrap(); let poseidon_commitment_le = poseidon_commitment.to_bytes_le(); input[88..].copy_from_slice(&poseidon_commitment_le); @@ -463,15 +451,15 @@ impl AppCircuit for SyncStepCircuit { args: &Self::Witness, k: u32, ) -> Result, Error> { - let mut thread_pool = ShaThreadBuilder::from_stage(stage); - let range = RangeChip::::new(RangeStrategy::Vertical, 8); + let mut builder = ShaCircuitBuilder::::from_stage(stage); + let range = builder.range_chip(8); - let assigned_instances = Self::synthesize(&mut thread_pool, &range, args)?; + let assigned_instances = Self::synthesize(&mut builder, &range, args)?; match stage { CircuitBuilderStage::Prover => {} _ => { - thread_pool.config( + builder.config( k as usize, Some( var("MINIMUM_ROWS") @@ -483,156 +471,150 @@ impl AppCircuit for SyncStepCircuit { } } - Ok(Eth2CircuitBuilder::from_stage( - assigned_instances, - thread_pool, - pinning.map(|p| p.break_points), - stage, - )) + Ok(builder) } } -#[cfg(test)] -mod tests { - use std::{ - env::{set_var, var}, - fs, - os::unix::thread, - }; - - use crate::{ - builder::Eth2CircuitBuilder, - util::{full_prover, full_verifier, gen_pkey, Halo2ConfigPinning}, - witness::SyncStepArgs, - }; - - use super::*; - use ark_std::{end_timer, start_timer}; - use eth_types::Testnet; - use group::Group; - use halo2_base::{ - gates::{ - builder::{CircuitBuilderStage, FlexGateConfigParams}, - flex_gate::GateStrategy, - range::RangeStrategy, - }, - utils::{decompose, fs::gen_srs}, - }; - use halo2_proofs::{ - circuit::SimpleFloorPlanner, - dev::MockProver, - halo2curves::bn256::Fr, - plonk::{keygen_pk, keygen_vk, Circuit, FloorPlanner}, - poly::kzg::commitment::ParamsKZG, - }; - use halo2curves::{bls12_381::G1Affine, bn256::Bn256}; - use pasta_curves::group::UncompressedEncoding; - use rand::{rngs::OsRng, thread_rng}; - use rayon::iter::ParallelIterator; - use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; - use snark_verifier_sdk::{ - evm::{encode_calldata, evm_verify, gen_evm_proof_shplonk}, - halo2::{aggregation::AggregationCircuit, gen_proof_shplonk, gen_snark_shplonk}, - CircuitExt, SHPLONK, - }; - - fn load_circuit_args() -> SyncStepArgs { - serde_json::from_slice(&fs::read("../test_data/sync_step_512.json").unwrap()).unwrap() - } - - #[test] - fn test_sync_circuit() { - const K: u32 = 21; - let params = gen_srs(K); - - let witness = load_circuit_args(); - - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - - let circuit = SyncStepCircuit::::create_circuit( - CircuitBuilderStage::Mock, - Some(pinning), - &witness, - K, - ) - .unwrap(); - - let sync_pi_commit = SyncStepCircuit::::instance_commitment(&witness); - - let timer = start_timer!(|| "sync_step mock prover"); - let prover = MockProver::::run(K, &circuit, vec![vec![sync_pi_commit]]).unwrap(); - prover.assert_satisfied_par(); - end_timer!(timer); - } - - #[test] - fn test_sync_proofgen() { - const K: u32 = 22; - let params = gen_srs(K); - - let pk = SyncStepCircuit::::read_or_create_pk( - ¶ms, - "../build/sync_step.pkey", - "./config/sync_step.json", - false, - &SyncStepArgs::::default(), - ); - - let witness = load_circuit_args(); - - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - - let circuit = SyncStepCircuit::::create_circuit( - CircuitBuilderStage::Prover, - Some(pinning), - &witness, - K, - ) - .unwrap(); - - let instances = circuit.instances(); - let proof = full_prover(¶ms, &pk, circuit, instances.clone()); - - assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) - } - - #[test] - fn test_sync_evm_verify() { - const K: u32 = 22; - let params = gen_srs(K); - - let pk = SyncStepCircuit::::read_or_create_pk( - ¶ms, - "../build/sync_step.pkey", - "./config/sync_step.json", - false, - &SyncStepArgs::::default(), - ); - - let witness = load_circuit_args(); - - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - - let circuit = SyncStepCircuit::::create_circuit( - CircuitBuilderStage::Prover, - Some(pinning), - &witness, - K, - ) - .unwrap(); - - let num_instances = circuit.num_instance(); - let instances = circuit.instances(); - let proof = gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); - println!("proof size: {}", proof.len()); - let deployment_code = SyncStepCircuit::::gen_evm_verifier_shplonk( - ¶ms, - &pk, - None::, - &witness, - ) - .unwrap(); - println!("deployment_code size: {}", deployment_code.len()); - evm_verify(deployment_code, instances, proof); - } -} +// #[cfg(test)] +// mod tests { +// use std::{ +// env::{set_var, var}, +// fs, +// os::unix::thread, +// }; + +// use crate::{ +// util::{full_prover, full_verifier, gen_pkey, Halo2ConfigPinning}, +// witness::SyncStepArgs, +// }; + +// use super::*; +// use ark_std::{end_timer, start_timer}; +// use eth_types::Testnet; +// use group::Group; +// use halo2_base::{ +// gates::{ +// builder::{CircuitBuilderStage, FlexGateConfigParams}, +// flex_gate::GateStrategy, +// range::RangeStrategy, +// }, +// utils::{decompose, fs::gen_srs}, +// }; +// use halo2_proofs::{ +// circuit::SimpleFloorPlanner, +// dev::MockProver, +// halo2curves::bn256::Fr, +// plonk::{keygen_pk, keygen_vk, Circuit, FloorPlanner}, +// poly::kzg::commitment::ParamsKZG, +// }; +// use halo2curves::{bls12_381::G1Affine, bn256::Bn256}; +// use pasta_curves::group::UncompressedEncoding; +// use rand::{rngs::OsRng, thread_rng}; +// use rayon::iter::ParallelIterator; +// use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; +// use snark_verifier_sdk::{ +// evm::{encode_calldata, evm_verify, gen_evm_proof_shplonk}, +// halo2::{aggregation::AggregationCircuit, gen_proof_shplonk, gen_snark_shplonk}, +// CircuitExt, SHPLONK, +// }; + +// fn load_circuit_args() -> SyncStepArgs { +// serde_json::from_slice(&fs::read("../test_data/sync_step_512.json").unwrap()).unwrap() +// } + +// #[test] +// fn test_sync_circuit() { +// const K: u32 = 21; +// let params = gen_srs(K); + +// let witness = load_circuit_args(); + +// let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + +// let circuit = SyncStepCircuit::::create_circuit( +// CircuitBuilderStage::Mock, +// Some(pinning), +// &witness, +// K, +// ) +// .unwrap(); + +// let sync_pi_commit = SyncStepCircuit::::instance_commitment(&witness); + +// let timer = start_timer!(|| "sync_step mock prover"); +// let prover = MockProver::::run(K, &circuit, vec![vec![sync_pi_commit]]).unwrap(); +// prover.assert_satisfied_par(); +// end_timer!(timer); +// } + +// #[test] +// fn test_sync_proofgen() { +// const K: u32 = 22; +// let params = gen_srs(K); + +// let pk = SyncStepCircuit::::read_or_create_pk( +// ¶ms, +// "../build/sync_step.pkey", +// "./config/sync_step.json", +// false, +// &SyncStepArgs::::default(), +// ); + +// let witness = load_circuit_args(); + +// let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + +// let circuit = SyncStepCircuit::::create_circuit( +// CircuitBuilderStage::Prover, +// Some(pinning), +// &witness, +// K, +// ) +// .unwrap(); + +// let instances = circuit.instances(); +// let proof = full_prover(¶ms, &pk, circuit, instances.clone()); + +// assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) +// } + +// #[test] +// fn test_sync_evm_verify() { +// const K: u32 = 22; +// let params = gen_srs(K); + +// let pk = SyncStepCircuit::::read_or_create_pk( +// ¶ms, +// "../build/sync_step.pkey", +// "./config/sync_step.json", +// false, +// &SyncStepArgs::::default(), +// ); + +// let witness = load_circuit_args(); + +// let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + +// let circuit = SyncStepCircuit::::create_circuit( +// CircuitBuilderStage::Prover, +// Some(pinning), +// &witness, +// K, +// ) +// .unwrap(); + +// let num_instances = circuit.num_instance(); +// let instances = circuit.instances(); +// let proof = gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); +// println!("proof size: {}", proof.len()); +// let deployment_code = SyncStepCircuit::::gen_evm_verifier_shplonk( +// ¶ms, +// &pk, +// None::, +// &witness, +// ) +// .unwrap(); +// println!("deployment_code size: {}", deployment_code.len()); +// evm_verify(deployment_code, instances, proof); +// } +// } diff --git a/lightclient-circuits/src/util.rs b/lightclient-circuits/src/util.rs index 8aad7296..bc23397f 100644 --- a/lightclient-circuits/src/util.rs +++ b/lightclient-circuits/src/util.rs @@ -19,8 +19,14 @@ mod circuit; pub use circuit::*; use halo2_base::{ - gates::builder::{FlexGateConfigParams, GateThreadBuilder, MultiPhaseThreadBreakPoints}, - safe_types::{GateInstructions, RangeChip, RangeInstructions}, + halo2_proofs::{ + circuit::{Layouter, Region, Value}, + plonk::{ + Challenge, ConstraintSystem, Error, Expression, FirstPhase, ProvingKey, SecondPhase, + VirtualCells, + }, + poly::kzg::commitment::ParamsKZG, + }, utils::ScalarField, AssignedValue, Context, QuantumCell, }; @@ -31,24 +37,9 @@ use halo2_ecc::{ use itertools::Itertools; use num_bigint::BigUint; -use snark_verifier_sdk::CircuitExt; -use crate::{ - gadget::{ - crypto::{Fp2Point, FpPoint}, - Expr, - }, - witness, -}; +use crate::{gadget::Expr, witness}; use eth_types::*; -use halo2_proofs::{ - circuit::{Layouter, Region, Value}, - plonk::{ - Challenge, ConstraintSystem, Error, Expression, FirstPhase, ProvingKey, SecondPhase, - VirtualCells, - }, - poly::kzg::commitment::ParamsKZG, -}; /// Helper trait that implements functionality to represent a generic type as /// array of N-bits. @@ -113,7 +104,7 @@ impl Challenges { pub mod to_bytes { use crate::gadget::Expr; use eth_types::Field; - use halo2_proofs::plonk::Expression; + use halo2_base::halo2_proofs::plonk::Expression; pub(crate) fn expr(bits: &[Expression]) -> Vec> { debug_assert!(bits.len() % 8 == 0, "bits not a multiple of 8"); @@ -144,55 +135,6 @@ pub mod to_bytes { } } -/// Converts assigned bytes into biginterger -/// Warning: method does not perform any checks on input `bytes`. -pub fn decode_into_field( - bytes: impl IntoIterator>, - limb_bases: &[F], - gate: &impl GateInstructions, - ctx: &mut Context, -) -> ProperCrtUint { - let bytes = bytes.into_iter().collect_vec(); - let limb_bytes = C::LIMB_BITS / 8; - let bits = C::NUM_LIMBS * C::LIMB_BITS; - - let value = BigUint::from_bytes_le( - &bytes - .iter() - .map(|v| v.value().get_lower_32() as u8) - .collect_vec(), - ); - - // inputs is a bool or uint8. - let assigned_uint = if bits == 1 || limb_bytes == 8 { - ProperUint::new(bytes) - } else { - let byte_base = (0..limb_bytes) - .map(|i| QuantumCell::Constant(gate.pow_of_two()[i * 8])) - .collect_vec(); - let limbs = bytes - .chunks(limb_bytes) - .map(|chunk| gate.inner_product(ctx, chunk.to_vec(), byte_base[..chunk.len()].to_vec())) - .collect::>(); - ProperUint::new(limbs) - }; - - assigned_uint.into_crt(ctx, gate, value, limb_bases, C::LIMB_BITS) -} - -pub fn decode_into_field_be>>( - bytes: I, - limb_bases: &[F], - gate: &impl GateInstructions, - ctx: &mut Context, -) -> ProperCrtUint -where - I::IntoIter: DoubleEndedIterator, -{ - let bytes = bytes.into_iter().rev().collect_vec(); - decode_into_field::(bytes, limb_bases, gate, ctx) -} - pub fn bigint_to_le_bytes( limbs: impl IntoIterator, limb_bits: usize, @@ -206,32 +148,6 @@ pub fn bigint_to_le_bytes( .collect() } -pub fn print_fq_dev(x: &FpPoint, label: &str) { - let bytes = bigint_to_le_bytes( - x.limbs().iter().map(|e| *e.value()), - C::LIMB_BITS, - C::BYTES_COMPRESSED, - ); - let bn = BigUint::from_bytes_le(&bytes); - println!("{label}: {}", bn); -} - -pub fn print_fq2_dev(u: &Fp2Point, label: &str) { - let c0_bytes = bigint_to_le_bytes( - u.0[0].limbs().iter().map(|e| *e.value()), - C::LIMB_BITS, - C::BYTES_COMPRESSED / 2, - ); - let c1_bytes = bigint_to_le_bytes( - u.0[1].limbs().iter().map(|e| *e.value()), - C::LIMB_BITS, - C::BYTES_COMPRESSED / 2, - ); - let c0 = BigUint::from_bytes_le(&c0_bytes); - let c1 = BigUint::from_bytes_le(&c1_bytes); - println!("{label}: ({}, {})", c0, c1); -} - pub fn pad_to_ssz_chunk(le_bytes: &[u8]) -> Vec { assert!(le_bytes.len() <= 32); let mut chunk = le_bytes.to_vec(); diff --git a/lightclient-circuits/src/util/circuit.rs b/lightclient-circuits/src/util/circuit.rs index fdb9262e..1ac53371 100644 --- a/lightclient-circuits/src/util/circuit.rs +++ b/lightclient-circuits/src/util/circuit.rs @@ -2,13 +2,15 @@ use std::env::{args, set_var, var}; use std::fs; use std::{fs::File, path::Path}; -use halo2_base::gates::builder::{ - CircuitBuilderStage, FlexGateConfigParams, MultiPhaseThreadBreakPoints, +use halo2_base::gates::circuit::CircuitBuilderStage; +use halo2_base::gates::flex_gate::{MultiPhaseThreadBreakPoints, FlexGateConfigParams}; +use halo2_base::halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr, G1Affine}, + plonk::ProvingKey, + plonk::{Circuit, Error, VerifyingKey}, + poly::commitment::Params, + poly::kzg::commitment::ParamsKZG, }; -use halo2_proofs::plonk::{Circuit, Error, VerifyingKey}; -use halo2_proofs::poly::commitment::Params; -use halo2_proofs::{plonk::ProvingKey, poly::kzg::commitment::ParamsKZG}; -use halo2curves::bn256::{Bn256, Fr, G1Affine}; use serde::{Deserialize, Serialize}; use snark_verifier_sdk::evm::{ encode_calldata, evm_verify, gen_evm_proof, gen_evm_proof_shplonk, gen_evm_verifier_shplonk, diff --git a/lightclient-circuits/src/util/common.rs b/lightclient-circuits/src/util/common.rs index 5829961b..2e0ed16f 100644 --- a/lightclient-circuits/src/util/common.rs +++ b/lightclient-circuits/src/util/common.rs @@ -2,21 +2,19 @@ use crate::gadget::Expr; use eth_types::*; use halo2_base::{ gates::{ - builder::{ - CircuitBuilderStage, FlexGateConfigParams, KeygenAssignments, - MultiPhaseThreadBreakPoints, + circuit::CircuitBuilderStage, + flex_gate::{FlexGateConfig, MultiPhaseThreadBreakPoints}, + }, + halo2_proofs::{ + circuit::{AssignedCell, Cell as Halo2Cell, Layouter, Region, Value}, + plonk::{ + Advice, Assigned, Column, ConstraintSystem, Error, Expression, Selector, VirtualCells, }, - flex_gate::FlexGateConfig, + poly::Rotation, }, + virtual_region::manager::VirtualRegionManager, Context, }; -use halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region, Value}, - plonk::{ - Advice, Assigned, Column, ConstraintSystem, Error, Expression, Selector, VirtualCells, - }, - poly::Rotation, -}; use std::hash::Hash; @@ -121,12 +119,12 @@ impl CellType { #[derive(Clone, Debug)] pub struct AssignedValueCell { - pub cell: halo2_proofs::circuit::Cell, + pub cell: Halo2Cell, pub value: F, } impl AssignedValueCell { - pub fn cell(&self) -> halo2_proofs::circuit::Cell { + pub fn cell(&self) -> Halo2Cell { self.cell } @@ -136,70 +134,52 @@ impl AssignedValueCell { } pub trait ThreadBuilderConfigBase: Clone + Sized { - fn configure(meta: &mut ConstraintSystem, params: FlexGateConfigParams) -> Self; + fn configure(meta: &mut ConstraintSystem) -> Self; fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error>; fn annotate_columns_in_region(&self, region: &mut Region); } -pub trait ThreadBuilderBase: Clone + Sized { - type Config: ThreadBuilderConfigBase; +pub trait ThreadBuilderBase: VirtualRegionManager + Clone { + type CustomContext; - fn new(witness_gen_only: bool) -> Self; + fn custom_context(&mut self) -> &mut Self::CustomContext; +} - fn from_stage(stage: CircuitBuilderStage) -> Self; +// pub trait ThreadBuilderBase: VirtualRegionManager + Clone + Sized { +// type Config: ThreadBuilderConfigBase; - fn mock() -> Self { - Self::new(false) - } +// fn new(witness_gen_only: bool) -> Self; - fn keygen() -> Self { - Self::new(false).unknown(true) - } +// fn from_stage(stage: CircuitBuilderStage) -> Self; - fn prover() -> Self { - Self::new(true) - } +// fn mock() -> Self { +// Self::new(false) +// } - fn unknown(self, use_unknown: bool) -> Self; - - fn config(&self, k: usize, minimum_rows: Option) -> FlexGateConfigParams; - - /// Returns a mutable reference to the [Context] of a gate thread. Spawns a new thread for the given phase, if none exists. - /// * `phase`: The challenge phase (as an index) of the gate thread. - fn main(&mut self) -> &mut Context; - - fn witness_gen_only(&self) -> bool; - - /// Returns the `use_unknown` flag. - fn use_unknown(&self) -> bool; - - /// Returns the current number of threads in the [GateThreadBuilder]. - fn thread_count(&self) -> usize; - - /// Creates a new thread id by incrementing the `thread count` - fn get_new_thread_id(&mut self) -> usize; - - /// Assigns all advice and fixed cells, turns on selectors, imposes equality constraints. - /// This should only be called during keygen. - fn assign_all( - &mut self, - gate: &FlexGateConfig, - lookup_advice: &[Vec>], - q_lookup: &[Option], - config: &Self::Config, - region: &mut Region, - assignments: KeygenAssignments, - ) -> Result, Error>; - - /// Assigns witnesses. This should only be called during proof generation. - fn assign_witnesses( - &mut self, - gate: &FlexGateConfig, - lookup_advice: &[Vec>], - config: &Self::Config, - region: &mut Region, - break_points: &mut MultiPhaseThreadBreakPoints, - ) -> Result<(), Error>; -} +// fn keygen() -> Self { +// Self::new(false).unknown(true) +// } + +// fn prover() -> Self { +// Self::new(true) +// } + +// fn unknown(self, use_unknown: bool) -> Self; + +// /// Returns a mutable reference to the [Context] of a gate thread. Spawns a new thread for the given phase, if none exists. +// /// * `phase`: The challenge phase (as an index) of the gate thread. +// fn main(&mut self) -> &mut Context; + +// fn witness_gen_only(&self) -> bool; + +// /// Returns the `use_unknown` flag. +// fn use_unknown(&self) -> bool; + +// /// Returns the current number of threads in the [GateThreadBuilder]. +// fn thread_count(&self) -> usize; + +// /// Creates a new thread id by incrementing the `thread count` +// fn get_new_thread_id(&mut self) -> usize; +// } diff --git a/lightclient-circuits/src/util/constraint_builder.rs b/lightclient-circuits/src/util/constraint_builder.rs index 9738dccb..de93d226 100644 --- a/lightclient-circuits/src/util/constraint_builder.rs +++ b/lightclient-circuits/src/util/constraint_builder.rs @@ -1,6 +1,6 @@ use crate::gadget::Expr; use eth_types::Field; -use halo2_proofs::plonk::Expression; +use halo2_base::halo2_proofs::plonk::Expression; use super::{Cell, CellType}; diff --git a/lightclient-circuits/src/util/proof.rs b/lightclient-circuits/src/util/proof.rs index 3cbb5eab..1d4b55da 100644 --- a/lightclient-circuits/src/util/proof.rs +++ b/lightclient-circuits/src/util/proof.rs @@ -2,9 +2,8 @@ use std::fs; use std::{fs::File, path::Path}; use ark_std::{end_timer, start_timer}; -use halo2_proofs::halo2curves::bn256::{Bn256, Fr, G1Affine}; -use halo2_proofs::poly::VerificationStrategy; -use halo2_proofs::{ +use halo2_base::halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, ProvingKey, VerifyingKey}, poly::{ commitment::{Params, ParamsProver}, @@ -17,6 +16,7 @@ use halo2_proofs::{ transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, + SerdeFormat::RawBytesUnchecked, }; use rand::rngs::OsRng; use snark_verifier_sdk::CircuitExt; @@ -34,11 +34,8 @@ pub fn read_vkey>(path: &Path) -> Result, let mut file = File::open(path).map_err(|_| "failed to read file")?; - let vk = VerifyingKey::::read::<_, C>( - &mut file, - halo2_proofs::SerdeFormat::RawBytesUnchecked, - ) - .map_err(|_| "failed to decode vkey"); + let vk = VerifyingKey::::read::<_, C>(&mut file, RawBytesUnchecked) + .map_err(|_| "failed to decode vkey"); end_timer!(timer); @@ -66,17 +63,14 @@ pub fn gen_pkey>( match File::open(&vkey_path) { Ok(mut file) => ( start_timer!(|| "Loading vkey"), - VerifyingKey::::read::<_, C>( - &mut file, - halo2_proofs::SerdeFormat::RawBytesUnchecked, - ) - .expect("failed to read vkey"), + VerifyingKey::::read::<_, C>(&mut file, RawBytesUnchecked) + .expect("failed to read vkey"), ), Err(_) => { let timer = start_timer!(|| "Creating and writting vkey"); let vk = keygen_vk(params, circuit).expect("vk generation should not fail"); let mut file = File::create(vkey_path).expect("couldn't create vkey file"); - vk.write(&mut file, halo2_proofs::SerdeFormat::RawBytesUnchecked) + vk.write(&mut file, RawBytesUnchecked) .expect("Failed to write vkey"); (timer, vk) } diff --git a/lightclient-circuits/src/witness/rotation.rs b/lightclient-circuits/src/witness/rotation.rs index 2cb65422..d67330d0 100644 --- a/lightclient-circuits/src/witness/rotation.rs +++ b/lightclient-circuits/src/witness/rotation.rs @@ -4,7 +4,6 @@ use std::marker::PhantomData; use crate::gadget::crypto::constant_randomness; use super::HashInput; -use eth_types::AppCurveExt; use eth_types::{Field, Spec}; use sync_committee_primitives::consensus_types::{BeaconBlockHeader, BeaconState}; diff --git a/preprocessor/Cargo.toml b/preprocessor/Cargo.toml index a2be115e..fc545e42 100644 --- a/preprocessor/Cargo.toml +++ b/preprocessor/Cargo.toml @@ -32,14 +32,14 @@ halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.gi "dev-graph", ] } halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false, features = [ - "halo2-pse", + "halo2-axiom", "display", ] } snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "community-edition", default-features = false, features = [ "display", "loader_halo2", "loader_evm", - "halo2-pse", + "halo2-axiom", ] } ark-std = { version = "0.4.0", features = ["print-trace"] } # sync-committee-verifier = { git = "https://github.com/polytope-labs/sync-committee-rs", version = "0.1.0", features=["testnet"] } diff --git a/prover/Cargo.toml b/prover/Cargo.toml index 75adec6d..9f5ddd76 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -21,12 +21,12 @@ http = "0.2" halo2curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.1" } # verifier SDK -snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.1", default-features = false, features = [ +snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.1-ce", default-features = false, features = [ "display", "loader_halo2", "loader_evm", ] } -snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.1", default-features = false, features = [ +snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.1-ce", default-features = false, features = [ "display", "loader_halo2", "loader_evm", diff --git a/rust-toolchain b/rust-toolchain index 0675d073..6f6d7b39 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2023-04-18 +nightly-2023-08-12 From ee19af05185c89cc707ce4e7b2c3430725b058e3 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Tue, 31 Oct 2023 12:02:41 +0100 Subject: [PATCH 02/23] update version in circuits crate --- Cargo.toml | 18 +- eth-types/Cargo.toml | 4 +- eth-types/src/lib.rs | 5 +- lightclient-circuits/Cargo.toml | 22 +- lightclient-circuits/src/aggregation.rs | 78 +- .../src/committee_update_circuit.rs | 882 +++++++++--------- lightclient-circuits/src/gadget/common.rs | 18 +- .../src/gadget/crypto/builder.rs | 103 +- .../src/gadget/crypto/hash2curve.rs | 700 -------------- lightclient-circuits/src/gadget/crypto/mod.rs | 15 +- .../src/gadget/crypto/sha256_flex.rs | 67 +- .../gadget/crypto/sha256_flex/compression.rs | 54 +- .../src/gadget/crypto/sha256_flex/gate.rs | 100 +- .../src/gadget/crypto/sha256_flex/spread.rs | 24 +- .../src/gadget/crypto/sha256_flex/util.rs | 2 +- .../src/gadget/crypto/sha256_wide.rs | 234 ++--- .../src/gadget/crypto/sha256_wide/config.rs | 46 +- .../src/gadget/crypto/sha256_wide/gate.rs | 192 ++-- .../src/gadget/crypto/sha256_wide/util.rs | 14 +- .../src/gadget/crypto/sha256_wide/witness.rs | 38 +- lightclient-circuits/src/lib.rs | 7 +- lightclient-circuits/src/poseidon.rs | 21 +- lightclient-circuits/src/ssz_merkle.rs | 26 +- lightclient-circuits/src/sync_step_circuit.rs | 427 ++++----- lightclient-circuits/src/util.rs | 2 +- lightclient-circuits/src/util/circuit.rs | 7 +- lightclient-circuits/src/util/common.rs | 84 +- lightclient-circuits/src/util/proof.rs | 6 +- lightclient-circuits/src/witness/hashing.rs | 10 + lightclient-circuits/tests/step.rs | 222 ++--- preprocessor/Cargo.toml | 11 +- preprocessor/src/lib.rs | 6 +- preprocessor/src/rotation.rs | 7 +- preprocessor/src/sync.rs | 7 +- 34 files changed, 1391 insertions(+), 2068 deletions(-) delete mode 100644 lightclient-circuits/src/gadget/crypto/hash2curve.rs diff --git a/Cargo.toml b/Cargo.toml index 305e2c3e..b89ef8c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,8 @@ [workspace] members = ["lightclient-circuits", "preprocessor", "eth-types"] +resolver = "2" + # Definition of benchmarks profile to use. [profile.bench] opt-level = 3 @@ -22,8 +24,8 @@ lto = "thin" incremental = true [patch."https://github.com/axiom-crypto/halo2curves"] -halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "bls12-381/hash_to_curve" } -# halo2curves = { path = "../halo2curves" +# halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "bls12-381/hash_to_curve" } +halo2curves = { path = "../halo2curves" } [patch."https://github.com/axiom-crypto/halo2-lib"] # halo2-base = { git = "https://github.com/timoftime/halo2-lib", rev = "765f52c", default-features = false, features = [ @@ -36,19 +38,19 @@ halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "bls1 halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ - "halo2-axiom", + "halo2-pse", "display", ] } halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false, features = [ - "halo2-axiom", + "halo2-pse", ] } # poseidon = { path = "../halo2-lib/hashes/poseidon", default-features = false } [patch."https://github.com/axiom-crypto/snark-verifier.git"] # snark-verifier = { git = "https://github.com/timoftime/snark-verifier", branch = "timoftime/bump-revm", default-features = false } # snark-verifier-sdk = { git = "https://github.com/timoftime/snark-verifier", branch = "timoftime/bump-revm", default-features = false } -# snark-verifier = { path = "../snark-verifier/snark-verifier", default-features = false } -# snark-verifier-sdk = { path = "../snark-verifier/snark-verifier-sdk", default-features = false } +snark-verifier = { path = "../snark-verifier/snark-verifier" } +snark-verifier-sdk = { path = "../snark-verifier/snark-verifier-sdk" } [patch."https://github.com/ralexstokes/ssz-rs"] ssz-rs = { git = "https://github.com/polytope-labs/ssz-rs", branch = "main", default-features = false } @@ -60,3 +62,7 @@ sync-committee-prover = { git = "https://github.com/timoftime/sync-committee-rs" sync-committee-primitives = { git = "https://github.com/timoftime/sync-committee-rs", branch = "dev/accept-ssz", features = [ "testnet", ] } + +[patch."https://github.com/privacy-scaling-explorations/halo2curves"] +# # halo2curves = { git = "https://github.com/sygma-protocol/halo2curves", branch = "bls12-381/hash_to_curve" } +# halo2curves = { path = "../halo2curves-pse" } diff --git a/eth-types/Cargo.toml b/eth-types/Cargo.toml index 243cf95c..bdf524e6 100644 --- a/eth-types/Cargo.toml +++ b/eth-types/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" hex = "0.4" lazy_static = "1.4" halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false, features = [ - "halo2-axiom", + "halo2-pse", ] } # halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } halo2curves = { git = "https://github.com/axiom-crypto/halo2curves" } @@ -24,4 +24,4 @@ num = "0.4" num-bigint = { version = "0.4" } strum_macros = "0.24" strum = "0.24" -pasta_curves = "0.4.1" +# pasta_curves = "0.5" diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index 3a62d97f..bbc4a9d9 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -5,6 +5,7 @@ #![feature(trait_alias)] mod spec; use halo2_base::utils::BigPrimeField; +// use halo2curves::FieldExt; pub use spec::{Mainnet, Minimal, Spec, Testnet}; // mod curve; @@ -28,7 +29,7 @@ pub trait Field = BigPrimeField; // { // fn pow_const(&self, mut exp: usize) -> Self { // if exp == 0 { -// return Self::one(); +// return Self::ONE; // } // let mut base = *self; @@ -53,7 +54,7 @@ pub trait Field = BigPrimeField; // /// WARNING: CAN OVERFLOW. // fn from_bytes_le_unsecure<'a, I: IntoIterator>(bytes: I) -> Self { // let two = Self::from(2); -// let mut value = Self::zero(); +// let mut value = Self::ZERO; // for (i, byte) in bytes.into_iter().enumerate() { // value += Self::from(*byte as u64) * two.pow_const(8 * i); // } diff --git a/lightclient-circuits/Cargo.toml b/lightclient-circuits/Cargo.toml index 45eaa105..a82ff091 100644 --- a/lightclient-circuits/Cargo.toml +++ b/lightclient-circuits/Cargo.toml @@ -10,32 +10,32 @@ license = "MIT OR Apache-2.0" # halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02", features = [ # "dev-graph", # ] } -halo2curves = { git = "https://github.com/axiom-crypto/halo2curves" } +halo2curves = { git = "https://github.com/axiom-crypto/halo2curves", version = "0.4.0" } halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false, features = [ - "halo2-axiom", + "halo2-pse", "display", ] } halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } # poseidon = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } # verifier SDK -snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "develop", default-features = false, features = [ +snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "community-edition", default-features = false, features = [ "display", "loader_halo2", "loader_evm", - "halo2-axiom" + "halo2-pse", ] } -snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "develop", default-features = false, features = [ +snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "community-edition", default-features = false, features = [ "display", "loader_halo2", "loader_evm", - "halo2-axiom" + "halo2-pse", ] } # crypto num-bigint = { version = "0.4", features = ["rand"] } -pasta_curves = "0.4.1" -ff = "0.12" -group = "0.12" +# pasta_curves = "0.4.1" +# ff = "0.13" +# group = "0.13" sha2 = { version = "0.10.6", features = ["compress"] } # ethereum @@ -58,9 +58,9 @@ log = "0.4" hex = "0.4" rayon = "1.7.0" ark-std = { version = "0.4.0", features = ["print-trace"] } -getset="0.1.2" +getset = "0.1.2" +pse-poseidon = { git = "https://github.com/axiom-crypto/pse-poseidon.git" } -poseidon_native = { git = "https://github.com/axiom-crypto/halo2.git", branch = "axiom/dev", package = "poseidon" } [dev-dependencies] rstest = "0.18.2" test-utils = { git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "27e8a01" } diff --git a/lightclient-circuits/src/aggregation.rs b/lightclient-circuits/src/aggregation.rs index 19ad6638..b259b760 100644 --- a/lightclient-circuits/src/aggregation.rs +++ b/lightclient-circuits/src/aggregation.rs @@ -1,24 +1,68 @@ use std::{ env::{set_var, var}, - iter, + iter, path::Path, fs::File, }; use eth_types::Testnet; use halo2_base::{ - gates::builder::{CircuitBuilderStage, MultiPhaseThreadBreakPoints}, + gates::{circuit::CircuitBuilderStage, flex_gate::MultiPhaseThreadBreakPoints}, + halo2_proofs::{ + halo2curves::bn256::Fr, + plonk::Error, + poly::{commitment::Params, kzg::commitment::ParamsKZG}, + }, utils::fs::gen_srs, }; -use halo2_proofs::poly::{commitment::Params, kzg::commitment::ParamsKZG}; -use halo2curves::bn256::Fr; use serde::{Deserialize, Serialize}; -use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, Snark, SHPLONK}; +use snark_verifier_sdk::{halo2::aggregation::{AggregationCircuit, AggregationConfigParams}, Snark, SHPLONK}; -use crate::{ - committee_update_circuit::CommitteeUpdateCircuit, - util::{AppCircuit, Eth2ConfigPinning, PinnableCircuit}, -}; +use crate::util::{AppCircuit, Eth2ConfigPinning, PinnableCircuit, Halo2ConfigPinning}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AggregationConfigPinning { + pub params: AggregationConfigParams, + pub break_points: MultiPhaseThreadBreakPoints, +} + + +impl Halo2ConfigPinning for AggregationConfigPinning { + type BreakPoints = MultiPhaseThreadBreakPoints; -pub type AggregationConfigPinning = Eth2ConfigPinning; + fn from_path>(path: P) -> Self { + let pinning: Self = serde_json::from_reader( + File::open(&path) + .unwrap_or_else(|e| panic!("{:?} does not exist: {e:?}", path.as_ref())), + ) + .unwrap(); + pinning.set_var(); + pinning + } + + fn set_var(&self) { + set_var( + "FLEX_GATE_CONFIG_PARAMS", + serde_json::to_string(&self.params).unwrap(), + ); + set_var("LOOKUP_BITS", (self.params.degree - 1).to_string()); + } + + fn break_points(self) -> MultiPhaseThreadBreakPoints { + self.break_points + } + + fn from_var(break_points: MultiPhaseThreadBreakPoints) -> Self { + let params: AggregationConfigParams = + serde_json::from_str(&var("AGGR_CONFIG_PARAMS").unwrap()).unwrap(); + Self { + params, + break_points, + } + } + + fn degree(&self) -> u32 { + self.params.degree + } +} impl PinnableCircuit for AggregationCircuit { type Pinning = AggregationConfigPinning; @@ -38,16 +82,20 @@ impl AppCircuit for AggregationCircuit { pinning: Option, snark: &Self::Witness, k: u32, - ) -> Result, halo2_proofs::plonk::Error> { + ) -> Result, Error> { let lookup_bits = k as usize - 1; let params = gen_srs(k); + let circuit_params = pinning.map_or(AggregationConfigParams{ + degree: k, + ..Default::default() + }, |p| p.params); let mut circuit = AggregationCircuit::new::( stage, - pinning.map(|p| p.break_points), - lookup_bits, + circuit_params, ¶ms, snark.clone(), - ); + Default::default(), + ); match stage { CircuitBuilderStage::Prover => { @@ -55,7 +103,7 @@ impl AppCircuit for AggregationCircuit { } _ => { circuit.expose_previous_instances(false); - circuit.config(k, Some(10)); + circuit.calculate_params(Some(10)); set_var("LOOKUP_BITS", lookup_bits.to_string()); } }; diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index a49908ea..3d43b331 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -1,56 +1,39 @@ use std::{env::var, iter, marker::PhantomData, vec}; use crate::{ - builder::Eth2CircuitBuilder, gadget::crypto::{ - calculate_ysquared, Fp2Point, FpPoint, G1Chip, G1Point, G2Chip, G2Point, HashInstructions, - HashToCurveCache, HashToCurveChip, Sha256ChipWide, ShaBitThreadBuilder, ShaCircuitBuilder, + calculate_ysquared, G1Chip, G1Point, G2Chip, G2Point, HashInstructions, Sha256ChipWide, + ShaBitGateManager, ShaCircuitBuilder, }, poseidon::{fq_array_poseidon, fq_array_poseidon_native, poseidon_sponge}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, sync_step_circuit::{clear_3_bits, to_bytes_le, truncate_sha256_into_single_elem}, - util::{ - decode_into_field, gen_pkey, AppCircuit, AssignedValueCell, Challenges, Eth2ConfigPinning, - IntoWitness, ThreadBuilderBase, - }, + util::{gen_pkey, AppCircuit, Challenges, CommonGateManager, Eth2ConfigPinning, IntoWitness}, witness::{self, HashInput, HashInputChunk}, }; -use eth_types::{AppCurveExt, Field, Spec}; -use group::UncompressedEncoding; +use eth_types::{Field, Spec}; use halo2_base::{ - gates::{ - builder::{ - CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, - MultiPhaseThreadBreakPoints, RangeCircuitBuilder, - }, - flex_gate::GateStrategy, - range::{RangeConfig, RangeStrategy}, + gates::{circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, RangeChip, RangeInstructions}, + halo2_proofs::{ + circuit::{Layouter, Region, SimpleFloorPlanner, Value}, + dev::MockProver, + halo2curves::bn256, + plonk::{Circuit, ConstraintSystem, Error, ProvingKey}, + poly::{commitment::Params, kzg::commitment::ParamsKZG}, }, - safe_types::{GateInstructions, RangeChip, RangeInstructions}, utils::{fs::gen_srs, CurveAffineExt, ScalarField}, AssignedValue, Context, QuantumCell, }; use halo2_ecc::{ - bigint::ProperCrtUint, + bigint::{utils::decode_into_bn, ProperCrtUint}, bls12_381::{bls_signature, pairing::PairingChip, Fp12Chip, Fp2Chip, FpChip}, - ecc::{bls_signature::BlsSignatureChip, EcPoint, EccChip}, - fields::{fp12, vector::FieldVector, FieldChip, FieldExtConstructor}, -}; -use halo2_proofs::{ - circuit::{Layouter, Region, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error, ProvingKey}, - poly::{commitment::Params, kzg::commitment::ParamsKZG}, -}; -use halo2curves::{ - bls12_381::{self, Fq, Fq12, G1Affine, G2Affine, G2Prepared, G1, G2}, - bn256, + ecc::{EcPoint, EccChip}, + fields::{fp12, vector::FieldVector, FieldChip, FieldExtConstructor, PrimeFieldChip}, }; +use halo2curves::bls12_381::{self, Fq, Fq12, G1Affine, G2Affine, G2Prepared, G1, G2}; use itertools::Itertools; use lazy_static::__Deref; use num_bigint::BigUint; -use pasta_curves::group::{ff, GroupEncoding}; -use poseidon::PoseidonChip; use snark_verifier_sdk::CircuitExt; use ssz_rs::{Merkleized, Vector}; use sync_committee_primitives::consensus_types::BeaconBlockHeader; @@ -64,12 +47,12 @@ pub struct CommitteeUpdateCircuit { impl CommitteeUpdateCircuit { fn synthesize( - thread_pool: &mut ShaBitThreadBuilder, - range: &RangeChip, + builder: &mut ShaCircuitBuilder>, + fp_chip: &FpChip, args: &witness::CommitteeRotationArgs, ) -> Result>, Error> { - let fp_chip = FpChip::::new(range, G2::LIMB_BITS, G2::NUM_LIMBS); - let fp2_chip = Fp2Chip::::new(&fp_chip); + let range = fp_chip.range(); + let fp2_chip = Fp2Chip::::new(fp_chip); let g1_chip = EccChip::new(fp2_chip.fp_chip()); let sha256_chip = Sha256ChipWide::new(range, args.randomness); @@ -79,7 +62,7 @@ impl CommitteeUpdateCircuit { .iter() .map(|bytes| { assert_eq!(bytes.len(), 48); - thread_pool + builder .main() .assign_witnesses(bytes.iter().map(|&b| F::from(b as u64))) }) @@ -88,12 +71,11 @@ impl CommitteeUpdateCircuit { // Note: This is the root of the public keys in the SyncCommittee struct // not the root of the SyncCommittee struct itself. let committee_root_ssz = - Self::sync_committee_root_ssz(thread_pool, &sha256_chip, compressed_encodings.clone())?; + Self::sync_committee_root_ssz(builder, &sha256_chip, compressed_encodings.clone())?; let poseidon_commit = { - let pubkeys_x = - Self::decode_pubkeys_x(thread_pool.main(), &fp_chip, compressed_encodings); - fq_array_poseidon(thread_pool.main(), range.gate(), &pubkeys_x)? + let pubkeys_x = Self::decode_pubkeys_x(builder.main(), fp_chip, compressed_encodings); + fq_array_poseidon(builder.main(), range.gate(), &pubkeys_x)? }; // Finalized header @@ -103,10 +85,10 @@ impl CommitteeUpdateCircuit { .state_root .as_ref() .iter() - .map(|v| thread_pool.main().load_witness(F::from(*v as u64))) + .map(|v| builder.main().load_witness(F::from(*v as u64))) .collect_vec(); let finalized_header_root = ssz_merkleize_chunks( - thread_pool, + builder, &sha256_chip, [ finalized_slot_bytes, @@ -118,7 +100,7 @@ impl CommitteeUpdateCircuit { )?; // Verify that the sync committee root is in the finalized state root verify_merkle_proof( - thread_pool, + builder, &sha256_chip, args.sync_committee_branch .iter() @@ -136,34 +118,6 @@ impl CommitteeUpdateCircuit { Ok(public_inputs) } - pub fn instance(args: &witness::CommitteeRotationArgs) -> Vec> { - let pubkeys_x = args.pubkeys_compressed.iter().cloned().map(|mut bytes| { - bytes[47] &= 0b11111000; - bls12_381::Fq::from_bytes_le(&bytes) - }); - - let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x).unwrap(); - - let mut pk_vector: Vector, 512> = args - .pubkeys_compressed - .iter() - .cloned() - .map(|v| v.try_into().unwrap()) - .collect_vec() - .try_into() - .unwrap(); - - let ssz_root = pk_vector.hash_tree_root().unwrap(); - - let finalized_header_root = args.finalized_header.clone().hash_tree_root().unwrap(); - - let instance_vec = iter::once(poseidon_commitment) - .chain(ssz_root.0.map(|b| bn256::Fr::from(b as u64))) - .collect(); - - vec![instance_vec] - } - fn decode_pubkeys_x( ctx: &mut Context, fp_chip: &FpChip<'_, F>, @@ -176,27 +130,30 @@ impl CommitteeUpdateCircuit { .into_iter() .map(|assigned_bytes| { // assertion check for assigned_uncompressed vector to be equal to S::PubKeyCurve::BYTES_COMPRESSED from specification - assert_eq!(assigned_bytes.len(), G1::BYTES_COMPRESSED); + assert_eq!(assigned_bytes.len(), 48); // masked byte from compressed representation - let masked_byte = &assigned_bytes[G1::BYTES_COMPRESSED - 1]; + let masked_byte = &assigned_bytes[48 - 1]; // clear the flag bits from a last byte of compressed pubkey. // we are using [`clear_3_bits`] function which appears to be just as useful here as for public input commitment. let cleared_byte = clear_3_bits(ctx, range, masked_byte); // Use the cleared byte to construct the x coordinate - let assigned_x_bytes_cleared = [ - &assigned_bytes.as_slice()[..G1::BYTES_COMPRESSED - 1], - &[cleared_byte], - ] - .concat(); - - decode_into_field::(assigned_x_bytes_cleared, &fp_chip.limb_bases, gate, ctx) + let assigned_x_bytes_cleared = + [&assigned_bytes.as_slice()[..48 - 1], &[cleared_byte]].concat(); + + decode_into_bn::( + ctx, + gate, + assigned_x_bytes_cleared, + &fp_chip.limb_bases, + fp_chip.limb_bits(), + ) }) .collect() } - fn sync_committee_root_ssz>( - thread_pool: &mut ThreadBuilder, - hasher: &impl HashInstructions, + fn sync_committee_root_ssz>( + builder: &mut ShaCircuitBuilder, + hasher: &impl HashInstructions>, compressed_encodings: impl IntoIterator>>, ) -> Result>, Error> { let pubkeys_hashes: Vec>> = compressed_encodings @@ -204,14 +161,46 @@ impl CommitteeUpdateCircuit { .map(|bytes| { let input: HashInputChunk<_> = bytes .into_iter() - .pad_using(64, |_| thread_pool.main().load_zero()) + .pad_using(64, |_| builder.main().load_zero()) .into(); hasher - .digest::<64>(thread_pool, HashInput::Single(input), false) - .map(|r| r.output_bytes.into()) + .digest::<64>(builder, HashInput::Single(input), false) + .map(|r| r.into_iter().collect_vec().into()) }) .collect::, _>>()?; - ssz_merkleize_chunks(thread_pool, hasher, pubkeys_hashes) + ssz_merkleize_chunks(builder, hasher, pubkeys_hashes) + } + + pub fn instance( + args: &witness::CommitteeRotationArgs, + limb_bits: usize, + ) -> Vec> { + let pubkeys_x = args.pubkeys_compressed.iter().cloned().map(|mut bytes| { + bytes[47] &= 0b11111000; + bls12_381::Fq::from_bytes_le(&bytes) + }); + + let poseidon_commitment = + fq_array_poseidon_native::(pubkeys_x, limb_bits).unwrap(); + + let mut pk_vector: Vector, 512> = args + .pubkeys_compressed + .iter() + .cloned() + .map(|v| v.try_into().unwrap()) + .collect_vec() + .try_into() + .unwrap(); + + let ssz_root = pk_vector.hash_tree_root().unwrap(); + + let finalized_header_root = args.finalized_header.clone().hash_tree_root().unwrap(); + + let instance_vec = iter::once(poseidon_commitment) + .chain(ssz_root.0.map(|b| bn256::Fr::from(b as u64))) + .collect(); + + vec![instance_vec] } } @@ -225,375 +214,370 @@ impl AppCircuit for CommitteeUpdateCircuit { witness: &witness::CommitteeRotationArgs, k: u32, ) -> Result, Error> { - let mut thread_pool = ShaBitThreadBuilder::from_stage(stage); - let range = RangeChip::::new(RangeStrategy::Vertical, 8); + let mut builder = + ShaCircuitBuilder::>::from_stage(stage) + .use_k(k as usize); + let range = builder.range_chip(8); + let fp_chip = FpChip::new(&range, 120, 4); - let assigned_instances = Self::synthesize(&mut thread_pool, &range, witness)?; + let assigned_instances = Self::synthesize(&mut builder, &fp_chip, witness)?; match stage { CircuitBuilderStage::Prover => {} _ => { - thread_pool.config( - k as usize, - Some( - var("MINIMUM_ROWS") - .unwrap_or_else(|_| "0".to_string()) - .parse() - .unwrap(), - ), - ); + builder.calculate_params(Some( + var("MINIMUM_ROWS") + .unwrap_or_else(|_| "0".to_string()) + .parse() + .unwrap(), + )); } } - Ok(Eth2CircuitBuilder::from_stage( - assigned_instances, - thread_pool, - pinning.map(|p| p.break_points), - stage, - )) + Ok(builder) } } -#[cfg(test)] -mod tests { - use std::{ - env::{set_var, var}, - fs, - path::PathBuf, - }; - - use crate::{ - aggregation::AggregationConfigPinning, - gadget::crypto::constant_randomness, - util::{full_prover, full_verifier, gen_pkey, Halo2ConfigPinning, PinnableCircuit}, - witness::{CommitteeRotationArgs, SyncStepArgs}, - }; - - use super::*; - use ark_std::{end_timer, start_timer}; - use eth_types::Testnet; - use halo2_base::{ - gates::{ - builder::{CircuitBuilderStage, FlexGateConfigParams}, - flex_gate::GateStrategy, - range::RangeStrategy, - }, - utils::fs::gen_srs, - }; - use halo2_proofs::{ - circuit::SimpleFloorPlanner, - dev::MockProver, - halo2curves::bn256::Fr, - plonk::{keygen_pk, keygen_vk, Circuit, FloorPlanner}, - poly::{commitment::Params, kzg::commitment::ParamsKZG}, - }; - use halo2curves::{bls12_381::G1Affine, bn256::Bn256}; - use pasta_curves::group::UncompressedEncoding; - use rand::rngs::OsRng; - use rayon::iter::ParallelIterator; - use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; - use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; - use snark_verifier_sdk::{ - gen_pk, - halo2::{ - aggregation::{AggregationCircuit, AggregationConfigParams}, - gen_proof_shplonk, gen_snark_shplonk, - }, - CircuitExt, Snark, SHPLONK, - }; - - fn load_circuit_args() -> CommitteeRotationArgs { - #[derive(serde::Deserialize)] - struct ArgsJson { - finalized_header: BeaconBlockHeader, - committee_root_branch: Vec>, - pubkeys_compressed: Vec>, - } - - let ArgsJson { - pubkeys_compressed, - committee_root_branch, - finalized_header, - } = serde_json::from_slice(&fs::read("../test_data/rotation_512.json").unwrap()).unwrap(); - - CommitteeRotationArgs { - pubkeys_compressed, - randomness: constant_randomness(), - _spec: PhantomData, - finalized_header: finalized_header, - sync_committee_branch: committee_root_branch, - } - } - - fn gen_application_snark( - params: &ParamsKZG, - pk: &ProvingKey, - witness: &CommitteeRotationArgs, - ) -> Snark { - CommitteeUpdateCircuit::::gen_snark_shplonk( - params, - pk, - "./config/committee_update.json", - None::, - witness, - ) - .unwrap() - } - - #[test] - fn test_committee_update_circuit() { - const K: u32 = 18; - let params = gen_srs(K); - - let witness = load_circuit_args(); - - let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); - let circuit = CommitteeUpdateCircuit::::create_circuit( - CircuitBuilderStage::Mock, - Some(pinning), - &witness, - params.k(), - ) - .unwrap(); - - let timer = start_timer!(|| "committee_update mock prover"); - let prover = MockProver::::run(K, &circuit, circuit.instances()).unwrap(); - prover.assert_satisfied_par(); - end_timer!(timer); - } - - #[test] - fn test_committee_update_proofgen() { - const K: u32 = 18; - let params = gen_srs(K); - - let pk = CommitteeUpdateCircuit::::read_or_create_pk( - ¶ms, - "../build/committee_update.pkey", - "./config/committee_update.json", - false, - &CommitteeRotationArgs::::default(), - ); - - let witness = load_circuit_args(); - - let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); - - let circuit = CommitteeUpdateCircuit::::create_circuit( - CircuitBuilderStage::Prover, - Some(pinning), - &witness, - K, - ) - .unwrap(); - - let instances = circuit.instances(); - let proof = full_prover(¶ms, &pk, circuit, instances.clone()); - - assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) - } - - #[test] - fn test_circuit_aggregation_proofgen() { - const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; - const APP_K: u32 = 20; - let params_app = gen_srs(APP_K); - - const AGG_K: u32 = 22; - let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( - ¶ms_app, - "../build/committee_update.pkey", - "./config/committee_update.json", - false, - &CommitteeRotationArgs::::default(), - ); - let witness = load_circuit_args(); - let snark = gen_application_snark(¶ms_app, &pk_app, &witness); - - let params = gen_srs(AGG_K); - println!("agg_params k: {:?}", params.k()); - let lookup_bits = params.k() as usize - 1; - - let pk = AggregationCircuit::read_or_create_pk( - ¶ms, - "../build/aggregation.pkey", - AGG_CONFIG_PATH, - false, - &vec![snark.clone()], - ); - - let agg_config = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); - - let agg_circuit = AggregationCircuit::create_circuit( - CircuitBuilderStage::Prover, - Some(agg_config), - &vec![snark.clone()], - AGG_K, - ) - .unwrap(); - - let instances = agg_circuit.instances(); - let num_instances = agg_circuit.num_instance(); - - let proof = full_prover(¶ms, &pk, agg_circuit, instances.clone()); - - assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)); - } - - #[test] - fn test_circuit_aggregation_evm() { - const AGG_CONFIG_PATH: &str = "./config/committee_update_a.json"; - const APP_K: u32 = 21; - let params_app = gen_srs(APP_K); - - const AGG_K: u32 = 23; - let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( - ¶ms_app, - "../build/committee_update.pkey", - "./config/committee_update.json", - false, - &CommitteeRotationArgs::::default(), - ); - - let witness = load_circuit_args(); - let snark = gen_application_snark(¶ms_app, &pk_app, &witness); - - let params = gen_srs(AGG_K); - println!("agg_params k: {:?}", params.k()); - let lookup_bits = params.k() as usize - 1; - - let pk = AggregationCircuit::read_or_create_pk( - ¶ms, - "../build/aggregation.pkey", - AGG_CONFIG_PATH, - false, - &vec![snark.clone()], - ); - - let agg_config = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); - - let agg_circuit = AggregationCircuit::create_circuit( - CircuitBuilderStage::Prover, - Some(agg_config), - &vec![snark.clone()], - AGG_K, - ) - .unwrap(); - - let instances = agg_circuit.instances(); - let num_instances = agg_circuit.num_instance(); - - println!("num_instances: {:?}", num_instances); - println!("instances: {:?}", instances); - - let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); - println!("proof size: {}", proof.len()); - let deployment_code = AggregationCircuit::gen_evm_verifier_shplonk( - ¶ms, - &pk, - Some("contractyul"), - &vec![snark], - ) - .unwrap(); - println!("deployment_code size: {}", deployment_code.len()); - evm_verify(deployment_code, instances, proof); - } - - #[test] - fn test_circuit_aggregation_2_evm() { - const K0: u32 = 20; - const K1: u32 = 24; - const K2: u32 = 24; - - const APP_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; - const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation_1.json"; - const AGG_FINAL_CONFIG_PATH: &str = "./config/committee_update_aggregation_2.json"; - - // Layer 0 snark gen - let l0_snark = { - let p0 = gen_srs(K0); - let pk_l0 = CommitteeUpdateCircuit::::read_or_create_pk( - &p0, - "../build/committee_update.pkey", - APP_CONFIG_PATH, - false, - &CommitteeRotationArgs::::default(), - ); - let witness = load_circuit_args(); - let snark = gen_application_snark(&p0, &pk_l0, &witness); - println!( - "L0 num instances: {:?}", - snark.instances.iter().map(|i| i.len()).collect_vec() - ); - println!("L0 snark size: {}", snark.proof.len()); - snark - }; - - // Layer 1 snark gen - let l1_snark = { - let p1 = gen_srs(K1); - let mut circuit = AggregationCircuit::keygen::(&p1, vec![l0_snark.clone()]); - circuit.expose_previous_instances(false); - - println!("L1 Keygen num_instances: {:?}", circuit.num_instance()); - - let pk_l1 = gen_pk(&p1, &circuit, None); - circuit.write_pinning(AGG_CONFIG_PATH); - let pinning = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); - let lookup_bits = K1 as usize - 1; - let mut circuit = AggregationCircuit::new::( - CircuitBuilderStage::Prover, - Some(pinning.break_points), - lookup_bits, - &p1, - iter::once(l0_snark.clone()), - ); - circuit.expose_previous_instances(false); - - println!("L1 Prover num_instances: {:?}", circuit.num_instance()); - let snark = gen_snark_shplonk(&p1, &pk_l1, circuit, None::); - println!("L1 snark size: {}", snark.proof.len()); - - snark - }; - - // Layer 2 snark gen - let (proof, deployment_code, instances) = { - let p2 = gen_srs(K2); - let mut circuit = - AggregationCircuit::keygen::(&p2, iter::once(l1_snark.clone())); - circuit.expose_previous_instances(true); - - let num_instances = circuit.num_instance(); - println!("L2 Keygen num_instances: {:?}", num_instances); - - let pk_l2 = gen_pk(&p2, &circuit, None); - circuit.write_pinning(AGG_FINAL_CONFIG_PATH); - let pinning = AggregationConfigPinning::from_path(AGG_FINAL_CONFIG_PATH); - - let deployment_code = gen_evm_verifier_shplonk::( - &p2, - pk_l2.get_vk(), - num_instances, - Some(&PathBuf::from("contractyul")), - ); - let mut circuit = AggregationCircuit::prover::( - &p2, - iter::once(l1_snark.clone()), - pinning.break_points, - ); - circuit.expose_previous_instances(true); - - let num_instances = circuit.num_instance(); - let instances = circuit.instances(); - println!("L2 Prover num_instances: {:?}", num_instances); - - let proof = gen_evm_proof_shplonk(&p2, &pk_l2, circuit, instances.clone()); - println!("L2 proof size: {}", proof.len()); - println!("L2 Deployment Code Size: {}", deployment_code.len()); - (proof, deployment_code, instances) - }; - - evm_verify(deployment_code, instances, proof); - } -} +// #[cfg(test)] +// mod tests { +// use std::{ +// env::{set_var, var}, +// fs, +// path::PathBuf, +// }; + +// use crate::{ +// aggregation::AggregationConfigPinning, +// gadget::crypto::constant_randomness, +// util::{full_prover, full_verifier, gen_pkey, Halo2ConfigPinning, PinnableCircuit}, +// witness::{CommitteeRotationArgs, SyncStepArgs}, +// }; + +// use super::*; +// use ark_std::{end_timer, start_timer}; +// use eth_types::Testnet; +// use halo2_base::{ +// gates::{ +// builder::{CircuitBuilderStage, FlexGateConfigParams}, +// flex_gate::GateStrategy, +// range::RangeStrategy, +// }, +// utils::fs::gen_srs, +// }; +// use halo2_proofs::{ +// circuit::SimpleFloorPlanner, +// dev::MockProver, +// halo2curves::bn256::Fr, +// plonk::{keygen_pk, keygen_vk, Circuit, FloorPlanner}, +// poly::{commitment::Params, kzg::commitment::ParamsKZG}, +// }; +// use halo2curves::{bls12_381::G1Affine, bn256::Bn256}; +// use pasta_curves::group::UncompressedEncoding; +// use rand::rngs::OsRng; +// use rayon::iter::ParallelIterator; +// use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; +// use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; +// use snark_verifier_sdk::{ +// gen_pk, +// halo2::{ +// aggregation::{AggregationCircuit, AggregationConfigParams}, +// gen_proof_shplonk, gen_snark_shplonk, +// }, +// CircuitExt, Snark, SHPLONK, +// }; + +// fn load_circuit_args() -> CommitteeRotationArgs { +// #[derive(serde::Deserialize)] +// struct ArgsJson { +// finalized_header: BeaconBlockHeader, +// committee_root_branch: Vec>, +// pubkeys_compressed: Vec>, +// } + +// let ArgsJson { +// pubkeys_compressed, +// committee_root_branch, +// finalized_header, +// } = serde_json::from_slice(&fs::read("../test_data/rotation_512.json").unwrap()).unwrap(); + +// CommitteeRotationArgs { +// pubkeys_compressed, +// randomness: constant_randomness(), +// _spec: PhantomData, +// finalized_header: finalized_header, +// sync_committee_branch: committee_root_branch, +// } +// } + +// fn gen_application_snark( +// params: &ParamsKZG, +// pk: &ProvingKey, +// witness: &CommitteeRotationArgs, +// ) -> Snark { +// CommitteeUpdateCircuit::::gen_snark_shplonk( +// params, +// pk, +// "./config/committee_update.json", +// None::, +// witness, +// ) +// .unwrap() +// } + +// #[test] +// fn test_committee_update_circuit() { +// const K: u32 = 18; +// let params = gen_srs(K); + +// let witness = load_circuit_args(); + +// let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); +// let circuit = CommitteeUpdateCircuit::::create_circuit( +// CircuitBuilderStage::Mock, +// Some(pinning), +// &witness, +// params.k(), +// ) +// .unwrap(); + +// let timer = start_timer!(|| "committee_update mock prover"); +// let prover = MockProver::::run(K, &circuit, circuit.instances()).unwrap(); +// prover.assert_satisfied_par(); +// end_timer!(timer); +// } + +// #[test] +// fn test_committee_update_proofgen() { +// const K: u32 = 18; +// let params = gen_srs(K); + +// let pk = CommitteeUpdateCircuit::::read_or_create_pk( +// ¶ms, +// "../build/committee_update.pkey", +// "./config/committee_update.json", +// false, +// &CommitteeRotationArgs::::default(), +// ); + +// let witness = load_circuit_args(); + +// let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); + +// let circuit = CommitteeUpdateCircuit::::create_circuit( +// CircuitBuilderStage::Prover, +// Some(pinning), +// &witness, +// K, +// ) +// .unwrap(); + +// let instances = circuit.instances(); +// let proof = full_prover(¶ms, &pk, circuit, instances.clone()); + +// assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) +// } + +// #[test] +// fn test_circuit_aggregation_proofgen() { +// const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; +// const APP_K: u32 = 20; +// let params_app = gen_srs(APP_K); + +// const AGG_K: u32 = 22; +// let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( +// ¶ms_app, +// "../build/committee_update.pkey", +// "./config/committee_update.json", +// false, +// &CommitteeRotationArgs::::default(), +// ); +// let witness = load_circuit_args(); +// let snark = gen_application_snark(¶ms_app, &pk_app, &witness); + +// let params = gen_srs(AGG_K); +// println!("agg_params k: {:?}", params.k()); +// let lookup_bits = params.k() as usize - 1; + +// let pk = AggregationCircuit::read_or_create_pk( +// ¶ms, +// "../build/aggregation.pkey", +// AGG_CONFIG_PATH, +// false, +// &vec![snark.clone()], +// ); + +// let agg_config = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); + +// let agg_circuit = AggregationCircuit::create_circuit( +// CircuitBuilderStage::Prover, +// Some(agg_config), +// &vec![snark.clone()], +// AGG_K, +// ) +// .unwrap(); + +// let instances = agg_circuit.instances(); +// let num_instances = agg_circuit.num_instance(); + +// let proof = full_prover(¶ms, &pk, agg_circuit, instances.clone()); + +// assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)); +// } + +// #[test] +// fn test_circuit_aggregation_evm() { +// const AGG_CONFIG_PATH: &str = "./config/committee_update_a.json"; +// const APP_K: u32 = 21; +// let params_app = gen_srs(APP_K); + +// const AGG_K: u32 = 23; +// let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( +// ¶ms_app, +// "../build/committee_update.pkey", +// "./config/committee_update.json", +// false, +// &CommitteeRotationArgs::::default(), +// ); + +// let witness = load_circuit_args(); +// let snark = gen_application_snark(¶ms_app, &pk_app, &witness); + +// let params = gen_srs(AGG_K); +// println!("agg_params k: {:?}", params.k()); +// let lookup_bits = params.k() as usize - 1; + +// let pk = AggregationCircuit::read_or_create_pk( +// ¶ms, +// "../build/aggregation.pkey", +// AGG_CONFIG_PATH, +// false, +// &vec![snark.clone()], +// ); + +// let agg_config = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); + +// let agg_circuit = AggregationCircuit::create_circuit( +// CircuitBuilderStage::Prover, +// Some(agg_config), +// &vec![snark.clone()], +// AGG_K, +// ) +// .unwrap(); + +// let instances = agg_circuit.instances(); +// let num_instances = agg_circuit.num_instance(); + +// println!("num_instances: {:?}", num_instances); +// println!("instances: {:?}", instances); + +// let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); +// println!("proof size: {}", proof.len()); +// let deployment_code = AggregationCircuit::gen_evm_verifier_shplonk( +// ¶ms, +// &pk, +// Some("contractyul"), +// &vec![snark], +// ) +// .unwrap(); +// println!("deployment_code size: {}", deployment_code.len()); +// evm_verify(deployment_code, instances, proof); +// } + +// #[test] +// fn test_circuit_aggregation_2_evm() { +// const K0: u32 = 20; +// const K1: u32 = 24; +// const K2: u32 = 24; + +// const APP_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; +// const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation_1.json"; +// const AGG_FINAL_CONFIG_PATH: &str = "./config/committee_update_aggregation_2.json"; + +// // Layer 0 snark gen +// let l0_snark = { +// let p0 = gen_srs(K0); +// let pk_l0 = CommitteeUpdateCircuit::::read_or_create_pk( +// &p0, +// "../build/committee_update.pkey", +// APP_CONFIG_PATH, +// false, +// &CommitteeRotationArgs::::default(), +// ); +// let witness = load_circuit_args(); +// let snark = gen_application_snark(&p0, &pk_l0, &witness); +// println!( +// "L0 num instances: {:?}", +// snark.instances.iter().map(|i| i.len()).collect_vec() +// ); +// println!("L0 snark size: {}", snark.proof.len()); +// snark +// }; + +// // Layer 1 snark gen +// let l1_snark = { +// let p1 = gen_srs(K1); +// let mut circuit = AggregationCircuit::keygen::(&p1, vec![l0_snark.clone()]); +// circuit.expose_previous_instances(false); + +// println!("L1 Keygen num_instances: {:?}", circuit.num_instance()); + +// let pk_l1 = gen_pk(&p1, &circuit, None); +// circuit.write_pinning(AGG_CONFIG_PATH); +// let pinning = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); +// let lookup_bits = K1 as usize - 1; +// let mut circuit = AggregationCircuit::new::( +// CircuitBuilderStage::Prover, +// Some(pinning.break_points), +// lookup_bits, +// &p1, +// iter::once(l0_snark.clone()), +// ); +// circuit.expose_previous_instances(false); + +// println!("L1 Prover num_instances: {:?}", circuit.num_instance()); +// let snark = gen_snark_shplonk(&p1, &pk_l1, circuit, None::); +// println!("L1 snark size: {}", snark.proof.len()); + +// snark +// }; + +// // Layer 2 snark gen +// let (proof, deployment_code, instances) = { +// let p2 = gen_srs(K2); +// let mut circuit = +// AggregationCircuit::keygen::(&p2, iter::once(l1_snark.clone())); +// circuit.expose_previous_instances(true); + +// let num_instances = circuit.num_instance(); +// println!("L2 Keygen num_instances: {:?}", num_instances); + +// let pk_l2 = gen_pk(&p2, &circuit, None); +// circuit.write_pinning(AGG_FINAL_CONFIG_PATH); +// let pinning = AggregationConfigPinning::from_path(AGG_FINAL_CONFIG_PATH); + +// let deployment_code = gen_evm_verifier_shplonk::( +// &p2, +// pk_l2.get_vk(), +// num_instances, +// Some(&PathBuf::from("contractyul")), +// ); +// let mut circuit = AggregationCircuit::prover::( +// &p2, +// iter::once(l1_snark.clone()), +// pinning.break_points, +// ); +// circuit.expose_previous_instances(true); + +// let num_instances = circuit.num_instance(); +// let instances = circuit.instances(); +// println!("L2 Prover num_instances: {:?}", num_instances); + +// let proof = gen_evm_proof_shplonk(&p2, &pk_l2, circuit, instances.clone()); +// println!("L2 proof size: {}", proof.len()); +// println!("L2 Deployment Code Size: {}", deployment_code.len()); +// (proof, deployment_code, instances) +// }; + +// evm_verify(deployment_code, instances, proof); +// } +// } diff --git a/lightclient-circuits/src/gadget/common.rs b/lightclient-circuits/src/gadget/common.rs index 3b9d9e0a..4b3f36ca 100644 --- a/lightclient-circuits/src/gadget/common.rs +++ b/lightclient-circuits/src/gadget/common.rs @@ -17,7 +17,7 @@ pub mod sum { pub fn value(values: &[u8]) -> F { values .iter() - .fold(F::zero(), |acc, value| acc + F::from(*value as u64)) + .fold(F::ZERO, |acc, value| acc + F::from(*value as u64)) } } @@ -36,7 +36,7 @@ pub mod and { /// Returns the product of all given values. pub fn value(inputs: Vec) -> F { - inputs.iter().fold(F::one(), |acc, input| acc * input) + inputs.iter().fold(F::ONE, |acc, input| acc * input) } } @@ -70,7 +70,7 @@ pub mod not { /// Returns a value that represents the NOT of the given value. pub fn value(b: F) -> F { - F::one() - b + F::ONE - b } } @@ -108,7 +108,7 @@ pub mod select { /// Returns the `when_true` value when the selector is true, else returns /// the `when_false` value. pub fn value(selector: F, when_true: F, when_false: F) -> F { - selector * when_true + (F::one() - selector) * when_false + selector * when_true + (F::ONE - selector) * when_false } /// Returns the `when_true` word when selector is true, else returns the @@ -118,7 +118,7 @@ pub mod select { when_true: [u8; 32], when_false: [u8; 32], ) -> [u8; 32] { - if selector == F::one() { + if selector == F::ONE { when_true } else { when_false @@ -179,9 +179,9 @@ impl Expr for i32 { Expression::Constant( F::from(self.unsigned_abs() as u64) * if self.is_negative() { - -F::one() + -F::ONE } else { - F::one() + F::ONE }, ) } @@ -191,7 +191,7 @@ impl Expr for i32 { /// single expression. pub fn expr_from_bytes>(bytes: &[E]) -> Expression { let mut value = 0.expr(); - let mut multiplier = F::one(); + let mut multiplier = F::ONE; for byte in bytes.iter() { value = value + byte.expr() * multiplier; multiplier *= F::from(256); @@ -234,7 +234,7 @@ pub mod rlc { if !values.is_empty() { generic(values, randomness) } else { - F::zero() + F::ZERO } } diff --git a/lightclient-circuits/src/gadget/crypto/builder.rs b/lightclient-circuits/src/gadget/crypto/builder.rs index ebb1ec20..2d0bcbd0 100644 --- a/lightclient-circuits/src/gadget/crypto/builder.rs +++ b/lightclient-circuits/src/gadget/crypto/builder.rs @@ -7,7 +7,10 @@ use halo2_base::{ circuit::{ builder::BaseCircuitBuilder, BaseCircuitParams, BaseConfig, CircuitBuilderStage, }, - flex_gate::threads::SinglePhaseCoreManager, + flex_gate::{ + threads::{CommonCircuitBuilder, SinglePhaseCoreManager}, + MultiPhaseThreadBreakPoints, + }, RangeChip, }, halo2_proofs::{ @@ -18,42 +21,44 @@ use halo2_base::{ virtual_region::manager::VirtualRegionManager, Context, }; +use itertools::Itertools; +use snark_verifier_sdk::CircuitExt; use crate::{ - gadget::crypto::{Sha256Chip, ShaThreadBuilder}, - util::ThreadBuilderBase, + gadget::crypto::{Sha256Chip, ShaFlexGateManager}, + util::{CommonGateManager, Eth2ConfigPinning, GateBuilderConfig, PinnableCircuit}, }; use super::sha256_flex::{assign_threads_sha, SpreadConfig, FIRST_PHASE}; #[derive(Debug, Clone)] -pub struct SHAConfig { - pub compression: SpreadConfig, +pub struct SHAConfig> { + pub compression: CustomConfig, pub base: BaseConfig, } -impl SHAConfig { +impl> SHAConfig { pub fn configure(meta: &mut ConstraintSystem, params: BaseCircuitParams) -> Self { let base = BaseConfig::configure(meta, params); - let compression = SpreadConfig::configure(meta, 8, 1); + let compression = GateConfig::configure(meta); Self { base, compression } } } #[derive(Getters)] -pub struct ShaCircuitBuilder> { +pub struct ShaCircuitBuilder> { #[getset(get = "pub", get_mut = "pub")] pub(crate) sha: ThreadBuilder, #[getset(get = "pub", get_mut = "pub")] pub(crate) base: BaseCircuitBuilder, } -impl> ShaCircuitBuilder { +impl> ShaCircuitBuilder { pub fn new(witness_gen_only: bool) -> Self { let base = BaseCircuitBuilder::new(witness_gen_only); Self { - sha: ShaThreadBuilder::new(witness_gen_only) + sha: GateManager::new(witness_gen_only) .use_copy_manager(base.core().phase_manager[FIRST_PHASE].copy_manager.clone()), base, } @@ -123,10 +128,15 @@ impl> ShaCircuitBuilder &mut Context { - self.base.main(0) + /// Sets the break points of the circuit. + pub fn set_break_points(&mut self, break_points: MultiPhaseThreadBreakPoints) { + self.base.set_break_points(break_points); + } + + /// Returns new with break points + pub fn use_break_points(mut self, break_points: MultiPhaseThreadBreakPoints) -> Self { + self.set_break_points(break_points); + self } /// Returns [SinglePhaseCoreManager] with the virtual region with all core threads in the given phase. @@ -138,7 +148,7 @@ impl> ShaCircuitBuilder (&mut Context, &mut ThreadBuilder::CustomContext) { + pub fn sha_contexts_pair(&mut self) -> (&mut Context, GateManager::CustomContext<'_>) { (self.base.main(0), self.sha.custom_context()) } @@ -148,10 +158,31 @@ impl> ShaCircuitBuilder> Circuit - for ShaCircuitBuilder +impl> CommonCircuitBuilder + for ShaCircuitBuilder { - type Config = SHAConfig; + fn main(&mut self) -> &mut Context { + self.base.main(0) + } + + fn thread_count(&self) -> usize { + self.thread_count() + } + + fn new_context(&self, context_id: usize) -> Context { + self.new_context(context_id) + } + + fn new_thread(&mut self) -> &mut Context { + self.new_thread() + } +} + +impl> Circuit for ShaCircuitBuilder +where + GateManager::Config: GateBuilderConfig, +{ + type Config = SHAConfig; type FloorPlanner = SimpleFloorPlanner; type Params = BaseCircuitParams; @@ -167,7 +198,7 @@ impl> Circuit SHAConfig::configure(meta, params) } - fn configure(_meta: &mut ConstraintSystem) -> SHAConfig { + fn configure(_meta: &mut ConstraintSystem) -> Self::Config { unreachable!("You must use configure_with_params"); } @@ -191,3 +222,37 @@ impl> Circuit Ok(()) } } + +impl> CircuitExt + for ShaCircuitBuilder +where + GateManager::Config: GateBuilderConfig, +{ + fn num_instance(&self) -> Vec { + self.base + .assigned_instances + .iter() + .map(|e| e.len()) + .collect() + } + + fn instances(&self) -> Vec> { + self.base + .assigned_instances + .iter() + .map(|v| v.into_iter().map(|av| *av.value()).collect_vec()) + .collect() + } +} + +impl> PinnableCircuit + for ShaCircuitBuilder +where + GateManager::Config: GateBuilderConfig, +{ + type Pinning = Eth2ConfigPinning; + + fn break_points(&self) -> MultiPhaseThreadBreakPoints { + self.base.break_points() + } +} diff --git a/lightclient-circuits/src/gadget/crypto/hash2curve.rs b/lightclient-circuits/src/gadget/crypto/hash2curve.rs deleted file mode 100644 index c20792ec..00000000 --- a/lightclient-circuits/src/gadget/crypto/hash2curve.rs +++ /dev/null @@ -1,700 +0,0 @@ -// //! The chip that implements `draft-irtf-cfrg-hash-to-curve-16` -// //! https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16 - -use std::ops::Deref; -use std::{cell::RefCell, iter, marker::PhantomData}; - -use super::{ - util::{fp2_sgn0, i2osp, strxor}, - Fp2Point, G1Point, G2Point, HashInstructions, -}; -use super::{AssignedHashResult, ShaContexts, ShaThreadBuilder}; -use crate::util::{AsBits, ThreadBuilderBase}; -use crate::{ - util::{bigint_to_le_bytes, decode_into_field, decode_into_field_be}, - witness::HashInput, -}; -use eth_types::{AppCurveExt, Field, HashCurveExt, Spec}; -use ff::Field as _; -use halo2_base::{ - safe_types::{GateInstructions, RangeInstructions, SafeBytes32, SafeTypeChip}, - utils::ScalarField, - AssignedValue, Context, QuantumCell, -}; -use halo2_ecc::{ - bigint::{CRTInteger, ProperUint}, - ecc::EccChip, - fields::{ - fp::FpChip, fp2, vector::FieldVector, FieldChip, FieldExtConstructor, PrimeField, - Selectable, - }, -}; -use halo2_proofs::{circuit::Region, plonk::Error}; -use halo2curves::group::GroupEncoding; -use itertools::Itertools; -use num_bigint::{BigInt, BigUint}; -use pasta_curves::arithmetic::SqrtRatio; - -const G2_EXT_DEGREE: usize = 2; - -// L = ceil((ceil(log2(p)) + k) / 8) (see section 5 of ietf draft link above) -const L: usize = 64; - -#[allow(type_alias_bounds)] -pub type Fp2Chip<'chip, F, C: AppCurveExt, Fp = ::Fp> = - fp2::Fp2Chip<'chip, F, FpChip<'chip, F, Fp>, C::Fq>; - -#[derive(Debug)] -pub struct HashToCurveChip<'a, S: Spec, F: Field, HC: HashInstructions> { - hash_chip: &'a HC, - _f: PhantomData, - _spec: PhantomData, -} - -impl<'a, S: Spec, F: Field, HC: HashInstructions + 'a> HashToCurveChip<'a, S, F, HC> { - pub fn new(hash_chip: &'a HC) -> Self { - Self { - hash_chip, - _f: PhantomData, - _spec: PhantomData, - } - } - - pub fn hash_to_curve( - &self, - thread_pool: &mut ShaThreadBuilder, - fp_chip: &FpChip, - msg: HashInput>, - cache: &mut HashToCurveCache, - ) -> Result, Error> - where - C::Fq: FieldExtConstructor, - { - let u = self.hash_to_field::(thread_pool, fp_chip, msg, cache)?; - let p = self.map_to_curve::(thread_pool.main(), fp_chip, u, cache)?; - Ok(p) - } - - /// Implements [section 5.2 of `draft-irtf-cfrg-hash-to-curve-16`][hash_to_field]. - /// - /// [hash_to_field]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.2 - /// - /// References: - /// - https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/blob/6ce20a1/poc/hash_to_field.py#L49 - /// - https://github.com/paulmillr/noble-curves/blob/bf70ba9/src/abstract/hash-to-curve.ts#L128 - /// - https://github.com/succinctlabs/telepathy-circuits/blob/d5c7771/circuits/hash_to_field.circom#L11 - fn hash_to_field( - &self, - thread_pool: &mut ShaThreadBuilder, - fp_chip: &FpChip, - msg: HashInput>, - cache: &mut HashToCurveCache, - ) -> Result<[Fp2Point; 2], Error> { - let range = self.hash_chip.range(); - let gate = range.gate(); - let safe_types = SafeTypeChip::new(range); - - // constants - let zero = thread_pool.main().load_zero(); - let one = thread_pool.main().load_constant(F::one()); - - let assigned_msg = msg.into_assigned(thread_pool.main()).to_vec(); - - let len_in_bytes = 2 * G2_EXT_DEGREE * L; - let extended_msg = Self::expand_message_xmd( - thread_pool, - self.hash_chip, - assigned_msg, - len_in_bytes, - cache, - )?; - - let limb_bases = cache.binary_bases.get_or_insert_with(|| { - C::limb_bytes_bases() - .into_iter() - .map(|base| thread_pool.main().load_constant(base)) - .collect() - }); - - // 2^256 - let two_pow_256 = - fp_chip.load_constant_uint(thread_pool.main(), BigUint::from(2u8).pow(256)); - let fq_bytes = C::BYTES_COMPRESSED / 2; - - let mut fst = true; - let u = extended_msg - .chunks(L) - .chunks(G2_EXT_DEGREE) - .into_iter() - .map(|elm_chunk| { - FieldVector( - elm_chunk - .map(|tv| { - let mut buf = vec![zero; fq_bytes]; - let rem = fq_bytes - 32; - buf[rem..].copy_from_slice(&tv[..32]); - let lo = decode_into_field_be::( - buf.to_vec(), - &fp_chip.limb_bases, - gate, - thread_pool.main(), - ); - - buf[rem..].copy_from_slice(&tv[32..]); - let hi = decode_into_field_be::( - buf.to_vec(), - &fp_chip.limb_bases, - gate, - thread_pool.main(), - ); - - let lo_2_256 = - fp_chip.mul_no_carry(thread_pool.main(), lo, two_pow_256.clone()); - let lo_2_356_hi = - fp_chip.add_no_carry(thread_pool.main(), lo_2_256, hi); - fp_chip.carry_mod(thread_pool.main(), lo_2_356_hi) - }) - .collect_vec(), - ) - }) - .collect_vec() - .try_into() - .unwrap(); - - Ok(u) - } - - pub fn map_to_curve( - &self, - ctx: &mut Context, - fp_chip: &FpChip, - u: [Fp2Point; 2], - cache: &mut HashToCurveCache, - ) -> Result, Error> - where - C::Fq: FieldExtConstructor, - { - let fp2_chip = Fp2Chip::<_, C>::new(fp_chip); - let ecc_chip = EccChip::>::new(&fp2_chip); - - let [u0, u1] = u; - - let p1 = Self::map_to_curve_simple_swu::(u0, &fp2_chip, ctx, cache); - let p2 = Self::map_to_curve_simple_swu::(u1, &fp2_chip, ctx, cache); - - let p_sum = ecc_chip.add_unequal(ctx, p1, p2, false); - - let iso_p = Self::isogeny_map::(p_sum, &fp2_chip, ctx, cache); - - Ok(Self::clear_cofactor::(iso_p, &ecc_chip, ctx, cache)) - } - - /// Implements [section 5.3 of `draft-irtf-cfrg-hash-to-curve-16`][expand_message_xmd]. - /// - /// [expand_message_xmd]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3 - /// - /// References: - /// - https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/blob/6ce20a1/poc/hash_to_field.py#L89 - /// - https://github.com/paulmillr/noble-curves/blob/bf70ba9/src/abstract/hash-to-curve.ts#L63 - /// - https://github.com/succinctlabs/telepathy-circuits/blob/d5c7771/circuits/hash_to_field.circom#L139 - fn expand_message_xmd( - thread_pool: &mut ShaThreadBuilder, - hash_chip: &HC, - msg: Vec>, - len_in_bytes: usize, - cache: &mut HashToCurveCache, - ) -> Result>, Error> { - let range = hash_chip.range(); - let gate = range.gate(); - - // constants - // const MAX_INPUT_SIZE: usize = 192; - let zero = thread_pool.main().load_zero(); - let one = thread_pool.main().load_constant(F::one()); - - // assign DST bytes & cache them - let dst_len = thread_pool - .main() - .load_constant(F::from(S::DST.len() as u64)); - let dst_prime = cache - .dst_with_len - .get_or_insert_with(|| { - S::DST - .iter() - .map(|&b| thread_pool.main().load_constant(F::from(b as u64))) - .chain(iter::once(dst_len)) - .collect() - }) - .clone(); - - // padding and length strings - let z_pad = i2osp(0, HC::BLOCK_SIZE, |b| zero); // TODO: cache these - let l_i_b_str = i2osp(len_in_bytes as u128, 2, |b| { - thread_pool.main().load_constant(b) - }); - - // compute blocks - let ell = len_in_bytes.div_ceil(HC::DIGEST_SIZE); - let mut b_vals = Vec::with_capacity(ell); - let msg_prime = z_pad - .into_iter() - .chain(msg) - .chain(l_i_b_str) - .chain(iter::once(zero)) - .chain(dst_prime.clone()); - - let b_0 = hash_chip - .digest::<143>(thread_pool, msg_prime.into(), false)? - .output_bytes; - - b_vals.insert( - 0, - hash_chip - .digest::<77>( - thread_pool, - b_0.into_iter() - .chain(iter::once(one)) - .chain(dst_prime.clone()) - .into(), - false, - )? - .output_bytes, - ); - - for i in 1..ell { - let preimg = strxor(b_0, b_vals[i - 1], gate, thread_pool.main()) - .into_iter() - .chain(iter::once( - thread_pool.main().load_constant(F::from(i as u64 + 1)), - )) - .chain(dst_prime.clone()) - .into(); - - b_vals.insert( - i, - hash_chip - .digest::<77>(thread_pool, preimg, false)? - .output_bytes, - ); - } - - let uniform_bytes = b_vals - .into_iter() - .flatten() - .take(len_in_bytes) - .collect_vec(); - - Ok(uniform_bytes) - } - - /// Implements [section 6.2 of draft-irtf-cfrg-hash-to-curve-16][map_to_curve_simple_swu] - /// - /// [map_to_curve_simple_swu]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#appendix-F.1-3 - /// - /// References: - /// - https://github.com/mikelodder7/bls12_381_plus/blob/ml/0.5.6/src/hash_to_curve/map_g2.rs#L388 - /// - https://github.com/paulmillr/noble-curves/blob/bf70ba9/src/abstract/weierstrass.ts#L1175 - fn map_to_curve_simple_swu( - u: Fp2Point, - fp2_chip: &Fp2Chip, - ctx: &mut Context, - cache: &mut HashToCurveCache, - ) -> G2Point - where - C::Fq: FieldExtConstructor, - { - let fp_chip = fp2_chip.fp_chip(); - let gate = fp_chip.range().gate(); - - // constants - let swu_a = cache - .swu_a - .get_or_insert_with(|| fp2_chip.load_constant(ctx, C::SWU_A)) - .deref() - .clone(); - let swu_b = cache - .swu_b - .get_or_insert_with(|| fp2_chip.load_constant(ctx, C::SWU_B)) - .deref() - .clone(); - let swu_z = cache - .swu_z - .get_or_insert_with(|| fp2_chip.load_constant(ctx, C::SWU_Z)) - .deref() - .clone(); - let fq2_one = cache - .fq2_one - .get_or_insert_with(|| fp2_chip.load_constant(ctx, ::one())) - .deref() - .clone(); - - let usq = fp2_chip.mul(ctx, u.clone(), u.clone()); // 1. tv1 = u^2 - let z_usq = fp2_chip.mul(ctx, usq, swu_z.clone()); // 2. tv1 = Z * tv1 - let zsq_u4 = fp2_chip.mul(ctx, z_usq.clone(), z_usq.clone()); // 3. tv2 = tv1^2 - let tv2 = fp2_chip.add(ctx, zsq_u4, z_usq.clone()); // 4. tv2 = tv2 + tv1 - let tv3 = fp2_chip.add_no_carry(ctx, tv2.clone(), fq2_one); // 5. tv3 = tv2 + 1 - let x0_num = fp2_chip.mul(ctx, tv3, swu_b.clone()); // 6. tv3 = B * tv3 - - let x_den = { - let tv2_is_zero = fp2_chip.is_zero(ctx, tv2.clone()); - let tv2_neg = fp2_chip.negate(ctx, tv2); - - fp2_chip.select(ctx, swu_z, tv2_neg, tv2_is_zero) // tv2_is_zero ? swu_z : tv2_neg - }; // 7. tv4 = tv2 != 0 ? -tv2 : Z - - let x_den = fp2_chip.mul(ctx, x_den, swu_a.clone()); // 8. tv4 = A * tv4 - - let x0_num_sqr = fp2_chip.mul(ctx, x0_num.clone(), x0_num.clone()); // 9. tv2 = tv3^2 - let x_densq = fp2_chip.mul(ctx, x_den.clone(), x_den.clone()); // 10. tv6 = tv4^2 - let ax_densq = fp2_chip.mul(ctx, x_densq.clone(), swu_a); // 11. tv5 = A * tv6 - let tv2 = fp2_chip.add_no_carry(ctx, x0_num_sqr, ax_densq); // 12. tv2 = tv2 + tv5 - let tv2 = fp2_chip.mul(ctx, tv2, x0_num.clone()); // 13. tv2 = tv2 * tv3 - let gx_den = fp2_chip.mul(ctx, x_densq, x_den.clone()); // 14. tv6 = tv6 * tv4 - let tv5 = fp2_chip.mul(ctx, gx_den.clone(), swu_b); // 15. tv5 = B * tv6 - let gx0_num = fp2_chip.add(ctx, tv2, tv5); // 16. tv2 = tv2 + tv5 - - let x = fp2_chip.mul(ctx, &z_usq, &x0_num); // 17. x = tv1 * tv3 - - let (is_gx1_square, y1) = - Self::sqrt_ratio::(gx0_num, gx_den, u.clone(), fp2_chip, ctx, cache); // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) - - let y = fp2_chip.mul(ctx, &z_usq, &u); // 19. y = tv1 * u - let y = fp2_chip.mul(ctx, y, y1.clone()); // 20. y = y * y1 - let x = fp2_chip.select(ctx, x0_num, x, is_gx1_square); // 21. x = is_gx1_square ? tv3 : x - let y = fp2_chip.select(ctx, y1, y, is_gx1_square); // 22. y = is_gx1_square ? y1 : y - - let to_neg = { - let u_sgn = fp2_sgn0::<_, C>(u, ctx, fp_chip); - let y_sgn = fp2_sgn0::<_, C>(y.clone(), ctx, fp_chip); - gate.xor(ctx, u_sgn, y_sgn) - }; // 23. e1 = sgn0(u) == sgn0(y) // we implement an opposite condition: !e1 = sgn0(u) ^ sgn0(y) - - let y_neg = fp2_chip.negate(ctx, y.clone()); - let y = fp2_chip.select(ctx, y_neg, y, to_neg); // 24. y = !e1 ? -y : y - let x = fp2_chip.divide(ctx, x, x_den); // 25. x = x / tv4 - - G2Point::new(x, y) - } - - /// Implements [Appendix E.3 of draft-irtf-cfrg-hash-to-curve-16][isogeny_map_g2] - /// - /// [isogeny_map_g2]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#appendix-E.3 - /// - /// References: - /// - https://github.com/mikelodder7/bls12_381_plus/blob/ml/0.5.6/src/g2.rs#L1153 - /// - https://github.com/paulmillr/noble-curves/blob/bf70ba9/src/abstract/hash-to-curve.ts#L167 - pub fn isogeny_map( - p: G2Point, - fp2_chip: &Fp2Chip, - ctx: &mut Context, - cache: &mut HashToCurveCache, - ) -> G2Point - where - C::Fq: FieldExtConstructor, - { - // constants - let iso_coeffs = cache - .iso_coeffs - .get_or_insert_with(|| { - [ - C::ISO_XNUM.to_vec(), - C::ISO_XDEN.to_vec(), - C::ISO_YNUM.to_vec(), - C::ISO_YDEN.to_vec(), - ] - .map(|coeffs| { - coeffs - .into_iter() - .map(|iso| fp2_chip.load_constant(ctx, iso)) - .collect_vec() - }) - }) - .deref() - .clone(); - - let fq2_zero = cache - .fq2_zero - .get_or_insert_with(|| fp2_chip.load_constant(ctx, ::zero())) - .deref() - .clone(); - - let [x_num, x_den, y_num, y_den] = iso_coeffs.map(|coeffs| { - coeffs.into_iter().fold(fq2_zero.clone(), |acc, v| { - let acc = fp2_chip.mul(ctx, acc, &p.x); - let no_carry = fp2_chip.add_no_carry(ctx, acc, v); - fp2_chip.carry_mod(ctx, no_carry) - }) - }); - - let x = { fp2_chip.divide_unsafe(ctx, x_num, x_den) }; - - let y = { - let tv = fp2_chip.divide_unsafe(ctx, y_num, y_den); - fp2_chip.mul(ctx, &p.y, tv) - }; - - G2Point::new(x, y) - } - - /// Implements [Appendix G.3 of draft-irtf-cfrg-hash-to-curve-16][clear_cofactor] - /// - /// [clear_cofactor]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#appendix-G.3 - /// - /// References: - /// - https://github.com/mikelodder7/bls12_381_plus/blob/ml/0.5.6/src/g2.rs#L956 - /// - https://github.com/paulmillr/noble-curves/blob/bf70ba9/src/bls12-381.ts#L1111 - fn clear_cofactor( - p: G2Point, - ecc_chip: &EccChip>, - ctx: &mut Context, - cache: &mut HashToCurveCache, - ) -> G2Point - where - C::Fq: FieldExtConstructor, - { - let t1 = { - // scalar multiplication is very expensive in terms of rows used - // TODO: is there other ways to clear cofactor that avoid scalar multiplication? - let tv = Self::mul_by_bls_x::(p.clone(), ecc_chip, ctx, cache); - ecc_chip.negate(ctx, tv) - }; // [-x]P - - let t2 = Self::psi::(p.clone(), ecc_chip.field_chip(), ctx, cache); // Ψ(P) - - let t3 = ecc_chip.double(ctx, p.clone()); // 2P - let t3 = Self::psi2::(t3, ecc_chip.field_chip(), ctx, cache); // Ψ²(2P) - let t3 = ecc_chip.sub_unequal(ctx, t3, t2.clone(), false); // Ψ²(2P) - Ψ(P) - - let t2 = ecc_chip.add_unequal(ctx, t1.clone(), t2, false); // [-x]P + Ψ(P) - let t2 = { - let tv = Self::mul_by_bls_x::(t2, ecc_chip, ctx, cache); - ecc_chip.negate(ctx, tv) - }; // [x²]P - [x]Ψ(P) - - // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P) - let t3 = ecc_chip.add_unequal(ctx, t3, t2, false); - // Ψ²(2P) - Ψ(Plet ) + [x²]P - [x]Ψ(P) + [x]P - let t3 = ecc_chip.sub_unequal(ctx, t3, t1, false); - - // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P) + [x]P - 1P => [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P) - ecc_chip.sub_unequal(ctx, t3, p, false) - } - - // Implements [Appendix F.2.1 of draft-irtf-cfrg-hash-to-curve-16][sqrt_ration] - // - // [sqrt_ration]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#appendix-F.2.1 - fn sqrt_ratio( - num: Fp2Point, - div: Fp2Point, - u: Fp2Point, - fp2_chip: &Fp2Chip, - ctx: &mut Context, - cache: &mut HashToCurveCache, - ) -> (AssignedValue, Fp2Point) - where - C::Fq: FieldExtConstructor, - { - let num_v = Self::assigned_fq2_to_value::(&num); - let div_v = Self::assigned_fq2_to_value::(&div); - let u = Self::assigned_fq2_to_value::(&u); - - let (is_square, y) = C::Fq::sqrt_ratio(&num_v, &div_v); - - let is_square = ctx.load_witness(F::from(is_square.unwrap_u8() as u64)); - fp2_chip.fp_chip().gate().assert_bit(ctx, is_square); // assert is_square is boolean - - let y_assigned = fp2_chip.load_private(ctx, y); - let y_sqr = fp2_chip.mul(ctx, y_assigned.clone(), y_assigned.clone()); // y_sqr = y1^2 - - let ratio = fp2_chip.divide(ctx, num, div); // r = u / v - - let swu_z = cache - .swu_z - .get_or_insert_with(|| fp2_chip.load_constant(ctx, C::SWU_Z)); - let ratio_z = fp2_chip.mul(ctx, ratio.clone(), swu_z.clone()); // r_z = r * z - - let y_check = fp2_chip.select(ctx, ratio, ratio_z, is_square); // y_check = is_square ? ratio : r_z - - fp2_chip.assert_equal(ctx, y_check, y_sqr); // assert y_check == y_sqr - - (is_square, y_assigned) - } - - pub fn mul_by_bls_x( - p: G2Point, - ecc_chip: &EccChip>, - ctx: &mut Context, - cache: &mut HashToCurveCache, - ) -> G2Point - where - C::Fq: FieldExtConstructor, - { - let bls_x_bits = cache - .bsl_x_bits - .get_or_insert_with(|| { - (0..64) - .map(|i| ((C::BLS_X >> i) & 1) as u8) - .map(|b| ctx.load_constant(F::from(b as u64))) - .collect_vec() - }) - .deref() - .clone(); - - ecc_chip.scalar_mult_bits(ctx, p, bls_x_bits, 4) - } - - pub fn psi( - p: G2Point, - fp2_chip: &Fp2Chip, - ctx: &mut Context, - cache: &mut HashToCurveCache, - ) -> G2Point - where - C::Fq: FieldExtConstructor, - { - // 1 / ((u+1) ^ ((q-1)/3)) - let psi_x = cache - .psi_x - .get_or_insert_with(|| fp2_chip.load_constant(ctx, C::PSI_X)); - - // 1 / ((u+1) ^ (p-1)/2) - let psi_y = cache - .psi_y - .get_or_insert_with(|| fp2_chip.load_constant(ctx, C::PSI_Y)); - - let x_frob = fp2_chip.conjugate(ctx, p.x); - let y_frob = fp2_chip.conjugate(ctx, p.y); - - let x = fp2_chip.mul(ctx, x_frob, psi_x.clone()); - let y = fp2_chip.mul(ctx, y_frob, psi_y.clone()); - - G2Point::new(x, y) - } - - pub fn psi2( - p: G2Point, - fp2_chip: &Fp2Chip, - ctx: &mut Context, - cache: &mut HashToCurveCache, - ) -> G2Point - where - C::Fq: FieldExtConstructor, - { - // 1 / 2 ^ ((q-1)/3) - let psi2_x = cache - .psi2_x - .get_or_insert_with(|| fp2_chip.load_constant(ctx, C::PSI2_X)); - - let x = fp2_chip.mul(ctx, p.x, psi2_x.clone()); - let y = fp2_chip.negate(ctx, p.y); - - G2Point::new(x, y) - } - - fn assigned_fq2_to_value(u: &Fp2Point) -> C::Fq { - C::get_fq(u.0.iter().map(|c| { - bigint_to_le_bytes( - c.limbs().iter().map(|e| *e.value()), - C::LIMB_BITS, - C::BYTES_COMPRESSED / 2, - ) - })) - } -} - -#[derive(Clone, Debug, Default)] -pub struct HashToCurveCache { - dst_with_len: Option>>, - binary_bases: Option>>, - swu_a: Option>, - swu_b: Option>, - swu_z: Option>, - fq2_zero: Option>, - fq2_one: Option>, - iso_coeffs: Option<[Vec>; 4]>, - psi_x: Option>, - psi_y: Option>, - psi2_x: Option>, - bsl_x_bits: Option>>, -} - -#[cfg(test)] -mod test { - use std::env::var; - use std::vec; - use std::{cell::RefCell, marker::PhantomData}; - - use crate::gadget::crypto::sha256_flex::{SpreadChip, SpreadConfig}; - use crate::gadget::crypto::ShaCircuitBuilder; - use crate::gadget::crypto::{Sha256Chip, ShaThreadBuilder}; - use crate::util::{print_fq2_dev, Challenges, IntoWitness}; - - use super::*; - use eth_types::{Mainnet, Testnet}; - use halo2_base::gates::builder::FlexGateConfigParams; - use halo2_base::gates::range::RangeConfig; - use halo2_base::safe_types::RangeChip; - use halo2_base::SKIP_FIRST_PASS; - use halo2_base::{ - gates::{builder::GateThreadBuilder, range::RangeStrategy}, - halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::MockProver, - halo2curves::bn256::Fr, - plonk::{Circuit, ConstraintSystem}, - }, - }; - use halo2_ecc::bigint::CRTInteger; - use halo2_proofs::circuit::Value; - use halo2curves::bls12_381::G2; - use sha2::{Digest, Sha256}; - - fn get_circuit( - k: usize, - mut builder: ShaThreadBuilder, - input_vector: &[Vec], - ) -> Result>, Error> { - let range = RangeChip::default(8); - let sha256 = Sha256Chip::new(&range); - - let h2c_chip = HashToCurveChip::::new(&sha256); - let fp_chip = halo2_ecc::bls12_381::FpChip::::new(&range, G2::LIMB_BITS, G2::NUM_LIMBS); - let fp2_chip = halo2_ecc::bls12_381::Fp2Chip::new(&fp_chip); - - for input in input_vector { - let mut cache = HashToCurveCache::::default(); - let hp = h2c_chip.hash_to_curve::( - &mut builder, - &fp_chip, - input.clone().into_witness(), - &mut cache, - )?; - - // print_fq2_dev::(hp.x(), "res_p.x"); - // print_fq2_dev::(hp.y(), "res_p.y"); - - println!( - "msghash: {:?}", - ( - fp2_chip.get_assigned_value(&hp.x.into()), - fp2_chip.get_assigned_value(&hp.y.into()) - ) - ); - } - - builder.config(k, None); - Ok(ShaCircuitBuilder::mock(builder)) - } - - #[test] - fn test_hash_to_g2() { - let k = 17; - - let test_input = vec![0u8; 32]; - let builder = ShaThreadBuilder::::mock(); - let circuit = get_circuit(k, builder, &[test_input]).unwrap(); - - let prover = MockProver::run(k as u32, &circuit, vec![]).unwrap(); - prover.assert_satisfied(); - } -} diff --git a/lightclient-circuits/src/gadget/crypto/mod.rs b/lightclient-circuits/src/gadget/crypto/mod.rs index 93d53ad7..13cb7559 100644 --- a/lightclient-circuits/src/gadget/crypto/mod.rs +++ b/lightclient-circuits/src/gadget/crypto/mod.rs @@ -1,8 +1,8 @@ mod builder; mod ecc; -// mod hash2curve; + mod sha256_flex; -// mod sha256_wide; +mod sha256_wide; pub use builder::{SHAConfig, ShaCircuitBuilder}; use eth_types::Field; @@ -14,8 +14,8 @@ use halo2_ecc::{ fields::{fp2, vector::FieldVector, FieldExtConstructor}, }; use lazy_static::lazy_static; -pub use sha256_flex::{Sha256Chip, ShaContexts, ShaThreadBuilder}; -// pub use sha256_wide::{Sha256ChipWide, ShaBitThreadBuilder}; +pub use sha256_flex::{Sha256Chip, ShaContexts, ShaFlexGateManager}; +pub use sha256_wide::{Sha256ChipWide, ShaBitGateManager}; pub use ecc::calculate_ysquared; @@ -31,13 +31,6 @@ pub type G2Chip<'chip, F> = EccChip<'chip, F, Fp2Chip<'chip, F>>; pub use halo2_ecc::ecc::hash_to_curve::HashInstructions; -#[derive(Debug, Clone)] -pub struct AssignedHashResult { - // pub input_len: AssignedValue, - pub input_bytes: Vec>, - pub output_bytes: [AssignedValue; 32], -} - // This is a temporary measure. TODO: use challenges API. pub fn constant_randomness() -> F { F::from_u128(0xca9d6022267d3bd658bf) diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs index 26f4203f..bc3cef4b 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs @@ -3,12 +3,12 @@ mod gate; mod spread; mod util; -pub use gate::ShaThreadBuilder; +pub use gate::ShaFlexGateManager; +use halo2_base::gates::flex_gate::threads::CommonCircuitBuilder; use halo2_base::gates::RangeChip; pub use spread::SpreadConfig; use eth_types::Field; -use ff::PrimeField; use itertools::Itertools; use sha2::compress256; use sha2::digest::generic_array::GenericArray; @@ -35,7 +35,7 @@ pub use self::gate::ShaContexts; pub(super) use self::gate::{assign_threads_sha, FIRST_PHASE}; pub use self::spread::SpreadChip; -use super::{AssignedHashResult, HashInstructions}; +use super::{HashInstructions, ShaCircuitBuilder}; #[derive(Debug, Clone)] pub struct Sha256Chip<'a, F: Field> { @@ -46,15 +46,15 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { const BLOCK_SIZE: usize = 64; const DIGEST_SIZE: usize = 32; - type ThreadManager = ShaThreadBuilder; - type Output = AssignedHashResult; + type CircuitBuilder = ShaCircuitBuilder>; + type Output = Vec>; fn digest( &self, - thread_pool: &mut ShaThreadBuilder, - input: HashInput>, + builder: &mut Self::CircuitBuilder, + input: impl IntoIterator>, strict: bool, - ) -> Result, Error> { + ) -> Result>, Error> { let max_processed_bytes = { let mut max_bytes = MAX_INPUT_SIZE + 9; let remainder = max_bytes % 64; @@ -64,9 +64,16 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { max_bytes }; - let assigned_input = input.into_assigned(thread_pool.main()); + let mut assigned_input_bytes = input + .into_iter() + .map(|cell| match cell { + QuantumCell::Existing(v) => v, + QuantumCell::Witness(v) => builder.main().load_witness(v), + QuantumCell::Constant(v) => builder.main().load_constant(v), + _ => unreachable!(), + }) + .collect_vec(); - let mut assigned_input_bytes = assigned_input.to_vec(); let input_byte_size = assigned_input_bytes.len(); let input_byte_size_with_9 = input_byte_size + 9; assert!(input_byte_size <= MAX_INPUT_SIZE); @@ -88,7 +95,7 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { // remaining_byte_size, // one_round_size * (max_round - num_round) // ); - let mut assign_byte = |byte: u8| thread_pool.main().load_witness(F::from(byte as u64)); + let mut assign_byte = |byte: u8| builder.main().load_witness(F::from(byte as u64)); assigned_input_bytes.push(assign_byte(0x80)); @@ -110,18 +117,18 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { if strict { for &assigned in assigned_input_bytes.iter() { - range.range_check(thread_pool.main(), assigned, 8); + range.range_check(builder.main(), assigned, 8); } } - let assigned_num_round = thread_pool.main().load_witness(F::from(num_round as u64)); + let assigned_num_round = builder.main().load_witness(F::from(num_round as u64)); // compute an initial state from the precomputed_input. let mut last_state = INIT_STATE; let mut assigned_last_state_vec = vec![last_state .iter() - .map(|state| thread_pool.main().load_witness(F::from(*state as u64))) + .map(|state| builder.main().load_witness(F::from(*state as u64))) .collect_vec()]; let mut num_processed_input = 0; @@ -129,7 +136,7 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { let assigned_input_word_at_round = &assigned_input_bytes[num_processed_input..(num_processed_input + one_round_size)]; let new_assigned_hs_out = sha256_compression( - thread_pool, + builder, &self.spread, assigned_input_word_at_round, assigned_last_state_vec.last().unwrap(), @@ -139,21 +146,17 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { num_processed_input += one_round_size; } - let zero = thread_pool.main().load_zero(); + let zero = builder.main().load_zero(); let mut output_h_out = vec![zero; 8]; for (n_round, assigned_state) in assigned_last_state_vec.into_iter().enumerate() { let selector = gate.is_equal( - thread_pool.main(), + builder.main(), QuantumCell::Constant(F::from(n_round as u64)), assigned_num_round, ); for i in 0..8 { - output_h_out[i] = gate.select( - thread_pool.main(), - assigned_state[i], - output_h_out[i], - selector, - ) + output_h_out[i] = + gate.select(builder.main(), assigned_state[i], output_h_out[i], selector) } } let output_digest_bytes = output_h_out @@ -162,34 +165,28 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { let be_bytes = assigned_word.value().get_lower_32().to_be_bytes().to_vec(); let assigned_bytes = (0..4) .map(|idx| { - let assigned = thread_pool - .main() - .load_witness(F::from(be_bytes[idx] as u64)); - range.range_check(thread_pool.main(), assigned, 8); + let assigned = builder.main().load_witness(F::from(be_bytes[idx] as u64)); + range.range_check(builder.main(), assigned, 8); assigned }) .collect_vec(); - let mut sum = thread_pool.main().load_zero(); + let mut sum = builder.main().load_zero(); for (idx, assigned_byte) in assigned_bytes.iter().copied().enumerate() { sum = gate.mul_add( - thread_pool.main(), + builder.main(), assigned_byte, QuantumCell::Constant(F::from(1u64 << (24 - 8 * idx))), sum, ); } - thread_pool.main().constrain_equal(&assigned_word, &sum); + builder.main().constrain_equal(&assigned_word, &sum); assigned_bytes }) .collect_vec() .try_into() .unwrap(); - let result = AssignedHashResult { - input_bytes: assigned_input_bytes, - output_bytes: output_digest_bytes, - }; - Ok(result) + Ok(output_digest_bytes) } } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs index ee9750ec..d32eaae8 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs @@ -1,27 +1,29 @@ use std::cell::RefMut; use crate::gadget::crypto::ShaCircuitBuilder; -use crate::util::ThreadBuilderBase; +use crate::util::CommonGateManager; use super::gate::ShaContexts; use super::spread::{self, SpreadChip, SpreadConfig}; use super::util::{bits_le_to_fe, fe_to_bits_le}; -use super::ShaThreadBuilder; +use super::ShaFlexGateManager; use eth_types::Field; -use halo2_base::halo2_proofs::{ - circuit::{AssignedCell, Cell, Layouter, Region, SimpleFloorPlanner, Value}, - plonk::{ - Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, Selector, TableColumn, - VirtualCells, - }, - poly::Rotation, -}; -use halo2_base::utils::fe_to_bigint; -use halo2_base::QuantumCell; use halo2_base::{ - gates::{flex_gate::FlexGateConfig, range::RangeConfig, GateInstructions, RangeInstructions}, - utils::{bigint_to_fe, biguint_to_fe, fe_to_biguint, modulus}, - AssignedValue, Context, + gates::{ + flex_gate::{threads::CommonCircuitBuilder, FlexGateConfig}, + range::RangeConfig, + GateInstructions, RangeInstructions, + }, + halo2_proofs::{ + circuit::{AssignedCell, Cell, Layouter, Region, SimpleFloorPlanner, Value}, + plonk::{ + Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, Selector, + TableColumn, VirtualCells, + }, + poly::Rotation, + }, + utils::{bigint_to_fe, biguint_to_fe, fe_to_bigint, fe_to_biguint, modulus}, + AssignedValue, Context, QuantumCell, }; use itertools::Itertools; use sha2::{Digest, Sha256}; @@ -56,7 +58,7 @@ pub const INIT_STATE: [u32; NUM_STATE_WORD] = [ pub type SpreadU32<'a, F> = (AssignedValue, AssignedValue); pub fn sha256_compression<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaCircuitBuilder>, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, assigned_input_bytes: &[AssignedValue], pre_state_words: &[AssignedValue], @@ -249,7 +251,7 @@ pub fn sha256_compression<'a, 'b: 'a, F: Field>( } fn state_to_spread_u32<'a, F: Field>( - thread_pool: &mut ShaCircuitBuilder>, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x: &AssignedValue, ) -> Result, Error> { @@ -277,7 +279,7 @@ fn mod_u32<'a, 'b: 'a, F: Field>( ) -> AssignedValue { let gate = range.gate(); let lo = F::from(x.value().get_lower_32() as u64); - let hi = F::from(((x.value().get_lower_128() >> 32) & ((1u128 << 32) - 1)) as u64); + let hi = F::from(((x.value().get_lower_64() >> 32) & ((1u64 << 32) - 1)) as u64); let assigned_lo = ctx.load_witness(lo); let assigned_hi = ctx.load_witness(hi); range.range_check(ctx, assigned_lo, 32); @@ -292,7 +294,7 @@ fn mod_u32<'a, 'b: 'a, F: Field>( } fn ch<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaCircuitBuilder>, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x: &SpreadU32<'a, F>, y: &SpreadU32<'a, F>, @@ -402,7 +404,7 @@ fn ch<'a, 'b: 'a, F: Field>( } fn maj<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaCircuitBuilder>, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x: &SpreadU32<'a, F>, y: &SpreadU32<'a, F>, @@ -474,7 +476,7 @@ fn three_add<'a, 'b: 'a, F: Field>( } fn sigma_upper0<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x_spread: &SpreadU32, ) -> Result, Error> { @@ -499,7 +501,7 @@ fn sigma_upper0<'a, 'b: 'a, F: Field>( } fn sigma_upper1<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x_spread: &SpreadU32, ) -> Result, Error> { @@ -524,7 +526,7 @@ fn sigma_upper1<'a, 'b: 'a, F: Field>( } fn sigma_lower0<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaCircuitBuilder>, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x_spread: &SpreadU32, ) -> Result, Error> { @@ -549,7 +551,7 @@ fn sigma_lower0<'a, 'b: 'a, F: Field>( } fn sigma_lower1<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaThreadBuilder, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x_spread: &SpreadU32, ) -> Result, Error> { @@ -575,7 +577,7 @@ fn sigma_lower1<'a, 'b: 'a, F: Field>( #[allow(clippy::too_many_arguments)] fn sigma_generic<'a, 'b: 'a, F: Field>( - thread_pool: &mut ShaCircuitBuilder>, + thread_pool: &mut ShaCircuitBuilder>, spread_chip: &SpreadChip<'a, F>, x_spread: &SpreadU32, starts: &[usize; 4], @@ -674,7 +676,7 @@ fn sigma_generic<'a, 'b: 'a, F: Field>( }; let (r_lo, r_hi) = { let lo = F::from(r_spread.value().get_lower_32() as u64); - let hi = F::from(((r_spread.value().get_lower_128() >> 32) & ((1u128 << 32) - 1)) as u64); + let hi = F::from(((r_spread.value().get_lower_64() >> 32) & ((1u64 << 32) - 1)) as u64); let assigned_lo = thread_pool.main().load_witness(lo); let assigned_hi = thread_pool.main().load_witness(hi); range.range_check(thread_pool.main(), assigned_lo, 32); diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs index 547ce382..bd8f34ed 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs @@ -13,6 +13,8 @@ use halo2_base::{ }; use itertools::Itertools; +use crate::util::{CommonGateManager, GateBuilderConfig}; + use super::SpreadConfig; pub const FIRST_PHASE: usize = 0; @@ -21,7 +23,7 @@ struct Dence; struct Spread; #[derive(Clone, Debug, Default, CopyGetters)] -pub struct ShaThreadBuilder { +pub struct ShaFlexGateManager { #[getset(get_copy = "pub")] witness_gen_only: bool, /// The `unknown` flag is used during key generation. If true, during key generation witness [Value]s are replaced with Value::unknown() for safety. @@ -37,34 +39,7 @@ pub struct ShaThreadBuilder { pub type ShaContexts<'a, F> = (&'a mut Context, &'a mut Context); -impl ShaThreadBuilder { - pub fn new(witness_gen_only: bool) -> Self { - Self { - witness_gen_only, - use_unknown: false, - threads_spread: Vec::new(), - threads_dense: Vec::new(), - copy_manager: SharedCopyConstraintManager::default(), - } - } - - pub fn mock() -> Self { - Self::new(false) - } - - pub fn keygen() -> Self { - Self::new(false).unknown(true) - } - - pub fn prover() -> Self { - Self::new(true) - } - - pub fn from_stage(stage: CircuitBuilderStage) -> Self { - Self::new(stage == CircuitBuilderStage::Prover) - .unknown(stage == CircuitBuilderStage::Keygen) - } - +impl ShaFlexGateManager { /// Mutates `self` to use the given copy manager everywhere, including in all threads. pub fn set_copy_manager(&mut self, copy_manager: SharedCopyConstraintManager) { self.copy_manager = copy_manager.clone(); @@ -76,30 +51,6 @@ impl ShaThreadBuilder { } } - /// Returns `self` with a given copy manager - pub fn use_copy_manager(mut self, copy_manager: SharedCopyConstraintManager) -> Self { - self.set_copy_manager(copy_manager); - self - } - - pub fn unknown(mut self, use_unknown: bool) -> Self { - self.use_unknown = use_unknown; - self - } - - pub fn contexts_pair(&mut self) -> ShaContexts { - if self.threads_dense.is_empty() { - self.new_thread_dense(); - } - if self.threads_spread.is_empty() { - self.new_thread_spread(); - } - ( - self.threads_dense.last_mut().unwrap(), - self.threads_spread.last_mut().unwrap(), - ) - } - pub fn new_thread_dense(&mut self) -> &mut Context { let thread_id = self.threads_dense.len(); self.threads_dense.push(Context::new( @@ -127,18 +78,51 @@ impl ShaThreadBuilder { // pub fn thread_count(&self) -> usize { // self.core.thread_count() // } +} - // pub fn get_new_thread_id(&mut self) -> usize { - // self.core.thread_count() - // } +impl CommonGateManager for ShaFlexGateManager { + type CustomContext<'a> = ShaContexts<'a, F>; + + fn new(witness_gen_only: bool) -> Self { + Self { + witness_gen_only, + use_unknown: false, + threads_spread: Vec::new(), + threads_dense: Vec::new(), + copy_manager: SharedCopyConstraintManager::default(), + } + } + + fn custom_context(&mut self) -> ShaContexts { + if self.threads_dense.is_empty() { + self.new_thread_dense(); + } + if self.threads_spread.is_empty() { + self.new_thread_spread(); + } + ( + self.threads_dense.last_mut().unwrap(), + self.threads_spread.last_mut().unwrap(), + ) + } + + fn use_copy_manager(mut self, copy_manager: SharedCopyConstraintManager) -> Self { + self.set_copy_manager(copy_manager); + self + } + + fn unknown(mut self, use_unknown: bool) -> Self { + self.use_unknown = use_unknown; + self + } } -impl VirtualRegionManager for ShaThreadBuilder { +impl VirtualRegionManager for ShaFlexGateManager { type Config = SpreadConfig; fn assign_raw(&self, spread: &Self::Config, region: &mut Region) { spread.annotate_columns_in_region(region); - + if self.witness_gen_only() { assign_threads_sha( &self.threads_dense, diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs index e59dc550..439db355 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use halo2_base::utils::{decompose, ScalarField}; use halo2_base::QuantumCell; use halo2_base::{ @@ -12,15 +10,17 @@ use halo2_base::{ utils::BigPrimeField, }; use halo2_base::{ - gates::{GateInstructions, RangeInstructions}, + gates::{flex_gate::threads::CommonCircuitBuilder, GateInstructions, RangeInstructions}, AssignedValue, Context, }; use itertools::Itertools; +use std::marker::PhantomData; use crate::gadget::crypto::ShaCircuitBuilder; +use crate::util::GateBuilderConfig; -use super::ShaThreadBuilder; -use super::util::{fe_to_bits_le, bits_le_to_fe}; +use super::util::{bits_le_to_fe, fe_to_bits_le}; +use super::ShaFlexGateManager; #[derive(Debug, Clone)] pub struct SpreadConfig { @@ -75,8 +75,14 @@ impl SpreadConfig { _f: PhantomData, } } +} + +impl GateBuilderConfig for SpreadConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { + Self::configure(meta, 8, 1) // todo: configure + } - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { layouter.assign_table( || "spread table", |mut table| { @@ -107,7 +113,7 @@ impl SpreadConfig { Ok(()) } - pub fn annotate_columns_in_region(&self, region: &mut Region) { + fn annotate_columns_in_region(&self, region: &mut Region) { for (i, &column) in self.spreads.iter().enumerate() { region.name_column(|| format!("spread_{i}"), column); } @@ -131,7 +137,7 @@ impl<'a, F: BigPrimeField> SpreadChip<'a, F> { } pub fn spread( &self, - thread_pool: &mut ShaCircuitBuilder>, + thread_pool: &mut ShaCircuitBuilder>, dense: &AssignedValue, ) -> Result, Error> { let gate = self.range.gate(); @@ -184,7 +190,7 @@ impl<'a, F: BigPrimeField> SpreadChip<'a, F> { fn spread_limb( &self, - thread_pool: &mut ShaCircuitBuilder>, + thread_pool: &mut ShaCircuitBuilder>, limb: &AssignedValue, ) -> Result, Error> { let (ctx_base, (ctx_dense, ctx_spread)) = thread_pool.sha_contexts_pair(); diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs index 0415286f..67e82c14 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs @@ -3,7 +3,7 @@ use halo2_base::utils::{biguint_to_fe, fe_to_biguint}; use itertools::Itertools; use num_bigint::BigUint; -use crate::{util::AssignedValueCell, witness::HashInput}; +use crate::witness::HashInput; pub fn fe_to_bits_le(val: &F, size: usize) -> Vec { let val_bytes = fe_to_biguint(val).to_bytes_le(); diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs index 98a597d6..beed6692 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs @@ -1,12 +1,11 @@ -mod gate; mod config; +mod gate; mod util; mod witness; use eth_types::Field; -use ff::PrimeField; -use halo2_base::gates::builder::KeygenAssignments; -use halo2_proofs::circuit::Value; +use halo2_base::gates::flex_gate::threads::CommonCircuitBuilder; +use halo2_base::gates::RangeChip; use itertools::Itertools; use std::collections::HashMap; use std::iter; @@ -16,26 +15,23 @@ use std::{cell::RefCell, char::MAX}; use crate::gadget::crypto::sha256_wide::util::Sha256AssignedRows; use crate::gadget::crypto::sha256_wide::witness::multi_sha256; use crate::gadget::rlc; -use crate::util::{AssignedValueCell, ThreadBuilderBase}; use crate::witness::HashInput; -use halo2_base::safe_types::RangeChip; -use halo2_base::QuantumCell; use halo2_base::{ gates::{GateInstructions, RangeInstructions}, - AssignedValue, Context, -}; -use halo2_base::{utils::value_to_option, ContextCell}; -use halo2_proofs::{ - circuit::{self, AssignedCell, Region}, - plonk::{Assigned, Error}, + halo2_proofs::{ + circuit::{self, AssignedCell, Region}, + plonk::{Assigned, Error}, + }, + utils::value_to_option, + AssignedValue, Context, ContextCell, QuantumCell, }; -pub use self::gate::ShaBitThreadBuilder; use self::config::Sha256BitConfig; +pub use self::gate::ShaBitGateManager; use self::util::{NUM_BYTES_FINAL_HASH, NUM_WORDS_TO_ABSORB}; -use super::{AssignedHashResult, HashInstructions}; +use super::{HashInstructions, ShaCircuitBuilder}; const SHA256_CONTEXT_ID: usize = usize::MAX; @@ -63,17 +59,32 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { const BLOCK_SIZE: usize = 64; const DIGEST_SIZE: usize = 32; - type ThreadManager = ShaBitThreadBuilder; - type Output = AssignedHashResult; + type CircuitBuilder = ShaCircuitBuilder>; + type Output = Vec>; fn digest( &self, - thread_pool: &mut ShaBitThreadBuilder, - input: HashInput>, + builder: &mut Self::CircuitBuilder, + input: impl IntoIterator>, strict: bool, - ) -> Result, Error> { - let binary_input: HashInput = input.clone().into(); - let assigned_input = input.into_assigned(thread_pool.main()); + ) -> Result>, Error> { + let mut assigned_input = input + .into_iter() + .map(|cell| match cell { + QuantumCell::Existing(v) => v, + QuantumCell::Witness(v) => builder.main().load_witness(v), + QuantumCell::Constant(v) => builder.main().load_constant(v), + _ => unreachable!(), + }) + .collect_vec(); + + let binary_input: HashInput = HashInput::Single( + assigned_input + .iter() + .map(|av| av.value().get_lower_32() as u8) + .collect_vec() + .into(), + ); let mut assigned_input_bytes = assigned_input.to_vec(); let rnd = QuantumCell::Constant(self.randomness); @@ -87,7 +98,7 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { let mut assigned_rounds = vec![]; let assigned_output = - self.load_digest::(thread_pool, binary_input, &mut assigned_rounds)?; + self.load_digest::(builder, binary_input, &mut assigned_rounds)?; let one_round_size = Self::BLOCK_SIZE; let num_round = 1; @@ -101,7 +112,7 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { let zero_padding_byte_size = padded_size - input_byte_size; let max_round = max_byte_size / one_round_size; - let mut assign_byte = |byte: u8| thread_pool.main().load_witness(F::from(byte as u64)); + let mut assign_byte = |byte: u8| builder.main().load_witness(F::from(byte as u64)); for _ in 0..zero_padding_byte_size { assigned_input_bytes.push(assign_byte(0u8)); @@ -110,14 +121,14 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { assert_eq!(assigned_input_bytes.len(), num_round * one_round_size); for &assigned in assigned_input_bytes.iter() { - range.range_check(thread_pool.main(), assigned, 8); + range.range_check(builder.main(), assigned, 8); } - let zero = thread_pool.main().load_zero(); + let zero = builder.main().load_zero(); let mut full_input_len = zero; let mut cur_input_rlc = zero; - let ctx_gate = thread_pool.main(); + let ctx_gate = builder.main(); for round_idx in 0..max_round { full_input_len = { let muled = gate.mul( @@ -151,18 +162,8 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { let hash_rlc = rlc::assigned_value(&assigned_output, &rnd, gate, ctx_gate); ctx_gate.constrain_equal(&hash_rlc, &assigned_rounds[round_idx].output_rlc); } - for &byte in assigned_output.iter() { - range.range_check(ctx_gate, byte, 8); - } - - Ok(AssignedHashResult { - input_bytes: vec![], - output_bytes: assigned_output.try_into().unwrap(), - }) - } - fn range(&self) -> &RangeChip { - self.range + Ok(assigned_output.to_vec()) } } @@ -173,7 +174,7 @@ impl<'a, F: Field> Sha256ChipWide<'a, F> { pub fn load_digest( &self, - thread_pool: &mut ShaBitThreadBuilder, + builder: &mut ShaCircuitBuilder>, input: HashInput, assigned_rounds: &mut Vec>, ) -> Result<[AssignedValue; NUM_BYTES_FINAL_HASH], Error> { @@ -184,7 +185,8 @@ impl<'a, F: Field> Sha256ChipWide<'a, F> { let vec_vecs = witness .iter() .map(|sha256_row| { - thread_pool + builder + .sha .sha_contexts() .load_sha256_row(sha256_row, &mut assigned_rows) }) @@ -200,7 +202,7 @@ impl<'a, F: Field> Sha256ChipWide<'a, F> { let hash_sha = hashes[0]; - let ctx_gate = thread_pool.main(); + let ctx_gate = builder.main(); let mut reassign_to_gate = |val_sha: AssignedValue| -> AssignedValue { let val_gate = ctx_gate.load_witness(*val_sha.value()); @@ -244,78 +246,78 @@ impl<'a, F: Field> Sha256ChipWide<'a, F> { } } -#[cfg(test)] -mod test { - use std::env::var; - use std::vec; - use std::{cell::RefCell, marker::PhantomData}; - - use crate::gadget::crypto::{constant_randomness, ShaCircuitBuilder}; - use crate::util::{full_prover, full_verifier, gen_pkey, Challenges, IntoWitness}; - - use super::*; - use ark_std::{end_timer, start_timer}; - use eth_types::Testnet; - use halo2_base::gates::builder::FlexGateConfigParams; - use halo2_base::gates::range::RangeConfig; - use halo2_base::utils::fs::gen_srs; - use halo2_base::SKIP_FIRST_PASS; - use halo2_base::{ - gates::{builder::GateThreadBuilder, range::RangeStrategy}, - halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::MockProver, - halo2curves::bn256::Fr, - plonk::{Circuit, ConstraintSystem}, - }, - }; - use sha2::{Digest, Sha256}; - - // fn test_circuit( - // k: usize, - // builder: &mut ShaBitThreadBuilder, - // input_vector: &[Vec], - // ) -> Result<(), Error> { - // let range = RangeChip::default(8); - // let sha256 = Sha256ChipWide::new(&range, constant_randomness()); - - // for input in input_vector { - // let _ = sha256.digest::<64>(builder, input.as_slice().into_witness(), false)?; - // } - - // builder.config(k, None); - - // Ok(()) - // } - - // #[test] - // fn test_sha256_chip_constant_size() { - // let k = 10; - - // let test_input = vec![0u8; 64]; - - // let mut builder = ShaBitThreadBuilder::::mock(); - - // test_circuit(k, &mut builder, &[test_input]).unwrap(); - - // let circuit = ShaCircuitBuilder::mock(builder); - - // let prover = MockProver::run(k as u32, &circuit, vec![]).unwrap(); - - // prover.assert_satisfied_par(); - // } - - // #[test] - // fn test_sha256_wide_params_gen() { - // let k = 10; - // let test_input = vec![1u8; 64]; - // let mut builder = ShaBitThreadBuilder::::keygen(); - - // test_circuit(k, &mut builder, &[test_input]).unwrap(); - - // let circuit = ShaCircuitBuilder::keygen(builder); - - // let params = gen_srs(k as u32); - // let pk = gen_pkey(|| "sha256_wide_chip", ¶ms, None, &circuit).unwrap(); - // } -} +// #[cfg(test)] +// mod test { +// use std::env::var; +// use std::vec; +// use std::{cell::RefCell, marker::PhantomData}; + +// use crate::gadget::crypto::{constant_randomness, ShaCircuitBuilder}; +// use crate::util::{full_prover, full_verifier, gen_pkey, Challenges, IntoWitness}; + +// use super::*; +// use ark_std::{end_timer, start_timer}; +// use eth_types::Testnet; +// use halo2_base::gates::builder::FlexGateConfigParams; +// use halo2_base::gates::range::RangeConfig; +// use halo2_base::utils::fs::gen_srs; +// use halo2_base::SKIP_FIRST_PASS; +// use halo2_base::{ +// gates::{builder::GateThreadBuilder, range::RangeStrategy}, +// halo2_proofs::{ +// circuit::{Layouter, SimpleFloorPlanner}, +// dev::MockProver, +// halo2curves::bn256::Fr, +// plonk::{Circuit, ConstraintSystem}, +// }, +// }; +// use sha2::{Digest, Sha256}; + +// // fn test_circuit( +// // k: usize, +// // builder: &mut ShaBitThreadBuilder, +// // input_vector: &[Vec], +// // ) -> Result<(), Error> { +// // let range = RangeChip::default(8); +// // let sha256 = Sha256ChipWide::new(&range, constant_randomness()); + +// // for input in input_vector { +// // let _ = sha256.digest::<64>(builder, input.as_slice().into_witness(), false)?; +// // } + +// // builder.config(k, None); + +// // Ok(()) +// // } + +// // #[test] +// // fn test_sha256_chip_constant_size() { +// // let k = 10; + +// // let test_input = vec![0u8; 64]; + +// // let mut builder = ShaBitThreadBuilder::::mock(); + +// // test_circuit(k, &mut builder, &[test_input]).unwrap(); + +// // let circuit = ShaCircuitBuilder::mock(builder); + +// // let prover = MockProver::run(k as u32, &circuit, vec![]).unwrap(); + +// // prover.assert_satisfied_par(); +// // } + +// // #[test] +// // fn test_sha256_wide_params_gen() { +// // let k = 10; +// // let test_input = vec![1u8; 64]; +// // let mut builder = ShaBitThreadBuilder::::keygen(); + +// // test_circuit(k, &mut builder, &[test_input]).unwrap(); + +// // let circuit = ShaCircuitBuilder::keygen(builder); + +// // let params = gen_srs(k as u32); +// // let pk = gen_pkey(|| "sha256_wide_chip", ¶ms, None, &circuit).unwrap(); +// // } +// } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs index 4063785f..a2844235 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs @@ -10,20 +10,22 @@ use std::marker::PhantomData; use crate::gadget::crypto::constant_randomness; use crate::gadget::{and, not, rlc, select, sum, xor, Expr}; -use crate::util::ThreadBuilderConfigBase; +use crate::util::GateBuilderConfig; use crate::witness::HashInputChunk; use crate::{ - util::{AssignedValueCell, BaseConstraintBuilder, Challenges}, + util::{BaseConstraintBuilder, Challenges}, witness::{self, HashInput}, }; use eth_types::{Field, Spec}; -use halo2_base::gates::builder::FlexGateConfigParams; -use halo2_base::{AssignedValue, Context, ContextCell, QuantumCell}; -use halo2_proofs::circuit; -use halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region, Value}, - plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, - poly::Rotation, +use halo2_base::halo2_proofs::circuit; +use halo2_base::virtual_region::copy_constraints::CopyConstraintManager; +use halo2_base::{ + halo2_proofs::{ + circuit::{AssignedCell, Layouter, Region, Value}, + plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, + poly::Rotation, + }, + AssignedValue, Context, ContextCell, QuantumCell, }; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; @@ -72,11 +74,11 @@ pub struct Sha256BitConfig, CA = Column> { pub offset: usize, } -impl ThreadBuilderConfigBase for Sha256BitConfig { - fn configure(meta: &mut ConstraintSystem, _params: FlexGateConfigParams) -> Self { +impl GateBuilderConfig for Sha256BitConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { // consts let two = F::from(2); - let f256 = two.pow_const(8); + let f256 = F::from(256); let r: F = constant_randomness(); // TODO: use challenges API let q_enable = meta.fixed_column(); @@ -801,7 +803,7 @@ impl Sha256BitConfig, Context> { region: &mut Region, config: &Sha256BitConfig, use_unknown: bool, - mut assigned_advices: Option<&mut HashMap<(usize, usize), (circuit::Cell, usize)>>, + mut copy_manager: Option<&mut CopyConstraintManager>, ) -> Result<(), Error> { // Fixed values for (name, column, ctx) in [ @@ -828,8 +830,10 @@ impl Sha256BitConfig, Context> { .assign_fixed(|| name, *column, offset, || Value::known(val))? .cell(); - if let Some(assigned_advices) = assigned_advices.as_mut() { - assigned_advices.insert((ctx.context_id, offset), (cell, offset)); + if let Some(copy_manager) = copy_manager.as_mut() { + copy_manager + .assigned_advices + .insert(ContextCell::new(ctx.type_id(), ctx.id(), offset), cell); } } } @@ -852,8 +856,10 @@ impl Sha256BitConfig, Context> { .assign_advice(|| name, *column, offset, || value)? .cell(); - if let Some(assigned_advices) = assigned_advices.as_mut() { - assigned_advices.insert((ctx.context_id, offset), (cell, offset)); + if let Some(copy_manager) = copy_manager.as_mut() { + copy_manager + .assigned_advices + .insert(ContextCell::new(ctx.type_id(), ctx.id(), offset), cell); } } } @@ -905,8 +911,10 @@ impl Sha256BitConfig, Context> { } .cell(); - if let Some(assigned_advices) = assigned_advices.as_mut() { - assigned_advices.insert((ctx.context_id, offset), (cell, offset)); + if let Some(copy_manager) = copy_manager.as_mut() { + copy_manager + .assigned_advices + .insert(ContextCell::new(ctx.type_id(), ctx.id(), offset), cell); } } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs index 0c2ab342..34cd3ecc 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs @@ -1,24 +1,22 @@ -use std::{cell::RefCell, collections::HashMap, iter, mem}; +use std::{any::TypeId, cell::RefCell, collections::HashMap, iter, mem}; use eth_types::Field; +use getset::CopyGetters; use halo2_base::{ - gates::{ - builder::{ - assign_threads_in, CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, - KeygenAssignments, ThreadBreakPoints, - }, - flex_gate::FlexGateConfig, + gates::{circuit::CircuitBuilderStage, flex_gate::FlexGateConfig}, + halo2_proofs::{ + circuit::{self, Region, Value}, + plonk::{Advice, Column, Error, Selector}, }, utils::ScalarField, + virtual_region::{ + copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, + }, Context, }; -use halo2_proofs::{ - circuit::{self, Region, Value}, - plonk::{Advice, Column, Error, Selector}, -}; use itertools::Itertools; -use crate::util::{ThreadBuilderBase, ThreadBuilderConfigBase}; +use crate::util::{CommonGateManager, GateBuilderConfig}; use super::{config::Sha256BitConfig, witness::ShaRow}; @@ -26,23 +24,40 @@ pub const FIRST_PHASE: usize = 0; pub type Sha256BitContexts = Sha256BitConfig, Context>; -#[derive(Clone, Debug)] -pub struct ShaBitThreadBuilder { +#[derive(Clone, Debug, CopyGetters)] +pub struct ShaBitGateManager { + #[getset(get_copy = "pub")] + witness_gen_only: bool, + /// The `unknown` flag is used during key generation. If true, during key generation witness [Value]s are replaced with Value::unknown() for safety. + #[getset(get_copy = "pub")] + pub(crate) use_unknown: bool, + /// Threads for spread table assignment. sha_contexts: Sha256BitContexts, - /// [`GateThreadBuilder`] with threads for basic gate; also in charge of thread IDs - pub gate_builder: GateThreadBuilder, sha_offset: usize, -} -impl ThreadBuilderBase for ShaBitThreadBuilder { - type Config = Sha256BitConfig; + pub copy_manager: SharedCopyConstraintManager, +} - fn new(mut witness_gen_only: bool) -> Self { - let mut gate_builder = GateThreadBuilder::new(witness_gen_only); - let mut new_context = || Context::new(witness_gen_only, gate_builder.get_new_thread_id()); +impl CommonGateManager for ShaBitGateManager { + type CustomContext<'a> = &'a mut Sha256BitContexts; + + fn new(witness_gen_only: bool) -> Self { + let copy_manager = SharedCopyConstraintManager::default(); + let mut context_id = 0; + let mut new_context = || { + Context::new( + witness_gen_only, + FIRST_PHASE, + TypeId::of::(), + context_id, + copy_manager.clone(), + ) + }; Self { + witness_gen_only, + use_unknown: false, sha_contexts: Sha256BitConfig { q_enable: new_context(), q_first: new_context(), @@ -71,129 +86,58 @@ impl ThreadBuilderBase for ShaBitThreadBuilder { _f: std::marker::PhantomData, offset: 0, }, - gate_builder, sha_offset: 0, + copy_manager: SharedCopyConstraintManager::default(), } } + fn custom_context(&mut self) -> Self::CustomContext<'_> { + self.sha_contexts() + } + fn from_stage(stage: CircuitBuilderStage) -> Self { Self::new(stage == CircuitBuilderStage::Prover) .unknown(stage == CircuitBuilderStage::Keygen) } - fn unknown(mut self, use_unknown: bool) -> Self { - self.gate_builder = self.gate_builder.unknown(use_unknown); + fn use_copy_manager(mut self, copy_manager: SharedCopyConstraintManager) -> Self { + self.set_copy_manager(copy_manager); self } - fn config(&self, k: usize, minimum_rows: Option) -> FlexGateConfigParams { - self.gate_builder.config(k, minimum_rows) - } - - fn main(&mut self) -> &mut Context { - self.gate_builder.main(FIRST_PHASE) - } - - fn witness_gen_only(&self) -> bool { - self.gate_builder.witness_gen_only() - } - - fn use_unknown(&self) -> bool { - self.gate_builder.use_unknown() - } - - fn thread_count(&self) -> usize { - self.gate_builder.thread_count() - } - - fn get_new_thread_id(&mut self) -> usize { - self.gate_builder.get_new_thread_id() + fn unknown(mut self, use_unknown: bool) -> Self { + self.use_unknown = use_unknown; + self } +} - fn assign_all( - &mut self, - gate: &FlexGateConfig, - lookup_advice: &[Vec>], - q_lookup: &[Option], - config: &Sha256BitConfig, - region: &mut Region, - KeygenAssignments { - mut assigned_advices, - assigned_constants, - mut break_points, - }: KeygenAssignments, - ) -> Result, Error> { - assert!(!self.witness_gen_only()); +impl VirtualRegionManager for ShaBitGateManager { + type Config = Sha256BitConfig; + fn assign_raw(&self, config: &Self::Config, region: &mut Region) { config.annotate_columns_in_region(region); - let use_unknown = self.use_unknown(); - - self.sha_contexts().assign_in_region( - region, - config, - use_unknown, - Some(&mut assigned_advices), - )?; - - let main_ctx = self.gate_builder.main(0); - // for ctx in self - // .threads_spread - // .iter_mut() - // .chain(self.threads_dense.iter_mut()) - // { - // main_ctx - // .advice_equality_constraints - // .append(&mut ctx.advice_equality_constraints); - // main_ctx - // .constant_equality_constraints - // .append(&mut ctx.constant_equality_constraints); - // } - - Ok(self.gate_builder.assign_all( - gate, - lookup_advice, - q_lookup, - region, - KeygenAssignments { - assigned_advices, - assigned_constants, - break_points, - }, - )) - } - - fn assign_witnesses( - &mut self, - gate: &FlexGateConfig, - lookup_advice: &[Vec>], - config: &Self::Config, - region: &mut Region, - break_points: &mut halo2_base::gates::builder::MultiPhaseThreadBreakPoints, - ) -> Result<(), Error> { - let use_unknown = self.use_unknown(); - - let break_points_gate = mem::take(&mut break_points[FIRST_PHASE]); - // warning: we currently take all contexts from phase 0, which means you can't read the values - // from these contexts later in phase 1. If we want to read, should clone here - let threads = mem::take(&mut self.gate_builder.threads[FIRST_PHASE]); - - assign_threads_in( - FIRST_PHASE, - threads, - gate, - &lookup_advice[FIRST_PHASE], - region, - break_points_gate, - ); - - self.sha_contexts() - .assign_in_region(region, config, use_unknown, None) + if self.witness_gen_only() { + self.sha_contexts + .assign_in_region(region, config, false, None) + .unwrap(); + } else { + let mut copy_manager = self.copy_manager.lock().unwrap(); + self.sha_contexts + .assign_in_region(region, config, self.use_unknown(), Some(&mut copy_manager)) + .unwrap(); + } } } -impl ShaBitThreadBuilder { +impl ShaBitGateManager { pub fn sha_contexts(&mut self) -> &mut Sha256BitContexts { &mut self.sha_contexts } + + /// Mutates `self` to use the given copy manager everywhere, including in all threads. + pub fn set_copy_manager(&mut self, copy_manager: SharedCopyConstraintManager) { + self.copy_manager = copy_manager.clone(); + // TODO: set to `self.sha_contexts`. + } } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs index 51150ab0..01c0b34c 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs @@ -1,13 +1,13 @@ use eth_types::Field; use halo2_base::{ + halo2_proofs::circuit::AssignedCell, utils::{biguint_to_fe, fe_to_biguint}, AssignedValue, }; -use halo2_proofs::circuit::AssignedCell; use itertools::Itertools; use num_bigint::BigUint; -use crate::{util::AssignedValueCell, witness::HashInput}; +use crate::witness::HashInput; pub(crate) const NUM_BITS_PER_BYTE: usize = 8; pub(crate) const NUM_BYTES_PER_WORD: usize = 4; @@ -69,13 +69,13 @@ impl Sha256AssignedRows { /// Decodes be bits pub mod decode { use eth_types::Field; - use halo2_proofs::plonk::Expression; + use halo2_base::halo2_proofs::plonk::Expression; use crate::gadget::Expr; pub(crate) fn expr(bits: &[Expression]) -> Expression { let mut value = 0.expr(); - let mut multiplier = F::one(); + let mut multiplier = F::ONE; for bit in bits.iter().rev() { value = value + bit.expr() * multiplier; multiplier *= F::from(2); @@ -95,7 +95,7 @@ pub mod decode { /// Rotates bits to the right pub mod rotate { use eth_types::Field; - use halo2_proofs::plonk::Expression; + use halo2_base::halo2_proofs::plonk::Expression; pub(crate) fn expr(bits: &[Expression], count: usize) -> Vec> { let mut rotated = bits.to_vec(); @@ -114,7 +114,7 @@ pub mod shift { use super::NUM_BITS_PER_WORD; use eth_types::Field; - use halo2_proofs::plonk::Expression; + use halo2_base::halo2_proofs::plonk::Expression; pub(crate) fn expr(bits: &[Expression], count: usize) -> Vec> { let mut res = vec![0.expr(); count]; @@ -131,7 +131,7 @@ pub mod shift { pub mod to_le_bytes { use crate::util::to_bytes; use eth_types::Field; - use halo2_proofs::plonk::Expression; + use halo2_base::halo2_proofs::plonk::Expression; pub(crate) fn expr(bits: &[Expression]) -> Vec> { to_bytes::expr(&bits.iter().rev().cloned().collect::>()) diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs index 8608c820..35f55ba0 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs @@ -42,10 +42,10 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, // Set the initial state let mut hs: [u64; 8] = H.to_vec().try_into().unwrap(); let mut length = 0usize; - let mut data_rlc = F::zero(); - let mut rnd_pow = F::zero(); - let mut u8_pow = [F::one(), F::zero()]; - let mut data_vals = [F::zero(); 2]; + let mut data_rlc = F::ZERO; + let mut rnd_pow = F::ZERO; + let mut u8_pow = [F::ONE, F::ZERO]; + let mut data_vals = [F::ZERO; 2]; let mut in_padding = false; @@ -104,10 +104,10 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, false, length, data_rlc, - F::zero(), + F::ZERO, [false, false, false, in_padding], - [F::zero(); ABSORB_WIDTH_PER_ROW_BYTES], - [F::zero(); NUM_BYTES_FINAL_HASH], + [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES], + [F::ZERO; NUM_BYTES_FINAL_HASH], ) }; add_row_start(d, h, idx == 0); @@ -119,7 +119,7 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, for (round, round_cst) in ROUND_CST.iter().enumerate() { // Padding/Length/Data rlc let mut is_paddings = [false; ABSORB_WIDTH_PER_ROW_BYTES]; - let mut inter_data_rlcs = [F::zero(); ABSORB_WIDTH_PER_ROW_BYTES]; + let mut inter_data_rlcs = [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES]; let mut is_right = false; // feature: [multi input lookups] if round < NUM_WORDS_TO_ABSORB { // padding/length @@ -194,12 +194,12 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, if round < NUM_WORDS_TO_ABSORB { data_rlc } else { - F::zero() + F::ZERO }, - F::zero(), + F::ZERO, is_paddings, inter_data_rlcs, - [F::zero(); NUM_BYTES_FINAL_HASH], + [F::ZERO; NUM_BYTES_FINAL_HASH], ); // Truncate the newly calculated values @@ -226,11 +226,11 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, .collect::>(); rlc::value(&hash_bytes, rnd) } else { - F::zero() + F::ZERO }; let final_hash_bytes = if is_final_block { - let mut bytes = [F::zero(); NUM_BYTES_FINAL_HASH]; + let mut bytes = [F::ZERO; NUM_BYTES_FINAL_HASH]; for (i, h) in hs.iter().enumerate() { for (j, byte) in (*h as u32).to_be_bytes().into_iter().enumerate() { bytes[4 * i + j] = F::from(byte as u64); @@ -238,7 +238,7 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, } bytes } else { - [F::zero(); NUM_BYTES_FINAL_HASH] + [F::ZERO; NUM_BYTES_FINAL_HASH] }; // Add end rows @@ -250,11 +250,11 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, false, false, 0, - F::zero(), - F::zero(), + F::ZERO, + F::ZERO, [false; ABSORB_WIDTH_PER_ROW_BYTES], - [F::zero(); ABSORB_WIDTH_PER_ROW_BYTES], - [F::zero(); NUM_BYTES_FINAL_HASH], + [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES], + [F::ZERO; NUM_BYTES_FINAL_HASH], ) }; add_row_end(hs[3], hs[7]); @@ -271,7 +271,7 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, data_rlc, hash_rlc, [false, false, false, in_padding], - [F::zero(); ABSORB_WIDTH_PER_ROW_BYTES], + [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES], final_hash_bytes, ); diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index eb505fbb..fa17ac28 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -11,12 +11,13 @@ pub mod gadget; pub mod util; pub mod witness; -// pub mod aggregation; -// pub mod committee_update_circuit; +pub mod aggregation; +pub mod committee_update_circuit; pub mod sync_step_circuit; // pub mod builder; mod poseidon; mod ssz_merkle; -pub use halo2_base::gates::flex_gate::FlexGateConfigParams; +pub use halo2_base; + diff --git a/lightclient-circuits/src/poseidon.rs b/lightclient-circuits/src/poseidon.rs index 38cac8f3..7c1dcf1b 100644 --- a/lightclient-circuits/src/poseidon.rs +++ b/lightclient-circuits/src/poseidon.rs @@ -1,13 +1,16 @@ use crate::gadget::crypto::G1Point; use eth_types::{Field, Spec}; use halo2_base::{ - gates::GateInstructions, halo2_proofs::plonk::Error, poseidon::PoseidonChip, AssignedValue, - Context, + gates::GateInstructions, + halo2_proofs::plonk::Error, + poseidon::{hasher::PoseidonSponge, PoseidonChip}, + utils::ScalarField, + AssignedValue, Context, }; use halo2_ecc::bigint::{ProperCrtUint, ProperUint}; use halo2curves::bls12_381::{Fq, G1Affine, G1}; use itertools::Itertools; -use poseidon_native::Poseidon as PoseidonNative; +use pse_poseidon::Poseidon as PoseidonNative; const POSEIDON_SIZE: usize = 16; const R_F: usize = 8; @@ -24,8 +27,8 @@ pub fn fq_array_poseidon<'a, F: Field>( .copied() .collect_vec(); - let mut poseidon = PoseidonChip::::new(ctx, R_F, R_P) - .expect("failed to construct Poseidon circuit"); + let mut poseidon = + PoseidonSponge::::new::(ctx); let mut current_poseidon_hash = None; @@ -35,7 +38,7 @@ pub fn fq_array_poseidon<'a, F: Field>( poseidon.update(&[current_poseidon_hash.unwrap()]); } - current_poseidon_hash.insert(poseidon.squeeze(ctx, gate)?); + current_poseidon_hash.insert(poseidon.squeeze(ctx, gate)); } Ok(current_poseidon_hash.unwrap()) @@ -73,8 +76,8 @@ pub fn poseidon_sponge( gate: &impl GateInstructions, elems: Vec>, ) -> Result, Error> { - let mut poseidon = PoseidonChip::::new(ctx, R_F, R_P) - .expect("failed to construct Poseidon circuit"); + let mut poseidon = + PoseidonSponge::::new::(ctx); let mut current_poseidon_hash = None; for (i, chunk) in elems.chunks(POSEIDON_SIZE - 3).enumerate() { @@ -82,7 +85,7 @@ pub fn poseidon_sponge( if i != 0 { poseidon.update(&[current_poseidon_hash.unwrap()]); } - current_poseidon_hash.insert(poseidon.squeeze(ctx, gate)?); + current_poseidon_hash.insert(poseidon.squeeze(ctx, gate)); } Ok(current_poseidon_hash.unwrap()) diff --git a/lightclient-circuits/src/ssz_merkle.rs b/lightclient-circuits/src/ssz_merkle.rs index 419728d9..0b8710ff 100644 --- a/lightclient-circuits/src/ssz_merkle.rs +++ b/lightclient-circuits/src/ssz_merkle.rs @@ -2,20 +2,21 @@ use std::os::unix::thread; use eth_types::Field; use halo2_base::{ + gates::flex_gate::threads::CommonCircuitBuilder, halo2_proofs::{circuit::Region, plonk::Error}, AssignedValue, Context, QuantumCell, }; use itertools::Itertools; use crate::{ - gadget::crypto::{HashInstructions, ShaContexts, ShaThreadBuilder}, - util::{IntoConstant, IntoWitness, ThreadBuilderBase}, + gadget::crypto::{HashInstructions, ShaContexts, ShaFlexGateManager}, + util::{CommonGateManager, IntoConstant, IntoWitness}, witness::{HashInput, HashInputChunk}, }; -pub fn ssz_merkleize_chunks>( - thread_pool: &mut ThreadBuilder, - hasher: &impl HashInstructions, +pub fn ssz_merkleize_chunks>( + builder: &mut CircuitBuilder, + hasher: &impl HashInstructions, chunks: impl IntoIterator>>, ) -> Result>, Error> { let mut chunks = chunks.into_iter().collect_vec(); @@ -34,8 +35,8 @@ pub fn ssz_merkleize_chunks>( .tuples() .map(|(left, right)| { hasher - .digest::<64>(thread_pool, HashInput::TwoToOne(left, right), false) - .map(|res| res.output_bytes.into()) + .digest::<64>(builder, HashInput::TwoToOne(left, right), false) + .map(|res| res.into()) }) .collect::, _>>()?; } @@ -50,9 +51,9 @@ pub fn ssz_merkleize_chunks>( Ok(root.bytes) } -pub fn verify_merkle_proof>( - thread_pool: &mut ThreadBuilder, - hasher: &impl HashInstructions, +pub fn verify_merkle_proof>( + builder: &mut CircuitBuilder, + hasher: &impl HashInstructions, proof: impl IntoIterator>>, leaf: HashInputChunk>, root: &[AssignedValue], @@ -63,7 +64,7 @@ pub fn verify_merkle_proof>( for witness in proof.into_iter() { computed_hash = hasher .digest::<64>( - thread_pool, + builder, if gindex % 2 == 0 { HashInput::TwoToOne(computed_hash, witness) } else { @@ -71,7 +72,6 @@ pub fn verify_merkle_proof>( }, false, )? - .output_bytes .into(); gindex /= 2; } @@ -82,7 +82,7 @@ pub fn verify_merkle_proof>( }); computed_root.zip(root.iter()).for_each(|(a, b)| { - thread_pool.main().constrain_equal(&a, b); + builder.main().constrain_equal(&a, b); }); Ok(()) diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 0647a03c..3e4ac765 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -15,24 +15,23 @@ use std::{ use crate::{ gadget::crypto::{ calculate_ysquared, G1Chip, G1Point, G2Chip, G2Point, HashInstructions, Sha256Chip, - ShaCircuitBuilder, ShaThreadBuilder, + ShaCircuitBuilder, ShaFlexGateManager, }, poseidon::{fq_array_poseidon, fq_array_poseidon_native, poseidon_sponge}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, - util::{ - gen_pkey, AppCircuit, AssignedValueCell, Challenges, Eth2ConfigPinning, IntoWitness, - ThreadBuilderBase, - }, + util::{gen_pkey, AppCircuit, Challenges, CommonGateManager, Eth2ConfigPinning, IntoWitness}, witness::{self, HashInput, HashInputChunk, SyncStepArgs}, }; use eth_types::{Field, Spec}; -use ff::PrimeField; -use group::UncompressedEncoding; use halo2_base::{ - gates::{range::RangeConfig, RangeChip, RangeInstructions, GateInstructions, circuit::CircuitBuilderStage}, + gates::{ + circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, range::RangeConfig, + GateInstructions, RangeChip, RangeInstructions, + }, halo2_proofs::{ circuit::{Layouter, Region, SimpleFloorPlanner, Value}, dev::MockProver, + halo2curves::bn256, plonk::{Circuit, Column, ConstraintSystem, Error, Instance, ProvingKey}, poly::{commitment::Params, kzg::commitment::ParamsKZG}, }, @@ -43,18 +42,25 @@ use halo2_base::{ }; use halo2_ecc::{ bigint::ProperCrtUint, - bls12_381::{bls_signature::{self, BlsSignatureChip}, pairing::PairingChip, Fp12Chip, Fp2Chip, FpChip, Fp2Point}, - ecc::{hash_to_curve::HashToCurveChip, EcPoint, EccChip}, + bls12_381::{ + bls_signature::{self, BlsSignatureChip}, + pairing::PairingChip, + Fp12Chip, Fp2Chip, Fp2Point, FpChip, + }, + ecc::{ + hash_to_curve::{ExpandMsgXmd, HashToCurveChip}, + EcPoint, EccChip, + }, fields::{fp12, fp2, vector::FieldVector, FieldChip, FieldExtConstructor}, }; +use halo2curves::bls12_381::{Fq, Fq12, Fr, G1Affine, G2Affine, G2Prepared, G1, G2}; use halo2curves::{ - bls12_381::{Fq, Fq12, Fr, G1Affine, G2Affine, G2Prepared, G1, G2}, - bn256::{self, Bn256}, + ff::PrimeField, + group::{GroupEncoding, UncompressedEncoding}, }; use itertools::Itertools; use lazy_static::__Deref; use num_bigint::BigUint; -use pasta_curves::group::{ff, GroupEncoding}; // use snark_verifier_sdk::{evm::gen_evm_verifier_shplonk, CircuitExt}; use ssz_rs::{Merkleized, Node}; @@ -67,8 +73,8 @@ pub struct SyncStepCircuit { impl SyncStepCircuit { fn synthesize( - thread_pool: &mut ShaThreadBuilder, - range: &RangeChip, + builder: &mut ShaCircuitBuilder>, + fp_chip: &FpChip, args: &witness::SyncStepArgs, ) -> Result>, Error> { assert!( @@ -76,16 +82,16 @@ impl SyncStepCircuit { "no attestations supplied" ); + let range = fp_chip.range(); let gate = range.gate(); let sha256_chip = Sha256Chip::new(range); - let fp_chip = FpChip::::new(range, G2::LIMB_BITS, G2::NUM_LIMBS); let fp2_chip = Fp2Chip::::new(&fp_chip); let g1_chip = EccChip::new(fp2_chip.fp_chip()); let g2_chip = EccChip::new(&fp2_chip); let fp12_chip = Fp12Chip::::new(fp2_chip.fp_chip()); let pairing_chip = PairingChip::new(&fp_chip); let bls_chip = BlsSignatureChip::new(&fp_chip, &pairing_chip); - let h2c_chip = HashToCurveChip::::new(&sha256_chip, &fp2_chip); + let h2c_chip = HashToCurveChip::new(&sha256_chip, &fp2_chip); let execution_payload_root: HashInputChunk> = args.execution_payload_root.clone().into_witness(); @@ -102,21 +108,21 @@ impl SyncStepCircuit { let mut assigned_affines = vec![]; let (agg_pubkey, participation_sum) = Self::aggregate_pubkeys( - thread_pool.main(), - &fp_chip, + builder.main(), + fp_chip, &pubkey_affines, &args.pariticipation_bits, &mut assigned_affines, ); let poseidon_commit = fq_array_poseidon( - thread_pool.main(), + builder.main(), range.gate(), assigned_affines.iter().map(|p| &p.x), )?; let fp12_one = { - use ff::Field; - fp12_chip.load_constant(thread_pool.main(), Fq12::one()) + use halo2curves::ff::Field; + fp12_chip.load_constant(builder.main(), Fq12::ONE) }; // Verify attestted header @@ -126,10 +132,10 @@ impl SyncStepCircuit { .state_root .as_ref() .iter() - .map(|v| thread_pool.main().load_witness(F::from(*v as u64))) + .map(|v| builder.main().load_witness(F::from(*v as u64))) .collect_vec(); let attested_header = ssz_merkleize_chunks( - thread_pool, + builder, &sha256_chip, [ attested_slot_bytes.clone(), @@ -139,22 +145,18 @@ impl SyncStepCircuit { args.attested_header.body_root.as_ref().into_witness(), ], )?; - let g1_neg = g1_chip.load_private_unchecked( - thread_pool.main(), - G1::generator_affine().neg().into_coordinates(), - ); let finalized_block_body_root = args .finalized_header .body_root .as_ref() .iter() - .map(|&b| thread_pool.main().load_witness(F::from(b as u64))) + .map(|&b| builder.main().load_witness(F::from(b as u64))) .collect_vec(); let finalized_slot_bytes: HashInputChunk<_> = args.finalized_header.slot.into_witness(); let finalized_header_root = ssz_merkleize_chunks( - thread_pool, + builder, &sha256_chip, [ finalized_slot_bytes.clone(), @@ -165,35 +167,26 @@ impl SyncStepCircuit { ], )?; - let signing_root = sha256_chip - .digest::<64>( - thread_pool, - HashInput::TwoToOne(attested_header.into(), args.domain.to_vec().into_witness()), - false, - )? - .output_bytes; - - let g1_neg = g1_chip.load_private_unchecked( - thread_pool.main(), - G1::generator_affine().neg().into_coordinates(), - ); + let signing_root = sha256_chip.digest::<64>( + builder, + HashInput::TwoToOne(attested_header.into(), args.domain.to_vec().into_witness()), + false, + )?; let signature = - Self::assign_signature(thread_pool.main(), &g2_chip, &args.signature_compressed); + Self::assign_signature(builder.main(), &g2_chip, &args.signature_compressed); - let msghash = h2c_chip.hash_to_curve::( - thread_pool, - &fp_chip, - signing_root.into(), + let msghash = h2c_chip.hash_to_curve::( + builder, + signing_root.into_iter().map(|av| QuantumCell::Existing(av)), + S::DST, )?; - let res = - bls_chip.verify_pairing(thread_pool.main(), signature, msghash, agg_pubkey, g1_neg); - fp12_chip.assert_equal(thread_pool.main(), res, fp12_one); + bls_chip.assert_valid_signature(builder.main(), signature, msghash, agg_pubkey); // verify finalized block header against current beacon state merkle proof verify_merkle_proof( - thread_pool, + builder, &sha256_chip, args.finality_branch .iter() @@ -205,7 +198,7 @@ impl SyncStepCircuit { // verify execution state root against finilized block body merkle proof verify_merkle_proof( - thread_pool, + builder, &sha256_chip, args.execution_payload_branch .iter() @@ -216,10 +209,9 @@ impl SyncStepCircuit { )?; // Public Input Commitment - let participation_sum_le = - to_bytes_le::<_, 8>(thread_pool.main(), gate, &participation_sum); + let participation_sum_le = to_bytes_le::<_, 8>(builder.main(), gate, &participation_sum); - let poseidon_commit_le = to_bytes_le::<_, 32>(thread_pool.main(), gate, &poseidon_commit); + let poseidon_commit_le = to_bytes_le::<_, 32>(builder.main(), gate, &poseidon_commit); // See "Onion hashing vs. Input concatenation" in https://github.com/ChainSafe/Spectre/issues/17#issuecomment-1740965182 let public_inputs_concat = itertools::chain![ @@ -239,18 +231,17 @@ impl SyncStepCircuit { .collect_vec(); let pi_hash_bytes = sha256_chip - .digest::<{ 8 * 3 + 32 * 3 }>( - thread_pool, - HashInputChunk::new(public_inputs_concat).into(), - false, - )? - .output_bytes; - let pi_commit = truncate_sha256_into_single_elem(thread_pool.main(), range, pi_hash_bytes); + .digest::<{ 8 * 3 + 32 * 3 }>(builder, public_inputs_concat, false)? + .try_into() + .unwrap(); + + let pi_commit = truncate_sha256_into_single_elem(builder.main(), range, pi_hash_bytes); Ok(vec![pi_commit]) } pub fn instance_commitment(args: &SyncStepArgs) -> bn256::Fr { + use sha2::Digest; const INPUT_SIZE: usize = 8 * 3 + 32 * 3; let mut input = [0; INPUT_SIZE]; @@ -296,7 +287,8 @@ impl SyncStepCircuit { }) .collect_vec(); let poseidon_commitment = - fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x), todo!()).unwrap(); + fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x), todo!()) + .unwrap(); let poseidon_commitment_le = poseidon_commitment.to_bytes_le(); input[88..].copy_from_slice(&poseidon_commitment_le); @@ -376,8 +368,8 @@ impl SyncStepCircuit { g2_chip: &G2Chip, bytes_compressed: &[u8], ) -> EcPoint> { - let sig_affine = G2Affine::from_bytes(&bytes_compressed.to_vec().try_into().unwrap()) - .expect("correct signature"); + let sig_affine = + G2Affine::from_bytes(&bytes_compressed.try_into().unwrap()).expect("correct signature"); g2_chip.load_private_unchecked(ctx, sig_affine.into_coordinates()) } @@ -395,8 +387,6 @@ impl SyncStepCircuit { let g1_chip = G1Chip::::new(fp_chip); - let pubkey_compressed_len = G1::BYTES_COMPRESSED; - let mut participation_bits = vec![]; assert_eq!(pubkey_affines.len(), S::SYNC_COMMITTEE_SIZE); @@ -412,7 +402,7 @@ impl SyncStepCircuit { // Square y coordinate let ysq = fp_chip.mul(ctx, assigned_pk.y.clone(), assigned_pk.y.clone()); // Calculate y^2 using the elliptic curve equation - let ysq_calc = calculate_ysquared::(ctx, fp_chip, assigned_pk.x.clone()); + let ysq_calc = calculate_ysquared::(ctx, fp_chip, assigned_pk.x.clone()); // Constrain witness y^2 to be equal to calculated y^2 fp_chip.assert_equal(ctx, ysq, ysq_calc); @@ -451,23 +441,23 @@ impl AppCircuit for SyncStepCircuit { args: &Self::Witness, k: u32, ) -> Result, Error> { - let mut builder = ShaCircuitBuilder::::from_stage(stage); + let mut builder = + ShaCircuitBuilder::>::from_stage(stage) + .use_k(k as usize); let range = builder.range_chip(8); + let fp_chip = FpChip::new(&range, 120, 4); - let assigned_instances = Self::synthesize(&mut builder, &range, args)?; + let assigned_instances = Self::synthesize(&mut builder, &fp_chip, args)?; match stage { CircuitBuilderStage::Prover => {} _ => { - builder.config( - k as usize, - Some( - var("MINIMUM_ROWS") - .unwrap_or_else(|_| "0".to_string()) - .parse() - .unwrap(), - ), - ); + builder.calculate_params(Some( + var("MINIMUM_ROWS") + .unwrap_or_else(|_| "0".to_string()) + .parse() + .unwrap(), + )); } } @@ -475,146 +465,139 @@ impl AppCircuit for SyncStepCircuit { } } -// #[cfg(test)] -// mod tests { -// use std::{ -// env::{set_var, var}, -// fs, -// os::unix::thread, -// }; - -// use crate::{ -// util::{full_prover, full_verifier, gen_pkey, Halo2ConfigPinning}, -// witness::SyncStepArgs, -// }; - -// use super::*; -// use ark_std::{end_timer, start_timer}; -// use eth_types::Testnet; -// use group::Group; -// use halo2_base::{ -// gates::{ -// builder::{CircuitBuilderStage, FlexGateConfigParams}, -// flex_gate::GateStrategy, -// range::RangeStrategy, -// }, -// utils::{decompose, fs::gen_srs}, -// }; -// use halo2_proofs::{ -// circuit::SimpleFloorPlanner, -// dev::MockProver, -// halo2curves::bn256::Fr, -// plonk::{keygen_pk, keygen_vk, Circuit, FloorPlanner}, -// poly::kzg::commitment::ParamsKZG, -// }; -// use halo2curves::{bls12_381::G1Affine, bn256::Bn256}; -// use pasta_curves::group::UncompressedEncoding; -// use rand::{rngs::OsRng, thread_rng}; -// use rayon::iter::ParallelIterator; -// use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; -// use snark_verifier_sdk::{ -// evm::{encode_calldata, evm_verify, gen_evm_proof_shplonk}, -// halo2::{aggregation::AggregationCircuit, gen_proof_shplonk, gen_snark_shplonk}, -// CircuitExt, SHPLONK, -// }; - -// fn load_circuit_args() -> SyncStepArgs { -// serde_json::from_slice(&fs::read("../test_data/sync_step_512.json").unwrap()).unwrap() -// } - -// #[test] -// fn test_sync_circuit() { -// const K: u32 = 21; -// let params = gen_srs(K); - -// let witness = load_circuit_args(); - -// let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - -// let circuit = SyncStepCircuit::::create_circuit( -// CircuitBuilderStage::Mock, -// Some(pinning), -// &witness, -// K, -// ) -// .unwrap(); - -// let sync_pi_commit = SyncStepCircuit::::instance_commitment(&witness); - -// let timer = start_timer!(|| "sync_step mock prover"); -// let prover = MockProver::::run(K, &circuit, vec![vec![sync_pi_commit]]).unwrap(); -// prover.assert_satisfied_par(); -// end_timer!(timer); -// } - -// #[test] -// fn test_sync_proofgen() { -// const K: u32 = 22; -// let params = gen_srs(K); - -// let pk = SyncStepCircuit::::read_or_create_pk( -// ¶ms, -// "../build/sync_step.pkey", -// "./config/sync_step.json", -// false, -// &SyncStepArgs::::default(), -// ); - -// let witness = load_circuit_args(); - -// let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - -// let circuit = SyncStepCircuit::::create_circuit( -// CircuitBuilderStage::Prover, -// Some(pinning), -// &witness, -// K, -// ) -// .unwrap(); - -// let instances = circuit.instances(); -// let proof = full_prover(¶ms, &pk, circuit, instances.clone()); - -// assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) -// } - -// #[test] -// fn test_sync_evm_verify() { -// const K: u32 = 22; -// let params = gen_srs(K); - -// let pk = SyncStepCircuit::::read_or_create_pk( -// ¶ms, -// "../build/sync_step.pkey", -// "./config/sync_step.json", -// false, -// &SyncStepArgs::::default(), -// ); - -// let witness = load_circuit_args(); - -// let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - -// let circuit = SyncStepCircuit::::create_circuit( -// CircuitBuilderStage::Prover, -// Some(pinning), -// &witness, -// K, -// ) -// .unwrap(); - -// let num_instances = circuit.num_instance(); -// let instances = circuit.instances(); -// let proof = gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); -// println!("proof size: {}", proof.len()); -// let deployment_code = SyncStepCircuit::::gen_evm_verifier_shplonk( -// ¶ms, -// &pk, -// None::, -// &witness, -// ) -// .unwrap(); -// println!("deployment_code size: {}", deployment_code.len()); -// evm_verify(deployment_code, instances, proof); -// } -// } +#[cfg(test)] +mod tests { + use std::{ + env::{set_var, var}, + fs, + os::unix::thread, + }; + + use crate::{ + util::{full_prover, full_verifier, gen_pkey, Halo2ConfigPinning}, + witness::SyncStepArgs, + }; + + use super::*; + use ark_std::{end_timer, start_timer}; + use eth_types::Testnet; + use halo2_base::{ + halo2_proofs::{ + circuit::SimpleFloorPlanner, + dev::MockProver, + halo2curves::bn256::Fr, + plonk::{keygen_pk, keygen_vk, Circuit, FloorPlanner}, + poly::kzg::commitment::ParamsKZG, + }, + utils::{decompose, fs::gen_srs}, + }; + use halo2curves::{bls12_381::G1Affine, bn256::Bn256}; + use rand::{rngs::OsRng, thread_rng}; + use rayon::iter::ParallelIterator; + use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; + use snark_verifier_sdk::{ + evm::{encode_calldata, evm_verify, gen_evm_proof_shplonk}, + halo2::{aggregation::AggregationCircuit, gen_proof_shplonk, gen_snark_shplonk}, + CircuitExt, SHPLONK, + }; + + fn load_circuit_args() -> SyncStepArgs { + serde_json::from_slice(&fs::read("../test_data/sync_step_512.json").unwrap()).unwrap() + } + + #[test] + fn test_sync_circuit() { + const K: u32 = 21; + let params = gen_srs(K); + + let witness = load_circuit_args(); + + let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + + let circuit = SyncStepCircuit::::create_circuit( + CircuitBuilderStage::Mock, + Some(pinning), + &witness, + K, + ) + .unwrap(); + + let sync_pi_commit = SyncStepCircuit::::instance_commitment(&witness); + + let timer = start_timer!(|| "sync_step mock prover"); + let prover = MockProver::::run(K, &circuit, vec![vec![sync_pi_commit]]).unwrap(); + prover.assert_satisfied_par(); + end_timer!(timer); + } + + #[test] + fn test_sync_proofgen() { + const K: u32 = 22; + let params = gen_srs(K); + + let pk = SyncStepCircuit::::read_or_create_pk( + ¶ms, + "../build/sync_step.pkey", + "./config/sync_step.json", + false, + &SyncStepArgs::::default(), + ); + + let witness = load_circuit_args(); + + let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + + let circuit = SyncStepCircuit::::create_circuit( + CircuitBuilderStage::Prover, + Some(pinning), + &witness, + K, + ) + .unwrap(); + + let instances = circuit.instances(); + let proof = full_prover(¶ms, &pk, circuit, instances.clone()); + + assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) + } + + #[test] + fn test_sync_evm_verify() { + const K: u32 = 22; + let params = gen_srs(K); + + let pk = SyncStepCircuit::::read_or_create_pk( + ¶ms, + "../build/sync_step.pkey", + "./config/sync_step.json", + false, + &SyncStepArgs::::default(), + ); + + let witness = load_circuit_args(); + + let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + + let circuit = SyncStepCircuit::::create_circuit( + CircuitBuilderStage::Prover, + Some(pinning), + &witness, + K, + ) + .unwrap(); + + let num_instances = circuit.num_instance(); + let instances = circuit.instances(); + let proof = gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); + println!("proof size: {}", proof.len()); + let deployment_code = SyncStepCircuit::::gen_evm_verifier_shplonk( + ¶ms, + &pk, + None::, + &witness, + ) + .unwrap(); + println!("deployment_code size: {}", deployment_code.len()); + evm_verify(deployment_code, instances, proof); + } +} diff --git a/lightclient-circuits/src/util.rs b/lightclient-circuits/src/util.rs index bc23397f..eb6fb021 100644 --- a/lightclient-circuits/src/util.rs +++ b/lightclient-circuits/src/util.rs @@ -111,7 +111,7 @@ pub mod to_bytes { let mut bytes = Vec::new(); for byte_bits in bits.chunks(8) { let mut value = 0.expr(); - let mut multiplier = F::one(); + let mut multiplier = F::ONE; for byte in byte_bits.iter() { value = value + byte.expr() * multiplier; multiplier *= F::from(2); diff --git a/lightclient-circuits/src/util/circuit.rs b/lightclient-circuits/src/util/circuit.rs index 1ac53371..4d127cea 100644 --- a/lightclient-circuits/src/util/circuit.rs +++ b/lightclient-circuits/src/util/circuit.rs @@ -11,6 +11,7 @@ use halo2_base::halo2_proofs::{ poly::commitment::Params, poly::kzg::commitment::ParamsKZG, }; +use halo2_base::utils::BigPrimeField; use serde::{Deserialize, Serialize}; use snark_verifier_sdk::evm::{ encode_calldata, evm_verify, gen_evm_proof, gen_evm_proof_shplonk, gen_evm_verifier_shplonk, @@ -78,7 +79,7 @@ impl Halo2ConfigPinning for Eth2ConfigPinning { } } -pub trait PinnableCircuit: CircuitExt { +pub trait PinnableCircuit: CircuitExt { type Pinning: Halo2ConfigPinning; fn break_points(&self) -> ::BreakPoints; @@ -262,10 +263,10 @@ pub fn write_calldata_generic>( calldata } -fn custom_read_pk(fname: P, _: &C) -> ProvingKey +fn custom_read_pk(fname: P, c: &C) -> ProvingKey where C: Circuit, P: AsRef, { - read_pk::(fname.as_ref()).expect("proving key should exist") + read_pk::(fname.as_ref(), c.params()).expect("proving key should exist") } diff --git a/lightclient-circuits/src/util/common.rs b/lightclient-circuits/src/util/common.rs index 2e0ed16f..0bedc338 100644 --- a/lightclient-circuits/src/util/common.rs +++ b/lightclient-circuits/src/util/common.rs @@ -12,7 +12,9 @@ use halo2_base::{ }, poly::Rotation, }, - virtual_region::manager::VirtualRegionManager, + virtual_region::{ + copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, + }, Context, }; @@ -117,23 +119,7 @@ impl CellType { } } -#[derive(Clone, Debug)] -pub struct AssignedValueCell { - pub cell: Halo2Cell, - pub value: F, -} - -impl AssignedValueCell { - pub fn cell(&self) -> Halo2Cell { - self.cell - } - - pub fn value(&self) -> F { - self.value - } -} - -pub trait ThreadBuilderConfigBase: Clone + Sized { +pub trait GateBuilderConfig: Clone + Sized { fn configure(meta: &mut ConstraintSystem) -> Self; fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error>; @@ -141,45 +127,49 @@ pub trait ThreadBuilderConfigBase: Clone + Sized { fn annotate_columns_in_region(&self, region: &mut Region); } -pub trait ThreadBuilderBase: VirtualRegionManager + Clone { - type CustomContext; +pub trait CommonGateManager: VirtualRegionManager + Clone { + type CustomContext<'a> + where + Self: 'a; - fn custom_context(&mut self) -> &mut Self::CustomContext; -} + fn new(witness_gen_only: bool) -> Self; -// pub trait ThreadBuilderBase: VirtualRegionManager + Clone + Sized { -// type Config: ThreadBuilderConfigBase; + fn custom_context(&mut self) -> Self::CustomContext<'_>; -// fn new(witness_gen_only: bool) -> Self; + /// Returns `self` with a given copy manager + fn use_copy_manager(self, copy_manager: SharedCopyConstraintManager) -> Self; -// fn from_stage(stage: CircuitBuilderStage) -> Self; + fn from_stage(stage: CircuitBuilderStage) -> Self { + Self::new(stage == CircuitBuilderStage::Prover) + .unknown(stage == CircuitBuilderStage::Keygen) + } -// fn mock() -> Self { -// Self::new(false) -// } + fn mock() -> Self { + Self::new(false) + } -// fn keygen() -> Self { -// Self::new(false).unknown(true) -// } + fn keygen() -> Self { + Self::new(false).unknown(true) + } -// fn prover() -> Self { -// Self::new(true) -// } + fn prover() -> Self { + Self::new(true) + } -// fn unknown(self, use_unknown: bool) -> Self; + fn unknown(self, use_unknown: bool) -> Self; -// /// Returns a mutable reference to the [Context] of a gate thread. Spawns a new thread for the given phase, if none exists. -// /// * `phase`: The challenge phase (as an index) of the gate thread. -// fn main(&mut self) -> &mut Context; + // /// Returns a mutable reference to the [Context] of a gate thread. Spawns a new thread for the given phase, if none exists. + // /// * `phase`: The challenge phase (as an index) of the gate thread. + // fn main(&mut self) -> &mut Context; -// fn witness_gen_only(&self) -> bool; + // fn witness_gen_only(&self) -> bool; -// /// Returns the `use_unknown` flag. -// fn use_unknown(&self) -> bool; + // /// Returns the `use_unknown` flag. + // fn use_unknown(&self) -> bool; -// /// Returns the current number of threads in the [GateThreadBuilder]. -// fn thread_count(&self) -> usize; + // /// Returns the current number of threads in the [GateThreadBuilder]. + // fn thread_count(&self) -> usize; -// /// Creates a new thread id by incrementing the `thread count` -// fn get_new_thread_id(&mut self) -> usize; -// } + // /// Creates a new thread id by incrementing the `thread count` + // fn get_new_thread_id(&mut self) -> usize; +} diff --git a/lightclient-circuits/src/util/proof.rs b/lightclient-circuits/src/util/proof.rs index 1d4b55da..bc47462f 100644 --- a/lightclient-circuits/src/util/proof.rs +++ b/lightclient-circuits/src/util/proof.rs @@ -29,12 +29,12 @@ pub use halo2_base::utils::fs::{gen_srs, read_or_create_srs, read_params}; /// If the provided `k` value is larger than the `k` value of the loaded parameters, an error is returned, as the provided `k` is too large. /// Otherwise, if the `k` value is smaller than the `k` value of the loaded parameters, the parameters are downsized to fit the requested `k`. #[allow(clippy::type_complexity)] -pub fn read_vkey>(path: &Path) -> Result, &'static str> { +pub fn read_vkey>(path: &Path, params: C::Params) -> Result, &'static str> { let timer = start_timer!(|| "Loading vkey"); let mut file = File::open(path).map_err(|_| "failed to read file")?; - let vk = VerifyingKey::::read::<_, C>(&mut file, RawBytesUnchecked) + let vk = VerifyingKey::::read::<_, C>(&mut file, RawBytesUnchecked, params) .map_err(|_| "failed to decode vkey"); end_timer!(timer); @@ -63,7 +63,7 @@ pub fn gen_pkey>( match File::open(&vkey_path) { Ok(mut file) => ( start_timer!(|| "Loading vkey"), - VerifyingKey::::read::<_, C>(&mut file, RawBytesUnchecked) + VerifyingKey::::read::<_, C>(&mut file, RawBytesUnchecked, circuit.params()) .expect("failed to read vkey"), ), Err(_) => { diff --git a/lightclient-circuits/src/witness/hashing.rs b/lightclient-circuits/src/witness/hashing.rs index 7cc51f50..f2f1b1fe 100644 --- a/lightclient-circuits/src/witness/hashing.rs +++ b/lightclient-circuits/src/witness/hashing.rs @@ -65,6 +65,16 @@ impl HashInput { } } +impl IntoIterator for HashInput> { + type Item = QuantumCell; + + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.to_vec().into_iter() + } +} + impl HashInput> { pub fn into_assigned(self, ctx: &mut Context) -> HashInput> { self.map(|cell| match cell { diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index 2dbc5e07..d88e2536 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -3,9 +3,11 @@ use eth_types::Minimal; use ethereum_consensus_types::presets::minimal::{LightClientBootstrap, LightClientUpdateCapella}; use ethereum_consensus_types::signing::{compute_domain, DomainType}; use ethereum_consensus_types::{ForkData, Root}; -use halo2_base::gates::builder::CircuitBuilderStage; -use halo2_proofs::dev::MockProver; -use halo2curves::bn256::{self, Fr}; +use halo2_base::gates::circuit::CircuitBuilderStage; +use halo2_base::halo2_proofs::{ + halo2curves::bn256::{self, Fr}, + dev::MockProver, +}; use itertools::Itertools; use light_client_verifier::ZiplineUpdateWitnessCapella; use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; @@ -527,110 +529,110 @@ fn test_eth2_spec_evm_verify( snark_verifier_sdk::evm::evm_verify(deployment_code, instances, proof); } -mod solidity_tests { - use super::*; - use ethers::{ - contract::abigen, - core::utils::{Anvil, AnvilInstance}, - middleware::SignerMiddleware, - providers::{Http, Provider}, - signers::{LocalWallet, Signer}, - }; - use halo2_base::safe_types::ScalarField; - use halo2curves::group::UncompressedEncoding; - use lightclient_circuits::poseidon::fq_array_poseidon_native; - use std::sync::Arc; - - /// Ensure that the instance encoding implemented in Solidity matches exactly the instance encoding expected by the circuit - #[rstest] - #[tokio::test] - async fn test_instance_commitment_evm_equivalence( - #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] - #[exclude("deneb*")] - path: PathBuf, - ) -> anyhow::Result<()> { - let (witness, _) = read_test_files_and_gen_witness(path); - let instance = SyncStepCircuit::::instance_commitment(&witness); - let poseidon_commitment_le = extract_poseidon_committee_commitment(&witness)?; - - let anvil_instance = Anvil::new().spawn(); - let ethclient: Arc, _>> = make_client(&anvil_instance); - let contract = SyncStepExternal::deploy(ethclient, ())?.send().await?; - - let result = contract - .to_input_commitment(SyncStepInput::from(witness), poseidon_commitment_le) - .call() - .await?; - let mut result_bytes = [0_u8; 32]; - result.to_little_endian(&mut result_bytes); - - assert_eq!(bn256::Fr::from_bytes(&result_bytes).unwrap(), instance); - Ok(()) - } - - abigen!( - SyncStepExternal, - "../contracts/out/SyncStepExternal.sol/SyncStepExternal.json" - ); - - // SyncStepInput type produced by abigen macro matches the solidity struct type - impl From> for SyncStepInput { - fn from(args: SyncStepArgs) -> Self { - let participation = args - .pariticipation_bits - .iter() - .map(|v| *v as u64) - .sum::(); - - let finalized_header_root: [u8; 32] = args - .finalized_header - .clone() - .hash_tree_root() - .unwrap() - .as_bytes() - .try_into() - .unwrap(); - - let execution_payload_root: [u8; 32] = args.execution_payload_root.try_into().unwrap(); - - SyncStepInput { - attested_slot: args.attested_header.slot, - finalized_slot: args.finalized_header.slot, - participation: participation, - finalized_header_root, - execution_payload_root, - } - } - } - - fn extract_poseidon_committee_commitment( - witness: &SyncStepArgs, - ) -> anyhow::Result<[u8; 32]> { - let pubkey_affines = witness - .pubkeys_uncompressed - .iter() - .cloned() - .map(|bytes| { - halo2curves::bls12_381::G1Affine::from_uncompressed_unchecked( - &bytes.as_slice().try_into().unwrap(), - ) - .unwrap() - }) - .collect_vec(); - let poseidon_commitment = - fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x)).unwrap(); - Ok(poseidon_commitment.to_bytes_le().try_into().unwrap()) - } - - /// Return a fresh ethereum chain+client to test against - fn make_client(anvil: &AnvilInstance) -> Arc, LocalWallet>> { - let provider = Provider::::try_from(anvil.endpoint()) - .unwrap() - .interval(std::time::Duration::from_millis(10u64)); - let wallet: LocalWallet = anvil.keys()[0].clone().into(); - - let client: SignerMiddleware, _> = - SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id())); - Arc::new(client) - } -} +// mod solidity_tests { +// use super::*; +// use ethers::{ +// contract::abigen, +// core::utils::{Anvil, AnvilInstance}, +// middleware::SignerMiddleware, +// providers::{Http, Provider}, +// signers::{LocalWallet, Signer}, +// }; +// use halo2_base::safe_types::ScalarField; +// use halo2curves::group::UncompressedEncoding; +// use lightclient_circuits::poseidon::fq_array_poseidon_native; +// use std::sync::Arc; + +// /// Ensure that the instance encoding implemented in Solidity matches exactly the instance encoding expected by the circuit +// #[rstest] +// #[tokio::test] +// async fn test_instance_commitment_evm_equivalence( +// #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] +// #[exclude("deneb*")] +// path: PathBuf, +// ) -> anyhow::Result<()> { +// let (witness, _) = read_test_files_and_gen_witness(path); +// let instance = SyncStepCircuit::::instance_commitment(&witness); +// let poseidon_commitment_le = extract_poseidon_committee_commitment(&witness)?; + +// let anvil_instance = Anvil::new().spawn(); +// let ethclient: Arc, _>> = make_client(&anvil_instance); +// let contract = SyncStepExternal::deploy(ethclient, ())?.send().await?; + +// let result = contract +// .to_input_commitment(SyncStepInput::from(witness), poseidon_commitment_le) +// .call() +// .await?; +// let mut result_bytes = [0_u8; 32]; +// result.to_little_endian(&mut result_bytes); + +// assert_eq!(bn256::Fr::from_bytes(&result_bytes).unwrap(), instance); +// Ok(()) +// } + +// abigen!( +// SyncStepExternal, +// "../contracts/out/SyncStepExternal.sol/SyncStepExternal.json" +// ); + +// // SyncStepInput type produced by abigen macro matches the solidity struct type +// impl From> for SyncStepInput { +// fn from(args: SyncStepArgs) -> Self { +// let participation = args +// .pariticipation_bits +// .iter() +// .map(|v| *v as u64) +// .sum::(); + +// let finalized_header_root: [u8; 32] = args +// .finalized_header +// .clone() +// .hash_tree_root() +// .unwrap() +// .as_bytes() +// .try_into() +// .unwrap(); + +// let execution_payload_root: [u8; 32] = args.execution_payload_root.try_into().unwrap(); + +// SyncStepInput { +// attested_slot: args.attested_header.slot, +// finalized_slot: args.finalized_header.slot, +// participation: participation, +// finalized_header_root, +// execution_payload_root, +// } +// } +// } + +// fn extract_poseidon_committee_commitment( +// witness: &SyncStepArgs, +// ) -> anyhow::Result<[u8; 32]> { +// let pubkey_affines = witness +// .pubkeys_uncompressed +// .iter() +// .cloned() +// .map(|bytes| { +// halo2curves::bls12_381::G1Affine::from_uncompressed_unchecked( +// &bytes.as_slice().try_into().unwrap(), +// ) +// .unwrap() +// }) +// .collect_vec(); +// let poseidon_commitment = +// fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x)).unwrap(); +// Ok(poseidon_commitment.to_bytes_le().try_into().unwrap()) +// } + +// /// Return a fresh ethereum chain+client to test against +// fn make_client(anvil: &AnvilInstance) -> Arc, LocalWallet>> { +// let provider = Provider::::try_from(anvil.endpoint()) +// .unwrap() +// .interval(std::time::Duration::from_millis(10u64)); +// let wallet: LocalWallet = anvil.keys()[0].clone().into(); + +// let client: SignerMiddleware, _> = +// SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id())); +// Arc::new(client) +// } +// } diff --git a/preprocessor/Cargo.toml b/preprocessor/Cargo.toml index fc545e42..bcd50355 100644 --- a/preprocessor/Cargo.toml +++ b/preprocessor/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] # ethereum ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "adf1a0b14cef90b9536f28ef89da1fab316465e1" } -halo2curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.1" } +halo2curves = { git = "https://github.com/axiom-crypto/halo2curves", version = "0.4.0"} sync-committee-prover = { git = "https://github.com/polytope-labs/sync-committee-rs", version = "0.1.0", features=["testnet"] } sync-committee-primitives = { git = "https://github.com/polytope-labs/sync-committee-rs", version = "0.1.0", features=["testnet"] } @@ -28,18 +28,11 @@ eth-types = { path = "../eth-types" } lightclient-circuits = { path = "../lightclient-circuits" } [dev-dependencies] -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02", features = [ - "dev-graph", -] } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false, features = [ - "halo2-axiom", - "display", -] } snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "community-edition", default-features = false, features = [ "display", "loader_halo2", "loader_evm", - "halo2-axiom", + "halo2-pse", ] } ark-std = { version = "0.4.0", features = ["print-trace"] } # sync-committee-verifier = { git = "https://github.com/polytope-labs/sync-committee-rs", version = "0.1.0", features=["testnet"] } diff --git a/preprocessor/src/lib.rs b/preprocessor/src/lib.rs index 2d38face..998835c2 100644 --- a/preprocessor/src/lib.rs +++ b/preprocessor/src/lib.rs @@ -1,4 +1,6 @@ mod sync; pub use sync::*; -mod rotation; -pub use rotation::*; +// mod rotation; +// pub use rotation::*; + +pub(crate) use lightclient_circuits::halo2_base; diff --git a/preprocessor/src/rotation.rs b/preprocessor/src/rotation.rs index f68518c4..bc8d52cc 100644 --- a/preprocessor/src/rotation.rs +++ b/preprocessor/src/rotation.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; +use crate::halo2_base::halo2_proofs::halo2curves::bn256::Fr; use eth_types::Spec; -use halo2curves::bn256::Fr; use itertools::Itertools; use lightclient_circuits::{gadget::crypto, witness::CommitteeRotationArgs}; use ssz_rs::Merkleized; @@ -96,12 +96,11 @@ pub async fn read_rotation_args( #[cfg(test)] mod tests { use eth_types::Testnet; - use halo2_base::gates::builder::CircuitBuilderStage; - use halo2_proofs::dev::MockProver; + use crate::halo2_base::halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use halo2curves::bn256::Fr; use lightclient_circuits::{ committee_update_circuit::CommitteeUpdateCircuit, - util::{gen_srs, AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, + util::{gen_srs, AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, halo2_base::gates::circuit::CircuitBuilderStage, }; use snark_verifier_sdk::CircuitExt; diff --git a/preprocessor/src/sync.rs b/preprocessor/src/sync.rs index 6906cbd5..ff5c201f 100644 --- a/preprocessor/src/sync.rs +++ b/preprocessor/src/sync.rs @@ -59,7 +59,7 @@ pub async fn fetch_step_args(node_url: String) -> eyre::Result(path: String) -> eyre::Result Date: Tue, 31 Oct 2023 12:46:17 +0100 Subject: [PATCH 03/23] fix step circuit --- .../src/committee_update_circuit.rs | 7 ++- .../src/gadget/crypto/builder.rs | 25 +++++++++- lightclient-circuits/src/sync_step_circuit.rs | 15 +++--- lightclient-circuits/tests/step.rs | 2 +- preprocessor/scripts/util.ts | 50 ++++++++++--------- test_data/rotation_512.json | 2 +- test_data/sync_step_512.json | 2 +- 7 files changed, 66 insertions(+), 37 deletions(-) diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 3d43b331..c63ed716 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -216,14 +216,17 @@ impl AppCircuit for CommitteeUpdateCircuit { ) -> Result, Error> { let mut builder = ShaCircuitBuilder::>::from_stage(stage) - .use_k(k as usize); + .use_k(k as usize) + .use_instance_columns(1); let range = builder.range_chip(8); let fp_chip = FpChip::new(&range, 120, 4); let assigned_instances = Self::synthesize(&mut builder, &fp_chip, witness)?; match stage { - CircuitBuilderStage::Prover => {} + CircuitBuilderStage::Prover => { + builder.set_instances(0, assigned_instances); + } _ => { builder.calculate_params(Some( var("MINIMUM_ROWS") diff --git a/lightclient-circuits/src/gadget/crypto/builder.rs b/lightclient-circuits/src/gadget/crypto/builder.rs index 2d0bcbd0..8aded728 100644 --- a/lightclient-circuits/src/gadget/crypto/builder.rs +++ b/lightclient-circuits/src/gadget/crypto/builder.rs @@ -19,7 +19,7 @@ use halo2_base::{ }, utils::BigPrimeField, virtual_region::manager::VirtualRegionManager, - Context, + Context, AssignedValue, }; use itertools::Itertools; use snark_verifier_sdk::CircuitExt; @@ -106,6 +106,27 @@ impl> ShaCircuitBuilder Self { + self.set_instance_columns(num_instance_columns); + self + } + + pub fn set_instances(&mut self, column: usize, assigned_instances: Vec>) { + self.base.assigned_instances[column] = assigned_instances; + } + + /// Returns new with `self.assigned_instances` resized to specified number of instance columns. + pub fn use_instances(mut self, column: usize, assigned_instances: Vec>) -> Self { + self.set_instances(column, assigned_instances); + self + } + /// Sets new `k` = log2 of domain pub fn set_k(&mut self, k: usize) { self.base.set_k(k); @@ -240,7 +261,7 @@ where self.base .assigned_instances .iter() - .map(|v| v.into_iter().map(|av| *av.value()).collect_vec()) + .map(|v| v.iter().map(|av| *av.value()).collect_vec()) .collect() } } diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 3e4ac765..6ddd3fc6 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -240,7 +240,7 @@ impl SyncStepCircuit { Ok(vec![pi_commit]) } - pub fn instance_commitment(args: &SyncStepArgs) -> bn256::Fr { + pub fn instance_commitment(args: &SyncStepArgs, limb_bits: usize) -> bn256::Fr { use sha2::Digest; const INPUT_SIZE: usize = 8 * 3 + 32 * 3; let mut input = [0; INPUT_SIZE]; @@ -287,7 +287,7 @@ impl SyncStepCircuit { }) .collect_vec(); let poseidon_commitment = - fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x), todo!()) + fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x), limb_bits) .unwrap(); let poseidon_commitment_le = poseidon_commitment.to_bytes_le(); input[88..].copy_from_slice(&poseidon_commitment_le); @@ -443,14 +443,17 @@ impl AppCircuit for SyncStepCircuit { ) -> Result, Error> { let mut builder = ShaCircuitBuilder::>::from_stage(stage) - .use_k(k as usize); + .use_k(k as usize) + .use_instance_columns(1); let range = builder.range_chip(8); - let fp_chip = FpChip::new(&range, 120, 4); + let fp_chip = FpChip::new(&range, 112, 4); let assigned_instances = Self::synthesize(&mut builder, &fp_chip, args)?; match stage { - CircuitBuilderStage::Prover => {} + CircuitBuilderStage::Prover => { + builder.set_instances(0, assigned_instances); + } _ => { builder.calculate_params(Some( var("MINIMUM_ROWS") @@ -522,7 +525,7 @@ mod tests { ) .unwrap(); - let sync_pi_commit = SyncStepCircuit::::instance_commitment(&witness); + let sync_pi_commit = SyncStepCircuit::::instance_commitment(&witness, 112); let timer = start_timer!(|| "sync_step mock prover"); let prover = MockProver::::run(K, &circuit, vec![vec![sync_pi_commit]]).unwrap(); diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index d88e2536..f574957d 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -442,7 +442,7 @@ fn run_test_eth2_spec_mock(path: PathB .unwrap() }; - let sync_pi_commit = SyncStepCircuit::::instance_commitment(&sync_witness); + let sync_pi_commit = SyncStepCircuit::::instance_commitment(&sync_witness, todo!()); let timer = start_timer!(|| "sync_step mock prover run"); let prover = diff --git a/preprocessor/scripts/util.ts b/preprocessor/scripts/util.ts index d4a820e8..0813071d 100644 --- a/preprocessor/scripts/util.ts +++ b/preprocessor/scripts/util.ts @@ -177,36 +177,38 @@ export function sortInOrderBitstrings(gindices: GindexBitstring[], bitLength: nu } export function g1PointToLeBytes(p: ProjPointType, compressed: boolean): Uint8Array { - let bytes = p.toRawBytes(compressed); - bytes.reverse(); - var bytesLe = new Uint8Array(compressed ? 48 : 96); - if (compressed) { - bytesLe = bytes; - } else { - bytesLe.set(bytes.slice(0, 48), 48); - bytesLe.set(bytes.slice(48, 96), 0); - } + return p.toRawBytes(compressed); + // let bytes = p.toRawBytes(compressed); + // bytes.reverse(); + // var bytesLe = new Uint8Array(compressed ? 48 : 96); + // if (compressed) { + // bytesLe = bytes; + // } else { + // bytesLe.set(bytes.slice(0, 48), 48); + // bytesLe.set(bytes.slice(48, 96), 0); + // } - return bytesLe; + // return bytesLe; } export type Fp2 = { c0: bigint; c1: bigint }; export function g2PointToLeBytes(p: ProjPointType, compressed: boolean): Uint8Array { - let bytes = p.toRawBytes(compressed); - bytes.reverse(); - var bytesLe = new Uint8Array(compressed ? 96 : 192); - if (compressed) { - // bytesLe.set(bytes.slice(0, 48), 48); - // bytesLe.set(bytes.slice(48, 96), 0); - bytesLe = bytes; - } else { - bytesLe.set(bytes.slice(0, 48), 144); - bytesLe.set(bytes.slice(48, 96), 96); - bytesLe.set(bytes.slice(96, 144), 48); - bytesLe.set(bytes.slice(144, 192), 0); - } + return p.toRawBytes(compressed); + // let bytes = p.toRawBytes(compressed); + // bytes.reverse(); + // var bytesLe = new Uint8Array(compressed ? 96 : 192); + // if (compressed) { + // // bytesLe.set(bytes.slice(0, 48), 48); + // // bytesLe.set(bytes.slice(48, 96), 0); + // bytesLe = bytes; + // } else { + // bytesLe.set(bytes.slice(0, 48), 144); + // bytesLe.set(bytes.slice(48, 96), 96); + // bytesLe.set(bytes.slice(96, 144), 48); + // bytesLe.set(bytes.slice(144, 192), 0); + // } - return bytesLe; + // return bytesLe; } diff --git a/test_data/rotation_512.json b/test_data/rotation_512.json index caea465a..c7a42f0c 100644 --- a/test_data/rotation_512.json +++ b/test_data/rotation_512.json @@ -1 +1 @@ -{"finalized_header":{"slot":"32","proposer_index":"0","parent_root":"0x0000000000000000000000000000000000000000000000000000000000000000","state_root":"0xe68b17f8e98f4b3b94aba19c39b19c672fd2a17652ee4e8648ceb8881b70c399","body_root":"0xcfc05f337393c3a62425aa3a1fb3b7113c5da404d6a7f89edd41bfb5e14a5e92"},"committee_root_branch":[[86,129,244,105,55,145,204,110,41,118,238,89,5,110,185,150,189,45,149,248,58,234,168,240,52,197,56,179,60,156,28,146],[101,159,210,75,34,250,69,36,206,94,165,251,220,48,127,45,10,229,35,237,214,252,174,87,106,220,136,159,124,237,45,207],[154,62,126,57,57,157,54,12,199,230,118,173,17,119,81,116,195,56,129,94,43,82,59,142,203,254,56,248,190,65,195,7],[110,211,142,94,6,128,7,99,93,122,179,185,34,100,118,177,122,81,82,200,22,17,180,0,237,192,18,14,240,147,108,131],[155,36,233,182,3,218,183,52,31,229,11,170,186,135,40,250,236,16,108,30,173,17,32,146,190,16,108,215,239,76,73,95],[253,111,231,138,179,250,203,151,251,234,163,160,110,138,90,87,8,77,145,188,106,199,46,50,165,228,189,28,154,12,26,169]],"pubkeys_compressed":[[245,241,81,229,47,30,138,91,9,228,198,240,178,95,177,52,99,212,66,112,159,33,168,79,152,220,183,106,121,83,170,82,37,193,46,77,213,36,169,95,155,232,223,223,160,98,28,130],[8,222,219,53,149,240,234,115,131,225,1,231,113,165,54,70,71,139,127,73,101,162,160,171,150,20,87,5,41,131,40,49,74,20,157,1,136,30,205,172,78,194,146,210,69,167,202,134],[192,86,238,207,62,64,21,118,136,174,125,174,174,219,186,172,27,42,223,103,247,201,201,197,85,224,165,11,123,19,26,41,139,15,5,90,106,23,123,249,127,205,54,172,66,136,254,152],[18,72,135,107,133,99,179,171,126,20,141,239,51,111,236,157,28,141,123,206,165,148,198,21,226,239,214,6,173,159,68,98,71,16,10,19,56,8,52,50,45,22,111,17,159,70,250,168],[162,154,132,214,70,167,209,231,90,35,156,21,205,83,27,185,213,37,124,107,78,21,99,207,42,65,155,152,236,8,34,123,182,230,5,204,243,127,7,200,137,60,1,41,227,110,102,145],[87,207,218,247,29,124,175,174,113,107,105,179,150,124,28,113,14,76,86,84,147,4,225,88,187,179,129,46,141,68,22,132,166,124,198,4,238,234,51,38,32,157,204,238,191,99,71,128],[82,86,63,36,217,202,50,146,218,52,177,158,176,34,4,37,116,158,219,100,128,70,41,198,145,54,28,30,150,50,69,86,231,39,221,199,241,129,252,246,85,65,111,245,26,155,113,167],[238,112,71,182,174,164,77,101,234,245,172,34,228,172,230,225,15,29,197,197,6,211,152,127,213,57,150,218,95,69,185,94,72,123,29,241,10,33,191,71,244,59,113,57,160,105,64,181],[178,243,83,234,179,46,225,215,96,190,234,118,246,12,68,56,101,197,28,119,30,209,83,87,175,108,39,8,47,109,250,110,203,25,88,111,157,45,60,9,37,193,70,197,32,94,6,149],[225,155,253,88,194,98,129,13,30,246,100,101,220,131,198,25,61,237,227,11,224,152,167,98,78,165,124,144,188,43,252,193,147,65,1,51,49,239,124,110,37,114,87,2,80,24,190,170],[168,135,178,1,104,184,1,99,25,134,238,3,219,89,154,255,90,61,38,206,7,67,120,211,23,214,46,11,81,40,126,131,254,126,114,156,246,125,143,176,242,100,106,103,235,243,227,171],[12,216,153,162,127,196,36,165,71,96,109,153,17,157,14,235,21,147,35,247,120,114,237,137,249,141,245,17,30,193,189,119,251,207,67,236,121,56,192,10,128,190,95,225,213,206,116,138],[246,30,57,239,188,200,223,241,34,33,28,226,5,174,210,6,221,34,157,205,143,41,19,197,61,122,84,109,76,4,40,94,170,165,230,27,73,150,183,231,18,4,222,17,37,71,45,143],[58,66,169,60,18,247,11,189,107,192,36,165,175,223,84,206,165,70,151,74,143,39,164,145,43,152,6,232,38,149,115,22,164,83,248,199,75,98,79,250,99,174,35,33,187,125,136,168],[142,35,59,46,82,209,193,200,96,127,156,40,215,137,143,154,67,204,72,238,140,109,65,62,25,146,52,57,67,114,144,5,108,238,163,83,118,86,145,40,18,208,201,15,48,78,172,153],[182,76,71,221,10,120,106,141,204,197,240,189,156,187,68,236,213,226,11,87,210,149,102,142,50,31,122,126,115,50,86,3,26,183,183,48,138,161,90,114,217,179,183,221,184,49,255,140],[137,138,120,52,80,223,24,209,19,160,50,135,131,68,221,118,177,175,49,127,70,191,68,100,14,243,30,141,220,81,7,245,166,115,140,76,127,53,30,176,147,218,2,124,22,231,35,171],[91,202,141,223,171,75,240,247,167,105,245,1,162,244,135,221,119,155,133,201,79,142,3,63,245,60,152,151,215,17,177,46,77,2,205,231,139,204,223,95,62,97,72,115,154,19,121,175],[201,58,199,110,106,180,50,111,177,144,163,81,231,183,237,216,123,84,72,53,130,137,147,25,50,227,209,223,226,112,108,229,237,194,142,76,255,204,0,163,189,72,243,34,77,60,215,131],[24,29,157,223,12,89,110,140,99,27,36,222,247,88,7,240,241,167,76,185,203,135,105,159,132,119,8,3,210,189,197,95,240,175,237,241,242,28,110,89,16,49,95,255,117,2,72,171],[244,124,226,76,221,142,61,53,43,60,26,112,250,16,105,89,168,10,240,19,89,130,159,182,200,174,215,231,153,233,173,18,12,65,57,202,1,213,23,103,122,57,116,130,214,68,99,163],[58,243,203,92,56,208,139,22,48,228,97,207,17,246,239,137,50,221,19,106,181,102,226,84,85,2,170,61,60,1,201,229,147,86,137,87,121,113,43,69,139,33,49,167,14,42,205,145],[133,173,102,155,39,237,32,70,71,83,221,124,229,8,230,17,187,70,44,202,139,20,226,147,17,60,183,203,247,186,19,93,252,132,137,38,233,33,60,84,168,156,15,137,199,90,204,152],[198,47,83,19,224,43,18,220,129,12,114,50,47,178,118,193,237,181,249,140,113,33,159,238,117,74,212,117,135,228,210,253,103,218,86,77,22,37,140,178,33,10,135,172,17,89,222,146],[77,221,202,37,130,188,128,160,214,16,26,226,166,116,170,190,169,132,73,129,173,102,24,141,102,95,246,76,106,35,243,56,82,208,57,140,139,201,162,173,146,240,219,55,133,154,191,136],[183,61,63,70,118,65,163,220,169,216,10,232,180,9,10,118,156,31,43,225,137,67,125,177,79,103,119,223,172,183,47,7,149,97,120,73,81,119,22,195,175,162,72,117,117,92,219,160],[141,101,19,41,119,39,5,223,238,60,19,94,6,27,137,171,236,228,14,146,208,154,63,92,72,94,90,26,5,31,150,201,68,205,107,5,255,18,198,170,106,227,235,239,179,57,133,181],[170,212,32,140,29,67,176,155,199,37,127,93,1,73,164,119,254,164,109,181,166,219,233,148,42,212,87,184,0,146,81,195,110,166,136,230,2,1,163,32,39,231,231,183,230,189,63,138],[169,128,3,54,175,183,160,197,120,1,168,181,223,166,5,48,0,50,106,38,239,92,255,84,22,206,158,82,102,70,36,113,40,223,179,206,197,103,162,66,145,230,101,85,74,133,85,137],[46,169,218,149,131,147,89,213,196,98,214,84,145,81,255,32,95,175,37,19,12,204,99,126,235,115,174,199,239,41,101,168,142,12,42,170,223,202,225,135,218,152,135,198,141,214,34,149],[103,3,222,238,88,158,181,138,56,34,34,205,77,130,92,243,172,162,236,111,200,38,32,229,232,49,185,241,45,167,254,138,102,128,194,237,185,52,219,17,124,107,81,187,242,189,8,176],[58,130,151,168,254,195,61,86,71,107,61,227,225,33,86,99,61,152,186,73,229,252,34,221,33,128,95,253,119,90,197,27,176,103,187,23,110,222,135,27,191,51,244,250,162,134,143,176],[1,9,112,120,119,93,15,143,144,94,129,212,18,46,170,91,57,236,161,55,44,248,234,223,114,69,219,118,7,158,47,97,65,198,141,110,126,194,16,54,148,104,234,3,187,156,190,178],[30,20,60,203,234,250,64,185,239,253,106,150,66,13,151,169,158,93,151,9,165,106,158,101,85,111,154,158,152,4,17,177,43,175,221,174,19,17,132,105,83,107,173,152,152,140,73,132],[142,188,211,138,96,251,209,54,171,171,110,181,147,104,57,180,151,0,253,156,55,163,106,184,242,59,83,124,54,231,133,50,77,49,210,184,47,100,135,45,215,48,216,34,148,8,63,132],[229,96,237,160,95,194,59,34,142,111,196,141,176,58,254,28,149,136,8,152,106,78,113,103,157,110,20,186,26,240,41,21,220,149,117,185,233,220,37,56,129,194,201,95,188,206,250,152],[188,171,89,151,203,193,26,33,16,6,19,106,34,71,177,84,119,95,127,106,48,73,218,192,125,229,169,32,124,173,62,107,150,59,178,16,247,158,188,101,166,215,121,126,216,126,32,184],[229,30,244,90,216,24,179,86,183,223,30,154,43,102,241,106,183,101,253,93,143,78,136,51,198,11,212,60,203,139,200,4,158,101,23,227,149,167,205,36,159,82,213,202,130,177,143,131],[251,13,229,251,182,137,108,26,144,40,136,216,107,113,255,40,66,59,5,70,120,175,234,193,177,93,136,0,49,229,38,71,20,105,205,132,204,107,175,92,164,74,166,84,87,118,224,174],[20,32,209,181,25,139,231,159,26,78,79,232,231,170,132,11,219,214,1,100,237,26,46,42,165,121,7,195,3,76,168,94,217,14,93,203,156,63,199,114,63,174,120,11,215,18,122,174],[43,21,154,132,45,163,153,180,7,119,181,227,80,17,81,151,174,31,95,157,104,186,255,232,188,46,108,187,79,0,163,85,238,180,146,17,141,81,124,241,33,168,112,111,174,89,137,179],[178,116,219,167,249,31,253,107,125,87,172,79,243,207,93,175,53,183,76,177,170,63,75,24,29,53,193,24,225,220,159,4,153,159,186,100,250,18,114,129,107,129,220,255,252,140,75,174],[133,104,172,220,246,17,202,91,28,27,20,47,142,100,156,191,42,170,18,177,176,147,181,91,251,97,181,125,251,223,1,73,9,202,24,91,125,174,213,209,197,252,227,208,199,197,157,151],[118,47,163,72,217,163,186,67,72,4,127,8,52,86,130,134,169,110,62,25,152,178,199,249,253,23,95,102,98,100,239,156,132,123,28,39,183,13,100,29,82,68,19,59,249,22,227,132],[237,251,142,235,116,194,193,166,203,51,171,35,5,137,128,99,17,171,135,48,46,197,23,21,216,236,221,201,50,121,36,157,75,143,59,6,142,28,148,101,186,196,143,77,18,90,249,142],[13,225,119,45,52,45,40,247,191,109,158,128,86,147,9,250,232,236,34,54,43,198,165,17,51,225,149,67,108,181,214,6,196,14,211,170,81,59,85,208,29,14,246,92,134,249,48,153],[175,58,162,143,12,142,168,19,205,231,183,86,211,3,56,229,122,207,90,60,156,178,154,137,10,195,69,252,229,31,205,92,119,78,123,50,22,9,253,184,244,120,78,202,13,210,170,173],[174,56,128,0,13,246,82,243,45,18,89,246,47,243,103,13,183,146,110,169,55,127,82,96,35,66,129,69,233,191,184,70,13,41,217,99,238,73,228,131,50,26,211,218,19,19,209,140],[194,35,77,99,188,157,130,83,243,206,151,194,107,96,115,202,242,53,231,222,85,60,245,111,137,109,178,78,51,224,23,150,194,177,82,7,57,251,138,85,15,165,53,115,85,78,20,162],[209,121,169,46,112,31,107,199,75,96,95,214,163,0,183,10,168,194,165,46,195,49,25,91,33,143,154,102,35,60,64,242,196,199,250,215,248,222,177,21,69,42,210,73,136,129,107,165],[133,48,198,224,79,198,187,16,57,197,216,237,186,65,199,104,220,32,231,201,12,7,161,21,240,194,148,67,201,69,158,237,105,17,16,229,5,24,187,70,239,20,66,238,180,208,230,153],[48,10,5,172,15,124,185,182,86,228,152,89,0,27,189,188,166,195,193,108,92,22,45,116,203,153,10,208,212,63,96,174,20,72,118,47,230,128,32,121,102,8,13,212,42,68,228,148],[116,148,183,64,167,230,245,2,201,75,192,123,222,84,190,122,91,80,211,210,110,134,205,13,59,123,63,179,105,44,151,90,133,8,108,71,175,129,117,229,166,22,162,188,72,111,140,137],[9,21,211,194,80,171,223,241,143,117,111,141,245,172,111,116,252,188,94,143,151,20,222,171,120,64,42,100,179,65,87,138,207,70,189,111,41,51,18,238,4,177,105,185,8,206,209,141],[162,176,183,37,205,74,126,252,41,232,192,36,83,250,142,207,211,11,58,90,71,252,168,70,29,229,104,45,169,84,26,55,49,6,8,100,21,192,160,241,39,19,140,191,194,78,94,146],[191,215,10,212,223,13,93,109,106,226,44,97,37,130,196,253,24,34,134,88,36,26,75,61,127,198,136,79,108,104,52,117,87,164,13,220,185,76,238,171,187,57,235,24,82,145,81,166],[18,213,40,117,22,184,21,6,198,96,223,32,161,87,151,234,21,69,194,255,146,30,69,93,225,91,42,107,31,16,16,246,235,183,145,231,177,207,90,232,217,216,55,56,197,77,93,167],[22,86,146,80,27,252,86,203,234,129,59,208,130,161,231,56,124,110,183,97,195,185,210,156,217,213,227,197,79,68,49,53,231,158,107,75,245,248,21,225,152,163,54,119,39,160,95,132],[182,35,43,163,42,1,34,239,109,7,56,229,237,17,127,115,97,171,229,121,86,235,22,3,74,54,70,56,117,52,12,187,20,147,116,179,81,237,167,123,72,167,254,5,138,107,79,173],[83,227,83,33,199,93,51,179,31,121,3,113,181,163,188,127,185,119,58,58,91,66,66,253,4,76,212,249,216,174,44,165,82,124,178,160,211,29,227,131,99,135,161,93,243,59,164,150],[84,180,33,234,135,146,139,107,172,93,186,192,156,248,204,15,127,102,244,180,131,5,1,235,134,112,157,139,203,218,216,84,205,129,244,89,70,133,116,99,214,199,182,75,96,230,153,172],[190,135,74,28,44,50,43,183,171,222,152,174,158,224,235,101,34,155,196,87,16,7,194,104,133,38,204,242,21,99,87,238,3,105,241,80,28,123,153,130,101,82,210,209,243,135,55,171],[158,252,216,6,217,53,85,60,208,251,45,128,114,37,246,146,248,3,27,43,58,53,225,219,225,250,9,217,194,29,71,209,40,201,255,88,75,42,233,243,228,205,149,123,245,172,242,132],[41,121,181,146,126,39,71,72,183,19,143,159,3,107,236,8,22,81,67,65,251,54,241,143,158,148,188,53,243,203,205,80,179,161,75,209,166,97,67,196,85,187,211,52,208,7,17,163],[74,239,132,54,106,157,70,121,50,58,251,200,90,239,91,112,162,14,93,153,205,226,59,95,159,173,221,22,18,39,164,17,5,190,81,245,199,87,2,88,52,169,106,177,231,157,149,169],[201,104,40,16,110,133,95,184,8,196,182,80,176,130,229,1,250,110,76,236,116,95,93,27,77,242,120,83,44,6,17,149,88,254,193,157,44,108,86,64,133,175,204,182,201,254,209,178],[7,9,60,140,78,213,116,55,215,167,186,103,204,12,40,220,243,77,116,111,133,12,90,193,149,57,128,180,139,191,237,190,183,221,218,118,183,124,63,91,201,220,107,71,185,178,18,140],[182,196,203,136,69,251,12,124,147,87,249,59,157,31,236,204,76,99,24,108,179,213,142,203,151,253,138,29,254,127,22,159,41,153,176,115,218,69,215,74,27,55,55,153,148,43,54,183],[114,191,44,56,174,230,134,2,103,110,238,142,135,168,76,239,98,209,247,54,121,88,24,212,65,30,64,51,126,24,112,162,139,244,89,152,37,161,109,198,53,149,133,63,78,41,163,140],[181,197,6,94,165,45,248,61,129,214,218,171,150,233,50,174,222,73,250,50,163,74,88,28,12,162,159,191,183,119,202,139,246,157,106,232,153,150,86,213,90,198,172,84,146,240,237,161],[34,219,228,211,109,16,81,244,156,50,108,219,45,248,115,169,2,177,65,215,28,156,200,108,231,206,235,85,19,231,54,255,85,68,66,23,143,69,95,216,218,84,186,50,239,1,176,161],[50,253,224,80,245,61,66,39,220,35,135,225,105,182,144,144,87,130,223,185,181,167,185,192,32,93,225,96,35,0,137,160,39,188,204,197,21,209,159,180,38,119,49,215,4,183,80,161],[114,10,207,242,13,131,195,155,150,62,103,141,127,67,130,251,167,51,246,88,225,92,157,207,126,106,60,211,126,226,62,230,79,48,16,176,208,63,113,76,235,247,52,195,37,21,82,173],[185,162,220,29,220,237,206,170,83,176,123,96,118,138,6,245,9,178,200,154,49,88,2,20,45,40,189,205,24,47,185,26,183,42,55,105,47,85,54,133,65,71,67,62,219,64,86,151],[174,132,177,147,100,4,24,24,160,112,118,28,163,62,239,166,106,214,106,193,172,139,44,128,58,33,6,112,119,249,42,135,38,28,113,46,244,152,114,177,103,66,101,166,233,101,135,177],[6,170,26,244,24,183,251,227,153,234,78,61,184,170,227,157,195,169,181,208,164,189,215,88,160,168,82,11,131,132,200,27,26,51,175,37,38,9,144,81,191,50,180,87,45,149,88,174],[115,53,247,160,118,156,62,83,230,55,79,4,112,0,134,175,51,206,197,24,118,26,184,91,98,129,204,55,195,228,117,98,173,251,246,107,247,16,172,185,247,185,248,254,49,72,75,183],[91,54,103,235,4,32,68,180,128,198,8,197,147,255,236,231,109,73,190,45,241,236,196,169,144,142,197,28,210,110,38,245,37,163,232,74,85,72,166,72,255,12,147,134,222,72,92,173],[56,135,173,253,154,196,115,31,92,107,68,174,186,192,127,40,182,185,176,131,9,36,223,223,236,220,89,171,50,157,225,196,120,72,215,92,107,47,176,212,181,121,144,129,149,53,135,145],[113,94,202,217,207,207,205,27,11,214,24,110,66,99,139,10,54,89,252,9,214,130,84,164,226,146,187,193,237,169,150,177,217,206,192,22,232,122,101,47,98,191,15,36,87,154,74,178],[65,243,170,224,192,178,80,41,57,17,188,132,210,207,139,233,1,149,118,177,40,197,229,230,159,148,29,19,92,222,47,108,104,181,33,92,132,5,88,245,10,234,76,165,54,190,74,162],[44,165,9,9,104,177,141,120,191,113,137,242,170,95,103,93,154,104,213,242,147,174,105,117,182,7,66,164,173,222,138,171,144,203,241,179,226,210,100,254,199,146,1,165,167,231,203,173],[42,60,8,137,247,13,172,77,179,52,214,140,79,126,255,59,176,3,108,113,197,90,143,183,128,163,70,231,100,162,47,28,47,114,47,254,24,192,15,104,21,183,44,167,129,85,114,162],[213,69,139,87,238,134,139,152,174,98,209,132,155,73,122,253,127,163,18,218,124,68,64,217,51,166,173,35,144,118,144,40,121,243,21,171,151,212,88,9,124,72,185,38,135,55,225,165],[170,188,49,150,11,137,32,107,138,78,21,9,174,117,6,62,208,183,202,169,30,12,138,128,80,10,225,166,141,88,0,79,198,70,143,38,155,75,7,228,93,86,71,46,202,162,238,160],[155,251,164,250,81,186,192,52,193,65,13,43,170,196,203,68,111,82,9,214,192,183,253,50,119,139,55,213,36,12,210,214,137,48,249,80,240,56,203,191,68,169,175,162,214,11,135,152],[199,9,16,239,242,54,98,171,47,115,253,234,105,22,107,181,177,167,14,165,27,31,27,42,147,199,185,233,239,150,24,37,218,187,30,163,215,150,70,54,80,48,187,83,124,133,87,182],[163,88,39,50,35,157,214,115,26,236,126,28,154,45,15,218,125,98,246,243,253,80,190,170,114,136,224,44,142,38,6,217,232,21,80,213,16,70,40,201,60,107,163,157,210,35,98,144],[200,176,238,20,36,201,6,95,36,45,123,201,0,16,153,124,103,7,163,239,141,206,154,98,1,190,247,248,174,85,224,42,191,119,129,239,250,206,160,56,180,193,45,81,71,172,222,149],[189,96,122,115,60,96,92,71,231,95,67,17,244,172,25,196,227,83,76,144,82,133,108,178,45,103,227,57,47,93,37,98,36,23,30,235,148,174,212,34,146,71,181,98,184,194,153,180],[147,7,175,241,53,203,178,32,74,186,114,138,188,55,209,247,67,164,26,128,89,2,181,106,136,19,185,127,12,99,245,100,59,122,152,90,65,97,212,207,114,82,109,163,102,175,42,149],[200,168,70,65,167,39,234,91,5,195,239,39,57,143,211,77,254,175,231,175,174,176,18,179,143,32,161,77,50,156,80,162,255,97,238,132,254,170,177,203,105,83,215,67,56,61,216,171],[197,224,134,51,116,77,237,42,20,66,147,118,47,162,147,38,196,130,200,129,165,250,246,34,64,36,231,240,136,81,164,46,73,239,152,30,31,219,163,150,143,52,34,180,219,237,191,146],[130,80,181,152,82,201,190,165,187,41,184,146,39,17,104,223,93,89,152,179,141,111,206,132,72,236,167,56,214,220,236,39,243,1,107,228,166,67,248,237,139,127,45,220,221,44,235,130],[146,60,102,84,107,100,129,216,187,160,46,76,241,161,11,15,149,48,4,4,89,68,245,182,142,105,112,91,108,161,145,4,18,155,243,170,4,46,47,155,146,153,112,183,57,116,182,183],[235,70,58,182,108,50,21,7,140,77,148,222,19,9,240,161,68,215,45,22,55,144,9,106,178,105,138,193,55,114,128,88,58,119,42,119,26,233,246,49,89,226,40,161,254,99,167,185],[160,240,195,138,130,56,11,220,53,85,210,119,80,89,88,58,193,12,111,107,250,173,14,143,211,149,112,188,234,219,238,199,28,152,35,210,85,81,86,65,117,44,84,101,4,111,196,180],[162,145,55,79,7,241,147,230,8,229,248,114,169,243,255,130,180,4,108,37,39,209,131,165,84,43,188,24,188,22,159,94,95,249,98,47,218,88,67,166,210,146,137,211,118,156,188,153],[13,149,110,35,97,164,20,240,130,168,221,189,64,84,34,196,146,80,1,49,104,14,66,158,231,218,15,101,207,77,37,5,243,4,3,10,203,206,68,132,50,18,32,238,145,149,42,130],[98,47,102,56,230,248,236,248,193,214,245,196,209,83,163,106,209,187,161,80,65,214,88,35,177,163,187,62,245,78,107,22,216,74,224,52,98,59,60,250,79,200,18,34,84,50,227,136],[55,145,106,171,130,241,44,196,205,90,186,21,182,145,216,240,83,53,213,33,133,74,195,120,39,232,47,15,55,54,16,233,255,31,135,7,120,86,74,93,76,251,231,175,182,174,101,142],[74,215,190,195,202,243,222,119,5,170,92,232,52,72,38,216,192,132,57,219,160,124,244,12,132,197,141,19,123,201,123,110,57,133,180,238,142,91,196,98,243,250,221,47,111,22,100,142],[157,13,172,214,25,127,0,242,60,38,131,132,84,24,56,132,213,65,103,38,207,187,82,170,200,67,96,30,230,84,233,120,243,223,188,221,217,231,127,210,219,205,124,13,121,157,137,175],[133,76,180,109,25,229,212,15,148,3,169,202,212,245,28,166,57,10,177,88,182,1,196,140,144,87,175,60,44,203,46,118,96,14,214,121,170,210,232,111,87,8,137,43,60,88,203,164],[73,254,179,96,112,100,96,235,222,137,151,39,160,100,253,192,212,34,88,45,15,142,131,58,49,226,183,109,180,11,87,97,143,82,160,246,62,97,32,128,57,221,65,199,191,132,191,162],[52,15,159,102,81,183,221,180,209,186,170,215,148,171,255,81,50,234,30,125,229,67,90,181,123,111,111,211,110,159,169,11,132,121,132,70,51,64,155,50,245,101,5,58,152,37,39,131],[236,242,103,238,177,121,248,25,170,75,53,248,231,242,95,242,118,15,183,134,74,172,40,241,91,129,7,133,123,151,18,155,53,85,70,174,150,73,139,101,244,122,38,36,48,207,136,174],[147,229,189,173,207,253,73,54,199,15,90,11,239,149,23,180,198,235,107,147,114,206,180,136,176,164,46,46,254,185,144,45,235,51,187,125,108,44,111,21,186,62,179,239,26,161,215,135],[133,83,145,155,76,215,5,48,221,10,77,182,168,201,140,1,155,60,209,174,118,183,84,2,75,16,255,207,255,219,242,207,61,85,25,214,144,100,124,171,39,200,114,48,107,3,158,170],[31,10,235,193,179,183,29,127,28,12,106,195,145,73,120,101,219,131,55,116,80,181,90,194,242,157,151,240,100,212,109,255,173,250,220,193,47,92,15,7,74,248,145,52,202,176,254,164],[225,75,93,12,246,57,33,98,236,160,29,211,217,242,129,85,111,37,247,238,176,188,48,133,125,158,166,237,225,202,29,161,51,247,45,79,87,166,62,82,117,102,191,70,141,47,42,135],[174,188,10,104,23,0,66,168,59,149,169,164,30,102,220,145,218,228,136,248,53,103,100,206,3,231,103,224,125,18,225,17,25,197,141,0,132,236,31,216,43,209,7,73,231,175,14,151],[38,223,46,175,213,96,108,185,143,13,198,139,229,143,224,108,109,110,131,25,172,28,196,103,164,113,163,134,233,191,152,162,161,184,163,83,128,25,29,7,84,106,213,89,82,112,161,166],[65,8,148,218,62,95,181,146,205,25,73,224,19,73,120,69,232,112,211,222,39,62,71,57,96,104,87,20,5,159,236,48,9,38,8,102,225,122,126,49,88,226,203,126,228,0,11,129],[56,217,114,105,210,94,83,75,166,67,141,233,79,164,252,16,139,13,42,35,174,208,255,68,114,204,170,192,6,42,80,22,2,31,72,174,131,235,255,235,7,170,61,243,203,126,63,140],[142,47,41,127,242,122,97,198,233,254,38,187,83,121,32,107,151,180,185,239,52,114,181,223,90,112,64,38,126,191,229,21,171,183,200,90,114,90,17,84,58,74,248,17,20,144,249,174],[17,2,57,181,109,103,137,33,139,139,69,21,94,61,92,225,33,254,112,229,237,14,169,205,117,26,34,167,166,45,127,56,76,106,237,223,244,15,223,32,121,220,187,73,192,236,50,146],[31,100,168,144,179,186,156,159,92,165,210,235,189,64,182,67,140,235,149,121,244,46,142,249,112,22,222,85,17,175,158,19,50,135,188,238,235,101,118,193,196,219,131,69,246,69,106,168],[140,242,134,230,67,69,122,146,177,115,218,217,139,213,160,68,163,73,208,255,41,159,160,249,37,119,135,107,96,20,133,168,215,40,228,67,194,10,237,242,145,92,198,88,83,61,47,148],[67,18,64,153,168,255,59,185,1,237,244,96,31,1,203,202,86,4,145,98,64,147,168,248,204,119,42,46,54,50,99,149,121,172,242,75,187,101,96,28,5,105,234,56,219,194,179,132],[134,104,246,183,41,8,196,150,135,237,80,251,149,69,62,226,196,58,149,110,193,231,20,227,251,52,195,142,41,164,34,97,36,166,250,218,221,65,160,55,79,48,167,207,47,51,240,136],[203,244,207,232,16,231,94,239,89,45,240,173,80,203,212,42,167,120,70,51,5,242,52,184,240,153,58,233,209,49,224,229,151,156,63,244,241,206,201,50,93,63,46,3,150,188,94,160],[187,76,100,121,31,45,195,168,165,253,88,21,86,178,223,185,175,95,7,163,193,196,55,241,107,194,70,71,56,33,68,25,55,238,245,73,224,103,117,109,13,209,23,222,60,249,53,133],[237,140,246,74,31,203,239,97,246,33,178,242,143,73,122,169,40,20,34,246,159,79,77,156,153,97,154,113,190,4,112,146,148,185,95,88,109,164,221,17,220,205,221,9,92,80,116,153],[147,19,62,145,255,42,83,194,18,138,105,211,30,161,114,106,65,149,11,54,254,117,231,49,91,146,66,157,251,202,107,52,33,98,123,145,7,220,224,133,160,217,79,94,138,20,125,150],[248,233,196,25,87,59,223,21,234,35,204,47,17,122,22,224,79,246,24,166,103,140,32,63,243,7,151,147,68,221,195,250,152,207,253,101,130,250,35,59,97,218,40,116,201,85,78,148],[187,236,221,233,215,145,112,140,87,27,134,240,142,6,138,27,139,9,46,224,104,71,202,142,234,199,16,227,151,210,90,117,1,191,207,168,122,205,2,253,1,208,196,134,39,144,182,142],[251,106,229,184,142,159,27,130,56,11,96,11,105,131,58,226,255,241,166,70,249,10,92,186,14,165,96,28,16,100,217,111,88,170,142,175,78,206,88,137,247,205,23,71,48,252,160,146],[237,62,199,3,42,104,98,132,30,206,251,30,53,128,30,12,114,234,22,172,99,136,193,233,6,97,7,226,192,0,146,81,64,109,118,204,6,182,155,9,179,105,192,180,190,47,218,170],[150,183,197,244,103,67,166,173,87,39,188,186,165,231,217,5,4,193,242,144,43,21,104,206,148,237,66,147,36,141,55,227,161,39,199,138,188,117,239,135,194,180,26,189,91,255,110,144],[72,196,126,93,99,88,188,122,249,225,187,200,48,19,221,183,130,18,31,196,66,220,111,224,65,69,146,3,202,117,47,148,229,135,29,38,82,136,106,6,40,136,81,220,14,41,158,139],[249,20,65,253,208,126,58,31,97,84,248,32,87,146,133,19,4,247,27,10,137,196,203,165,32,244,67,66,157,246,32,23,65,255,221,46,3,8,191,168,224,161,16,31,209,206,50,149],[19,37,180,149,143,243,56,65,207,157,11,129,135,95,40,162,129,139,222,111,92,198,202,21,169,46,105,171,65,197,27,128,66,38,232,157,50,63,167,114,252,88,36,75,226,67,58,148],[200,164,17,210,70,253,138,172,120,242,255,19,55,22,17,5,27,232,159,228,168,123,121,196,196,59,250,17,213,65,92,101,171,160,149,207,251,83,225,15,121,135,124,149,149,201,8,175],[209,95,253,141,23,46,62,191,138,118,149,23,6,224,16,159,5,220,53,147,93,36,80,77,229,54,242,245,144,139,75,122,78,106,77,70,214,219,57,62,129,115,9,238,99,238,228,149],[250,228,184,4,98,252,213,239,27,22,91,238,103,94,188,237,58,204,161,82,136,86,131,214,147,1,240,185,95,70,235,102,99,19,241,138,53,176,56,65,17,213,101,196,115,123,241,147],[197,107,21,137,118,192,228,202,134,253,213,63,82,113,156,40,57,198,115,76,103,120,8,178,93,169,114,189,114,246,241,244,122,208,239,232,153,235,245,160,9,255,71,247,111,70,166,176],[216,106,228,241,12,236,138,239,73,44,146,138,38,220,128,201,220,194,221,69,188,97,254,136,88,38,171,78,193,116,146,19,250,62,223,60,198,213,15,137,208,240,98,184,38,84,187,162],[163,253,11,41,102,76,171,90,168,159,193,191,250,110,41,112,138,183,32,66,111,69,105,29,242,175,72,65,50,124,241,69,158,186,93,178,66,116,68,117,125,44,20,150,4,201,148,142],[40,35,107,62,215,145,112,63,41,107,41,176,14,69,99,43,214,39,146,181,224,104,59,124,63,113,125,171,28,135,29,225,67,207,29,0,27,22,190,36,229,127,159,44,107,178,75,181],[133,158,107,220,238,61,190,117,25,122,141,254,194,133,41,81,159,139,98,120,127,151,220,30,140,3,95,201,182,162,28,66,188,79,95,6,223,71,33,177,188,177,202,224,57,190,195,130],[162,123,71,92,9,153,146,73,218,175,243,255,123,20,80,168,114,121,140,226,170,175,186,235,38,45,180,231,61,24,108,13,229,44,119,60,108,161,2,81,68,48,208,62,2,41,14,131],[219,12,247,120,0,89,113,186,85,83,91,115,224,180,18,1,20,103,5,123,65,191,57,240,170,207,105,201,187,25,88,249,244,83,254,3,234,101,158,118,145,4,157,13,28,219,112,134],[39,137,238,180,6,140,45,113,156,40,157,8,115,42,64,218,32,185,238,65,134,66,116,12,41,101,145,201,69,125,178,211,71,49,231,82,141,47,2,139,152,254,212,55,251,158,122,145],[194,89,166,159,92,8,152,76,139,138,79,63,70,109,43,110,139,216,106,177,170,77,215,105,229,125,89,191,232,186,110,162,127,250,132,251,243,210,70,74,17,16,253,26,1,120,75,151],[220,191,198,142,44,223,192,127,229,125,134,185,44,100,29,167,61,254,84,84,124,171,244,100,3,155,171,152,146,232,62,251,205,164,82,68,178,134,222,40,176,231,114,72,42,103,199,181],[65,226,195,7,92,12,217,63,141,216,39,63,42,253,10,104,89,182,158,54,131,132,75,111,168,116,173,204,240,37,172,28,197,255,212,120,95,101,148,185,54,202,104,151,31,116,156,141],[65,16,62,167,24,107,206,143,49,111,80,52,166,196,13,106,234,95,127,90,169,204,81,100,56,3,235,42,187,233,244,77,221,61,235,42,200,178,58,245,108,187,192,131,115,198,29,133],[219,241,157,86,206,123,107,32,135,68,47,105,165,210,88,56,136,118,13,7,2,83,72,236,96,90,114,199,241,229,136,33,41,162,173,228,25,58,73,200,154,55,47,20,167,141,220,185],[165,167,141,175,1,5,255,31,78,198,239,119,120,217,210,23,19,180,17,87,125,0,159,59,40,248,176,122,218,203,49,16,186,46,210,66,217,179,204,104,95,29,12,21,125,62,41,131],[49,122,34,130,164,139,131,181,92,115,150,4,198,201,186,168,249,243,91,140,14,105,216,74,134,176,28,191,71,80,18,64,4,125,224,255,40,213,65,249,74,185,219,149,23,209,18,139],[206,56,234,42,13,64,92,50,249,113,175,129,111,163,30,171,54,246,51,103,138,200,151,70,8,56,164,251,180,40,74,28,115,171,34,140,168,233,43,96,156,61,142,245,225,154,221,173],[215,187,138,186,119,223,82,131,72,39,162,45,214,53,43,68,105,51,171,10,173,136,99,78,217,26,51,32,78,175,26,106,193,150,68,132,69,53,185,177,209,81,141,88,138,199,24,145],[165,20,167,84,216,50,134,117,122,235,89,60,102,155,179,139,4,35,177,231,78,252,180,82,7,214,151,158,2,23,100,72,92,215,119,85,137,14,252,24,69,21,6,47,255,57,118,144],[239,153,174,21,43,22,177,224,187,50,24,74,18,141,219,159,46,16,189,77,82,86,106,197,190,208,21,124,59,204,49,224,76,178,110,47,97,242,178,139,213,202,243,92,123,56,95,185],[152,69,34,134,15,139,118,233,103,65,194,130,99,189,80,74,217,85,228,132,35,51,94,207,82,143,140,76,147,126,52,148,24,129,186,181,118,55,98,202,30,45,7,57,105,29,236,169],[80,13,246,171,169,217,28,120,44,6,27,90,127,207,73,234,140,254,92,227,156,173,11,143,38,223,159,255,178,7,121,221,152,189,176,202,18,131,169,123,163,244,115,11,185,51,140,136],[213,105,50,165,253,187,155,107,184,135,151,73,78,50,60,77,172,226,218,231,145,62,71,15,42,25,191,200,213,26,155,35,213,34,149,33,89,126,42,91,68,107,146,215,129,200,42,133],[231,73,139,17,17,175,152,62,58,62,219,180,236,6,231,178,133,46,128,41,144,160,81,177,64,16,74,136,203,251,197,65,249,249,55,80,28,183,51,11,24,61,18,165,174,119,85,180],[189,4,121,54,17,95,205,230,93,214,152,200,186,125,46,202,242,126,106,165,102,106,184,165,241,94,106,115,80,57,171,155,217,170,105,171,214,28,159,13,32,196,213,11,114,66,165,172],[156,91,234,50,211,145,20,181,134,68,144,175,37,175,72,2,172,9,221,86,99,227,221,150,203,89,165,242,91,167,248,184,164,179,117,16,228,32,103,229,193,159,148,214,251,53,185,150],[109,123,107,161,193,27,194,153,127,189,232,104,135,191,9,13,110,198,231,244,107,0,89,239,6,215,117,120,104,166,31,225,212,20,185,18,238,242,171,166,143,77,190,177,234,222,15,174],[102,113,162,95,45,179,234,61,230,211,188,7,205,8,118,63,63,91,43,85,168,143,177,226,69,251,147,126,96,201,173,188,64,139,118,219,102,255,42,8,240,71,153,122,82,249,249,182],[26,84,1,8,249,41,221,244,59,218,238,190,47,56,149,163,209,48,130,159,217,141,173,87,162,249,135,147,141,220,187,91,252,31,141,243,215,170,8,119,80,31,193,78,195,239,192,163],[218,193,158,202,209,78,115,216,9,142,123,55,45,10,199,212,15,155,117,190,67,49,168,121,82,253,149,200,237,45,50,41,8,142,196,57,59,161,77,77,255,62,218,234,255,216,246,170],[184,191,188,102,155,29,91,187,27,106,27,79,235,252,71,130,238,110,114,58,39,4,68,167,120,115,248,83,17,211,47,154,104,169,202,7,31,252,6,216,65,92,203,180,143,142,72,143],[105,160,166,1,185,184,255,87,23,127,104,108,217,202,46,156,112,27,199,206,182,120,239,132,45,44,218,222,77,209,112,70,15,166,100,112,89,7,36,59,89,209,60,158,153,134,85,166],[225,128,19,97,243,231,6,144,246,153,197,21,247,57,157,14,78,13,131,63,19,136,129,140,205,137,215,166,4,89,192,49,198,19,176,48,125,25,238,221,124,51,222,25,92,145,14,151],[20,142,184,245,100,101,132,56,175,244,135,8,187,10,67,10,244,23,68,240,191,93,44,18,168,93,74,215,164,67,49,25,205,203,238,218,132,202,225,82,131,190,209,8,31,213,39,153],[16,245,248,115,132,212,52,243,118,165,70,210,202,115,65,251,148,180,180,93,2,33,225,183,63,48,212,225,25,20,123,148,105,133,161,232,64,103,48,4,167,83,160,44,160,167,104,180],[90,251,63,237,124,10,68,120,220,131,98,192,51,161,42,193,224,171,100,63,83,80,172,34,185,175,29,144,80,22,185,43,59,45,159,53,147,196,12,60,94,54,46,176,82,189,157,144],[38,72,158,73,177,91,248,14,254,184,45,185,198,36,41,217,107,191,202,48,161,214,96,51,84,86,178,140,84,214,38,237,206,236,248,108,231,130,233,62,132,48,196,234,0,210,37,132],[181,199,208,51,59,60,63,109,217,168,106,211,124,168,247,227,86,203,193,30,123,46,199,187,172,99,60,133,23,213,50,79,253,148,188,134,136,187,3,212,13,104,74,94,84,238,107,130],[80,39,87,163,221,161,208,222,66,214,26,23,161,195,72,56,39,87,14,79,93,126,6,184,202,90,41,122,205,204,94,194,1,11,33,62,159,213,207,254,171,169,108,128,2,180,74,131],[249,191,31,148,98,17,141,209,241,80,212,68,186,216,8,109,241,177,196,104,29,194,141,30,210,90,181,191,239,69,48,199,207,78,235,26,17,8,12,64,136,84,183,102,118,6,19,162],[228,236,112,78,54,113,159,36,62,149,94,197,205,36,150,25,89,223,254,195,144,98,140,1,158,14,93,226,190,226,209,54,120,4,146,194,36,203,206,150,5,57,168,106,112,217,42,153],[252,16,210,119,202,217,167,184,16,52,150,137,168,175,251,28,152,157,91,29,211,140,20,237,39,103,119,143,113,150,115,227,245,214,237,160,156,102,205,142,129,234,65,69,185,162,234,128],[119,152,140,52,82,87,164,172,32,124,154,221,255,221,86,146,13,172,221,151,102,233,186,93,148,206,97,25,232,88,173,67,208,110,219,166,9,163,154,218,26,187,209,112,22,217,99,162],[195,236,22,227,178,119,32,243,65,252,79,190,69,173,11,178,221,51,98,63,179,207,192,78,109,3,95,62,221,114,111,138,83,252,34,126,67,112,198,255,70,61,51,140,232,96,251,177],[179,69,188,207,199,177,76,0,209,9,127,78,1,209,97,0,27,127,254,65,44,139,12,244,43,125,91,124,166,108,201,166,30,128,164,65,107,79,240,85,55,10,19,34,4,87,5,175],[105,118,192,103,40,209,113,51,80,127,209,60,223,9,120,49,46,6,145,84,40,166,102,212,53,10,98,196,109,173,157,104,55,2,29,82,218,67,77,201,235,31,80,156,44,185,100,149],[76,178,47,194,39,249,117,28,62,119,182,174,0,240,146,217,244,118,76,127,29,155,60,203,115,114,187,9,17,151,238,91,188,8,68,100,28,188,230,80,221,146,139,238,155,50,207,152],[154,173,227,154,48,233,247,168,165,61,128,185,52,182,178,172,197,105,76,75,16,105,123,102,86,27,30,178,187,100,91,106,249,217,112,186,136,156,86,37,141,241,170,161,197,253,9,151],[241,163,216,70,34,58,19,213,47,2,38,38,255,165,120,139,163,102,149,39,130,115,131,8,101,38,53,71,196,98,65,228,99,161,174,170,152,35,134,228,160,212,193,144,153,12,255,134],[83,239,30,230,116,68,218,55,88,97,7,21,158,194,158,253,234,144,121,163,225,240,154,1,161,236,149,217,28,152,238,170,25,68,165,245,203,150,200,117,109,116,110,206,165,159,249,142],[98,144,39,171,4,111,135,50,132,3,131,252,173,161,92,137,104,23,201,144,54,151,216,41,42,51,204,201,92,227,246,131,175,77,253,154,41,45,177,111,252,3,187,78,58,38,20,177],[154,34,48,141,166,124,44,19,196,13,110,83,131,75,119,11,136,85,168,162,152,80,83,87,21,7,1,51,244,96,4,102,77,125,250,82,132,39,173,28,134,148,130,250,200,227,46,178],[94,100,201,189,142,167,114,189,198,105,207,105,134,12,130,23,217,133,208,69,47,105,203,126,17,157,159,185,141,100,87,57,236,115,186,255,248,28,33,188,50,13,32,109,149,253,28,145],[115,239,30,198,183,97,121,35,224,130,149,15,172,204,166,71,15,175,199,113,221,51,45,255,106,137,52,203,20,160,160,243,72,209,171,79,5,71,85,83,226,85,234,165,252,152,219,182],[147,210,171,136,42,77,43,77,87,154,120,21,109,149,165,8,178,221,135,124,63,248,118,197,52,102,208,33,17,56,230,182,230,106,47,173,78,192,155,217,140,240,68,216,164,127,13,162],[249,232,32,160,58,57,169,22,226,203,100,130,203,183,80,56,104,205,150,101,12,159,183,73,142,70,150,127,115,63,109,169,160,67,192,254,176,103,63,67,241,224,160,203,49,207,52,170],[242,144,30,77,121,12,192,164,123,250,205,159,141,42,208,113,109,195,96,167,198,22,254,199,21,38,90,32,182,134,3,201,117,64,139,19,196,103,179,170,241,246,92,214,219,105,168,164],[52,72,242,198,231,166,122,118,179,125,213,207,16,226,7,104,180,117,163,113,96,152,167,115,128,236,125,102,82,151,196,43,130,70,243,142,74,169,30,90,152,33,119,173,89,238,113,163],[18,19,46,99,120,152,86,84,50,155,55,138,125,190,25,217,90,62,205,190,27,223,9,209,144,229,148,112,207,53,0,33,171,213,53,109,32,122,122,201,45,86,12,84,188,100,78,166],[35,93,184,105,150,14,66,41,228,183,164,244,225,97,130,51,1,119,168,231,130,211,32,102,4,24,189,230,220,171,34,177,251,52,154,113,24,77,70,54,2,120,201,181,84,221,125,175],[136,251,210,187,19,159,48,192,210,132,120,40,253,229,108,78,192,230,64,89,7,244,161,254,170,131,117,194,138,59,51,126,75,48,6,229,54,232,142,51,84,171,56,222,195,8,215,174],[108,86,14,81,114,12,9,41,55,128,133,61,49,115,127,23,205,60,143,162,14,10,208,14,247,42,104,123,109,141,155,13,129,61,45,86,142,171,221,7,54,115,199,22,63,91,149,160],[178,149,22,140,56,219,147,25,223,44,3,173,23,169,74,231,249,13,99,49,149,165,54,124,90,216,118,43,156,55,242,204,212,52,171,203,208,166,252,94,102,27,66,216,46,91,64,160],[57,113,247,34,217,205,111,154,159,54,69,136,5,16,119,117,222,27,114,117,6,42,145,46,160,116,38,213,4,139,138,242,244,109,244,45,162,131,179,48,134,209,165,2,43,234,95,176],[254,32,229,0,159,178,138,188,4,58,88,83,88,244,124,54,25,96,97,191,32,101,177,83,28,189,101,185,132,107,116,254,144,116,88,40,165,242,119,90,20,181,141,43,45,147,194,135],[177,235,172,186,20,20,149,218,135,189,159,251,188,58,218,9,2,244,5,31,96,180,51,65,146,43,56,73,171,127,110,158,203,252,241,60,189,250,22,223,125,31,43,32,166,112,17,128],[34,143,161,53,251,232,235,246,167,244,168,71,114,239,131,126,12,87,202,108,137,252,122,144,80,126,96,196,3,251,72,112,226,110,169,92,114,152,61,46,101,57,198,116,70,121,13,172],[119,201,228,121,130,26,85,89,55,248,142,67,31,132,1,37,144,40,187,185,215,129,8,248,238,15,3,84,191,137,16,220,204,51,127,70,62,66,60,25,250,127,77,153,128,244,227,149],[180,105,90,111,50,108,166,202,204,251,55,156,254,242,156,91,162,90,214,153,112,165,252,180,7,5,221,78,153,5,235,64,79,138,38,167,109,89,58,130,51,144,48,119,127,231,93,140],[39,243,109,205,31,43,209,218,101,22,115,236,35,218,134,41,41,153,141,240,2,81,68,198,197,234,144,135,122,183,96,43,40,76,253,83,5,162,226,144,166,246,36,104,58,226,138,147],[253,175,81,41,228,120,148,187,86,224,104,98,65,119,223,40,101,34,166,66,95,161,67,26,87,37,230,56,68,40,173,249,248,10,153,137,142,206,219,166,99,108,150,141,207,155,60,163],[60,103,164,140,99,191,171,67,196,21,135,143,217,35,193,229,164,19,114,224,234,17,196,96,214,80,71,114,186,47,73,120,155,28,136,59,131,50,122,150,198,77,228,26,131,112,175,161],[241,132,166,25,164,179,118,233,170,70,217,50,191,13,210,190,197,174,114,82,0,146,122,229,16,112,247,201,81,175,37,185,108,240,129,132,26,158,24,103,152,167,172,99,140,128,238,153],[189,82,148,22,24,188,212,237,215,71,11,101,216,11,92,8,38,149,69,232,151,94,57,91,243,223,11,214,8,53,246,80,118,207,141,200,248,127,60,96,199,252,34,135,168,205,221,165],[185,196,179,222,25,216,21,100,109,232,167,17,61,212,75,216,251,210,233,177,133,69,47,138,1,110,139,221,44,36,127,209,145,161,171,203,139,120,161,0,68,167,145,26,200,88,8,139],[175,222,152,110,82,171,46,220,42,49,36,77,164,187,125,28,138,223,6,28,71,36,13,24,37,233,236,224,86,139,178,40,12,138,159,30,48,140,39,169,151,120,109,164,78,165,50,172],[62,27,218,238,208,12,152,224,47,159,221,81,160,215,228,157,52,103,117,23,37,240,18,59,105,83,105,0,34,206,79,5,65,68,48,207,254,46,251,98,41,23,65,151,25,249,172,139],[154,55,208,47,183,160,31,41,15,139,28,249,23,99,95,132,89,216,184,171,137,163,119,88,132,175,188,23,194,16,163,205,105,231,77,143,86,246,152,233,218,208,7,149,175,20,148,169],[1,51,189,126,208,151,5,49,215,225,185,99,24,134,162,207,224,149,219,177,141,42,64,35,194,244,107,1,245,234,173,128,14,27,216,111,149,60,107,30,254,126,17,29,229,78,165,146],[157,180,170,159,88,232,134,49,61,252,118,215,143,105,146,22,8,197,97,60,51,93,252,219,116,145,204,66,253,35,166,211,89,37,229,72,149,69,84,64,225,82,96,56,144,76,188,172],[118,187,44,42,95,70,245,16,31,243,185,118,47,2,57,83,46,211,87,71,92,242,137,127,114,227,66,238,17,25,63,62,11,142,110,103,74,161,127,235,18,154,39,152,94,238,219,142],[98,221,114,74,210,21,227,14,221,50,237,190,224,108,172,255,218,154,5,226,113,224,189,3,245,67,163,135,182,14,49,121,8,23,105,197,148,171,143,168,156,89,68,97,12,27,239,177],[174,163,82,57,171,225,97,197,120,181,198,111,30,88,160,182,203,96,89,107,56,167,245,170,178,213,168,192,210,132,190,19,117,252,10,46,145,251,137,186,34,82,250,46,109,114,36,136],[9,37,51,213,201,46,44,70,57,32,226,230,114,22,220,253,160,36,33,229,101,18,60,140,146,110,67,172,205,124,225,142,85,150,80,2,173,9,95,154,188,242,124,80,169,123,12,142],[96,83,172,223,15,72,246,249,237,111,130,181,78,194,233,89,151,186,96,243,232,16,189,162,240,253,142,130,206,44,239,201,233,240,83,19,177,115,189,169,150,62,29,170,4,154,103,150],[227,65,68,145,43,216,30,116,28,12,230,128,118,158,66,188,56,157,152,167,128,87,2,210,6,224,141,234,96,66,247,31,111,75,197,212,12,211,90,42,123,210,124,44,179,85,43,141],[104,22,76,181,83,54,200,121,30,192,237,69,20,0,75,142,3,12,127,57,83,108,63,205,46,35,78,242,241,76,3,80,173,81,220,203,93,117,250,175,163,104,197,167,192,8,165,185],[121,252,72,117,212,113,84,80,129,222,10,213,63,125,46,180,137,23,76,89,150,53,232,112,206,168,79,94,224,176,114,236,213,83,63,110,71,77,166,116,15,0,123,106,165,225,140,128],[200,199,2,133,97,176,121,104,194,174,107,88,156,80,135,113,220,133,93,144,248,89,2,237,227,47,170,214,74,128,148,134,150,126,165,16,4,81,127,238,181,221,97,110,227,119,137,145],[217,136,153,21,194,60,33,179,130,83,254,248,230,14,251,33,93,159,84,141,210,196,102,108,112,86,162,204,41,192,183,89,85,94,69,154,182,230,46,67,147,244,70,36,150,47,11,138],[134,236,39,231,126,118,21,85,111,203,39,170,12,99,64,38,86,149,81,91,145,119,220,111,201,49,182,28,229,138,101,55,116,15,213,199,83,237,106,1,180,125,133,89,11,223,24,167],[186,153,109,146,166,207,2,114,155,113,54,12,112,123,134,174,208,210,53,104,60,149,208,202,40,102,167,173,212,79,158,163,111,123,174,18,251,84,138,163,74,239,58,116,127,118,252,138],[239,104,48,49,219,184,24,209,59,230,156,78,80,195,173,236,119,26,119,122,182,48,97,195,185,154,19,140,11,161,97,230,137,102,66,58,187,181,15,67,10,160,202,15,219,247,112,180],[255,62,89,196,38,194,225,112,0,175,27,59,148,38,55,59,146,200,22,161,99,104,222,57,252,222,169,64,98,136,154,103,132,108,11,135,241,102,194,134,253,97,218,74,48,97,243,142],[196,55,67,4,133,31,209,152,240,135,68,129,32,224,253,62,92,91,51,105,75,207,38,18,239,103,1,19,2,190,188,128,197,178,117,207,39,170,93,177,138,13,132,48,131,172,248,131],[146,61,201,151,255,222,39,102,194,142,0,213,208,62,34,138,197,71,229,197,234,55,26,187,117,191,125,155,193,85,105,78,250,250,240,56,148,82,93,25,240,98,176,159,190,39,254,178],[195,151,105,96,59,158,152,60,21,16,173,138,138,170,87,108,69,161,14,250,44,228,143,55,134,26,52,17,67,156,15,218,35,0,13,64,203,37,249,78,46,79,222,5,63,212,4,164],[73,104,171,60,223,236,124,58,195,42,148,49,13,81,194,147,208,31,113,96,39,182,148,73,76,149,136,31,79,167,70,54,61,110,56,202,228,248,164,241,72,216,222,237,249,221,183,151],[91,230,131,97,82,94,108,247,136,194,55,144,72,147,32,46,18,129,182,13,180,187,253,205,32,133,232,33,49,103,181,225,93,228,150,106,157,29,241,227,251,44,248,122,70,194,219,133],[61,218,227,176,110,242,202,44,192,94,210,16,98,93,88,170,233,208,87,17,235,77,194,133,47,214,214,163,78,44,131,167,8,100,187,13,255,89,40,239,98,74,155,88,137,18,120,164],[152,2,60,33,202,228,197,26,37,5,101,83,77,140,137,72,20,96,81,115,44,85,39,63,193,70,122,147,21,30,53,120,140,123,244,103,235,226,56,49,140,45,223,3,79,125,206,151],[243,13,198,101,224,9,64,133,252,188,212,72,138,106,102,26,52,157,89,86,34,213,40,55,16,149,244,73,224,35,251,250,148,163,95,170,7,42,193,154,226,6,242,11,246,117,151,182],[237,99,176,39,224,47,255,246,184,56,244,249,173,125,139,210,159,90,125,193,227,169,139,231,177,62,80,83,59,200,205,94,197,173,248,254,203,107,163,194,200,44,228,229,222,90,207,133],[166,235,14,224,34,248,22,66,162,85,223,105,109,165,29,221,56,117,41,52,82,255,206,164,63,226,227,190,34,79,153,134,20,31,72,104,54,237,60,104,72,22,206,70,47,147,27,146],[212,154,1,45,90,94,219,21,101,190,241,11,7,56,147,65,59,119,130,131,187,254,56,207,160,75,104,88,89,125,108,32,184,75,105,222,35,123,208,8,226,38,23,166,168,66,235,175],[22,51,179,245,4,80,119,148,110,241,45,230,113,78,180,60,253,5,24,198,6,213,60,66,86,120,12,45,77,236,213,222,80,250,233,9,63,65,25,22,241,115,131,170,100,210,233,136],[100,124,171,2,129,251,92,124,237,57,140,63,183,190,230,143,161,121,241,173,187,190,145,127,190,2,114,233,69,46,97,9,29,233,153,162,225,134,180,232,47,207,120,21,7,184,48,147],[56,255,38,176,143,9,123,131,5,88,192,59,217,173,13,125,205,45,105,94,115,37,184,126,15,235,81,153,113,58,42,140,138,158,86,65,234,191,154,46,209,159,224,215,121,167,174,172],[74,175,188,10,169,93,51,122,48,157,177,174,203,45,198,11,8,172,54,30,231,184,220,121,130,113,30,183,236,188,186,37,32,89,209,171,173,239,10,27,7,255,63,216,144,155,204,176],[52,87,215,32,183,251,244,249,33,73,81,110,254,140,47,162,21,100,209,44,133,114,137,206,145,180,147,203,234,230,80,39,252,139,137,8,3,227,88,135,142,167,131,197,25,46,3,148],[66,194,17,12,87,64,194,205,198,44,66,252,155,197,106,224,178,196,137,248,20,101,77,24,70,7,78,253,45,109,110,110,49,70,74,149,51,199,204,149,118,59,95,190,162,137,163,174],[37,243,49,12,254,111,249,8,76,105,92,0,53,120,29,16,6,197,108,72,194,0,188,148,182,231,111,89,185,197,137,193,17,123,1,156,193,77,98,30,149,181,40,140,40,216,221,128],[231,18,108,60,32,213,254,65,90,72,153,50,78,65,184,10,95,34,221,205,220,68,150,211,135,130,213,122,46,105,197,132,53,73,67,179,51,174,16,36,188,222,179,45,22,239,68,167],[214,223,37,109,140,64,243,244,18,103,252,3,172,247,70,194,26,102,121,64,84,180,165,131,30,147,196,242,6,254,16,214,120,213,114,144,199,108,102,141,234,197,83,44,201,232,137,151],[34,72,112,119,153,187,237,62,181,59,137,30,222,132,120,83,180,21,37,60,11,76,109,112,70,215,3,28,134,167,10,220,130,121,42,61,94,26,162,66,152,26,73,97,63,45,231,151],[217,47,188,162,105,3,110,170,241,84,58,18,54,74,207,230,153,5,2,77,87,67,73,52,165,141,83,18,82,148,153,85,225,30,134,8,165,22,166,142,138,180,152,62,175,215,158,128],[33,125,88,78,240,248,202,11,3,205,197,91,2,107,166,53,147,118,23,231,253,62,41,128,192,191,167,2,172,60,16,209,118,113,206,26,146,214,1,159,100,190,100,252,248,17,137,179],[115,25,48,63,143,185,179,28,234,36,235,60,246,162,53,166,165,25,103,56,167,45,176,38,148,109,251,64,127,123,95,20,187,103,32,102,157,104,240,68,103,151,244,84,180,20,130,183],[246,13,241,240,82,202,180,244,2,70,33,148,78,22,95,106,11,99,77,64,83,132,187,116,160,181,180,97,93,135,31,61,59,244,112,218,204,105,200,247,112,64,58,127,95,234,114,171],[57,209,183,228,41,171,74,4,165,211,31,14,103,104,33,48,35,193,133,72,87,136,158,124,88,92,220,239,33,130,243,168,237,230,79,151,189,101,106,12,85,25,81,130,206,165,31,151],[81,213,204,126,181,91,119,60,55,56,61,186,209,23,4,40,239,243,248,185,184,17,186,217,218,209,201,66,127,238,219,255,223,115,136,20,31,89,27,20,129,148,50,44,205,154,249,134],[147,134,221,153,138,157,179,110,120,59,184,133,53,10,242,252,36,1,184,230,119,53,235,254,209,49,37,17,105,17,223,41,23,180,133,55,102,110,137,180,184,118,22,161,44,122,236,134],[151,224,162,10,179,75,53,131,168,203,114,195,252,97,44,255,226,169,121,243,33,107,67,121,166,248,87,162,163,111,109,126,102,155,36,61,189,63,236,141,25,65,105,133,202,68,11,183],[161,226,179,196,181,33,163,57,102,137,21,220,1,210,12,104,2,111,209,111,40,203,65,152,172,103,143,27,148,148,216,118,14,84,110,222,117,188,167,30,42,109,240,43,229,177,253,144],[139,135,153,123,233,156,242,176,185,22,19,130,152,93,223,9,63,86,247,3,22,67,98,97,80,18,164,56,5,218,17,49,94,88,167,177,71,142,25,124,61,118,15,216,50,8,61,174],[233,157,46,10,38,40,228,222,169,219,142,84,109,178,8,62,93,203,83,173,164,132,40,208,71,180,246,81,105,145,81,183,241,44,7,119,195,67,90,112,214,234,201,106,31,234,232,153],[34,52,222,100,230,132,227,17,240,21,50,222,108,254,245,51,9,12,4,124,83,13,167,76,165,147,132,203,133,39,55,77,163,162,48,250,253,34,123,231,96,226,180,77,116,244,133,131],[90,49,125,65,42,86,106,169,254,140,111,179,235,190,215,138,246,178,109,184,192,32,18,91,13,56,153,158,232,90,125,250,114,100,134,193,115,184,198,170,209,240,127,46,211,117,134,167],[191,195,44,201,12,20,31,26,178,135,141,43,102,46,35,196,108,195,64,184,208,208,241,230,166,188,201,67,232,173,26,66,31,175,40,222,210,154,1,59,55,110,95,233,183,178,232,152],[134,234,53,0,115,89,196,182,91,184,58,190,194,120,79,164,220,107,51,138,161,128,93,129,48,139,116,232,52,237,242,96,18,125,5,35,131,240,86,108,55,32,230,184,67,26,135,130],[142,125,164,39,14,40,16,156,190,100,251,71,11,90,22,90,130,176,1,23,44,160,156,218,122,98,236,75,247,218,126,114,219,74,213,162,34,234,144,16,154,98,180,62,49,84,145,148],[128,143,22,208,173,204,195,227,105,51,85,24,72,147,114,226,35,91,234,31,8,35,17,160,12,210,87,231,225,70,223,0,254,150,114,86,103,134,16,50,3,161,122,146,2,145,183,161],[249,118,168,165,51,198,24,32,49,108,150,50,192,189,62,99,24,170,144,83,54,10,118,254,173,176,92,88,217,33,174,193,147,186,217,8,112,182,252,75,194,181,59,47,161,228,226,142],[193,185,97,166,158,39,13,32,174,249,130,125,56,107,66,45,129,114,174,151,99,212,218,205,34,28,92,183,165,14,34,245,17,49,139,13,238,160,103,115,234,118,180,98,34,149,100,178],[177,190,100,128,229,120,243,187,47,89,58,32,145,203,108,220,14,77,39,232,60,30,15,148,66,239,169,98,96,41,17,35,247,106,26,149,126,28,203,131,54,234,239,22,50,142,42,162],[234,154,240,101,60,94,144,134,247,34,242,49,130,124,241,254,127,135,38,80,203,251,229,71,56,137,11,237,229,114,107,192,12,101,100,177,72,230,128,48,85,93,178,135,176,51,68,176],[17,154,29,238,230,143,152,155,151,242,27,69,118,35,181,106,71,73,3,90,46,106,2,172,107,62,86,244,10,56,32,82,184,200,143,86,97,202,41,100,5,190,147,166,148,41,145,162],[19,3,83,108,180,38,97,147,200,156,102,232,243,225,92,25,10,213,200,166,153,206,232,32,120,81,124,172,40,216,115,227,15,166,26,4,123,204,159,123,135,212,49,120,36,124,235,179],[250,170,195,230,155,146,61,48,199,155,36,234,218,164,18,74,189,26,49,238,156,239,31,63,37,23,71,175,144,155,244,231,203,147,212,235,159,126,246,21,19,79,102,243,246,178,158,168],[76,221,169,49,6,88,220,238,138,104,215,204,31,223,69,139,159,158,231,234,58,87,225,137,96,243,170,19,38,86,91,125,110,49,3,157,179,164,195,237,192,186,10,81,238,127,43,168],[58,208,203,152,126,44,47,242,188,29,206,129,44,121,182,90,193,106,165,40,239,20,74,251,7,121,212,40,138,68,236,241,133,129,13,67,210,231,34,4,1,97,103,103,100,142,93,162],[26,36,251,221,32,230,249,125,213,233,210,88,231,252,28,74,183,215,130,8,195,88,19,91,32,233,129,79,35,101,45,164,178,49,68,150,46,56,41,33,99,211,78,179,140,231,64,183],[56,124,133,129,251,7,230,195,198,219,203,188,68,107,36,89,237,118,124,85,60,187,154,199,177,172,21,210,143,134,197,148,210,2,199,201,248,140,203,204,14,34,202,239,59,22,133,141],[96,253,74,104,35,76,190,217,24,217,72,71,169,116,106,157,73,59,189,226,200,31,1,170,151,216,190,176,96,151,110,94,116,25,108,94,33,84,1,104,209,43,75,114,81,18,51,168],[3,130,106,151,197,254,55,178,61,132,128,119,241,65,72,199,17,212,116,156,93,96,57,176,234,157,15,201,79,74,194,107,157,180,129,252,242,25,134,208,174,211,66,121,60,50,216,152],[10,74,5,23,146,237,161,120,150,162,42,105,106,181,163,153,99,154,229,204,61,252,224,153,46,171,205,38,156,24,184,163,9,192,118,237,54,200,150,124,231,144,201,198,185,237,127,161],[141,243,220,73,151,98,119,157,129,47,217,119,112,109,113,235,165,191,178,165,208,185,145,91,17,179,7,20,158,60,25,128,84,240,174,63,234,250,8,158,110,106,185,140,186,114,74,131],[206,212,92,21,10,126,243,161,166,127,142,150,197,187,151,164,143,94,150,88,190,32,181,17,162,98,184,242,228,75,164,21,104,177,199,128,68,54,110,177,235,113,16,198,188,110,56,153],[117,75,247,178,107,92,25,242,154,143,8,107,29,96,48,27,145,29,101,93,67,216,27,26,77,210,173,247,13,251,193,64,140,51,45,226,39,126,186,119,2,220,212,81,75,5,7,129],[91,134,102,175,92,218,59,43,127,147,125,102,99,97,93,191,208,232,29,26,58,69,145,82,40,202,147,105,206,210,30,94,99,126,186,139,250,128,122,220,64,54,73,170,231,18,200,141],[12,35,28,147,202,6,244,105,240,55,154,203,30,197,132,90,82,145,20,161,22,136,168,99,133,183,119,58,197,218,106,244,103,142,221,145,37,55,150,62,246,102,59,194,229,210,152,183],[229,15,9,134,212,222,204,127,140,27,167,249,43,197,176,50,65,48,194,43,92,251,156,237,45,246,237,101,125,224,228,64,27,196,105,75,93,76,232,122,138,10,229,46,33,231,153,174],[158,165,30,159,39,74,110,215,11,248,189,56,194,218,73,230,131,231,156,39,116,203,24,74,71,71,130,202,164,153,149,68,60,22,15,140,126,6,174,247,104,114,207,199,194,145,211,129],[108,94,119,152,10,92,217,222,178,214,64,227,17,27,157,76,121,14,233,7,147,91,7,14,0,146,173,35,175,117,162,173,50,51,250,202,24,132,251,248,173,206,138,179,72,148,248,130],[114,183,238,41,201,94,87,128,155,84,1,79,205,93,242,129,92,92,84,117,197,209,54,154,142,104,23,109,101,139,251,44,245,113,52,105,28,135,196,164,210,102,43,254,237,142,244,134],[189,76,139,30,216,117,7,6,190,12,10,220,137,61,146,107,126,78,185,65,79,141,19,46,95,113,41,101,95,150,133,32,189,142,24,142,102,156,124,221,151,105,102,247,138,38,18,183],[61,42,214,98,187,213,109,7,13,235,127,113,99,220,149,5,139,148,45,37,15,166,68,168,186,180,46,179,146,245,139,44,102,38,74,116,226,184,53,82,138,82,148,89,124,11,8,144],[88,34,195,153,93,96,78,3,179,41,113,89,24,98,112,159,210,157,22,69,180,12,228,66,224,104,50,21,66,155,191,128,250,109,231,44,160,89,255,22,117,81,57,136,14,216,51,145],[181,90,105,132,248,182,160,35,1,16,115,173,104,80,248,146,97,20,194,233,151,30,173,224,16,165,226,245,73,58,206,187,252,251,124,154,192,75,140,77,128,45,158,49,209,132,198,164],[189,198,197,249,46,193,177,202,240,247,8,25,101,106,3,140,244,29,27,167,11,181,205,210,223,41,186,87,167,125,115,13,125,192,142,210,130,48,23,253,6,64,162,244,231,88,220,168],[86,111,38,139,152,146,207,222,218,119,146,70,1,196,225,198,85,140,226,44,210,0,201,230,147,94,235,65,203,108,16,155,209,86,196,252,81,119,32,252,181,140,57,49,237,52,104,132],[140,165,186,116,16,98,53,157,245,217,199,142,161,115,114,221,194,67,98,163,116,163,181,125,131,111,82,85,196,135,232,238,196,41,91,70,108,248,56,177,95,188,175,247,25,75,140,140],[248,206,177,33,228,220,89,185,96,93,96,148,23,202,174,55,90,75,195,211,144,242,7,128,35,218,211,232,4,79,124,221,80,232,14,90,55,249,22,221,223,190,252,251,204,129,185,137],[228,50,29,106,77,15,80,222,29,173,115,20,152,26,88,166,148,248,59,156,245,254,87,124,186,36,41,129,21,52,123,141,189,140,56,74,6,33,75,172,128,149,224,100,58,63,86,176],[59,23,124,22,119,241,178,116,123,33,88,30,0,163,249,200,205,205,95,185,47,87,46,132,148,253,158,48,2,86,41,100,184,105,159,99,81,242,154,127,42,199,73,121,248,237,107,130],[126,159,110,176,120,250,226,236,248,136,101,178,34,99,103,76,70,167,69,239,145,96,102,187,146,45,86,115,196,104,134,245,115,79,210,198,157,202,4,227,208,113,174,141,149,87,240,167],[118,140,141,197,52,93,221,211,148,60,132,33,144,12,237,148,142,172,213,233,234,164,51,224,217,38,152,160,95,16,50,181,184,53,225,135,179,94,126,241,180,171,125,98,48,188,150,139],[77,29,116,228,28,109,82,203,184,211,76,153,196,238,115,156,66,69,103,171,129,4,87,228,192,61,150,115,55,228,164,43,197,151,236,143,19,197,7,135,130,123,168,242,144,236,79,145],[13,8,88,179,229,249,85,48,79,241,22,86,247,29,49,135,1,57,214,74,200,247,79,215,48,35,132,153,179,87,74,19,147,174,55,155,66,247,218,244,17,112,4,235,13,72,252,161],[99,200,240,186,253,114,223,66,193,90,95,89,150,254,187,181,126,178,50,134,24,162,105,220,247,176,228,41,251,197,236,191,21,137,84,48,162,70,204,77,50,31,174,238,47,241,226,151],[233,55,84,159,144,201,98,244,144,34,254,40,218,162,7,116,104,114,102,190,89,220,104,244,121,56,229,156,162,7,118,52,249,45,242,238,94,21,36,230,204,7,120,162,195,240,222,168],[145,235,54,121,238,131,112,247,160,123,231,184,155,186,137,33,233,184,244,241,169,31,39,194,232,114,96,20,135,180,89,204,182,79,249,202,35,48,1,79,64,251,41,64,128,29,238,139],[110,191,196,50,95,28,74,90,132,99,211,167,102,102,160,15,106,61,184,117,218,245,1,101,20,141,20,132,212,162,38,135,38,145,196,86,179,236,4,40,127,228,141,147,111,65,144,143],[118,86,172,95,252,220,234,216,42,214,96,36,159,236,10,241,9,144,83,150,8,246,172,231,246,126,174,209,254,209,114,66,83,104,54,173,243,68,46,35,0,217,239,207,247,1,174,179],[42,213,114,221,194,21,94,57,117,62,199,232,25,194,190,59,174,172,189,29,221,80,113,41,100,95,173,28,166,174,70,23,69,232,21,8,108,56,44,6,195,58,250,247,35,147,165,149],[140,13,142,72,214,138,147,141,77,28,110,104,10,158,53,64,158,111,1,10,198,118,134,192,201,124,102,163,95,191,60,196,8,133,3,226,65,62,150,82,164,73,164,128,154,174,167,138],[201,30,188,189,147,140,176,142,67,130,1,206,144,182,9,86,171,122,59,80,159,159,101,18,74,114,129,243,197,211,162,90,105,110,141,238,72,34,252,129,155,232,206,251,109,40,83,133],[175,159,125,78,69,206,248,243,225,160,67,26,248,67,163,222,29,113,106,36,222,47,104,106,231,77,59,239,138,60,17,129,223,89,81,103,10,60,172,155,64,226,219,178,194,25,91,171],[229,134,163,252,147,227,111,174,20,134,169,112,68,2,112,133,121,115,58,207,215,219,60,255,126,177,157,240,153,157,226,35,221,31,95,231,90,154,142,73,216,166,222,189,134,216,136,172],[179,10,247,115,98,160,25,236,177,82,246,19,160,227,177,140,239,150,11,60,129,50,49,19,5,234,190,235,239,173,160,5,150,120,235,144,147,240,251,229,164,59,39,117,62,165,110,129],[130,214,113,15,116,115,28,164,81,74,87,13,147,253,104,167,44,171,120,79,223,251,236,94,196,152,40,234,154,18,110,11,174,235,110,238,42,66,58,252,202,24,23,87,116,63,72,153],[223,164,130,110,245,55,241,225,38,98,24,174,54,16,112,82,151,42,197,154,173,214,147,187,138,195,202,11,5,17,149,255,220,127,11,120,215,153,37,103,86,154,21,153,75,155,145,180],[148,0,203,138,127,37,105,226,76,171,30,93,137,230,226,1,255,187,220,201,143,224,46,11,133,197,141,227,192,30,74,228,105,74,185,67,190,171,85,33,187,216,217,190,206,100,215,137],[201,204,129,30,110,12,11,124,102,203,139,153,157,11,254,199,35,111,4,13,160,161,250,82,11,174,155,193,46,157,138,29,2,4,240,97,194,51,144,90,47,20,102,157,180,162,89,128],[208,96,33,15,193,211,174,20,73,165,162,98,168,65,19,110,127,241,136,55,39,95,38,35,122,64,210,182,119,191,223,176,101,31,100,32,98,208,2,48,62,159,63,27,48,207,250,164],[233,136,36,29,71,166,86,249,119,230,2,233,242,161,68,153,122,116,115,97,220,250,171,36,240,145,96,210,203,182,151,118,233,45,95,93,23,199,189,84,24,240,28,228,103,157,185,128],[43,152,17,182,242,204,128,124,67,1,212,14,131,37,28,204,155,201,168,115,141,161,22,190,109,228,18,66,115,58,133,114,211,10,78,7,102,149,255,6,169,159,80,189,165,97,237,133],[127,76,225,4,47,188,11,83,249,106,7,36,184,163,205,163,56,97,156,236,45,80,161,125,51,11,82,173,1,5,97,228,199,165,159,20,180,87,98,214,68,131,108,212,157,63,102,161],[189,188,235,114,12,55,186,100,139,24,8,249,236,175,206,26,57,143,234,124,84,160,194,56,68,195,177,133,145,79,243,94,15,126,150,180,46,128,203,226,219,188,233,111,230,225,188,176],[157,185,133,185,1,211,140,57,35,238,215,75,98,176,27,30,212,99,15,179,2,222,169,173,4,156,178,206,65,141,202,45,63,127,141,116,222,161,190,39,219,166,73,195,151,45,90,135],[107,54,93,134,34,50,22,125,114,26,137,227,123,8,254,103,47,235,185,19,28,237,206,42,200,174,61,130,178,218,156,9,214,83,18,71,226,65,63,199,124,246,7,39,113,188,124,167],[115,23,14,129,169,30,200,157,138,223,122,50,162,255,102,224,192,150,155,207,198,191,79,233,13,182,196,215,107,119,176,14,36,129,229,196,126,164,173,93,5,34,38,109,20,121,158,137],[126,243,254,17,30,20,199,178,219,78,154,26,197,185,172,153,192,85,136,63,137,252,107,32,104,13,15,69,141,37,46,245,245,138,63,235,1,193,118,13,222,110,220,198,232,114,207,163],[36,165,51,124,98,25,167,81,79,43,247,151,1,192,32,23,173,229,243,244,180,140,5,139,234,110,94,83,131,187,180,0,212,182,135,99,103,33,188,133,61,133,142,238,16,140,249,138],[110,118,248,106,40,234,38,232,117,244,214,63,216,24,93,211,18,168,141,215,113,242,221,237,185,83,94,129,119,15,62,98,206,183,96,230,205,168,90,39,21,124,92,165,195,3,186,169],[204,250,10,105,29,63,65,204,49,75,207,196,222,105,67,161,28,46,49,34,1,135,13,152,125,16,179,89,119,4,52,23,249,217,38,30,209,7,143,242,76,158,126,20,20,177,148,174],[175,158,135,230,18,89,48,73,107,216,141,95,159,59,204,166,32,67,41,242,249,240,139,31,128,166,66,162,38,251,181,25,171,156,105,54,14,10,196,61,207,202,13,79,44,234,80,174],[63,110,244,76,161,156,78,38,96,134,31,235,42,53,188,34,201,211,167,198,93,238,37,85,142,60,95,151,134,55,204,188,170,76,117,211,5,243,187,72,251,108,11,26,109,70,78,171],[50,150,14,29,183,120,118,220,27,93,216,195,73,31,181,221,130,26,193,138,195,69,41,243,166,235,200,31,233,254,67,93,217,116,79,64,212,82,248,116,166,16,178,115,35,126,102,133],[60,154,7,36,82,44,171,251,157,225,198,99,54,20,204,8,207,200,22,120,243,116,24,216,167,31,246,86,247,27,146,245,160,109,10,221,143,182,164,36,253,77,98,75,104,175,168,170],[161,167,198,170,123,64,102,251,15,227,116,100,231,38,128,62,39,137,107,150,117,144,110,22,63,34,221,219,85,38,160,87,176,10,129,187,243,135,96,107,2,21,182,245,225,139,231,161],[49,176,231,83,197,245,209,226,148,126,198,246,253,78,144,91,95,203,149,18,136,189,149,5,82,138,222,250,127,244,127,243,254,104,170,176,46,146,142,111,239,160,231,94,130,100,252,136],[81,86,76,60,221,65,249,243,108,43,88,252,181,152,79,98,81,184,60,149,135,160,148,217,192,53,194,220,118,165,149,89,31,216,6,230,245,3,228,210,108,32,224,199,81,127,149,141],[102,180,84,116,10,207,31,159,64,70,212,148,25,48,81,87,93,59,255,67,202,129,81,6,86,17,251,115,161,225,45,46,91,187,191,252,211,37,174,26,129,8,115,137,99,76,190,130],[196,206,158,239,26,197,100,119,1,80,123,13,210,178,129,169,248,1,78,54,185,117,105,226,10,165,38,231,206,24,232,195,128,142,99,49,45,86,85,100,237,138,56,61,56,202,164,144],[236,41,202,151,217,116,253,88,58,89,233,6,251,95,223,109,203,185,212,213,210,177,94,201,80,202,124,49,63,140,128,123,8,118,221,158,154,141,109,100,248,192,184,8,103,100,106,185],[62,105,39,91,25,66,147,18,81,102,6,32,95,69,55,33,83,36,62,81,5,81,98,75,255,144,41,157,42,118,157,180,107,230,110,22,225,150,55,214,124,118,227,185,196,251,190,151],[209,178,185,192,163,135,142,39,204,42,236,59,218,48,151,46,165,80,105,254,66,218,3,156,9,246,53,196,216,114,135,117,8,199,37,151,149,253,109,236,166,141,206,203,33,85,229,173],[197,249,211,65,136,183,89,110,196,249,130,104,35,141,74,111,234,144,251,241,109,119,63,244,133,32,93,92,255,124,144,205,153,66,157,89,227,46,58,191,149,200,42,29,169,3,217,164],[215,141,207,75,93,116,111,194,68,112,53,125,186,76,88,96,81,36,127,60,20,233,95,115,77,75,246,12,107,117,51,126,145,188,238,202,35,59,47,245,79,47,114,249,74,132,71,131],[48,217,201,127,73,41,155,201,84,235,62,77,10,45,212,240,83,154,93,143,242,221,171,123,238,169,23,30,238,0,172,134,193,61,76,129,17,82,52,28,46,112,159,229,215,139,59,167],[84,197,159,225,154,176,39,120,21,183,119,65,175,123,158,38,20,193,81,73,126,30,11,195,172,17,109,120,129,96,164,56,165,179,161,97,45,100,208,133,138,16,1,202,199,176,126,129],[75,253,143,49,199,114,102,142,158,200,90,97,140,123,222,157,137,93,35,221,9,6,225,154,28,0,99,155,249,131,158,141,78,132,232,60,91,78,32,46,102,194,199,75,216,148,26,165],[249,14,211,89,223,58,27,105,76,75,13,106,28,134,47,117,6,13,52,173,28,76,94,180,57,92,179,194,189,24,60,200,166,64,30,198,197,240,217,81,193,247,248,180,171,44,0,181],[156,173,198,181,155,173,160,26,156,209,88,92,149,175,223,48,192,199,226,131,201,97,16,2,50,192,193,1,144,198,252,91,69,184,29,86,87,123,89,168,254,138,216,165,32,180,113,138],[132,246,159,240,247,224,175,9,160,75,111,212,26,132,24,208,96,117,12,180,107,20,25,156,4,233,171,169,72,77,12,37,93,143,7,131,119,214,12,61,142,34,166,104,75,49,125,151],[50,200,38,178,181,112,127,24,31,238,85,87,58,137,11,51,207,33,2,107,104,222,141,107,137,118,225,193,248,72,92,145,98,237,241,201,27,245,25,182,174,104,160,185,180,229,178,142],[33,43,126,221,40,23,172,21,198,7,1,235,87,135,26,224,241,20,165,109,223,54,139,154,5,58,60,171,165,47,123,150,204,220,69,3,109,7,247,250,160,178,116,253,190,21,223,138],[45,120,81,139,102,138,58,175,216,75,200,192,38,157,57,138,61,226,3,111,172,65,83,172,30,190,103,207,227,95,117,174,109,144,191,149,18,218,61,117,68,178,144,188,124,109,165,136],[145,5,55,229,198,191,217,13,229,237,166,12,248,65,78,26,231,7,179,118,48,118,17,106,236,196,29,104,170,170,174,182,118,95,114,134,139,26,204,224,153,249,198,10,204,61,209,136],[13,5,177,161,221,148,153,82,221,210,249,174,228,36,241,26,25,230,206,152,163,34,131,132,212,171,68,25,174,253,183,122,254,118,50,252,31,213,134,254,214,194,74,155,114,208,209,176],[154,35,243,124,129,233,238,214,193,250,246,189,167,220,190,70,31,196,212,90,240,87,113,213,150,64,153,150,247,115,59,100,112,5,231,75,59,6,211,177,135,167,49,219,96,162,38,179],[79,83,201,127,174,191,83,220,142,81,243,32,251,253,130,12,192,2,187,243,34,153,202,155,104,97,28,233,78,235,118,228,161,61,13,153,48,51,140,78,151,36,254,222,101,123,132,177],[52,232,212,100,69,98,143,35,61,73,21,27,59,153,237,120,138,195,182,187,253,163,128,180,158,248,196,36,52,135,238,53,37,22,93,253,4,143,168,255,85,252,123,84,173,68,78,177],[5,104,155,20,124,27,21,44,94,109,255,158,15,106,167,57,181,238,234,158,210,109,159,186,172,118,94,223,160,43,231,206,244,152,185,213,45,141,15,121,17,26,171,172,194,179,72,171],[18,82,138,28,69,247,57,9,109,70,157,75,21,72,107,71,27,15,124,137,63,79,153,107,56,37,86,11,187,127,100,98,101,121,56,5,75,242,32,45,7,86,22,164,57,190,195,171],[61,98,87,182,194,59,41,254,249,212,18,186,200,249,214,91,149,131,44,64,253,70,117,50,64,180,249,14,247,19,146,69,234,53,216,223,25,54,83,207,190,107,115,64,57,6,183,183],[135,16,100,185,147,137,34,37,218,135,167,14,180,189,104,107,102,3,184,209,213,84,203,169,113,235,200,129,202,62,18,118,132,197,206,184,143,45,221,246,109,134,107,21,197,69,81,175],[244,198,141,101,83,153,4,162,222,242,101,160,109,195,94,178,62,225,78,37,195,0,195,14,94,201,65,2,215,211,56,155,38,32,190,77,127,165,7,225,242,48,204,171,240,70,62,151],[226,12,231,225,223,215,217,18,196,163,124,158,148,143,68,159,231,221,102,100,127,81,97,125,247,135,83,225,188,165,252,100,131,205,174,218,78,46,73,26,245,171,60,49,141,250,201,164],[27,1,102,133,120,38,90,103,22,35,70,76,152,27,183,6,152,140,105,40,168,98,237,220,39,55,174,154,223,99,101,196,223,33,199,154,202,2,116,219,238,27,156,121,194,193,108,172],[223,233,235,135,235,56,1,107,163,53,138,108,199,174,100,93,29,16,62,144,56,59,153,22,102,2,103,5,149,58,227,156,154,82,125,202,70,122,154,237,224,62,32,42,140,107,80,140],[126,49,20,179,148,183,40,73,220,153,25,177,164,65,201,250,167,21,100,180,226,146,130,63,56,217,251,9,84,133,197,126,31,168,239,99,202,43,214,225,184,66,97,133,189,218,163,169],[202,14,14,157,251,224,199,227,125,19,43,29,94,196,73,26,106,122,51,175,231,63,211,146,111,10,35,206,20,81,32,179,100,39,145,23,247,114,209,114,107,148,23,254,95,117,46,142],[68,177,27,186,201,247,20,19,233,37,104,219,94,148,201,249,167,240,31,23,105,81,177,191,77,206,246,200,133,102,116,106,196,234,89,162,127,61,111,25,212,184,78,45,205,178,216,143],[35,57,162,141,228,207,176,14,60,185,203,115,231,80,246,198,2,92,32,29,54,17,139,237,102,35,223,210,148,90,210,175,25,101,190,52,167,200,153,220,176,121,193,113,132,217,98,136],[200,7,164,18,164,222,246,158,173,139,192,152,92,165,82,161,28,50,56,93,131,164,253,39,49,251,215,149,75,13,166,148,22,70,225,15,184,115,183,218,86,146,21,165,159,228,71,172],[158,32,97,33,176,215,23,3,240,27,220,28,173,13,239,44,105,124,95,150,225,77,2,203,22,210,147,185,142,141,184,49,155,229,165,101,246,168,103,95,33,229,233,191,235,54,141,150],[186,160,230,67,222,205,229,77,226,80,152,54,159,150,6,197,211,76,250,186,113,237,138,247,159,217,203,69,49,8,234,78,6,53,241,143,73,145,216,129,214,184,131,4,78,161,212,133],[242,108,160,115,253,20,164,83,46,8,242,159,16,138,214,107,188,31,154,226,146,136,250,94,87,144,85,8,105,112,224,39,151,119,146,165,136,223,207,252,63,193,12,143,67,28,85,171],[157,240,91,111,46,136,185,178,88,79,133,20,192,109,74,103,226,19,74,231,231,196,227,91,99,229,78,18,211,139,239,133,204,248,229,137,174,122,228,182,227,223,165,0,121,196,41,168],[21,128,124,27,110,84,130,52,66,155,49,129,173,42,229,87,153,104,246,161,139,95,196,205,17,97,164,162,32,150,120,179,244,236,102,142,56,244,254,39,198,195,86,186,201,36,178,172],[109,139,58,49,181,55,156,226,10,164,248,38,253,219,66,43,40,137,79,116,63,246,71,159,204,168,134,224,80,240,65,226,184,50,37,140,35,183,160,69,115,85,22,195,245,184,250,145],[157,43,90,156,122,213,168,1,34,107,162,154,149,46,235,41,176,158,218,252,28,215,58,130,66,28,34,196,240,118,29,251,84,66,112,2,120,169,90,106,213,162,54,240,74,246,162,131],[206,107,192,175,247,120,119,63,64,171,104,76,99,64,181,126,154,41,180,59,71,60,180,104,14,51,169,76,48,2,21,219,181,216,225,68,243,143,146,222,165,40,9,131,255,70,201,151],[221,3,255,33,47,107,230,121,97,209,229,33,117,128,155,76,28,162,14,229,78,67,241,195,201,121,155,218,195,149,126,97,7,75,64,188,165,44,108,235,121,238,115,61,126,103,140,180],[48,71,149,230,162,104,253,99,207,170,104,58,167,40,196,212,146,95,63,109,236,87,39,70,39,49,101,155,233,43,21,27,39,179,154,215,28,195,213,87,193,171,237,244,186,133,107,143],[65,19,145,99,18,90,215,140,114,98,84,22,191,77,113,206,2,187,163,7,202,254,40,27,195,155,128,125,123,173,149,159,193,194,217,188,210,212,174,173,211,43,84,58,35,64,166,182],[100,180,39,249,217,8,140,147,140,37,26,20,160,185,145,177,143,99,234,178,162,128,87,234,232,22,224,122,143,189,141,21,116,111,138,139,219,91,92,11,75,21,206,221,4,184,128,168],[31,51,169,6,210,73,197,224,126,73,59,186,104,119,230,121,8,43,247,171,36,236,43,238,179,92,166,5,189,128,111,226,43,82,237,18,182,20,83,118,84,110,236,100,116,59,147,150],[183,98,83,226,166,163,20,80,124,238,118,142,108,99,8,0,235,170,54,5,59,186,155,219,117,208,130,220,0,44,219,37,170,194,9,219,124,117,244,191,239,166,176,99,232,232,177,165],[181,150,145,0,229,163,63,150,67,149,111,124,226,157,188,106,251,58,86,27,151,110,124,124,92,186,126,190,22,8,34,98,130,4,149,205,129,234,235,42,34,130,99,254,225,154,50,168],[129,130,212,237,4,19,143,162,34,109,126,32,13,109,132,135,24,131,42,94,226,6,227,91,125,63,12,86,220,113,193,96,32,82,233,36,77,49,226,162,236,212,195,237,14,17,45,163],[109,38,171,114,220,174,221,97,230,198,1,170,7,184,107,136,113,230,183,139,104,204,6,18,47,203,220,159,175,40,149,34,231,139,173,200,134,21,13,43,100,134,167,228,253,75,137,151],[6,197,222,3,136,175,84,208,10,212,68,203,118,79,71,188,112,99,103,21,82,116,114,122,223,168,99,208,74,27,145,66,130,96,171,183,143,247,173,42,250,126,243,50,24,144,206,150],[202,195,170,238,2,185,169,249,181,243,138,32,165,111,66,21,94,119,75,40,7,108,92,82,179,148,181,115,237,112,116,242,12,140,191,136,31,29,143,148,18,161,127,250,60,159,34,168],[173,140,72,142,200,228,34,34,16,2,56,43,56,194,240,179,32,47,105,255,113,8,128,212,216,54,42,139,34,50,48,171,243,35,193,238,107,48,19,189,66,22,113,216,27,72,48,181],[194,156,76,221,134,77,151,80,137,72,60,247,114,96,143,136,113,109,176,86,145,124,166,210,11,23,109,184,220,174,191,171,25,118,113,4,175,171,100,154,175,138,212,214,167,181,144,166],[141,67,177,53,57,149,42,31,84,201,82,139,56,171,70,14,18,232,1,37,34,205,131,94,108,219,25,78,37,107,28,77,220,77,20,223,48,156,201,201,179,255,199,44,185,69,241,168],[32,147,77,206,60,56,143,75,222,172,5,51,93,128,14,204,243,92,220,250,100,4,145,174,131,128,231,82,73,204,67,146,252,103,118,3,116,211,134,153,149,253,188,144,203,180,42,184],[126,204,49,218,114,71,53,97,254,180,125,131,38,43,215,161,51,41,156,37,168,130,6,244,132,86,115,50,187,229,93,94,111,182,27,249,10,153,29,53,67,56,31,9,200,52,26,173],[5,234,218,121,8,56,249,101,87,45,203,250,32,86,145,201,136,240,171,40,75,26,82,124,241,167,1,89,159,220,39,90,65,77,107,182,219,120,1,137,80,141,32,239,158,3,140,135],[136,9,233,146,66,51,144,192,39,211,180,188,174,21,174,83,30,219,83,5,157,60,140,12,103,128,34,85,13,30,87,27,195,128,252,217,121,30,163,18,26,141,179,108,163,161,208,138],[119,241,20,163,172,243,169,145,217,219,171,208,93,133,238,69,23,232,101,173,227,81,208,16,141,173,162,77,178,79,249,196,222,110,57,245,224,247,103,107,108,249,202,130,98,143,229,138],[151,40,100,28,255,100,36,192,32,100,129,106,73,103,158,53,183,250,51,176,209,176,55,28,77,125,219,66,140,32,57,92,228,165,149,158,125,69,90,55,17,237,174,95,190,208,249,182],[220,49,102,13,206,45,28,213,126,186,139,181,124,186,104,230,138,161,84,191,129,14,218,7,86,190,24,119,248,46,64,120,224,64,138,15,103,225,111,154,208,19,254,9,97,94,226,183],[132,10,106,197,109,149,90,112,197,9,106,246,93,140,93,7,104,173,36,245,20,125,84,108,96,187,201,52,20,230,10,188,165,30,83,4,49,112,101,161,203,6,129,47,180,149,114,134],[2,247,18,108,215,132,220,159,199,226,208,114,89,97,139,157,217,41,108,157,139,16,5,206,210,73,13,110,239,174,105,132,123,178,18,121,229,131,9,167,176,128,115,149,113,246,115,168],[204,29,110,9,18,156,175,160,23,160,135,130,232,127,147,142,88,124,211,193,20,126,140,250,83,52,50,239,37,27,80,135,111,111,179,42,134,82,115,166,193,29,18,46,209,60,47,149],[7,108,150,13,96,9,27,238,204,255,108,123,181,51,45,0,63,21,246,92,170,237,216,61,80,27,171,73,128,226,25,176,26,157,11,65,133,49,63,95,97,5,170,23,225,63,32,174],[58,177,218,103,29,245,14,18,14,12,130,245,110,185,195,214,210,108,58,240,117,204,95,122,5,65,174,2,30,173,200,43,30,164,174,165,77,151,14,227,113,195,45,84,121,206,123,168],[113,124,78,119,72,23,129,148,185,139,167,26,210,162,138,240,176,222,72,147,8,58,233,85,64,148,37,218,33,60,94,171,224,132,185,238,149,46,59,8,71,15,233,194,16,66,160,139],[134,158,20,33,207,36,173,146,106,46,224,109,44,222,177,61,92,4,244,66,85,147,219,198,117,235,116,110,184,202,97,101,113,22,71,200,111,100,94,74,219,200,99,243,57,246,130,166],[44,67,226,14,122,92,101,229,56,115,211,134,78,162,41,129,112,65,197,210,255,140,80,192,53,130,241,147,44,88,232,35,151,20,64,20,152,38,232,56,154,186,230,142,26,6,59,184],[150,63,63,90,139,200,148,9,88,99,198,199,113,251,160,237,208,151,215,213,115,224,34,19,216,136,149,212,52,140,68,65,178,146,247,96,222,26,195,217,28,156,44,85,199,109,172,146],[100,188,9,144,184,220,9,117,205,156,43,36,43,74,201,6,51,76,96,213,69,79,19,251,95,224,109,27,157,239,226,241,29,65,191,86,170,220,210,236,76,188,255,148,236,103,177,175],[63,78,94,114,233,154,36,25,128,139,84,85,176,130,19,62,4,198,97,98,219,220,82,38,28,1,249,164,17,22,201,205,78,153,214,184,18,43,96,94,71,11,241,195,168,84,247,172],[33,110,14,205,117,188,244,8,105,50,154,40,172,215,242,209,164,100,220,210,187,61,48,7,201,41,166,65,205,112,39,233,88,4,204,65,89,17,79,224,50,200,205,221,95,161,84,174],[205,102,232,233,230,122,180,215,187,213,95,253,186,230,70,98,181,66,203,108,137,10,33,185,34,157,111,244,35,46,88,155,254,143,141,200,251,120,178,48,214,252,160,153,211,237,69,170],[9,102,200,194,238,196,178,77,50,240,54,144,25,130,98,224,182,228,207,22,65,159,172,64,105,123,88,1,250,104,94,182,110,81,208,83,51,8,192,65,24,26,43,151,148,112,95,141],[7,220,43,215,16,69,92,251,99,193,211,128,185,120,24,63,251,153,125,216,6,178,216,118,54,233,122,30,95,231,43,122,169,164,119,136,180,18,160,31,56,227,46,120,156,8,122,183],[164,197,139,66,144,73,88,8,198,31,241,75,217,225,95,233,212,7,118,190,138,18,39,132,157,165,24,189,152,56,207,116,227,232,22,29,251,172,174,99,179,96,116,229,78,20,12,148],[102,108,195,173,121,10,81,211,91,130,232,213,136,100,219,156,62,211,148,35,118,63,179,160,123,255,120,249,4,38,213,231,189,137,202,166,250,137,13,69,44,80,145,5,200,139,17,166],[160,83,64,117,143,138,214,218,71,115,200,214,146,4,238,212,56,125,173,24,96,166,228,97,65,65,141,90,210,19,30,20,247,21,111,125,85,226,97,37,109,20,22,57,161,148,123,131],[64,99,48,78,229,143,38,16,248,194,19,201,114,82,220,233,71,182,56,192,240,54,39,127,134,180,169,175,126,106,192,89,126,215,219,85,10,200,122,37,92,207,96,198,165,11,69,129],[197,69,123,32,182,42,24,231,85,114,237,87,96,53,163,164,231,181,1,126,232,218,232,2,144,209,40,129,236,154,222,69,227,18,72,207,199,16,161,226,254,12,110,232,146,183,19,171],[247,190,215,203,172,250,131,16,195,201,29,162,93,205,249,149,202,244,71,142,0,202,102,68,91,180,166,113,245,32,99,216,150,19,226,78,47,124,166,230,79,21,122,143,4,138,68,168],[230,178,8,187,226,29,114,63,79,230,214,179,241,209,254,184,42,202,255,90,87,104,148,77,146,65,104,169,0,99,199,181,230,67,174,22,61,151,170,163,155,164,27,205,243,53,83,149],[19,246,91,100,67,237,42,25,36,253,194,72,200,138,111,53,16,117,147,107,96,98,78,109,46,183,97,61,120,79,35,161,204,128,116,212,12,199,100,166,120,139,60,182,45,177,21,183],[126,102,188,26,144,231,60,0,82,181,250,204,237,20,2,206,162,79,196,213,200,182,179,171,156,201,80,8,137,229,19,123,41,61,29,26,240,144,133,135,85,85,190,188,95,252,216,182],[34,201,244,20,93,139,26,97,208,10,231,57,101,188,90,193,248,56,72,120,141,248,227,4,69,74,231,16,221,124,130,191,136,3,53,27,180,175,156,166,184,197,197,129,205,115,38,153],[71,56,159,102,174,128,7,42,13,39,198,154,16,242,140,111,103,24,167,196,35,102,40,182,213,255,172,95,167,77,55,205,174,0,208,167,211,106,60,158,60,149,39,239,238,236,25,143],[75,95,50,137,33,243,244,141,9,0,103,125,22,187,137,100,149,114,145,224,212,184,8,187,230,235,120,233,81,106,79,49,116,40,70,28,111,88,70,168,216,210,225,123,49,211,179,176],[206,7,110,181,61,132,176,234,136,50,158,242,11,98,111,14,95,39,203,136,5,205,39,99,232,5,177,221,103,16,121,23,102,3,95,203,53,244,138,10,68,189,251,255,87,206,209,180],[163,230,19,221,253,160,6,46,213,156,203,204,150,74,239,33,46,122,81,17,206,209,116,223,68,60,11,121,250,175,221,193,30,110,83,121,148,60,145,210,21,46,233,117,146,120,178,184],[219,91,24,44,207,249,92,48,200,168,114,76,72,56,11,76,125,25,122,121,123,119,237,241,247,188,199,210,167,96,85,123,182,14,211,191,85,88,55,106,73,8,127,205,123,202,63,182],[185,154,12,254,187,69,136,126,36,143,172,45,80,108,221,174,63,136,154,108,208,87,116,94,228,122,99,253,253,103,179,201,180,14,115,22,151,92,233,25,4,60,9,33,137,146,147,135],[176,10,82,62,179,190,192,120,230,239,200,107,174,5,131,222,168,203,75,91,106,21,112,61,113,73,49,120,53,37,143,46,207,217,135,94,5,60,172,238,165,114,248,21,183,87,24,151],[161,15,211,253,54,165,90,165,202,183,170,49,215,101,217,252,223,139,90,98,121,85,229,136,6,188,14,163,187,1,151,47,40,215,76,152,198,0,68,13,149,12,229,35,236,254,168,153],[3,76,215,241,188,252,182,237,64,172,98,200,162,62,54,55,194,115,128,210,251,109,141,121,64,200,122,88,165,136,223,208,181,197,4,237,73,23,53,106,180,238,23,176,90,255,213,148],[160,210,94,142,18,229,132,0,121,199,228,42,36,209,229,41,6,242,159,224,21,83,250,136,28,170,30,24,10,124,36,89,116,125,69,61,195,107,249,179,238,173,203,145,244,191,28,182],[193,102,187,156,160,146,124,149,134,88,205,211,24,245,3,197,200,236,96,52,202,204,1,9,198,176,143,52,90,102,122,254,146,111,167,110,49,62,85,246,53,198,39,250,37,197,125,138],[64,46,28,185,206,137,209,111,43,215,223,71,148,113,76,128,2,47,172,129,245,184,231,193,108,76,13,183,8,182,200,86,224,170,133,215,73,91,168,67,128,79,167,253,9,44,110,169],[220,115,113,110,39,56,128,138,4,136,190,84,9,118,42,27,100,20,0,144,219,132,85,19,177,4,72,181,60,173,185,16,226,37,210,175,185,223,0,180,170,211,181,28,175,167,28,146],[56,48,170,204,127,133,11,213,66,68,131,50,95,84,13,125,221,79,229,17,217,191,155,24,170,254,249,130,68,50,151,28,233,233,166,70,195,115,87,15,199,183,248,66,64,158,158,172],[196,68,129,82,114,0,10,151,238,189,156,205,123,127,183,2,135,57,132,217,170,230,176,252,233,141,237,180,237,179,223,105,146,168,16,245,234,120,85,211,73,218,131,12,13,8,191,164],[45,239,11,75,30,7,137,250,158,100,17,158,42,224,183,20,128,200,28,115,122,60,67,83,73,101,178,188,27,232,97,35,42,50,228,188,206,187,102,165,46,49,201,191,77,235,143,179],[186,29,58,61,11,67,218,58,78,236,113,238,145,227,142,25,101,208,94,131,124,227,236,151,13,146,253,12,150,34,83,66,168,253,5,120,202,84,26,133,157,54,171,45,109,74,152,172],[48,111,73,0,76,70,106,199,28,19,225,158,115,168,115,42,184,191,151,78,51,134,10,239,148,240,150,213,203,229,174,163,55,94,209,186,40,141,223,31,69,190,147,170,114,20,114,132],[176,130,246,95,191,138,116,197,40,37,202,27,91,171,135,3,136,208,204,152,31,153,225,226,12,8,105,9,238,84,191,227,51,150,82,42,120,84,102,189,75,13,192,201,181,195,121,185],[212,186,46,71,35,72,173,228,106,230,20,158,122,163,62,3,74,79,35,68,68,231,62,141,34,92,165,240,126,42,203,110,28,187,162,63,112,115,230,88,201,181,48,151,249,150,250,173],[159,200,105,15,144,14,5,178,179,202,147,4,173,173,211,55,174,24,115,170,71,132,218,36,148,91,141,203,46,213,161,53,67,23,198,5,95,108,172,40,109,34,230,126,45,206,211,173],[103,141,213,86,173,52,154,68,219,193,209,229,5,234,4,79,205,128,108,91,226,115,49,113,220,85,122,203,44,91,179,232,192,158,190,129,161,204,249,170,236,3,111,87,23,69,75,175],[243,192,60,172,90,51,11,48,216,107,163,185,114,62,63,230,65,76,39,169,183,79,59,93,170,144,169,1,63,221,124,251,103,236,70,211,169,4,103,140,7,210,68,28,218,71,5,143],[108,72,87,239,81,124,82,163,62,28,141,236,26,95,202,76,16,78,164,102,38,39,219,123,160,101,158,100,5,19,120,115,13,58,162,50,38,173,139,126,192,36,126,86,244,16,11,179],[170,189,172,93,251,234,1,180,169,118,234,225,122,195,231,123,212,190,56,168,107,6,204,134,149,55,18,136,81,127,160,31,33,82,202,202,41,81,48,99,116,224,109,3,142,162,160,167],[189,43,74,238,164,215,71,86,90,86,238,25,177,196,166,90,250,20,239,61,165,79,46,127,177,3,200,250,100,52,248,177,99,38,33,171,43,51,201,14,114,116,197,177,145,48,80,151],[6,19,181,242,186,21,24,182,217,60,19,64,74,203,132,249,137,166,250,143,3,210,25,27,3,181,127,129,64,70,226,63,223,88,206,246,26,242,82,177,78,130,171,219,114,214,255,149],[227,121,225,249,198,9,69,199,208,143,227,61,187,155,110,4,63,27,57,185,255,78,23,91,62,31,240,182,211,236,54,243,51,164,71,92,216,81,226,239,100,133,88,254,93,170,47,139],[250,129,12,248,135,157,57,146,245,233,124,153,217,197,173,96,232,153,184,148,151,147,14,229,160,20,251,31,218,32,176,37,18,120,113,144,35,71,77,224,220,215,247,195,181,217,203,160],[239,100,108,241,125,52,31,178,109,126,104,76,112,9,151,102,86,24,149,130,201,146,70,11,218,193,138,84,120,164,226,44,190,12,26,134,214,215,243,75,200,160,140,158,179,236,74,137],[253,211,38,182,159,85,154,12,178,178,235,209,161,12,186,140,159,223,116,15,164,205,149,34,182,140,88,66,84,90,1,254,220,158,168,38,112,231,88,103,93,161,190,197,114,6,16,136],[206,241,5,65,244,126,51,255,119,194,184,165,223,233,108,87,33,102,109,5,159,3,25,124,80,132,211,87,95,129,71,142,136,88,63,106,232,221,243,102,243,237,90,2,16,126,187,176],[170,246,166,105,139,183,178,13,179,223,20,137,209,172,157,135,132,134,137,74,215,97,135,118,110,167,60,253,251,89,242,42,224,248,20,143,151,56,109,162,132,182,92,206,175,150,85,137],[250,44,6,163,194,91,72,32,13,53,164,161,50,158,163,72,0,5,198,104,229,122,101,141,180,94,52,190,246,166,11,66,58,84,17,107,8,19,35,155,82,243,118,60,136,235,63,140],[83,66,62,107,126,19,65,105,109,103,177,44,110,39,97,106,221,128,128,67,62,247,239,67,29,188,63,17,53,91,97,63,144,9,248,202,56,153,221,4,16,146,182,33,37,214,240,166],[127,21,52,216,108,157,86,104,140,33,204,112,132,37,22,243,34,154,167,144,109,35,101,118,138,215,20,0,58,29,21,207,84,211,148,119,53,77,34,159,135,228,112,27,127,99,141,139],[61,0,209,222,216,50,141,105,211,247,144,46,19,11,187,77,96,226,104,245,48,173,198,50,199,115,237,128,178,131,108,181,71,213,0,109,145,93,119,232,243,57,55,29,14,214,8,165],[39,56,206,152,237,232,108,67,98,200,76,150,156,237,8,1,124,210,27,253,15,210,136,166,168,76,53,184,198,235,177,183,105,128,239,240,81,67,2,184,183,52,246,200,158,154,164,161],[213,214,189,41,216,102,86,211,218,10,250,155,174,140,69,245,113,251,130,21,173,130,3,169,92,202,123,120,141,96,74,104,105,53,106,76,171,67,11,255,197,153,188,153,195,220,118,169],[64,0,140,86,29,149,63,221,118,11,88,117,187,165,93,17,208,243,235,185,123,158,96,68,14,70,74,132,245,235,112,49,216,5,80,72,222,64,191,139,58,41,23,251,225,202,12,162],[221,167,165,25,6,116,113,167,202,84,26,92,253,86,248,226,227,147,151,132,110,99,26,172,201,115,189,124,24,203,99,185,185,104,193,47,224,60,248,140,124,229,150,158,245,74,141,171],[116,17,36,180,107,224,143,28,94,195,254,250,117,221,253,55,129,105,206,174,138,22,22,76,46,76,86,181,125,157,214,196,74,130,221,159,13,130,230,140,150,127,118,184,195,168,241,160],[9,85,151,230,122,119,90,122,95,25,59,29,215,208,221,161,225,208,3,57,201,179,28,168,187,133,62,151,201,226,228,127,216,50,65,45,149,88,178,77,246,98,112,98,46,190,20,160],[45,91,115,41,170,86,160,234,217,173,62,130,195,123,93,186,218,158,211,77,246,188,108,195,195,83,71,207,46,89,1,36,218,109,18,38,207,38,193,177,179,116,26,95,174,65,246,162],[44,18,233,253,69,219,247,160,97,36,253,119,168,241,133,61,29,177,145,250,224,18,94,190,76,117,8,169,153,137,218,152,248,164,221,187,237,210,205,178,225,233,123,191,240,3,166,168],[242,88,156,188,3,79,153,45,68,32,56,184,133,118,209,93,122,127,141,134,200,221,121,188,108,141,152,42,222,250,233,68,12,209,4,23,66,218,145,113,240,160,226,84,28,175,11,181],[21,232,198,183,122,173,61,155,170,83,237,157,21,70,225,57,130,191,242,157,108,140,244,125,224,137,240,121,108,254,168,80,0,237,55,9,36,241,102,42,214,18,26,95,101,132,101,176],[111,7,227,16,126,10,212,35,161,140,96,42,149,226,39,196,210,60,89,51,144,119,146,113,222,64,182,195,120,90,141,26,28,6,17,155,223,240,127,211,34,14,126,22,137,13,109,173],[146,166,240,209,81,56,16,34,84,14,67,119,75,249,23,20,92,26,108,166,246,203,139,135,180,192,122,209,197,83,147,222,228,49,170,129,153,29,113,132,39,14,49,82,235,110,214,175],[4,193,214,61,161,76,143,243,42,124,139,72,121,102,118,132,194,158,45,52,46,225,245,213,123,168,92,233,17,87,185,156,132,48,133,71,242,2,110,16,207,237,125,151,179,214,85,146],[72,17,168,203,75,179,26,79,77,12,37,105,63,253,18,172,227,156,174,136,163,97,225,249,21,173,119,70,140,189,111,66,185,115,182,7,59,120,84,97,88,145,186,130,160,225,22,148],[152,128,178,225,90,212,101,8,143,22,35,237,182,45,141,126,56,251,208,74,18,249,207,220,180,139,230,72,155,130,75,139,189,0,51,78,57,150,7,130,52,20,210,253,118,227,246,150],[118,125,122,110,209,128,168,53,184,184,209,209,181,236,191,177,161,173,75,113,152,50,51,215,199,0,124,4,189,223,42,79,183,229,161,234,252,200,150,188,129,5,224,231,17,71,215,131],[72,248,58,174,153,68,43,62,127,141,186,50,233,109,198,7,135,100,98,82,67,41,50,136,32,212,38,197,107,39,148,74,79,174,0,219,244,218,117,177,121,123,214,110,4,81,86,150],[102,5,163,216,194,161,232,212,109,162,23,11,245,208,223,113,175,31,174,169,83,100,19,150,122,230,212,164,203,159,186,192,114,209,185,46,235,237,43,134,228,219,110,138,124,75,125,168],[169,193,112,196,184,47,97,125,58,19,221,161,15,206,166,77,182,156,17,214,245,156,28,199,65,16,100,137,15,37,95,219,248,61,47,211,94,4,39,92,234,131,172,170,184,69,223,129],[184,208,155,245,182,73,67,65,112,156,239,107,167,107,254,205,226,212,45,10,7,35,207,124,85,210,190,238,143,159,175,98,181,183,8,223,135,20,5,141,252,142,77,69,116,71,14,148],[203,126,121,64,251,213,177,81,35,114,38,219,86,190,207,74,151,187,233,1,67,73,232,93,129,122,158,33,140,152,212,213,219,192,28,43,86,65,208,173,55,74,152,244,211,145,191,152],[172,82,72,202,29,45,88,186,243,219,96,205,234,233,170,161,111,139,148,71,141,31,141,71,84,229,124,70,159,46,139,117,195,43,169,88,163,233,74,45,78,202,161,9,205,43,47,139],[156,163,94,205,1,34,241,7,117,250,92,170,103,2,48,234,76,115,253,112,77,216,99,185,190,36,169,84,122,137,189,156,40,67,232,255,83,78,96,58,161,243,57,60,42,74,177,142],[250,231,203,241,112,213,97,246,70,79,57,85,220,87,247,176,24,53,115,23,233,35,13,139,168,81,37,226,2,126,223,125,125,148,231,193,82,244,170,61,144,155,217,105,213,37,200,149],[249,86,66,207,29,170,248,212,121,173,102,157,229,53,32,72,36,108,151,75,168,68,211,111,163,148,40,217,168,44,55,97,74,160,205,64,140,230,241,212,162,116,90,242,206,209,175,140],[226,182,44,161,101,190,194,120,181,68,173,61,197,249,243,140,196,191,117,17,39,49,156,216,178,187,86,143,247,27,121,56,173,173,194,22,14,18,135,51,22,128,109,179,123,87,63,160],[198,243,201,112,35,64,115,118,91,113,169,255,126,179,206,228,35,172,15,73,120,134,36,239,232,89,168,254,154,178,215,69,74,157,175,120,166,61,1,67,216,114,117,23,169,113,133,165],[30,10,83,107,224,17,229,17,149,46,117,54,1,155,86,247,188,189,191,222,135,116,148,246,75,149,58,176,60,104,168,0,223,77,249,187,216,252,7,146,43,208,218,123,249,218,212,176],[129,135,218,87,224,234,125,179,111,10,38,38,21,135,78,40,85,144,240,146,54,239,16,13,51,214,45,240,253,84,224,228,15,65,106,168,181,117,132,51,255,65,191,255,211,187,22,130],[54,11,18,212,193,139,61,95,176,123,172,71,126,244,138,30,109,18,16,10,159,1,222,81,62,170,96,81,157,180,184,209,96,76,241,121,198,222,174,20,124,218,243,164,162,170,9,176],[65,100,93,218,116,111,36,105,245,247,197,190,240,206,49,224,24,32,222,98,35,70,24,145,221,45,19,170,170,201,191,76,42,138,233,10,149,11,57,183,165,107,34,3,221,33,178,184],[181,15,97,201,135,20,36,162,92,51,94,88,54,27,62,47,226,70,128,46,33,81,114,36,254,31,143,218,172,122,144,7,239,67,145,0,102,28,180,45,94,89,229,163,81,173,33,147],[252,153,196,138,70,122,0,135,232,232,123,203,66,137,84,24,46,138,42,252,94,220,170,92,149,59,171,44,237,46,136,177,68,74,96,222,116,241,56,9,39,227,56,73,160,55,155,133],[15,108,31,94,39,48,183,62,125,86,26,172,144,115,195,108,228,229,21,93,50,27,110,6,85,62,187,198,27,24,13,97,62,230,239,139,213,68,254,154,68,167,159,242,205,158,33,182],[160,69,160,172,130,147,209,99,73,88,20,170,99,140,48,83,134,29,98,168,111,221,174,210,146,44,150,3,109,156,111,20,214,83,19,52,236,61,173,222,247,255,45,168,34,218,68,169],[202,171,41,132,246,35,249,189,134,157,90,198,105,122,200,7,36,87,108,18,54,254,123,159,54,141,30,73,9,98,12,91,228,145,125,134,87,98,202,101,189,143,12,38,204,79,139,160],[240,178,181,227,75,190,232,243,172,106,247,133,245,122,214,221,118,146,64,162,110,191,197,14,70,1,165,175,201,187,158,174,67,34,159,59,250,26,231,216,53,65,164,244,228,3,123,178],[227,165,247,107,103,91,57,206,161,190,130,116,87,214,109,66,117,43,14,38,65,127,27,87,1,192,15,203,60,27,47,129,172,26,33,10,138,75,69,149,161,107,191,140,91,135,234,143],[53,229,135,71,166,180,85,44,53,222,97,173,247,2,149,145,64,185,61,67,242,115,139,184,78,34,178,23,125,194,133,48,29,22,134,63,15,7,96,108,35,68,117,41,70,244,220,183],[24,238,210,119,63,87,186,39,72,4,126,115,190,96,20,4,159,177,94,176,228,166,223,118,92,116,8,2,70,152,49,228,173,60,32,254,93,36,128,123,159,48,61,229,192,27,130,161],[143,103,171,52,37,225,80,192,57,24,146,203,163,54,41,216,106,28,245,159,143,32,77,208,217,83,123,185,34,47,179,63,190,80,234,196,171,152,122,207,190,51,186,239,228,50,149,138],[12,238,142,164,238,123,210,241,7,20,42,5,126,1,144,71,192,99,160,143,1,21,215,207,177,89,167,49,145,85,75,227,56,246,20,50,173,13,121,183,151,246,87,200,185,221,135,170],[133,86,138,43,140,194,204,232,234,249,206,238,248,149,125,43,19,203,132,202,152,218,221,159,34,142,78,13,22,164,202,179,140,69,210,217,247,235,158,159,43,100,64,249,212,91,68,136],[124,83,78,229,158,55,61,106,232,172,109,26,206,22,235,93,2,34,121,144,16,84,153,95,35,206,97,213,250,117,25,64,215,27,182,129,250,150,134,221,0,151,160,155,46,157,177,144],[52,157,207,232,35,62,176,206,184,164,176,86,234,209,139,201,32,1,156,208,253,143,103,62,149,92,24,69,71,188,149,158,105,4,1,36,149,187,98,84,72,192,120,14,200,143,174,161],[150,66,217,93,51,68,140,168,19,216,10,140,254,198,143,24,16,21,67,112,11,185,114,236,6,72,82,5,37,25,216,88,234,219,13,222,9,137,73,210,10,250,39,198,101,181,166,139],[78,0,3,186,162,2,151,86,20,36,221,18,94,199,85,161,118,77,79,189,120,52,110,112,71,90,44,190,243,33,239,108,113,56,36,93,186,58,107,80,97,8,152,145,164,80,97,169],[120,211,227,243,130,150,14,200,127,243,152,144,195,36,11,87,59,145,56,83,108,102,151,253,150,101,152,194,52,179,176,34,46,62,3,186,0,49,8,54,186,2,54,176,66,152,70,185],[153,136,230,85,8,82,90,194,129,63,14,139,42,84,20,218,130,109,143,255,110,1,186,47,38,194,100,155,63,25,210,88,179,209,219,83,13,242,132,26,230,242,156,181,155,233,101,133]]} \ No newline at end of file +{"finalized_header":{"slot":"32","proposer_index":"0","parent_root":"0x0000000000000000000000000000000000000000000000000000000000000000","state_root":"0x83882e1522eed275247e81c11991048313854f04de924ec21d8523954a07d266","body_root":"0xcfc05f337393c3a62425aa3a1fb3b7113c5da404d6a7f89edd41bfb5e14a5e92"},"committee_root_branch":[[86,129,244,105,55,145,204,110,41,118,238,89,5,110,185,150,189,45,149,248,58,234,168,240,52,197,56,179,60,156,28,146],[238,129,156,168,109,208,216,32,17,238,21,252,96,225,118,158,43,165,28,140,14,116,182,107,45,45,197,223,134,161,192,120],[154,62,126,57,57,157,54,12,199,230,118,173,17,119,81,116,195,56,129,94,43,82,59,142,203,254,56,248,190,65,195,7],[110,211,142,94,6,128,7,99,93,122,179,185,34,100,118,177,122,81,82,200,22,17,180,0,237,192,18,14,240,147,108,131],[155,36,233,182,3,218,183,52,31,229,11,170,186,135,40,250,236,16,108,30,173,17,32,146,190,16,108,215,239,76,73,95],[68,177,30,58,180,74,214,199,111,188,103,22,162,155,83,145,41,251,226,97,205,72,114,173,12,185,219,75,73,41,191,198]],"pubkeys_compressed":[[130,28,98,160,223,223,232,155,95,169,36,213,77,46,193,37,82,170,83,121,106,183,220,152,79,168,33,159,112,66,212,99,52,177,95,178,240,198,228,9,91,138,30,47,229,81,241,245],[134,202,167,69,210,146,194,78,172,205,30,136,1,157,20,74,49,40,131,41,5,87,20,150,171,160,162,101,73,127,139,71,70,54,165,113,231,1,225,131,115,234,240,149,53,219,222,8],[152,254,136,66,172,54,205,127,249,123,23,106,90,5,15,139,41,26,19,123,11,165,224,85,197,201,201,247,103,223,42,27,172,186,219,174,174,125,174,136,118,21,64,62,207,238,86,192],[168,250,70,159,17,111,22,45,50,52,8,56,19,10,16,71,98,68,159,173,6,214,239,226,21,198,148,165,206,123,141,28,157,236,111,51,239,141,20,126,171,179,99,133,107,135,72,18],[145,102,110,227,41,1,60,137,200,7,127,243,204,5,230,182,123,34,8,236,152,155,65,42,207,99,21,78,107,124,37,213,185,27,83,205,21,156,35,90,231,209,167,70,214,132,154,162],[128,71,99,191,238,204,157,32,38,51,234,238,4,198,124,166,132,22,68,141,46,129,179,187,88,225,4,147,84,86,76,14,113,28,124,150,179,105,107,113,174,175,124,29,247,218,207,87],[167,113,155,26,245,111,65,85,246,252,129,241,199,221,39,231,86,69,50,150,30,28,54,145,198,41,70,128,100,219,158,116,37,4,34,176,158,177,52,218,146,50,202,217,36,63,86,82],[181,64,105,160,57,113,59,244,71,191,33,10,241,29,123,72,94,185,69,95,218,150,57,213,127,152,211,6,197,197,29,15,225,230,172,228,34,172,245,234,101,77,164,174,182,71,112,238],[149,6,94,32,197,70,193,37,9,60,45,157,111,88,25,203,110,250,109,47,8,39,108,175,87,83,209,30,119,28,197,101,56,68,12,246,118,234,190,96,215,225,46,179,234,83,243,178],[170,190,24,80,2,87,114,37,110,124,239,49,51,1,65,147,193,252,43,188,144,124,165,78,98,167,152,224,11,227,237,61,25,198,131,220,101,100,246,30,13,129,98,194,88,253,155,225],[171,227,243,235,103,106,100,242,176,143,125,246,156,114,126,254,131,126,40,81,11,46,214,23,211,120,67,7,206,38,61,90,255,154,89,219,3,238,134,25,99,1,184,104,1,178,135,168],[138,116,206,213,225,95,190,128,10,192,56,121,236,67,207,251,119,189,193,30,17,245,141,249,137,237,114,120,247,35,147,21,235,14,157,17,153,109,96,71,165,36,196,127,162,153,216,12],[143,45,71,37,17,222,4,18,231,183,150,73,27,230,165,170,94,40,4,76,109,84,122,61,197,19,41,143,205,157,34,221,6,210,174,5,226,28,33,34,241,223,200,188,239,57,30,246],[168,136,125,187,33,35,174,99,250,79,98,75,199,248,83,164,22,115,149,38,232,6,152,43,145,164,39,143,74,151,70,165,206,84,223,175,165,36,192,107,189,11,247,18,60,169,66,58],[153,172,78,48,15,201,208,18,40,145,86,118,83,163,238,108,5,144,114,67,57,52,146,25,62,65,109,140,238,72,204,67,154,143,137,215,40,156,127,96,200,193,209,82,46,59,35,142],[140,255,49,184,221,183,179,217,114,90,161,138,48,183,183,26,3,86,50,115,126,122,31,50,142,102,149,210,87,11,226,213,236,68,187,156,189,240,197,204,141,106,120,10,221,71,76,182],[171,35,231,22,124,2,218,147,176,30,53,127,76,140,115,166,245,7,81,220,141,30,243,14,100,68,191,70,127,49,175,177,118,221,68,131,135,50,160,19,209,24,223,80,52,120,138,137],[175,121,19,154,115,72,97,62,95,223,204,139,231,205,2,77,46,177,17,215,151,152,60,245,63,3,142,79,201,133,155,119,221,135,244,162,1,245,105,167,247,240,75,171,223,141,202,91],[131,215,60,77,34,243,72,189,163,0,204,255,76,142,194,237,229,108,112,226,223,209,227,50,25,147,137,130,53,72,84,123,216,237,183,231,81,163,144,177,111,50,180,106,110,199,58,201],[171,72,2,117,255,95,49,16,89,110,28,242,241,237,175,240,95,197,189,210,3,8,119,132,159,105,135,203,185,76,167,241,240,7,88,247,222,36,27,99,140,110,89,12,223,157,29,24],[163,99,68,214,130,116,57,122,103,23,213,1,202,57,65,12,18,173,233,153,231,215,174,200,182,159,130,89,19,240,10,168,89,105,16,250,112,26,60,43,53,61,142,221,76,226,124,244],[145,205,42,14,167,49,33,139,69,43,113,121,87,137,86,147,229,201,1,60,61,170,2,85,84,226,102,181,106,19,221,50,137,239,246,17,207,97,228,48,22,139,208,56,92,203,243,58],[152,204,90,199,137,15,156,168,84,60,33,233,38,137,132,252,93,19,186,247,203,183,60,17,147,226,20,139,202,44,70,187,17,230,8,229,124,221,83,71,70,32,237,39,155,102,173,133],[146,222,89,17,172,135,10,33,178,140,37,22,77,86,218,103,253,210,228,135,117,212,74,117,238,159,33,113,140,249,181,237,193,118,178,47,50,114,12,129,220,18,43,224,19,83,47,198],[136,191,154,133,55,219,240,146,173,162,201,139,140,57,208,82,56,243,35,106,76,246,95,102,141,24,102,173,129,73,132,169,190,170,116,166,226,26,16,214,160,128,188,130,37,202,221,77],[160,219,92,117,117,72,162,175,195,22,119,81,73,120,97,149,7,47,183,172,223,119,103,79,177,125,67,137,225,43,31,156,118,10,9,180,232,10,216,169,220,163,65,118,70,63,61,183],[181,133,57,179,239,235,227,106,170,198,18,255,5,107,205,68,201,150,31,5,26,90,94,72,92,63,154,208,146,14,228,236,171,137,27,6,94,19,60,238,223,5,39,119,41,19,101,141],[138,63,189,230,183,231,231,39,32,163,1,2,230,136,166,110,195,81,146,0,184,87,212,42,148,233,219,166,181,109,164,254,119,164,73,1,93,127,37,199,155,176,67,29,140,32,212,170],[137,85,133,74,85,101,230,145,66,162,103,197,206,179,223,40,113,36,70,102,82,158,206,22,84,255,92,239,38,106,50,0,48,5,166,223,181,168,1,120,197,160,183,175,54,3,128,169],[149,34,214,141,198,135,152,218,135,225,202,223,170,42,12,142,168,101,41,239,199,174,115,235,126,99,204,12,19,37,175,95,32,255,81,145,84,214,98,196,213,89,147,131,149,218,169,46],[176,8,189,242,187,81,107,124,17,219,52,185,237,194,128,102,138,254,167,45,241,185,49,232,229,32,38,200,111,236,162,172,243,92,130,77,205,34,34,56,138,181,158,88,238,222,3,103],[176,143,134,162,250,244,51,191,27,135,222,110,23,187,103,176,27,197,90,119,253,95,128,33,221,34,252,229,73,186,152,61,99,86,33,225,227,61,107,71,86,61,195,254,168,151,130,58],[178,190,156,187,3,234,104,148,54,16,194,126,110,141,198,65,97,47,158,7,118,219,69,114,223,234,248,44,55,161,236,57,91,170,46,18,212,129,94,144,143,15,93,119,120,112,9,1],[132,73,140,152,152,173,107,83,105,132,17,19,174,221,175,43,177,17,4,152,158,154,111,85,101,158,106,165,9,151,93,158,169,151,13,66,150,106,253,239,185,64,250,234,203,60,20,30],[132,63,8,148,34,216,48,215,45,135,100,47,184,210,49,77,50,133,231,54,124,83,59,242,184,106,163,55,156,253,0,151,180,57,104,147,181,110,171,171,54,209,251,96,138,211,188,142],[152,250,206,188,95,201,194,129,56,37,220,233,185,117,149,220,21,41,240,26,186,20,110,157,103,113,78,106,152,8,136,149,28,254,58,176,141,196,111,142,34,59,194,95,160,237,96,229],[184,32,126,216,126,121,215,166,101,188,158,247,16,178,59,150,107,62,173,124,32,169,229,125,192,218,73,48,106,127,95,119,84,177,71,34,106,19,6,16,33,26,193,203,151,89,171,188],[131,143,177,130,202,213,82,159,36,205,167,149,227,23,101,158,4,200,139,203,60,212,11,198,51,136,78,143,93,253,101,183,106,241,102,43,154,30,223,183,86,179,24,216,90,244,30,229],[174,224,118,87,84,166,74,164,92,175,107,204,132,205,105,20,71,38,229,49,0,136,93,177,193,234,175,120,70,5,59,66,40,255,113,107,216,136,40,144,26,108,137,182,251,229,13,251],[174,122,18,215,11,120,174,63,114,199,63,156,203,93,14,217,94,168,76,3,195,7,121,165,42,46,26,237,100,1,214,219,11,132,170,231,232,79,78,26,159,231,139,25,181,209,32,20],[179,137,89,174,111,112,168,33,241,124,81,141,17,146,180,238,85,163,0,79,187,108,46,188,232,255,186,104,157,95,31,174,151,81,17,80,227,181,119,7,180,153,163,45,132,154,21,43],[174,75,140,252,255,220,129,107,129,114,18,250,100,186,159,153,4,159,220,225,24,193,53,29,24,75,63,170,177,76,183,53,175,93,207,243,79,172,87,125,107,253,31,249,167,219,116,178],[151,157,197,199,208,227,252,197,209,213,174,125,91,24,202,9,73,1,223,251,125,181,97,251,91,181,147,176,177,18,170,42,191,156,100,142,47,20,27,28,91,202,17,246,220,172,104,133],[132,227,22,249,59,19,68,82,29,100,13,183,39,28,123,132,156,239,100,98,102,95,23,253,249,199,178,152,25,62,110,169,134,130,86,52,8,127,4,72,67,186,163,217,72,163,47,118],[142,249,90,18,77,143,196,186,101,148,28,142,6,59,143,75,157,36,121,50,201,221,236,216,21,23,197,46,48,135,171,17,99,128,137,5,35,171,51,203,166,193,194,116,235,142,251,237],[153,48,249,134,92,246,14,29,208,85,59,81,170,211,14,196,6,214,181,108,67,149,225,51,17,165,198,43,54,34,236,232,250,9,147,86,128,158,109,191,247,40,45,52,45,119,225,13],[173,170,210,13,202,78,120,244,184,253,9,22,50,123,78,119,92,205,31,229,252,69,195,10,137,154,178,156,60,90,207,122,229,56,3,211,86,183,231,205,19,168,142,12,143,162,58,175],[140,209,19,19,218,211,26,50,131,228,73,238,99,217,41,13,70,184,191,233,69,129,66,35,96,82,127,55,169,110,146,183,13,103,243,47,246,89,18,45,243,82,246,13,0,128,56,174],[162,20,78,85,115,53,165,15,85,138,251,57,7,82,177,194,150,23,224,51,78,178,109,137,111,245,60,85,222,231,53,242,202,115,96,107,194,151,206,243,83,130,157,188,99,77,35,194],[165,107,129,136,73,210,42,69,21,177,222,248,215,250,199,196,242,64,60,35,102,154,143,33,91,25,49,195,46,165,194,168,10,183,0,163,214,95,96,75,199,107,31,112,46,169,121,209],[153,230,208,180,238,66,20,239,70,187,24,5,229,16,17,105,237,158,69,201,67,148,194,240,21,161,7,12,201,231,32,220,104,199,65,186,237,216,197,57,16,187,198,79,224,198,48,133],[148,228,68,42,212,13,8,102,121,32,128,230,47,118,72,20,174,96,63,212,208,10,153,203,116,45,22,92,108,193,195,166,188,189,27,0,89,152,228,86,182,185,124,15,172,5,10,48],[137,140,111,72,188,162,22,166,229,117,129,175,71,108,8,133,90,151,44,105,179,63,123,59,13,205,134,110,210,211,80,91,122,190,84,222,123,192,75,201,2,245,230,167,64,183,148,116],[141,209,206,8,185,105,177,4,238,18,51,41,111,189,70,207,138,87,65,179,100,42,64,120,171,222,20,151,143,94,188,252,116,111,172,245,141,111,117,143,241,223,171,80,194,211,21,9],[146,94,78,194,191,140,19,39,241,160,192,21,100,8,6,49,55,26,84,169,45,104,229,29,70,168,252,71,90,58,11,211,207,142,250,83,36,192,232,41,252,126,74,205,37,183,176,162],[166,81,145,82,24,235,57,187,171,238,76,185,220,13,164,87,117,52,104,108,79,136,198,127,61,75,26,36,88,134,34,24,253,196,130,37,97,44,226,106,109,93,13,223,212,10,215,191],[167,93,77,197,56,55,216,217,232,90,207,177,231,145,183,235,246,16,16,31,107,42,91,225,93,69,30,146,255,194,69,21,234,151,87,161,32,223,96,198,6,21,184,22,117,40,213,18],[132,95,160,39,119,54,163,152,225,21,248,245,75,107,158,231,53,49,68,79,197,227,213,217,156,210,185,195,97,183,110,124,56,231,161,130,208,59,129,234,203,86,252,27,80,146,86,22],[173,79,107,138,5,254,167,72,123,167,237,81,179,116,147,20,187,12,52,117,56,70,54,74,3,22,235,86,121,229,171,97,115,127,17,237,229,56,7,109,239,34,1,42,163,43,35,182],[150,164,59,243,93,161,135,99,131,227,29,211,160,178,124,82,165,44,174,216,249,212,76,4,253,66,66,91,58,58,119,185,127,188,163,181,113,3,121,31,179,51,93,199,33,83,227,83],[172,153,230,96,75,182,199,214,99,116,133,70,89,244,129,205,84,216,218,203,139,157,112,134,235,1,5,131,180,244,102,127,15,204,248,156,192,186,93,172,107,139,146,135,234,33,180,84],[171,55,135,243,209,210,82,101,130,153,123,28,80,241,105,3,238,87,99,21,242,204,38,133,104,194,7,16,87,196,155,34,101,235,224,158,174,152,222,171,183,43,50,44,28,74,135,190],[132,242,172,245,123,149,205,228,243,233,42,75,88,255,201,40,209,71,29,194,217,9,250,225,219,225,53,58,43,27,3,248,146,246,37,114,128,45,251,208,60,85,53,217,6,216,252,158],[163,17,7,208,52,211,187,85,196,67,97,166,209,75,161,179,80,205,203,243,53,188,148,158,143,241,54,251,65,67,81,22,8,236,107,3,159,143,19,183,72,71,39,126,146,181,121,41],[169,149,157,231,177,106,169,52,88,2,87,199,245,81,190,5,17,164,39,18,22,221,173,159,95,59,226,205,153,93,14,162,112,91,239,90,200,251,58,50,121,70,157,106,54,132,239,74],[178,209,254,201,182,204,175,133,64,86,108,44,157,193,254,88,149,17,6,44,83,120,242,77,27,93,95,116,236,76,110,250,1,229,130,176,80,182,196,8,184,95,133,110,16,40,104,201],[140,18,178,185,71,107,220,201,91,63,124,183,118,218,221,183,190,237,191,139,180,128,57,149,193,90,12,133,111,116,77,243,220,40,12,204,103,186,167,215,55,116,213,78,140,60,9,7],[183,54,43,148,153,55,55,27,74,215,69,218,115,176,153,41,159,22,127,254,29,138,253,151,203,142,213,179,108,24,99,76,204,236,31,157,59,249,87,147,124,12,251,69,136,203,196,182],[140,163,41,78,63,133,149,53,198,109,161,37,152,89,244,139,162,112,24,126,51,64,30,65,212,24,88,121,54,247,209,98,239,76,168,135,142,238,110,103,2,134,230,174,56,44,191,114],[161,237,240,146,84,172,198,90,213,86,150,153,232,106,157,246,139,202,119,183,191,159,162,12,28,88,74,163,50,250,73,222,174,50,233,150,171,218,214,129,61,248,45,165,94,6,197,181],[161,176,1,239,50,186,84,218,216,95,69,143,23,66,68,85,255,54,231,19,85,235,206,231,108,200,156,28,215,65,177,2,169,115,248,45,219,108,50,156,244,81,16,109,211,228,219,34],[161,80,183,4,215,49,119,38,180,159,209,21,197,204,188,39,160,137,0,35,96,225,93,32,192,185,167,181,185,223,130,87,144,144,182,105,225,135,35,220,39,66,61,245,80,224,253,50],[173,82,21,37,195,52,247,235,76,113,63,208,176,16,48,79,230,62,226,126,211,60,106,126,207,157,92,225,88,246,51,167,251,130,67,127,141,103,62,150,155,195,131,13,242,207,10,114],[151,86,64,219,62,67,71,65,133,54,85,47,105,55,42,183,26,185,47,24,205,189,40,45,20,2,88,49,154,200,178,9,245,6,138,118,96,123,176,83,170,206,237,220,29,220,162,185],[177,135,101,233,166,101,66,103,177,114,152,244,46,113,28,38,135,42,249,119,112,6,33,58,128,44,139,172,193,106,214,106,166,239,62,163,28,118,112,160,24,24,4,100,147,177,132,174],[174,88,149,45,87,180,50,191,81,144,9,38,37,175,51,26,27,200,132,131,11,82,168,160,88,215,189,164,208,181,169,195,157,227,170,184,61,78,234,153,227,251,183,24,244,26,170,6],[183,75,72,49,254,248,185,247,185,172,16,247,107,246,251,173,98,117,228,195,55,204,129,98,91,184,26,118,24,197,206,51,175,134,0,112,4,79,55,230,83,62,156,118,160,247,53,115],[173,92,72,222,134,147,12,255,72,166,72,85,74,232,163,37,245,38,110,210,28,197,142,144,169,196,236,241,45,190,73,109,231,236,255,147,197,8,198,128,180,68,32,4,235,103,54,91],[145,135,53,149,129,144,121,181,212,176,47,107,92,215,72,120,196,225,157,50,171,89,220,236,223,223,36,9,131,176,185,182,40,127,192,186,174,68,107,92,31,115,196,154,253,173,135,56],[178,74,154,87,36,15,191,98,47,101,122,232,22,192,206,217,177,150,169,237,193,187,146,226,164,84,130,214,9,252,89,54,10,139,99,66,110,24,214,11,27,205,207,207,217,202,94,113],[162,74,190,54,165,76,234,10,245,88,5,132,92,33,181,104,108,47,222,92,19,29,148,159,230,229,197,40,177,118,149,1,233,139,207,210,132,188,17,57,41,80,178,192,224,170,243,65],[173,203,231,167,165,1,146,199,254,100,210,226,179,241,203,144,171,138,222,173,164,66,7,182,117,105,174,147,242,213,104,154,93,103,95,170,242,137,113,191,120,141,177,104,9,9,165,44],[162,114,85,129,167,44,183,21,104,15,192,24,254,47,114,47,28,47,162,100,231,70,163,128,183,143,90,197,113,108,3,176,59,255,126,79,140,214,52,179,77,172,13,247,137,8,60,42],[165,225,55,135,38,185,72,124,9,88,212,151,171,21,243,121,40,144,118,144,35,173,166,51,217,64,68,124,218,18,163,127,253,122,73,155,132,209,98,174,152,139,134,238,87,139,69,213],[160,238,162,202,46,71,86,93,228,7,75,155,38,143,70,198,79,0,88,141,166,225,10,80,128,138,12,30,169,202,183,208,62,6,117,174,9,21,78,138,107,32,137,11,150,49,188,170],[152,135,11,214,162,175,169,68,191,203,56,240,80,249,48,137,214,210,12,36,213,55,139,119,50,253,183,192,214,9,82,111,68,203,196,170,43,13,65,193,52,192,186,81,250,164,251,155],[182,87,133,124,83,187,48,80,54,70,150,215,163,30,187,218,37,24,150,239,233,185,199,147,42,27,31,27,165,14,167,177,181,107,22,105,234,253,115,47,171,98,54,242,239,16,9,199],[144,98,35,210,157,163,107,60,201,40,70,16,213,80,21,232,217,6,38,142,44,224,136,114,170,190,80,253,243,246,98,125,218,15,45,154,28,126,236,26,115,214,157,35,50,39,88,163],[149,222,172,71,81,45,193,180,56,160,206,250,239,129,119,191,42,224,85,174,248,247,190,1,98,154,206,141,239,163,7,103,124,153,16,0,201,123,45,36,95,6,201,36,20,238,176,200],[180,153,194,184,98,181,71,146,34,212,174,148,235,30,23,36,98,37,93,47,57,227,103,45,178,108,133,82,144,76,83,227,196,25,172,244,17,67,95,231,71,92,96,60,115,122,96,189],[149,42,175,102,163,109,82,114,207,212,97,65,90,152,122,59,100,245,99,12,127,185,19,136,106,181,2,89,128,26,164,67,247,209,55,188,138,114,186,74,32,178,203,53,241,175,7,147],[171,216,61,56,67,215,83,105,203,177,170,254,132,238,97,255,162,80,156,50,77,161,32,143,179,18,176,174,175,231,175,254,77,211,143,57,39,239,195,5,91,234,39,167,65,70,168,200],[146,191,237,219,180,34,52,143,150,163,219,31,30,152,239,73,46,164,81,136,240,231,36,64,34,246,250,165,129,200,130,196,38,147,162,47,118,147,66,20,42,237,77,116,51,134,224,197],[130,235,44,221,220,45,127,139,237,248,67,166,228,107,1,243,39,236,220,214,56,167,236,72,132,206,111,141,179,152,89,93,223,104,17,39,146,184,41,187,165,190,201,82,152,181,80,130],[183,182,116,57,183,112,153,146,155,47,46,4,170,243,155,18,4,145,161,108,91,112,105,142,182,245,68,89,4,4,48,149,15,11,161,241,76,46,160,187,216,129,100,107,84,102,60,146],[185,167,99,254,161,40,226,89,49,246,233,26,119,42,119,58,88,128,114,55,193,138,105,178,106,9,144,55,22,45,215,68,161,240,9,19,222,148,77,140,7,21,50,108,182,58,70,235],[180,196,111,4,101,84,44,117,65,86,81,85,210,35,152,28,199,238,219,234,188,112,149,211,143,14,173,250,107,111,12,193,58,88,89,80,119,210,85,53,220,11,56,130,138,195,240,160],[153,188,156,118,211,137,146,210,166,67,88,218,47,98,249,95,94,159,22,188,24,188,43,84,165,131,209,39,37,108,4,180,130,255,243,169,114,248,229,8,230,147,241,7,79,55,145,162],[130,42,149,145,238,32,18,50,132,68,206,203,10,3,4,243,5,37,77,207,101,15,218,231,158,66,14,104,49,1,80,146,196,34,84,64,189,221,168,130,240,20,164,97,35,110,149,13],[136,227,50,84,34,18,200,79,250,60,59,98,52,224,74,216,22,107,78,245,62,187,163,177,35,88,214,65,80,161,187,209,106,163,83,209,196,245,214,193,248,236,248,230,56,102,47,98],[142,101,174,182,175,231,251,76,93,74,86,120,7,135,31,255,233,16,54,55,15,47,232,39,120,195,74,133,33,213,53,83,240,216,145,182,21,186,90,205,196,44,241,130,171,106,145,55],[142,100,22,111,47,221,250,243,98,196,91,142,238,180,133,57,110,123,201,123,19,141,197,132,12,244,124,160,219,57,132,192,216,38,72,52,232,92,170,5,119,222,243,202,195,190,215,74],[175,137,157,121,13,124,205,219,210,127,231,217,221,188,223,243,120,233,84,230,30,96,67,200,170,82,187,207,38,103,65,213,132,56,24,84,132,131,38,60,242,0,127,25,214,172,13,157],[164,203,88,60,43,137,8,87,111,232,210,170,121,214,14,96,118,46,203,44,60,175,87,144,140,196,1,182,88,177,10,57,166,28,245,212,202,169,3,148,15,212,229,25,109,180,76,133],[162,191,132,191,199,65,221,57,128,32,97,62,246,160,82,143,97,87,11,180,109,183,226,49,58,131,142,15,45,88,34,212,192,253,100,160,39,151,137,222,235,96,100,112,96,179,254,73],[131,39,37,152,58,5,101,245,50,155,64,51,70,132,121,132,11,169,159,110,211,111,111,123,181,90,67,229,125,30,234,50,81,255,171,148,215,170,186,209,180,221,183,81,102,159,15,52],[174,136,207,48,36,38,122,244,101,139,73,150,174,70,85,53,155,18,151,123,133,7,129,91,241,40,172,74,134,183,15,118,242,95,242,231,248,53,75,170,25,248,121,177,238,103,242,236],[135,215,161,26,239,179,62,186,21,111,44,108,125,187,51,235,45,144,185,254,46,46,164,176,136,180,206,114,147,107,235,198,180,23,149,239,11,90,15,199,54,73,253,207,173,189,229,147],[170,158,3,107,48,114,200,39,171,124,100,144,214,25,85,61,207,242,219,255,207,255,16,75,2,84,183,118,174,209,60,155,1,140,201,168,182,77,10,221,48,5,215,76,155,145,83,133],[164,254,176,202,52,145,248,74,7,15,92,47,193,220,250,173,255,109,212,100,240,151,157,242,194,90,181,80,116,55,131,219,101,120,73,145,195,106,12,28,127,29,183,179,193,235,10,31],[135,42,47,141,70,191,102,117,82,62,166,87,79,45,247,51,161,29,202,225,237,166,158,125,133,48,188,176,238,247,37,111,85,129,242,217,211,29,160,236,98,33,57,246,12,93,75,225],[151,14,175,231,73,7,209,43,216,31,236,132,0,141,197,25,17,225,18,125,224,103,231,3,206,100,103,53,248,136,228,218,145,220,102,30,164,169,149,59,168,66,0,23,104,10,188,174],[166,161,112,82,89,213,106,84,7,29,25,128,83,163,184,161,162,152,191,233,134,163,113,164,103,196,28,172,25,131,110,109,108,224,143,229,139,198,13,143,185,108,96,213,175,46,223,38],[129,11,0,228,126,203,226,88,49,126,122,225,102,8,38,9,48,236,159,5,20,87,104,96,57,71,62,39,222,211,112,232,69,120,73,19,224,73,25,205,146,181,95,62,218,148,8,65],[140,63,126,203,243,61,170,7,235,255,235,131,174,72,31,2,22,80,42,6,192,170,204,114,68,255,208,174,35,42,13,139,16,252,164,79,233,141,67,166,75,83,94,210,105,114,217,56],[174,249,144,20,17,248,74,58,84,17,90,114,90,200,183,171,21,229,191,126,38,64,112,90,223,181,114,52,239,185,180,151,107,32,121,83,187,38,254,233,198,97,122,242,127,41,47,142],[146,50,236,192,73,187,220,121,32,223,15,244,223,237,106,76,56,127,45,166,167,34,26,117,205,169,14,237,229,112,254,33,225,92,61,94,21,69,139,139,33,137,103,109,181,57,2,17],[168,106,69,246,69,131,219,196,193,118,101,235,238,188,135,50,19,158,175,17,85,222,22,112,249,142,46,244,121,149,235,140,67,182,64,189,235,210,165,92,159,156,186,179,144,168,100,31],[148,47,61,83,88,198,92,145,242,237,10,194,67,228,40,215,168,133,20,96,107,135,119,37,249,160,159,41,255,208,73,163,68,160,213,139,217,218,115,177,146,122,69,67,230,134,242,140],[132,179,194,219,56,234,105,5,28,96,101,187,75,242,172,121,149,99,50,54,46,42,119,204,248,168,147,64,98,145,4,86,202,203,1,31,96,244,237,1,185,59,255,168,153,64,18,67],[136,240,51,47,207,167,48,79,55,160,65,221,218,250,166,36,97,34,164,41,142,195,52,251,227,20,231,193,110,149,58,196,226,62,69,149,251,80,237,135,150,196,8,41,183,246,104,134],[160,94,188,150,3,46,63,93,50,201,206,241,244,63,156,151,229,224,49,209,233,58,153,240,184,52,242,5,51,70,120,167,42,212,203,80,173,240,45,89,239,94,231,16,232,207,244,203],[133,53,249,60,222,23,209,13,109,117,103,224,73,245,238,55,25,68,33,56,71,70,194,107,241,55,196,193,163,7,95,175,185,223,178,86,21,88,253,165,168,195,45,31,121,100,76,187],[153,116,80,92,9,221,205,220,17,221,164,109,88,95,185,148,146,112,4,190,113,154,97,153,156,77,79,159,246,34,20,40,169,122,73,143,242,178,33,246,97,239,203,31,74,246,140,237],[150,125,20,138,94,79,217,160,133,224,220,7,145,123,98,33,52,107,202,251,157,66,146,91,49,231,117,254,54,11,149,65,106,114,161,30,211,105,138,18,194,83,42,255,145,62,19,147],[148,78,85,201,116,40,218,97,59,35,250,130,101,253,207,152,250,195,221,68,147,151,7,243,63,32,140,103,166,24,246,79,224,22,122,17,47,204,35,234,21,223,59,87,25,196,233,248],[142,182,144,39,134,196,208,1,253,2,205,122,168,207,191,1,117,90,210,151,227,16,199,234,142,202,71,104,224,46,9,139,27,138,6,142,240,134,27,87,140,112,145,215,233,221,236,187],[146,160,252,48,71,23,205,247,137,88,206,78,175,142,170,88,111,217,100,16,28,96,165,14,186,92,10,249,70,166,241,255,226,58,131,105,11,96,11,56,130,27,159,142,184,229,106,251],[170,218,47,190,180,192,105,179,9,155,182,6,204,118,109,64,81,146,0,192,226,7,97,6,233,193,136,99,172,22,234,114,12,30,128,53,30,251,206,30,132,98,104,42,3,199,62,237],[144,110,255,91,189,26,180,194,135,239,117,188,138,199,39,161,227,55,141,36,147,66,237,148,206,104,21,43,144,242,193,4,5,217,231,165,186,188,39,87,173,166,67,103,244,197,183,150],[139,158,41,14,220,81,136,40,6,106,136,82,38,29,135,229,148,47,117,202,3,146,69,65,224,111,220,66,196,31,18,130,183,221,19,48,200,187,225,249,122,188,88,99,93,126,196,72],[149,50,206,209,31,16,161,224,168,191,8,3,46,221,255,65,23,32,246,157,66,67,244,32,165,203,196,137,10,27,247,4,19,133,146,87,32,248,84,97,31,58,126,208,253,65,20,249],[148,58,67,226,75,36,88,252,114,167,63,50,157,232,38,66,128,27,197,65,171,105,46,169,21,202,198,92,111,222,139,129,162,40,95,135,129,11,157,207,65,56,243,143,149,180,37,19],[175,8,201,149,149,124,135,121,15,225,83,251,207,149,160,171,101,92,65,213,17,250,59,196,196,121,123,168,228,159,232,27,5,17,22,55,19,255,242,120,172,138,253,70,210,17,164,200],[149,228,238,99,238,9,115,129,62,57,219,214,70,77,106,78,122,75,139,144,245,242,54,229,77,80,36,93,147,53,220,5,159,16,224,6,23,149,118,138,191,62,46,23,141,253,95,209],[147,241,123,115,196,101,213,17,65,56,176,53,138,241,19,99,102,235,70,95,185,240,1,147,214,131,86,136,82,161,204,58,237,188,94,103,238,91,22,27,239,213,252,98,4,184,228,250],[176,166,70,111,247,71,255,9,160,245,235,153,232,239,208,122,244,241,246,114,189,114,169,93,178,8,120,103,76,115,198,57,40,156,113,82,63,213,253,134,202,228,192,118,137,21,107,197],[162,187,84,38,184,98,240,208,137,15,213,198,60,223,62,250,19,146,116,193,78,171,38,88,136,254,97,188,69,221,194,220,201,128,220,38,138,146,44,73,239,138,236,12,241,228,106,216],[142,148,201,4,150,20,44,125,117,68,116,66,178,93,186,158,69,241,124,50,65,72,175,242,29,105,69,111,66,32,183,138,112,41,110,250,191,193,159,168,90,171,76,102,41,11,253,163],[181,75,178,107,44,159,127,229,36,190,22,27,0,29,207,67,225,29,135,28,171,125,113,63,124,59,104,224,181,146,39,214,43,99,69,14,176,41,107,41,63,112,145,215,62,107,35,40],[130,195,190,57,224,202,177,188,177,33,71,223,6,95,79,188,66,28,162,182,201,95,3,140,30,220,151,127,120,98,139,159,81,41,133,194,254,141,122,25,117,190,61,238,220,107,158,133],[131,14,41,2,62,208,48,68,81,2,161,108,60,119,44,229,13,108,24,61,231,180,45,38,235,186,175,170,226,140,121,114,168,80,20,123,255,243,175,218,73,146,153,9,92,71,123,162],[134,112,219,28,13,157,4,145,118,158,101,234,3,254,83,244,249,88,25,187,201,105,207,170,240,57,191,65,123,5,103,20,1,18,180,224,115,91,83,85,186,113,89,0,120,247,12,219],[145,122,158,251,55,212,254,152,139,2,47,141,82,231,49,71,211,178,125,69,201,145,101,41,12,116,66,134,65,238,185,32,218,64,42,115,8,157,40,156,113,45,140,6,180,238,137,39],[151,75,120,1,26,253,16,17,74,70,210,243,251,132,250,127,162,110,186,232,191,89,125,229,105,215,77,170,177,106,216,139,110,43,109,70,63,79,138,139,76,152,8,92,159,166,89,194],[181,199,103,42,72,114,231,176,40,222,134,178,68,82,164,205,251,62,232,146,152,171,155,3,100,244,171,124,84,84,254,61,167,29,100,44,185,134,125,229,127,192,223,44,142,198,191,220],[141,156,116,31,151,104,202,54,185,148,101,95,120,212,255,197,28,172,37,240,204,173,116,168,111,75,132,131,54,158,182,89,104,10,253,42,63,39,216,141,63,217,12,92,7,195,226,65],[133,29,198,115,131,192,187,108,245,58,178,200,42,235,61,221,77,244,233,187,42,235,3,56,100,81,204,169,90,127,95,234,106,13,196,166,52,80,111,49,143,206,107,24,167,62,16,65],[185,220,141,167,20,47,55,154,200,73,58,25,228,173,162,41,33,136,229,241,199,114,90,96,236,72,83,2,7,13,118,136,56,88,210,165,105,47,68,135,32,107,123,206,86,157,241,219],[131,41,62,125,21,12,29,95,104,204,179,217,66,210,46,186,16,49,203,218,122,176,248,40,59,159,0,125,87,17,180,19,23,210,217,120,119,239,198,78,31,255,5,1,175,141,167,165],[139,18,209,23,149,219,185,74,249,65,213,40,255,224,125,4,64,18,80,71,191,28,176,134,74,216,105,14,140,91,243,249,168,186,201,198,4,150,115,92,181,131,139,164,130,34,122,49],[173,221,154,225,245,142,61,156,96,43,233,168,140,34,171,115,28,74,40,180,251,164,56,8,70,151,200,138,103,51,246,54,171,30,163,111,129,175,113,249,50,92,64,13,42,234,56,206],[145,24,199,138,88,141,81,209,177,185,53,69,132,68,150,193,106,26,175,78,32,51,26,217,78,99,136,173,10,171,51,105,68,43,53,214,45,162,39,72,131,82,223,119,186,138,187,215],[144,118,57,255,47,6,21,69,24,252,14,137,85,119,215,92,72,100,23,2,158,151,214,7,82,180,252,78,231,177,35,4,139,179,155,102,60,89,235,122,117,134,50,216,84,167,20,165],[185,95,56,123,92,243,202,213,139,178,242,97,47,110,178,76,224,49,204,59,124,21,208,190,197,106,86,82,77,189,16,46,159,219,141,18,74,24,50,187,224,177,22,43,21,174,153,239],[169,236,29,105,57,7,45,30,202,98,55,118,181,186,129,24,148,52,126,147,76,140,143,82,207,94,51,35,132,228,85,217,74,80,189,99,130,194,65,103,233,118,139,15,134,34,69,152],[136,140,51,185,11,115,244,163,123,169,131,18,202,176,189,152,221,121,7,178,255,159,223,38,143,11,173,156,227,92,254,140,234,73,207,127,90,27,6,44,120,28,217,169,171,246,13,80],[133,42,200,129,215,146,107,68,91,42,126,89,33,149,34,213,35,155,26,213,200,191,25,42,15,71,62,145,231,218,226,172,77,60,50,78,73,151,135,184,107,155,187,253,165,50,105,213],[180,85,119,174,165,18,61,24,11,51,183,28,80,55,249,249,65,197,251,203,136,74,16,64,177,81,160,144,41,128,46,133,178,231,6,236,180,219,62,58,62,152,175,17,17,139,73,231],[172,165,66,114,11,213,196,32,13,159,28,214,171,105,170,217,155,171,57,80,115,106,94,241,165,184,106,102,165,106,126,242,202,46,125,186,200,152,214,93,230,205,95,17,54,121,4,189],[150,185,53,251,214,148,159,193,229,103,32,228,16,117,179,164,184,248,167,91,242,165,89,203,150,221,227,99,86,221,9,172,2,72,175,37,175,144,68,134,181,20,145,211,50,234,91,156],[174,15,222,234,177,190,77,143,166,171,242,238,18,185,20,212,225,31,166,104,120,117,215,6,239,89,0,107,244,231,198,110,13,9,191,135,104,232,189,127,153,194,27,193,161,107,123,109],[182,249,249,82,122,153,71,240,8,42,255,102,219,118,139,64,188,173,201,96,126,147,251,69,226,177,143,168,85,43,91,63,63,118,8,205,7,188,211,230,61,234,179,45,95,162,113,102],[163,192,239,195,78,193,31,80,119,8,170,215,243,141,31,252,91,187,220,141,147,135,249,162,87,173,141,217,159,130,48,209,163,149,56,47,190,238,218,59,244,221,41,249,8,1,84,26],[170,246,216,255,234,218,62,255,77,77,161,59,57,196,142,8,41,50,45,237,200,149,253,82,121,168,49,67,190,117,155,15,212,199,10,45,55,123,142,9,216,115,78,209,202,158,193,218],[143,72,142,143,180,203,92,65,216,6,252,31,7,202,169,104,154,47,211,17,83,248,115,120,167,68,4,39,58,114,110,238,130,71,252,235,79,27,106,27,187,91,29,155,102,188,191,184],[166,85,134,153,158,60,209,89,59,36,7,89,112,100,166,15,70,112,209,77,222,218,44,45,132,239,120,182,206,199,27,112,156,46,202,217,108,104,127,23,87,255,184,185,1,166,160,105],[151,14,145,92,25,222,51,124,221,238,25,125,48,176,19,198,49,192,89,4,166,215,137,205,140,129,136,19,63,131,13,78,14,157,57,247,21,197,153,246,144,6,231,243,97,19,128,225],[153,39,213,31,8,209,190,131,82,225,202,132,218,238,203,205,25,49,67,164,215,74,93,168,18,44,93,191,240,68,23,244,10,67,10,187,8,135,244,175,56,132,101,100,245,184,142,20],[180,104,167,160,44,160,83,167,4,48,103,64,232,161,133,105,148,123,20,25,225,212,48,63,183,225,33,2,93,180,180,148,251,65,115,202,210,70,165,118,243,52,212,132,115,248,245,16],[144,157,189,82,176,46,54,94,60,12,196,147,53,159,45,59,43,185,22,80,144,29,175,185,34,172,80,83,63,100,171,224,193,42,161,51,192,98,131,220,120,68,10,124,237,63,251,90],[132,37,210,0,234,196,48,132,62,233,130,231,108,248,236,206,237,38,214,84,140,178,86,84,51,96,214,161,48,202,191,107,217,41,36,198,185,45,184,254,14,248,91,177,73,158,72,38],[130,107,238,84,94,74,104,13,212,3,187,136,134,188,148,253,79,50,213,23,133,60,99,172,187,199,46,123,30,193,203,86,227,247,168,124,211,106,168,217,109,63,60,59,51,208,199,181],[131,74,180,2,128,108,169,171,254,207,213,159,62,33,11,1,194,94,204,205,122,41,90,202,184,6,126,93,79,14,87,39,56,72,195,161,23,26,214,66,222,208,161,221,163,87,39,80],[162,19,6,118,102,183,84,136,64,12,8,17,26,235,78,207,199,48,69,239,191,181,90,210,30,141,194,29,104,196,177,241,109,8,216,186,68,212,80,241,209,141,17,98,148,31,191,249],[153,42,217,112,106,168,57,5,150,206,203,36,194,146,4,120,54,209,226,190,226,93,14,158,1,140,98,144,195,254,223,89,25,150,36,205,197,94,149,62,36,159,113,54,78,112,236,228],[128,234,162,185,69,65,234,129,142,205,102,156,160,237,214,245,227,115,150,113,143,119,103,39,237,20,140,211,29,91,157,152,28,251,175,168,137,150,52,16,184,167,217,202,119,210,16,252],[162,99,217,22,112,209,187,26,218,154,163,9,166,219,110,208,67,173,88,232,25,97,206,148,93,186,233,102,151,221,172,13,146,86,221,255,221,154,124,32,172,164,87,82,52,140,152,119],[177,251,96,232,140,51,61,70,255,198,112,67,126,34,252,83,138,111,114,221,62,95,3,109,78,192,207,179,63,98,51,221,178,11,173,69,190,79,252,65,243,32,119,178,227,22,236,195],[175,5,87,4,34,19,10,55,85,240,79,107,65,164,128,30,166,201,108,166,124,91,125,43,244,12,139,44,65,254,127,27,0,97,209,1,78,127,9,209,0,76,177,199,207,188,69,179],[149,100,185,44,156,80,31,235,201,77,67,218,82,29,2,55,104,157,173,109,196,98,10,53,212,102,166,40,84,145,6,46,49,120,9,223,60,209,127,80,51,113,209,40,103,192,118,105],[152,207,50,155,238,139,146,221,80,230,188,28,100,68,8,188,91,238,151,17,9,187,114,115,203,60,155,29,127,76,118,244,217,146,240,0,174,182,119,62,28,117,249,39,194,47,178,76],[151,9,253,197,161,170,241,141,37,86,156,136,186,112,217,249,106,91,100,187,178,30,27,86,102,123,105,16,75,76,105,197,172,178,182,52,185,128,61,165,168,247,233,48,154,227,173,154],[134,255,12,153,144,193,212,160,228,134,35,152,170,174,161,99,228,65,98,196,71,53,38,101,8,131,115,130,39,149,102,163,139,120,165,255,38,38,2,47,213,19,58,34,70,216,163,241],[142,249,159,165,206,110,116,109,117,200,150,203,245,165,68,25,170,238,152,28,217,149,236,161,1,154,240,225,163,121,144,234,253,158,194,158,21,7,97,88,55,218,68,116,230,30,239,83],[177,20,38,58,78,187,3,252,111,177,45,41,154,253,77,175,131,246,227,92,201,204,51,42,41,216,151,54,144,201,23,104,137,92,161,173,252,131,3,132,50,135,111,4,171,39,144,98],[178,46,227,200,250,130,148,134,28,173,39,132,82,250,125,77,102,4,96,244,51,1,7,21,87,83,80,152,162,168,85,136,11,119,75,131,83,110,13,196,19,44,124,166,141,48,34,154],[145,28,253,149,109,32,13,50,188,33,28,248,255,186,115,236,57,87,100,141,185,159,157,17,126,203,105,47,69,208,133,217,23,130,12,134,105,207,105,198,189,114,167,142,189,201,100,94],[182,219,152,252,165,234,85,226,83,85,71,5,79,171,209,72,243,160,160,20,203,52,137,106,255,45,51,221,113,199,175,15,71,166,204,172,15,149,130,224,35,121,97,183,198,30,239,115],[162,13,127,164,216,68,240,140,217,155,192,78,173,47,106,230,182,230,56,17,33,208,102,52,197,118,248,63,124,135,221,178,8,165,149,109,21,120,154,87,77,43,77,42,136,171,210,147],[170,52,207,49,203,160,224,241,67,63,103,176,254,192,67,160,169,109,63,115,127,150,70,142,73,183,159,12,101,150,205,104,56,80,183,203,130,100,203,226,22,169,57,58,160,32,232,249],[164,168,105,219,214,92,246,241,170,179,103,196,19,139,64,117,201,3,134,182,32,90,38,21,199,254,22,198,167,96,195,109,113,208,42,141,159,205,250,123,164,192,12,121,77,30,144,242],[163,113,238,89,173,119,33,152,90,30,169,74,142,243,70,130,43,196,151,82,102,125,236,128,115,167,152,96,113,163,117,180,104,7,226,16,207,213,125,179,118,122,166,231,198,242,72,52],[166,78,100,188,84,12,86,45,201,122,122,32,109,53,213,171,33,0,53,207,112,148,229,144,209,9,223,27,190,205,62,90,217,25,190,125,138,55,155,50,84,86,152,120,99,46,19,18],[175,125,221,84,181,201,120,2,54,70,77,24,113,154,52,251,177,34,171,220,230,189,24,4,102,32,211,130,231,168,119,1,51,130,97,225,244,164,183,228,41,66,14,150,105,184,93,35],[174,215,8,195,222,56,171,84,51,142,232,54,229,6,48,75,126,51,59,138,194,117,131,170,254,161,244,7,89,64,230,192,78,108,229,253,40,120,132,210,192,48,159,19,187,210,251,136],[160,149,91,63,22,199,115,54,7,221,171,142,86,45,61,129,13,155,141,109,123,104,42,247,14,208,10,14,162,143,60,205,23,127,115,49,61,133,128,55,41,9,12,114,81,14,86,108],[160,64,91,46,216,66,27,102,94,252,166,208,203,171,52,212,204,242,55,156,43,118,216,90,124,54,165,149,49,99,13,249,231,74,169,23,173,3,44,223,25,147,219,56,140,22,149,178],[176,95,234,43,2,165,209,134,48,179,131,162,45,244,109,244,242,138,139,4,213,38,116,160,46,145,42,6,117,114,27,222,117,119,16,5,136,69,54,159,154,111,205,217,34,247,113,57],[135,194,147,45,43,141,181,20,90,119,242,165,40,88,116,144,254,116,107,132,185,101,189,28,83,177,101,32,191,97,96,25,54,124,244,88,83,88,58,4,188,138,178,159,0,229,32,254],[128,17,112,166,32,43,31,125,223,22,250,189,60,241,252,203,158,110,127,171,73,56,43,146,65,51,180,96,31,5,244,2,9,218,58,188,251,159,189,135,218,149,20,20,186,172,235,177],[172,13,121,70,116,198,57,101,46,61,152,114,92,169,110,226,112,72,251,3,196,96,126,80,144,122,252,137,108,202,87,12,126,131,239,114,71,168,244,167,246,235,232,251,53,161,143,34],[149,227,244,128,153,77,127,250,25,60,66,62,70,127,51,204,220,16,137,191,84,3,15,238,248,8,129,215,185,187,40,144,37,1,132,31,67,142,248,55,89,85,26,130,121,228,201,119],[140,93,231,127,119,48,144,51,130,58,89,109,167,38,138,79,64,235,5,153,78,221,5,7,180,252,165,112,153,214,90,162,91,156,242,254,156,55,251,204,202,166,108,50,111,90,105,180],[147,138,226,58,104,36,246,166,144,226,162,5,83,253,76,40,43,96,183,122,135,144,234,197,198,68,81,2,240,141,153,41,41,134,218,35,236,115,22,101,218,209,43,31,205,109,243,39],[163,60,155,207,141,150,108,99,166,219,206,142,137,153,10,248,249,173,40,68,56,230,37,87,26,67,161,95,66,166,34,101,40,223,119,65,98,104,224,86,187,148,120,228,41,81,175,253],[161,175,112,131,26,228,77,198,150,122,50,131,59,136,28,155,120,73,47,186,114,71,80,214,96,196,17,234,224,114,19,164,229,193,35,217,143,135,21,196,67,171,191,99,140,164,103,60],[153,238,128,140,99,172,167,152,103,24,158,26,132,129,240,108,185,37,175,81,201,247,112,16,229,122,146,0,82,114,174,197,190,210,13,191,50,217,70,170,233,118,179,164,25,166,132,241],[165,221,205,168,135,34,252,199,96,60,127,248,200,141,207,118,80,246,53,8,214,11,223,243,91,57,94,151,232,69,149,38,8,92,11,216,101,11,71,215,237,212,188,24,22,148,82,189],[139,8,88,200,26,145,167,68,0,161,120,139,203,171,161,145,209,127,36,44,221,139,110,1,138,47,69,133,177,233,210,251,216,75,212,61,17,167,232,109,100,21,216,25,222,179,196,185],[172,50,165,78,164,109,120,151,169,39,140,48,30,159,138,12,40,178,139,86,224,236,233,37,24,13,36,71,28,6,223,138,28,125,187,164,77,36,49,42,220,46,171,82,110,152,222,175],[139,172,249,25,151,65,23,41,98,251,46,254,207,48,68,65,5,79,206,34,0,105,83,105,59,18,240,37,23,117,103,52,157,228,215,160,81,221,159,47,224,152,12,208,238,218,27,62],[169,148,20,175,149,7,208,218,233,152,246,86,143,77,231,105,205,163,16,194,23,188,175,132,88,119,163,137,171,184,216,89,132,95,99,23,249,28,139,15,41,31,160,183,47,208,55,154],[146,165,78,229,29,17,126,254,30,107,60,149,111,216,27,14,128,173,234,245,1,107,244,194,35,64,42,141,177,219,149,224,207,162,134,24,99,185,225,215,49,5,151,208,126,189,51,1],[172,188,76,144,56,96,82,225,64,84,69,149,72,229,37,89,211,166,35,253,66,204,145,116,219,252,93,51,60,97,197,8,22,146,105,143,215,118,252,61,49,134,232,88,159,170,180,157],[142,219,238,94,152,39,154,18,235,127,161,74,103,110,142,11,62,63,25,17,238,66,227,114,127,137,242,92,71,87,211,46,83,57,2,47,118,185,243,31,16,245,70,95,42,44,187,118],[177,239,27,12,97,68,89,156,168,143,171,148,197,105,23,8,121,49,14,182,135,163,67,245,3,189,224,113,226,5,154,218,255,172,108,224,190,237,50,221,14,227,21,210,74,114,221,98],[136,36,114,109,46,250,82,34,186,137,251,145,46,10,252,117,19,190,132,210,192,168,213,178,170,245,167,56,107,89,96,203,182,160,88,30,111,198,181,120,197,97,225,171,57,82,163,174],[142,12,123,169,80,124,242,188,154,95,9,173,2,80,150,85,142,225,124,205,172,67,110,146,140,60,18,101,229,33,36,160,253,220,22,114,230,226,32,57,70,44,46,201,213,51,37,9],[150,103,154,4,170,29,62,150,169,189,115,177,19,83,240,233,201,239,44,206,130,142,253,240,162,189,16,232,243,96,186,151,89,233,194,78,181,130,111,237,249,246,72,15,223,172,83,96],[141,43,85,179,44,124,210,123,42,90,211,12,212,197,75,111,31,247,66,96,234,141,224,6,210,2,87,128,167,152,157,56,188,66,158,118,128,230,12,28,116,30,216,43,145,68,65,227],[185,165,8,192,167,197,104,163,175,250,117,93,203,220,81,173,80,3,76,241,242,78,35,46,205,63,108,83,57,127,12,3,142,75,0,20,69,237,192,30,121,200,54,83,181,76,22,104],[128,140,225,165,106,123,0,15,116,166,77,71,110,63,83,213,236,114,176,224,94,79,168,206,112,232,53,150,89,76,23,137,180,46,125,63,213,10,222,129,80,84,113,212,117,72,252,121],[145,137,119,227,110,97,221,181,238,127,81,4,16,165,126,150,134,148,128,74,214,170,47,227,237,2,89,248,144,93,133,220,113,135,80,156,88,107,174,194,104,121,176,97,133,2,199,200],[138,11,47,150,36,70,244,147,67,46,230,182,154,69,94,85,89,183,192,41,204,162,86,112,108,102,196,210,141,84,159,93,33,251,14,230,248,254,83,130,179,33,60,194,21,153,136,217],[167,24,223,11,89,133,125,180,1,106,237,83,199,213,15,116,55,101,138,229,28,182,49,201,111,220,119,145,91,81,149,86,38,64,99,12,170,39,203,111,85,21,118,126,231,39,236,134],[138,252,118,127,116,58,239,74,163,138,84,251,18,174,123,111,163,158,79,212,173,167,102,40,202,208,149,60,104,53,210,208,174,134,123,112,12,54,113,155,114,2,207,166,146,109,153,186],[180,112,247,219,15,202,160,10,67,15,181,187,58,66,102,137,230,97,161,11,140,19,154,185,195,97,48,182,122,119,26,119,236,173,195,80,78,156,230,59,209,24,184,219,49,48,104,239],[142,243,97,48,74,218,97,253,134,194,102,241,135,11,108,132,103,154,136,98,64,169,222,252,57,222,104,99,161,22,200,146,59,55,38,148,59,27,175,0,112,225,194,38,196,89,62,255],[131,248,172,131,48,132,13,138,177,93,170,39,207,117,178,197,128,188,190,2,19,1,103,239,18,38,207,75,105,51,91,92,62,253,224,32,129,68,135,240,152,209,31,133,4,67,55,196],[178,254,39,190,159,176,98,240,25,93,82,148,56,240,250,250,78,105,85,193,155,125,191,117,187,26,55,234,197,229,71,197,138,34,62,208,213,0,142,194,102,39,222,255,151,201,61,146],[164,4,212,63,5,222,79,46,78,249,37,203,64,13,0,35,218,15,156,67,17,52,26,134,55,143,228,44,250,14,161,69,108,87,170,138,138,173,16,21,60,152,158,59,96,105,151,195],[151,183,221,249,237,222,216,72,241,164,248,228,202,56,110,61,54,70,167,79,31,136,149,76,73,148,182,39,96,113,31,208,147,194,81,13,49,148,42,195,58,124,236,223,60,171,104,73],[133,219,194,70,122,248,44,251,227,241,29,157,106,150,228,93,225,181,103,49,33,232,133,32,205,253,187,180,13,182,129,18,46,32,147,72,144,55,194,136,247,108,94,82,97,131,230,91],[164,120,18,137,88,155,74,98,239,40,89,255,13,187,100,8,167,131,44,78,163,214,214,47,133,194,77,235,17,87,208,233,170,88,93,98,16,210,94,192,44,202,242,110,176,227,218,61],[151,206,125,79,3,223,45,140,49,56,226,235,103,244,123,140,120,53,30,21,147,122,70,193,63,39,85,44,115,81,96,20,72,137,140,77,83,101,5,37,26,197,228,202,33,60,2,152],[182,151,117,246,11,242,6,226,154,193,42,7,170,95,163,148,250,251,35,224,73,244,149,16,55,40,213,34,86,89,157,52,26,102,106,138,72,212,188,252,133,64,9,224,101,198,13,243],[133,207,90,222,229,228,44,200,194,163,107,203,254,248,173,197,94,205,200,59,83,80,62,177,231,139,169,227,193,125,90,159,210,139,125,173,249,244,56,184,246,255,47,224,39,176,99,237],[146,27,147,47,70,206,22,72,104,60,237,54,104,72,31,20,134,153,79,34,190,227,226,63,164,206,255,82,52,41,117,56,221,29,165,109,105,223,85,162,66,22,248,34,224,14,235,166],[175,235,66,168,166,23,38,226,8,208,123,35,222,105,75,184,32,108,125,89,88,104,75,160,207,56,254,187,131,130,119,59,65,147,56,7,11,241,190,101,21,219,94,90,45,1,154,212],[136,233,210,100,170,131,115,241,22,25,65,63,9,233,250,80,222,213,236,77,45,12,120,86,66,60,213,6,198,24,5,253,60,180,78,113,230,45,241,110,148,119,80,4,245,179,51,22],[147,48,184,7,21,120,207,47,232,180,134,225,162,153,233,29,9,97,46,69,233,114,2,190,127,145,190,187,173,241,121,161,143,230,190,183,63,140,57,237,124,92,251,129,2,171,124,100],[172,174,167,121,215,224,159,209,46,154,191,234,65,86,158,138,140,42,58,113,153,81,235,15,126,184,37,115,94,105,45,205,125,13,173,217,59,192,88,5,131,123,9,143,176,38,255,56],[176,204,155,144,216,63,255,7,27,10,239,173,171,209,89,32,37,186,188,236,183,30,113,130,121,220,184,231,30,54,172,8,11,198,45,203,174,177,157,48,122,51,93,169,10,188,175,74],[148,3,46,25,197,131,167,142,135,88,227,3,8,137,139,252,39,80,230,234,203,147,180,145,206,137,114,133,44,209,100,21,162,47,140,254,110,81,73,33,249,244,251,183,32,215,87,52],[174,163,137,162,190,95,59,118,149,204,199,51,149,74,70,49,110,110,109,45,253,78,7,70,24,77,101,20,248,137,196,178,224,106,197,155,252,66,44,198,205,194,64,87,12,17,194,66],[128,221,216,40,140,40,181,149,30,98,77,193,156,1,123,17,193,137,197,185,89,111,231,182,148,188,0,194,72,108,197,6,16,29,120,53,0,92,105,76,8,249,111,254,12,49,243,37],[167,68,239,22,45,179,222,188,36,16,174,51,179,67,73,53,132,197,105,46,122,213,130,135,211,150,68,220,205,221,34,95,10,184,65,78,50,153,72,90,65,254,213,32,60,108,18,231],[151,137,232,201,44,83,197,234,141,102,108,199,144,114,213,120,214,16,254,6,242,196,147,30,131,165,180,84,64,121,102,26,194,70,247,172,3,252,103,18,244,243,64,140,109,37,223,214],[151,231,45,63,97,73,26,152,66,162,26,94,61,42,121,130,220,10,167,134,28,3,215,70,112,109,76,11,60,37,21,180,83,120,132,222,30,137,59,181,62,237,187,153,119,112,72,34],[128,158,215,175,62,152,180,138,142,166,22,165,8,134,30,225,85,153,148,82,18,83,141,165,52,73,67,87,77,2,5,153,230,207,74,54,18,58,84,241,170,110,3,105,162,188,47,217],[179,137,17,248,252,100,190,100,159,1,214,146,26,206,113,118,209,16,60,172,2,167,191,192,128,41,62,253,231,23,118,147,53,166,107,2,91,197,205,3,11,202,248,240,78,88,125,33],[183,130,20,180,84,244,151,103,68,240,104,157,102,32,103,187,20,95,123,127,64,251,109,148,38,176,45,167,56,103,25,165,166,53,162,246,60,235,36,234,28,179,185,143,63,48,25,115],[171,114,234,95,127,58,64,112,247,200,105,204,218,112,244,59,61,31,135,93,97,180,181,160,116,187,132,83,64,77,99,11,106,95,22,78,148,33,70,2,244,180,202,82,240,241,13,246],[151,31,165,206,130,81,25,85,12,106,101,189,151,79,230,237,168,243,130,33,239,220,92,88,124,158,136,87,72,133,193,35,48,33,104,103,14,31,211,165,4,74,171,41,228,183,209,57],[134,249,154,205,44,50,148,129,20,27,89,31,20,136,115,223,255,219,238,127,66,201,209,218,217,186,17,184,185,248,243,239,40,4,23,209,186,61,56,55,60,119,91,181,126,204,213,81],[134,236,122,44,161,22,118,184,180,137,110,102,55,133,180,23,41,223,17,105,17,37,49,209,254,235,53,119,230,184,1,36,252,242,10,53,133,184,59,120,110,179,157,138,153,221,134,147],[183,11,68,202,133,105,65,25,141,236,63,189,61,36,155,102,126,109,111,163,162,87,248,166,121,67,107,33,243,121,169,226,255,44,97,252,195,114,203,168,131,53,75,179,10,162,224,151],[144,253,177,229,43,240,109,42,30,167,188,117,222,110,84,14,118,216,148,148,27,143,103,172,152,65,203,40,111,209,111,2,104,12,210,1,220,21,137,102,57,163,33,181,196,179,226,161],[174,61,8,50,216,15,118,61,124,25,142,71,177,167,88,94,49,17,218,5,56,164,18,80,97,98,67,22,3,247,86,63,9,223,93,152,130,19,22,185,176,242,156,233,123,153,135,139],[153,232,234,31,106,201,234,214,112,90,67,195,119,7,44,241,183,81,145,105,81,246,180,71,208,40,132,164,173,83,203,93,62,8,178,109,84,142,219,169,222,228,40,38,10,46,157,233],[131,133,244,116,77,180,226,96,231,123,34,253,250,48,162,163,77,55,39,133,203,132,147,165,76,167,13,83,124,4,12,9,51,245,254,108,222,50,21,240,17,227,132,230,100,222,52,34],[167,134,117,211,46,127,240,209,170,198,184,115,193,134,100,114,250,125,90,232,158,153,56,13,91,18,32,192,184,109,178,246,138,215,190,235,179,111,140,254,169,106,86,42,65,125,49,90],[152,232,178,183,233,95,110,55,59,1,154,210,222,40,175,31,66,26,173,232,67,201,188,166,230,241,208,208,184,64,195,108,196,35,46,102,43,141,135,178,26,31,20,12,201,44,195,191],[130,135,26,67,184,230,32,55,108,86,240,131,35,5,125,18,96,242,237,52,232,116,139,48,129,93,128,161,138,51,107,220,164,79,120,194,190,58,184,91,182,196,89,115,0,53,234,134],[148,145,84,49,62,180,98,154,16,144,234,34,162,213,74,219,114,126,218,247,75,236,98,122,218,156,160,44,23,1,176,130,90,22,90,11,71,251,100,190,156,16,40,14,39,164,125,142],[161,183,145,2,146,122,161,3,50,16,134,103,86,114,150,254,0,223,70,225,231,87,210,12,160,17,35,8,31,234,91,35,226,114,147,72,24,85,51,105,227,195,204,173,208,22,143,128],[142,226,228,161,47,59,181,194,75,252,182,112,8,217,186,147,193,174,33,217,88,92,176,173,254,118,10,54,83,144,170,24,99,62,189,192,50,150,108,49,32,24,198,51,165,168,118,249],[178,100,149,34,98,180,118,234,115,103,160,238,13,139,49,17,245,34,14,165,183,92,28,34,205,218,212,99,151,174,114,129,45,66,107,56,125,130,249,174,32,13,39,158,166,97,185,193],[162,42,142,50,22,239,234,54,131,203,28,126,149,26,106,247,35,17,41,96,98,169,239,66,148,15,30,60,232,39,77,14,220,108,203,145,32,58,89,47,187,243,120,229,128,100,190,177],[176,68,51,176,135,178,93,85,48,128,230,72,177,100,101,12,192,107,114,229,237,11,137,56,71,229,251,203,80,38,135,127,254,241,124,130,49,242,34,247,134,144,94,60,101,240,154,234],[162,145,41,148,166,147,190,5,100,41,202,97,86,143,200,184,82,32,56,10,244,86,62,107,172,2,106,46,90,3,73,71,106,181,35,118,69,27,242,151,155,152,143,230,238,29,154,17],[179,235,124,36,120,49,212,135,123,159,204,123,4,26,166,15,227,115,216,40,172,124,81,120,32,232,206,153,166,200,213,10,25,92,225,243,232,102,156,200,147,97,38,180,108,83,3,19],[168,158,178,246,243,102,79,19,21,246,126,159,235,212,147,203,231,244,155,144,175,71,23,37,63,31,239,156,238,49,26,189,74,18,164,218,234,36,155,199,48,61,146,155,230,195,170,250],[168,43,127,238,81,10,186,192,237,195,164,179,157,3,49,110,125,91,86,38,19,170,243,96,137,225,87,58,234,231,158,159,139,69,223,31,204,215,104,138,238,220,88,6,49,169,221,76],[162,93,142,100,103,103,97,1,4,34,231,210,67,13,129,133,241,236,68,138,40,212,121,7,251,74,20,239,40,165,106,193,90,182,121,44,129,206,29,188,242,47,44,126,152,203,208,58],[183,64,231,140,179,78,211,99,33,41,56,46,150,68,49,178,164,45,101,35,79,129,233,32,91,19,88,195,8,130,215,183,74,28,252,231,88,210,233,213,125,249,230,32,221,251,36,26],[141,133,22,59,239,202,34,14,204,203,140,248,201,199,2,210,148,197,134,143,210,21,172,177,199,154,187,60,85,124,118,237,89,36,107,68,188,203,219,198,195,230,7,251,129,133,124,56],[168,51,18,81,114,75,43,209,104,1,84,33,94,108,25,116,94,110,151,96,176,190,216,151,170,1,31,200,226,189,59,73,157,106,116,169,71,72,217,24,217,190,76,35,104,74,253,96],[152,216,50,60,121,66,211,174,208,134,25,242,252,129,180,157,107,194,74,79,201,15,157,234,176,57,96,93,156,116,212,17,199,72,65,241,119,128,132,61,178,55,254,197,151,106,130,3],[161,127,237,185,198,201,144,231,124,150,200,54,237,118,192,9,163,184,24,156,38,205,171,46,153,224,252,61,204,229,154,99,153,163,181,106,105,42,162,150,120,161,237,146,23,5,74,10],[131,74,114,186,140,185,106,110,158,8,250,234,63,174,240,84,128,25,60,158,20,7,179,17,91,145,185,208,165,178,191,165,235,113,109,112,119,217,47,129,157,119,98,151,73,220,243,141],[153,56,110,188,198,16,113,235,177,110,54,68,128,199,177,104,21,164,75,228,242,184,98,162,17,181,32,190,88,150,94,143,164,151,187,197,150,142,127,166,161,243,126,10,21,92,212,206],[129,7,5,75,81,212,220,2,119,186,126,39,226,45,51,140,64,193,251,13,247,173,210,77,26,27,216,67,93,101,29,145,27,48,96,29,107,8,143,154,242,25,92,107,178,247,75,117],[141,200,18,231,170,73,54,64,220,122,128,250,139,186,126,99,94,30,210,206,105,147,202,40,82,145,69,58,26,29,232,208,191,93,97,99,102,125,147,127,43,59,218,92,175,102,134,91],[183,152,210,229,194,59,102,246,62,150,55,37,145,221,142,103,244,106,218,197,58,119,183,133,99,168,136,22,161,20,145,82,90,132,197,30,203,154,55,240,105,244,6,202,147,28,35,12],[174,153,231,33,46,229,10,138,122,232,76,93,75,105,196,27,64,228,224,125,101,237,246,45,237,156,251,92,43,194,48,65,50,176,197,43,249,167,27,140,127,204,222,212,134,9,15,229],[129,211,145,194,199,207,114,104,247,174,6,126,140,15,22,60,68,149,153,164,202,130,71,71,74,24,203,116,39,156,231,131,230,73,218,194,56,189,248,11,215,110,74,39,159,30,165,158],[130,248,148,72,179,138,206,173,248,251,132,24,202,250,51,50,173,162,117,175,35,173,146,0,14,7,91,147,7,233,14,121,76,157,27,17,227,64,214,178,222,217,92,10,152,119,94,108],[134,244,142,237,254,43,102,210,164,196,135,28,105,52,113,245,44,251,139,101,109,23,104,142,154,54,209,197,117,84,92,92,129,242,93,205,79,1,84,155,128,87,94,201,41,238,183,114],[183,18,38,138,247,102,105,151,221,124,156,102,142,24,142,189,32,133,150,95,101,41,113,95,46,19,141,79,65,185,78,126,107,146,61,137,220,10,12,190,6,7,117,216,30,139,76,189],[144,8,11,124,89,148,82,138,82,53,184,226,116,74,38,102,44,139,245,146,179,46,180,186,168,68,166,15,37,45,148,139,5,149,220,99,113,127,235,13,7,109,213,187,98,214,42,61],[145,51,216,14,136,57,81,117,22,255,89,160,44,231,109,250,128,191,155,66,21,50,104,224,66,228,12,180,69,22,157,210,159,112,98,24,89,113,41,179,3,78,96,93,153,195,34,88],[164,198,132,209,49,158,45,128,77,140,75,192,154,124,251,252,187,206,58,73,245,226,165,16,224,173,30,151,233,194,20,97,146,248,80,104,173,115,16,1,35,160,182,248,132,105,90,181],[168,220,88,231,244,162,64,6,253,23,48,130,210,142,192,125,13,115,125,167,87,186,41,223,210,205,181,11,167,27,29,244,140,3,106,101,25,8,247,240,202,177,193,46,249,197,198,189],[132,104,52,237,49,57,140,181,252,32,119,81,252,196,86,209,155,16,108,203,65,235,94,147,230,201,0,210,44,226,140,85,198,225,196,1,70,146,119,218,222,207,146,152,139,38,111,86],[140,140,75,25,247,175,188,95,177,56,248,108,70,91,41,196,238,232,135,196,85,82,111,131,125,181,163,116,163,98,67,194,221,114,115,161,142,199,217,245,157,53,98,16,116,186,165,140],[137,185,129,204,251,252,190,223,221,22,249,55,90,14,232,80,221,124,79,4,232,211,218,35,128,7,242,144,211,195,75,90,55,174,202,23,148,96,93,96,185,89,220,228,33,177,206,248],[176,86,63,58,100,224,149,128,172,75,33,6,74,56,140,189,141,123,52,21,129,41,36,186,124,87,254,245,156,59,248,148,166,88,26,152,20,115,173,29,222,80,15,77,106,29,50,228],[130,107,237,248,121,73,199,42,127,154,242,81,99,159,105,184,100,41,86,2,48,158,253,148,132,46,87,47,185,95,205,205,200,249,163,0,30,88,33,123,116,178,241,119,22,124,23,59],[167,240,87,149,141,174,113,208,227,4,202,157,198,210,79,115,245,134,104,196,115,86,45,146,187,102,96,145,239,69,167,70,76,103,99,34,178,101,136,248,236,226,250,120,176,110,159,126],[139,150,188,48,98,125,171,180,241,126,94,179,135,225,53,184,181,50,16,95,160,152,38,217,224,51,164,234,233,213,172,142,148,237,12,144,33,132,60,148,211,221,93,52,197,141,140,118],[145,79,236,144,242,168,123,130,135,7,197,19,143,236,151,197,43,164,228,55,115,150,61,192,228,87,4,129,171,103,69,66,156,115,238,196,153,76,211,184,203,82,109,28,228,116,29,77],[161,252,72,13,235,4,112,17,244,218,247,66,155,55,174,147,19,74,87,179,153,132,35,48,215,79,247,200,74,214,57,1,135,49,29,247,86,22,241,79,48,85,249,229,179,88,8,13],[151,226,241,47,238,174,31,50,77,204,70,162,48,84,137,21,191,236,197,251,41,228,176,247,220,105,162,24,134,50,178,126,181,187,254,150,89,95,90,193,66,223,114,253,186,240,200,99],[168,222,240,195,162,120,7,204,230,36,21,94,238,242,45,249,52,118,7,162,156,229,56,121,244,104,220,89,190,102,114,104,116,7,162,218,40,254,34,144,244,98,201,144,159,84,55,233],[139,238,29,128,64,41,251,64,79,1,48,35,202,249,79,182,204,89,180,135,20,96,114,232,194,39,31,169,241,244,184,233,33,137,186,155,184,231,123,160,247,112,131,238,121,54,235,145],[143,144,65,111,147,141,228,127,40,4,236,179,86,196,145,38,135,38,162,212,132,20,141,20,101,1,245,218,117,184,61,106,15,160,102,102,167,211,99,132,90,74,28,95,50,196,191,110],[179,174,1,247,207,239,217,0,35,46,68,243,173,54,104,83,66,114,209,254,209,174,126,246,231,172,246,8,150,83,144,9,241,10,236,159,36,96,214,42,216,234,220,252,95,172,86,118],[149,165,147,35,247,250,58,195,6,44,56,108,8,21,232,69,23,70,174,166,28,173,95,100,41,113,80,221,29,189,172,174,59,190,194,25,232,199,62,117,57,94,21,194,221,114,213,42],[138,167,174,154,128,164,73,164,82,150,62,65,226,3,133,8,196,60,191,95,163,102,124,201,192,134,118,198,10,1,111,158,64,53,158,10,104,110,28,77,141,147,138,214,72,142,13,140],[133,83,40,109,251,206,232,155,129,252,34,72,238,141,110,105,90,162,211,197,243,129,114,74,18,101,159,159,80,59,122,171,86,9,182,144,206,1,130,67,142,176,140,147,189,188,30,201],[171,91,25,194,178,219,226,64,155,172,60,10,103,81,89,223,129,17,60,138,239,59,77,231,106,104,47,222,36,106,113,29,222,163,67,248,26,67,160,225,243,248,206,69,78,125,159,175],[172,136,216,134,189,222,166,216,73,142,154,90,231,95,31,221,35,226,157,153,240,157,177,126,255,60,219,215,207,58,115,121,133,112,2,68,112,169,134,20,174,111,227,147,252,163,134,229],[129,110,165,62,117,39,59,164,229,251,240,147,144,235,120,150,5,160,173,239,235,190,234,5,19,49,50,129,60,11,150,239,140,177,227,160,19,246,82,177,236,25,160,98,115,247,10,179],[153,72,63,116,87,23,24,202,252,58,66,42,238,110,235,174,11,110,18,154,234,40,152,196,94,236,251,223,79,120,171,44,167,104,253,147,13,87,74,81,164,28,115,116,15,113,214,130],[180,145,155,75,153,21,154,86,103,37,153,215,120,11,127,220,255,149,17,5,11,202,195,138,187,147,214,173,154,197,42,151,82,112,16,54,174,24,98,38,225,241,55,245,110,130,164,223],[137,215,100,206,190,217,216,187,33,85,171,190,67,185,74,105,228,74,30,192,227,141,197,133,11,46,224,143,201,220,187,255,1,226,230,137,93,30,171,76,226,105,37,127,138,203,0,148],[128,89,162,180,157,102,20,47,90,144,51,194,97,240,4,2,29,138,157,46,193,155,174,11,82,250,161,160,13,4,111,35,199,254,11,157,153,139,203,102,124,11,12,110,30,129,204,201],[164,250,207,48,27,63,159,62,48,2,208,98,32,100,31,101,176,223,191,119,182,210,64,122,35,38,95,39,55,136,241,127,110,19,65,168,98,162,165,73,20,174,211,193,15,33,96,208],[128,185,157,103,228,28,240,24,84,189,199,23,93,95,45,233,118,151,182,203,210,96,145,240,36,171,250,220,97,115,116,122,153,68,161,242,233,2,230,119,249,86,166,71,29,36,136,233],[133,237,97,165,189,80,159,169,6,255,149,102,7,78,10,211,114,133,58,115,66,18,228,109,190,22,161,141,115,168,201,155,204,28,37,131,14,212,1,67,124,128,204,242,182,17,152,43],[161,102,63,157,212,108,131,68,214,98,87,180,20,159,165,199,228,97,5,1,173,82,11,51,125,161,80,45,236,156,97,56,163,205,163,184,36,7,106,249,83,11,188,47,4,225,76,127],[176,188,225,230,111,233,188,219,226,203,128,46,180,150,126,15,94,243,79,145,133,177,195,68,56,194,160,84,124,234,143,57,26,206,175,236,249,8,24,139,100,186,55,12,114,235,188,189],[135,90,45,151,195,73,166,219,39,190,161,222,116,141,127,63,45,202,141,65,206,178,156,4,173,169,222,2,179,15,99,212,30,27,176,98,75,215,238,35,57,140,211,1,185,133,185,157],[167,124,188,113,39,7,246,124,199,63,65,226,71,18,83,214,9,156,218,178,130,61,174,200,42,206,237,28,19,185,235,47,103,254,8,123,227,137,26,114,125,22,50,34,134,93,54,107],[137,158,121,20,109,38,34,5,93,173,164,126,196,229,129,36,14,176,119,107,215,196,182,13,233,79,191,198,207,155,150,192,224,102,255,162,50,122,223,138,157,200,30,169,129,14,23,115],[163,207,114,232,198,220,110,222,13,118,193,1,235,63,138,245,245,46,37,141,69,15,13,104,32,107,252,137,63,136,85,192,153,172,185,197,26,154,78,219,178,199,20,30,17,254,243,126],[138,249,140,16,238,142,133,61,133,188,33,103,99,135,182,212,0,180,187,131,83,94,110,234,139,5,140,180,244,243,229,173,23,32,192,1,151,247,43,79,81,167,25,98,124,51,165,36],[169,186,3,195,165,92,124,21,39,90,168,205,230,96,183,206,98,62,15,119,129,94,83,185,237,221,242,113,215,141,168,18,211,93,24,216,63,214,244,117,232,38,234,40,106,248,118,110],[174,148,177,20,20,126,158,76,242,143,7,209,30,38,217,249,23,52,4,119,89,179,16,125,152,13,135,1,34,49,46,28,161,67,105,222,196,207,75,49,204,65,63,29,105,10,250,204],[174,80,234,44,79,13,202,207,61,196,10,14,54,105,156,171,25,181,251,38,162,66,166,128,31,139,240,249,242,41,67,32,166,204,59,159,95,141,216,107,73,48,89,18,230,135,158,175],[171,78,70,109,26,11,108,251,72,187,243,5,211,117,76,170,188,204,55,134,151,95,60,142,85,37,238,93,198,167,211,201,34,188,53,42,235,31,134,96,38,78,156,161,76,244,110,63],[133,102,126,35,115,178,16,166,116,248,82,212,64,79,116,217,93,67,254,233,31,200,235,166,243,41,69,195,138,193,26,130,221,181,31,73,195,216,93,27,220,118,120,183,29,14,150,50],[170,168,175,104,75,98,77,253,36,164,182,143,221,10,109,160,245,146,27,247,86,246,31,167,216,24,116,243,120,22,200,207,8,204,20,54,99,198,225,157,251,171,44,82,36,7,154,60],[161,231,139,225,245,182,21,2,107,96,135,243,187,129,10,176,87,160,38,85,219,221,34,63,22,110,144,117,150,107,137,39,62,128,38,231,100,116,227,15,251,102,64,123,170,198,167,161],[136,252,100,130,94,231,160,239,111,142,146,46,176,170,104,254,243,127,244,127,250,222,138,82,5,149,189,136,18,149,203,95,91,144,78,253,246,198,126,148,226,209,245,197,83,231,176,49],[141,149,127,81,199,224,32,108,210,228,3,245,230,6,216,31,89,149,165,118,220,194,53,192,217,148,160,135,149,60,184,81,98,79,152,181,252,88,43,108,243,249,65,221,60,76,86,81],[130,190,76,99,137,115,8,129,26,174,37,211,252,191,187,91,46,45,225,161,115,251,17,86,6,81,129,202,67,255,59,93,87,81,48,25,148,212,70,64,159,31,207,10,116,84,180,102],[144,164,202,56,61,56,138,237,100,85,86,45,49,99,142,128,195,232,24,206,231,38,165,10,226,105,117,185,54,78,1,248,169,129,178,210,13,123,80,1,119,100,197,26,239,158,206,196],[185,106,100,103,8,184,192,248,100,109,141,154,158,221,118,8,123,128,140,63,49,124,202,80,201,94,177,210,213,212,185,203,109,223,95,251,6,233,89,58,88,253,116,217,151,202,41,236],[151,190,251,196,185,227,118,124,214,55,150,225,22,110,230,107,180,157,118,42,157,41,144,255,75,98,81,5,81,62,36,83,33,55,69,95,32,6,102,81,18,147,66,25,91,39,105,62],[173,229,85,33,203,206,141,166,236,109,253,149,151,37,199,8,117,135,114,216,196,53,246,9,156,3,218,66,254,105,80,165,46,151,48,218,59,236,42,204,39,142,135,163,192,185,178,209],[164,217,3,169,29,42,200,149,191,58,46,227,89,157,66,153,205,144,124,255,92,93,32,133,244,63,119,109,241,251,144,234,111,74,141,35,104,130,249,196,110,89,183,136,65,211,249,197],[131,71,132,74,249,114,47,79,245,47,59,35,202,238,188,145,126,51,117,107,12,246,75,77,115,95,233,20,60,127,36,81,96,88,76,186,125,53,112,68,194,111,116,93,75,207,141,215],[167,59,139,215,229,159,112,46,28,52,82,17,129,76,61,193,134,172,0,238,30,23,169,238,123,171,221,242,143,93,154,83,240,212,45,10,77,62,235,84,201,155,41,73,127,201,217,48],[129,126,176,199,202,1,16,138,133,208,100,45,97,161,179,165,56,164,96,129,120,109,17,172,195,11,30,126,73,81,193,20,38,158,123,175,65,119,183,21,120,39,176,154,225,159,197,84],[165,26,148,216,75,199,194,102,46,32,78,91,60,232,132,78,141,158,131,249,155,99,0,28,154,225,6,9,221,35,93,137,157,222,123,140,97,90,200,158,142,102,114,199,49,143,253,75],[181,0,44,171,180,248,247,193,81,217,240,197,198,30,64,166,200,60,24,189,194,179,92,57,180,94,76,28,173,52,13,6,117,47,134,28,106,13,75,76,105,27,58,223,89,211,14,249],[138,113,180,32,165,216,138,254,168,89,123,87,86,29,184,69,91,252,198,144,1,193,192,50,2,16,97,201,131,226,199,192,48,223,175,149,92,88,209,156,26,160,173,155,181,198,173,156],[151,125,49,75,104,166,34,142,61,12,214,119,131,7,143,93,37,12,77,72,169,171,233,4,156,25,20,107,180,12,117,96,208,24,132,26,212,111,75,160,9,175,224,247,240,159,246,132],[142,178,229,180,185,160,104,174,182,25,245,27,201,241,237,98,145,92,72,248,193,225,118,137,107,141,222,104,107,2,33,207,51,11,137,58,87,85,238,31,24,127,112,181,178,38,200,50],[138,223,21,190,253,116,178,160,250,247,7,109,3,69,220,204,150,123,47,165,171,60,58,5,154,139,54,223,109,165,20,241,224,26,135,87,235,1,7,198,21,172,23,40,221,126,43,33],[136,165,109,124,188,144,178,68,117,61,218,18,149,191,144,109,174,117,95,227,207,103,190,30,172,83,65,172,111,3,226,61,138,57,157,38,192,200,75,216,175,58,138,102,139,81,120,45],[136,209,61,204,10,198,249,153,224,204,26,139,134,114,95,118,182,174,170,170,104,29,196,236,106,17,118,48,118,179,7,231,26,78,65,248,12,166,237,229,13,217,191,198,229,55,5,145],[176,209,208,114,155,74,194,214,254,134,213,31,252,50,118,254,122,183,253,174,25,68,171,212,132,131,34,163,152,206,230,25,26,241,36,228,174,249,210,221,82,153,148,221,161,177,5,13],[179,38,162,96,219,49,167,135,177,211,6,59,75,231,5,112,100,59,115,247,150,153,64,150,213,113,87,240,90,212,196,31,70,190,220,167,189,246,250,193,214,238,233,129,124,243,35,154],[177,132,123,101,222,254,36,151,78,140,51,48,153,13,61,161,228,118,235,78,233,28,97,104,155,202,153,34,243,187,2,192,12,130,253,251,32,243,81,142,220,83,191,174,127,201,83,79],[177,78,68,173,84,123,252,85,255,168,143,4,253,93,22,37,53,238,135,52,36,196,248,158,180,128,163,253,187,182,195,138,120,237,153,59,27,21,73,61,35,143,98,69,100,212,232,52],[171,72,179,194,172,171,26,17,121,15,141,45,213,185,152,244,206,231,43,160,223,94,118,172,186,159,109,210,158,234,238,181,57,167,106,15,158,255,109,94,44,21,27,124,20,155,104,5],[171,195,190,57,164,22,86,7,45,32,242,75,5,56,121,101,98,100,127,187,11,86,37,56,107,153,79,63,137,124,15,27,71,107,72,21,75,157,70,109,9,57,247,69,28,138,82,18],[183,183,6,57,64,115,107,190,207,83,54,25,223,216,53,234,69,146,19,247,14,249,180,64,50,117,70,253,64,44,131,149,91,214,249,200,186,18,212,249,254,41,59,194,182,87,98,61],[175,81,69,197,21,107,134,109,246,221,45,143,184,206,197,132,118,18,62,202,129,200,235,113,169,203,84,213,209,184,3,102,107,104,189,180,14,167,135,218,37,34,137,147,185,100,16,135],[151,62,70,240,171,204,48,242,225,7,165,127,77,190,32,38,155,56,211,215,2,65,201,94,14,195,0,195,37,78,225,62,178,94,195,109,160,101,242,222,162,4,153,83,101,141,198,244],[164,201,250,141,49,60,171,245,26,73,46,78,218,174,205,131,100,252,165,188,225,83,135,247,125,97,81,127,100,102,221,231,159,68,143,148,158,124,163,196,18,217,215,223,225,231,12,226],[172,108,193,194,121,156,27,238,219,116,2,202,154,199,33,223,196,101,99,223,154,174,55,39,220,237,98,168,40,105,140,152,6,183,27,152,76,70,35,22,103,90,38,120,133,102,1,27],[140,80,107,140,42,32,62,224,237,154,122,70,202,125,82,154,156,227,58,149,5,103,2,102,22,153,59,56,144,62,16,29,93,100,174,199,108,138,53,163,107,1,56,235,135,235,233,223],[169,163,218,189,133,97,66,184,225,214,43,202,99,239,168,31,126,197,133,84,9,251,217,56,63,130,146,226,180,100,21,167,250,201,65,164,177,25,153,220,73,40,183,148,179,20,49,126],[142,46,117,95,254,23,148,107,114,209,114,247,23,145,39,100,179,32,81,20,206,35,10,111,146,211,63,231,175,51,122,106,26,73,196,94,29,43,19,125,227,199,224,251,157,14,14,202],[143,216,178,205,45,78,184,212,25,111,61,127,162,89,234,196,106,116,102,133,200,246,206,77,191,177,81,105,23,31,240,167,249,201,148,94,219,104,37,233,19,20,247,201,186,27,177,68],[136,98,217,132,113,193,121,176,220,153,200,167,52,190,101,25,175,210,90,148,210,223,35,102,237,139,17,54,29,32,92,2,198,246,80,231,115,203,185,60,14,176,207,228,141,162,57,35],[172,71,228,159,165,21,146,86,218,183,115,184,15,225,70,22,148,166,13,75,149,215,251,49,39,253,164,131,93,56,50,28,161,82,165,92,152,192,139,173,158,246,222,164,18,164,7,200],[150,141,54,235,191,233,229,33,95,103,168,246,101,165,229,155,49,184,141,142,185,147,210,22,203,2,77,225,150,95,124,105,44,239,13,173,28,220,27,240,3,23,215,176,33,97,32,158],[133,212,161,78,4,131,184,214,129,216,145,73,143,241,53,6,78,234,8,49,69,203,217,159,247,138,237,113,186,250,76,211,197,6,150,159,54,152,80,226,77,229,205,222,67,230,160,186],[171,85,28,67,143,12,193,63,252,207,223,136,165,146,119,151,39,224,112,105,8,85,144,87,94,250,136,146,226,154,31,188,107,214,138,16,159,242,8,46,83,164,20,253,115,160,108,242],[168,41,196,121,0,165,223,227,182,228,122,174,137,229,248,204,133,239,139,211,18,78,229,99,91,227,196,231,231,74,19,226,103,74,109,192,20,133,79,88,178,185,136,46,111,91,240,157],[172,178,36,201,186,86,195,198,39,254,244,56,142,102,236,244,179,120,150,32,162,164,97,17,205,196,95,139,161,246,104,153,87,229,42,173,129,49,155,66,52,130,84,110,27,124,128,21],[145,250,184,245,195,22,85,115,69,160,183,35,140,37,50,184,226,65,240,80,224,134,168,204,159,71,246,63,116,79,137,40,43,66,219,253,38,248,164,10,226,156,55,181,49,58,139,109],[131,162,246,74,240,54,162,213,106,90,169,120,2,112,66,84,251,29,118,240,196,34,28,66,130,58,215,28,252,218,158,176,41,235,46,149,154,162,107,34,1,168,213,122,156,90,43,157],[151,201,70,255,131,9,40,165,222,146,143,243,68,225,216,181,219,21,2,48,76,169,51,14,104,180,60,71,59,180,41,154,126,181,64,99,76,104,171,64,63,119,120,247,175,192,107,206],[180,140,103,126,61,115,238,121,235,108,44,165,188,64,75,7,97,126,149,195,218,155,121,201,195,241,67,78,229,14,162,28,76,155,128,117,33,229,209,97,121,230,107,47,33,255,3,221],[143,107,133,186,244,237,171,193,87,213,195,28,215,154,179,39,27,21,43,233,155,101,49,39,70,39,87,236,109,63,95,146,212,196,40,167,58,104,170,207,99,253,104,162,230,149,71,48],[182,166,64,35,58,84,43,211,173,174,212,210,188,217,194,193,159,149,173,123,125,128,155,195,27,40,254,202,7,163,187,2,206,113,77,191,22,84,98,114,140,215,90,18,99,145,19,65],[168,128,184,4,221,206,21,75,11,92,91,219,139,138,111,116,21,141,189,143,122,224,22,232,234,87,128,162,178,234,99,143,177,145,185,160,20,26,37,140,147,140,8,217,249,39,180,100],[150,147,59,116,100,236,110,84,118,83,20,182,18,237,82,43,226,111,128,189,5,166,92,179,238,43,236,36,171,247,43,8,121,230,119,104,186,59,73,126,224,197,73,210,6,169,51,31],[165,177,232,232,99,176,166,239,191,244,117,124,219,9,194,170,37,219,44,0,220,130,208,117,219,155,186,59,5,54,170,235,0,8,99,108,142,118,238,124,80,20,163,166,226,83,98,183],[168,50,154,225,254,99,130,34,42,235,234,129,205,149,4,130,98,34,8,22,190,126,186,92,124,124,110,151,27,86,58,251,106,188,157,226,124,111,149,67,150,63,163,229,0,145,150,181],[163,45,17,14,237,195,212,236,162,226,49,77,36,233,82,32,96,193,113,220,86,12,63,125,91,227,6,226,94,42,131,24,135,132,109,13,32,126,109,34,162,143,19,4,237,212,130,129],[151,137,75,253,228,167,134,100,43,13,21,134,200,173,139,231,34,149,40,175,159,220,203,47,18,6,204,104,139,183,230,113,136,107,184,7,170,1,198,230,97,221,174,220,114,171,38,109],[150,206,144,24,50,243,126,250,42,173,247,143,183,171,96,130,66,145,27,74,208,99,168,223,122,114,116,82,21,103,99,112,188,71,79,118,203,68,212,10,208,84,175,136,3,222,197,6],[168,34,159,60,250,127,161,18,148,143,29,31,136,191,140,12,242,116,112,237,115,181,148,179,82,92,108,7,40,75,119,94,21,66,111,165,32,138,243,181,249,169,185,2,238,170,195,202],[181,48,72,27,216,113,22,66,189,19,48,107,238,193,35,243,171,48,50,34,139,42,54,216,212,128,8,113,255,105,47,32,179,240,194,56,43,56,2,16,34,34,228,200,142,72,140,173],[166,144,181,167,214,212,138,175,154,100,171,175,4,113,118,25,171,191,174,220,184,109,23,11,210,166,124,145,86,176,109,113,136,143,96,114,247,60,72,137,80,151,77,134,221,76,156,194],[168,241,69,185,44,199,255,179,201,201,156,48,223,20,77,220,77,28,107,37,78,25,219,108,94,131,205,34,37,1,232,18,14,70,171,56,139,82,201,84,31,42,149,57,53,177,67,141],[184,42,180,203,144,188,253,149,153,134,211,116,3,118,103,252,146,67,204,73,82,231,128,131,174,145,4,100,250,220,92,243,204,14,128,93,51,5,172,222,75,143,56,60,206,77,147,32],[173,26,52,200,9,31,56,67,53,29,153,10,249,27,182,111,94,93,229,187,50,115,86,132,244,6,130,168,37,156,41,51,161,215,43,38,131,125,180,254,97,53,71,114,218,49,204,126],[135,140,3,158,239,32,141,80,137,1,120,219,182,107,77,65,90,39,220,159,89,1,167,241,124,82,26,75,40,171,240,136,201,145,86,32,250,203,45,87,101,249,56,8,121,218,234,5],[138,208,161,163,108,179,141,26,18,163,30,121,217,252,128,195,27,87,30,13,85,34,128,103,12,140,60,157,5,83,219,30,83,174,21,174,188,180,211,39,192,144,51,66,146,233,9,136],[138,229,143,98,130,202,249,108,107,103,247,224,245,57,110,222,196,249,79,178,77,162,173,141,16,208,81,227,173,101,232,23,69,238,133,93,208,171,219,217,145,169,243,172,163,20,241,119],[182,249,208,190,95,174,237,17,55,90,69,125,158,149,165,228,92,57,32,140,66,219,125,77,28,55,176,209,176,51,250,183,53,158,103,73,106,129,100,32,192,36,100,255,28,100,40,151],[183,226,94,97,9,254,19,208,154,111,225,103,15,138,64,224,120,64,46,248,119,24,190,86,7,218,14,129,191,84,161,138,230,104,186,124,181,139,186,126,213,28,45,206,13,102,49,220],[134,114,149,180,47,129,6,203,161,101,112,49,4,83,30,165,188,10,230,20,52,201,187,96,108,84,125,20,245,36,173,104,7,93,140,93,246,106,9,197,112,90,149,109,197,106,10,132],[168,115,246,113,149,115,128,176,167,9,131,229,121,18,178,123,132,105,174,239,110,13,73,210,206,5,16,139,157,108,41,217,157,139,97,89,114,208,226,199,159,220,132,215,108,18,247,2],[149,47,60,209,46,18,29,193,166,115,82,134,42,179,111,111,135,80,27,37,239,50,52,83,250,140,126,20,193,211,124,88,142,147,127,232,130,135,160,23,160,175,156,18,9,110,29,204],[174,32,63,225,23,170,5,97,95,63,49,133,65,11,157,26,176,25,226,128,73,171,27,80,61,216,237,170,92,246,21,63,0,45,51,181,123,108,255,204,238,27,9,96,13,150,108,7],[168,123,206,121,84,45,195,113,227,14,151,77,165,174,164,30,43,200,173,30,2,174,65,5,122,95,204,117,240,58,108,210,214,195,185,110,245,130,12,14,18,14,245,29,103,218,177,58],[139,160,66,16,194,233,15,71,8,59,46,149,238,185,132,224,171,94,60,33,218,37,148,64,85,233,58,8,147,72,222,176,240,138,162,210,26,167,139,185,148,129,23,72,119,78,124,113],[166,130,246,57,243,99,200,219,74,94,100,111,200,71,22,113,101,97,202,184,110,116,235,117,198,219,147,85,66,244,4,92,61,177,222,44,109,224,46,106,146,173,36,207,33,20,158,134],[184,59,6,26,142,230,186,154,56,232,38,152,20,64,20,151,35,232,88,44,147,241,130,53,192,80,140,255,210,197,65,112,129,41,162,78,134,211,115,56,229,101,92,122,14,226,67,44],[146,172,109,199,85,44,156,28,217,195,26,222,96,247,146,178,65,68,140,52,212,149,136,216,19,34,224,115,213,215,151,208,237,160,251,113,199,198,99,88,9,148,200,139,90,63,63,150],[175,177,103,236,148,255,188,76,236,210,220,170,86,191,65,29,241,226,239,157,27,109,224,95,251,19,79,69,213,96,76,51,6,201,74,43,36,43,156,205,117,9,220,184,144,9,188,100],[172,247,84,168,195,241,11,71,94,96,43,18,184,214,153,78,205,201,22,17,164,249,1,28,38,82,220,219,98,97,198,4,62,19,130,176,85,84,139,128,25,36,154,233,114,94,78,63],[174,84,161,95,221,205,200,50,224,79,17,89,65,204,4,88,233,39,112,205,65,166,41,201,7,48,61,187,210,220,100,164,209,242,215,172,40,154,50,105,8,244,188,117,205,14,110,33],[170,69,237,211,153,160,252,214,48,178,120,251,200,141,143,254,155,88,46,35,244,111,157,34,185,33,10,137,108,203,66,181,98,70,230,186,253,95,213,187,215,180,122,230,233,232,102,205],[141,95,112,148,151,43,26,24,65,192,8,51,83,208,81,110,182,94,104,250,1,88,123,105,64,172,159,65,22,207,228,182,224,98,130,25,144,54,240,50,77,178,196,238,194,200,102,9],[183,122,8,156,120,46,227,56,31,160,18,180,136,119,164,169,122,43,231,95,30,122,233,54,118,216,178,6,216,125,153,251,63,24,120,185,128,211,193,99,251,92,69,16,215,43,220,7],[148,12,20,78,229,116,96,179,99,174,172,251,29,22,232,227,116,207,56,152,189,24,165,157,132,39,18,138,190,118,7,212,233,95,225,217,75,241,31,198,8,88,73,144,66,139,197,164],[166,17,139,200,5,145,80,44,69,13,137,250,166,202,137,189,231,213,38,4,249,120,255,123,160,179,63,118,35,148,211,62,156,219,100,136,213,232,130,91,211,81,10,121,173,195,108,102],[131,123,148,161,57,22,20,109,37,97,226,85,125,111,21,247,20,30,19,210,90,141,65,65,97,228,166,96,24,173,125,56,212,238,4,146,214,200,115,71,218,214,138,143,117,64,83,160],[129,69,11,165,198,96,207,92,37,122,200,10,85,219,215,126,89,192,106,126,175,169,180,134,127,39,54,240,192,56,182,71,233,220,82,114,201,19,194,248,16,38,143,229,78,48,99,64],[171,19,183,146,232,110,12,254,226,161,16,199,207,72,18,227,69,222,154,236,129,40,209,144,2,232,218,232,126,1,181,231,164,163,53,96,87,237,114,85,231,24,42,182,32,123,69,197],[168,68,138,4,143,122,21,79,230,166,124,47,78,226,19,150,216,99,32,245,113,166,180,91,68,102,202,0,142,71,244,202,149,249,205,93,162,29,201,195,16,131,250,172,203,215,190,247],[149,83,53,243,205,27,164,155,163,170,151,61,22,174,67,230,181,199,99,0,169,104,65,146,77,148,104,87,90,255,202,42,184,254,209,241,179,214,230,79,63,114,29,226,187,8,178,230],[183,21,177,45,182,60,139,120,166,100,199,12,212,116,128,204,161,35,79,120,61,97,183,46,109,78,98,96,107,147,117,16,53,111,138,200,72,194,253,36,25,42,237,67,100,91,246,19],[182,216,252,95,188,190,85,85,135,133,144,240,26,29,61,41,123,19,229,137,8,80,201,156,171,179,182,200,213,196,79,162,206,2,20,237,204,250,181,82,0,60,231,144,26,188,102,126],[153,38,115,205,129,197,197,184,166,156,175,180,27,53,3,136,191,130,124,221,16,231,74,69,4,227,248,141,120,72,56,248,193,90,188,101,57,231,10,208,97,26,139,93,20,244,201,34],[143,25,236,238,239,39,149,60,158,60,106,211,167,208,0,174,205,55,77,167,95,172,255,213,182,40,102,35,196,167,24,103,111,140,242,16,154,198,39,13,42,7,128,174,102,159,56,71],[176,179,211,49,123,225,210,216,168,70,88,111,28,70,40,116,49,79,106,81,233,120,235,230,187,8,184,212,224,145,114,149,100,137,187,22,125,103,0,9,141,244,243,33,137,50,95,75],[180,209,206,87,255,251,189,68,10,138,244,53,203,95,3,102,23,121,16,103,221,177,5,232,99,39,205,5,136,203,39,95,14,111,98,11,242,158,50,136,234,176,132,61,181,110,7,206],[184,178,120,146,117,233,46,21,210,145,60,148,121,83,110,30,193,221,175,250,121,11,60,68,223,116,209,206,17,81,122,46,33,239,74,150,204,203,156,213,46,6,160,253,221,19,230,163],[182,63,202,123,205,127,8,73,106,55,88,85,191,211,14,182,123,85,96,167,210,199,188,247,241,237,119,123,121,122,25,125,76,11,56,72,76,114,168,200,48,92,249,207,44,24,91,219],[135,147,146,137,33,9,60,4,25,233,92,151,22,115,14,180,201,179,103,253,253,99,122,228,94,116,87,208,108,154,136,63,174,221,108,80,45,172,143,36,126,136,69,187,254,12,154,185],[151,24,87,183,21,248,114,165,238,172,60,5,94,135,217,207,46,143,37,53,120,49,73,113,61,112,21,106,91,75,203,168,222,131,5,174,107,200,239,230,120,192,190,179,62,82,10,176],[153,168,254,236,35,229,12,149,13,68,0,198,152,76,215,40,47,151,1,187,163,14,188,6,136,229,85,121,98,90,139,223,252,217,101,215,49,170,183,202,165,90,165,54,253,211,15,161],[148,213,255,90,176,23,238,180,106,53,23,73,237,4,197,181,208,223,136,165,88,122,200,64,121,141,109,251,210,128,115,194,55,54,62,162,200,98,172,64,237,182,252,188,241,215,76,3],[182,28,191,244,145,203,173,238,179,249,107,195,61,69,125,116,89,36,124,10,24,30,170,28,136,250,83,21,224,159,242,6,41,229,209,36,42,228,199,121,0,132,229,18,142,94,210,160],[138,125,197,37,250,39,198,53,246,85,62,49,110,167,111,146,254,122,102,90,52,143,176,198,9,1,204,202,52,96,236,200,197,3,245,24,211,205,88,134,149,124,146,160,156,187,102,193],[169,110,44,9,253,167,79,128,67,168,91,73,215,133,170,224,86,200,182,8,183,13,76,108,193,231,184,245,129,172,47,2,128,76,113,148,71,223,215,43,111,209,137,206,185,28,46,64],[146,28,167,175,28,181,211,170,180,0,223,185,175,210,37,226,16,185,173,60,181,72,4,177,19,85,132,219,144,0,20,100,27,42,118,9,84,190,136,4,138,128,56,39,110,113,115,220],[172,158,158,64,66,248,183,199,15,87,115,195,70,166,233,233,28,151,50,68,130,249,254,170,24,155,191,217,17,229,79,221,125,13,84,95,50,131,68,66,213,11,133,127,204,170,48,56],[164,191,8,13,12,131,218,73,211,85,120,234,245,16,168,146,105,223,179,237,180,237,141,233,252,176,230,170,217,132,57,135,2,183,127,123,205,156,189,238,151,10,0,114,82,129,68,196],[179,143,235,77,191,201,49,46,165,102,187,206,188,228,50,42,35,97,232,27,188,178,101,73,83,67,60,122,115,28,200,128,20,183,224,42,158,17,100,158,250,137,7,30,75,11,239,45],[172,152,74,109,45,171,54,157,133,26,84,202,120,5,253,168,66,83,34,150,12,253,146,13,151,236,227,124,131,94,208,101,25,142,227,145,238,113,236,78,58,218,67,11,61,58,29,186],[132,114,20,114,170,147,190,69,31,223,141,40,186,209,94,55,163,174,229,203,213,150,240,148,239,10,134,51,78,151,191,184,42,115,168,115,158,225,19,28,199,106,70,76,0,73,111,48],[185,121,195,181,201,192,13,75,189,102,84,120,42,82,150,51,227,191,84,238,9,105,8,12,226,225,153,31,152,204,208,136,3,135,171,91,27,202,37,40,197,116,138,191,95,246,130,176],[173,250,150,249,151,48,181,201,88,230,115,112,63,162,187,28,110,203,42,126,240,165,92,34,141,62,231,68,68,35,79,74,3,62,163,122,158,20,230,106,228,173,72,35,71,46,186,212],[173,211,206,45,126,230,34,109,40,172,108,95,5,198,23,67,53,161,213,46,203,141,91,148,36,218,132,71,170,115,24,174,55,211,173,173,4,147,202,179,178,5,14,144,15,105,200,159],[175,75,69,23,87,111,3,236,170,249,204,161,129,190,158,192,232,179,91,44,203,122,85,220,113,49,115,226,91,108,128,205,79,4,234,5,229,209,193,219,68,154,52,173,86,213,141,103],[143,5,71,218,28,68,210,7,140,103,4,169,211,70,236,103,251,124,221,63,1,169,144,170,93,59,79,183,169,39,76,65,230,63,62,114,185,163,107,216,48,11,51,90,172,60,192,243],[179,11,16,244,86,126,36,192,126,139,173,38,50,162,58,13,115,120,19,5,100,158,101,160,123,219,39,38,102,164,78,16,76,202,95,26,236,141,28,62,163,82,124,81,239,87,72,108],[167,160,162,142,3,109,224,116,99,48,81,41,202,202,82,33,31,160,127,81,136,18,55,149,134,204,6,107,168,56,190,212,123,231,195,122,225,234,118,169,180,1,234,251,93,172,189,170],[151,80,48,145,177,197,116,114,14,201,51,43,171,33,38,99,177,248,52,100,250,200,3,177,127,46,79,165,61,239,20,250,90,166,196,177,25,238,86,90,86,71,215,164,238,74,43,189],[149,255,214,114,219,171,130,78,177,82,242,26,246,206,88,223,63,226,70,64,129,127,181,3,27,25,210,3,143,250,166,137,249,132,203,74,64,19,60,217,182,24,21,186,242,181,19,6],[139,47,170,93,254,88,133,100,239,226,81,216,92,71,164,51,243,54,236,211,182,240,31,62,91,23,78,255,185,57,27,63,4,110,155,187,61,227,143,208,199,69,9,198,249,225,121,227],[160,203,217,181,195,247,215,220,224,77,71,35,144,113,120,18,37,176,32,218,31,251,20,160,229,14,147,151,148,184,153,232,96,173,197,217,153,124,233,245,146,57,157,135,248,12,129,250],[137,74,236,179,158,140,160,200,75,243,215,214,134,26,12,190,44,226,164,120,84,138,193,218,11,70,146,201,130,149,24,86,102,151,9,112,76,104,126,109,178,31,52,125,241,108,100,239],[136,16,6,114,197,190,161,93,103,88,231,112,38,168,158,220,254,1,90,84,66,88,140,182,34,149,205,164,15,116,223,159,140,186,12,161,209,235,178,178,12,154,85,159,182,38,211,253],[176,187,126,16,2,90,237,243,102,243,221,232,106,63,88,136,142,71,129,95,87,211,132,80,124,25,3,159,5,109,102,33,87,108,233,223,165,184,194,119,255,51,126,244,65,5,241,206],[137,85,150,175,206,92,182,132,162,109,56,151,143,20,248,224,42,242,89,251,253,60,167,110,118,135,97,215,74,137,134,132,135,157,172,209,137,20,223,179,13,178,183,139,105,166,246,170],[140,63,235,136,60,118,243,82,155,35,19,8,107,17,84,58,66,11,166,246,190,52,94,180,141,101,122,229,104,198,5,0,72,163,158,50,161,164,53,13,32,72,91,194,163,6,44,250],[166,240,214,37,33,182,146,16,4,221,153,56,202,248,9,144,63,97,91,53,17,63,188,29,67,239,247,62,67,128,128,221,106,97,39,110,44,177,103,109,105,65,19,126,107,62,66,83],[139,141,99,127,27,112,228,135,159,34,77,53,119,148,211,84,207,21,29,58,0,20,215,138,118,101,35,109,144,167,154,34,243,22,37,132,112,204,33,140,104,86,157,108,216,52,21,127],[165,8,214,14,29,55,57,243,232,119,93,145,109,0,213,71,181,108,131,178,128,237,115,199,50,198,173,48,245,104,226,96,77,187,11,19,46,144,247,211,105,141,50,216,222,209,0,61],[161,164,154,158,200,246,52,183,184,2,67,81,240,239,128,105,183,177,235,198,184,53,76,168,166,136,210,15,253,27,210,124,1,8,237,156,150,76,200,98,67,108,232,237,152,206,56,39],[169,118,220,195,153,188,153,197,255,11,67,171,76,106,53,105,104,74,96,141,120,123,202,92,169,3,130,173,21,130,251,113,245,69,140,174,155,250,10,218,211,86,102,216,41,189,214,213],[162,12,202,225,251,23,41,58,139,191,64,222,72,80,5,216,49,112,235,245,132,74,70,14,68,96,158,123,185,235,243,208,17,93,165,187,117,88,11,118,221,63,149,29,86,140,0,64],[171,141,74,245,158,150,229,124,140,248,60,224,47,193,104,185,185,99,203,24,124,189,115,201,172,26,99,110,132,151,147,227,226,248,86,253,92,26,84,202,167,113,116,6,25,165,167,221],[160,241,168,195,184,118,127,150,140,230,130,13,159,221,130,74,196,214,157,125,181,86,76,46,76,22,22,138,174,206,105,129,55,253,221,117,250,254,195,94,28,143,224,107,180,36,17,116],[160,20,190,46,98,112,98,246,77,178,88,149,45,65,50,216,127,228,226,201,151,62,133,187,168,28,179,201,57,3,208,225,161,221,208,215,29,59,25,95,122,90,119,122,230,151,85,9],[162,246,65,174,95,26,116,179,177,193,38,207,38,18,109,218,36,1,89,46,207,71,83,195,195,108,188,246,77,211,158,218,186,93,123,195,130,62,173,217,234,160,86,170,41,115,91,45],[168,166,3,240,191,123,233,225,178,205,210,237,187,221,164,248,152,218,137,153,169,8,117,76,190,94,18,224,250,145,177,29,61,133,241,168,119,253,36,97,160,247,219,69,253,233,18,44],[181,11,175,28,84,226,160,240,113,145,218,66,23,4,209,12,68,233,250,222,42,152,141,108,188,121,221,200,134,141,127,122,93,209,118,133,184,56,32,68,45,153,79,3,188,156,88,242],[176,101,132,101,95,26,18,214,42,102,241,36,9,55,237,0,80,168,254,108,121,240,137,224,125,244,140,108,157,242,191,130,57,225,70,21,157,237,83,170,155,61,173,122,183,198,232,21],[173,109,13,137,22,126,14,34,211,127,240,223,155,17,6,28,26,141,90,120,195,182,64,222,113,146,119,144,51,89,60,210,196,39,226,149,42,96,140,161,35,212,10,126,16,227,7,111],[175,214,110,235,82,49,14,39,132,113,29,153,129,170,49,228,222,147,83,197,209,122,192,180,135,139,203,246,166,108,26,92,20,23,249,75,119,67,14,84,34,16,56,81,209,240,166,146],[146,85,214,179,151,125,237,207,16,110,2,242,71,133,48,132,156,185,87,17,233,92,168,123,213,245,225,46,52,45,158,194,132,118,102,121,72,139,124,42,243,143,76,161,61,214,193,4],[148,22,225,160,130,186,145,88,97,84,120,59,7,182,115,185,66,111,189,140,70,119,173,21,249,225,97,163,136,174,156,227,172,18,253,63,105,37,12,77,79,26,179,75,203,168,17,72],[150,246,227,118,253,210,20,52,130,7,150,57,78,51,0,189,139,75,130,155,72,230,139,180,220,207,249,18,74,208,251,56,126,141,45,182,237,35,22,143,8,101,212,90,225,178,128,152],[131,215,71,17,231,224,5,129,188,150,200,252,234,161,229,183,79,42,223,189,4,124,0,199,215,51,50,152,113,75,173,161,177,191,236,181,209,209,184,184,53,168,128,209,110,122,125,118],[150,86,81,4,110,214,123,121,177,117,218,244,219,0,174,79,74,148,39,107,197,38,212,32,136,50,41,67,82,98,100,135,7,198,109,233,50,186,141,127,62,43,68,153,174,58,248,72],[168,125,75,124,138,110,219,228,134,43,237,235,46,185,209,114,192,186,159,203,164,212,230,122,150,19,100,83,169,174,31,175,113,223,208,245,11,23,162,109,212,232,161,194,216,163,5,102],[129,223,69,184,170,172,131,234,92,39,4,94,211,47,61,248,219,95,37,15,137,100,16,65,199,28,156,245,214,17,156,182,77,166,206,15,161,221,19,58,125,97,47,184,196,112,193,169],[148,14,71,116,69,77,142,252,141,5,20,135,223,8,183,181,98,175,159,143,238,190,210,85,124,207,35,7,10,45,212,226,205,254,107,167,107,239,156,112,65,67,73,182,245,155,208,184],[152,191,145,211,244,152,74,55,173,208,65,86,43,28,192,219,213,212,152,140,33,158,122,129,93,232,73,67,1,233,187,151,74,207,190,86,219,38,114,35,81,177,213,251,64,121,126,203],[139,47,43,205,9,161,202,78,45,74,233,163,88,169,43,195,117,139,46,159,70,124,229,84,71,141,31,141,71,148,139,111,161,170,233,234,205,96,219,243,186,88,45,29,202,72,82,172],[142,177,74,42,60,57,243,161,58,96,78,83,255,232,67,40,156,189,137,122,84,169,36,190,185,99,216,77,112,253,115,76,234,48,2,103,170,92,250,117,7,241,34,1,205,94,163,156],[149,200,37,213,105,217,155,144,61,170,244,82,193,231,148,125,125,223,126,2,226,37,81,168,139,13,35,233,23,115,53,24,176,247,87,220,85,57,79,70,246,97,213,112,241,203,231,250],[140,175,209,206,242,90,116,162,212,241,230,140,64,205,160,74,97,55,44,168,217,40,148,163,111,211,68,168,75,151,108,36,72,32,53,229,157,102,173,121,212,248,170,29,207,66,86,249],[160,63,87,123,179,109,128,22,51,135,18,14,22,194,173,173,56,121,27,247,143,86,187,178,216,156,49,39,17,117,191,196,140,243,249,197,61,173,68,181,120,194,190,101,161,44,182,226],[165,133,113,169,23,117,114,216,67,1,61,166,120,175,157,74,69,215,178,154,254,168,89,232,239,36,134,120,73,15,172,35,228,206,179,126,255,169,113,91,118,115,64,35,112,201,243,198],[176,212,218,249,123,218,208,43,146,7,252,216,187,249,77,223,0,168,104,60,176,58,149,75,246,148,116,135,222,191,189,188,247,86,155,1,54,117,46,149,17,229,17,224,107,83,10,30],[130,22,187,211,255,191,65,255,51,132,117,181,168,106,65,15,228,224,84,253,240,45,214,51,13,16,239,54,146,240,144,85,40,78,135,21,38,38,10,111,179,125,234,224,87,218,135,129],[176,9,170,162,164,243,218,124,20,174,222,198,121,241,76,96,209,184,180,157,81,96,170,62,81,222,1,159,10,16,18,109,30,138,244,126,71,172,123,176,95,61,139,193,212,18,11,54],[184,178,33,221,3,34,107,165,183,57,11,149,10,233,138,42,76,191,201,170,170,19,45,221,145,24,70,35,98,222,32,24,224,49,206,240,190,197,247,245,105,36,111,116,218,93,100,65],[147,33,173,81,163,229,89,94,45,180,28,102,0,145,67,239,7,144,122,172,218,143,31,254,36,114,81,33,46,128,70,226,47,62,27,54,88,94,51,92,162,36,20,135,201,97,15,181],[133,155,55,160,73,56,227,39,9,56,241,116,222,96,74,68,177,136,46,237,44,171,59,149,92,170,220,94,252,42,138,46,24,84,137,66,203,123,232,232,135,0,122,70,138,196,153,252],[182,33,158,205,242,159,167,68,154,254,68,213,139,239,230,62,97,13,24,27,198,187,62,85,6,110,27,50,93,21,229,228,108,195,115,144,172,26,86,125,62,183,48,39,94,31,108,15],[169,68,218,34,168,45,255,247,222,173,61,236,52,19,83,214,20,111,156,109,3,150,44,146,210,174,221,111,168,98,29,134,83,48,140,99,170,20,88,73,99,209,147,130,172,160,69,160],[160,139,79,204,38,12,143,189,101,202,98,87,134,125,145,228,91,12,98,9,73,30,141,54,159,123,254,54,18,108,87,36,7,200,122,105,198,90,157,134,189,249,35,246,132,41,171,202],[178,123,3,228,244,164,65,53,216,231,26,250,59,159,34,67,174,158,187,201,175,165,1,70,14,197,191,110,162,64,146,118,221,214,122,245,133,247,106,172,243,232,190,75,227,181,178,240],[143,234,135,91,140,191,107,161,149,69,75,138,10,33,26,172,129,47,27,60,203,15,192,1,87,27,127,65,38,14,43,117,66,109,214,87,116,130,190,161,206,57,91,103,107,247,165,227],[183,220,244,70,41,117,68,35,108,96,7,15,63,134,22,29,48,133,194,125,23,178,34,78,184,139,115,242,67,61,185,64,145,149,2,247,173,97,222,53,44,85,180,166,71,135,229,53],[161,130,27,192,229,61,48,159,123,128,36,93,254,32,60,173,228,49,152,70,2,8,116,92,118,223,166,228,176,94,177,159,4,20,96,190,115,126,4,72,39,186,87,63,119,210,238,24],[138,149,50,228,239,186,51,190,207,122,152,171,196,234,80,190,63,179,47,34,185,123,83,217,208,77,32,143,159,245,28,106,216,41,54,163,203,146,24,57,192,80,225,37,52,171,103,143],[170,135,221,185,200,87,246,151,183,121,13,173,50,20,246,56,227,75,85,145,49,167,89,177,207,215,21,1,143,160,99,192,71,144,1,126,5,42,20,7,241,210,123,238,164,142,238,12],[136,68,91,212,249,64,100,43,159,158,235,247,217,210,69,140,179,202,164,22,13,78,142,34,159,221,218,152,202,132,203,19,43,125,149,248,238,206,249,234,232,204,194,140,43,138,86,133],[144,177,157,46,155,160,151,0,221,134,150,250,129,182,27,215,64,25,117,250,213,97,206,35,95,153,84,16,144,121,34,2,93,235,22,206,26,109,172,232,106,61,55,158,229,78,83,124],[161,174,143,200,14,120,192,72,84,98,187,149,36,1,4,105,158,149,188,71,69,24,92,149,62,103,143,253,208,156,1,32,201,139,209,234,86,176,164,184,206,176,62,35,232,207,157,52],[139,166,181,101,198,39,250,10,210,73,137,9,222,13,219,234,88,216,25,37,5,82,72,6,236,114,185,11,112,67,21,16,24,143,198,254,140,10,216,19,168,140,68,51,93,217,66,150],[169,97,80,164,145,152,8,97,80,107,58,186,93,36,56,113,108,239,33,243,190,44,90,71,112,110,52,120,189,79,77,118,161,85,199,94,18,221,36,20,86,151,2,162,186,3,0,78],[185,70,152,66,176,54,2,186,54,8,49,0,186,3,62,46,34,176,179,52,194,152,101,150,253,151,102,108,83,56,145,59,87,11,36,195,144,152,243,127,200,14,150,130,243,227,211,120],[133,101,233,155,181,156,242,230,26,132,242,13,83,219,209,179,88,210,25,63,155,100,194,38,47,186,1,110,255,143,109,130,218,20,84,42,139,14,63,129,194,90,82,8,85,230,136,153]]} \ No newline at end of file diff --git a/test_data/sync_step_512.json b/test_data/sync_step_512.json index d3ae3ecb..5bc5b519 100644 --- a/test_data/sync_step_512.json +++ b/test_data/sync_step_512.json @@ -1 +1 @@ -{"signature_compressed":[200,254,107,189,12,8,173,129,28,29,87,212,180,74,179,192,64,25,185,4,16,220,52,40,245,205,18,191,10,177,190,44,127,223,221,36,253,76,127,34,2,59,217,208,38,159,231,24,203,152,211,201,142,76,167,98,228,45,61,127,21,74,146,45,123,238,179,105,233,142,152,165,193,71,239,52,77,134,34,198,130,253,239,162,112,211,113,227,118,185,56,140,58,16,66,136],"pubkeys_uncompressed":[[245,241,81,229,47,30,138,91,9,228,198,240,178,95,177,52,99,212,66,112,159,33,168,79,152,220,183,106,121,83,170,82,37,193,46,77,213,36,169,95,155,232,223,223,160,98,28,2,82,173,234,23,122,220,206,114,95,139,71,208,178,115,112,87,42,214,197,99,129,34,202,184,32,16,60,155,203,179,35,153,57,222,96,180,129,76,17,118,49,216,41,99,167,215,144,10],[8,222,219,53,149,240,234,115,131,225,1,231,113,165,54,70,71,139,127,73,101,162,160,171,150,20,87,5,41,131,40,49,74,20,157,1,136,30,205,172,78,194,146,210,69,167,202,6,79,153,211,216,172,195,240,185,231,49,78,201,116,43,254,181,158,58,117,206,79,220,87,10,143,162,75,131,112,42,164,76,127,195,28,80,53,70,45,130,113,147,189,119,189,77,147,12],[192,86,238,207,62,64,21,118,136,174,125,174,174,219,186,172,27,42,223,103,247,201,201,197,85,224,165,11,123,19,26,41,139,15,5,90,106,23,123,249,127,205,54,172,66,136,254,24,33,177,69,155,102,69,53,61,62,42,61,211,46,182,115,61,46,221,225,4,126,145,154,51,7,108,94,56,113,228,249,107,73,36,240,5,10,179,181,2,204,142,181,12,59,32,182,11],[18,72,135,107,133,99,179,171,126,20,141,239,51,111,236,157,28,141,123,206,165,148,198,21,226,239,214,6,173,159,68,98,71,16,10,19,56,8,52,50,45,22,111,17,159,70,250,8,246,139,31,218,2,172,42,169,21,29,11,127,55,47,210,71,243,201,243,223,81,40,101,208,209,239,169,187,205,87,166,101,120,143,58,75,147,130,202,76,14,167,206,33,225,251,160,22],[162,154,132,214,70,167,209,231,90,35,156,21,205,83,27,185,213,37,124,107,78,21,99,207,42,65,155,152,236,8,34,123,182,230,5,204,243,127,7,200,137,60,1,41,227,110,102,17,227,135,101,86,203,39,35,62,23,30,38,99,120,68,106,85,227,42,106,130,254,132,62,102,66,114,159,31,62,7,34,58,163,254,78,119,234,57,131,22,38,176,143,37,54,87,122,5],[87,207,218,247,29,124,175,174,113,107,105,179,150,124,28,113,14,76,86,84,147,4,225,88,187,179,129,46,141,68,22,132,166,124,198,4,238,234,51,38,32,157,204,238,191,99,71,0,186,114,174,227,179,28,15,223,112,197,35,120,127,152,0,243,81,23,175,188,8,68,150,113,99,242,49,22,158,47,6,79,112,166,55,1,148,150,189,211,195,241,149,105,62,180,157,1],[82,86,63,36,217,202,50,146,218,52,177,158,176,34,4,37,116,158,219,100,128,70,41,198,145,54,28,30,150,50,69,86,231,39,221,199,241,129,252,246,85,65,111,245,26,155,113,7,76,132,183,20,176,70,96,237,198,202,16,223,15,208,70,94,81,218,79,182,155,48,134,253,62,172,127,91,11,11,16,144,183,116,84,109,32,3,106,31,42,171,215,240,9,110,44,21],[238,112,71,182,174,164,77,101,234,245,172,34,228,172,230,225,15,29,197,197,6,211,152,127,213,57,150,218,95,69,185,94,72,123,29,241,10,33,191,71,244,59,113,57,160,105,64,21,89,216,46,223,47,197,119,171,104,227,173,11,141,76,47,8,3,211,189,123,203,191,29,183,64,238,86,236,255,156,30,121,185,58,118,130,221,87,3,29,45,197,188,8,138,145,191,21],[178,243,83,234,179,46,225,215,96,190,234,118,246,12,68,56,101,197,28,119,30,209,83,87,175,108,39,8,47,109,250,110,203,25,88,111,157,45,60,9,37,193,70,197,32,94,6,21,99,188,179,107,238,154,225,110,124,182,138,95,161,195,168,207,255,37,176,90,38,153,113,197,123,66,201,43,4,6,172,219,218,80,118,180,43,125,55,141,212,93,57,46,116,166,221,10],[225,155,253,88,194,98,129,13,30,246,100,101,220,131,198,25,61,237,227,11,224,152,167,98,78,165,124,144,188,43,252,193,147,65,1,51,49,239,124,110,37,114,87,2,80,24,190,10,202,131,186,111,105,230,184,134,14,235,190,109,176,70,64,112,61,105,122,109,14,2,89,237,246,16,103,187,41,132,65,23,118,215,197,141,191,86,248,99,205,167,181,75,130,31,97,17],[168,135,178,1,104,184,1,99,25,134,238,3,219,89,154,255,90,61,38,206,7,67,120,211,23,214,46,11,81,40,126,131,254,126,114,156,246,125,143,176,242,100,106,103,235,243,227,11,231,195,253,97,130,70,147,227,174,37,62,102,157,173,148,211,89,216,216,138,56,188,6,219,108,187,222,222,218,1,179,211,184,151,244,167,120,85,115,49,142,131,99,189,75,172,28,22],[12,216,153,162,127,196,36,165,71,96,109,153,17,157,14,235,21,147,35,247,120,114,237,137,249,141,245,17,30,193,189,119,251,207,67,236,121,56,192,10,128,190,95,225,213,206,116,10,32,64,76,41,191,140,182,80,34,39,113,110,15,141,171,13,68,116,41,109,42,106,231,113,7,65,167,100,3,180,158,44,135,139,114,83,91,119,128,43,107,16,128,188,103,143,229,5],[246,30,57,239,188,200,223,241,34,33,28,226,5,174,210,6,221,34,157,205,143,41,19,197,61,122,84,109,76,4,40,94,170,165,230,27,73,150,183,231,18,4,222,17,37,71,45,15,190,105,15,232,206,201,235,42,200,39,232,19,173,128,128,249,47,233,118,195,45,216,16,61,53,40,22,101,0,146,61,225,45,109,133,78,4,50,246,56,18,117,233,214,157,43,246,3],[58,66,169,60,18,247,11,189,107,192,36,165,175,223,84,206,165,70,151,74,143,39,164,145,43,152,6,232,38,149,115,22,164,83,248,199,75,98,79,250,99,174,35,33,187,125,136,8,54,188,124,178,109,106,52,139,239,119,87,254,14,99,188,120,143,111,163,254,62,177,14,11,74,99,46,204,243,56,140,28,190,247,242,53,149,177,129,194,147,79,50,164,236,107,246,20],[142,35,59,46,82,209,193,200,96,127,156,40,215,137,143,154,67,204,72,238,140,109,65,62,25,146,52,57,67,114,144,5,108,238,163,83,118,86,145,40,18,208,201,15,48,78,172,25,127,224,88,46,183,80,4,207,109,189,166,50,159,40,44,225,63,227,26,108,161,69,181,75,101,248,121,206,146,51,52,37,220,33,218,85,236,52,236,142,105,21,82,188,100,24,172,12],[182,76,71,221,10,120,106,141,204,197,240,189,156,187,68,236,213,226,11,87,210,149,102,142,50,31,122,126,115,50,86,3,26,183,183,48,138,161,90,114,217,179,183,221,184,49,255,12,34,40,16,224,103,177,41,9,42,138,39,204,91,77,76,217,251,186,29,48,118,137,222,79,177,127,209,168,52,26,1,73,42,227,178,250,88,34,144,152,120,250,67,248,125,138,11,3],[137,138,120,52,80,223,24,209,19,160,50,135,131,68,221,118,177,175,49,127,70,191,68,100,14,243,30,141,220,81,7,245,166,115,140,76,127,53,30,176,147,218,2,124,22,231,35,11,237,29,59,166,113,177,156,96,101,128,229,191,169,96,212,53,251,140,183,129,52,132,255,151,155,43,146,200,224,139,111,232,141,215,33,68,41,157,218,148,174,229,111,101,67,93,240,18],[91,202,141,223,171,75,240,247,167,105,245,1,162,244,135,221,119,155,133,201,79,142,3,63,245,60,152,151,215,17,177,46,77,2,205,231,139,204,223,95,62,97,72,115,154,19,121,15,132,6,41,123,92,54,38,176,185,245,212,154,89,145,159,119,133,5,120,120,30,167,185,171,179,117,28,252,188,198,218,158,253,243,178,232,117,152,79,208,114,89,90,12,167,203,2,25],[201,58,199,110,106,180,50,111,177,144,163,81,231,183,237,216,123,84,72,53,130,137,147,25,50,227,209,223,226,112,108,229,237,194,142,76,255,204,0,163,189,72,243,34,77,60,215,3,80,198,15,19,180,64,98,242,145,186,93,154,82,165,140,223,80,28,159,203,109,173,98,245,149,111,71,157,5,127,77,255,101,226,125,185,38,1,60,71,145,61,47,139,183,61,59,5],[24,29,157,223,12,89,110,140,99,27,36,222,247,88,7,240,241,167,76,185,203,135,105,159,132,119,8,3,210,189,197,95,240,175,237,241,242,28,110,89,16,49,95,255,117,2,72,11,93,184,23,189,44,205,10,246,143,169,18,88,105,47,235,245,155,94,223,239,169,29,88,25,17,177,145,181,148,198,64,141,4,112,120,60,11,194,47,104,254,59,202,207,119,105,235,25],[244,124,226,76,221,142,61,53,43,60,26,112,250,16,105,89,168,10,240,19,89,130,159,182,200,174,215,231,153,233,173,18,12,65,57,202,1,213,23,103,122,57,116,130,214,68,99,3,230,229,33,12,0,75,46,111,156,249,228,180,44,51,82,109,73,172,198,233,14,142,193,145,58,68,20,13,53,163,234,77,151,65,190,112,61,255,47,117,252,104,136,204,91,221,7,17],[58,243,203,92,56,208,139,22,48,228,97,207,17,246,239,137,50,221,19,106,181,102,226,84,85,2,170,61,60,1,201,229,147,86,137,87,121,113,43,69,139,33,49,167,14,42,205,17,6,102,236,211,0,145,150,253,31,96,225,38,180,97,100,65,84,232,10,87,30,178,156,107,8,156,40,141,1,163,60,135,89,86,133,219,29,190,61,112,154,101,66,254,142,159,168,0],[133,173,102,155,39,237,32,70,71,83,221,124,229,8,230,17,187,70,44,202,139,20,226,147,17,60,183,203,247,186,19,93,252,132,137,38,233,33,60,84,168,156,15,137,199,90,204,24,29,180,136,245,207,51,38,244,147,150,21,36,61,36,11,192,109,1,56,102,237,98,4,173,228,11,78,120,190,255,118,103,240,35,240,213,73,54,248,222,83,208,43,133,130,127,34,11],[198,47,83,19,224,43,18,220,129,12,114,50,47,178,118,193,237,181,249,140,113,33,159,238,117,74,212,117,135,228,210,253,103,218,86,77,22,37,140,178,33,10,135,172,17,89,222,18,144,61,152,33,72,249,203,237,174,42,3,53,149,239,51,4,200,45,58,62,168,8,36,62,43,106,111,221,95,78,118,78,168,9,161,215,149,245,12,248,1,65,206,68,88,80,205,9],[77,221,202,37,130,188,128,160,214,16,26,226,166,116,170,190,169,132,73,129,173,102,24,141,102,95,246,76,106,35,243,56,82,208,57,140,139,201,162,173,146,240,219,55,133,154,191,8,206,243,109,165,8,156,57,111,247,26,69,59,165,15,234,24,200,217,34,146,151,236,6,33,173,215,52,89,35,108,14,50,234,99,150,225,105,249,67,128,253,124,59,116,206,224,107,8],[183,61,63,70,118,65,163,220,169,216,10,232,180,9,10,118,156,31,43,225,137,67,125,177,79,103,119,223,172,183,47,7,149,97,120,73,81,119,22,195,175,162,72,117,117,92,219,0,93,5,154,13,122,164,134,128,11,47,177,124,151,93,72,5,19,67,67,87,155,95,207,156,164,132,126,89,222,148,120,174,166,87,68,56,118,242,59,183,133,229,40,89,247,213,211,24],[141,101,19,41,119,39,5,223,238,60,19,94,6,27,137,171,236,228,14,146,208,154,63,92,72,94,90,26,5,31,150,201,68,205,107,5,255,18,198,170,106,227,235,239,179,57,133,21,204,208,147,54,167,9,151,184,93,123,230,167,153,106,189,241,222,233,54,212,3,80,184,81,217,161,57,117,181,86,86,176,240,243,74,39,25,95,166,150,168,154,55,214,211,110,218,14],[170,212,32,140,29,67,176,155,199,37,127,93,1,73,164,119,254,164,109,181,166,219,233,148,42,212,87,184,0,146,81,195,110,166,136,230,2,1,163,32,39,231,231,183,230,189,63,10,107,206,245,81,147,47,200,68,152,86,102,117,187,57,183,140,97,116,0,184,52,224,154,197,117,169,206,182,182,0,171,143,122,52,202,183,57,191,86,159,96,31,119,28,53,72,206,0],[169,128,3,54,175,183,160,197,120,1,168,181,223,166,5,48,0,50,106,38,239,92,255,84,22,206,158,82,102,70,36,113,40,223,179,206,197,103,162,66,145,230,101,85,74,133,85,9,185,106,182,196,1,4,4,36,130,163,216,204,198,117,117,11,200,133,222,16,181,160,150,88,94,49,93,25,25,173,132,77,146,201,99,143,31,145,34,217,173,86,94,83,132,137,34,3],[46,169,218,149,131,147,89,213,196,98,214,84,145,81,255,32,95,175,37,19,12,204,99,126,235,115,174,199,239,41,101,168,142,12,42,170,223,202,225,135,218,152,135,198,141,214,34,21,236,66,174,78,211,1,46,7,142,204,123,35,159,50,122,5,69,85,195,80,108,178,95,254,62,102,110,6,241,126,66,132,212,146,20,73,204,76,132,81,95,106,218,21,160,148,37,6],[103,3,222,238,88,158,181,138,56,34,34,205,77,130,92,243,172,162,236,111,200,38,32,229,232,49,185,241,45,167,254,138,102,128,194,237,185,52,219,17,124,107,81,187,242,189,8,16,106,171,138,52,124,241,22,118,236,225,9,245,192,221,5,190,140,10,41,164,143,56,43,216,186,193,254,107,248,205,81,91,203,9,154,93,188,84,210,70,115,30,45,30,79,53,243,19],[58,130,151,168,254,195,61,86,71,107,61,227,225,33,86,99,61,152,186,73,229,252,34,221,33,128,95,253,119,90,197,27,176,103,187,23,110,222,135,27,191,51,244,250,162,134,143,16,188,118,9,125,210,148,73,0,130,181,80,205,164,1,56,104,236,160,54,154,73,181,151,165,44,119,11,213,12,73,158,192,90,155,55,26,0,132,115,241,238,32,234,55,249,31,17,24],[1,9,112,120,119,93,15,143,144,94,129,212,18,46,170,91,57,236,161,55,44,248,234,223,114,69,219,118,7,158,47,97,65,198,141,110,126,194,16,54,148,104,234,3,187,156,190,18,86,53,47,85,79,171,93,204,185,240,223,34,162,30,134,207,170,114,18,196,140,128,52,199,222,63,97,73,102,212,247,163,244,95,29,44,82,9,104,194,153,176,121,76,150,176,94,21],[30,20,60,203,234,250,64,185,239,253,106,150,66,13,151,169,158,93,151,9,165,106,158,101,85,111,154,158,152,4,17,177,43,175,221,174,19,17,132,105,83,107,173,152,152,140,73,4,7,65,95,46,143,145,175,131,204,63,252,252,104,45,227,28,59,249,221,208,170,195,221,219,251,46,185,197,251,22,90,174,38,41,180,47,72,77,221,64,115,89,55,249,97,172,236,11],[142,188,211,138,96,251,209,54,171,171,110,181,147,104,57,180,151,0,253,156,55,163,106,184,242,59,83,124,54,231,133,50,77,49,210,184,47,100,135,45,215,48,216,34,148,8,63,4,134,106,255,92,76,25,208,102,108,74,200,38,229,170,142,118,114,44,97,148,105,217,23,127,252,154,40,198,44,46,167,181,110,247,4,195,101,83,79,84,183,147,217,46,10,185,21,5],[229,96,237,160,95,194,59,34,142,111,196,141,176,58,254,28,149,136,8,152,106,78,113,103,157,110,20,186,26,240,41,21,220,149,117,185,233,220,37,56,129,194,201,95,188,206,250,24,165,110,177,196,115,184,131,168,233,95,107,228,30,126,97,209,21,17,251,122,232,47,89,165,231,150,87,222,217,246,8,141,129,217,100,220,44,75,33,190,58,74,225,46,233,241,4,9],[188,171,89,151,203,193,26,33,16,6,19,106,34,71,177,84,119,95,127,106,48,73,218,192,125,229,169,32,124,173,62,107,150,59,178,16,247,158,188,101,166,215,121,126,216,126,32,24,35,235,30,171,97,29,154,221,223,88,241,19,175,72,56,136,216,11,40,250,86,32,5,195,29,182,220,64,181,116,144,115,54,115,23,15,227,226,32,231,177,105,158,53,192,67,153,17],[229,30,244,90,216,24,179,86,183,223,30,154,43,102,241,106,183,101,253,93,143,78,136,51,198,11,212,60,203,139,200,4,158,101,23,227,149,167,205,36,159,82,213,202,130,177,143,3,65,78,35,2,193,157,154,193,27,144,137,196,195,48,241,90,178,41,62,9,34,105,166,150,243,28,58,108,86,157,56,97,80,193,89,5,75,49,78,175,131,145,139,75,26,67,246,12],[251,13,229,251,182,137,108,26,144,40,136,216,107,113,255,40,66,59,5,70,120,175,234,193,177,93,136,0,49,229,38,71,20,105,205,132,204,107,175,92,164,74,166,84,87,118,224,14,185,93,178,63,79,31,70,135,175,123,250,121,7,71,4,15,153,19,214,133,255,30,112,146,108,74,139,152,2,122,249,247,108,45,194,24,254,135,76,89,185,247,28,222,95,11,206,20],[20,32,209,181,25,139,231,159,26,78,79,232,231,170,132,11,219,214,1,100,237,26,46,42,165,121,7,195,3,76,168,94,217,14,93,203,156,63,199,114,63,174,120,11,215,18,122,14,68,24,151,165,166,183,66,23,138,113,44,90,39,117,121,217,107,115,58,145,60,227,33,174,145,108,139,239,38,32,139,57,158,250,117,212,111,49,111,254,211,127,175,120,29,54,91,18],[43,21,154,132,45,163,153,180,7,119,181,227,80,17,81,151,174,31,95,157,104,186,255,232,188,46,108,187,79,0,163,85,238,180,146,17,141,81,124,241,33,168,112,111,174,89,137,19,122,119,76,184,214,161,127,195,38,31,218,135,70,26,5,166,153,28,71,195,159,28,42,142,61,107,12,172,175,90,161,229,62,242,81,182,195,34,27,190,246,119,189,239,17,13,103,13],[178,116,219,167,249,31,253,107,125,87,172,79,243,207,93,175,53,183,76,177,170,63,75,24,29,53,193,24,225,220,159,4,153,159,186,100,250,18,114,129,107,129,220,255,252,140,75,14,206,71,117,32,65,177,81,146,160,10,98,224,139,249,156,249,228,42,36,78,108,246,129,129,54,252,163,45,195,42,229,84,234,222,89,113,1,126,45,196,196,208,195,58,0,138,174,21],[133,104,172,220,246,17,202,91,28,27,20,47,142,100,156,191,42,170,18,177,176,147,181,91,251,97,181,125,251,223,1,73,9,202,24,91,125,174,213,209,197,252,227,208,199,197,157,23,94,156,226,150,149,3,40,100,54,130,215,227,183,175,213,16,45,134,51,220,227,57,159,177,28,233,21,223,20,55,95,207,79,196,224,47,240,28,98,25,223,163,33,251,104,166,66,1],[118,47,163,72,217,163,186,67,72,4,127,8,52,86,130,134,169,110,62,25,152,178,199,249,253,23,95,102,98,100,239,156,132,123,28,39,183,13,100,29,82,68,19,59,249,22,227,4,163,72,201,110,196,190,176,126,195,72,85,80,238,246,22,250,94,50,42,7,178,32,249,187,230,90,199,48,250,193,119,105,87,13,146,74,140,158,31,48,209,131,123,221,148,132,231,4],[237,251,142,235,116,194,193,166,203,51,171,35,5,137,128,99,17,171,135,48,46,197,23,21,216,236,221,201,50,121,36,157,75,143,59,6,142,28,148,101,186,196,143,77,18,90,249,14,24,152,193,203,87,166,122,170,157,218,70,190,86,244,103,58,183,172,29,235,225,101,198,157,121,187,134,63,61,139,171,15,202,187,164,2,7,134,146,51,23,195,221,145,134,31,153,4],[13,225,119,45,52,45,40,247,191,109,158,128,86,147,9,250,232,236,34,54,43,198,165,17,51,225,149,67,108,181,214,6,196,14,211,170,81,59,85,208,29,14,246,92,134,249,48,25,27,158,83,191,146,3,125,12,90,1,130,137,232,128,119,82,35,244,20,229,208,234,140,41,2,86,153,243,65,115,125,17,162,84,191,77,165,246,33,237,96,199,193,71,9,11,212,5],[175,58,162,143,12,142,168,19,205,231,183,86,211,3,56,229,122,207,90,60,156,178,154,137,10,195,69,252,229,31,205,92,119,78,123,50,22,9,253,184,244,120,78,202,13,210,170,13,82,71,64,136,225,100,170,178,82,50,219,190,40,233,180,65,151,204,200,151,176,246,91,78,1,76,76,87,194,188,253,184,243,89,67,46,84,56,203,27,10,143,143,103,178,0,186,17],[174,56,128,0,13,246,82,243,45,18,89,246,47,243,103,13,183,146,110,169,55,127,82,96,35,66,129,69,233,191,184,70,13,41,217,99,238,73,228,131,50,26,211,218,19,19,209,12,149,2,113,23,19,171,162,137,161,222,58,91,108,210,225,196,51,194,191,150,94,219,250,83,192,234,160,188,249,237,81,173,114,45,133,212,207,97,13,210,43,68,43,43,30,134,82,7],[194,35,77,99,188,157,130,83,243,206,151,194,107,96,115,202,242,53,231,222,85,60,245,111,137,109,178,78,51,224,23,150,194,177,82,7,57,251,138,85,15,165,53,115,85,78,20,2,140,27,37,110,86,206,135,45,253,32,231,252,206,251,0,84,103,174,41,144,5,151,137,96,140,120,21,191,206,180,219,145,53,73,11,73,220,244,122,217,6,125,78,144,5,15,172,17],[209,121,169,46,112,31,107,199,75,96,95,214,163,0,183,10,168,194,165,46,195,49,25,91,33,143,154,102,35,60,64,242,196,199,250,215,248,222,177,21,69,42,210,73,136,129,107,5,8,234,70,15,231,24,174,237,202,144,5,183,16,6,196,24,141,173,60,73,24,219,12,71,180,128,74,105,19,95,206,240,116,23,136,200,96,83,98,50,137,52,19,188,0,68,86,22],[133,48,198,224,79,198,187,16,57,197,216,237,186,65,199,104,220,32,231,201,12,7,161,21,240,194,148,67,201,69,158,237,105,17,16,229,5,24,187,70,239,20,66,238,180,208,230,25,150,99,142,173,107,3,21,42,151,66,249,191,240,164,184,41,62,18,185,196,51,182,84,149,222,176,193,1,42,166,21,210,25,123,141,107,84,213,31,163,38,122,229,188,102,110,151,0],[48,10,5,172,15,124,185,182,86,228,152,89,0,27,189,188,166,195,193,108,92,22,45,116,203,153,10,208,212,63,96,174,20,72,118,47,230,128,32,121,102,8,13,212,42,68,228,20,98,51,170,151,224,172,135,98,139,70,150,23,123,41,54,242,196,212,47,94,151,96,178,142,49,106,210,199,134,120,82,23,5,207,148,220,219,53,101,144,224,51,148,207,3,145,131,1],[116,148,183,64,167,230,245,2,201,75,192,123,222,84,190,122,91,80,211,210,110,134,205,13,59,123,63,179,105,44,151,90,133,8,108,71,175,129,117,229,166,22,162,188,72,111,140,9,130,188,104,83,252,203,154,30,21,85,16,169,183,49,88,105,212,30,242,63,148,115,86,60,47,36,206,210,63,25,237,35,37,79,165,216,177,80,156,174,123,187,162,46,121,82,177,12],[9,21,211,194,80,171,223,241,143,117,111,141,245,172,111,116,252,188,94,143,151,20,222,171,120,64,42,100,179,65,87,138,207,70,189,111,41,51,18,238,4,177,105,185,8,206,209,13,43,24,11,21,78,7,165,64,2,80,192,203,140,233,75,102,44,201,114,132,244,209,100,55,30,51,54,54,240,84,137,51,242,179,72,113,159,229,93,228,238,197,106,225,75,235,61,3],[162,176,183,37,205,74,126,252,41,232,192,36,83,250,142,207,211,11,58,90,71,252,168,70,29,229,104,45,169,84,26,55,49,6,8,100,21,192,160,241,39,19,140,191,194,78,94,18,162,186,136,148,137,7,25,22,69,101,190,255,38,30,2,71,131,173,202,33,247,241,74,124,156,229,230,245,32,68,103,121,113,168,253,136,43,68,97,135,194,165,176,165,152,195,244,2],[191,215,10,212,223,13,93,109,106,226,44,97,37,130,196,253,24,34,134,88,36,26,75,61,127,198,136,79,108,104,52,117,87,164,13,220,185,76,238,171,187,57,235,24,82,145,81,6,7,163,49,177,165,140,25,242,85,155,202,170,134,39,140,197,122,0,187,122,176,116,191,195,21,18,23,189,50,98,44,161,169,144,185,147,189,202,141,9,248,146,114,113,105,102,36,13],[18,213,40,117,22,184,21,6,198,96,223,32,161,87,151,234,21,69,194,255,146,30,69,93,225,91,42,107,31,16,16,246,235,183,145,231,177,207,90,232,217,216,55,56,197,77,93,7,64,3,49,70,14,48,46,131,110,17,191,179,133,252,187,199,73,151,203,153,68,178,221,65,194,162,147,247,41,13,227,231,167,89,168,177,12,136,221,73,128,75,56,92,129,172,108,19],[22,86,146,80,27,252,86,203,234,129,59,208,130,161,231,56,124,110,183,97,195,185,210,156,217,213,227,197,79,68,49,53,231,158,107,75,245,248,21,225,152,163,54,119,39,160,95,4,101,124,244,245,87,1,160,166,65,167,204,98,102,205,209,13,105,19,151,57,132,125,81,179,185,4,129,232,154,4,34,98,29,229,125,239,126,118,139,34,120,87,10,34,27,150,101,2],[182,35,43,163,42,1,34,239,109,7,56,229,237,17,127,115,97,171,229,121,86,235,22,3,74,54,70,56,117,52,12,187,20,147,116,179,81,237,167,123,72,167,254,5,138,107,79,13,152,105,220,128,20,43,19,154,19,253,154,84,22,221,161,77,222,81,216,22,236,216,177,21,234,74,158,246,155,60,8,10,19,218,189,143,19,143,193,71,16,123,203,133,86,40,150,23],[83,227,83,33,199,93,51,179,31,121,3,113,181,163,188,127,185,119,58,58,91,66,66,253,4,76,212,249,216,174,44,165,82,124,178,160,211,29,227,131,99,135,161,93,243,59,164,22,158,255,25,116,27,71,174,88,159,165,181,29,206,255,75,102,71,148,64,89,251,146,109,45,164,111,187,163,24,135,177,149,159,224,112,232,117,115,219,141,90,208,101,180,111,157,211,6],[84,180,33,234,135,146,139,107,172,93,186,192,156,248,204,15,127,102,244,180,131,5,1,235,134,112,157,139,203,218,216,84,205,129,244,89,70,133,116,99,214,199,182,75,96,230,153,12,93,49,87,11,37,52,115,180,212,55,138,38,148,76,71,80,67,46,191,206,243,119,41,116,76,177,243,8,149,161,15,110,235,190,39,83,173,14,140,207,119,140,23,180,71,28,76,18],[190,135,74,28,44,50,43,183,171,222,152,174,158,224,235,101,34,155,196,87,16,7,194,104,133,38,204,242,21,99,87,238,3,105,241,80,28,123,153,130,101,82,210,209,243,135,55,11,9,241,71,33,227,113,41,121,159,20,45,208,210,150,99,6,120,109,106,203,237,25,18,5,202,30,58,216,195,241,57,3,230,47,29,250,178,183,195,198,161,96,194,51,47,9,47,14],[158,252,216,6,217,53,85,60,208,251,45,128,114,37,246,146,248,3,27,43,58,53,225,219,225,250,9,217,194,29,71,209,40,201,255,88,75,42,233,243,228,205,149,123,245,172,242,4,7,173,50,107,144,187,7,233,105,106,223,167,127,125,34,35,13,128,133,161,191,74,180,10,31,189,192,179,103,12,23,120,254,231,217,40,243,126,245,21,76,14,255,102,84,230,142,9],[41,121,181,146,126,39,71,72,183,19,143,159,3,107,236,8,22,81,67,65,251,54,241,143,158,148,188,53,243,203,205,80,179,161,75,209,166,97,67,196,85,187,211,52,208,7,17,3,121,88,163,156,100,145,118,144,208,163,131,158,55,40,158,210,250,240,238,105,166,4,16,145,40,181,169,142,80,31,172,211,20,106,10,84,19,207,198,54,5,183,249,248,152,26,155,22],[74,239,132,54,106,157,70,121,50,58,251,200,90,239,91,112,162,14,93,153,205,226,59,95,159,173,221,22,18,39,164,17,5,190,81,245,199,87,2,88,52,169,106,177,231,157,149,9,6,76,141,66,123,194,210,35,196,67,245,34,145,162,134,195,177,5,19,230,0,234,236,102,163,195,206,78,180,44,28,19,10,254,231,143,236,230,80,53,166,219,208,89,110,86,79,18],[201,104,40,16,110,133,95,184,8,196,182,80,176,130,229,1,250,110,76,236,116,95,93,27,77,242,120,83,44,6,17,149,88,254,193,157,44,108,86,64,133,175,204,182,201,254,209,18,156,237,76,9,116,201,244,208,223,131,174,241,9,255,42,176,174,172,9,11,69,154,176,126,197,197,123,10,200,107,197,9,190,165,102,246,112,105,107,14,104,217,185,35,122,70,237,13],[7,9,60,140,78,213,116,55,215,167,186,103,204,12,40,220,243,77,116,111,133,12,90,193,149,57,128,180,139,191,237,190,183,221,218,118,183,124,63,91,201,220,107,71,185,178,18,12,161,170,120,89,161,40,23,198,42,145,116,22,216,74,111,206,255,204,202,4,252,18,253,113,117,77,130,49,128,240,9,230,192,238,176,100,47,136,20,24,255,136,76,56,149,124,202,11],[182,196,203,136,69,251,12,124,147,87,249,59,157,31,236,204,76,99,24,108,179,213,142,203,151,253,138,29,254,127,22,159,41,153,176,115,218,69,215,74,27,55,55,153,148,43,54,23,82,28,76,33,3,63,142,28,136,112,142,124,99,72,221,59,55,47,33,236,151,75,58,71,5,48,197,145,69,12,34,230,57,253,199,26,245,81,0,247,145,222,247,249,66,149,73,17],[114,191,44,56,174,230,134,2,103,110,238,142,135,168,76,239,98,209,247,54,121,88,24,212,65,30,64,51,126,24,112,162,139,244,89,152,37,161,109,198,53,149,133,63,78,41,163,12,140,96,25,55,24,235,98,103,86,247,189,49,192,65,244,3,20,227,131,170,226,161,4,216,160,159,85,111,166,180,55,8,214,210,139,134,100,113,97,44,81,20,244,14,212,179,223,9],[181,197,6,94,165,45,248,61,129,214,218,171,150,233,50,174,222,73,250,50,163,74,88,28,12,162,159,191,183,119,202,139,246,157,106,232,153,150,86,213,90,198,172,84,146,240,237,1,193,32,35,215,85,221,222,42,6,252,169,34,88,96,174,193,84,43,36,19,91,166,33,195,153,110,139,7,136,74,181,77,230,219,190,116,61,59,174,6,63,157,176,51,55,97,197,21],[34,219,228,211,109,16,81,244,156,50,108,219,45,248,115,169,2,177,65,215,28,156,200,108,231,206,235,85,19,231,54,255,85,68,66,23,143,69,95,216,218,84,186,50,239,1,176,1,176,126,230,253,37,192,195,19,54,168,239,161,97,99,213,90,167,134,63,71,13,15,116,185,9,95,44,74,79,215,54,189,178,203,116,190,173,186,153,124,81,249,56,180,149,33,237,19],[50,253,224,80,245,61,66,39,220,35,135,225,105,182,144,144,87,130,223,185,181,167,185,192,32,93,225,96,35,0,137,160,39,188,204,197,21,209,159,180,38,119,49,215,4,183,80,1,239,52,73,77,53,83,228,205,187,50,176,99,177,131,25,129,173,237,21,15,39,195,163,19,72,162,180,20,225,86,15,36,223,176,84,185,69,96,12,94,113,127,64,160,172,55,52,18],[114,10,207,242,13,131,195,155,150,62,103,141,127,67,130,251,167,51,246,88,225,92,157,207,126,106,60,211,126,226,62,230,79,48,16,176,208,63,113,76,235,247,52,195,37,21,82,13,101,209,129,40,228,232,82,28,16,98,169,36,159,57,1,37,18,202,254,140,210,119,99,151,228,174,34,158,225,122,208,142,65,180,65,172,145,26,37,204,176,44,115,228,246,10,18,24],[185,162,220,29,220,237,206,170,83,176,123,96,118,138,6,245,9,178,200,154,49,88,2,20,45,40,189,205,24,47,185,26,183,42,55,105,47,85,54,133,65,71,67,62,219,64,86,23,107,55,54,86,168,220,220,7,193,248,117,92,187,89,25,3,102,9,215,183,237,158,41,212,69,76,35,91,224,158,253,201,1,235,49,208,33,118,135,126,4,215,63,173,234,112,172,2],[174,132,177,147,100,4,24,24,160,112,118,28,163,62,239,166,106,214,106,193,172,139,44,128,58,33,6,112,119,249,42,135,38,28,113,46,244,152,114,177,103,66,101,166,233,101,135,17,235,168,202,87,8,120,232,207,235,33,18,178,45,72,64,10,131,69,58,58,214,236,251,142,9,209,227,152,93,211,152,66,96,189,65,33,113,198,117,69,74,52,26,255,71,210,198,17],[6,170,26,244,24,183,251,227,153,234,78,61,184,170,227,157,195,169,181,208,164,189,215,88,160,168,82,11,131,132,200,27,26,51,175,37,38,9,144,81,191,50,180,87,45,149,88,14,56,149,122,244,58,238,44,170,9,158,208,112,138,41,39,168,46,229,238,85,163,228,111,239,43,226,126,9,170,84,73,150,79,250,81,120,228,176,123,101,204,61,99,217,141,74,225,15],[115,53,247,160,118,156,62,83,230,55,79,4,112,0,134,175,51,206,197,24,118,26,184,91,98,129,204,55,195,228,117,98,173,251,246,107,247,16,172,185,247,185,248,254,49,72,75,23,88,118,71,34,42,126,194,156,7,30,143,72,187,52,91,26,215,117,168,60,100,121,69,24,159,215,119,27,215,72,101,248,132,184,76,66,136,61,36,19,8,29,240,154,160,234,204,21],[91,54,103,235,4,32,68,180,128,198,8,197,147,255,236,231,109,73,190,45,241,236,196,169,144,142,197,28,210,110,38,245,37,163,232,74,85,72,166,72,255,12,147,134,222,72,92,13,75,133,148,163,249,41,38,4,89,97,106,127,134,175,97,164,59,250,95,139,203,246,189,37,7,110,113,119,98,81,63,83,214,107,154,213,226,31,25,24,146,87,37,219,233,17,86,19],[56,135,173,253,154,196,115,31,92,107,68,174,186,192,127,40,182,185,176,131,9,36,223,223,236,220,89,171,50,157,225,196,120,72,215,92,107,47,176,212,181,121,144,129,149,53,135,17,45,36,22,173,203,238,159,61,107,150,183,103,103,189,189,76,205,151,179,153,28,9,237,253,130,251,148,30,104,159,19,220,226,182,232,67,205,198,214,7,26,172,69,148,73,111,214,10],[113,94,202,217,207,207,205,27,11,214,24,110,66,99,139,10,54,89,252,9,214,130,84,164,226,146,187,193,237,169,150,177,217,206,192,22,232,122,101,47,98,191,15,36,87,154,74,18,119,39,54,226,122,125,66,236,120,5,172,0,132,89,36,202,95,19,20,221,201,204,55,2,101,128,237,14,54,190,145,209,149,5,4,8,243,149,174,0,199,189,135,152,230,79,228,20],[65,243,170,224,192,178,80,41,57,17,188,132,210,207,139,233,1,149,118,177,40,197,229,230,159,148,29,19,92,222,47,108,104,181,33,92,132,5,88,245,10,234,76,165,54,190,74,2,146,107,148,107,157,200,65,137,251,89,25,15,99,78,247,210,159,157,192,144,35,0,20,95,25,34,128,172,126,144,207,47,23,189,245,230,230,84,155,231,133,150,186,62,31,85,30,23],[44,165,9,9,104,177,141,120,191,113,137,242,170,95,103,93,154,104,213,242,147,174,105,117,182,7,66,164,173,222,138,171,144,203,241,179,226,210,100,254,199,146,1,165,167,231,203,13,241,40,248,182,162,102,185,184,67,153,71,20,105,134,19,88,224,163,104,4,162,86,8,22,174,48,217,49,141,77,239,249,239,103,149,171,228,224,145,18,8,50,167,53,22,255,162,19],[42,60,8,137,247,13,172,77,179,52,214,140,79,126,255,59,176,3,108,113,197,90,143,183,128,163,70,231,100,162,47,28,47,114,47,254,24,192,15,104,21,183,44,167,129,85,114,2,127,175,252,212,14,208,43,206,49,236,221,41,212,69,180,14,251,160,206,156,215,170,193,45,204,226,111,220,7,149,160,146,169,255,218,87,219,231,19,219,62,109,92,146,65,135,122,18],[213,69,139,87,238,134,139,152,174,98,209,132,155,73,122,253,127,163,18,218,124,68,64,217,51,166,173,35,144,118,144,40,121,243,21,171,151,212,88,9,124,72,185,38,135,55,225,5,244,80,101,152,135,236,184,125,255,60,225,89,142,95,241,131,116,124,244,21,124,160,23,85,13,116,32,209,76,49,84,242,78,141,94,52,48,125,136,98,107,1,214,236,232,205,101,25],[170,188,49,150,11,137,32,107,138,78,21,9,174,117,6,62,208,183,202,169,30,12,138,128,80,10,225,166,141,88,0,79,198,70,143,38,155,75,7,228,93,86,71,46,202,162,238,0,199,29,98,49,215,242,15,136,118,164,72,251,179,53,177,136,41,97,159,221,67,96,13,248,245,164,137,157,43,42,10,5,123,232,183,74,6,223,146,45,28,210,198,180,75,213,24,21],[155,251,164,250,81,186,192,52,193,65,13,43,170,196,203,68,111,82,9,214,192,183,253,50,119,139,55,213,36,12,210,214,137,48,249,80,240,56,203,191,68,169,175,162,214,11,135,24,212,51,13,223,15,75,113,249,180,245,142,152,116,182,30,26,206,4,240,24,164,188,122,128,162,124,82,136,29,215,193,79,17,181,95,93,219,77,65,137,218,232,40,41,13,17,77,8],[199,9,16,239,242,54,98,171,47,115,253,234,105,22,107,181,177,167,14,165,27,31,27,42,147,199,185,233,239,150,24,37,218,187,30,163,215,150,70,54,80,48,187,83,124,133,87,22,116,240,61,213,97,38,130,122,33,41,92,88,180,141,186,175,170,19,116,164,216,32,48,130,110,241,1,206,57,211,207,79,162,190,111,194,170,205,64,243,138,161,40,34,7,32,75,22],[163,88,39,50,35,157,214,115,26,236,126,28,154,45,15,218,125,98,246,243,253,80,190,170,114,136,224,44,142,38,6,217,232,21,80,213,16,70,40,201,60,107,163,157,210,35,98,16,104,139,41,146,28,224,219,142,128,189,127,59,244,150,172,181,183,75,227,197,233,107,252,177,44,238,93,186,230,187,26,172,7,206,10,168,153,226,22,247,21,66,179,220,40,157,165,1],[200,176,238,20,36,201,6,95,36,45,123,201,0,16,153,124,103,7,163,239,141,206,154,98,1,190,247,248,174,85,224,42,191,119,129,239,250,206,160,56,180,193,45,81,71,172,222,21,224,68,169,183,141,26,98,117,234,132,73,32,194,55,61,42,40,143,41,135,187,149,137,30,134,125,122,38,221,197,72,154,93,251,10,187,165,164,122,245,20,112,94,119,162,1,125,10],[189,96,122,115,60,96,92,71,231,95,67,17,244,172,25,196,227,83,76,144,82,133,108,178,45,103,227,57,47,93,37,98,36,23,30,235,148,174,212,34,146,71,181,98,184,194,153,20,193,186,23,216,232,24,58,251,118,61,219,91,197,178,54,22,76,37,171,158,48,13,3,55,15,79,238,6,80,169,206,119,144,211,145,33,97,116,251,204,65,156,249,201,118,60,91,15],[147,7,175,241,53,203,178,32,74,186,114,138,188,55,209,247,67,164,26,128,89,2,181,106,136,19,185,127,12,99,245,100,59,122,152,90,65,97,212,207,114,82,109,163,102,175,42,21,17,106,248,193,33,176,57,179,74,235,94,33,104,151,225,189,55,82,131,3,177,188,179,152,122,8,215,80,179,217,20,2,4,31,84,23,246,61,60,6,157,122,169,134,164,35,187,6],[200,168,70,65,167,39,234,91,5,195,239,39,57,143,211,77,254,175,231,175,174,176,18,179,143,32,161,77,50,156,80,162,255,97,238,132,254,170,177,203,105,83,215,67,56,61,216,11,41,251,178,93,170,235,229,54,243,14,117,194,158,150,15,249,40,238,248,169,210,67,24,170,134,118,69,230,174,255,198,191,153,249,95,242,207,105,241,18,38,29,209,7,152,226,34,16],[197,224,134,51,116,77,237,42,20,66,147,118,47,162,147,38,196,130,200,129,165,250,246,34,64,36,231,240,136,81,164,46,73,239,152,30,31,219,163,150,143,52,34,180,219,237,191,18,169,89,72,99,183,108,41,196,234,2,197,129,157,116,253,243,23,120,127,85,61,27,57,72,6,159,136,218,134,129,238,44,112,81,22,199,68,38,235,143,173,157,176,222,30,91,156,6],[130,80,181,152,82,201,190,165,187,41,184,146,39,17,104,223,93,89,152,179,141,111,206,132,72,236,167,56,214,220,236,39,243,1,107,228,166,67,248,237,139,127,45,220,221,44,235,2,125,82,160,122,108,69,111,76,8,76,151,182,53,9,108,197,216,131,154,78,196,33,110,25,55,159,111,93,135,19,174,81,6,113,36,194,87,186,114,173,20,56,238,150,221,158,91,4],[146,60,102,84,107,100,129,216,187,160,46,76,241,161,11,15,149,48,4,4,89,68,245,182,142,105,112,91,108,161,145,4,18,155,243,170,4,46,47,155,146,153,112,183,57,116,182,23,51,3,232,64,36,123,41,5,202,144,209,235,96,49,28,222,46,61,14,238,83,8,168,4,213,187,137,1,0,156,190,107,168,130,84,192,171,132,113,139,223,72,56,49,6,38,250,23],[235,70,58,182,108,50,21,7,140,77,148,222,19,9,240,161,68,215,45,22,55,144,9,106,178,105,138,193,55,114,128,88,58,119,42,119,26,233,246,49,89,226,40,161,254,99,167,25,231,3,70,225,4,11,32,228,125,132,238,254,185,243,219,28,14,89,13,175,56,33,173,199,201,124,121,10,58,119,17,252,184,164,137,190,83,69,15,185,237,137,67,55,228,53,1,20],[160,240,195,138,130,56,11,220,53,85,210,119,80,89,88,58,193,12,111,107,250,173,14,143,211,149,112,188,234,219,238,199,28,152,35,210,85,81,86,65,117,44,84,101,4,111,196,20,239,89,77,114,169,215,21,220,72,232,159,255,127,48,226,245,47,164,71,94,65,63,231,84,122,222,138,156,212,81,94,199,26,80,115,1,7,68,62,63,233,33,225,71,101,96,203,23],[162,145,55,79,7,241,147,230,8,229,248,114,169,243,255,130,180,4,108,37,39,209,131,165,84,43,188,24,188,22,159,94,95,249,98,47,218,88,67,166,210,146,137,211,118,156,188,25,85,251,2,178,91,59,176,50,153,157,8,48,119,95,200,83,217,144,198,139,45,60,62,109,249,4,161,103,206,97,207,126,102,40,131,235,135,11,117,11,43,250,203,21,206,61,33,8],[13,149,110,35,97,164,20,240,130,168,221,189,64,84,34,196,146,80,1,49,104,14,66,158,231,218,15,101,207,77,37,5,243,4,3,10,203,206,68,132,50,18,32,238,145,149,42,2,110,74,31,48,175,112,164,88,76,1,87,255,93,131,232,150,176,206,20,64,180,75,208,98,63,140,188,180,237,128,190,117,183,171,188,242,210,94,62,206,243,185,182,107,118,114,247,11],[98,47,102,56,230,248,236,248,193,214,245,196,209,83,163,106,209,187,161,80,65,214,88,35,177,163,187,62,245,78,107,22,216,74,224,52,98,59,60,250,79,200,18,34,84,50,227,8,37,204,54,252,215,202,223,115,109,94,60,37,121,25,228,73,232,46,242,150,181,195,159,118,179,180,19,245,103,122,182,10,173,110,234,101,188,202,187,49,131,42,248,142,178,164,176,5],[55,145,106,171,130,241,44,196,205,90,186,21,182,145,216,240,83,53,213,33,133,74,195,120,39,232,47,15,55,54,16,233,255,31,135,7,120,86,74,93,76,251,231,175,182,174,101,14,173,225,234,154,221,251,95,130,226,59,142,110,143,170,91,60,17,96,163,95,54,155,225,179,76,94,62,181,163,10,212,216,180,187,106,19,69,70,86,59,39,126,157,118,123,113,118,8],[74,215,190,195,202,243,222,119,5,170,92,232,52,72,38,216,192,132,57,219,160,124,244,12,132,197,141,19,123,201,123,110,57,133,180,238,142,91,196,98,243,250,221,47,111,22,100,14,16,16,121,71,170,97,15,11,73,18,180,253,136,196,145,68,142,185,129,142,77,238,109,200,102,213,127,55,226,237,180,134,86,79,37,24,150,243,227,0,244,226,224,67,109,49,4,9],[157,13,172,214,25,127,0,242,60,38,131,132,84,24,56,132,213,65,103,38,207,187,82,170,200,67,96,30,230,84,233,120,243,223,188,221,217,231,127,210,219,205,124,13,121,157,137,15,24,97,106,238,227,214,160,218,66,112,121,9,128,166,158,122,123,42,145,160,205,82,141,157,190,136,23,69,127,64,172,65,28,175,129,145,178,149,61,2,139,191,62,107,91,17,101,18],[133,76,180,109,25,229,212,15,148,3,169,202,212,245,28,166,57,10,177,88,182,1,196,140,144,87,175,60,44,203,46,118,96,14,214,121,170,210,232,111,87,8,137,43,60,88,203,4,254,16,172,202,16,154,167,233,56,143,29,252,22,24,135,45,112,10,215,235,112,66,99,222,172,145,193,189,26,190,16,217,42,136,249,44,191,254,53,0,153,70,24,126,193,184,132,21],[73,254,179,96,112,100,96,235,222,137,151,39,160,100,253,192,212,34,88,45,15,142,131,58,49,226,183,109,180,11,87,97,143,82,160,246,62,97,32,128,57,221,65,199,191,132,191,2,208,18,98,72,125,161,190,182,180,21,95,252,11,149,169,97,166,167,252,5,38,241,33,109,63,193,134,56,188,242,88,58,69,128,9,86,34,72,4,75,198,143,99,117,220,254,8,22],[52,15,159,102,81,183,221,180,209,186,170,215,148,171,255,81,50,234,30,125,229,67,90,181,123,111,111,211,110,159,169,11,132,121,132,70,51,64,155,50,245,101,5,58,152,37,39,3,202,138,236,181,131,130,232,228,43,142,103,29,5,136,158,101,51,85,176,26,109,15,162,120,44,244,124,97,189,222,37,255,210,156,152,55,5,76,17,165,14,180,123,204,36,168,48,3],[236,242,103,238,177,121,248,25,170,75,53,248,231,242,95,242,118,15,183,134,74,172,40,241,91,129,7,133,123,151,18,155,53,85,70,174,150,73,139,101,244,122,38,36,48,207,136,14,97,219,44,227,208,35,89,75,77,23,200,83,192,209,111,45,175,233,233,207,74,13,27,109,110,133,121,241,16,208,43,251,58,54,196,211,230,182,99,193,214,81,233,69,248,98,78,23],[147,229,189,173,207,253,73,54,199,15,90,11,239,149,23,180,198,235,107,147,114,206,180,136,176,164,46,46,254,185,144,45,235,51,187,125,108,44,111,21,186,62,179,239,26,161,215,7,111,72,206,223,176,76,87,112,81,220,21,118,48,235,7,254,134,179,157,58,141,142,214,143,118,214,25,4,146,155,107,76,54,33,11,108,163,103,83,145,100,11,79,110,89,160,71,10],[133,83,145,155,76,215,5,48,221,10,77,182,168,201,140,1,155,60,209,174,118,183,84,2,75,16,255,207,255,219,242,207,61,85,25,214,144,100,124,171,39,200,114,48,107,3,158,10,141,114,28,74,32,88,104,226,77,165,232,62,228,66,137,165,68,189,31,146,128,30,227,42,221,24,49,117,176,183,229,112,197,34,38,117,136,143,83,229,26,255,116,216,118,245,98,14],[31,10,235,193,179,183,29,127,28,12,106,195,145,73,120,101,219,131,55,116,80,181,90,194,242,157,151,240,100,212,109,255,173,250,220,193,47,92,15,7,74,248,145,52,202,176,254,4,192,79,153,249,141,246,56,3,203,146,238,25,156,34,215,92,74,32,242,74,33,28,27,149,70,75,167,250,245,14,201,32,69,209,125,66,153,113,90,76,60,111,134,72,238,2,208,21],[225,75,93,12,246,57,33,98,236,160,29,211,217,242,129,85,111,37,247,238,176,188,48,133,125,158,166,237,225,202,29,161,51,247,45,79,87,166,62,82,117,102,191,70,141,47,42,7,28,163,223,180,253,42,136,203,186,150,52,86,96,25,250,38,185,122,169,19,89,125,64,43,123,0,31,106,101,83,236,74,163,212,82,100,81,253,65,104,130,187,29,178,146,97,185,9],[174,188,10,104,23,0,66,168,59,149,169,164,30,102,220,145,218,228,136,248,53,103,100,206,3,231,103,224,125,18,225,17,25,197,141,0,132,236,31,216,43,209,7,73,231,175,14,23,73,246,137,6,200,25,126,192,199,158,227,17,108,150,27,17,127,203,251,179,228,122,5,106,113,50,236,15,96,45,39,21,1,83,142,154,21,148,29,154,228,168,75,90,8,150,183,9],[38,223,46,175,213,96,108,185,143,13,198,139,229,143,224,108,109,110,131,25,172,28,196,103,164,113,163,134,233,191,152,162,161,184,163,83,128,25,29,7,84,106,213,89,82,112,161,6,16,210,46,31,95,23,186,159,234,245,136,250,233,55,11,72,76,207,159,21,54,198,91,140,232,52,87,35,38,135,147,157,118,90,83,150,86,173,123,184,153,152,179,66,104,228,48,13],[65,8,148,218,62,95,181,146,205,25,73,224,19,73,120,69,232,112,211,222,39,62,71,57,96,104,87,20,5,159,236,48,9,38,8,102,225,122,126,49,88,226,203,126,228,0,11,1,243,161,110,181,11,60,134,224,140,192,67,243,244,133,16,103,167,69,220,152,150,157,24,17,173,15,214,82,144,7,196,123,234,15,244,138,148,137,214,97,232,242,150,54,38,136,75,10],[56,217,114,105,210,94,83,75,166,67,141,233,79,164,252,16,139,13,42,35,174,208,255,68,114,204,170,192,6,42,80,22,2,31,72,174,131,235,255,235,7,170,61,243,203,126,63,12,132,163,146,7,255,202,119,135,163,41,162,78,124,210,174,6,149,172,61,134,127,219,102,4,217,155,213,78,199,253,210,115,200,235,102,68,202,213,113,36,95,30,29,249,250,93,169,4],[142,47,41,127,242,122,97,198,233,254,38,187,83,121,32,107,151,180,185,239,52,114,181,223,90,112,64,38,126,191,229,21,171,183,200,90,114,90,17,84,58,74,248,17,20,144,249,14,70,169,116,159,78,168,42,54,61,156,140,225,94,240,188,229,26,229,134,216,1,37,220,22,152,5,173,191,234,89,44,138,148,32,110,73,115,64,234,113,197,146,173,194,205,161,95,20],[17,2,57,181,109,103,137,33,139,139,69,21,94,61,92,225,33,254,112,229,237,14,169,205,117,26,34,167,166,45,127,56,76,106,237,223,244,15,223,32,121,220,187,73,192,236,50,18,112,54,204,56,148,148,110,247,33,216,104,48,214,15,224,37,3,116,24,101,255,241,166,135,207,186,132,79,22,47,227,161,12,204,54,182,54,191,167,236,201,197,12,97,42,80,243,4],[31,100,168,144,179,186,156,159,92,165,210,235,189,64,182,67,140,235,149,121,244,46,142,249,112,22,222,85,17,175,158,19,50,135,188,238,235,101,118,193,196,219,131,69,246,69,106,8,93,100,125,205,195,26,104,16,155,131,165,64,250,49,207,238,10,188,201,74,245,118,6,162,124,206,15,96,192,162,7,175,225,52,229,30,110,182,124,179,139,11,178,124,119,179,131,16],[140,242,134,230,67,69,122,146,177,115,218,217,139,213,160,68,163,73,208,255,41,159,160,249,37,119,135,107,96,20,133,168,215,40,228,67,194,10,237,242,145,92,198,88,83,61,47,20,56,5,218,112,164,158,123,24,67,138,51,99,223,84,52,120,100,248,98,83,133,105,14,73,13,203,216,174,176,71,169,99,225,125,84,146,169,30,90,87,97,24,69,122,114,98,93,8],[67,18,64,153,168,255,59,185,1,237,244,96,31,1,203,202,86,4,145,98,64,147,168,248,204,119,42,46,54,50,99,149,121,172,242,75,187,101,96,28,5,105,234,56,219,194,179,4,18,186,53,151,34,77,144,178,171,209,62,226,76,4,83,87,193,220,92,125,158,137,110,45,212,224,70,231,76,231,123,179,113,106,223,169,81,219,82,215,153,199,15,38,85,219,31,1],[134,104,246,183,41,8,196,150,135,237,80,251,149,69,62,226,196,58,149,110,193,231,20,227,251,52,195,142,41,164,34,97,36,166,250,218,221,65,160,55,79,48,167,207,47,51,240,8,204,240,128,59,52,79,185,105,185,248,42,123,19,155,151,32,139,62,95,66,70,255,44,246,34,60,77,254,151,185,234,22,156,142,183,174,188,195,11,206,99,229,166,151,31,125,27,4],[203,244,207,232,16,231,94,239,89,45,240,173,80,203,212,42,167,120,70,51,5,242,52,184,240,153,58,233,209,49,224,229,151,156,63,244,241,206,201,50,93,63,46,3,150,188,94,0,31,170,241,19,72,255,170,170,252,239,104,140,91,43,57,195,174,126,18,124,131,97,46,175,116,20,66,205,148,137,248,199,78,38,147,231,75,236,98,170,252,89,50,31,158,127,39,15],[187,76,100,121,31,45,195,168,165,253,88,21,86,178,223,185,175,95,7,163,193,196,55,241,107,194,70,71,56,33,68,25,55,238,245,73,224,103,117,109,13,209,23,222,60,249,53,5,154,215,24,210,112,52,28,4,165,14,21,182,208,150,61,215,238,10,178,249,255,110,218,200,28,196,137,51,209,99,239,56,169,173,250,118,74,53,67,65,153,125,193,110,251,64,208,4],[237,140,246,74,31,203,239,97,246,33,178,242,143,73,122,169,40,20,34,246,159,79,77,156,153,97,154,113,190,4,112,146,148,185,95,88,109,164,221,17,220,205,221,9,92,80,116,25,4,96,148,14,1,170,77,149,187,92,30,102,103,168,66,169,228,53,151,222,13,197,203,61,211,79,189,138,129,233,55,238,167,244,140,223,109,75,65,214,88,2,44,198,177,237,220,1],[147,19,62,145,255,42,83,194,18,138,105,211,30,161,114,106,65,149,11,54,254,117,231,49,91,146,66,157,251,202,107,52,33,98,123,145,7,220,224,133,160,217,79,94,138,20,125,22,202,107,202,9,252,183,93,187,187,110,126,117,193,131,224,192,83,171,158,219,42,28,85,229,101,105,74,198,149,189,23,101,244,18,13,44,126,10,100,176,44,4,155,238,30,229,133,11],[248,233,196,25,87,59,223,21,234,35,204,47,17,122,22,224,79,246,24,166,103,140,32,63,243,7,151,147,68,221,195,250,152,207,253,101,130,250,35,59,97,218,40,116,201,85,78,20,21,115,135,56,237,40,124,145,166,110,176,64,232,66,86,220,82,195,249,245,91,141,121,198,87,159,129,186,102,217,134,21,184,183,107,198,214,5,63,105,92,26,192,253,0,196,15,4],[187,236,221,233,215,145,112,140,87,27,134,240,142,6,138,27,139,9,46,224,104,71,202,142,234,199,16,227,151,210,90,117,1,191,207,168,122,205,2,253,1,208,196,134,39,144,182,14,82,169,39,182,153,110,212,242,160,37,108,19,149,4,148,215,84,96,16,73,242,0,125,31,75,121,156,213,180,108,84,153,45,246,175,128,102,111,22,187,130,96,143,245,56,185,67,9],[251,106,229,184,142,159,27,130,56,11,96,11,105,131,58,226,255,241,166,70,249,10,92,186,14,165,96,28,16,100,217,111,88,170,142,175,78,206,88,137,247,205,23,71,48,252,160,18,179,209,84,18,51,143,228,200,213,166,110,51,138,99,118,93,81,26,35,152,100,127,172,170,239,93,0,49,56,3,40,209,131,106,200,172,244,33,31,65,244,141,19,50,164,52,100,11],[237,62,199,3,42,104,98,132,30,206,251,30,53,128,30,12,114,234,22,172,99,136,193,233,6,97,7,226,192,0,146,81,64,109,118,204,6,182,155,9,179,105,192,180,190,47,218,10,52,199,244,188,130,106,139,81,46,83,39,152,178,152,29,176,187,69,198,59,196,11,7,157,17,12,145,27,139,111,61,138,34,27,48,149,152,67,244,97,167,42,9,177,157,153,43,13],[150,183,197,244,103,67,166,173,87,39,188,186,165,231,217,5,4,193,242,144,43,21,104,206,148,237,66,147,36,141,55,227,161,39,199,138,188,117,239,135,194,180,26,189,91,255,110,16,164,102,147,108,106,16,61,247,193,210,214,132,107,57,220,36,238,190,131,84,66,159,58,216,99,55,90,198,146,110,36,235,81,152,112,205,204,145,76,202,237,35,189,174,236,138,7,0],[72,196,126,93,99,88,188,122,249,225,187,200,48,19,221,183,130,18,31,196,66,220,111,224,65,69,146,3,202,117,47,148,229,135,29,38,82,136,106,6,40,136,81,220,14,41,158,11,181,152,167,195,130,119,246,126,62,195,156,182,91,191,226,26,184,250,249,33,18,186,79,236,215,137,40,157,129,190,194,33,175,121,91,72,106,182,169,128,14,153,169,169,109,66,143,7],[249,20,65,253,208,126,58,31,97,84,248,32,87,146,133,19,4,247,27,10,137,196,203,165,32,244,67,66,157,246,32,23,65,255,221,46,3,8,191,168,224,161,16,31,209,206,50,21,194,130,8,216,138,248,196,213,165,118,64,8,134,67,127,157,251,169,219,161,101,132,241,178,51,241,239,99,227,121,139,143,145,215,116,238,191,214,64,84,179,83,191,126,212,7,233,1],[19,37,180,149,143,243,56,65,207,157,11,129,135,95,40,162,129,139,222,111,92,198,202,21,169,46,105,171,65,197,27,128,66,38,232,157,50,63,167,114,252,88,36,75,226,67,58,20,159,213,197,199,183,190,78,16,229,228,129,240,10,156,113,98,143,101,172,205,171,23,39,138,5,46,198,63,171,175,110,211,90,26,22,36,238,224,41,57,233,206,169,231,79,34,237,1],[200,164,17,210,70,253,138,172,120,242,255,19,55,22,17,5,27,232,159,228,168,123,121,196,196,59,250,17,213,65,92,101,171,160,149,207,251,83,225,15,121,135,124,149,149,201,8,15,87,167,155,226,47,109,79,206,250,102,243,20,79,108,178,27,192,149,64,162,214,120,190,210,140,35,74,22,42,128,109,109,54,222,234,99,57,168,228,10,35,211,94,111,205,30,13,14],[209,95,253,141,23,46,62,191,138,118,149,23,6,224,16,159,5,220,53,147,93,36,80,77,229,54,242,245,144,139,75,122,78,106,77,70,214,219,57,62,129,115,9,238,99,238,228,21,177,42,72,51,13,149,183,46,46,241,141,75,198,155,240,171,226,200,229,224,130,150,90,178,166,63,245,66,243,17,251,155,246,211,48,202,68,40,108,208,53,26,99,72,139,175,130,7],[250,228,184,4,98,252,213,239,27,22,91,238,103,94,188,237,58,204,161,82,136,86,131,214,147,1,240,185,95,70,235,102,99,19,241,138,53,176,56,65,17,213,101,196,115,123,241,19,7,38,210,206,121,234,26,215,247,218,87,241,100,158,179,207,194,185,165,60,52,188,132,236,235,250,52,150,35,202,12,238,187,70,90,125,81,6,247,118,134,177,205,126,3,242,60,5],[197,107,21,137,118,192,228,202,134,253,213,63,82,113,156,40,57,198,115,76,103,120,8,178,93,169,114,189,114,246,241,244,122,208,239,232,153,235,245,160,9,255,71,247,111,70,166,16,200,37,124,26,122,92,27,88,27,197,120,164,154,223,137,158,206,229,3,145,60,80,37,46,118,84,126,172,72,194,3,68,18,172,89,42,139,149,199,53,148,56,211,58,62,121,19,13],[216,106,228,241,12,236,138,239,73,44,146,138,38,220,128,201,220,194,221,69,188,97,254,136,88,38,171,78,193,116,146,19,250,62,223,60,198,213,15,137,208,240,98,184,38,84,187,2,124,185,254,91,43,46,235,16,158,185,79,179,249,62,173,72,35,29,214,173,244,113,247,242,84,113,39,62,139,192,227,144,54,5,13,145,56,12,99,106,172,107,77,111,126,187,3,16],[163,253,11,41,102,76,171,90,168,159,193,191,250,110,41,112,138,183,32,66,111,69,105,29,242,175,72,65,50,124,241,69,158,186,93,178,66,116,68,117,125,44,20,150,4,201,148,14,195,139,72,74,215,4,99,26,14,18,124,73,98,88,135,143,233,234,43,81,44,162,132,214,19,120,8,193,163,83,109,12,210,77,129,255,53,107,36,45,155,159,217,38,201,192,100,10],[40,35,107,62,215,145,112,63,41,107,41,176,14,69,99,43,214,39,146,181,224,104,59,124,63,113,125,171,28,135,29,225,67,207,29,0,27,22,190,36,229,127,159,44,107,178,75,21,218,241,196,251,91,249,167,111,245,58,59,34,127,153,176,158,31,99,129,97,174,10,121,25,52,194,38,212,249,156,154,110,15,175,124,59,50,141,94,211,43,223,145,94,8,120,105,23],[133,158,107,220,238,61,190,117,25,122,141,254,194,133,41,81,159,139,98,120,127,151,220,30,140,3,95,201,182,162,28,66,188,79,95,6,223,71,33,177,188,177,202,224,57,190,195,2,215,94,120,85,181,36,219,78,32,9,195,147,120,163,29,207,101,216,177,28,94,2,133,123,136,171,239,76,54,32,92,236,39,202,12,90,208,172,77,25,136,117,127,126,208,155,201,4],[162,123,71,92,9,153,146,73,218,175,243,255,123,20,80,168,114,121,140,226,170,175,186,235,38,45,180,231,61,24,108,13,229,44,119,60,108,161,2,81,68,48,208,62,2,41,14,3,180,108,61,29,121,173,158,91,27,228,69,209,222,167,9,122,213,245,119,103,140,240,0,252,48,105,142,76,144,162,28,144,126,113,22,245,228,190,195,10,74,208,233,213,125,78,208,5],[219,12,247,120,0,89,113,186,85,83,91,115,224,180,18,1,20,103,5,123,65,191,57,240,170,207,105,201,187,25,88,249,244,83,254,3,234,101,158,118,145,4,157,13,28,219,112,6,35,41,89,227,106,173,124,150,127,183,170,116,86,186,162,112,227,149,40,238,154,34,169,218,163,202,222,236,93,120,84,206,3,61,250,178,30,239,20,69,159,74,218,74,216,114,210,4],[39,137,238,180,6,140,45,113,156,40,157,8,115,42,64,218,32,185,238,65,134,66,116,12,41,101,145,201,69,125,178,211,71,49,231,82,141,47,2,139,152,254,212,55,251,158,122,17,66,242,117,87,137,19,156,9,35,158,182,195,80,187,112,9,79,172,188,159,80,194,71,230,9,115,187,238,4,186,246,226,37,190,54,182,71,59,249,37,45,53,24,86,147,143,171,3],[194,89,166,159,92,8,152,76,139,138,79,63,70,109,43,110,139,216,106,177,170,77,215,105,229,125,89,191,232,186,110,162,127,250,132,251,243,210,70,74,17,16,253,26,1,120,75,23,181,164,45,117,139,157,44,174,175,9,249,172,51,222,253,242,23,160,174,254,52,225,134,123,12,30,137,99,49,89,214,111,31,187,124,149,80,121,91,49,193,47,148,20,33,63,177,0],[220,191,198,142,44,223,192,127,229,125,134,185,44,100,29,167,61,254,84,84,124,171,244,100,3,155,171,152,146,232,62,251,205,164,82,68,178,134,222,40,176,231,114,72,42,103,199,21,141,202,18,54,221,36,72,69,124,228,136,164,94,9,64,76,165,194,131,199,254,20,218,233,43,75,57,200,55,23,105,87,223,108,225,38,128,99,53,94,215,251,163,23,56,253,118,14],[65,226,195,7,92,12,217,63,141,216,39,63,42,253,10,104,89,182,158,54,131,132,75,111,168,116,173,204,240,37,172,28,197,255,212,120,95,101,148,185,54,202,104,151,31,116,156,13,24,154,20,208,156,75,115,121,137,49,140,173,145,8,3,128,8,18,91,117,112,176,111,36,141,246,123,251,113,88,161,176,250,206,175,250,4,185,69,245,33,219,202,2,227,166,176,3],[65,16,62,167,24,107,206,143,49,111,80,52,166,196,13,106,234,95,127,90,169,204,81,100,56,3,235,42,187,233,244,77,221,61,235,42,200,178,58,245,108,187,192,131,115,198,29,5,241,135,198,67,126,79,103,106,143,245,34,28,152,54,245,142,17,155,168,225,207,255,174,246,171,38,94,114,76,254,220,197,186,41,252,246,63,251,47,25,146,107,95,109,140,70,33,4],[219,241,157,86,206,123,107,32,135,68,47,105,165,210,88,56,136,118,13,7,2,83,72,236,96,90,114,199,241,229,136,33,41,162,173,228,25,58,73,200,154,55,47,20,167,141,220,25,144,98,116,35,56,231,82,189,154,93,118,61,132,7,6,193,111,162,203,210,185,202,210,149,58,158,219,173,121,145,49,212,207,121,125,75,255,145,43,129,71,195,105,128,122,15,169,25],[165,167,141,175,1,5,255,31,78,198,239,119,120,217,210,23,19,180,17,87,125,0,159,59,40,248,176,122,218,203,49,16,186,46,210,66,217,179,204,104,95,29,12,21,125,62,41,3,136,116,122,248,185,153,222,98,151,133,29,176,254,3,193,141,164,163,201,90,78,232,99,209,120,73,163,126,151,71,173,121,210,77,232,21,59,134,176,255,1,188,2,164,163,182,25,12],[49,122,34,130,164,139,131,181,92,115,150,4,198,201,186,168,249,243,91,140,14,105,216,74,134,176,28,191,71,80,18,64,4,125,224,255,40,213,65,249,74,185,219,149,23,209,18,11,206,116,146,29,148,107,208,241,235,194,239,74,188,0,52,32,126,148,39,51,245,112,91,180,206,155,133,157,144,10,246,209,162,157,254,199,186,89,212,122,255,160,226,187,106,56,186,10],[206,56,234,42,13,64,92,50,249,113,175,129,111,163,30,171,54,246,51,103,138,200,151,70,8,56,164,251,180,40,74,28,115,171,34,140,168,233,43,96,156,61,142,245,225,154,221,13,224,151,231,138,109,224,159,187,234,196,176,181,173,27,82,181,46,7,185,137,158,9,101,25,239,29,167,19,50,170,123,149,85,55,163,174,154,49,86,101,153,213,39,0,55,218,23,23],[215,187,138,186,119,223,82,131,72,39,162,45,214,53,43,68,105,51,171,10,173,136,99,78,217,26,51,32,78,175,26,106,193,150,68,132,69,53,185,177,209,81,141,88,138,199,24,17,217,16,24,29,221,162,213,77,55,44,131,74,198,161,63,47,120,173,85,185,153,141,142,188,75,31,163,18,164,70,11,73,246,113,103,232,61,119,106,231,0,251,171,219,55,190,97,6],[165,20,167,84,216,50,134,117,122,235,89,60,102,155,179,139,4,35,177,231,78,252,180,82,7,214,151,158,2,23,100,72,92,215,119,85,137,14,252,24,69,21,6,47,255,57,118,16,162,174,105,151,119,228,33,173,164,162,65,137,255,140,41,98,224,241,219,214,191,237,242,36,224,184,243,211,239,206,71,76,28,123,109,142,43,252,194,246,72,140,49,211,201,86,98,4],[239,153,174,21,43,22,177,224,187,50,24,74,18,141,219,159,46,16,189,77,82,86,106,197,190,208,21,124,59,204,49,224,76,178,110,47,97,242,178,139,213,202,243,92,123,56,95,25,253,84,164,186,114,118,166,18,63,202,119,195,105,241,163,41,224,165,190,139,25,11,2,158,30,60,241,66,71,134,130,65,146,129,108,130,172,16,35,219,24,43,189,211,58,53,242,25],[152,69,34,134,15,139,118,233,103,65,194,130,99,189,80,74,217,85,228,132,35,51,94,207,82,143,140,76,147,126,52,148,24,129,186,181,118,55,98,202,30,45,7,57,105,29,236,9,239,225,150,101,75,90,177,95,163,15,121,163,40,101,102,200,4,190,6,66,18,176,192,142,144,180,35,76,49,255,88,119,223,44,147,224,13,91,202,167,168,131,6,196,160,42,224,25],[80,13,246,171,169,217,28,120,44,6,27,90,127,207,73,234,140,254,92,227,156,173,11,143,38,223,159,255,178,7,121,221,152,189,176,202,18,131,169,123,163,244,115,11,185,51,140,8,163,19,128,156,148,67,37,49,227,74,107,77,122,137,15,16,187,55,240,146,36,159,154,36,243,242,115,246,89,25,68,200,188,138,114,73,113,24,215,128,36,201,226,22,58,45,141,2],[213,105,50,165,253,187,155,107,184,135,151,73,78,50,60,77,172,226,218,231,145,62,71,15,42,25,191,200,213,26,155,35,213,34,149,33,89,126,42,91,68,107,146,215,129,200,42,5,98,127,108,209,138,140,29,221,53,153,49,178,102,48,226,11,76,192,176,171,114,160,204,61,198,241,201,113,131,125,190,235,252,142,130,54,13,57,58,118,151,31,156,190,100,252,28,0],[231,73,139,17,17,175,152,62,58,62,219,180,236,6,231,178,133,46,128,41,144,160,81,177,64,16,74,136,203,251,197,65,249,249,55,80,28,183,51,11,24,61,18,165,174,119,85,20,234,67,132,229,127,124,133,29,121,198,102,67,96,50,136,161,39,186,67,9,31,86,34,140,119,92,180,232,147,238,58,67,99,164,85,77,98,221,68,37,125,178,94,87,215,141,198,13],[189,4,121,54,17,95,205,230,93,214,152,200,186,125,46,202,242,126,106,165,102,106,184,165,241,94,106,115,80,57,171,155,217,170,105,171,214,28,159,13,32,196,213,11,114,66,165,12,134,230,212,174,41,217,57,254,111,139,157,59,160,184,114,90,138,222,75,188,241,11,249,135,90,119,31,89,226,68,71,49,80,211,16,161,187,21,123,77,164,162,241,34,7,147,57,20],[156,91,234,50,211,145,20,181,134,68,144,175,37,175,72,2,172,9,221,86,99,227,221,150,203,89,165,242,91,167,248,184,164,179,117,16,228,32,103,229,193,159,148,214,251,53,185,22,161,147,104,199,188,230,66,227,41,86,71,90,110,89,29,233,210,201,17,32,47,152,214,240,233,57,160,140,62,114,11,34,58,61,233,26,92,173,159,35,57,62,160,238,72,153,122,10],[109,123,107,161,193,27,194,153,127,189,232,104,135,191,9,13,110,198,231,244,107,0,89,239,6,215,117,120,104,166,31,225,212,20,185,18,238,242,171,166,143,77,190,177,234,222,15,14,80,84,54,56,151,174,92,80,73,61,243,9,233,161,209,176,114,44,89,244,137,95,63,46,245,42,73,239,135,185,47,139,102,82,212,142,143,245,11,69,82,179,94,195,148,162,18,13],[102,113,162,95,45,179,234,61,230,211,188,7,205,8,118,63,63,91,43,85,168,143,177,226,69,251,147,126,96,201,173,188,64,139,118,219,102,255,42,8,240,71,153,122,82,249,249,22,192,144,166,37,61,130,133,7,217,234,180,32,121,140,251,74,164,17,46,96,79,92,46,41,149,172,56,113,197,211,2,185,104,26,10,217,248,34,158,82,139,122,100,107,159,4,198,16],[26,84,1,8,249,41,221,244,59,218,238,190,47,56,149,163,209,48,130,159,217,141,173,87,162,249,135,147,141,220,187,91,252,31,141,243,215,170,8,119,80,31,193,78,195,239,192,3,157,55,0,28,34,114,145,61,233,57,107,140,26,57,237,17,145,176,219,108,34,197,159,101,111,238,223,72,190,177,132,52,219,167,23,39,152,62,83,112,119,168,183,131,173,31,51,25],[218,193,158,202,209,78,115,216,9,142,123,55,45,10,199,212,15,155,117,190,67,49,168,121,82,253,149,200,237,45,50,41,8,142,196,57,59,161,77,77,255,62,218,234,255,216,246,10,179,9,183,130,39,143,223,20,123,203,192,67,52,149,52,197,164,9,193,135,203,147,37,9,219,128,114,167,56,162,78,35,161,15,63,249,29,225,108,168,137,244,240,124,244,67,189,21],[184,191,188,102,155,29,91,187,27,106,27,79,235,252,71,130,238,110,114,58,39,4,68,167,120,115,248,83,17,211,47,154,104,169,202,7,31,252,6,216,65,92,203,180,143,142,72,15,244,149,25,16,87,139,1,167,31,174,76,72,181,11,66,121,174,62,197,24,129,6,227,244,78,232,129,113,152,171,56,142,142,122,171,145,210,253,230,11,136,3,113,144,90,249,166,1],[105,160,166,1,185,184,255,87,23,127,104,108,217,202,46,156,112,27,199,206,182,120,239,132,45,44,218,222,77,209,112,70,15,166,100,112,89,7,36,59,89,209,60,158,153,134,85,6,136,103,124,135,92,26,98,187,12,151,146,159,102,178,49,19,135,220,232,89,249,43,138,253,221,104,235,230,123,224,90,28,202,189,18,213,167,156,2,125,120,237,41,197,12,247,37,18],[225,128,19,97,243,231,6,144,246,153,197,21,247,57,157,14,78,13,131,63,19,136,129,140,205,137,215,166,4,89,192,49,198,19,176,48,125,25,238,221,124,51,222,25,92,145,14,23,13,197,84,56,24,161,25,187,50,8,53,136,183,239,126,187,249,132,67,252,144,17,142,113,162,46,83,4,98,221,226,39,157,199,15,152,181,61,235,144,21,21,10,169,55,45,80,0],[20,142,184,245,100,101,132,56,175,244,135,8,187,10,67,10,244,23,68,240,191,93,44,18,168,93,74,215,164,67,49,25,205,203,238,218,132,202,225,82,131,190,209,8,31,213,39,25,52,202,99,20,170,46,167,178,243,74,37,72,133,174,93,40,108,150,232,191,89,150,137,27,228,152,245,127,245,65,9,128,61,66,228,29,93,139,23,248,174,138,226,17,187,253,212,11],[16,245,248,115,132,212,52,243,118,165,70,210,202,115,65,251,148,180,180,93,2,33,225,183,63,48,212,225,25,20,123,148,105,133,161,232,64,103,48,4,167,83,160,44,160,167,104,20,112,172,84,161,207,160,91,247,62,119,183,52,249,34,188,142,76,29,247,229,190,106,153,176,186,149,104,222,43,0,79,212,253,222,177,191,90,231,198,89,178,239,102,191,68,102,193,19],[90,251,63,237,124,10,68,120,220,131,98,192,51,161,42,193,224,171,100,63,83,80,172,34,185,175,29,144,80,22,185,43,59,45,159,53,147,196,12,60,94,54,46,176,82,189,157,16,81,134,226,48,206,91,131,59,139,85,246,249,242,142,19,65,155,64,171,187,221,149,139,159,39,217,120,85,77,95,117,215,239,134,161,26,93,134,210,145,119,167,163,84,137,23,167,11],[38,72,158,73,177,91,248,14,254,184,45,185,198,36,41,217,107,191,202,48,161,214,96,51,84,86,178,140,84,214,38,237,206,236,248,108,231,130,233,62,132,48,196,234,0,210,37,4,211,159,121,20,67,188,175,141,102,11,192,169,172,186,176,187,131,39,153,241,61,247,6,1,252,138,79,182,250,172,232,81,10,250,95,230,207,3,200,186,20,210,252,136,157,95,144,11],[181,199,208,51,59,60,63,109,217,168,106,211,124,168,247,227,86,203,193,30,123,46,199,187,172,99,60,133,23,213,50,79,253,148,188,134,136,187,3,212,13,104,74,94,84,238,107,2,41,108,176,245,203,182,137,170,174,205,87,100,107,33,178,172,151,163,227,114,246,103,187,48,194,74,112,172,112,185,129,166,231,32,154,35,141,221,199,2,102,15,97,26,41,197,48,2],[80,39,87,163,221,161,208,222,66,214,26,23,161,195,72,56,39,87,14,79,93,126,6,184,202,90,41,122,205,204,94,194,1,11,33,62,159,213,207,254,171,169,108,128,2,180,74,3,252,123,188,150,195,91,85,24,42,119,146,85,129,153,136,138,222,24,56,169,15,145,106,38,191,152,199,7,2,73,106,51,128,211,167,19,130,177,186,184,96,133,6,136,112,114,31,1],[249,191,31,148,98,17,141,209,241,80,212,68,186,216,8,109,241,177,196,104,29,194,141,30,210,90,181,191,239,69,48,199,207,78,235,26,17,8,12,64,136,84,183,102,118,6,19,2,89,93,164,173,56,97,11,238,100,196,162,93,6,81,140,97,69,86,140,37,203,21,50,58,176,27,192,230,118,212,35,159,184,130,20,115,224,98,94,151,13,3,18,112,6,190,64,22],[228,236,112,78,54,113,159,36,62,149,94,197,205,36,150,25,89,223,254,195,144,98,140,1,158,14,93,226,190,226,209,54,120,4,146,194,36,203,206,150,5,57,168,106,112,217,42,25,168,88,194,71,206,83,195,43,82,38,183,19,202,2,223,40,239,17,98,175,113,61,74,45,43,144,94,23,66,199,202,47,227,119,16,168,117,28,72,241,19,248,8,86,9,220,231,4],[252,16,210,119,202,217,167,184,16,52,150,137,168,175,251,28,152,157,91,29,211,140,20,237,39,103,119,143,113,150,115,227,245,214,237,160,156,102,205,142,129,234,65,69,185,162,234,0,150,23,68,11,107,122,194,176,182,203,118,119,178,173,226,112,162,252,134,231,88,218,111,233,203,127,139,239,243,81,54,29,61,8,201,213,34,167,25,45,212,227,245,31,86,177,114,9],[119,152,140,52,82,87,164,172,32,124,154,221,255,221,86,146,13,172,221,151,102,233,186,93,148,206,97,25,232,88,173,67,208,110,219,166,9,163,154,218,26,187,209,112,22,217,99,2,186,82,252,213,117,200,110,102,163,98,202,234,24,184,241,57,138,86,40,235,207,98,192,30,95,99,205,136,212,180,129,211,176,33,134,229,209,51,193,237,64,95,29,99,160,52,206,19],[195,236,22,227,178,119,32,243,65,252,79,190,69,173,11,178,221,51,98,63,179,207,192,78,109,3,95,62,221,114,111,138,83,252,34,126,67,112,198,255,70,61,51,140,232,96,251,17,26,217,138,24,182,211,104,82,212,1,121,226,211,163,9,114,9,103,193,212,28,241,62,173,165,58,97,181,162,142,212,38,144,229,160,49,202,63,179,108,214,57,157,103,139,228,175,17],[179,69,188,207,199,177,76,0,209,9,127,78,1,209,97,0,27,127,254,65,44,139,12,244,43,125,91,124,166,108,201,166,30,128,164,65,107,79,240,85,55,10,19,34,4,87,5,15,158,245,245,48,161,225,248,221,132,132,173,80,160,18,29,16,143,107,136,36,90,87,20,219,109,81,131,197,146,22,203,9,174,88,202,83,160,119,102,140,10,125,19,230,140,47,114,20],[105,118,192,103,40,209,113,51,80,127,209,60,223,9,120,49,46,6,145,84,40,166,102,212,53,10,98,196,109,173,157,104,55,2,29,82,218,67,77,201,235,31,80,156,44,185,100,21,198,238,10,233,145,212,147,89,36,122,29,107,30,205,236,115,251,103,131,229,189,129,55,84,1,190,0,66,74,214,183,245,138,249,136,243,94,4,47,166,37,10,7,238,29,41,226,12],[76,178,47,194,39,249,117,28,62,119,182,174,0,240,146,217,244,118,76,127,29,155,60,203,115,114,187,9,17,151,238,91,188,8,68,100,28,188,230,80,221,146,139,238,155,50,207,24,136,2,173,45,194,217,202,32,161,141,21,202,185,65,208,93,219,37,60,116,184,162,188,116,180,161,206,48,98,252,190,217,141,138,199,111,5,12,13,68,160,153,65,163,206,109,197,5],[154,173,227,154,48,233,247,168,165,61,128,185,52,182,178,172,197,105,76,75,16,105,123,102,86,27,30,178,187,100,91,106,249,217,112,186,136,156,86,37,141,241,170,161,197,253,9,23,61,50,14,187,55,224,207,250,185,122,138,74,184,42,4,95,29,189,173,167,27,30,73,32,138,66,91,64,185,134,125,214,48,48,243,70,228,242,166,57,248,44,156,65,252,212,209,5],[241,163,216,70,34,58,19,213,47,2,38,38,255,165,120,139,163,102,149,39,130,115,131,8,101,38,53,71,196,98,65,228,99,161,174,170,152,35,134,228,160,212,193,144,153,12,255,6,70,4,148,51,201,174,98,173,27,82,36,223,36,59,47,236,197,36,44,171,197,48,180,57,49,164,193,250,183,73,135,92,14,111,193,77,236,245,240,45,11,222,220,186,28,64,8,0],[83,239,30,230,116,68,218,55,88,97,7,21,158,194,158,253,234,144,121,163,225,240,154,1,161,236,149,217,28,152,238,170,25,68,165,245,203,150,200,117,109,116,110,206,165,159,249,14,216,204,166,62,58,91,97,236,92,140,229,196,57,98,232,213,154,53,220,86,53,241,206,138,241,66,188,35,154,139,206,208,59,36,117,16,242,24,193,132,198,201,107,1,144,121,99,7],[98,144,39,171,4,111,135,50,132,3,131,252,173,161,92,137,104,23,201,144,54,151,216,41,42,51,204,201,92,227,246,131,175,77,253,154,41,45,177,111,252,3,187,78,58,38,20,17,115,66,199,234,32,196,47,135,134,39,6,238,44,229,61,70,209,127,133,186,155,95,15,48,90,207,155,112,208,107,149,33,94,72,156,170,222,107,42,64,62,213,136,26,255,114,40,20],[154,34,48,141,166,124,44,19,196,13,110,83,131,75,119,11,136,85,168,162,152,80,83,87,21,7,1,51,244,96,4,102,77,125,250,82,132,39,173,28,134,148,130,250,200,227,46,18,128,189,97,178,119,202,165,36,155,173,23,167,153,49,79,56,159,220,183,152,220,86,98,239,81,95,228,169,92,224,30,246,58,223,87,13,84,35,177,228,186,23,39,119,251,90,103,21],[94,100,201,189,142,167,114,189,198,105,207,105,134,12,130,23,217,133,208,69,47,105,203,126,17,157,159,185,141,100,87,57,236,115,186,255,248,28,33,188,50,13,32,109,149,253,28,17,228,98,134,136,119,130,251,3,55,168,25,2,182,42,182,154,134,140,23,92,225,105,250,223,43,2,120,242,53,25,82,225,161,224,120,180,41,132,203,97,110,127,3,206,43,40,214,12],[115,239,30,198,183,97,121,35,224,130,149,15,172,204,166,71,15,175,199,113,221,51,45,255,106,137,52,203,20,160,160,243,72,209,171,79,5,71,85,83,226,85,234,165,252,152,219,22,138,173,234,247,238,138,69,202,121,137,60,39,153,110,206,176,109,241,140,59,59,108,249,138,74,221,248,212,226,172,158,22,38,152,125,74,179,106,43,53,208,56,67,59,53,220,227,22],[147,210,171,136,42,77,43,77,87,154,120,21,109,149,165,8,178,221,135,124,63,248,118,197,52,102,208,33,17,56,230,182,230,106,47,173,78,192,155,217,140,240,68,216,164,127,13,2,82,75,175,230,178,96,14,233,235,139,52,114,11,57,1,15,146,98,40,193,190,88,5,219,185,106,48,85,140,140,155,148,76,179,63,199,28,175,225,122,114,230,180,115,174,15,86,19],[249,232,32,160,58,57,169,22,226,203,100,130,203,183,80,56,104,205,150,101,12,159,183,73,142,70,150,127,115,63,109,169,160,67,192,254,176,103,63,67,241,224,160,203,49,207,52,10,26,131,249,135,147,170,172,188,125,113,32,239,89,218,80,214,38,58,223,86,96,53,37,11,193,84,137,40,235,152,212,101,56,80,172,240,163,55,93,58,154,225,45,125,139,2,165,25],[242,144,30,77,121,12,192,164,123,250,205,159,141,42,208,113,109,195,96,167,198,22,254,199,21,38,90,32,182,134,3,201,117,64,139,19,196,103,179,170,241,246,92,214,219,105,168,4,232,65,253,143,70,74,50,182,5,177,148,178,255,73,158,206,220,60,60,128,209,130,180,12,243,230,160,53,133,81,188,14,18,18,60,39,133,111,73,68,3,90,145,106,60,33,173,21],[52,72,242,198,231,166,122,118,179,125,213,207,16,226,7,104,180,117,163,113,96,152,167,115,128,236,125,102,82,151,196,43,130,70,243,142,74,169,30,90,152,33,119,173,89,238,113,3,70,31,86,229,216,207,121,34,119,39,164,81,233,175,5,225,236,225,45,103,94,146,158,201,159,198,224,25,42,14,52,157,2,246,180,55,211,156,246,71,39,218,52,171,178,163,56,21],[18,19,46,99,120,152,86,84,50,155,55,138,125,190,25,217,90,62,205,190,27,223,9,209,144,229,148,112,207,53,0,33,171,213,53,109,32,122,122,201,45,86,12,84,188,100,78,6,152,12,224,29,132,87,22,165,42,240,61,247,91,213,127,21,13,25,146,60,29,243,5,161,48,234,23,113,134,174,188,66,82,180,22,68,88,95,125,140,53,76,12,241,186,117,7,17],[35,93,184,105,150,14,66,41,228,183,164,244,225,97,130,51,1,119,168,231,130,211,32,102,4,24,189,230,220,171,34,177,251,52,154,113,24,77,70,54,2,120,201,181,84,221,125,15,196,96,142,108,74,103,99,44,67,130,14,11,176,180,191,10,8,182,113,208,220,51,78,182,37,137,98,127,127,156,133,84,221,111,130,35,178,213,142,248,127,244,81,103,1,42,17,18],[136,251,210,187,19,159,48,192,210,132,120,40,253,229,108,78,192,230,64,89,7,244,161,254,170,131,117,194,138,59,51,126,75,48,6,229,54,232,142,51,84,171,56,222,195,8,215,14,130,129,118,10,5,24,131,78,145,81,166,79,4,123,139,125,75,138,216,125,128,103,77,176,109,153,198,252,18,189,127,119,254,120,182,45,188,92,99,53,90,187,90,126,202,138,157,21],[108,86,14,81,114,12,9,41,55,128,133,61,49,115,127,23,205,60,143,162,14,10,208,14,247,42,104,123,109,141,155,13,129,61,45,86,142,171,221,7,54,115,199,22,63,91,149,0,209,241,247,6,198,229,78,94,80,181,149,42,249,36,142,79,118,162,93,178,133,161,29,123,189,71,246,80,88,95,199,159,9,160,202,134,155,142,247,214,222,240,180,236,131,161,143,22],[178,149,22,140,56,219,147,25,223,44,3,173,23,169,74,231,249,13,99,49,149,165,54,124,90,216,118,43,156,55,242,204,212,52,171,203,208,166,252,94,102,27,66,216,46,91,64,0,146,10,0,30,240,155,131,252,70,186,123,163,87,113,99,98,132,67,62,81,126,158,16,135,108,209,60,234,168,214,232,106,30,169,139,244,42,149,248,32,178,27,149,253,254,249,194,15],[57,113,247,34,217,205,111,154,159,54,69,136,5,16,119,117,222,27,114,117,6,42,145,46,160,116,38,213,4,139,138,242,244,109,244,45,162,131,179,48,134,209,165,2,43,234,95,16,129,149,42,98,122,15,129,25,131,143,155,134,88,244,206,117,165,25,116,219,223,103,3,185,60,169,81,72,60,190,178,223,39,203,21,153,250,53,234,17,209,38,87,166,190,209,100,13],[254,32,229,0,159,178,138,188,4,58,88,83,88,244,124,54,25,96,97,191,32,101,177,83,28,189,101,185,132,107,116,254,144,116,88,40,165,242,119,90,20,181,141,43,45,147,194,7,89,186,105,93,102,143,235,60,15,175,234,236,247,169,155,228,79,13,94,93,225,199,56,202,233,116,239,181,67,99,37,57,154,164,36,161,148,233,114,182,159,112,52,91,103,21,145,4],[177,235,172,186,20,20,149,218,135,189,159,251,188,58,218,9,2,244,5,31,96,180,51,65,146,43,56,73,171,127,110,158,203,252,241,60,189,250,22,223,125,31,43,32,166,112,17,0,29,33,79,103,54,59,184,62,147,75,153,101,137,26,104,117,137,168,216,64,141,163,128,61,65,231,115,76,41,63,207,252,152,172,237,145,74,99,175,48,105,131,211,146,66,9,57,8],[34,143,161,53,251,232,235,246,167,244,168,71,114,239,131,126,12,87,202,108,137,252,122,144,80,126,96,196,3,251,72,112,226,110,169,92,114,152,61,46,101,57,198,116,70,121,13,12,53,6,197,10,164,75,158,208,133,191,63,76,229,126,113,166,171,145,255,219,52,74,30,4,214,211,169,80,113,156,190,249,24,106,248,15,229,126,21,123,194,140,203,18,221,165,182,20],[119,201,228,121,130,26,85,89,55,248,142,67,31,132,1,37,144,40,187,185,215,129,8,248,238,15,3,84,191,137,16,220,204,51,127,70,62,66,60,25,250,127,77,153,128,244,227,21,49,171,199,236,33,185,215,84,147,26,11,223,232,95,4,66,207,22,58,173,60,254,197,182,79,135,99,46,143,116,94,84,169,107,44,11,31,108,151,136,27,115,209,96,200,243,97,6],[180,105,90,111,50,108,166,202,204,251,55,156,254,242,156,91,162,90,214,153,112,165,252,180,7,5,221,78,153,5,235,64,79,138,38,167,109,89,58,130,51,144,48,119,127,231,93,12,51,132,254,176,45,189,90,211,70,160,128,192,216,118,167,183,26,139,110,216,142,94,241,91,243,164,12,159,33,49,172,35,240,40,15,102,143,32,208,155,156,216,192,137,163,211,107,11],[39,243,109,205,31,43,209,218,101,22,115,236,35,218,134,41,41,153,141,240,2,81,68,198,197,234,144,135,122,183,96,43,40,76,253,83,5,162,226,144,166,246,36,104,58,226,138,19,178,113,201,127,168,62,103,73,19,226,216,62,220,74,179,167,7,197,252,33,2,162,203,6,196,118,98,29,2,227,102,245,253,213,165,127,206,138,169,235,99,191,103,57,139,230,199,7],[253,175,81,41,228,120,148,187,86,224,104,98,65,119,223,40,101,34,166,66,95,161,67,26,87,37,230,56,68,40,173,249,248,10,153,137,142,206,219,166,99,108,150,141,207,155,60,3,241,190,81,56,170,181,67,248,108,21,92,211,42,137,104,81,155,112,232,207,24,68,210,184,8,46,249,240,163,240,142,203,195,214,167,234,139,131,33,159,96,28,231,110,175,4,239,13],[60,103,164,140,99,191,171,67,196,21,135,143,217,35,193,229,164,19,114,224,234,17,196,96,214,80,71,114,186,47,73,120,155,28,136,59,131,50,122,150,198,77,228,26,131,112,175,1,131,1,197,178,79,234,20,240,54,186,8,252,95,107,98,245,169,200,32,198,224,20,42,247,129,38,70,90,62,92,168,125,196,3,99,239,117,236,37,255,126,37,175,166,208,178,208,16],[241,132,166,25,164,179,118,233,170,70,217,50,191,13,210,190,197,174,114,82,0,146,122,229,16,112,247,201,81,175,37,185,108,240,129,132,26,158,24,103,152,167,172,99,140,128,238,25,60,254,168,169,176,103,196,110,113,246,76,152,93,89,81,146,103,150,128,143,144,216,251,52,11,235,4,6,73,81,216,52,115,4,129,41,116,162,112,50,142,249,254,168,149,48,189,0],[189,82,148,22,24,188,212,237,215,71,11,101,216,11,92,8,38,149,69,232,151,94,57,91,243,223,11,214,8,53,246,80,118,207,141,200,248,127,60,96,199,252,34,135,168,205,221,5,128,182,17,238,253,85,183,8,63,241,42,31,111,140,179,161,132,95,96,55,71,0,135,238,194,237,242,148,162,81,66,87,60,231,226,146,51,240,187,146,253,0,16,169,120,207,231,21],[185,196,179,222,25,216,21,100,109,232,167,17,61,212,75,216,251,210,233,177,133,69,47,138,1,110,139,221,44,36,127,209,145,161,171,203,139,120,161,0,68,167,145,26,200,88,8,11,149,155,119,106,134,4,107,156,18,193,9,198,28,130,16,21,14,36,206,247,115,126,50,250,123,53,145,4,86,50,0,166,228,108,97,221,160,113,172,23,34,215,163,180,118,34,249,7],[175,222,152,110,82,171,46,220,42,49,36,77,164,187,125,28,138,223,6,28,71,36,13,24,37,233,236,224,86,139,178,40,12,138,159,30,48,140,39,169,151,120,109,164,78,165,50,12,224,128,225,17,104,171,12,127,33,77,42,30,25,14,29,41,85,47,182,103,10,133,104,227,170,135,237,155,14,116,124,103,187,137,159,90,63,70,106,21,39,145,243,105,229,202,180,15],[62,27,218,238,208,12,152,224,47,159,221,81,160,215,228,157,52,103,117,23,37,240,18,59,105,83,105,0,34,206,79,5,65,68,48,207,254,46,251,98,41,23,65,151,25,249,172,11,118,68,10,201,215,63,141,162,73,10,23,32,97,216,18,145,146,241,231,228,0,125,189,47,66,128,127,224,55,137,238,168,248,62,96,33,253,153,206,255,6,200,213,8,154,50,130,5],[154,55,208,47,183,160,31,41,15,139,28,249,23,99,95,132,89,216,184,171,137,163,119,88,132,175,188,23,194,16,163,205,105,231,77,143,86,246,152,233,218,208,7,149,175,20,148,9,96,65,143,26,180,110,188,30,38,233,94,136,111,114,213,219,100,84,119,59,217,226,238,18,119,31,238,33,174,180,222,154,62,207,1,114,111,187,100,139,49,38,237,193,219,1,148,14],[1,51,189,126,208,151,5,49,215,225,185,99,24,134,162,207,224,149,219,177,141,42,64,35,194,244,107,1,245,234,173,128,14,27,216,111,149,60,107,30,254,126,17,29,229,78,165,18,143,197,216,204,96,164,25,39,116,227,170,188,157,126,252,87,238,212,16,14,109,83,120,246,236,99,28,197,248,48,123,50,212,252,135,95,20,96,16,49,158,2,59,180,152,99,46,9],[157,180,170,159,88,232,134,49,61,252,118,215,143,105,146,22,8,197,97,60,51,93,252,219,116,145,204,66,253,35,166,211,89,37,229,72,149,69,84,64,225,82,96,56,144,76,188,12,86,153,147,234,83,187,102,8,12,79,62,216,155,201,226,205,182,240,83,218,232,98,75,141,44,136,96,202,163,215,152,228,190,219,103,234,101,119,191,167,14,89,170,44,193,225,24,18],[118,187,44,42,95,70,245,16,31,243,185,118,47,2,57,83,46,211,87,71,92,242,137,127,114,227,66,238,17,25,63,62,11,142,110,103,74,161,127,235,18,154,39,152,94,238,219,14,29,55,153,71,65,3,152,191,18,175,203,127,62,228,88,205,109,192,150,102,64,17,200,82,39,124,244,220,25,219,87,206,125,116,166,173,63,100,155,79,2,246,131,117,202,253,107,1],[98,221,114,74,210,21,227,14,221,50,237,190,224,108,172,255,218,154,5,226,113,224,189,3,245,67,163,135,182,14,49,121,8,23,105,197,148,171,143,168,156,89,68,97,12,27,239,17,228,187,241,107,246,94,151,62,59,45,2,93,136,154,202,203,128,113,153,186,61,164,3,204,222,156,69,247,177,94,197,207,229,116,151,125,36,228,187,159,36,70,143,153,216,228,197,15],[174,163,82,57,171,225,97,197,120,181,198,111,30,88,160,182,203,96,89,107,56,167,245,170,178,213,168,192,210,132,190,19,117,252,10,46,145,251,137,186,34,82,250,46,109,114,36,8,237,41,76,69,128,131,162,22,85,53,61,99,63,51,46,98,245,167,5,138,28,166,109,73,195,144,235,13,124,5,137,137,169,146,172,23,66,17,104,33,106,39,104,100,129,204,159,1],[9,37,51,213,201,46,44,70,57,32,226,230,114,22,220,253,160,36,33,229,101,18,60,140,146,110,67,172,205,124,225,142,85,150,80,2,173,9,95,154,188,242,124,80,169,123,12,14,184,158,211,198,26,31,95,198,75,43,204,221,244,60,140,234,81,56,194,189,188,43,7,62,106,79,90,36,246,221,169,103,31,33,86,109,152,81,115,87,9,160,100,138,119,84,204,3],[96,83,172,223,15,72,246,249,237,111,130,181,78,194,233,89,151,186,96,243,232,16,189,162,240,253,142,130,206,44,239,201,233,240,83,19,177,115,189,169,150,62,29,170,4,154,103,22,96,78,161,229,239,35,113,20,193,206,144,125,171,110,234,179,77,250,59,139,204,173,221,165,225,231,162,72,125,184,6,117,151,213,83,95,126,74,110,7,97,64,151,159,21,230,199,1],[227,65,68,145,43,216,30,116,28,12,230,128,118,158,66,188,56,157,152,167,128,87,2,210,6,224,141,234,96,66,247,31,111,75,197,212,12,211,90,42,123,210,124,44,179,85,43,13,142,243,178,97,39,24,210,150,178,161,25,180,167,112,30,213,45,73,17,117,218,225,242,162,18,20,133,176,48,41,167,129,188,53,136,3,166,57,250,138,30,21,26,22,64,36,57,6],[104,22,76,181,83,54,200,121,30,192,237,69,20,0,75,142,3,12,127,57,83,108,63,205,46,35,78,242,241,76,3,80,173,81,220,203,93,117,250,175,163,104,197,167,192,8,165,25,100,83,202,46,21,253,143,76,139,14,81,208,34,195,34,48,106,11,247,128,57,220,243,102,58,12,232,60,215,132,243,212,211,129,204,51,107,0,202,216,53,223,68,157,4,43,28,15],[121,252,72,117,212,113,84,80,129,222,10,213,63,125,46,180,137,23,76,89,150,53,232,112,206,168,79,94,224,176,114,236,213,83,63,110,71,77,166,116,15,0,123,106,165,225,140,0,37,169,232,205,48,213,210,32,64,158,155,127,231,23,99,88,57,139,116,181,141,229,52,116,194,41,191,19,157,140,179,184,20,137,108,48,204,88,22,235,44,69,5,19,179,82,86,3],[200,199,2,133,97,176,121,104,194,174,107,88,156,80,135,113,220,133,93,144,248,89,2,237,227,47,170,214,74,128,148,134,150,126,165,16,4,81,127,238,181,221,97,110,227,119,137,17,34,27,12,152,168,224,101,100,103,71,113,132,239,119,134,243,118,113,119,131,230,129,63,165,210,45,99,211,219,236,95,214,208,68,185,89,75,2,81,230,57,156,84,135,46,221,221,3],[217,136,153,21,194,60,33,179,130,83,254,248,230,14,251,33,93,159,84,141,210,196,102,108,112,86,162,204,41,192,183,89,85,94,69,154,182,230,46,67,147,244,70,36,150,47,11,10,189,215,242,135,45,5,104,245,120,76,45,59,98,75,235,113,57,2,61,31,203,41,75,94,24,160,33,212,69,181,46,111,222,11,143,19,231,176,208,179,101,45,190,56,67,66,168,4],[134,236,39,231,126,118,21,85,111,203,39,170,12,99,64,38,86,149,81,91,145,119,220,111,201,49,182,28,229,138,101,55,116,15,213,199,83,237,106,1,180,125,133,89,11,223,24,7,123,103,68,122,166,121,98,45,58,162,130,142,112,30,106,33,14,142,172,243,47,75,242,48,11,131,89,220,16,28,39,81,152,184,161,196,248,95,183,65,232,199,89,254,61,112,17,21],[186,153,109,146,166,207,2,114,155,113,54,12,112,123,134,174,208,210,53,104,60,149,208,202,40,102,167,173,212,79,158,163,111,123,174,18,251,84,138,163,74,239,58,116,127,118,252,10,190,65,16,180,95,135,96,110,34,89,22,201,150,201,159,218,153,82,108,159,80,109,254,157,96,169,187,39,90,99,122,211,26,170,93,168,38,255,167,219,245,123,29,199,242,46,248,6],[239,104,48,49,219,184,24,209,59,230,156,78,80,195,173,236,119,26,119,122,182,48,97,195,185,154,19,140,11,161,97,230,137,102,66,58,187,181,15,67,10,160,202,15,219,247,112,20,41,200,18,54,23,47,63,84,19,178,182,151,62,198,231,24,53,174,142,127,58,182,22,150,80,159,24,21,204,230,97,67,222,21,97,70,66,172,255,214,119,222,34,96,184,188,252,21],[255,62,89,196,38,194,225,112,0,175,27,59,148,38,55,59,146,200,22,161,99,104,222,57,252,222,169,64,98,136,154,103,132,108,11,135,241,102,194,134,253,97,218,74,48,97,243,14,140,231,152,156,4,36,66,196,90,100,55,81,101,242,101,181,249,85,162,186,219,54,18,72,218,204,223,168,170,153,145,96,158,186,239,173,83,150,249,36,211,144,124,48,62,108,171,8],[196,55,67,4,133,31,209,152,240,135,68,129,32,224,253,62,92,91,51,105,75,207,38,18,239,103,1,19,2,190,188,128,197,178,117,207,39,170,93,177,138,13,132,48,131,172,248,3,125,235,73,70,152,132,160,69,5,229,82,73,187,145,204,39,233,179,59,150,88,182,23,19,20,116,125,235,103,43,125,150,23,50,205,164,178,64,40,243,25,24,4,254,162,187,104,2],[146,61,201,151,255,222,39,102,194,142,0,213,208,62,34,138,197,71,229,197,234,55,26,187,117,191,125,155,193,85,105,78,250,250,240,56,148,82,93,25,240,98,176,159,190,39,254,18,60,176,194,80,16,106,140,103,196,22,102,254,35,78,107,94,236,1,202,230,217,197,189,231,234,55,48,196,69,241,166,241,171,104,10,159,176,58,63,223,3,61,67,33,85,156,209,22],[195,151,105,96,59,158,152,60,21,16,173,138,138,170,87,108,69,161,14,250,44,228,143,55,134,26,52,17,67,156,15,218,35,0,13,64,203,37,249,78,46,79,222,5,63,212,4,4,113,2,114,95,3,227,98,78,15,195,101,57,235,62,216,101,196,171,114,113,140,5,172,217,165,13,149,44,61,229,128,177,233,62,223,19,186,190,177,56,59,125,245,208,3,45,128,21],[73,104,171,60,223,236,124,58,195,42,148,49,13,81,194,147,208,31,113,96,39,182,148,73,76,149,136,31,79,167,70,54,61,110,56,202,228,248,164,241,72,216,222,237,249,221,183,23,43,168,9,148,2,246,232,141,1,124,157,246,45,126,138,149,129,156,48,17,164,64,95,41,221,202,60,50,217,42,93,142,130,210,144,142,144,176,254,125,119,42,139,179,177,88,66,11],[91,230,131,97,82,94,108,247,136,194,55,144,72,147,32,46,18,129,182,13,180,187,253,205,32,133,232,33,49,103,181,225,93,228,150,106,157,29,241,227,251,44,248,122,70,194,219,5,205,173,95,96,81,100,249,153,45,59,188,162,153,7,86,94,20,26,109,202,162,58,12,146,120,71,61,35,196,185,222,184,34,115,254,3,234,237,174,121,204,6,113,18,120,123,97,9],[61,218,227,176,110,242,202,44,192,94,210,16,98,93,88,170,233,208,87,17,235,77,194,133,47,214,214,163,78,44,131,167,8,100,187,13,255,89,40,239,98,74,155,88,137,18,120,4,45,104,177,110,220,13,196,197,199,5,196,129,253,192,166,26,58,197,90,215,188,240,162,240,151,77,119,88,181,252,182,170,43,201,144,118,29,254,245,144,215,117,111,10,18,186,89,15],[152,2,60,33,202,228,197,26,37,5,101,83,77,140,137,72,20,96,81,115,44,85,39,63,193,70,122,147,21,30,53,120,140,123,244,103,235,226,56,49,140,45,223,3,79,125,206,23,207,157,59,151,83,57,5,72,254,122,132,128,5,181,2,82,122,183,217,113,90,119,18,153,54,79,53,77,212,66,254,147,220,243,202,255,153,235,45,171,12,81,30,38,226,33,216,0],[243,13,198,101,224,9,64,133,252,188,212,72,138,106,102,26,52,157,89,86,34,213,40,55,16,149,244,73,224,35,251,250,148,163,95,170,7,42,193,154,226,6,242,11,246,117,151,22,8,71,121,231,129,118,42,168,122,122,38,102,177,177,134,57,171,227,129,238,182,216,7,1,235,56,171,138,183,131,93,248,37,87,121,108,76,72,105,24,146,161,183,223,186,215,82,22],[237,99,176,39,224,47,255,246,184,56,244,249,173,125,139,210,159,90,125,193,227,169,139,231,177,62,80,83,59,200,205,94,197,173,248,254,203,107,163,194,200,44,228,229,222,90,207,5,180,8,122,89,133,249,162,149,235,198,123,229,156,165,229,192,188,68,26,232,104,58,111,156,15,5,223,198,166,18,241,16,97,243,125,24,59,185,103,68,144,197,162,43,59,141,62,4],[166,235,14,224,34,248,22,66,162,85,223,105,109,165,29,221,56,117,41,52,82,255,206,164,63,226,227,190,34,79,153,134,20,31,72,104,54,237,60,104,72,22,206,70,47,147,27,18,35,188,33,178,78,61,61,210,227,48,108,223,141,142,213,207,221,174,110,225,177,206,82,5,160,22,35,99,104,20,157,165,27,173,78,69,166,112,175,156,69,70,49,252,26,28,249,1],[212,154,1,45,90,94,219,21,101,190,241,11,7,56,147,65,59,119,130,131,187,254,56,207,160,75,104,88,89,125,108,32,184,75,105,222,35,123,208,8,226,38,23,166,168,66,235,15,47,129,103,108,141,66,7,196,157,83,190,20,20,49,167,185,159,122,214,186,199,119,137,233,34,167,91,240,8,56,185,76,104,65,157,10,118,172,142,225,103,95,111,183,253,47,45,15],[22,51,179,245,4,80,119,148,110,241,45,230,113,78,180,60,253,5,24,198,6,213,60,66,86,120,12,45,77,236,213,222,80,250,233,9,63,65,25,22,241,115,131,170,100,210,233,8,202,209,36,250,184,69,141,181,21,245,178,220,40,187,46,215,129,254,54,50,168,138,73,3,108,157,73,120,36,183,35,94,232,254,46,22,130,0,39,231,49,163,143,26,226,61,80,1],[100,124,171,2,129,251,92,124,237,57,140,63,183,190,230,143,161,121,241,173,187,190,145,127,190,2,114,233,69,46,97,9,29,233,153,162,225,134,180,232,47,207,120,21,7,184,48,19,63,79,133,202,139,106,106,114,12,43,177,49,209,137,108,208,244,69,49,168,66,154,206,21,201,230,117,242,167,40,13,40,83,115,133,156,72,72,169,119,102,224,183,98,43,7,50,4],[56,255,38,176,143,9,123,131,5,88,192,59,217,173,13,125,205,45,105,94,115,37,184,126,15,235,81,153,113,58,42,140,138,158,86,65,234,191,154,46,209,159,224,215,121,167,174,12,217,101,197,22,79,223,103,243,60,135,3,51,97,58,253,59,59,64,104,151,38,5,191,28,57,115,93,77,124,134,85,246,14,18,226,122,184,78,141,229,242,174,179,56,38,206,227,13],[74,175,188,10,169,93,51,122,48,157,177,174,203,45,198,11,8,172,54,30,231,184,220,121,130,113,30,183,236,188,186,37,32,89,209,171,173,239,10,27,7,255,63,216,144,155,204,16,245,214,53,96,55,55,66,211,202,138,201,208,211,1,86,182,113,69,196,107,37,120,13,153,196,189,217,113,183,150,110,180,233,82,149,20,140,116,12,180,194,217,109,75,250,255,81,17],[52,87,215,32,183,251,244,249,33,73,81,110,254,140,47,162,21,100,209,44,133,114,137,206,145,180,147,203,234,230,80,39,252,139,137,8,3,227,88,135,142,167,131,197,25,46,3,20,83,134,177,70,111,192,98,97,179,9,135,175,44,32,30,191,128,84,222,210,184,118,108,115,22,238,144,51,243,114,145,159,121,90,208,235,70,40,182,250,106,19,56,23,113,93,156,9],[66,194,17,12,87,64,194,205,198,44,66,252,155,197,106,224,178,196,137,248,20,101,77,24,70,7,78,253,45,109,110,110,49,70,74,149,51,199,204,149,118,59,95,190,162,137,163,14,93,6,236,61,242,128,85,70,54,237,32,188,98,73,52,248,50,3,28,223,95,33,178,130,97,48,84,246,237,96,185,113,42,96,44,148,226,18,142,243,19,41,36,181,86,2,171,24],[37,243,49,12,254,111,249,8,76,105,92,0,53,120,29,16,6,197,108,72,194,0,188,148,182,231,111,89,185,197,137,193,17,123,1,156,193,77,98,30,149,181,40,140,40,216,221,0,12,223,7,227,111,224,138,86,207,222,243,234,112,129,118,195,247,201,37,243,120,99,144,182,200,67,246,86,76,141,131,17,38,173,186,243,99,167,16,224,116,43,51,130,255,171,164,10],[231,18,108,60,32,213,254,65,90,72,153,50,78,65,184,10,95,34,221,205,220,68,150,211,135,130,213,122,46,105,197,132,53,73,67,179,51,174,16,36,188,222,179,45,22,239,68,7,117,50,213,210,62,107,221,33,143,23,160,138,8,227,11,192,233,45,161,212,38,118,143,199,217,156,145,112,209,251,231,30,77,255,227,42,215,246,145,97,145,238,237,51,177,130,110,20],[214,223,37,109,140,64,243,244,18,103,252,3,172,247,70,194,26,102,121,64,84,180,165,131,30,147,196,242,6,254,16,214,120,213,114,144,199,108,102,141,234,197,83,44,201,232,137,23,218,3,120,63,133,108,189,210,0,96,220,111,6,100,153,32,62,156,149,23,0,201,220,102,214,178,249,28,33,93,246,204,51,17,101,110,171,34,76,116,17,219,17,44,130,23,216,10],[34,72,112,119,153,187,237,62,181,59,137,30,222,132,120,83,180,21,37,60,11,76,109,112,70,215,3,28,134,167,10,220,130,121,42,61,94,26,162,66,152,26,73,97,63,45,231,23,243,252,87,219,128,201,209,143,47,15,179,143,116,100,168,111,212,223,14,247,226,110,63,130,69,254,184,206,15,2,190,47,102,57,116,170,244,131,142,108,195,240,75,141,128,220,189,3],[217,47,188,162,105,3,110,170,241,84,58,18,54,74,207,230,153,5,2,77,87,67,73,52,165,141,83,18,82,148,153,85,225,30,134,8,165,22,166,142,138,180,152,62,175,215,158,0,17,39,219,182,148,153,234,114,50,239,138,97,3,48,145,138,31,125,181,220,72,47,79,104,96,212,159,171,8,161,119,3,212,12,86,79,229,27,72,162,219,107,90,201,216,237,34,1],[33,125,88,78,240,248,202,11,3,205,197,91,2,107,166,53,147,118,23,231,253,62,41,128,192,191,167,2,172,60,16,209,118,113,206,26,146,214,1,159,100,190,100,252,248,17,137,19,10,219,91,49,219,132,4,201,38,59,133,179,41,193,1,182,42,238,183,143,175,245,16,155,141,194,240,65,54,9,197,241,232,24,54,108,7,161,126,255,193,232,8,130,140,86,78,24],[115,25,48,63,143,185,179,28,234,36,235,60,246,162,53,166,165,25,103,56,167,45,176,38,148,109,251,64,127,123,95,20,187,103,32,102,157,104,240,68,103,151,244,84,180,20,130,23,66,8,160,144,71,112,133,251,165,57,74,108,98,52,153,85,158,253,70,205,230,79,104,95,191,27,13,197,190,81,191,18,142,197,221,198,83,243,228,22,32,75,85,231,137,48,125,18],[246,13,241,240,82,202,180,244,2,70,33,148,78,22,95,106,11,99,77,64,83,132,187,116,160,181,180,97,93,135,31,61,59,244,112,218,204,105,200,247,112,64,58,127,95,234,114,11,164,230,183,80,59,197,34,127,59,255,108,81,229,67,47,42,158,69,248,137,157,128,22,12,254,234,192,198,125,231,63,213,207,62,109,66,65,61,195,125,40,199,205,69,198,145,53,25],[57,209,183,228,41,171,74,4,165,211,31,14,103,104,33,48,35,193,133,72,87,136,158,124,88,92,220,239,33,130,243,168,237,230,79,151,189,101,106,12,85,25,81,130,206,165,31,23,27,86,14,52,127,203,107,148,81,126,135,253,208,176,98,91,51,54,8,247,208,103,153,169,230,188,93,196,11,128,124,226,139,108,14,12,106,81,4,190,191,112,99,12,178,185,95,11],[81,213,204,126,181,91,119,60,55,56,61,186,209,23,4,40,239,243,248,185,184,17,186,217,218,209,201,66,127,238,219,255,223,115,136,20,31,89,27,20,129,148,50,44,205,154,249,6,96,48,45,165,193,127,40,37,227,153,6,195,71,171,90,219,65,140,245,52,116,0,201,174,89,0,69,156,241,83,78,4,119,14,103,252,226,119,40,1,162,55,211,226,113,185,208,2],[147,134,221,153,138,157,179,110,120,59,184,133,53,10,242,252,36,1,184,230,119,53,235,254,209,49,37,17,105,17,223,41,23,180,133,55,102,110,137,180,184,118,22,161,44,122,236,6,181,19,61,182,251,105,158,25,159,182,190,55,120,2,54,36,198,78,146,236,174,92,54,43,80,20,149,182,172,29,15,162,247,216,61,196,10,220,209,223,248,43,136,63,99,166,164,1],[151,224,162,10,179,75,53,131,168,203,114,195,252,97,44,255,226,169,121,243,33,107,67,121,166,248,87,162,163,111,109,126,102,155,36,61,189,63,236,141,25,65,105,133,202,68,11,23,13,129,232,22,145,49,123,224,200,67,44,20,72,220,250,229,115,153,172,31,188,119,24,16,197,105,127,27,11,171,189,37,3,14,244,18,165,137,18,75,205,187,229,180,82,157,188,15],[161,226,179,196,181,33,163,57,102,137,21,220,1,210,12,104,2,111,209,111,40,203,65,152,172,103,143,27,148,148,216,118,14,84,110,222,117,188,167,30,42,109,240,43,229,177,253,16,178,106,224,250,169,53,225,218,96,207,110,186,253,213,230,98,141,207,177,1,115,255,32,234,216,152,2,242,3,121,231,217,240,68,147,43,33,248,230,162,183,202,52,10,168,93,34,11],[139,135,153,123,233,156,242,176,185,22,19,130,152,93,223,9,63,86,247,3,22,67,98,97,80,18,164,56,5,218,17,49,94,88,167,177,71,142,25,124,61,118,15,216,50,8,61,14,101,172,140,131,90,177,117,252,94,68,184,81,182,69,165,92,88,57,230,197,106,90,153,230,217,73,121,46,105,223,126,174,159,188,250,82,137,58,140,90,185,96,23,126,123,185,87,24],[233,157,46,10,38,40,228,222,169,219,142,84,109,178,8,62,93,203,83,173,164,132,40,208,71,180,246,81,105,145,81,183,241,44,7,119,195,67,90,112,214,234,201,106,31,234,232,25,210,121,178,203,174,187,231,181,243,184,64,220,216,213,53,209,135,150,156,129,174,89,65,84,69,83,190,100,179,204,206,177,28,11,5,176,17,222,121,253,68,234,143,211,189,160,246,9],[34,52,222,100,230,132,227,17,240,21,50,222,108,254,245,51,9,12,4,124,83,13,167,76,165,147,132,203,133,39,55,77,163,162,48,250,253,34,123,231,96,226,180,77,116,244,133,3,177,109,195,192,6,205,152,12,37,144,61,177,45,134,219,134,178,19,194,114,3,100,200,146,56,182,149,29,171,211,18,34,85,63,108,15,100,10,109,203,81,232,26,166,156,138,219,10],[90,49,125,65,42,86,106,169,254,140,111,179,235,190,215,138,246,178,109,184,192,32,18,91,13,56,153,158,232,90,125,250,114,100,134,193,115,184,198,170,209,240,127,46,211,117,134,7,161,101,147,207,149,248,122,88,136,62,162,191,86,123,161,244,203,97,131,132,241,247,212,198,212,15,39,139,127,251,77,17,83,97,105,139,237,53,148,155,86,117,29,248,247,203,131,15],[191,195,44,201,12,20,31,26,178,135,141,43,102,46,35,196,108,195,64,184,208,208,241,230,166,188,201,67,232,173,26,66,31,175,40,222,210,154,1,59,55,110,95,233,183,178,232,24,247,130,164,246,93,53,255,244,240,249,162,31,7,250,243,201,245,137,36,16,59,99,150,210,34,113,55,76,43,232,167,119,125,147,56,8,118,20,189,47,204,75,23,160,198,78,88,4],[134,234,53,0,115,89,196,182,91,184,58,190,194,120,79,164,220,107,51,138,161,128,93,129,48,139,116,232,52,237,242,96,18,125,5,35,131,240,86,108,55,32,230,184,67,26,135,2,204,117,137,194,72,227,74,82,120,60,41,195,67,189,95,28,73,212,144,41,129,117,20,248,221,31,173,13,148,11,38,139,150,24,222,253,160,130,28,26,145,193,8,183,237,211,32,4],[142,125,164,39,14,40,16,156,190,100,251,71,11,90,22,90,130,176,1,23,44,160,156,218,122,98,236,75,247,218,126,114,219,74,213,162,34,234,144,16,154,98,180,62,49,84,145,20,30,218,47,108,43,7,94,32,233,189,91,16,21,63,88,112,159,249,163,224,27,139,70,88,186,236,154,20,64,48,202,58,40,28,30,255,248,29,18,120,75,207,158,179,19,101,32,6],[128,143,22,208,173,204,195,227,105,51,85,24,72,147,114,226,35,91,234,31,8,35,17,160,12,210,87,231,225,70,223,0,254,150,114,86,103,134,16,50,3,161,122,146,2,145,183,1,152,128,120,224,241,198,226,4,179,86,86,254,143,117,159,9,51,27,0,218,227,105,225,13,209,151,190,34,209,249,186,158,88,231,19,37,29,250,215,231,40,122,49,10,172,111,84,16],[249,118,168,165,51,198,24,32,49,108,150,50,192,189,62,99,24,170,144,83,54,10,118,254,173,176,92,88,217,33,174,193,147,186,217,8,112,182,252,75,194,181,59,47,161,228,226,14,27,66,124,175,164,71,80,85,185,154,73,78,165,137,75,119,118,228,1,219,152,166,216,218,146,21,19,11,137,115,112,156,150,16,182,55,222,165,179,253,167,114,92,150,44,69,96,3],[193,185,97,166,158,39,13,32,174,249,130,125,56,107,66,45,129,114,174,151,99,212,218,205,34,28,92,183,165,14,34,245,17,49,139,13,238,160,103,115,234,118,180,98,34,149,100,18,247,58,79,6,217,89,41,118,247,18,167,133,74,37,223,75,145,198,60,72,11,240,237,170,37,237,154,126,177,80,25,123,9,21,204,37,120,183,168,119,48,13,124,213,2,16,196,25],[177,190,100,128,229,120,243,187,47,89,58,32,145,203,108,220,14,77,39,232,60,30,15,148,66,239,169,98,96,41,17,35,247,106,26,149,126,28,203,131,54,234,239,22,50,142,42,2,89,147,115,187,188,215,35,63,72,227,243,144,187,171,38,199,197,59,182,86,126,215,172,64,29,99,209,14,205,11,231,200,203,167,122,204,79,76,170,34,124,100,241,176,110,101,40,19],[234,154,240,101,60,94,144,134,247,34,242,49,130,124,241,254,127,135,38,80,203,251,229,71,56,137,11,237,229,114,107,192,12,101,100,177,72,230,128,48,85,93,178,135,176,51,68,16,119,246,121,251,175,180,251,0,172,11,29,198,116,152,11,169,14,241,82,24,251,71,103,134,83,204,207,114,184,33,108,43,57,43,76,166,83,8,119,5,237,138,228,164,198,87,21,23],[17,154,29,238,230,143,152,155,151,242,27,69,118,35,181,106,71,73,3,90,46,106,2,172,107,62,86,244,10,56,32,82,184,200,143,86,97,202,41,100,5,190,147,166,148,41,145,2,158,106,132,133,42,129,184,27,115,131,90,198,11,196,254,18,240,93,205,92,227,76,123,110,0,148,4,228,199,81,214,27,204,134,22,1,67,147,137,142,176,161,225,213,9,153,21,14],[19,3,83,108,180,38,97,147,200,156,102,232,243,225,92,25,10,213,200,166,153,206,232,32,120,81,124,172,40,216,115,227,15,166,26,4,123,204,159,123,135,212,49,120,36,124,235,19,86,51,98,209,62,136,88,104,233,33,131,22,46,50,12,27,244,183,60,128,149,110,175,181,110,203,220,211,248,156,212,101,234,51,185,109,61,73,175,177,245,14,224,192,240,242,150,20],[250,170,195,230,155,146,61,48,199,155,36,234,218,164,18,74,189,26,49,238,156,239,31,63,37,23,71,175,144,155,244,231,203,147,212,235,159,126,246,21,19,79,102,243,246,178,158,8,129,146,13,206,26,222,143,230,62,159,76,182,157,8,172,252,27,37,25,141,224,243,109,237,181,157,37,231,152,153,10,49,208,98,236,187,125,240,229,124,72,38,162,222,70,48,234,14],[76,221,169,49,6,88,220,238,138,104,215,204,31,223,69,139,159,158,231,234,58,87,225,137,96,243,170,19,38,86,91,125,110,49,3,157,179,164,195,237,192,186,10,81,238,127,43,8,201,45,156,186,171,70,183,37,165,214,19,155,77,229,124,237,144,89,64,90,254,182,18,114,63,161,107,165,59,241,40,14,74,36,168,78,8,214,199,221,193,66,143,119,235,52,125,15],[58,208,203,152,126,44,47,242,188,29,206,129,44,121,182,90,193,106,165,40,239,20,74,251,7,121,212,40,138,68,236,241,133,129,13,67,210,231,34,4,1,97,103,103,100,142,93,2,160,205,107,3,129,184,54,221,123,143,1,249,154,196,103,232,49,7,168,227,90,23,41,93,5,233,86,6,161,18,25,138,219,137,216,132,22,90,20,215,224,218,86,188,191,64,214,17],[26,36,251,221,32,230,249,125,213,233,210,88,231,252,28,74,183,215,130,8,195,88,19,91,32,233,129,79,35,101,45,164,178,49,68,150,46,56,41,33,99,211,78,179,140,231,64,23,116,7,194,154,27,199,249,175,79,166,187,28,253,175,73,57,175,30,53,140,70,159,116,102,242,246,73,155,96,129,142,15,8,202,138,103,96,194,218,71,143,76,235,174,201,182,15,17],[56,124,133,129,251,7,230,195,198,219,203,188,68,107,36,89,237,118,124,85,60,187,154,199,177,172,21,210,143,134,197,148,210,2,199,201,248,140,203,204,14,34,202,239,59,22,133,13,49,12,5,65,3,19,49,123,234,65,3,136,218,96,30,245,185,171,65,196,197,8,13,95,7,161,239,223,195,187,175,223,238,121,117,225,125,204,156,31,187,129,135,15,180,89,34,12],[96,253,74,104,35,76,190,217,24,217,72,71,169,116,106,157,73,59,189,226,200,31,1,170,151,216,190,176,96,151,110,94,116,25,108,94,33,84,1,104,209,43,75,114,81,18,51,8,195,211,214,199,74,225,184,77,13,12,122,240,151,6,143,156,41,42,13,207,224,86,19,91,73,242,255,14,218,230,83,12,155,183,138,114,19,17,38,41,84,131,213,228,180,38,115,18],[3,130,106,151,197,254,55,178,61,132,128,119,241,65,72,199,17,212,116,156,93,96,57,176,234,157,15,201,79,74,194,107,157,180,129,252,242,25,134,208,174,211,66,121,60,50,216,24,78,143,42,254,110,0,154,209,213,102,45,232,171,23,253,37,124,201,39,165,122,156,207,18,161,21,60,112,102,99,246,189,16,105,81,195,117,252,108,56,194,185,197,243,248,61,67,7],[10,74,5,23,146,237,161,120,150,162,42,105,106,181,163,153,99,154,229,204,61,252,224,153,46,171,205,38,156,24,184,163,9,192,118,237,54,200,150,124,231,144,201,198,185,237,127,1,162,123,91,26,90,217,28,138,119,13,192,102,171,254,144,165,243,101,3,34,194,213,118,83,111,46,0,208,149,2,130,9,54,173,84,119,127,185,230,249,112,197,157,63,89,53,189,21],[141,243,220,73,151,98,119,157,129,47,217,119,112,109,113,235,165,191,178,165,208,185,145,91,17,179,7,20,158,60,25,128,84,240,174,63,234,250,8,158,110,106,185,140,186,114,74,3,244,215,62,103,140,24,103,145,63,198,28,195,107,33,212,62,83,181,96,147,223,204,95,231,134,11,193,105,133,126,179,2,155,134,58,119,98,68,140,111,237,51,140,160,99,3,63,11],[206,212,92,21,10,126,243,161,166,127,142,150,197,187,151,164,143,94,150,88,190,32,181,17,162,98,184,242,228,75,164,21,104,177,199,128,68,54,110,177,235,113,16,198,188,110,56,25,3,93,42,49,249,22,250,181,14,182,29,127,189,140,163,117,118,68,132,66,125,173,135,25,231,138,82,12,181,122,169,60,80,144,190,153,50,146,47,242,163,129,47,174,102,59,206,0],[117,75,247,178,107,92,25,242,154,143,8,107,29,96,48,27,145,29,101,93,67,216,27,26,77,210,173,247,13,251,193,64,140,51,45,226,39,126,186,119,2,220,212,81,75,5,7,1,111,5,47,197,152,190,204,132,254,174,97,232,27,48,253,129,109,29,100,82,6,4,56,219,145,84,180,42,242,120,37,0,181,71,74,64,28,111,141,151,219,16,151,214,159,131,133,3],[91,134,102,175,92,218,59,43,127,147,125,102,99,97,93,191,208,232,29,26,58,69,145,82,40,202,147,105,206,210,30,94,99,126,186,139,250,128,122,220,64,54,73,170,231,18,200,13,29,106,107,133,203,209,248,238,187,144,184,41,113,62,184,70,97,54,229,104,74,28,122,190,169,62,224,61,206,11,128,222,182,182,8,169,21,24,34,30,195,36,142,80,51,99,143,9],[12,35,28,147,202,6,244,105,240,55,154,203,30,197,132,90,82,145,20,161,22,136,168,99,133,183,119,58,197,218,106,244,103,142,221,145,37,55,150,62,246,102,59,194,229,210,152,23,117,65,53,104,116,90,92,139,33,127,86,228,173,236,10,61,223,249,19,245,38,129,244,191,186,215,187,204,94,176,158,48,53,101,218,82,231,26,54,33,201,35,72,227,71,22,251,13],[229,15,9,134,212,222,204,127,140,27,167,249,43,197,176,50,65,48,194,43,92,251,156,237,45,246,237,101,125,224,228,64,27,196,105,75,93,76,232,122,138,10,229,46,33,231,153,14,242,193,84,149,248,12,227,189,95,73,104,63,148,189,127,125,253,119,35,86,98,120,43,20,80,114,6,130,182,100,31,141,85,158,78,7,126,74,103,212,1,31,183,158,120,25,199,15],[158,165,30,159,39,74,110,215,11,248,189,56,194,218,73,230,131,231,156,39,116,203,24,74,71,71,130,202,164,153,149,68,60,22,15,140,126,6,174,247,104,114,207,199,194,145,211,1,68,10,111,99,195,54,124,161,217,213,178,180,92,249,53,101,15,155,174,165,62,235,87,109,107,155,132,98,88,137,82,48,55,167,156,75,58,73,179,8,56,159,240,159,48,50,11,10],[108,94,119,152,10,92,217,222,178,214,64,227,17,27,157,76,121,14,233,7,147,91,7,14,0,146,173,35,175,117,162,173,50,51,250,202,24,132,251,248,173,206,138,179,72,148,248,2,80,95,139,51,44,72,36,233,170,186,173,11,125,186,66,157,209,245,6,240,180,165,233,132,89,222,159,191,56,233,189,135,163,41,14,58,17,91,237,121,68,204,99,234,182,221,106,3],[114,183,238,41,201,94,87,128,155,84,1,79,205,93,242,129,92,92,84,117,197,209,54,154,142,104,23,109,101,139,251,44,245,113,52,105,28,135,196,164,210,102,43,254,237,142,244,6,157,197,214,104,49,186,245,253,2,154,131,69,248,53,179,97,110,145,28,130,64,128,78,205,110,239,101,141,57,53,13,177,247,174,96,197,25,22,41,96,237,145,219,239,137,15,189,0],[189,76,139,30,216,117,7,6,190,12,10,220,137,61,146,107,126,78,185,65,79,141,19,46,95,113,41,101,95,150,133,32,189,142,24,142,102,156,124,221,151,105,102,247,138,38,18,23,175,196,94,242,182,131,100,45,247,159,126,100,184,232,231,179,135,40,181,47,130,97,192,189,192,107,38,172,242,61,130,28,81,114,124,24,166,130,151,229,54,50,133,175,233,252,138,24],[61,42,214,98,187,213,109,7,13,235,127,113,99,220,149,5,139,148,45,37,15,166,68,168,186,180,46,179,146,245,139,44,102,38,74,116,226,184,53,82,138,82,148,89,124,11,8,16,144,20,249,39,94,107,174,157,118,252,169,24,183,249,200,49,14,39,155,214,53,126,253,149,62,16,177,179,55,101,22,87,223,210,50,154,240,30,5,186,233,85,64,66,248,8,75,6],[88,34,195,153,93,96,78,3,179,41,113,89,24,98,112,159,210,157,22,69,180,12,228,66,224,104,50,21,66,155,191,128,250,109,231,44,160,89,255,22,117,81,57,136,14,216,51,17,142,122,6,17,233,85,104,170,126,202,196,200,16,6,170,250,153,243,207,45,59,255,4,85,56,171,96,36,176,204,36,113,7,180,233,62,251,232,75,186,182,203,199,214,10,102,18,1],[181,90,105,132,248,182,160,35,1,16,115,173,104,80,248,146,97,20,194,233,151,30,173,224,16,165,226,245,73,58,206,187,252,251,124,154,192,75,140,77,128,45,158,49,209,132,198,4,187,57,192,89,233,52,227,189,181,130,244,148,213,240,159,197,3,185,165,127,17,142,159,139,239,210,108,219,114,240,133,244,254,16,81,129,117,160,187,177,168,60,186,163,253,91,192,25],[189,198,197,249,46,193,177,202,240,247,8,25,101,106,3,140,244,29,27,167,11,181,205,210,223,41,186,87,167,125,115,13,125,192,142,210,130,48,23,253,6,64,162,244,231,88,220,8,76,219,31,9,165,210,215,138,110,75,129,240,192,211,190,235,209,114,201,104,141,185,100,147,105,133,122,212,97,28,17,163,74,58,10,19,134,123,85,163,110,124,115,249,47,80,134,17],[86,111,38,139,152,146,207,222,218,119,146,70,1,196,225,198,85,140,226,44,210,0,201,230,147,94,235,65,203,108,16,155,209,86,196,252,81,119,32,252,181,140,57,49,237,52,104,4,158,208,62,190,7,244,128,243,199,133,177,232,26,223,86,76,108,186,69,94,226,181,42,235,151,123,229,145,0,198,80,110,5,23,254,192,155,172,91,81,82,171,28,109,186,127,215,4],[140,165,186,116,16,98,53,157,245,217,199,142,161,115,114,221,194,67,98,163,116,163,181,125,131,111,82,85,196,135,232,238,196,41,91,70,108,248,56,177,95,188,175,247,25,75,140,12,104,82,167,213,149,127,11,130,211,38,180,244,133,242,157,216,147,200,162,106,33,76,122,255,48,54,144,90,176,149,170,57,99,47,69,149,102,27,178,119,121,243,32,234,174,223,30,7],[248,206,177,33,228,220,89,185,96,93,96,148,23,202,174,55,90,75,195,211,144,242,7,128,35,218,211,232,4,79,124,221,80,232,14,90,55,249,22,221,223,190,252,251,204,129,185,9,217,74,236,251,209,227,189,120,187,47,43,10,235,126,51,100,238,139,24,128,60,39,196,100,17,178,110,86,152,234,22,228,145,40,168,241,124,133,93,91,21,171,250,197,188,237,252,4],[228,50,29,106,77,15,80,222,29,173,115,20,152,26,88,166,148,248,59,156,245,254,87,124,186,36,41,129,21,52,123,141,189,140,56,74,6,33,75,172,128,149,224,100,58,63,86,16,131,42,9,198,160,56,155,193,113,147,178,179,218,68,103,58,55,49,84,76,174,102,111,198,6,7,228,28,65,254,250,120,212,195,143,147,216,230,92,160,41,6,201,116,198,195,173,25],[59,23,124,22,119,241,178,116,123,33,88,30,0,163,249,200,205,205,95,185,47,87,46,132,148,253,158,48,2,86,41,100,184,105,159,99,81,242,154,127,42,199,73,121,248,237,107,2,47,25,235,136,236,60,238,190,97,233,7,5,36,208,42,79,162,227,12,189,83,195,54,87,155,235,190,188,186,117,210,176,120,165,183,227,210,173,179,101,174,3,16,56,118,63,126,12],[126,159,110,176,120,250,226,236,248,136,101,178,34,99,103,76,70,167,69,239,145,96,102,187,146,45,86,115,196,104,134,245,115,79,210,198,157,202,4,227,208,113,174,141,149,87,240,7,83,54,87,94,113,227,131,241,24,103,4,51,153,85,48,2,98,204,178,155,62,21,226,203,77,70,120,229,215,67,81,111,155,78,187,184,77,55,75,117,190,150,253,179,30,219,166,19],[118,140,141,197,52,93,221,211,148,60,132,33,144,12,237,148,142,172,213,233,234,164,51,224,217,38,152,160,95,16,50,181,184,53,225,135,179,94,126,241,180,171,125,98,48,188,150,11,50,24,143,237,237,202,252,32,230,82,206,200,240,69,234,15,218,177,13,14,159,153,232,13,231,211,215,14,13,165,57,140,108,40,110,56,60,166,116,230,175,189,234,33,109,96,107,4],[77,29,116,228,28,109,82,203,184,211,76,153,196,238,115,156,66,69,103,171,129,4,87,228,192,61,150,115,55,228,164,43,197,151,236,143,19,197,7,135,130,123,168,242,144,236,79,17,249,198,89,94,68,171,20,69,10,168,53,202,11,21,57,0,205,138,18,228,164,153,188,163,44,19,29,123,151,240,134,128,174,28,223,165,50,176,253,47,143,250,167,234,198,76,155,6],[13,8,88,179,229,249,85,48,79,241,22,86,247,29,49,135,1,57,214,74,200,247,79,215,48,35,132,153,179,87,74,19,147,174,55,155,66,247,218,244,17,112,4,235,13,72,252,1,64,184,125,126,160,101,177,244,96,98,69,135,181,65,76,35,109,39,255,90,6,234,179,223,250,178,233,248,218,97,171,216,136,102,202,88,181,81,107,33,216,8,38,104,58,95,83,16],[99,200,240,186,253,114,223,66,193,90,95,89,150,254,187,181,126,178,50,134,24,162,105,220,247,176,228,41,251,197,236,191,21,137,84,48,162,70,204,77,50,31,174,238,47,241,226,23,40,85,166,6,92,223,162,17,242,221,224,23,220,155,92,28,117,187,27,53,103,19,120,218,34,209,129,243,152,0,171,166,114,254,137,39,88,235,96,175,32,193,41,246,161,213,216,6],[233,55,84,159,144,201,98,244,144,34,254,40,218,162,7,116,104,114,102,190,89,220,104,244,121,56,229,156,162,7,118,52,249,45,242,238,94,21,36,230,204,7,120,162,195,240,222,8,34,242,231,204,100,229,115,163,97,220,27,148,238,229,217,128,249,219,170,78,166,30,249,18,126,20,175,179,234,223,226,192,89,57,10,109,119,100,83,44,172,198,135,254,131,107,10,17],[145,235,54,121,238,131,112,247,160,123,231,184,155,186,137,33,233,184,244,241,169,31,39,194,232,114,96,20,135,180,89,204,182,79,249,202,35,48,1,79,64,251,41,64,128,29,238,11,112,111,140,231,204,66,130,166,211,169,51,118,83,85,215,135,29,37,191,252,9,1,58,209,70,110,80,198,15,110,57,20,172,177,239,188,218,99,57,137,114,58,178,153,218,101,186,3],[110,191,196,50,95,28,74,90,132,99,211,167,102,102,160,15,106,61,184,117,218,245,1,101,20,141,20,132,212,162,38,135,38,145,196,86,179,236,4,40,127,228,141,147,111,65,144,15,54,172,196,66,213,159,29,143,97,208,43,130,185,32,14,13,249,247,202,103,199,143,107,146,203,49,197,223,118,132,224,175,98,62,54,202,227,63,127,22,71,6,223,205,176,75,36,1],[118,86,172,95,252,220,234,216,42,214,96,36,159,236,10,241,9,144,83,150,8,246,172,231,246,126,174,209,254,209,114,66,83,104,54,173,243,68,46,35,0,217,239,207,247,1,174,19,166,128,6,26,157,132,143,110,209,243,128,200,255,81,190,145,173,182,155,21,54,248,188,42,30,139,228,140,123,35,60,87,32,199,84,12,224,164,114,74,190,46,111,171,100,94,232,24],[42,213,114,221,194,21,94,57,117,62,199,232,25,194,190,59,174,172,189,29,221,80,113,41,100,95,173,28,166,174,70,23,69,232,21,8,108,56,44,6,195,58,250,247,35,147,165,21,61,180,107,29,210,71,125,173,221,234,142,138,98,158,63,241,207,143,235,4,47,129,246,105,77,154,118,158,80,117,228,86,177,126,55,214,53,173,165,140,28,233,143,29,247,73,73,5],[140,13,142,72,214,138,147,141,77,28,110,104,10,158,53,64,158,111,1,10,198,118,134,192,201,124,102,163,95,191,60,196,8,133,3,226,65,62,150,82,164,73,164,128,154,174,167,10,253,128,41,58,13,95,18,248,191,237,132,104,168,110,71,118,169,254,95,58,195,149,214,37,103,13,163,83,139,184,103,25,36,184,60,182,140,108,89,157,24,60,37,14,180,134,40,5],[201,30,188,189,147,140,176,142,67,130,1,206,144,182,9,86,171,122,59,80,159,159,101,18,74,114,129,243,197,211,162,90,105,110,141,238,72,34,252,129,155,232,206,251,109,40,83,5,66,211,86,239,173,235,238,190,102,127,70,63,224,125,169,51,74,107,74,42,186,53,173,54,55,221,182,33,81,8,90,147,51,177,177,134,31,91,207,195,5,150,166,41,72,72,48,8],[175,159,125,78,69,206,248,243,225,160,67,26,248,67,163,222,29,113,106,36,222,47,104,106,231,77,59,239,138,60,17,129,223,89,81,103,10,60,172,155,64,226,219,178,194,25,91,11,140,147,27,103,0,110,163,215,164,180,116,43,129,234,89,99,118,222,167,28,62,17,188,71,91,2,99,182,49,17,95,23,162,181,144,74,89,188,189,228,234,210,166,108,156,56,118,15],[229,134,163,252,147,227,111,174,20,134,169,112,68,2,112,133,121,115,58,207,215,219,60,255,126,177,157,240,153,157,226,35,221,31,95,231,90,154,142,73,216,166,222,189,134,216,136,12,107,160,41,134,241,0,57,94,111,159,144,110,1,217,60,106,63,133,175,111,15,229,80,46,35,160,215,30,159,123,155,59,29,4,51,231,163,146,227,227,115,55,170,227,186,12,81,22],[179,10,247,115,98,160,25,236,177,82,246,19,160,227,177,140,239,150,11,60,129,50,49,19,5,234,190,235,239,173,160,5,150,120,235,144,147,240,251,229,164,59,39,117,62,165,110,1,36,158,244,68,95,235,103,192,182,103,36,126,151,55,59,88,103,15,23,193,91,148,130,145,216,1,171,219,131,6,203,36,174,253,90,240,42,140,102,110,162,141,97,138,239,234,54,9],[130,214,113,15,116,115,28,164,81,74,87,13,147,253,104,167,44,171,120,79,223,251,236,94,196,152,40,234,154,18,110,11,174,235,110,238,42,66,58,252,202,24,23,87,116,63,72,25,140,210,185,210,106,196,238,148,113,17,7,246,164,51,153,75,197,227,211,218,75,75,122,95,209,104,113,69,108,218,255,163,229,213,161,208,40,221,156,124,200,35,25,222,77,143,255,6],[223,164,130,110,245,55,241,225,38,98,24,174,54,16,112,82,151,42,197,154,173,214,147,187,138,195,202,11,5,17,149,255,220,127,11,120,215,153,37,103,86,154,21,153,75,155,145,20,56,186,76,186,188,178,155,102,43,133,117,16,224,92,144,3,198,142,92,252,238,99,52,160,5,241,187,73,103,126,100,119,79,11,175,93,98,246,103,243,205,112,220,246,199,4,86,20],[148,0,203,138,127,37,105,226,76,171,30,93,137,230,226,1,255,187,220,201,143,224,46,11,133,197,141,227,192,30,74,228,105,74,185,67,190,171,85,33,187,216,217,190,206,100,215,9,64,227,253,192,188,146,53,205,183,227,55,3,220,46,213,184,184,210,21,155,159,41,160,112,222,139,90,148,62,165,70,36,240,168,179,107,78,58,120,44,125,170,243,216,117,91,149,7],[201,204,129,30,110,12,11,124,102,203,139,153,157,11,254,199,35,111,4,13,160,161,250,82,11,174,155,193,46,157,138,29,2,4,240,97,194,51,144,90,47,20,102,157,180,162,89,0,225,74,75,102,46,210,202,232,5,180,55,2,171,206,81,165,167,116,20,176,161,69,225,104,77,154,235,222,59,192,210,22,123,120,227,60,221,185,94,91,104,254,73,187,57,233,19,3],[208,96,33,15,193,211,174,20,73,165,162,98,168,65,19,110,127,241,136,55,39,95,38,35,122,64,210,182,119,191,223,176,101,31,100,32,98,208,2,48,62,159,63,27,48,207,250,4,43,229,192,151,151,179,205,240,0,9,166,24,154,76,194,85,50,65,233,219,230,184,149,133,23,107,210,130,178,175,5,10,78,239,252,82,102,180,219,19,54,226,4,196,181,55,103,14],[233,136,36,29,71,166,86,249,119,230,2,233,242,161,68,153,122,116,115,97,220,250,171,36,240,145,96,210,203,182,151,118,233,45,95,93,23,199,189,84,24,240,28,228,103,157,185,0,37,27,126,58,19,96,42,244,31,202,222,191,149,107,182,163,226,205,215,35,188,26,155,66,167,113,252,229,237,11,242,186,255,215,199,1,64,86,215,63,52,74,249,187,139,195,77,5],[43,152,17,182,242,204,128,124,67,1,212,14,131,37,28,204,155,201,168,115,141,161,22,190,109,228,18,66,115,58,133,114,211,10,78,7,102,149,255,6,169,159,80,189,165,97,237,5,50,167,105,68,162,42,132,122,173,13,182,46,2,140,239,143,121,7,139,103,24,217,181,217,120,126,81,172,212,16,200,111,46,205,189,152,131,36,245,101,225,143,134,218,138,169,228,5],[127,76,225,4,47,188,11,83,249,106,7,36,184,163,205,163,56,97,156,236,45,80,161,125,51,11,82,173,1,5,97,228,199,165,159,20,180,87,98,214,68,131,108,212,157,63,102,1,55,197,46,134,26,78,143,170,69,68,62,212,180,203,250,217,61,79,166,13,242,177,251,42,173,72,159,115,39,247,34,66,185,54,218,252,77,83,175,25,95,148,246,49,175,158,101,21],[189,188,235,114,12,55,186,100,139,24,8,249,236,175,206,26,57,143,234,124,84,160,194,56,68,195,177,133,145,79,243,94,15,126,150,180,46,128,203,226,219,188,233,111,230,225,188,16,248,82,198,193,36,42,144,49,72,46,148,90,12,179,5,202,215,189,190,222,93,122,143,74,46,204,92,134,243,75,226,168,22,113,133,82,225,99,125,107,222,47,122,242,106,142,166,17],[157,185,133,185,1,211,140,57,35,238,215,75,98,176,27,30,212,99,15,179,2,222,169,173,4,156,178,206,65,141,202,45,63,127,141,116,222,161,190,39,219,166,73,195,151,45,90,7,148,176,174,84,23,238,90,213,187,39,17,197,5,63,147,129,131,182,53,65,45,239,141,50,191,61,9,183,102,16,26,197,147,230,126,118,142,205,62,158,38,247,234,226,162,20,66,4],[107,54,93,134,34,50,22,125,114,26,137,227,123,8,254,103,47,235,185,19,28,237,206,42,200,174,61,130,178,218,156,9,214,83,18,71,226,65,63,199,124,246,7,39,113,188,124,7,31,54,165,36,177,169,35,238,67,247,154,23,189,172,185,83,127,107,175,60,117,147,102,13,134,129,79,25,141,244,239,117,96,24,99,176,13,80,98,60,222,56,105,60,100,156,197,17],[115,23,14,129,169,30,200,157,138,223,122,50,162,255,102,224,192,150,155,207,198,191,79,233,13,182,196,215,107,119,176,14,36,129,229,196,126,164,173,93,5,34,38,109,20,121,158,9,94,195,233,114,33,188,207,168,68,127,124,138,30,101,64,70,30,208,0,171,149,36,6,206,192,247,151,174,45,5,115,230,191,225,233,36,127,50,191,82,51,176,115,51,82,9,137,0],[126,243,254,17,30,20,199,178,219,78,154,26,197,185,172,153,192,85,136,63,137,252,107,32,104,13,15,69,141,37,46,245,245,138,63,235,1,193,118,13,222,110,220,198,232,114,207,3,63,229,118,25,207,122,70,110,82,51,125,132,10,114,176,172,234,248,213,230,162,165,122,196,50,147,80,68,224,139,208,172,99,165,208,50,199,210,8,31,223,154,26,209,66,238,45,25],[36,165,51,124,98,25,167,81,79,43,247,151,1,192,32,23,173,229,243,244,180,140,5,139,234,110,94,83,131,187,180,0,212,182,135,99,103,33,188,133,61,133,142,238,16,140,249,10,23,165,39,247,156,43,227,245,23,160,248,215,173,180,55,40,202,212,159,253,205,15,124,98,164,162,119,246,42,223,59,41,2,80,210,139,122,185,101,54,110,75,41,245,240,41,250,9],[110,118,248,106,40,234,38,232,117,244,214,63,216,24,93,211,18,168,141,215,113,242,221,237,185,83,94,129,119,15,62,98,206,183,96,230,205,168,90,39,21,124,92,165,195,3,186,9,31,3,158,155,10,242,63,113,18,36,60,165,52,253,83,39,245,46,26,83,70,235,206,146,209,11,168,226,134,243,160,124,49,79,221,175,87,110,71,167,138,110,109,62,229,164,85,16],[204,250,10,105,29,63,65,204,49,75,207,196,222,105,67,161,28,46,49,34,1,135,13,152,125,16,179,89,119,4,52,23,249,217,38,30,209,7,143,242,76,158,126,20,20,177,148,14,108,76,119,65,243,64,1,171,88,103,32,45,58,233,103,195,134,87,35,18,111,42,84,7,26,198,61,109,40,11,132,71,162,97,91,253,183,209,157,134,113,60,222,81,39,203,93,19],[175,158,135,230,18,89,48,73,107,216,141,95,159,59,204,166,32,67,41,242,249,240,139,31,128,166,66,162,38,251,181,25,171,156,105,54,14,10,196,61,207,202,13,79,44,234,80,14,169,50,168,18,254,181,97,167,160,72,46,198,10,228,51,73,209,202,122,242,166,203,202,8,157,49,222,185,114,57,57,240,142,60,84,244,94,8,35,52,93,31,49,251,254,181,215,16],[63,110,244,76,161,156,78,38,96,134,31,235,42,53,188,34,201,211,167,198,93,238,37,85,142,60,95,151,134,55,204,188,170,76,117,211,5,243,187,72,251,108,11,26,109,70,78,11,73,75,164,46,210,64,203,149,250,48,100,81,138,96,188,69,117,34,62,61,162,75,13,245,82,115,185,63,176,172,195,216,5,135,71,179,103,135,220,109,104,214,133,25,150,108,161,17],[50,150,14,29,183,120,118,220,27,93,216,195,73,31,181,221,130,26,193,138,195,69,41,243,166,235,200,31,233,254,67,93,217,116,79,64,212,82,248,116,166,16,178,115,35,126,102,5,34,94,206,118,172,197,189,122,249,83,96,66,141,226,22,209,221,153,136,220,189,24,168,26,91,102,229,116,170,10,178,167,224,80,5,76,116,64,40,92,7,69,221,171,45,71,54,1],[60,154,7,36,82,44,171,251,157,225,198,99,54,20,204,8,207,200,22,120,243,116,24,216,167,31,246,86,247,27,146,245,160,109,10,221,143,182,164,36,253,77,98,75,104,175,168,10,187,150,13,84,171,210,171,176,15,228,217,19,6,221,29,118,57,95,208,75,148,8,136,111,12,122,207,66,43,1,183,100,250,142,252,46,154,92,39,2,77,113,202,150,198,23,216,19],[161,167,198,170,123,64,102,251,15,227,116,100,231,38,128,62,39,137,107,150,117,144,110,22,63,34,221,219,85,38,160,87,176,10,129,187,243,135,96,107,2,21,182,245,225,139,231,1,158,75,227,22,100,31,214,38,0,33,224,247,108,241,69,175,205,162,109,248,113,195,222,96,58,168,88,204,247,239,15,186,228,36,241,142,10,134,80,23,233,37,20,67,125,78,216,19],[49,176,231,83,197,245,209,226,148,126,198,246,253,78,144,91,95,203,149,18,136,189,149,5,82,138,222,250,127,244,127,243,254,104,170,176,46,146,142,111,239,160,231,94,130,100,252,8,112,95,115,63,12,217,142,166,192,129,50,8,190,9,83,102,109,72,26,189,103,102,65,72,93,87,19,148,153,134,197,31,246,164,69,198,208,65,147,64,170,202,115,168,181,84,51,0],[81,86,76,60,221,65,249,243,108,43,88,252,181,152,79,98,81,184,60,149,135,160,148,217,192,53,194,220,118,165,149,89,31,216,6,230,245,3,228,210,108,32,224,199,81,127,149,13,135,230,244,9,216,89,196,134,145,47,25,52,88,114,201,210,186,221,176,189,109,49,24,142,12,143,179,120,114,104,116,195,244,9,109,153,42,156,61,158,240,216,224,125,213,23,175,7],[102,180,84,116,10,207,31,159,64,70,212,148,25,48,81,87,93,59,255,67,202,129,81,6,86,17,251,115,161,225,45,46,91,187,191,252,211,37,174,26,129,8,115,137,99,76,190,2,138,56,32,97,223,87,22,184,0,6,209,95,95,107,130,16,110,223,55,50,94,36,88,158,30,72,1,176,15,166,135,75,236,121,85,77,44,161,206,171,71,236,23,114,238,119,158,6],[196,206,158,239,26,197,100,119,1,80,123,13,210,178,129,169,248,1,78,54,185,117,105,226,10,165,38,231,206,24,232,195,128,142,99,49,45,86,85,100,237,138,56,61,56,202,164,16,2,208,121,83,58,251,209,42,211,49,90,225,154,146,168,154,135,59,130,153,84,8,178,221,221,152,6,235,150,178,169,142,131,148,173,29,131,230,230,164,39,0,63,26,228,34,150,2],[236,41,202,151,217,116,253,88,58,89,233,6,251,95,223,109,203,185,212,213,210,177,94,201,80,202,124,49,63,140,128,123,8,118,221,158,154,141,109,100,248,192,184,8,103,100,106,25,124,71,222,163,6,209,157,104,9,38,168,253,14,55,71,199,90,98,225,81,41,157,78,179,163,202,178,71,108,56,66,36,253,249,39,81,11,246,124,83,76,4,3,91,234,136,235,17],[62,105,39,91,25,66,147,18,81,102,6,32,95,69,55,33,83,36,62,81,5,81,98,75,255,144,41,157,42,118,157,180,107,230,110,22,225,150,55,214,124,118,227,185,196,251,190,23,189,16,149,143,112,58,63,103,20,212,137,233,230,83,112,27,3,175,178,148,223,202,174,203,104,162,171,247,56,38,220,254,2,190,70,183,207,167,183,60,179,217,204,200,244,191,127,7],[209,178,185,192,163,135,142,39,204,42,236,59,218,48,151,46,165,80,105,254,66,218,3,156,9,246,53,196,216,114,135,117,8,199,37,151,149,253,109,236,166,141,206,203,33,85,229,13,254,106,65,192,246,111,250,75,15,249,215,197,68,19,4,20,97,24,160,159,132,183,86,93,0,76,165,239,100,254,142,124,116,113,59,41,149,73,194,121,132,146,36,104,124,76,174,15],[197,249,211,65,136,183,89,110,196,249,130,104,35,141,74,111,234,144,251,241,109,119,63,244,133,32,93,92,255,124,144,205,153,66,157,89,227,46,58,191,149,200,42,29,169,3,217,4,199,194,24,213,169,7,227,41,186,39,91,197,230,18,22,17,52,118,255,69,180,143,161,189,18,148,105,43,149,170,14,30,128,229,137,55,61,114,106,4,212,22,76,250,54,166,2,15],[215,141,207,75,93,116,111,194,68,112,53,125,186,76,88,96,81,36,127,60,20,233,95,115,77,75,246,12,107,117,51,126,145,188,238,202,35,59,47,245,79,47,114,249,74,132,71,3,5,38,40,251,102,128,63,132,77,255,13,96,20,56,38,74,16,130,228,7,214,24,46,106,120,234,235,62,133,246,68,78,116,229,157,138,81,202,20,217,110,55,104,5,132,19,4,12],[48,217,201,127,73,41,155,201,84,235,62,77,10,45,212,240,83,154,93,143,242,221,171,123,238,169,23,30,238,0,172,134,193,61,76,129,17,82,52,28,46,112,159,229,215,139,59,7,178,82,37,19,71,178,103,248,190,19,197,45,249,115,83,170,235,134,4,225,178,76,115,5,82,251,130,67,2,151,164,46,224,180,165,207,35,151,189,186,251,70,198,111,253,60,30,22],[84,197,159,225,154,176,39,120,21,183,119,65,175,123,158,38,20,193,81,73,126,30,11,195,172,17,109,120,129,96,164,56,165,179,161,97,45,100,208,133,138,16,1,202,199,176,126,1,142,203,30,59,14,208,189,33,163,99,254,32,114,127,142,94,89,108,186,18,243,224,38,27,86,59,142,145,171,108,43,191,92,70,221,207,5,114,133,94,103,83,250,40,80,219,23,7],[75,253,143,49,199,114,102,142,158,200,90,97,140,123,222,157,137,93,35,221,9,6,225,154,28,0,99,155,249,131,158,141,78,132,232,60,91,78,32,46,102,194,199,75,216,148,26,5,226,133,116,111,157,57,182,214,198,39,132,233,90,245,188,66,235,13,133,191,254,212,85,104,205,69,255,55,87,133,160,138,104,159,147,32,210,168,62,28,94,55,177,167,192,88,58,17],[249,14,211,89,223,58,27,105,76,75,13,106,28,134,47,117,6,13,52,173,28,76,94,180,57,92,179,194,189,24,60,200,166,64,30,198,197,240,217,81,193,247,248,180,171,44,0,21,175,248,164,227,66,145,48,86,181,63,78,70,20,180,133,60,136,12,215,112,69,90,121,232,8,34,134,2,173,59,167,12,229,237,197,51,192,130,131,234,31,47,100,181,83,163,212,25],[156,173,198,181,155,173,160,26,156,209,88,92,149,175,223,48,192,199,226,131,201,97,16,2,50,192,193,1,144,198,252,91,69,184,29,86,87,123,89,168,254,138,216,165,32,180,113,10,246,46,34,150,169,27,207,215,28,25,61,178,124,54,84,202,44,46,2,237,80,104,76,61,166,162,170,30,178,224,115,112,6,5,202,82,49,76,25,215,204,150,2,254,184,8,5,2],[132,246,159,240,247,224,175,9,160,75,111,212,26,132,24,208,96,117,12,180,107,20,25,156,4,233,171,169,72,77,12,37,93,143,7,131,119,214,12,61,142,34,166,104,75,49,125,23,64,45,2,19,254,176,62,192,158,107,199,46,116,50,234,69,167,140,226,255,197,8,211,11,81,228,66,217,55,185,69,175,217,194,216,169,84,3,197,130,86,230,123,234,198,205,174,6],[50,200,38,178,181,112,127,24,31,238,85,87,58,137,11,51,207,33,2,107,104,222,141,107,137,118,225,193,248,72,92,145,98,237,241,201,27,245,25,182,174,104,160,185,180,229,178,14,86,113,220,200,164,236,244,200,172,31,77,10,207,88,86,202,151,232,189,207,37,123,46,200,93,47,173,13,60,67,208,43,88,80,108,137,100,255,251,47,186,165,196,223,215,117,197,10],[33,43,126,221,40,23,172,21,198,7,1,235,87,135,26,224,241,20,165,109,223,54,139,154,5,58,60,171,165,47,123,150,204,220,69,3,109,7,247,250,160,178,116,253,190,21,223,10,238,121,53,115,146,62,189,81,4,194,177,91,45,51,228,89,58,148,129,129,171,145,86,63,153,232,85,2,247,97,74,171,212,135,123,233,225,118,120,115,61,130,84,219,246,72,70,9],[45,120,81,139,102,138,58,175,216,75,200,192,38,157,57,138,61,226,3,111,172,65,83,172,30,190,103,207,227,95,117,174,109,144,191,149,18,218,61,117,68,178,144,188,124,109,165,8,124,47,135,204,151,185,219,191,203,197,95,182,119,148,22,166,152,181,138,189,176,212,216,11,200,155,89,90,179,166,255,113,167,91,45,86,111,110,123,24,6,14,107,157,189,156,49,7],[145,5,55,229,198,191,217,13,229,237,166,12,248,65,78,26,231,7,179,118,48,118,17,106,236,196,29,104,170,170,174,182,118,95,114,134,139,26,204,224,153,249,198,10,204,61,209,8,31,85,231,65,201,202,132,97,135,165,61,1,88,98,152,42,52,224,41,40,238,236,221,154,176,12,143,143,23,0,20,169,216,86,191,205,231,159,244,90,153,234,223,155,197,144,146,9],[13,5,177,161,221,148,153,82,221,210,249,174,228,36,241,26,25,230,206,152,163,34,131,132,212,171,68,25,174,253,183,122,254,118,50,252,31,213,134,254,214,194,74,155,114,208,209,16,49,210,61,77,190,231,213,43,62,46,53,176,112,94,227,193,57,34,24,172,90,72,184,123,33,101,200,137,76,74,150,160,239,80,86,182,187,98,185,81,214,168,241,235,237,157,18,22],[154,35,243,124,129,233,238,214,193,250,246,189,167,220,190,70,31,196,212,90,240,87,113,213,150,64,153,150,247,115,59,100,112,5,231,75,59,6,211,177,135,167,49,219,96,162,38,19,105,180,221,81,166,69,158,0,1,49,129,146,148,215,221,74,129,36,205,75,101,75,179,70,244,246,151,222,94,93,74,12,11,139,156,235,130,183,113,237,131,249,164,135,240,92,117,21],[79,83,201,127,174,191,83,220,142,81,243,32,251,253,130,12,192,2,187,243,34,153,202,155,104,97,28,233,78,235,118,228,161,61,13,153,48,51,140,78,151,36,254,222,101,123,132,17,140,72,98,26,30,230,82,77,139,11,176,173,147,68,222,121,143,50,237,111,38,11,20,74,250,7,25,201,216,33,36,164,250,112,176,49,160,66,180,134,131,41,147,226,150,85,25,14],[52,232,212,100,69,98,143,35,61,73,21,27,59,153,237,120,138,195,182,187,253,163,128,180,158,248,196,36,52,135,238,53,37,22,93,253,4,143,168,255,85,252,123,84,173,68,78,17,11,175,2,205,171,244,76,64,98,82,96,18,221,119,225,21,98,143,77,65,44,99,1,5,55,34,172,6,177,38,214,186,82,84,98,80,116,141,195,111,101,210,133,64,47,239,200,17],[5,104,155,20,124,27,21,44,94,109,255,158,15,106,167,57,181,238,234,158,210,109,159,186,172,118,94,223,160,43,231,206,244,152,185,213,45,141,15,121,17,26,171,172,194,179,72,11,166,220,212,89,39,111,211,252,194,2,204,125,80,5,59,133,232,44,176,16,197,199,244,163,200,174,71,205,240,130,208,227,31,84,108,169,175,145,221,115,19,137,110,53,104,144,56,21],[18,82,138,28,69,247,57,9,109,70,157,75,21,72,107,71,27,15,124,137,63,79,153,107,56,37,86,11,187,127,100,98,101,121,56,5,75,242,32,45,7,86,22,164,57,190,195,11,192,160,59,177,63,244,51,228,47,188,34,236,64,119,79,252,105,22,218,254,62,65,138,218,66,43,191,203,25,14,207,131,145,153,134,33,224,42,254,160,38,176,92,174,132,123,106,13],[61,98,87,182,194,59,41,254,249,212,18,186,200,249,214,91,149,131,44,64,253,70,117,50,64,180,249,14,247,19,146,69,234,53,216,223,25,54,83,207,190,107,115,64,57,6,183,23,195,4,40,114,12,22,246,235,221,33,104,255,188,60,10,47,19,119,105,226,1,183,80,48,182,88,69,48,111,207,162,234,236,199,104,39,16,12,168,240,189,57,195,97,155,252,226,21],[135,16,100,185,147,137,34,37,218,135,167,14,180,189,104,107,102,3,184,209,213,84,203,169,113,235,200,129,202,62,18,118,132,197,206,184,143,45,221,246,109,134,107,21,197,69,81,15,132,245,153,91,56,149,126,103,179,120,172,213,62,202,230,183,31,143,102,164,194,249,32,94,110,240,251,188,73,225,73,84,123,146,109,210,26,144,110,132,156,88,240,149,88,149,253,20],[244,198,141,101,83,153,4,162,222,242,101,160,109,195,94,178,62,225,78,37,195,0,195,14,94,201,65,2,215,211,56,155,38,32,190,77,127,165,7,225,242,48,204,171,240,70,62,23,36,144,176,180,13,15,108,130,177,103,179,254,117,180,250,208,180,211,127,175,143,101,254,241,105,21,142,22,172,130,140,230,167,54,101,169,171,115,41,235,95,190,84,147,216,70,56,0],[226,12,231,225,223,215,217,18,196,163,124,158,148,143,68,159,231,221,102,100,127,81,97,125,247,135,83,225,188,165,252,100,131,205,174,218,78,46,73,26,245,171,60,49,141,250,201,4,159,169,25,22,171,34,45,212,37,78,123,213,28,60,192,6,237,223,2,56,100,166,147,203,128,193,207,143,2,33,58,26,70,173,175,175,205,45,217,242,158,19,186,228,12,52,100,17],[27,1,102,133,120,38,90,103,22,35,70,76,152,27,183,6,152,140,105,40,168,98,237,220,39,55,174,154,223,99,101,196,223,33,199,154,202,2,116,219,238,27,156,121,194,193,108,12,30,30,20,226,213,122,81,201,143,131,186,175,56,186,213,212,127,17,183,58,23,53,231,187,181,50,239,232,177,92,175,46,224,24,213,253,186,144,33,237,89,249,158,232,236,33,192,18],[223,233,235,135,235,56,1,107,163,53,138,108,199,174,100,93,29,16,62,144,56,59,153,22,102,2,103,5,149,58,227,156,154,82,125,202,70,122,154,237,224,62,32,42,140,107,80,12,11,35,223,204,179,30,235,30,94,48,12,186,38,216,39,204,68,48,160,253,74,75,81,151,241,182,155,84,111,92,187,130,110,136,184,89,1,213,97,125,212,207,23,249,249,206,0,0],[126,49,20,179,148,183,40,73,220,153,25,177,164,65,201,250,167,21,100,180,226,146,130,63,56,217,251,9,84,133,197,126,31,168,239,99,202,43,214,225,184,66,97,133,189,218,163,9,67,182,150,104,77,105,68,84,90,63,139,123,164,127,194,50,8,222,248,165,184,245,229,75,174,227,59,58,155,237,136,10,132,187,33,24,220,79,232,59,200,91,240,244,131,176,108,16],[202,14,14,157,251,224,199,227,125,19,43,29,94,196,73,26,106,122,51,175,231,63,211,146,111,10,35,206,20,81,32,179,100,39,145,23,247,114,209,114,107,148,23,254,95,117,46,14,218,99,203,199,177,53,143,174,246,97,124,25,144,201,216,106,145,88,163,61,103,56,79,4,214,207,56,30,117,225,138,161,104,167,63,201,109,0,198,101,11,21,249,93,186,176,75,8],[68,177,27,186,201,247,20,19,233,37,104,219,94,148,201,249,167,240,31,23,105,81,177,191,77,206,246,200,133,102,116,106,196,234,89,162,127,61,111,25,212,184,78,45,205,178,216,15,227,133,69,7,67,237,21,6,33,50,126,230,187,233,208,177,215,235,108,17,174,31,80,0,244,113,90,51,99,146,218,200,245,43,251,218,49,159,43,35,54,99,102,83,253,238,62,10],[35,57,162,141,228,207,176,14,60,185,203,115,231,80,246,198,2,92,32,29,54,17,139,237,102,35,223,210,148,90,210,175,25,101,190,52,167,200,153,220,176,121,193,113,132,217,98,8,96,216,159,18,149,3,104,160,51,161,111,247,191,134,229,107,176,177,166,11,251,230,102,50,139,44,35,231,233,207,113,80,251,106,141,18,44,11,192,190,234,184,236,142,27,45,56,2],[200,7,164,18,164,222,246,158,173,139,192,152,92,165,82,161,28,50,56,93,131,164,253,39,49,251,215,149,75,13,166,148,22,70,225,15,184,115,183,218,86,146,21,165,159,228,71,12,152,73,252,212,211,159,240,243,232,152,166,75,136,38,218,157,136,212,189,229,177,134,32,239,12,36,232,43,118,7,19,168,54,201,25,165,66,160,67,23,44,220,23,52,55,110,182,15],[158,32,97,33,176,215,23,3,240,27,220,28,173,13,239,44,105,124,95,150,225,77,2,203,22,210,147,185,142,141,184,49,155,229,165,101,246,168,103,95,33,229,233,191,235,54,141,22,4,2,217,27,45,131,2,42,188,55,61,105,217,207,149,114,215,221,102,195,45,79,210,255,161,123,10,71,48,212,26,203,215,128,97,156,207,130,149,29,163,187,215,162,143,62,237,11],[186,160,230,67,222,205,229,77,226,80,152,54,159,150,6,197,211,76,250,186,113,237,138,247,159,217,203,69,49,8,234,78,6,53,241,143,73,145,216,129,214,184,131,4,78,161,212,5,110,98,23,125,37,158,253,207,20,107,54,158,49,231,7,84,96,77,28,88,55,134,123,229,184,254,242,166,72,131,197,219,36,149,60,225,243,89,177,91,13,243,146,102,12,127,220,7],[242,108,160,115,253,20,164,83,46,8,242,159,16,138,214,107,188,31,154,226,146,136,250,94,87,144,85,8,105,112,224,39,151,119,146,165,136,223,207,252,63,193,12,143,67,28,85,11,88,1,238,33,169,103,193,135,142,156,203,115,147,92,150,228,175,77,192,142,170,126,118,202,140,25,62,58,92,68,109,239,173,80,103,96,166,172,48,19,225,201,25,157,184,236,183,15],[157,240,91,111,46,136,185,178,88,79,133,20,192,109,74,103,226,19,74,231,231,196,227,91,99,229,78,18,211,139,239,133,204,248,229,137,174,122,228,182,227,223,165,0,121,196,41,8,228,241,199,76,144,135,21,133,60,241,18,59,36,146,197,67,41,139,175,167,105,73,247,58,111,127,243,220,46,162,56,160,199,36,160,108,236,67,207,10,119,59,227,178,99,23,181,15],[21,128,124,27,110,84,130,52,66,155,49,129,173,42,229,87,153,104,246,161,139,95,196,205,17,97,164,162,32,150,120,179,244,236,102,142,56,244,254,39,198,195,86,186,201,36,178,12,31,232,69,124,237,147,215,219,54,35,97,67,31,64,61,228,13,238,121,119,101,3,172,30,84,167,197,184,224,205,60,181,209,84,44,47,210,208,165,179,123,67,67,60,104,232,37,22],[109,139,58,49,181,55,156,226,10,164,248,38,253,219,66,43,40,137,79,116,63,246,71,159,204,168,134,224,80,240,65,226,184,50,37,140,35,183,160,69,115,85,22,195,245,184,250,17,243,176,95,174,85,207,209,17,8,140,96,236,225,31,244,232,136,88,117,204,113,216,56,243,141,153,135,122,252,182,54,32,226,165,135,83,129,58,12,195,208,131,87,102,172,171,109,7],[157,43,90,156,122,213,168,1,34,107,162,154,149,46,235,41,176,158,218,252,28,215,58,130,66,28,34,196,240,118,29,251,84,66,112,2,120,169,90,106,213,162,54,240,74,246,162,3,87,156,221,130,187,226,228,93,72,146,55,145,185,27,236,27,19,92,194,136,107,58,120,78,55,56,92,255,29,83,131,177,168,53,240,178,59,204,158,53,119,249,211,189,58,36,3,7],[206,107,192,175,247,120,119,63,64,171,104,76,99,64,181,126,154,41,180,59,71,60,180,104,14,51,169,76,48,2,21,219,181,216,225,68,243,143,146,222,165,40,9,131,255,70,201,23,158,126,180,125,3,13,61,115,84,157,211,64,125,220,191,189,94,241,3,98,125,153,6,144,142,191,169,232,75,82,87,103,192,43,250,18,129,30,227,137,143,175,59,195,255,67,8,6],[221,3,255,33,47,107,230,121,97,209,229,33,117,128,155,76,28,162,14,229,78,67,241,195,201,121,155,218,195,149,126,97,7,75,64,188,165,44,108,235,121,238,115,61,126,103,140,20,74,199,247,188,44,193,19,27,234,232,28,79,204,172,254,174,220,136,48,28,202,189,212,57,3,154,2,176,72,52,197,200,91,26,218,25,236,147,137,44,173,24,126,86,189,191,146,22],[48,71,149,230,162,104,253,99,207,170,104,58,167,40,196,212,146,95,63,109,236,87,39,70,39,49,101,155,233,43,21,27,39,179,154,215,28,195,213,87,193,171,237,244,186,133,107,15,87,62,57,177,66,131,83,142,84,52,59,195,170,224,78,14,214,241,23,52,252,96,71,189,243,32,148,146,255,109,198,249,57,2,29,76,55,54,175,152,39,195,1,65,219,141,7,7],[65,19,145,99,18,90,215,140,114,98,84,22,191,77,113,206,2,187,163,7,202,254,40,27,195,155,128,125,123,173,149,159,193,194,217,188,210,212,174,173,211,43,84,58,35,64,166,22,169,101,217,162,204,222,136,135,239,194,255,51,81,187,123,5,234,180,85,51,177,36,129,78,65,149,93,116,38,171,198,72,79,165,228,172,84,209,174,236,210,19,179,211,250,175,96,13],[100,180,39,249,217,8,140,147,140,37,26,20,160,185,145,177,143,99,234,178,162,128,87,234,232,22,224,122,143,189,141,21,116,111,138,139,219,91,92,11,75,21,206,221,4,184,128,8,202,33,1,254,155,10,146,214,101,97,55,29,84,81,103,12,236,47,162,214,131,165,181,110,244,87,214,107,64,200,250,110,192,229,168,206,229,139,49,92,201,12,101,157,223,215,39,18],[31,51,169,6,210,73,197,224,126,73,59,186,104,119,230,121,8,43,247,171,36,236,43,238,179,92,166,5,189,128,111,226,43,82,237,18,182,20,83,118,84,110,236,100,116,59,147,22,194,222,196,251,13,131,51,62,251,132,224,103,197,58,193,245,198,120,133,113,216,5,63,142,218,15,99,151,172,247,198,163,28,205,32,235,130,216,27,104,215,197,197,168,192,149,10,12],[183,98,83,226,166,163,20,80,124,238,118,142,108,99,8,0,235,170,54,5,59,186,155,219,117,208,130,220,0,44,219,37,170,194,9,219,124,117,244,191,239,166,176,99,232,232,177,5,231,179,47,103,168,76,156,123,58,205,67,119,101,42,62,42,125,22,135,127,173,14,44,181,223,185,57,17,154,198,83,60,201,73,217,199,13,24,20,71,240,11,142,225,253,54,241,16],[181,150,145,0,229,163,63,150,67,149,111,124,226,157,188,106,251,58,86,27,151,110,124,124,92,186,126,190,22,8,34,98,130,4,149,205,129,234,235,42,34,130,99,254,225,154,50,8,89,82,87,86,19,95,97,28,62,138,22,234,50,46,214,198,51,78,34,138,72,78,48,56,249,192,252,139,32,104,226,252,245,152,61,39,83,176,69,173,124,196,28,91,212,239,186,22],[129,130,212,237,4,19,143,162,34,109,126,32,13,109,132,135,24,131,42,94,226,6,227,91,125,63,12,86,220,113,193,96,32,82,233,36,77,49,226,162,236,212,195,237,14,17,45,3,209,109,84,54,74,245,183,212,41,127,135,113,219,30,239,34,200,251,191,29,64,87,48,113,130,60,101,216,130,149,218,27,94,77,242,126,58,144,16,171,4,135,174,198,140,52,113,18],[109,38,171,114,220,174,221,97,230,198,1,170,7,184,107,136,113,230,183,139,104,204,6,18,47,203,220,159,175,40,149,34,231,139,173,200,134,21,13,43,100,134,167,228,253,75,137,23,155,214,81,73,245,72,164,180,116,187,111,8,132,24,202,136,76,152,202,103,116,248,111,104,231,240,190,202,64,86,169,36,144,77,114,237,69,124,139,21,87,18,177,74,215,5,68,12],[6,197,222,3,136,175,84,208,10,212,68,203,118,79,71,188,112,99,103,21,82,116,114,122,223,168,99,208,74,27,145,66,130,96,171,183,143,247,173,42,250,126,243,50,24,144,206,22,94,22,147,37,107,83,41,71,10,162,218,141,247,249,26,27,22,211,106,151,118,44,186,1,217,219,253,53,89,1,160,228,254,162,33,194,22,176,152,187,24,150,63,242,222,57,222,12],[202,195,170,238,2,185,169,249,181,243,138,32,165,111,66,21,94,119,75,40,7,108,92,82,179,148,181,115,237,112,116,242,12,140,191,136,31,29,143,148,18,161,127,250,60,159,34,8,31,220,81,28,21,148,234,251,159,180,123,215,87,79,122,92,134,61,48,1,46,181,178,115,180,78,210,136,175,214,169,57,250,137,211,142,149,11,32,164,14,18,211,72,152,120,177,20],[173,140,72,142,200,228,34,34,16,2,56,43,56,194,240,179,32,47,105,255,113,8,128,212,216,54,42,139,34,50,48,171,243,35,193,238,107,48,19,189,66,22,113,216,27,72,48,21,192,247,222,89,243,167,66,168,122,155,43,72,152,145,166,111,214,167,228,211,194,127,171,44,83,165,111,107,196,8,60,110,228,75,29,249,1,12,167,54,80,144,92,7,164,47,1,19],[194,156,76,221,134,77,151,80,137,72,60,247,114,96,143,136,113,109,176,86,145,124,166,210,11,23,109,184,220,174,191,171,25,118,113,4,175,171,100,154,175,138,212,214,167,181,144,6,90,140,65,180,8,118,66,200,223,192,90,136,180,167,4,152,152,42,99,18,75,80,245,48,1,101,102,165,31,253,102,228,132,216,158,179,6,118,118,22,99,110,93,85,115,74,95,21],[141,67,177,53,57,149,42,31,84,201,82,139,56,171,70,14,18,232,1,37,34,205,131,94,108,219,25,78,37,107,28,77,220,77,20,223,48,156,201,201,179,255,199,44,185,69,241,8,212,247,23,247,139,83,131,234,120,96,32,235,142,244,203,121,96,121,137,17,96,45,66,191,204,247,0,206,145,2,209,140,44,129,38,66,107,12,81,230,94,86,125,159,244,132,11,23],[32,147,77,206,60,56,143,75,222,172,5,51,93,128,14,204,243,92,220,250,100,4,145,174,131,128,231,82,73,204,67,146,252,103,118,3,116,211,134,153,149,253,188,144,203,180,42,24,181,132,61,22,65,5,83,132,86,74,130,101,111,127,6,209,38,150,77,125,244,185,190,129,147,234,231,200,224,121,86,145,199,133,54,64,163,123,87,139,244,34,51,48,104,82,81,18],[126,204,49,218,114,71,53,97,254,180,125,131,38,43,215,161,51,41,156,37,168,130,6,244,132,86,115,50,187,229,93,94,111,182,27,249,10,153,29,53,67,56,31,9,200,52,26,13,207,116,236,162,104,201,106,134,49,188,197,177,52,174,92,24,182,185,105,63,211,207,84,209,191,156,254,207,28,223,190,86,113,232,11,247,102,35,189,193,188,40,122,169,168,142,158,18],[5,234,218,121,8,56,249,101,87,45,203,250,32,86,145,201,136,240,171,40,75,26,82,124,241,167,1,89,159,220,39,90,65,77,107,182,219,120,1,137,80,141,32,239,158,3,140,7,67,225,165,155,100,239,55,33,31,44,10,219,13,161,236,246,174,1,83,24,192,101,120,36,216,251,187,35,163,92,233,3,104,178,105,106,208,252,25,134,127,83,162,209,153,91,113,8],[136,9,233,146,66,51,144,192,39,211,180,188,174,21,174,83,30,219,83,5,157,60,140,12,103,128,34,85,13,30,87,27,195,128,252,217,121,30,163,18,26,141,179,108,163,161,208,10,118,123,225,72,9,181,181,234,142,199,158,77,208,158,134,45,210,235,234,159,101,65,230,144,157,187,221,78,255,195,53,28,179,233,136,128,54,74,135,8,67,114,234,244,216,186,12,3],[119,241,20,163,172,243,169,145,217,219,171,208,93,133,238,69,23,232,101,173,227,81,208,16,141,173,162,77,178,79,249,196,222,110,57,245,224,247,103,107,108,249,202,130,98,143,229,10,145,21,135,187,27,180,238,173,85,203,8,253,184,213,64,1,97,23,97,25,246,149,139,116,8,161,128,15,116,61,99,20,1,94,133,24,75,71,145,19,28,136,101,38,197,170,234,5],[151,40,100,28,255,100,36,192,32,100,129,106,73,103,158,53,183,250,51,176,209,176,55,28,77,125,219,66,140,32,57,92,228,165,149,158,125,69,90,55,17,237,174,95,190,208,249,22,72,59,109,72,33,229,160,193,62,230,193,205,252,226,103,165,13,167,220,221,178,41,178,36,200,34,248,11,95,109,161,143,23,220,215,3,207,151,143,146,175,94,93,28,182,206,121,17],[220,49,102,13,206,45,28,213,126,186,139,181,124,186,104,230,138,161,84,191,129,14,218,7,86,190,24,119,248,46,64,120,224,64,138,15,103,225,111,154,208,19,254,9,97,94,226,23,229,108,2,122,129,97,41,99,21,125,142,41,225,182,112,238,81,38,172,224,162,243,0,50,238,136,7,95,146,85,22,54,192,225,189,208,156,57,194,94,21,1,97,235,218,184,173,13],[132,10,106,197,109,149,90,112,197,9,106,246,93,140,93,7,104,173,36,245,20,125,84,108,96,187,201,52,20,230,10,188,165,30,83,4,49,112,101,161,203,6,129,47,180,149,114,6,149,244,25,240,19,80,151,82,169,17,57,49,209,101,98,209,20,192,74,79,82,33,49,71,88,82,76,228,224,54,104,124,184,117,95,202,129,107,233,182,158,7,85,42,255,142,232,2],[2,247,18,108,215,132,220,159,199,226,208,114,89,97,139,157,217,41,108,157,139,16,5,206,210,73,13,110,239,174,105,132,123,178,18,121,229,131,9,167,176,128,115,149,113,246,115,8,167,57,92,125,211,3,243,211,228,188,63,30,69,127,238,117,187,37,200,166,101,201,211,191,220,53,19,247,67,124,69,47,184,239,68,199,34,46,5,81,215,62,207,179,46,25,183,15],[204,29,110,9,18,156,175,160,23,160,135,130,232,127,147,142,88,124,211,193,20,126,140,250,83,52,50,239,37,27,80,135,111,111,179,42,134,82,115,166,193,29,18,46,209,60,47,21,188,117,67,178,87,202,180,52,43,17,191,212,22,216,34,38,220,55,1,162,221,115,184,109,125,134,72,9,145,34,228,247,250,235,50,6,129,100,52,186,31,107,64,147,107,99,182,12],[7,108,150,13,96,9,27,238,204,255,108,123,181,51,45,0,63,21,246,92,170,237,216,61,80,27,171,73,128,226,25,176,26,157,11,65,133,49,63,95,97,5,170,23,225,63,32,14,156,131,239,253,40,234,154,219,41,155,88,101,173,143,83,30,204,188,172,233,16,171,140,49,94,156,106,60,252,96,147,99,100,133,144,99,99,190,212,150,14,154,135,228,53,99,69,18],[58,177,218,103,29,245,14,18,14,12,130,245,110,185,195,214,210,108,58,240,117,204,95,122,5,65,174,2,30,173,200,43,30,164,174,165,77,151,14,227,113,195,45,84,121,206,123,8,183,64,25,99,219,146,255,208,224,144,24,103,221,182,225,61,229,42,132,112,107,62,184,229,72,170,126,76,177,197,184,194,117,40,40,184,168,187,113,84,97,111,135,98,252,120,164,21],[113,124,78,119,72,23,129,148,185,139,167,26,210,162,138,240,176,222,72,147,8,58,233,85,64,148,37,218,33,60,94,171,224,132,185,238,149,46,59,8,71,15,233,194,16,66,160,11,124,175,128,138,217,83,135,11,120,233,252,58,118,201,83,245,87,73,108,164,7,114,66,193,218,131,93,146,138,239,214,154,180,28,100,68,73,240,109,47,229,201,176,191,101,63,211,7],[134,158,20,33,207,36,173,146,106,46,224,109,44,222,177,61,92,4,244,66,85,147,219,198,117,235,116,110,184,202,97,101,113,22,71,200,111,100,94,74,219,200,99,243,57,246,130,6,210,78,213,204,180,60,27,204,109,243,231,75,125,133,78,24,215,212,63,225,134,54,101,252,118,155,32,212,13,120,191,171,92,90,110,228,242,192,177,163,77,0,159,84,235,212,150,13],[44,67,226,14,122,92,101,229,56,115,211,134,78,162,41,129,112,65,197,210,255,140,80,192,53,130,241,147,44,88,232,35,151,20,64,20,152,38,232,56,154,186,230,142,26,6,59,24,30,124,132,47,103,177,45,57,241,124,248,106,36,62,240,80,136,72,86,67,185,236,108,87,112,174,30,141,138,223,81,37,119,254,143,191,197,88,154,241,241,241,106,152,166,214,158,24],[150,63,63,90,139,200,148,9,88,99,198,199,113,251,160,237,208,151,215,213,115,224,34,19,216,136,149,212,52,140,68,65,178,146,247,96,222,26,195,217,28,156,44,85,199,109,172,18,57,81,53,64,191,13,31,253,241,189,213,226,172,215,229,230,98,202,255,17,44,131,73,79,154,14,168,158,229,201,184,243,138,168,249,107,92,87,163,140,193,36,147,229,198,118,159,4],[100,188,9,144,184,220,9,117,205,156,43,36,43,74,201,6,51,76,96,213,69,79,19,251,95,224,109,27,157,239,226,241,29,65,191,86,170,220,210,236,76,188,255,148,236,103,177,15,130,208,129,169,191,35,208,95,227,0,52,183,86,119,61,187,133,70,6,99,206,249,18,162,228,38,161,15,156,234,152,157,104,28,13,126,50,31,203,253,90,5,123,192,9,228,43,22],[63,78,94,114,233,154,36,25,128,139,84,85,176,130,19,62,4,198,97,98,219,220,82,38,28,1,249,164,17,22,201,205,78,153,214,184,18,43,96,94,71,11,241,195,168,84,247,12,236,150,198,150,118,190,98,183,83,148,92,222,63,92,115,254,54,57,55,217,142,47,151,20,45,194,99,233,166,236,129,118,205,93,189,87,53,207,129,50,248,176,31,223,254,2,138,16],[33,110,14,205,117,188,244,8,105,50,154,40,172,215,242,209,164,100,220,210,187,61,48,7,201,41,166,65,205,112,39,233,88,4,204,65,89,17,79,224,50,200,205,221,95,161,84,14,154,207,92,222,14,235,132,142,190,86,213,95,121,55,3,52,34,201,46,30,70,253,244,77,14,163,45,133,99,75,56,247,41,133,51,199,71,233,175,235,50,0,21,18,171,86,85,25],[205,102,232,233,230,122,180,215,187,213,95,253,186,230,70,98,181,66,203,108,137,10,33,185,34,157,111,244,35,46,88,155,254,143,141,200,251,120,178,48,214,252,160,153,211,237,69,10,248,231,238,221,185,219,126,150,199,224,68,19,142,137,240,192,0,91,47,250,237,103,29,102,167,243,213,119,106,80,31,105,9,202,152,7,136,161,18,23,114,107,193,120,199,182,130,18],[9,102,200,194,238,196,178,77,50,240,54,144,25,130,98,224,182,228,207,22,65,159,172,64,105,123,88,1,250,104,94,182,110,81,208,83,51,8,192,65,24,26,43,151,148,112,95,13,4,28,183,54,250,43,30,113,102,213,109,75,192,119,85,235,108,209,183,224,18,243,14,33,49,137,139,201,211,213,213,123,126,45,90,141,84,185,4,55,131,166,62,241,101,171,161,0],[7,220,43,215,16,69,92,251,99,193,211,128,185,120,24,63,251,153,125,216,6,178,216,118,54,233,122,30,95,231,43,122,169,164,119,136,180,18,160,31,56,227,46,120,156,8,122,23,225,81,164,230,0,155,238,203,55,17,108,32,23,56,40,68,79,72,102,92,78,4,231,16,55,112,143,56,111,110,175,21,208,145,160,43,254,130,93,15,82,13,231,143,240,163,12,23],[164,197,139,66,144,73,88,8,198,31,241,75,217,225,95,233,212,7,118,190,138,18,39,132,157,165,24,189,152,56,207,116,227,232,22,29,251,172,174,99,179,96,116,229,78,20,12,20,16,110,203,52,115,45,243,73,164,170,153,9,196,89,195,54,66,192,134,219,237,178,192,101,239,140,142,179,237,13,30,201,94,33,161,59,221,62,38,102,87,101,228,135,125,234,49,1],[102,108,195,173,121,10,81,211,91,130,232,213,136,100,219,156,62,211,148,35,118,63,179,160,123,255,120,249,4,38,213,231,189,137,202,166,250,137,13,69,44,80,145,5,200,139,17,6,7,218,222,227,48,204,154,211,39,144,16,226,160,48,66,107,125,126,65,156,226,226,167,56,180,191,167,73,121,157,36,253,95,44,36,60,157,66,83,179,130,115,64,225,16,111,106,22],[160,83,64,117,143,138,214,218,71,115,200,214,146,4,238,212,56,125,173,24,96,166,228,97,65,65,141,90,210,19,30,20,247,21,111,125,85,226,97,37,109,20,22,57,161,148,123,3,237,65,44,102,167,230,155,105,55,203,220,181,169,20,51,200,252,172,36,0,2,215,196,189,2,55,214,163,172,86,254,63,171,73,96,63,183,46,131,95,70,93,173,179,200,126,40,4],[64,99,48,78,229,143,38,16,248,194,19,201,114,82,220,233,71,182,56,192,240,54,39,127,134,180,169,175,126,106,192,89,126,215,219,85,10,200,122,37,92,207,96,198,165,11,69,1,31,90,126,61,26,6,62,155,203,23,39,2,168,111,156,49,251,65,182,110,7,131,220,158,14,134,23,96,168,244,240,130,219,237,220,205,116,236,78,235,157,62,47,53,190,240,204,10],[197,69,123,32,182,42,24,231,85,114,237,87,96,53,163,164,231,181,1,126,232,218,232,2,144,209,40,129,236,154,222,69,227,18,72,207,199,16,161,226,254,12,110,232,146,183,19,11,197,154,14,35,83,195,3,189,177,171,222,77,16,177,239,226,177,47,50,189,230,161,38,154,150,145,44,35,9,74,108,223,154,19,40,89,229,171,115,2,234,62,110,104,228,229,24,20],[247,190,215,203,172,250,131,16,195,201,29,162,93,205,249,149,202,244,71,142,0,202,102,68,91,180,166,113,245,32,99,216,150,19,226,78,47,124,166,230,79,21,122,143,4,138,68,8,115,186,73,19,125,177,49,190,81,214,65,185,233,55,215,23,177,161,220,39,178,31,167,196,153,73,118,237,165,82,186,101,250,146,230,169,60,136,140,65,110,127,185,217,169,240,147,18],[230,178,8,187,226,29,114,63,79,230,214,179,241,209,254,184,42,202,255,90,87,104,148,77,146,65,104,169,0,99,199,181,230,67,174,22,61,151,170,163,155,164,27,205,243,53,83,21,75,236,21,110,148,44,25,63,216,48,2,109,54,0,164,236,104,189,223,93,2,59,99,147,101,172,171,48,195,102,162,110,140,19,117,42,136,238,88,95,169,73,220,223,213,66,136,3],[19,246,91,100,67,237,42,25,36,253,194,72,200,138,111,53,16,117,147,107,96,98,78,109,46,183,97,61,120,79,35,161,204,128,116,212,12,199,100,166,120,139,60,182,45,177,21,23,101,149,116,54,252,232,205,72,182,54,236,205,90,188,29,27,226,130,121,217,239,132,120,216,25,239,48,160,168,52,88,175,3,245,42,103,156,66,248,84,117,189,28,172,23,99,127,18],[126,102,188,26,144,231,60,0,82,181,250,204,237,20,2,206,162,79,196,213,200,182,179,171,156,201,80,8,137,229,19,123,41,61,29,26,240,144,133,135,85,85,190,188,95,252,216,22,143,9,50,15,13,53,129,2,41,252,208,44,202,125,223,98,151,128,128,189,75,76,143,230,250,185,214,113,194,207,58,142,75,74,243,122,67,254,74,207,245,246,6,135,151,170,105,13],[34,201,244,20,93,139,26,97,208,10,231,57,101,188,90,193,248,56,72,120,141,248,227,4,69,74,231,16,221,124,130,191,136,3,53,27,180,175,156,166,184,197,197,129,205,115,38,25,219,68,26,156,187,249,50,176,4,169,210,246,222,15,143,15,79,210,70,201,174,143,122,28,119,68,249,210,174,140,202,153,199,202,253,213,206,28,218,53,70,3,192,153,71,0,119,8],[71,56,159,102,174,128,7,42,13,39,198,154,16,242,140,111,103,24,167,196,35,102,40,182,213,255,172,95,167,77,55,205,174,0,208,167,211,106,60,158,60,149,39,239,238,236,25,15,185,227,30,126,174,190,3,36,232,176,107,248,143,12,206,67,44,66,71,119,45,233,61,15,217,65,212,222,166,102,167,255,213,149,41,151,182,110,162,20,57,164,165,48,191,12,129,10],[75,95,50,137,33,243,244,141,9,0,103,125,22,187,137,100,149,114,145,224,212,184,8,187,230,235,120,233,81,106,79,49,116,40,70,28,111,88,70,168,216,210,225,123,49,211,179,16,20,16,86,5,7,205,166,50,67,141,216,231,12,160,234,164,2,102,209,212,105,201,164,6,167,105,172,174,70,159,33,18,24,87,43,56,215,134,171,252,102,15,216,188,40,75,108,21],[206,7,110,181,61,132,176,234,136,50,158,242,11,98,111,14,95,39,203,136,5,205,39,99,232,5,177,221,103,16,121,23,102,3,95,203,53,244,138,10,68,189,251,255,87,206,209,20,249,100,189,239,202,73,118,41,163,98,220,234,33,83,243,253,227,96,78,142,165,73,19,56,62,195,181,82,149,229,240,169,222,255,39,134,79,185,255,186,250,94,168,83,17,99,79,21],[163,230,19,221,253,160,6,46,213,156,203,204,150,74,239,33,46,122,81,17,206,209,116,223,68,60,11,121,250,175,221,193,30,110,83,121,148,60,145,210,21,46,233,117,146,120,178,24,228,213,47,176,82,239,196,26,217,168,198,181,99,172,20,181,157,154,50,197,44,23,65,241,54,95,32,75,141,227,203,24,200,69,166,71,73,152,200,211,160,23,19,193,71,231,199,22],[219,91,24,44,207,249,92,48,200,168,114,76,72,56,11,76,125,25,122,121,123,119,237,241,247,188,199,210,167,96,85,123,182,14,211,191,85,88,55,106,73,8,127,205,123,202,63,22,110,51,33,198,59,58,34,199,82,52,14,178,107,1,160,137,35,254,55,179,166,200,77,203,212,154,197,123,192,97,71,196,229,208,248,250,53,167,148,21,102,221,196,44,105,135,176,17],[185,154,12,254,187,69,136,126,36,143,172,45,80,108,221,174,63,136,154,108,208,87,116,94,228,122,99,253,253,103,179,201,180,14,115,22,151,92,233,25,4,60,9,33,137,146,147,7,167,168,107,217,118,45,161,52,226,125,68,129,169,111,192,136,77,216,123,74,241,181,111,76,198,203,98,117,184,179,155,64,155,68,170,227,55,204,124,202,77,72,24,177,57,78,57,0],[176,10,82,62,179,190,192,120,230,239,200,107,174,5,131,222,168,203,75,91,106,21,112,61,113,73,49,120,53,37,143,46,207,217,135,94,5,60,172,238,165,114,248,21,183,87,24,23,190,51,16,236,41,23,166,142,186,168,97,214,134,134,56,104,140,192,35,72,203,70,195,243,92,57,40,57,177,243,148,2,67,33,1,119,200,74,175,136,189,30,33,31,208,156,75,0],[161,15,211,253,54,165,90,165,202,183,170,49,215,101,217,252,223,139,90,98,121,85,229,136,6,188,14,163,187,1,151,47,40,215,76,152,198,0,68,13,149,12,229,35,236,254,168,25,139,0,229,61,60,7,17,243,115,37,34,19,215,123,187,175,25,90,232,213,223,174,185,135,62,104,223,34,161,185,72,24,85,50,37,217,36,180,65,221,228,117,161,139,188,90,243,2],[3,76,215,241,188,252,182,237,64,172,98,200,162,62,54,55,194,115,128,210,251,109,141,121,64,200,122,88,165,136,223,208,181,197,4,237,73,23,53,106,180,238,23,176,90,255,213,20,220,189,212,237,140,150,51,187,109,198,166,125,57,231,137,216,172,53,243,84,1,235,124,23,134,112,138,175,84,233,180,9,48,196,210,14,236,147,192,242,239,103,101,213,94,215,197,3],[160,210,94,142,18,229,132,0,121,199,228,42,36,209,229,41,6,242,159,224,21,83,250,136,28,170,30,24,10,124,36,89,116,125,69,61,195,107,249,179,238,173,203,145,244,191,28,22,229,200,50,160,185,194,158,244,160,28,166,233,217,127,138,127,216,215,94,210,115,92,175,92,161,14,70,47,42,24,247,229,102,155,230,76,211,58,227,80,164,127,204,123,240,0,92,14],[193,102,187,156,160,146,124,149,134,88,205,211,24,245,3,197,200,236,96,52,202,204,1,9,198,176,143,52,90,102,122,254,146,111,167,110,49,62,85,246,53,198,39,250,37,197,125,10,114,196,15,3,216,182,43,78,145,92,195,58,159,230,224,129,198,224,116,209,237,70,221,54,157,232,42,242,105,194,10,178,136,102,73,194,162,185,169,39,123,143,39,65,239,5,75,3],[64,46,28,185,206,137,209,111,43,215,223,71,148,113,76,128,2,47,172,129,245,184,231,193,108,76,13,183,8,182,200,86,224,170,133,215,73,91,168,67,128,79,167,253,9,44,110,9,19,197,238,101,60,176,49,238,198,163,77,43,202,247,234,181,245,87,143,224,158,20,184,20,138,131,201,219,10,180,99,236,14,147,253,41,187,199,194,95,43,60,206,176,240,7,80,14],[220,115,113,110,39,56,128,138,4,136,190,84,9,118,42,27,100,20,0,144,219,132,85,19,177,4,72,181,60,173,185,16,226,37,210,175,185,223,0,180,170,211,181,28,175,167,28,18,15,9,78,198,63,107,153,177,17,163,152,100,18,36,82,8,80,245,130,218,83,233,150,157,79,214,196,28,239,66,243,254,91,211,238,26,61,69,191,85,89,110,134,44,112,219,60,11],[56,48,170,204,127,133,11,213,66,68,131,50,95,84,13,125,221,79,229,17,217,191,155,24,170,254,249,130,68,50,151,28,233,233,166,70,195,115,87,15,199,183,248,66,64,158,158,12,34,47,157,162,113,135,37,205,61,74,40,77,145,225,6,136,46,62,180,30,164,129,158,173,219,79,32,179,83,242,121,134,151,97,48,170,107,167,0,139,52,248,124,6,60,171,128,19],[196,68,129,82,114,0,10,151,238,189,156,205,123,127,183,2,135,57,132,217,170,230,176,252,233,141,237,180,237,179,223,105,146,168,16,245,234,120,85,211,73,218,131,12,13,8,191,4,236,34,15,97,177,206,61,82,16,14,208,125,41,164,212,40,94,143,245,17,111,9,179,47,50,223,117,121,249,135,33,68,117,93,135,231,245,129,144,217,82,241,237,89,235,107,78,20],[45,239,11,75,30,7,137,250,158,100,17,158,42,224,183,20,128,200,28,115,122,60,67,83,73,101,178,188,27,232,97,35,42,50,228,188,206,187,102,165,46,49,201,191,77,235,143,19,139,141,235,129,45,32,160,83,156,160,234,136,8,53,100,153,150,1,182,140,70,152,188,84,187,78,69,245,179,191,137,22,44,207,224,181,216,198,191,178,233,189,81,203,206,110,216,13],[186,29,58,61,11,67,218,58,78,236,113,238,145,227,142,25,101,208,94,131,124,227,236,151,13,146,253,12,150,34,83,66,168,253,5,120,202,84,26,133,157,54,171,45,109,74,152,12,180,133,37,235,27,89,233,50,120,180,89,4,98,239,123,125,154,75,21,208,74,202,196,65,198,23,29,165,72,150,55,52,25,116,91,169,240,234,135,5,154,214,40,63,239,60,38,24],[48,111,73,0,76,70,106,199,28,19,225,158,115,168,115,42,184,191,151,78,51,134,10,239,148,240,150,213,203,229,174,163,55,94,209,186,40,141,223,31,69,190,147,170,114,20,114,4,211,39,130,26,219,98,77,108,190,123,203,79,149,88,177,14,140,143,248,201,159,152,97,111,211,196,122,132,21,109,134,85,230,59,124,171,108,247,60,63,204,244,88,149,87,193,177,1],[176,130,246,95,191,138,116,197,40,37,202,27,91,171,135,3,136,208,204,152,31,153,225,226,12,8,105,9,238,84,191,227,51,150,82,42,120,84,102,189,75,13,192,201,181,195,121,25,46,73,160,143,207,130,48,174,49,15,220,127,42,219,118,49,218,216,119,112,198,133,150,28,252,120,254,73,141,80,104,106,222,242,182,158,234,222,201,105,117,198,157,136,3,37,105,19],[212,186,46,71,35,72,173,228,106,230,20,158,122,163,62,3,74,79,35,68,68,231,62,141,34,92,165,240,126,42,203,110,28,187,162,63,112,115,230,88,201,181,48,151,249,150,250,13,94,238,119,19,33,200,72,240,243,168,114,54,119,126,180,8,33,50,155,219,59,35,159,47,218,248,202,227,35,66,112,166,245,34,80,38,76,83,10,82,112,15,157,84,242,212,138,17],[159,200,105,15,144,14,5,178,179,202,147,4,173,173,211,55,174,24,115,170,71,132,218,36,148,91,141,203,46,213,161,53,67,23,198,5,95,108,172,40,109,34,230,126,45,206,211,13,173,115,220,68,42,48,205,102,125,168,35,18,132,91,72,175,235,10,156,8,74,100,81,246,101,166,231,181,197,121,87,222,26,52,144,216,246,114,236,15,89,58,56,132,164,143,2,13],[103,141,213,86,173,52,154,68,219,193,209,229,5,234,4,79,205,128,108,91,226,115,49,113,220,85,122,203,44,91,179,232,192,158,190,129,161,204,249,170,236,3,111,87,23,69,75,15,241,148,3,251,139,42,44,45,118,45,117,147,157,133,120,221,198,249,223,167,239,140,148,0,85,37,47,62,9,228,81,239,62,116,141,14,138,7,209,186,131,9,135,13,64,29,113,19],[243,192,60,172,90,51,11,48,216,107,163,185,114,62,63,230,65,76,39,169,183,79,59,93,170,144,169,1,63,221,124,251,103,236,70,211,169,4,103,140,7,210,68,28,218,71,5,15,172,21,120,217,2,107,94,161,135,143,231,79,199,78,30,12,71,221,33,197,117,226,251,49,212,139,236,45,130,176,57,33,130,146,21,139,113,234,71,91,199,7,53,58,43,192,25,7],[108,72,87,239,81,124,82,163,62,28,141,236,26,95,202,76,16,78,164,102,38,39,219,123,160,101,158,100,5,19,120,115,13,58,162,50,38,173,139,126,192,36,126,86,244,16,11,19,167,235,228,115,240,241,85,229,110,10,30,88,88,31,216,43,210,141,81,220,20,220,50,178,52,44,202,63,219,184,182,19,79,68,72,132,61,63,229,14,20,136,77,197,191,220,211,14],[170,189,172,93,251,234,1,180,169,118,234,225,122,195,231,123,212,190,56,168,107,6,204,134,149,55,18,136,81,127,160,31,33,82,202,202,41,81,48,99,116,224,109,3,142,162,160,7,183,229,196,248,66,62,206,249,87,16,60,247,51,149,23,192,209,79,42,158,227,118,104,19,255,157,63,155,145,140,211,246,73,2,185,121,9,107,17,47,222,73,47,14,255,150,181,18],[189,43,74,238,164,215,71,86,90,86,238,25,177,196,166,90,250,20,239,61,165,79,46,127,177,3,200,250,100,52,248,177,99,38,33,171,43,51,201,14,114,116,197,177,145,48,80,23,59,144,239,3,155,53,106,214,50,72,51,114,116,247,210,17,229,80,89,168,109,93,251,255,114,118,19,192,25,98,199,35,195,59,191,187,241,35,64,62,134,198,185,239,203,239,139,1],[6,19,181,242,186,21,24,182,217,60,19,64,74,203,132,249,137,166,250,143,3,210,25,27,3,181,127,129,64,70,226,63,223,88,206,246,26,242,82,177,78,130,171,219,114,214,255,21,106,120,138,143,127,117,114,57,227,138,238,114,125,241,55,227,75,16,249,26,102,60,250,26,123,184,143,125,77,65,119,52,157,59,52,12,23,118,56,59,124,127,183,180,174,194,94,10],[227,121,225,249,198,9,69,199,208,143,227,61,187,155,110,4,63,27,57,185,255,78,23,91,62,31,240,182,211,236,54,243,51,164,71,92,216,81,226,239,100,133,88,254,93,170,47,11,163,55,1,228,141,214,56,103,195,213,9,117,32,86,90,30,91,152,157,189,48,247,97,128,65,145,44,26,49,155,138,27,47,108,50,137,189,247,120,26,116,30,137,224,130,9,71,4],[250,129,12,248,135,157,57,146,245,233,124,153,217,197,173,96,232,153,184,148,151,147,14,229,160,20,251,31,218,32,176,37,18,120,113,144,35,71,77,224,220,215,247,195,181,217,203,0,146,252,58,248,184,224,195,82,73,111,199,15,204,108,43,165,37,137,112,69,119,137,205,204,199,54,46,24,212,149,231,213,39,163,190,56,154,200,38,146,89,147,112,18,89,45,79,19],[239,100,108,241,125,52,31,178,109,126,104,76,112,9,151,102,86,24,149,130,201,146,70,11,218,193,138,84,120,164,226,44,190,12,26,134,214,215,243,75,200,160,140,158,179,236,74,9,205,20,230,254,138,241,68,233,107,23,189,195,54,100,183,212,67,196,131,38,61,88,78,91,231,185,146,108,72,41,133,78,156,14,45,124,38,43,147,231,93,145,175,104,2,9,251,6],[253,211,38,182,159,85,154,12,178,178,235,209,161,12,186,140,159,223,116,15,164,205,149,34,182,140,88,66,84,90,1,254,220,158,168,38,112,231,88,103,93,161,190,197,114,6,16,8,105,112,109,200,195,69,60,181,249,242,241,221,13,228,206,109,224,63,113,147,255,105,86,33,121,0,52,186,196,3,237,16,83,162,196,248,190,133,0,164,29,253,182,62,243,142,197,9],[206,241,5,65,244,126,51,255,119,194,184,165,223,233,108,87,33,102,109,5,159,3,25,124,80,132,211,87,95,129,71,142,136,88,63,106,232,221,243,102,243,237,90,2,16,126,187,16,234,136,123,198,119,191,7,253,166,109,251,189,131,207,72,68,66,207,162,171,126,129,215,33,75,249,236,169,112,213,135,246,159,179,127,97,115,176,28,153,72,206,56,129,161,239,242,19],[170,246,166,105,139,183,178,13,179,223,20,137,209,172,157,135,132,134,137,74,215,97,135,118,110,167,60,253,251,89,242,42,224,248,20,143,151,56,109,162,132,182,92,206,175,150,85,9,199,240,254,89,152,150,221,106,123,107,80,6,248,206,103,54,46,95,127,121,86,217,43,117,82,85,173,130,128,64,255,163,36,158,122,127,46,87,255,50,79,71,33,246,190,212,205,3],[250,44,6,163,194,91,72,32,13,53,164,161,50,158,163,72,0,5,198,104,229,122,101,141,180,94,52,190,246,166,11,66,58,84,17,107,8,19,35,155,82,243,118,60,136,235,63,12,117,58,130,127,113,204,164,214,247,17,75,31,56,60,143,9,8,12,182,144,98,120,186,28,42,15,252,117,163,234,26,54,165,64,193,0,213,171,169,237,67,111,9,235,196,212,248,8],[83,66,62,107,126,19,65,105,109,103,177,44,110,39,97,106,221,128,128,67,62,247,239,67,29,188,63,17,53,91,97,63,144,9,248,202,56,153,221,4,16,146,182,33,37,214,240,6,52,153,13,0,216,84,12,112,246,151,18,86,175,222,78,201,129,215,247,104,10,253,38,238,6,63,24,125,128,193,158,105,174,160,116,122,211,222,39,188,234,204,17,242,35,224,156,17],[127,21,52,216,108,157,86,104,140,33,204,112,132,37,22,243,34,154,167,144,109,35,101,118,138,215,20,0,58,29,21,207,84,211,148,119,53,77,34,159,135,228,112,27,127,99,141,11,178,87,190,77,139,93,6,45,170,247,91,90,219,168,76,230,82,20,133,203,137,136,44,95,17,133,3,119,248,42,92,150,135,140,81,67,129,92,221,18,138,163,82,118,225,95,193,5],[61,0,209,222,216,50,141,105,211,247,144,46,19,11,187,77,96,226,104,245,48,173,198,50,199,115,237,128,178,131,108,181,71,213,0,109,145,93,119,232,243,57,55,29,14,214,8,5,130,107,220,49,207,180,184,116,28,255,78,120,214,240,27,18,169,244,223,89,71,40,173,207,195,228,195,48,238,45,249,234,196,51,29,106,77,244,174,240,201,33,236,233,253,14,206,25],[39,56,206,152,237,232,108,67,98,200,76,150,156,237,8,1,124,210,27,253,15,210,136,166,168,76,53,184,198,235,177,183,105,128,239,240,81,67,2,184,183,52,246,200,158,154,164,1,92,61,120,93,31,115,205,179,141,221,149,135,42,250,98,17,213,228,164,18,172,223,8,203,158,10,158,54,196,231,32,29,176,220,106,222,124,66,101,250,212,78,217,245,197,21,90,16],[213,214,189,41,216,102,86,211,218,10,250,155,174,140,69,245,113,251,130,21,173,130,3,169,92,202,123,120,141,96,74,104,105,53,106,76,171,67,11,255,197,153,188,153,195,220,118,9,95,90,152,127,252,107,25,234,11,34,111,218,223,193,53,179,121,57,149,156,211,162,37,237,179,142,95,161,57,135,166,47,45,235,135,136,192,77,235,187,81,150,81,85,178,22,46,18],[64,0,140,86,29,149,63,221,118,11,88,117,187,165,93,17,208,243,235,185,123,158,96,68,14,70,74,132,245,235,112,49,216,5,80,72,222,64,191,139,58,41,23,251,225,202,12,2,77,242,201,231,117,169,11,128,165,163,158,149,90,220,47,66,241,96,47,137,52,43,136,136,222,170,144,247,116,73,220,243,218,71,153,9,223,85,63,169,32,59,211,220,139,191,58,17],[221,167,165,25,6,116,113,167,202,84,26,92,253,86,248,226,227,147,151,132,110,99,26,172,201,115,189,124,24,203,99,185,185,104,193,47,224,60,248,140,124,229,150,158,245,74,141,11,53,61,141,201,109,123,208,184,91,65,165,134,119,180,89,131,119,133,254,90,137,78,179,15,182,65,185,8,172,4,131,232,223,136,158,154,91,244,62,152,95,250,84,31,29,252,242,22],[116,17,36,180,107,224,143,28,94,195,254,250,117,221,253,55,129,105,206,174,138,22,22,76,46,76,86,181,125,157,214,196,74,130,221,159,13,130,230,140,150,127,118,184,195,168,241,0,214,193,43,10,22,1,92,159,251,84,113,252,26,122,94,108,207,152,185,102,208,116,177,95,246,21,175,182,39,28,63,61,59,80,179,85,104,77,243,217,151,249,71,24,10,186,207,20],[9,85,151,230,122,119,90,122,95,25,59,29,215,208,221,161,225,208,3,57,201,179,28,168,187,133,62,151,201,226,228,127,216,50,65,45,149,88,178,77,246,98,112,98,46,190,20,0,234,130,246,112,135,197,112,129,147,111,34,210,212,5,43,15,50,138,109,17,225,153,121,154,180,127,193,49,94,139,188,177,166,20,49,198,118,68,46,208,228,170,70,129,226,186,188,21],[45,91,115,41,170,86,160,234,217,173,62,130,195,123,93,186,218,158,211,77,246,188,108,195,195,83,71,207,46,89,1,36,218,109,18,38,207,38,193,177,179,116,26,95,174,65,246,2,172,176,151,50,94,13,213,53,230,176,19,226,191,45,171,86,89,242,171,249,165,82,151,28,200,222,216,44,22,3,127,247,86,182,171,24,97,237,178,120,85,57,107,132,192,125,237,13],[44,18,233,253,69,219,247,160,97,36,253,119,168,241,133,61,29,177,145,250,224,18,94,190,76,117,8,169,153,137,218,152,248,164,221,187,237,210,205,178,225,233,123,191,240,3,166,8,196,242,189,166,184,89,230,173,206,182,88,248,19,225,98,81,250,29,43,97,107,159,236,234,32,238,136,11,0,147,120,16,55,17,196,2,53,40,27,136,163,141,96,0,161,250,66,15],[242,88,156,188,3,79,153,45,68,32,56,184,133,118,209,93,122,127,141,134,200,221,121,188,108,141,152,42,222,250,233,68,12,209,4,23,66,218,145,113,240,160,226,84,28,175,11,21,125,26,51,37,12,255,61,1,195,199,210,103,14,245,42,136,148,36,160,36,81,74,153,70,178,88,148,78,65,191,22,72,157,195,103,45,9,38,71,84,38,159,196,120,204,153,57,16],[21,232,198,183,122,173,61,155,170,83,237,157,21,70,225,57,130,191,242,157,108,140,244,125,224,137,240,121,108,254,168,80,0,237,55,9,36,241,102,42,214,18,26,95,101,132,101,16,81,59,115,118,66,31,91,151,244,209,33,246,249,53,96,9,238,231,123,224,216,207,203,241,212,155,117,214,87,170,65,128,65,212,176,179,41,125,154,24,15,7,240,14,236,5,6,20],[111,7,227,16,126,10,212,35,161,140,96,42,149,226,39,196,210,60,89,51,144,119,146,113,222,64,182,195,120,90,141,26,28,6,17,155,223,240,127,211,34,14,126,22,137,13,109,13,154,58,146,245,39,160,162,54,248,245,40,147,221,103,73,10,172,61,66,80,239,133,169,220,19,183,67,83,193,87,62,143,86,142,70,255,207,195,216,229,151,204,228,168,216,164,230,22],[146,166,240,209,81,56,16,34,84,14,67,119,75,249,23,20,92,26,108,166,246,203,139,135,180,192,122,209,197,83,147,222,228,49,170,129,153,29,113,132,39,14,49,82,235,110,214,15,134,161,109,9,236,226,163,137,107,194,74,57,48,78,147,136,52,135,250,87,167,229,66,155,193,29,53,34,249,212,229,215,133,246,56,109,119,110,132,168,247,11,178,230,219,26,103,21],[4,193,214,61,161,76,143,243,42,124,139,72,121,102,118,132,194,158,45,52,46,225,245,213,123,168,92,233,17,87,185,156,132,48,133,71,242,2,110,16,207,237,125,151,179,214,85,18,190,89,99,245,124,71,212,70,174,47,67,36,218,3,227,75,121,226,56,173,218,122,46,196,3,98,80,47,138,251,118,153,81,62,206,119,112,106,123,147,28,108,55,69,47,137,84,5],[72,17,168,203,75,179,26,79,77,12,37,105,63,253,18,172,227,156,174,136,163,97,225,249,21,173,119,70,140,189,111,66,185,115,182,7,59,120,84,97,88,145,186,130,160,225,22,20,224,254,232,90,111,118,127,101,86,246,146,78,220,159,33,253,122,198,109,84,79,152,62,255,6,119,131,20,2,67,31,130,221,139,205,88,5,170,218,141,117,109,47,162,207,131,96,11],[152,128,178,225,90,212,101,8,143,22,35,237,182,45,141,126,56,251,208,74,18,249,207,220,180,139,230,72,155,130,75,139,189,0,51,78,57,150,7,130,52,20,210,253,118,227,246,22,85,145,126,128,53,91,67,69,195,56,223,206,146,239,185,145,249,230,236,241,162,68,34,201,127,56,190,179,35,175,7,208,184,2,40,221,37,108,248,197,135,190,98,252,51,221,20,8],[118,125,122,110,209,128,168,53,184,184,209,209,181,236,191,177,161,173,75,113,152,50,51,215,199,0,124,4,189,223,42,79,183,229,161,234,252,200,150,188,129,5,224,231,17,71,215,3,126,11,55,110,14,242,10,251,186,40,204,58,19,47,241,50,103,220,74,213,124,183,0,58,31,97,96,84,34,192,100,14,103,114,25,237,204,132,148,172,219,255,204,142,137,120,83,0],[72,248,58,174,153,68,43,62,127,141,186,50,233,109,198,7,135,100,98,82,67,41,50,136,32,212,38,197,107,39,148,74,79,174,0,219,244,218,117,177,121,123,214,110,4,81,86,22,85,89,241,152,146,237,79,13,26,89,59,28,255,193,176,239,221,103,218,30,248,233,160,224,248,48,73,147,156,197,177,138,124,55,119,207,2,230,22,208,100,132,18,165,7,88,187,1],[102,5,163,216,194,161,232,212,109,162,23,11,245,208,223,113,175,31,174,169,83,100,19,150,122,230,212,164,203,159,186,192,114,209,185,46,235,237,43,134,228,219,110,138,124,75,125,8,30,53,208,166,56,51,133,152,178,184,44,254,223,240,19,252,60,232,61,19,100,179,43,69,108,21,24,10,93,176,3,129,97,91,205,108,145,55,60,10,125,174,115,126,103,180,72,20],[169,193,112,196,184,47,97,125,58,19,221,161,15,206,166,77,182,156,17,214,245,156,28,199,65,16,100,137,15,37,95,219,248,61,47,211,94,4,39,92,234,131,172,170,184,69,223,1,97,188,126,97,238,38,130,160,247,65,132,188,137,61,118,62,24,86,167,98,228,26,252,194,235,123,236,104,238,68,174,244,11,98,234,203,65,90,89,159,35,64,17,222,236,13,152,3],[184,208,155,245,182,73,67,65,112,156,239,107,167,107,254,205,226,212,45,10,7,35,207,124,85,210,190,238,143,159,175,98,181,183,8,223,135,20,5,141,252,142,77,69,116,71,14,20,214,31,19,197,210,46,6,36,92,194,41,44,236,182,170,195,62,255,91,38,37,182,236,131,114,101,150,182,47,191,236,4,49,179,143,2,223,188,36,234,75,133,43,26,210,127,137,7],[203,126,121,64,251,213,177,81,35,114,38,219,86,190,207,74,151,187,233,1,67,73,232,93,129,122,158,33,140,152,212,213,219,192,28,43,86,65,208,173,55,74,152,244,211,145,191,24,78,47,87,177,151,137,148,57,156,43,133,218,189,148,76,238,64,120,244,91,158,120,211,90,179,186,5,209,153,7,202,40,12,201,108,197,97,89,29,170,117,70,130,163,206,234,137,2],[172,82,72,202,29,45,88,186,243,219,96,205,234,233,170,161,111,139,148,71,141,31,141,71,84,229,124,70,159,46,139,117,195,43,169,88,163,233,74,45,78,202,161,9,205,43,47,11,169,1,221,74,122,110,69,156,56,234,250,78,151,32,188,97,206,68,207,242,86,149,133,60,11,187,76,154,140,179,105,74,129,8,11,126,255,76,232,140,19,59,85,250,177,169,230,11],[156,163,94,205,1,34,241,7,117,250,92,170,103,2,48,234,76,115,253,112,77,216,99,185,190,36,169,84,122,137,189,156,40,67,232,255,83,78,96,58,161,243,57,60,42,74,177,14,77,221,31,197,240,110,17,55,177,22,139,186,59,84,126,32,48,174,51,181,14,174,83,23,205,2,209,181,80,234,201,108,180,20,19,24,123,165,135,84,81,169,167,1,69,217,21,4],[250,231,203,241,112,213,97,246,70,79,57,85,220,87,247,176,24,53,115,23,233,35,13,139,168,81,37,226,2,126,223,125,125,148,231,193,82,244,170,61,144,155,217,105,213,37,200,21,220,130,5,19,183,226,244,219,36,115,158,7,14,199,156,53,125,80,66,18,172,158,121,121,39,216,71,177,188,27,48,146,20,107,36,176,33,186,41,4,186,94,46,253,4,117,17,7],[249,86,66,207,29,170,248,212,121,173,102,157,229,53,32,72,36,108,151,75,168,68,211,111,163,148,40,217,168,44,55,97,74,160,205,64,140,230,241,212,162,116,90,242,206,209,175,12,168,57,250,250,169,218,102,191,64,186,194,123,94,150,79,19,100,182,128,45,29,68,49,71,90,201,197,243,248,34,54,141,186,93,88,52,15,184,21,128,201,47,109,250,50,113,8,12],[226,182,44,161,101,190,194,120,181,68,173,61,197,249,243,140,196,191,117,17,39,49,156,216,178,187,86,143,247,27,121,56,173,173,194,22,14,18,135,51,22,128,109,179,123,87,63,0,182,32,43,93,141,114,7,55,195,94,92,31,142,156,215,41,99,155,80,207,201,182,191,190,108,127,92,100,137,198,103,136,172,25,148,242,164,16,53,247,18,116,192,67,199,153,240,23],[198,243,201,112,35,64,115,118,91,113,169,255,126,179,206,228,35,172,15,73,120,134,36,239,232,89,168,254,154,178,215,69,74,157,175,120,166,61,1,67,216,114,117,23,169,113,133,5,158,199,232,10,152,169,167,127,143,39,54,141,65,13,79,33,70,57,66,34,188,241,214,68,117,60,152,199,141,127,179,250,214,166,50,97,123,27,142,101,66,117,111,217,174,71,29,14],[30,10,83,107,224,17,229,17,149,46,117,54,1,155,86,247,188,189,191,222,135,116,148,246,75,149,58,176,60,104,168,0,223,77,249,187,216,252,7,146,43,208,218,123,249,218,212,16,173,122,241,136,113,17,129,12,69,7,157,185,226,59,141,220,96,233,182,180,122,26,77,121,179,41,49,30,191,33,117,70,221,75,209,99,45,106,143,111,100,148,208,109,101,23,166,13],[129,135,218,87,224,234,125,179,111,10,38,38,21,135,78,40,85,144,240,146,54,239,16,13,51,214,45,240,253,84,224,228,15,65,106,168,181,117,132,51,255,65,191,255,211,187,22,2,90,138,242,46,41,12,51,243,66,240,95,49,30,255,22,157,252,44,9,48,46,37,12,253,142,184,110,175,126,26,181,126,116,225,187,140,171,236,51,171,105,155,85,175,90,176,138,11],[54,11,18,212,193,139,61,95,176,123,172,71,126,244,138,30,109,18,16,10,159,1,222,81,62,170,96,81,157,180,184,209,96,76,241,121,198,222,174,20,124,218,243,164,162,170,9,16,126,153,226,180,15,135,209,160,162,147,153,168,3,124,251,58,140,255,100,15,3,155,200,104,58,8,130,113,245,222,223,6,8,18,222,20,204,127,57,35,46,223,249,91,119,52,57,21],[65,100,93,218,116,111,36,105,245,247,197,190,240,206,49,224,24,32,222,98,35,70,24,145,221,45,19,170,170,201,191,76,42,138,233,10,149,11,57,183,165,107,34,3,221,33,178,24,72,60,83,241,100,11,63,29,8,47,140,177,253,42,242,37,92,236,245,56,189,47,16,6,187,249,198,108,119,86,148,222,61,207,164,243,18,51,225,250,125,145,174,85,234,182,156,25],[181,15,97,201,135,20,36,162,92,51,94,88,54,27,62,47,226,70,128,46,33,81,114,36,254,31,143,218,172,122,144,7,239,67,145,0,102,28,180,45,94,89,229,163,81,173,33,19,35,89,216,195,214,223,190,172,47,229,164,43,230,35,102,203,137,112,246,208,145,21,90,66,203,130,248,117,143,184,115,207,117,225,238,247,218,34,179,191,67,196,74,74,169,101,132,6],[252,153,196,138,70,122,0,135,232,232,123,203,66,137,84,24,46,138,42,252,94,220,170,92,149,59,171,44,237,46,136,177,68,74,96,222,116,241,56,9,39,227,56,73,160,55,155,5,113,221,101,65,53,226,108,232,105,235,149,109,160,72,145,27,44,142,48,212,251,14,200,40,87,181,55,137,99,200,144,163,6,118,251,210,118,133,102,252,190,133,43,138,119,151,187,9],[15,108,31,94,39,48,183,62,125,86,26,172,144,115,195,108,228,229,21,93,50,27,110,6,85,62,187,198,27,24,13,97,62,230,239,139,213,68,254,154,68,167,159,242,205,158,33,22,69,133,244,252,81,104,161,145,202,245,174,179,73,241,152,144,197,90,230,122,177,140,58,28,202,101,230,80,71,235,94,98,204,242,127,64,211,36,19,229,157,130,48,198,0,246,157,16],[160,69,160,172,130,147,209,99,73,88,20,170,99,140,48,83,134,29,98,168,111,221,174,210,146,44,150,3,109,156,111,20,214,83,19,52,236,61,173,222,247,255,45,168,34,218,68,9,146,221,164,53,16,60,230,205,121,190,161,62,104,109,130,240,154,194,197,126,230,47,40,72,222,125,207,202,209,153,243,103,2,187,178,186,33,160,166,106,186,186,88,24,253,117,53,20],[202,171,41,132,246,35,249,189,134,157,90,198,105,122,200,7,36,87,108,18,54,254,123,159,54,141,30,73,9,98,12,91,228,145,125,134,87,98,202,101,189,143,12,38,204,79,139,0,147,242,110,83,46,121,43,156,29,62,116,143,97,223,37,131,246,207,97,195,64,190,37,167,236,244,180,250,51,178,87,100,103,108,110,137,51,88,23,211,71,62,210,35,184,255,64,20],[240,178,181,227,75,190,232,243,172,106,247,133,245,122,214,221,118,146,64,162,110,191,197,14,70,1,165,175,201,187,158,174,67,34,159,59,250,26,231,216,53,65,164,244,228,3,123,18,191,79,88,97,56,238,208,210,73,233,146,49,33,87,19,199,233,22,97,85,146,108,151,169,49,167,132,143,204,68,30,1,43,179,235,225,93,152,232,228,22,6,80,180,144,192,202,23],[227,165,247,107,103,91,57,206,161,190,130,116,87,214,109,66,117,43,14,38,65,127,27,87,1,192,15,203,60,27,47,129,172,26,33,10,138,75,69,149,161,107,191,140,91,135,234,15,115,12,59,158,166,101,100,165,246,41,55,94,150,124,138,27,167,171,169,68,253,85,138,20,1,166,132,0,16,92,20,4,92,85,109,41,182,248,221,142,39,232,242,196,148,163,35,7],[53,229,135,71,166,180,85,44,53,222,97,173,247,2,149,145,64,185,61,67,242,115,139,184,78,34,178,23,125,194,133,48,29,22,134,63,15,7,96,108,35,68,117,41,70,244,220,23,255,192,207,86,10,234,109,14,72,218,121,61,254,153,154,43,212,175,6,194,188,137,238,125,29,34,245,187,239,118,184,3,35,46,180,235,62,73,183,107,139,245,126,238,197,63,91,21],[24,238,210,119,63,87,186,39,72,4,126,115,190,96,20,4,159,177,94,176,228,166,223,118,92,116,8,2,70,152,49,228,173,60,32,254,93,36,128,123,159,48,61,229,192,27,130,1,147,193,28,195,4,208,210,151,115,253,112,11,138,71,132,67,215,96,83,235,47,105,145,0,209,248,74,140,196,29,50,113,98,235,203,69,30,157,212,116,216,155,150,118,122,249,56,25],[143,103,171,52,37,225,80,192,57,24,146,203,163,54,41,216,106,28,245,159,143,32,77,208,217,83,123,185,34,47,179,63,190,80,234,196,171,152,122,207,190,51,186,239,228,50,149,10,5,123,218,126,32,15,186,113,116,40,75,120,138,12,133,47,116,193,191,112,221,124,226,154,21,215,198,195,16,120,164,255,189,236,131,8,205,79,233,220,220,166,51,202,87,127,109,12],[12,238,142,164,238,123,210,241,7,20,42,5,126,1,144,71,192,99,160,143,1,21,215,207,177,89,167,49,145,85,75,227,56,246,20,50,173,13,121,183,151,246,87,200,185,221,135,10,191,34,170,160,181,88,190,146,213,173,176,57,200,189,66,216,214,212,137,46,190,189,163,236,133,199,115,239,32,13,93,87,115,198,191,69,33,24,72,111,172,159,95,94,1,95,29,25],[133,86,138,43,140,194,204,232,234,249,206,238,248,149,125,43,19,203,132,202,152,218,221,159,34,142,78,13,22,164,202,179,140,69,210,217,247,235,158,159,43,100,64,249,212,91,68,8,193,128,18,103,187,51,129,53,211,35,92,183,122,49,205,93,119,151,149,75,125,250,188,105,42,129,144,41,224,32,99,42,206,45,84,28,117,216,95,46,201,132,34,29,149,5,76,6],[124,83,78,229,158,55,61,106,232,172,109,26,206,22,235,93,2,34,121,144,16,84,153,95,35,206,97,213,250,117,25,64,215,27,182,129,250,150,134,221,0,151,160,155,46,157,177,16,168,230,26,248,22,106,165,82,217,154,247,206,88,37,147,245,107,238,77,138,32,90,192,235,209,147,3,207,48,152,187,140,137,126,211,25,82,38,41,118,5,47,161,72,69,112,137,9],[52,157,207,232,35,62,176,206,184,164,176,86,234,209,139,201,32,1,156,208,253,143,103,62,149,92,24,69,71,188,149,158,105,4,1,36,149,187,98,84,72,192,120,14,200,143,174,1,80,201,192,163,6,198,95,112,195,100,2,51,173,182,87,101,79,81,246,86,3,39,148,151,5,142,135,91,125,241,243,85,139,38,96,20,154,141,206,102,58,18,36,175,105,218,192,22],[150,66,217,93,51,68,140,168,19,216,10,140,254,198,143,24,16,21,67,112,11,185,114,236,6,72,82,5,37,25,216,88,234,219,13,222,9,137,73,210,10,250,39,198,101,181,166,11,98,10,21,23,142,87,117,70,179,195,148,89,204,152,180,194,118,63,214,2,4,230,73,170,28,55,115,48,242,204,27,187,189,41,212,15,128,101,139,180,240,214,35,108,168,163,242,8],[78,0,3,186,162,2,151,86,20,36,221,18,94,199,85,161,118,77,79,189,120,52,110,112,71,90,44,190,243,33,239,108,113,56,36,93,186,58,107,80,97,8,152,145,164,80,97,9,233,249,122,218,22,115,12,42,158,96,233,39,37,222,85,35,91,121,99,65,93,6,90,63,158,135,229,148,150,120,164,103,205,254,19,120,246,55,108,54,12,246,105,167,31,157,108,21],[120,211,227,243,130,150,14,200,127,243,152,144,195,36,11,87,59,145,56,83,108,102,151,253,150,101,152,194,52,179,176,34,46,62,3,186,0,49,8,54,186,2,54,176,66,152,70,25,65,55,233,44,87,172,228,159,159,22,213,35,239,146,121,133,156,212,186,142,23,182,228,221,104,145,31,209,235,187,85,99,111,203,12,90,209,240,203,210,120,84,201,98,252,40,84,13],[153,136,230,85,8,82,90,194,129,63,14,139,42,84,20,218,130,109,143,255,110,1,186,47,38,194,100,155,63,25,210,88,179,209,219,83,13,242,132,26,230,242,156,181,155,233,101,5,99,73,147,155,204,205,220,150,164,64,151,255,250,179,212,255,248,98,50,133,164,132,113,95,211,189,40,216,60,154,62,10,100,12,88,157,67,11,41,130,254,240,45,191,32,169,108,8]],"pariticipation_bits":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],"attested_header":{"slot":"32","proposer_index":"0","parent_root":"0x0000000000000000000000000000000000000000000000000000000000000000","state_root":"0xe68b17f8e98f4b3b94aba19c39b19c672fd2a17652ee4e8648ceb8881b70c399","body_root":"0xcfc05f337393c3a62425aa3a1fb3b7113c5da404d6a7f89edd41bfb5e14a5e92"},"finalized_header":{"slot":"0","proposer_index":"0","parent_root":"0x0000000000000000000000000000000000000000000000000000000000000000","state_root":"0x0000000000000000000000000000000000000000000000000000000000000000","body_root":"0x1e10d615015401a475217be60cd4f0f53e510b12173f48039d852e5022981639"},"finality_branch":[[235,99,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[61,75,229,208,25,186,21,234,62,243,4,168,59,138,6,127,46,121,244,106,63,172,128,105,48,106,108,129,74,10,53,235],[245,231,188,71,118,237,220,99,117,107,215,179,149,131,24,141,94,92,179,5,43,0,98,135,125,224,240,153,169,38,103,30],[110,211,142,94,6,128,7,99,93,122,179,185,34,100,118,177,122,81,82,200,22,17,180,0,237,192,18,14,240,147,108,131],[155,36,233,182,3,218,183,52,31,229,11,170,186,135,40,250,236,16,108,30,173,17,32,146,190,16,108,215,239,76,73,95],[253,111,231,138,179,250,203,151,251,234,163,160,110,138,90,87,8,77,145,188,106,199,46,50,165,228,189,28,154,12,26,169]],"execution_payload_branch":[[66,176,82,84,29,206,69,85,125,131,211,70,52,164,90,86,210,22,212,55,94,90,149,132,246,68,92,228,230,51,36,175],[51,100,136,3,63,229,243,239,76,204,18,175,7,185,55,11,146,229,83,227,94,203,74,51,122,27,28,14,74,254,30,14],[219,86,17,78,0,253,212,193,248,92,137,43,243,90,201,168,146,137,170,236,177,235,208,169,108,222,96,106,116,139,93,113],[156,200,108,117,214,234,134,249,66,137,170,240,18,207,96,236,49,180,252,246,212,177,241,162,156,106,55,243,83,138,77,132]],"execution_payload_root":[248,214,204,83,123,89,238,36,211,105,76,76,135,239,192,98,48,143,66,207,58,182,74,167,199,24,117,135,7,66,1,254],"domain":[7,0,0,0,48,83,175,74,95,250,246,166,104,40,151,228,42,212,194,8,48,56,232,147,61,9,41,204,88,234,56,134]} \ No newline at end of file +{"signature_compressed":[183,172,229,233,97,99,214,180,185,192,151,68,34,84,126,96,96,108,121,18,147,229,200,183,206,9,56,212,116,141,44,49,80,153,24,181,42,78,30,173,37,75,33,160,107,42,15,199,12,89,186,229,246,166,89,193,233,120,231,193,193,211,28,247,180,102,206,31,166,43,201,190,99,168,34,57,104,172,241,177,144,45,104,241,67,240,8,50,225,162,207,234,199,77,65,22],"pubkeys_uncompressed":[[2,28,98,160,223,223,232,155,95,169,36,213,77,46,193,37,82,170,83,121,106,183,220,152,79,168,33,159,112,66,212,99,52,177,95,178,240,198,228,9,91,138,30,47,229,81,241,245,10,144,215,167,99,41,216,49,118,17,76,129,180,96,222,57,153,35,179,203,155,60,16,32,184,202,34,129,99,197,214,42,87,112,115,178,208,71,139,95,114,206,220,122,23,234,173,82],[6,202,167,69,210,146,194,78,172,205,30,136,1,157,20,74,49,40,131,41,5,87,20,150,171,160,162,101,73,127,139,71,70,54,165,113,231,1,225,131,115,234,240,149,53,219,222,8,12,147,77,189,119,189,147,113,130,45,70,53,80,28,195,127,76,164,42,112,131,75,162,143,10,87,220,79,206,117,58,158,181,254,43,116,201,78,49,231,185,240,195,172,216,211,153,79],[24,254,136,66,172,54,205,127,249,123,23,106,90,5,15,139,41,26,19,123,11,165,224,85,197,201,201,247,103,223,42,27,172,186,219,174,174,125,174,136,118,21,64,62,207,238,86,192,11,182,32,59,12,181,142,204,2,181,179,10,5,240,36,73,107,249,228,113,56,94,108,7,51,154,145,126,4,225,221,46,61,115,182,46,211,61,42,62,61,53,69,102,155,69,177,33],[8,250,70,159,17,111,22,45,50,52,8,56,19,10,16,71,98,68,159,173,6,214,239,226,21,198,148,165,206,123,141,28,157,236,111,51,239,141,20,126,171,179,99,133,107,135,72,18,22,160,251,225,33,206,167,14,76,202,130,147,75,58,143,120,101,166,87,205,187,169,239,209,208,101,40,81,223,243,201,243,71,210,47,55,127,11,29,21,169,42,172,2,218,31,139,246],[17,102,110,227,41,1,60,137,200,7,127,243,204,5,230,182,123,34,8,236,152,155,65,42,207,99,21,78,107,124,37,213,185,27,83,205,21,156,35,90,231,209,167,70,214,132,154,162,5,122,87,54,37,143,176,38,22,131,57,234,119,78,254,163,58,34,7,62,31,159,114,66,102,62,132,254,130,106,42,227,85,106,68,120,99,38,30,23,62,35,39,203,86,101,135,227],[0,71,99,191,238,204,157,32,38,51,234,238,4,198,124,166,132,22,68,141,46,129,179,187,88,225,4,147,84,86,76,14,113,28,124,150,179,105,107,113,174,175,124,29,247,218,207,87,1,157,180,62,105,149,241,195,211,189,150,148,1,55,166,112,79,6,47,158,22,49,242,99,113,150,68,8,188,175,23,81,243,0,152,127,120,35,197,112,223,15,28,179,227,174,114,186],[7,113,155,26,245,111,65,85,246,252,129,241,199,221,39,231,86,69,50,150,30,28,54,145,198,41,70,128,100,219,158,116,37,4,34,176,158,177,52,218,146,50,202,217,36,63,86,82,21,44,110,9,240,215,171,42,31,106,3,32,109,84,116,183,144,16,11,11,91,127,172,62,253,134,48,155,182,79,218,81,94,70,208,15,223,16,202,198,237,96,70,176,20,183,132,76],[21,64,105,160,57,113,59,244,71,191,33,10,241,29,123,72,94,185,69,95,218,150,57,213,127,152,211,6,197,197,29,15,225,230,172,228,34,172,245,234,101,77,164,174,182,71,112,238,21,191,145,138,8,188,197,45,29,3,87,221,130,118,58,185,121,30,156,255,236,86,238,64,183,29,191,203,123,189,211,3,8,47,76,141,11,173,227,104,171,119,197,47,223,46,216,89],[21,6,94,32,197,70,193,37,9,60,45,157,111,88,25,203,110,250,109,47,8,39,108,175,87,83,209,30,119,28,197,101,56,68,12,246,118,234,190,96,215,225,46,179,234,83,243,178,10,221,166,116,46,57,93,212,141,55,125,43,180,118,80,218,219,172,6,4,43,201,66,123,197,113,153,38,90,176,37,255,207,168,195,161,95,138,182,124,110,225,154,238,107,179,188,99],[10,190,24,80,2,87,114,37,110,124,239,49,51,1,65,147,193,252,43,188,144,124,165,78,98,167,152,224,11,227,237,61,25,198,131,220,101,100,246,30,13,129,98,194,88,253,155,225,17,97,31,130,75,181,167,205,99,248,86,191,141,197,215,118,23,65,132,41,187,103,16,246,237,89,2,14,109,122,105,61,112,64,70,176,109,190,235,14,134,184,230,105,111,186,131,202],[11,227,243,235,103,106,100,242,176,143,125,246,156,114,126,254,131,126,40,81,11,46,214,23,211,120,67,7,206,38,61,90,255,154,89,219,3,238,134,25,99,1,184,104,1,178,135,168,22,28,172,75,189,99,131,142,49,115,85,120,167,244,151,184,211,179,1,218,222,222,187,108,219,6,188,56,138,216,216,89,211,148,173,157,102,62,37,174,227,147,70,130,97,253,195,231],[10,116,206,213,225,95,190,128,10,192,56,121,236,67,207,251,119,189,193,30,17,245,141,249,137,237,114,120,247,35,147,21,235,14,157,17,153,109,96,71,165,36,196,127,162,153,216,12,5,229,143,103,188,128,16,107,43,128,119,91,83,114,139,135,44,158,180,3,100,167,65,7,113,231,106,42,109,41,116,68,13,171,141,15,110,113,39,34,80,182,140,191,41,76,64,32],[15,45,71,37,17,222,4,18,231,183,150,73,27,230,165,170,94,40,4,76,109,84,122,61,197,19,41,143,205,157,34,221,6,210,174,5,226,28,33,34,241,223,200,188,239,57,30,246,3,246,43,157,214,233,117,18,56,246,50,4,78,133,109,45,225,61,146,0,101,22,40,53,61,16,216,45,195,118,233,47,249,128,128,173,19,232,39,200,42,235,201,206,232,15,105,190],[8,136,125,187,33,35,174,99,250,79,98,75,199,248,83,164,22,115,149,38,232,6,152,43,145,164,39,143,74,151,70,165,206,84,223,175,165,36,192,107,189,11,247,18,60,169,66,58,20,246,107,236,164,50,79,147,194,129,177,149,53,242,247,190,28,140,56,243,204,46,99,74,11,14,177,62,254,163,111,143,120,188,99,14,254,87,119,239,139,52,106,109,178,124,188,54],[25,172,78,48,15,201,208,18,40,145,86,118,83,163,238,108,5,144,114,67,57,52,146,25,62,65,109,140,238,72,204,67,154,143,137,215,40,156,127,96,200,193,209,82,46,59,35,142,12,172,24,100,188,82,21,105,142,236,52,236,85,218,33,220,37,52,51,146,206,121,248,101,75,181,69,161,108,26,227,63,225,44,40,159,50,166,189,109,207,4,80,183,46,88,224,127],[12,255,49,184,221,183,179,217,114,90,161,138,48,183,183,26,3,86,50,115,126,122,31,50,142,102,149,210,87,11,226,213,236,68,187,156,189,240,197,204,141,106,120,10,221,71,76,182,3,11,138,125,248,67,250,120,152,144,34,88,250,178,227,42,73,1,26,52,168,209,127,177,79,222,137,118,48,29,186,251,217,76,77,91,204,39,138,42,9,41,177,103,224,16,40,34],[11,35,231,22,124,2,218,147,176,30,53,127,76,140,115,166,245,7,81,220,141,30,243,14,100,68,191,70,127,49,175,177,118,221,68,131,135,50,160,19,209,24,223,80,52,120,138,137,18,240,93,67,101,111,229,174,148,218,157,41,68,33,215,141,232,111,139,224,200,146,43,155,151,255,132,52,129,183,140,251,53,212,96,169,191,229,128,101,96,156,177,113,166,59,29,237],[15,121,19,154,115,72,97,62,95,223,204,139,231,205,2,77,46,177,17,215,151,152,60,245,63,3,142,79,201,133,155,119,221,135,244,162,1,245,105,167,247,240,75,171,223,141,202,91,25,2,203,167,12,90,89,114,208,79,152,117,232,178,243,253,158,218,198,188,252,28,117,179,171,185,167,30,120,120,5,133,119,159,145,89,154,212,245,185,176,38,54,92,123,41,6,132],[3,215,60,77,34,243,72,189,163,0,204,255,76,142,194,237,229,108,112,226,223,209,227,50,25,147,137,130,53,72,84,123,216,237,183,231,81,163,144,177,111,50,180,106,110,199,58,201,5,59,61,183,139,47,61,145,71,60,1,38,185,125,226,101,255,77,127,5,157,71,111,149,245,98,173,109,203,159,28,80,223,140,165,82,154,93,186,145,242,98,64,180,19,15,198,80],[11,72,2,117,255,95,49,16,89,110,28,242,241,237,175,240,95,197,189,210,3,8,119,132,159,105,135,203,185,76,167,241,240,7,88,247,222,36,27,99,140,110,89,12,223,157,29,24,25,235,105,119,207,202,59,254,104,47,194,11,60,120,112,4,141,64,198,148,181,145,177,17,25,88,29,169,239,223,94,155,245,235,47,105,88,18,169,143,246,10,205,44,189,23,184,93],[3,99,68,214,130,116,57,122,103,23,213,1,202,57,65,12,18,173,233,153,231,215,174,200,182,159,130,89,19,240,10,168,89,105,16,250,112,26,60,43,53,61,142,221,76,226,124,244,17,7,221,91,204,136,104,252,117,47,255,61,112,190,65,151,77,234,163,53,13,20,68,58,145,193,142,14,233,198,172,73,109,82,51,44,180,228,249,156,111,46,75,0,12,33,229,230],[17,205,42,14,167,49,33,139,69,43,113,121,87,137,86,147,229,201,1,60,61,170,2,85,84,226,102,181,106,19,221,50,137,239,246,17,207,97,228,48,22,139,208,56,92,203,243,58,0,168,159,142,254,66,101,154,112,61,190,29,219,133,86,89,135,60,163,1,141,40,156,8,107,156,178,30,87,10,232,84,65,100,97,180,38,225,96,31,253,150,145,0,211,236,102,6],[24,204,90,199,137,15,156,168,84,60,33,233,38,137,132,252,93,19,186,247,203,183,60,17,147,226,20,139,202,44,70,187,17,230,8,229,124,221,83,71,70,32,237,39,155,102,173,133,11,34,127,130,133,43,208,83,222,248,54,73,213,240,35,240,103,118,255,190,120,78,11,228,173,4,98,237,102,56,1,109,192,11,36,61,36,21,150,147,244,38,51,207,245,136,180,29],[18,222,89,17,172,135,10,33,178,140,37,22,77,86,218,103,253,210,228,135,117,212,74,117,238,159,33,113,140,249,181,237,193,118,178,47,50,114,12,129,220,18,43,224,19,83,47,198,9,205,80,88,68,206,65,1,248,12,245,149,215,161,9,168,78,118,78,95,221,111,106,43,62,36,8,168,62,58,45,200,4,51,239,149,53,3,42,174,237,203,249,72,33,152,61,144],[8,191,154,133,55,219,240,146,173,162,201,139,140,57,208,82,56,243,35,106,76,246,95,102,141,24,102,173,129,73,132,169,190,170,116,166,226,26,16,214,160,128,188,130,37,202,221,77,8,107,224,206,116,59,124,253,128,67,249,105,225,150,99,234,50,14,108,35,89,52,215,173,33,6,236,151,146,34,217,200,24,234,15,165,59,69,26,247,111,57,156,8,165,109,243,206],[0,219,92,117,117,72,162,175,195,22,119,81,73,120,97,149,7,47,183,172,223,119,103,79,177,125,67,137,225,43,31,156,118,10,9,180,232,10,216,169,220,163,65,118,70,63,61,183,24,211,213,247,89,40,229,133,183,59,242,118,56,68,87,166,174,120,148,222,89,126,132,164,156,207,95,155,87,67,67,19,5,72,93,151,124,177,47,11,128,134,164,122,13,154,5,93],[21,133,57,179,239,235,227,106,170,198,18,255,5,107,205,68,201,150,31,5,26,90,94,72,92,63,154,208,146,14,228,236,171,137,27,6,94,19,60,238,223,5,39,119,41,19,101,141,14,218,110,211,214,55,154,168,150,166,95,25,39,74,243,240,176,86,86,181,117,57,161,217,81,184,80,3,212,54,233,222,241,189,106,153,167,230,123,93,184,151,9,167,54,147,208,204],[10,63,189,230,183,231,231,39,32,163,1,2,230,136,166,110,195,81,146,0,184,87,212,42,148,233,219,166,181,109,164,254,119,164,73,1,93,127,37,199,155,176,67,29,140,32,212,170,0,206,72,53,28,119,31,96,159,86,191,57,183,202,52,122,143,171,0,182,182,206,169,117,197,154,224,52,184,0,116,97,140,183,57,187,117,102,86,152,68,200,47,147,81,245,206,107],[9,85,133,74,85,101,230,145,66,162,103,197,206,179,223,40,113,36,70,102,82,158,206,22,84,255,92,239,38,106,50,0,48,5,166,223,181,168,1,120,197,160,183,175,54,3,128,169,3,34,137,132,83,94,86,173,217,34,145,31,143,99,201,146,77,132,173,25,25,93,49,94,88,150,160,181,16,222,133,200,11,117,117,198,204,216,163,130,36,4,4,1,196,182,106,185],[21,34,214,141,198,135,152,218,135,225,202,223,170,42,12,142,168,101,41,239,199,174,115,235,126,99,204,12,19,37,175,95,32,255,81,145,84,214,98,196,213,89,147,131,149,218,169,46,6,37,148,160,21,218,106,95,81,132,76,204,73,20,146,212,132,66,126,241,6,110,102,62,254,95,178,108,80,195,85,69,5,122,50,159,35,123,204,142,7,46,1,211,78,174,66,236],[16,8,189,242,187,81,107,124,17,219,52,185,237,194,128,102,138,254,167,45,241,185,49,232,229,32,38,200,111,236,162,172,243,92,130,77,205,34,34,56,138,181,158,88,238,222,3,103,19,243,53,79,30,45,30,115,70,210,84,188,93,154,9,203,91,81,205,248,107,254,193,186,216,43,56,143,164,41,10,140,190,5,221,192,245,9,225,236,118,22,241,124,52,138,171,106],[16,143,134,162,250,244,51,191,27,135,222,110,23,187,103,176,27,197,90,119,253,95,128,33,221,34,252,229,73,186,152,61,99,86,33,225,227,61,107,71,86,61,195,254,168,151,130,58,24,17,31,249,55,234,32,238,241,115,132,0,26,55,155,90,192,158,73,12,213,11,119,44,165,151,181,73,154,54,160,236,104,56,1,164,205,80,181,130,0,73,148,210,125,9,118,188],[18,190,156,187,3,234,104,148,54,16,194,126,110,141,198,65,97,47,158,7,118,219,69,114,223,234,248,44,55,161,236,57,91,170,46,18,212,129,94,144,143,15,93,119,120,112,9,1,21,94,176,150,76,121,176,153,194,104,9,82,44,29,95,244,163,247,212,102,73,97,63,222,199,52,128,140,196,18,114,170,207,134,30,162,34,223,240,185,204,93,171,79,85,47,53,86],[4,73,140,152,152,173,107,83,105,132,17,19,174,221,175,43,177,17,4,152,158,154,111,85,101,158,106,165,9,151,93,158,169,151,13,66,150,106,253,239,185,64,250,234,203,60,20,30,11,236,172,97,249,55,89,115,64,221,77,72,47,180,41,38,174,90,22,251,197,185,46,251,219,221,195,170,208,221,249,59,28,227,45,104,252,252,63,204,131,175,145,143,46,95,65,7],[4,63,8,148,34,216,48,215,45,135,100,47,184,210,49,77,50,133,231,54,124,83,59,242,184,106,163,55,156,253,0,151,180,57,104,147,181,110,171,171,54,209,251,96,138,211,188,142,5,21,185,10,46,217,147,183,84,79,83,101,195,4,247,110,181,167,46,44,198,40,154,252,127,23,217,105,148,97,44,114,118,142,170,229,38,200,74,108,102,208,25,76,92,255,106,134],[24,250,206,188,95,201,194,129,56,37,220,233,185,117,149,220,21,41,240,26,186,20,110,157,103,113,78,106,152,8,136,149,28,254,58,176,141,196,111,142,34,59,194,95,160,237,96,229,9,4,241,233,46,225,74,58,190,33,75,44,220,100,217,129,141,8,246,217,222,87,150,231,165,89,47,232,122,251,17,21,209,97,126,30,228,107,95,233,168,131,184,115,196,177,110,165],[24,32,126,216,126,121,215,166,101,188,158,247,16,178,59,150,107,62,173,124,32,169,229,125,192,218,73,48,106,127,95,119,84,177,71,34,106,19,6,16,33,26,193,203,151,89,171,188,17,153,67,192,53,158,105,177,231,32,226,227,15,23,115,54,115,144,116,181,64,220,182,29,195,5,32,86,250,40,11,216,136,56,72,175,19,241,88,223,221,154,29,97,171,30,235,35],[3,143,177,130,202,213,82,159,36,205,167,149,227,23,101,158,4,200,139,203,60,212,11,198,51,136,78,143,93,253,101,183,106,241,102,43,154,30,223,183,86,179,24,216,90,244,30,229,12,246,67,26,75,139,145,131,175,78,49,75,5,89,193,80,97,56,157,86,108,58,28,243,150,166,105,34,9,62,41,178,90,241,48,195,196,137,144,27,193,154,157,193,2,35,78,65],[14,224,118,87,84,166,74,164,92,175,107,204,132,205,105,20,71,38,229,49,0,136,93,177,193,234,175,120,70,5,59,66,40,255,113,107,216,136,40,144,26,108,137,182,251,229,13,251,20,206,11,95,222,28,247,185,89,76,135,254,24,194,45,108,247,249,122,2,152,139,74,108,146,112,30,255,133,214,19,153,15,4,71,7,121,250,123,175,135,70,31,79,63,178,93,185],[14,122,18,215,11,120,174,63,114,199,63,156,203,93,14,217,94,168,76,3,195,7,121,165,42,46,26,237,100,1,214,219,11,132,170,231,232,79,78,26,159,231,139,25,181,209,32,20,18,91,54,29,120,175,127,211,254,111,49,111,212,117,250,158,57,139,32,38,239,139,108,145,174,33,227,60,145,58,115,107,217,121,117,39,90,44,113,138,23,66,183,166,165,151,24,68],[19,137,89,174,111,112,168,33,241,124,81,141,17,146,180,238,85,163,0,79,187,108,46,188,232,255,186,104,157,95,31,174,151,81,17,80,227,181,119,7,180,153,163,45,132,154,21,43,13,103,13,17,239,189,119,246,190,27,34,195,182,81,242,62,229,161,90,175,172,12,107,61,142,42,28,159,195,71,28,153,166,5,26,70,135,218,31,38,195,127,161,214,184,76,119,122],[14,75,140,252,255,220,129,107,129,114,18,250,100,186,159,153,4,159,220,225,24,193,53,29,24,75,63,170,177,76,183,53,175,93,207,243,79,172,87,125,107,253,31,249,167,219,116,178,21,174,138,0,58,195,208,196,196,45,126,1,113,89,222,234,84,229,42,195,45,163,252,54,129,129,246,108,78,36,42,228,249,156,249,139,224,98,10,160,146,81,177,65,32,117,71,206],[23,157,197,199,208,227,252,197,209,213,174,125,91,24,202,9,73,1,223,251,125,181,97,251,91,181,147,176,177,18,170,42,191,156,100,142,47,20,27,28,91,202,17,246,220,172,104,133,1,66,166,104,251,33,163,223,25,98,28,240,47,224,196,79,207,95,55,20,223,21,233,28,177,159,57,227,220,51,134,45,16,213,175,183,227,215,130,54,100,40,3,149,150,226,156,94],[4,227,22,249,59,19,68,82,29,100,13,183,39,28,123,132,156,239,100,98,102,95,23,253,249,199,178,152,25,62,110,169,134,130,86,52,8,127,4,72,67,186,163,217,72,163,47,118,4,231,132,148,221,123,131,209,48,31,158,140,74,146,13,87,105,119,193,250,48,199,90,230,187,249,32,178,7,42,50,94,250,22,246,238,80,85,72,195,126,176,190,196,110,201,72,163],[14,249,90,18,77,143,196,186,101,148,28,142,6,59,143,75,157,36,121,50,201,221,236,216,21,23,197,46,48,135,171,17,99,128,137,5,35,171,51,203,166,193,194,116,235,142,251,237,4,153,31,134,145,221,195,23,51,146,134,7,2,164,187,202,15,171,139,61,63,134,187,121,157,198,101,225,235,29,172,183,58,103,244,86,190,70,218,157,170,122,166,87,203,193,152,24],[25,48,249,134,92,246,14,29,208,85,59,81,170,211,14,196,6,214,181,108,67,149,225,51,17,165,198,43,54,34,236,232,250,9,147,86,128,158,109,191,247,40,45,52,45,119,225,13,5,212,11,9,71,193,199,96,237,33,246,165,77,191,84,162,17,125,115,65,243,153,86,2,41,140,234,208,229,20,244,35,82,119,128,232,137,130,1,90,12,125,3,146,191,83,158,27],[13,170,210,13,202,78,120,244,184,253,9,22,50,123,78,119,92,205,31,229,252,69,195,10,137,154,178,156,60,90,207,122,229,56,3,211,86,183,231,205,19,168,142,12,143,162,58,175,17,186,0,178,103,143,143,10,27,203,56,84,46,67,89,243,184,253,188,194,87,76,76,1,78,91,246,176,151,200,204,151,65,180,233,40,190,219,50,82,178,170,100,225,136,64,71,82],[12,209,19,19,218,211,26,50,131,228,73,238,99,217,41,13,70,184,191,233,69,129,66,35,96,82,127,55,169,110,146,183,13,103,243,47,246,89,18,45,243,82,246,13,0,128,56,174,7,82,134,30,43,43,68,43,210,13,97,207,212,133,45,114,173,81,237,249,188,160,234,192,83,250,219,94,150,191,194,51,196,225,210,108,91,58,222,161,137,162,171,19,23,113,2,149],[2,20,78,85,115,53,165,15,85,138,251,57,7,82,177,194,150,23,224,51,78,178,109,137,111,245,60,85,222,231,53,242,202,115,96,107,194,151,206,243,83,130,157,188,99,77,35,194,17,172,15,5,144,78,125,6,217,122,244,220,73,11,73,53,145,219,180,206,191,21,120,140,96,137,151,5,144,41,174,103,84,0,251,206,252,231,32,253,45,135,206,86,110,37,27,140],[5,107,129,136,73,210,42,69,21,177,222,248,215,250,199,196,242,64,60,35,102,154,143,33,91,25,49,195,46,165,194,168,10,183,0,163,214,95,96,75,199,107,31,112,46,169,121,209,22,86,68,0,188,19,52,137,50,98,83,96,200,136,23,116,240,206,95,19,105,74,128,180,71,12,219,24,73,60,173,141,24,196,6,16,183,5,144,202,237,174,24,231,15,70,234,8],[25,230,208,180,238,66,20,239,70,187,24,5,229,16,17,105,237,158,69,201,67,148,194,240,21,161,7,12,201,231,32,220,104,199,65,186,237,216,197,57,16,187,198,79,224,198,48,133,0,151,110,102,188,229,122,38,163,31,213,84,107,141,123,25,210,21,166,42,1,193,176,222,149,84,182,51,196,185,18,62,41,184,164,240,191,249,66,151,42,21,3,107,173,142,99,150],[20,228,68,42,212,13,8,102,121,32,128,230,47,118,72,20,174,96,63,212,208,10,153,203,116,45,22,92,108,193,195,166,188,189,27,0,89,152,228,86,182,185,124,15,172,5,10,48,1,131,145,3,207,148,51,224,144,101,53,219,220,148,207,5,23,82,120,134,199,210,106,49,142,178,96,151,94,47,212,196,242,54,41,123,23,150,70,139,98,135,172,224,151,170,51,98],[9,140,111,72,188,162,22,166,229,117,129,175,71,108,8,133,90,151,44,105,179,63,123,59,13,205,134,110,210,211,80,91,122,190,84,222,123,192,75,201,2,245,230,167,64,183,148,116,12,177,82,121,46,162,187,123,174,156,80,177,216,165,79,37,35,237,25,63,210,206,36,47,60,86,115,148,63,242,30,212,105,88,49,183,169,16,85,21,30,154,203,252,83,104,188,130],[13,209,206,8,185,105,177,4,238,18,51,41,111,189,70,207,138,87,65,179,100,42,64,120,171,222,20,151,143,94,188,252,116,111,172,245,141,111,117,143,241,223,171,80,194,211,21,9,3,61,235,75,225,106,197,238,228,93,229,159,113,72,179,242,51,137,84,240,54,54,51,30,55,100,209,244,132,114,201,44,102,75,233,140,203,192,80,2,64,165,7,78,21,11,24,43],[18,94,78,194,191,140,19,39,241,160,192,21,100,8,6,49,55,26,84,169,45,104,229,29,70,168,252,71,90,58,11,211,207,142,250,83,36,192,232,41,252,126,74,205,37,183,176,162,2,244,195,152,165,176,165,194,135,97,68,43,136,253,168,113,121,103,68,32,245,230,229,156,124,74,241,247,33,202,173,131,71,2,30,38,255,190,101,69,22,25,7,137,148,136,186,162],[6,81,145,82,24,235,57,187,171,238,76,185,220,13,164,87,117,52,104,108,79,136,198,127,61,75,26,36,88,134,34,24,253,196,130,37,97,44,226,106,109,93,13,223,212,10,215,191,13,36,102,105,113,114,146,248,9,141,202,189,147,185,144,169,161,44,98,50,189,23,18,21,195,191,116,176,122,187,0,122,197,140,39,134,170,202,155,85,242,25,140,165,177,49,163,7],[7,93,77,197,56,55,216,217,232,90,207,177,231,145,183,235,246,16,16,31,107,42,91,225,93,69,30,146,255,194,69,21,234,151,87,161,32,223,96,198,6,21,184,22,117,40,213,18,19,108,172,129,92,56,75,128,73,221,136,12,177,168,89,167,231,227,13,41,247,147,162,194,65,221,178,68,153,203,151,73,199,187,252,133,179,191,17,110,131,46,48,14,70,49,3,64],[4,95,160,39,119,54,163,152,225,21,248,245,75,107,158,231,53,49,68,79,197,227,213,217,156,210,185,195,97,183,110,124,56,231,161,130,208,59,129,234,203,86,252,27,80,146,86,22,2,101,150,27,34,10,87,120,34,139,118,126,239,125,229,29,98,34,4,154,232,129,4,185,179,81,125,132,57,151,19,105,13,209,205,102,98,204,167,65,166,160,1,87,245,244,124,101],[13,79,107,138,5,254,167,72,123,167,237,81,179,116,147,20,187,12,52,117,56,70,54,74,3,22,235,86,121,229,171,97,115,127,17,237,229,56,7,109,239,34,1,42,163,43,35,182,23,150,40,86,133,203,123,16,71,193,143,19,143,189,218,19,10,8,60,155,246,158,74,234,21,177,216,236,22,216,81,222,77,161,221,22,84,154,253,19,154,19,43,20,128,220,105,152],[22,164,59,243,93,161,135,99,131,227,29,211,160,178,124,82,165,44,174,216,249,212,76,4,253,66,66,91,58,58,119,185,127,188,163,181,113,3,121,31,179,51,93,199,33,83,227,83,6,211,157,111,180,101,208,90,141,219,115,117,232,112,224,159,149,177,135,24,163,187,111,164,45,109,146,251,89,64,148,71,102,75,255,206,29,181,165,159,88,174,71,27,116,25,255,158],[12,153,230,96,75,182,199,214,99,116,133,70,89,244,129,205,84,216,218,203,139,157,112,134,235,1,5,131,180,244,102,127,15,204,248,156,192,186,93,172,107,139,146,135,234,33,180,84,18,76,28,71,180,23,140,119,207,140,14,173,83,39,190,235,110,15,161,149,8,243,177,76,116,41,119,243,206,191,46,67,80,71,76,148,38,138,55,212,180,115,52,37,11,87,49,93],[11,55,135,243,209,210,82,101,130,153,123,28,80,241,105,3,238,87,99,21,242,204,38,133,104,194,7,16,87,196,155,34,101,235,224,158,174,152,222,171,183,43,50,44,28,74,135,190,14,47,9,47,51,194,96,161,198,195,183,178,250,29,47,230,3,57,241,195,216,58,30,202,5,18,25,237,203,106,109,120,6,99,150,210,208,45,20,159,121,41,113,227,33,71,241,9],[4,242,172,245,123,149,205,228,243,233,42,75,88,255,201,40,209,71,29,194,217,9,250,225,219,225,53,58,43,27,3,248,146,246,37,114,128,45,251,208,60,85,53,217,6,216,252,158,9,142,230,84,102,255,14,76,21,245,126,243,40,217,231,254,120,23,12,103,179,192,189,31,10,180,74,191,161,133,128,13,35,34,125,127,167,223,106,105,233,7,187,144,107,50,173,7],[3,17,7,208,52,211,187,85,196,67,97,166,209,75,161,179,80,205,203,243,53,188,148,158,143,241,54,251,65,67,81,22,8,236,107,3,159,143,19,183,72,71,39,126,146,181,121,41,22,155,26,152,248,249,183,5,54,198,207,19,84,10,106,20,211,172,31,80,142,169,181,40,145,16,4,166,105,238,240,250,210,158,40,55,158,131,163,208,144,118,145,100,156,163,88,121],[9,149,157,231,177,106,169,52,88,2,87,199,245,81,190,5,17,164,39,18,22,221,173,159,95,59,226,205,153,93,14,162,112,91,239,90,200,251,58,50,121,70,157,106,54,132,239,74,18,79,86,110,89,208,219,166,53,80,230,236,143,231,254,10,19,28,44,180,78,206,195,163,102,236,234,0,230,19,5,177,195,134,162,145,34,245,67,196,35,210,194,123,66,141,76,6],[18,209,254,201,182,204,175,133,64,86,108,44,157,193,254,88,149,17,6,44,83,120,242,77,27,93,95,116,236,76,110,250,1,229,130,176,80,182,196,8,184,95,133,110,16,40,104,201,13,237,70,122,35,185,217,104,14,107,105,112,246,102,165,190,9,197,107,200,10,123,197,197,126,176,154,69,11,9,172,174,176,42,255,9,241,174,131,223,208,244,201,116,9,76,237,156],[12,18,178,185,71,107,220,201,91,63,124,183,118,218,221,183,190,237,191,139,180,128,57,149,193,90,12,133,111,116,77,243,220,40,12,204,103,186,167,215,55,116,213,78,140,60,9,7,11,202,124,149,56,76,136,255,24,20,136,47,100,176,238,192,230,9,240,128,49,130,77,117,113,253,18,252,4,202,204,255,206,111,74,216,22,116,145,42,198,23,40,161,89,120,170,161],[23,54,43,148,153,55,55,27,74,215,69,218,115,176,153,41,159,22,127,254,29,138,253,151,203,142,213,179,108,24,99,76,204,236,31,157,59,249,87,147,124,12,251,69,136,203,196,182,17,73,149,66,249,247,222,145,247,0,81,245,26,199,253,57,230,34,12,69,145,197,48,5,71,58,75,151,236,33,47,55,59,221,72,99,124,142,112,136,28,142,63,3,33,76,28,82],[12,163,41,78,63,133,149,53,198,109,161,37,152,89,244,139,162,112,24,126,51,64,30,65,212,24,88,121,54,247,209,98,239,76,168,135,142,238,110,103,2,134,230,174,56,44,191,114,9,223,179,212,14,244,20,81,44,97,113,100,134,139,210,214,8,55,180,166,111,85,159,160,216,4,161,226,170,131,227,20,3,244,65,192,49,189,247,86,103,98,235,24,55,25,96,140],[1,237,240,146,84,172,198,90,213,86,150,153,232,106,157,246,139,202,119,183,191,159,162,12,28,88,74,163,50,250,73,222,174,50,233,150,171,218,214,129,61,248,45,165,94,6,197,181,21,197,97,55,51,176,157,63,6,174,59,61,116,190,219,230,77,181,74,136,7,139,110,153,195,33,166,91,19,36,43,84,193,174,96,88,34,169,252,6,42,222,221,85,215,35,32,193],[1,176,1,239,50,186,84,218,216,95,69,143,23,66,68,85,255,54,231,19,85,235,206,231,108,200,156,28,215,65,177,2,169,115,248,45,219,108,50,156,244,81,16,109,211,228,219,34,19,237,33,149,180,56,249,81,124,153,186,173,190,116,203,178,189,54,215,79,74,44,95,9,185,116,15,13,71,63,134,167,90,213,99,97,161,239,168,54,19,195,192,37,253,230,126,176],[1,80,183,4,215,49,119,38,180,159,209,21,197,204,188,39,160,137,0,35,96,225,93,32,192,185,167,181,185,223,130,87,144,144,182,105,225,135,35,220,39,66,61,245,80,224,253,50,18,52,55,172,160,64,127,113,94,12,96,69,185,84,176,223,36,15,86,225,20,180,162,72,19,163,195,39,15,21,237,173,129,25,131,177,99,176,50,187,205,228,83,53,77,73,52,239],[13,82,21,37,195,52,247,235,76,113,63,208,176,16,48,79,230,62,226,126,211,60,106,126,207,157,92,225,88,246,51,167,251,130,67,127,141,103,62,150,155,195,131,13,242,207,10,114,24,18,10,246,228,115,44,176,204,37,26,145,172,65,180,65,142,208,122,225,158,34,174,228,151,99,119,210,140,254,202,18,37,1,57,159,36,169,98,16,28,82,232,228,40,129,209,101],[23,86,64,219,62,67,71,65,133,54,85,47,105,55,42,183,26,185,47,24,205,189,40,45,20,2,88,49,154,200,178,9,245,6,138,118,96,123,176,83,170,206,237,220,29,220,162,185,2,172,112,234,173,63,215,4,126,135,118,33,208,49,235,1,201,253,158,224,91,35,76,69,212,41,158,237,183,215,9,102,3,25,89,187,92,117,248,193,7,220,220,168,86,54,55,107],[17,135,101,233,166,101,66,103,177,114,152,244,46,113,28,38,135,42,249,119,112,6,33,58,128,44,139,172,193,106,214,106,166,239,62,163,28,118,112,160,24,24,4,100,147,177,132,174,17,198,210,71,255,26,52,74,69,117,198,113,33,65,189,96,66,152,211,93,152,227,209,9,142,251,236,214,58,58,69,131,10,64,72,45,178,18,33,235,207,232,120,8,87,202,168,235],[14,88,149,45,87,180,50,191,81,144,9,38,37,175,51,26,27,200,132,131,11,82,168,160,88,215,189,164,208,181,169,195,157,227,170,184,61,78,234,153,227,251,183,24,244,26,170,6,15,225,74,141,217,99,61,204,101,123,176,228,120,81,250,79,150,73,84,170,9,126,226,43,239,111,228,163,85,238,229,46,168,39,41,138,112,208,158,9,170,44,238,58,244,122,149,56],[23,75,72,49,254,248,185,247,185,172,16,247,107,246,251,173,98,117,228,195,55,204,129,98,91,184,26,118,24,197,206,51,175,134,0,112,4,79,55,230,83,62,156,118,160,247,53,115,21,204,234,160,154,240,29,8,19,36,61,136,66,76,184,132,248,101,72,215,27,119,215,159,24,69,121,100,60,168,117,215,26,91,52,187,72,143,30,7,156,194,126,42,34,71,118,88],[13,92,72,222,134,147,12,255,72,166,72,85,74,232,163,37,245,38,110,210,28,197,142,144,169,196,236,241,45,190,73,109,231,236,255,147,197,8,198,128,180,68,32,4,235,103,54,91,19,86,17,233,219,37,87,146,24,25,31,226,213,154,107,214,83,63,81,98,119,113,110,7,37,189,246,203,139,95,250,59,164,97,175,134,127,106,97,89,4,38,41,249,163,148,133,75],[17,135,53,149,129,144,121,181,212,176,47,107,92,215,72,120,196,225,157,50,171,89,220,236,223,223,36,9,131,176,185,182,40,127,192,186,174,68,107,92,31,115,196,154,253,173,135,56,10,214,111,73,148,69,172,26,7,214,198,205,67,232,182,226,220,19,159,104,30,148,251,130,253,237,9,28,153,179,151,205,76,189,189,103,103,183,150,107,61,159,238,203,173,22,36,45],[18,74,154,87,36,15,191,98,47,101,122,232,22,192,206,217,177,150,169,237,193,187,146,226,164,84,130,214,9,252,89,54,10,139,99,66,110,24,214,11,27,205,207,207,217,202,94,113,20,228,79,230,152,135,189,199,0,174,149,243,8,4,5,149,209,145,190,54,14,237,128,101,2,55,204,201,221,20,19,95,202,36,89,132,0,172,5,120,236,66,125,122,226,54,39,119],[2,74,190,54,165,76,234,10,245,88,5,132,92,33,181,104,108,47,222,92,19,29,148,159,230,229,197,40,177,118,149,1,233,139,207,210,132,188,17,57,41,80,178,192,224,170,243,65,23,30,85,31,62,186,150,133,231,155,84,230,230,245,189,23,47,207,144,126,172,128,34,25,95,20,0,35,144,192,157,159,210,247,78,99,15,25,89,251,137,65,200,157,107,148,107,146],[13,203,231,167,165,1,146,199,254,100,210,226,179,241,203,144,171,138,222,173,164,66,7,182,117,105,174,147,242,213,104,154,93,103,95,170,242,137,113,191,120,141,177,104,9,9,165,44,19,162,255,22,53,167,50,8,18,145,224,228,171,149,103,239,249,239,77,141,49,217,48,174,22,8,86,162,4,104,163,224,88,19,134,105,20,71,153,67,184,185,102,162,182,248,40,241],[2,114,85,129,167,44,183,21,104,15,192,24,254,47,114,47,28,47,162,100,231,70,163,128,183,143,90,197,113,108,3,176,59,255,126,79,140,214,52,179,77,172,13,247,137,8,60,42,18,122,135,65,146,92,109,62,219,19,231,219,87,218,255,169,146,160,149,7,220,111,226,204,45,193,170,215,156,206,160,251,14,180,69,212,41,221,236,49,206,43,208,14,212,252,175,127],[5,225,55,135,38,185,72,124,9,88,212,151,171,21,243,121,40,144,118,144,35,173,166,51,217,64,68,124,218,18,163,127,253,122,73,155,132,209,98,174,152,139,134,238,87,139,69,213,25,101,205,232,236,214,1,107,98,136,125,48,52,94,141,78,242,84,49,76,209,32,116,13,85,23,160,124,21,244,124,116,131,241,95,142,89,225,60,255,125,184,236,135,152,101,80,244],[0,238,162,202,46,71,86,93,228,7,75,155,38,143,70,198,79,0,88,141,166,225,10,80,128,138,12,30,169,202,183,208,62,6,117,174,9,21,78,138,107,32,137,11,150,49,188,170,21,24,213,75,180,198,210,28,45,146,223,6,74,183,232,123,5,10,42,43,157,137,164,245,248,13,96,67,221,159,97,41,136,177,53,179,251,72,164,118,136,15,242,215,49,98,29,199],[24,135,11,214,162,175,169,68,191,203,56,240,80,249,48,137,214,210,12,36,213,55,139,119,50,253,183,192,214,9,82,111,68,203,196,170,43,13,65,193,52,192,186,81,250,164,251,155,8,77,17,13,41,40,232,218,137,65,77,219,93,95,181,17,79,193,215,29,136,82,124,162,128,122,188,164,24,240,4,206,26,30,182,116,152,142,245,180,249,113,75,15,223,13,51,212],[22,87,133,124,83,187,48,80,54,70,150,215,163,30,187,218,37,24,150,239,233,185,199,147,42,27,31,27,165,14,167,177,181,107,22,105,234,253,115,47,171,98,54,242,239,16,9,199,22,75,32,7,34,40,161,138,243,64,205,170,194,111,190,162,79,207,211,57,206,1,241,110,130,48,32,216,164,116,19,170,175,186,141,180,88,92,41,33,122,130,38,97,213,61,240,116],[16,98,35,210,157,163,107,60,201,40,70,16,213,80,21,232,217,6,38,142,44,224,136,114,170,190,80,253,243,246,98,125,218,15,45,154,28,126,236,26,115,214,157,35,50,39,88,163,1,165,157,40,220,179,66,21,247,22,226,153,168,10,206,7,172,26,187,230,186,93,238,44,177,252,107,233,197,227,75,183,181,172,150,244,59,127,189,128,142,219,224,28,146,41,139,104],[21,222,172,71,81,45,193,180,56,160,206,250,239,129,119,191,42,224,85,174,248,247,190,1,98,154,206,141,239,163,7,103,124,153,16,0,201,123,45,36,95,6,201,36,20,238,176,200,10,125,1,162,119,94,112,20,245,122,164,165,187,10,251,93,154,72,197,221,38,122,125,134,30,137,149,187,135,41,143,40,42,61,55,194,32,73,132,234,117,98,26,141,183,169,68,224],[20,153,194,184,98,181,71,146,34,212,174,148,235,30,23,36,98,37,93,47,57,227,103,45,178,108,133,82,144,76,83,227,196,25,172,244,17,67,95,231,71,92,96,60,115,122,96,189,15,91,60,118,201,249,156,65,204,251,116,97,33,145,211,144,119,206,169,80,6,238,79,15,55,3,13,48,158,171,37,76,22,54,178,197,91,219,61,118,251,58,24,232,216,23,186,193],[21,42,175,102,163,109,82,114,207,212,97,65,90,152,122,59,100,245,99,12,127,185,19,136,106,181,2,89,128,26,164,67,247,209,55,188,138,114,186,74,32,178,203,53,241,175,7,147,6,187,35,164,134,169,122,157,6,60,61,246,23,84,31,4,2,20,217,179,80,215,8,122,152,179,188,177,3,131,82,55,189,225,151,104,33,94,235,74,179,57,176,33,193,248,106,17],[11,216,61,56,67,215,83,105,203,177,170,254,132,238,97,255,162,80,156,50,77,161,32,143,179,18,176,174,175,231,175,254,77,211,143,57,39,239,195,5,91,234,39,167,65,70,168,200,16,34,226,152,7,209,29,38,18,241,105,207,242,95,249,153,191,198,255,174,230,69,118,134,170,24,67,210,169,248,238,40,249,15,150,158,194,117,14,243,54,229,235,170,93,178,251,41],[18,191,237,219,180,34,52,143,150,163,219,31,30,152,239,73,46,164,81,136,240,231,36,64,34,246,250,165,129,200,130,196,38,147,162,47,118,147,66,20,42,237,77,116,51,134,224,197,6,156,91,30,222,176,157,173,143,235,38,68,199,22,81,112,44,238,129,134,218,136,159,6,72,57,27,61,85,127,120,23,243,253,116,157,129,197,2,234,196,41,108,183,99,72,89,169],[2,235,44,221,220,45,127,139,237,248,67,166,228,107,1,243,39,236,220,214,56,167,236,72,132,206,111,141,179,152,89,93,223,104,17,39,146,184,41,187,165,190,201,82,152,181,80,130,4,91,158,221,150,238,56,20,173,114,186,87,194,36,113,6,81,174,19,135,93,111,159,55,25,110,33,196,78,154,131,216,197,108,9,53,182,151,76,8,76,111,69,108,122,160,82,125],[23,182,116,57,183,112,153,146,155,47,46,4,170,243,155,18,4,145,161,108,91,112,105,142,182,245,68,89,4,4,48,149,15,11,161,241,76,46,160,187,216,129,100,107,84,102,60,146,23,250,38,6,49,56,72,223,139,113,132,171,192,84,130,168,107,190,156,0,1,137,187,213,4,168,8,83,238,14,61,46,222,28,49,96,235,209,144,202,5,41,123,36,64,232,3,51],[25,167,99,254,161,40,226,89,49,246,233,26,119,42,119,58,88,128,114,55,193,138,105,178,106,9,144,55,22,45,215,68,161,240,9,19,222,148,77,140,7,21,50,108,182,58,70,235,20,1,53,228,55,67,137,237,185,15,69,83,190,137,164,184,252,17,119,58,10,121,124,201,199,173,33,56,175,13,89,14,28,219,243,185,254,238,132,125,228,32,11,4,225,70,3,231],[20,196,111,4,101,84,44,117,65,86,81,85,210,35,152,28,199,238,219,234,188,112,149,211,143,14,173,250,107,111,12,193,58,88,89,80,119,210,85,53,220,11,56,130,138,195,240,160,23,203,96,101,71,225,33,233,63,62,68,7,1,115,80,26,199,94,81,212,156,138,222,122,84,231,63,65,94,71,164,47,245,226,48,127,255,159,232,72,220,21,215,169,114,77,89,239],[25,188,156,118,211,137,146,210,166,67,88,218,47,98,249,95,94,159,22,188,24,188,43,84,165,131,209,39,37,108,4,180,130,255,243,169,114,248,229,8,230,147,241,7,79,55,145,162,8,33,61,206,21,203,250,43,11,117,11,135,235,131,40,102,126,207,97,206,103,161,4,249,109,62,60,45,139,198,144,217,83,200,95,119,48,8,157,153,50,176,59,91,178,2,251,85],[2,42,149,145,238,32,18,50,132,68,206,203,10,3,4,243,5,37,77,207,101,15,218,231,158,66,14,104,49,1,80,146,196,34,84,64,189,221,168,130,240,20,164,97,35,110,149,13,11,247,114,118,107,182,185,243,206,62,94,210,242,188,171,183,117,190,128,237,180,188,140,63,98,208,75,180,64,20,206,176,150,232,131,93,255,87,1,76,88,164,112,175,48,31,74,110],[8,227,50,84,34,18,200,79,250,60,59,98,52,224,74,216,22,107,78,245,62,187,163,177,35,88,214,65,80,161,187,209,106,163,83,209,196,245,214,193,248,236,248,230,56,102,47,98,5,176,164,178,142,248,42,131,49,187,202,188,101,234,110,173,10,182,122,103,245,19,180,179,118,159,195,181,150,242,46,232,73,228,25,121,37,60,94,109,115,223,202,215,252,54,204,37],[14,101,174,182,175,231,251,76,93,74,86,120,7,135,31,255,233,16,54,55,15,47,232,39,120,195,74,133,33,213,53,83,240,216,145,182,21,186,90,205,196,44,241,130,171,106,145,55,8,118,113,123,118,157,126,39,59,86,70,69,19,106,187,180,216,212,10,163,181,62,94,76,179,225,155,54,95,163,96,17,60,91,170,143,110,142,59,226,130,95,251,221,154,234,225,173],[14,100,22,111,47,221,250,243,98,196,91,142,238,180,133,57,110,123,201,123,19,141,197,132,12,244,124,160,219,57,132,192,216,38,72,52,232,92,170,5,119,222,243,202,195,190,215,74,9,4,49,109,67,224,226,244,0,227,243,150,24,37,79,86,134,180,237,226,55,127,213,102,200,109,238,77,142,129,185,142,68,145,196,136,253,180,18,73,11,15,97,170,71,121,16,16],[15,137,157,121,13,124,205,219,210,127,231,217,221,188,223,243,120,233,84,230,30,96,67,200,170,82,187,207,38,103,65,213,132,56,24,84,132,131,38,60,242,0,127,25,214,172,13,157,18,101,17,91,107,62,191,139,2,61,149,178,145,129,175,28,65,172,64,127,69,23,136,190,157,141,82,205,160,145,42,123,122,158,166,128,9,121,112,66,218,160,214,227,238,106,97,24],[4,203,88,60,43,137,8,87,111,232,210,170,121,214,14,96,118,46,203,44,60,175,87,144,140,196,1,182,88,177,10,57,166,28,245,212,202,169,3,148,15,212,229,25,109,180,76,133,21,132,184,193,126,24,70,153,0,53,254,191,44,249,136,42,217,16,190,26,189,193,145,172,222,99,66,112,235,215,10,112,45,135,24,22,252,29,143,56,233,167,154,16,202,172,16,254],[2,191,132,191,199,65,221,57,128,32,97,62,246,160,82,143,97,87,11,180,109,183,226,49,58,131,142,15,45,88,34,212,192,253,100,160,39,151,137,222,235,96,100,112,96,179,254,73,22,8,254,220,117,99,143,198,75,4,72,34,86,9,128,69,58,88,242,188,56,134,193,63,109,33,241,38,5,252,167,166,97,169,149,11,252,95,21,180,182,190,161,125,72,98,18,208],[3,39,37,152,58,5,101,245,50,155,64,51,70,132,121,132,11,169,159,110,211,111,111,123,181,90,67,229,125,30,234,50,81,255,171,148,215,170,186,209,180,221,183,81,102,159,15,52,3,48,168,36,204,123,180,14,165,17,76,5,55,152,156,210,255,37,222,189,97,124,244,44,120,162,15,109,26,176,85,51,101,158,136,5,29,103,142,43,228,232,130,131,181,236,138,202],[14,136,207,48,36,38,122,244,101,139,73,150,174,70,85,53,155,18,151,123,133,7,129,91,241,40,172,74,134,183,15,118,242,95,242,231,248,53,75,170,25,248,121,177,238,103,242,236,23,78,98,248,69,233,81,214,193,99,182,230,211,196,54,58,251,43,208,16,241,121,133,110,109,27,13,74,207,233,233,175,45,111,209,192,83,200,23,77,75,89,35,208,227,44,219,97],[7,215,161,26,239,179,62,186,21,111,44,108,125,187,51,235,45,144,185,254,46,46,164,176,136,180,206,114,147,107,235,198,180,23,149,239,11,90,15,199,54,73,253,207,173,189,229,147,10,71,160,89,110,79,11,100,145,83,103,163,108,11,33,54,76,107,155,146,4,25,214,118,143,214,142,141,58,157,179,134,254,7,235,48,118,21,220,81,112,87,76,176,223,206,72,111],[10,158,3,107,48,114,200,39,171,124,100,144,214,25,85,61,207,242,219,255,207,255,16,75,2,84,183,118,174,209,60,155,1,140,201,168,182,77,10,221,48,5,215,76,155,145,83,133,14,98,245,118,216,116,255,26,229,83,143,136,117,38,34,197,112,229,183,176,117,49,24,221,42,227,30,128,146,31,189,68,165,137,66,228,62,232,165,77,226,104,88,32,74,28,114,141],[4,254,176,202,52,145,248,74,7,15,92,47,193,220,250,173,255,109,212,100,240,151,157,242,194,90,181,80,116,55,131,219,101,120,73,145,195,106,12,28,127,29,183,179,193,235,10,31,21,208,2,238,72,134,111,60,76,90,113,153,66,125,209,69,32,201,14,245,250,167,75,70,149,27,28,33,74,242,32,74,92,215,34,156,25,238,146,203,3,56,246,141,249,153,79,192],[7,42,47,141,70,191,102,117,82,62,166,87,79,45,247,51,161,29,202,225,237,166,158,125,133,48,188,176,238,247,37,111,85,129,242,217,211,29,160,236,98,33,57,246,12,93,75,225,9,185,97,146,178,29,187,130,104,65,253,81,100,82,212,163,74,236,83,101,106,31,0,123,43,64,125,89,19,169,122,185,38,250,25,96,86,52,150,186,203,136,42,253,180,223,163,28],[23,14,175,231,73,7,209,43,216,31,236,132,0,141,197,25,17,225,18,125,224,103,231,3,206,100,103,53,248,136,228,218,145,220,102,30,164,169,149,59,168,66,0,23,104,10,188,174,9,183,150,8,90,75,168,228,154,29,148,21,154,142,83,1,21,39,45,96,15,236,50,113,106,5,122,228,179,251,203,127,17,27,150,108,17,227,158,199,192,126,25,200,6,137,246,73],[6,161,112,82,89,213,106,84,7,29,25,128,83,163,184,161,162,152,191,233,134,163,113,164,103,196,28,172,25,131,110,109,108,224,143,229,139,198,13,143,185,108,96,213,175,46,223,38,13,48,228,104,66,179,152,153,184,123,173,86,150,83,90,118,157,147,135,38,35,87,52,232,140,91,198,54,21,159,207,76,72,11,55,233,250,136,245,234,159,186,23,95,31,46,210,16],[1,11,0,228,126,203,226,88,49,126,122,225,102,8,38,9,48,236,159,5,20,87,104,96,57,71,62,39,222,211,112,232,69,120,73,19,224,73,25,205,146,181,95,62,218,148,8,65,10,75,136,38,54,150,242,232,97,214,137,148,138,244,15,234,123,196,7,144,82,214,15,173,17,24,157,150,152,220,69,167,103,16,133,244,243,67,192,140,224,134,60,11,181,110,161,243],[12,63,126,203,243,61,170,7,235,255,235,131,174,72,31,2,22,80,42,6,192,170,204,114,68,255,208,174,35,42,13,139,16,252,164,79,233,141,67,166,75,83,94,210,105,114,217,56,4,169,93,250,249,29,30,95,36,113,213,202,68,102,235,200,115,210,253,199,78,213,155,217,4,102,219,127,134,61,172,149,6,174,210,124,78,162,41,163,135,119,202,255,7,146,163,132],[14,249,144,20,17,248,74,58,84,17,90,114,90,200,183,171,21,229,191,126,38,64,112,90,223,181,114,52,239,185,180,151,107,32,121,83,187,38,254,233,198,97,122,242,127,41,47,142,20,95,161,205,194,173,146,197,113,234,64,115,73,110,32,148,138,44,89,234,191,173,5,152,22,220,37,1,216,134,229,26,229,188,240,94,225,140,156,61,54,42,168,78,159,116,169,70],[18,50,236,192,73,187,220,121,32,223,15,244,223,237,106,76,56,127,45,166,167,34,26,117,205,169,14,237,229,112,254,33,225,92,61,94,21,69,139,139,33,137,103,109,181,57,2,17,4,243,80,42,97,12,197,201,236,167,191,54,182,54,204,12,161,227,47,22,79,132,186,207,135,166,241,255,101,24,116,3,37,224,15,214,48,104,216,33,247,110,148,148,56,204,54,112],[8,106,69,246,69,131,219,196,193,118,101,235,238,188,135,50,19,158,175,17,85,222,22,112,249,142,46,244,121,149,235,140,67,182,64,189,235,210,165,92,159,156,186,179,144,168,100,31,16,131,179,119,124,178,11,139,179,124,182,110,30,229,52,225,175,7,162,192,96,15,206,124,162,6,118,245,74,201,188,10,238,207,49,250,64,165,131,155,16,104,26,195,205,125,100,93],[20,47,61,83,88,198,92,145,242,237,10,194,67,228,40,215,168,133,20,96,107,135,119,37,249,160,159,41,255,208,73,163,68,160,213,139,217,218,115,177,146,122,69,67,230,134,242,140,8,93,98,114,122,69,24,97,87,90,30,169,146,84,125,225,99,169,71,176,174,216,203,13,73,14,105,133,83,98,248,100,120,52,84,223,99,51,138,67,24,123,158,164,112,218,5,56],[4,179,194,219,56,234,105,5,28,96,101,187,75,242,172,121,149,99,50,54,46,42,119,204,248,168,147,64,98,145,4,86,202,203,1,31,96,244,237,1,185,59,255,168,153,64,18,67,1,31,219,85,38,15,199,153,215,82,219,81,169,223,106,113,179,123,231,76,231,70,224,212,45,110,137,158,125,92,220,193,87,83,4,76,226,62,209,171,178,144,77,34,151,53,186,18],[8,240,51,47,207,167,48,79,55,160,65,221,218,250,166,36,97,34,164,41,142,195,52,251,227,20,231,193,110,149,58,196,226,62,69,149,251,80,237,135,150,196,8,41,183,246,104,134,4,27,125,31,151,166,229,99,206,11,195,188,174,183,142,156,22,234,185,151,254,77,60,34,246,44,255,70,66,95,62,139,32,151,155,19,123,42,248,185,105,185,79,52,59,128,240,204],[0,94,188,150,3,46,63,93,50,201,206,241,244,63,156,151,229,224,49,209,233,58,153,240,184,52,242,5,51,70,120,167,42,212,203,80,173,240,45,89,239,94,231,16,232,207,244,203,15,39,127,158,31,50,89,252,170,98,236,75,231,147,38,78,199,248,137,148,205,66,20,116,175,46,97,131,124,18,126,174,195,57,43,91,140,104,239,252,170,170,255,72,19,241,170,31],[5,53,249,60,222,23,209,13,109,117,103,224,73,245,238,55,25,68,33,56,71,70,194,107,241,55,196,193,163,7,95,175,185,223,178,86,21,88,253,165,168,195,45,31,121,100,76,187,4,208,64,251,110,193,125,153,65,67,53,74,118,250,173,169,56,239,99,209,51,137,196,28,200,218,110,255,249,178,10,238,215,61,150,208,182,21,14,165,4,28,52,112,210,24,215,154],[25,116,80,92,9,221,205,220,17,221,164,109,88,95,185,148,146,112,4,190,113,154,97,153,156,77,79,159,246,34,20,40,169,122,73,143,242,178,33,246,97,239,203,31,74,246,140,237,1,220,237,177,198,44,2,88,214,65,75,109,223,140,244,167,238,55,233,129,138,189,79,211,61,203,197,13,222,151,53,228,169,66,168,103,102,30,92,187,149,77,170,1,14,148,96,4],[22,125,20,138,94,79,217,160,133,224,220,7,145,123,98,33,52,107,202,251,157,66,146,91,49,231,117,254,54,11,149,65,106,114,161,30,211,105,138,18,194,83,42,255,145,62,19,147,11,133,229,30,238,155,4,44,176,100,10,126,44,13,18,244,101,23,189,149,198,74,105,101,229,85,28,42,219,158,171,83,192,224,131,193,117,126,110,187,187,93,183,252,9,202,107,202],[20,78,85,201,116,40,218,97,59,35,250,130,101,253,207,152,250,195,221,68,147,151,7,243,63,32,140,103,166,24,246,79,224,22,122,17,47,204,35,234,21,223,59,87,25,196,233,248,4,15,196,0,253,192,26,92,105,63,5,214,198,107,183,184,21,134,217,102,186,129,159,87,198,121,141,91,245,249,195,82,220,86,66,232,64,176,110,166,145,124,40,237,56,135,115,21],[14,182,144,39,134,196,208,1,253,2,205,122,168,207,191,1,117,90,210,151,227,16,199,234,142,202,71,104,224,46,9,139,27,138,6,142,240,134,27,87,140,112,145,215,233,221,236,187,9,67,185,56,245,143,96,130,187,22,111,102,128,175,246,45,153,84,108,180,213,156,121,75,31,125,0,242,73,16,96,84,215,148,4,149,19,108,37,160,242,212,110,153,182,39,169,82],[18,160,252,48,71,23,205,247,137,88,206,78,175,142,170,88,111,217,100,16,28,96,165,14,186,92,10,249,70,166,241,255,226,58,131,105,11,96,11,56,130,27,159,142,184,229,106,251,11,100,52,164,50,19,141,244,65,31,33,244,172,200,106,131,209,40,3,56,49,0,93,239,170,172,127,100,152,35,26,81,93,118,99,138,51,110,166,213,200,228,143,51,18,84,209,179],[10,218,47,190,180,192,105,179,9,155,182,6,204,118,109,64,81,146,0,192,226,7,97,6,233,193,136,99,172,22,234,114,12,30,128,53,30,251,206,30,132,98,104,42,3,199,62,237,13,43,153,157,177,9,42,167,97,244,67,152,149,48,27,34,138,61,111,139,27,145,12,17,157,7,11,196,59,198,69,187,176,29,152,178,152,39,83,46,81,139,106,130,188,244,199,52],[16,110,255,91,189,26,180,194,135,239,117,188,138,199,39,161,227,55,141,36,147,66,237,148,206,104,21,43,144,242,193,4,5,217,231,165,186,188,39,87,173,166,67,103,244,197,183,150,0,7,138,236,174,189,35,237,202,76,145,204,205,112,152,81,235,36,110,146,198,90,55,99,216,58,159,66,84,131,190,238,36,220,57,107,132,214,210,193,247,61,16,106,108,147,102,164],[11,158,41,14,220,81,136,40,6,106,136,82,38,29,135,229,148,47,117,202,3,146,69,65,224,111,220,66,196,31,18,130,183,221,19,48,200,187,225,249,122,188,88,99,93,126,196,72,7,143,66,109,169,169,153,14,128,169,182,106,72,91,121,175,33,194,190,129,157,40,137,215,236,79,186,18,33,249,250,184,26,226,191,91,182,156,195,62,126,246,119,130,195,167,152,181],[21,50,206,209,31,16,161,224,168,191,8,3,46,221,255,65,23,32,246,157,66,67,244,32,165,203,196,137,10,27,247,4,19,133,146,87,32,248,84,97,31,58,126,208,253,65,20,249,1,233,7,212,126,191,83,179,84,64,214,191,238,116,215,145,143,139,121,227,99,239,241,51,178,241,132,101,161,219,169,251,157,127,67,134,8,64,118,165,213,196,248,138,216,8,130,194],[20,58,67,226,75,36,88,252,114,167,63,50,157,232,38,66,128,27,197,65,171,105,46,169,21,202,198,92,111,222,139,129,162,40,95,135,129,11,157,207,65,56,243,143,149,180,37,19,1,237,34,79,231,169,206,233,57,41,224,238,36,22,26,90,211,110,175,171,63,198,46,5,138,39,23,171,205,172,101,143,98,113,156,10,240,129,228,229,16,78,190,183,199,197,213,159],[15,8,201,149,149,124,135,121,15,225,83,251,207,149,160,171,101,92,65,213,17,250,59,196,196,121,123,168,228,159,232,27,5,17,22,55,19,255,242,120,172,138,253,70,210,17,164,200,14,13,30,205,111,94,211,35,10,228,168,57,99,234,222,54,109,109,128,42,22,74,35,140,210,190,120,214,162,64,149,192,27,178,108,79,20,243,102,250,206,79,109,47,226,155,167,87],[21,228,238,99,238,9,115,129,62,57,219,214,70,77,106,78,122,75,139,144,245,242,54,229,77,80,36,93,147,53,220,5,159,16,224,6,23,149,118,138,191,62,46,23,141,253,95,209,7,130,175,139,72,99,26,53,208,108,40,68,202,48,211,246,155,251,17,243,66,245,63,166,178,90,150,130,224,229,200,226,171,240,155,198,75,141,241,46,46,183,149,13,51,72,42,177],[19,241,123,115,196,101,213,17,65,56,176,53,138,241,19,99,102,235,70,95,185,240,1,147,214,131,86,136,82,161,204,58,237,188,94,103,238,91,22,27,239,213,252,98,4,184,228,250,5,60,242,3,126,205,177,134,118,247,6,81,125,90,70,187,238,12,202,35,150,52,250,235,236,132,188,52,60,165,185,194,207,179,158,100,241,87,218,247,215,26,234,121,206,210,38,7],[16,166,70,111,247,71,255,9,160,245,235,153,232,239,208,122,244,241,246,114,189,114,169,93,178,8,120,103,76,115,198,57,40,156,113,82,63,213,253,134,202,228,192,118,137,21,107,197,13,19,121,62,58,211,56,148,53,199,149,139,42,89,172,18,68,3,194,72,172,126,84,118,46,37,80,60,145,3,229,206,158,137,223,154,164,120,197,27,88,27,92,122,26,124,37,200],[2,187,84,38,184,98,240,208,137,15,213,198,60,223,62,250,19,146,116,193,78,171,38,88,136,254,97,188,69,221,194,220,201,128,220,38,138,146,44,73,239,138,236,12,241,228,106,216,16,3,187,126,111,77,107,172,106,99,12,56,145,13,5,54,144,227,192,139,62,39,113,84,242,247,113,244,173,214,29,35,72,173,62,249,179,79,185,158,16,235,46,43,91,254,185,124],[14,148,201,4,150,20,44,125,117,68,116,66,178,93,186,158,69,241,124,50,65,72,175,242,29,105,69,111,66,32,183,138,112,41,110,250,191,193,159,168,90,171,76,102,41,11,253,163,10,100,192,201,38,217,159,155,45,36,107,53,255,129,77,210,12,109,83,163,193,8,120,19,214,132,162,44,81,43,234,233,143,135,88,98,73,124,18,14,26,99,4,215,74,72,139,195],[21,75,178,107,44,159,127,229,36,190,22,27,0,29,207,67,225,29,135,28,171,125,113,63,124,59,104,224,181,146,39,214,43,99,69,14,176,41,107,41,63,112,145,215,62,107,35,40,23,105,120,8,94,145,223,43,211,94,141,50,59,124,175,15,110,154,156,249,212,38,194,52,25,121,10,174,97,129,99,31,158,176,153,127,34,59,58,245,111,167,249,91,251,196,241,218],[2,195,190,57,224,202,177,188,177,33,71,223,6,95,79,188,66,28,162,182,201,95,3,140,30,220,151,127,120,98,139,159,81,41,133,194,254,141,122,25,117,190,61,238,220,107,158,133,4,201,155,208,126,127,117,136,25,77,172,208,90,12,202,39,236,92,32,54,76,239,171,136,123,133,2,94,28,177,216,101,207,29,163,120,147,195,9,32,78,219,36,181,85,120,94,215],[3,14,41,2,62,208,48,68,81,2,161,108,60,119,44,229,13,108,24,61,231,180,45,38,235,186,175,170,226,140,121,114,168,80,20,123,255,243,175,218,73,146,153,9,92,71,123,162,5,208,78,125,213,233,208,74,10,195,190,228,245,22,113,126,144,28,162,144,76,142,105,48,252,0,240,140,103,119,245,213,122,9,167,222,209,69,228,27,91,158,173,121,29,61,108,180],[6,112,219,28,13,157,4,145,118,158,101,234,3,254,83,244,249,88,25,187,201,105,207,170,240,57,191,65,123,5,103,20,1,18,180,224,115,91,83,85,186,113,89,0,120,247,12,219,4,210,114,216,74,218,74,159,69,20,239,30,178,250,61,3,206,84,120,93,236,222,202,163,218,169,34,154,238,40,149,227,112,162,186,86,116,170,183,127,150,124,173,106,227,89,41,35],[17,122,158,251,55,212,254,152,139,2,47,141,82,231,49,71,211,178,125,69,201,145,101,41,12,116,66,134,65,238,185,32,218,64,42,115,8,157,40,156,113,45,140,6,180,238,137,39,3,171,143,147,86,24,53,45,37,249,59,71,182,54,190,37,226,246,186,4,238,187,115,9,230,71,194,80,159,188,172,79,9,112,187,80,195,182,158,35,9,156,19,137,87,117,242,66],[23,75,120,1,26,253,16,17,74,70,210,243,251,132,250,127,162,110,186,232,191,89,125,229,105,215,77,170,177,106,216,139,110,43,109,70,63,79,138,139,76,152,8,92,159,166,89,194,0,177,63,33,20,148,47,193,49,91,121,80,149,124,187,31,111,214,89,49,99,137,30,12,123,134,225,52,254,174,160,23,242,253,222,51,172,249,9,175,174,44,157,139,117,45,164,181],[21,199,103,42,72,114,231,176,40,222,134,178,68,82,164,205,251,62,232,146,152,171,155,3,100,244,171,124,84,84,254,61,167,29,100,44,185,134,125,229,127,192,223,44,142,198,191,220,14,118,253,56,23,163,251,215,94,53,99,128,38,225,108,223,87,105,23,55,200,57,75,43,233,218,20,254,199,131,194,165,76,64,9,94,164,136,228,124,69,72,36,221,54,18,202,141],[13,156,116,31,151,104,202,54,185,148,101,95,120,212,255,197,28,172,37,240,204,173,116,168,111,75,132,131,54,158,182,89,104,10,253,42,63,39,216,141,63,217,12,92,7,195,226,65,3,176,166,227,2,202,219,33,245,69,185,4,250,175,206,250,176,161,88,113,251,123,246,141,36,111,176,112,117,91,18,8,128,3,8,145,173,140,49,137,121,115,75,156,208,20,154,24],[5,29,198,115,131,192,187,108,245,58,178,200,42,235,61,221,77,244,233,187,42,235,3,56,100,81,204,169,90,127,95,234,106,13,196,166,52,80,111,49,143,206,107,24,167,62,16,65,4,33,70,140,109,95,107,146,25,47,251,63,246,252,41,186,197,220,254,76,114,94,38,171,246,174,255,207,225,168,155,17,142,245,54,152,28,34,245,143,106,103,79,126,67,198,135,241],[25,220,141,167,20,47,55,154,200,73,58,25,228,173,162,41,33,136,229,241,199,114,90,96,236,72,83,2,7,13,118,136,56,88,210,165,105,47,68,135,32,107,123,206,86,157,241,219,25,169,15,122,128,105,195,71,129,43,145,255,75,125,121,207,212,49,145,121,173,219,158,58,149,210,202,185,210,203,162,111,193,6,7,132,61,118,93,154,189,82,231,56,35,116,98,144],[3,41,62,125,21,12,29,95,104,204,179,217,66,210,46,186,16,49,203,218,122,176,248,40,59,159,0,125,87,17,180,19,23,210,217,120,119,239,198,78,31,255,5,1,175,141,167,165,12,25,182,163,164,2,188,1,255,176,134,59,21,232,77,210,121,173,71,151,126,163,73,120,209,99,232,78,90,201,163,164,141,193,3,254,176,29,133,151,98,222,153,185,248,122,116,136],[11,18,209,23,149,219,185,74,249,65,213,40,255,224,125,4,64,18,80,71,191,28,176,134,74,216,105,14,140,91,243,249,168,186,201,198,4,150,115,92,181,131,139,164,130,34,122,49,10,186,56,106,187,226,160,255,122,212,89,186,199,254,157,162,209,246,10,144,157,133,155,206,180,91,112,245,51,39,148,126,32,52,0,188,74,239,194,235,241,208,107,148,29,146,116,206],[13,221,154,225,245,142,61,156,96,43,233,168,140,34,171,115,28,74,40,180,251,164,56,8,70,151,200,138,103,51,246,54,171,30,163,111,129,175,113,249,50,92,64,13,42,234,56,206,23,23,218,55,0,39,213,153,101,86,49,154,174,163,55,85,149,123,170,50,19,167,29,239,25,101,9,158,137,185,7,46,181,82,27,173,181,176,196,234,187,159,224,109,138,231,151,224],[17,24,199,138,88,141,81,209,177,185,53,69,132,68,150,193,106,26,175,78,32,51,26,217,78,99,136,173,10,171,51,105,68,43,53,214,45,162,39,72,131,82,223,119,186,138,187,215,6,97,190,55,219,171,251,0,231,106,119,61,232,103,113,246,73,11,70,164,18,163,31,75,188,142,141,153,185,85,173,120,47,63,161,198,74,131,44,55,77,213,162,221,29,24,16,217],[16,118,57,255,47,6,21,69,24,252,14,137,85,119,215,92,72,100,23,2,158,151,214,7,82,180,252,78,231,177,35,4,139,179,155,102,60,89,235,122,117,134,50,216,84,167,20,165,4,98,86,201,211,49,140,72,246,194,252,43,142,109,123,28,76,71,206,239,211,243,184,224,36,242,237,191,214,219,241,224,98,41,140,255,137,65,162,164,173,33,228,119,151,105,174,162],[25,95,56,123,92,243,202,213,139,178,242,97,47,110,178,76,224,49,204,59,124,21,208,190,197,106,86,82,77,189,16,46,159,219,141,18,74,24,50,187,224,177,22,43,21,174,153,239,25,242,53,58,211,189,43,24,219,35,16,172,130,108,129,146,65,130,134,71,66,241,60,30,158,2,11,25,139,190,165,224,41,163,241,105,195,119,202,63,18,166,118,114,186,164,84,253],[9,236,29,105,57,7,45,30,202,98,55,118,181,186,129,24,148,52,126,147,76,140,143,82,207,94,51,35,132,228,85,217,74,80,189,99,130,194,65,103,233,118,139,15,134,34,69,152,25,224,42,160,196,6,131,168,167,202,91,13,224,147,44,223,119,88,255,49,76,35,180,144,142,192,176,18,66,6,190,4,200,102,101,40,163,121,15,163,95,177,90,75,101,150,225,239],[8,140,51,185,11,115,244,163,123,169,131,18,202,176,189,152,221,121,7,178,255,159,223,38,143,11,173,156,227,92,254,140,234,73,207,127,90,27,6,44,120,28,217,169,171,246,13,80,2,141,45,58,22,226,201,36,128,215,24,113,73,114,138,188,200,68,25,89,246,115,242,243,36,154,159,36,146,240,55,187,16,15,137,122,77,107,74,227,49,37,67,148,156,128,19,163],[5,42,200,129,215,146,107,68,91,42,126,89,33,149,34,213,35,155,26,213,200,191,25,42,15,71,62,145,231,218,226,172,77,60,50,78,73,151,135,184,107,155,187,253,165,50,105,213,0,28,252,100,190,156,31,151,118,58,57,13,54,130,142,252,235,190,125,131,113,201,241,198,61,204,160,114,171,176,192,76,11,226,48,102,178,49,153,53,221,29,140,138,209,108,127,98],[20,85,119,174,165,18,61,24,11,51,183,28,80,55,249,249,65,197,251,203,136,74,16,64,177,81,160,144,41,128,46,133,178,231,6,236,180,219,62,58,62,152,175,17,17,139,73,231,13,198,141,215,87,94,178,125,37,68,221,98,77,85,164,99,67,58,238,147,232,180,92,119,140,34,86,31,9,67,186,39,161,136,50,96,67,102,198,121,29,133,124,127,229,132,67,234],[12,165,66,114,11,213,196,32,13,159,28,214,171,105,170,217,155,171,57,80,115,106,94,241,165,184,106,102,165,106,126,242,202,46,125,186,200,152,214,93,230,205,95,17,54,121,4,189,20,57,147,7,34,241,162,164,77,123,21,187,161,16,211,80,49,71,68,226,89,31,119,90,135,249,11,241,188,75,222,138,90,114,184,160,59,157,139,111,254,57,217,41,174,212,230,134],[22,185,53,251,214,148,159,193,229,103,32,228,16,117,179,164,184,248,167,91,242,165,89,203,150,221,227,99,86,221,9,172,2,72,175,37,175,144,68,134,181,20,145,211,50,234,91,156,10,122,153,72,238,160,62,57,35,159,173,92,26,233,61,58,34,11,114,62,140,160,57,233,240,214,152,47,32,17,201,210,233,29,89,110,90,71,86,41,227,66,230,188,199,104,147,161],[14,15,222,234,177,190,77,143,166,171,242,238,18,185,20,212,225,31,166,104,120,117,215,6,239,89,0,107,244,231,198,110,13,9,191,135,104,232,189,127,153,194,27,193,161,107,123,109,13,18,162,148,195,94,179,82,69,11,245,143,142,212,82,102,139,47,185,135,239,73,42,245,46,63,95,137,244,89,44,114,176,209,161,233,9,243,61,73,80,92,174,151,56,54,84,80],[22,249,249,82,122,153,71,240,8,42,255,102,219,118,139,64,188,173,201,96,126,147,251,69,226,177,143,168,85,43,91,63,63,118,8,205,7,188,211,230,61,234,179,45,95,162,113,102,16,198,4,159,107,100,122,139,82,158,34,248,217,10,26,104,185,2,211,197,113,56,172,149,41,46,92,79,96,46,17,164,74,251,140,121,32,180,234,217,7,133,130,61,37,166,144,192],[3,192,239,195,78,193,31,80,119,8,170,215,243,141,31,252,91,187,220,141,147,135,249,162,87,173,141,217,159,130,48,209,163,149,56,47,190,238,218,59,244,221,41,249,8,1,84,26,25,51,31,173,131,183,168,119,112,83,62,152,39,23,167,219,52,132,177,190,72,223,238,111,101,159,197,34,108,219,176,145,17,237,57,26,140,107,57,233,61,145,114,34,28,0,55,157],[10,246,216,255,234,218,62,255,77,77,161,59,57,196,142,8,41,50,45,237,200,149,253,82,121,168,49,67,190,117,155,15,212,199,10,45,55,123,142,9,216,115,78,209,202,158,193,218,21,189,67,244,124,240,244,137,168,108,225,29,249,63,15,161,35,78,162,56,167,114,128,219,9,37,147,203,135,193,9,164,197,52,149,52,67,192,203,123,20,223,143,39,130,183,9,179],[15,72,142,143,180,203,92,65,216,6,252,31,7,202,169,104,154,47,211,17,83,248,115,120,167,68,4,39,58,114,110,238,130,71,252,235,79,27,106,27,187,91,29,155,102,188,191,184,1,166,249,90,144,113,3,136,11,230,253,210,145,171,122,142,142,56,171,152,113,129,232,78,244,227,6,129,24,197,62,174,121,66,11,181,72,76,174,31,167,1,139,87,16,25,149,244],[6,85,134,153,158,60,209,89,59,36,7,89,112,100,166,15,70,112,209,77,222,218,44,45,132,239,120,182,206,199,27,112,156,46,202,217,108,104,127,23,87,255,184,185,1,166,160,105,18,37,247,12,197,41,237,120,125,2,156,167,213,18,189,202,28,90,224,123,230,235,104,221,253,138,43,249,89,232,220,135,19,49,178,102,159,146,151,12,187,98,26,92,135,124,103,136],[23,14,145,92,25,222,51,124,221,238,25,125,48,176,19,198,49,192,89,4,166,215,137,205,140,129,136,19,63,131,13,78,14,157,57,247,21,197,153,246,144,6,231,243,97,19,128,225,0,80,45,55,169,10,21,21,144,235,61,181,152,15,199,157,39,226,221,98,4,83,46,162,113,142,17,144,252,67,132,249,187,126,239,183,136,53,8,50,187,25,161,24,56,84,197,13],[25,39,213,31,8,209,190,131,82,225,202,132,218,238,203,205,25,49,67,164,215,74,93,168,18,44,93,191,240,68,23,244,10,67,10,187,8,135,244,175,56,132,101,100,245,184,142,20,11,212,253,187,17,226,138,174,248,23,139,93,29,228,66,61,128,9,65,245,127,245,152,228,27,137,150,89,191,232,150,108,40,93,174,133,72,37,74,243,178,167,46,170,20,99,202,52],[20,104,167,160,44,160,83,167,4,48,103,64,232,161,133,105,148,123,20,25,225,212,48,63,183,225,33,2,93,180,180,148,251,65,115,202,210,70,165,118,243,52,212,132,115,248,245,16,19,193,102,68,191,102,239,178,89,198,231,90,191,177,222,253,212,79,0,43,222,104,149,186,176,153,106,190,229,247,29,76,142,188,34,249,52,183,119,62,247,91,160,207,161,84,172,112],[16,157,189,82,176,46,54,94,60,12,196,147,53,159,45,59,43,185,22,80,144,29,175,185,34,172,80,83,63,100,171,224,193,42,161,51,192,98,131,220,120,68,10,124,237,63,251,90,11,167,23,137,84,163,167,119,145,210,134,93,26,161,134,239,215,117,95,77,85,120,217,39,159,139,149,221,187,171,64,155,65,19,142,242,249,246,85,139,59,131,91,206,48,226,134,81],[4,37,210,0,234,196,48,132,62,233,130,231,108,248,236,206,237,38,214,84,140,178,86,84,51,96,214,161,48,202,191,107,217,41,36,198,185,45,184,254,14,248,91,177,73,158,72,38,11,144,95,157,136,252,210,20,186,200,3,207,230,95,250,10,81,232,172,250,182,79,138,252,1,6,247,61,241,153,39,131,187,176,186,172,169,192,11,102,141,175,188,67,20,121,159,211],[2,107,238,84,94,74,104,13,212,3,187,136,134,188,148,253,79,50,213,23,133,60,99,172,187,199,46,123,30,193,203,86,227,247,168,124,211,106,168,217,109,63,60,59,51,208,199,181,2,48,197,41,26,97,15,102,2,199,221,141,35,154,32,231,166,129,185,112,172,112,74,194,48,187,103,246,114,227,163,151,172,178,33,107,100,87,205,174,170,137,182,203,245,176,108,41],[3,74,180,2,128,108,169,171,254,207,213,159,62,33,11,1,194,94,204,205,122,41,90,202,184,6,126,93,79,14,87,39,56,72,195,161,23,26,214,66,222,208,161,221,163,87,39,80,1,31,114,112,136,6,133,96,184,186,177,130,19,167,211,128,51,106,73,2,7,199,152,191,38,106,145,15,169,56,24,222,138,136,153,129,85,146,119,42,24,85,91,195,150,188,123,252],[2,19,6,118,102,183,84,136,64,12,8,17,26,235,78,207,199,48,69,239,191,181,90,210,30,141,194,29,104,196,177,241,109,8,216,186,68,212,80,241,209,141,17,98,148,31,191,249,22,64,190,6,112,18,3,13,151,94,98,224,115,20,130,184,159,35,212,118,230,192,27,176,58,50,21,203,37,140,86,69,97,140,81,6,93,162,196,100,238,11,97,56,173,164,93,89],[25,42,217,112,106,168,57,5,150,206,203,36,194,146,4,120,54,209,226,190,226,93,14,158,1,140,98,144,195,254,223,89,25,150,36,205,197,94,149,62,36,159,113,54,78,112,236,228,4,231,220,9,86,8,248,19,241,72,28,117,168,16,119,227,47,202,199,66,23,94,144,43,45,74,61,113,175,98,17,239,40,223,2,202,19,183,38,82,43,195,83,206,71,194,88,168],[0,234,162,185,69,65,234,129,142,205,102,156,160,237,214,245,227,115,150,113,143,119,103,39,237,20,140,211,29,91,157,152,28,251,175,168,137,150,52,16,184,167,217,202,119,210,16,252,9,114,177,86,31,245,227,212,45,25,167,34,213,201,8,61,29,54,81,243,239,139,127,203,233,111,218,88,231,134,252,162,112,226,173,178,119,118,203,182,176,194,122,107,11,68,23,150],[2,99,217,22,112,209,187,26,218,154,163,9,166,219,110,208,67,173,88,232,25,97,206,148,93,186,233,102,151,221,172,13,146,86,221,255,221,154,124,32,172,164,87,82,52,140,152,119,19,206,52,160,99,29,95,64,237,193,51,209,229,134,33,176,211,129,180,212,136,205,99,95,30,192,98,207,235,40,86,138,57,241,184,24,234,202,98,163,102,110,200,117,213,252,82,186],[17,251,96,232,140,51,61,70,255,198,112,67,126,34,252,83,138,111,114,221,62,95,3,109,78,192,207,179,63,98,51,221,178,11,173,69,190,79,252,65,243,32,119,178,227,22,236,195,17,175,228,139,103,157,57,214,108,179,63,202,49,160,229,144,38,212,142,162,181,97,58,165,173,62,241,28,212,193,103,9,114,9,163,211,226,121,1,212,82,104,211,182,24,138,217,26],[15,5,87,4,34,19,10,55,85,240,79,107,65,164,128,30,166,201,108,166,124,91,125,43,244,12,139,44,65,254,127,27,0,97,209,1,78,127,9,209,0,76,177,199,207,188,69,179,20,114,47,140,230,19,125,10,140,102,119,160,83,202,88,174,9,203,22,146,197,131,81,109,219,20,87,90,36,136,107,143,16,29,18,160,80,173,132,132,221,248,225,161,48,245,245,158],[21,100,185,44,156,80,31,235,201,77,67,218,82,29,2,55,104,157,173,109,196,98,10,53,212,102,166,40,84,145,6,46,49,120,9,223,60,209,127,80,51,113,209,40,103,192,118,105,12,226,41,29,238,7,10,37,166,47,4,94,243,136,249,138,245,183,214,74,66,0,190,1,84,55,129,189,229,131,103,251,115,236,205,30,107,29,122,36,89,147,212,145,233,10,238,198],[24,207,50,155,238,139,146,221,80,230,188,28,100,68,8,188,91,238,151,17,9,187,114,115,203,60,155,29,127,76,118,244,217,146,240,0,174,182,119,62,28,117,249,39,194,47,178,76,5,197,109,206,163,65,153,160,68,13,12,5,111,199,138,141,217,190,252,98,48,206,161,180,116,188,162,184,116,60,37,219,93,208,65,185,202,21,141,161,32,202,217,194,45,173,2,136],[23,9,253,197,161,170,241,141,37,86,156,136,186,112,217,249,106,91,100,187,178,30,27,86,102,123,105,16,75,76,105,197,172,178,182,52,185,128,61,165,168,247,233,48,154,227,173,154,5,209,212,252,65,156,44,248,57,166,242,228,70,243,48,48,214,125,134,185,64,91,66,138,32,73,30,27,167,173,189,29,95,4,42,184,74,138,122,185,250,207,224,55,187,14,50,61],[6,255,12,153,144,193,212,160,228,134,35,152,170,174,161,99,228,65,98,196,71,53,38,101,8,131,115,130,39,149,102,163,139,120,165,255,38,38,2,47,213,19,58,34,70,216,163,241,0,8,64,28,186,220,222,11,45,240,245,236,77,193,111,14,92,135,73,183,250,193,164,49,57,180,48,197,171,44,36,197,236,47,59,36,223,36,82,27,173,98,174,201,51,148,4,70],[14,249,159,165,206,110,116,109,117,200,150,203,245,165,68,25,170,238,152,28,217,149,236,161,1,154,240,225,163,121,144,234,253,158,194,158,21,7,97,88,55,218,68,116,230,30,239,83,7,99,121,144,1,107,201,198,132,193,24,242,16,117,36,59,208,206,139,154,35,188,66,241,138,206,241,53,86,220,53,154,213,232,98,57,196,229,140,92,236,97,91,58,62,166,204,216],[17,20,38,58,78,187,3,252,111,177,45,41,154,253,77,175,131,246,227,92,201,204,51,42,41,216,151,54,144,201,23,104,137,92,161,173,252,131,3,132,50,135,111,4,171,39,144,98,20,40,114,255,26,136,213,62,64,42,107,222,170,156,72,94,33,149,107,208,112,155,207,90,48,15,95,155,186,133,127,209,70,61,229,44,238,6,39,134,135,47,196,32,234,199,66,115],[18,46,227,200,250,130,148,134,28,173,39,132,82,250,125,77,102,4,96,244,51,1,7,21,87,83,80,152,162,168,85,136,11,119,75,131,83,110,13,196,19,44,124,166,141,48,34,154,21,103,90,251,119,39,23,186,228,177,35,84,13,87,223,58,246,30,224,92,169,228,95,81,239,98,86,220,152,183,220,159,56,79,49,153,167,23,173,155,36,165,202,119,178,97,189,128],[17,28,253,149,109,32,13,50,188,33,28,248,255,186,115,236,57,87,100,141,185,159,157,17,126,203,105,47,69,208,133,217,23,130,12,134,105,207,105,198,189,114,167,142,189,201,100,94,12,214,40,43,206,3,127,110,97,203,132,41,180,120,224,161,225,82,25,53,242,120,2,43,223,250,105,225,92,23,140,134,154,182,42,182,2,25,168,55,3,251,130,119,136,134,98,228],[22,219,152,252,165,234,85,226,83,85,71,5,79,171,209,72,243,160,160,20,203,52,137,106,255,45,51,221,113,199,175,15,71,166,204,172,15,149,130,224,35,121,97,183,198,30,239,115,22,227,220,53,59,67,56,208,53,43,106,179,74,125,152,38,22,158,172,226,212,248,221,74,138,249,108,59,59,140,241,109,176,206,110,153,39,60,137,121,202,69,138,238,247,234,173,138],[2,13,127,164,216,68,240,140,217,155,192,78,173,47,106,230,182,230,56,17,33,208,102,52,197,118,248,63,124,135,221,178,8,165,149,109,21,120,154,87,77,43,77,42,136,171,210,147,19,86,15,174,115,180,230,114,122,225,175,28,199,63,179,76,148,155,140,140,85,48,106,185,219,5,88,190,193,40,98,146,15,1,57,11,114,52,139,235,233,14,96,178,230,175,75,82],[10,52,207,49,203,160,224,241,67,63,103,176,254,192,67,160,169,109,63,115,127,150,70,142,73,183,159,12,101,150,205,104,56,80,183,203,130,100,203,226,22,169,57,58,160,32,232,249,25,165,2,139,125,45,225,154,58,93,55,163,240,172,80,56,101,212,152,235,40,137,84,193,11,37,53,96,86,223,58,38,214,80,218,89,239,32,113,125,188,172,170,147,135,249,131,26],[4,168,105,219,214,92,246,241,170,179,103,196,19,139,64,117,201,3,134,182,32,90,38,21,199,254,22,198,167,96,195,109,113,208,42,141,159,205,250,123,164,192,12,121,77,30,144,242,21,173,33,60,106,145,90,3,68,73,111,133,39,60,18,18,14,188,81,133,53,160,230,243,12,180,130,209,128,60,60,220,206,158,73,255,178,148,177,5,182,50,74,70,143,253,65,232],[3,113,238,89,173,119,33,152,90,30,169,74,142,243,70,130,43,196,151,82,102,125,236,128,115,167,152,96,113,163,117,180,104,7,226,16,207,213,125,179,118,122,166,231,198,242,72,52,21,56,163,178,171,52,218,39,71,246,156,211,55,180,246,2,157,52,14,42,25,224,198,159,201,158,146,94,103,45,225,236,225,5,175,233,81,164,39,119,34,121,207,216,229,86,31,70],[6,78,100,188,84,12,86,45,201,122,122,32,109,53,213,171,33,0,53,207,112,148,229,144,209,9,223,27,190,205,62,90,217,25,190,125,138,55,155,50,84,86,152,120,99,46,19,18,17,7,117,186,241,12,76,53,140,125,95,88,68,22,180,82,66,188,174,134,113,23,234,48,161,5,243,29,60,146,25,13,21,127,213,91,247,61,240,42,165,22,87,132,29,224,12,152],[15,125,221,84,181,201,120,2,54,70,77,24,113,154,52,251,177,34,171,220,230,189,24,4,102,32,211,130,231,168,119,1,51,130,97,225,244,164,183,228,41,66,14,150,105,184,93,35,18,17,42,1,103,81,244,127,248,142,213,178,35,130,111,221,84,133,156,127,127,98,137,37,182,78,51,220,208,113,182,8,10,191,180,176,11,14,130,67,44,99,103,74,108,142,96,196],[14,215,8,195,222,56,171,84,51,142,232,54,229,6,48,75,126,51,59,138,194,117,131,170,254,161,244,7,89,64,230,192,78,108,229,253,40,120,132,210,192,48,159,19,187,210,251,136,21,157,138,202,126,90,187,90,53,99,92,188,45,182,120,254,119,127,189,18,252,198,153,109,176,77,103,128,125,216,138,75,125,139,123,4,79,166,81,145,78,131,24,5,10,118,129,130],[0,149,91,63,22,199,115,54,7,221,171,142,86,45,61,129,13,155,141,109,123,104,42,247,14,208,10,14,162,143,60,205,23,127,115,49,61,133,128,55,41,9,12,114,81,14,86,108,22,143,161,131,236,180,240,222,214,247,142,155,134,202,160,9,159,199,95,88,80,246,71,189,123,29,161,133,178,93,162,118,79,142,36,249,42,149,181,80,94,78,229,198,6,247,241,209],[0,64,91,46,216,66,27,102,94,252,166,208,203,171,52,212,204,242,55,156,43,118,216,90,124,54,165,149,49,99,13,249,231,74,169,23,173,3,44,223,25,147,219,56,140,22,149,178,15,194,249,254,253,149,27,178,32,248,149,42,244,139,169,30,106,232,214,168,234,60,209,108,135,16,158,126,81,62,67,132,98,99,113,87,163,123,186,70,252,131,155,240,30,0,10,146],[16,95,234,43,2,165,209,134,48,179,131,162,45,244,109,244,242,138,139,4,213,38,116,160,46,145,42,6,117,114,27,222,117,119,16,5,136,69,54,159,154,111,205,217,34,247,113,57,13,100,209,190,166,87,38,209,17,234,53,250,153,21,203,39,223,178,190,60,72,81,169,60,185,3,103,223,219,116,25,165,117,206,244,88,134,155,143,131,25,129,15,122,98,42,149,129],[7,194,147,45,43,141,181,20,90,119,242,165,40,88,116,144,254,116,107,132,185,101,189,28,83,177,101,32,191,97,96,25,54,124,244,88,83,88,58,4,188,138,178,159,0,229,32,254,4,145,21,103,91,52,112,159,182,114,233,148,161,36,164,154,57,37,99,67,181,239,116,233,202,56,199,225,93,94,13,79,228,155,169,247,236,234,175,15,60,235,143,102,93,105,186,89],[0,17,112,166,32,43,31,125,223,22,250,189,60,241,252,203,158,110,127,171,73,56,43,146,65,51,180,96,31,5,244,2,9,218,58,188,251,159,189,135,218,149,20,20,186,172,235,177,8,57,9,66,146,211,131,105,48,175,99,74,145,237,172,152,252,207,63,41,76,115,231,65,61,128,163,141,64,216,168,137,117,104,26,137,101,153,75,147,62,184,59,54,103,79,33,29],[12,13,121,70,116,198,57,101,46,61,152,114,92,169,110,226,112,72,251,3,196,96,126,80,144,122,252,137,108,202,87,12,126,131,239,114,71,168,244,167,246,235,232,251,53,161,143,34,20,182,165,221,18,203,140,194,123,21,126,229,15,248,106,24,249,190,156,113,80,169,211,214,4,30,74,52,219,255,145,171,166,113,126,229,76,63,191,133,208,158,75,164,10,197,6,53],[21,227,244,128,153,77,127,250,25,60,66,62,70,127,51,204,220,16,137,191,84,3,15,238,248,8,129,215,185,187,40,144,37,1,132,31,67,142,248,55,89,85,26,130,121,228,201,119,6,97,243,200,96,209,115,27,136,151,108,31,11,44,107,169,84,94,116,143,46,99,135,79,182,197,254,60,173,58,22,207,66,4,95,232,223,11,26,147,84,215,185,33,236,199,171,49],[12,93,231,127,119,48,144,51,130,58,89,109,167,38,138,79,64,235,5,153,78,221,5,7,180,252,165,112,153,214,90,162,91,156,242,254,156,55,251,204,202,166,108,50,111,90,105,180,11,107,211,163,137,192,216,156,155,208,32,143,102,15,40,240,35,172,49,33,159,12,164,243,91,241,94,142,216,110,139,26,183,167,118,216,192,128,160,70,211,90,189,45,176,254,132,51],[19,138,226,58,104,36,246,166,144,226,162,5,83,253,76,40,43,96,183,122,135,144,234,197,198,68,81,2,240,141,153,41,41,134,218,35,236,115,22,101,218,209,43,31,205,109,243,39,7,199,230,139,57,103,191,99,235,169,138,206,127,165,213,253,245,102,227,2,29,98,118,196,6,203,162,2,33,252,197,7,167,179,74,220,62,216,226,19,73,103,62,168,127,201,113,178],[3,60,155,207,141,150,108,99,166,219,206,142,137,153,10,248,249,173,40,68,56,230,37,87,26,67,161,95,66,166,34,101,40,223,119,65,98,104,224,86,187,148,120,228,41,81,175,253,13,239,4,175,110,231,28,96,159,33,131,139,234,167,214,195,203,142,240,163,240,249,46,8,184,210,68,24,207,232,112,155,81,104,137,42,211,92,21,108,248,67,181,170,56,81,190,241],[1,175,112,131,26,228,77,198,150,122,50,131,59,136,28,155,120,73,47,186,114,71,80,214,96,196,17,234,224,114,19,164,229,193,35,217,143,135,21,196,67,171,191,99,140,164,103,60,16,208,178,208,166,175,37,126,255,37,236,117,239,99,3,196,125,168,92,62,90,70,38,129,247,42,20,224,198,32,200,169,245,98,107,95,252,8,186,54,240,20,234,79,178,197,1,131],[25,238,128,140,99,172,167,152,103,24,158,26,132,129,240,108,185,37,175,81,201,247,112,16,229,122,146,0,82,114,174,197,190,210,13,191,50,217,70,170,233,118,179,164,25,166,132,241,0,189,48,149,168,254,249,142,50,112,162,116,41,129,4,115,52,216,81,73,6,4,235,11,52,251,216,144,143,128,150,103,146,81,89,93,152,76,246,113,110,196,103,176,169,168,254,60],[5,221,205,168,135,34,252,199,96,60,127,248,200,141,207,118,80,246,53,8,214,11,223,243,91,57,94,151,232,69,149,38,8,92,11,216,101,11,71,215,237,212,188,24,22,148,82,189,21,231,207,120,169,16,0,253,146,187,240,51,146,226,231,60,87,66,81,162,148,242,237,194,238,135,0,71,55,96,95,132,161,179,140,111,31,42,241,63,8,183,85,253,238,17,182,128],[11,8,88,200,26,145,167,68,0,161,120,139,203,171,161,145,209,127,36,44,221,139,110,1,138,47,69,133,177,233,210,251,216,75,212,61,17,167,232,109,100,21,216,25,222,179,196,185,7,249,34,118,180,163,215,34,23,172,113,160,221,97,108,228,166,0,50,86,4,145,53,123,250,50,126,115,247,206,36,14,21,16,130,28,198,9,193,18,156,107,4,134,106,119,155,149],[12,50,165,78,164,109,120,151,169,39,140,48,30,159,138,12,40,178,139,86,224,236,233,37,24,13,36,71,28,6,223,138,28,125,187,164,77,36,49,42,220,46,171,82,110,152,222,175,15,180,202,229,105,243,145,39,21,106,70,63,90,159,137,187,103,124,116,14,155,237,135,170,227,104,133,10,103,182,47,85,41,29,14,25,30,42,77,33,127,12,171,104,17,225,128,224],[11,172,249,25,151,65,23,41,98,251,46,254,207,48,68,65,5,79,206,34,0,105,83,105,59,18,240,37,23,117,103,52,157,228,215,160,81,221,159,47,224,152,12,208,238,218,27,62,5,130,50,154,8,213,200,6,255,206,153,253,33,96,62,248,168,238,137,55,224,127,128,66,47,189,125,0,228,231,241,146,145,18,216,97,32,23,10,73,162,141,63,215,201,10,68,118],[9,148,20,175,149,7,208,218,233,152,246,86,143,77,231,105,205,163,16,194,23,188,175,132,88,119,163,137,171,184,216,89,132,95,99,23,249,28,139,15,41,31,160,183,47,208,55,154,14,148,1,219,193,237,38,49,139,100,187,111,114,1,207,62,154,222,180,174,33,238,31,119,18,238,226,217,59,119,84,100,219,213,114,111,136,94,233,38,30,188,110,180,26,143,65,96],[18,165,78,229,29,17,126,254,30,107,60,149,111,216,27,14,128,173,234,245,1,107,244,194,35,64,42,141,177,219,149,224,207,162,134,24,99,185,225,215,49,5,151,208,126,189,51,1,9,46,99,152,180,59,2,158,49,16,96,20,95,135,252,212,50,123,48,248,197,28,99,236,246,120,83,109,14,16,212,238,87,252,126,157,188,170,227,116,39,25,164,96,204,216,197,143],[12,188,76,144,56,96,82,225,64,84,69,149,72,229,37,89,211,166,35,253,66,204,145,116,219,252,93,51,60,97,197,8,22,146,105,143,215,118,252,61,49,134,232,88,159,170,180,157,18,24,225,193,44,170,89,14,167,191,119,101,234,103,219,190,228,152,215,163,202,96,136,44,141,75,98,232,218,83,240,182,205,226,201,155,216,62,79,12,8,102,187,83,234,147,153,86],[14,219,238,94,152,39,154,18,235,127,161,74,103,110,142,11,62,63,25,17,238,66,227,114,127,137,242,92,71,87,211,46,83,57,2,47,118,185,243,31,16,245,70,95,42,44,187,118,1,107,253,202,117,131,246,2,79,155,100,63,173,166,116,125,206,87,219,25,220,244,124,39,82,200,17,64,102,150,192,109,205,88,228,62,127,203,175,18,191,152,3,65,71,153,55,29],[17,239,27,12,97,68,89,156,168,143,171,148,197,105,23,8,121,49,14,182,135,163,67,245,3,189,224,113,226,5,154,218,255,172,108,224,190,237,50,221,14,227,21,210,74,114,221,98,15,197,228,216,153,143,70,36,159,187,228,36,125,151,116,229,207,197,94,177,247,69,156,222,204,3,164,61,186,153,113,128,203,202,154,136,93,2,45,59,62,151,94,246,107,241,187,228],[8,36,114,109,46,250,82,34,186,137,251,145,46,10,252,117,19,190,132,210,192,168,213,178,170,245,167,56,107,89,96,203,182,160,88,30,111,198,181,120,197,97,225,171,57,82,163,174,1,159,204,129,100,104,39,106,33,104,17,66,23,172,146,169,137,137,5,124,13,235,144,195,73,109,166,28,138,5,167,245,98,46,51,63,99,61,53,85,22,162,131,128,69,76,41,237],[14,12,123,169,80,124,242,188,154,95,9,173,2,80,150,85,142,225,124,205,172,67,110,146,140,60,18,101,229,33,36,160,253,220,22,114,230,226,32,57,70,44,46,201,213,51,37,9,3,204,84,119,138,100,160,9,87,115,81,152,109,86,33,31,103,169,221,246,36,90,79,106,62,7,43,188,189,194,56,81,234,140,60,244,221,204,43,75,198,95,31,26,198,211,158,184],[22,103,154,4,170,29,62,150,169,189,115,177,19,83,240,233,201,239,44,206,130,142,253,240,162,189,16,232,243,96,186,151,89,233,194,78,181,130,111,237,249,246,72,15,223,172,83,96,1,199,230,21,159,151,64,97,7,110,74,126,95,83,213,151,117,6,184,125,72,162,231,225,165,221,173,204,139,59,250,77,179,234,110,171,125,144,206,193,20,113,35,239,229,161,78,96],[13,43,85,179,44,124,210,123,42,90,211,12,212,197,75,111,31,247,66,96,234,141,224,6,210,2,87,128,167,152,157,56,188,66,158,118,128,230,12,28,116,30,216,43,145,68,65,227,6,57,36,64,22,26,21,30,138,250,57,166,3,136,53,188,129,167,41,48,176,133,20,18,162,242,225,218,117,17,73,45,213,30,112,167,180,25,161,178,150,210,24,39,97,178,243,142],[25,165,8,192,167,197,104,163,175,250,117,93,203,220,81,173,80,3,76,241,242,78,35,46,205,63,108,83,57,127,12,3,142,75,0,20,69,237,192,30,121,200,54,83,181,76,22,104,15,28,43,4,157,68,223,53,216,202,0,107,51,204,129,211,212,243,132,215,60,232,12,58,102,243,220,57,128,247,11,106,48,34,195,34,208,81,14,139,76,143,253,21,46,202,83,100],[0,140,225,165,106,123,0,15,116,166,77,71,110,63,83,213,236,114,176,224,94,79,168,206,112,232,53,150,89,76,23,137,180,46,125,63,213,10,222,129,80,84,113,212,117,72,252,121,3,86,82,179,19,5,69,44,235,22,88,204,48,108,137,20,184,179,140,157,19,191,41,194,116,52,229,141,181,116,139,57,88,99,23,231,127,155,158,64,32,210,213,48,205,232,169,37],[17,137,119,227,110,97,221,181,238,127,81,4,16,165,126,150,134,148,128,74,214,170,47,227,237,2,89,248,144,93,133,220,113,135,80,156,88,107,174,194,104,121,176,97,133,2,199,200,3,221,221,46,135,84,156,57,230,81,2,75,89,185,68,208,214,95,236,219,211,99,45,210,165,63,129,230,131,119,113,118,243,134,119,239,132,113,71,103,100,101,224,168,152,12,27,34],[10,11,47,150,36,70,244,147,67,46,230,182,154,69,94,85,89,183,192,41,204,162,86,112,108,102,196,210,141,84,159,93,33,251,14,230,248,254,83,130,179,33,60,194,21,153,136,217,4,168,66,67,56,190,45,101,179,208,176,231,19,143,11,222,111,46,181,69,212,33,160,24,94,75,41,203,31,61,2,57,113,235,75,98,59,45,76,120,245,104,5,45,135,242,215,189],[7,24,223,11,89,133,125,180,1,106,237,83,199,213,15,116,55,101,138,229,28,182,49,201,111,220,119,145,91,81,149,86,38,64,99,12,170,39,203,111,85,21,118,126,231,39,236,134,21,17,112,61,254,89,199,232,65,183,95,248,196,161,184,152,81,39,28,16,220,89,131,11,48,242,75,47,243,172,142,14,33,106,30,112,142,130,162,58,45,98,121,166,122,68,103,123],[10,252,118,127,116,58,239,74,163,138,84,251,18,174,123,111,163,158,79,212,173,167,102,40,202,208,149,60,104,53,210,208,174,134,123,112,12,54,113,155,114,2,207,166,146,109,153,186,6,248,46,242,199,29,123,245,219,167,255,38,168,93,170,26,211,122,99,90,39,187,169,96,157,254,109,80,159,108,82,153,218,159,201,150,201,22,89,34,110,96,135,95,180,16,65,190],[20,112,247,219,15,202,160,10,67,15,181,187,58,66,102,137,230,97,161,11,140,19,154,185,195,97,48,182,122,119,26,119,236,173,195,80,78,156,230,59,209,24,184,219,49,48,104,239,21,252,188,184,96,34,222,119,214,255,172,66,70,97,21,222,67,97,230,204,21,24,159,80,150,22,182,58,127,142,174,53,24,231,198,62,151,182,178,19,84,63,47,23,54,18,200,41],[14,243,97,48,74,218,97,253,134,194,102,241,135,11,108,132,103,154,136,98,64,169,222,252,57,222,104,99,161,22,200,146,59,55,38,148,59,27,175,0,112,225,194,38,196,89,62,255,8,171,108,62,48,124,144,211,36,249,150,83,173,239,186,158,96,145,153,170,168,223,204,218,72,18,54,219,186,162,85,249,181,101,242,101,81,55,100,90,196,66,36,4,156,152,231,140],[3,248,172,131,48,132,13,138,177,93,170,39,207,117,178,197,128,188,190,2,19,1,103,239,18,38,207,75,105,51,91,92,62,253,224,32,129,68,135,240,152,209,31,133,4,67,55,196,2,104,187,162,254,4,24,25,243,40,64,178,164,205,50,23,150,125,43,103,235,125,116,20,19,23,182,88,150,59,179,233,39,204,145,187,73,82,229,5,69,160,132,152,70,73,235,125],[18,254,39,190,159,176,98,240,25,93,82,148,56,240,250,250,78,105,85,193,155,125,191,117,187,26,55,234,197,229,71,197,138,34,62,208,213,0,142,194,102,39,222,255,151,201,61,146,22,209,156,85,33,67,61,3,223,63,58,176,159,10,104,171,241,166,241,69,196,48,55,234,231,189,197,217,230,202,1,236,94,107,78,35,254,102,22,196,103,140,106,16,80,194,176,60],[4,4,212,63,5,222,79,46,78,249,37,203,64,13,0,35,218,15,156,67,17,52,26,134,55,143,228,44,250,14,161,69,108,87,170,138,138,173,16,21,60,152,158,59,96,105,151,195,21,128,45,3,208,245,125,59,56,177,190,186,19,223,62,233,177,128,229,61,44,149,13,165,217,172,5,140,113,114,171,196,101,216,62,235,57,101,195,15,78,98,227,3,95,114,2,113],[23,183,221,249,237,222,216,72,241,164,248,228,202,56,110,61,54,70,167,79,31,136,149,76,73,148,182,39,96,113,31,208,147,194,81,13,49,148,42,195,58,124,236,223,60,171,104,73,11,66,88,177,179,139,42,119,125,254,176,144,142,144,210,130,142,93,42,217,50,60,202,221,41,95,64,164,17,48,156,129,149,138,126,45,246,157,124,1,141,232,246,2,148,9,168,43],[5,219,194,70,122,248,44,251,227,241,29,157,106,150,228,93,225,181,103,49,33,232,133,32,205,253,187,180,13,182,129,18,46,32,147,72,144,55,194,136,247,108,94,82,97,131,230,91,9,97,123,120,18,113,6,204,121,174,237,234,3,254,115,34,184,222,185,196,35,61,71,120,146,12,58,162,202,109,26,20,94,86,7,153,162,188,59,45,153,249,100,81,96,95,173,205],[4,120,18,137,88,155,74,98,239,40,89,255,13,187,100,8,167,131,44,78,163,214,214,47,133,194,77,235,17,87,208,233,170,88,93,98,16,210,94,192,44,202,242,110,176,227,218,61,15,89,186,18,10,111,117,215,144,245,254,29,118,144,201,43,170,182,252,181,88,119,77,151,240,162,240,188,215,90,197,58,26,166,192,253,129,196,5,199,197,196,13,220,110,177,104,45],[23,206,125,79,3,223,45,140,49,56,226,235,103,244,123,140,120,53,30,21,147,122,70,193,63,39,85,44,115,81,96,20,72,137,140,77,83,101,5,37,26,197,228,202,33,60,2,152,0,216,33,226,38,30,81,12,171,45,235,153,255,202,243,220,147,254,66,212,77,53,79,54,153,18,119,90,113,217,183,122,82,2,181,5,128,132,122,254,72,5,57,83,151,59,157,207],[22,151,117,246,11,242,6,226,154,193,42,7,170,95,163,148,250,251,35,224,73,244,149,16,55,40,213,34,86,89,157,52,26,102,106,138,72,212,188,252,133,64,9,224,101,198,13,243,22,82,215,186,223,183,161,146,24,105,72,76,108,121,87,37,248,93,131,183,138,171,56,235,1,7,216,182,238,129,227,171,57,134,177,177,102,38,122,122,168,42,118,129,231,121,71,8],[5,207,90,222,229,228,44,200,194,163,107,203,254,248,173,197,94,205,200,59,83,80,62,177,231,139,169,227,193,125,90,159,210,139,125,173,249,244,56,184,246,255,47,224,39,176,99,237,4,62,141,59,43,162,197,144,68,103,185,59,24,125,243,97,16,241,18,166,198,223,5,15,156,111,58,104,232,26,68,188,192,229,165,156,229,123,198,235,149,162,249,133,89,122,8,180],[18,27,147,47,70,206,22,72,104,60,237,54,104,72,31,20,134,153,79,34,190,227,226,63,164,206,255,82,52,41,117,56,221,29,165,109,105,223,85,162,66,22,248,34,224,14,235,166,1,249,28,26,252,49,70,69,156,175,112,166,69,78,173,27,165,157,20,104,99,35,22,160,5,82,206,177,225,110,174,221,207,213,142,141,223,108,48,227,210,61,61,78,178,33,188,35],[15,235,66,168,166,23,38,226,8,208,123,35,222,105,75,184,32,108,125,89,88,104,75,160,207,56,254,187,131,130,119,59,65,147,56,7,11,241,190,101,21,219,94,90,45,1,154,212,15,45,47,253,183,111,95,103,225,142,172,118,10,157,65,104,76,185,56,8,240,91,167,34,233,137,119,199,186,214,122,159,185,167,49,20,20,190,83,157,196,7,66,141,108,103,129,47],[8,233,210,100,170,131,115,241,22,25,65,63,9,233,250,80,222,213,236,77,45,12,120,86,66,60,213,6,198,24,5,253,60,180,78,113,230,45,241,110,148,119,80,4,245,179,51,22,1,80,61,226,26,143,163,49,231,39,0,130,22,46,254,232,94,35,183,36,120,73,157,108,3,73,138,168,50,54,254,129,215,46,187,40,220,178,245,21,181,141,69,184,250,36,209,202],[19,48,184,7,21,120,207,47,232,180,134,225,162,153,233,29,9,97,46,69,233,114,2,190,127,145,190,187,173,241,121,161,143,230,190,183,63,140,57,237,124,92,251,129,2,171,124,100,4,50,7,43,98,183,224,102,119,169,72,72,156,133,115,83,40,13,40,167,242,117,230,201,21,206,154,66,168,49,69,244,208,108,137,209,49,177,43,12,114,106,106,139,202,133,79,63],[12,174,167,121,215,224,159,209,46,154,191,234,65,86,158,138,140,42,58,113,153,81,235,15,126,184,37,115,94,105,45,205,125,13,173,217,59,192,88,5,131,123,9,143,176,38,255,56,13,227,206,38,56,179,174,242,229,141,78,184,122,226,18,14,246,85,134,124,77,93,115,57,28,191,5,38,151,104,64,59,59,253,58,97,51,3,135,60,243,103,223,79,22,197,101,217],[16,204,155,144,216,63,255,7,27,10,239,173,171,209,89,32,37,186,188,236,183,30,113,130,121,220,184,231,30,54,172,8,11,198,45,203,174,177,157,48,122,51,93,169,10,188,175,74,17,81,255,250,75,109,217,194,180,12,116,140,20,149,82,233,180,110,150,183,113,217,189,196,153,13,120,37,107,196,69,113,182,86,1,211,208,201,138,202,211,66,55,55,96,53,214,245],[20,3,46,25,197,131,167,142,135,88,227,3,8,137,139,252,39,80,230,234,203,147,180,145,206,137,114,133,44,209,100,21,162,47,140,254,110,81,73,33,249,244,251,183,32,215,87,52,9,156,93,113,23,56,19,106,250,182,40,70,235,208,90,121,159,145,114,243,51,144,238,22,115,108,118,184,210,222,84,128,191,30,32,44,175,135,9,179,97,98,192,111,70,177,134,83],[14,163,137,162,190,95,59,118,149,204,199,51,149,74,70,49,110,110,109,45,253,78,7,70,24,77,101,20,248,137,196,178,224,106,197,155,252,66,44,198,205,194,64,87,12,17,194,66,24,171,2,86,181,36,41,19,243,142,18,226,148,44,96,42,113,185,96,237,246,84,48,97,130,178,33,95,223,28,3,50,248,52,73,98,188,32,237,54,70,85,128,242,61,236,6,93],[0,221,216,40,140,40,181,149,30,98,77,193,156,1,123,17,193,137,197,185,89,111,231,182,148,188,0,194,72,108,197,6,16,29,120,53,0,92,105,76,8,249,111,254,12,49,243,37,10,164,171,255,130,51,43,116,224,16,167,99,243,186,173,38,17,131,141,76,86,246,67,200,182,144,99,120,243,37,201,247,195,118,129,112,234,243,222,207,86,138,224,111,227,7,223,12],[7,68,239,22,45,179,222,188,36,16,174,51,179,67,73,53,132,197,105,46,122,213,130,135,211,150,68,220,205,221,34,95,10,184,65,78,50,153,72,90,65,254,213,32,60,108,18,231,20,110,130,177,51,237,238,145,97,145,246,215,42,227,255,77,30,231,251,209,112,145,156,217,199,143,118,38,212,161,45,233,192,11,227,8,138,160,23,143,33,221,107,62,210,213,50,117],[23,137,232,201,44,83,197,234,141,102,108,199,144,114,213,120,214,16,254,6,242,196,147,30,131,165,180,84,64,121,102,26,194,70,247,172,3,252,103,18,244,243,64,140,109,37,223,214,10,216,23,130,44,17,219,17,116,76,34,171,110,101,17,51,204,246,93,33,28,249,178,214,102,220,201,0,23,149,156,62,32,153,100,6,111,220,96,0,210,189,108,133,63,120,3,218],[23,231,45,63,97,73,26,152,66,162,26,94,61,42,121,130,220,10,167,134,28,3,215,70,112,109,76,11,60,37,21,180,83,120,132,222,30,137,59,181,62,237,187,153,119,112,72,34,3,189,220,128,141,75,240,195,108,142,131,244,170,116,57,102,47,190,2,15,206,184,254,69,130,63,110,226,247,14,223,212,111,168,100,116,143,179,15,47,143,209,201,128,219,87,252,243],[0,158,215,175,62,152,180,138,142,166,22,165,8,134,30,225,85,153,148,82,18,83,141,165,52,73,67,87,77,2,5,153,230,207,74,54,18,58,84,241,170,110,3,105,162,188,47,217,1,34,237,216,201,90,107,219,162,72,27,229,79,86,12,212,3,119,161,8,171,159,212,96,104,79,47,72,220,181,125,31,138,145,48,3,97,138,239,50,114,234,153,148,182,219,39,17],[19,137,17,248,252,100,190,100,159,1,214,146,26,206,113,118,209,16,60,172,2,167,191,192,128,41,62,253,231,23,118,147,53,166,107,2,91,197,205,3,11,202,248,240,78,88,125,33,24,78,86,140,130,8,232,193,255,126,161,7,108,54,24,232,241,197,9,54,65,240,194,141,155,16,245,175,143,183,238,42,182,1,193,41,179,133,59,38,201,4,132,219,49,91,219,10],[23,130,20,180,84,244,151,103,68,240,104,157,102,32,103,187,20,95,123,127,64,251,109,148,38,176,45,167,56,103,25,165,166,53,162,246,60,235,36,234,28,179,185,143,63,48,25,115,18,125,48,137,231,85,75,32,22,228,243,83,198,221,197,142,18,191,81,190,197,13,27,191,95,104,79,230,205,70,253,158,85,153,52,98,108,74,57,165,251,133,112,71,144,160,8,66],[11,114,234,95,127,58,64,112,247,200,105,204,218,112,244,59,61,31,135,93,97,180,181,160,116,187,132,83,64,77,99,11,106,95,22,78,148,33,70,2,244,180,202,82,240,241,13,246,25,53,145,198,69,205,199,40,125,195,61,65,66,109,62,207,213,63,231,125,198,192,234,254,12,22,128,157,137,248,69,158,42,47,67,229,81,108,255,59,127,34,197,59,80,183,230,164],[23,31,165,206,130,81,25,85,12,106,101,189,151,79,230,237,168,243,130,33,239,220,92,88,124,158,136,87,72,133,193,35,48,33,104,103,14,31,211,165,4,74,171,41,228,183,209,57,11,95,185,178,12,99,112,191,190,4,81,106,12,14,108,139,226,124,128,11,196,93,188,230,169,153,103,208,247,8,54,51,91,98,176,208,253,135,126,81,148,107,203,127,52,14,86,27],[6,249,154,205,44,50,148,129,20,27,89,31,20,136,115,223,255,219,238,127,66,201,209,218,217,186,17,184,185,248,243,239,40,4,23,209,186,61,56,55,60,119,91,181,126,204,213,81,2,208,185,113,226,211,55,162,1,40,119,226,252,103,14,119,4,78,83,241,156,69,0,89,174,201,0,116,52,245,140,65,219,90,171,71,195,6,153,227,37,40,127,193,165,45,48,96],[6,236,122,44,161,22,118,184,180,137,110,102,55,133,180,23,41,223,17,105,17,37,49,209,254,235,53,119,230,184,1,36,252,242,10,53,133,184,59,120,110,179,157,138,153,221,134,147,1,164,166,99,63,136,43,248,223,209,220,10,196,61,216,247,162,15,29,172,182,149,20,80,43,54,92,174,236,146,78,198,36,54,2,120,55,190,182,159,25,158,105,251,182,61,19,181],[23,11,68,202,133,105,65,25,141,236,63,189,61,36,155,102,126,109,111,163,162,87,248,166,121,67,107,33,243,121,169,226,255,44,97,252,195,114,203,168,131,53,75,179,10,162,224,151,15,188,157,82,180,229,187,205,75,18,137,165,18,244,14,3,37,189,171,11,27,127,105,197,16,24,119,188,31,172,153,115,229,250,220,72,20,44,67,200,224,123,49,145,22,232,129,13],[16,253,177,229,43,240,109,42,30,167,188,117,222,110,84,14,118,216,148,148,27,143,103,172,152,65,203,40,111,209,111,2,104,12,210,1,220,21,137,102,57,163,33,181,196,179,226,161,11,34,93,168,10,52,202,183,162,230,248,33,43,147,68,240,217,231,121,3,242,2,152,216,234,32,255,115,1,177,207,141,98,230,213,253,186,110,207,96,218,225,53,169,250,224,106,178],[14,61,8,50,216,15,118,61,124,25,142,71,177,167,88,94,49,17,218,5,56,164,18,80,97,98,67,22,3,247,86,63,9,223,93,152,130,19,22,185,176,242,156,233,123,153,135,139,24,87,185,123,126,23,96,185,90,140,58,137,82,250,188,159,174,126,223,105,46,121,73,217,230,153,90,106,197,230,57,88,92,165,69,182,81,184,68,94,252,117,177,90,131,140,172,101],[25,232,234,31,106,201,234,214,112,90,67,195,119,7,44,241,183,81,145,105,81,246,180,71,208,40,132,164,173,83,203,93,62,8,178,109,84,142,219,169,222,228,40,38,10,46,157,233,9,246,160,189,211,143,234,68,253,121,222,17,176,5,11,28,177,206,204,179,100,190,83,69,84,65,89,174,129,156,150,135,209,53,213,216,220,64,184,243,181,231,187,174,203,178,121,210],[3,133,244,116,77,180,226,96,231,123,34,253,250,48,162,163,77,55,39,133,203,132,147,165,76,167,13,83,124,4,12,9,51,245,254,108,222,50,21,240,17,227,132,230,100,222,52,34,10,219,138,156,166,26,232,81,203,109,10,100,15,108,63,85,34,18,211,171,29,149,182,56,146,200,100,3,114,194,19,178,134,219,134,45,177,61,144,37,12,152,205,6,192,195,109,177],[7,134,117,211,46,127,240,209,170,198,184,115,193,134,100,114,250,125,90,232,158,153,56,13,91,18,32,192,184,109,178,246,138,215,190,235,179,111,140,254,169,106,86,42,65,125,49,90,15,131,203,247,248,29,117,86,155,148,53,237,139,105,97,83,17,77,251,127,139,39,15,212,198,212,247,241,132,131,97,203,244,161,123,86,191,162,62,136,88,122,248,149,207,147,101,161],[24,232,178,183,233,95,110,55,59,1,154,210,222,40,175,31,66,26,173,232,67,201,188,166,230,241,208,208,184,64,195,108,196,35,46,102,43,141,135,178,26,31,20,12,201,44,195,191,4,88,78,198,160,23,75,204,47,189,20,118,8,56,147,125,119,167,232,43,76,55,113,34,210,150,99,59,16,36,137,245,201,243,250,7,31,162,249,240,244,255,53,93,246,164,130,247],[2,135,26,67,184,230,32,55,108,86,240,131,35,5,125,18,96,242,237,52,232,116,139,48,129,93,128,161,138,51,107,220,164,79,120,194,190,58,184,91,182,196,89,115,0,53,234,134,4,32,211,237,183,8,193,145,26,28,130,160,253,222,24,150,139,38,11,148,13,173,31,221,248,20,117,129,41,144,212,73,28,95,189,67,195,41,60,120,82,74,227,72,194,137,117,204],[20,145,84,49,62,180,98,154,16,144,234,34,162,213,74,219,114,126,218,247,75,236,98,122,218,156,160,44,23,1,176,130,90,22,90,11,71,251,100,190,156,16,40,14,39,164,125,142,6,32,101,19,179,158,207,75,120,18,29,248,255,30,28,40,58,202,48,64,20,154,236,186,88,70,139,27,224,163,249,159,112,88,63,21,16,91,189,233,32,94,7,43,108,47,218,30],[1,183,145,2,146,122,161,3,50,16,134,103,86,114,150,254,0,223,70,225,231,87,210,12,160,17,35,8,31,234,91,35,226,114,147,72,24,85,51,105,227,195,204,173,208,22,143,128,16,84,111,172,10,49,122,40,231,215,250,29,37,19,231,88,158,186,249,209,34,190,151,209,13,225,105,227,218,0,27,51,9,159,117,143,254,86,86,179,4,226,198,241,224,120,128,152],[14,226,228,161,47,59,181,194,75,252,182,112,8,217,186,147,193,174,33,217,88,92,176,173,254,118,10,54,83,144,170,24,99,62,189,192,50,150,108,49,32,24,198,51,165,168,118,249,3,96,69,44,150,92,114,167,253,179,165,222,55,182,16,150,156,112,115,137,11,19,21,146,218,216,166,152,219,1,228,118,119,75,137,165,78,73,154,185,85,80,71,164,175,124,66,27],[18,100,149,34,98,180,118,234,115,103,160,238,13,139,49,17,245,34,14,165,183,92,28,34,205,218,212,99,151,174,114,129,45,66,107,56,125,130,249,174,32,13,39,158,166,97,185,193,25,196,16,2,213,124,13,48,119,168,183,120,37,204,21,9,123,25,80,177,126,154,237,37,170,237,240,11,72,60,198,145,75,223,37,74,133,167,18,247,118,41,89,217,6,79,58,247],[2,42,142,50,22,239,234,54,131,203,28,126,149,26,106,247,35,17,41,96,98,169,239,66,148,15,30,60,232,39,77,14,220,108,203,145,32,58,89,47,187,243,120,229,128,100,190,177,19,40,101,110,176,241,100,124,34,170,76,79,204,122,167,203,200,231,11,205,14,209,99,29,64,172,215,126,86,182,59,197,199,38,171,187,144,243,227,72,63,35,215,188,187,115,147,89],[16,68,51,176,135,178,93,85,48,128,230,72,177,100,101,12,192,107,114,229,237,11,137,56,71,229,251,203,80,38,135,127,254,241,124,130,49,242,34,247,134,144,94,60,101,240,154,234,23,21,87,198,164,228,138,237,5,119,8,83,166,76,43,57,43,108,33,184,114,207,204,83,134,103,71,251,24,82,241,14,169,11,152,116,198,29,11,172,0,251,180,175,251,121,246,119],[2,145,41,148,166,147,190,5,100,41,202,97,86,143,200,184,82,32,56,10,244,86,62,107,172,2,106,46,90,3,73,71,106,181,35,118,69,27,242,151,155,152,143,230,238,29,154,17,14,21,153,9,213,225,161,176,142,137,147,67,1,22,134,204,27,214,81,199,228,4,148,0,110,123,76,227,92,205,93,240,18,254,196,11,198,90,131,115,27,184,129,42,133,132,106,158],[19,235,124,36,120,49,212,135,123,159,204,123,4,26,166,15,227,115,216,40,172,124,81,120,32,232,206,153,166,200,213,10,25,92,225,243,232,102,156,200,147,97,38,180,108,83,3,19,20,150,242,240,192,224,14,245,177,175,73,61,109,185,51,234,101,212,156,248,211,220,203,110,181,175,110,149,128,60,183,244,27,12,50,46,22,131,33,233,104,88,136,62,209,98,51,86],[8,158,178,246,243,102,79,19,21,246,126,159,235,212,147,203,231,244,155,144,175,71,23,37,63,31,239,156,238,49,26,189,74,18,164,218,234,36,155,199,48,61,146,155,230,195,170,250,14,234,48,70,222,162,38,72,124,229,240,125,187,236,98,208,49,10,153,152,231,37,157,181,237,109,243,224,141,25,37,27,252,172,8,157,182,76,159,62,230,143,222,26,206,13,146,129],[8,43,127,238,81,10,186,192,237,195,164,179,157,3,49,110,125,91,86,38,19,170,243,96,137,225,87,58,234,231,158,159,139,69,223,31,204,215,104,138,238,220,88,6,49,169,221,76,15,125,52,235,119,143,66,193,221,199,214,8,78,168,36,74,14,40,241,59,165,107,161,63,114,18,182,254,90,64,89,144,237,124,229,77,155,19,214,165,37,183,70,171,186,156,45,201],[2,93,142,100,103,103,97,1,4,34,231,210,67,13,129,133,241,236,68,138,40,212,121,7,251,74,20,239,40,165,106,193,90,182,121,44,129,206,29,188,242,47,44,126,152,203,208,58,17,214,64,191,188,86,218,224,215,20,90,22,132,216,137,219,138,25,18,161,6,86,233,5,93,41,23,90,227,168,7,49,232,103,196,154,249,1,143,123,221,54,184,129,3,107,205,160],[23,64,231,140,179,78,211,99,33,41,56,46,150,68,49,178,164,45,101,35,79,129,233,32,91,19,88,195,8,130,215,183,74,28,252,231,88,210,233,213,125,249,230,32,221,251,36,26,17,15,182,201,174,235,76,143,71,218,194,96,103,138,202,8,15,142,129,96,155,73,246,242,102,116,159,70,140,53,30,175,57,73,175,253,28,187,166,79,175,249,199,27,154,194,7,116],[13,133,22,59,239,202,34,14,204,203,140,248,201,199,2,210,148,197,134,143,210,21,172,177,199,154,187,60,85,124,118,237,89,36,107,68,188,203,219,198,195,230,7,251,129,133,124,56,12,34,89,180,15,135,129,187,31,156,204,125,225,117,121,238,223,175,187,195,223,239,161,7,95,13,8,197,196,65,171,185,245,30,96,218,136,3,65,234,123,49,19,3,65,5,12,49],[8,51,18,81,114,75,43,209,104,1,84,33,94,108,25,116,94,110,151,96,176,190,216,151,170,1,31,200,226,189,59,73,157,106,116,169,71,72,217,24,217,190,76,35,104,74,253,96,18,115,38,180,228,213,131,84,41,38,17,19,114,138,183,155,12,83,230,218,14,255,242,73,91,19,86,224,207,13,42,41,156,143,6,151,240,122,12,13,77,184,225,74,199,214,211,195],[24,216,50,60,121,66,211,174,208,134,25,242,252,129,180,157,107,194,74,79,201,15,157,234,176,57,96,93,156,116,212,17,199,72,65,241,119,128,132,61,178,55,254,197,151,106,130,3,7,67,61,248,243,197,185,194,56,108,252,117,195,81,105,16,189,246,99,102,112,60,21,161,18,207,156,122,165,39,201,124,37,253,23,171,232,45,102,213,209,154,0,110,254,42,143,78],[1,127,237,185,198,201,144,231,124,150,200,54,237,118,192,9,163,184,24,156,38,205,171,46,153,224,252,61,204,229,154,99,153,163,181,106,105,42,162,150,120,161,237,146,23,5,74,10,21,189,53,89,63,157,197,112,249,230,185,127,119,84,173,54,9,130,2,149,208,0,46,111,83,118,213,194,34,3,101,243,165,144,254,171,102,192,13,119,138,28,217,90,26,91,123,162],[3,74,114,186,140,185,106,110,158,8,250,234,63,174,240,84,128,25,60,158,20,7,179,17,91,145,185,208,165,178,191,165,235,113,109,112,119,217,47,129,157,119,98,151,73,220,243,141,11,63,3,99,160,140,51,237,111,140,68,98,119,58,134,155,2,179,126,133,105,193,11,134,231,95,204,223,147,96,181,83,62,212,33,107,195,28,198,63,145,103,24,140,103,62,215,244],[25,56,110,188,198,16,113,235,177,110,54,68,128,199,177,104,21,164,75,228,242,184,98,162,17,181,32,190,88,150,94,143,164,151,187,197,150,142,127,166,161,243,126,10,21,92,212,206,0,206,59,102,174,47,129,163,242,47,146,50,153,190,144,80,60,169,122,181,12,82,138,231,25,135,173,125,66,132,68,118,117,163,140,189,127,29,182,14,181,250,22,249,49,42,93,3],[1,7,5,75,81,212,220,2,119,186,126,39,226,45,51,140,64,193,251,13,247,173,210,77,26,27,216,67,93,101,29,145,27,48,96,29,107,8,143,154,242,25,92,107,178,247,75,117,3,133,131,159,214,151,16,219,151,141,111,28,64,74,71,181,0,37,120,242,42,180,84,145,219,56,4,6,82,100,29,109,129,253,48,27,232,97,174,254,132,204,190,152,197,47,5,111],[13,200,18,231,170,73,54,64,220,122,128,250,139,186,126,99,94,30,210,206,105,147,202,40,82,145,69,58,26,29,232,208,191,93,97,99,102,125,147,127,43,59,218,92,175,102,134,91,9,143,99,51,80,142,36,195,30,34,24,21,169,8,182,182,222,128,11,206,61,224,62,169,190,122,28,74,104,229,54,97,70,184,62,113,41,184,144,187,238,248,209,203,133,107,106,29],[23,152,210,229,194,59,102,246,62,150,55,37,145,221,142,103,244,106,218,197,58,119,183,133,99,168,136,22,161,20,145,82,90,132,197,30,203,154,55,240,105,244,6,202,147,28,35,12,13,251,22,71,227,72,35,201,33,54,26,231,82,218,101,53,48,158,176,94,204,187,215,186,191,244,129,38,245,19,249,223,61,10,236,173,228,86,127,33,139,92,90,116,104,53,65,117],[14,153,231,33,46,229,10,138,122,232,76,93,75,105,196,27,64,228,224,125,101,237,246,45,237,156,251,92,43,194,48,65,50,176,197,43,249,167,27,140,127,204,222,212,134,9,15,229,15,199,25,120,158,183,31,1,212,103,74,126,7,78,158,85,141,31,100,182,130,6,114,80,20,43,120,98,86,35,119,253,125,127,189,148,63,104,73,95,189,227,12,248,149,84,193,242],[1,211,145,194,199,207,114,104,247,174,6,126,140,15,22,60,68,149,153,164,202,130,71,71,74,24,203,116,39,156,231,131,230,73,218,194,56,189,248,11,215,110,74,39,159,30,165,158,10,11,50,48,159,240,159,56,8,179,73,58,75,156,167,55,48,82,137,88,98,132,155,107,109,87,235,62,165,174,155,15,101,53,249,92,180,178,213,217,161,124,54,195,99,111,10,68],[2,248,148,72,179,138,206,173,248,251,132,24,202,250,51,50,173,162,117,175,35,173,146,0,14,7,91,147,7,233,14,121,76,157,27,17,227,64,214,178,222,217,92,10,152,119,94,108,3,106,221,182,234,99,204,68,121,237,91,17,58,14,41,163,135,189,233,56,191,159,222,89,132,233,165,180,240,6,245,209,157,66,186,125,11,173,186,170,233,36,72,44,51,139,95,80],[6,244,142,237,254,43,102,210,164,196,135,28,105,52,113,245,44,251,139,101,109,23,104,142,154,54,209,197,117,84,92,92,129,242,93,205,79,1,84,155,128,87,94,201,41,238,183,114,0,189,15,137,239,219,145,237,96,41,22,25,197,96,174,247,177,13,53,57,141,101,239,110,205,78,128,64,130,28,145,110,97,179,53,248,69,131,154,2,253,245,186,49,104,214,197,157],[23,18,38,138,247,102,105,151,221,124,156,102,142,24,142,189,32,133,150,95,101,41,113,95,46,19,141,79,65,185,78,126,107,146,61,137,220,10,12,190,6,7,117,216,30,139,76,189,24,138,252,233,175,133,50,54,229,151,130,166,24,124,114,81,28,130,61,242,172,38,107,192,189,192,97,130,47,181,40,135,179,231,232,184,100,126,159,247,45,100,131,182,242,94,196,175],[16,8,11,124,89,148,82,138,82,53,184,226,116,74,38,102,44,139,245,146,179,46,180,186,168,68,166,15,37,45,148,139,5,149,220,99,113,127,235,13,7,109,213,187,98,214,42,61,6,75,8,248,66,64,85,233,186,5,30,240,154,50,210,223,87,22,101,55,179,177,16,62,149,253,126,53,214,155,39,14,49,200,249,183,24,169,252,118,157,174,107,94,39,249,20,144],[17,51,216,14,136,57,81,117,22,255,89,160,44,231,109,250,128,191,155,66,21,50,104,224,66,228,12,180,69,22,157,210,159,112,98,24,89,113,41,179,3,78,96,93,153,195,34,88,1,18,102,10,214,199,203,182,186,75,232,251,62,233,180,7,113,36,204,176,36,96,171,56,85,4,255,59,45,207,243,153,250,170,6,16,200,196,202,126,170,104,85,233,17,6,122,142],[4,198,132,209,49,158,45,128,77,140,75,192,154,124,251,252,187,206,58,73,245,226,165,16,224,173,30,151,233,194,20,97,146,248,80,104,173,115,16,1,35,160,182,248,132,105,90,181,25,192,91,253,163,186,60,168,177,187,160,117,129,81,16,254,244,133,240,114,219,108,210,239,139,159,142,17,127,165,185,3,197,159,240,213,148,244,130,181,189,227,52,233,89,192,57,187],[8,220,88,231,244,162,64,6,253,23,48,130,210,142,192,125,13,115,125,167,87,186,41,223,210,205,181,11,167,27,29,244,140,3,106,101,25,8,247,240,202,177,193,46,249,197,198,189,17,134,80,47,249,115,124,110,163,85,123,134,19,10,58,74,163,17,28,97,212,122,133,105,147,100,185,141,104,201,114,209,235,190,211,192,240,129,75,110,138,215,210,165,9,31,219,76],[4,104,52,237,49,57,140,181,252,32,119,81,252,196,86,209,155,16,108,203,65,235,94,147,230,201,0,210,44,226,140,85,198,225,196,1,70,146,119,218,222,207,146,152,139,38,111,86,4,215,127,186,109,28,171,82,81,91,172,155,192,254,23,5,110,80,198,0,145,229,123,151,235,42,181,226,94,69,186,108,76,86,223,26,232,177,133,199,243,128,244,7,190,62,208,158],[12,140,75,25,247,175,188,95,177,56,248,108,70,91,41,196,238,232,135,196,85,82,111,131,125,181,163,116,163,98,67,194,221,114,115,161,142,199,217,245,157,53,98,16,116,186,165,140,7,30,223,174,234,32,243,121,119,178,27,102,149,69,47,99,57,170,149,176,90,144,54,48,255,122,76,33,106,162,200,147,216,157,242,133,244,180,38,211,130,11,127,149,213,167,82,104],[9,185,129,204,251,252,190,223,221,22,249,55,90,14,232,80,221,124,79,4,232,211,218,35,128,7,242,144,211,195,75,90,55,174,202,23,148,96,93,96,185,89,220,228,33,177,206,248,4,252,237,188,197,250,171,21,91,93,133,124,241,168,40,145,228,22,234,152,86,110,178,17,100,196,39,60,128,24,139,238,100,51,126,235,10,43,47,187,120,189,227,209,251,236,74,217],[16,86,63,58,100,224,149,128,172,75,33,6,74,56,140,189,141,123,52,21,129,41,36,186,124,87,254,245,156,59,248,148,166,88,26,152,20,115,173,29,222,80,15,77,106,29,50,228,25,173,195,198,116,201,6,41,160,92,230,216,147,143,195,212,120,250,254,65,28,228,7,6,198,111,102,174,76,84,49,55,58,103,68,218,179,178,147,113,193,155,56,160,198,9,42,131],[2,107,237,248,121,73,199,42,127,154,242,81,99,159,105,184,100,41,86,2,48,158,253,148,132,46,87,47,185,95,205,205,200,249,163,0,30,88,33,123,116,178,241,119,22,124,23,59,12,126,63,118,56,16,3,174,101,179,173,210,227,183,165,120,176,210,117,186,188,190,235,155,87,54,195,83,189,12,227,162,79,42,208,36,5,7,233,97,190,238,60,236,136,235,25,47],[7,240,87,149,141,174,113,208,227,4,202,157,198,210,79,115,245,134,104,196,115,86,45,146,187,102,96,145,239,69,167,70,76,103,99,34,178,101,136,248,236,226,250,120,176,110,159,126,19,166,219,30,179,253,150,190,117,75,55,77,184,187,78,155,111,81,67,215,229,120,70,77,203,226,21,62,155,178,204,98,2,48,85,153,51,4,103,24,241,131,227,113,94,87,54,83],[11,150,188,48,98,125,171,180,241,126,94,179,135,225,53,184,181,50,16,95,160,152,38,217,224,51,164,234,233,213,172,142,148,237,12,144,33,132,60,148,211,221,93,52,197,141,140,118,4,107,96,109,33,234,189,175,230,116,166,60,56,110,40,108,140,57,165,13,14,215,211,231,13,232,153,159,14,13,177,218,15,234,69,240,200,206,82,230,32,252,202,237,237,143,24,50],[17,79,236,144,242,168,123,130,135,7,197,19,143,236,151,197,43,164,228,55,115,150,61,192,228,87,4,129,171,103,69,66,156,115,238,196,153,76,211,184,203,82,109,28,228,116,29,77,6,155,76,198,234,167,250,143,47,253,176,50,165,223,28,174,128,134,240,151,123,29,19,44,163,188,153,164,228,18,138,205,0,57,21,11,202,53,168,10,69,20,171,68,94,89,198,249],[1,252,72,13,235,4,112,17,244,218,247,66,155,55,174,147,19,74,87,179,153,132,35,48,215,79,247,200,74,214,57,1,135,49,29,247,86,22,241,79,48,85,249,229,179,88,8,13,16,83,95,58,104,38,8,216,33,107,81,181,88,202,102,136,216,171,97,218,248,233,178,250,223,179,234,6,90,255,39,109,35,76,65,181,135,69,98,96,244,177,101,160,126,125,184,64],[23,226,241,47,238,174,31,50,77,204,70,162,48,84,137,21,191,236,197,251,41,228,176,247,220,105,162,24,134,50,178,126,181,187,254,150,89,95,90,193,66,223,114,253,186,240,200,99,6,216,213,161,246,41,193,32,175,96,235,88,39,137,254,114,166,171,0,152,243,129,209,34,218,120,19,103,53,27,187,117,28,92,155,220,23,224,221,242,17,162,223,92,6,166,85,40],[8,222,240,195,162,120,7,204,230,36,21,94,238,242,45,249,52,118,7,162,156,229,56,121,244,104,220,89,190,102,114,104,116,7,162,218,40,254,34,144,244,98,201,144,159,84,55,233,17,10,107,131,254,135,198,172,44,83,100,119,109,10,57,89,192,226,223,234,179,175,20,126,18,249,30,166,78,170,219,249,128,217,229,238,148,27,220,97,163,115,229,100,204,231,242,34],[11,238,29,128,64,41,251,64,79,1,48,35,202,249,79,182,204,89,180,135,20,96,114,232,194,39,31,169,241,244,184,233,33,137,186,155,184,231,123,160,247,112,131,238,121,54,235,145,3,186,101,218,153,178,58,114,137,57,99,218,188,239,177,172,20,57,110,15,198,80,110,70,209,58,1,9,252,191,37,29,135,215,85,83,118,51,169,211,166,130,66,204,231,140,111,112],[15,144,65,111,147,141,228,127,40,4,236,179,86,196,145,38,135,38,162,212,132,20,141,20,101,1,245,218,117,184,61,106,15,160,102,102,167,211,99,132,90,74,28,95,50,196,191,110,1,36,75,176,205,223,6,71,22,127,63,227,202,54,62,98,175,224,132,118,223,197,49,203,146,107,143,199,103,202,247,249,13,14,32,185,130,43,208,97,143,29,159,213,66,196,172,54],[19,174,1,247,207,239,217,0,35,46,68,243,173,54,104,83,66,114,209,254,209,174,126,246,231,172,246,8,150,83,144,9,241,10,236,159,36,96,214,42,216,234,220,252,95,172,86,118,24,232,94,100,171,111,46,190,74,114,164,224,12,84,199,32,87,60,35,123,140,228,139,30,42,188,248,54,21,155,182,173,145,190,81,255,200,128,243,209,110,143,132,157,26,6,128,166],[21,165,147,35,247,250,58,195,6,44,56,108,8,21,232,69,23,70,174,166,28,173,95,100,41,113,80,221,29,189,172,174,59,190,194,25,232,199,62,117,57,94,21,194,221,114,213,42,5,73,73,247,29,143,233,28,140,165,173,53,214,55,126,177,86,228,117,80,158,118,154,77,105,246,129,47,4,235,143,207,241,63,158,98,138,142,234,221,173,125,71,210,29,107,180,61],[10,167,174,154,128,164,73,164,82,150,62,65,226,3,133,8,196,60,191,95,163,102,124,201,192,134,118,198,10,1,111,158,64,53,158,10,104,110,28,77,141,147,138,214,72,142,13,140,5,40,134,180,14,37,60,24,157,89,108,140,182,60,184,36,25,103,184,139,83,163,13,103,37,214,149,195,58,95,254,169,118,71,110,168,104,132,237,191,248,18,95,13,58,41,128,253],[5,83,40,109,251,206,232,155,129,252,34,72,238,141,110,105,90,162,211,197,243,129,114,74,18,101,159,159,80,59,122,171,86,9,182,144,206,1,130,67,142,176,140,147,189,188,30,201,8,48,72,72,41,166,150,5,195,207,91,31,134,177,177,51,147,90,8,81,33,182,221,55,54,173,53,186,42,74,107,74,51,169,125,224,63,70,127,102,190,238,235,173,239,86,211,66],[11,91,25,194,178,219,226,64,155,172,60,10,103,81,89,223,129,17,60,138,239,59,77,231,106,104,47,222,36,106,113,29,222,163,67,248,26,67,160,225,243,248,206,69,78,125,159,175,15,118,56,156,108,166,210,234,228,189,188,89,74,144,181,162,23,95,17,49,182,99,2,91,71,188,17,62,28,167,222,118,99,89,234,129,43,116,180,164,215,163,110,0,103,27,147,140],[12,136,216,134,189,222,166,216,73,142,154,90,231,95,31,221,35,226,157,153,240,157,177,126,255,60,219,215,207,58,115,121,133,112,2,68,112,169,134,20,174,111,227,147,252,163,134,229,22,81,12,186,227,170,55,115,227,227,146,163,231,51,4,29,59,155,123,159,30,215,160,35,46,80,229,15,111,175,133,63,106,60,217,1,110,144,159,111,94,57,0,241,134,41,160,107],[1,110,165,62,117,39,59,164,229,251,240,147,144,235,120,150,5,160,173,239,235,190,234,5,19,49,50,129,60,11,150,239,140,177,227,160,19,246,82,177,236,25,160,98,115,247,10,179,9,54,234,239,138,97,141,162,110,102,140,42,240,90,253,174,36,203,6,131,219,171,1,216,145,130,148,91,193,23,15,103,88,59,55,151,126,36,103,182,192,103,235,95,68,244,158,36],[25,72,63,116,87,23,24,202,252,58,66,42,238,110,235,174,11,110,18,154,234,40,152,196,94,236,251,223,79,120,171,44,167,104,253,147,13,87,74,81,164,28,115,116,15,113,214,130,6,255,143,77,222,25,35,200,124,156,221,40,208,161,213,229,163,255,218,108,69,113,104,209,95,122,75,75,218,211,227,197,75,153,51,164,246,7,17,113,148,238,196,106,210,185,210,140],[20,145,155,75,153,21,154,86,103,37,153,215,120,11,127,220,255,149,17,5,11,202,195,138,187,147,214,173,154,197,42,151,82,112,16,54,174,24,98,38,225,241,55,245,110,130,164,223,20,86,4,199,246,220,112,205,243,103,246,98,93,175,11,79,119,100,126,103,73,187,241,5,160,52,99,238,252,92,142,198,3,144,92,224,16,117,133,43,102,155,178,188,186,76,186,56],[9,215,100,206,190,217,216,187,33,85,171,190,67,185,74,105,228,74,30,192,227,141,197,133,11,46,224,143,201,220,187,255,1,226,230,137,93,30,171,76,226,105,37,127,138,203,0,148,7,149,91,117,216,243,170,125,44,120,58,78,107,179,168,240,36,70,165,62,148,90,139,222,112,160,41,159,155,21,210,184,184,213,46,220,3,55,227,183,205,53,146,188,192,253,227,64],[0,89,162,180,157,102,20,47,90,144,51,194,97,240,4,2,29,138,157,46,193,155,174,11,82,250,161,160,13,4,111,35,199,254,11,157,153,139,203,102,124,11,12,110,30,129,204,201,3,19,233,57,187,73,254,104,91,94,185,221,60,227,120,123,22,210,192,59,222,235,154,77,104,225,69,161,176,20,116,167,165,81,206,171,2,55,180,5,232,202,210,46,102,75,74,225],[4,250,207,48,27,63,159,62,48,2,208,98,32,100,31,101,176,223,191,119,182,210,64,122,35,38,95,39,55,136,241,127,110,19,65,168,98,162,165,73,20,174,211,193,15,33,96,208,14,103,55,181,196,4,226,54,19,219,180,102,82,252,239,78,10,5,175,178,130,210,107,23,133,149,184,230,219,233,65,50,85,194,76,154,24,166,9,0,240,205,179,151,151,192,229,43],[0,185,157,103,228,28,240,24,84,189,199,23,93,95,45,233,118,151,182,203,210,96,145,240,36,171,250,220,97,115,116,122,153,68,161,242,233,2,230,119,249,86,166,71,29,36,136,233,5,77,195,139,187,249,74,52,63,215,86,64,1,199,215,255,186,242,11,237,229,252,113,167,66,155,26,188,35,215,205,226,163,182,107,149,191,222,202,31,244,42,96,19,58,126,27,37],[5,237,97,165,189,80,159,169,6,255,149,102,7,78,10,211,114,133,58,115,66,18,228,109,190,22,161,141,115,168,201,155,204,28,37,131,14,212,1,67,124,128,204,242,182,17,152,43,5,228,169,138,218,134,143,225,101,245,36,131,152,189,205,46,111,200,16,212,172,81,126,120,217,181,217,24,103,139,7,121,143,239,140,2,46,182,13,173,122,132,42,162,68,105,167,50],[1,102,63,157,212,108,131,68,214,98,87,180,20,159,165,199,228,97,5,1,173,82,11,51,125,161,80,45,236,156,97,56,163,205,163,184,36,7,106,249,83,11,188,47,4,225,76,127,21,101,158,175,49,246,148,95,25,175,83,77,252,218,54,185,66,34,247,39,115,159,72,173,42,251,177,242,13,166,79,61,217,250,203,180,212,62,68,69,170,143,78,26,134,46,197,55],[16,188,225,230,111,233,188,219,226,203,128,46,180,150,126,15,94,243,79,145,133,177,195,68,56,194,160,84,124,234,143,57,26,206,175,236,249,8,24,139,100,186,55,12,114,235,188,189,17,166,142,106,242,122,47,222,107,125,99,225,82,133,113,22,168,226,75,243,134,92,204,46,74,143,122,93,222,190,189,215,202,5,179,12,90,148,46,72,49,144,42,36,193,198,82,248],[7,90,45,151,195,73,166,219,39,190,161,222,116,141,127,63,45,202,141,65,206,178,156,4,173,169,222,2,179,15,99,212,30,27,176,98,75,215,238,35,57,140,211,1,185,133,185,157,4,66,20,162,226,234,247,38,158,62,205,142,118,126,230,147,197,26,16,102,183,9,61,191,50,141,239,45,65,53,182,131,129,147,63,5,197,17,39,187,213,90,238,23,84,174,176,148],[7,124,188,113,39,7,246,124,199,63,65,226,71,18,83,214,9,156,218,178,130,61,174,200,42,206,237,28,19,185,235,47,103,254,8,123,227,137,26,114,125,22,50,34,134,93,54,107,17,197,156,100,60,105,56,222,60,98,80,13,176,99,24,96,117,239,244,141,25,79,129,134,13,102,147,117,60,175,107,127,83,185,172,189,23,154,247,67,238,35,169,177,36,165,54,31],[9,158,121,20,109,38,34,5,93,173,164,126,196,229,129,36,14,176,119,107,215,196,182,13,233,79,191,198,207,155,150,192,224,102,255,162,50,122,223,138,157,200,30,169,129,14,23,115,0,137,9,82,51,115,176,51,82,191,50,127,36,233,225,191,230,115,5,45,174,151,247,192,206,6,36,149,171,0,208,30,70,64,101,30,138,124,127,68,168,207,188,33,114,233,195,94],[3,207,114,232,198,220,110,222,13,118,193,1,235,63,138,245,245,46,37,141,69,15,13,104,32,107,252,137,63,136,85,192,153,172,185,197,26,154,78,219,178,199,20,30,17,254,243,126,25,45,238,66,209,26,154,223,31,8,210,199,50,208,165,99,172,208,139,224,68,80,147,50,196,122,165,162,230,213,248,234,172,176,114,10,132,125,51,82,110,70,122,207,25,118,229,63],[10,249,140,16,238,142,133,61,133,188,33,103,99,135,182,212,0,180,187,131,83,94,110,234,139,5,140,180,244,243,229,173,23,32,192,1,151,247,43,79,81,167,25,98,124,51,165,36,9,250,41,240,245,41,75,110,54,101,185,122,139,210,80,2,41,59,223,42,246,119,162,164,98,124,15,205,253,159,212,202,40,55,180,173,215,248,160,23,245,227,43,156,247,39,165,23],[9,186,3,195,165,92,124,21,39,90,168,205,230,96,183,206,98,62,15,119,129,94,83,185,237,221,242,113,215,141,168,18,211,93,24,216,63,214,244,117,232,38,234,40,106,248,118,110,16,85,164,229,62,109,110,138,167,71,110,87,175,221,79,49,124,160,243,134,226,168,11,209,146,206,235,70,83,26,46,245,39,83,253,52,165,60,36,18,113,63,242,10,155,158,3,31],[14,148,177,20,20,126,158,76,242,143,7,209,30,38,217,249,23,52,4,119,89,179,16,125,152,13,135,1,34,49,46,28,161,67,105,222,196,207,75,49,204,65,63,29,105,10,250,204,19,93,203,39,81,222,60,113,134,157,209,183,253,91,97,162,71,132,11,40,109,61,198,26,7,84,42,111,18,35,87,134,195,103,233,58,45,32,103,88,171,1,64,243,65,119,76,108],[14,80,234,44,79,13,202,207,61,196,10,14,54,105,156,171,25,181,251,38,162,66,166,128,31,139,240,249,242,41,67,32,166,204,59,159,95,141,216,107,73,48,89,18,230,135,158,175,16,215,181,254,251,49,31,93,52,35,8,94,244,84,60,142,240,57,57,114,185,222,49,157,8,202,203,166,242,122,202,209,73,51,228,10,198,46,72,160,167,97,181,254,18,168,50,169],[11,78,70,109,26,11,108,251,72,187,243,5,211,117,76,170,188,204,55,134,151,95,60,142,85,37,238,93,198,167,211,201,34,188,53,42,235,31,134,96,38,78,156,161,76,244,110,63,17,161,108,150,25,133,214,104,109,220,135,103,179,71,135,5,216,195,172,176,63,185,115,82,245,13,75,162,61,62,34,117,69,188,96,138,81,100,48,250,149,203,64,210,46,164,75,73],[5,102,126,35,115,178,16,166,116,248,82,212,64,79,116,217,93,67,254,233,31,200,235,166,243,41,69,195,138,193,26,130,221,181,31,73,195,216,93,27,220,118,120,183,29,14,150,50,1,54,71,45,171,221,69,7,92,40,64,116,76,5,80,224,167,178,10,170,116,229,102,91,26,168,24,189,220,136,153,221,209,22,226,141,66,96,83,249,122,189,197,172,118,206,94,34],[10,168,175,104,75,98,77,253,36,164,182,143,221,10,109,160,245,146,27,247,86,246,31,167,216,24,116,243,120,22,200,207,8,204,20,54,99,198,225,157,251,171,44,82,36,7,154,60,19,216,23,198,150,202,113,77,2,39,92,154,46,252,142,250,100,183,1,43,66,207,122,12,111,136,8,148,75,208,95,57,118,29,221,6,19,217,228,15,176,171,210,171,84,13,150,187],[1,231,139,225,245,182,21,2,107,96,135,243,187,129,10,176,87,160,38,85,219,221,34,63,22,110,144,117,150,107,137,39,62,128,38,231,100,116,227,15,251,102,64,123,170,198,167,161,19,216,78,125,67,20,37,233,23,80,134,10,142,241,36,228,186,15,239,247,204,88,168,58,96,222,195,113,248,109,162,205,175,69,241,108,247,224,33,0,38,214,31,100,22,227,75,158],[8,252,100,130,94,231,160,239,111,142,146,46,176,170,104,254,243,127,244,127,250,222,138,82,5,149,189,136,18,149,203,95,91,144,78,253,246,198,126,148,226,209,245,197,83,231,176,49,0,51,84,181,168,115,202,170,64,147,65,208,198,69,164,246,31,197,134,153,148,19,87,93,72,65,102,103,189,26,72,109,102,83,9,190,8,50,129,192,166,142,217,12,63,115,95,112],[13,149,127,81,199,224,32,108,210,228,3,245,230,6,216,31,89,149,165,118,220,194,53,192,217,148,160,135,149,60,184,81,98,79,152,181,252,88,43,108,243,249,65,221,60,76,86,81,7,175,23,213,125,224,216,240,158,61,156,42,153,109,9,244,195,116,104,114,120,179,143,12,142,24,49,109,189,176,221,186,210,201,114,88,52,25,47,145,134,196,89,216,9,244,230,135],[2,190,76,99,137,115,8,129,26,174,37,211,252,191,187,91,46,45,225,161,115,251,17,86,6,81,129,202,67,255,59,93,87,81,48,25,148,212,70,64,159,31,207,10,116,84,180,102,6,158,119,238,114,23,236,71,171,206,161,44,77,85,121,236,75,135,166,15,176,1,72,30,158,88,36,94,50,55,223,110,16,130,107,95,95,209,6,0,184,22,87,223,97,32,56,138],[16,164,202,56,61,56,138,237,100,85,86,45,49,99,142,128,195,232,24,206,231,38,165,10,226,105,117,185,54,78,1,248,169,129,178,210,13,123,80,1,119,100,197,26,239,158,206,196,2,150,34,228,26,63,0,39,164,230,230,131,29,173,148,131,142,169,178,150,235,6,152,221,221,178,8,84,153,130,59,135,154,168,146,154,225,90,49,211,42,209,251,58,83,121,208,2],[25,106,100,103,8,184,192,248,100,109,141,154,158,221,118,8,123,128,140,63,49,124,202,80,201,94,177,210,213,212,185,203,109,223,95,251,6,233,89,58,88,253,116,217,151,202,41,236,17,235,136,234,91,3,4,76,83,124,246,11,81,39,249,253,36,66,56,108,71,178,202,163,179,78,157,41,81,225,98,90,199,71,55,14,253,168,38,9,104,157,209,6,163,222,71,124],[23,190,251,196,185,227,118,124,214,55,150,225,22,110,230,107,180,157,118,42,157,41,144,255,75,98,81,5,81,62,36,83,33,55,69,95,32,6,102,81,18,147,66,25,91,39,105,62,7,127,191,244,200,204,217,179,60,183,167,207,183,70,190,2,254,220,38,56,247,171,162,104,203,174,202,223,148,178,175,3,27,112,83,230,233,137,212,20,103,63,58,112,143,149,16,189],[13,229,85,33,203,206,141,166,236,109,253,149,151,37,199,8,117,135,114,216,196,53,246,9,156,3,218,66,254,105,80,165,46,151,48,218,59,236,42,204,39,142,135,163,192,185,178,209,15,174,76,124,104,36,146,132,121,194,73,149,41,59,113,116,124,142,254,100,239,165,76,0,93,86,183,132,159,160,24,97,20,4,19,68,197,215,249,15,75,250,111,246,192,65,106,254],[4,217,3,169,29,42,200,149,191,58,46,227,89,157,66,153,205,144,124,255,92,93,32,133,244,63,119,109,241,251,144,234,111,74,141,35,104,130,249,196,110,89,183,136,65,211,249,197,15,2,166,54,250,76,22,212,4,106,114,61,55,137,229,128,30,14,170,149,43,105,148,18,189,161,143,180,69,255,118,52,17,22,18,230,197,91,39,186,41,227,7,169,213,24,194,199],[3,71,132,74,249,114,47,79,245,47,59,35,202,238,188,145,126,51,117,107,12,246,75,77,115,95,233,20,60,127,36,81,96,88,76,186,125,53,112,68,194,111,116,93,75,207,141,215,12,4,19,132,5,104,55,110,217,20,202,81,138,157,229,116,78,68,246,133,62,235,234,120,106,46,24,214,7,228,130,16,74,38,56,20,96,13,255,77,132,63,128,102,251,40,38,5],[7,59,139,215,229,159,112,46,28,52,82,17,129,76,61,193,134,172,0,238,30,23,169,238,123,171,221,242,143,93,154,83,240,212,45,10,77,62,235,84,201,155,41,73,127,201,217,48,22,30,60,253,111,198,70,251,186,189,151,35,207,165,180,224,46,164,151,2,67,130,251,82,5,115,76,178,225,4,134,235,170,83,115,249,45,197,19,190,248,103,178,71,19,37,82,178],[1,126,176,199,202,1,16,138,133,208,100,45,97,161,179,165,56,164,96,129,120,109,17,172,195,11,30,126,73,81,193,20,38,158,123,175,65,119,183,21,120,39,176,154,225,159,197,84,7,23,219,80,40,250,83,103,94,133,114,5,207,221,70,92,191,43,108,171,145,142,59,86,27,38,224,243,18,186,108,89,94,142,127,114,32,254,99,163,33,189,208,14,59,30,203,142],[5,26,148,216,75,199,194,102,46,32,78,91,60,232,132,78,141,158,131,249,155,99,0,28,154,225,6,9,221,35,93,137,157,222,123,140,97,90,200,158,142,102,114,199,49,143,253,75,17,58,88,192,167,177,55,94,28,62,168,210,32,147,159,104,138,160,133,87,55,255,69,205,104,85,212,254,191,133,13,235,66,188,245,90,233,132,39,198,214,182,57,157,111,116,133,226],[21,0,44,171,180,248,247,193,81,217,240,197,198,30,64,166,200,60,24,189,194,179,92,57,180,94,76,28,173,52,13,6,117,47,134,28,106,13,75,76,105,27,58,223,89,211,14,249,25,212,163,83,181,100,47,31,234,131,130,192,51,197,237,229,12,167,59,173,2,134,34,8,232,121,90,69,112,215,12,136,60,133,180,20,70,78,63,181,86,48,145,66,227,164,248,175],[10,113,180,32,165,216,138,254,168,89,123,87,86,29,184,69,91,252,198,144,1,193,192,50,2,16,97,201,131,226,199,192,48,223,175,149,92,88,209,156,26,160,173,155,181,198,173,156,2,5,8,184,254,2,150,204,215,25,76,49,82,202,5,6,112,115,224,178,30,170,162,166,61,76,104,80,237,2,46,44,202,84,54,124,178,61,25,28,215,207,27,169,150,34,46,246],[23,125,49,75,104,166,34,142,61,12,214,119,131,7,143,93,37,12,77,72,169,171,233,4,156,25,20,107,180,12,117,96,208,24,132,26,212,111,75,160,9,175,224,247,240,159,246,132,6,174,205,198,234,123,230,86,130,197,3,84,169,216,194,217,175,69,185,55,217,66,228,81,11,211,8,197,255,226,140,167,69,234,50,116,46,199,107,158,192,62,176,254,19,2,45,64],[14,178,229,180,185,160,104,174,182,25,245,27,201,241,237,98,145,92,72,248,193,225,118,137,107,141,222,104,107,2,33,207,51,11,137,58,87,85,238,31,24,127,112,181,178,38,200,50,10,197,117,215,223,196,165,186,47,251,255,100,137,108,80,88,43,208,67,60,13,173,47,93,200,46,123,37,207,189,232,151,202,86,88,207,10,77,31,172,200,244,236,164,200,220,113,86],[10,223,21,190,253,116,178,160,250,247,7,109,3,69,220,204,150,123,47,165,171,60,58,5,154,139,54,223,109,165,20,241,224,26,135,87,235,1,7,198,21,172,23,40,221,126,43,33,9,70,72,246,219,84,130,61,115,120,118,225,233,123,135,212,171,74,97,247,2,85,232,153,63,86,145,171,129,129,148,58,89,228,51,45,91,177,194,4,81,189,62,146,115,53,121,238],[8,165,109,124,188,144,178,68,117,61,218,18,149,191,144,109,174,117,95,227,207,103,190,30,172,83,65,172,111,3,226,61,138,57,157,38,192,200,75,216,175,58,138,102,139,81,120,45,7,49,156,189,157,107,14,6,24,123,110,111,86,45,91,167,113,255,166,179,90,89,155,200,11,216,212,176,189,138,181,152,166,22,148,119,182,95,197,203,191,219,185,151,204,135,47,124],[8,209,61,204,10,198,249,153,224,204,26,139,134,114,95,118,182,174,170,170,104,29,196,236,106,17,118,48,118,179,7,231,26,78,65,248,12,166,237,229,13,217,191,198,229,55,5,145,9,146,144,197,155,223,234,153,90,244,159,231,205,191,86,216,169,20,0,23,143,143,12,176,154,221,236,238,40,41,224,52,42,152,98,88,1,61,165,135,97,132,202,201,65,231,85,31],[16,209,208,114,155,74,194,214,254,134,213,31,252,50,118,254,122,183,253,174,25,68,171,212,132,131,34,163,152,206,230,25,26,241,36,228,174,249,210,221,82,153,148,221,161,177,5,13,22,18,157,237,235,241,168,214,81,185,98,187,182,86,80,239,160,150,74,76,137,200,101,33,123,184,72,90,172,24,34,57,193,227,94,112,176,53,46,62,43,213,231,190,77,61,210,49],[19,38,162,96,219,49,167,135,177,211,6,59,75,231,5,112,100,59,115,247,150,153,64,150,213,113,87,240,90,212,196,31,70,190,220,167,189,246,250,193,214,238,233,129,124,243,35,154,21,117,92,240,135,164,249,131,237,113,183,130,235,156,139,11,12,74,93,94,222,151,246,244,70,179,75,101,75,205,36,129,74,221,215,148,146,129,49,1,0,158,69,166,81,221,180,105],[17,132,123,101,222,254,36,151,78,140,51,48,153,13,61,161,228,118,235,78,233,28,97,104,155,202,153,34,243,187,2,192,12,130,253,251,32,243,81,142,220,83,191,174,127,201,83,79,14,25,85,150,226,147,41,131,134,180,66,160,49,176,112,250,164,36,33,216,201,25,7,250,74,20,11,38,111,237,50,143,121,222,68,147,173,176,11,139,77,82,230,30,26,98,72,140],[17,78,68,173,84,123,252,85,255,168,143,4,253,93,22,37,53,238,135,52,36,196,248,158,180,128,163,253,187,182,195,138,120,237,153,59,27,21,73,61,35,143,98,69,100,212,232,52,17,200,239,47,64,133,210,101,111,195,141,116,80,98,84,82,186,214,38,177,6,172,34,55,5,1,99,44,65,77,143,98,21,225,119,221,18,96,82,98,64,76,244,171,205,2,175,11],[11,72,179,194,172,171,26,17,121,15,141,45,213,185,152,244,206,231,43,160,223,94,118,172,186,159,109,210,158,234,238,181,57,167,106,15,158,255,109,94,44,21,27,124,20,155,104,5,21,56,144,104,53,110,137,19,115,221,145,175,169,108,84,31,227,208,130,240,205,71,174,200,163,244,199,197,16,176,44,232,133,59,5,80,125,204,2,194,252,211,111,39,89,212,220,166],[11,195,190,57,164,22,86,7,45,32,242,75,5,56,121,101,98,100,127,187,11,86,37,56,107,153,79,63,137,124,15,27,71,107,72,21,75,157,70,109,9,57,247,69,28,138,82,18,13,106,123,132,174,92,176,38,160,254,42,224,33,134,153,145,131,207,14,25,203,191,43,66,218,138,65,62,254,218,22,105,252,79,119,64,236,34,188,47,228,51,244,63,177,59,160,192],[23,183,6,57,64,115,107,190,207,83,54,25,223,216,53,234,69,146,19,247,14,249,180,64,50,117,70,253,64,44,131,149,91,214,249,200,186,18,212,249,254,41,59,194,182,87,98,61,21,226,252,155,97,195,57,189,240,168,12,16,39,104,199,236,234,162,207,111,48,69,88,182,48,80,183,1,226,105,119,19,47,10,60,188,255,104,33,221,235,246,22,12,114,40,4,195],[15,81,69,197,21,107,134,109,246,221,45,143,184,206,197,132,118,18,62,202,129,200,235,113,169,203,84,213,209,184,3,102,107,104,189,180,14,167,135,218,37,34,137,147,185,100,16,135,20,253,149,88,149,240,88,156,132,110,144,26,210,109,146,123,84,73,225,73,188,251,240,110,94,32,249,194,164,102,143,31,183,230,202,62,213,172,120,179,103,126,149,56,91,153,245,132],[23,62,70,240,171,204,48,242,225,7,165,127,77,190,32,38,155,56,211,215,2,65,201,94,14,195,0,195,37,78,225,62,178,94,195,109,160,101,242,222,162,4,153,83,101,141,198,244,0,56,70,216,147,84,190,95,235,41,115,171,169,101,54,167,230,140,130,172,22,142,21,105,241,254,101,143,175,127,211,180,208,250,180,117,254,179,103,177,130,108,15,13,180,176,144,36],[4,201,250,141,49,60,171,245,26,73,46,78,218,174,205,131,100,252,165,188,225,83,135,247,125,97,81,127,100,102,221,231,159,68,143,148,158,124,163,196,18,217,215,223,225,231,12,226,17,100,52,12,228,186,19,158,242,217,45,205,175,175,173,70,26,58,33,2,143,207,193,128,203,147,166,100,56,2,223,237,6,192,60,28,213,123,78,37,212,45,34,171,22,25,169,159],[12,108,193,194,121,156,27,238,219,116,2,202,154,199,33,223,196,101,99,223,154,174,55,39,220,237,98,168,40,105,140,152,6,183,27,152,76,70,35,22,103,90,38,120,133,102,1,27,18,192,33,236,232,158,249,89,237,33,144,186,253,213,24,224,46,175,92,177,232,239,50,181,187,231,53,23,58,183,17,127,212,213,186,56,175,186,131,143,201,81,122,213,226,20,30,30],[12,80,107,140,42,32,62,224,237,154,122,70,202,125,82,154,156,227,58,149,5,103,2,102,22,153,59,56,144,62,16,29,93,100,174,199,108,138,53,163,107,1,56,235,135,235,233,223,0,0,206,249,249,23,207,212,125,97,213,1,89,184,136,110,130,187,92,111,84,155,182,241,151,81,75,74,253,160,48,68,204,39,216,38,186,12,48,94,30,235,30,179,204,223,35,11],[9,163,218,189,133,97,66,184,225,214,43,202,99,239,168,31,126,197,133,84,9,251,217,56,63,130,146,226,180,100,21,167,250,201,65,164,177,25,153,220,73,40,183,148,179,20,49,126,16,108,176,131,244,240,91,200,59,232,79,220,24,33,187,132,10,136,237,155,58,59,227,174,75,229,245,184,165,248,222,8,50,194,127,164,123,139,63,90,84,68,105,77,104,150,182,67],[14,46,117,95,254,23,148,107,114,209,114,247,23,145,39,100,179,32,81,20,206,35,10,111,146,211,63,231,175,51,122,106,26,73,196,94,29,43,19,125,227,199,224,251,157,14,14,202,8,75,176,186,93,249,21,11,101,198,0,109,201,63,167,104,161,138,225,117,30,56,207,214,4,79,56,103,61,163,88,145,106,216,201,144,25,124,97,246,174,143,53,177,199,203,99,218],[15,216,178,205,45,78,184,212,25,111,61,127,162,89,234,196,106,116,102,133,200,246,206,77,191,177,81,105,23,31,240,167,249,201,148,94,219,104,37,233,19,20,247,201,186,27,177,68,10,62,238,253,83,102,99,54,35,43,159,49,218,251,43,245,200,218,146,99,51,90,113,244,0,80,31,174,17,108,235,215,177,208,233,187,230,126,50,33,6,21,237,67,7,69,133,227],[8,98,217,132,113,193,121,176,220,153,200,167,52,190,101,25,175,210,90,148,210,223,35,102,237,139,17,54,29,32,92,2,198,246,80,231,115,203,185,60,14,176,207,228,141,162,57,35,2,56,45,27,142,236,184,234,190,192,11,44,18,141,106,251,80,113,207,233,231,35,44,139,50,102,230,251,11,166,177,176,107,229,134,191,247,111,161,51,160,104,3,149,18,159,216,96],[12,71,228,159,165,21,146,86,218,183,115,184,15,225,70,22,148,166,13,75,149,215,251,49,39,253,164,131,93,56,50,28,161,82,165,92,152,192,139,173,158,246,222,164,18,164,7,200,15,182,110,55,52,23,220,44,23,67,160,66,165,25,201,54,168,19,7,118,43,232,36,12,239,32,134,177,229,189,212,136,157,218,38,136,75,166,152,232,243,240,159,211,212,252,73,152],[22,141,54,235,191,233,229,33,95,103,168,246,101,165,229,155,49,184,141,142,185,147,210,22,203,2,77,225,150,95,124,105,44,239,13,173,28,220,27,240,3,23,215,176,33,97,32,158,11,237,62,143,162,215,187,163,29,149,130,207,156,97,128,215,203,26,212,48,71,10,123,161,255,210,79,45,195,102,221,215,114,149,207,217,105,61,55,188,42,2,131,45,27,217,2,4],[5,212,161,78,4,131,184,214,129,216,145,73,143,241,53,6,78,234,8,49,69,203,217,159,247,138,237,113,186,250,76,211,197,6,150,159,54,152,80,226,77,229,205,222,67,230,160,186,7,220,127,12,102,146,243,13,91,177,89,243,225,60,149,36,219,197,131,72,166,242,254,184,229,123,134,55,88,28,77,96,84,7,231,49,158,54,107,20,207,253,158,37,125,23,98,110],[11,85,28,67,143,12,193,63,252,207,223,136,165,146,119,151,39,224,112,105,8,85,144,87,94,250,136,146,226,154,31,188,107,214,138,16,159,242,8,46,83,164,20,253,115,160,108,242,15,183,236,184,157,25,201,225,19,48,172,166,96,103,80,173,239,109,68,92,58,62,25,140,202,118,126,170,142,192,77,175,228,150,92,147,115,203,156,142,135,193,103,169,33,238,1,88],[8,41,196,121,0,165,223,227,182,228,122,174,137,229,248,204,133,239,139,211,18,78,229,99,91,227,196,231,231,74,19,226,103,74,109,192,20,133,79,88,178,185,136,46,111,91,240,157,15,181,23,99,178,227,59,119,10,207,67,236,108,160,36,199,160,56,162,46,220,243,127,111,58,247,73,105,167,175,139,41,67,197,146,36,59,18,241,60,133,21,135,144,76,199,241,228],[12,178,36,201,186,86,195,198,39,254,244,56,142,102,236,244,179,120,150,32,162,164,97,17,205,196,95,139,161,246,104,153,87,229,42,173,129,49,155,66,52,130,84,110,27,124,128,21,22,37,232,104,60,67,67,123,179,165,208,210,47,44,84,209,181,60,205,224,184,197,167,84,30,172,3,101,119,121,238,13,228,61,64,31,67,97,35,54,219,215,147,237,124,69,232,31],[17,250,184,245,195,22,85,115,69,160,183,35,140,37,50,184,226,65,240,80,224,134,168,204,159,71,246,63,116,79,137,40,43,66,219,253,38,248,164,10,226,156,55,181,49,58,139,109,7,109,171,172,102,87,131,208,195,12,58,129,83,135,165,226,32,54,182,252,122,135,153,141,243,56,216,113,204,117,88,136,232,244,31,225,236,96,140,8,17,209,207,85,174,95,176,243],[3,162,246,74,240,54,162,213,106,90,169,120,2,112,66,84,251,29,118,240,196,34,28,66,130,58,215,28,252,218,158,176,41,235,46,149,154,162,107,34,1,168,213,122,156,90,43,157,7,3,36,58,189,211,249,119,53,158,204,59,178,240,53,168,177,131,83,29,255,92,56,55,78,120,58,107,136,194,92,19,27,236,27,185,145,55,146,72,93,228,226,187,130,221,156,87],[23,201,70,255,131,9,40,165,222,146,143,243,68,225,216,181,219,21,2,48,76,169,51,14,104,180,60,71,59,180,41,154,126,181,64,99,76,104,171,64,63,119,120,247,175,192,107,206,6,8,67,255,195,59,175,143,137,227,30,129,18,250,43,192,103,87,82,75,232,169,191,142,144,6,153,125,98,3,241,94,189,191,220,125,64,211,157,84,115,61,13,3,125,180,126,158],[20,140,103,126,61,115,238,121,235,108,44,165,188,64,75,7,97,126,149,195,218,155,121,201,195,241,67,78,229,14,162,28,76,155,128,117,33,229,209,97,121,230,107,47,33,255,3,221,22,146,191,189,86,126,24,173,44,137,147,236,25,218,26,91,200,197,52,72,176,2,154,3,57,212,189,202,28,48,136,220,174,254,172,204,79,28,232,234,27,19,193,44,188,247,199,74],[15,107,133,186,244,237,171,193,87,213,195,28,215,154,179,39,27,21,43,233,155,101,49,39,70,39,87,236,109,63,95,146,212,196,40,167,58,104,170,207,99,253,104,162,230,149,71,48,7,7,141,219,65,1,195,39,152,175,54,55,76,29,2,57,249,198,109,255,146,148,32,243,189,71,96,252,52,23,241,214,14,78,224,170,195,59,52,84,142,83,131,66,177,57,62,87],[22,166,64,35,58,84,43,211,173,174,212,210,188,217,194,193,159,149,173,123,125,128,155,195,27,40,254,202,7,163,187,2,206,113,77,191,22,84,98,114,140,215,90,18,99,145,19,65,13,96,175,250,211,179,19,210,236,174,209,84,172,228,165,79,72,198,171,38,116,93,149,65,78,129,36,177,51,85,180,234,5,123,187,81,51,255,194,239,135,136,222,204,162,217,101,169],[8,128,184,4,221,206,21,75,11,92,91,219,139,138,111,116,21,141,189,143,122,224,22,232,234,87,128,162,178,234,99,143,177,145,185,160,20,26,37,140,147,140,8,217,249,39,180,100,18,39,215,223,157,101,12,201,92,49,139,229,206,168,229,192,110,250,200,64,107,214,87,244,110,181,165,131,214,162,47,236,12,103,81,84,29,55,97,101,214,146,10,155,254,1,33,202],[22,147,59,116,100,236,110,84,118,83,20,182,18,237,82,43,226,111,128,189,5,166,92,179,238,43,236,36,171,247,43,8,121,230,119,104,186,59,73,126,224,197,73,210,6,169,51,31,12,10,149,192,168,197,197,215,104,27,216,130,235,32,205,28,163,198,247,172,151,99,15,218,142,63,5,216,113,133,120,198,245,193,58,197,103,224,132,251,62,51,131,13,251,196,222,194],[5,177,232,232,99,176,166,239,191,244,117,124,219,9,194,170,37,219,44,0,220,130,208,117,219,155,186,59,5,54,170,235,0,8,99,108,142,118,238,124,80,20,163,166,226,83,98,183,16,241,54,253,225,142,11,240,71,20,24,13,199,217,73,201,60,83,198,154,17,57,185,223,181,44,14,173,127,135,22,125,42,62,42,101,119,67,205,58,123,156,76,168,103,47,179,231],[8,50,154,225,254,99,130,34,42,235,234,129,205,149,4,130,98,34,8,22,190,126,186,92,124,124,110,151,27,86,58,251,106,188,157,226,124,111,149,67,150,63,163,229,0,145,150,181,22,186,239,212,91,28,196,124,173,69,176,83,39,61,152,245,252,226,104,32,139,252,192,249,56,48,78,72,138,34,78,51,198,214,46,50,234,22,138,62,28,97,95,19,86,87,82,89],[3,45,17,14,237,195,212,236,162,226,49,77,36,233,82,32,96,193,113,220,86,12,63,125,91,227,6,226,94,42,131,24,135,132,109,13,32,126,109,34,162,143,19,4,237,212,130,129,18,113,52,140,198,174,135,4,171,16,144,58,126,242,77,94,27,218,149,130,216,101,60,130,113,48,87,64,29,191,251,200,34,239,30,219,113,135,127,41,212,183,245,74,54,84,109,209],[23,137,75,253,228,167,134,100,43,13,21,134,200,173,139,231,34,149,40,175,159,220,203,47,18,6,204,104,139,183,230,113,136,107,184,7,170,1,198,230,97,221,174,220,114,171,38,109,12,68,5,215,74,177,18,87,21,139,124,69,237,114,77,144,36,169,86,64,202,190,240,231,104,111,248,116,103,202,152,76,136,202,24,132,8,111,187,116,180,164,72,245,73,81,214,155],[22,206,144,24,50,243,126,250,42,173,247,143,183,171,96,130,66,145,27,74,208,99,168,223,122,114,116,82,21,103,99,112,188,71,79,118,203,68,212,10,208,84,175,136,3,222,197,6,12,222,57,222,242,63,150,24,187,152,176,22,194,33,162,254,228,160,1,89,53,253,219,217,1,186,44,118,151,106,211,22,27,26,249,247,141,218,162,10,71,41,83,107,37,147,22,94],[8,34,159,60,250,127,161,18,148,143,29,31,136,191,140,12,242,116,112,237,115,181,148,179,82,92,108,7,40,75,119,94,21,66,111,165,32,138,243,181,249,169,185,2,238,170,195,202,20,177,120,152,72,211,18,14,164,32,11,149,142,211,137,250,57,169,214,175,136,210,78,180,115,178,181,46,1,48,61,134,92,122,79,87,215,123,180,159,251,234,148,21,28,81,220,31],[21,48,72,27,216,113,22,66,189,19,48,107,238,193,35,243,171,48,50,34,139,42,54,216,212,128,8,113,255,105,47,32,179,240,194,56,43,56,2,16,34,34,228,200,142,72,140,173,19,1,47,164,7,92,144,80,54,167,12,1,249,29,75,228,110,60,8,196,107,111,165,83,44,171,127,194,211,228,167,214,111,166,145,152,72,43,155,122,168,66,167,243,89,222,247,192],[6,144,181,167,214,212,138,175,154,100,171,175,4,113,118,25,171,191,174,220,184,109,23,11,210,166,124,145,86,176,109,113,136,143,96,114,247,60,72,137,80,151,77,134,221,76,156,194,21,95,74,115,85,93,110,99,22,118,118,6,179,158,216,132,228,102,253,31,165,102,101,1,48,245,80,75,18,99,42,152,152,4,167,180,136,90,192,223,200,66,118,8,180,65,140,90],[8,241,69,185,44,199,255,179,201,201,156,48,223,20,77,220,77,28,107,37,78,25,219,108,94,131,205,34,37,1,232,18,14,70,171,56,139,82,201,84,31,42,149,57,53,177,67,141,23,11,132,244,159,125,86,94,230,81,12,107,66,38,129,44,140,209,2,145,206,0,247,204,191,66,45,96,17,137,121,96,121,203,244,142,235,32,96,120,234,131,83,139,247,23,247,212],[24,42,180,203,144,188,253,149,153,134,211,116,3,118,103,252,146,67,204,73,82,231,128,131,174,145,4,100,250,220,92,243,204,14,128,93,51,5,172,222,75,143,56,60,206,77,147,32,18,81,82,104,48,51,34,244,139,87,123,163,64,54,133,199,145,86,121,224,200,231,234,147,129,190,185,244,125,77,150,38,209,6,127,111,101,130,74,86,132,83,5,65,22,61,132,181],[13,26,52,200,9,31,56,67,53,29,153,10,249,27,182,111,94,93,229,187,50,115,86,132,244,6,130,168,37,156,41,51,161,215,43,38,131,125,180,254,97,53,71,114,218,49,204,126,18,158,142,168,169,122,40,188,193,189,35,102,247,11,232,113,86,190,223,28,207,254,156,191,209,84,207,211,63,105,185,182,24,92,174,52,177,197,188,49,134,106,201,104,162,236,116,207],[7,140,3,158,239,32,141,80,137,1,120,219,182,107,77,65,90,39,220,159,89,1,167,241,124,82,26,75,40,171,240,136,201,145,86,32,250,203,45,87,101,249,56,8,121,218,234,5,8,113,91,153,209,162,83,127,134,25,252,208,106,105,178,104,3,233,92,163,35,187,251,216,36,120,101,192,24,83,1,174,246,236,161,13,219,10,44,31,33,55,239,100,155,165,225,67],[10,208,161,163,108,179,141,26,18,163,30,121,217,252,128,195,27,87,30,13,85,34,128,103,12,140,60,157,5,83,219,30,83,174,21,174,188,180,211,39,192,144,51,66,146,233,9,136,3,12,186,216,244,234,114,67,8,135,74,54,128,136,233,179,28,53,195,255,78,221,187,157,144,230,65,101,159,234,235,210,45,134,158,208,77,158,199,142,234,181,181,9,72,225,123,118],[10,229,143,98,130,202,249,108,107,103,247,224,245,57,110,222,196,249,79,178,77,162,173,141,16,208,81,227,173,101,232,23,69,238,133,93,208,171,219,217,145,169,243,172,163,20,241,119,5,234,170,197,38,101,136,28,19,145,71,75,24,133,94,1,20,99,61,116,15,128,161,8,116,139,149,246,25,97,23,97,1,64,213,184,253,8,203,85,173,238,180,27,187,135,21,145],[22,249,208,190,95,174,237,17,55,90,69,125,158,149,165,228,92,57,32,140,66,219,125,77,28,55,176,209,176,51,250,183,53,158,103,73,106,129,100,32,192,36,100,255,28,100,40,151,17,121,206,182,28,93,94,175,146,143,151,207,3,215,220,23,143,161,109,95,11,248,34,200,36,178,41,178,221,220,167,13,165,103,226,252,205,193,230,62,193,160,229,33,72,109,59,72],[23,226,94,97,9,254,19,208,154,111,225,103,15,138,64,224,120,64,46,248,119,24,190,86,7,218,14,129,191,84,161,138,230,104,186,124,181,139,186,126,213,28,45,206,13,102,49,220,13,173,184,218,235,97,1,21,94,194,57,156,208,189,225,192,54,22,85,146,95,7,136,238,50,0,243,162,224,172,38,81,238,112,182,225,41,142,125,21,99,41,97,129,122,2,108,229],[6,114,149,180,47,129,6,203,161,101,112,49,4,83,30,165,188,10,230,20,52,201,187,96,108,84,125,20,245,36,173,104,7,93,140,93,246,106,9,197,112,90,149,109,197,106,10,132,2,232,142,255,42,85,7,158,182,233,107,129,202,95,117,184,124,104,54,224,228,76,82,88,71,49,33,82,79,74,192,20,209,98,101,209,49,57,17,169,82,151,80,19,240,25,244,149],[8,115,246,113,149,115,128,176,167,9,131,229,121,18,178,123,132,105,174,239,110,13,73,210,206,5,16,139,157,108,41,217,157,139,97,89,114,208,226,199,159,220,132,215,108,18,247,2,15,183,25,46,179,207,62,215,81,5,46,34,199,68,239,184,47,69,124,67,247,19,53,220,191,211,201,101,166,200,37,187,117,238,127,69,30,63,188,228,211,243,3,211,125,92,57,167],[21,47,60,209,46,18,29,193,166,115,82,134,42,179,111,111,135,80,27,37,239,50,52,83,250,140,126,20,193,211,124,88,142,147,127,232,130,135,160,23,160,175,156,18,9,110,29,204,12,182,99,107,147,64,107,31,186,52,100,129,6,50,235,250,247,228,34,145,9,72,134,125,109,184,115,221,162,1,55,220,38,34,216,22,212,191,17,43,52,180,202,87,178,67,117,188],[14,32,63,225,23,170,5,97,95,63,49,133,65,11,157,26,176,25,226,128,73,171,27,80,61,216,237,170,92,246,21,63,0,45,51,181,123,108,255,204,238,27,9,96,13,150,108,7,18,69,99,53,228,135,154,14,150,212,190,99,99,144,133,100,99,147,96,252,60,106,156,94,49,140,171,16,233,172,188,204,30,83,143,173,101,88,155,41,219,154,234,40,253,239,131,156],[8,123,206,121,84,45,195,113,227,14,151,77,165,174,164,30,43,200,173,30,2,174,65,5,122,95,204,117,240,58,108,210,214,195,185,110,245,130,12,14,18,14,245,29,103,218,177,58,21,164,120,252,98,135,111,97,84,113,187,168,184,40,40,117,194,184,197,177,76,126,170,72,229,184,62,107,112,132,42,229,61,225,182,221,103,24,144,224,208,255,146,219,99,25,64,183],[11,160,66,16,194,233,15,71,8,59,46,149,238,185,132,224,171,94,60,33,218,37,148,64,85,233,58,8,147,72,222,176,240,138,162,210,26,167,139,185,148,129,23,72,119,78,124,113,7,211,63,101,191,176,201,229,47,109,240,73,68,100,28,180,154,214,239,138,146,93,131,218,193,66,114,7,164,108,73,87,245,83,201,118,58,252,233,120,11,135,83,217,138,128,175,124],[6,130,246,57,243,99,200,219,74,94,100,111,200,71,22,113,101,97,202,184,110,116,235,117,198,219,147,85,66,244,4,92,61,177,222,44,109,224,46,106,146,173,36,207,33,20,158,134,13,150,212,235,84,159,0,77,163,177,192,242,228,110,90,92,171,191,120,13,212,32,155,118,252,101,54,134,225,63,212,215,24,78,133,125,75,231,243,109,204,27,60,180,204,213,78,210],[24,59,6,26,142,230,186,154,56,232,38,152,20,64,20,151,35,232,88,44,147,241,130,53,192,80,140,255,210,197,65,112,129,41,162,78,134,211,115,56,229,101,92,122,14,226,67,44,24,158,214,166,152,106,241,241,241,154,88,197,191,143,254,119,37,81,223,138,141,30,174,112,87,108,236,185,67,86,72,136,80,240,62,36,106,248,124,241,57,45,177,103,47,132,124,30],[18,172,109,199,85,44,156,28,217,195,26,222,96,247,146,178,65,68,140,52,212,149,136,216,19,34,224,115,213,215,151,208,237,160,251,113,199,198,99,88,9,148,200,139,90,63,63,150,4,159,118,198,229,147,36,193,140,163,87,92,107,249,168,138,243,184,201,229,158,168,14,154,79,73,131,44,17,255,202,98,230,229,215,172,226,213,189,241,253,31,13,191,64,53,81,57],[15,177,103,236,148,255,188,76,236,210,220,170,86,191,65,29,241,226,239,157,27,109,224,95,251,19,79,69,213,96,76,51,6,201,74,43,36,43,156,205,117,9,220,184,144,9,188,100,22,43,228,9,192,123,5,90,253,203,31,50,126,13,28,104,157,152,234,156,15,161,38,228,162,18,249,206,99,6,70,133,187,61,119,86,183,52,0,227,95,208,35,191,169,129,208,130],[12,247,84,168,195,241,11,71,94,96,43,18,184,214,153,78,205,201,22,17,164,249,1,28,38,82,220,219,98,97,198,4,62,19,130,176,85,84,139,128,25,36,154,233,114,94,78,63,16,138,2,254,223,31,176,248,50,129,207,53,87,189,93,205,118,129,236,166,233,99,194,45,20,151,47,142,217,55,57,54,254,115,92,63,222,92,148,83,183,98,190,118,150,198,150,236],[14,84,161,95,221,205,200,50,224,79,17,89,65,204,4,88,233,39,112,205,65,166,41,201,7,48,61,187,210,220,100,164,209,242,215,172,40,154,50,105,8,244,188,117,205,14,110,33,25,85,86,171,18,21,0,50,235,175,233,71,199,51,133,41,247,56,75,99,133,45,163,14,77,244,253,70,30,46,201,34,52,3,55,121,95,213,86,190,142,132,235,14,222,92,207,154],[10,69,237,211,153,160,252,214,48,178,120,251,200,141,143,254,155,88,46,35,244,111,157,34,185,33,10,137,108,203,66,181,98,70,230,186,253,95,213,187,215,180,122,230,233,232,102,205,18,130,182,199,120,193,107,114,23,18,161,136,7,152,202,9,105,31,80,106,119,213,243,167,102,29,103,237,250,47,91,0,192,240,137,142,19,68,224,199,150,126,219,185,221,238,231,248],[13,95,112,148,151,43,26,24,65,192,8,51,83,208,81,110,182,94,104,250,1,88,123,105,64,172,159,65,22,207,228,182,224,98,130,25,144,54,240,50,77,178,196,238,194,200,102,9,0,161,171,101,241,62,166,131,55,4,185,84,141,90,45,126,123,213,213,211,201,139,137,49,33,14,243,18,224,183,209,108,235,85,119,192,75,109,213,102,113,30,43,250,54,183,28,4],[23,122,8,156,120,46,227,56,31,160,18,180,136,119,164,169,122,43,231,95,30,122,233,54,118,216,178,6,216,125,153,251,63,24,120,185,128,211,193,99,251,92,69,16,215,43,220,7,23,12,163,240,143,231,13,82,15,93,130,254,43,160,145,208,21,175,110,111,56,143,112,55,16,231,4,78,92,102,72,79,68,40,56,23,32,108,17,55,203,238,155,0,230,164,81,225],[20,12,20,78,229,116,96,179,99,174,172,251,29,22,232,227,116,207,56,152,189,24,165,157,132,39,18,138,190,118,7,212,233,95,225,217,75,241,31,198,8,88,73,144,66,139,197,164,1,49,234,125,135,228,101,87,102,38,62,221,59,161,33,94,201,30,13,237,179,142,140,239,101,192,178,237,219,134,192,66,54,195,89,196,9,153,170,164,73,243,45,115,52,203,110,16],[6,17,139,200,5,145,80,44,69,13,137,250,166,202,137,189,231,213,38,4,249,120,255,123,160,179,63,118,35,148,211,62,156,219,100,136,213,232,130,91,211,81,10,121,173,195,108,102,22,106,111,16,225,64,115,130,179,83,66,157,60,36,44,95,253,36,157,121,73,167,191,180,56,167,226,226,156,65,126,125,107,66,48,160,226,16,144,39,211,154,204,48,227,222,218,7],[3,123,148,161,57,22,20,109,37,97,226,85,125,111,21,247,20,30,19,210,90,141,65,65,97,228,166,96,24,173,125,56,212,238,4,146,214,200,115,71,218,214,138,143,117,64,83,160,4,40,126,200,179,173,93,70,95,131,46,183,63,96,73,171,63,254,86,172,163,214,55,2,189,196,215,2,0,36,172,252,200,51,20,169,181,220,203,55,105,155,230,167,102,44,65,237],[1,69,11,165,198,96,207,92,37,122,200,10,85,219,215,126,89,192,106,126,175,169,180,134,127,39,54,240,192,56,182,71,233,220,82,114,201,19,194,248,16,38,143,229,78,48,99,64,10,204,240,190,53,47,62,157,235,78,236,116,205,220,237,219,130,240,244,168,96,23,134,14,158,220,131,7,110,182,65,251,49,156,111,168,2,39,23,203,155,62,6,26,61,126,90,31],[11,19,183,146,232,110,12,254,226,161,16,199,207,72,18,227,69,222,154,236,129,40,209,144,2,232,218,232,126,1,181,231,164,163,53,96,87,237,114,85,231,24,42,182,32,123,69,197,20,24,229,228,104,110,62,234,2,115,171,229,89,40,19,154,223,108,74,9,35,44,145,150,154,38,161,230,189,50,47,177,226,239,177,16,77,222,171,177,189,3,195,83,35,14,154,197],[8,68,138,4,143,122,21,79,230,166,124,47,78,226,19,150,216,99,32,245,113,166,180,91,68,102,202,0,142,71,244,202,149,249,205,93,162,29,201,195,16,131,250,172,203,215,190,247,18,147,240,169,217,185,127,110,65,140,136,60,169,230,146,250,101,186,82,165,237,118,73,153,196,167,31,178,39,220,161,177,23,215,55,233,185,65,214,81,190,49,177,125,19,73,186,115],[21,83,53,243,205,27,164,155,163,170,151,61,22,174,67,230,181,199,99,0,169,104,65,146,77,148,104,87,90,255,202,42,184,254,209,241,179,214,230,79,63,114,29,226,187,8,178,230,3,136,66,213,223,220,73,169,95,88,238,136,42,117,19,140,110,162,102,195,48,171,172,101,147,99,59,2,93,223,189,104,236,164,0,54,109,2,48,216,63,25,44,148,110,21,236,75],[23,21,177,45,182,60,139,120,166,100,199,12,212,116,128,204,161,35,79,120,61,97,183,46,109,78,98,96,107,147,117,16,53,111,138,200,72,194,253,36,25,42,237,67,100,91,246,19,18,127,99,23,172,28,189,117,84,248,66,156,103,42,245,3,175,88,52,168,160,48,239,25,216,120,132,239,217,121,130,226,27,29,188,90,205,236,54,182,72,205,232,252,54,116,149,101],[22,216,252,95,188,190,85,85,135,133,144,240,26,29,61,41,123,19,229,137,8,80,201,156,171,179,182,200,213,196,79,162,206,2,20,237,204,250,181,82,0,60,231,144,26,188,102,126,13,105,170,151,135,6,246,245,207,74,254,67,122,243,74,75,142,58,207,194,113,214,185,250,230,143,76,75,189,128,128,151,98,223,125,202,44,208,252,41,2,129,53,13,15,50,9,143],[25,38,115,205,129,197,197,184,166,156,175,180,27,53,3,136,191,130,124,221,16,231,74,69,4,227,248,141,120,72,56,248,193,90,188,101,57,231,10,208,97,26,139,93,20,244,201,34,8,119,0,71,153,192,3,70,53,218,28,206,213,253,202,199,153,202,140,174,210,249,68,119,28,122,143,174,201,70,210,79,15,143,15,222,246,210,169,4,176,50,249,187,156,26,68,219],[15,25,236,238,239,39,149,60,158,60,106,211,167,208,0,174,205,55,77,167,95,172,255,213,182,40,102,35,196,167,24,103,111,140,242,16,154,198,39,13,42,7,128,174,102,159,56,71,10,129,12,191,48,165,164,57,20,162,110,182,151,41,149,213,255,167,102,166,222,212,65,217,15,61,233,45,119,71,66,44,67,206,12,143,248,107,176,232,36,3,190,174,126,30,227,185],[16,179,211,49,123,225,210,216,168,70,88,111,28,70,40,116,49,79,106,81,233,120,235,230,187,8,184,212,224,145,114,149,100,137,187,22,125,103,0,9,141,244,243,33,137,50,95,75,21,108,75,40,188,216,15,102,252,171,134,215,56,43,87,24,18,33,159,70,174,172,105,167,6,164,201,105,212,209,102,2,164,234,160,12,231,216,141,67,50,166,205,7,5,86,16,20],[20,209,206,87,255,251,189,68,10,138,244,53,203,95,3,102,23,121,16,103,221,177,5,232,99,39,205,5,136,203,39,95,14,111,98,11,242,158,50,136,234,176,132,61,181,110,7,206,21,79,99,17,83,168,94,250,186,255,185,79,134,39,255,222,169,240,229,149,82,181,195,62,56,19,73,165,142,78,96,227,253,243,83,33,234,220,98,163,41,118,73,202,239,189,100,249],[24,178,120,146,117,233,46,21,210,145,60,148,121,83,110,30,193,221,175,250,121,11,60,68,223,116,209,206,17,81,122,46,33,239,74,150,204,203,156,213,46,6,160,253,221,19,230,163,22,199,231,71,193,19,23,160,211,200,152,73,71,166,69,200,24,203,227,141,75,32,95,54,241,65,23,44,197,50,154,157,181,20,172,99,181,198,168,217,26,196,239,82,176,47,213,228],[22,63,202,123,205,127,8,73,106,55,88,85,191,211,14,182,123,85,96,167,210,199,188,247,241,237,119,123,121,122,25,125,76,11,56,72,76,114,168,200,48,92,249,207,44,24,91,219,17,176,135,105,44,196,221,102,21,148,167,53,250,248,208,229,196,71,97,192,123,197,154,212,203,77,200,166,179,55,254,35,137,160,1,107,178,14,52,82,199,34,58,59,198,33,51,110],[7,147,146,137,33,9,60,4,25,233,92,151,22,115,14,180,201,179,103,253,253,99,122,228,94,116,87,208,108,154,136,63,174,221,108,80,45,172,143,36,126,136,69,187,254,12,154,185,0,57,78,57,177,24,72,77,202,124,204,55,227,170,68,155,64,155,179,184,117,98,203,198,76,111,181,241,74,123,216,77,136,192,111,169,129,68,125,226,52,161,45,118,217,107,168,167],[23,24,87,183,21,248,114,165,238,172,60,5,94,135,217,207,46,143,37,53,120,49,73,113,61,112,21,106,91,75,203,168,222,131,5,174,107,200,239,230,120,192,190,179,62,82,10,176,0,75,156,208,31,33,30,189,136,175,74,200,119,1,33,67,2,148,243,177,57,40,57,92,243,195,70,203,72,35,192,140,104,56,134,134,214,97,168,186,142,166,23,41,236,16,51,190],[25,168,254,236,35,229,12,149,13,68,0,198,152,76,215,40,47,151,1,187,163,14,188,6,136,229,85,121,98,90,139,223,252,217,101,215,49,170,183,202,165,90,165,54,253,211,15,161,2,243,90,188,139,161,117,228,221,65,180,36,217,37,50,85,24,72,185,161,34,223,104,62,135,185,174,223,213,232,90,25,175,187,123,215,19,34,37,115,243,17,7,60,61,229,0,139],[20,213,255,90,176,23,238,180,106,53,23,73,237,4,197,181,208,223,136,165,88,122,200,64,121,141,109,251,210,128,115,194,55,54,62,162,200,98,172,64,237,182,252,188,241,215,76,3,3,197,215,94,213,101,103,239,242,192,147,236,14,210,196,48,9,180,233,84,175,138,112,134,23,124,235,1,84,243,53,172,216,137,231,57,125,166,198,109,187,51,150,140,237,212,189,220],[22,28,191,244,145,203,173,238,179,249,107,195,61,69,125,116,89,36,124,10,24,30,170,28,136,250,83,21,224,159,242,6,41,229,209,36,42,228,199,121,0,132,229,18,142,94,210,160,14,92,0,240,123,204,127,164,80,227,58,211,76,230,155,102,229,247,24,42,47,70,14,161,92,175,92,115,210,94,215,216,127,138,127,217,233,166,28,160,244,158,194,185,160,50,200,229],[10,125,197,37,250,39,198,53,246,85,62,49,110,167,111,146,254,122,102,90,52,143,176,198,9,1,204,202,52,96,236,200,197,3,245,24,211,205,88,134,149,124,146,160,156,187,102,193,3,75,5,239,65,39,143,123,39,169,185,162,194,73,102,136,178,10,194,105,242,42,232,157,54,221,70,237,209,116,224,198,129,224,230,159,58,195,92,145,78,43,182,216,3,15,196,114],[9,110,44,9,253,167,79,128,67,168,91,73,215,133,170,224,86,200,182,8,183,13,76,108,193,231,184,245,129,172,47,2,128,76,113,148,71,223,215,43,111,209,137,206,185,28,46,64,14,80,7,240,176,206,60,43,95,194,199,187,41,253,147,14,236,99,180,10,219,201,131,138,20,184,20,158,224,143,87,245,181,234,247,202,43,77,163,198,238,49,176,60,101,238,197,19],[18,28,167,175,28,181,211,170,180,0,223,185,175,210,37,226,16,185,173,60,181,72,4,177,19,85,132,219,144,0,20,100,27,42,118,9,84,190,136,4,138,128,56,39,110,113,115,220,11,60,219,112,44,134,110,89,85,191,69,61,26,238,211,91,254,243,66,239,28,196,214,79,157,150,233,83,218,130,245,80,8,82,36,18,100,152,163,17,177,153,107,63,198,78,9,15],[12,158,158,64,66,248,183,199,15,87,115,195,70,166,233,233,28,151,50,68,130,249,254,170,24,155,191,217,17,229,79,221,125,13,84,95,50,131,68,66,213,11,133,127,204,170,48,56,19,128,171,60,6,124,248,52,139,0,167,107,170,48,97,151,134,121,242,83,179,32,79,219,173,158,129,164,30,180,62,46,136,6,225,145,77,40,74,61,205,37,135,113,162,157,47,34],[4,191,8,13,12,131,218,73,211,85,120,234,245,16,168,146,105,223,179,237,180,237,141,233,252,176,230,170,217,132,57,135,2,183,127,123,205,156,189,238,151,10,0,114,82,129,68,196,20,78,107,235,89,237,241,82,217,144,129,245,231,135,93,117,68,33,135,249,121,117,223,50,47,179,9,111,17,245,143,94,40,212,164,41,125,208,14,16,82,61,206,177,97,15,34,236],[19,143,235,77,191,201,49,46,165,102,187,206,188,228,50,42,35,97,232,27,188,178,101,73,83,67,60,122,115,28,200,128,20,183,224,42,158,17,100,158,250,137,7,30,75,11,239,45,13,216,110,206,203,81,189,233,178,191,198,216,181,224,207,44,22,137,191,179,245,69,78,187,84,188,152,70,140,182,1,150,153,100,53,8,136,234,160,156,83,160,32,45,129,235,141,139],[12,152,74,109,45,171,54,157,133,26,84,202,120,5,253,168,66,83,34,150,12,253,146,13,151,236,227,124,131,94,208,101,25,142,227,145,238,113,236,78,58,218,67,11,61,58,29,186,24,38,60,239,63,40,214,154,5,135,234,240,169,91,116,25,52,55,150,72,165,29,23,198,65,196,202,74,208,21,75,154,125,123,239,98,4,89,180,120,50,233,89,27,235,37,133,180],[4,114,20,114,170,147,190,69,31,223,141,40,186,209,94,55,163,174,229,203,213,150,240,148,239,10,134,51,78,151,191,184,42,115,168,115,158,225,19,28,199,106,70,76,0,73,111,48,1,177,193,87,149,88,244,204,63,60,247,108,171,124,59,230,85,134,109,21,132,122,196,211,111,97,152,159,201,248,143,140,14,177,88,149,79,203,123,190,108,77,98,219,26,130,39,211],[25,121,195,181,201,192,13,75,189,102,84,120,42,82,150,51,227,191,84,238,9,105,8,12,226,225,153,31,152,204,208,136,3,135,171,91,27,202,37,40,197,116,138,191,95,246,130,176,19,105,37,3,136,157,198,117,105,201,222,234,158,182,242,222,106,104,80,141,73,254,120,252,28,150,133,198,112,119,216,218,49,118,219,42,127,220,15,49,174,48,130,207,143,160,73,46],[13,250,150,249,151,48,181,201,88,230,115,112,63,162,187,28,110,203,42,126,240,165,92,34,141,62,231,68,68,35,79,74,3,62,163,122,158,20,230,106,228,173,72,35,71,46,186,212,17,138,212,242,84,157,15,112,82,10,83,76,38,80,34,245,166,112,66,35,227,202,248,218,47,159,35,59,219,155,50,33,8,180,126,119,54,114,168,243,240,72,200,33,19,119,238,94],[13,211,206,45,126,230,34,109,40,172,108,95,5,198,23,67,53,161,213,46,203,141,91,148,36,218,132,71,170,115,24,174,55,211,173,173,4,147,202,179,178,5,14,144,15,105,200,159,13,2,143,164,132,56,58,89,15,236,114,246,216,144,52,26,222,87,121,197,181,231,166,101,246,81,100,74,8,156,10,235,175,72,91,132,18,35,168,125,102,205,48,42,68,220,115,173],[15,75,69,23,87,111,3,236,170,249,204,161,129,190,158,192,232,179,91,44,203,122,85,220,113,49,115,226,91,108,128,205,79,4,234,5,229,209,193,219,68,154,52,173,86,213,141,103,19,113,29,64,13,135,9,131,186,209,7,138,14,141,116,62,239,81,228,9,62,47,37,85,0,148,140,239,167,223,249,198,221,120,133,157,147,117,45,118,45,44,42,139,251,3,148,241],[15,5,71,218,28,68,210,7,140,103,4,169,211,70,236,103,251,124,221,63,1,169,144,170,93,59,79,183,169,39,76,65,230,63,62,114,185,163,107,216,48,11,51,90,172,60,192,243,7,25,192,43,58,53,7,199,91,71,234,113,139,21,146,130,33,57,176,130,45,236,139,212,49,251,226,117,197,33,221,71,12,30,78,199,79,231,143,135,161,94,107,2,217,120,21,172],[19,11,16,244,86,126,36,192,126,139,173,38,50,162,58,13,115,120,19,5,100,158,101,160,123,219,39,38,102,164,78,16,76,202,95,26,236,141,28,62,163,82,124,81,239,87,72,108,14,211,220,191,197,77,136,20,14,229,63,61,132,72,68,79,19,182,184,219,63,202,44,52,178,50,220,20,220,81,141,210,43,216,31,88,88,30,10,110,229,85,241,240,115,228,235,167],[7,160,162,142,3,109,224,116,99,48,81,41,202,202,82,33,31,160,127,81,136,18,55,149,134,204,6,107,168,56,190,212,123,231,195,122,225,234,118,169,180,1,234,251,93,172,189,170,18,181,150,255,14,47,73,222,47,17,107,9,121,185,2,73,246,211,140,145,155,63,157,255,19,104,118,227,158,42,79,209,192,23,149,51,247,60,16,87,249,206,62,66,248,196,229,183],[23,80,48,145,177,197,116,114,14,201,51,43,171,33,38,99,177,248,52,100,250,200,3,177,127,46,79,165,61,239,20,250,90,166,196,177,25,238,86,90,86,71,215,164,238,74,43,189,1,139,239,203,239,185,198,134,62,64,35,241,187,191,59,195,35,199,98,25,192,19,118,114,255,251,93,109,168,89,80,229,17,210,247,116,114,51,72,50,214,106,53,155,3,239,144,59],[21,255,214,114,219,171,130,78,177,82,242,26,246,206,88,223,63,226,70,64,129,127,181,3,27,25,210,3,143,250,166,137,249,132,203,74,64,19,60,217,182,24,21,186,242,181,19,6,10,94,194,174,180,183,127,124,59,56,118,23,12,52,59,157,52,119,65,77,125,143,184,123,26,250,60,102,26,249,16,75,227,55,241,125,114,238,138,227,57,114,117,127,143,138,120,106],[11,47,170,93,254,88,133,100,239,226,81,216,92,71,164,51,243,54,236,211,182,240,31,62,91,23,78,255,185,57,27,63,4,110,155,187,61,227,143,208,199,69,9,198,249,225,121,227,4,71,9,130,224,137,30,116,26,120,247,189,137,50,108,47,27,138,155,49,26,44,145,65,128,97,247,48,189,157,152,91,30,90,86,32,117,9,213,195,103,56,214,141,228,1,55,163],[0,203,217,181,195,247,215,220,224,77,71,35,144,113,120,18,37,176,32,218,31,251,20,160,229,14,147,151,148,184,153,232,96,173,197,217,153,124,233,245,146,57,157,135,248,12,129,250,19,79,45,89,18,112,147,89,146,38,200,154,56,190,163,39,213,231,149,212,24,46,54,199,204,205,137,119,69,112,137,37,165,43,108,204,15,199,111,73,82,195,224,184,248,58,252,146],[9,74,236,179,158,140,160,200,75,243,215,214,134,26,12,190,44,226,164,120,84,138,193,218,11,70,146,201,130,149,24,86,102,151,9,112,76,104,126,109,178,31,52,125,241,108,100,239,6,251,9,2,104,175,145,93,231,147,43,38,124,45,14,156,78,133,41,72,108,146,185,231,91,78,88,61,38,131,196,67,212,183,100,54,195,189,23,107,233,68,241,138,254,230,20,205],[8,16,6,114,197,190,161,93,103,88,231,112,38,168,158,220,254,1,90,84,66,88,140,182,34,149,205,164,15,116,223,159,140,186,12,161,209,235,178,178,12,154,85,159,182,38,211,253,9,197,142,243,62,182,253,29,164,0,133,190,248,196,162,83,16,237,3,196,186,52,0,121,33,86,105,255,147,113,63,224,109,206,228,13,221,241,242,249,181,60,69,195,200,109,112,105],[16,187,126,16,2,90,237,243,102,243,221,232,106,63,88,136,142,71,129,95,87,211,132,80,124,25,3,159,5,109,102,33,87,108,233,223,165,184,194,119,255,51,126,244,65,5,241,206,19,242,239,161,129,56,206,72,153,28,176,115,97,127,179,159,246,135,213,112,169,236,249,75,33,215,129,126,171,162,207,66,68,72,207,131,189,251,109,166,253,7,191,119,198,123,136,234],[9,85,150,175,206,92,182,132,162,109,56,151,143,20,248,224,42,242,89,251,253,60,167,110,118,135,97,215,74,137,134,132,135,157,172,209,137,20,223,179,13,178,183,139,105,166,246,170,3,205,212,190,246,33,71,79,50,255,87,46,127,122,158,36,163,255,64,128,130,173,85,82,117,43,217,86,121,127,95,46,54,103,206,248,6,80,107,123,106,221,150,152,89,254,240,199],[12,63,235,136,60,118,243,82,155,35,19,8,107,17,84,58,66,11,166,246,190,52,94,180,141,101,122,229,104,198,5,0,72,163,158,50,161,164,53,13,32,72,91,194,163,6,44,250,8,248,212,196,235,9,111,67,237,169,171,213,0,193,64,165,54,26,234,163,117,252,15,42,28,186,120,98,144,182,12,8,9,143,60,56,31,75,17,247,214,164,204,113,127,130,58,117],[6,240,214,37,33,182,146,16,4,221,153,56,202,248,9,144,63,97,91,53,17,63,188,29,67,239,247,62,67,128,128,221,106,97,39,110,44,177,103,109,105,65,19,126,107,62,66,83,17,156,224,35,242,17,204,234,188,39,222,211,122,116,160,174,105,158,193,128,125,24,63,6,238,38,253,10,104,247,215,129,201,78,222,175,86,18,151,246,112,12,84,216,0,13,153,52],[11,141,99,127,27,112,228,135,159,34,77,53,119,148,211,84,207,21,29,58,0,20,215,138,118,101,35,109,144,167,154,34,243,22,37,132,112,204,33,140,104,86,157,108,216,52,21,127,5,193,95,225,118,82,163,138,18,221,92,129,67,81,140,135,150,92,42,248,119,3,133,17,95,44,136,137,203,133,20,82,230,76,168,219,90,91,247,170,45,6,93,139,77,190,87,178],[5,8,214,14,29,55,57,243,232,119,93,145,109,0,213,71,181,108,131,178,128,237,115,199,50,198,173,48,245,104,226,96,77,187,11,19,46,144,247,211,105,141,50,216,222,209,0,61,25,206,14,253,233,236,33,201,240,174,244,77,106,29,51,196,234,249,45,238,48,195,228,195,207,173,40,71,89,223,244,169,18,27,240,214,120,78,255,28,116,184,180,207,49,220,107,130],[1,164,154,158,200,246,52,183,184,2,67,81,240,239,128,105,183,177,235,198,184,53,76,168,166,136,210,15,253,27,210,124,1,8,237,156,150,76,200,98,67,108,232,237,152,206,56,39,16,90,21,197,245,217,78,212,250,101,66,124,222,106,220,176,29,32,231,196,54,158,10,158,203,8,223,172,18,164,228,213,17,98,250,42,135,149,221,141,179,205,115,31,93,120,61,92],[9,118,220,195,153,188,153,197,255,11,67,171,76,106,53,105,104,74,96,141,120,123,202,92,169,3,130,173,21,130,251,113,245,69,140,174,155,250,10,218,211,86,102,216,41,189,214,213,18,46,22,178,85,81,150,81,187,235,77,192,136,135,235,45,47,166,135,57,161,95,142,179,237,37,162,211,156,149,57,121,179,53,193,223,218,111,34,11,234,25,107,252,127,152,90,95],[2,12,202,225,251,23,41,58,139,191,64,222,72,80,5,216,49,112,235,245,132,74,70,14,68,96,158,123,185,235,243,208,17,93,165,187,117,88,11,118,221,63,149,29,86,140,0,64,17,58,191,139,220,211,59,32,169,63,85,223,9,153,71,218,243,220,73,116,247,144,170,222,136,136,43,52,137,47,96,241,66,47,220,90,149,158,163,165,128,11,169,117,231,201,242,77],[11,141,74,245,158,150,229,124,140,248,60,224,47,193,104,185,185,99,203,24,124,189,115,201,172,26,99,110,132,151,147,227,226,248,86,253,92,26,84,202,167,113,116,6,25,165,167,221,22,242,252,29,31,84,250,95,152,62,244,91,154,158,136,223,232,131,4,172,8,185,65,182,15,179,78,137,90,254,133,119,131,89,180,119,134,165,65,91,184,208,123,109,201,141,61,53],[0,241,168,195,184,118,127,150,140,230,130,13,159,221,130,74,196,214,157,125,181,86,76,46,76,22,22,138,174,206,105,129,55,253,221,117,250,254,195,94,28,143,224,107,180,36,17,116,20,207,186,10,24,71,249,151,217,243,77,104,85,179,80,59,61,63,28,39,182,175,21,246,95,177,116,208,102,185,152,207,108,94,122,26,252,113,84,251,159,92,1,22,10,43,193,214],[0,20,190,46,98,112,98,246,77,178,88,149,45,65,50,216,127,228,226,201,151,62,133,187,168,28,179,201,57,3,208,225,161,221,208,215,29,59,25,95,122,90,119,122,230,151,85,9,21,188,186,226,129,70,170,228,208,46,68,118,198,49,20,166,177,188,139,94,49,193,127,180,154,121,153,225,17,109,138,50,15,43,5,212,210,34,111,147,129,112,197,135,112,246,130,234],[2,246,65,174,95,26,116,179,177,193,38,207,38,18,109,218,36,1,89,46,207,71,83,195,195,108,188,246,77,211,158,218,186,93,123,195,130,62,173,217,234,160,86,170,41,115,91,45,13,237,125,192,132,107,57,85,120,178,237,97,24,171,182,86,247,127,3,22,44,216,222,200,28,151,82,165,249,171,242,89,86,171,45,191,226,19,176,230,53,213,13,94,50,151,176,172],[8,166,3,240,191,123,233,225,178,205,210,237,187,221,164,248,152,218,137,153,169,8,117,76,190,94,18,224,250,145,177,29,61,133,241,168,119,253,36,97,160,247,219,69,253,233,18,44,15,66,250,161,0,96,141,163,136,27,40,53,2,196,17,55,16,120,147,0,11,136,238,32,234,236,159,107,97,43,29,250,81,98,225,19,248,88,182,206,173,230,89,184,166,189,242,196],[21,11,175,28,84,226,160,240,113,145,218,66,23,4,209,12,68,233,250,222,42,152,141,108,188,121,221,200,134,141,127,122,93,209,118,133,184,56,32,68,45,153,79,3,188,156,88,242,16,57,153,204,120,196,159,38,84,71,38,9,45,103,195,157,72,22,191,65,78,148,88,178,70,153,74,81,36,160,36,148,136,42,245,14,103,210,199,195,1,61,255,12,37,51,26,125],[16,101,132,101,95,26,18,214,42,102,241,36,9,55,237,0,80,168,254,108,121,240,137,224,125,244,140,108,157,242,191,130,57,225,70,21,157,237,83,170,155,61,173,122,183,198,232,21,20,6,5,236,14,240,7,15,24,154,125,41,179,176,212,65,128,65,170,87,214,117,155,212,241,203,207,216,224,123,231,238,9,96,53,249,246,33,209,244,151,91,31,66,118,115,59,81],[13,109,13,137,22,126,14,34,211,127,240,223,155,17,6,28,26,141,90,120,195,182,64,222,113,146,119,144,51,89,60,210,196,39,226,149,42,96,140,161,35,212,10,126,16,227,7,111,22,230,164,216,168,228,204,151,229,216,195,207,255,70,142,86,143,62,87,193,83,67,183,19,220,169,133,239,80,66,61,172,10,73,103,221,147,40,245,248,54,162,160,39,245,146,58,154],[15,214,110,235,82,49,14,39,132,113,29,153,129,170,49,228,222,147,83,197,209,122,192,180,135,139,203,246,166,108,26,92,20,23,249,75,119,67,14,84,34,16,56,81,209,240,166,146,21,103,26,219,230,178,11,247,168,132,110,119,109,56,246,133,215,229,212,249,34,53,29,193,155,66,229,167,87,250,135,52,136,147,78,48,57,74,194,107,137,163,226,236,9,109,161,134],[18,85,214,179,151,125,237,207,16,110,2,242,71,133,48,132,156,185,87,17,233,92,168,123,213,245,225,46,52,45,158,194,132,118,102,121,72,139,124,42,243,143,76,161,61,214,193,4,5,84,137,47,69,55,108,28,147,123,106,112,119,206,62,81,153,118,251,138,47,80,98,3,196,46,122,218,173,56,226,121,75,227,3,218,36,67,47,174,70,212,71,124,245,99,89,190],[20,22,225,160,130,186,145,88,97,84,120,59,7,182,115,185,66,111,189,140,70,119,173,21,249,225,97,163,136,174,156,227,172,18,253,63,105,37,12,77,79,26,179,75,203,168,17,72,11,96,131,207,162,47,109,117,141,218,170,5,88,205,139,221,130,31,67,2,20,131,119,6,255,62,152,79,84,109,198,122,253,33,159,220,78,146,246,86,101,127,118,111,90,232,254,224],[22,246,227,118,253,210,20,52,130,7,150,57,78,51,0,189,139,75,130,155,72,230,139,180,220,207,249,18,74,208,251,56,126,141,45,182,237,35,22,143,8,101,212,90,225,178,128,152,8,20,221,51,252,98,190,135,197,248,108,37,221,40,2,184,208,7,175,35,179,190,56,127,201,34,68,162,241,236,230,249,145,185,239,146,206,223,56,195,69,67,91,53,128,126,145,85],[3,215,71,17,231,224,5,129,188,150,200,252,234,161,229,183,79,42,223,189,4,124,0,199,215,51,50,152,113,75,173,161,177,191,236,181,209,209,184,184,53,168,128,209,110,122,125,118,0,83,120,137,142,204,255,219,172,148,132,204,237,25,114,103,14,100,192,34,84,96,97,31,58,0,183,124,213,74,220,103,50,241,47,19,58,204,40,186,251,10,242,14,110,55,11,126],[22,86,81,4,110,214,123,121,177,117,218,244,219,0,174,79,74,148,39,107,197,38,212,32,136,50,41,67,82,98,100,135,7,198,109,233,50,186,141,127,62,43,68,153,174,58,248,72,1,187,88,7,165,18,132,100,208,22,230,2,207,119,55,124,138,177,197,156,147,73,48,248,224,160,233,248,30,218,103,221,239,176,193,255,28,59,89,26,13,79,237,146,152,241,89,85],[8,125,75,124,138,110,219,228,134,43,237,235,46,185,209,114,192,186,159,203,164,212,230,122,150,19,100,83,169,174,31,175,113,223,208,245,11,23,162,109,212,232,161,194,216,163,5,102,20,72,180,103,126,115,174,125,10,60,55,145,108,205,91,97,129,3,176,93,10,24,21,108,69,43,179,100,19,61,232,60,252,19,240,223,254,44,184,178,152,133,51,56,166,208,53,30],[1,223,69,184,170,172,131,234,92,39,4,94,211,47,61,248,219,95,37,15,137,100,16,65,199,28,156,245,214,17,156,182,77,166,206,15,161,221,19,58,125,97,47,184,196,112,193,169,3,152,13,236,222,17,64,35,159,89,90,65,203,234,98,11,244,174,68,238,104,236,123,235,194,252,26,228,98,167,86,24,62,118,61,137,188,132,65,247,160,130,38,238,97,126,188,97],[20,14,71,116,69,77,142,252,141,5,20,135,223,8,183,181,98,175,159,143,238,190,210,85,124,207,35,7,10,45,212,226,205,254,107,167,107,239,156,112,65,67,73,182,245,155,208,184,7,137,127,210,26,43,133,75,234,36,188,223,2,143,179,49,4,236,191,47,182,150,101,114,131,236,182,37,38,91,255,62,195,170,182,236,44,41,194,92,36,6,46,210,197,19,31,214],[24,191,145,211,244,152,74,55,173,208,65,86,43,28,192,219,213,212,152,140,33,158,122,129,93,232,73,67,1,233,187,151,74,207,190,86,219,38,114,35,81,177,213,251,64,121,126,203,2,137,234,206,163,130,70,117,170,29,89,97,197,108,201,12,40,202,7,153,209,5,186,179,90,211,120,158,91,244,120,64,238,76,148,189,218,133,43,156,57,148,137,151,177,87,47,78],[11,47,43,205,9,161,202,78,45,74,233,163,88,169,43,195,117,139,46,159,70,124,229,84,71,141,31,141,71,148,139,111,161,170,233,234,205,96,219,243,186,88,45,29,202,72,82,172,11,230,169,177,250,85,59,19,140,232,76,255,126,11,8,129,74,105,179,140,154,76,187,11,60,133,149,86,242,207,68,206,97,188,32,151,78,250,234,56,156,69,110,122,74,221,1,169],[14,177,74,42,60,57,243,161,58,96,78,83,255,232,67,40,156,189,137,122,84,169,36,190,185,99,216,77,112,253,115,76,234,48,2,103,170,92,250,117,7,241,34,1,205,94,163,156,4,21,217,69,1,167,169,81,84,135,165,123,24,19,20,180,108,201,234,80,181,209,2,205,23,83,174,14,181,51,174,48,32,126,84,59,186,139,22,177,55,17,110,240,197,31,221,77],[21,200,37,213,105,217,155,144,61,170,244,82,193,231,148,125,125,223,126,2,226,37,81,168,139,13,35,233,23,115,53,24,176,247,87,220,85,57,79,70,246,97,213,112,241,203,231,250,7,17,117,4,253,46,94,186,4,41,186,33,176,36,107,20,146,48,27,188,177,71,216,39,121,121,158,172,18,66,80,125,53,156,199,14,7,158,115,36,219,244,226,183,19,5,130,220],[12,175,209,206,242,90,116,162,212,241,230,140,64,205,160,74,97,55,44,168,217,40,148,163,111,211,68,168,75,151,108,36,72,32,53,229,157,102,173,121,212,248,170,29,207,66,86,249,12,8,113,50,250,109,47,201,128,21,184,15,52,88,93,186,141,54,34,248,243,197,201,90,71,49,68,29,45,128,182,100,19,79,150,94,123,194,186,64,191,102,218,169,250,250,57,168],[0,63,87,123,179,109,128,22,51,135,18,14,22,194,173,173,56,121,27,247,143,86,187,178,216,156,49,39,17,117,191,196,140,243,249,197,61,173,68,181,120,194,190,101,161,44,182,226,23,240,153,199,67,192,116,18,247,53,16,164,242,148,25,172,136,103,198,137,100,92,127,108,190,191,182,201,207,80,155,99,41,215,156,142,31,92,94,195,55,7,114,141,93,43,32,182],[5,133,113,169,23,117,114,216,67,1,61,166,120,175,157,74,69,215,178,154,254,168,89,232,239,36,134,120,73,15,172,35,228,206,179,126,255,169,113,91,118,115,64,35,112,201,243,198,14,29,71,174,217,111,117,66,101,142,27,123,97,50,166,214,250,179,127,141,199,152,60,117,68,214,241,188,34,66,57,70,33,79,13,65,141,54,39,143,127,167,169,152,10,232,199,158],[16,212,218,249,123,218,208,43,146,7,252,216,187,249,77,223,0,168,104,60,176,58,149,75,246,148,116,135,222,191,189,188,247,86,155,1,54,117,46,149,17,229,17,224,107,83,10,30,13,166,23,101,109,208,148,100,111,143,106,45,99,209,75,221,70,117,33,191,30,49,41,179,121,77,26,122,180,182,233,96,220,141,59,226,185,157,7,69,12,129,17,113,136,241,122,173],[2,22,187,211,255,191,65,255,51,132,117,181,168,106,65,15,228,224,84,253,240,45,214,51,13,16,239,54,146,240,144,85,40,78,135,21,38,38,10,111,179,125,234,224,87,218,135,129,11,138,176,90,175,85,155,105,171,51,236,171,140,187,225,116,126,181,26,126,175,110,184,142,253,12,37,46,48,9,44,252,157,22,255,30,49,95,240,66,243,51,12,41,46,242,138,90],[16,9,170,162,164,243,218,124,20,174,222,198,121,241,76,96,209,184,180,157,81,96,170,62,81,222,1,159,10,16,18,109,30,138,244,126,71,172,123,176,95,61,139,193,212,18,11,54,21,57,52,119,91,249,223,46,35,57,127,204,20,222,18,8,6,223,222,245,113,130,8,58,104,200,155,3,15,100,255,140,58,251,124,3,168,153,147,162,160,209,135,15,180,226,153,126],[24,178,33,221,3,34,107,165,183,57,11,149,10,233,138,42,76,191,201,170,170,19,45,221,145,24,70,35,98,222,32,24,224,49,206,240,190,197,247,245,105,36,111,116,218,93,100,65,25,156,182,234,85,174,145,125,250,225,51,18,243,164,207,61,222,148,86,119,108,198,249,187,6,16,47,189,56,245,236,92,37,242,42,253,177,140,47,8,29,63,11,100,241,83,60,72],[19,33,173,81,163,229,89,94,45,180,28,102,0,145,67,239,7,144,122,172,218,143,31,254,36,114,81,33,46,128,70,226,47,62,27,54,88,94,51,92,162,36,20,135,201,97,15,181,6,132,101,169,74,74,196,67,191,179,34,218,247,238,225,117,207,115,184,143,117,248,130,203,66,90,21,145,208,246,112,137,203,102,35,230,43,164,229,47,172,190,223,214,195,216,89,35],[5,155,55,160,73,56,227,39,9,56,241,116,222,96,74,68,177,136,46,237,44,171,59,149,92,170,220,94,252,42,138,46,24,84,137,66,203,123,232,232,135,0,122,70,138,196,153,252,9,187,151,119,138,43,133,190,252,102,133,118,210,251,118,6,163,144,200,99,137,55,181,87,40,200,14,251,212,48,142,44,27,145,72,160,109,149,235,105,232,108,226,53,65,101,221,113],[22,33,158,205,242,159,167,68,154,254,68,213,139,239,230,62,97,13,24,27,198,187,62,85,6,110,27,50,93,21,229,228,108,195,115,144,172,26,86,125,62,183,48,39,94,31,108,15,16,157,246,0,198,48,130,157,229,19,36,211,64,127,242,204,98,94,235,71,80,230,101,202,28,58,140,177,122,230,90,197,144,152,241,73,179,174,245,202,145,161,104,81,252,244,133,69],[9,68,218,34,168,45,255,247,222,173,61,236,52,19,83,214,20,111,156,109,3,150,44,146,210,174,221,111,168,98,29,134,83,48,140,99,170,20,88,73,99,209,147,130,172,160,69,160,20,53,117,253,24,88,186,186,106,166,160,33,186,178,187,2,103,243,153,209,202,207,125,222,72,40,47,230,126,197,194,154,240,130,109,104,62,161,190,121,205,230,60,16,53,164,221,146],[0,139,79,204,38,12,143,189,101,202,98,87,134,125,145,228,91,12,98,9,73,30,141,54,159,123,254,54,18,108,87,36,7,200,122,105,198,90,157,134,189,249,35,246,132,41,171,202,20,64,255,184,35,210,62,71,211,23,88,51,137,110,108,103,100,87,178,51,250,180,244,236,167,37,190,64,195,97,207,246,131,37,223,97,143,116,62,29,156,43,121,46,83,110,242,147],[18,123,3,228,244,164,65,53,216,231,26,250,59,159,34,67,174,158,187,201,175,165,1,70,14,197,191,110,162,64,146,118,221,214,122,245,133,247,106,172,243,232,190,75,227,181,178,240,23,202,192,144,180,80,6,22,228,232,152,93,225,235,179,43,1,30,68,204,143,132,167,49,169,151,108,146,85,97,22,233,199,19,87,33,49,146,233,73,210,208,238,56,97,88,79,191],[15,234,135,91,140,191,107,161,149,69,75,138,10,33,26,172,129,47,27,60,203,15,192,1,87,27,127,65,38,14,43,117,66,109,214,87,116,130,190,161,206,57,91,103,107,247,165,227,7,35,163,148,196,242,232,39,142,221,248,182,41,109,85,92,4,20,92,16,0,132,166,1,20,138,85,253,68,169,171,167,27,138,124,150,94,55,41,246,165,100,101,166,158,59,12,115],[23,220,244,70,41,117,68,35,108,96,7,15,63,134,22,29,48,133,194,125,23,178,34,78,184,139,115,242,67,61,185,64,145,149,2,247,173,97,222,53,44,85,180,166,71,135,229,53,21,91,63,197,238,126,245,139,107,183,73,62,235,180,46,35,3,184,118,239,187,245,34,29,125,238,137,188,194,6,175,212,43,154,153,254,61,121,218,72,14,109,234,10,86,207,192,255],[1,130,27,192,229,61,48,159,123,128,36,93,254,32,60,173,228,49,152,70,2,8,116,92,118,223,166,228,176,94,177,159,4,20,96,190,115,126,4,72,39,186,87,63,119,210,238,24,25,56,249,122,118,150,155,216,116,212,157,30,69,203,235,98,113,50,29,196,140,74,248,209,0,145,105,47,235,83,96,215,67,132,71,138,11,112,253,115,151,210,208,4,195,28,193,147],[10,149,50,228,239,186,51,190,207,122,152,171,196,234,80,190,63,179,47,34,185,123,83,217,208,77,32,143,159,245,28,106,216,41,54,163,203,146,24,57,192,80,225,37,52,171,103,143,12,109,127,87,202,51,166,220,220,233,79,205,8,131,236,189,255,164,120,16,195,198,215,21,154,226,124,221,112,191,193,116,47,133,12,138,120,75,40,116,113,186,15,32,126,218,123,5],[10,135,221,185,200,87,246,151,183,121,13,173,50,20,246,56,227,75,85,145,49,167,89,177,207,215,21,1,143,160,99,192,71,144,1,126,5,42,20,7,241,210,123,238,164,142,238,12,25,29,95,1,94,95,159,172,111,72,24,33,69,191,198,115,87,93,13,32,239,115,199,133,236,163,189,190,46,137,212,214,216,66,189,200,57,176,173,213,146,190,88,181,160,170,34,191],[8,68,91,212,249,64,100,43,159,158,235,247,217,210,69,140,179,202,164,22,13,78,142,34,159,221,218,152,202,132,203,19,43,125,149,248,238,206,249,234,232,204,194,140,43,138,86,133,6,76,5,149,29,34,132,201,46,95,216,117,28,84,45,206,42,99,32,224,41,144,129,42,105,188,250,125,75,149,151,119,93,205,49,122,183,92,35,211,53,129,51,187,103,18,128,193],[16,177,157,46,155,160,151,0,221,134,150,250,129,182,27,215,64,25,117,250,213,97,206,35,95,153,84,16,144,121,34,2,93,235,22,206,26,109,172,232,106,61,55,158,229,78,83,124,9,137,112,69,72,161,47,5,118,41,38,82,25,211,126,137,140,187,152,48,207,3,147,209,235,192,90,32,138,77,238,107,245,147,37,88,206,247,154,217,82,165,106,22,248,26,230,168],[1,174,143,200,14,120,192,72,84,98,187,149,36,1,4,105,158,149,188,71,69,24,92,149,62,103,143,253,208,156,1,32,201,139,209,234,86,176,164,184,206,176,62,35,232,207,157,52,22,192,218,105,175,36,18,58,102,206,141,154,20,96,38,139,85,243,241,125,91,135,142,5,151,148,39,3,86,246,81,79,101,87,182,173,51,2,100,195,112,95,198,6,163,192,201,80],[11,166,181,101,198,39,250,10,210,73,137,9,222,13,219,234,88,216,25,37,5,82,72,6,236,114,185,11,112,67,21,16,24,143,198,254,140,10,216,19,168,140,68,51,93,217,66,150,8,242,163,168,108,35,214,240,180,139,101,128,15,212,41,189,187,27,204,242,48,115,55,28,170,73,230,4,2,214,63,118,194,180,152,204,89,148,195,179,70,117,87,142,23,21,10,98],[9,97,80,164,145,152,8,97,80,107,58,186,93,36,56,113,108,239,33,243,190,44,90,71,112,110,52,120,189,79,77,118,161,85,199,94,18,221,36,20,86,151,2,162,186,3,0,78,21,108,157,31,167,105,246,12,54,108,55,246,120,19,254,205,103,164,120,150,148,229,135,158,63,90,6,93,65,99,121,91,35,85,222,37,39,233,96,158,42,12,115,22,218,122,249,233],[25,70,152,66,176,54,2,186,54,8,49,0,186,3,62,46,34,176,179,52,194,152,101,150,253,151,102,108,83,56,145,59,87,11,36,195,144,152,243,127,200,14,150,130,243,227,211,120,13,84,40,252,98,201,84,120,210,203,240,209,90,12,203,111,99,85,187,235,209,31,145,104,221,228,182,23,142,186,212,156,133,121,146,239,35,213,22,159,159,228,172,87,44,233,55,65],[5,101,233,155,181,156,242,230,26,132,242,13,83,219,209,179,88,210,25,63,155,100,194,38,47,186,1,110,255,143,109,130,218,20,84,42,139,14,63,129,194,90,82,8,85,230,136,153,8,108,169,32,191,45,240,254,130,41,11,67,157,88,12,100,10,62,154,60,216,40,189,211,95,113,132,164,133,50,98,248,255,212,179,250,255,151,64,164,150,220,205,204,155,147,73,99]],"pariticipation_bits":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],"attested_header":{"slot":"32","proposer_index":"0","parent_root":"0x0000000000000000000000000000000000000000000000000000000000000000","state_root":"0x83882e1522eed275247e81c11991048313854f04de924ec21d8523954a07d266","body_root":"0xcfc05f337393c3a62425aa3a1fb3b7113c5da404d6a7f89edd41bfb5e14a5e92"},"finalized_header":{"slot":"0","proposer_index":"0","parent_root":"0x0000000000000000000000000000000000000000000000000000000000000000","state_root":"0x0000000000000000000000000000000000000000000000000000000000000000","body_root":"0x1e10d615015401a475217be60cd4f0f53e510b12173f48039d852e5022981639"},"finality_branch":[[235,99,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[61,75,229,208,25,186,21,234,62,243,4,168,59,138,6,127,46,121,244,106,63,172,128,105,48,106,108,129,74,10,53,235],[132,125,93,24,223,75,246,58,97,156,174,15,187,209,43,213,214,3,210,195,52,32,97,31,221,245,74,217,78,45,148,83],[110,211,142,94,6,128,7,99,93,122,179,185,34,100,118,177,122,81,82,200,22,17,180,0,237,192,18,14,240,147,108,131],[155,36,233,182,3,218,183,52,31,229,11,170,186,135,40,250,236,16,108,30,173,17,32,146,190,16,108,215,239,76,73,95],[68,177,30,58,180,74,214,199,111,188,103,22,162,155,83,145,41,251,226,97,205,72,114,173,12,185,219,75,73,41,191,198]],"execution_payload_branch":[[66,176,82,84,29,206,69,85,125,131,211,70,52,164,90,86,210,22,212,55,94,90,149,132,246,68,92,228,230,51,36,175],[51,100,136,3,63,229,243,239,76,204,18,175,7,185,55,11,146,229,83,227,94,203,74,51,122,27,28,14,74,254,30,14],[219,86,17,78,0,253,212,193,248,92,137,43,243,90,201,168,146,137,170,236,177,235,208,169,108,222,96,106,116,139,93,113],[156,200,108,117,214,234,134,249,66,137,170,240,18,207,96,236,49,180,252,246,212,177,241,162,156,106,55,243,83,138,77,132]],"execution_payload_root":[248,214,204,83,123,89,238,36,211,105,76,76,135,239,192,98,48,143,66,207,58,182,74,167,199,24,117,135,7,66,1,254],"domain":[7,0,0,0,48,83,175,74,95,250,246,166,104,40,151,228,42,212,194,8,48,56,232,147,61,9,41,204,88,234,56,134]} \ No newline at end of file From 2e0480499f80cd3e1d5c8b342aca35961eb14900 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Tue, 31 Oct 2023 16:42:48 +0100 Subject: [PATCH 04/23] fix sha wide chip gate --- .../src/committee_update_circuit.rs | 688 +++++++++--------- .../src/gadget/crypto/sha256_wide.rs | 2 +- .../src/gadget/crypto/sha256_wide/config.rs | 2 +- .../src/gadget/crypto/sha256_wide/gate.rs | 2 + .../src/gadget/crypto/sha256_wide/util.rs | 2 +- lightclient-circuits/src/lib.rs | 4 + lightclient-circuits/src/sync_step_circuit.rs | 4 +- 7 files changed, 353 insertions(+), 351 deletions(-) diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index c63ed716..4495b1cf 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -9,11 +9,14 @@ use crate::{ ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, sync_step_circuit::{clear_3_bits, to_bytes_le, truncate_sha256_into_single_elem}, util::{gen_pkey, AppCircuit, Challenges, CommonGateManager, Eth2ConfigPinning, IntoWitness}, - witness::{self, HashInput, HashInputChunk}, + witness::{self, HashInput, HashInputChunk}, Eth2CircuitBuilder, }; use eth_types::{Field, Spec}; use halo2_base::{ - gates::{circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, RangeChip, RangeInstructions}, + gates::{ + circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, RangeChip, + RangeInstructions, + }, halo2_proofs::{ circuit::{Layouter, Region, SimpleFloorPlanner, Value}, dev::MockProver, @@ -215,7 +218,7 @@ impl AppCircuit for CommitteeUpdateCircuit { k: u32, ) -> Result, Error> { let mut builder = - ShaCircuitBuilder::>::from_stage(stage) + Eth2CircuitBuilder::>::from_stage(stage) .use_k(k as usize) .use_instance_columns(1); let range = builder.range_chip(8); @@ -241,346 +244,339 @@ impl AppCircuit for CommitteeUpdateCircuit { } } -// #[cfg(test)] -// mod tests { -// use std::{ -// env::{set_var, var}, -// fs, -// path::PathBuf, -// }; - -// use crate::{ -// aggregation::AggregationConfigPinning, -// gadget::crypto::constant_randomness, -// util::{full_prover, full_verifier, gen_pkey, Halo2ConfigPinning, PinnableCircuit}, -// witness::{CommitteeRotationArgs, SyncStepArgs}, -// }; - -// use super::*; -// use ark_std::{end_timer, start_timer}; -// use eth_types::Testnet; -// use halo2_base::{ -// gates::{ -// builder::{CircuitBuilderStage, FlexGateConfigParams}, -// flex_gate::GateStrategy, -// range::RangeStrategy, -// }, -// utils::fs::gen_srs, -// }; -// use halo2_proofs::{ -// circuit::SimpleFloorPlanner, -// dev::MockProver, -// halo2curves::bn256::Fr, -// plonk::{keygen_pk, keygen_vk, Circuit, FloorPlanner}, -// poly::{commitment::Params, kzg::commitment::ParamsKZG}, -// }; -// use halo2curves::{bls12_381::G1Affine, bn256::Bn256}; -// use pasta_curves::group::UncompressedEncoding; -// use rand::rngs::OsRng; -// use rayon::iter::ParallelIterator; -// use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; -// use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; -// use snark_verifier_sdk::{ -// gen_pk, -// halo2::{ -// aggregation::{AggregationCircuit, AggregationConfigParams}, -// gen_proof_shplonk, gen_snark_shplonk, -// }, -// CircuitExt, Snark, SHPLONK, -// }; - -// fn load_circuit_args() -> CommitteeRotationArgs { -// #[derive(serde::Deserialize)] -// struct ArgsJson { -// finalized_header: BeaconBlockHeader, -// committee_root_branch: Vec>, -// pubkeys_compressed: Vec>, -// } - -// let ArgsJson { -// pubkeys_compressed, -// committee_root_branch, -// finalized_header, -// } = serde_json::from_slice(&fs::read("../test_data/rotation_512.json").unwrap()).unwrap(); - -// CommitteeRotationArgs { -// pubkeys_compressed, -// randomness: constant_randomness(), -// _spec: PhantomData, -// finalized_header: finalized_header, -// sync_committee_branch: committee_root_branch, -// } -// } - -// fn gen_application_snark( -// params: &ParamsKZG, -// pk: &ProvingKey, -// witness: &CommitteeRotationArgs, -// ) -> Snark { -// CommitteeUpdateCircuit::::gen_snark_shplonk( -// params, -// pk, -// "./config/committee_update.json", -// None::, -// witness, -// ) -// .unwrap() -// } - -// #[test] -// fn test_committee_update_circuit() { -// const K: u32 = 18; -// let params = gen_srs(K); - -// let witness = load_circuit_args(); - -// let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); -// let circuit = CommitteeUpdateCircuit::::create_circuit( -// CircuitBuilderStage::Mock, -// Some(pinning), -// &witness, -// params.k(), -// ) -// .unwrap(); - -// let timer = start_timer!(|| "committee_update mock prover"); -// let prover = MockProver::::run(K, &circuit, circuit.instances()).unwrap(); -// prover.assert_satisfied_par(); -// end_timer!(timer); -// } - -// #[test] -// fn test_committee_update_proofgen() { -// const K: u32 = 18; -// let params = gen_srs(K); - -// let pk = CommitteeUpdateCircuit::::read_or_create_pk( -// ¶ms, -// "../build/committee_update.pkey", -// "./config/committee_update.json", -// false, -// &CommitteeRotationArgs::::default(), -// ); - -// let witness = load_circuit_args(); - -// let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); - -// let circuit = CommitteeUpdateCircuit::::create_circuit( -// CircuitBuilderStage::Prover, -// Some(pinning), -// &witness, -// K, -// ) -// .unwrap(); - -// let instances = circuit.instances(); -// let proof = full_prover(¶ms, &pk, circuit, instances.clone()); - -// assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) -// } - -// #[test] -// fn test_circuit_aggregation_proofgen() { -// const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; -// const APP_K: u32 = 20; -// let params_app = gen_srs(APP_K); - -// const AGG_K: u32 = 22; -// let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( -// ¶ms_app, -// "../build/committee_update.pkey", -// "./config/committee_update.json", -// false, -// &CommitteeRotationArgs::::default(), -// ); -// let witness = load_circuit_args(); -// let snark = gen_application_snark(¶ms_app, &pk_app, &witness); - -// let params = gen_srs(AGG_K); -// println!("agg_params k: {:?}", params.k()); -// let lookup_bits = params.k() as usize - 1; - -// let pk = AggregationCircuit::read_or_create_pk( -// ¶ms, -// "../build/aggregation.pkey", -// AGG_CONFIG_PATH, -// false, -// &vec![snark.clone()], -// ); - -// let agg_config = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); - -// let agg_circuit = AggregationCircuit::create_circuit( -// CircuitBuilderStage::Prover, -// Some(agg_config), -// &vec![snark.clone()], -// AGG_K, -// ) -// .unwrap(); - -// let instances = agg_circuit.instances(); -// let num_instances = agg_circuit.num_instance(); - -// let proof = full_prover(¶ms, &pk, agg_circuit, instances.clone()); - -// assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)); -// } - -// #[test] -// fn test_circuit_aggregation_evm() { -// const AGG_CONFIG_PATH: &str = "./config/committee_update_a.json"; -// const APP_K: u32 = 21; -// let params_app = gen_srs(APP_K); - -// const AGG_K: u32 = 23; -// let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( -// ¶ms_app, -// "../build/committee_update.pkey", -// "./config/committee_update.json", -// false, -// &CommitteeRotationArgs::::default(), -// ); - -// let witness = load_circuit_args(); -// let snark = gen_application_snark(¶ms_app, &pk_app, &witness); - -// let params = gen_srs(AGG_K); -// println!("agg_params k: {:?}", params.k()); -// let lookup_bits = params.k() as usize - 1; - -// let pk = AggregationCircuit::read_or_create_pk( -// ¶ms, -// "../build/aggregation.pkey", -// AGG_CONFIG_PATH, -// false, -// &vec![snark.clone()], -// ); - -// let agg_config = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); - -// let agg_circuit = AggregationCircuit::create_circuit( -// CircuitBuilderStage::Prover, -// Some(agg_config), -// &vec![snark.clone()], -// AGG_K, -// ) -// .unwrap(); - -// let instances = agg_circuit.instances(); -// let num_instances = agg_circuit.num_instance(); - -// println!("num_instances: {:?}", num_instances); -// println!("instances: {:?}", instances); - -// let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); -// println!("proof size: {}", proof.len()); -// let deployment_code = AggregationCircuit::gen_evm_verifier_shplonk( -// ¶ms, -// &pk, -// Some("contractyul"), -// &vec![snark], -// ) -// .unwrap(); -// println!("deployment_code size: {}", deployment_code.len()); -// evm_verify(deployment_code, instances, proof); -// } - -// #[test] -// fn test_circuit_aggregation_2_evm() { -// const K0: u32 = 20; -// const K1: u32 = 24; -// const K2: u32 = 24; - -// const APP_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; -// const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation_1.json"; -// const AGG_FINAL_CONFIG_PATH: &str = "./config/committee_update_aggregation_2.json"; - -// // Layer 0 snark gen -// let l0_snark = { -// let p0 = gen_srs(K0); -// let pk_l0 = CommitteeUpdateCircuit::::read_or_create_pk( -// &p0, -// "../build/committee_update.pkey", -// APP_CONFIG_PATH, -// false, -// &CommitteeRotationArgs::::default(), -// ); -// let witness = load_circuit_args(); -// let snark = gen_application_snark(&p0, &pk_l0, &witness); -// println!( -// "L0 num instances: {:?}", -// snark.instances.iter().map(|i| i.len()).collect_vec() -// ); -// println!("L0 snark size: {}", snark.proof.len()); -// snark -// }; - -// // Layer 1 snark gen -// let l1_snark = { -// let p1 = gen_srs(K1); -// let mut circuit = AggregationCircuit::keygen::(&p1, vec![l0_snark.clone()]); -// circuit.expose_previous_instances(false); - -// println!("L1 Keygen num_instances: {:?}", circuit.num_instance()); - -// let pk_l1 = gen_pk(&p1, &circuit, None); -// circuit.write_pinning(AGG_CONFIG_PATH); -// let pinning = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); -// let lookup_bits = K1 as usize - 1; -// let mut circuit = AggregationCircuit::new::( -// CircuitBuilderStage::Prover, -// Some(pinning.break_points), -// lookup_bits, -// &p1, -// iter::once(l0_snark.clone()), -// ); -// circuit.expose_previous_instances(false); - -// println!("L1 Prover num_instances: {:?}", circuit.num_instance()); -// let snark = gen_snark_shplonk(&p1, &pk_l1, circuit, None::); -// println!("L1 snark size: {}", snark.proof.len()); - -// snark -// }; - -// // Layer 2 snark gen -// let (proof, deployment_code, instances) = { -// let p2 = gen_srs(K2); -// let mut circuit = -// AggregationCircuit::keygen::(&p2, iter::once(l1_snark.clone())); -// circuit.expose_previous_instances(true); - -// let num_instances = circuit.num_instance(); -// println!("L2 Keygen num_instances: {:?}", num_instances); - -// let pk_l2 = gen_pk(&p2, &circuit, None); -// circuit.write_pinning(AGG_FINAL_CONFIG_PATH); -// let pinning = AggregationConfigPinning::from_path(AGG_FINAL_CONFIG_PATH); - -// let deployment_code = gen_evm_verifier_shplonk::( -// &p2, -// pk_l2.get_vk(), -// num_instances, -// Some(&PathBuf::from("contractyul")), -// ); -// let mut circuit = AggregationCircuit::prover::( -// &p2, -// iter::once(l1_snark.clone()), -// pinning.break_points, -// ); -// circuit.expose_previous_instances(true); - -// let num_instances = circuit.num_instance(); -// let instances = circuit.instances(); -// println!("L2 Prover num_instances: {:?}", num_instances); - -// let proof = gen_evm_proof_shplonk(&p2, &pk_l2, circuit, instances.clone()); -// println!("L2 proof size: {}", proof.len()); -// println!("L2 Deployment Code Size: {}", deployment_code.len()); -// (proof, deployment_code, instances) -// }; - -// evm_verify(deployment_code, instances, proof); -// } -// } +#[cfg(test)] +mod tests { + use std::{ + env::{set_var, var}, + fs, + path::PathBuf, + }; + + use crate::{ + aggregation::AggregationConfigPinning, + gadget::crypto::constant_randomness, + util::{full_prover, full_verifier, gen_pkey, Halo2ConfigPinning, PinnableCircuit}, + witness::{CommitteeRotationArgs, SyncStepArgs}, + }; + + use super::*; + use ark_std::{end_timer, start_timer}; + use eth_types::Testnet; + use halo2_base::{ + halo2_proofs::{ + circuit::SimpleFloorPlanner, + dev::MockProver, + halo2curves::bn256::Fr, + plonk::{keygen_pk, keygen_vk, Circuit, FloorPlanner}, + poly::{commitment::Params, kzg::commitment::ParamsKZG}, + }, + utils::fs::gen_srs, + }; + use halo2curves::{bls12_381::G1Affine, bn256::Bn256}; + use rand::rngs::OsRng; + use rayon::iter::ParallelIterator; + use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; + use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; + use snark_verifier_sdk::{ + gen_pk, + halo2::{ + aggregation::{AggregationCircuit, AggregationConfigParams}, + gen_proof_shplonk, gen_snark_shplonk, + }, + CircuitExt, Snark, SHPLONK, + }; + + fn load_circuit_args() -> CommitteeRotationArgs { + #[derive(serde::Deserialize)] + struct ArgsJson { + finalized_header: BeaconBlockHeader, + committee_root_branch: Vec>, + pubkeys_compressed: Vec>, + } + + let ArgsJson { + pubkeys_compressed, + committee_root_branch, + finalized_header, + } = serde_json::from_slice(&fs::read("../test_data/rotation_512.json").unwrap()).unwrap(); + + CommitteeRotationArgs { + pubkeys_compressed, + randomness: constant_randomness(), + _spec: PhantomData, + finalized_header, + sync_committee_branch: committee_root_branch, + } + } + + fn gen_application_snark( + params: &ParamsKZG, + pk: &ProvingKey, + witness: &CommitteeRotationArgs, + ) -> Snark { + CommitteeUpdateCircuit::::gen_snark_shplonk( + params, + pk, + "./config/committee_update.json", + None::, + witness, + ) + .unwrap() + } + + #[test] + fn test_committee_update_circuit() { + const K: u32 = 18; + let params = gen_srs(K); + + let witness = load_circuit_args(); + + let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); + let circuit = CommitteeUpdateCircuit::::create_circuit( + CircuitBuilderStage::Mock, + Some(pinning), + &witness, + params.k(), + ) + .unwrap(); + + let timer = start_timer!(|| "committee_update mock prover"); + let prover = MockProver::::run(K, &circuit, circuit.instances()).unwrap(); + prover.assert_satisfied_par(); + end_timer!(timer); + } + + #[test] + fn test_committee_update_proofgen() { + const K: u32 = 18; + let params = gen_srs(K); + + let pk = CommitteeUpdateCircuit::::read_or_create_pk( + ¶ms, + "../build/committee_update.pkey", + "./config/committee_update.json", + false, + &CommitteeRotationArgs::::default(), + ); + + let witness = load_circuit_args(); + + let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); + + let circuit = CommitteeUpdateCircuit::::create_circuit( + CircuitBuilderStage::Prover, + Some(pinning), + &witness, + K, + ) + .unwrap(); + + let instances = circuit.instances(); + let proof = full_prover(¶ms, &pk, circuit, instances.clone()); + + assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) + } + + #[test] + fn test_circuit_aggregation_proofgen() { + const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; + const APP_K: u32 = 20; + let params_app = gen_srs(APP_K); + + const AGG_K: u32 = 22; + let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( + ¶ms_app, + "../build/committee_update.pkey", + "./config/committee_update.json", + false, + &CommitteeRotationArgs::::default(), + ); + let witness = load_circuit_args(); + let snark = gen_application_snark(¶ms_app, &pk_app, &witness); + + let params = gen_srs(AGG_K); + println!("agg_params k: {:?}", params.k()); + let lookup_bits = params.k() as usize - 1; + + let pk = AggregationCircuit::read_or_create_pk( + ¶ms, + "../build/aggregation.pkey", + AGG_CONFIG_PATH, + false, + &vec![snark.clone()], + ); + + let agg_config = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); + + let agg_circuit = AggregationCircuit::create_circuit( + CircuitBuilderStage::Prover, + Some(agg_config), + &vec![snark.clone()], + AGG_K, + ) + .unwrap(); + + let instances = agg_circuit.instances(); + let num_instances = agg_circuit.num_instance(); + + let proof = full_prover(¶ms, &pk, agg_circuit, instances.clone()); + + assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)); + } + + #[test] + fn test_circuit_aggregation_evm() { + const AGG_CONFIG_PATH: &str = "./config/committee_update_a.json"; + const APP_K: u32 = 21; + let params_app = gen_srs(APP_K); + + const AGG_K: u32 = 23; + let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( + ¶ms_app, + "../build/committee_update.pkey", + "./config/committee_update.json", + false, + &CommitteeRotationArgs::::default(), + ); + + let witness = load_circuit_args(); + let snark = gen_application_snark(¶ms_app, &pk_app, &witness); + + let params = gen_srs(AGG_K); + println!("agg_params k: {:?}", params.k()); + let lookup_bits = params.k() as usize - 1; + + let pk = AggregationCircuit::read_or_create_pk( + ¶ms, + "../build/aggregation.pkey", + AGG_CONFIG_PATH, + false, + &vec![snark.clone()], + ); + + let agg_config = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); + + let agg_circuit = AggregationCircuit::create_circuit( + CircuitBuilderStage::Prover, + Some(agg_config), + &vec![snark.clone()], + AGG_K, + ) + .unwrap(); + + let instances = agg_circuit.instances(); + let num_instances = agg_circuit.num_instance(); + + println!("num_instances: {:?}", num_instances); + println!("instances: {:?}", instances); + + let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); + println!("proof size: {}", proof.len()); + let deployment_code = AggregationCircuit::gen_evm_verifier_shplonk( + ¶ms, + &pk, + Some("contractyul"), + &vec![snark], + ) + .unwrap(); + println!("deployment_code size: {}", deployment_code.len()); + evm_verify(deployment_code, instances, proof); + } + + #[test] + fn test_circuit_aggregation_2_evm() { + const K0: u32 = 20; + const K1: u32 = 24; + const K2: u32 = 24; + + const APP_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; + const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation_1.json"; + const AGG_FINAL_CONFIG_PATH: &str = "./config/committee_update_aggregation_2.json"; + + // Layer 0 snark gen + let l0_snark = { + let p0 = gen_srs(K0); + let pk_l0 = CommitteeUpdateCircuit::::read_or_create_pk( + &p0, + "../build/committee_update.pkey", + APP_CONFIG_PATH, + false, + &CommitteeRotationArgs::::default(), + ); + let witness = load_circuit_args(); + let snark = gen_application_snark(&p0, &pk_l0, &witness); + println!( + "L0 num instances: {:?}", + snark.instances.iter().map(|i| i.len()).collect_vec() + ); + println!("L0 snark size: {}", snark.proof.len()); + snark + }; + + // Layer 1 snark gen + let l1_snark = { + let p1 = gen_srs(K1); + let pk_l1 = AggregationCircuit::read_or_create_pk( + &p1, + "./build/l1_aggregation.pkey", + AGG_CONFIG_PATH, + false, + &vec![l0_snark.clone()], + ); + + let pinning = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); + let lookup_bits = K1 as usize - 1; + let circuit = AggregationCircuit::create_circuit( + CircuitBuilderStage::Prover, + Some(pinning), + &vec![l0_snark.clone()], + K1, + ) + .unwrap(); + + println!("L1 Prover num_instances: {:?}", circuit.num_instance()); + let snark = gen_snark_shplonk(&p1, &pk_l1, circuit, None::); + println!("L1 snark size: {}", snark.proof.len()); + + snark + }; + + // Layer 2 snark gen + let (proof, deployment_code, instances) = { + let p2 = gen_srs(K2); + let pk_l2 = AggregationCircuit::read_or_create_pk( + &p2, + "./build/l2_aggregation.pkey", + AGG_FINAL_CONFIG_PATH, + false, + &vec![l0_snark.clone()], + ); + let pinning = AggregationConfigPinning::from_path(AGG_FINAL_CONFIG_PATH); + + let mut circuit = AggregationCircuit::create_circuit( + CircuitBuilderStage::Prover, + Some(pinning), + &vec![l1_snark.clone()], + K2, + ) + .unwrap(); + let num_instances = circuit.num_instance(); + + let deployment_code = gen_evm_verifier_shplonk::( + &p2, + pk_l2.get_vk(), + vec![65], + Some(&PathBuf::from("contractyul")), + ); + let instances = circuit.instances(); + println!("L2 Prover num_instances: {:?}", num_instances); + + let proof = gen_evm_proof_shplonk(&p2, &pk_l2, circuit, instances.clone()); + println!("L2 proof size: {}", proof.len()); + println!("L2 Deployment Code Size: {}", deployment_code.len()); + (proof, deployment_code, instances) + }; + + evm_verify(deployment_code, instances, proof); + } +} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs index beed6692..49faae32 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs @@ -228,7 +228,7 @@ impl<'a, F: Field> Sha256ChipWide<'a, F> { .try_into() .unwrap(); - let is_final = reassign_to_gate(assigned_rows.is_final[round_idx]); + let is_final = reassign_to_gate(assigned_rows.is_enabled[round_idx]); let output_rlc = reassign_to_gate(assigned_rows.output_rlc[0]); assigned_rounds.push(AssignedSha256Round { diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs index a2844235..94030d1e 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs @@ -772,7 +772,7 @@ impl Sha256BitConfig, Context> { } if round == NUM_ROUNDS + 7 { - assigned_rows.is_final.push(is_enabled); + assigned_rows.is_enabled.push(is_enabled); assigned_rows.input_len.push(input_len); } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs index 34cd3ecc..641aff8b 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs @@ -47,6 +47,7 @@ impl CommonGateManager for ShaBitGateManager { let copy_manager = SharedCopyConstraintManager::default(); let mut context_id = 0; let mut new_context = || { + context_id += 1; Context::new( witness_gen_only, FIRST_PHASE, @@ -55,6 +56,7 @@ impl CommonGateManager for ShaBitGateManager { copy_manager.clone(), ) }; + Self { witness_gen_only, use_unknown: false, diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs index 01c0b34c..f29f67e6 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs @@ -51,7 +51,7 @@ pub struct Sha256AssignedRows { /// Input words at the row. pub input_rlc: Vec>, /// Whether the output word is enabled at the row. - pub is_final: Vec>, + pub is_enabled: Vec>, /// Whether the row is padding. pub padding_selectors: Vec<[AssignedValue; 4]>, /// Output words at the row. diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index fa17ac28..407a81e5 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -21,3 +21,7 @@ mod ssz_merkle; pub use halo2_base; +use halo2_base::halo2_proofs::halo2curves::bn256; +#[allow(type_alias_bounds)] +pub type Eth2CircuitBuilder> = + gadget::crypto::ShaCircuitBuilder; diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 6ddd3fc6..6bdd8ba8 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -20,7 +20,7 @@ use crate::{ poseidon::{fq_array_poseidon, fq_array_poseidon_native, poseidon_sponge}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, util::{gen_pkey, AppCircuit, Challenges, CommonGateManager, Eth2ConfigPinning, IntoWitness}, - witness::{self, HashInput, HashInputChunk, SyncStepArgs}, + witness::{self, HashInput, HashInputChunk, SyncStepArgs}, Eth2CircuitBuilder, }; use eth_types::{Field, Spec}; use halo2_base::{ @@ -442,7 +442,7 @@ impl AppCircuit for SyncStepCircuit { k: u32, ) -> Result, Error> { let mut builder = - ShaCircuitBuilder::>::from_stage(stage) + Eth2CircuitBuilder::>::from_stage(stage) .use_k(k as usize) .use_instance_columns(1); let range = builder.range_chip(8); From b402db8467b9c5c851a845f52104b2cffa0fe238 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Tue, 31 Oct 2023 17:19:48 +0100 Subject: [PATCH 05/23] fix prover --- Cargo.toml | 2 +- eth-types/src/curve.rs | 92 --------------------------------- lightclient-circuits/src/lib.rs | 1 + preprocessor/src/lib.rs | 4 +- preprocessor/src/rotation.rs | 1 - preprocessor/src/sync.rs | 8 +-- prover/Cargo.toml | 2 +- prover/src/main.rs | 2 +- prover/src/rpc.rs | 60 +++++++++------------ 9 files changed, 32 insertions(+), 140 deletions(-) delete mode 100644 eth-types/src/curve.rs diff --git a/Cargo.toml b/Cargo.toml index b89ef8c0..563158a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["lightclient-circuits", "preprocessor", "eth-types"] +members = ["lightclient-circuits", "preprocessor", "eth-types", "prover"] resolver = "2" diff --git a/eth-types/src/curve.rs b/eth-types/src/curve.rs deleted file mode 100644 index 87697a6d..00000000 --- a/eth-types/src/curve.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::array::TryFromSliceError; -use std::iter; - -use halo2_ecc::fields::PrimeField; -use halo2_ecc::halo2_base::utils::CurveAffineExt; -use halo2_proofs::arithmetic::Field as Halo2Field; -use halo2curves::CurveExt; -use halo2curves::FieldExt; -use itertools::Itertools; -use pasta_curves::arithmetic::SqrtRatio; -use pasta_curves::group::GroupEncoding; -use pasta_curves::group::UncompressedEncoding; - -use crate::Field; - -pub trait AppCurveExt: CurveExt { - /// Prime field of order $p$ over which the elliptic curves is defined. - type Fp: PrimeField; - /// Prime field of order $q = p^k$ where k is the embedding degree. - type Fq: PrimeField + FieldExt + Halo2Field = Self::Fp; - /// Affine version of the curve. - type Affine: CurveAffineExt - + GroupEncoding - + UncompressedEncoding; - /// Compressed representation of the curve. - type CompressedRepr: TryFrom, Error = TryFromSliceError>; - /// Compressed representation of the curve. - type UnompressedRepr: TryFrom, Error = TryFromSliceError>; - /// Constant $b$ in the curve equation $y^2 = x^3 + b$. - const B: u64; - // Bytes needed to encode [`Self::Fq]; - const BYTES_COMPRESSED: usize; - // Bytes needed to encode curve in uncompressed form. - const BYTES_UNCOMPRESSED: usize; - /// Number of bits in a single limb. - const LIMB_BITS: usize; - /// Number of limbs in the prime field. - const NUM_LIMBS: usize; - - fn generator_affine() -> ::Affine; - - fn limb_bytes_bases() -> Vec { - iter::repeat(8) - .enumerate() - .map(|(i, x)| i * x) - .take_while(|&bits| bits <= Self::LIMB_BITS) - .map(|bits| F::from_u128(1u128 << bits)) - .collect() - } -} - - -mod bls12_381 { - use super::*; - use halo2curves::bls12_381::{ - Fq, Fq2, G1Affine, G1Compressed, G1Uncompressed, G2Affine, G2Compressed, G2Uncompressed, - G1, G2, - }; - - impl AppCurveExt for G1 { - type Affine = G1Affine; - type Fp = Fq; - type CompressedRepr = G1Compressed; - type UnompressedRepr = G1Uncompressed; - const BYTES_COMPRESSED: usize = 48; - const BYTES_UNCOMPRESSED: usize = Self::BYTES_COMPRESSED * 2; - const LIMB_BITS: usize = 112; - const NUM_LIMBS: usize = 4; - const B: u64 = 4; - - fn generator_affine() -> G1Affine { - G1Affine::generator() - } - } - - impl AppCurveExt for G2 { - type Affine = G2Affine; - type Fp = Fq; - type Fq = Fq2; - type CompressedRepr = G2Compressed; - type UnompressedRepr = G2Uncompressed; - const BYTES_COMPRESSED: usize = 96; - const BYTES_UNCOMPRESSED: usize = Self::BYTES_COMPRESSED * 2; - const LIMB_BITS: usize = 112; - const NUM_LIMBS: usize = 4; - const B: u64 = 4; - - fn generator_affine() -> G2Affine { - G2Affine::generator() - } - } -} diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 407a81e5..6f50fbf3 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -20,6 +20,7 @@ mod poseidon; mod ssz_merkle; pub use halo2_base; +pub use halo2_base::halo2_proofs; use halo2_base::halo2_proofs::halo2curves::bn256; #[allow(type_alias_bounds)] diff --git a/preprocessor/src/lib.rs b/preprocessor/src/lib.rs index 998835c2..41903f91 100644 --- a/preprocessor/src/lib.rs +++ b/preprocessor/src/lib.rs @@ -1,6 +1,6 @@ mod sync; pub use sync::*; -// mod rotation; -// pub use rotation::*; +mod rotation; +pub use rotation::*; pub(crate) use lightclient_circuits::halo2_base; diff --git a/preprocessor/src/rotation.rs b/preprocessor/src/rotation.rs index bc8d52cc..5d19496a 100644 --- a/preprocessor/src/rotation.rs +++ b/preprocessor/src/rotation.rs @@ -97,7 +97,6 @@ pub async fn read_rotation_args( mod tests { use eth_types::Testnet; use crate::halo2_base::halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; - use halo2curves::bn256::Fr; use lightclient_circuits::{ committee_update_circuit::CommitteeUpdateCircuit, util::{gen_srs, AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, halo2_base::gates::circuit::CircuitBuilderStage, diff --git a/preprocessor/src/sync.rs b/preprocessor/src/sync.rs index ff5c201f..13e3466a 100644 --- a/preprocessor/src/sync.rs +++ b/preprocessor/src/sync.rs @@ -58,8 +58,7 @@ pub async fn fetch_step_args(node_url: String) -> eyre::Result(node_url: String) -> eyre::Result { signature_compressed, pubkeys_uncompressed, diff --git a/prover/Cargo.toml b/prover/Cargo.toml index 9f5ddd76..0bd0a276 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -18,7 +18,7 @@ jsonrpc-v2 = { version = "0.12", default-features = false, features = ["easy-err http = "0.2" # halo2 -halo2curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.1" } +halo2curves = { git = "https://github.com/axiom-crypto/halo2curves", version = "0.4.0" } # verifier SDK snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.1-ce", default-features = false, features = [ diff --git a/prover/src/main.rs b/prover/src/main.rs index 7af4a213..d459411a 100644 --- a/prover/src/main.rs +++ b/prover/src/main.rs @@ -5,7 +5,7 @@ use args::{Args, Cli, Out, Proof}; use axum::{response::IntoResponse, routing::post, Router}; use cli_batteries::version; use ethers::prelude::*; -use halo2curves::bn256::{Bn256, Fr, G1Affine}; +use lightclient_circuits::halo2_proofs::halo2curves::bn256::{Bn256, Fr, G1Affine}; use http::StatusCode; use itertools::Itertools; use jsonrpc_v2::{MapRouter as JsonRpcMapRouter, Server as JsonRpcServer}; diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index 5da9f37c..fe07883e 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -1,19 +1,19 @@ use super::{args, args::Spec}; use ethers::prelude::*; -use halo2curves::bn256::Fr; +use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use jsonrpc_v2::{Error as JsonRpcError, Params}; use lightclient_circuits::{ aggregation::AggregationConfigPinning, committee_update_circuit::CommitteeUpdateCircuit, + halo2_base::gates::circuit::CircuitBuilderStage, sync_step_circuit::SyncStepCircuit, util::{gen_srs, AppCircuit, Halo2ConfigPinning}, }; use preprocessor::{fetch_rotation_args, fetch_step_args}; use serde::{Deserialize, Serialize}; -use snark_verifier::loader::halo2::halo2_ecc::halo2_base::gates::builder::CircuitBuilderStage; use snark_verifier_sdk::{ evm::gen_evm_verifier_shplonk, gen_pk, @@ -140,25 +140,20 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_handler( let l1_snark = { let k = k.unwrap_or(24); let p1 = gen_srs(k); - let mut circuit = AggregationCircuit::keygen::(&p1, vec![l0_snark.clone()]); - circuit.expose_previous_instances(false); - - println!("L1 Keygen num_instances: {:?}", circuit.num_instance()); - - let pk_l1 = gen_pk(&p1, &circuit, None); - let pinning = AggregationConfigPinning::from_path(agg_l1_config_path); - let lookup_bits = k as usize - 1; - let mut circuit = AggregationCircuit::new::( - CircuitBuilderStage::Prover, - Some(pinning.break_points), - lookup_bits, + let pk_l1 = AggregationCircuit::read_pk( &p1, - std::iter::once(l0_snark.clone()), + "./build/committee_update_aggregation_l1.pkey", + &vec![l0_snark.clone()], ); - circuit.expose_previous_instances(false); - println!("L1 Prover num_instances: {:?}", circuit.num_instance()); - let snark = gen_snark_shplonk(&p1, &pk_l1, circuit, None::); + let snark = AggregationCircuit::gen_snark_shplonk( + &p1, + &pk_l1, + agg_l1_config_path, + None::, + &vec![l0_snark.clone()], + ) + .map_err(JsonRpcError::internal)?; println!("L1 snark size: {}", snark.proof.len()); snark @@ -167,26 +162,19 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_handler( let (proof, instances) = { let k = k.unwrap_or(24); let p2 = gen_srs(k); - let mut circuit = - AggregationCircuit::keygen::(&p2, std::iter::once(l1_snark.clone())); - circuit.expose_previous_instances(true); - - let pk_l2 = gen_pk(&p2, &circuit, None); - let pinning = AggregationConfigPinning::from_path(agg_l2_config_path); - - let mut circuit = AggregationCircuit::prover::( + let pk_l2 = AggregationCircuit::read_pk( &p2, - std::iter::once(l1_snark.clone()), - pinning.break_points, + "./build/committee_update_aggregation_l2.pkey", + &vec![l0_snark.clone()], ); - circuit.expose_previous_instances(true); - - let instances = circuit.instances(); - - let proof = - snark_verifier_sdk::evm::gen_evm_proof_shplonk(&p2, &pk_l2, circuit, instances.clone()); - - (proof, instances) + AggregationCircuit::gen_evm_proof_shplonk( + &p2, + &pk_l2, + agg_l2_config_path, + None, + &vec![l0_snark.clone()], + ) + .map_err(JsonRpcError::internal)? }; let public_inputs = instances[0] From e4bde3823b2ed2cf67fb55cf7f2be876c6ca79f8 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Mon, 6 Nov 2023 16:56:56 +0100 Subject: [PATCH 06/23] fix proofgen --- lightclient-circuits/config/aggregation.json | 30 ------- .../config/committee_update.json | 19 +++-- .../config/committee_update_a.json | 24 ------ .../config/committee_update_aggregation.json | 30 ------- .../committee_update_aggregation_1.json | 36 --------- .../committee_update_aggregation_2.json | 22 ------ lightclient-circuits/config/sync_step.json | 19 ++--- lightclient-circuits/src/aggregation.rs | 12 ++- .../src/committee_update_circuit.rs | 46 ++++------- lightclient-circuits/src/gadget/common.rs | 5 -- .../src/gadget/crypto/builder.rs | 13 +++- .../src/gadget/crypto/sha256_flex.rs | 6 +- .../gadget/crypto/sha256_flex/compression.rs | 4 +- lightclient-circuits/src/lib.rs | 3 + lightclient-circuits/src/sync_step_circuit.rs | 41 +++++----- lightclient-circuits/src/util.rs | 2 +- lightclient-circuits/src/util/circuit.rs | 78 +++++++++++++------ lightclient-circuits/src/util/proof.rs | 49 ------------ lightclient-circuits/src/witness/hashing.rs | 2 +- lightclient-circuits/src/witness/sync.rs | 5 +- lightclient-circuits/tests/step.rs | 42 +++++----- prover/src/rpc.rs | 11 +-- 22 files changed, 156 insertions(+), 343 deletions(-) delete mode 100644 lightclient-circuits/config/aggregation.json delete mode 100644 lightclient-circuits/config/committee_update_a.json delete mode 100644 lightclient-circuits/config/committee_update_aggregation.json delete mode 100644 lightclient-circuits/config/committee_update_aggregation_1.json delete mode 100644 lightclient-circuits/config/committee_update_aggregation_2.json diff --git a/lightclient-circuits/config/aggregation.json b/lightclient-circuits/config/aggregation.json deleted file mode 100644 index 6ec4ebd2..00000000 --- a/lightclient-circuits/config/aggregation.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "params": { - "strategy": "Vertical", - "k": 22, - "num_advice_per_phase": [ - 8, - 0, - 0 - ], - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "num_fixed": 1 - }, - "break_points": [ - [ - 4194294, - 4194293, - 4194294, - 4194292, - 4194293, - 4194294, - 4194294 - ], - [], - [] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update.json b/lightclient-circuits/config/committee_update.json index 6b07b830..e0ff3c54 100644 --- a/lightclient-circuits/config/committee_update.json +++ b/lightclient-circuits/config/committee_update.json @@ -1,24 +1,23 @@ { "params": { - "strategy": "Vertical", - "k": 21, + "k": 20, "num_advice_per_phase": [ - 2, - 0, - 0 + 4 ], + "num_fixed": 1, "num_lookup_advice_per_phase": [ 1, 0, 0 ], - "num_fixed": 1 + "lookup_bits": 8, + "num_instance_columns": 1 }, "break_points": [ [ - 2097139 - ], - [], - [] + 1048564, + 1048566, + 1048565 + ] ] } \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_a.json b/lightclient-circuits/config/committee_update_a.json deleted file mode 100644 index 22c3366a..00000000 --- a/lightclient-circuits/config/committee_update_a.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "params": { - "strategy": "Vertical", - "k": 24, - "num_advice_per_phase": [ - 2, - 0, - 0 - ], - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "num_fixed": 1 - }, - "break_points": [ - [ - 16777205 - ], - [], - [] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_aggregation.json b/lightclient-circuits/config/committee_update_aggregation.json deleted file mode 100644 index db5a3b24..00000000 --- a/lightclient-circuits/config/committee_update_aggregation.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "params": { - "strategy": "Vertical", - "k": 19, - "num_advice_per_phase": [ - 8, - 0, - 0 - ], - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "num_fixed": 1 - }, - "break_points": [ - [ - 524276, - 524276, - 524274, - 524276, - 524275, - 524275, - 524275 - ], - [], - [] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_aggregation_1.json b/lightclient-circuits/config/committee_update_aggregation_1.json deleted file mode 100644 index 193bb1cb..00000000 --- a/lightclient-circuits/config/committee_update_aggregation_1.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "params": { - "strategy": "Vertical", - "k": 21, - "num_advice_per_phase": [ - 14, - 0, - 0 - ], - "num_lookup_advice_per_phase": [ - 2, - 0, - 0 - ], - "num_fixed": 1 - }, - "break_points": [ - [ - 2097140, - 2097141, - 2097141, - 2097142, - 2097142, - 2097141, - 2097141, - 2097142, - 2097140, - 2097142, - 2097140, - 2097142, - 2097140 - ], - [], - [] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_aggregation_2.json b/lightclient-circuits/config/committee_update_aggregation_2.json deleted file mode 100644 index 19792c2d..00000000 --- a/lightclient-circuits/config/committee_update_aggregation_2.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "params": { - "strategy": "Vertical", - "k": 24, - "num_advice_per_phase": [ - 1, - 0, - 0 - ], - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "num_fixed": 1 - }, - "break_points": [ - [], - [], - [] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/sync_step.json b/lightclient-circuits/config/sync_step.json index 0fa9d3f8..8f0ef69f 100644 --- a/lightclient-circuits/config/sync_step.json +++ b/lightclient-circuits/config/sync_step.json @@ -1,28 +1,25 @@ { "params": { - "strategy": "Vertical", "k": 22, "num_advice_per_phase": [ - 6, - 0, - 0 + 6 ], + "num_fixed": 1, "num_lookup_advice_per_phase": [ 1, 0, 0 ], - "num_fixed": 1 + "lookup_bits": 8, + "num_instance_columns": 1 }, "break_points": [ [ - 4194294, - 4194293, + 4194292, 4194292, 4194293, - 4194292 - ], - [], - [] + 4194294, + 4194294 + ] ] } \ No newline at end of file diff --git a/lightclient-circuits/src/aggregation.rs b/lightclient-circuits/src/aggregation.rs index b259b760..29dfd74b 100644 --- a/lightclient-circuits/src/aggregation.rs +++ b/lightclient-circuits/src/aggregation.rs @@ -1,6 +1,8 @@ use std::{ env::{set_var, var}, - iter, path::Path, fs::File, + fs::File, + iter, + path::Path, }; use eth_types::Testnet; @@ -14,9 +16,12 @@ use halo2_base::{ utils::fs::gen_srs, }; use serde::{Deserialize, Serialize}; -use snark_verifier_sdk::{halo2::aggregation::{AggregationCircuit, AggregationConfigParams}, Snark, SHPLONK}; +use snark_verifier_sdk::{ + halo2::aggregation::{AggregationCircuit, AggregationConfigParams}, + Snark, SHPLONK, +}; -use crate::util::{AppCircuit, Eth2ConfigPinning, PinnableCircuit, Halo2ConfigPinning}; +use crate::util::{AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning, PinnableCircuit}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AggregationConfigPinning { @@ -24,7 +29,6 @@ pub struct AggregationConfigPinning { pub break_points: MultiPhaseThreadBreakPoints, } - impl Halo2ConfigPinning for AggregationConfigPinning { type BreakPoints = MultiPhaseThreadBreakPoints; diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 4495b1cf..25f400ce 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -9,7 +9,7 @@ use crate::{ ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, sync_step_circuit::{clear_3_bits, to_bytes_le, truncate_sha256_into_single_elem}, util::{gen_pkey, AppCircuit, Challenges, CommonGateManager, Eth2ConfigPinning, IntoWitness}, - witness::{self, HashInput, HashInputChunk}, Eth2CircuitBuilder, + witness::{self, HashInput, HashInputChunk}, Eth2CircuitBuilder, LIMB_BITS, NUM_LIMBS, }; use eth_types::{Field, Spec}; use halo2_base::{ @@ -222,13 +222,17 @@ impl AppCircuit for CommitteeUpdateCircuit { .use_k(k as usize) .use_instance_columns(1); let range = builder.range_chip(8); - let fp_chip = FpChip::new(&range, 120, 4); + let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); let assigned_instances = Self::synthesize(&mut builder, &fp_chip, witness)?; match stage { CircuitBuilderStage::Prover => { builder.set_instances(0, assigned_instances); + if let Some(pinning) = pinning { + builder.set_params(pinning.params); + builder.set_break_points(pinning.break_points); + } } _ => { builder.calculate_params(Some( @@ -255,7 +259,7 @@ mod tests { use crate::{ aggregation::AggregationConfigPinning, gadget::crypto::constant_randomness, - util::{full_prover, full_verifier, gen_pkey, Halo2ConfigPinning, PinnableCircuit}, + util::{gen_pkey, Halo2ConfigPinning, PinnableCircuit}, witness::{CommitteeRotationArgs, SyncStepArgs}, }; @@ -361,20 +365,13 @@ mod tests { let witness = load_circuit_args(); - let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); - - let circuit = CommitteeUpdateCircuit::::create_circuit( - CircuitBuilderStage::Prover, - Some(pinning), + let circuit = CommitteeUpdateCircuit::::gen_proof_shplonk( + ¶ms, + &pk, + "./config/committee_update.json", &witness, - K, ) - .unwrap(); - - let instances = circuit.instances(); - let proof = full_prover(¶ms, &pk, circuit, instances.clone()); - - assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) + .expect("proof generation & verification should not fail"); } #[test] @@ -406,22 +403,13 @@ mod tests { &vec![snark.clone()], ); - let agg_config = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); - - let agg_circuit = AggregationCircuit::create_circuit( - CircuitBuilderStage::Prover, - Some(agg_config), + let circuit = AggregationCircuit::gen_proof_shplonk( + ¶ms, + &pk, + AGG_CONFIG_PATH, &vec![snark.clone()], - AGG_K, ) - .unwrap(); - - let instances = agg_circuit.instances(); - let num_instances = agg_circuit.num_instance(); - - let proof = full_prover(¶ms, &pk, agg_circuit, instances.clone()); - - assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)); + .expect("proof generation & verification should not fail"); } #[test] diff --git a/lightclient-circuits/src/gadget/common.rs b/lightclient-circuits/src/gadget/common.rs index 4b3f36ca..d5631dab 100644 --- a/lightclient-circuits/src/gadget/common.rs +++ b/lightclient-circuits/src/gadget/common.rs @@ -199,11 +199,6 @@ pub fn expr_from_bytes>(bytes: &[E]) -> Expression { value } -/// Returns 2**by as Field -pub fn pow_of_two(by: usize) -> F { - F::from(2).pow(&[by as u64, 0, 0, 0]) -} - /// Returns the random linear combination of the inputs. /// Encoding is done as follows: v_0 * R^0 + v_1 * R^1 + ... pub mod rlc { diff --git a/lightclient-circuits/src/gadget/crypto/builder.rs b/lightclient-circuits/src/gadget/crypto/builder.rs index 8aded728..aff68dbb 100644 --- a/lightclient-circuits/src/gadget/crypto/builder.rs +++ b/lightclient-circuits/src/gadget/crypto/builder.rs @@ -166,7 +166,12 @@ impl> ShaCircuitBuilder) -> BaseCircuitParams { - self.base.calculate_params(minimum_rows) + let params = self.base.calculate_params(minimum_rows); + set_var( + "GATE_CONFIG_PARAMS", + serde_json::to_string(¶ms).unwrap(), + ); + params } pub fn sha_contexts_pair(&mut self) -> (&mut Context, GateManager::CustomContext<'_>) { @@ -187,15 +192,15 @@ impl> CommonCircuitBuilder } fn thread_count(&self) -> usize { - self.thread_count() + unimplemented!() } fn new_context(&self, context_id: usize) -> Context { - self.new_context(context_id) + unimplemented!() } fn new_thread(&mut self) -> &mut Context { - self.new_thread() + unimplemented!() } } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs index bc3cef4b..277f6c3a 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs @@ -182,9 +182,7 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { builder.main().constrain_equal(&assigned_word, &sum); assigned_bytes }) - .collect_vec() - .try_into() - .unwrap(); + .collect_vec(); Ok(output_digest_bytes) } @@ -205,7 +203,7 @@ mod test { use std::{cell::RefCell, marker::PhantomData}; use crate::gadget::crypto::ShaCircuitBuilder; - use crate::util::{full_prover, full_verifier, gen_pkey, Challenges, IntoWitness}; + use crate::util::{gen_pkey, Challenges, IntoWitness}; use super::*; use ark_std::{end_timer, start_timer}; diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs index d32eaae8..2b06d525 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs @@ -227,7 +227,7 @@ pub fn sha256_compression<'a, 'b: 'a, F: Field>( }; a_spread = state_to_spread_u32(thread_pool, spread_chip, &a)?; } - let new_states = vec![a, b, c, d, e, f, g, h]; + let new_states = [a, b, c, d, e, f, g, h]; let next_state_words = new_states .iter() .copied() @@ -279,7 +279,7 @@ fn mod_u32<'a, 'b: 'a, F: Field>( ) -> AssignedValue { let gate = range.gate(); let lo = F::from(x.value().get_lower_32() as u64); - let hi = F::from(((x.value().get_lower_64() >> 32) & ((1u64 << 32) - 1)) as u64); + let hi = F::from((x.value().get_lower_64() >> 32) & ((1u64 << 32) - 1)); let assigned_lo = ctx.load_witness(lo); let assigned_hi = ctx.load_witness(hi); range.range_check(ctx, assigned_lo, 32); diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 6f50fbf3..61e8256e 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -22,6 +22,9 @@ mod ssz_merkle; pub use halo2_base; pub use halo2_base::halo2_proofs; +pub const NUM_LIMBS: usize = 4; +pub const LIMB_BITS: usize = 112; + use halo2_base::halo2_proofs::halo2curves::bn256; #[allow(type_alias_bounds)] pub type Eth2CircuitBuilder> = diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 6bdd8ba8..424d3cc8 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -20,7 +20,8 @@ use crate::{ poseidon::{fq_array_poseidon, fq_array_poseidon_native, poseidon_sponge}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, util::{gen_pkey, AppCircuit, Challenges, CommonGateManager, Eth2ConfigPinning, IntoWitness}, - witness::{self, HashInput, HashInputChunk, SyncStepArgs}, Eth2CircuitBuilder, + witness::{self, HashInput, HashInputChunk, SyncStepArgs}, + Eth2CircuitBuilder, LIMB_BITS, NUM_LIMBS, }; use eth_types::{Field, Spec}; use halo2_base::{ @@ -85,12 +86,12 @@ impl SyncStepCircuit { let range = fp_chip.range(); let gate = range.gate(); let sha256_chip = Sha256Chip::new(range); - let fp2_chip = Fp2Chip::::new(&fp_chip); + let fp2_chip = Fp2Chip::::new(fp_chip); let g1_chip = EccChip::new(fp2_chip.fp_chip()); let g2_chip = EccChip::new(&fp2_chip); let fp12_chip = Fp12Chip::::new(fp2_chip.fp_chip()); - let pairing_chip = PairingChip::new(&fp_chip); - let bls_chip = BlsSignatureChip::new(&fp_chip, &pairing_chip); + let pairing_chip = PairingChip::new(fp_chip); + let bls_chip = BlsSignatureChip::new(fp_chip, &pairing_chip); let h2c_chip = HashToCurveChip::new(&sha256_chip, &fp2_chip); let execution_payload_root: HashInputChunk> = @@ -441,18 +442,21 @@ impl AppCircuit for SyncStepCircuit { args: &Self::Witness, k: u32, ) -> Result, Error> { - let mut builder = - Eth2CircuitBuilder::>::from_stage(stage) - .use_k(k as usize) - .use_instance_columns(1); + let mut builder = Eth2CircuitBuilder::>::from_stage(stage) + .use_k(k as usize) + .use_instance_columns(1); let range = builder.range_chip(8); - let fp_chip = FpChip::new(&range, 112, 4); + let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); let assigned_instances = Self::synthesize(&mut builder, &fp_chip, args)?; match stage { CircuitBuilderStage::Prover => { builder.set_instances(0, assigned_instances); + if let Some(pinning) = pinning { + builder.set_params(pinning.params); + builder.set_break_points(pinning.break_points); + } } _ => { builder.calculate_params(Some( @@ -477,7 +481,7 @@ mod tests { }; use crate::{ - util::{full_prover, full_verifier, gen_pkey, Halo2ConfigPinning}, + util::{gen_pkey, Halo2ConfigPinning}, witness::SyncStepArgs, }; @@ -548,20 +552,13 @@ mod tests { let witness = load_circuit_args(); - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - - let circuit = SyncStepCircuit::::create_circuit( - CircuitBuilderStage::Prover, - Some(pinning), + let _ = SyncStepCircuit::::gen_proof_shplonk( + ¶ms, + &pk, + "./config/sync_step.json", &witness, - K, ) - .unwrap(); - - let instances = circuit.instances(); - let proof = full_prover(¶ms, &pk, circuit, instances.clone()); - - assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) + .expect("proof generation & verification should not fail"); } #[test] diff --git a/lightclient-circuits/src/util.rs b/lightclient-circuits/src/util.rs index eb6fb021..44487b7c 100644 --- a/lightclient-circuits/src/util.rs +++ b/lightclient-circuits/src/util.rs @@ -83,7 +83,7 @@ impl Challenges { } /// Returns `Value` of challenges from `Layouter`. - pub fn values(&self, layouter: &mut impl Layouter) -> Challenges> { + pub fn values(&self, layouter: &impl Layouter) -> Challenges> { Challenges { sha256_input: layouter.get_challenge(self.sha256_input), } diff --git a/lightclient-circuits/src/util/circuit.rs b/lightclient-circuits/src/util/circuit.rs index 4d127cea..7faa8b42 100644 --- a/lightclient-circuits/src/util/circuit.rs +++ b/lightclient-circuits/src/util/circuit.rs @@ -2,8 +2,8 @@ use std::env::{args, set_var, var}; use std::fs; use std::{fs::File, path::Path}; -use halo2_base::gates::circuit::CircuitBuilderStage; -use halo2_base::gates::flex_gate::{MultiPhaseThreadBreakPoints, FlexGateConfigParams}; +use halo2_base::gates::circuit::{CircuitBuilderStage, BaseCircuitParams}; +use halo2_base::gates::flex_gate::{FlexGateConfigParams, MultiPhaseThreadBreakPoints}; use halo2_base::halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::ProvingKey, @@ -17,6 +17,7 @@ use snark_verifier_sdk::evm::{ encode_calldata, evm_verify, gen_evm_proof, gen_evm_proof_shplonk, gen_evm_verifier_shplonk, }; use snark_verifier_sdk::halo2::aggregation::AggregationCircuit; +use snark_verifier_sdk::halo2::gen_proof_shplonk; use snark_verifier_sdk::{gen_pk, halo2::gen_snark_shplonk, read_pk}; use snark_verifier_sdk::{CircuitExt, Snark}; @@ -36,7 +37,7 @@ pub trait Halo2ConfigPinning: Serialize { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Eth2ConfigPinning { - pub params: FlexGateConfigParams, + pub params: BaseCircuitParams, pub break_points: MultiPhaseThreadBreakPoints, } @@ -55,7 +56,7 @@ impl Halo2ConfigPinning for Eth2ConfigPinning { fn set_var(&self) { set_var( - "FLEX_GATE_CONFIG_PARAMS", + "GATE_CONFIG_PARAMS", serde_json::to_string(&self.params).unwrap(), ); set_var("LOOKUP_BITS", (self.params.k - 1).to_string()); @@ -66,8 +67,8 @@ impl Halo2ConfigPinning for Eth2ConfigPinning { } fn from_var(break_points: MultiPhaseThreadBreakPoints) -> Self { - let params: FlexGateConfigParams = - serde_json::from_str(&var("FLEX_GATE_CONFIG_PARAMS").unwrap()).unwrap(); + let params: BaseCircuitParams = + serde_json::from_str(&var("GATE_CONFIG_PARAMS").unwrap()).unwrap(); Self { params, break_points, @@ -103,7 +104,7 @@ pub trait AppCircuit { fn create_circuit( stage: CircuitBuilderStage, pinning: Option, - args: &Self::Witness, + witness_args: &Self::Witness, k: u32, ) -> Result, Error>; @@ -112,10 +113,15 @@ pub trait AppCircuit { fn read_pk( params: &ParamsKZG, path: impl AsRef, - args: &Self::Witness, + witness_args: &Self::Witness, ) -> ProvingKey { - let circuit = - Self::create_circuit(CircuitBuilderStage::Keygen, None, args, params.k()).unwrap(); + let circuit = Self::create_circuit( + CircuitBuilderStage::Keygen, + None, + witness_args, + params.k(), + ) + .unwrap(); custom_read_pk(path, &circuit) } @@ -125,10 +131,15 @@ pub trait AppCircuit { params: &ParamsKZG, pk_path: impl AsRef, pinning_path: impl AsRef, - witness: &Self::Witness, + witness_args: &Self::Witness, ) -> ProvingKey { - let circuit = - Self::create_circuit(CircuitBuilderStage::Keygen, None, witness, params.k()).unwrap(); + let circuit = Self::create_circuit( + CircuitBuilderStage::Keygen, + None, + witness_args, + params.k(), + ) + .unwrap(); let pk_exists = pk_path.as_ref().exists(); let pk = gen_pk(params, &circuit, Some(pk_path.as_ref())); @@ -149,27 +160,46 @@ pub trait AppCircuit { pk_path: impl AsRef, pinning_path: impl AsRef, read_only: bool, - witness: &Self::Witness, + witness_args: &Self::Witness, ) -> ProvingKey { if read_only { - Self::read_pk(params, pk_path, witness) + Self::read_pk(params, pk_path, witness_args) } else { - Self::create_pk(params, pk_path, pinning_path, witness) + Self::create_pk(params, pk_path, pinning_path, witness_args) } } + fn gen_proof_shplonk( + params: &ParamsKZG, + pk: &ProvingKey, + pinning_path: impl AsRef, + witness_args: &Self::Witness, + ) -> Result, Error> { + let pinning = Self::Pinning::from_path(pinning_path); + let circuit = Self::create_circuit( + CircuitBuilderStage::Prover, + Some(pinning), + witness_args, + params.k(), + )?; + let instances = circuit.instances(); + let proof = gen_proof_shplonk(params, pk, circuit, instances, None); + + Ok(proof) + } + fn gen_snark_shplonk( params: &ParamsKZG, pk: &ProvingKey, pinning_path: impl AsRef, path: Option>, - witness: &Self::Witness, + witness_args: &Self::Witness, ) -> Result { let pinning = Self::Pinning::from_path(pinning_path); let circuit = Self::create_circuit( CircuitBuilderStage::Prover, Some(pinning), - witness, + witness_args, params.k(), )?; let snark = gen_snark_shplonk(params, pk, circuit, path); @@ -181,9 +211,9 @@ pub trait AppCircuit { params: &ParamsKZG, pk: &ProvingKey, yul_path: Option>, - witness: &Self::Witness, + witness_args: &Self::Witness, ) -> Result, Error> { - let circuit = Self::create_circuit(CircuitBuilderStage::Keygen, None, witness, params.k())?; + let circuit = Self::create_circuit(CircuitBuilderStage::Keygen, None, witness_args, params.k())?; let deployment_code = custom_gen_evm_verifier_shplonk(params, pk.get_vk(), &circuit, yul_path); @@ -195,13 +225,13 @@ pub trait AppCircuit { pk: &ProvingKey, pinning_path: impl AsRef, deployment_code: Option>, - witness: &Self::Witness, + witness_args: &Self::Witness, ) -> Result<(Vec, Vec>), Error> { let pinning = Self::Pinning::from_path(pinning_path); let circuit = Self::create_circuit( CircuitBuilderStage::Prover, Some(pinning), - witness, + witness_args, params.k(), )?; let instances = circuit.instances(); @@ -216,13 +246,13 @@ pub trait AppCircuit { pinning_path: impl AsRef, path: impl AsRef, deployment_code: Option>, - witness: &Self::Witness, + witness_args: &Self::Witness, ) -> Result { let pinning = Self::Pinning::from_path(pinning_path); let circuit = Self::create_circuit( CircuitBuilderStage::Prover, Some(pinning), - witness, + witness_args, params.k(), )?; let calldata = write_calldata_generic(params, pk, circuit, path, deployment_code); diff --git a/lightclient-circuits/src/util/proof.rs b/lightclient-circuits/src/util/proof.rs index bc47462f..f7719e64 100644 --- a/lightclient-circuits/src/util/proof.rs +++ b/lightclient-circuits/src/util/proof.rs @@ -90,52 +90,3 @@ pub fn gen_pkey>( Ok(pkey) } -/// Generates a proof given the public setup, the proving key, the initiated circuit and its public inputs. -pub fn full_prover>( - params: &ParamsKZG, - pk: &ProvingKey, - circuit: C, - public_inputs: Vec>, -) -> Vec { - let pf_time = start_timer!(|| "Creating proof"); - - let instance: Vec<&[Fr]> = public_inputs.iter().map(|input| &input[..]).collect(); - let instances = &[&instance[..]]; - - let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); - create_proof::< - KZGCommitmentScheme, - ProverSHPLONK<'_, Bn256>, - Challenge255, - _, - Blake2bWrite, G1Affine, Challenge255>, - _, - >(params, pk, &[circuit], instances, OsRng, &mut transcript) - .expect("prover should not fail"); - let proof = transcript.finalize(); - end_timer!(pf_time); - proof -} - -pub fn full_verifier( - params: &ParamsKZG, - vk: &VerifyingKey, - proof: Vec, - public_inputs: Vec>, -) -> bool { - let verifier_params = params.verifier_params(); - let strategy = SingleStrategy::new(params); - let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - - let instance: Vec<&[Fr]> = public_inputs.iter().map(|input| &input[..]).collect(); - let instances = &[&instance[..]]; - - verify_proof::< - KZGCommitmentScheme, - VerifierSHPLONK<'_, Bn256>, - Challenge255, - Blake2bRead<&[u8], G1Affine, Challenge255>, - SingleStrategy<'_, Bn256>, - >(verifier_params, vk, strategy, instances, &mut transcript) - .is_ok() -} diff --git a/lightclient-circuits/src/witness/hashing.rs b/lightclient-circuits/src/witness/hashing.rs index f2f1b1fe..25599c8f 100644 --- a/lightclient-circuits/src/witness/hashing.rs +++ b/lightclient-circuits/src/witness/hashing.rs @@ -46,7 +46,7 @@ impl HashInput { let mut all = left .bytes .into_iter() - .chain(right.bytes.into_iter()) + .chain(right.bytes) .map(f) .collect_vec(); let remainer = all.split_off(left_size); diff --git a/lightclient-circuits/src/witness/sync.rs b/lightclient-circuits/src/witness/sync.rs index 575c2988..28dd5182 100644 --- a/lightclient-circuits/src/witness/sync.rs +++ b/lightclient-circuits/src/witness/sync.rs @@ -35,7 +35,8 @@ pub struct SyncStepArgs { impl Default for SyncStepArgs { fn default() -> Self { - let dummy_pk_bytes = hex::decode("f5f151e52f1e8a5b09e4c6f0b25fb13463d442709f21a84f98dcb76a7953aa5225c12e4dd524a95f9be8dfdfa0621c0252adea177adcce725f8b47d0b27370572ad6c5638122cab820103c9bcbb3239939de60b4814c117631d82963a7d7900a").unwrap(); + let dummy_pk_bytes = hex::decode("021c62a0dfdfe89b5fa924d54d2ec12552aa53796ab7dc984fa8219f7042d46334b15fb2f0c6e4095b8a1e2fe551f1f50a90d7a76329d83176114c81b460de399923b3cb9b3c1020b8ca228163c5d62a577073b2d0478b5f72cedc7a17eaad52").unwrap(); + let signature_compressed = hex::decode("aabe63f791d9d80aa5c5ff9a384be8ba8a61a66e9bc9e82b7f1774639b125de5de476b533b1b522e75d4bd93ad2a405a03f71fe3daf9cae3685a6b8dc9adf4b89403203ab0e081c694aa8665492a70464cdae666a168a5ea55237268cb5a2c46").unwrap(); let state_merkle_branch = iter::repeat(vec![0u8; 32]) .take(S::FINALIZED_HEADER_DEPTH) @@ -65,7 +66,7 @@ impl Default for SyncStepArgs { let finality_merkle_branch = vec![vec![0; 32]; S::FINALIZED_HEADER_DEPTH]; Self { - signature_compressed: hex::decode("462c5acb68722355eaa568a166e6da4c46702a496586aa94c681e0b03a200394b8f4adc98d6b5a68e3caf9dae31ff7035a402aad93bdd4752e521b3b536b47dee55d129b6374177f2be8c99b6ea6618abae84b389affc5a50ad8d991f763beaa").unwrap(), + signature_compressed, pubkeys_uncompressed: iter::repeat(dummy_pk_bytes) .take(S::SYNC_COMMITTEE_SIZE) .collect_vec(), diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index f574957d..c80799f7 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -10,6 +10,7 @@ use halo2_base::halo2_proofs::{ }; use itertools::Itertools; use light_client_verifier::ZiplineUpdateWitnessCapella; +use lightclient_circuits::LIMB_BITS; use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; use lightclient_circuits::gadget::crypto; use lightclient_circuits::sync_step_circuit::SyncStepCircuit; @@ -17,7 +18,6 @@ use lightclient_circuits::util::gen_srs; use lightclient_circuits::util::AppCircuit; use lightclient_circuits::util::Eth2ConfigPinning; use lightclient_circuits::util::Halo2ConfigPinning; -use lightclient_circuits::util::{full_prover, full_verifier}; use lightclient_circuits::witness::{CommitteeRotationArgs, SyncStepArgs}; use rstest::rstest; use snark_verifier_sdk::CircuitExt; @@ -172,21 +172,22 @@ fn to_sync_ciruit_witness< ..Default::default() }; - args.signature_compressed.reverse(); + // args.signature_compressed.reverse(); let pubkeys_uncompressed = zipline_witness .committee .pubkeys .iter() .map(|pk| { - let p = pk.decompressed_bytes(); - let mut x = p[0..48].to_vec(); - let mut y = p[48..96].to_vec(); - x.reverse(); - y.reverse(); - let mut res = vec![]; - res.append(&mut x); - res.append(&mut y); - res + // let p = pk.decompressed_bytes(); + // let mut x = p[0..48].to_vec(); + // let mut y = p[48..96].to_vec(); + // x.reverse(); + // y.reverse(); + // let mut res = vec![]; + // res.append(&mut x); + // res.append(&mut y); + // res + pk.decompressed_bytes() }) .collect_vec(); args.pubkeys_uncompressed = pubkeys_uncompressed; @@ -442,7 +443,7 @@ fn run_test_eth2_spec_mock(path: PathB .unwrap() }; - let sync_pi_commit = SyncStepCircuit::::instance_commitment(&sync_witness, todo!()); + let sync_pi_commit = SyncStepCircuit::::instance_commitment(&sync_witness, LIMB_BITS); let timer = start_timer!(|| "sync_step mock prover run"); let prover = @@ -469,20 +470,13 @@ fn test_eth2_spec_proofgen( &SyncStepArgs::::default(), ); - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - - let circuit = SyncStepCircuit::::create_circuit( - CircuitBuilderStage::Prover, - Some(pinning), + let _ = SyncStepCircuit::::gen_proof_shplonk( + ¶ms, + &pk, + "./config/sync_step.json", &witness, - K, ) - .unwrap(); - - let instances = circuit.instances(); - let proof = full_prover(¶ms, &pk, circuit, instances.clone()); - - assert!(full_verifier(¶ms, pk.get_vk(), proof, instances)) + .expect("proof generation & verification should not fail"); } #[rstest] diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index fe07883e..d8c25180 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -5,21 +5,14 @@ use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use jsonrpc_v2::{Error as JsonRpcError, Params}; use lightclient_circuits::{ - aggregation::AggregationConfigPinning, committee_update_circuit::CommitteeUpdateCircuit, - halo2_base::gates::circuit::CircuitBuilderStage, sync_step_circuit::SyncStepCircuit, - util::{gen_srs, AppCircuit, Halo2ConfigPinning}, + util::{gen_srs, AppCircuit}, }; use preprocessor::{fetch_rotation_args, fetch_step_args}; use serde::{Deserialize, Serialize}; -use snark_verifier_sdk::{ - evm::gen_evm_verifier_shplonk, - gen_pk, - halo2::{aggregation::AggregationCircuit, gen_snark_shplonk}, - CircuitExt, Snark, SHPLONK, -}; +use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, Snark}; use std::path::PathBuf; From 069948394ec6b7496f25b7402289a23a0f16f27d Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Tue, 7 Nov 2023 14:46:22 +0100 Subject: [PATCH 07/23] fix instance gen & refactor --- Cargo.toml | 57 ++-- .../tests/rotation_input_encoding.rs | 93 +++--- contract-tests/tests/step_input_encoding.rs | 58 ++-- eth-types/Cargo.toml | 4 +- lightclient-circuits/Cargo.toml | 7 +- .../src/committee_update_circuit.rs | 269 ++++++++---------- lightclient-circuits/src/lib.rs | 5 +- lightclient-circuits/tests/step.rs | 16 +- preprocessor/Cargo.toml | 1 - preprocessor/scripts/generateTestData.ts | 6 +- preprocessor/scripts/util.ts | 29 -- prover/src/cli.rs | 2 +- prover/src/main.rs | 2 - prover/src/rpc.rs | 7 +- test-utils/src/conversions.rs | 10 +- test-utils/src/lib.rs | 72 ++--- 16 files changed, 276 insertions(+), 362 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9fbd87c6..518540f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,47 +23,21 @@ rpath = false lto = "thin" incremental = true -[patch."https://github.com/axiom-crypto/halo2curves"] -# halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "bls12-381/hash_to_curve" } -halo2curves = { path = "../halo2curves" } [workspace.dependencies] lightclient-circuits = { path = "lightclient-circuits" } test-utils = { path = "test-utils" } -ethereum-consensus-types = { git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "27e8a01" } eth-types = { path = "eth-types" } contracts = { path = "contracts" } preprocessor = { path = "preprocessor" } -ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "adf1a0b14cef90b9536f28ef89da1fab316465e1" } -zipline-test-utils = { package = "test-utils", git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "27e8a01" } -light-client-verifier = { git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "27e8a01" } -sync-committee-primitives = { git = "https://github.com/polytope-labs/sync-committee-rs", version = "0.1.0" } -halo2curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.1" } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false, features = [ - "halo2-pse", - "display", -] } -snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "community-edition", default-features = false, features = [ - "display", - "loader_halo2", - "loader_evm", - "halo2-pse", -] } - -[patch."https://github.com/privacy-scaling-explorations/halo2curves"] -halo2curves = { git = "https://github.com/sygmaprotocol/halo2curves", branch = "dev/bls12_381" } -# halo2curves = { path = "../halo2curves" } # halo2 -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02", features = [ - "dev-graph", -] } -halo2curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.1" } halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false, features = [ "halo2-pse", "display", ] } halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } -poseidon = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } +halo2curves = { git = "https://github.com/axiom-crypto/halo2curves", version = "0.4.0" } + # verifier SDK snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "community-edition", default-features = false, features = [ @@ -81,6 +55,9 @@ snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git halo2_solidity_verifier = { git = "https://github.com/privacy-scaling-explorations/halo2-solidity-verifier", branch = "ac/initial-verifier-PR" } # ethereum types +ethereum-consensus-types = { git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "27e8a01" } +zipline-test-utils = { package = "test-utils", git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "27e8a01" } +light-client-verifier = { git = "ssh://git@github.com/sygmaprotocol/Zipline.git", rev = "27e8a01" } sync-committee-primitives = { git = "https://github.com/polytope-labs/sync-committee-rs", version = "0.1.0" } sync-committee-prover = { git = "https://github.com/polytope-labs/sync-committee-rs", version = "0.1.0", features = [ "testnet", @@ -104,13 +81,25 @@ serde_json = "1.0.78" log = "0.4.14" hex = "0.4" -[patch."https://github.com/privacy-scaling-explorations/halo2curves"] -halo2curves = { git = "https://github.com/sygmaprotocol/halo2curves", branch = "dev/bls12_381" } +[patch."https://github.com/axiom-crypto/halo2curves"] +# halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "bls12-381/hash_to_curve" } +halo2curves = { path = "../halo2curves" } + +# [patch."https://github.com/privacy-scaling-explorations/halo2curves"] +# halo2curves = { git = "https://github.com/sygmaprotocol/halo2curves", branch = "dev/bls12_381" } +# # halo2curves = { path = "../halo2curves" } + +# [patch."https://github.com/privacy-scaling-explorations/halo2curves"] +# halo2curves = { git = "https://github.com/sygmaprotocol/halo2curves", branch = "dev/bls12_381" } [patch."https://github.com/axiom-crypto/halo2-lib"] -halo2-base = { git = "https://github.com/timoftime/halo2-lib", rev = "95bf9a5ce6b62a3f28b163748a7494281d814496" } -halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", rev = "95bf9a5ce6b62a3f28b163748a7494281d814496" } -poseidon = { git = "https://github.com/timoftime/halo2-lib", rev = "95bf9a5ce6b62a3f28b163748a7494281d814496" } +halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ + "halo2-pse", + "display", +] } +halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false, features = [ + "halo2-pse", +] } [patch."https://github.com/axiom-crypto/snark-verifier.git"] # snark-verifier = { git = "https://github.com/timoftime/snark-verifier", branch = "timoftime/bump-revm", default-features = false } @@ -125,6 +114,6 @@ ssz-rs = { git = "https://github.com/polytope-labs/ssz-rs", branch = "main" } sync-committee-prover = { git = "https://github.com/timoftime/sync-committee-rs", branch = "dev/accept-ssz" } sync-committee-primitives = { git = "https://github.com/timoftime/sync-committee-rs", branch = "dev/accept-ssz" } -[patch."https://github.com/privacy-scaling-explorations/halo2curves"] +# [patch."https://github.com/privacy-scaling-explorations/halo2curves"] # # halo2curves = { git = "https://github.com/sygma-protocol/halo2curves", branch = "bls12-381/hash_to_curve" } # halo2curves = { path = "../halo2curves-pse" } diff --git a/contract-tests/tests/rotation_input_encoding.rs b/contract-tests/tests/rotation_input_encoding.rs index b16f1fe5..a6c564a0 100644 --- a/contract-tests/tests/rotation_input_encoding.rs +++ b/contract-tests/tests/rotation_input_encoding.rs @@ -1,3 +1,4 @@ +#![allow(incomplete_features)] #![feature(generic_const_exprs)] use std::path::PathBuf; @@ -5,10 +6,11 @@ use std::path::PathBuf; use contract_tests::make_client; use eth_types::Minimal; use ethers::contract::abigen; -use halo2curves::bn256::{self, Fr}; use itertools::Itertools; use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; +use lightclient_circuits::halo2_proofs::halo2curves::bn256::{self, Fr}; use lightclient_circuits::witness::CommitteeRotationArgs; +use lightclient_circuits::LIMB_BITS; use rstest::rstest; use ssz_rs::prelude::*; use ssz_rs::Merkleized; @@ -19,46 +21,6 @@ abigen!( "../contracts/out/RotateExternal.sol/RotateExternal.json" ); -#[rstest] -#[tokio::test] -async fn test_rotate_public_input_evm_equivalence( - #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] - #[exclude("deneb*")] - path: PathBuf, -) -> anyhow::Result<()> { - let (_, witness) = read_test_files_and_gen_witness(&path); - let instance = CommitteeUpdateCircuit::::instance(&witness); - let finalized_block_root = witness - .finalized_header - .clone() - .hash_tree_root() - .unwrap() - .as_bytes() - .try_into() - .unwrap(); - - let (_anvil_instance, ethclient) = make_client(); - let contract = RotateExternal::deploy(ethclient, ())?.send().await?; - - let result = contract - .to_public_inputs(RotateInput::from(witness), finalized_block_root) - .call() - .await?; - - // convert each of the returned values to a field element - let result_decoded: Vec<_> = result - .iter() - .map(|v| { - let mut b = [0_u8; 32]; - v.to_little_endian(&mut b); - bn256::Fr::from_bytes(&b).unwrap() - }) - .collect(); - - assert_eq!(result_decoded.len(), instance[0].len()); - assert_eq!(vec![result_decoded], instance); - Ok(()) -} // CommitteeRotationArgs type produced by abigen macro matches the solidity struct type impl From> for RotateInput @@ -71,10 +33,10 @@ where .pubkeys_compressed .iter() .cloned() - .map(|mut b| { - b.reverse(); - b - }) + // .map(|mut b| { + // b.reverse(); + // b + // }) .collect_vec(), ) .unwrap(); @@ -101,3 +63,44 @@ where } } } + +#[rstest] +#[tokio::test] +async fn test_rotate_public_input_evm_equivalence( + #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] + #[exclude("deneb*")] + path: PathBuf, +) -> anyhow::Result<()> { + let (_, witness) = read_test_files_and_gen_witness(&path); + let instance = CommitteeUpdateCircuit::::instance(&witness, LIMB_BITS); + let finalized_block_root = witness + .finalized_header + .clone() + .hash_tree_root() + .unwrap() + .as_bytes() + .try_into() + .unwrap(); + + let (_anvil_instance, ethclient) = make_client(); + let contract = RotateExternal::deploy(ethclient, ())?.send().await?; + + let result = contract + .to_public_inputs(RotateInput::from(witness), finalized_block_root) + .call() + .await?; + + // convert each of the returned values to a field element + let result_decoded: Vec<_> = result + .iter() + .map(|v| { + let mut b = [0_u8; 32]; + v.to_little_endian(&mut b); + bn256::Fr::from_bytes(&b).expect("bad bn256::Fr encoding") + }) + .collect(); + + assert_eq!(result_decoded.len(), instance[0].len()); + assert_eq!(vec![result_decoded], instance); + Ok(()) +} diff --git a/contract-tests/tests/step_input_encoding.rs b/contract-tests/tests/step_input_encoding.rs index bb3fdd4c..0973daaa 100644 --- a/contract-tests/tests/step_input_encoding.rs +++ b/contract-tests/tests/step_input_encoding.rs @@ -3,9 +3,9 @@ use std::path::PathBuf; use contract_tests::make_client; use eth_types::Minimal; use ethers::contract::abigen; -use halo2curves::bn256; -use lightclient_circuits::sync_step_circuit::SyncStepCircuit; +use lightclient_circuits::halo2_proofs::halo2curves::bn256; use lightclient_circuits::witness::SyncStepArgs; +use lightclient_circuits::{sync_step_circuit::SyncStepCircuit, LIMB_BITS}; use rstest::rstest; use ssz_rs::Merkleized; use test_utils::{ @@ -17,32 +17,6 @@ abigen!( "../contracts/out/SyncStepExternal.sol/SyncStepExternal.json" ); -#[rstest] -#[tokio::test] -async fn test_step_instance_commitment_evm_equivalence( - #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] - #[exclude("deneb*")] - path: PathBuf, -) -> anyhow::Result<()> { - let (witness, _) = read_test_files_and_gen_witness(&path); - let instance = SyncStepCircuit::::instance_commitment(&witness); - let poseidon_commitment_le = - poseidon_committee_commitment_from_uncompressed(&witness.pubkeys_uncompressed)?; - - let (_anvil_instance, ethclient) = make_client(); - let contract = SyncStepExternal::deploy(ethclient, ())?.send().await?; - - let result = contract - .to_input_commitment(SyncStepInput::from(witness), poseidon_commitment_le) - .call() - .await?; - let mut result_bytes = [0_u8; 32]; - result.to_little_endian(&mut result_bytes); - - assert_eq!(bn256::Fr::from_bytes(&result_bytes).unwrap(), instance); - Ok(()) -} - // SyncStepInput type produced by abigen macro matches the solidity struct type impl From> for SyncStepInput { fn from(args: SyncStepArgs) -> Self { @@ -66,9 +40,35 @@ impl From> for SyncStepInput { SyncStepInput { attested_slot: args.attested_header.slot, finalized_slot: args.finalized_header.slot, - participation: participation, + participation, finalized_header_root, execution_payload_root, } } } + +#[rstest] +#[tokio::test] +async fn test_step_instance_commitment_evm_equivalence( + #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] + #[exclude("deneb*")] + path: PathBuf, +) -> anyhow::Result<()> { + let (witness, _) = read_test_files_and_gen_witness(&path); + let instance = SyncStepCircuit::::instance_commitment(&witness, LIMB_BITS); + let poseidon_commitment_le = + poseidon_committee_commitment_from_uncompressed(&witness.pubkeys_uncompressed)?; + + let (_anvil_instance, ethclient) = make_client(); + let contract = SyncStepExternal::deploy(ethclient, ())?.send().await?; + + let result = contract + .to_input_commitment(SyncStepInput::from(witness), poseidon_commitment_le) + .call() + .await?; + let mut result_bytes = [0_u8; 32]; + result.to_little_endian(&mut result_bytes); + + assert_eq!(bn256::Fr::from_bytes(&result_bytes).unwrap(), instance); + Ok(()) +} diff --git a/eth-types/Cargo.toml b/eth-types/Cargo.toml index 7732a250..996b84db 100644 --- a/eth-types/Cargo.toml +++ b/eth-types/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" pasta_curves.workspace = true uint.workspace = true hex.workspace = true -halo2_proofs.workspace = true +halo2-base.workspace = true halo2-ecc.workspace = true serde.workspace = true serde_json.workspace = true @@ -21,4 +21,4 @@ subtle = "2.4" num = "0.4" num-bigint.workspace = true strum_macros = "0.24" -strum = "0.24" \ No newline at end of file +strum = "0.24" diff --git a/lightclient-circuits/Cargo.toml b/lightclient-circuits/Cargo.toml index 663aa18c..f31b0452 100644 --- a/lightclient-circuits/Cargo.toml +++ b/lightclient-circuits/Cargo.toml @@ -7,20 +7,22 @@ license = "MIT OR Apache-2.0" [dependencies] # halo2 -halo2_proofs.workspace = true halo2curves.workspace = true halo2-base.workspace = true halo2-ecc.workspace = true -poseidon.workspace = true + # verifier SDK snark-verifier.workspace = true snark-verifier-sdk.workspace = true + # crypto group.workspace = true num-bigint.workspace = true pasta_curves.workspace = true ff.workspace = true sha2.workspace = true +pse-poseidon = { git = "https://github.com/axiom-crypto/pse-poseidon.git" } + # ethereum sync-committee-primitives.workspace = true ssz-rs.workspace = true @@ -42,6 +44,7 @@ strum = "0.25" strum_macros = "0.25" rand = "0.8" lazy_static = "1.4" +getset = "0.1.2" [dev-dependencies] rstest = "0.18.2" diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index fd03498d..64264ca4 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -9,7 +9,8 @@ use crate::{ ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, sync_step_circuit::{clear_3_bits, to_bytes_le, truncate_sha256_into_single_elem}, util::{gen_pkey, AppCircuit, Challenges, CommonGateManager, Eth2ConfigPinning, IntoWitness}, - witness::{self, HashInput, HashInputChunk}, Eth2CircuitBuilder, LIMB_BITS, NUM_LIMBS, + witness::{self, HashInput, HashInputChunk}, + Eth2CircuitBuilder, LIMB_BITS, NUM_LIMBS, }; use eth_types::{Field, Spec}; use halo2_base::{ @@ -121,39 +122,6 @@ impl CommitteeUpdateCircuit { Ok(public_inputs) } - pub fn instance(args: &witness::CommitteeRotationArgs) -> Vec> - where - [(); { S::SYNC_COMMITTEE_SIZE }]:, - { - let pubkeys_x = args.pubkeys_compressed.iter().cloned().map(|mut bytes| { - bytes.reverse(); - bytes[47] &= 0b00011111; - bls12_381::Fq::from_bytes_le(&bytes) - }); - - let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x).unwrap(); - - let mut pk_vector: Vector, { S::SYNC_COMMITTEE_SIZE }> = args - .pubkeys_compressed - .iter() - .cloned() - .map(|v| v.try_into().unwrap()) - .collect_vec() - .try_into() - .unwrap(); - - let ssz_root = pk_vector.hash_tree_root().unwrap(); - - let finalized_header_root = args.finalized_header.clone().hash_tree_root().unwrap(); - - let instance_vec = iter::once(poseidon_commitment) - .chain(ssz_root.0.map(|b| bn256::Fr::from(b as u64))) - .chain(finalized_header_root.0.map(|b| bn256::Fr::from(b as u64))) - .collect(); - - vec![instance_vec] - } - fn decode_pubkeys_x( ctx: &mut Context, fp_chip: &FpChip<'_, F>, @@ -210,16 +178,20 @@ impl CommitteeUpdateCircuit { pub fn instance( args: &witness::CommitteeRotationArgs, limb_bits: usize, - ) -> Vec> { + ) -> Vec> + where + [(); { S::SYNC_COMMITTEE_SIZE }]:, + { let pubkeys_x = args.pubkeys_compressed.iter().cloned().map(|mut bytes| { - bytes[47] &= 0b11111000; + bytes.reverse(); + bytes[47] &= 0b00011111; bls12_381::Fq::from_bytes_le(&bytes) }); let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x, limb_bits).unwrap(); - let mut pk_vector: Vector, 512> = args + let mut pk_vector: Vector, { S::SYNC_COMMITTEE_SIZE }> = args .pubkeys_compressed .iter() .cloned() @@ -234,6 +206,7 @@ impl CommitteeUpdateCircuit { let instance_vec = iter::once(poseidon_commitment) .chain(ssz_root.0.map(|b| bn256::Fr::from(b as u64))) + .chain(finalized_header_root.0.map(|b| bn256::Fr::from(b as u64))) .collect(); vec![instance_vec] @@ -250,10 +223,9 @@ impl AppCircuit for CommitteeUpdateCircuit { witness: &witness::CommitteeRotationArgs, k: u32, ) -> Result, Error> { - let mut builder = - Eth2CircuitBuilder::>::from_stage(stage) - .use_k(k as usize) - .use_instance_columns(1); + let mut builder = Eth2CircuitBuilder::>::from_stage(stage) + .use_k(k as usize) + .use_instance_columns(1); let range = builder.range_chip(8); let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); @@ -388,10 +360,13 @@ mod tests { const K: u32 = 18; let params = gen_srs(K); + const PINNING_PATH: &str = "./config/committee_update_18.json"; + const PKEY_PATH: &str = "../build/committee_update_18.pkey"; + let pk = CommitteeUpdateCircuit::::read_or_create_pk( ¶ms, - "../build/committee_update.pkey", - "./config/committee_update.json", + PKEY_PATH, + PINNING_PATH, false, &CommitteeRotationArgs::::default(), ); @@ -401,7 +376,7 @@ mod tests { let circuit = CommitteeUpdateCircuit::::gen_proof_shplonk( ¶ms, &pk, - "./config/committee_update.json", + PINNING_PATH, &witness, ) .expect("proof generation & verification should not fail"); @@ -409,6 +384,8 @@ mod tests { #[test] fn test_circuit_aggregation_proofgen() { + const APP_PINNING_PATH: &str = "./config/committee_update_20.json"; + const APP_PK_PATH: &str = "../build/committee_update_20.pkey"; const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; const APP_K: u32 = 20; let params_app = gen_srs(APP_K); @@ -416,8 +393,8 @@ mod tests { const AGG_K: u32 = 22; let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( ¶ms_app, - "../build/committee_update.pkey", - "./config/committee_update.json", + APP_PK_PATH, + APP_PINNING_PATH, false, &CommitteeRotationArgs::::default(), ); @@ -447,15 +424,17 @@ mod tests { #[test] fn test_circuit_aggregation_evm() { - const AGG_CONFIG_PATH: &str = "./config/committee_update_a.json"; const APP_K: u32 = 21; + const APP_PINNING_PATH: &str = "./config/committee_update_21.json"; + const APP_PK_PATH: &str = "../build/committee_update_21.pkey"; + const AGG_CONFIG_PATH: &str = "./config/committee_update_a.json"; let params_app = gen_srs(APP_K); const AGG_K: u32 = 23; let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( ¶ms_app, - "../build/committee_update.pkey", - "./config/committee_update.json", + APP_PINNING_PATH, + APP_PINNING_PATH, false, &CommitteeRotationArgs::::default(), ); @@ -504,100 +483,100 @@ mod tests { evm_verify(deployment_code, instances, proof); } - #[test] - fn test_circuit_aggregation_2_evm() { - const K0: u32 = 20; - const K1: u32 = 24; - const K2: u32 = 24; - - const APP_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; - const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation_1.json"; - const AGG_FINAL_CONFIG_PATH: &str = "./config/committee_update_aggregation_2.json"; - - // Layer 0 snark gen - let l0_snark = { - let p0 = gen_srs(K0); - let pk_l0 = CommitteeUpdateCircuit::::read_or_create_pk( - &p0, - "../build/committee_update.pkey", - APP_CONFIG_PATH, - false, - &CommitteeRotationArgs::::default(), - ); - let witness = load_circuit_args(); - let snark = gen_application_snark(&p0, &pk_l0, &witness); - println!( - "L0 num instances: {:?}", - snark.instances.iter().map(|i| i.len()).collect_vec() - ); - println!("L0 snark size: {}", snark.proof.len()); - snark - }; - - // Layer 1 snark gen - let l1_snark = { - let p1 = gen_srs(K1); - let pk_l1 = AggregationCircuit::read_or_create_pk( - &p1, - "./build/l1_aggregation.pkey", - AGG_CONFIG_PATH, - false, - &vec![l0_snark.clone()], - ); - - let pinning = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); - let lookup_bits = K1 as usize - 1; - let circuit = AggregationCircuit::create_circuit( - CircuitBuilderStage::Prover, - Some(pinning), - &vec![l0_snark.clone()], - K1, - ) - .unwrap(); - - println!("L1 Prover num_instances: {:?}", circuit.num_instance()); - let snark = gen_snark_shplonk(&p1, &pk_l1, circuit, None::); - println!("L1 snark size: {}", snark.proof.len()); - - snark - }; - - // Layer 2 snark gen - let (proof, deployment_code, instances) = { - let p2 = gen_srs(K2); - let pk_l2 = AggregationCircuit::read_or_create_pk( - &p2, - "./build/l2_aggregation.pkey", - AGG_FINAL_CONFIG_PATH, - false, - &vec![l0_snark.clone()], - ); - let pinning = AggregationConfigPinning::from_path(AGG_FINAL_CONFIG_PATH); - - let mut circuit = AggregationCircuit::create_circuit( - CircuitBuilderStage::Prover, - Some(pinning), - &vec![l1_snark.clone()], - K2, - ) - .unwrap(); - let num_instances = circuit.num_instance(); - - let deployment_code = gen_evm_verifier_shplonk::( - &p2, - pk_l2.get_vk(), - vec![65], - Some(&PathBuf::from("contractyul")), - ); - let instances = circuit.instances(); - println!("L2 Prover num_instances: {:?}", num_instances); - - let proof = gen_evm_proof_shplonk(&p2, &pk_l2, circuit, instances.clone()); - println!("L2 proof size: {}", proof.len()); - println!("L2 Deployment Code Size: {}", deployment_code.len()); - (proof, deployment_code, instances) - }; - - evm_verify(deployment_code, instances, proof); - } + // #[test] + // fn test_circuit_aggregation_2_evm() { + // const K0: u32 = 20; + // const K1: u32 = 24; + // const K2: u32 = 24; + + // const APP_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; + // const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation_1.json"; + // const AGG_FINAL_CONFIG_PATH: &str = "./config/committee_update_aggregation_2.json"; + + // // Layer 0 snark gen + // let l0_snark = { + // let p0 = gen_srs(K0); + // let pk_l0 = CommitteeUpdateCircuit::::read_or_create_pk( + // &p0, + // "../build/committee_update.pkey", + // APP_CONFIG_PATH, + // false, + // &CommitteeRotationArgs::::default(), + // ); + // let witness = load_circuit_args(); + // let snark = gen_application_snark(&p0, &pk_l0, &witness); + // println!( + // "L0 num instances: {:?}", + // snark.instances.iter().map(|i| i.len()).collect_vec() + // ); + // println!("L0 snark size: {}", snark.proof.len()); + // snark + // }; + + // // Layer 1 snark gen + // let l1_snark = { + // let p1 = gen_srs(K1); + // let pk_l1 = AggregationCircuit::read_or_create_pk( + // &p1, + // "./build/l1_aggregation.pkey", + // AGG_CONFIG_PATH, + // false, + // &vec![l0_snark.clone()], + // ); + + // let pinning = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); + // let lookup_bits = K1 as usize - 1; + // let circuit = AggregationCircuit::create_circuit( + // CircuitBuilderStage::Prover, + // Some(pinning), + // &vec![l0_snark.clone()], + // K1, + // ) + // .unwrap(); + + // println!("L1 Prover num_instances: {:?}", circuit.num_instance()); + // let snark = gen_snark_shplonk(&p1, &pk_l1, circuit, None::); + // println!("L1 snark size: {}", snark.proof.len()); + + // snark + // }; + + // // Layer 2 snark gen + // let (proof, deployment_code, instances) = { + // let p2 = gen_srs(K2); + // let pk_l2 = AggregationCircuit::read_or_create_pk( + // &p2, + // "./build/l2_aggregation.pkey", + // AGG_FINAL_CONFIG_PATH, + // false, + // &vec![l0_snark.clone()], + // ); + // let pinning = AggregationConfigPinning::from_path(AGG_FINAL_CONFIG_PATH); + + // let mut circuit = AggregationCircuit::create_circuit( + // CircuitBuilderStage::Prover, + // Some(pinning), + // &vec![l1_snark.clone()], + // K2, + // ) + // .unwrap(); + // let num_instances = circuit.num_instance(); + + // let deployment_code = gen_evm_verifier_shplonk::( + // &p2, + // pk_l2.get_vk(), + // vec![65], + // Some(&PathBuf::from("contractyul")), + // ); + // let instances = circuit.instances(); + // println!("L2 Prover num_instances: {:?}", num_instances); + + // let proof = gen_evm_proof_shplonk(&p2, &pk_l2, circuit, instances.clone()); + // println!("L2 proof size: {}", proof.len()); + // println!("L2 Deployment Code Size: {}", deployment_code.len()); + // (proof, deployment_code, instances) + // }; + + // evm_verify(deployment_code, instances, proof); + // } } diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 61e8256e..6f912615 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -6,7 +6,7 @@ #![feature(trait_alias)] #![feature(generic_arg_infer)] #![feature(return_position_impl_trait_in_trait)] -#![allow(unused, clippy::uninlined_format_args, clippy::needless_range_loop)] +#![allow(unused, clippy::needless_range_loop)] pub mod gadget; pub mod util; pub mod witness; @@ -15,8 +15,7 @@ pub mod aggregation; pub mod committee_update_circuit; pub mod sync_step_circuit; -// pub mod builder; -mod poseidon; +pub mod poseidon; mod ssz_merkle; pub use halo2_base; diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index d26cda80..933d19c4 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -1,10 +1,9 @@ -#![feature(generic_const_exprs)] - use ark_std::{end_timer, start_timer}; use eth_types::Minimal; -use halo2_base::gates::builder::CircuitBuilderStage; -use halo2_proofs::dev::MockProver; -use halo2curves::bn256; +use halo2_base::gates::circuit::CircuitBuilderStage; +use halo2_base::halo2_proofs::dev::MockProver; +use halo2_base::halo2_proofs::halo2curves::bn256; +use lightclient_circuits::LIMB_BITS; use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; use lightclient_circuits::sync_step_circuit::SyncStepCircuit; use lightclient_circuits::util::gen_srs; @@ -56,7 +55,7 @@ fn run_test_eth2_spec_mock(path: PathB let prover = MockProver::::run( K_ROTATION, &rotation_circuit, - rotation_circuit.instances(), //CommitteeUpdateCircuit::::instance(rotation_witness.pubkeys_compressed), + CommitteeUpdateCircuit::::instance(&rotation_witness, LIMB_BITS), ) .unwrap(); prover.assert_satisfied_par(); @@ -74,7 +73,8 @@ fn run_test_eth2_spec_mock(path: PathB .unwrap() }; - let sync_pi_commit = SyncStepCircuit::::instance_commitment(&sync_witness, LIMB_BITS); + let sync_pi_commit = + SyncStepCircuit::::instance_commitment(&sync_witness, LIMB_BITS); let timer = start_timer!(|| "sync_step mock prover run"); let prover = @@ -101,7 +101,7 @@ fn test_eth2_spec_proofgen( &SyncStepArgs::::default(), ); - let _ = SyncStepCircuit::::gen_proof_shplonk( + let _ = SyncStepCircuit::::gen_proof_shplonk( ¶ms, &pk, "./config/sync_step.json", diff --git a/preprocessor/Cargo.toml b/preprocessor/Cargo.toml index 8feb3a00..40ce7990 100644 --- a/preprocessor/Cargo.toml +++ b/preprocessor/Cargo.toml @@ -25,7 +25,6 @@ eth-types.workspace = true lightclient-circuits.workspace = true [dev-dependencies] -halo2_proofs.workspace = true halo2-base.workspace = true snark-verifier-sdk.workspace = true ark-std.workspace = true diff --git a/preprocessor/scripts/generateTestData.ts b/preprocessor/scripts/generateTestData.ts index c322b018..add25bb8 100644 --- a/preprocessor/scripts/generateTestData.ts +++ b/preprocessor/scripts/generateTestData.ts @@ -4,7 +4,7 @@ import { ssz, } from "@lodestar/types" import { createProof, ProofType, SingleProof, createNodeFromProof } from "@chainsafe/persistent-merkle-tree"; -import { g1PointToLeBytes as g1PointToBytesLE, g2PointToLeBytes, serialize } from "./util"; +import { g1PointToLeBytes as g1PointToBytesLE, serialize } from "./util"; import { hexToBytes, bytesToHex } from "@noble/curves/abstract/utils"; import { ProjPointType } from "@noble/curves/abstract/weierstrass"; import { computeSigningRoot } from "@lodestar/state-transition"; @@ -37,7 +37,7 @@ let pubKeyPoints: ProjPointType[] = []; for (let i = 0; i < N_validators; i++) { let privKey = i < privKeyHexes.length ? hexToBytes(privKeyHexes[i]) : bls12_381.utils.randomPrivateKey(); let p = bls12_381.G1.ProjectivePoint.fromPrivateKey(privKey); - let pubkey = g1PointToBytesLE(p, true); + let pubkey = p.toRawBytes(true); beaconState.validators.push({ pubkey: pubkey, @@ -152,7 +152,7 @@ let aggSignature = bls12_381.aggregateSignatures(signatures); // assert signature is valid console.assert(bls12_381.verify(aggSignature, msgPoint, aggregatedPubKey)); -const syncSigBytes = g2PointToLeBytes(aggSignature, true); +const syncSigBytes = aggSignature.toRawBytes(true); const attestedBlockJson = ssz.phase0.BeaconBlockHeader.toJson(attestedBlock); //----------------- State tree -----------------// diff --git a/preprocessor/scripts/util.ts b/preprocessor/scripts/util.ts index 0813071d..7d55f67f 100644 --- a/preprocessor/scripts/util.ts +++ b/preprocessor/scripts/util.ts @@ -178,38 +178,9 @@ export function sortInOrderBitstrings(gindices: GindexBitstring[], bitLength: nu export function g1PointToLeBytes(p: ProjPointType, compressed: boolean): Uint8Array { return p.toRawBytes(compressed); - // let bytes = p.toRawBytes(compressed); - // bytes.reverse(); - // var bytesLe = new Uint8Array(compressed ? 48 : 96); - // if (compressed) { - // bytesLe = bytes; - // } else { - // bytesLe.set(bytes.slice(0, 48), 48); - // bytesLe.set(bytes.slice(48, 96), 0); - // } - - // return bytesLe; } export type Fp2 = { c0: bigint; c1: bigint }; -export function g2PointToLeBytes(p: ProjPointType, compressed: boolean): Uint8Array { - return p.toRawBytes(compressed); - // let bytes = p.toRawBytes(compressed); - // bytes.reverse(); - // var bytesLe = new Uint8Array(compressed ? 96 : 192); - // if (compressed) { - // // bytesLe.set(bytes.slice(0, 48), 48); - // // bytesLe.set(bytes.slice(48, 96), 0); - // bytesLe = bytes; - // } else { - // bytesLe.set(bytes.slice(0, 48), 144); - // bytesLe.set(bytes.slice(48, 96), 96); - // bytesLe.set(bytes.slice(96, 144), 48); - // bytesLe.set(bytes.slice(144, 192), 0); - // } - - // return bytesLe; -} export function formatHex(str: string): string { diff --git a/prover/src/cli.rs b/prover/src/cli.rs index d162a7f9..445e377a 100644 --- a/prover/src/cli.rs +++ b/prover/src/cli.rs @@ -2,9 +2,9 @@ use crate::args::{Args, Out, Proof}; use ethers::abi::Address; use ethers::providers::{Http, Provider}; -use halo2curves::bn256::{Bn256, Fr, G1Affine}; use itertools::Itertools; use lightclient_circuits::{ + halo2_proofs::halo2curves::bn256::{Bn256, Fr, G1Affine}, committee_update_circuit::CommitteeUpdateCircuit, sync_step_circuit::SyncStepCircuit, util::{gen_srs, AppCircuit}, diff --git a/prover/src/main.rs b/prover/src/main.rs index b37cd62e..af07cdef 100644 --- a/prover/src/main.rs +++ b/prover/src/main.rs @@ -8,8 +8,6 @@ pub mod rpc_client; use args::Cli; use axum::{response::IntoResponse, routing::post, Router}; use cli_batteries::version; -use ethers::prelude::*; -use lightclient_circuits::halo2_proofs::halo2curves::bn256::{Bn256, Fr, G1Affine}; use http::StatusCode; use jsonrpc_v2::{MapRouter as JsonRpcMapRouter, Server as JsonRpcServer}; diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index df24f563..2fbefcee 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -12,12 +12,7 @@ use lightclient_circuits::{ use preprocessor::{fetch_rotation_args, fetch_step_args}; use jsonrpc_v2::{MapRouter as JsonRpcMapRouter, Server as JsonRpcServer}; -use snark_verifier::loader::halo2::halo2_ecc::halo2_base::gates::builder::CircuitBuilderStage; -use snark_verifier_sdk::{ - gen_pk, - halo2::{aggregation::AggregationCircuit, gen_snark_shplonk}, - CircuitExt, Snark, SHPLONK, -}; +use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, Snark}; use std::path::PathBuf; use crate::rpc_api::{ diff --git a/test-utils/src/conversions.rs b/test-utils/src/conversions.rs index d2fef8d1..35cc99e1 100644 --- a/test-utils/src/conversions.rs +++ b/test-utils/src/conversions.rs @@ -25,7 +25,7 @@ pub fn sync_input_from_args(args: SyncStepArgs) -> SyncStepInput { attested_slot: args.attested_header.slot, finalized_slot: args.finalized_header.slot, - participation: participation, + participation, finalized_header_root, execution_payload_root, } @@ -42,10 +42,10 @@ where .pubkeys_compressed .iter() .cloned() - .map(|mut b| { - b.reverse(); - b - }) + // .map(|mut b| { + // b.reverse(); + // b + // }) .collect_vec(), ) .unwrap(); diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index 339c3497..85f496b2 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -1,34 +1,34 @@ +#![allow(incomplete_features)] #![feature(generic_const_exprs)] +use crate::execution_payload_header::ExecutionPayloadHeader; +use crate::test_types::{ByteVector, TestMeta, TestStep}; use eth_types::Minimal; use ethereum_consensus_types::presets::minimal::{LightClientBootstrap, LightClientUpdateCapella}; use ethereum_consensus_types::signing::{compute_domain, DomainType}; use ethereum_consensus_types::{ForkData, Root}; -use halo2_base::safe_types::ScalarField; use halo2curves::bls12_381; -use halo2curves::bn256::{self, Fr}; use halo2curves::group::UncompressedEncoding; use itertools::Itertools; use light_client_verifier::ZiplineUpdateWitnessCapella; use lightclient_circuits::gadget::crypto; +use lightclient_circuits::halo2_proofs::halo2curves::bn256::{self, Fr}; use lightclient_circuits::poseidon::fq_array_poseidon_native; use lightclient_circuits::witness::{CommitteeRotationArgs, SyncStepArgs}; +use lightclient_circuits::LIMB_BITS; use ssz_rs::prelude::*; use ssz_rs::Merkleized; -use std::path::PathBuf; +use std::path::Path; use sync_committee_primitives::consensus_types::BeaconBlockHeader; use zipline_test_utils::{load_snappy_ssz, load_yaml}; -use crate::execution_payload_header::ExecutionPayloadHeader; -use crate::test_types::{ByteVector, TestMeta, TestStep}; - +pub mod conversions; mod execution_payload_header; mod test_types; -pub mod conversions; // loads the boostrap on the path and return the initial sync committee poseidon and sync period pub fn get_initial_sync_committee_poseidon( - path: &PathBuf, + path: &Path, ) -> anyhow::Result<(usize, [u8; 32])> { let bootstrap: LightClientBootstrap = load_snappy_ssz(path.join("bootstrap.ssz_snappy").to_str().unwrap()).unwrap(); @@ -36,17 +36,7 @@ pub fn get_initial_sync_committee_poseidon Root { +pub fn validators_root_from_test_path(path: &Path) -> Root { let meta: TestMeta = load_yaml(path.join("meta.yaml").to_str().unwrap()); Root::try_from( hex::decode(meta.genesis_validators_root.trim_start_matches("0x")) @@ -67,15 +57,12 @@ pub fn validators_root_from_test_path(path: &PathBuf) -> Root { // Load the updates for a given test and only includes the first sequence of steps that Spectre can perform // e.g. the the steps are cut at the first `ForceUpdate` step pub fn valid_updates_from_test_path( - path: &PathBuf, + path: &Path, ) -> Vec> { let steps: Vec = load_yaml(path.join("steps.yaml").to_str().unwrap()); let updates = steps .iter() - .take_while(|step| match step { - TestStep::ProcessUpdate { .. } => true, - _ => false, - }) + .take_while(|step| matches!(step, TestStep::ProcessUpdate { .. })) .filter_map(|step| match step { TestStep::ProcessUpdate { update, .. } => { let update: LightClientUpdateCapella = load_snappy_ssz( @@ -93,7 +80,7 @@ pub fn valid_updates_from_test_path( } pub fn read_test_files_and_gen_witness( - path: &PathBuf, + path: &Path, ) -> (SyncStepArgs, CommitteeRotationArgs) { let bootstrap: LightClientBootstrap = load_snappy_ssz(path.join("bootstrap.ssz_snappy").to_str().unwrap()).unwrap(); @@ -135,15 +122,15 @@ pub fn read_test_files_and_gen_witness( .map(|pk| pk.to_bytes().to_vec()) .collect_vec(), randomness: crypto::constant_randomness(), - _spec: Default::default(), finalized_header: sync_wit.attested_header.clone(), sync_committee_branch, + _spec: Default::default(), }; (sync_wit, rotation_wit) } pub fn poseidon_committee_commitment_from_uncompressed( - pubkeys_uncompressed: &Vec>, + pubkeys_uncompressed: &[Vec], ) -> anyhow::Result<[u8; 32]> { let pubkey_affines = pubkeys_uncompressed .iter() @@ -156,19 +143,21 @@ pub fn poseidon_committee_commitment_from_uncompressed( }) .collect_vec(); let poseidon_commitment = - fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x)).unwrap(); - Ok(poseidon_commitment.to_bytes_le().try_into().unwrap()) + fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x), LIMB_BITS) + .unwrap(); + Ok(poseidon_commitment.to_bytes()) } pub fn poseidon_committee_commitment_from_compressed( - pubkeys_compressed: &Vec>, + pubkeys_compressed: &[Vec], ) -> anyhow::Result<[u8; 32]> { let pubkeys_x = pubkeys_compressed.iter().cloned().map(|mut bytes| { - bytes[47] &= 0b00011111; - bls12_381::Fq::from_bytes_le(&bytes) + bytes[0] &= 0b00011111; + bls12_381::Fq::from_bytes_be(&bytes.try_into().unwrap()) + .expect("bad bls12_381::Fq encoding") }); - let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x).unwrap(); - Ok(poseidon_commitment.to_bytes_le().try_into().unwrap()) + let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x, LIMB_BITS).unwrap(); + Ok(poseidon_commitment.to_bytes()) } fn to_sync_ciruit_witness< @@ -201,22 +190,11 @@ fn to_sync_ciruit_witness< ..Default::default() }; - args.signature_compressed.reverse(); let pubkeys_uncompressed = zipline_witness .committee .pubkeys .iter() - .map(|pk| { - let p = pk.decompressed_bytes(); - let mut x = p[0..48].to_vec(); - let mut y = p[48..96].to_vec(); - x.reverse(); - y.reverse(); - let mut res = vec![]; - res.append(&mut x); - res.append(&mut y); - res - }) + .map(|pk| pk.decompressed_bytes()) .collect_vec(); args.pubkeys_uncompressed = pubkeys_uncompressed; args.pariticipation_bits = zipline_witness From f13d855fd32598cdd3fd73d283117697379d5b66 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Tue, 7 Nov 2023 15:23:20 +0100 Subject: [PATCH 08/23] fix prover rpc --- Cargo.toml | 10 ---------- justfile | 10 +++++----- prover/src/rpc.rs | 4 ++-- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 518540f2..b58cb21c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,12 +85,6 @@ hex = "0.4" # halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "bls12-381/hash_to_curve" } halo2curves = { path = "../halo2curves" } -# [patch."https://github.com/privacy-scaling-explorations/halo2curves"] -# halo2curves = { git = "https://github.com/sygmaprotocol/halo2curves", branch = "dev/bls12_381" } -# # halo2curves = { path = "../halo2curves" } - -# [patch."https://github.com/privacy-scaling-explorations/halo2curves"] -# halo2curves = { git = "https://github.com/sygmaprotocol/halo2curves", branch = "dev/bls12_381" } [patch."https://github.com/axiom-crypto/halo2-lib"] halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ @@ -113,7 +107,3 @@ ssz-rs = { git = "https://github.com/polytope-labs/ssz-rs", branch = "main" } [patch."https://github.com/polytope-labs/sync-committee-rs"] sync-committee-prover = { git = "https://github.com/timoftime/sync-committee-rs", branch = "dev/accept-ssz" } sync-committee-primitives = { git = "https://github.com/timoftime/sync-committee-rs", branch = "dev/accept-ssz" } - -# [patch."https://github.com/privacy-scaling-explorations/halo2curves"] -# # halo2curves = { git = "https://github.com/sygma-protocol/halo2curves", branch = "bls12-381/hash_to_curve" } -# halo2curves = { path = "../halo2curves-pse" } diff --git a/justfile b/justfile index 9ca27712..6c1060df 100644 --- a/justfile +++ b/justfile @@ -11,19 +11,19 @@ lint: fmt cargo clippy --all-targets --all-features --workspace setup-step-circuit: - cargo run -r -- sync-step -c ./lightclient-circuits/config/sync_step.json -o artifacts -k 22 + cargo run -r -- circuit sync-step -c ./lightclient-circuits/config/sync_step.json -o artifacts -k 22 setup-rotation-circuit: - cargo run -r -- committee-update -c ./lightclient-circuits/config/committee_update.json -o artifacts -k 18 + cargo run -r -- circuit committee-update -c ./lightclient-circuits/config/committee_update.json -o artifacts -k 18 # TODO: generate committee-update snark - cargo run -r -- aggregation -c ./lightclient-circuits/config/aggregation.json --app-pk-path \ + cargo run -r -- circuit aggregation -c ./lightclient-circuits/config/aggregation.json --app-pk-path \ ./build/committee_update.pkey --app-config-path ./lightclient-circuits/config/committee_update.json -i ./rotation -o artifacts -k 22 gen-step-evm-verifier: - cargo run -r -- sync-step -c ./lightclient-circuits/config/sync_step.json -o evm-verifier ./contracts/snark-verifiers/sync_step.yul + cargo run -r -- circuit sync-step -c ./lightclient-circuits/config/sync_step.json -o evm-verifier ./contracts/snark-verifiers/sync_step.yul gen-rotation-evm-verifier: - cargo run -r -- aggregation -c ./lightclient-circuits/config/aggregation.json --app-pk-path ./build/committee_update.pkey --app-config-path ./lightclient-circuits/config/committee_update.json -i ./rotation -o evm-verifier ./contracts/snark-verifiers/committee_update_aggregated.yul + cargo run -r -- circuit aggregation -c ./lightclient-circuits/config/aggregation.json --app-pk-path ./build/committee_update.pkey --app-config-path ./lightclient-circuits/config/committee_update.json -i ./rotation -o evm-verifier ./contracts/snark-verifiers/committee_update_aggregated.yul build-contracts: cd contracts && forge build diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index 2fbefcee..6e77a96d 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -135,14 +135,14 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_handler( let pk_l2 = AggregationCircuit::read_pk( &p2, "./build/committee_update_aggregation_l2.pkey", - &vec![l0_snark.clone()], + &vec![l1_snark.clone()], ); AggregationCircuit::gen_evm_proof_shplonk( &p2, &pk_l2, agg_l2_config_path, None, - &vec![l0_snark.clone()], + &vec![l1_snark.clone()], ) .map_err(JsonRpcError::internal)? }; From 472824a59be435bf798c3ed8908a257c4fdc6de1 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 8 Nov 2023 15:37:09 +0100 Subject: [PATCH 09/23] fix some tests --- .../config/committee_update_20.json | 23 +++ .../config/committee_update_aggregation.json | 21 +++ lightclient-circuits/src/aggregation.rs | 28 +-- lightclient-circuits/src/builder.rs | 161 ------------------ .../src/committee_update_circuit.rs | 3 +- 5 files changed, 63 insertions(+), 173 deletions(-) create mode 100644 lightclient-circuits/config/committee_update_20.json create mode 100644 lightclient-circuits/config/committee_update_aggregation.json delete mode 100644 lightclient-circuits/src/builder.rs diff --git a/lightclient-circuits/config/committee_update_20.json b/lightclient-circuits/config/committee_update_20.json new file mode 100644 index 00000000..e0ff3c54 --- /dev/null +++ b/lightclient-circuits/config/committee_update_20.json @@ -0,0 +1,23 @@ +{ + "params": { + "k": 20, + "num_advice_per_phase": [ + 4 + ], + "num_fixed": 1, + "num_lookup_advice_per_phase": [ + 1, + 0, + 0 + ], + "lookup_bits": 8, + "num_instance_columns": 1 + }, + "break_points": [ + [ + 1048564, + 1048566, + 1048565 + ] + ] +} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_aggregation.json b/lightclient-circuits/config/committee_update_aggregation.json new file mode 100644 index 00000000..c2ab190d --- /dev/null +++ b/lightclient-circuits/config/committee_update_aggregation.json @@ -0,0 +1,21 @@ +{ + "params": { + "degree": 22, + "num_advice": 9, + "num_lookup_advice": 2, + "num_fixed": 1, + "lookup_bits": 8 + }, + "break_points": [ + [ + 4194292, + 4194294, + 4194292, + 4194293, + 4194293, + 4194293, + 4194293, + 4194294 + ] + ] +} \ No newline at end of file diff --git a/lightclient-circuits/src/aggregation.rs b/lightclient-circuits/src/aggregation.rs index 29dfd74b..408cdf8e 100644 --- a/lightclient-circuits/src/aggregation.rs +++ b/lightclient-circuits/src/aggregation.rs @@ -44,7 +44,7 @@ impl Halo2ConfigPinning for AggregationConfigPinning { fn set_var(&self) { set_var( - "FLEX_GATE_CONFIG_PARAMS", + "AGG_CONFIG_PARAMS", serde_json::to_string(&self.params).unwrap(), ); set_var("LOOKUP_BITS", (self.params.degree - 1).to_string()); @@ -56,7 +56,7 @@ impl Halo2ConfigPinning for AggregationConfigPinning { fn from_var(break_points: MultiPhaseThreadBreakPoints) -> Self { let params: AggregationConfigParams = - serde_json::from_str(&var("AGGR_CONFIG_PARAMS").unwrap()).unwrap(); + serde_json::from_str(&var("AGG_CONFIG_PARAMS").unwrap()).unwrap(); Self { params, break_points, @@ -87,28 +87,36 @@ impl AppCircuit for AggregationCircuit { snark: &Self::Witness, k: u32, ) -> Result, Error> { - let lookup_bits = k as usize - 1; + // let lookup_bits = k as usize - 1; let params = gen_srs(k); - let circuit_params = pinning.map_or(AggregationConfigParams{ - degree: k, - ..Default::default() - }, |p| p.params); + let circuit_params = pinning.clone().map_or( + AggregationConfigParams { + degree: k, + lookup_bits: 8, + ..Default::default() + }, + |p| p.params, + ); let mut circuit = AggregationCircuit::new::( stage, circuit_params, ¶ms, snark.clone(), Default::default(), - ); + ); match stage { CircuitBuilderStage::Prover => { circuit.expose_previous_instances(false); + circuit.set_params(circuit_params); + circuit.set_break_points(pinning.map_or(vec![], |p| p.break_points)); } _ => { circuit.expose_previous_instances(false); - circuit.calculate_params(Some(10)); - set_var("LOOKUP_BITS", lookup_bits.to_string()); + set_var( + "AGG_CONFIG_PARAMS", + serde_json::to_string(&circuit.calculate_params(Some(10))).unwrap(), + ); } }; diff --git a/lightclient-circuits/src/builder.rs b/lightclient-circuits/src/builder.rs deleted file mode 100644 index d6530a17..00000000 --- a/lightclient-circuits/src/builder.rs +++ /dev/null @@ -1,161 +0,0 @@ -use eth_types::Field; -use halo2_base::{ - gates::{CircuitBuilderStage, FlexGateConfigParams, MultiPhaseThreadBreakPoints}, - AssignedValue, - halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - plonk::{Circuit, Column, ConstraintSystem, Error, Instance}, - } -}; -use log::debug; - -use crate::{ - gadget::crypto::{SHAConfig, ShaCircuitBuilder, ShaThreadBuilder}, - util::{Eth2ConfigPinning, PinnableCircuit, ThreadBuilderBase, ThreadBuilderConfigBase}, -}; - -#[derive(Clone, Debug)] -/// Config shared for block header and storage proof circuits -pub struct Eth2Config> { - sha: SHAConfig, - pub instance: Column, -} - -/// This is an extension of [`ShaCircuitBuilder`] that adds support for public instances (aka public inputs+outputs) -pub struct Eth2CircuitBuilder> { - pub inner: ShaCircuitBuilder, - pub assigned_instances: Vec>, -} - -impl> Eth2CircuitBuilder { - pub fn new( - assigned_instances: Vec>, - builder: ShaCircuitBuilder, - ) -> Self { - Self { - assigned_instances, - inner: builder, - } - } - - pub fn from_stage( - assigned_instances: Vec>, - builder: ThreadBuilder, - break_points: Option, - stage: CircuitBuilderStage, - ) -> Self { - Self::new( - assigned_instances, - ShaCircuitBuilder::from_stage(builder, break_points, stage), - ) - } - - /// Creates a new [Eth2CircuitBuilder] with `use_unknown` of [ThreadBuilder] set to true. - pub fn keygen(assigned_instances: Vec>, builder: ThreadBuilder) -> Self { - Self { - assigned_instances, - inner: ShaCircuitBuilder::keygen(builder), - } - } - - /// Creates a new [Eth2CircuitBuilder] with `use_unknown` of [ThreadBuilder] set to false. - pub fn mock(assigned_instances: Vec>, builder: ThreadBuilder) -> Self { - Self { - assigned_instances, - inner: ShaCircuitBuilder::mock(builder), - } - } - - /// Creates a new [Eth2CircuitBuilder]. - pub fn prover( - assigned_instances: Vec>, - builder: ThreadBuilder, - break_points: MultiPhaseThreadBreakPoints, - ) -> Self { - Self { - assigned_instances, - inner: ShaCircuitBuilder::prover(builder, break_points), - } - } - - pub fn config(&self, k: usize, minimum_rows: Option) -> FlexGateConfigParams { - self.inner.config(k, minimum_rows) - } - - pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { - self.inner.break_points.borrow().clone() - } - - pub fn instance_count(&self) -> usize { - self.assigned_instances.len() - } - - pub fn instance(&self) -> Vec { - self.assigned_instances.iter().map(|v| *v.value()).collect() - } -} - -impl> Circuit - for Eth2CircuitBuilder -{ - type Config = Eth2Config; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - unimplemented!() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let sha = ShaCircuitBuilder::::configure(meta); - let instance = meta.instance_column(); - meta.enable_equality(instance); - - Eth2Config { sha, instance } - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // we later `take` the builder, so we need to save this value - let witness_gen_only = self.inner.builder.borrow().witness_gen_only(); - - let assigned_advices = self.inner.sub_synthesize(&config.sha, &mut layouter)?; - - if !witness_gen_only { - // expose public instances - let mut layouter = layouter.namespace(|| "expose"); - for (i, instance) in self.assigned_instances.iter().enumerate() { - let cell = instance.cell.unwrap(); - let (cell, _) = assigned_advices - .get(&(cell.context_id, cell.offset)) - .expect("instance not assigned"); - layouter.constrain_instance(*cell, config.instance, i); - } - } - Ok(()) - } -} - -impl> snark_verifier_sdk::CircuitExt - for Eth2CircuitBuilder -{ - fn num_instance(&self) -> Vec { - vec![self.instance_count()] - } - - fn instances(&self) -> Vec> { - vec![self.instance()] - } -} - -impl> PinnableCircuit - for Eth2CircuitBuilder -{ - type Pinning = Eth2ConfigPinning; - - fn break_points(&self) -> MultiPhaseThreadBreakPoints { - self.inner.break_points.borrow().clone() - } -} diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 64264ca4..6b7ab3b0 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -403,11 +403,10 @@ mod tests { let params = gen_srs(AGG_K); println!("agg_params k: {:?}", params.k()); - let lookup_bits = params.k() as usize - 1; let pk = AggregationCircuit::read_or_create_pk( ¶ms, - "../build/aggregation.pkey", + "../build/committee_update_aggregation_22.pkey", AGG_CONFIG_PATH, false, &vec![snark.clone()], From 8c5474cd9ac057ebf4bdf663bd0b246722a75af5 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 8 Nov 2023 20:35:59 +0100 Subject: [PATCH 10/23] switch to remote deps --- Cargo.toml | 23 ++++++++++++------- lightclient-circuits/src/sync_step_circuit.rs | 5 ---- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b58cb21c..64df0a1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,24 +82,31 @@ log = "0.4.14" hex = "0.4" [patch."https://github.com/axiom-crypto/halo2curves"] -# halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "bls12-381/hash_to_curve" } -halo2curves = { path = "../halo2curves" } +halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "support_bls12-381" } +# halo2curves = { path = "../halo2curves" } [patch."https://github.com/axiom-crypto/halo2-lib"] -halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ +halo2-base = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ "halo2-pse", "display", ] } -halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false, features = [ +halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ "halo2-pse", ] } +# halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ +# "halo2-pse", +# "display", +# ] } +# halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false, features = [ +# "halo2-pse", +# ] } [patch."https://github.com/axiom-crypto/snark-verifier.git"] -# snark-verifier = { git = "https://github.com/timoftime/snark-verifier", branch = "timoftime/bump-revm", default-features = false } -# snark-verifier-sdk = { git = "https://github.com/timoftime/snark-verifier", branch = "timoftime/bump-revm", default-features = false } -snark-verifier = { path = "../snark-verifier/snark-verifier" } -snark-verifier-sdk = { path = "../snark-verifier/snark-verifier-sdk" } +snark-verifier = { git = "https://github.com/timoftime/snark-verifier", branch = "halo2-pse-fix", default-features = false } +snark-verifier-sdk = { git = "https://github.com/timoftime/snark-verifier", branch = "halo2-pse-fix", default-features = false } +# snark-verifier = { path = "../snark-verifier/snark-verifier" } +# snark-verifier-sdk = { path = "../snark-verifier/snark-verifier-sdk" } [patch."https://github.com/ralexstokes/ssz-rs"] ssz-rs = { git = "https://github.com/polytope-labs/ssz-rs", branch = "main" } diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 424d3cc8..1d4a257d 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -121,11 +121,6 @@ impl SyncStepCircuit { assigned_affines.iter().map(|p| &p.x), )?; - let fp12_one = { - use halo2curves::ff::Field; - fp12_chip.load_constant(builder.main(), Fq12::ONE) - }; - // Verify attestted header let attested_slot_bytes: HashInputChunk<_> = args.attested_header.slot.into_witness(); let attested_header_state_root = args From c6f1d8554de6b0a89f67fe1eeba8293264a4e659 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 22 Nov 2023 15:28:19 +0100 Subject: [PATCH 11/23] rename circuit files --- Cargo.toml | 3 +++ .../tests/rotation_input_encoding.rs | 2 +- contract-tests/tests/step_input_encoding.rs | 4 +-- lightclient-circuits/src/lib.rs | 4 +-- ..._update_circuit.rs => rotation_circuit.rs} | 11 ++++---- .../{sync_step_circuit.rs => step_circuit.rs} | 27 +++++++++---------- lightclient-circuits/tests/step.rs | 18 ++++++------- preprocessor/src/rotation.rs | 2 +- preprocessor/src/sync.rs | 8 +++--- prover/src/cli.rs | 8 +++--- prover/src/rpc.rs | 10 +++---- 11 files changed, 48 insertions(+), 49 deletions(-) rename lightclient-circuits/src/{committee_update_circuit.rs => rotation_circuit.rs} (99%) rename lightclient-circuits/src/{sync_step_circuit.rs => step_circuit.rs} (95%) diff --git a/Cargo.toml b/Cargo.toml index 64df0a1f..dc991a88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ preprocessor = { path = "preprocessor" } halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false, features = [ "halo2-pse", "display", + "jemallocator" ] } halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } halo2curves = { git = "https://github.com/axiom-crypto/halo2curves", version = "0.4.0" } @@ -90,9 +91,11 @@ halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "supp halo2-base = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ "halo2-pse", "display", + "jemallocator" ] } halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ "halo2-pse", + "jemallocator" ] } # halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ # "halo2-pse", diff --git a/contract-tests/tests/rotation_input_encoding.rs b/contract-tests/tests/rotation_input_encoding.rs index a6c564a0..a97a6961 100644 --- a/contract-tests/tests/rotation_input_encoding.rs +++ b/contract-tests/tests/rotation_input_encoding.rs @@ -7,7 +7,7 @@ use contract_tests::make_client; use eth_types::Minimal; use ethers::contract::abigen; use itertools::Itertools; -use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; +use lightclient_circuits::rotation_circuit::CommitteeUpdateCircuit; use lightclient_circuits::halo2_proofs::halo2curves::bn256::{self, Fr}; use lightclient_circuits::witness::CommitteeRotationArgs; use lightclient_circuits::LIMB_BITS; diff --git a/contract-tests/tests/step_input_encoding.rs b/contract-tests/tests/step_input_encoding.rs index 0973daaa..9237c539 100644 --- a/contract-tests/tests/step_input_encoding.rs +++ b/contract-tests/tests/step_input_encoding.rs @@ -5,7 +5,7 @@ use eth_types::Minimal; use ethers::contract::abigen; use lightclient_circuits::halo2_proofs::halo2curves::bn256; use lightclient_circuits::witness::SyncStepArgs; -use lightclient_circuits::{sync_step_circuit::SyncStepCircuit, LIMB_BITS}; +use lightclient_circuits::{step_circuit::StepCircuit, LIMB_BITS}; use rstest::rstest; use ssz_rs::Merkleized; use test_utils::{ @@ -55,7 +55,7 @@ async fn test_step_instance_commitment_evm_equivalence( path: PathBuf, ) -> anyhow::Result<()> { let (witness, _) = read_test_files_and_gen_witness(&path); - let instance = SyncStepCircuit::::instance_commitment(&witness, LIMB_BITS); + let instance = StepCircuit::::instance_commitment(&witness, LIMB_BITS); let poseidon_commitment_le = poseidon_committee_commitment_from_uncompressed(&witness.pubkeys_uncompressed)?; diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 6f912615..0889c55c 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -12,8 +12,8 @@ pub mod util; pub mod witness; pub mod aggregation; -pub mod committee_update_circuit; -pub mod sync_step_circuit; +pub mod rotation_circuit; +pub mod step_circuit; pub mod poseidon; mod ssz_merkle; diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/rotation_circuit.rs similarity index 99% rename from lightclient-circuits/src/committee_update_circuit.rs rename to lightclient-circuits/src/rotation_circuit.rs index 6b7ab3b0..9457a5a9 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/rotation_circuit.rs @@ -1,5 +1,4 @@ use std::{env::var, iter, marker::PhantomData, vec}; - use crate::{ gadget::crypto::{ calculate_ysquared, G1Chip, G1Point, G2Chip, G2Point, HashInstructions, Sha256ChipWide, @@ -7,7 +6,7 @@ use crate::{ }, poseidon::{fq_array_poseidon, fq_array_poseidon_native, poseidon_sponge}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, - sync_step_circuit::{clear_3_bits, to_bytes_le, truncate_sha256_into_single_elem}, + step_circuit::{clear_3_bits, to_bytes_le, truncate_sha256_into_single_elem}, util::{gen_pkey, AppCircuit, Challenges, CommonGateManager, Eth2ConfigPinning, IntoWitness}, witness::{self, HashInput, HashInputChunk}, Eth2CircuitBuilder, LIMB_BITS, NUM_LIMBS, @@ -36,7 +35,6 @@ use halo2_ecc::{ }; use halo2curves::bls12_381::{self, Fq, Fq12, G1Affine, G2Affine, G2Prepared, G1, G2}; use itertools::Itertools; -use lazy_static::__Deref; use num_bigint::BigUint; use snark_verifier_sdk::CircuitExt; use ssz_rs::{Merkleized, Vector}; @@ -322,11 +320,12 @@ mod tests { params: &ParamsKZG, pk: &ProvingKey, witness: &CommitteeRotationArgs, + pinning_path: &str, ) -> Snark { CommitteeUpdateCircuit::::gen_snark_shplonk( params, pk, - "./config/committee_update.json", + pinning_path, None::, witness, ) @@ -399,7 +398,7 @@ mod tests { &CommitteeRotationArgs::::default(), ); let witness = load_circuit_args(); - let snark = gen_application_snark(¶ms_app, &pk_app, &witness); + let snark = gen_application_snark(¶ms_app, &pk_app, &witness, APP_PINNING_PATH); let params = gen_srs(AGG_K); println!("agg_params k: {:?}", params.k()); @@ -439,7 +438,7 @@ mod tests { ); let witness = load_circuit_args(); - let snark = gen_application_snark(¶ms_app, &pk_app, &witness); + let snark = gen_application_snark(¶ms_app, &pk_app, &witness, APP_PINNING_PATH); let params = gen_srs(AGG_K); println!("agg_params k: {:?}", params.k()); diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/step_circuit.rs similarity index 95% rename from lightclient-circuits/src/sync_step_circuit.rs rename to lightclient-circuits/src/step_circuit.rs index 1d4a257d..dc766e54 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/step_circuit.rs @@ -11,7 +11,6 @@ use std::{ rc::Rc, vec, }; - use crate::{ gadget::crypto::{ calculate_ysquared, G1Chip, G1Point, G2Chip, G2Point, HashInstructions, Sha256Chip, @@ -54,25 +53,23 @@ use halo2_ecc::{ }, fields::{fp12, fp2, vector::FieldVector, FieldChip, FieldExtConstructor}, }; -use halo2curves::bls12_381::{Fq, Fq12, Fr, G1Affine, G2Affine, G2Prepared, G1, G2}; use halo2curves::{ + bls12_381::{Fq, Fq12, Fr, G1Affine, G2Affine, G2Prepared, G1, G2}, ff::PrimeField, group::{GroupEncoding, UncompressedEncoding}, }; use itertools::Itertools; -use lazy_static::__Deref; use num_bigint::BigUint; -// use snark_verifier_sdk::{evm::gen_evm_verifier_shplonk, CircuitExt}; use ssz_rs::{Merkleized, Node}; #[allow(type_alias_bounds)] #[derive(Clone, Debug, Default)] -pub struct SyncStepCircuit { +pub struct StepCircuit { _f: PhantomData, _spec: PhantomData, } -impl SyncStepCircuit { +impl StepCircuit { fn synthesize( builder: &mut ShaCircuitBuilder>, fp_chip: &FpChip, @@ -358,7 +355,7 @@ pub fn to_bytes_le( assigned_bytes } -impl SyncStepCircuit { +impl StepCircuit { fn assign_signature( ctx: &mut Context, g2_chip: &G2Chip, @@ -427,7 +424,7 @@ impl SyncStepCircuit { } } -impl AppCircuit for SyncStepCircuit { +impl AppCircuit for StepCircuit { type Pinning = Eth2ConfigPinning; type Witness = witness::SyncStepArgs; @@ -516,7 +513,7 @@ mod tests { let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - let circuit = SyncStepCircuit::::create_circuit( + let circuit = StepCircuit::::create_circuit( CircuitBuilderStage::Mock, Some(pinning), &witness, @@ -524,7 +521,7 @@ mod tests { ) .unwrap(); - let sync_pi_commit = SyncStepCircuit::::instance_commitment(&witness, 112); + let sync_pi_commit = StepCircuit::::instance_commitment(&witness, 112); let timer = start_timer!(|| "sync_step mock prover"); let prover = MockProver::::run(K, &circuit, vec![vec![sync_pi_commit]]).unwrap(); @@ -537,7 +534,7 @@ mod tests { const K: u32 = 22; let params = gen_srs(K); - let pk = SyncStepCircuit::::read_or_create_pk( + let pk = StepCircuit::::read_or_create_pk( ¶ms, "../build/sync_step.pkey", "./config/sync_step.json", @@ -547,7 +544,7 @@ mod tests { let witness = load_circuit_args(); - let _ = SyncStepCircuit::::gen_proof_shplonk( + let _ = StepCircuit::::gen_proof_shplonk( ¶ms, &pk, "./config/sync_step.json", @@ -561,7 +558,7 @@ mod tests { const K: u32 = 22; let params = gen_srs(K); - let pk = SyncStepCircuit::::read_or_create_pk( + let pk = StepCircuit::::read_or_create_pk( ¶ms, "../build/sync_step.pkey", "./config/sync_step.json", @@ -573,7 +570,7 @@ mod tests { let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - let circuit = SyncStepCircuit::::create_circuit( + let circuit = StepCircuit::::create_circuit( CircuitBuilderStage::Prover, Some(pinning), &witness, @@ -585,7 +582,7 @@ mod tests { let instances = circuit.instances(); let proof = gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); println!("proof size: {}", proof.len()); - let deployment_code = SyncStepCircuit::::gen_evm_verifier_shplonk( + let deployment_code = StepCircuit::::gen_evm_verifier_shplonk( ¶ms, &pk, None::, diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index 933d19c4..b38ddbc0 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -4,8 +4,8 @@ use halo2_base::gates::circuit::CircuitBuilderStage; use halo2_base::halo2_proofs::dev::MockProver; use halo2_base::halo2_proofs::halo2curves::bn256; use lightclient_circuits::LIMB_BITS; -use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; -use lightclient_circuits::sync_step_circuit::SyncStepCircuit; +use lightclient_circuits::rotation_circuit::CommitteeUpdateCircuit; +use lightclient_circuits::step_circuit::StepCircuit; use lightclient_circuits::util::gen_srs; use lightclient_circuits::util::AppCircuit; use lightclient_circuits::util::Eth2ConfigPinning; @@ -64,7 +64,7 @@ fn run_test_eth2_spec_mock(path: PathB let sync_circuit = { let pinning: Eth2ConfigPinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - SyncStepCircuit::::create_circuit( + StepCircuit::::create_circuit( CircuitBuilderStage::Mock, Some(pinning), &sync_witness, @@ -74,7 +74,7 @@ fn run_test_eth2_spec_mock(path: PathB }; let sync_pi_commit = - SyncStepCircuit::::instance_commitment(&sync_witness, LIMB_BITS); + StepCircuit::::instance_commitment(&sync_witness, LIMB_BITS); let timer = start_timer!(|| "sync_step mock prover run"); let prover = @@ -93,7 +93,7 @@ fn test_eth2_spec_proofgen( let (witness, _) = read_test_files_and_gen_witness(&path); let params = gen_srs(K); - let pk = SyncStepCircuit::::read_or_create_pk( + let pk = StepCircuit::::read_or_create_pk( ¶ms, "../build/sync_step.pkey", "./config/sync_step.json", @@ -101,7 +101,7 @@ fn test_eth2_spec_proofgen( &SyncStepArgs::::default(), ); - let _ = SyncStepCircuit::::gen_proof_shplonk( + let _ = StepCircuit::::gen_proof_shplonk( ¶ms, &pk, "./config/sync_step.json", @@ -119,7 +119,7 @@ fn test_eth2_spec_evm_verify( const K: u32 = 21; let params = gen_srs(K); - let pk = SyncStepCircuit::::read_or_create_pk( + let pk = StepCircuit::::read_or_create_pk( ¶ms, "../build/sync_step.pkey", "./config/sync_step.json", @@ -131,7 +131,7 @@ fn test_eth2_spec_evm_verify( let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); - let circuit = SyncStepCircuit::::create_circuit( + let circuit = StepCircuit::::create_circuit( CircuitBuilderStage::Prover, Some(pinning), &witness, @@ -143,7 +143,7 @@ fn test_eth2_spec_evm_verify( let proof = snark_verifier_sdk::evm::gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); println!("proof size: {}", proof.len()); - let deployment_code = SyncStepCircuit::::gen_evm_verifier_shplonk( + let deployment_code = StepCircuit::::gen_evm_verifier_shplonk( ¶ms, &pk, None::, diff --git a/preprocessor/src/rotation.rs b/preprocessor/src/rotation.rs index 5d19496a..771daa8a 100644 --- a/preprocessor/src/rotation.rs +++ b/preprocessor/src/rotation.rs @@ -98,7 +98,7 @@ mod tests { use eth_types::Testnet; use crate::halo2_base::halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use lightclient_circuits::{ - committee_update_circuit::CommitteeUpdateCircuit, + rotation_circuit::CommitteeUpdateCircuit, util::{gen_srs, AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, halo2_base::gates::circuit::CircuitBuilderStage, }; use snark_verifier_sdk::CircuitExt; diff --git a/preprocessor/src/sync.rs b/preprocessor/src/sync.rs index 13e3466a..c5e2faaa 100644 --- a/preprocessor/src/sync.rs +++ b/preprocessor/src/sync.rs @@ -179,7 +179,7 @@ mod tests { use eth_types::Testnet; use lightclient_circuits::{ halo2_base::gates::circuit::CircuitBuilderStage, - sync_step_circuit::SyncStepCircuit, + step_circuit::StepCircuit, util::{gen_srs, AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, }; use snark_verifier_sdk::CircuitExt; @@ -196,7 +196,7 @@ mod tests { .unwrap(); let pinning = Eth2ConfigPinning::from_path(CONFIG_PATH); - let circuit = SyncStepCircuit::::create_circuit( + let circuit = StepCircuit::::create_circuit( CircuitBuilderStage::Mock, Some(pinning), &witness, @@ -214,7 +214,7 @@ mod tests { const K: u32 = 21; let params = gen_srs(K); - let pk = SyncStepCircuit::::read_or_create_pk( + let pk = StepCircuit::::read_or_create_pk( ¶ms, "../build/sync_step.pkey", CONFIG_PATH, @@ -226,7 +226,7 @@ mod tests { .await .unwrap(); - SyncStepCircuit::::gen_snark_shplonk( + StepCircuit::::gen_snark_shplonk( ¶ms, &pk, CONFIG_PATH, diff --git a/prover/src/cli.rs b/prover/src/cli.rs index 445e377a..a6ea5a0e 100644 --- a/prover/src/cli.rs +++ b/prover/src/cli.rs @@ -5,8 +5,8 @@ use ethers::providers::{Http, Provider}; use itertools::Itertools; use lightclient_circuits::{ halo2_proofs::halo2curves::bn256::{Bn256, Fr, G1Affine}, - committee_update_circuit::CommitteeUpdateCircuit, - sync_step_circuit::SyncStepCircuit, + rotation_circuit::CommitteeUpdateCircuit, + step_circuit::StepCircuit, util::{gen_srs, AppCircuit}, }; use primitive_types::U256; @@ -45,11 +45,11 @@ pub(crate) async fn spec_app(proof: &Proof) -> eyre::Result< .await } Proof::SyncStep(args) => { - generic_circuit_cli::, _, _>( + generic_circuit_cli::, _, _>( args, fetch_step_args, "sync_step", - as AppCircuit>::Witness::default(), + as AppCircuit>::Witness::default(), ) .await } diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index 6e77a96d..5e556c3e 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -5,8 +5,8 @@ use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use jsonrpc_v2::{Error as JsonRpcError, Params}; use lightclient_circuits::{ - committee_update_circuit::CommitteeUpdateCircuit, - sync_step_circuit::SyncStepCircuit, + rotation_circuit::CommitteeUpdateCircuit, + step_circuit::StepCircuit, util::{gen_srs, AppCircuit}, }; use preprocessor::{fetch_rotation_args, fetch_step_args}; @@ -173,7 +173,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_handler( Spec::Minimal => { let pk_filename = format!("step_circuit_minimal.pkey"); let witness = fetch_step_args(beacon_api).await.unwrap(); - gen_evm_proof::>( + gen_evm_proof::>( k, build_dir, pk_filename, @@ -185,7 +185,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_handler( let pk_filename = format!("step_circuit_testnet.pkey"); let witness = fetch_step_args(beacon_api).await.unwrap(); - gen_evm_proof::>( + gen_evm_proof::>( k, build_dir, pk_filename, @@ -197,7 +197,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_handler( let pk_filename = format!("step_circuit_mainnet.pkey"); let witness = fetch_step_args(beacon_api).await.unwrap(); - gen_evm_proof::>( + gen_evm_proof::>( k, build_dir, pk_filename, From f859c0cf7f52881a28ab165751a9fd5d5ff9ea87 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 22 Nov 2023 19:56:45 +0100 Subject: [PATCH 12/23] refactor --- lightclient-circuits/src/aggregation.rs | 22 ++--- .../src/gadget/crypto/builder.rs | 21 +++-- lightclient-circuits/src/gadget/crypto/mod.rs | 4 - .../src/gadget/crypto/sha256_flex.rs | 70 ++++++--------- .../gadget/crypto/sha256_flex/compression.rs | 33 ++----- .../src/gadget/crypto/sha256_flex/gate.rs | 1 - .../src/gadget/crypto/sha256_flex/util.rs | 2 - .../src/gadget/crypto/sha256_wide.rs | 20 +---- .../src/gadget/crypto/sha256_wide/config.rs | 37 +++----- .../src/gadget/crypto/sha256_wide/gate.rs | 21 ++--- .../src/gadget/crypto/sha256_wide/util.rs | 11 +-- .../src/gadget/crypto/sha256_wide/witness.rs | 27 ++---- lightclient-circuits/src/lib.rs | 2 +- lightclient-circuits/src/poseidon.rs | 19 ++-- lightclient-circuits/src/rotation_circuit.rs | 76 +++++----------- lightclient-circuits/src/ssz_merkle.rs | 18 ++-- lightclient-circuits/src/step_circuit.rs | 88 ++++--------------- lightclient-circuits/src/util.rs | 75 ---------------- lightclient-circuits/src/util/circuit.rs | 36 ++++---- lightclient-circuits/src/util/common.rs | 28 +----- .../src/util/constraint_builder.rs | 6 +- lightclient-circuits/src/util/proof.rs | 30 +++---- lightclient-circuits/src/witness/rotation.rs | 16 +--- lightclient-circuits/src/witness/sync.rs | 14 ++- 24 files changed, 171 insertions(+), 506 deletions(-) diff --git a/lightclient-circuits/src/aggregation.rs b/lightclient-circuits/src/aggregation.rs index 408cdf8e..4ce959c1 100644 --- a/lightclient-circuits/src/aggregation.rs +++ b/lightclient-circuits/src/aggregation.rs @@ -1,18 +1,7 @@ -use std::{ - env::{set_var, var}, - fs::File, - iter, - path::Path, -}; - -use eth_types::Testnet; +use crate::util::{AppCircuit, Halo2ConfigPinning, PinnableCircuit}; use halo2_base::{ gates::{circuit::CircuitBuilderStage, flex_gate::MultiPhaseThreadBreakPoints}, - halo2_proofs::{ - halo2curves::bn256::Fr, - plonk::Error, - poly::{commitment::Params, kzg::commitment::ParamsKZG}, - }, + halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}, utils::fs::gen_srs, }; use serde::{Deserialize, Serialize}; @@ -20,8 +9,11 @@ use snark_verifier_sdk::{ halo2::aggregation::{AggregationCircuit, AggregationConfigParams}, Snark, SHPLONK, }; - -use crate::util::{AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning, PinnableCircuit}; +use std::{ + env::{set_var, var}, + fs::File, + path::Path, +}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AggregationConfigPinning { diff --git a/lightclient-circuits/src/gadget/crypto/builder.rs b/lightclient-circuits/src/gadget/crypto/builder.rs index aff68dbb..4c22cb6d 100644 --- a/lightclient-circuits/src/gadget/crypto/builder.rs +++ b/lightclient-circuits/src/gadget/crypto/builder.rs @@ -1,5 +1,6 @@ -use std::{cell::RefCell, collections::HashMap, env::set_var, marker::PhantomData, mem}; +use std::env::set_var; +use crate::util::{CommonGateManager, Eth2ConfigPinning, GateBuilderConfig, PinnableCircuit}; use eth_types::Field; use getset::Getters; use halo2_base::{ @@ -18,18 +19,12 @@ use halo2_base::{ plonk::{Circuit, ConstraintSystem, Error}, }, utils::BigPrimeField, - virtual_region::manager::VirtualRegionManager, - Context, AssignedValue, + AssignedValue, Context, }; use itertools::Itertools; use snark_verifier_sdk::CircuitExt; -use crate::{ - gadget::crypto::{Sha256Chip, ShaFlexGateManager}, - util::{CommonGateManager, Eth2ConfigPinning, GateBuilderConfig, PinnableCircuit}, -}; - -use super::sha256_flex::{assign_threads_sha, SpreadConfig, FIRST_PHASE}; +use super::sha256_flex::FIRST_PHASE; #[derive(Debug, Clone)] pub struct SHAConfig> { @@ -122,7 +117,11 @@ impl> ShaCircuitBuilder>) -> Self { + pub fn use_instances( + mut self, + column: usize, + assigned_instances: Vec>, + ) -> Self { self.set_instances(column, assigned_instances); self } @@ -195,7 +194,7 @@ impl> CommonCircuitBuilder unimplemented!() } - fn new_context(&self, context_id: usize) -> Context { + fn new_context(&self, _context_id: usize) -> Context { unimplemented!() } diff --git a/lightclient-circuits/src/gadget/crypto/mod.rs b/lightclient-circuits/src/gadget/crypto/mod.rs index 13cb7559..46fc5610 100644 --- a/lightclient-circuits/src/gadget/crypto/mod.rs +++ b/lightclient-circuits/src/gadget/crypto/mod.rs @@ -6,20 +6,16 @@ mod sha256_wide; pub use builder::{SHAConfig, ShaCircuitBuilder}; use eth_types::Field; -use halo2_base::{AssignedValue, QuantumCell}; use halo2_ecc::{ bigint::ProperCrtUint, bls12_381::{Fp2Chip, Fp2Point, FpChip}, ecc::{EcPoint, EccChip}, - fields::{fp2, vector::FieldVector, FieldExtConstructor}, }; -use lazy_static::lazy_static; pub use sha256_flex::{Sha256Chip, ShaContexts, ShaFlexGateManager}; pub use sha256_wide::{Sha256ChipWide, ShaBitGateManager}; pub use ecc::calculate_ysquared; -use crate::witness::HashInput; pub type G1Point = EcPoint>; pub type G2Point = EcPoint>; diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs index 277f6c3a..d32d4bc8 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs @@ -3,36 +3,22 @@ mod gate; mod spread; mod util; +use crate::gadget::crypto::sha256_flex::compression::{sha256_compression, INIT_STATE}; +use eth_types::Field; pub use gate::ShaFlexGateManager; use halo2_base::gates::flex_gate::threads::CommonCircuitBuilder; use halo2_base::gates::RangeChip; -pub use spread::SpreadConfig; - -use eth_types::Field; -use itertools::Itertools; -use sha2::compress256; -use sha2::digest::generic_array::GenericArray; -use std::collections::HashMap; -use std::{cell::RefCell, char::MAX}; - -use crate::gadget::crypto::sha256_flex::compression::{sha256_compression, INIT_STATE}; -use crate::witness::HashInput; +use halo2_base::halo2_proofs::plonk::Error; use halo2_base::QuantumCell; use halo2_base::{ gates::{GateInstructions, RangeInstructions}, - AssignedValue, Context, -}; -use halo2_base::{ - halo2_proofs::{ - circuit::{self, AssignedCell, Region}, - plonk::{Assigned, Error}, - }, - utils::value_to_option, - ContextCell, + AssignedValue, }; +use itertools::Itertools; +pub use spread::SpreadConfig; pub use self::gate::ShaContexts; -pub(super) use self::gate::{assign_threads_sha, FIRST_PHASE}; +pub(super) use self::gate::FIRST_PHASE; pub use self::spread::SpreadChip; use super::{HashInstructions, ShaCircuitBuilder}; @@ -87,7 +73,6 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { } else { input_byte_size_with_9 / one_round_size + 1 }; - let max_round = max_processed_bytes / one_round_size; let padded_size = one_round_size * num_round; let zero_padding_byte_size = padded_size - input_byte_size_with_9; // let remaining_byte_size = MAX_INPUT_SIZE - padded_size; @@ -124,7 +109,7 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { let assigned_num_round = builder.main().load_witness(F::from(num_round as u64)); // compute an initial state from the precomputed_input. - let mut last_state = INIT_STATE; + let last_state = INIT_STATE; let mut assigned_last_state_vec = vec![last_state .iter() @@ -198,26 +183,25 @@ impl<'a, F: Field> Sha256Chip<'a, F> { #[cfg(test)] mod test { - use std::env::var; - use std::vec; - use std::{cell::RefCell, marker::PhantomData}; - - use crate::gadget::crypto::ShaCircuitBuilder; - use crate::util::{gen_pkey, Challenges, IntoWitness}; - - use super::*; - use ark_std::{end_timer, start_timer}; - use eth_types::Testnet; - use halo2_base::gates::range::RangeConfig; - use halo2_base::halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::MockProver, - halo2curves::bn256::Fr, - plonk::{Circuit, ConstraintSystem}, - }; - use halo2_base::utils::fs::gen_srs; - use halo2_base::SKIP_FIRST_PASS; - use sha2::{Digest, Sha256}; + // use std::env::var; + // use std::vec; + // use std::{cell::RefCell, marker::PhantomData}; + + // use crate::gadget::crypto::ShaCircuitBuilder; + // use crate::util::{gen_pkey, IntoWitness}; + // use super::*; + // use ark_std::{end_timer, start_timer}; + // use eth_types::Testnet; + // use halo2_base::gates::range::RangeConfig; + // use halo2_base::halo2_proofs::{ + // circuit::{Layouter, SimpleFloorPlanner}, + // dev::MockProver, + // halo2curves::bn256::Fr, + // plonk::{Circuit, ConstraintSystem}, + // }; + // use halo2_base::utils::fs::gen_srs; + // use halo2_base::SKIP_FIRST_PASS; + // use sha2::{Digest, Sha256}; // fn test_circuit( // k: usize, diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs index 2b06d525..0d479645 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs @@ -1,35 +1,14 @@ -use std::cell::RefMut; - -use crate::gadget::crypto::ShaCircuitBuilder; -use crate::util::CommonGateManager; - -use super::gate::ShaContexts; -use super::spread::{self, SpreadChip, SpreadConfig}; +use super::spread::SpreadChip; use super::util::{bits_le_to_fe, fe_to_bits_le}; use super::ShaFlexGateManager; +use crate::gadget::crypto::ShaCircuitBuilder; use eth_types::Field; use halo2_base::{ - gates::{ - flex_gate::{threads::CommonCircuitBuilder, FlexGateConfig}, - range::RangeConfig, - GateInstructions, RangeInstructions, - }, - halo2_proofs::{ - circuit::{AssignedCell, Cell, Layouter, Region, SimpleFloorPlanner, Value}, - plonk::{ - Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, Selector, - TableColumn, VirtualCells, - }, - poly::Rotation, - }, - utils::{bigint_to_fe, biguint_to_fe, fe_to_bigint, fe_to_biguint, modulus}, + gates::{flex_gate::threads::CommonCircuitBuilder, GateInstructions, RangeInstructions}, + halo2_proofs::plonk::Error, AssignedValue, Context, QuantumCell, }; use itertools::Itertools; -use sha2::{Digest, Sha256}; - -// const BLOCK_BYTE: usize = 64; -// const DIGEST_BYTE: usize = 32; pub const NUM_ROUND: usize = 64; pub const NUM_STATE_WORD: usize = 8; @@ -149,7 +128,9 @@ pub fn sha256_compression<'a, 'b: 'a, F: Field>( // let mut e_bits = gate.num_to_bits(ctx, &e, 32); // let mut f_bits = gate.num_to_bits(ctx, &f, 32); // let mut g_bits = gate.num_to_bits(ctx, &g, 32); + #[allow(unused_assignments)] let mut t1 = thread_pool.main().load_zero(); + #[allow(unused_assignments)] let mut t2 = thread_pool.main().load_zero(); for idx in 0..64 { t1 = { @@ -594,7 +575,7 @@ fn sigma_generic<'a, 'b: 'a, F: Field>( bits.append(&mut fe_to_bits_le(hi, 32)); bits }; - let mut assign_bits = |bits: &Vec, start: usize, end: usize, padding: usize| { + let mut assign_bits = |bits: &Vec, start: usize, end: usize, _padding: usize| { let fe_val: F = { let mut bits = bits[(2 * start)..(2 * end)].to_vec(); bits.extend_from_slice(&vec![false; 64 - bits.len()]); diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs index bd8f34ed..b5264411 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs @@ -2,7 +2,6 @@ use std::any::TypeId; use getset::CopyGetters; use halo2_base::{ - gates::circuit::CircuitBuilderStage, halo2_proofs::circuit::{Region, Value}, utils::BigPrimeField, virtual_region::{ diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs index 67e82c14..5dd65145 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs @@ -3,8 +3,6 @@ use halo2_base::utils::{biguint_to_fe, fe_to_biguint}; use itertools::Itertools; use num_bigint::BigUint; -use crate::witness::HashInput; - pub fn fe_to_bits_le(val: &F, size: usize) -> Vec { let val_bytes = fe_to_biguint(val).to_bytes_le(); let mut bits = val_bytes diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs index 49faae32..d638c1a5 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs @@ -7,10 +7,6 @@ use eth_types::Field; use halo2_base::gates::flex_gate::threads::CommonCircuitBuilder; use halo2_base::gates::RangeChip; use itertools::Itertools; -use std::collections::HashMap; -use std::iter; -use std::os::unix::thread; -use std::{cell::RefCell, char::MAX}; use crate::gadget::crypto::sha256_wide::util::Sha256AssignedRows; use crate::gadget::crypto::sha256_wide::witness::multi_sha256; @@ -19,22 +15,15 @@ use crate::witness::HashInput; use halo2_base::{ gates::{GateInstructions, RangeInstructions}, - halo2_proofs::{ - circuit::{self, AssignedCell, Region}, - plonk::{Assigned, Error}, - }, - utils::value_to_option, - AssignedValue, Context, ContextCell, QuantumCell, + halo2_proofs::plonk::Error, + AssignedValue, QuantumCell, }; -use self::config::Sha256BitConfig; pub use self::gate::ShaBitGateManager; use self::util::{NUM_BYTES_FINAL_HASH, NUM_WORDS_TO_ABSORB}; use super::{HashInstructions, ShaCircuitBuilder}; -const SHA256_CONTEXT_ID: usize = usize::MAX; - #[derive(Debug)] pub struct Sha256ChipWide<'a, F: Field> { range: &'a RangeChip, @@ -66,9 +55,9 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { &self, builder: &mut Self::CircuitBuilder, input: impl IntoIterator>, - strict: bool, + _strict: bool, ) -> Result>, Error> { - let mut assigned_input = input + let assigned_input = input .into_iter() .map(|cell| match cell { QuantumCell::Existing(v) => v, @@ -101,7 +90,6 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { self.load_digest::(builder, binary_input, &mut assigned_rounds)?; let one_round_size = Self::BLOCK_SIZE; - let num_round = 1; let num_round = if input_byte_size % one_round_size == 0 { input_byte_size / one_round_size diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs index 94030d1e..b8c5715b 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs @@ -2,38 +2,25 @@ //! This implementation is based on: //! - https://github.com/SoraSuegami/zkevm-circuits/blob/main/zkevm-circuits/src/sha256_circuit/sha256_bit.rs -use std::cell::RefCell; -use std::collections::HashMap; -use std::hash::Hash; -use std::iter; -use std::marker::PhantomData; - +use super::{util::*, witness::ShaRow}; use crate::gadget::crypto::constant_randomness; use crate::gadget::{and, not, rlc, select, sum, xor, Expr}; +use crate::util::BaseConstraintBuilder; use crate::util::GateBuilderConfig; -use crate::witness::HashInputChunk; -use crate::{ - util::{BaseConstraintBuilder, Challenges}, - witness::{self, HashInput}, -}; -use eth_types::{Field, Spec}; -use halo2_base::halo2_proofs::circuit; +use eth_types::Field; use halo2_base::virtual_region::copy_constraints::CopyConstraintManager; use halo2_base::{ halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region, Value}, + circuit::{Layouter, Region, Value}, plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, }, AssignedValue, Context, ContextCell, QuantumCell, }; -use rayon::prelude::{IntoParallelIterator, ParallelIterator}; - -use super::util::*; use itertools::Itertools; use log::debug; - -use super::witness::{multi_sha256, ShaRow}; +use std::iter; +use std::marker::PhantomData; /// Configuration for [`Sha256WideChip`]. #[derive(Clone, Debug)] @@ -76,10 +63,6 @@ pub struct Sha256BitConfig, CA = Column> { impl GateBuilderConfig for Sha256BitConfig { fn configure(meta: &mut ConstraintSystem) -> Self { - // consts - let two = F::from(2); - let f256 = F::from(256); - let r: F = constant_randomness(); // TODO: use challenges API let q_enable = meta.fixed_column(); let q_first = meta.fixed_column(); @@ -614,7 +597,7 @@ impl GateBuilderConfig for Sha256BitConfig { }); } - fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + fn load(&self, _layouter: &mut impl Layouter) -> Result<(), Error> { Ok(()) } } @@ -740,13 +723,13 @@ impl Sha256BitConfig, Context> { .is_paddings .iter_mut() .zip(row.is_paddings) - .map(|(mut ctx, val)| ctx.load_witness(F::from(val))) + .map(|(ctx, val)| ctx.load_witness(F::from(val))) .collect_vec() .try_into() .unwrap(); // Intermediary data rlcs - for ((ctx, data_rlc)) in self.data_rlcs.iter_mut().zip(row.intermediary_data_rlcs) { + for (ctx, data_rlc) in self.data_rlcs.iter_mut().zip(row.intermediary_data_rlcs) { ctx.assign_cell(QuantumCell::Witness(data_rlc)); } @@ -760,7 +743,7 @@ impl Sha256BitConfig, Context> { (&mut self.input_len, F::from(row.length as u64)), (&mut self.hash_rlc, row.hash_rlc), ] - .map(|(mut ctx, value)| ctx.load_witness(value)); + .map(|(ctx, value)| ctx.load_witness(value)); if (4..20).contains(&round) { assigned_rows.padding_selectors.push(padding_selectors); diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs index 641aff8b..7ef6ac4d 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs @@ -1,24 +1,16 @@ -use std::{any::TypeId, cell::RefCell, collections::HashMap, iter, mem}; - +use super::config::Sha256BitConfig; +use crate::util::{CommonGateManager, GateBuilderConfig}; use eth_types::Field; use getset::CopyGetters; use halo2_base::{ - gates::{circuit::CircuitBuilderStage, flex_gate::FlexGateConfig}, - halo2_proofs::{ - circuit::{self, Region, Value}, - plonk::{Advice, Column, Error, Selector}, - }, - utils::ScalarField, + gates::circuit::CircuitBuilderStage, + halo2_proofs::circuit::Region, virtual_region::{ copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, }, Context, }; -use itertools::Itertools; - -use crate::util::{CommonGateManager, GateBuilderConfig}; - -use super::{config::Sha256BitConfig, witness::ShaRow}; +use std::any::TypeId; pub const FIRST_PHASE: usize = 0; @@ -35,8 +27,6 @@ pub struct ShaBitGateManager { /// Threads for spread table assignment. sha_contexts: Sha256BitContexts, - sha_offset: usize, - pub copy_manager: SharedCopyConstraintManager, } @@ -88,7 +78,6 @@ impl CommonGateManager for ShaBitGateManager { _f: std::marker::PhantomData, offset: 0, }, - sha_offset: 0, copy_manager: SharedCopyConstraintManager::default(), } } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs index f29f67e6..0cbb3edd 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs @@ -1,13 +1,5 @@ use eth_types::Field; -use halo2_base::{ - halo2_proofs::circuit::AssignedCell, - utils::{biguint_to_fe, fe_to_biguint}, - AssignedValue, -}; -use itertools::Itertools; -use num_bigint::BigUint; - -use crate::witness::HashInput; +use halo2_base::AssignedValue; pub(crate) const NUM_BITS_PER_BYTE: usize = 8; pub(crate) const NUM_BYTES_PER_WORD: usize = 4; @@ -20,7 +12,6 @@ pub(crate) const RATE_IN_BITS: usize = RATE * NUM_BITS_PER_BYTE; pub(crate) const NUM_WORDS_TO_ABSORB: usize = 16; pub(crate) const ABSORB_WIDTH_PER_ROW_BYTES: usize = 4; pub(crate) const NUM_BITS_PADDING_LENGTH: usize = 64; -pub(crate) const NUM_START_ROWS: usize = 4; pub(crate) const NUM_END_ROWS: usize = 4; pub(crate) const NUM_BYTES_FINAL_HASH: usize = 32; pub(crate) const MAX_DEGREE: usize = 5; diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs index 35f55ba0..34342d99 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs @@ -10,7 +10,6 @@ pub struct ShaRow { pub(crate) a: [bool; NUM_BITS_PER_WORD_EXT], pub(crate) e: [bool; NUM_BITS_PER_WORD_EXT], pub(crate) is_final: bool, - pub(crate) is_right: bool, pub(crate) length: usize, pub(crate) data_rlc: F, pub(crate) hash_rlc: F, @@ -19,10 +18,7 @@ pub struct ShaRow { pub(crate) final_hash_bytes: [F; NUM_BYTES_FINAL_HASH], } -pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, is_rlc: [bool; 2]) { - // Prepare inputs RLCs in advance - let mut inputs_rlc = inputs.map(|input| rlc::value(input, rnd)); - +pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F) { let left_bits = into_bits(inputs[0]); let right_bits = into_bits(inputs[1]); let input_len = inputs[0].len() + inputs[1].len(); @@ -43,9 +39,6 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, let mut hs: [u64; 8] = H.to_vec().try_into().unwrap(); let mut length = 0usize; let mut data_rlc = F::ZERO; - let mut rnd_pow = F::ZERO; - let mut u8_pow = [F::ONE, F::ZERO]; - let mut data_vals = [F::ZERO; 2]; let mut in_padding = false; @@ -58,7 +51,6 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, a: u64, e: u64, is_final, - is_right: bool, length, data_rlc, hash_rlc, @@ -77,7 +69,6 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, a: word_to_bits(a, NUM_BITS_PER_WORD_EXT).try_into().unwrap(), e: word_to_bits(e, NUM_BITS_PER_WORD_EXT).try_into().unwrap(), is_final, - is_right, length, data_rlc, hash_rlc, @@ -101,7 +92,6 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, a, e, is_final, - false, length, data_rlc, F::ZERO, @@ -120,7 +110,6 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, // Padding/Length/Data rlc let mut is_paddings = [false; ABSORB_WIDTH_PER_ROW_BYTES]; let mut inter_data_rlcs = [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES]; - let mut is_right = false; // feature: [multi input lookups] if round < NUM_WORDS_TO_ABSORB { // padding/length for is_padding in is_paddings.iter_mut() { @@ -185,7 +174,6 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, a, e, false, - is_right, if round < NUM_WORDS_TO_ABSORB { length } else { @@ -248,7 +236,6 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, a, e, false, - false, 0, F::ZERO, F::ZERO, @@ -266,7 +253,6 @@ pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F, hs[0], hs[4], is_final_block, - false, length, data_rlc, hash_rlc, @@ -294,16 +280,13 @@ pub fn multi_sha256(inputs: &[HashInput], rnd: F) -> Vec let inputs = inputs .iter() .map(|input| match input { - HashInput::Single(inner) => ([inner.bytes.as_slice(), &[]], [inner.is_rlc, false]), - HashInput::TwoToOne(left, right) => ( - [left.bytes.as_slice(), right.bytes.as_slice()], - [left.is_rlc, right.is_rlc], - ), + HashInput::Single(inner) => [inner.bytes.as_slice(), &[]], + HashInput::TwoToOne(left, right) => [left.bytes.as_slice(), right.bytes.as_slice()], }) .collect_vec(); let mut rows: Vec> = Vec::new(); - for (bytes, is_rlc) in inputs { - sha256(&mut rows, &bytes, rnd, is_rlc); + for bytes in inputs { + sha256(&mut rows, &bytes, rnd); } rows } diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 0889c55c..47e1139e 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -6,7 +6,7 @@ #![feature(trait_alias)] #![feature(generic_arg_infer)] #![feature(return_position_impl_trait_in_trait)] -#![allow(unused, clippy::needless_range_loop)] +#![allow(clippy::needless_range_loop)] pub mod gadget; pub mod util; pub mod witness; diff --git a/lightclient-circuits/src/poseidon.rs b/lightclient-circuits/src/poseidon.rs index e47be79f..bc96fce8 100644 --- a/lightclient-circuits/src/poseidon.rs +++ b/lightclient-circuits/src/poseidon.rs @@ -1,14 +1,10 @@ -use crate::gadget::crypto::G1Point; -use eth_types::{Field, Spec}; +use eth_types::Field; use halo2_base::{ - gates::GateInstructions, - halo2_proofs::plonk::Error, - poseidon::{hasher::PoseidonSponge, PoseidonChip}, - utils::ScalarField, + gates::GateInstructions, halo2_proofs::plonk::Error, poseidon::hasher::PoseidonSponge, AssignedValue, Context, }; -use halo2_ecc::bigint::{ProperCrtUint, ProperUint}; -use halo2curves::bls12_381::{Fq, G1Affine, G1}; +use halo2_ecc::bigint::ProperCrtUint; +use halo2curves::bls12_381::Fq; use itertools::Itertools; use pse_poseidon::Poseidon as PoseidonNative; @@ -37,8 +33,7 @@ pub fn fq_array_poseidon<'a, F: Field>( if i != 0 { poseidon.update(&[current_poseidon_hash.unwrap()]); } - - current_poseidon_hash.insert(poseidon.squeeze(ctx, gate)); + let _ = current_poseidon_hash.insert(poseidon.squeeze(ctx, gate)); } Ok(current_poseidon_hash.unwrap()) @@ -65,7 +60,7 @@ pub fn fq_array_poseidon_native( if i != 0 { poseidon.update(&[current_poseidon_hash.unwrap()]); } - current_poseidon_hash.insert(poseidon.squeeze()); + let _ = current_poseidon_hash.insert(poseidon.squeeze()); } Ok(current_poseidon_hash.unwrap()) } @@ -84,7 +79,7 @@ pub fn poseidon_sponge( if i != 0 { poseidon.update(&[current_poseidon_hash.unwrap()]); } - current_poseidon_hash.insert(poseidon.squeeze(ctx, gate)); + let _ = current_poseidon_hash.insert(poseidon.squeeze(ctx, gate)); } Ok(current_poseidon_hash.unwrap()) diff --git a/lightclient-circuits/src/rotation_circuit.rs b/lightclient-circuits/src/rotation_circuit.rs index 9457a5a9..3a2162c5 100644 --- a/lightclient-circuits/src/rotation_circuit.rs +++ b/lightclient-circuits/src/rotation_circuit.rs @@ -1,44 +1,29 @@ -use std::{env::var, iter, marker::PhantomData, vec}; use crate::{ - gadget::crypto::{ - calculate_ysquared, G1Chip, G1Point, G2Chip, G2Point, HashInstructions, Sha256ChipWide, - ShaBitGateManager, ShaCircuitBuilder, - }, - poseidon::{fq_array_poseidon, fq_array_poseidon_native, poseidon_sponge}, + gadget::crypto::{HashInstructions, Sha256ChipWide, ShaBitGateManager, ShaCircuitBuilder}, + poseidon::{fq_array_poseidon, fq_array_poseidon_native}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, - step_circuit::{clear_3_bits, to_bytes_le, truncate_sha256_into_single_elem}, - util::{gen_pkey, AppCircuit, Challenges, CommonGateManager, Eth2ConfigPinning, IntoWitness}, + step_circuit::clear_3_bits, + util::{AppCircuit, CommonGateManager, Eth2ConfigPinning, IntoWitness}, witness::{self, HashInput, HashInputChunk}, Eth2CircuitBuilder, LIMB_BITS, NUM_LIMBS, }; use eth_types::{Field, Spec}; use halo2_base::{ gates::{ - circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, RangeChip, - RangeInstructions, + circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, RangeInstructions, }, - halo2_proofs::{ - circuit::{Layouter, Region, SimpleFloorPlanner, Value}, - dev::MockProver, - halo2curves::bn256, - plonk::{Circuit, ConstraintSystem, Error, ProvingKey}, - poly::{commitment::Params, kzg::commitment::ParamsKZG}, - }, - utils::{fs::gen_srs, CurveAffineExt, ScalarField}, + halo2_proofs::{halo2curves::bn256, plonk::Error}, AssignedValue, Context, QuantumCell, }; use halo2_ecc::{ bigint::{utils::decode_into_bn, ProperCrtUint}, - bls12_381::{bls_signature, pairing::PairingChip, Fp12Chip, Fp2Chip, FpChip}, - ecc::{EcPoint, EccChip}, - fields::{fp12, vector::FieldVector, FieldChip, FieldExtConstructor, PrimeFieldChip}, + bls12_381::FpChip, + fields::FieldChip, }; -use halo2curves::bls12_381::{self, Fq, Fq12, G1Affine, G2Affine, G2Prepared, G1, G2}; +use halo2curves::bls12_381; use itertools::Itertools; -use num_bigint::BigUint; -use snark_verifier_sdk::CircuitExt; use ssz_rs::{Merkleized, Vector}; -use sync_committee_primitives::consensus_types::BeaconBlockHeader; +use std::{env::var, iter, marker::PhantomData, vec}; #[allow(type_alias_bounds)] #[derive(Clone, Debug, Default)] @@ -54,8 +39,6 @@ impl CommitteeUpdateCircuit { args: &witness::CommitteeRotationArgs, ) -> Result>, Error> { let range = fp_chip.range(); - let fp2_chip = Fp2Chip::::new(fp_chip); - let g1_chip = EccChip::new(fp2_chip.fp_chip()); let sha256_chip = Sha256ChipWide::new(range, args.randomness); @@ -178,7 +161,7 @@ impl CommitteeUpdateCircuit { limb_bits: usize, ) -> Vec> where - [(); { S::SYNC_COMMITTEE_SIZE }]:, + [(); S::SYNC_COMMITTEE_SIZE]:, { let pubkeys_x = args.pubkeys_compressed.iter().cloned().map(|mut bytes| { bytes.reverse(); @@ -253,17 +236,11 @@ impl AppCircuit for CommitteeUpdateCircuit { #[cfg(test)] mod tests { - use std::{ - env::{set_var, var}, - fs, - path::PathBuf, - }; + use std::fs; use crate::{ - aggregation::AggregationConfigPinning, - gadget::crypto::constant_randomness, - util::{gen_pkey, Halo2ConfigPinning, PinnableCircuit}, - witness::{CommitteeRotationArgs, SyncStepArgs}, + aggregation::AggregationConfigPinning, gadget::crypto::constant_randomness, + util::Halo2ConfigPinning, witness::CommitteeRotationArgs, }; use super::*; @@ -271,27 +248,16 @@ mod tests { use eth_types::Testnet; use halo2_base::{ halo2_proofs::{ - circuit::SimpleFloorPlanner, dev::MockProver, halo2curves::bn256::Fr, - plonk::{keygen_pk, keygen_vk, Circuit, FloorPlanner}, + plonk::ProvingKey, poly::{commitment::Params, kzg::commitment::ParamsKZG}, }, utils::fs::gen_srs, }; - use halo2curves::{bls12_381::G1Affine, bn256::Bn256}; - use rand::rngs::OsRng; - use rayon::iter::ParallelIterator; - use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; - use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; - use snark_verifier_sdk::{ - gen_pk, - halo2::{ - aggregation::{AggregationCircuit, AggregationConfigParams}, - gen_proof_shplonk, gen_snark_shplonk, - }, - CircuitExt, Snark, SHPLONK, - }; + use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk}; + use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, CircuitExt, Snark}; + use sync_committee_primitives::consensus_types::BeaconBlockHeader; fn load_circuit_args() -> CommitteeRotationArgs { #[derive(serde::Deserialize)] @@ -372,7 +338,7 @@ mod tests { let witness = load_circuit_args(); - let circuit = CommitteeUpdateCircuit::::gen_proof_shplonk( + let _ = CommitteeUpdateCircuit::::gen_proof_shplonk( ¶ms, &pk, PINNING_PATH, @@ -411,7 +377,7 @@ mod tests { &vec![snark.clone()], ); - let circuit = AggregationCircuit::gen_proof_shplonk( + let _ = AggregationCircuit::gen_proof_shplonk( ¶ms, &pk, AGG_CONFIG_PATH, @@ -424,7 +390,6 @@ mod tests { fn test_circuit_aggregation_evm() { const APP_K: u32 = 21; const APP_PINNING_PATH: &str = "./config/committee_update_21.json"; - const APP_PK_PATH: &str = "../build/committee_update_21.pkey"; const AGG_CONFIG_PATH: &str = "./config/committee_update_a.json"; let params_app = gen_srs(APP_K); @@ -442,7 +407,6 @@ mod tests { let params = gen_srs(AGG_K); println!("agg_params k: {:?}", params.k()); - let lookup_bits = params.k() as usize - 1; let pk = AggregationCircuit::read_or_create_pk( ¶ms, diff --git a/lightclient-circuits/src/ssz_merkle.rs b/lightclient-circuits/src/ssz_merkle.rs index 0b8710ff..76267080 100644 --- a/lightclient-circuits/src/ssz_merkle.rs +++ b/lightclient-circuits/src/ssz_merkle.rs @@ -1,19 +1,15 @@ -use std::os::unix::thread; - +use crate::{ + gadget::crypto::HashInstructions, + util::IntoConstant, + witness::{HashInput, HashInputChunk}, +}; use eth_types::Field; use halo2_base::{ - gates::flex_gate::threads::CommonCircuitBuilder, - halo2_proofs::{circuit::Region, plonk::Error}, - AssignedValue, Context, QuantumCell, + gates::flex_gate::threads::CommonCircuitBuilder, halo2_proofs::plonk::Error, AssignedValue, + QuantumCell, }; use itertools::Itertools; -use crate::{ - gadget::crypto::{HashInstructions, ShaContexts, ShaFlexGateManager}, - util::{CommonGateManager, IntoConstant, IntoWitness}, - witness::{HashInput, HashInputChunk}, -}; - pub fn ssz_merkleize_chunks>( builder: &mut CircuitBuilder, hasher: &impl HashInstructions, diff --git a/lightclient-circuits/src/step_circuit.rs b/lightclient-circuits/src/step_circuit.rs index dc766e54..758753d5 100644 --- a/lightclient-circuits/src/step_circuit.rs +++ b/lightclient-circuits/src/step_circuit.rs @@ -1,66 +1,40 @@ -use std::{ - cell::RefCell, - collections::HashMap, - env::{set_var, var}, - fs, - io::Read, - iter, - marker::PhantomData, - ops::Neg, - path::Path, - rc::Rc, - vec, -}; use crate::{ gadget::crypto::{ - calculate_ysquared, G1Chip, G1Point, G2Chip, G2Point, HashInstructions, Sha256Chip, + calculate_ysquared, G1Chip, G1Point, G2Chip, HashInstructions, Sha256Chip, ShaCircuitBuilder, ShaFlexGateManager, }, - poseidon::{fq_array_poseidon, fq_array_poseidon_native, poseidon_sponge}, + poseidon::{fq_array_poseidon, fq_array_poseidon_native}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, - util::{gen_pkey, AppCircuit, Challenges, CommonGateManager, Eth2ConfigPinning, IntoWitness}, + util::{AppCircuit, Eth2ConfigPinning, IntoWitness}, witness::{self, HashInput, HashInputChunk, SyncStepArgs}, Eth2CircuitBuilder, LIMB_BITS, NUM_LIMBS, }; use eth_types::{Field, Spec}; use halo2_base::{ gates::{ - circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, range::RangeConfig, - GateInstructions, RangeChip, RangeInstructions, - }, - halo2_proofs::{ - circuit::{Layouter, Region, SimpleFloorPlanner, Value}, - dev::MockProver, - halo2curves::bn256, - plonk::{Circuit, Column, ConstraintSystem, Error, Instance, ProvingKey}, - poly::{commitment::Params, kzg::commitment::ParamsKZG}, + circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, GateInstructions, + RangeInstructions, }, - poseidon::PoseidonChip, - utils::{decompose, fe_to_bigint, fe_to_biguint, fs::gen_srs, CurveAffineExt, ScalarField}, - AssignedValue, Context, - QuantumCell::{self, Witness}, + halo2_proofs::{halo2curves::bn256, plonk::Error}, + utils::CurveAffineExt, + AssignedValue, Context, QuantumCell, }; use halo2_ecc::{ - bigint::ProperCrtUint, - bls12_381::{ - bls_signature::{self, BlsSignatureChip}, - pairing::PairingChip, - Fp12Chip, Fp2Chip, Fp2Point, FpChip, - }, + bls12_381::{bls_signature::BlsSignatureChip, pairing::PairingChip, Fp2Chip, Fp2Point, FpChip}, ecc::{ hash_to_curve::{ExpandMsgXmd, HashToCurveChip}, EcPoint, EccChip, }, - fields::{fp12, fp2, vector::FieldVector, FieldChip, FieldExtConstructor}, + fields::FieldChip, }; use halo2curves::{ - bls12_381::{Fq, Fq12, Fr, G1Affine, G2Affine, G2Prepared, G1, G2}, - ff::PrimeField, + bls12_381::{G1Affine, G2Affine}, group::{GroupEncoding, UncompressedEncoding}, }; use itertools::Itertools; use num_bigint::BigUint; -use ssz_rs::{Merkleized, Node}; +use ssz_rs::Merkleized; +use std::{env::var, marker::PhantomData, vec}; #[allow(type_alias_bounds)] #[derive(Clone, Debug, Default)] @@ -84,9 +58,7 @@ impl StepCircuit { let gate = range.gate(); let sha256_chip = Sha256Chip::new(range); let fp2_chip = Fp2Chip::::new(fp_chip); - let g1_chip = EccChip::new(fp2_chip.fp_chip()); let g2_chip = EccChip::new(&fp2_chip); - let fp12_chip = Fp12Chip::::new(fp2_chip.fp_chip()); let pairing_chip = PairingChip::new(fp_chip); let bls_chip = BlsSignatureChip::new(fp_chip, &pairing_chip); let h2c_chip = HashToCurveChip::new(&sha256_chip, &fp2_chip); @@ -375,7 +347,6 @@ impl StepCircuit { pariticipation_bits: &[bool], assigned_affines: &mut Vec>, ) -> (G1Point, AssignedValue) { - let range = fp_chip.range(); let gate = fp_chip.gate(); let g1_chip = G1Chip::::new(fp_chip); @@ -466,39 +437,17 @@ impl AppCircuit for StepCircuit { #[cfg(test)] mod tests { - use std::{ - env::{set_var, var}, - fs, - os::unix::thread, - }; + use std::fs; - use crate::{ - util::{gen_pkey, Halo2ConfigPinning}, - witness::SyncStepArgs, - }; + use crate::{util::Halo2ConfigPinning, witness::SyncStepArgs}; use super::*; use ark_std::{end_timer, start_timer}; use eth_types::Testnet; use halo2_base::{ - halo2_proofs::{ - circuit::SimpleFloorPlanner, - dev::MockProver, - halo2curves::bn256::Fr, - plonk::{keygen_pk, keygen_vk, Circuit, FloorPlanner}, - poly::kzg::commitment::ParamsKZG, - }, - utils::{decompose, fs::gen_srs}, - }; - use halo2curves::{bls12_381::G1Affine, bn256::Bn256}; - use rand::{rngs::OsRng, thread_rng}; - use rayon::iter::ParallelIterator; - use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; - use snark_verifier_sdk::{ - evm::{encode_calldata, evm_verify, gen_evm_proof_shplonk}, - halo2::{aggregation::AggregationCircuit, gen_proof_shplonk, gen_snark_shplonk}, - CircuitExt, SHPLONK, + halo2_proofs::dev::MockProver, halo2_proofs::halo2curves::bn256::Fr, utils::fs::gen_srs, }; + use snark_verifier_sdk::{evm::{evm_verify, gen_evm_proof_shplonk}, CircuitExt}; fn load_circuit_args() -> SyncStepArgs { serde_json::from_slice(&fs::read("../test_data/sync_step_512.json").unwrap()).unwrap() @@ -507,8 +456,6 @@ mod tests { #[test] fn test_sync_circuit() { const K: u32 = 21; - let params = gen_srs(K); - let witness = load_circuit_args(); let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); @@ -578,7 +525,6 @@ mod tests { ) .unwrap(); - let num_instances = circuit.num_instance(); let instances = circuit.instances(); let proof = gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); println!("proof size: {}", proof.len()); diff --git a/lightclient-circuits/src/util.rs b/lightclient-circuits/src/util.rs index 44487b7c..8a2ae106 100644 --- a/lightclient-circuits/src/util.rs +++ b/lightclient-circuits/src/util.rs @@ -3,8 +3,6 @@ mod common; pub use common::*; -use std::{cell::RefCell, path::Path, rc::Rc}; - mod constraint_builder; pub(crate) use constraint_builder::*; @@ -12,33 +10,11 @@ mod conversion; pub(crate) use conversion::*; mod proof; -use halo2curves::bn256; pub use proof::*; mod circuit; pub use circuit::*; -use halo2_base::{ - halo2_proofs::{ - circuit::{Layouter, Region, Value}, - plonk::{ - Challenge, ConstraintSystem, Error, Expression, FirstPhase, ProvingKey, SecondPhase, - VirtualCells, - }, - poly::kzg::commitment::ParamsKZG, - }, - utils::ScalarField, - AssignedValue, Context, QuantumCell, -}; -use halo2_ecc::{ - bigint::{ProperCrtUint, ProperUint}, - fields::{fp::FpChip, FieldChip}, -}; - -use itertools::Itertools; -use num_bigint::BigUint; - -use crate::{gadget::Expr, witness}; use eth_types::*; /// Helper trait that implements functionality to represent a generic type as @@ -48,57 +24,6 @@ pub trait AsBits { fn as_bits(&self) -> [bool; N]; } -pub(crate) fn query_expression( - meta: &mut ConstraintSystem, - mut f: impl FnMut(&mut VirtualCells) -> T, -) -> T { - let mut expr = None; - meta.create_gate("Query expression", |meta| { - expr = Some(f(meta)); - Some(0.expr()) - }); - expr.unwrap() -} - -/// Randomness used in circuits. -#[derive(Default, Clone, Copy, Debug)] -pub struct Challenges { - sha256_input: T, -} - -impl Challenges { - /// Construct `Challenges` by allocating challenges in specific phases. - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - sha256_input: meta.challenge_usable_after(FirstPhase), - } - } - - /// Returns `Expression` of challenges from `ConstraintSystem`. - pub fn exprs(&self, meta: &mut ConstraintSystem) -> Challenges> { - let [sha256_input] = query_expression(meta, |meta| { - [self.sha256_input].map(|challenge| meta.query_challenge(challenge)) - }); - Challenges { sha256_input } - } - - /// Returns `Value` of challenges from `Layouter`. - pub fn values(&self, layouter: &impl Layouter) -> Challenges> { - Challenges { - sha256_input: layouter.get_challenge(self.sha256_input), - } - } -} - -impl Challenges { - pub fn sha256_input(&self) -> T { - self.sha256_input.clone() - } - - pub(crate) fn mock(sha256_input: T) -> Self { - Self { sha256_input } - } -} /// Packs bits into bytes pub mod to_bytes { diff --git a/lightclient-circuits/src/util/circuit.rs b/lightclient-circuits/src/util/circuit.rs index 7faa8b42..8c25ca39 100644 --- a/lightclient-circuits/src/util/circuit.rs +++ b/lightclient-circuits/src/util/circuit.rs @@ -1,9 +1,9 @@ -use std::env::{args, set_var, var}; +use std::env::{set_var, var}; use std::fs; use std::{fs::File, path::Path}; -use halo2_base::gates::circuit::{CircuitBuilderStage, BaseCircuitParams}; -use halo2_base::gates::flex_gate::{FlexGateConfigParams, MultiPhaseThreadBreakPoints}; +use halo2_base::gates::circuit::{BaseCircuitParams, CircuitBuilderStage}; +use halo2_base::gates::flex_gate::MultiPhaseThreadBreakPoints; use halo2_base::halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::ProvingKey, @@ -14,9 +14,8 @@ use halo2_base::halo2_proofs::{ use halo2_base::utils::BigPrimeField; use serde::{Deserialize, Serialize}; use snark_verifier_sdk::evm::{ - encode_calldata, evm_verify, gen_evm_proof, gen_evm_proof_shplonk, gen_evm_verifier_shplonk, + encode_calldata, evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk, }; -use snark_verifier_sdk::halo2::aggregation::AggregationCircuit; use snark_verifier_sdk::halo2::gen_proof_shplonk; use snark_verifier_sdk::{gen_pk, halo2::gen_snark_shplonk, read_pk}; use snark_verifier_sdk::{CircuitExt, Snark}; @@ -115,13 +114,9 @@ pub trait AppCircuit { path: impl AsRef, witness_args: &Self::Witness, ) -> ProvingKey { - let circuit = Self::create_circuit( - CircuitBuilderStage::Keygen, - None, - witness_args, - params.k(), - ) - .unwrap(); + let circuit = + Self::create_circuit(CircuitBuilderStage::Keygen, None, witness_args, params.k()) + .unwrap(); custom_read_pk(path, &circuit) } @@ -133,13 +128,9 @@ pub trait AppCircuit { pinning_path: impl AsRef, witness_args: &Self::Witness, ) -> ProvingKey { - let circuit = Self::create_circuit( - CircuitBuilderStage::Keygen, - None, - witness_args, - params.k(), - ) - .unwrap(); + let circuit = + Self::create_circuit(CircuitBuilderStage::Keygen, None, witness_args, params.k()) + .unwrap(); let pk_exists = pk_path.as_ref().exists(); let pk = gen_pk(params, &circuit, Some(pk_path.as_ref())); @@ -213,7 +204,8 @@ pub trait AppCircuit { yul_path: Option>, witness_args: &Self::Witness, ) -> Result, Error> { - let circuit = Self::create_circuit(CircuitBuilderStage::Keygen, None, witness_args, params.k())?; + let circuit = + Self::create_circuit(CircuitBuilderStage::Keygen, None, witness_args, params.k())?; let deployment_code = custom_gen_evm_verifier_shplonk(params, pk.get_vk(), &circuit, yul_path); @@ -237,6 +229,10 @@ pub trait AppCircuit { let instances = circuit.instances(); let proof = gen_evm_proof_shplonk(params, pk, circuit, instances.clone()); + if let Some(deployment_code) = deployment_code { + evm_verify(deployment_code, instances.clone(), proof.clone()); + } + Ok((proof, instances)) } diff --git a/lightclient-circuits/src/util/common.rs b/lightclient-circuits/src/util/common.rs index 0bedc338..32e18aaf 100644 --- a/lightclient-circuits/src/util/common.rs +++ b/lightclient-circuits/src/util/common.rs @@ -1,21 +1,16 @@ +#![allow(dead_code)] use crate::gadget::Expr; use eth_types::*; use halo2_base::{ - gates::{ - circuit::CircuitBuilderStage, - flex_gate::{FlexGateConfig, MultiPhaseThreadBreakPoints}, - }, + gates::circuit::CircuitBuilderStage, halo2_proofs::{ - circuit::{AssignedCell, Cell as Halo2Cell, Layouter, Region, Value}, - plonk::{ - Advice, Assigned, Column, ConstraintSystem, Error, Expression, Selector, VirtualCells, - }, + circuit::{AssignedCell, Layouter, Region, Value}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, poly::Rotation, }, virtual_region::{ copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, }, - Context, }; use std::hash::Hash; @@ -157,19 +152,4 @@ pub trait CommonGateManager: VirtualRegionManager + Clone { } fn unknown(self, use_unknown: bool) -> Self; - - // /// Returns a mutable reference to the [Context] of a gate thread. Spawns a new thread for the given phase, if none exists. - // /// * `phase`: The challenge phase (as an index) of the gate thread. - // fn main(&mut self) -> &mut Context; - - // fn witness_gen_only(&self) -> bool; - - // /// Returns the `use_unknown` flag. - // fn use_unknown(&self) -> bool; - - // /// Returns the current number of threads in the [GateThreadBuilder]. - // fn thread_count(&self) -> usize; - - // /// Creates a new thread id by incrementing the `thread count` - // fn get_new_thread_id(&mut self) -> usize; } diff --git a/lightclient-circuits/src/util/constraint_builder.rs b/lightclient-circuits/src/util/constraint_builder.rs index de93d226..b62b6e70 100644 --- a/lightclient-circuits/src/util/constraint_builder.rs +++ b/lightclient-circuits/src/util/constraint_builder.rs @@ -4,9 +4,6 @@ use halo2_base::halo2_proofs::plonk::Expression; use super::{Cell, CellType}; -pub type Constraint = (&'static str, Expression); -pub type Lookup = (&'static str, Vec<(Expression, Expression)>); - pub(crate) trait ConstrainBuilderCommon { fn add_constraint(&mut self, name: &'static str, constraint: Expression); @@ -100,6 +97,7 @@ impl BaseConstraintBuilder { } } + #[allow(dead_code)] pub(crate) fn require_zero(&mut self, name: &'static str, constraint: Expression) { self.add_constraint(name, constraint); } @@ -117,6 +115,7 @@ impl BaseConstraintBuilder { self.add_constraint(name, value.clone() * (1.expr() - value)); } + #[allow(dead_code)] pub(crate) fn require_in_set( &mut self, name: &'static str, @@ -145,6 +144,7 @@ impl BaseConstraintBuilder { ret } + #[allow(dead_code)] pub(crate) fn add_constraints(&mut self, constraints: Vec<(&'static str, Expression)>) { for (name, constraint) in constraints { self.add_constraint(name, constraint); diff --git a/lightclient-circuits/src/util/proof.rs b/lightclient-circuits/src/util/proof.rs index f7719e64..69460a96 100644 --- a/lightclient-circuits/src/util/proof.rs +++ b/lightclient-circuits/src/util/proof.rs @@ -4,22 +4,10 @@ use std::{fs::File, path::Path}; use ark_std::{end_timer, start_timer}; use halo2_base::halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, - plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, ProvingKey, VerifyingKey}, - poly::{ - commitment::{Params, ParamsProver}, - kzg::{ - commitment::{KZGCommitmentScheme, ParamsKZG}, - multiopen::{ProverGWC, ProverSHPLONK, VerifierSHPLONK}, - strategy::SingleStrategy, - }, - }, - transcript::{ - Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, - }, + plonk::{keygen_pk, keygen_vk, Circuit, ProvingKey, VerifyingKey}, + poly::kzg::commitment::ParamsKZG, SerdeFormat::RawBytesUnchecked, }; -use rand::rngs::OsRng; -use snark_verifier_sdk::CircuitExt; pub use halo2_base::utils::fs::{gen_srs, read_or_create_srs, read_params}; @@ -29,7 +17,10 @@ pub use halo2_base::utils::fs::{gen_srs, read_or_create_srs, read_params}; /// If the provided `k` value is larger than the `k` value of the loaded parameters, an error is returned, as the provided `k` is too large. /// Otherwise, if the `k` value is smaller than the `k` value of the loaded parameters, the parameters are downsized to fit the requested `k`. #[allow(clippy::type_complexity)] -pub fn read_vkey>(path: &Path, params: C::Params) -> Result, &'static str> { +pub fn read_vkey>( + path: &Path, + params: C::Params, +) -> Result, &'static str> { let timer = start_timer!(|| "Loading vkey"); let mut file = File::open(path).map_err(|_| "failed to read file")?; @@ -63,8 +54,12 @@ pub fn gen_pkey>( match File::open(&vkey_path) { Ok(mut file) => ( start_timer!(|| "Loading vkey"), - VerifyingKey::::read::<_, C>(&mut file, RawBytesUnchecked, circuit.params()) - .expect("failed to read vkey"), + VerifyingKey::::read::<_, C>( + &mut file, + RawBytesUnchecked, + circuit.params(), + ) + .expect("failed to read vkey"), ), Err(_) => { let timer = start_timer!(|| "Creating and writting vkey"); @@ -89,4 +84,3 @@ pub fn gen_pkey>( Ok(pkey) } - diff --git a/lightclient-circuits/src/witness/rotation.rs b/lightclient-circuits/src/witness/rotation.rs index d67330d0..4bc08be3 100644 --- a/lightclient-circuits/src/witness/rotation.rs +++ b/lightclient-circuits/src/witness/rotation.rs @@ -1,19 +1,9 @@ -use std::iter; -use std::marker::PhantomData; - use crate::gadget::crypto::constant_randomness; - -use super::HashInput; use eth_types::{Field, Spec}; -use sync_committee_primitives::consensus_types::{BeaconBlockHeader, BeaconState}; - -use halo2curves::bls12_381::Fq; -use halo2curves::bls12_381::G1; use itertools::Itertools; -use serde::Deserialize; -use sha2::{Digest, Sha256}; -use ssz_rs::Merkleized; -use ssz_rs::Node; +use std::iter; +use std::marker::PhantomData; +use sync_committee_primitives::consensus_types::BeaconBlockHeader; #[derive(Debug, Clone)] pub struct CommitteeRotationArgs { diff --git a/lightclient-circuits/src/witness/sync.rs b/lightclient-circuits/src/witness/sync.rs index 28dd5182..8feb3ccf 100644 --- a/lightclient-circuits/src/witness/sync.rs +++ b/lightclient-circuits/src/witness/sync.rs @@ -1,13 +1,10 @@ -use std::iter; -use std::marker::PhantomData; - -use super::HashInput; -use eth_types::{Field, Spec}; +use eth_types::Spec; use itertools::Itertools; use serde::Deserialize; use sha2::{Digest, Sha256}; -use ssz_rs::{Merkleized, Node}; -use sync_committee_primitives::consensus_types::{BeaconBlockHeader, BeaconState}; +use ssz_rs::Node; +use std::{iter, marker::PhantomData}; +use sync_committee_primitives::consensus_types::BeaconBlockHeader; #[derive(Debug, Clone, Deserialize)] pub struct SyncStepArgs { @@ -57,11 +54,10 @@ impl Default for SyncStepArgs { let beacon_block_body_root = compute_root(execution_state_root.clone(), &state_merkle_branch); - let mut finalized_block = BeaconBlockHeader { + let finalized_block = BeaconBlockHeader { body_root: Node::from_bytes(beacon_block_body_root.try_into().unwrap()), ..Default::default() }; - let finalized_header = finalized_block.hash_tree_root().unwrap().as_ref().to_vec(); let finality_merkle_branch = vec![vec![0; 32]; S::FINALIZED_HEADER_DEPTH]; From dfec12da59e7ea7c17283f90443d815a9c2940be Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Thu, 23 Nov 2023 16:34:46 +0100 Subject: [PATCH 13/23] rename circuit files back (to merge main) --- contract-tests/tests/rotation_input_encoding.rs | 2 +- contract-tests/tests/step_input_encoding.rs | 2 +- .../src/{rotation_circuit.rs => committee_update_circuit.rs} | 2 +- lightclient-circuits/src/lib.rs | 4 ++-- .../src/{step_circuit.rs => sync_step_circuit.rs} | 0 lightclient-circuits/tests/step.rs | 4 ++-- preprocessor/src/rotation.rs | 2 +- preprocessor/src/sync.rs | 2 +- prover/src/cli.rs | 4 ++-- prover/src/rpc.rs | 4 ++-- 10 files changed, 13 insertions(+), 13 deletions(-) rename lightclient-circuits/src/{rotation_circuit.rs => committee_update_circuit.rs} (99%) rename lightclient-circuits/src/{step_circuit.rs => sync_step_circuit.rs} (100%) diff --git a/contract-tests/tests/rotation_input_encoding.rs b/contract-tests/tests/rotation_input_encoding.rs index a97a6961..a6c564a0 100644 --- a/contract-tests/tests/rotation_input_encoding.rs +++ b/contract-tests/tests/rotation_input_encoding.rs @@ -7,7 +7,7 @@ use contract_tests::make_client; use eth_types::Minimal; use ethers::contract::abigen; use itertools::Itertools; -use lightclient_circuits::rotation_circuit::CommitteeUpdateCircuit; +use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; use lightclient_circuits::halo2_proofs::halo2curves::bn256::{self, Fr}; use lightclient_circuits::witness::CommitteeRotationArgs; use lightclient_circuits::LIMB_BITS; diff --git a/contract-tests/tests/step_input_encoding.rs b/contract-tests/tests/step_input_encoding.rs index 9237c539..24b3cbe0 100644 --- a/contract-tests/tests/step_input_encoding.rs +++ b/contract-tests/tests/step_input_encoding.rs @@ -5,7 +5,7 @@ use eth_types::Minimal; use ethers::contract::abigen; use lightclient_circuits::halo2_proofs::halo2curves::bn256; use lightclient_circuits::witness::SyncStepArgs; -use lightclient_circuits::{step_circuit::StepCircuit, LIMB_BITS}; +use lightclient_circuits::{sync_step_circuit::StepCircuit, LIMB_BITS}; use rstest::rstest; use ssz_rs::Merkleized; use test_utils::{ diff --git a/lightclient-circuits/src/rotation_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs similarity index 99% rename from lightclient-circuits/src/rotation_circuit.rs rename to lightclient-circuits/src/committee_update_circuit.rs index 3a2162c5..0ec9ac6e 100644 --- a/lightclient-circuits/src/rotation_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -2,7 +2,7 @@ use crate::{ gadget::crypto::{HashInstructions, Sha256ChipWide, ShaBitGateManager, ShaCircuitBuilder}, poseidon::{fq_array_poseidon, fq_array_poseidon_native}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, - step_circuit::clear_3_bits, + sync_step_circuit::clear_3_bits, util::{AppCircuit, CommonGateManager, Eth2ConfigPinning, IntoWitness}, witness::{self, HashInput, HashInputChunk}, Eth2CircuitBuilder, LIMB_BITS, NUM_LIMBS, diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 47e1139e..0b935785 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -12,8 +12,8 @@ pub mod util; pub mod witness; pub mod aggregation; -pub mod rotation_circuit; -pub mod step_circuit; +pub mod committee_update_circuit; +pub mod sync_step_circuit; pub mod poseidon; mod ssz_merkle; diff --git a/lightclient-circuits/src/step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs similarity index 100% rename from lightclient-circuits/src/step_circuit.rs rename to lightclient-circuits/src/sync_step_circuit.rs diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index b38ddbc0..5623aa64 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -4,8 +4,8 @@ use halo2_base::gates::circuit::CircuitBuilderStage; use halo2_base::halo2_proofs::dev::MockProver; use halo2_base::halo2_proofs::halo2curves::bn256; use lightclient_circuits::LIMB_BITS; -use lightclient_circuits::rotation_circuit::CommitteeUpdateCircuit; -use lightclient_circuits::step_circuit::StepCircuit; +use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; +use lightclient_circuits::sync_step_circuit::StepCircuit; use lightclient_circuits::util::gen_srs; use lightclient_circuits::util::AppCircuit; use lightclient_circuits::util::Eth2ConfigPinning; diff --git a/preprocessor/src/rotation.rs b/preprocessor/src/rotation.rs index 771daa8a..5d19496a 100644 --- a/preprocessor/src/rotation.rs +++ b/preprocessor/src/rotation.rs @@ -98,7 +98,7 @@ mod tests { use eth_types::Testnet; use crate::halo2_base::halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use lightclient_circuits::{ - rotation_circuit::CommitteeUpdateCircuit, + committee_update_circuit::CommitteeUpdateCircuit, util::{gen_srs, AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, halo2_base::gates::circuit::CircuitBuilderStage, }; use snark_verifier_sdk::CircuitExt; diff --git a/preprocessor/src/sync.rs b/preprocessor/src/sync.rs index c5e2faaa..34d36450 100644 --- a/preprocessor/src/sync.rs +++ b/preprocessor/src/sync.rs @@ -179,7 +179,7 @@ mod tests { use eth_types::Testnet; use lightclient_circuits::{ halo2_base::gates::circuit::CircuitBuilderStage, - step_circuit::StepCircuit, + sync_step_circuit::StepCircuit, util::{gen_srs, AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, }; use snark_verifier_sdk::CircuitExt; diff --git a/prover/src/cli.rs b/prover/src/cli.rs index a6ea5a0e..d86fb291 100644 --- a/prover/src/cli.rs +++ b/prover/src/cli.rs @@ -5,8 +5,8 @@ use ethers::providers::{Http, Provider}; use itertools::Itertools; use lightclient_circuits::{ halo2_proofs::halo2curves::bn256::{Bn256, Fr, G1Affine}, - rotation_circuit::CommitteeUpdateCircuit, - step_circuit::StepCircuit, + committee_update_circuit::CommitteeUpdateCircuit, + sync_step_circuit::StepCircuit, util::{gen_srs, AppCircuit}, }; use primitive_types::U256; diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index 5e556c3e..23152194 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -5,8 +5,8 @@ use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use jsonrpc_v2::{Error as JsonRpcError, Params}; use lightclient_circuits::{ - rotation_circuit::CommitteeUpdateCircuit, - step_circuit::StepCircuit, + committee_update_circuit::CommitteeUpdateCircuit, + sync_step_circuit::StepCircuit, util::{gen_srs, AppCircuit}, }; use preprocessor::{fetch_rotation_args, fetch_step_args}; From c914b58ee11130cba8bb58bffea46a097468efff Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Thu, 23 Nov 2023 18:37:04 +0100 Subject: [PATCH 14/23] post merge fixes --- .../tests/rotation_input_encoding.rs | 50 +--------- contract-tests/tests/step_input_encoding.rs | 5 +- contracts/rust-abi/lib.rs | 5 +- eth-types/src/lib.rs | 62 +------------ eth-types/src/spec.rs | 9 ++ .../src/committee_update_circuit.rs | 52 ++--------- lightclient-circuits/src/lib.rs | 3 - lightclient-circuits/src/poseidon.rs | 16 ++-- lightclient-circuits/src/sync_step_circuit.rs | 9 +- lightclient-circuits/src/witness/rotation.rs | 6 +- lightclient-circuits/src/witness/sync.rs | 14 ++- lightclient-circuits/tests/step.rs | 3 +- preprocessor/src/lib.rs | 5 +- preprocessor/src/rotation.rs | 8 +- preprocessor/src/sync.rs | 15 +-- prover/src/cli.rs | 4 +- prover/src/lib.rs | 1 + prover/src/rpc.rs | 93 ++++++------------- test-utils/src/lib.rs | 12 +-- 19 files changed, 94 insertions(+), 278 deletions(-) diff --git a/contract-tests/tests/rotation_input_encoding.rs b/contract-tests/tests/rotation_input_encoding.rs index f366cfbb..d57ac340 100644 --- a/contract-tests/tests/rotation_input_encoding.rs +++ b/contract-tests/tests/rotation_input_encoding.rs @@ -5,13 +5,13 @@ use std::path::PathBuf; use contract_tests::make_client; use eth_types::Minimal; +use eth_types::LIMB_BITS; use ethers::contract::abigen; use itertools::Itertools; use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; use lightclient_circuits::halo2_proofs::halo2curves::bn256::{self, Fr}; use lightclient_circuits::poseidon::poseidon_committee_commitment_from_compressed; use lightclient_circuits::witness::CommitteeRotationArgs; -use lightclient_circuits::LIMB_BITS; use rstest::rstest; use ssz_rs::prelude::*; use ssz_rs::Merkleized; @@ -23,7 +23,6 @@ abigen!( "../contracts/out/RotateExternal.sol/RotateExternal.json" ); - // CommitteeRotationArgs type produced by abigen macro matches the solidity struct type impl From> for RotateInput where @@ -35,10 +34,6 @@ where .pubkeys_compressed .iter() .cloned() - // .map(|mut b| { - // b.reverse(); - // b - // }) .collect_vec(), ) .unwrap(); @@ -55,7 +50,7 @@ where let sync_committee_ssz = pk_vector .hash_tree_root() .unwrap() - .as_bytes() + .deref() .try_into() .unwrap(); @@ -107,44 +102,3 @@ async fn test_rotate_public_input_evm_equivalence( Ok(()) } -// CommitteeRotationArgs type produced by abigen macro matches the solidity struct type -impl From> for RotateInput -where - [(); Spec::SYNC_COMMITTEE_SIZE]:, -{ - fn from(args: CommitteeRotationArgs) -> Self { - let poseidon_commitment_le = poseidon_committee_commitment_from_compressed( - &args - .pubkeys_compressed - .iter() - .cloned() - .map(|mut b| { - b.reverse(); - b - }) - .collect_vec(), - ) - .unwrap(); - - let mut pk_vector: Vector, { Spec::SYNC_COMMITTEE_SIZE }> = args - .pubkeys_compressed - .iter() - .cloned() - .map(|v| v.try_into().unwrap()) - .collect_vec() - .try_into() - .unwrap(); - - let sync_committee_ssz = pk_vector - .hash_tree_root() - .unwrap() - .deref() - .try_into() - .unwrap(); - - RotateInput { - sync_committee_ssz, - sync_committee_poseidon: poseidon_commitment_le, - } - } -} diff --git a/contract-tests/tests/step_input_encoding.rs b/contract-tests/tests/step_input_encoding.rs index 9cdd6b79..f53e43ce 100644 --- a/contract-tests/tests/step_input_encoding.rs +++ b/contract-tests/tests/step_input_encoding.rs @@ -2,13 +2,12 @@ use std::ops::Deref; use std::path::PathBuf; use contract_tests::make_client; -use eth_types::Minimal; +use eth_types::{Minimal, LIMB_BITS}; use ethers::contract::abigen; use lightclient_circuits::halo2_proofs::halo2curves::bn256; use lightclient_circuits::poseidon::poseidon_committee_commitment_from_uncompressed; -use lightclient_circuits::sync_step_circuit::SyncStepCircuit; +use lightclient_circuits::sync_step_circuit::StepCircuit; use lightclient_circuits::witness::SyncStepArgs; -use lightclient_circuits::{sync_step_circuit::StepCircuit, LIMB_BITS}; use rstest::rstest; use ssz_rs::Merkleized; use test_utils::read_test_files_and_gen_witness; diff --git a/contracts/rust-abi/lib.rs b/contracts/rust-abi/lib.rs index 016840c2..cfff4dda 100644 --- a/contracts/rust-abi/lib.rs +++ b/contracts/rust-abi/lib.rs @@ -1,6 +1,7 @@ +#![allow(incomplete_features)] #![feature(generic_const_exprs)] use std::ops::Deref; - +use eth_types::LIMB_BITS; use ethers::contract::abigen; use halo2_base::utils::ScalarField; use halo2curves::bls12_381::{self}; @@ -104,6 +105,6 @@ pub fn poseidon_committee_commitment_from_compressed(pubkeys_compressed: &[Vec(pubkeys_x).unwrap(); + let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x, LIMB_BITS).unwrap(); poseidon_commitment.to_bytes_le().try_into().unwrap() } diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index bbc4a9d9..735d57ec 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -5,67 +5,9 @@ #![feature(trait_alias)] mod spec; use halo2_base::utils::BigPrimeField; -// use halo2curves::FieldExt; pub use spec::{Mainnet, Minimal, Spec, Testnet}; -// mod curve; -// pub use curve::{AppCurveExt}; - -// use core::hash::Hash; -// use halo2_proofs::{ -// arithmetic::{Field as Halo2Field, FieldExt}, -// halo2curves::{ -// bn256::{Fq, Fr}, -// group::ff::PrimeField, -// }, -// }; +pub const NUM_LIMBS: usize = 4; +pub const LIMB_BITS: usize = 112; pub trait Field = BigPrimeField; - -// /// Trait used to reduce verbosity with the declaration of the [`PrimeField`] -// /// trait and its repr. -// pub trait Field: -// FieldExt + Halo2Field + Hash + Ord + halo2_ecc::fields::PrimeField -// { -// fn pow_const(&self, mut exp: usize) -> Self { -// if exp == 0 { -// return Self::ONE; -// } - -// let mut base = *self; - -// while exp & 1 == 0 { -// base = base.square(); -// exp >>= 1; -// } - -// let mut acc = base; -// while exp > 1 { -// exp >>= 1; -// base = base.square(); -// if exp & 1 == 1 { -// acc *= &base; -// } -// } -// acc -// } - -// /// Composes a field element from a little endian byte representation. -// /// WARNING: CAN OVERFLOW. -// fn from_bytes_le_unsecure<'a, I: IntoIterator>(bytes: I) -> Self { -// let two = Self::from(2); -// let mut value = Self::ZERO; -// for (i, byte) in bytes.into_iter().enumerate() { -// value += Self::from(*byte as u64) * two.pow_const(8 * i); -// } -// value -// } -// } - -// // Impl custom `Field` trait for BN256 Fr to be used and consistent with the -// // rest of the workspace. -// impl Field for Fr {} - -// // Impl custom `Field` trait for BN256 Frq to be used and consistent with the -// // rest of the workspace. -// impl Field for Fq {} diff --git a/eth-types/src/spec.rs b/eth-types/src/spec.rs index eeb406c3..0f9ff786 100644 --- a/eth-types/src/spec.rs +++ b/eth-types/src/spec.rs @@ -31,6 +31,9 @@ impl Spec for Minimal { const EXECUTION_STATE_ROOT_DEPTH: usize = 4; const FINALIZED_HEADER_INDEX: usize = 105; const FINALIZED_HEADER_DEPTH: usize = 6; + + const BYTES_PER_LOGS_BLOOM: usize = 256; + const MAX_EXTRA_DATA_BYTES: usize = 32; } #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] @@ -47,6 +50,9 @@ impl Spec for Testnet { const EXECUTION_STATE_ROOT_DEPTH: usize = 4; const FINALIZED_HEADER_INDEX: usize = 105; const FINALIZED_HEADER_DEPTH: usize = 6; + + const BYTES_PER_LOGS_BLOOM: usize = 256; + const MAX_EXTRA_DATA_BYTES: usize = 32; } #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] @@ -63,4 +69,7 @@ impl Spec for Mainnet { const EXECUTION_STATE_ROOT_DEPTH: usize = 4; const FINALIZED_HEADER_INDEX: usize = 105; const FINALIZED_HEADER_DEPTH: usize = 6; + + const BYTES_PER_LOGS_BLOOM: usize = 256; + const MAX_EXTRA_DATA_BYTES: usize = 32; } diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 588cbdac..7222f85c 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -5,9 +5,9 @@ use crate::{ sync_step_circuit::clear_3_bits, util::{AppCircuit, CommonGateManager, Eth2ConfigPinning, IntoWitness}, witness::{self, HashInput, HashInputChunk}, - Eth2CircuitBuilder, LIMB_BITS, NUM_LIMBS, + Eth2CircuitBuilder, }; -use eth_types::{Field, Spec}; +use eth_types::{Field, Spec, LIMB_BITS, NUM_LIMBS}; use halo2_base::{ gates::{ circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, RangeInstructions, @@ -103,44 +103,6 @@ impl CommitteeUpdateCircuit { Ok(public_inputs) } - pub fn instance(args: &witness::CommitteeRotationArgs) -> Vec> - where - [(); { S::SYNC_COMMITTEE_SIZE }]:, - { - let pubkeys_x = args.pubkeys_compressed.iter().cloned().map(|mut bytes| { - bytes.reverse(); - bytes[47] &= 0b00011111; - bls12_381::Fq::from_bytes_le(&bytes) - }); - - let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x).unwrap(); - - let mut pk_vector: Vector, { S::SYNC_COMMITTEE_SIZE }> = args - .pubkeys_compressed - .iter() - .cloned() - .map(|v| v.try_into().unwrap()) - .collect_vec() - .try_into() - .unwrap(); - - let ssz_root = pk_vector.hash_tree_root().unwrap(); - - let finalized_header_root = args.finalized_header.clone().hash_tree_root().unwrap(); - - let instance_vec = iter::once(poseidon_commitment) - .chain(ssz_root.as_ref().iter().map(|b| bn256::Fr::from(*b as u64))) - .chain( - finalized_header_root - .as_ref() - .iter() - .map(|b| bn256::Fr::from(*b as u64)), - ) - .collect(); - - vec![instance_vec] - } - fn decode_pubkeys_x( ctx: &mut Context, fp_chip: &FpChip<'_, F>, @@ -224,8 +186,13 @@ impl CommitteeUpdateCircuit { let finalized_header_root = args.finalized_header.clone().hash_tree_root().unwrap(); let instance_vec = iter::once(poseidon_commitment) - .chain(ssz_root.0.map(|b| bn256::Fr::from(b as u64))) - .chain(finalized_header_root.0.map(|b| bn256::Fr::from(b as u64))) + .chain(ssz_root.as_ref().iter().map(|b| bn256::Fr::from(*b as u64))) + .chain( + finalized_header_root + .as_ref() + .iter() + .map(|b| bn256::Fr::from(*b as u64)), + ) .collect(); vec![instance_vec] @@ -296,7 +263,6 @@ mod tests { }; use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk}; use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, CircuitExt, Snark}; - use sync_committee_primitives::consensus_types::BeaconBlockHeader; fn load_circuit_args() -> CommitteeRotationArgs { #[derive(serde::Deserialize)] diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 0b935785..48c2dded 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -21,9 +21,6 @@ mod ssz_merkle; pub use halo2_base; pub use halo2_base::halo2_proofs; -pub const NUM_LIMBS: usize = 4; -pub const LIMB_BITS: usize = 112; - use halo2_base::halo2_proofs::halo2curves::bn256; #[allow(type_alias_bounds)] pub type Eth2CircuitBuilder> = diff --git a/lightclient-circuits/src/poseidon.rs b/lightclient-circuits/src/poseidon.rs index f3b11c39..30ac3793 100644 --- a/lightclient-circuits/src/poseidon.rs +++ b/lightclient-circuits/src/poseidon.rs @@ -1,10 +1,13 @@ -use eth_types::Field; +use eth_types::{Field, LIMB_BITS}; use halo2_base::{ - gates::GateInstructions, halo2_proofs::plonk::Error, poseidon::hasher::PoseidonSponge, - AssignedValue, Context, + gates::GateInstructions, halo2_proofs::halo2curves::bn256, halo2_proofs::plonk::Error, + poseidon::hasher::PoseidonSponge, AssignedValue, Context, }; use halo2_ecc::bigint::ProperCrtUint; -use halo2curves::bls12_381::Fq; +use halo2curves::{ + bls12_381::{self, Fq}, + group::UncompressedEncoding, +}; use itertools::Itertools; use pse_poseidon::Poseidon as PoseidonNative; @@ -99,7 +102,8 @@ pub fn poseidon_committee_commitment_from_uncompressed( }) .collect_vec(); let poseidon_commitment = - fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x)).unwrap(); + fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x), LIMB_BITS) + .unwrap(); Ok(poseidon_commitment.to_bytes_le().try_into().unwrap()) } @@ -110,6 +114,6 @@ pub fn poseidon_committee_commitment_from_compressed( bytes[47] &= 0b00011111; bls12_381::Fq::from_bytes_le(&bytes) }); - let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x).unwrap(); + let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x, LIMB_BITS).unwrap(); Ok(poseidon_commitment.to_bytes_le().try_into().unwrap()) } diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 8bdd4a9b..986400e5 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -7,9 +7,9 @@ use crate::{ ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, util::{AppCircuit, Eth2ConfigPinning, IntoWitness}, witness::{self, HashInput, HashInputChunk, SyncStepArgs}, - Eth2CircuitBuilder, LIMB_BITS, NUM_LIMBS, + Eth2CircuitBuilder, }; -use eth_types::{Field, Spec}; +use eth_types::{Field, Spec, LIMB_BITS, NUM_LIMBS}; use halo2_base::{ gates::{ circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, GateInstructions, @@ -447,7 +447,10 @@ mod tests { use halo2_base::{ halo2_proofs::dev::MockProver, halo2_proofs::halo2curves::bn256::Fr, utils::fs::gen_srs, }; - use snark_verifier_sdk::{evm::{evm_verify, gen_evm_proof_shplonk}, CircuitExt}; + use snark_verifier_sdk::{ + evm::{evm_verify, gen_evm_proof_shplonk}, + CircuitExt, + }; fn load_circuit_args() -> SyncStepArgs { serde_json::from_slice(&fs::read("../test_data/sync_step_512.json").unwrap()).unwrap() diff --git a/lightclient-circuits/src/witness/rotation.rs b/lightclient-circuits/src/witness/rotation.rs index ca3b714d..5efb889e 100644 --- a/lightclient-circuits/src/witness/rotation.rs +++ b/lightclient-circuits/src/witness/rotation.rs @@ -1,13 +1,9 @@ use crate::gadget::crypto::constant_randomness; use eth_types::{Field, Spec}; use ethereum_consensus_types::BeaconBlockHeader; -use halo2curves::bls12_381::Fq; -use halo2curves::bls12_381::G1; use itertools::Itertools; use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; -use ssz_rs::Merkleized; -use ssz_rs::Node; +use std::{iter, marker::PhantomData}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CommitteeRotationArgs { diff --git a/lightclient-circuits/src/witness/sync.rs b/lightclient-circuits/src/witness/sync.rs index 476a2255..dd1d19ad 100644 --- a/lightclient-circuits/src/witness/sync.rs +++ b/lightclient-circuits/src/witness/sync.rs @@ -1,14 +1,12 @@ -use std::iter; -use std::marker::PhantomData; - -use super::HashInput; -use eth_types::{Field, Spec}; +use eth_types::Spec; use ethereum_consensus_types; +use ethereum_consensus_types::BeaconBlockHeader; use itertools::Itertools; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; -use ssz_rs::{Merkleized, Node}; -use ethereum_consensus_types::BeaconBlockHeader; +use ssz_rs::Node; +use std::iter; +use std::marker::PhantomData; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SyncStepArgs { @@ -58,7 +56,7 @@ impl Default for SyncStepArgs { let beacon_block_body_root = compute_root(execution_state_root.clone(), &state_merkle_branch); - let mut finalized_block = BeaconBlockHeader { + let finalized_block = BeaconBlockHeader { body_root: Node::try_from(beacon_block_body_root.as_slice()).unwrap(), ..Default::default() }; diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index 5623aa64..553535b1 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -1,9 +1,8 @@ use ark_std::{end_timer, start_timer}; -use eth_types::Minimal; +use eth_types::{Minimal, LIMB_BITS}; use halo2_base::gates::circuit::CircuitBuilderStage; use halo2_base::halo2_proofs::dev::MockProver; use halo2_base::halo2_proofs::halo2curves::bn256; -use lightclient_circuits::LIMB_BITS; use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; use lightclient_circuits::sync_step_circuit::StepCircuit; use lightclient_circuits::util::gen_srs; diff --git a/preprocessor/src/lib.rs b/preprocessor/src/lib.rs index 0e84a073..97594a12 100644 --- a/preprocessor/src/lib.rs +++ b/preprocessor/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(incomplete_features)] #![feature(generic_const_exprs)] mod sync; @@ -9,8 +10,8 @@ use ethereum_consensus_types::{ BeaconBlockHeader, ByteVector, LightClientBootstrap, LightClientFinalityUpdate, LightClientUpdateCapella, Root, }; -use halo2curves::bn256::Fr; use itertools::Itertools; +use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use lightclient_circuits::witness::{CommitteeRotationArgs, SyncStepArgs}; use serde::{Deserialize, Serialize}; use ssz_rs::{Node, Vector}; @@ -56,8 +57,6 @@ where signature_slot: update.signature_slot, }; -pub(crate) use lightclient_circuits::halo2_base; - let rotation_args = rotation::rotation_args_from_update(update).await?; let sync_args = diff --git a/preprocessor/src/rotation.rs b/preprocessor/src/rotation.rs index 5d498498..d295aab2 100644 --- a/preprocessor/src/rotation.rs +++ b/preprocessor/src/rotation.rs @@ -1,11 +1,10 @@ use std::marker::PhantomData; -use crate::halo2_base::halo2_proofs::halo2curves::bn256::Fr; use beacon_api_client::{BlockId, Client, ClientTypes}; use eth_types::Spec; use ethereum_consensus_types::{BeaconBlockHeader, LightClientUpdateCapella}; -use halo2curves::bn256::Fr; use itertools::Itertools; +use lightclient_circuits::halo2_base::halo2_proofs::halo2curves::bn256::Fr; use lightclient_circuits::{gadget::crypto, witness::CommitteeRotationArgs}; use log::debug; use ssz_rs::Merkleized; @@ -137,10 +136,11 @@ mod tests { use super::*; use beacon_api_client::mainnet::Client as MainnetClient; use eth_types::Testnet; - use crate::halo2_base::halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; + use lightclient_circuits::halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use lightclient_circuits::{ committee_update_circuit::CommitteeUpdateCircuit, - util::{gen_srs, AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, halo2_base::gates::circuit::CircuitBuilderStage, + halo2_base::gates::circuit::CircuitBuilderStage, + util::{gen_srs, AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, }; use reqwest::Url; use snark_verifier_sdk::CircuitExt; diff --git a/preprocessor/src/sync.rs b/preprocessor/src/sync.rs index fb48d838..6c8a6c05 100644 --- a/preprocessor/src/sync.rs +++ b/preprocessor/src/sync.rs @@ -66,13 +66,7 @@ pub async fn step_args_from_finality_update( ) -> eyre::Result> { let pubkeys_uncompressed = pubkeys_compressed .iter() - .map(|pk| { - G1Affine::from_bytes_unchecked(&pk.as_slice().try_into().unwrap()) - .unwrap() - .to_uncompressed() - .as_ref() - .to_vec() - }) + .map(|pk| pk.decompressed_bytes()) .collect_vec(); let execution_payload_root = finality_update @@ -125,6 +119,7 @@ pub async fn step_args_from_finality_update( .sync_aggregate .sync_committee_signature .to_bytes() + .to_vec(), pubkeys_uncompressed, pariticipation_bits: finality_update .sync_aggregate @@ -168,8 +163,8 @@ pub async fn read_step_args(path: String) -> eyre::Result(&client).await.unwrap(); - let witness = fetch_step_args::("http://3.128.78.74:5052".to_string()) - .await - .unwrap(); - StepCircuit::::gen_snark_shplonk( ¶ms, &pk, diff --git a/prover/src/cli.rs b/prover/src/cli.rs index eb04357f..68ba8446 100644 --- a/prover/src/cli.rs +++ b/prover/src/cli.rs @@ -76,12 +76,12 @@ where Proof::SyncStep(args) => { let client: Client = Client::new(Url::parse(&args.beacon_api_url).unwrap()); - generic_circuit_cli::, C, _>( + generic_circuit_cli::, C, _>( args, client, fetch_step_args, "step_circuit_testnet", - as AppCircuit>::Witness::default(), + as AppCircuit>::Witness::default(), ) .await?; } diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 0628a7b9..82b7823c 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(incomplete_features)] #![feature(generic_const_exprs)] pub mod rpc_api; pub mod rpc_client; diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index 569159f1..8fcc4b82 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -1,10 +1,9 @@ use super::args::Spec; - use ethers::prelude::*; -use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; - use itertools::Itertools; use jsonrpc_v2::{Error as JsonRpcError, Params}; +use jsonrpc_v2::{MapRouter as JsonRpcMapRouter, Server as JsonRpcServer}; +use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use lightclient_circuits::{ committee_update_circuit::CommitteeUpdateCircuit, sync_step_circuit::StepCircuit, @@ -13,15 +12,7 @@ use lightclient_circuits::{ use preprocessor::{ fetch_rotation_args, fetch_step_args, rotation_args_from_update, step_args_from_finality_update, }; - -use jsonrpc_v2::{MapRouter as JsonRpcMapRouter, Server as JsonRpcServer}; -use snark_verifier::loader::halo2::halo2_ecc::halo2_base::gates::builder::CircuitBuilderStage; -use snark_verifier_sdk::{ - evm::evm_verify, - gen_pk, - halo2::{aggregation::AggregationCircuit, gen_snark_shplonk}, - CircuitExt, Snark, SHPLONK, -}; +use snark_verifier_sdk::{evm::evm_verify, halo2::aggregation::AggregationCircuit, Snark}; use std::path::PathBuf; use url::Url; @@ -130,25 +121,16 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_handler( let l1_snark = { let k = k.unwrap_or(24); let p1 = gen_srs(k); - let mut circuit = AggregationCircuit::keygen::(&p1, vec![l0_snark.clone()]); - circuit.expose_previous_instances(false); - - println!("L1 Keygen num_instances: {:?}", circuit.num_instance()); - - let pk_l1 = gen_pk(&p1, &circuit, Some(&agg_l1_pk_path)); - let pinning = AggregationConfigPinning::from_path(agg_l1_config_path); - let lookup_bits = k as usize - 1; - let mut circuit = AggregationCircuit::new::( - CircuitBuilderStage::Prover, - Some(pinning.break_points), - lookup_bits, - &p1, - std::iter::once(l0_snark), - ); - circuit.expose_previous_instances(false); + let pk_l1 = AggregationCircuit::read_pk(&p1, agg_l1_pk_path, &vec![l0_snark.clone()]); - println!("L1 Prover num_instances: {:?}", circuit.num_instance()); - let snark = gen_snark_shplonk(&p1, &pk_l1, circuit, None::); + let snark = AggregationCircuit::gen_snark_shplonk( + &p1, + &pk_l1, + agg_l1_config_path, + None::, + &vec![l0_snark.clone()], + ) + .map_err(JsonRpcError::internal)?; println!("L1 snark size: {}", snark.proof.len()); snark @@ -157,26 +139,15 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_handler( let (proof, instances) = { let k = k.unwrap_or(24); let p2 = gen_srs(k); - let mut circuit = - AggregationCircuit::keygen::(&p2, std::iter::once(l1_snark.clone())); - circuit.expose_previous_instances(true); - - let pk_l2 = gen_pk(&p2, &circuit, Some(&agg_l2_pk_path)); - let pinning = AggregationConfigPinning::from_path(agg_l2_config_path); - - let mut circuit = AggregationCircuit::prover::( + let pk_l2 = AggregationCircuit::read_pk(&p2, agg_l2_pk_path, &vec![l1_snark.clone()]); + AggregationCircuit::gen_evm_proof_shplonk( &p2, - std::iter::once(l1_snark), - pinning.break_points, - ); - circuit.expose_previous_instances(true); - - let instances = circuit.instances(); - - let proof = - snark_verifier_sdk::evm::gen_evm_proof_shplonk(&p2, &pk_l2, circuit, instances.clone()); - - (proof, instances) + &pk_l2, + agg_l2_config_path, + None, + &vec![l1_snark.clone()], + ) + .map_err(JsonRpcError::internal)? }; let public_inputs = instances[0] @@ -247,11 +218,7 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_with_witness_handler( let l1_snark = { let k = k.unwrap_or(24); let p1 = gen_srs(k); - let pk_l1 = AggregationCircuit::read_pk( - &p1, - agg_l1_config_path, - &vec![l0_snark.clone()], - ); + let pk_l1 = AggregationCircuit::read_pk(&p1, agg_l1_pk_path, &vec![l0_snark.clone()]); let snark = AggregationCircuit::gen_snark_shplonk( &p1, @@ -269,11 +236,7 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_with_witness_handler( let (proof, instances) = { let k = k.unwrap_or(24); let p2 = gen_srs(k); - let pk_l2 = AggregationCircuit::read_pk( - &p2, - agg_l2_config_path, - &vec![l1_snark.clone()], - ); + let pk_l2 = AggregationCircuit::read_pk(&p2, agg_l2_pk_path, &vec![l1_snark.clone()]); AggregationCircuit::gen_evm_proof_shplonk( &p2, &pk_l2, @@ -312,7 +275,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_handler( let client = beacon_api_client::minimal::Client::new(Url::parse(&beacon_api)?); let witness = fetch_step_args(&client).await.unwrap(); - gen_evm_proof::>( + gen_evm_proof::>( k, build_dir, pk_filename, @@ -326,7 +289,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_handler( let witness = fetch_step_args(&client).await.unwrap(); - gen_evm_proof::>( + gen_evm_proof::>( k, build_dir, pk_filename, @@ -340,7 +303,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_handler( let witness = fetch_step_args(&client).await.unwrap(); - gen_evm_proof::>( + gen_evm_proof::>( k, build_dir, pk_filename, @@ -384,7 +347,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_with_witness_handler( let witness = step_args_from_finality_update(update, pubkeys, domain) .await .unwrap(); - gen_evm_proof::>( + gen_evm_proof::>( k, build_dir, pk_filename, @@ -400,7 +363,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_with_witness_handler( let witness = step_args_from_finality_update(update, pubkeys, domain) .await .unwrap(); - gen_evm_proof::>( + gen_evm_proof::>( k, build_dir, pk_filename, @@ -416,7 +379,7 @@ pub(crate) async fn gen_evm_proof_step_circuit_with_witness_handler( let witness = step_args_from_finality_update(update, pubkeys, domain) .await .unwrap(); - gen_evm_proof::>( + gen_evm_proof::>( k, build_dir, pk_filename, diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index 402ac5a9..1e8f1529 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -6,27 +6,21 @@ use crate::test_types::{ByteVector, TestMeta, TestStep}; use eth_types::Minimal; use ethereum_consensus_types::presets::minimal::{LightClientBootstrap, LightClientUpdateCapella}; use ethereum_consensus_types::signing::{compute_domain, DomainType}; +use ethereum_consensus_types::BeaconBlockHeader; use ethereum_consensus_types::{ForkData, Root}; -use halo2curves::bls12_381; -use halo2curves::group::UncompressedEncoding; use itertools::Itertools; use light_client_verifier::ZiplineUpdateWitnessCapella; use lightclient_circuits::gadget::crypto; -use lightclient_circuits::halo2_proofs::halo2curves::bn256::{self, Fr}; +use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use lightclient_circuits::poseidon::{ poseidon_committee_commitment_from_compressed, poseidon_committee_commitment_from_uncompressed, }; use lightclient_circuits::witness::{CommitteeRotationArgs, SyncStepArgs}; -use lightclient_circuits::LIMB_BITS; use ssz_rs::prelude::*; use ssz_rs::Merkleized; +use std::ops::Deref; use std::path::Path; -use sync_committee_primitives::consensus_types::BeaconBlockHeader; use zipline_test_utils::{load_snappy_ssz, load_yaml}; - -use crate::execution_payload_header::ExecutionPayloadHeader; -use crate::test_types::{ByteVector, TestMeta, TestStep}; -use ethereum_consensus_types::BeaconBlockHeader; pub mod conversions; mod execution_payload_header; mod test_types; From 2590c0d4fa8b1e274acb5334cdf4db89f491b79a Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Thu, 23 Nov 2023 18:59:49 +0100 Subject: [PATCH 15/23] fixes --- contract-tests/tests/spectre.rs | 29 +--------------------- contracts/rust-abi/lib.rs | 37 +++++++++++----------------- lightclient-circuits/src/poseidon.rs | 9 ++++--- prover/contractyul | 0 test-utils/src/conversions.rs | 4 --- 5 files changed, 20 insertions(+), 59 deletions(-) delete mode 100644 prover/contractyul diff --git a/contract-tests/tests/spectre.rs b/contract-tests/tests/spectre.rs index f9325205..9f716ac7 100644 --- a/contract-tests/tests/spectre.rs +++ b/contract-tests/tests/spectre.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use contract_tests::make_client; use contracts::{ - CommitteeUpdateMockVerifier, CommitteeUpdateVerifier, Spectre, StepMockVerifier, StepVerifier, + CommitteeUpdateMockVerifier, Spectre, StepMockVerifier, }; use ethers::core::types::U256; use ethers::providers::Middleware; @@ -75,33 +75,6 @@ async fn test_contract_initialization_and_first_step( //////////// deployment helpers ////////////////// -/// Deploy the Spectre contract using the given ethclient -/// Also deploys the step verifier and the update verifier contracts -/// and passes their addresses along with the other params to the constructor -async fn deploy_spectre( - ethclient: Arc, - initial_sync_period: usize, - initial_sync_committee_poseidon: [u8; 32], - slots_per_period: usize, -) -> anyhow::Result> { - let step_verifier = StepVerifier::deploy(ethclient.clone(), ())?.send().await?; - let update_verifier = CommitteeUpdateVerifier::deploy(ethclient.clone(), ())? - .send() - .await?; - Ok(Spectre::deploy( - ethclient, - ( - step_verifier.address(), - update_verifier.address(), - U256::from(initial_sync_period), - initial_sync_committee_poseidon, - U256::from(slots_per_period), - ), - )? - .send() - .await?) -} - /// Deploy the Spectre contract using the given ethclient /// Also deploys the step verifier and the update verifier contracts /// and passes their addresses along with the other params to the constructor diff --git a/contracts/rust-abi/lib.rs b/contracts/rust-abi/lib.rs index cfff4dda..6a090ac6 100644 --- a/contracts/rust-abi/lib.rs +++ b/contracts/rust-abi/lib.rs @@ -1,17 +1,14 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs)] -use std::ops::Deref; -use eth_types::LIMB_BITS; use ethers::contract::abigen; -use halo2_base::utils::ScalarField; -use halo2curves::bls12_381::{self}; use halo2curves::bn256::Fr; use itertools::Itertools; use lightclient_circuits::{ - poseidon::fq_array_poseidon_native, + poseidon::poseidon_committee_commitment_from_compressed, witness::{CommitteeRotationArgs, SyncStepArgs}, }; use ssz_rs::{Merkleized, Vector}; +use std::ops::Deref; abigen!( Spectre, "./out/Spectre.sol/Spectre.json"; @@ -66,16 +63,9 @@ where { fn from(args: CommitteeRotationArgs) -> Self { let poseidon_commitment_le = poseidon_committee_commitment_from_compressed( - &args - .pubkeys_compressed - .iter() - .cloned() - .map(|mut b| { - b.reverse(); - b - }) - .collect_vec(), - ); + &args.pubkeys_compressed.iter().cloned().collect_vec(), + ) + .unwrap(); let mut pk_vector: Vector, { Spec::SYNC_COMMITTEE_SIZE }> = args .pubkeys_compressed @@ -100,11 +90,12 @@ where } } -pub fn poseidon_committee_commitment_from_compressed(pubkeys_compressed: &[Vec]) -> [u8; 32] { - let pubkeys_x = pubkeys_compressed.iter().cloned().map(|mut bytes| { - bytes[47] &= 0b00011111; - bls12_381::Fq::from_bytes_le(&bytes) - }); - let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x, LIMB_BITS).unwrap(); - poseidon_commitment.to_bytes_le().try_into().unwrap() -} +// pub fn poseidon_committee_commitment_from_compressed(pubkeys_compressed: &[Vec]) -> [u8; 32] { +// let pubkeys_x = pubkeys_compressed.iter().cloned().map(|mut bytes| { +// bytes[0] &= 0b00011111; +// bls12_381::Fq::from_bytes_be(&bytes.try_into().unwrap()) +// .expect("bad bls12_381::Fq encoding") +// }); +// let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x, LIMB_BITS).unwrap(); +// poseidon_commitment.to_bytes() +// } diff --git a/lightclient-circuits/src/poseidon.rs b/lightclient-circuits/src/poseidon.rs index 30ac3793..3bd37087 100644 --- a/lightclient-circuits/src/poseidon.rs +++ b/lightclient-circuits/src/poseidon.rs @@ -104,16 +104,17 @@ pub fn poseidon_committee_commitment_from_uncompressed( let poseidon_commitment = fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x), LIMB_BITS) .unwrap(); - Ok(poseidon_commitment.to_bytes_le().try_into().unwrap()) + Ok(poseidon_commitment.to_bytes()) } pub fn poseidon_committee_commitment_from_compressed( pubkeys_compressed: &[Vec], ) -> Result<[u8; 32], Error> { let pubkeys_x = pubkeys_compressed.iter().cloned().map(|mut bytes| { - bytes[47] &= 0b00011111; - bls12_381::Fq::from_bytes_le(&bytes) + bytes[0] &= 0b00011111; + bls12_381::Fq::from_bytes_be(&bytes.try_into().unwrap()) + .expect("bad bls12_381::Fq encoding") }); let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x, LIMB_BITS).unwrap(); - Ok(poseidon_commitment.to_bytes_le().try_into().unwrap()) + Ok(poseidon_commitment.to_bytes()) } diff --git a/prover/contractyul b/prover/contractyul deleted file mode 100644 index e69de29b..00000000 diff --git a/test-utils/src/conversions.rs b/test-utils/src/conversions.rs index c94b2cf5..6e7c986c 100644 --- a/test-utils/src/conversions.rs +++ b/test-utils/src/conversions.rs @@ -43,10 +43,6 @@ where .pubkeys_compressed .iter() .cloned() - // .map(|mut b| { - // b.reverse(); - // b - // }) .collect_vec(), ) .unwrap(); From e3ed3af784b2b56b5dea73d727c5904f6f45f0ee Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Thu, 23 Nov 2023 19:00:12 +0100 Subject: [PATCH 16/23] fmt --- contract-tests/tests/rotation_input_encoding.rs | 7 +------ contract-tests/tests/spectre.rs | 4 +--- lightclient-circuits/src/gadget/common.rs | 9 ++------- lightclient-circuits/src/util.rs | 1 - prover/src/cli.rs | 2 +- test-utils/src/conversions.rs | 6 +----- 6 files changed, 6 insertions(+), 23 deletions(-) diff --git a/contract-tests/tests/rotation_input_encoding.rs b/contract-tests/tests/rotation_input_encoding.rs index d57ac340..569ee89a 100644 --- a/contract-tests/tests/rotation_input_encoding.rs +++ b/contract-tests/tests/rotation_input_encoding.rs @@ -30,11 +30,7 @@ where { fn from(args: CommitteeRotationArgs) -> Self { let poseidon_commitment_le = poseidon_committee_commitment_from_compressed( - &args - .pubkeys_compressed - .iter() - .cloned() - .collect_vec(), + &args.pubkeys_compressed.iter().cloned().collect_vec(), ) .unwrap(); @@ -101,4 +97,3 @@ async fn test_rotate_public_input_evm_equivalence( assert_eq!(vec![result_decoded], instance); Ok(()) } - diff --git a/contract-tests/tests/spectre.rs b/contract-tests/tests/spectre.rs index 9f716ac7..848706ef 100644 --- a/contract-tests/tests/spectre.rs +++ b/contract-tests/tests/spectre.rs @@ -6,9 +6,7 @@ use std::path::PathBuf; use std::sync::Arc; use contract_tests::make_client; -use contracts::{ - CommitteeUpdateMockVerifier, Spectre, StepMockVerifier, -}; +use contracts::{CommitteeUpdateMockVerifier, Spectre, StepMockVerifier}; use ethers::core::types::U256; use ethers::providers::Middleware; use rstest::rstest; diff --git a/lightclient-circuits/src/gadget/common.rs b/lightclient-circuits/src/gadget/common.rs index d5631dab..f75351c2 100644 --- a/lightclient-circuits/src/gadget/common.rs +++ b/lightclient-circuits/src/gadget/common.rs @@ -177,12 +177,7 @@ impl Expr for i32 { #[inline] fn expr(&self) -> Expression { Expression::Constant( - F::from(self.unsigned_abs() as u64) - * if self.is_negative() { - -F::ONE - } else { - F::ONE - }, + F::from(self.unsigned_abs() as u64) * if self.is_negative() { -F::ONE } else { F::ONE }, ) } } @@ -205,7 +200,7 @@ pub mod rlc { use std::ops::{Add, Mul}; use super::{Expr, Expression, Field}; - use halo2_base::{AssignedValue, Context, QuantumCell, gates::GateInstructions}; + use halo2_base::{gates::GateInstructions, AssignedValue, Context, QuantumCell}; /// Returns an expression that represents the random linear combination. pub fn expr>(expressions: &[E], randomness: E) -> Expression { diff --git a/lightclient-circuits/src/util.rs b/lightclient-circuits/src/util.rs index 8a2ae106..4ae8e821 100644 --- a/lightclient-circuits/src/util.rs +++ b/lightclient-circuits/src/util.rs @@ -24,7 +24,6 @@ pub trait AsBits { fn as_bits(&self) -> [bool; N]; } - /// Packs bits into bytes pub mod to_bytes { use crate::gadget::Expr; diff --git a/prover/src/cli.rs b/prover/src/cli.rs index 68ba8446..442fae6f 100644 --- a/prover/src/cli.rs +++ b/prover/src/cli.rs @@ -6,8 +6,8 @@ use ethers::abi::Address; use ethers::providers::{Http, Provider}; use itertools::Itertools; use lightclient_circuits::{ - halo2_proofs::halo2curves::bn256::{Bn256, Fr, G1Affine}, committee_update_circuit::CommitteeUpdateCircuit, + halo2_proofs::halo2curves::bn256::{Bn256, Fr, G1Affine}, sync_step_circuit::StepCircuit, util::{gen_srs, AppCircuit}, }; diff --git a/test-utils/src/conversions.rs b/test-utils/src/conversions.rs index 6e7c986c..753b45d2 100644 --- a/test-utils/src/conversions.rs +++ b/test-utils/src/conversions.rs @@ -39,11 +39,7 @@ where [(); Spec::SYNC_COMMITTEE_SIZE]:, { let poseidon_commitment_le = poseidon_committee_commitment_from_compressed( - &args - .pubkeys_compressed - .iter() - .cloned() - .collect_vec(), + &args.pubkeys_compressed.iter().cloned().collect_vec(), ) .unwrap(); From 4afe0455c1339821f2d1886b9d93e0365f0dcb86 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Sun, 26 Nov 2023 21:19:18 +0100 Subject: [PATCH 17/23] wip --- Cargo.toml | 39 +- eth-types/src/lib.rs | 3 +- lightclient-circuits/Cargo.toml | 4 +- .../config/committee_update_18.json | 21 + .../config/committee_update_21.json | 19 + .../config/committee_update_a.json | 15 + lightclient-circuits/contractyul | 2307 +++++++++++++++++ .../src/committee_update_circuit.rs | 91 +- lightclient-circuits/src/gadget/common.rs | 27 +- .../src/gadget/crypto/builder.rs | 2 +- .../src/gadget/crypto/sha256_flex.rs | 25 +- .../src/gadget/crypto/sha256_flex/gate.rs | 11 +- .../src/gadget/crypto/sha256_flex/spread.rs | 9 +- .../src/gadget/crypto/sha256_wide.rs | 198 +- .../src/gadget/crypto/sha256_wide/config.rs | 13 + .../src/gadget/crypto/sha256_wide/gate.rs | 183 +- lightclient-circuits/src/poseidon.rs | 18 +- lightclient-circuits/src/ssz_merkle.rs | 5 +- lightclient-circuits/src/sync_step_circuit.rs | 42 +- lightclient-circuits/src/util/circuit.rs | 3 +- 20 files changed, 2694 insertions(+), 341 deletions(-) create mode 100644 lightclient-circuits/config/committee_update_18.json create mode 100644 lightclient-circuits/config/committee_update_21.json create mode 100644 lightclient-circuits/config/committee_update_a.json create mode 100644 lightclient-circuits/contractyul diff --git a/Cargo.toml b/Cargo.toml index e2c9c6af..2b0438c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,9 @@ halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "comm "jemallocator" ] } halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } -halo2curves = { git = "https://github.com/axiom-crypto/halo2curves", version = "0.4.0" } +zkevm-hashes = { git = "https://github.com/axiom-crypto/halo2-lib", branch = "community-edition", default-features = false } + +halo2curves = { package = "halo2curves-axiom", version = "0.4.2" } # verifier SDK @@ -73,7 +75,7 @@ ff = "0.12" sha2 = { version = "0.10.6", features = ["compress"] } uint = "0.9.1" ark-std = { version = "0.4.0", features = ["print-trace"] } -poseidon_native = { git = "https://github.com/axiom-crypto/halo2.git", branch = "axiom/dev", package = "poseidon" } +# poseidon_native = { git = "https://github.com/axiom-crypto/halo2.git", branch = "axiom/dev", package = "poseidon" } # misc itertools = "0.11.0" @@ -82,34 +84,33 @@ serde_json = "1.0.78" log = "0.4.14" hex = "0.4" -[patch."https://github.com/axiom-crypto/halo2curves"] -halo2curves = { git = "https://github.com/timoftime/halo2curves", branch = "support_bls12-381" } -# halo2curves = { path = "../halo2curves" } +[patch.crates-io] +halo2curves = { git = "https://github.com/timoftime/halo2curves", package = "halo2curves-axiom", rev = "f3bb3f5a7d3a8ca806368f185c112283a73a94cb" } +ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } [patch."https://github.com/axiom-crypto/halo2-lib"] -halo2-base = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ - "halo2-pse", - "display", - "jemallocator" -] } -halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ - "halo2-pse", - "jemallocator" -] } -# halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ +# halo2-base = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ # "halo2-pse", # "display", +# "jemallocator" # ] } -# halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false, features = [ +# halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ # "halo2-pse", +# "jemallocator" # ] } +halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ + "halo2-pse", + "display", +] } +halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false, features = [ + "halo2-pse", +] } +zkevm-hashes = { path = "../halo2-lib/hashes/zkevm", default-features = false } + [patch."https://github.com/axiom-crypto/snark-verifier.git"] snark-verifier = { git = "https://github.com/timoftime/snark-verifier", branch = "halo2-pse-fix", default-features = false } snark-verifier-sdk = { git = "https://github.com/timoftime/snark-verifier", branch = "halo2-pse-fix", default-features = false } # snark-verifier = { path = "../snark-verifier/snark-verifier" } # snark-verifier-sdk = { path = "../snark-verifier/snark-verifier-sdk" } - -[patch.crates-io] -ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index 735d57ec..12cb69e3 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -5,9 +5,10 @@ #![feature(trait_alias)] mod spec; use halo2_base::utils::BigPrimeField; +use halo2curves::ff::PrimeField; pub use spec::{Mainnet, Minimal, Spec, Testnet}; pub const NUM_LIMBS: usize = 4; pub const LIMB_BITS: usize = 112; -pub trait Field = BigPrimeField; +pub trait Field = BigPrimeField + PrimeField; diff --git a/lightclient-circuits/Cargo.toml b/lightclient-circuits/Cargo.toml index 76ee3dfa..f2f9c959 100644 --- a/lightclient-circuits/Cargo.toml +++ b/lightclient-circuits/Cargo.toml @@ -10,6 +10,7 @@ license = "MIT OR Apache-2.0" halo2curves.workspace = true halo2-base.workspace = true halo2-ecc.workspace = true +zkevm-hashes.workspace = true # verifier SDK snark-verifier.workspace = true @@ -21,7 +22,7 @@ num-bigint.workspace = true pasta_curves.workspace = true ff.workspace = true sha2.workspace = true -pse-poseidon = { git = "https://github.com/axiom-crypto/pse-poseidon.git" } +# pse-poseidon = { git = "https://github.com/axiom-crypto/pse-poseidon.git" } # ethereum ssz_rs = { workspace = true, features = ["serde"] } @@ -37,7 +38,6 @@ serde_json.workspace = true itertools.workspace = true log.workspace = true hex.workspace = true -poseidon_native.workspace = true rayon = "1.7.0" array-init = "2.0.0" strum = "0.25" diff --git a/lightclient-circuits/config/committee_update_18.json b/lightclient-circuits/config/committee_update_18.json new file mode 100644 index 00000000..4649060f --- /dev/null +++ b/lightclient-circuits/config/committee_update_18.json @@ -0,0 +1,21 @@ +{ + "params": { + "k": 18, + "num_advice_per_phase": [ + 2 + ], + "num_fixed": 1, + "num_lookup_advice_per_phase": [ + 0, + 0, + 0 + ], + "lookup_bits": 8, + "num_instance_columns": 1 + }, + "break_points": [ + [ + 262134 + ] + ] +} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_21.json b/lightclient-circuits/config/committee_update_21.json new file mode 100644 index 00000000..fbd8480f --- /dev/null +++ b/lightclient-circuits/config/committee_update_21.json @@ -0,0 +1,19 @@ +{ + "params": { + "k": 21, + "num_advice_per_phase": [ + 1 + ], + "num_fixed": 1, + "num_lookup_advice_per_phase": [ + 0, + 0, + 0 + ], + "lookup_bits": 8, + "num_instance_columns": 1 + }, + "break_points": [ + [] + ] +} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_a.json b/lightclient-circuits/config/committee_update_a.json new file mode 100644 index 00000000..0295772a --- /dev/null +++ b/lightclient-circuits/config/committee_update_a.json @@ -0,0 +1,15 @@ +{ + "params": { + "degree": 23, + "num_advice": 3, + "num_lookup_advice": 1, + "num_fixed": 1, + "lookup_bits": 8 + }, + "break_points": [ + [ + 8388596, + 8388598 + ] + ] +} \ No newline at end of file diff --git a/lightclient-circuits/contractyul b/lightclient-circuits/contractyul new file mode 100644 index 00000000..eb08407c --- /dev/null +++ b/lightclient-circuits/contractyul @@ -0,0 +1,2307 @@ + +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.19 <0.8.21; + +contract Halo2Verifier { + fallback(bytes calldata) external returns (bytes memory) { + assembly { + let success := true + let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + let f_q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 + function validate_ec_point(x, y) -> valid { + { + let x_lt_p := lt(x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let y_lt_p := lt(y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + valid := and(x_lt_p, y_lt_p) + } + { + let y_square := mulmod(y, y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_square := mulmod(x, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_cube := mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_cube_plus_3 := addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let is_affine := eq(x_cube_plus_3, y_square) + valid := and(valid, is_affine) + } + } + mstore(0x20, mod(calldataload(0x0), f_q)) +mstore(0x40, mod(calldataload(0x20), f_q)) +mstore(0x60, mod(calldataload(0x40), f_q)) +mstore(0x80, mod(calldataload(0x60), f_q)) +mstore(0xa0, mod(calldataload(0x80), f_q)) +mstore(0xc0, mod(calldataload(0xa0), f_q)) +mstore(0xe0, mod(calldataload(0xc0), f_q)) +mstore(0x100, mod(calldataload(0xe0), f_q)) +mstore(0x120, mod(calldataload(0x100), f_q)) +mstore(0x140, mod(calldataload(0x120), f_q)) +mstore(0x160, mod(calldataload(0x140), f_q)) +mstore(0x180, mod(calldataload(0x160), f_q)) +mstore(0x1a0, mod(calldataload(0x180), f_q)) +mstore(0x1c0, mod(calldataload(0x1a0), f_q)) +mstore(0x1e0, mod(calldataload(0x1c0), f_q)) +mstore(0x200, mod(calldataload(0x1e0), f_q)) +mstore(0x220, mod(calldataload(0x200), f_q)) +mstore(0x240, mod(calldataload(0x220), f_q)) +mstore(0x260, mod(calldataload(0x240), f_q)) +mstore(0x280, mod(calldataload(0x260), f_q)) +mstore(0x2a0, mod(calldataload(0x280), f_q)) +mstore(0x2c0, mod(calldataload(0x2a0), f_q)) +mstore(0x2e0, mod(calldataload(0x2c0), f_q)) +mstore(0x300, mod(calldataload(0x2e0), f_q)) +mstore(0x320, mod(calldataload(0x300), f_q)) +mstore(0x340, mod(calldataload(0x320), f_q)) +mstore(0x360, mod(calldataload(0x340), f_q)) +mstore(0x380, mod(calldataload(0x360), f_q)) +mstore(0x3a0, mod(calldataload(0x380), f_q)) +mstore(0x3c0, mod(calldataload(0x3a0), f_q)) +mstore(0x3e0, mod(calldataload(0x3c0), f_q)) +mstore(0x400, mod(calldataload(0x3e0), f_q)) +mstore(0x420, mod(calldataload(0x400), f_q)) +mstore(0x440, mod(calldataload(0x420), f_q)) +mstore(0x460, mod(calldataload(0x440), f_q)) +mstore(0x480, mod(calldataload(0x460), f_q)) +mstore(0x4a0, mod(calldataload(0x480), f_q)) +mstore(0x4c0, mod(calldataload(0x4a0), f_q)) +mstore(0x4e0, mod(calldataload(0x4c0), f_q)) +mstore(0x500, mod(calldataload(0x4e0), f_q)) +mstore(0x520, mod(calldataload(0x500), f_q)) +mstore(0x540, mod(calldataload(0x520), f_q)) +mstore(0x560, mod(calldataload(0x540), f_q)) +mstore(0x580, mod(calldataload(0x560), f_q)) +mstore(0x5a0, mod(calldataload(0x580), f_q)) +mstore(0x5c0, mod(calldataload(0x5a0), f_q)) +mstore(0x5e0, mod(calldataload(0x5c0), f_q)) +mstore(0x600, mod(calldataload(0x5e0), f_q)) +mstore(0x620, mod(calldataload(0x600), f_q)) +mstore(0x640, mod(calldataload(0x620), f_q)) +mstore(0x660, mod(calldataload(0x640), f_q)) +mstore(0x680, mod(calldataload(0x660), f_q)) +mstore(0x6a0, mod(calldataload(0x680), f_q)) +mstore(0x6c0, mod(calldataload(0x6a0), f_q)) +mstore(0x6e0, mod(calldataload(0x6c0), f_q)) +mstore(0x700, mod(calldataload(0x6e0), f_q)) +mstore(0x720, mod(calldataload(0x700), f_q)) +mstore(0x740, mod(calldataload(0x720), f_q)) +mstore(0x760, mod(calldataload(0x740), f_q)) +mstore(0x780, mod(calldataload(0x760), f_q)) +mstore(0x7a0, mod(calldataload(0x780), f_q)) +mstore(0x7c0, mod(calldataload(0x7a0), f_q)) +mstore(0x7e0, mod(calldataload(0x7c0), f_q)) +mstore(0x800, mod(calldataload(0x7e0), f_q)) +mstore(0x820, mod(calldataload(0x800), f_q)) +mstore(0x840, mod(calldataload(0x820), f_q)) +mstore(0x860, mod(calldataload(0x840), f_q)) +mstore(0x880, mod(calldataload(0x860), f_q)) +mstore(0x8a0, mod(calldataload(0x880), f_q)) +mstore(0x8c0, mod(calldataload(0x8a0), f_q)) +mstore(0x8e0, mod(calldataload(0x8c0), f_q)) +mstore(0x900, mod(calldataload(0x8e0), f_q)) +mstore(0x920, mod(calldataload(0x900), f_q)) +mstore(0x940, mod(calldataload(0x920), f_q)) +mstore(0x960, mod(calldataload(0x940), f_q)) +mstore(0x980, mod(calldataload(0x960), f_q)) +mstore(0x9a0, mod(calldataload(0x980), f_q)) +mstore(0x0, 14012635205581322793076264054699840890414958961805977117099281830200581711072) + + { + let x := calldataload(0x9a0) + mstore(0x9c0, x) + let y := calldataload(0x9c0) + mstore(0x9e0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x9e0) + mstore(0xa00, x) + let y := calldataload(0xa00) + mstore(0xa20, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xa20) + mstore(0xa40, x) + let y := calldataload(0xa40) + mstore(0xa60, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xa60) + mstore(0xa80, x) + let y := calldataload(0xa80) + mstore(0xaa0, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0xac0, keccak256(0x0, 2752)) +{ + let hash := mload(0xac0) + mstore(0xae0, mod(hash, f_q)) + mstore(0xb00, hash) + } + + { + let x := calldataload(0xaa0) + mstore(0xb20, x) + let y := calldataload(0xac0) + mstore(0xb40, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xae0) + mstore(0xb60, x) + let y := calldataload(0xb00) + mstore(0xb80, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0xba0, keccak256(0xb00, 160)) +{ + let hash := mload(0xba0) + mstore(0xbc0, mod(hash, f_q)) + mstore(0xbe0, hash) + } +mstore8(3072, 1) +mstore(0xc00, keccak256(0xbe0, 33)) +{ + let hash := mload(0xc00) + mstore(0xc20, mod(hash, f_q)) + mstore(0xc40, hash) + } + + { + let x := calldataload(0xb20) + mstore(0xc60, x) + let y := calldataload(0xb40) + mstore(0xc80, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xb60) + mstore(0xca0, x) + let y := calldataload(0xb80) + mstore(0xcc0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xba0) + mstore(0xce0, x) + let y := calldataload(0xbc0) + mstore(0xd00, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xbe0) + mstore(0xd20, x) + let y := calldataload(0xc00) + mstore(0xd40, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xc20) + mstore(0xd60, x) + let y := calldataload(0xc40) + mstore(0xd80, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0xda0, keccak256(0xc40, 352)) +{ + let hash := mload(0xda0) + mstore(0xdc0, mod(hash, f_q)) + mstore(0xde0, hash) + } + + { + let x := calldataload(0xc60) + mstore(0xe00, x) + let y := calldataload(0xc80) + mstore(0xe20, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xca0) + mstore(0xe40, x) + let y := calldataload(0xcc0) + mstore(0xe60, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0xce0) + mstore(0xe80, x) + let y := calldataload(0xd00) + mstore(0xea0, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0xec0, keccak256(0xde0, 224)) +{ + let hash := mload(0xec0) + mstore(0xee0, mod(hash, f_q)) + mstore(0xf00, hash) + } +mstore(0xf20, mod(calldataload(0xd20), f_q)) +mstore(0xf40, mod(calldataload(0xd40), f_q)) +mstore(0xf60, mod(calldataload(0xd60), f_q)) +mstore(0xf80, mod(calldataload(0xd80), f_q)) +mstore(0xfa0, mod(calldataload(0xda0), f_q)) +mstore(0xfc0, mod(calldataload(0xdc0), f_q)) +mstore(0xfe0, mod(calldataload(0xde0), f_q)) +mstore(0x1000, mod(calldataload(0xe00), f_q)) +mstore(0x1020, mod(calldataload(0xe20), f_q)) +mstore(0x1040, mod(calldataload(0xe40), f_q)) +mstore(0x1060, mod(calldataload(0xe60), f_q)) +mstore(0x1080, mod(calldataload(0xe80), f_q)) +mstore(0x10a0, mod(calldataload(0xea0), f_q)) +mstore(0x10c0, mod(calldataload(0xec0), f_q)) +mstore(0x10e0, mod(calldataload(0xee0), f_q)) +mstore(0x1100, mod(calldataload(0xf00), f_q)) +mstore(0x1120, mod(calldataload(0xf20), f_q)) +mstore(0x1140, mod(calldataload(0xf40), f_q)) +mstore(0x1160, mod(calldataload(0xf60), f_q)) +mstore(0x1180, mod(calldataload(0xf80), f_q)) +mstore(0x11a0, mod(calldataload(0xfa0), f_q)) +mstore(0x11c0, mod(calldataload(0xfc0), f_q)) +mstore(0x11e0, mod(calldataload(0xfe0), f_q)) +mstore(0x1200, mod(calldataload(0x1000), f_q)) +mstore(0x1220, mod(calldataload(0x1020), f_q)) +mstore(0x1240, mod(calldataload(0x1040), f_q)) +mstore(0x1260, mod(calldataload(0x1060), f_q)) +mstore(0x1280, mod(calldataload(0x1080), f_q)) +mstore(0x12a0, mod(calldataload(0x10a0), f_q)) +mstore(0x12c0, mod(calldataload(0x10c0), f_q)) +mstore(0x12e0, mod(calldataload(0x10e0), f_q)) +mstore(0x1300, mod(calldataload(0x1100), f_q)) +mstore(0x1320, mod(calldataload(0x1120), f_q)) +mstore(0x1340, mod(calldataload(0x1140), f_q)) +mstore(0x1360, mod(calldataload(0x1160), f_q)) +mstore(0x1380, mod(calldataload(0x1180), f_q)) +mstore(0x13a0, mod(calldataload(0x11a0), f_q)) +mstore(0x13c0, mod(calldataload(0x11c0), f_q)) +mstore(0x13e0, keccak256(0xf00, 1248)) +{ + let hash := mload(0x13e0) + mstore(0x1400, mod(hash, f_q)) + mstore(0x1420, hash) + } +mstore8(5184, 1) +mstore(0x1440, keccak256(0x1420, 33)) +{ + let hash := mload(0x1440) + mstore(0x1460, mod(hash, f_q)) + mstore(0x1480, hash) + } + + { + let x := calldataload(0x11e0) + mstore(0x14a0, x) + let y := calldataload(0x1200) + mstore(0x14c0, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x14e0, keccak256(0x1480, 96)) +{ + let hash := mload(0x14e0) + mstore(0x1500, mod(hash, f_q)) + mstore(0x1520, hash) + } + + { + let x := calldataload(0x1220) + mstore(0x1540, x) + let y := calldataload(0x1240) + mstore(0x1560, y) + success := and(validate_ec_point(x, y), success) + } +{ + let x := mload(0x20) +x := add(x, shl(88, mload(0x40))) +x := add(x, shl(176, mload(0x60))) +mstore(5504, x) +let y := mload(0x80) +y := add(y, shl(88, mload(0xa0))) +y := add(y, shl(176, mload(0xc0))) +mstore(5536, y) + + success := and(validate_ec_point(x, y), success) + } +{ + let x := mload(0xe0) +x := add(x, shl(88, mload(0x100))) +x := add(x, shl(176, mload(0x120))) +mstore(5568, x) +let y := mload(0x140) +y := add(y, shl(88, mload(0x160))) +y := add(y, shl(176, mload(0x180))) +mstore(5600, y) + + success := and(validate_ec_point(x, y), success) + } +mstore(0x1600, mulmod(mload(0xee0), mload(0xee0), f_q)) +mstore(0x1620, mulmod(mload(0x1600), mload(0x1600), f_q)) +mstore(0x1640, mulmod(mload(0x1620), mload(0x1620), f_q)) +mstore(0x1660, mulmod(mload(0x1640), mload(0x1640), f_q)) +mstore(0x1680, mulmod(mload(0x1660), mload(0x1660), f_q)) +mstore(0x16a0, mulmod(mload(0x1680), mload(0x1680), f_q)) +mstore(0x16c0, mulmod(mload(0x16a0), mload(0x16a0), f_q)) +mstore(0x16e0, mulmod(mload(0x16c0), mload(0x16c0), f_q)) +mstore(0x1700, mulmod(mload(0x16e0), mload(0x16e0), f_q)) +mstore(0x1720, mulmod(mload(0x1700), mload(0x1700), f_q)) +mstore(0x1740, mulmod(mload(0x1720), mload(0x1720), f_q)) +mstore(0x1760, mulmod(mload(0x1740), mload(0x1740), f_q)) +mstore(0x1780, mulmod(mload(0x1760), mload(0x1760), f_q)) +mstore(0x17a0, mulmod(mload(0x1780), mload(0x1780), f_q)) +mstore(0x17c0, mulmod(mload(0x17a0), mload(0x17a0), f_q)) +mstore(0x17e0, mulmod(mload(0x17c0), mload(0x17c0), f_q)) +mstore(0x1800, mulmod(mload(0x17e0), mload(0x17e0), f_q)) +mstore(0x1820, mulmod(mload(0x1800), mload(0x1800), f_q)) +mstore(0x1840, mulmod(mload(0x1820), mload(0x1820), f_q)) +mstore(0x1860, mulmod(mload(0x1840), mload(0x1840), f_q)) +mstore(0x1880, mulmod(mload(0x1860), mload(0x1860), f_q)) +mstore(0x18a0, mulmod(mload(0x1880), mload(0x1880), f_q)) +mstore(0x18c0, mulmod(mload(0x18a0), mload(0x18a0), f_q)) +mstore(0x18e0, addmod(mload(0x18c0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x1900, mulmod(mload(0x18e0), 21888240262557392955334514970720457388010314637169927192662615958087340972065, f_q)) +mstore(0x1920, mulmod(mload(0x1900), 4506835738822104338668100540817374747935106310012997856968187171738630203507, f_q)) +mstore(0x1940, addmod(mload(0xee0), 17381407133017170883578305204439900340613258090403036486730017014837178292110, f_q)) +mstore(0x1960, mulmod(mload(0x1900), 21710372849001950800533397158415938114909991150039389063546734567764856596059, f_q)) +mstore(0x1980, addmod(mload(0xee0), 177870022837324421713008586841336973638373250376645280151469618810951899558, f_q)) +mstore(0x19a0, mulmod(mload(0x1900), 1887003188133998471169152042388914354640772748308168868301418279904560637395, f_q)) +mstore(0x19c0, addmod(mload(0xee0), 20001239683705276751077253702868360733907591652107865475396785906671247858222, f_q)) +mstore(0x19e0, mulmod(mload(0x1900), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) +mstore(0x1a00, addmod(mload(0xee0), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q)) +mstore(0x1a20, mulmod(mload(0x1900), 14655294445420895451632927078981340937842238432098198055057679026789553137428, f_q)) +mstore(0x1a40, addmod(mload(0xee0), 7232948426418379770613478666275934150706125968317836288640525159786255358189, f_q)) +mstore(0x1a60, mulmod(mload(0x1900), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q)) +mstore(0x1a80, addmod(mload(0xee0), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q)) +mstore(0x1aa0, mulmod(mload(0x1900), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q)) +mstore(0x1ac0, addmod(mload(0xee0), 12146688980418810893951125255607130521645347193942732958664170801695864621270, f_q)) +mstore(0x1ae0, mulmod(mload(0x1900), 1, f_q)) +mstore(0x1b00, addmod(mload(0xee0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x1b20, mulmod(mload(0x1900), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) +mstore(0x1b40, addmod(mload(0xee0), 13513867906530865119835332133273263211836799082674232843258448413103731898270, f_q)) +mstore(0x1b60, mulmod(mload(0x1900), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +mstore(0x1b80, addmod(mload(0xee0), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q)) +mstore(0x1ba0, mulmod(mload(0x1900), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q)) +mstore(0x1bc0, addmod(mload(0xee0), 18272764063556419981698118473909131571661591947471949595929891197711371770216, f_q)) +mstore(0x1be0, mulmod(mload(0x1900), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x1c00, addmod(mload(0xee0), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q)) +mstore(0x1c20, mulmod(mload(0x1900), 216092043779272773661818549620449970334216366264741118684015851799902419467, f_q)) +mstore(0x1c40, addmod(mload(0xee0), 21672150828060002448584587195636825118214148034151293225014188334775906076150, f_q)) +mstore(0x1c60, mulmod(mload(0x1900), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q)) +mstore(0x1c80, addmod(mload(0xee0), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q)) +mstore(0x1ca0, mulmod(mload(0x1900), 18610195890048912503953886742825279624920778288956610528523679659246523534888, f_q)) +mstore(0x1cc0, addmod(mload(0xee0), 3278046981790362718292519002431995463627586111459423815174524527329284960729, f_q)) +mstore(0x1ce0, mulmod(mload(0x1900), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) +mstore(0x1d00, addmod(mload(0xee0), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q)) +mstore(0x1d20, mulmod(mload(0x1900), 14875928112196239563830800280253496262679717528621719058794366823499719730250, f_q)) +mstore(0x1d40, addmod(mload(0xee0), 7012314759643035658415605465003778825868646871794315284903837363076088765367, f_q)) +mstore(0x1d60, mulmod(mload(0x1900), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q)) +mstore(0x1d80, addmod(mload(0xee0), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q)) +mstore(0x1da0, mulmod(mload(0x1900), 5522161504810533295870699551020523636289972223872138525048055197429246400245, f_q)) +mstore(0x1dc0, addmod(mload(0xee0), 16366081367028741926375706194236751452258392176543895818650148989146562095372, f_q)) +mstore(0x1de0, mulmod(mload(0x1900), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) +mstore(0x1e00, addmod(mload(0xee0), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q)) +mstore(0x1e20, mulmod(mload(0x1900), 9100833993744738801214480881117348002768153232283708533639316963648253510584, f_q)) +mstore(0x1e40, addmod(mload(0xee0), 12787408878094536421031924864139927085780211168132325810058887222927554985033, f_q)) +mstore(0x1e60, mulmod(mload(0x1900), 4245441013247250116003069945606352967193023389718465410501109428393342802981, f_q)) +mstore(0x1e80, addmod(mload(0xee0), 17642801858592025106243335799650922121355341010697568933197094758182465692636, f_q)) +mstore(0x1ea0, mulmod(mload(0x1900), 6132660129994545119218258312491950835441607143741804980633129304664017206141, f_q)) +mstore(0x1ec0, addmod(mload(0xee0), 15755582741844730103028147432765324253106757256674229363065074881911791289476, f_q)) +mstore(0x1ee0, mulmod(mload(0x1900), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q)) +mstore(0x1f00, addmod(mload(0xee0), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q)) +mstore(0x1f20, mulmod(mload(0x1900), 515148244606945972463850631189471072103916690263705052318085725998468254533, f_q)) +mstore(0x1f40, addmod(mload(0xee0), 21373094627232329249782555114067804016444447710152329291380118460577340241084, f_q)) +mstore(0x1f60, mulmod(mload(0x1900), 5980488956150442207659150513163747165544364597008566989111579977672498964212, f_q)) +mstore(0x1f80, addmod(mload(0xee0), 15907753915688833014587255232093527923003999803407467354586624208903309531405, f_q)) +mstore(0x1fa0, mulmod(mload(0x1900), 5223738580615264174925218065001555728265216895679471490312087802465486318994, f_q)) +mstore(0x1fc0, addmod(mload(0xee0), 16664504291224011047321187680255719360283147504736562853386116384110322176623, f_q)) +mstore(0x1fe0, mulmod(mload(0x1900), 14557038802599140430182096396825290815503940951075961210638273254419942783582, f_q)) +mstore(0x2000, addmod(mload(0xee0), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q)) +mstore(0x2020, mulmod(mload(0x1900), 16976236069879939850923145256911338076234942200101755618884183331004076579046, f_q)) +mstore(0x2040, addmod(mload(0xee0), 4912006801959335371323260488345937012313422200314278724814020855571731916571, f_q)) +mstore(0x2060, mulmod(mload(0x1900), 13553911191894110065493137367144919847521088405945523452288398666974237857208, f_q)) +mstore(0x2080, addmod(mload(0xee0), 8334331679945165156753268378112355241027275994470510891409805519601570638409, f_q)) +mstore(0x20a0, mulmod(mload(0x1900), 12222687719926148270818604386979005738180875192307070468454582955273533101023, f_q)) +mstore(0x20c0, addmod(mload(0xee0), 9665555151913126951427801358278269350367489208108963875243621231302275394594, f_q)) +mstore(0x20e0, mulmod(mload(0x1900), 9697063347556872083384215826199993067635178715531258559890418744774301211662, f_q)) +mstore(0x2100, addmod(mload(0xee0), 12191179524282403138862189919057282020913185684884775783807785441801507283955, f_q)) +mstore(0x2120, mulmod(mload(0x1900), 13783318220968413117070077848579881425001701814458176881760898225529300547844, f_q)) +mstore(0x2140, addmod(mload(0xee0), 8104924650870862105176327896677393663546662585957857461937305961046507947773, f_q)) +mstore(0x2160, mulmod(mload(0x1900), 10807735674816066981985242612061336605021639643453679977988966079770672437131, f_q)) +mstore(0x2180, addmod(mload(0xee0), 11080507197023208240261163133195938483526724756962354365709238106805136058486, f_q)) +mstore(0x21a0, mulmod(mload(0x1900), 15487660954688013862248478071816391715224351867581977083810729441220383572585, f_q)) +mstore(0x21c0, addmod(mload(0xee0), 6400581917151261359997927673440883373324012532834057259887474745355424923032, f_q)) +mstore(0x21e0, mulmod(mload(0x1900), 12459868075641381822485233712013080087763946065665469821362892189399541605692, f_q)) +mstore(0x2200, addmod(mload(0xee0), 9428374796197893399761172033244195000784418334750564522335311997176266889925, f_q)) +mstore(0x2220, mulmod(mload(0x1900), 12562571400845953139885120066983392294851269266041089223701347829190217414825, f_q)) +mstore(0x2240, addmod(mload(0xee0), 9325671470993322082361285678273882793697095134374945119996856357385591080792, f_q)) +mstore(0x2260, mulmod(mload(0x1900), 16038300751658239075779628684257016433412502747804121525056508685985277092575, f_q)) +mstore(0x2280, addmod(mload(0xee0), 5849942120181036146466777061000258655135861652611912818641695500590531403042, f_q)) +mstore(0x22a0, mulmod(mload(0x1900), 17665522928519859765452767154433594409738037332395989540221744312194874941704, f_q)) +mstore(0x22c0, addmod(mload(0xee0), 4222719943319415456793638590823680678810327068020044803476459874380933553913, f_q)) +mstore(0x22e0, mulmod(mload(0x1900), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q)) +mstore(0x2300, addmod(mload(0xee0), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q)) +mstore(0x2320, mulmod(mload(0x1900), 1918679275621049296283934091410967415474987212511681231948800935495808101054, f_q)) +mstore(0x2340, addmod(mload(0xee0), 19969563596218225925962471653846307673073377187904353111749403251080000394563, f_q)) +mstore(0x2360, mulmod(mload(0x1900), 13498745591877810872211159461644682954739332524336278910448604883789771736885, f_q)) +mstore(0x2380, addmod(mload(0xee0), 8389497279961464350035246283612592133809031876079755433249599302786036758732, f_q)) +mstore(0x23a0, mulmod(mload(0x1900), 6604851689411953560355663038203889299997924520355363678860500374111951937637, f_q)) +mstore(0x23c0, addmod(mload(0xee0), 15283391182427321661890742707053385788550439880060670664837703812463856557980, f_q)) +mstore(0x23e0, mulmod(mload(0x1900), 20345677989844117909528750049476969581182118546166966482506114734614108237981, f_q)) +mstore(0x2400, addmod(mload(0xee0), 1542564881995157312717655695780305507366245854249067861192089451961700257636, f_q)) +mstore(0x2420, mulmod(mload(0x1900), 11244009323710436498447061620026171700033960328162115124806024297270121927878, f_q)) +mstore(0x2440, addmod(mload(0xee0), 10644233548128838723799344125231103388514404072253919218892179889305686567739, f_q)) +mstore(0x2460, mulmod(mload(0x1900), 790608022292213379425324383664216541739009722347092850716054055768832299157, f_q)) +mstore(0x2480, addmod(mload(0xee0), 21097634849547061842821081361593058546809354678068941492982150130806976196460, f_q)) +mstore(0x24a0, mulmod(mload(0x1900), 13894403229372218245111098554468346933152618215322268934207074514797092422856, f_q)) +mstore(0x24c0, addmod(mload(0xee0), 7993839642467056977135307190788928155395746185093765409491129671778716072761, f_q)) +mstore(0x24e0, mulmod(mload(0x1900), 5289443209903185443361862148540090689648485914368835830972895623576469023722, f_q)) +mstore(0x2500, addmod(mload(0xee0), 16598799661936089778884543596717184398899878486047198512725308562999339471895, f_q)) +mstore(0x2520, mulmod(mload(0x1900), 19715528266218439644661892824912275086257866064695767122686506494361332681035, f_q)) +mstore(0x2540, addmod(mload(0xee0), 2172714605620835577584512920345000002290498335720267221011697692214475814582, f_q)) +mstore(0x2560, mulmod(mload(0x1900), 15161189183906287273290738379431332336600234154579306802151507052820126345529, f_q)) +mstore(0x2580, addmod(mload(0xee0), 6727053687932987948955667365825942751948130245836727541546697133755682150088, f_q)) +mstore(0x25a0, mulmod(mload(0x1900), 12456424076401232823832128238027368612265814450984711658287606686035629293382, f_q)) +mstore(0x25c0, addmod(mload(0xee0), 9431818795438042398414277507229906476282549949431322685410597500540179202235, f_q)) +mstore(0x25e0, mulmod(mload(0x1900), 557567375339945239933617516585967620814823575807691402619711360028043331811, f_q)) +mstore(0x2600, addmod(mload(0xee0), 21330675496499329982312788228671307467733540824608342941078492826547765163806, f_q)) +mstore(0x2620, mulmod(mload(0x1900), 3675353143102618619098608207619541954347747556257261634661810167705798540391, f_q)) +mstore(0x2640, addmod(mload(0xee0), 18212889728736656603147797537637733134200616844158772709036394018870009955226, f_q)) +mstore(0x2660, mulmod(mload(0x1900), 16611719114775828483319365659907682366622074960672212059891361227499450055959, f_q)) +mstore(0x2680, addmod(mload(0xee0), 5276523757063446738927040085349592721926289439743822283806842959076358439658, f_q)) +mstore(0x26a0, mulmod(mload(0x1900), 16386136101309958540926610099404767784529741901845901994660986029617143477017, f_q)) +mstore(0x26c0, addmod(mload(0xee0), 5502106770529316681319795645852507304018622498570132349037218156958665018600, f_q)) +mstore(0x26e0, mulmod(mload(0x1900), 4509404676247677387317362072810231899718070082381452255950861037254608304934, f_q)) +mstore(0x2700, addmod(mload(0xee0), 17378838195591597834929043672447043188830294318034582087747343149321200190683, f_q)) +mstore(0x2720, mulmod(mload(0x1900), 16810138474166795540944740696920121481076613636731046381068745586671284628566, f_q)) +mstore(0x2740, addmod(mload(0xee0), 5078104397672479681301665048337153607471750763684987962629458599904523867051, f_q)) +mstore(0x2760, mulmod(mload(0x1900), 6866457077948847028333856457654941632900463970069876241424363695212127143359, f_q)) +mstore(0x2780, addmod(mload(0xee0), 15021785793890428193912549287602333455647900430346158102273840491363681352258, f_q)) +mstore(0x27a0, mulmod(mload(0x1900), 15050098906272869114113753879341673724544293065073132019915594147673843274264, f_q)) +mstore(0x27c0, addmod(mload(0xee0), 6838143965566406108132651865915601364004071335342902323782610038901965221353, f_q)) +mstore(0x27e0, mulmod(mload(0x1900), 20169013865622130318472103510465966222180994822334426398191891983290742724178, f_q)) +mstore(0x2800, addmod(mload(0xee0), 1719229006217144903774302234791308866367369578081607945506312203285065771439, f_q)) +mstore(0x2820, mulmod(mload(0x1900), 186643418412310505059616433266667559953442348224063743563501145843011378043, f_q)) +mstore(0x2840, addmod(mload(0xee0), 21701599453426964717186789311990607528594922052191970600134703040732797117574, f_q)) +mstore(0x2860, mulmod(mload(0x1900), 14874205783542236433261764022044465911656512639684999678853651860683757650009, f_q)) +mstore(0x2880, addmod(mload(0xee0), 7014037088297038788984641723212809176891851760731034664844552325892050845608, f_q)) +mstore(0x28a0, mulmod(mload(0x1900), 7979162733397795051573074319197621017671482868667369798639936928904004403257, f_q)) +mstore(0x28c0, addmod(mload(0xee0), 13909080138441480170673331426059654070876881531748664545058267257671804092360, f_q)) +mstore(0x28e0, mulmod(mload(0x1900), 2579947959091681244170407980400327834520881737801886423874592072501514087543, f_q)) +mstore(0x2900, addmod(mload(0xee0), 19308294912747593978075997764856947254027482662614147919823612114074294408074, f_q)) +mstore(0x2920, mulmod(mload(0x1900), 14647314289404762345502669568052757093995272955543899726274102521659398012023, f_q)) +mstore(0x2940, addmod(mload(0xee0), 7240928582434512876743736177204517994553091444872134617424101664916410483594, f_q)) +mstore(0x2960, mulmod(mload(0x1900), 17011225028452114973964561549541821925778010085385130152192105634715080939230, f_q)) +mstore(0x2980, addmod(mload(0xee0), 4877017843387160248281844195715453162770354315030904191506098551860727556387, f_q)) +mstore(0x29a0, mulmod(mload(0x1900), 13909366884621139424025272114967039910291313491339778088079465374131977916137, f_q)) +mstore(0x29c0, addmod(mload(0xee0), 7978875987218135798221133630290235178257050909076256255618738812443830579480, f_q)) +mstore(0x29e0, mulmod(mload(0x1900), 1881761935718519990121799628252273658786792458106649887437395059872945867717, f_q)) +mstore(0x2a00, addmod(mload(0xee0), 20006480936120755232124606117005001429761571942309384456260809126702862627900, f_q)) +mstore(0x2a20, mulmod(mload(0x1900), 3028954211863643442542224906848210122376574991720988392405983558451470419662, f_q)) +mstore(0x2a40, addmod(mload(0xee0), 18859288659975631779704180838409064966171789408695045951292220628124338075955, f_q)) +mstore(0x2a60, mulmod(mload(0x1900), 21662285561588145310352318480822402603888953131447478827940284064946709915517, f_q)) +mstore(0x2a80, addmod(mload(0xee0), 225957310251129911894087264434872484659411268968555515757920121629098580100, f_q)) +mstore(0x2aa0, mulmod(mload(0x1900), 378402637159574576880135946147807879590311002003309307938196385556607554558, f_q)) +mstore(0x2ac0, addmod(mload(0xee0), 21509840234679700645366269799109467208958053398412725035760007801019200941059, f_q)) +mstore(0x2ae0, mulmod(mload(0x1900), 21846745818185811051373434299876022191132089169516983080959277716660228899818, f_q)) +mstore(0x2b00, addmod(mload(0xee0), 41497053653464170872971445381252897416275230899051262738926469915579595799, f_q)) +mstore(0x2b20, mulmod(mload(0x1900), 13859044929805761416632426872339332999558462848915686437310885754636367370843, f_q)) +mstore(0x2b40, addmod(mload(0xee0), 8029197942033513805613978872917942088989901551500347906387318431939441124774, f_q)) +mstore(0x2b60, mulmod(mload(0x1900), 11770617947510597378885200406447716404126404817511323735042103519754393416137, f_q)) +mstore(0x2b80, addmod(mload(0xee0), 10117624924328677843361205338809558684421959582904710608656100666821415079480, f_q)) +mstore(0x2ba0, mulmod(mload(0x1900), 319601508938725283206379094021435277953558549162135554365739317130700042560, f_q)) +mstore(0x2bc0, addmod(mload(0xee0), 21568641362900549939040026651235839810594805851253898789332464869445108453057, f_q)) +mstore(0x2be0, mulmod(mload(0x1900), 13018529307372270489258244406856841315962482733096074798317807775255504614069, f_q)) +mstore(0x2c00, addmod(mload(0xee0), 8869713564467004732988161338400433772585881667319959545380396411320303881548, f_q)) +mstore(0x2c20, mulmod(mload(0x1900), 10796308735874323100034550353518537760791974349165624924803974431063123555547, f_q)) +mstore(0x2c40, addmod(mload(0xee0), 11091934135964952122211855391738737327756390051250409418894229755512684940070, f_q)) +mstore(0x2c60, mulmod(mload(0x1900), 5276270562549512946272803945594037128265390012927669941530122528135796334063, f_q)) +mstore(0x2c80, addmod(mload(0xee0), 16611972309289762275973601799663237960282974387488364402168081658440012161554, f_q)) +mstore(0x2ca0, mulmod(mload(0x1900), 14266951011404985116913611868501634000671234987509163410162221784496716449518, f_q)) +mstore(0x2cc0, addmod(mload(0xee0), 7621291860434290105332793876755641087877129412906870933535982402079092046099, f_q)) +mstore(0x2ce0, mulmod(mload(0x1900), 1459528961030896569807206253631725410868595642414057264270714861278164633285, f_q)) +mstore(0x2d00, addmod(mload(0xee0), 20428713910808378652439199491625549677679768758001977079427489325297643862332, f_q)) +mstore(0x2d20, mulmod(mload(0x1900), 21076048292421466101466588747331864862942213489407551704893671891150180812932, f_q)) +mstore(0x2d40, addmod(mload(0xee0), 812194579417809120779816997925410225606150911008482638804532295425627682685, f_q)) +mstore(0x2d60, mulmod(mload(0x1900), 3194789416964050406424265110350613664596286587119568977604859939037397011192, f_q)) +mstore(0x2d80, addmod(mload(0xee0), 18693453454875224815822140634906661423952077813296465366093344247538411484425, f_q)) +mstore(0x2da0, mulmod(mload(0x1900), 19778923120933943678545788030240206353357864532158814848334232828008683217357, f_q)) +mstore(0x2dc0, addmod(mload(0xee0), 2109319750905331543700617715017068735190499868257219495363971358567125278260, f_q)) +mstore(0x2de0, mulmod(mload(0x1900), 3090451643741879200285099477849831179472024364989630500355756836624424014697, f_q)) +mstore(0x2e00, addmod(mload(0xee0), 18797791228097396021961306267407443909076340035426403843342447349951384480920, f_q)) +{ + let prod := mload(0x1940) + + prod := mulmod(mload(0x1980), prod, f_q) + mstore(0x2e20, prod) + + prod := mulmod(mload(0x19c0), prod, f_q) + mstore(0x2e40, prod) + + prod := mulmod(mload(0x1a00), prod, f_q) + mstore(0x2e60, prod) + + prod := mulmod(mload(0x1a40), prod, f_q) + mstore(0x2e80, prod) + + prod := mulmod(mload(0x1a80), prod, f_q) + mstore(0x2ea0, prod) + + prod := mulmod(mload(0x1ac0), prod, f_q) + mstore(0x2ec0, prod) + + prod := mulmod(mload(0x1b00), prod, f_q) + mstore(0x2ee0, prod) + + prod := mulmod(mload(0x1b40), prod, f_q) + mstore(0x2f00, prod) + + prod := mulmod(mload(0x1b80), prod, f_q) + mstore(0x2f20, prod) + + prod := mulmod(mload(0x1bc0), prod, f_q) + mstore(0x2f40, prod) + + prod := mulmod(mload(0x1c00), prod, f_q) + mstore(0x2f60, prod) + + prod := mulmod(mload(0x1c40), prod, f_q) + mstore(0x2f80, prod) + + prod := mulmod(mload(0x1c80), prod, f_q) + mstore(0x2fa0, prod) + + prod := mulmod(mload(0x1cc0), prod, f_q) + mstore(0x2fc0, prod) + + prod := mulmod(mload(0x1d00), prod, f_q) + mstore(0x2fe0, prod) + + prod := mulmod(mload(0x1d40), prod, f_q) + mstore(0x3000, prod) + + prod := mulmod(mload(0x1d80), prod, f_q) + mstore(0x3020, prod) + + prod := mulmod(mload(0x1dc0), prod, f_q) + mstore(0x3040, prod) + + prod := mulmod(mload(0x1e00), prod, f_q) + mstore(0x3060, prod) + + prod := mulmod(mload(0x1e40), prod, f_q) + mstore(0x3080, prod) + + prod := mulmod(mload(0x1e80), prod, f_q) + mstore(0x30a0, prod) + + prod := mulmod(mload(0x1ec0), prod, f_q) + mstore(0x30c0, prod) + + prod := mulmod(mload(0x1f00), prod, f_q) + mstore(0x30e0, prod) + + prod := mulmod(mload(0x1f40), prod, f_q) + mstore(0x3100, prod) + + prod := mulmod(mload(0x1f80), prod, f_q) + mstore(0x3120, prod) + + prod := mulmod(mload(0x1fc0), prod, f_q) + mstore(0x3140, prod) + + prod := mulmod(mload(0x2000), prod, f_q) + mstore(0x3160, prod) + + prod := mulmod(mload(0x2040), prod, f_q) + mstore(0x3180, prod) + + prod := mulmod(mload(0x2080), prod, f_q) + mstore(0x31a0, prod) + + prod := mulmod(mload(0x20c0), prod, f_q) + mstore(0x31c0, prod) + + prod := mulmod(mload(0x2100), prod, f_q) + mstore(0x31e0, prod) + + prod := mulmod(mload(0x2140), prod, f_q) + mstore(0x3200, prod) + + prod := mulmod(mload(0x2180), prod, f_q) + mstore(0x3220, prod) + + prod := mulmod(mload(0x21c0), prod, f_q) + mstore(0x3240, prod) + + prod := mulmod(mload(0x2200), prod, f_q) + mstore(0x3260, prod) + + prod := mulmod(mload(0x2240), prod, f_q) + mstore(0x3280, prod) + + prod := mulmod(mload(0x2280), prod, f_q) + mstore(0x32a0, prod) + + prod := mulmod(mload(0x22c0), prod, f_q) + mstore(0x32c0, prod) + + prod := mulmod(mload(0x2300), prod, f_q) + mstore(0x32e0, prod) + + prod := mulmod(mload(0x2340), prod, f_q) + mstore(0x3300, prod) + + prod := mulmod(mload(0x2380), prod, f_q) + mstore(0x3320, prod) + + prod := mulmod(mload(0x23c0), prod, f_q) + mstore(0x3340, prod) + + prod := mulmod(mload(0x2400), prod, f_q) + mstore(0x3360, prod) + + prod := mulmod(mload(0x2440), prod, f_q) + mstore(0x3380, prod) + + prod := mulmod(mload(0x2480), prod, f_q) + mstore(0x33a0, prod) + + prod := mulmod(mload(0x24c0), prod, f_q) + mstore(0x33c0, prod) + + prod := mulmod(mload(0x2500), prod, f_q) + mstore(0x33e0, prod) + + prod := mulmod(mload(0x2540), prod, f_q) + mstore(0x3400, prod) + + prod := mulmod(mload(0x2580), prod, f_q) + mstore(0x3420, prod) + + prod := mulmod(mload(0x25c0), prod, f_q) + mstore(0x3440, prod) + + prod := mulmod(mload(0x2600), prod, f_q) + mstore(0x3460, prod) + + prod := mulmod(mload(0x2640), prod, f_q) + mstore(0x3480, prod) + + prod := mulmod(mload(0x2680), prod, f_q) + mstore(0x34a0, prod) + + prod := mulmod(mload(0x26c0), prod, f_q) + mstore(0x34c0, prod) + + prod := mulmod(mload(0x2700), prod, f_q) + mstore(0x34e0, prod) + + prod := mulmod(mload(0x2740), prod, f_q) + mstore(0x3500, prod) + + prod := mulmod(mload(0x2780), prod, f_q) + mstore(0x3520, prod) + + prod := mulmod(mload(0x27c0), prod, f_q) + mstore(0x3540, prod) + + prod := mulmod(mload(0x2800), prod, f_q) + mstore(0x3560, prod) + + prod := mulmod(mload(0x2840), prod, f_q) + mstore(0x3580, prod) + + prod := mulmod(mload(0x2880), prod, f_q) + mstore(0x35a0, prod) + + prod := mulmod(mload(0x28c0), prod, f_q) + mstore(0x35c0, prod) + + prod := mulmod(mload(0x2900), prod, f_q) + mstore(0x35e0, prod) + + prod := mulmod(mload(0x2940), prod, f_q) + mstore(0x3600, prod) + + prod := mulmod(mload(0x2980), prod, f_q) + mstore(0x3620, prod) + + prod := mulmod(mload(0x29c0), prod, f_q) + mstore(0x3640, prod) + + prod := mulmod(mload(0x2a00), prod, f_q) + mstore(0x3660, prod) + + prod := mulmod(mload(0x2a40), prod, f_q) + mstore(0x3680, prod) + + prod := mulmod(mload(0x2a80), prod, f_q) + mstore(0x36a0, prod) + + prod := mulmod(mload(0x2ac0), prod, f_q) + mstore(0x36c0, prod) + + prod := mulmod(mload(0x2b00), prod, f_q) + mstore(0x36e0, prod) + + prod := mulmod(mload(0x2b40), prod, f_q) + mstore(0x3700, prod) + + prod := mulmod(mload(0x2b80), prod, f_q) + mstore(0x3720, prod) + + prod := mulmod(mload(0x2bc0), prod, f_q) + mstore(0x3740, prod) + + prod := mulmod(mload(0x2c00), prod, f_q) + mstore(0x3760, prod) + + prod := mulmod(mload(0x2c40), prod, f_q) + mstore(0x3780, prod) + + prod := mulmod(mload(0x2c80), prod, f_q) + mstore(0x37a0, prod) + + prod := mulmod(mload(0x2cc0), prod, f_q) + mstore(0x37c0, prod) + + prod := mulmod(mload(0x2d00), prod, f_q) + mstore(0x37e0, prod) + + prod := mulmod(mload(0x2d40), prod, f_q) + mstore(0x3800, prod) + + prod := mulmod(mload(0x2d80), prod, f_q) + mstore(0x3820, prod) + + prod := mulmod(mload(0x2dc0), prod, f_q) + mstore(0x3840, prod) + + prod := mulmod(mload(0x2e00), prod, f_q) + mstore(0x3860, prod) + + prod := mulmod(mload(0x18e0), prod, f_q) + mstore(0x3880, prod) + + } +mstore(0x38c0, 32) +mstore(0x38e0, 32) +mstore(0x3900, 32) +mstore(0x3920, mload(0x3880)) +mstore(0x3940, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x3960, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x38c0, 0xc0, 0x38a0, 0x20), 1), success) +{ + + let inv := mload(0x38a0) + let v + + v := mload(0x18e0) + mstore(6368, mulmod(mload(0x3860), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2e00) + mstore(11776, mulmod(mload(0x3840), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2dc0) + mstore(11712, mulmod(mload(0x3820), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2d80) + mstore(11648, mulmod(mload(0x3800), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2d40) + mstore(11584, mulmod(mload(0x37e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2d00) + mstore(11520, mulmod(mload(0x37c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2cc0) + mstore(11456, mulmod(mload(0x37a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2c80) + mstore(11392, mulmod(mload(0x3780), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2c40) + mstore(11328, mulmod(mload(0x3760), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2c00) + mstore(11264, mulmod(mload(0x3740), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2bc0) + mstore(11200, mulmod(mload(0x3720), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2b80) + mstore(11136, mulmod(mload(0x3700), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2b40) + mstore(11072, mulmod(mload(0x36e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2b00) + mstore(11008, mulmod(mload(0x36c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2ac0) + mstore(10944, mulmod(mload(0x36a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2a80) + mstore(10880, mulmod(mload(0x3680), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2a40) + mstore(10816, mulmod(mload(0x3660), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2a00) + mstore(10752, mulmod(mload(0x3640), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x29c0) + mstore(10688, mulmod(mload(0x3620), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2980) + mstore(10624, mulmod(mload(0x3600), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2940) + mstore(10560, mulmod(mload(0x35e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2900) + mstore(10496, mulmod(mload(0x35c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x28c0) + mstore(10432, mulmod(mload(0x35a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2880) + mstore(10368, mulmod(mload(0x3580), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2840) + mstore(10304, mulmod(mload(0x3560), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2800) + mstore(10240, mulmod(mload(0x3540), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x27c0) + mstore(10176, mulmod(mload(0x3520), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2780) + mstore(10112, mulmod(mload(0x3500), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2740) + mstore(10048, mulmod(mload(0x34e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2700) + mstore(9984, mulmod(mload(0x34c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x26c0) + mstore(9920, mulmod(mload(0x34a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2680) + mstore(9856, mulmod(mload(0x3480), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2640) + mstore(9792, mulmod(mload(0x3460), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2600) + mstore(9728, mulmod(mload(0x3440), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x25c0) + mstore(9664, mulmod(mload(0x3420), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2580) + mstore(9600, mulmod(mload(0x3400), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2540) + mstore(9536, mulmod(mload(0x33e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2500) + mstore(9472, mulmod(mload(0x33c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x24c0) + mstore(9408, mulmod(mload(0x33a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2480) + mstore(9344, mulmod(mload(0x3380), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2440) + mstore(9280, mulmod(mload(0x3360), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2400) + mstore(9216, mulmod(mload(0x3340), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x23c0) + mstore(9152, mulmod(mload(0x3320), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2380) + mstore(9088, mulmod(mload(0x3300), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2340) + mstore(9024, mulmod(mload(0x32e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2300) + mstore(8960, mulmod(mload(0x32c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x22c0) + mstore(8896, mulmod(mload(0x32a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2280) + mstore(8832, mulmod(mload(0x3280), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2240) + mstore(8768, mulmod(mload(0x3260), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2200) + mstore(8704, mulmod(mload(0x3240), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x21c0) + mstore(8640, mulmod(mload(0x3220), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2180) + mstore(8576, mulmod(mload(0x3200), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2140) + mstore(8512, mulmod(mload(0x31e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2100) + mstore(8448, mulmod(mload(0x31c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x20c0) + mstore(8384, mulmod(mload(0x31a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2080) + mstore(8320, mulmod(mload(0x3180), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2040) + mstore(8256, mulmod(mload(0x3160), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2000) + mstore(8192, mulmod(mload(0x3140), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1fc0) + mstore(8128, mulmod(mload(0x3120), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1f80) + mstore(8064, mulmod(mload(0x3100), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1f40) + mstore(8000, mulmod(mload(0x30e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1f00) + mstore(7936, mulmod(mload(0x30c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ec0) + mstore(7872, mulmod(mload(0x30a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1e80) + mstore(7808, mulmod(mload(0x3080), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1e40) + mstore(7744, mulmod(mload(0x3060), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1e00) + mstore(7680, mulmod(mload(0x3040), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1dc0) + mstore(7616, mulmod(mload(0x3020), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1d80) + mstore(7552, mulmod(mload(0x3000), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1d40) + mstore(7488, mulmod(mload(0x2fe0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1d00) + mstore(7424, mulmod(mload(0x2fc0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1cc0) + mstore(7360, mulmod(mload(0x2fa0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1c80) + mstore(7296, mulmod(mload(0x2f80), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1c40) + mstore(7232, mulmod(mload(0x2f60), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1c00) + mstore(7168, mulmod(mload(0x2f40), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1bc0) + mstore(7104, mulmod(mload(0x2f20), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1b80) + mstore(7040, mulmod(mload(0x2f00), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1b40) + mstore(6976, mulmod(mload(0x2ee0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1b00) + mstore(6912, mulmod(mload(0x2ec0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ac0) + mstore(6848, mulmod(mload(0x2ea0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1a80) + mstore(6784, mulmod(mload(0x2e80), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1a40) + mstore(6720, mulmod(mload(0x2e60), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1a00) + mstore(6656, mulmod(mload(0x2e40), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x19c0) + mstore(6592, mulmod(mload(0x2e20), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1980) + mstore(6528, mulmod(mload(0x1940), inv, f_q)) + inv := mulmod(v, inv, f_q) + mstore(0x1940, inv) + + } +mstore(0x3980, mulmod(mload(0x1920), mload(0x1940), f_q)) +mstore(0x39a0, mulmod(mload(0x1960), mload(0x1980), f_q)) +mstore(0x39c0, mulmod(mload(0x19a0), mload(0x19c0), f_q)) +mstore(0x39e0, mulmod(mload(0x19e0), mload(0x1a00), f_q)) +mstore(0x3a00, mulmod(mload(0x1a20), mload(0x1a40), f_q)) +mstore(0x3a20, mulmod(mload(0x1a60), mload(0x1a80), f_q)) +mstore(0x3a40, mulmod(mload(0x1aa0), mload(0x1ac0), f_q)) +mstore(0x3a60, mulmod(mload(0x1ae0), mload(0x1b00), f_q)) +mstore(0x3a80, mulmod(mload(0x1b20), mload(0x1b40), f_q)) +mstore(0x3aa0, mulmod(mload(0x1b60), mload(0x1b80), f_q)) +mstore(0x3ac0, mulmod(mload(0x1ba0), mload(0x1bc0), f_q)) +mstore(0x3ae0, mulmod(mload(0x1be0), mload(0x1c00), f_q)) +mstore(0x3b00, mulmod(mload(0x1c20), mload(0x1c40), f_q)) +mstore(0x3b20, mulmod(mload(0x1c60), mload(0x1c80), f_q)) +mstore(0x3b40, mulmod(mload(0x1ca0), mload(0x1cc0), f_q)) +mstore(0x3b60, mulmod(mload(0x1ce0), mload(0x1d00), f_q)) +mstore(0x3b80, mulmod(mload(0x1d20), mload(0x1d40), f_q)) +mstore(0x3ba0, mulmod(mload(0x1d60), mload(0x1d80), f_q)) +mstore(0x3bc0, mulmod(mload(0x1da0), mload(0x1dc0), f_q)) +mstore(0x3be0, mulmod(mload(0x1de0), mload(0x1e00), f_q)) +mstore(0x3c00, mulmod(mload(0x1e20), mload(0x1e40), f_q)) +mstore(0x3c20, mulmod(mload(0x1e60), mload(0x1e80), f_q)) +mstore(0x3c40, mulmod(mload(0x1ea0), mload(0x1ec0), f_q)) +mstore(0x3c60, mulmod(mload(0x1ee0), mload(0x1f00), f_q)) +mstore(0x3c80, mulmod(mload(0x1f20), mload(0x1f40), f_q)) +mstore(0x3ca0, mulmod(mload(0x1f60), mload(0x1f80), f_q)) +mstore(0x3cc0, mulmod(mload(0x1fa0), mload(0x1fc0), f_q)) +mstore(0x3ce0, mulmod(mload(0x1fe0), mload(0x2000), f_q)) +mstore(0x3d00, mulmod(mload(0x2020), mload(0x2040), f_q)) +mstore(0x3d20, mulmod(mload(0x2060), mload(0x2080), f_q)) +mstore(0x3d40, mulmod(mload(0x20a0), mload(0x20c0), f_q)) +mstore(0x3d60, mulmod(mload(0x20e0), mload(0x2100), f_q)) +mstore(0x3d80, mulmod(mload(0x2120), mload(0x2140), f_q)) +mstore(0x3da0, mulmod(mload(0x2160), mload(0x2180), f_q)) +mstore(0x3dc0, mulmod(mload(0x21a0), mload(0x21c0), f_q)) +mstore(0x3de0, mulmod(mload(0x21e0), mload(0x2200), f_q)) +mstore(0x3e00, mulmod(mload(0x2220), mload(0x2240), f_q)) +mstore(0x3e20, mulmod(mload(0x2260), mload(0x2280), f_q)) +mstore(0x3e40, mulmod(mload(0x22a0), mload(0x22c0), f_q)) +mstore(0x3e60, mulmod(mload(0x22e0), mload(0x2300), f_q)) +mstore(0x3e80, mulmod(mload(0x2320), mload(0x2340), f_q)) +mstore(0x3ea0, mulmod(mload(0x2360), mload(0x2380), f_q)) +mstore(0x3ec0, mulmod(mload(0x23a0), mload(0x23c0), f_q)) +mstore(0x3ee0, mulmod(mload(0x23e0), mload(0x2400), f_q)) +mstore(0x3f00, mulmod(mload(0x2420), mload(0x2440), f_q)) +mstore(0x3f20, mulmod(mload(0x2460), mload(0x2480), f_q)) +mstore(0x3f40, mulmod(mload(0x24a0), mload(0x24c0), f_q)) +mstore(0x3f60, mulmod(mload(0x24e0), mload(0x2500), f_q)) +mstore(0x3f80, mulmod(mload(0x2520), mload(0x2540), f_q)) +mstore(0x3fa0, mulmod(mload(0x2560), mload(0x2580), f_q)) +mstore(0x3fc0, mulmod(mload(0x25a0), mload(0x25c0), f_q)) +mstore(0x3fe0, mulmod(mload(0x25e0), mload(0x2600), f_q)) +mstore(0x4000, mulmod(mload(0x2620), mload(0x2640), f_q)) +mstore(0x4020, mulmod(mload(0x2660), mload(0x2680), f_q)) +mstore(0x4040, mulmod(mload(0x26a0), mload(0x26c0), f_q)) +mstore(0x4060, mulmod(mload(0x26e0), mload(0x2700), f_q)) +mstore(0x4080, mulmod(mload(0x2720), mload(0x2740), f_q)) +mstore(0x40a0, mulmod(mload(0x2760), mload(0x2780), f_q)) +mstore(0x40c0, mulmod(mload(0x27a0), mload(0x27c0), f_q)) +mstore(0x40e0, mulmod(mload(0x27e0), mload(0x2800), f_q)) +mstore(0x4100, mulmod(mload(0x2820), mload(0x2840), f_q)) +mstore(0x4120, mulmod(mload(0x2860), mload(0x2880), f_q)) +mstore(0x4140, mulmod(mload(0x28a0), mload(0x28c0), f_q)) +mstore(0x4160, mulmod(mload(0x28e0), mload(0x2900), f_q)) +mstore(0x4180, mulmod(mload(0x2920), mload(0x2940), f_q)) +mstore(0x41a0, mulmod(mload(0x2960), mload(0x2980), f_q)) +mstore(0x41c0, mulmod(mload(0x29a0), mload(0x29c0), f_q)) +mstore(0x41e0, mulmod(mload(0x29e0), mload(0x2a00), f_q)) +mstore(0x4200, mulmod(mload(0x2a20), mload(0x2a40), f_q)) +mstore(0x4220, mulmod(mload(0x2a60), mload(0x2a80), f_q)) +mstore(0x4240, mulmod(mload(0x2aa0), mload(0x2ac0), f_q)) +mstore(0x4260, mulmod(mload(0x2ae0), mload(0x2b00), f_q)) +mstore(0x4280, mulmod(mload(0x2b20), mload(0x2b40), f_q)) +mstore(0x42a0, mulmod(mload(0x2b60), mload(0x2b80), f_q)) +mstore(0x42c0, mulmod(mload(0x2ba0), mload(0x2bc0), f_q)) +mstore(0x42e0, mulmod(mload(0x2be0), mload(0x2c00), f_q)) +mstore(0x4300, mulmod(mload(0x2c20), mload(0x2c40), f_q)) +mstore(0x4320, mulmod(mload(0x2c60), mload(0x2c80), f_q)) +mstore(0x4340, mulmod(mload(0x2ca0), mload(0x2cc0), f_q)) +mstore(0x4360, mulmod(mload(0x2ce0), mload(0x2d00), f_q)) +mstore(0x4380, mulmod(mload(0x2d20), mload(0x2d40), f_q)) +mstore(0x43a0, mulmod(mload(0x2d60), mload(0x2d80), f_q)) +mstore(0x43c0, mulmod(mload(0x2da0), mload(0x2dc0), f_q)) +mstore(0x43e0, mulmod(mload(0x2de0), mload(0x2e00), f_q)) +{ + let result := mulmod(mload(0x3a60), mload(0x20), f_q) +result := addmod(mulmod(mload(0x3a80), mload(0x40), f_q), result, f_q) +result := addmod(mulmod(mload(0x3aa0), mload(0x60), f_q), result, f_q) +result := addmod(mulmod(mload(0x3ac0), mload(0x80), f_q), result, f_q) +result := addmod(mulmod(mload(0x3ae0), mload(0xa0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3b00), mload(0xc0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3b20), mload(0xe0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3b40), mload(0x100), f_q), result, f_q) +result := addmod(mulmod(mload(0x3b60), mload(0x120), f_q), result, f_q) +result := addmod(mulmod(mload(0x3b80), mload(0x140), f_q), result, f_q) +result := addmod(mulmod(mload(0x3ba0), mload(0x160), f_q), result, f_q) +result := addmod(mulmod(mload(0x3bc0), mload(0x180), f_q), result, f_q) +result := addmod(mulmod(mload(0x3be0), mload(0x1a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3c00), mload(0x1c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3c20), mload(0x1e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3c40), mload(0x200), f_q), result, f_q) +result := addmod(mulmod(mload(0x3c60), mload(0x220), f_q), result, f_q) +result := addmod(mulmod(mload(0x3c80), mload(0x240), f_q), result, f_q) +result := addmod(mulmod(mload(0x3ca0), mload(0x260), f_q), result, f_q) +result := addmod(mulmod(mload(0x3cc0), mload(0x280), f_q), result, f_q) +result := addmod(mulmod(mload(0x3ce0), mload(0x2a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3d00), mload(0x2c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3d20), mload(0x2e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3d40), mload(0x300), f_q), result, f_q) +result := addmod(mulmod(mload(0x3d60), mload(0x320), f_q), result, f_q) +result := addmod(mulmod(mload(0x3d80), mload(0x340), f_q), result, f_q) +result := addmod(mulmod(mload(0x3da0), mload(0x360), f_q), result, f_q) +result := addmod(mulmod(mload(0x3dc0), mload(0x380), f_q), result, f_q) +result := addmod(mulmod(mload(0x3de0), mload(0x3a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3e00), mload(0x3c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3e20), mload(0x3e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3e40), mload(0x400), f_q), result, f_q) +result := addmod(mulmod(mload(0x3e60), mload(0x420), f_q), result, f_q) +result := addmod(mulmod(mload(0x3e80), mload(0x440), f_q), result, f_q) +result := addmod(mulmod(mload(0x3ea0), mload(0x460), f_q), result, f_q) +result := addmod(mulmod(mload(0x3ec0), mload(0x480), f_q), result, f_q) +result := addmod(mulmod(mload(0x3ee0), mload(0x4a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3f00), mload(0x4c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3f20), mload(0x4e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x3f40), mload(0x500), f_q), result, f_q) +result := addmod(mulmod(mload(0x3f60), mload(0x520), f_q), result, f_q) +result := addmod(mulmod(mload(0x3f80), mload(0x540), f_q), result, f_q) +result := addmod(mulmod(mload(0x3fa0), mload(0x560), f_q), result, f_q) +result := addmod(mulmod(mload(0x3fc0), mload(0x580), f_q), result, f_q) +result := addmod(mulmod(mload(0x3fe0), mload(0x5a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4000), mload(0x5c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4020), mload(0x5e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4040), mload(0x600), f_q), result, f_q) +result := addmod(mulmod(mload(0x4060), mload(0x620), f_q), result, f_q) +result := addmod(mulmod(mload(0x4080), mload(0x640), f_q), result, f_q) +result := addmod(mulmod(mload(0x40a0), mload(0x660), f_q), result, f_q) +result := addmod(mulmod(mload(0x40c0), mload(0x680), f_q), result, f_q) +result := addmod(mulmod(mload(0x40e0), mload(0x6a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4100), mload(0x6c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4120), mload(0x6e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4140), mload(0x700), f_q), result, f_q) +result := addmod(mulmod(mload(0x4160), mload(0x720), f_q), result, f_q) +result := addmod(mulmod(mload(0x4180), mload(0x740), f_q), result, f_q) +result := addmod(mulmod(mload(0x41a0), mload(0x760), f_q), result, f_q) +result := addmod(mulmod(mload(0x41c0), mload(0x780), f_q), result, f_q) +result := addmod(mulmod(mload(0x41e0), mload(0x7a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4200), mload(0x7c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4220), mload(0x7e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4240), mload(0x800), f_q), result, f_q) +result := addmod(mulmod(mload(0x4260), mload(0x820), f_q), result, f_q) +result := addmod(mulmod(mload(0x4280), mload(0x840), f_q), result, f_q) +result := addmod(mulmod(mload(0x42a0), mload(0x860), f_q), result, f_q) +result := addmod(mulmod(mload(0x42c0), mload(0x880), f_q), result, f_q) +result := addmod(mulmod(mload(0x42e0), mload(0x8a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4300), mload(0x8c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4320), mload(0x8e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x4340), mload(0x900), f_q), result, f_q) +result := addmod(mulmod(mload(0x4360), mload(0x920), f_q), result, f_q) +result := addmod(mulmod(mload(0x4380), mload(0x940), f_q), result, f_q) +result := addmod(mulmod(mload(0x43a0), mload(0x960), f_q), result, f_q) +result := addmod(mulmod(mload(0x43c0), mload(0x980), f_q), result, f_q) +result := addmod(mulmod(mload(0x43e0), mload(0x9a0), f_q), result, f_q) +mstore(17408, result) + } +mstore(0x4420, mulmod(mload(0xf60), mload(0xf40), f_q)) +mstore(0x4440, addmod(mload(0xf20), mload(0x4420), f_q)) +mstore(0x4460, addmod(mload(0x4440), sub(f_q, mload(0xf80)), f_q)) +mstore(0x4480, mulmod(mload(0x4460), mload(0x1100), f_q)) +mstore(0x44a0, mulmod(mload(0xdc0), mload(0x4480), f_q)) +mstore(0x44c0, mulmod(mload(0xfe0), mload(0xfc0), f_q)) +mstore(0x44e0, addmod(mload(0xfa0), mload(0x44c0), f_q)) +mstore(0x4500, addmod(mload(0x44e0), sub(f_q, mload(0x1000)), f_q)) +mstore(0x4520, mulmod(mload(0x4500), mload(0x1120), f_q)) +mstore(0x4540, addmod(mload(0x44a0), mload(0x4520), f_q)) +mstore(0x4560, mulmod(mload(0xdc0), mload(0x4540), f_q)) +mstore(0x4580, mulmod(mload(0x1060), mload(0x1040), f_q)) +mstore(0x45a0, addmod(mload(0x1020), mload(0x4580), f_q)) +mstore(0x45c0, addmod(mload(0x45a0), sub(f_q, mload(0x1080)), f_q)) +mstore(0x45e0, mulmod(mload(0x45c0), mload(0x1140), f_q)) +mstore(0x4600, addmod(mload(0x4560), mload(0x45e0), f_q)) +mstore(0x4620, mulmod(mload(0xdc0), mload(0x4600), f_q)) +mstore(0x4640, addmod(1, sub(f_q, mload(0x1240)), f_q)) +mstore(0x4660, mulmod(mload(0x4640), mload(0x3a60), f_q)) +mstore(0x4680, addmod(mload(0x4620), mload(0x4660), f_q)) +mstore(0x46a0, mulmod(mload(0xdc0), mload(0x4680), f_q)) +mstore(0x46c0, mulmod(mload(0x1300), mload(0x1300), f_q)) +mstore(0x46e0, addmod(mload(0x46c0), sub(f_q, mload(0x1300)), f_q)) +mstore(0x4700, mulmod(mload(0x46e0), mload(0x3980), f_q)) +mstore(0x4720, addmod(mload(0x46a0), mload(0x4700), f_q)) +mstore(0x4740, mulmod(mload(0xdc0), mload(0x4720), f_q)) +mstore(0x4760, addmod(mload(0x12a0), sub(f_q, mload(0x1280)), f_q)) +mstore(0x4780, mulmod(mload(0x4760), mload(0x3a60), f_q)) +mstore(0x47a0, addmod(mload(0x4740), mload(0x4780), f_q)) +mstore(0x47c0, mulmod(mload(0xdc0), mload(0x47a0), f_q)) +mstore(0x47e0, addmod(mload(0x1300), sub(f_q, mload(0x12e0)), f_q)) +mstore(0x4800, mulmod(mload(0x47e0), mload(0x3a60), f_q)) +mstore(0x4820, addmod(mload(0x47c0), mload(0x4800), f_q)) +mstore(0x4840, mulmod(mload(0xdc0), mload(0x4820), f_q)) +mstore(0x4860, addmod(1, sub(f_q, mload(0x3980)), f_q)) +mstore(0x4880, addmod(mload(0x39a0), mload(0x39c0), f_q)) +mstore(0x48a0, addmod(mload(0x4880), mload(0x39e0), f_q)) +mstore(0x48c0, addmod(mload(0x48a0), mload(0x3a00), f_q)) +mstore(0x48e0, addmod(mload(0x48c0), mload(0x3a20), f_q)) +mstore(0x4900, addmod(mload(0x48e0), mload(0x3a40), f_q)) +mstore(0x4920, addmod(mload(0x4860), sub(f_q, mload(0x4900)), f_q)) +mstore(0x4940, mulmod(mload(0x1180), mload(0xbc0), f_q)) +mstore(0x4960, addmod(mload(0x10c0), mload(0x4940), f_q)) +mstore(0x4980, addmod(mload(0x4960), mload(0xc20), f_q)) +mstore(0x49a0, mulmod(mload(0x11a0), mload(0xbc0), f_q)) +mstore(0x49c0, addmod(mload(0xf20), mload(0x49a0), f_q)) +mstore(0x49e0, addmod(mload(0x49c0), mload(0xc20), f_q)) +mstore(0x4a00, mulmod(mload(0x49e0), mload(0x4980), f_q)) +mstore(0x4a20, mulmod(mload(0x4a00), mload(0x1260), f_q)) +mstore(0x4a40, mulmod(1, mload(0xbc0), f_q)) +mstore(0x4a60, mulmod(mload(0xee0), mload(0x4a40), f_q)) +mstore(0x4a80, addmod(mload(0x10c0), mload(0x4a60), f_q)) +mstore(0x4aa0, addmod(mload(0x4a80), mload(0xc20), f_q)) +mstore(0x4ac0, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0xbc0), f_q)) +mstore(0x4ae0, mulmod(mload(0xee0), mload(0x4ac0), f_q)) +mstore(0x4b00, addmod(mload(0xf20), mload(0x4ae0), f_q)) +mstore(0x4b20, addmod(mload(0x4b00), mload(0xc20), f_q)) +mstore(0x4b40, mulmod(mload(0x4b20), mload(0x4aa0), f_q)) +mstore(0x4b60, mulmod(mload(0x4b40), mload(0x1240), f_q)) +mstore(0x4b80, addmod(mload(0x4a20), sub(f_q, mload(0x4b60)), f_q)) +mstore(0x4ba0, mulmod(mload(0x4b80), mload(0x4920), f_q)) +mstore(0x4bc0, addmod(mload(0x4840), mload(0x4ba0), f_q)) +mstore(0x4be0, mulmod(mload(0xdc0), mload(0x4bc0), f_q)) +mstore(0x4c00, mulmod(mload(0x11c0), mload(0xbc0), f_q)) +mstore(0x4c20, addmod(mload(0xfa0), mload(0x4c00), f_q)) +mstore(0x4c40, addmod(mload(0x4c20), mload(0xc20), f_q)) +mstore(0x4c60, mulmod(mload(0x11e0), mload(0xbc0), f_q)) +mstore(0x4c80, addmod(mload(0x1020), mload(0x4c60), f_q)) +mstore(0x4ca0, addmod(mload(0x4c80), mload(0xc20), f_q)) +mstore(0x4cc0, mulmod(mload(0x4ca0), mload(0x4c40), f_q)) +mstore(0x4ce0, mulmod(mload(0x4cc0), mload(0x12c0), f_q)) +mstore(0x4d00, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0xbc0), f_q)) +mstore(0x4d20, mulmod(mload(0xee0), mload(0x4d00), f_q)) +mstore(0x4d40, addmod(mload(0xfa0), mload(0x4d20), f_q)) +mstore(0x4d60, addmod(mload(0x4d40), mload(0xc20), f_q)) +mstore(0x4d80, mulmod(11166246659983828508719468090013646171463329086121580628794302409516816350802, mload(0xbc0), f_q)) +mstore(0x4da0, mulmod(mload(0xee0), mload(0x4d80), f_q)) +mstore(0x4dc0, addmod(mload(0x1020), mload(0x4da0), f_q)) +mstore(0x4de0, addmod(mload(0x4dc0), mload(0xc20), f_q)) +mstore(0x4e00, mulmod(mload(0x4de0), mload(0x4d60), f_q)) +mstore(0x4e20, mulmod(mload(0x4e00), mload(0x12a0), f_q)) +mstore(0x4e40, addmod(mload(0x4ce0), sub(f_q, mload(0x4e20)), f_q)) +mstore(0x4e60, mulmod(mload(0x4e40), mload(0x4920), f_q)) +mstore(0x4e80, addmod(mload(0x4be0), mload(0x4e60), f_q)) +mstore(0x4ea0, mulmod(mload(0xdc0), mload(0x4e80), f_q)) +mstore(0x4ec0, mulmod(mload(0x1200), mload(0xbc0), f_q)) +mstore(0x4ee0, addmod(mload(0x10a0), mload(0x4ec0), f_q)) +mstore(0x4f00, addmod(mload(0x4ee0), mload(0xc20), f_q)) +mstore(0x4f20, mulmod(mload(0x1220), mload(0xbc0), f_q)) +mstore(0x4f40, addmod(mload(0x4400), mload(0x4f20), f_q)) +mstore(0x4f60, addmod(mload(0x4f40), mload(0xc20), f_q)) +mstore(0x4f80, mulmod(mload(0x4f60), mload(0x4f00), f_q)) +mstore(0x4fa0, mulmod(mload(0x4f80), mload(0x1320), f_q)) +mstore(0x4fc0, mulmod(284840088355319032285349970403338060113257071685626700086398481893096618818, mload(0xbc0), f_q)) +mstore(0x4fe0, mulmod(mload(0xee0), mload(0x4fc0), f_q)) +mstore(0x5000, addmod(mload(0x10a0), mload(0x4fe0), f_q)) +mstore(0x5020, addmod(mload(0x5000), mload(0xc20), f_q)) +mstore(0x5040, mulmod(21134065618345176623193549882539580312263652408302468683943992798037078993309, mload(0xbc0), f_q)) +mstore(0x5060, mulmod(mload(0xee0), mload(0x5040), f_q)) +mstore(0x5080, addmod(mload(0x4400), mload(0x5060), f_q)) +mstore(0x50a0, addmod(mload(0x5080), mload(0xc20), f_q)) +mstore(0x50c0, mulmod(mload(0x50a0), mload(0x5020), f_q)) +mstore(0x50e0, mulmod(mload(0x50c0), mload(0x1300), f_q)) +mstore(0x5100, addmod(mload(0x4fa0), sub(f_q, mload(0x50e0)), f_q)) +mstore(0x5120, mulmod(mload(0x5100), mload(0x4920), f_q)) +mstore(0x5140, addmod(mload(0x4ea0), mload(0x5120), f_q)) +mstore(0x5160, mulmod(mload(0xdc0), mload(0x5140), f_q)) +mstore(0x5180, addmod(1, sub(f_q, mload(0x1340)), f_q)) +mstore(0x51a0, mulmod(mload(0x5180), mload(0x3a60), f_q)) +mstore(0x51c0, addmod(mload(0x5160), mload(0x51a0), f_q)) +mstore(0x51e0, mulmod(mload(0xdc0), mload(0x51c0), f_q)) +mstore(0x5200, mulmod(mload(0x1340), mload(0x1340), f_q)) +mstore(0x5220, addmod(mload(0x5200), sub(f_q, mload(0x1340)), f_q)) +mstore(0x5240, mulmod(mload(0x5220), mload(0x3980), f_q)) +mstore(0x5260, addmod(mload(0x51e0), mload(0x5240), f_q)) +mstore(0x5280, mulmod(mload(0xdc0), mload(0x5260), f_q)) +mstore(0x52a0, addmod(mload(0x1380), mload(0xbc0), f_q)) +mstore(0x52c0, mulmod(mload(0x52a0), mload(0x1360), f_q)) +mstore(0x52e0, addmod(mload(0x13c0), mload(0xc20), f_q)) +mstore(0x5300, mulmod(mload(0x52e0), mload(0x52c0), f_q)) +mstore(0x5320, addmod(mload(0x10a0), mload(0xbc0), f_q)) +mstore(0x5340, mulmod(mload(0x5320), mload(0x1340), f_q)) +mstore(0x5360, addmod(mload(0x10e0), mload(0xc20), f_q)) +mstore(0x5380, mulmod(mload(0x5360), mload(0x5340), f_q)) +mstore(0x53a0, addmod(mload(0x5300), sub(f_q, mload(0x5380)), f_q)) +mstore(0x53c0, mulmod(mload(0x53a0), mload(0x4920), f_q)) +mstore(0x53e0, addmod(mload(0x5280), mload(0x53c0), f_q)) +mstore(0x5400, mulmod(mload(0xdc0), mload(0x53e0), f_q)) +mstore(0x5420, addmod(mload(0x1380), sub(f_q, mload(0x13c0)), f_q)) +mstore(0x5440, mulmod(mload(0x5420), mload(0x3a60), f_q)) +mstore(0x5460, addmod(mload(0x5400), mload(0x5440), f_q)) +mstore(0x5480, mulmod(mload(0xdc0), mload(0x5460), f_q)) +mstore(0x54a0, mulmod(mload(0x5420), mload(0x4920), f_q)) +mstore(0x54c0, addmod(mload(0x1380), sub(f_q, mload(0x13a0)), f_q)) +mstore(0x54e0, mulmod(mload(0x54c0), mload(0x54a0), f_q)) +mstore(0x5500, addmod(mload(0x5480), mload(0x54e0), f_q)) +mstore(0x5520, mulmod(mload(0x18c0), mload(0x18c0), f_q)) +mstore(0x5540, mulmod(mload(0x5520), mload(0x18c0), f_q)) +mstore(0x5560, mulmod(1, mload(0x18c0), f_q)) +mstore(0x5580, mulmod(1, mload(0x5520), f_q)) +mstore(0x55a0, mulmod(mload(0x5500), mload(0x18e0), f_q)) +mstore(0x55c0, mulmod(mload(0x1600), mload(0xee0), f_q)) +mstore(0x55e0, mulmod(mload(0x55c0), mload(0xee0), f_q)) +mstore(0x5600, mulmod(mload(0xee0), 4506835738822104338668100540817374747935106310012997856968187171738630203507, f_q)) +mstore(0x5620, addmod(mload(0x1500), sub(f_q, mload(0x5600)), f_q)) +mstore(0x5640, mulmod(mload(0xee0), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q)) +mstore(0x5660, addmod(mload(0x1500), sub(f_q, mload(0x5640)), f_q)) +mstore(0x5680, mulmod(mload(0xee0), 1, f_q)) +mstore(0x56a0, addmod(mload(0x1500), sub(f_q, mload(0x5680)), f_q)) +mstore(0x56c0, mulmod(mload(0xee0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) +mstore(0x56e0, addmod(mload(0x1500), sub(f_q, mload(0x56c0)), f_q)) +mstore(0x5700, mulmod(mload(0xee0), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +mstore(0x5720, addmod(mload(0x1500), sub(f_q, mload(0x5700)), f_q)) +mstore(0x5740, mulmod(mload(0xee0), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q)) +mstore(0x5760, addmod(mload(0x1500), sub(f_q, mload(0x5740)), f_q)) +mstore(0x5780, mulmod(13213688729882003894512633350385593288217014177373218494356903340348818451480, mload(0x55c0), f_q)) +mstore(0x57a0, mulmod(mload(0x5780), 1, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x5780), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x57a0)), f_q), result, f_q) +mstore(22464, result) + } +mstore(0x57e0, mulmod(8207090019724696496350398458716998472718344609680392612601596849934418295470, mload(0x55c0), f_q)) +mstore(0x5800, mulmod(mload(0x57e0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x57e0), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5800)), f_q), result, f_q) +mstore(22560, result) + } +mstore(0x5840, mulmod(7391709068497399131897422873231908718558236401035363928063603272120120747483, mload(0x55c0), f_q)) +mstore(0x5860, mulmod(mload(0x5840), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x5840), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5860)), f_q), result, f_q) +mstore(22656, result) + } +mstore(0x58a0, mulmod(19036273796805830823244991598792794567595348772040298280440552631112242221017, mload(0x55c0), f_q)) +mstore(0x58c0, mulmod(mload(0x58a0), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x58a0), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x58c0)), f_q), result, f_q) +mstore(22752, result) + } +mstore(0x5900, mulmod(1, mload(0x56a0), f_q)) +mstore(0x5920, mulmod(mload(0x5900), mload(0x56e0), f_q)) +mstore(0x5940, mulmod(mload(0x5920), mload(0x5720), f_q)) +mstore(0x5960, mulmod(mload(0x5940), mload(0x5760), f_q)) +{ + let result := mulmod(mload(0x1500), 1, f_q) +result := addmod(mulmod(mload(0xee0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q) +mstore(22912, result) + } +mstore(0x59a0, mulmod(8829162144871436359454223005614551490263319522284589706138791622554149795206, mload(0x1600), f_q)) +mstore(0x59c0, mulmod(mload(0x59a0), 1, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x59a0), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x59c0)), f_q), result, f_q) +mstore(23008, result) + } +mstore(0x5a00, mulmod(7521631813486699681549447421085572414068158796105686593554181156957026089108, mload(0x1600), f_q)) +mstore(0x5a20, mulmod(mload(0x5a00), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x5a00), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5a20)), f_q), result, f_q) +mstore(23104, result) + } +mstore(0x5a60, mulmod(17271195128855212178510154473373610729639201669583744426527435765917537447443, mload(0x1600), f_q)) +mstore(0x5a80, mulmod(mload(0x5a60), 4506835738822104338668100540817374747935106310012997856968187171738630203507, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x5a60), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5a80)), f_q), result, f_q) +mstore(23200, result) + } +mstore(0x5ac0, mulmod(mload(0x5920), mload(0x5620), f_q)) +mstore(0x5ae0, mulmod(13513867906530865119835332133273263211836799082674232843258448413103731898271, mload(0xee0), f_q)) +mstore(0x5b00, mulmod(mload(0x5ae0), 1, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x5ae0), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5b00)), f_q), result, f_q) +mstore(23328, result) + } +mstore(0x5b40, mulmod(8374374965308410102411073611984011876711565317741801500439755773472076597346, mload(0xee0), f_q)) +mstore(0x5b60, mulmod(mload(0x5b40), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x5b40), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5b60)), f_q), result, f_q) +mstore(23424, result) + } +mstore(0x5ba0, mulmod(12146688980418810893951125255607130521645347193942732958664170801695864621271, mload(0xee0), f_q)) +mstore(0x5bc0, mulmod(mload(0x5ba0), 1, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x5ba0), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5bc0)), f_q), result, f_q) +mstore(23520, result) + } +mstore(0x5c00, mulmod(9741553891420464328295280489650144566903017206473301385034033384879943874346, mload(0xee0), f_q)) +mstore(0x5c20, mulmod(mload(0x5c00), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q)) +{ + let result := mulmod(mload(0x1500), mload(0x5c00), f_q) +result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5c20)), f_q), result, f_q) +mstore(23616, result) + } +mstore(0x5c60, mulmod(mload(0x5900), mload(0x5660), f_q)) +{ + let prod := mload(0x57c0) + + prod := mulmod(mload(0x5820), prod, f_q) + mstore(0x5c80, prod) + + prod := mulmod(mload(0x5880), prod, f_q) + mstore(0x5ca0, prod) + + prod := mulmod(mload(0x58e0), prod, f_q) + mstore(0x5cc0, prod) + + prod := mulmod(mload(0x5980), prod, f_q) + mstore(0x5ce0, prod) + + prod := mulmod(mload(0x5900), prod, f_q) + mstore(0x5d00, prod) + + prod := mulmod(mload(0x59e0), prod, f_q) + mstore(0x5d20, prod) + + prod := mulmod(mload(0x5a40), prod, f_q) + mstore(0x5d40, prod) + + prod := mulmod(mload(0x5aa0), prod, f_q) + mstore(0x5d60, prod) + + prod := mulmod(mload(0x5ac0), prod, f_q) + mstore(0x5d80, prod) + + prod := mulmod(mload(0x5b20), prod, f_q) + mstore(0x5da0, prod) + + prod := mulmod(mload(0x5b80), prod, f_q) + mstore(0x5dc0, prod) + + prod := mulmod(mload(0x5920), prod, f_q) + mstore(0x5de0, prod) + + prod := mulmod(mload(0x5be0), prod, f_q) + mstore(0x5e00, prod) + + prod := mulmod(mload(0x5c40), prod, f_q) + mstore(0x5e20, prod) + + prod := mulmod(mload(0x5c60), prod, f_q) + mstore(0x5e40, prod) + + } +mstore(0x5e80, 32) +mstore(0x5ea0, 32) +mstore(0x5ec0, 32) +mstore(0x5ee0, mload(0x5e40)) +mstore(0x5f00, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x5f20, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x5e80, 0xc0, 0x5e60, 0x20), 1), success) +{ + + let inv := mload(0x5e60) + let v + + v := mload(0x5c60) + mstore(23648, mulmod(mload(0x5e20), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5c40) + mstore(23616, mulmod(mload(0x5e00), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5be0) + mstore(23520, mulmod(mload(0x5de0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5920) + mstore(22816, mulmod(mload(0x5dc0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5b80) + mstore(23424, mulmod(mload(0x5da0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5b20) + mstore(23328, mulmod(mload(0x5d80), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5ac0) + mstore(23232, mulmod(mload(0x5d60), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5aa0) + mstore(23200, mulmod(mload(0x5d40), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5a40) + mstore(23104, mulmod(mload(0x5d20), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x59e0) + mstore(23008, mulmod(mload(0x5d00), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5900) + mstore(22784, mulmod(mload(0x5ce0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5980) + mstore(22912, mulmod(mload(0x5cc0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x58e0) + mstore(22752, mulmod(mload(0x5ca0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5880) + mstore(22656, mulmod(mload(0x5c80), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5820) + mstore(22560, mulmod(mload(0x57c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + mstore(0x57c0, inv) + + } +{ + let result := mload(0x57c0) +result := addmod(mload(0x5820), result, f_q) +result := addmod(mload(0x5880), result, f_q) +result := addmod(mload(0x58e0), result, f_q) +mstore(24384, result) + } +mstore(0x5f60, mulmod(mload(0x5960), mload(0x5900), f_q)) +{ + let result := mload(0x5980) +mstore(24448, result) + } +mstore(0x5fa0, mulmod(mload(0x5960), mload(0x5ac0), f_q)) +{ + let result := mload(0x59e0) +result := addmod(mload(0x5a40), result, f_q) +result := addmod(mload(0x5aa0), result, f_q) +mstore(24512, result) + } +mstore(0x5fe0, mulmod(mload(0x5960), mload(0x5920), f_q)) +{ + let result := mload(0x5b20) +result := addmod(mload(0x5b80), result, f_q) +mstore(24576, result) + } +mstore(0x6020, mulmod(mload(0x5960), mload(0x5c60), f_q)) +{ + let result := mload(0x5be0) +result := addmod(mload(0x5c40), result, f_q) +mstore(24640, result) + } +{ + let prod := mload(0x5f40) + + prod := mulmod(mload(0x5f80), prod, f_q) + mstore(0x6060, prod) + + prod := mulmod(mload(0x5fc0), prod, f_q) + mstore(0x6080, prod) + + prod := mulmod(mload(0x6000), prod, f_q) + mstore(0x60a0, prod) + + prod := mulmod(mload(0x6040), prod, f_q) + mstore(0x60c0, prod) + + } +mstore(0x6100, 32) +mstore(0x6120, 32) +mstore(0x6140, 32) +mstore(0x6160, mload(0x60c0)) +mstore(0x6180, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x61a0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x6100, 0xc0, 0x60e0, 0x20), 1), success) +{ + + let inv := mload(0x60e0) + let v + + v := mload(0x6040) + mstore(24640, mulmod(mload(0x60a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x6000) + mstore(24576, mulmod(mload(0x6080), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5fc0) + mstore(24512, mulmod(mload(0x6060), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x5f80) + mstore(24448, mulmod(mload(0x5f40), inv, f_q)) + inv := mulmod(v, inv, f_q) + mstore(0x5f40, inv) + + } +mstore(0x61c0, mulmod(mload(0x5f60), mload(0x5f80), f_q)) +mstore(0x61e0, mulmod(mload(0x5fa0), mload(0x5fc0), f_q)) +mstore(0x6200, mulmod(mload(0x5fe0), mload(0x6000), f_q)) +mstore(0x6220, mulmod(mload(0x6020), mload(0x6040), f_q)) +mstore(0x6240, mulmod(mload(0x1400), mload(0x1400), f_q)) +mstore(0x6260, mulmod(mload(0x6240), mload(0x1400), f_q)) +mstore(0x6280, mulmod(mload(0x6260), mload(0x1400), f_q)) +mstore(0x62a0, mulmod(mload(0x6280), mload(0x1400), f_q)) +mstore(0x62c0, mulmod(mload(0x62a0), mload(0x1400), f_q)) +mstore(0x62e0, mulmod(mload(0x62c0), mload(0x1400), f_q)) +mstore(0x6300, mulmod(mload(0x62e0), mload(0x1400), f_q)) +mstore(0x6320, mulmod(mload(0x6300), mload(0x1400), f_q)) +mstore(0x6340, mulmod(mload(0x6320), mload(0x1400), f_q)) +mstore(0x6360, mulmod(mload(0x6340), mload(0x1400), f_q)) +mstore(0x6380, mulmod(mload(0x6360), mload(0x1400), f_q)) +mstore(0x63a0, mulmod(mload(0x6380), mload(0x1400), f_q)) +mstore(0x63c0, mulmod(mload(0x63a0), mload(0x1400), f_q)) +mstore(0x63e0, mulmod(mload(0x63c0), mload(0x1400), f_q)) +mstore(0x6400, mulmod(mload(0x1460), mload(0x1460), f_q)) +mstore(0x6420, mulmod(mload(0x6400), mload(0x1460), f_q)) +mstore(0x6440, mulmod(mload(0x6420), mload(0x1460), f_q)) +mstore(0x6460, mulmod(mload(0x6440), mload(0x1460), f_q)) +{ + let result := mulmod(mload(0xf20), mload(0x57c0), f_q) +result := addmod(mulmod(mload(0xf40), mload(0x5820), f_q), result, f_q) +result := addmod(mulmod(mload(0xf60), mload(0x5880), f_q), result, f_q) +result := addmod(mulmod(mload(0xf80), mload(0x58e0), f_q), result, f_q) +mstore(25728, result) + } +mstore(0x64a0, mulmod(mload(0x6480), mload(0x5f40), f_q)) +mstore(0x64c0, mulmod(sub(f_q, mload(0x64a0)), 1, f_q)) +{ + let result := mulmod(mload(0xfa0), mload(0x57c0), f_q) +result := addmod(mulmod(mload(0xfc0), mload(0x5820), f_q), result, f_q) +result := addmod(mulmod(mload(0xfe0), mload(0x5880), f_q), result, f_q) +result := addmod(mulmod(mload(0x1000), mload(0x58e0), f_q), result, f_q) +mstore(25824, result) + } +mstore(0x6500, mulmod(mload(0x64e0), mload(0x5f40), f_q)) +mstore(0x6520, mulmod(sub(f_q, mload(0x6500)), mload(0x1400), f_q)) +mstore(0x6540, mulmod(1, mload(0x1400), f_q)) +mstore(0x6560, addmod(mload(0x64c0), mload(0x6520), f_q)) +{ + let result := mulmod(mload(0x1020), mload(0x57c0), f_q) +result := addmod(mulmod(mload(0x1040), mload(0x5820), f_q), result, f_q) +result := addmod(mulmod(mload(0x1060), mload(0x5880), f_q), result, f_q) +result := addmod(mulmod(mload(0x1080), mload(0x58e0), f_q), result, f_q) +mstore(25984, result) + } +mstore(0x65a0, mulmod(mload(0x6580), mload(0x5f40), f_q)) +mstore(0x65c0, mulmod(sub(f_q, mload(0x65a0)), mload(0x6240), f_q)) +mstore(0x65e0, mulmod(1, mload(0x6240), f_q)) +mstore(0x6600, addmod(mload(0x6560), mload(0x65c0), f_q)) +mstore(0x6620, mulmod(mload(0x6600), 1, f_q)) +mstore(0x6640, mulmod(mload(0x6540), 1, f_q)) +mstore(0x6660, mulmod(mload(0x65e0), 1, f_q)) +mstore(0x6680, mulmod(1, mload(0x5f60), f_q)) +{ + let result := mulmod(mload(0x10a0), mload(0x5980), f_q) +mstore(26272, result) + } +mstore(0x66c0, mulmod(mload(0x66a0), mload(0x61c0), f_q)) +mstore(0x66e0, mulmod(sub(f_q, mload(0x66c0)), 1, f_q)) +mstore(0x6700, mulmod(mload(0x6680), 1, f_q)) +{ + let result := mulmod(mload(0x13c0), mload(0x5980), f_q) +mstore(26400, result) + } +mstore(0x6740, mulmod(mload(0x6720), mload(0x61c0), f_q)) +mstore(0x6760, mulmod(sub(f_q, mload(0x6740)), mload(0x1400), f_q)) +mstore(0x6780, mulmod(mload(0x6680), mload(0x1400), f_q)) +mstore(0x67a0, addmod(mload(0x66e0), mload(0x6760), f_q)) +{ + let result := mulmod(mload(0x10c0), mload(0x5980), f_q) +mstore(26560, result) + } +mstore(0x67e0, mulmod(mload(0x67c0), mload(0x61c0), f_q)) +mstore(0x6800, mulmod(sub(f_q, mload(0x67e0)), mload(0x6240), f_q)) +mstore(0x6820, mulmod(mload(0x6680), mload(0x6240), f_q)) +mstore(0x6840, addmod(mload(0x67a0), mload(0x6800), f_q)) +{ + let result := mulmod(mload(0x10e0), mload(0x5980), f_q) +mstore(26720, result) + } +mstore(0x6880, mulmod(mload(0x6860), mload(0x61c0), f_q)) +mstore(0x68a0, mulmod(sub(f_q, mload(0x6880)), mload(0x6260), f_q)) +mstore(0x68c0, mulmod(mload(0x6680), mload(0x6260), f_q)) +mstore(0x68e0, addmod(mload(0x6840), mload(0x68a0), f_q)) +{ + let result := mulmod(mload(0x1100), mload(0x5980), f_q) +mstore(26880, result) + } +mstore(0x6920, mulmod(mload(0x6900), mload(0x61c0), f_q)) +mstore(0x6940, mulmod(sub(f_q, mload(0x6920)), mload(0x6280), f_q)) +mstore(0x6960, mulmod(mload(0x6680), mload(0x6280), f_q)) +mstore(0x6980, addmod(mload(0x68e0), mload(0x6940), f_q)) +{ + let result := mulmod(mload(0x1120), mload(0x5980), f_q) +mstore(27040, result) + } +mstore(0x69c0, mulmod(mload(0x69a0), mload(0x61c0), f_q)) +mstore(0x69e0, mulmod(sub(f_q, mload(0x69c0)), mload(0x62a0), f_q)) +mstore(0x6a00, mulmod(mload(0x6680), mload(0x62a0), f_q)) +mstore(0x6a20, addmod(mload(0x6980), mload(0x69e0), f_q)) +{ + let result := mulmod(mload(0x1140), mload(0x5980), f_q) +mstore(27200, result) + } +mstore(0x6a60, mulmod(mload(0x6a40), mload(0x61c0), f_q)) +mstore(0x6a80, mulmod(sub(f_q, mload(0x6a60)), mload(0x62c0), f_q)) +mstore(0x6aa0, mulmod(mload(0x6680), mload(0x62c0), f_q)) +mstore(0x6ac0, addmod(mload(0x6a20), mload(0x6a80), f_q)) +{ + let result := mulmod(mload(0x1180), mload(0x5980), f_q) +mstore(27360, result) + } +mstore(0x6b00, mulmod(mload(0x6ae0), mload(0x61c0), f_q)) +mstore(0x6b20, mulmod(sub(f_q, mload(0x6b00)), mload(0x62e0), f_q)) +mstore(0x6b40, mulmod(mload(0x6680), mload(0x62e0), f_q)) +mstore(0x6b60, addmod(mload(0x6ac0), mload(0x6b20), f_q)) +{ + let result := mulmod(mload(0x11a0), mload(0x5980), f_q) +mstore(27520, result) + } +mstore(0x6ba0, mulmod(mload(0x6b80), mload(0x61c0), f_q)) +mstore(0x6bc0, mulmod(sub(f_q, mload(0x6ba0)), mload(0x6300), f_q)) +mstore(0x6be0, mulmod(mload(0x6680), mload(0x6300), f_q)) +mstore(0x6c00, addmod(mload(0x6b60), mload(0x6bc0), f_q)) +{ + let result := mulmod(mload(0x11c0), mload(0x5980), f_q) +mstore(27680, result) + } +mstore(0x6c40, mulmod(mload(0x6c20), mload(0x61c0), f_q)) +mstore(0x6c60, mulmod(sub(f_q, mload(0x6c40)), mload(0x6320), f_q)) +mstore(0x6c80, mulmod(mload(0x6680), mload(0x6320), f_q)) +mstore(0x6ca0, addmod(mload(0x6c00), mload(0x6c60), f_q)) +{ + let result := mulmod(mload(0x11e0), mload(0x5980), f_q) +mstore(27840, result) + } +mstore(0x6ce0, mulmod(mload(0x6cc0), mload(0x61c0), f_q)) +mstore(0x6d00, mulmod(sub(f_q, mload(0x6ce0)), mload(0x6340), f_q)) +mstore(0x6d20, mulmod(mload(0x6680), mload(0x6340), f_q)) +mstore(0x6d40, addmod(mload(0x6ca0), mload(0x6d00), f_q)) +{ + let result := mulmod(mload(0x1200), mload(0x5980), f_q) +mstore(28000, result) + } +mstore(0x6d80, mulmod(mload(0x6d60), mload(0x61c0), f_q)) +mstore(0x6da0, mulmod(sub(f_q, mload(0x6d80)), mload(0x6360), f_q)) +mstore(0x6dc0, mulmod(mload(0x6680), mload(0x6360), f_q)) +mstore(0x6de0, addmod(mload(0x6d40), mload(0x6da0), f_q)) +{ + let result := mulmod(mload(0x1220), mload(0x5980), f_q) +mstore(28160, result) + } +mstore(0x6e20, mulmod(mload(0x6e00), mload(0x61c0), f_q)) +mstore(0x6e40, mulmod(sub(f_q, mload(0x6e20)), mload(0x6380), f_q)) +mstore(0x6e60, mulmod(mload(0x6680), mload(0x6380), f_q)) +mstore(0x6e80, addmod(mload(0x6de0), mload(0x6e40), f_q)) +mstore(0x6ea0, mulmod(mload(0x5560), mload(0x5f60), f_q)) +mstore(0x6ec0, mulmod(mload(0x5580), mload(0x5f60), f_q)) +{ + let result := mulmod(mload(0x55a0), mload(0x5980), f_q) +mstore(28384, result) + } +mstore(0x6f00, mulmod(mload(0x6ee0), mload(0x61c0), f_q)) +mstore(0x6f20, mulmod(sub(f_q, mload(0x6f00)), mload(0x63a0), f_q)) +mstore(0x6f40, mulmod(mload(0x6680), mload(0x63a0), f_q)) +mstore(0x6f60, mulmod(mload(0x6ea0), mload(0x63a0), f_q)) +mstore(0x6f80, mulmod(mload(0x6ec0), mload(0x63a0), f_q)) +mstore(0x6fa0, addmod(mload(0x6e80), mload(0x6f20), f_q)) +{ + let result := mulmod(mload(0x1160), mload(0x5980), f_q) +mstore(28608, result) + } +mstore(0x6fe0, mulmod(mload(0x6fc0), mload(0x61c0), f_q)) +mstore(0x7000, mulmod(sub(f_q, mload(0x6fe0)), mload(0x63c0), f_q)) +mstore(0x7020, mulmod(mload(0x6680), mload(0x63c0), f_q)) +mstore(0x7040, addmod(mload(0x6fa0), mload(0x7000), f_q)) +mstore(0x7060, mulmod(mload(0x7040), mload(0x1460), f_q)) +mstore(0x7080, mulmod(mload(0x6700), mload(0x1460), f_q)) +mstore(0x70a0, mulmod(mload(0x6780), mload(0x1460), f_q)) +mstore(0x70c0, mulmod(mload(0x6820), mload(0x1460), f_q)) +mstore(0x70e0, mulmod(mload(0x68c0), mload(0x1460), f_q)) +mstore(0x7100, mulmod(mload(0x6960), mload(0x1460), f_q)) +mstore(0x7120, mulmod(mload(0x6a00), mload(0x1460), f_q)) +mstore(0x7140, mulmod(mload(0x6aa0), mload(0x1460), f_q)) +mstore(0x7160, mulmod(mload(0x6b40), mload(0x1460), f_q)) +mstore(0x7180, mulmod(mload(0x6be0), mload(0x1460), f_q)) +mstore(0x71a0, mulmod(mload(0x6c80), mload(0x1460), f_q)) +mstore(0x71c0, mulmod(mload(0x6d20), mload(0x1460), f_q)) +mstore(0x71e0, mulmod(mload(0x6dc0), mload(0x1460), f_q)) +mstore(0x7200, mulmod(mload(0x6e60), mload(0x1460), f_q)) +mstore(0x7220, mulmod(mload(0x6f40), mload(0x1460), f_q)) +mstore(0x7240, mulmod(mload(0x6f60), mload(0x1460), f_q)) +mstore(0x7260, mulmod(mload(0x6f80), mload(0x1460), f_q)) +mstore(0x7280, mulmod(mload(0x7020), mload(0x1460), f_q)) +mstore(0x72a0, addmod(mload(0x6620), mload(0x7060), f_q)) +mstore(0x72c0, mulmod(1, mload(0x5fa0), f_q)) +{ + let result := mulmod(mload(0x1240), mload(0x59e0), f_q) +result := addmod(mulmod(mload(0x1260), mload(0x5a40), f_q), result, f_q) +result := addmod(mulmod(mload(0x1280), mload(0x5aa0), f_q), result, f_q) +mstore(29408, result) + } +mstore(0x7300, mulmod(mload(0x72e0), mload(0x61e0), f_q)) +mstore(0x7320, mulmod(sub(f_q, mload(0x7300)), 1, f_q)) +mstore(0x7340, mulmod(mload(0x72c0), 1, f_q)) +{ + let result := mulmod(mload(0x12a0), mload(0x59e0), f_q) +result := addmod(mulmod(mload(0x12c0), mload(0x5a40), f_q), result, f_q) +result := addmod(mulmod(mload(0x12e0), mload(0x5aa0), f_q), result, f_q) +mstore(29536, result) + } +mstore(0x7380, mulmod(mload(0x7360), mload(0x61e0), f_q)) +mstore(0x73a0, mulmod(sub(f_q, mload(0x7380)), mload(0x1400), f_q)) +mstore(0x73c0, mulmod(mload(0x72c0), mload(0x1400), f_q)) +mstore(0x73e0, addmod(mload(0x7320), mload(0x73a0), f_q)) +mstore(0x7400, mulmod(mload(0x73e0), mload(0x6400), f_q)) +mstore(0x7420, mulmod(mload(0x7340), mload(0x6400), f_q)) +mstore(0x7440, mulmod(mload(0x73c0), mload(0x6400), f_q)) +mstore(0x7460, addmod(mload(0x72a0), mload(0x7400), f_q)) +mstore(0x7480, mulmod(1, mload(0x5fe0), f_q)) +{ + let result := mulmod(mload(0x1300), mload(0x5b20), f_q) +result := addmod(mulmod(mload(0x1320), mload(0x5b80), f_q), result, f_q) +mstore(29856, result) + } +mstore(0x74c0, mulmod(mload(0x74a0), mload(0x6200), f_q)) +mstore(0x74e0, mulmod(sub(f_q, mload(0x74c0)), 1, f_q)) +mstore(0x7500, mulmod(mload(0x7480), 1, f_q)) +{ + let result := mulmod(mload(0x1340), mload(0x5b20), f_q) +result := addmod(mulmod(mload(0x1360), mload(0x5b80), f_q), result, f_q) +mstore(29984, result) + } +mstore(0x7540, mulmod(mload(0x7520), mload(0x6200), f_q)) +mstore(0x7560, mulmod(sub(f_q, mload(0x7540)), mload(0x1400), f_q)) +mstore(0x7580, mulmod(mload(0x7480), mload(0x1400), f_q)) +mstore(0x75a0, addmod(mload(0x74e0), mload(0x7560), f_q)) +mstore(0x75c0, mulmod(mload(0x75a0), mload(0x6420), f_q)) +mstore(0x75e0, mulmod(mload(0x7500), mload(0x6420), f_q)) +mstore(0x7600, mulmod(mload(0x7580), mload(0x6420), f_q)) +mstore(0x7620, addmod(mload(0x7460), mload(0x75c0), f_q)) +mstore(0x7640, mulmod(1, mload(0x6020), f_q)) +{ + let result := mulmod(mload(0x1380), mload(0x5be0), f_q) +result := addmod(mulmod(mload(0x13a0), mload(0x5c40), f_q), result, f_q) +mstore(30304, result) + } +mstore(0x7680, mulmod(mload(0x7660), mload(0x6220), f_q)) +mstore(0x76a0, mulmod(sub(f_q, mload(0x7680)), 1, f_q)) +mstore(0x76c0, mulmod(mload(0x7640), 1, f_q)) +mstore(0x76e0, mulmod(mload(0x76a0), mload(0x6440), f_q)) +mstore(0x7700, mulmod(mload(0x76c0), mload(0x6440), f_q)) +mstore(0x7720, addmod(mload(0x7620), mload(0x76e0), f_q)) +mstore(0x7740, mulmod(1, mload(0x5960), f_q)) +mstore(0x7760, mulmod(1, mload(0x1500), f_q)) +mstore(0x7780, 0x0000000000000000000000000000000000000000000000000000000000000001) + mstore(0x77a0, 0x0000000000000000000000000000000000000000000000000000000000000002) +mstore(0x77c0, mload(0x7720)) +success := and(eq(staticcall(gas(), 0x7, 0x7780, 0x60, 0x7780, 0x40), 1), success) +mstore(0x77e0, mload(0x7780)) + mstore(0x7800, mload(0x77a0)) +mstore(0x7820, mload(0x9c0)) + mstore(0x7840, mload(0x9e0)) +success := and(eq(staticcall(gas(), 0x6, 0x77e0, 0x80, 0x77e0, 0x40), 1), success) +mstore(0x7860, mload(0xa00)) + mstore(0x7880, mload(0xa20)) +mstore(0x78a0, mload(0x6640)) +success := and(eq(staticcall(gas(), 0x7, 0x7860, 0x60, 0x7860, 0x40), 1), success) +mstore(0x78c0, mload(0x77e0)) + mstore(0x78e0, mload(0x7800)) +mstore(0x7900, mload(0x7860)) + mstore(0x7920, mload(0x7880)) +success := and(eq(staticcall(gas(), 0x6, 0x78c0, 0x80, 0x78c0, 0x40), 1), success) +mstore(0x7940, mload(0xa40)) + mstore(0x7960, mload(0xa60)) +mstore(0x7980, mload(0x6660)) +success := and(eq(staticcall(gas(), 0x7, 0x7940, 0x60, 0x7940, 0x40), 1), success) +mstore(0x79a0, mload(0x78c0)) + mstore(0x79c0, mload(0x78e0)) +mstore(0x79e0, mload(0x7940)) + mstore(0x7a00, mload(0x7960)) +success := and(eq(staticcall(gas(), 0x6, 0x79a0, 0x80, 0x79a0, 0x40), 1), success) +mstore(0x7a20, mload(0xa80)) + mstore(0x7a40, mload(0xaa0)) +mstore(0x7a60, mload(0x7080)) +success := and(eq(staticcall(gas(), 0x7, 0x7a20, 0x60, 0x7a20, 0x40), 1), success) +mstore(0x7a80, mload(0x79a0)) + mstore(0x7aa0, mload(0x79c0)) +mstore(0x7ac0, mload(0x7a20)) + mstore(0x7ae0, mload(0x7a40)) +success := and(eq(staticcall(gas(), 0x6, 0x7a80, 0x80, 0x7a80, 0x40), 1), success) +mstore(0x7b00, mload(0xb60)) + mstore(0x7b20, mload(0xb80)) +mstore(0x7b40, mload(0x70a0)) +success := and(eq(staticcall(gas(), 0x7, 0x7b00, 0x60, 0x7b00, 0x40), 1), success) +mstore(0x7b60, mload(0x7a80)) + mstore(0x7b80, mload(0x7aa0)) +mstore(0x7ba0, mload(0x7b00)) + mstore(0x7bc0, mload(0x7b20)) +success := and(eq(staticcall(gas(), 0x6, 0x7b60, 0x80, 0x7b60, 0x40), 1), success) +mstore(0x7be0, 0x02529801904a042ae2e6e0506500939e3e1aae9d8453ca1bc9bdce0e042177e8) + mstore(0x7c00, 0x1c02cafbb17f01639588c4d0380b473fdf417c437b30b6d0b3b5ca0092024766) +mstore(0x7c20, mload(0x70c0)) +success := and(eq(staticcall(gas(), 0x7, 0x7be0, 0x60, 0x7be0, 0x40), 1), success) +mstore(0x7c40, mload(0x7b60)) + mstore(0x7c60, mload(0x7b80)) +mstore(0x7c80, mload(0x7be0)) + mstore(0x7ca0, mload(0x7c00)) +success := and(eq(staticcall(gas(), 0x6, 0x7c40, 0x80, 0x7c40, 0x40), 1), success) +mstore(0x7cc0, 0x03fab5527cc07125117069ef9aaa8d159cbacf20f5a795fb9e9279d3a330df37) + mstore(0x7ce0, 0x0c79716bdab8b8e9064cf0e18fa6ea148b3c2c347d8af670deaab48124f25c19) +mstore(0x7d00, mload(0x70e0)) +success := and(eq(staticcall(gas(), 0x7, 0x7cc0, 0x60, 0x7cc0, 0x40), 1), success) +mstore(0x7d20, mload(0x7c40)) + mstore(0x7d40, mload(0x7c60)) +mstore(0x7d60, mload(0x7cc0)) + mstore(0x7d80, mload(0x7ce0)) +success := and(eq(staticcall(gas(), 0x6, 0x7d20, 0x80, 0x7d20, 0x40), 1), success) +mstore(0x7da0, 0x104921367752748430ed7cd30ff25d3c197ab4c7b8848e6e19c7fffdceaf2952) + mstore(0x7dc0, 0x1768e69d499e4b0b78195ba8650460be7853032e4422619ff3a71866d73e3f61) +mstore(0x7de0, mload(0x7100)) +success := and(eq(staticcall(gas(), 0x7, 0x7da0, 0x60, 0x7da0, 0x40), 1), success) +mstore(0x7e00, mload(0x7d20)) + mstore(0x7e20, mload(0x7d40)) +mstore(0x7e40, mload(0x7da0)) + mstore(0x7e60, mload(0x7dc0)) +success := and(eq(staticcall(gas(), 0x6, 0x7e00, 0x80, 0x7e00, 0x40), 1), success) +mstore(0x7e80, 0x20e969dfec5b4b2628746eaa13552f4da062c8b77aa7f7491ec4ea67ccd06cd8) + mstore(0x7ea0, 0x115c896126f1785878e65c2fa009b4b7eb68db9ec213bcf540489ae74149e2d1) +mstore(0x7ec0, mload(0x7120)) +success := and(eq(staticcall(gas(), 0x7, 0x7e80, 0x60, 0x7e80, 0x40), 1), success) +mstore(0x7ee0, mload(0x7e00)) + mstore(0x7f00, mload(0x7e20)) +mstore(0x7f20, mload(0x7e80)) + mstore(0x7f40, mload(0x7ea0)) +success := and(eq(staticcall(gas(), 0x6, 0x7ee0, 0x80, 0x7ee0, 0x40), 1), success) +mstore(0x7f60, 0x1b1b120eef75878fc4d88fcf5c2a8d27c0e3ff3d48074680849ac386cdac4852) + mstore(0x7f80, 0x268bd68c8051137a1398d395dce4c5d081eb3d275083a2f5d9e1fd8130b564ee) +mstore(0x7fa0, mload(0x7140)) +success := and(eq(staticcall(gas(), 0x7, 0x7f60, 0x60, 0x7f60, 0x40), 1), success) +mstore(0x7fc0, mload(0x7ee0)) + mstore(0x7fe0, mload(0x7f00)) +mstore(0x8000, mload(0x7f60)) + mstore(0x8020, mload(0x7f80)) +success := and(eq(staticcall(gas(), 0x6, 0x7fc0, 0x80, 0x7fc0, 0x40), 1), success) +mstore(0x8040, 0x1963f0599c52648a352eb510c753e922e542763dff76fbb32d098cc201b5a2fc) + mstore(0x8060, 0x29efcbd2af6d9fafc14fc334c92d163d316b6f2497423ba2ef7fb3efc4dda0db) +mstore(0x8080, mload(0x7160)) +success := and(eq(staticcall(gas(), 0x7, 0x8040, 0x60, 0x8040, 0x40), 1), success) +mstore(0x80a0, mload(0x7fc0)) + mstore(0x80c0, mload(0x7fe0)) +mstore(0x80e0, mload(0x8040)) + mstore(0x8100, mload(0x8060)) +success := and(eq(staticcall(gas(), 0x6, 0x80a0, 0x80, 0x80a0, 0x40), 1), success) +mstore(0x8120, 0x141d9b72ee15b4c295f928013de035a1c66ee026065deb2c03b2f50fa518a899) + mstore(0x8140, 0x2742eeb55603d0a1075bd00ce29a56dea927181ef4ffbff4a796e6452712d1c8) +mstore(0x8160, mload(0x7180)) +success := and(eq(staticcall(gas(), 0x7, 0x8120, 0x60, 0x8120, 0x40), 1), success) +mstore(0x8180, mload(0x80a0)) + mstore(0x81a0, mload(0x80c0)) +mstore(0x81c0, mload(0x8120)) + mstore(0x81e0, mload(0x8140)) +success := and(eq(staticcall(gas(), 0x6, 0x8180, 0x80, 0x8180, 0x40), 1), success) +mstore(0x8200, 0x2ca225b95e6bf7dea6c1da59fa8f219e4557d81829867d068edd92a512bab196) + mstore(0x8220, 0x02028e28c6bf82bc05fda0808b71b4e7b4f643a6c90bd9422eb2c7308c74f333) +mstore(0x8240, mload(0x71a0)) +success := and(eq(staticcall(gas(), 0x7, 0x8200, 0x60, 0x8200, 0x40), 1), success) +mstore(0x8260, mload(0x8180)) + mstore(0x8280, mload(0x81a0)) +mstore(0x82a0, mload(0x8200)) + mstore(0x82c0, mload(0x8220)) +success := and(eq(staticcall(gas(), 0x6, 0x8260, 0x80, 0x8260, 0x40), 1), success) +mstore(0x82e0, 0x04fdb5e1380e5c24b89e18fe8350090448fdff68168f30d895b7ceb66e7c1c72) + mstore(0x8300, 0x0e03ff6f5381c65fa8c8034ecdb70142d944ad2376829c442a96e554892a398b) +mstore(0x8320, mload(0x71c0)) +success := and(eq(staticcall(gas(), 0x7, 0x82e0, 0x60, 0x82e0, 0x40), 1), success) +mstore(0x8340, mload(0x8260)) + mstore(0x8360, mload(0x8280)) +mstore(0x8380, mload(0x82e0)) + mstore(0x83a0, mload(0x8300)) +success := and(eq(staticcall(gas(), 0x6, 0x8340, 0x80, 0x8340, 0x40), 1), success) +mstore(0x83c0, 0x14a4136420fd357c9d8b1b12f0af40965f1b0c6ddab81de11d42f1fe5d117d6e) + mstore(0x83e0, 0x0bdc4c68aa97468b20fe6b873aabf6619d92fe21a3e81a9bdc37d8a95b26e68a) +mstore(0x8400, mload(0x71e0)) +success := and(eq(staticcall(gas(), 0x7, 0x83c0, 0x60, 0x83c0, 0x40), 1), success) +mstore(0x8420, mload(0x8340)) + mstore(0x8440, mload(0x8360)) +mstore(0x8460, mload(0x83c0)) + mstore(0x8480, mload(0x83e0)) +success := and(eq(staticcall(gas(), 0x6, 0x8420, 0x80, 0x8420, 0x40), 1), success) +mstore(0x84a0, 0x0afbba6998967360bca4ed453f798405a0f5da3d9fa13221af670c071183caba) + mstore(0x84c0, 0x0ce036829484cbc26d88591f313ebad4b9ce4a11a6e4712fe96670b5736c955c) +mstore(0x84e0, mload(0x7200)) +success := and(eq(staticcall(gas(), 0x7, 0x84a0, 0x60, 0x84a0, 0x40), 1), success) +mstore(0x8500, mload(0x8420)) + mstore(0x8520, mload(0x8440)) +mstore(0x8540, mload(0x84a0)) + mstore(0x8560, mload(0x84c0)) +success := and(eq(staticcall(gas(), 0x6, 0x8500, 0x80, 0x8500, 0x40), 1), success) +mstore(0x8580, mload(0xe00)) + mstore(0x85a0, mload(0xe20)) +mstore(0x85c0, mload(0x7220)) +success := and(eq(staticcall(gas(), 0x7, 0x8580, 0x60, 0x8580, 0x40), 1), success) +mstore(0x85e0, mload(0x8500)) + mstore(0x8600, mload(0x8520)) +mstore(0x8620, mload(0x8580)) + mstore(0x8640, mload(0x85a0)) +success := and(eq(staticcall(gas(), 0x6, 0x85e0, 0x80, 0x85e0, 0x40), 1), success) +mstore(0x8660, mload(0xe40)) + mstore(0x8680, mload(0xe60)) +mstore(0x86a0, mload(0x7240)) +success := and(eq(staticcall(gas(), 0x7, 0x8660, 0x60, 0x8660, 0x40), 1), success) +mstore(0x86c0, mload(0x85e0)) + mstore(0x86e0, mload(0x8600)) +mstore(0x8700, mload(0x8660)) + mstore(0x8720, mload(0x8680)) +success := and(eq(staticcall(gas(), 0x6, 0x86c0, 0x80, 0x86c0, 0x40), 1), success) +mstore(0x8740, mload(0xe80)) + mstore(0x8760, mload(0xea0)) +mstore(0x8780, mload(0x7260)) +success := and(eq(staticcall(gas(), 0x7, 0x8740, 0x60, 0x8740, 0x40), 1), success) +mstore(0x87a0, mload(0x86c0)) + mstore(0x87c0, mload(0x86e0)) +mstore(0x87e0, mload(0x8740)) + mstore(0x8800, mload(0x8760)) +success := and(eq(staticcall(gas(), 0x6, 0x87a0, 0x80, 0x87a0, 0x40), 1), success) +mstore(0x8820, mload(0xd60)) + mstore(0x8840, mload(0xd80)) +mstore(0x8860, mload(0x7280)) +success := and(eq(staticcall(gas(), 0x7, 0x8820, 0x60, 0x8820, 0x40), 1), success) +mstore(0x8880, mload(0x87a0)) + mstore(0x88a0, mload(0x87c0)) +mstore(0x88c0, mload(0x8820)) + mstore(0x88e0, mload(0x8840)) +success := and(eq(staticcall(gas(), 0x6, 0x8880, 0x80, 0x8880, 0x40), 1), success) +mstore(0x8900, mload(0xc60)) + mstore(0x8920, mload(0xc80)) +mstore(0x8940, mload(0x7420)) +success := and(eq(staticcall(gas(), 0x7, 0x8900, 0x60, 0x8900, 0x40), 1), success) +mstore(0x8960, mload(0x8880)) + mstore(0x8980, mload(0x88a0)) +mstore(0x89a0, mload(0x8900)) + mstore(0x89c0, mload(0x8920)) +success := and(eq(staticcall(gas(), 0x6, 0x8960, 0x80, 0x8960, 0x40), 1), success) +mstore(0x89e0, mload(0xca0)) + mstore(0x8a00, mload(0xcc0)) +mstore(0x8a20, mload(0x7440)) +success := and(eq(staticcall(gas(), 0x7, 0x89e0, 0x60, 0x89e0, 0x40), 1), success) +mstore(0x8a40, mload(0x8960)) + mstore(0x8a60, mload(0x8980)) +mstore(0x8a80, mload(0x89e0)) + mstore(0x8aa0, mload(0x8a00)) +success := and(eq(staticcall(gas(), 0x6, 0x8a40, 0x80, 0x8a40, 0x40), 1), success) +mstore(0x8ac0, mload(0xce0)) + mstore(0x8ae0, mload(0xd00)) +mstore(0x8b00, mload(0x75e0)) +success := and(eq(staticcall(gas(), 0x7, 0x8ac0, 0x60, 0x8ac0, 0x40), 1), success) +mstore(0x8b20, mload(0x8a40)) + mstore(0x8b40, mload(0x8a60)) +mstore(0x8b60, mload(0x8ac0)) + mstore(0x8b80, mload(0x8ae0)) +success := and(eq(staticcall(gas(), 0x6, 0x8b20, 0x80, 0x8b20, 0x40), 1), success) +mstore(0x8ba0, mload(0xd20)) + mstore(0x8bc0, mload(0xd40)) +mstore(0x8be0, mload(0x7600)) +success := and(eq(staticcall(gas(), 0x7, 0x8ba0, 0x60, 0x8ba0, 0x40), 1), success) +mstore(0x8c00, mload(0x8b20)) + mstore(0x8c20, mload(0x8b40)) +mstore(0x8c40, mload(0x8ba0)) + mstore(0x8c60, mload(0x8bc0)) +success := and(eq(staticcall(gas(), 0x6, 0x8c00, 0x80, 0x8c00, 0x40), 1), success) +mstore(0x8c80, mload(0xb20)) + mstore(0x8ca0, mload(0xb40)) +mstore(0x8cc0, mload(0x7700)) +success := and(eq(staticcall(gas(), 0x7, 0x8c80, 0x60, 0x8c80, 0x40), 1), success) +mstore(0x8ce0, mload(0x8c00)) + mstore(0x8d00, mload(0x8c20)) +mstore(0x8d20, mload(0x8c80)) + mstore(0x8d40, mload(0x8ca0)) +success := and(eq(staticcall(gas(), 0x6, 0x8ce0, 0x80, 0x8ce0, 0x40), 1), success) +mstore(0x8d60, mload(0x14a0)) + mstore(0x8d80, mload(0x14c0)) +mstore(0x8da0, sub(f_q, mload(0x7740))) +success := and(eq(staticcall(gas(), 0x7, 0x8d60, 0x60, 0x8d60, 0x40), 1), success) +mstore(0x8dc0, mload(0x8ce0)) + mstore(0x8de0, mload(0x8d00)) +mstore(0x8e00, mload(0x8d60)) + mstore(0x8e20, mload(0x8d80)) +success := and(eq(staticcall(gas(), 0x6, 0x8dc0, 0x80, 0x8dc0, 0x40), 1), success) +mstore(0x8e40, mload(0x1540)) + mstore(0x8e60, mload(0x1560)) +mstore(0x8e80, mload(0x7760)) +success := and(eq(staticcall(gas(), 0x7, 0x8e40, 0x60, 0x8e40, 0x40), 1), success) +mstore(0x8ea0, mload(0x8dc0)) + mstore(0x8ec0, mload(0x8de0)) +mstore(0x8ee0, mload(0x8e40)) + mstore(0x8f00, mload(0x8e60)) +success := and(eq(staticcall(gas(), 0x6, 0x8ea0, 0x80, 0x8ea0, 0x40), 1), success) +mstore(0x8f20, mload(0x8ea0)) + mstore(0x8f40, mload(0x8ec0)) +mstore(0x8f60, mload(0x1540)) + mstore(0x8f80, mload(0x1560)) +mstore(0x8fa0, mload(0x1580)) + mstore(0x8fc0, mload(0x15a0)) +mstore(0x8fe0, mload(0x15c0)) + mstore(0x9000, mload(0x15e0)) +mstore(0x9020, keccak256(0x8f20, 256)) +mstore(36928, mod(mload(36896), f_q)) +mstore(0x9060, mulmod(mload(0x9040), mload(0x9040), f_q)) +mstore(0x9080, mulmod(1, mload(0x9040), f_q)) +mstore(0x90a0, mload(0x8fa0)) + mstore(0x90c0, mload(0x8fc0)) +mstore(0x90e0, mload(0x9080)) +success := and(eq(staticcall(gas(), 0x7, 0x90a0, 0x60, 0x90a0, 0x40), 1), success) +mstore(0x9100, mload(0x8f20)) + mstore(0x9120, mload(0x8f40)) +mstore(0x9140, mload(0x90a0)) + mstore(0x9160, mload(0x90c0)) +success := and(eq(staticcall(gas(), 0x6, 0x9100, 0x80, 0x9100, 0x40), 1), success) +mstore(0x9180, mload(0x8fe0)) + mstore(0x91a0, mload(0x9000)) +mstore(0x91c0, mload(0x9080)) +success := and(eq(staticcall(gas(), 0x7, 0x9180, 0x60, 0x9180, 0x40), 1), success) +mstore(0x91e0, mload(0x8f60)) + mstore(0x9200, mload(0x8f80)) +mstore(0x9220, mload(0x9180)) + mstore(0x9240, mload(0x91a0)) +success := and(eq(staticcall(gas(), 0x6, 0x91e0, 0x80, 0x91e0, 0x40), 1), success) +mstore(0x9260, mload(0x9100)) + mstore(0x9280, mload(0x9120)) +mstore(0x92a0, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) + mstore(0x92c0, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) + mstore(0x92e0, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) + mstore(0x9300, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) +mstore(0x9320, mload(0x91e0)) + mstore(0x9340, mload(0x9200)) +mstore(0x9360, 0x0181624e80f3d6ae28df7e01eaeab1c0e919877a3b8a6b7fbc69a6817d596ea2) + mstore(0x9380, 0x1783d30dcb12d259bb89098addf6280fa4b653be7a152542a28f7b926e27e648) + mstore(0x93a0, 0x00ae44489d41a0d179e2dfdc03bddd883b7109f8b6ae316a59e815c1a6b35304) + mstore(0x93c0, 0x0b2147ab62a386bd63e6de1522109b8c9588ab466f5aadfde8c41ca3749423ee) +success := and(eq(staticcall(gas(), 0x8, 0x9260, 0x180, 0x9260, 0x20), 1), success) +success := and(eq(mload(0x9260), 1), success) + + // Revert if anything fails + if iszero(success) { revert(0, 0) } + + // Return empty bytes on success + return(0, 0) + + } + } +} + \ No newline at end of file diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 7222f85c..3da91b35 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -58,47 +58,49 @@ impl CommitteeUpdateCircuit { let committee_root_ssz = Self::sync_committee_root_ssz(builder, &sha256_chip, compressed_encodings.clone())?; - let poseidon_commit = { - let pubkeys_x = Self::decode_pubkeys_x(builder.main(), fp_chip, compressed_encodings); - fq_array_poseidon(builder.main(), range.gate(), &pubkeys_x)? - }; + // let poseidon_commit = { + // let pubkeys_x = Self::decode_pubkeys_x(builder.main(), fp_chip, compressed_encodings); + // fq_array_poseidon(builder.main(), range.gate(), &pubkeys_x)? + // }; // Finalized header - let finalized_slot_bytes: HashInputChunk<_> = args.finalized_header.slot.into_witness(); - let finalized_state_root = args - .finalized_header - .state_root - .as_ref() - .iter() - .map(|v| builder.main().load_witness(F::from(*v as u64))) - .collect_vec(); - let finalized_header_root = ssz_merkleize_chunks( - builder, - &sha256_chip, - [ - finalized_slot_bytes, - args.finalized_header.proposer_index.into_witness(), - args.finalized_header.parent_root.as_ref().into_witness(), - finalized_state_root.clone().into(), - args.finalized_header.body_root.as_ref().into_witness(), - ], - )?; - // Verify that the sync committee root is in the finalized state root - verify_merkle_proof( - builder, - &sha256_chip, - args.sync_committee_branch - .iter() - .map(|w| w.clone().into_witness()), - committee_root_ssz.clone().into(), - &finalized_state_root, - S::SYNC_COMMITTEE_PUBKEYS_ROOT_INDEX, - )?; - - let public_inputs = iter::once(poseidon_commit) - .chain(committee_root_ssz) - .chain(finalized_header_root) - .collect(); + // let finalized_slot_bytes: HashInputChunk<_> = args.finalized_header.slot.into_witness(); + // let finalized_state_root = args + // .finalized_header + // .state_root + // .as_ref() + // .iter() + // .map(|v| builder.main().load_witness(F::from(*v as u64))) + // .collect_vec(); + // let finalized_header_root = ssz_merkleize_chunks( + // builder, + // &sha256_chip, + // [ + // finalized_slot_bytes, + // args.finalized_header.proposer_index.into_witness(), + // args.finalized_header.parent_root.as_ref().into_witness(), + // finalized_state_root.clone().into(), + // args.finalized_header.body_root.as_ref().into_witness(), + // ], + // )?; + // // Verify that the sync committee root is in the finalized state root + // verify_merkle_proof( + // builder, + // &sha256_chip, + // args.sync_committee_branch + // .iter() + // .map(|w| w.clone().into_witness()), + // committee_root_ssz.clone().into(), + // &finalized_state_root, + // S::SYNC_COMMITTEE_PUBKEYS_ROOT_INDEX, + // )?; + + // let public_inputs = iter::once(poseidon_commit) + // .chain(committee_root_ssz) + // .chain(finalized_header_root) + // .collect(); + + let public_inputs = vec![]; Ok(public_inputs) } @@ -149,7 +151,7 @@ impl CommitteeUpdateCircuit { .pad_using(64, |_| builder.main().load_zero()) .into(); hasher - .digest::<64>(builder, HashInput::Single(input), false) + .digest(builder, HashInput::Single(input)) .map(|r| r.into_iter().collect_vec().into()) }) .collect::, _>>()?; @@ -354,10 +356,10 @@ mod tests { #[test] fn test_circuit_aggregation_proofgen() { - const APP_PINNING_PATH: &str = "./config/committee_update_20.json"; - const APP_PK_PATH: &str = "../build/committee_update_20.pkey"; + const APP_PINNING_PATH: &str = "./config/committee_update_18.json"; + const APP_PK_PATH: &str = "../build/committee_update_18.pkey"; const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; - const APP_K: u32 = 20; + const APP_K: u32 = 18; let params_app = gen_srs(APP_K); const AGG_K: u32 = 22; @@ -394,6 +396,7 @@ mod tests { #[test] fn test_circuit_aggregation_evm() { const APP_K: u32 = 21; + const APP_PK_PATH: &str = "../build/committee_update_21.pkey"; const APP_PINNING_PATH: &str = "./config/committee_update_21.json"; const AGG_CONFIG_PATH: &str = "./config/committee_update_a.json"; let params_app = gen_srs(APP_K); @@ -401,7 +404,7 @@ mod tests { const AGG_K: u32 = 23; let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( ¶ms_app, - APP_PINNING_PATH, + APP_PK_PATH, APP_PINNING_PATH, false, &CommitteeRotationArgs::::default(), diff --git a/lightclient-circuits/src/gadget/common.rs b/lightclient-circuits/src/gadget/common.rs index f75351c2..49bdc324 100644 --- a/lightclient-circuits/src/gadget/common.rs +++ b/lightclient-circuits/src/gadget/common.rs @@ -1,6 +1,7 @@ //! Utility traits, functions used in the crate. use eth_types::Field; -use halo2_base::halo2_proofs::plonk::Expression; +use halo2_base::{halo2_proofs::plonk::Expression, Context, gates::GateInstructions, AssignedValue, QuantumCell}; +use itertools::Itertools; /// Returns the sum of the passed in cells pub mod sum { @@ -261,3 +262,27 @@ pub mod rlc { values.fold(init, |acc, value| acc * randomness.clone() + value) } } + +pub fn to_bytes_le( + a: &AssignedValue, + gate: &impl GateInstructions, + ctx: &mut Context, +) -> Vec> { + let byte_bases = (0..MAX_BYTES) + .map(|i| QuantumCell::Constant(gate.pow_of_two()[i * 8])) + .collect_vec(); + + let assigned_bytes = a + .value() + .to_bytes_le() + .into_iter() + .take(MAX_BYTES) + .map(|v| ctx.load_witness(F::from(v as u64))) + .collect_vec(); + + // Constrain poseidon bytes to be equal to the recovered checksum + let checksum = gate.inner_product(ctx, assigned_bytes.clone(), byte_bases); + ctx.constrain_equal(&a, &checksum); + + assigned_bytes +} diff --git a/lightclient-circuits/src/gadget/crypto/builder.rs b/lightclient-circuits/src/gadget/crypto/builder.rs index 4c22cb6d..0e9254e9 100644 --- a/lightclient-circuits/src/gadget/crypto/builder.rs +++ b/lightclient-circuits/src/gadget/crypto/builder.rs @@ -32,7 +32,7 @@ pub struct SHAConfig> { pub base: BaseConfig, } -impl> SHAConfig { +impl> SHAConfig { pub fn configure(meta: &mut ConstraintSystem, params: BaseCircuitParams) -> Self { let base = BaseConfig::configure(meta, params); let compression = GateConfig::configure(meta); diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs index d32d4bc8..a9138abc 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs @@ -35,14 +35,14 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { type CircuitBuilder = ShaCircuitBuilder>; type Output = Vec>; - fn digest( + fn digest_varlen( &self, builder: &mut Self::CircuitBuilder, input: impl IntoIterator>, - strict: bool, + max_len: usize, ) -> Result>, Error> { let max_processed_bytes = { - let mut max_bytes = MAX_INPUT_SIZE + 9; + let mut max_bytes = max_len + 9; let remainder = max_bytes % 64; if remainder != 0 { max_bytes += 64 - remainder; @@ -62,10 +62,11 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { let input_byte_size = assigned_input_bytes.len(); let input_byte_size_with_9 = input_byte_size + 9; - assert!(input_byte_size <= MAX_INPUT_SIZE); let range = self.spread.range(); let gate = &range.gate; + assert!(input_byte_size <= max_len); + let one_round_size = Self::BLOCK_SIZE; let num_round = if input_byte_size_with_9 % one_round_size == 0 { @@ -100,12 +101,6 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { // assigned_input_bytes.push(assign_byte(0u8)); // } - if strict { - for &assigned in assigned_input_bytes.iter() { - range.range_check(builder.main(), assigned, 8); - } - } - let assigned_num_round = builder.main().load_witness(F::from(num_round as u64)); // compute an initial state from the precomputed_input. @@ -171,6 +166,16 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { Ok(output_digest_bytes) } + + fn digest( + &self, + ctx: &mut Self::CircuitBuilder, + input: impl IntoIterator>, + ) -> Result { + let input = input.into_iter().collect_vec(); + let input_len = input.len(); + self.digest_varlen(ctx, input, input_len) + } } impl<'a, F: Field> Sha256Chip<'a, F> { diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs index b5264411..cf9eb3c9 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs @@ -1,5 +1,6 @@ use std::any::TypeId; +use eth_types::Field; use getset::CopyGetters; use halo2_base::{ halo2_proofs::circuit::{Region, Value}, @@ -22,7 +23,7 @@ struct Dence; struct Spread; #[derive(Clone, Debug, Default, CopyGetters)] -pub struct ShaFlexGateManager { +pub struct ShaFlexGateManager { #[getset(get_copy = "pub")] witness_gen_only: bool, /// The `unknown` flag is used during key generation. If true, during key generation witness [Value]s are replaced with Value::unknown() for safety. @@ -38,7 +39,7 @@ pub struct ShaFlexGateManager { pub type ShaContexts<'a, F> = (&'a mut Context, &'a mut Context); -impl ShaFlexGateManager { +impl ShaFlexGateManager { /// Mutates `self` to use the given copy manager everywhere, including in all threads. pub fn set_copy_manager(&mut self, copy_manager: SharedCopyConstraintManager) { self.copy_manager = copy_manager.clone(); @@ -79,7 +80,7 @@ impl ShaFlexGateManager { // } } -impl CommonGateManager for ShaFlexGateManager { +impl CommonGateManager for ShaFlexGateManager { type CustomContext<'a> = ShaContexts<'a, F>; fn new(witness_gen_only: bool) -> Self { @@ -116,7 +117,7 @@ impl CommonGateManager for ShaFlexGateManager { } } -impl VirtualRegionManager for ShaFlexGateManager { +impl VirtualRegionManager for ShaFlexGateManager { type Config = SpreadConfig; fn assign_raw(&self, spread: &Self::Config, region: &mut Region) { @@ -149,7 +150,7 @@ impl VirtualRegionManager for ShaFlexGateManager { /// Pure advice witness assignment in a single phase. Uses preprocessed `break_points` to determine when /// to split a thread into a new column. #[allow(clippy::type_complexity)] -pub fn assign_threads_sha( +pub fn assign_threads_sha( threads_dense: &[Context], threads_spread: &[Context], spread: &SpreadConfig, diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs index 439db355..b95d348c 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs @@ -1,3 +1,4 @@ +use eth_types::Field; use halo2_base::utils::{decompose, ScalarField}; use halo2_base::QuantumCell; use halo2_base::{ @@ -23,7 +24,7 @@ use super::util::{bits_le_to_fe, fe_to_bits_le}; use super::ShaFlexGateManager; #[derive(Debug, Clone)] -pub struct SpreadConfig { +pub struct SpreadConfig { pub denses: Vec>, pub spreads: Vec>, pub table_dense: TableColumn, @@ -33,7 +34,7 @@ pub struct SpreadConfig { _f: PhantomData, } -impl SpreadConfig { +impl SpreadConfig { pub fn configure( meta: &mut ConstraintSystem, num_bits_lookup: usize, @@ -77,7 +78,7 @@ impl SpreadConfig { } } -impl GateBuilderConfig for SpreadConfig { +impl GateBuilderConfig for SpreadConfig { fn configure(meta: &mut ConstraintSystem) -> Self { Self::configure(meta, 8, 1) // todo: configure } @@ -129,7 +130,7 @@ pub struct SpreadChip<'a, F: ScalarField> { range: &'a RangeChip, } -impl<'a, F: BigPrimeField> SpreadChip<'a, F> { +impl<'a, F: Field> SpreadChip<'a, F> { pub fn new(range: &'a RangeChip) -> Self { debug_assert_eq!(16 % range.lookup_bits(), 0); diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs index d638c1a5..4e557532 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs @@ -4,25 +4,30 @@ mod util; mod witness; use eth_types::Field; -use halo2_base::gates::flex_gate::threads::CommonCircuitBuilder; use halo2_base::gates::RangeChip; +use halo2_base::{gates::flex_gate::threads::CommonCircuitBuilder, Context}; use itertools::Itertools; +use zkevm_hashes::sha256::vanilla::util::get_num_sha2_blocks; +use zkevm_hashes::{ + sha256::vanilla::{ + util::to_be_bytes, + witness::{generate_witnesses_multi_sha256, generate_witnesses_sha256}, + }, + util::word::Word, +}; -use crate::gadget::crypto::sha256_wide::util::Sha256AssignedRows; -use crate::gadget::crypto::sha256_wide::witness::multi_sha256; -use crate::gadget::rlc; use crate::witness::HashInput; - use halo2_base::{ gates::{GateInstructions, RangeInstructions}, halo2_proofs::plonk::Error, AssignedValue, QuantumCell, }; +use sha2::Digest; pub use self::gate::ShaBitGateManager; use self::util::{NUM_BYTES_FINAL_HASH, NUM_WORDS_TO_ABSORB}; - use super::{HashInstructions, ShaCircuitBuilder}; +use crate::gadget::common::to_bytes_le; #[derive(Debug)] pub struct Sha256ChipWide<'a, F: Field> { @@ -51,13 +56,12 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { type CircuitBuilder = ShaCircuitBuilder>; type Output = Vec>; - fn digest( + fn digest( &self, builder: &mut Self::CircuitBuilder, input: impl IntoIterator>, - _strict: bool, ) -> Result>, Error> { - let assigned_input = input + let assigned_bytes = input .into_iter() .map(|cell| match cell { QuantumCell::Existing(v) => v, @@ -68,90 +72,54 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { .collect_vec(); let binary_input: HashInput = HashInput::Single( - assigned_input + assigned_bytes .iter() .map(|av| av.value().get_lower_32() as u8) .collect_vec() .into(), ); - let mut assigned_input_bytes = assigned_input.to_vec(); - let rnd = QuantumCell::Constant(self.randomness); - let input_byte_size = assigned_input_bytes.len(); - let max_byte_size = MAX_INPUT_SIZE; - assert!(input_byte_size <= max_byte_size); + let input_len = assigned_bytes.len(); + let max_byte_size = assigned_bytes.len(); let range = &self.range; let gate = &range.gate; - assert!(assigned_input_bytes.len() <= MAX_INPUT_SIZE); - - let mut assigned_rounds = vec![]; - let assigned_output = - self.load_digest::(builder, binary_input, &mut assigned_rounds)?; - let one_round_size = Self::BLOCK_SIZE; + let mut virtual_rows = vec![]; + let input_bytes = binary_input.to_vec(); - let num_round = if input_byte_size % one_round_size == 0 { - input_byte_size / one_round_size - } else { - input_byte_size / one_round_size + 1 - }; - let padded_size = one_round_size * num_round; - let zero_padding_byte_size = padded_size - input_byte_size; - let max_round = max_byte_size / one_round_size; + generate_witnesses_sha256(&mut virtual_rows, &input_bytes); + let blocks = builder.sha.load_virtual_rows(virtual_rows); - let mut assign_byte = |byte: u8| builder.main().load_witness(F::from(byte as u64)); + let num_rounds = get_num_sha2_blocks(input_len); - for _ in 0..zero_padding_byte_size { - assigned_input_bytes.push(assign_byte(0u8)); - } + let num_input_words = (input_len + 3) / 4; + let num_input_rounds = num_input_words.div_ceil(NUM_WORDS_TO_ABSORB); - assert_eq!(assigned_input_bytes.len(), num_round * one_round_size); + let byte_bases = (0..4) + .map(|i| QuantumCell::Constant(gate.pow_of_two()[i * 8])) + .collect_vec(); - for &assigned in assigned_input_bytes.iter() { - range.range_check(builder.main(), assigned, 8); + for r in 0..num_input_rounds { + for w in 0..(num_input_words - r * NUM_WORDS_TO_ABSORB) { + let i = (r * NUM_WORDS_TO_ABSORB + w) * 4; + let checksum = gate.inner_product(builder.main(), assigned_bytes[i..i+4].to_vec(), byte_bases.clone()); + builder.main().constrain_equal(&checksum, &blocks[r].word_values[w]); + } } - let zero = builder.main().load_zero(); - let mut full_input_len = zero; - - let mut cur_input_rlc = zero; - let ctx_gate = builder.main(); - for round_idx in 0..max_round { - full_input_len = { - let muled = gate.mul( - ctx_gate, - assigned_rounds[round_idx].is_final, - assigned_rounds[round_idx].input_len, - ); - gate.add(ctx_gate, full_input_len, muled) - }; - - for word_idx in 0..NUM_WORDS_TO_ABSORB { - let offset_in = 64 * round_idx + 4 * word_idx; - let assigned_input_u32 = &assigned_input_bytes[offset_in..(offset_in + 4)]; - - for (idx, &assigned_byte) in assigned_input_u32.iter().enumerate() { - let tmp = gate.mul_add(ctx_gate, cur_input_rlc, rnd, assigned_byte); - cur_input_rlc = gate.select( - ctx_gate, - cur_input_rlc, - tmp, - assigned_rounds[round_idx].padding_selectors[word_idx][idx], - ); - } - - ctx_gate.constrain_equal( - &cur_input_rlc, - &assigned_rounds[round_idx].input_rlcs[word_idx], - ); - } + let hash_bytes = word_to_bytes_le(blocks[num_rounds-1].hash, gate, builder.main()); - let hash_rlc = rlc::assigned_value(&assigned_output, &rnd, gate, ctx_gate); - ctx_gate.constrain_equal(&hash_rlc, &assigned_rounds[round_idx].output_rlc); - } + Ok(hash_bytes) + } - Ok(assigned_output.to_vec()) + fn digest_varlen( + &self, + ctx: &mut Self::CircuitBuilder, + input: impl IntoIterator>, + max_input_len: usize, + ) -> Result { + unimplemented!() } } @@ -159,79 +127,17 @@ impl<'a, F: Field> Sha256ChipWide<'a, F> { pub fn new(range: &'a RangeChip, randomness: F) -> Self { Self { range, randomness } } +} - pub fn load_digest( - &self, - builder: &mut ShaCircuitBuilder>, - input: HashInput, - assigned_rounds: &mut Vec>, - ) -> Result<[AssignedValue; NUM_BYTES_FINAL_HASH], Error> { - let max_round = MAX_INPUT_SIZE / Self::BLOCK_SIZE; - - let mut assigned_rows = Sha256AssignedRows::new(); - let witness = multi_sha256(&[input], self.randomness); - let vec_vecs = witness - .iter() - .map(|sha256_row| { - builder - .sha - .sha_contexts() - .load_sha256_row(sha256_row, &mut assigned_rows) - }) - .collect::, Error>>()?; - let hashes: Vec<[_; NUM_BYTES_FINAL_HASH]> = vec_vecs - .into_iter() - .filter_map(|hash_bytes| { - (!hash_bytes.is_empty()).then(|| hash_bytes.try_into().unwrap()) - }) - .collect(); - - assert_eq!(hashes.len(), 1); - - let hash_sha = hashes[0]; - - let ctx_gate = builder.main(); - - let mut reassign_to_gate = |val_sha: AssignedValue| -> AssignedValue { - let val_gate = ctx_gate.load_witness(*val_sha.value()); - ctx_gate.constrain_equal(&val_sha, &val_gate); - val_gate - }; - - for round_idx in 0..max_round { - let input_len = reassign_to_gate(assigned_rows.input_len[round_idx]); - - let input_rlcs = assigned_rows.input_rlc[16 * round_idx..16 * (round_idx + 1)] - .iter() - .map(|v| reassign_to_gate(*v)) - .collect_vec() - .try_into() - .unwrap(); - - let padding_selectors = assigned_rows.padding_selectors - [16 * round_idx..16 * (round_idx + 1)] - .iter() - .map(|values| values.map(&mut reassign_to_gate)) - .collect_vec() - .try_into() - .unwrap(); - - let is_final = reassign_to_gate(assigned_rows.is_enabled[round_idx]); - let output_rlc = reassign_to_gate(assigned_rows.output_rlc[0]); - - assigned_rounds.push(AssignedSha256Round { - is_final, - input_len, - input_rlcs, - padding_selectors, - output_rlc, - }) - } - - let hash_gate = hash_sha.map(reassign_to_gate); - - Ok(hash_gate) - } +pub fn word_to_bytes_le( + word: Word>, + gate: &impl GateInstructions, + ctx: &mut Context, +) -> Vec> { + to_bytes_le::<_, 16>(&word.lo(), gate, ctx) + .into_iter() + .chain(to_bytes_le::<_, 16>(&word.hi(), gate, ctx)) + .collect() } // #[cfg(test)] diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs index b8c5715b..63f40414 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs @@ -21,6 +21,19 @@ use itertools::Itertools; use log::debug; use std::iter; use std::marker::PhantomData; +use zkevm_hashes::sha256::vanilla::columns::Sha256CircuitConfig; + +impl GateBuilderConfig for Sha256CircuitConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { + Sha256CircuitConfig::new(meta) + } + + fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + Ok(()) + } + + fn annotate_columns_in_region(&self, region: &mut Region) {} +} /// Configuration for [`Sha256WideChip`]. #[derive(Clone, Debug)] diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs index 7ef6ac4d..68019c5a 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs @@ -1,4 +1,3 @@ -use super::config::Sha256BitConfig; use crate::util::{CommonGateManager, GateBuilderConfig}; use eth_types::Field; use getset::CopyGetters; @@ -8,13 +7,25 @@ use halo2_base::{ virtual_region::{ copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, }, - Context, + AssignedValue, Context, }; +use itertools::Itertools; use std::any::TypeId; +use zkevm_hashes::{ + sha256::{ + component::circuit::LoadedSha256, + vanilla::{ + columns::Sha256CircuitConfig, + param::{NUM_START_ROWS, NUM_WORDS_TO_ABSORB, SHA256_NUM_ROWS}, + witness::{AssignedSha256Block, VirtualShaRow}, + }, + }, + util::word::Word, +}; -pub const FIRST_PHASE: usize = 0; +use super::witness::ShaRow; -pub type Sha256BitContexts = Sha256BitConfig, Context>; +pub const FIRST_PHASE: usize = 0; #[derive(Clone, Debug, CopyGetters)] pub struct ShaBitGateManager { @@ -25,65 +36,27 @@ pub struct ShaBitGateManager { pub(crate) use_unknown: bool, /// Threads for spread table assignment. - sha_contexts: Sha256BitContexts, + virtual_rows: Vec, + loaded_blocks: Vec>, pub copy_manager: SharedCopyConstraintManager, } impl CommonGateManager for ShaBitGateManager { - type CustomContext<'a> = &'a mut Sha256BitContexts; + type CustomContext<'a> = (); fn new(witness_gen_only: bool) -> Self { - let copy_manager = SharedCopyConstraintManager::default(); - let mut context_id = 0; - let mut new_context = || { - context_id += 1; - Context::new( - witness_gen_only, - FIRST_PHASE, - TypeId::of::(), - context_id, - copy_manager.clone(), - ) - }; - Self { witness_gen_only, use_unknown: false, - sha_contexts: Sha256BitConfig { - q_enable: new_context(), - q_first: new_context(), - q_extend: new_context(), - q_start: new_context(), - q_compression: new_context(), - q_end: new_context(), - q_padding: new_context(), - q_padding_last: new_context(), - q_squeeze: new_context(), - q_final_word: new_context(), - word_w: array_init::array_init(|_| new_context()), - word_a: array_init::array_init(|_| new_context()), - word_e: array_init::array_init(|_| new_context()), - is_final: new_context(), - is_paddings: array_init::array_init(|_| new_context()), - data_rlcs: array_init::array_init(|_| new_context()), - round_cst: new_context(), - h_a: new_context(), - h_e: new_context(), - is_enabled: new_context(), - input_rlc: new_context(), - input_len: new_context(), - hash_rlc: new_context(), - final_hash_bytes: array_init::array_init(|_| new_context()), - _f: std::marker::PhantomData, - offset: 0, - }, + virtual_rows: Vec::new(), + loaded_blocks: Vec::new(), copy_manager: SharedCopyConstraintManager::default(), } } fn custom_context(&mut self) -> Self::CustomContext<'_> { - self.sha_contexts() + () } fn from_stage(stage: CircuitBuilderStage) -> Self { @@ -103,27 +76,111 @@ impl CommonGateManager for ShaBitGateManager { } impl VirtualRegionManager for ShaBitGateManager { - type Config = Sha256BitConfig; + type Config = Sha256CircuitConfig; fn assign_raw(&self, config: &Self::Config, region: &mut Region) { - config.annotate_columns_in_region(region); - - if self.witness_gen_only() { - self.sha_contexts - .assign_in_region(region, config, false, None) - .unwrap(); - } else { - let mut copy_manager = self.copy_manager.lock().unwrap(); - self.sha_contexts - .assign_in_region(region, config, self.use_unknown(), Some(&mut copy_manager)) - .unwrap(); - } + // config.annotate_columns_in_region(region); + let mut copy_manager = self.copy_manager.lock().unwrap(); + + config + .assign_sha256_rows(region, self.virtual_rows.clone(), None, 0) + .into_iter() + .zip(&self.loaded_blocks) + .for_each(|(vanilla, loaded)| { + copy_manager + .assigned_advices + .insert(loaded.is_final.cell.unwrap(), vanilla.is_final().cell()); + copy_manager + .assigned_advices + .insert(loaded.hash.lo().cell.unwrap(), vanilla.output().lo().cell()); + copy_manager + .assigned_advices + .insert(loaded.hash.hi().cell.unwrap(), vanilla.output().hi().cell()); + vanilla + .word_values() + .iter() + .zip(loaded.word_values) + .for_each(|(vanilla_input_word, loaded_input_word)| { + copy_manager + .assigned_advices + .insert(loaded_input_word.cell.unwrap(), vanilla_input_word.cell()); + }); + }); + + // if self.witness_gen_only() { + // config + // .assign_in_region(region, config, false, None) + // .unwrap(); + // } else { + // let mut copy_manager = self.copy_manager.lock().unwrap(); + // config.assign_sha256_rows(region, config, self.use_unknown(), Some(&mut copy_manager)) + // .unwrap(); + // } } } impl ShaBitGateManager { - pub fn sha_contexts(&mut self) -> &mut Sha256BitContexts { - &mut self.sha_contexts + pub fn load_virtual_rows(&mut self, virtual_rows: Vec) -> Vec> { + struct UnassignedShaTableRow { + is_final: F, + io: F, + // length: F, + } + let table_rows = virtual_rows + .iter() + .enumerate() + .map(|(offset, row)| { + let round = offset % SHA256_NUM_ROWS; + let q_input = + (NUM_START_ROWS..NUM_START_ROWS + NUM_WORDS_TO_ABSORB).contains(&round); + + let io_value = if q_input { + F::from(row.word_value as u64) + } else if round >= SHA256_NUM_ROWS - 2 { + F::from_u128(row.hash_limb) + } else { + F::ZERO + }; + + UnassignedShaTableRow { + is_final: F::from(row.is_final), + io: io_value, + // length: F::from(row.length as u64), + } + }) + // .enumerate() + .collect_vec(); + debug_assert_eq!(table_rows.len() % SHA256_NUM_ROWS, 0); + self.virtual_rows.extend(virtual_rows); + let mut copy_manager = self.copy_manager.lock().unwrap(); + + let loaded_blocks = table_rows + .chunks_exact(SHA256_NUM_ROWS) + .map(|rows| { + let last_row = rows.last().unwrap(); // rows[SHA256_NUM_ROWS - 1] + let is_final = copy_manager.mock_external_assigned(last_row.is_final); + let output_lo = copy_manager.mock_external_assigned(last_row.io); + let output_hi = copy_manager.mock_external_assigned(rows[SHA256_NUM_ROWS - 2].io); + let input_rows = &rows[NUM_START_ROWS..NUM_START_ROWS + NUM_WORDS_TO_ABSORB]; + let word_values: [_; NUM_WORDS_TO_ABSORB] = input_rows + .iter() + .map(|row| copy_manager.mock_external_assigned(row.io)) + .collect::>() + .try_into() + .unwrap(); + // let length = + // copy_manager.mock_external_assigned(input_rows.last().unwrap().1.length); + LoadedSha256 { + is_final, + hash: Word::new([output_lo, output_hi]), + word_values, + } + }) + .collect_vec(); + + self.loaded_blocks.extend(loaded_blocks.clone()); + + loaded_blocks } /// Mutates `self` to use the given copy manager everywhere, including in all threads. diff --git a/lightclient-circuits/src/poseidon.rs b/lightclient-circuits/src/poseidon.rs index 3bd37087..c9c4346a 100644 --- a/lightclient-circuits/src/poseidon.rs +++ b/lightclient-circuits/src/poseidon.rs @@ -9,7 +9,7 @@ use halo2curves::{ group::UncompressedEncoding, }; use itertools::Itertools; -use pse_poseidon::Poseidon as PoseidonNative; +// use pse_poseidon::Poseidon as PoseidonNative; const POSEIDON_SIZE: usize = 16; const R_F: usize = 8; @@ -55,16 +55,16 @@ pub fn fq_array_poseidon_native( .collect_vec() }) .collect_vec(); - let mut poseidon = PoseidonNative::::new(R_F, R_P); + // let mut poseidon = PoseidonNative::::new(R_F, R_P); let mut current_poseidon_hash = None; - for (i, chunk) in limbs.chunks(POSEIDON_SIZE - 3).enumerate() { - poseidon.update(chunk); - if i != 0 { - poseidon.update(&[current_poseidon_hash.unwrap()]); - } - let _ = current_poseidon_hash.insert(poseidon.squeeze()); - } + // for (i, chunk) in limbs.chunks(POSEIDON_SIZE - 3).enumerate() { + // poseidon.update(chunk); + // if i != 0 { + // poseidon.update(&[current_poseidon_hash.unwrap()]); + // } + // let _ = current_poseidon_hash.insert(poseidon.squeeze()); + // } Ok(current_poseidon_hash.unwrap()) } diff --git a/lightclient-circuits/src/ssz_merkle.rs b/lightclient-circuits/src/ssz_merkle.rs index 76267080..d416c405 100644 --- a/lightclient-circuits/src/ssz_merkle.rs +++ b/lightclient-circuits/src/ssz_merkle.rs @@ -31,7 +31,7 @@ pub fn ssz_merkleize_chunks>( .tuples() .map(|(left, right)| { hasher - .digest::<64>(builder, HashInput::TwoToOne(left, right), false) + .digest(builder, HashInput::TwoToOne(left, right)) .map(|res| res.into()) }) .collect::, _>>()?; @@ -59,14 +59,13 @@ pub fn verify_merkle_proof>( for witness in proof.into_iter() { computed_hash = hasher - .digest::<64>( + .digest( builder, if gindex % 2 == 0 { HashInput::TwoToOne(computed_hash, witness) } else { HashInput::TwoToOne(witness, computed_hash) }, - false, )? .into(); gindex /= 2; diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 986400e5..627a07e9 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -1,7 +1,10 @@ use crate::{ - gadget::crypto::{ - calculate_ysquared, G1Chip, G1Point, G2Chip, HashInstructions, Sha256Chip, - ShaCircuitBuilder, ShaFlexGateManager, + gadget::{ + crypto::{ + calculate_ysquared, G1Chip, G1Point, G2Chip, HashInstructions, Sha256Chip, + ShaCircuitBuilder, ShaFlexGateManager, + }, + to_bytes_le, }, poseidon::{fq_array_poseidon, fq_array_poseidon_native}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, @@ -132,10 +135,9 @@ impl StepCircuit { ], )?; - let signing_root = sha256_chip.digest::<64>( + let signing_root = sha256_chip.digest( builder, HashInput::TwoToOne(attested_header.into(), args.domain.to_vec().into_witness()), - false, )?; let signature = @@ -174,9 +176,9 @@ impl StepCircuit { )?; // Public Input Commitment - let participation_sum_le = to_bytes_le::<_, 8>(builder.main(), gate, &participation_sum); + let participation_sum_le = to_bytes_le::<_, 8>(&participation_sum, gate, builder.main()); - let poseidon_commit_le = to_bytes_le::<_, 32>(builder.main(), gate, &poseidon_commit); + let poseidon_commit_le = to_bytes_le::<_, 32>(&poseidon_commit, gate, builder.main()); // See "Onion hashing vs. Input concatenation" in https://github.com/ChainSafe/Spectre/issues/17#issuecomment-1740965182 let public_inputs_concat = itertools::chain![ @@ -196,7 +198,7 @@ impl StepCircuit { .collect_vec(); let pi_hash_bytes = sha256_chip - .digest::<{ 8 * 3 + 32 * 3 }>(builder, public_inputs_concat, false)? + .digest(builder, public_inputs_concat)? .try_into() .unwrap(); @@ -303,30 +305,6 @@ pub fn clear_3_bits( range.div_mod(ctx, b_shifted, BigUint::from(8u64), 8).0 } -pub fn to_bytes_le( - ctx: &mut Context, - gate: &impl GateInstructions, - a: &AssignedValue, -) -> Vec> { - let byte_bases = (0..MAX_BYTES) - .map(|i| QuantumCell::Constant(gate.pow_of_two()[i * 8])) - .collect_vec(); - - let assigned_bytes = a - .value() - .to_bytes_le() - .into_iter() - .take(MAX_BYTES) - .map(|v| ctx.load_witness(F::from(v as u64))) - .collect_vec(); - - // Constrain poseidon bytes to be equal to the recovered checksum - let checksum = gate.inner_product(ctx, assigned_bytes.clone(), byte_bases); - ctx.constrain_equal(&checksum, &checksum); - - assigned_bytes -} - impl StepCircuit { fn assign_signature( ctx: &mut Context, diff --git a/lightclient-circuits/src/util/circuit.rs b/lightclient-circuits/src/util/circuit.rs index 8c25ca39..f03bad77 100644 --- a/lightclient-circuits/src/util/circuit.rs +++ b/lightclient-circuits/src/util/circuit.rs @@ -2,6 +2,7 @@ use std::env::{set_var, var}; use std::fs; use std::{fs::File, path::Path}; +use eth_types::Field; use halo2_base::gates::circuit::{BaseCircuitParams, CircuitBuilderStage}; use halo2_base::gates::flex_gate::MultiPhaseThreadBreakPoints; use halo2_base::halo2_proofs::{ @@ -79,7 +80,7 @@ impl Halo2ConfigPinning for Eth2ConfigPinning { } } -pub trait PinnableCircuit: CircuitExt { +pub trait PinnableCircuit: CircuitExt { type Pinning: Halo2ConfigPinning; fn break_points(&self) -> ::BreakPoints; From 95e9155e1708d9ff87ef29e08be80f1afd54bd79 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Sun, 26 Nov 2023 21:45:47 +0100 Subject: [PATCH 18/23] remove redundant --- .../tests/rotation_input_encoding.rs | 6 +- contracts/rust-abi/lib.rs | 5 +- lightclient-circuits/Cargo.toml | 2 +- lightclient-circuits/contractyul | 2307 ----------------- .../src/committee_update_circuit.rs | 114 +- lightclient-circuits/src/gadget/common.rs | 264 +- .../src/gadget/crypto/builder.rs | 1 - lightclient-circuits/src/gadget/crypto/mod.rs | 6 - .../src/gadget/crypto/sha256_flex/gate.rs | 1 - .../src/gadget/crypto/sha256_flex/spread.rs | 1 - .../src/gadget/crypto/sha256_wide.rs | 65 +- .../src/gadget/crypto/sha256_wide/config.rs | 923 ------- .../src/gadget/crypto/sha256_wide/gate.rs | 29 +- .../src/gadget/crypto/sha256_wide/util.rs | 151 -- .../src/gadget/crypto/sha256_wide/witness.rs | 292 --- lightclient-circuits/src/poseidon.rs | 18 +- lightclient-circuits/src/ssz_merkle.rs | 250 +- lightclient-circuits/src/util.rs | 45 - lightclient-circuits/src/util/circuit.rs | 1 - lightclient-circuits/src/util/common.rs | 107 +- .../src/util/constraint_builder.rs | 186 -- lightclient-circuits/src/witness/rotation.rs | 10 +- preprocessor/src/lib.rs | 3 +- preprocessor/src/rotation.rs | 19 +- prover/src/rpc.rs | 6 +- test-utils/src/conversions.rs | 2 +- test-utils/src/lib.rs | 7 +- 27 files changed, 129 insertions(+), 4692 deletions(-) delete mode 100644 lightclient-circuits/contractyul delete mode 100644 lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs delete mode 100644 lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs delete mode 100644 lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs delete mode 100644 lightclient-circuits/src/util/constraint_builder.rs diff --git a/contract-tests/tests/rotation_input_encoding.rs b/contract-tests/tests/rotation_input_encoding.rs index 569ee89a..14543727 100644 --- a/contract-tests/tests/rotation_input_encoding.rs +++ b/contract-tests/tests/rotation_input_encoding.rs @@ -9,7 +9,7 @@ use eth_types::LIMB_BITS; use ethers::contract::abigen; use itertools::Itertools; use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; -use lightclient_circuits::halo2_proofs::halo2curves::bn256::{self, Fr}; +use lightclient_circuits::halo2_proofs::halo2curves::bn256; use lightclient_circuits::poseidon::poseidon_committee_commitment_from_compressed; use lightclient_circuits::witness::CommitteeRotationArgs; use rstest::rstest; @@ -24,11 +24,11 @@ abigen!( ); // CommitteeRotationArgs type produced by abigen macro matches the solidity struct type -impl From> for RotateInput +impl From> for RotateInput where [(); Spec::SYNC_COMMITTEE_SIZE]:, { - fn from(args: CommitteeRotationArgs) -> Self { + fn from(args: CommitteeRotationArgs) -> Self { let poseidon_commitment_le = poseidon_committee_commitment_from_compressed( &args.pubkeys_compressed.iter().cloned().collect_vec(), ) diff --git a/contracts/rust-abi/lib.rs b/contracts/rust-abi/lib.rs index 6a090ac6..ca7cc0e5 100644 --- a/contracts/rust-abi/lib.rs +++ b/contracts/rust-abi/lib.rs @@ -1,7 +1,6 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs)] use ethers::contract::abigen; -use halo2curves::bn256::Fr; use itertools::Itertools; use lightclient_circuits::{ poseidon::poseidon_committee_commitment_from_compressed, @@ -57,11 +56,11 @@ impl From> for SyncStepInput { } // CommitteeRotationArgs type produced by abigen macro matches the solidity struct type -impl From> for RotateInput +impl From> for RotateInput where [(); Spec::SYNC_COMMITTEE_SIZE]:, { - fn from(args: CommitteeRotationArgs) -> Self { + fn from(args: CommitteeRotationArgs) -> Self { let poseidon_commitment_le = poseidon_committee_commitment_from_compressed( &args.pubkeys_compressed.iter().cloned().collect_vec(), ) diff --git a/lightclient-circuits/Cargo.toml b/lightclient-circuits/Cargo.toml index f2f9c959..c1dc9ce3 100644 --- a/lightclient-circuits/Cargo.toml +++ b/lightclient-circuits/Cargo.toml @@ -22,7 +22,7 @@ num-bigint.workspace = true pasta_curves.workspace = true ff.workspace = true sha2.workspace = true -# pse-poseidon = { git = "https://github.com/axiom-crypto/pse-poseidon.git" } +pse-poseidon = { git = "https://github.com/axiom-crypto/pse-poseidon.git" } # ethereum ssz_rs = { workspace = true, features = ["serde"] } diff --git a/lightclient-circuits/contractyul b/lightclient-circuits/contractyul deleted file mode 100644 index eb08407c..00000000 --- a/lightclient-circuits/contractyul +++ /dev/null @@ -1,2307 +0,0 @@ - -// SPDX-License-Identifier: MIT - -pragma solidity >=0.8.19 <0.8.21; - -contract Halo2Verifier { - fallback(bytes calldata) external returns (bytes memory) { - assembly { - let success := true - let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 - let f_q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 - function validate_ec_point(x, y) -> valid { - { - let x_lt_p := lt(x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let y_lt_p := lt(y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - valid := and(x_lt_p, y_lt_p) - } - { - let y_square := mulmod(y, y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_square := mulmod(x, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_cube := mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_cube_plus_3 := addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let is_affine := eq(x_cube_plus_3, y_square) - valid := and(valid, is_affine) - } - } - mstore(0x20, mod(calldataload(0x0), f_q)) -mstore(0x40, mod(calldataload(0x20), f_q)) -mstore(0x60, mod(calldataload(0x40), f_q)) -mstore(0x80, mod(calldataload(0x60), f_q)) -mstore(0xa0, mod(calldataload(0x80), f_q)) -mstore(0xc0, mod(calldataload(0xa0), f_q)) -mstore(0xe0, mod(calldataload(0xc0), f_q)) -mstore(0x100, mod(calldataload(0xe0), f_q)) -mstore(0x120, mod(calldataload(0x100), f_q)) -mstore(0x140, mod(calldataload(0x120), f_q)) -mstore(0x160, mod(calldataload(0x140), f_q)) -mstore(0x180, mod(calldataload(0x160), f_q)) -mstore(0x1a0, mod(calldataload(0x180), f_q)) -mstore(0x1c0, mod(calldataload(0x1a0), f_q)) -mstore(0x1e0, mod(calldataload(0x1c0), f_q)) -mstore(0x200, mod(calldataload(0x1e0), f_q)) -mstore(0x220, mod(calldataload(0x200), f_q)) -mstore(0x240, mod(calldataload(0x220), f_q)) -mstore(0x260, mod(calldataload(0x240), f_q)) -mstore(0x280, mod(calldataload(0x260), f_q)) -mstore(0x2a0, mod(calldataload(0x280), f_q)) -mstore(0x2c0, mod(calldataload(0x2a0), f_q)) -mstore(0x2e0, mod(calldataload(0x2c0), f_q)) -mstore(0x300, mod(calldataload(0x2e0), f_q)) -mstore(0x320, mod(calldataload(0x300), f_q)) -mstore(0x340, mod(calldataload(0x320), f_q)) -mstore(0x360, mod(calldataload(0x340), f_q)) -mstore(0x380, mod(calldataload(0x360), f_q)) -mstore(0x3a0, mod(calldataload(0x380), f_q)) -mstore(0x3c0, mod(calldataload(0x3a0), f_q)) -mstore(0x3e0, mod(calldataload(0x3c0), f_q)) -mstore(0x400, mod(calldataload(0x3e0), f_q)) -mstore(0x420, mod(calldataload(0x400), f_q)) -mstore(0x440, mod(calldataload(0x420), f_q)) -mstore(0x460, mod(calldataload(0x440), f_q)) -mstore(0x480, mod(calldataload(0x460), f_q)) -mstore(0x4a0, mod(calldataload(0x480), f_q)) -mstore(0x4c0, mod(calldataload(0x4a0), f_q)) -mstore(0x4e0, mod(calldataload(0x4c0), f_q)) -mstore(0x500, mod(calldataload(0x4e0), f_q)) -mstore(0x520, mod(calldataload(0x500), f_q)) -mstore(0x540, mod(calldataload(0x520), f_q)) -mstore(0x560, mod(calldataload(0x540), f_q)) -mstore(0x580, mod(calldataload(0x560), f_q)) -mstore(0x5a0, mod(calldataload(0x580), f_q)) -mstore(0x5c0, mod(calldataload(0x5a0), f_q)) -mstore(0x5e0, mod(calldataload(0x5c0), f_q)) -mstore(0x600, mod(calldataload(0x5e0), f_q)) -mstore(0x620, mod(calldataload(0x600), f_q)) -mstore(0x640, mod(calldataload(0x620), f_q)) -mstore(0x660, mod(calldataload(0x640), f_q)) -mstore(0x680, mod(calldataload(0x660), f_q)) -mstore(0x6a0, mod(calldataload(0x680), f_q)) -mstore(0x6c0, mod(calldataload(0x6a0), f_q)) -mstore(0x6e0, mod(calldataload(0x6c0), f_q)) -mstore(0x700, mod(calldataload(0x6e0), f_q)) -mstore(0x720, mod(calldataload(0x700), f_q)) -mstore(0x740, mod(calldataload(0x720), f_q)) -mstore(0x760, mod(calldataload(0x740), f_q)) -mstore(0x780, mod(calldataload(0x760), f_q)) -mstore(0x7a0, mod(calldataload(0x780), f_q)) -mstore(0x7c0, mod(calldataload(0x7a0), f_q)) -mstore(0x7e0, mod(calldataload(0x7c0), f_q)) -mstore(0x800, mod(calldataload(0x7e0), f_q)) -mstore(0x820, mod(calldataload(0x800), f_q)) -mstore(0x840, mod(calldataload(0x820), f_q)) -mstore(0x860, mod(calldataload(0x840), f_q)) -mstore(0x880, mod(calldataload(0x860), f_q)) -mstore(0x8a0, mod(calldataload(0x880), f_q)) -mstore(0x8c0, mod(calldataload(0x8a0), f_q)) -mstore(0x8e0, mod(calldataload(0x8c0), f_q)) -mstore(0x900, mod(calldataload(0x8e0), f_q)) -mstore(0x920, mod(calldataload(0x900), f_q)) -mstore(0x940, mod(calldataload(0x920), f_q)) -mstore(0x960, mod(calldataload(0x940), f_q)) -mstore(0x980, mod(calldataload(0x960), f_q)) -mstore(0x9a0, mod(calldataload(0x980), f_q)) -mstore(0x0, 14012635205581322793076264054699840890414958961805977117099281830200581711072) - - { - let x := calldataload(0x9a0) - mstore(0x9c0, x) - let y := calldataload(0x9c0) - mstore(0x9e0, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x9e0) - mstore(0xa00, x) - let y := calldataload(0xa00) - mstore(0xa20, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xa20) - mstore(0xa40, x) - let y := calldataload(0xa40) - mstore(0xa60, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xa60) - mstore(0xa80, x) - let y := calldataload(0xa80) - mstore(0xaa0, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0xac0, keccak256(0x0, 2752)) -{ - let hash := mload(0xac0) - mstore(0xae0, mod(hash, f_q)) - mstore(0xb00, hash) - } - - { - let x := calldataload(0xaa0) - mstore(0xb20, x) - let y := calldataload(0xac0) - mstore(0xb40, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xae0) - mstore(0xb60, x) - let y := calldataload(0xb00) - mstore(0xb80, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0xba0, keccak256(0xb00, 160)) -{ - let hash := mload(0xba0) - mstore(0xbc0, mod(hash, f_q)) - mstore(0xbe0, hash) - } -mstore8(3072, 1) -mstore(0xc00, keccak256(0xbe0, 33)) -{ - let hash := mload(0xc00) - mstore(0xc20, mod(hash, f_q)) - mstore(0xc40, hash) - } - - { - let x := calldataload(0xb20) - mstore(0xc60, x) - let y := calldataload(0xb40) - mstore(0xc80, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xb60) - mstore(0xca0, x) - let y := calldataload(0xb80) - mstore(0xcc0, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xba0) - mstore(0xce0, x) - let y := calldataload(0xbc0) - mstore(0xd00, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xbe0) - mstore(0xd20, x) - let y := calldataload(0xc00) - mstore(0xd40, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xc20) - mstore(0xd60, x) - let y := calldataload(0xc40) - mstore(0xd80, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0xda0, keccak256(0xc40, 352)) -{ - let hash := mload(0xda0) - mstore(0xdc0, mod(hash, f_q)) - mstore(0xde0, hash) - } - - { - let x := calldataload(0xc60) - mstore(0xe00, x) - let y := calldataload(0xc80) - mstore(0xe20, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xca0) - mstore(0xe40, x) - let y := calldataload(0xcc0) - mstore(0xe60, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0xce0) - mstore(0xe80, x) - let y := calldataload(0xd00) - mstore(0xea0, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0xec0, keccak256(0xde0, 224)) -{ - let hash := mload(0xec0) - mstore(0xee0, mod(hash, f_q)) - mstore(0xf00, hash) - } -mstore(0xf20, mod(calldataload(0xd20), f_q)) -mstore(0xf40, mod(calldataload(0xd40), f_q)) -mstore(0xf60, mod(calldataload(0xd60), f_q)) -mstore(0xf80, mod(calldataload(0xd80), f_q)) -mstore(0xfa0, mod(calldataload(0xda0), f_q)) -mstore(0xfc0, mod(calldataload(0xdc0), f_q)) -mstore(0xfe0, mod(calldataload(0xde0), f_q)) -mstore(0x1000, mod(calldataload(0xe00), f_q)) -mstore(0x1020, mod(calldataload(0xe20), f_q)) -mstore(0x1040, mod(calldataload(0xe40), f_q)) -mstore(0x1060, mod(calldataload(0xe60), f_q)) -mstore(0x1080, mod(calldataload(0xe80), f_q)) -mstore(0x10a0, mod(calldataload(0xea0), f_q)) -mstore(0x10c0, mod(calldataload(0xec0), f_q)) -mstore(0x10e0, mod(calldataload(0xee0), f_q)) -mstore(0x1100, mod(calldataload(0xf00), f_q)) -mstore(0x1120, mod(calldataload(0xf20), f_q)) -mstore(0x1140, mod(calldataload(0xf40), f_q)) -mstore(0x1160, mod(calldataload(0xf60), f_q)) -mstore(0x1180, mod(calldataload(0xf80), f_q)) -mstore(0x11a0, mod(calldataload(0xfa0), f_q)) -mstore(0x11c0, mod(calldataload(0xfc0), f_q)) -mstore(0x11e0, mod(calldataload(0xfe0), f_q)) -mstore(0x1200, mod(calldataload(0x1000), f_q)) -mstore(0x1220, mod(calldataload(0x1020), f_q)) -mstore(0x1240, mod(calldataload(0x1040), f_q)) -mstore(0x1260, mod(calldataload(0x1060), f_q)) -mstore(0x1280, mod(calldataload(0x1080), f_q)) -mstore(0x12a0, mod(calldataload(0x10a0), f_q)) -mstore(0x12c0, mod(calldataload(0x10c0), f_q)) -mstore(0x12e0, mod(calldataload(0x10e0), f_q)) -mstore(0x1300, mod(calldataload(0x1100), f_q)) -mstore(0x1320, mod(calldataload(0x1120), f_q)) -mstore(0x1340, mod(calldataload(0x1140), f_q)) -mstore(0x1360, mod(calldataload(0x1160), f_q)) -mstore(0x1380, mod(calldataload(0x1180), f_q)) -mstore(0x13a0, mod(calldataload(0x11a0), f_q)) -mstore(0x13c0, mod(calldataload(0x11c0), f_q)) -mstore(0x13e0, keccak256(0xf00, 1248)) -{ - let hash := mload(0x13e0) - mstore(0x1400, mod(hash, f_q)) - mstore(0x1420, hash) - } -mstore8(5184, 1) -mstore(0x1440, keccak256(0x1420, 33)) -{ - let hash := mload(0x1440) - mstore(0x1460, mod(hash, f_q)) - mstore(0x1480, hash) - } - - { - let x := calldataload(0x11e0) - mstore(0x14a0, x) - let y := calldataload(0x1200) - mstore(0x14c0, y) - success := and(validate_ec_point(x, y), success) - } -mstore(0x14e0, keccak256(0x1480, 96)) -{ - let hash := mload(0x14e0) - mstore(0x1500, mod(hash, f_q)) - mstore(0x1520, hash) - } - - { - let x := calldataload(0x1220) - mstore(0x1540, x) - let y := calldataload(0x1240) - mstore(0x1560, y) - success := and(validate_ec_point(x, y), success) - } -{ - let x := mload(0x20) -x := add(x, shl(88, mload(0x40))) -x := add(x, shl(176, mload(0x60))) -mstore(5504, x) -let y := mload(0x80) -y := add(y, shl(88, mload(0xa0))) -y := add(y, shl(176, mload(0xc0))) -mstore(5536, y) - - success := and(validate_ec_point(x, y), success) - } -{ - let x := mload(0xe0) -x := add(x, shl(88, mload(0x100))) -x := add(x, shl(176, mload(0x120))) -mstore(5568, x) -let y := mload(0x140) -y := add(y, shl(88, mload(0x160))) -y := add(y, shl(176, mload(0x180))) -mstore(5600, y) - - success := and(validate_ec_point(x, y), success) - } -mstore(0x1600, mulmod(mload(0xee0), mload(0xee0), f_q)) -mstore(0x1620, mulmod(mload(0x1600), mload(0x1600), f_q)) -mstore(0x1640, mulmod(mload(0x1620), mload(0x1620), f_q)) -mstore(0x1660, mulmod(mload(0x1640), mload(0x1640), f_q)) -mstore(0x1680, mulmod(mload(0x1660), mload(0x1660), f_q)) -mstore(0x16a0, mulmod(mload(0x1680), mload(0x1680), f_q)) -mstore(0x16c0, mulmod(mload(0x16a0), mload(0x16a0), f_q)) -mstore(0x16e0, mulmod(mload(0x16c0), mload(0x16c0), f_q)) -mstore(0x1700, mulmod(mload(0x16e0), mload(0x16e0), f_q)) -mstore(0x1720, mulmod(mload(0x1700), mload(0x1700), f_q)) -mstore(0x1740, mulmod(mload(0x1720), mload(0x1720), f_q)) -mstore(0x1760, mulmod(mload(0x1740), mload(0x1740), f_q)) -mstore(0x1780, mulmod(mload(0x1760), mload(0x1760), f_q)) -mstore(0x17a0, mulmod(mload(0x1780), mload(0x1780), f_q)) -mstore(0x17c0, mulmod(mload(0x17a0), mload(0x17a0), f_q)) -mstore(0x17e0, mulmod(mload(0x17c0), mload(0x17c0), f_q)) -mstore(0x1800, mulmod(mload(0x17e0), mload(0x17e0), f_q)) -mstore(0x1820, mulmod(mload(0x1800), mload(0x1800), f_q)) -mstore(0x1840, mulmod(mload(0x1820), mload(0x1820), f_q)) -mstore(0x1860, mulmod(mload(0x1840), mload(0x1840), f_q)) -mstore(0x1880, mulmod(mload(0x1860), mload(0x1860), f_q)) -mstore(0x18a0, mulmod(mload(0x1880), mload(0x1880), f_q)) -mstore(0x18c0, mulmod(mload(0x18a0), mload(0x18a0), f_q)) -mstore(0x18e0, addmod(mload(0x18c0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) -mstore(0x1900, mulmod(mload(0x18e0), 21888240262557392955334514970720457388010314637169927192662615958087340972065, f_q)) -mstore(0x1920, mulmod(mload(0x1900), 4506835738822104338668100540817374747935106310012997856968187171738630203507, f_q)) -mstore(0x1940, addmod(mload(0xee0), 17381407133017170883578305204439900340613258090403036486730017014837178292110, f_q)) -mstore(0x1960, mulmod(mload(0x1900), 21710372849001950800533397158415938114909991150039389063546734567764856596059, f_q)) -mstore(0x1980, addmod(mload(0xee0), 177870022837324421713008586841336973638373250376645280151469618810951899558, f_q)) -mstore(0x19a0, mulmod(mload(0x1900), 1887003188133998471169152042388914354640772748308168868301418279904560637395, f_q)) -mstore(0x19c0, addmod(mload(0xee0), 20001239683705276751077253702868360733907591652107865475396785906671247858222, f_q)) -mstore(0x19e0, mulmod(mload(0x1900), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) -mstore(0x1a00, addmod(mload(0xee0), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q)) -mstore(0x1a20, mulmod(mload(0x1900), 14655294445420895451632927078981340937842238432098198055057679026789553137428, f_q)) -mstore(0x1a40, addmod(mload(0xee0), 7232948426418379770613478666275934150706125968317836288640525159786255358189, f_q)) -mstore(0x1a60, mulmod(mload(0x1900), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q)) -mstore(0x1a80, addmod(mload(0xee0), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q)) -mstore(0x1aa0, mulmod(mload(0x1900), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q)) -mstore(0x1ac0, addmod(mload(0xee0), 12146688980418810893951125255607130521645347193942732958664170801695864621270, f_q)) -mstore(0x1ae0, mulmod(mload(0x1900), 1, f_q)) -mstore(0x1b00, addmod(mload(0xee0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) -mstore(0x1b20, mulmod(mload(0x1900), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) -mstore(0x1b40, addmod(mload(0xee0), 13513867906530865119835332133273263211836799082674232843258448413103731898270, f_q)) -mstore(0x1b60, mulmod(mload(0x1900), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) -mstore(0x1b80, addmod(mload(0xee0), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q)) -mstore(0x1ba0, mulmod(mload(0x1900), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q)) -mstore(0x1bc0, addmod(mload(0xee0), 18272764063556419981698118473909131571661591947471949595929891197711371770216, f_q)) -mstore(0x1be0, mulmod(mload(0x1900), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) -mstore(0x1c00, addmod(mload(0xee0), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q)) -mstore(0x1c20, mulmod(mload(0x1900), 216092043779272773661818549620449970334216366264741118684015851799902419467, f_q)) -mstore(0x1c40, addmod(mload(0xee0), 21672150828060002448584587195636825118214148034151293225014188334775906076150, f_q)) -mstore(0x1c60, mulmod(mload(0x1900), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q)) -mstore(0x1c80, addmod(mload(0xee0), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q)) -mstore(0x1ca0, mulmod(mload(0x1900), 18610195890048912503953886742825279624920778288956610528523679659246523534888, f_q)) -mstore(0x1cc0, addmod(mload(0xee0), 3278046981790362718292519002431995463627586111459423815174524527329284960729, f_q)) -mstore(0x1ce0, mulmod(mload(0x1900), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) -mstore(0x1d00, addmod(mload(0xee0), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q)) -mstore(0x1d20, mulmod(mload(0x1900), 14875928112196239563830800280253496262679717528621719058794366823499719730250, f_q)) -mstore(0x1d40, addmod(mload(0xee0), 7012314759643035658415605465003778825868646871794315284903837363076088765367, f_q)) -mstore(0x1d60, mulmod(mload(0x1900), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q)) -mstore(0x1d80, addmod(mload(0xee0), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q)) -mstore(0x1da0, mulmod(mload(0x1900), 5522161504810533295870699551020523636289972223872138525048055197429246400245, f_q)) -mstore(0x1dc0, addmod(mload(0xee0), 16366081367028741926375706194236751452258392176543895818650148989146562095372, f_q)) -mstore(0x1de0, mulmod(mload(0x1900), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) -mstore(0x1e00, addmod(mload(0xee0), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q)) -mstore(0x1e20, mulmod(mload(0x1900), 9100833993744738801214480881117348002768153232283708533639316963648253510584, f_q)) -mstore(0x1e40, addmod(mload(0xee0), 12787408878094536421031924864139927085780211168132325810058887222927554985033, f_q)) -mstore(0x1e60, mulmod(mload(0x1900), 4245441013247250116003069945606352967193023389718465410501109428393342802981, f_q)) -mstore(0x1e80, addmod(mload(0xee0), 17642801858592025106243335799650922121355341010697568933197094758182465692636, f_q)) -mstore(0x1ea0, mulmod(mload(0x1900), 6132660129994545119218258312491950835441607143741804980633129304664017206141, f_q)) -mstore(0x1ec0, addmod(mload(0xee0), 15755582741844730103028147432765324253106757256674229363065074881911791289476, f_q)) -mstore(0x1ee0, mulmod(mload(0x1900), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q)) -mstore(0x1f00, addmod(mload(0xee0), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q)) -mstore(0x1f20, mulmod(mload(0x1900), 515148244606945972463850631189471072103916690263705052318085725998468254533, f_q)) -mstore(0x1f40, addmod(mload(0xee0), 21373094627232329249782555114067804016444447710152329291380118460577340241084, f_q)) -mstore(0x1f60, mulmod(mload(0x1900), 5980488956150442207659150513163747165544364597008566989111579977672498964212, f_q)) -mstore(0x1f80, addmod(mload(0xee0), 15907753915688833014587255232093527923003999803407467354586624208903309531405, f_q)) -mstore(0x1fa0, mulmod(mload(0x1900), 5223738580615264174925218065001555728265216895679471490312087802465486318994, f_q)) -mstore(0x1fc0, addmod(mload(0xee0), 16664504291224011047321187680255719360283147504736562853386116384110322176623, f_q)) -mstore(0x1fe0, mulmod(mload(0x1900), 14557038802599140430182096396825290815503940951075961210638273254419942783582, f_q)) -mstore(0x2000, addmod(mload(0xee0), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q)) -mstore(0x2020, mulmod(mload(0x1900), 16976236069879939850923145256911338076234942200101755618884183331004076579046, f_q)) -mstore(0x2040, addmod(mload(0xee0), 4912006801959335371323260488345937012313422200314278724814020855571731916571, f_q)) -mstore(0x2060, mulmod(mload(0x1900), 13553911191894110065493137367144919847521088405945523452288398666974237857208, f_q)) -mstore(0x2080, addmod(mload(0xee0), 8334331679945165156753268378112355241027275994470510891409805519601570638409, f_q)) -mstore(0x20a0, mulmod(mload(0x1900), 12222687719926148270818604386979005738180875192307070468454582955273533101023, f_q)) -mstore(0x20c0, addmod(mload(0xee0), 9665555151913126951427801358278269350367489208108963875243621231302275394594, f_q)) -mstore(0x20e0, mulmod(mload(0x1900), 9697063347556872083384215826199993067635178715531258559890418744774301211662, f_q)) -mstore(0x2100, addmod(mload(0xee0), 12191179524282403138862189919057282020913185684884775783807785441801507283955, f_q)) -mstore(0x2120, mulmod(mload(0x1900), 13783318220968413117070077848579881425001701814458176881760898225529300547844, f_q)) -mstore(0x2140, addmod(mload(0xee0), 8104924650870862105176327896677393663546662585957857461937305961046507947773, f_q)) -mstore(0x2160, mulmod(mload(0x1900), 10807735674816066981985242612061336605021639643453679977988966079770672437131, f_q)) -mstore(0x2180, addmod(mload(0xee0), 11080507197023208240261163133195938483526724756962354365709238106805136058486, f_q)) -mstore(0x21a0, mulmod(mload(0x1900), 15487660954688013862248478071816391715224351867581977083810729441220383572585, f_q)) -mstore(0x21c0, addmod(mload(0xee0), 6400581917151261359997927673440883373324012532834057259887474745355424923032, f_q)) -mstore(0x21e0, mulmod(mload(0x1900), 12459868075641381822485233712013080087763946065665469821362892189399541605692, f_q)) -mstore(0x2200, addmod(mload(0xee0), 9428374796197893399761172033244195000784418334750564522335311997176266889925, f_q)) -mstore(0x2220, mulmod(mload(0x1900), 12562571400845953139885120066983392294851269266041089223701347829190217414825, f_q)) -mstore(0x2240, addmod(mload(0xee0), 9325671470993322082361285678273882793697095134374945119996856357385591080792, f_q)) -mstore(0x2260, mulmod(mload(0x1900), 16038300751658239075779628684257016433412502747804121525056508685985277092575, f_q)) -mstore(0x2280, addmod(mload(0xee0), 5849942120181036146466777061000258655135861652611912818641695500590531403042, f_q)) -mstore(0x22a0, mulmod(mload(0x1900), 17665522928519859765452767154433594409738037332395989540221744312194874941704, f_q)) -mstore(0x22c0, addmod(mload(0xee0), 4222719943319415456793638590823680678810327068020044803476459874380933553913, f_q)) -mstore(0x22e0, mulmod(mload(0x1900), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q)) -mstore(0x2300, addmod(mload(0xee0), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q)) -mstore(0x2320, mulmod(mload(0x1900), 1918679275621049296283934091410967415474987212511681231948800935495808101054, f_q)) -mstore(0x2340, addmod(mload(0xee0), 19969563596218225925962471653846307673073377187904353111749403251080000394563, f_q)) -mstore(0x2360, mulmod(mload(0x1900), 13498745591877810872211159461644682954739332524336278910448604883789771736885, f_q)) -mstore(0x2380, addmod(mload(0xee0), 8389497279961464350035246283612592133809031876079755433249599302786036758732, f_q)) -mstore(0x23a0, mulmod(mload(0x1900), 6604851689411953560355663038203889299997924520355363678860500374111951937637, f_q)) -mstore(0x23c0, addmod(mload(0xee0), 15283391182427321661890742707053385788550439880060670664837703812463856557980, f_q)) -mstore(0x23e0, mulmod(mload(0x1900), 20345677989844117909528750049476969581182118546166966482506114734614108237981, f_q)) -mstore(0x2400, addmod(mload(0xee0), 1542564881995157312717655695780305507366245854249067861192089451961700257636, f_q)) -mstore(0x2420, mulmod(mload(0x1900), 11244009323710436498447061620026171700033960328162115124806024297270121927878, f_q)) -mstore(0x2440, addmod(mload(0xee0), 10644233548128838723799344125231103388514404072253919218892179889305686567739, f_q)) -mstore(0x2460, mulmod(mload(0x1900), 790608022292213379425324383664216541739009722347092850716054055768832299157, f_q)) -mstore(0x2480, addmod(mload(0xee0), 21097634849547061842821081361593058546809354678068941492982150130806976196460, f_q)) -mstore(0x24a0, mulmod(mload(0x1900), 13894403229372218245111098554468346933152618215322268934207074514797092422856, f_q)) -mstore(0x24c0, addmod(mload(0xee0), 7993839642467056977135307190788928155395746185093765409491129671778716072761, f_q)) -mstore(0x24e0, mulmod(mload(0x1900), 5289443209903185443361862148540090689648485914368835830972895623576469023722, f_q)) -mstore(0x2500, addmod(mload(0xee0), 16598799661936089778884543596717184398899878486047198512725308562999339471895, f_q)) -mstore(0x2520, mulmod(mload(0x1900), 19715528266218439644661892824912275086257866064695767122686506494361332681035, f_q)) -mstore(0x2540, addmod(mload(0xee0), 2172714605620835577584512920345000002290498335720267221011697692214475814582, f_q)) -mstore(0x2560, mulmod(mload(0x1900), 15161189183906287273290738379431332336600234154579306802151507052820126345529, f_q)) -mstore(0x2580, addmod(mload(0xee0), 6727053687932987948955667365825942751948130245836727541546697133755682150088, f_q)) -mstore(0x25a0, mulmod(mload(0x1900), 12456424076401232823832128238027368612265814450984711658287606686035629293382, f_q)) -mstore(0x25c0, addmod(mload(0xee0), 9431818795438042398414277507229906476282549949431322685410597500540179202235, f_q)) -mstore(0x25e0, mulmod(mload(0x1900), 557567375339945239933617516585967620814823575807691402619711360028043331811, f_q)) -mstore(0x2600, addmod(mload(0xee0), 21330675496499329982312788228671307467733540824608342941078492826547765163806, f_q)) -mstore(0x2620, mulmod(mload(0x1900), 3675353143102618619098608207619541954347747556257261634661810167705798540391, f_q)) -mstore(0x2640, addmod(mload(0xee0), 18212889728736656603147797537637733134200616844158772709036394018870009955226, f_q)) -mstore(0x2660, mulmod(mload(0x1900), 16611719114775828483319365659907682366622074960672212059891361227499450055959, f_q)) -mstore(0x2680, addmod(mload(0xee0), 5276523757063446738927040085349592721926289439743822283806842959076358439658, f_q)) -mstore(0x26a0, mulmod(mload(0x1900), 16386136101309958540926610099404767784529741901845901994660986029617143477017, f_q)) -mstore(0x26c0, addmod(mload(0xee0), 5502106770529316681319795645852507304018622498570132349037218156958665018600, f_q)) -mstore(0x26e0, mulmod(mload(0x1900), 4509404676247677387317362072810231899718070082381452255950861037254608304934, f_q)) -mstore(0x2700, addmod(mload(0xee0), 17378838195591597834929043672447043188830294318034582087747343149321200190683, f_q)) -mstore(0x2720, mulmod(mload(0x1900), 16810138474166795540944740696920121481076613636731046381068745586671284628566, f_q)) -mstore(0x2740, addmod(mload(0xee0), 5078104397672479681301665048337153607471750763684987962629458599904523867051, f_q)) -mstore(0x2760, mulmod(mload(0x1900), 6866457077948847028333856457654941632900463970069876241424363695212127143359, f_q)) -mstore(0x2780, addmod(mload(0xee0), 15021785793890428193912549287602333455647900430346158102273840491363681352258, f_q)) -mstore(0x27a0, mulmod(mload(0x1900), 15050098906272869114113753879341673724544293065073132019915594147673843274264, f_q)) -mstore(0x27c0, addmod(mload(0xee0), 6838143965566406108132651865915601364004071335342902323782610038901965221353, f_q)) -mstore(0x27e0, mulmod(mload(0x1900), 20169013865622130318472103510465966222180994822334426398191891983290742724178, f_q)) -mstore(0x2800, addmod(mload(0xee0), 1719229006217144903774302234791308866367369578081607945506312203285065771439, f_q)) -mstore(0x2820, mulmod(mload(0x1900), 186643418412310505059616433266667559953442348224063743563501145843011378043, f_q)) -mstore(0x2840, addmod(mload(0xee0), 21701599453426964717186789311990607528594922052191970600134703040732797117574, f_q)) -mstore(0x2860, mulmod(mload(0x1900), 14874205783542236433261764022044465911656512639684999678853651860683757650009, f_q)) -mstore(0x2880, addmod(mload(0xee0), 7014037088297038788984641723212809176891851760731034664844552325892050845608, f_q)) -mstore(0x28a0, mulmod(mload(0x1900), 7979162733397795051573074319197621017671482868667369798639936928904004403257, f_q)) -mstore(0x28c0, addmod(mload(0xee0), 13909080138441480170673331426059654070876881531748664545058267257671804092360, f_q)) -mstore(0x28e0, mulmod(mload(0x1900), 2579947959091681244170407980400327834520881737801886423874592072501514087543, f_q)) -mstore(0x2900, addmod(mload(0xee0), 19308294912747593978075997764856947254027482662614147919823612114074294408074, f_q)) -mstore(0x2920, mulmod(mload(0x1900), 14647314289404762345502669568052757093995272955543899726274102521659398012023, f_q)) -mstore(0x2940, addmod(mload(0xee0), 7240928582434512876743736177204517994553091444872134617424101664916410483594, f_q)) -mstore(0x2960, mulmod(mload(0x1900), 17011225028452114973964561549541821925778010085385130152192105634715080939230, f_q)) -mstore(0x2980, addmod(mload(0xee0), 4877017843387160248281844195715453162770354315030904191506098551860727556387, f_q)) -mstore(0x29a0, mulmod(mload(0x1900), 13909366884621139424025272114967039910291313491339778088079465374131977916137, f_q)) -mstore(0x29c0, addmod(mload(0xee0), 7978875987218135798221133630290235178257050909076256255618738812443830579480, f_q)) -mstore(0x29e0, mulmod(mload(0x1900), 1881761935718519990121799628252273658786792458106649887437395059872945867717, f_q)) -mstore(0x2a00, addmod(mload(0xee0), 20006480936120755232124606117005001429761571942309384456260809126702862627900, f_q)) -mstore(0x2a20, mulmod(mload(0x1900), 3028954211863643442542224906848210122376574991720988392405983558451470419662, f_q)) -mstore(0x2a40, addmod(mload(0xee0), 18859288659975631779704180838409064966171789408695045951292220628124338075955, f_q)) -mstore(0x2a60, mulmod(mload(0x1900), 21662285561588145310352318480822402603888953131447478827940284064946709915517, f_q)) -mstore(0x2a80, addmod(mload(0xee0), 225957310251129911894087264434872484659411268968555515757920121629098580100, f_q)) -mstore(0x2aa0, mulmod(mload(0x1900), 378402637159574576880135946147807879590311002003309307938196385556607554558, f_q)) -mstore(0x2ac0, addmod(mload(0xee0), 21509840234679700645366269799109467208958053398412725035760007801019200941059, f_q)) -mstore(0x2ae0, mulmod(mload(0x1900), 21846745818185811051373434299876022191132089169516983080959277716660228899818, f_q)) -mstore(0x2b00, addmod(mload(0xee0), 41497053653464170872971445381252897416275230899051262738926469915579595799, f_q)) -mstore(0x2b20, mulmod(mload(0x1900), 13859044929805761416632426872339332999558462848915686437310885754636367370843, f_q)) -mstore(0x2b40, addmod(mload(0xee0), 8029197942033513805613978872917942088989901551500347906387318431939441124774, f_q)) -mstore(0x2b60, mulmod(mload(0x1900), 11770617947510597378885200406447716404126404817511323735042103519754393416137, f_q)) -mstore(0x2b80, addmod(mload(0xee0), 10117624924328677843361205338809558684421959582904710608656100666821415079480, f_q)) -mstore(0x2ba0, mulmod(mload(0x1900), 319601508938725283206379094021435277953558549162135554365739317130700042560, f_q)) -mstore(0x2bc0, addmod(mload(0xee0), 21568641362900549939040026651235839810594805851253898789332464869445108453057, f_q)) -mstore(0x2be0, mulmod(mload(0x1900), 13018529307372270489258244406856841315962482733096074798317807775255504614069, f_q)) -mstore(0x2c00, addmod(mload(0xee0), 8869713564467004732988161338400433772585881667319959545380396411320303881548, f_q)) -mstore(0x2c20, mulmod(mload(0x1900), 10796308735874323100034550353518537760791974349165624924803974431063123555547, f_q)) -mstore(0x2c40, addmod(mload(0xee0), 11091934135964952122211855391738737327756390051250409418894229755512684940070, f_q)) -mstore(0x2c60, mulmod(mload(0x1900), 5276270562549512946272803945594037128265390012927669941530122528135796334063, f_q)) -mstore(0x2c80, addmod(mload(0xee0), 16611972309289762275973601799663237960282974387488364402168081658440012161554, f_q)) -mstore(0x2ca0, mulmod(mload(0x1900), 14266951011404985116913611868501634000671234987509163410162221784496716449518, f_q)) -mstore(0x2cc0, addmod(mload(0xee0), 7621291860434290105332793876755641087877129412906870933535982402079092046099, f_q)) -mstore(0x2ce0, mulmod(mload(0x1900), 1459528961030896569807206253631725410868595642414057264270714861278164633285, f_q)) -mstore(0x2d00, addmod(mload(0xee0), 20428713910808378652439199491625549677679768758001977079427489325297643862332, f_q)) -mstore(0x2d20, mulmod(mload(0x1900), 21076048292421466101466588747331864862942213489407551704893671891150180812932, f_q)) -mstore(0x2d40, addmod(mload(0xee0), 812194579417809120779816997925410225606150911008482638804532295425627682685, f_q)) -mstore(0x2d60, mulmod(mload(0x1900), 3194789416964050406424265110350613664596286587119568977604859939037397011192, f_q)) -mstore(0x2d80, addmod(mload(0xee0), 18693453454875224815822140634906661423952077813296465366093344247538411484425, f_q)) -mstore(0x2da0, mulmod(mload(0x1900), 19778923120933943678545788030240206353357864532158814848334232828008683217357, f_q)) -mstore(0x2dc0, addmod(mload(0xee0), 2109319750905331543700617715017068735190499868257219495363971358567125278260, f_q)) -mstore(0x2de0, mulmod(mload(0x1900), 3090451643741879200285099477849831179472024364989630500355756836624424014697, f_q)) -mstore(0x2e00, addmod(mload(0xee0), 18797791228097396021961306267407443909076340035426403843342447349951384480920, f_q)) -{ - let prod := mload(0x1940) - - prod := mulmod(mload(0x1980), prod, f_q) - mstore(0x2e20, prod) - - prod := mulmod(mload(0x19c0), prod, f_q) - mstore(0x2e40, prod) - - prod := mulmod(mload(0x1a00), prod, f_q) - mstore(0x2e60, prod) - - prod := mulmod(mload(0x1a40), prod, f_q) - mstore(0x2e80, prod) - - prod := mulmod(mload(0x1a80), prod, f_q) - mstore(0x2ea0, prod) - - prod := mulmod(mload(0x1ac0), prod, f_q) - mstore(0x2ec0, prod) - - prod := mulmod(mload(0x1b00), prod, f_q) - mstore(0x2ee0, prod) - - prod := mulmod(mload(0x1b40), prod, f_q) - mstore(0x2f00, prod) - - prod := mulmod(mload(0x1b80), prod, f_q) - mstore(0x2f20, prod) - - prod := mulmod(mload(0x1bc0), prod, f_q) - mstore(0x2f40, prod) - - prod := mulmod(mload(0x1c00), prod, f_q) - mstore(0x2f60, prod) - - prod := mulmod(mload(0x1c40), prod, f_q) - mstore(0x2f80, prod) - - prod := mulmod(mload(0x1c80), prod, f_q) - mstore(0x2fa0, prod) - - prod := mulmod(mload(0x1cc0), prod, f_q) - mstore(0x2fc0, prod) - - prod := mulmod(mload(0x1d00), prod, f_q) - mstore(0x2fe0, prod) - - prod := mulmod(mload(0x1d40), prod, f_q) - mstore(0x3000, prod) - - prod := mulmod(mload(0x1d80), prod, f_q) - mstore(0x3020, prod) - - prod := mulmod(mload(0x1dc0), prod, f_q) - mstore(0x3040, prod) - - prod := mulmod(mload(0x1e00), prod, f_q) - mstore(0x3060, prod) - - prod := mulmod(mload(0x1e40), prod, f_q) - mstore(0x3080, prod) - - prod := mulmod(mload(0x1e80), prod, f_q) - mstore(0x30a0, prod) - - prod := mulmod(mload(0x1ec0), prod, f_q) - mstore(0x30c0, prod) - - prod := mulmod(mload(0x1f00), prod, f_q) - mstore(0x30e0, prod) - - prod := mulmod(mload(0x1f40), prod, f_q) - mstore(0x3100, prod) - - prod := mulmod(mload(0x1f80), prod, f_q) - mstore(0x3120, prod) - - prod := mulmod(mload(0x1fc0), prod, f_q) - mstore(0x3140, prod) - - prod := mulmod(mload(0x2000), prod, f_q) - mstore(0x3160, prod) - - prod := mulmod(mload(0x2040), prod, f_q) - mstore(0x3180, prod) - - prod := mulmod(mload(0x2080), prod, f_q) - mstore(0x31a0, prod) - - prod := mulmod(mload(0x20c0), prod, f_q) - mstore(0x31c0, prod) - - prod := mulmod(mload(0x2100), prod, f_q) - mstore(0x31e0, prod) - - prod := mulmod(mload(0x2140), prod, f_q) - mstore(0x3200, prod) - - prod := mulmod(mload(0x2180), prod, f_q) - mstore(0x3220, prod) - - prod := mulmod(mload(0x21c0), prod, f_q) - mstore(0x3240, prod) - - prod := mulmod(mload(0x2200), prod, f_q) - mstore(0x3260, prod) - - prod := mulmod(mload(0x2240), prod, f_q) - mstore(0x3280, prod) - - prod := mulmod(mload(0x2280), prod, f_q) - mstore(0x32a0, prod) - - prod := mulmod(mload(0x22c0), prod, f_q) - mstore(0x32c0, prod) - - prod := mulmod(mload(0x2300), prod, f_q) - mstore(0x32e0, prod) - - prod := mulmod(mload(0x2340), prod, f_q) - mstore(0x3300, prod) - - prod := mulmod(mload(0x2380), prod, f_q) - mstore(0x3320, prod) - - prod := mulmod(mload(0x23c0), prod, f_q) - mstore(0x3340, prod) - - prod := mulmod(mload(0x2400), prod, f_q) - mstore(0x3360, prod) - - prod := mulmod(mload(0x2440), prod, f_q) - mstore(0x3380, prod) - - prod := mulmod(mload(0x2480), prod, f_q) - mstore(0x33a0, prod) - - prod := mulmod(mload(0x24c0), prod, f_q) - mstore(0x33c0, prod) - - prod := mulmod(mload(0x2500), prod, f_q) - mstore(0x33e0, prod) - - prod := mulmod(mload(0x2540), prod, f_q) - mstore(0x3400, prod) - - prod := mulmod(mload(0x2580), prod, f_q) - mstore(0x3420, prod) - - prod := mulmod(mload(0x25c0), prod, f_q) - mstore(0x3440, prod) - - prod := mulmod(mload(0x2600), prod, f_q) - mstore(0x3460, prod) - - prod := mulmod(mload(0x2640), prod, f_q) - mstore(0x3480, prod) - - prod := mulmod(mload(0x2680), prod, f_q) - mstore(0x34a0, prod) - - prod := mulmod(mload(0x26c0), prod, f_q) - mstore(0x34c0, prod) - - prod := mulmod(mload(0x2700), prod, f_q) - mstore(0x34e0, prod) - - prod := mulmod(mload(0x2740), prod, f_q) - mstore(0x3500, prod) - - prod := mulmod(mload(0x2780), prod, f_q) - mstore(0x3520, prod) - - prod := mulmod(mload(0x27c0), prod, f_q) - mstore(0x3540, prod) - - prod := mulmod(mload(0x2800), prod, f_q) - mstore(0x3560, prod) - - prod := mulmod(mload(0x2840), prod, f_q) - mstore(0x3580, prod) - - prod := mulmod(mload(0x2880), prod, f_q) - mstore(0x35a0, prod) - - prod := mulmod(mload(0x28c0), prod, f_q) - mstore(0x35c0, prod) - - prod := mulmod(mload(0x2900), prod, f_q) - mstore(0x35e0, prod) - - prod := mulmod(mload(0x2940), prod, f_q) - mstore(0x3600, prod) - - prod := mulmod(mload(0x2980), prod, f_q) - mstore(0x3620, prod) - - prod := mulmod(mload(0x29c0), prod, f_q) - mstore(0x3640, prod) - - prod := mulmod(mload(0x2a00), prod, f_q) - mstore(0x3660, prod) - - prod := mulmod(mload(0x2a40), prod, f_q) - mstore(0x3680, prod) - - prod := mulmod(mload(0x2a80), prod, f_q) - mstore(0x36a0, prod) - - prod := mulmod(mload(0x2ac0), prod, f_q) - mstore(0x36c0, prod) - - prod := mulmod(mload(0x2b00), prod, f_q) - mstore(0x36e0, prod) - - prod := mulmod(mload(0x2b40), prod, f_q) - mstore(0x3700, prod) - - prod := mulmod(mload(0x2b80), prod, f_q) - mstore(0x3720, prod) - - prod := mulmod(mload(0x2bc0), prod, f_q) - mstore(0x3740, prod) - - prod := mulmod(mload(0x2c00), prod, f_q) - mstore(0x3760, prod) - - prod := mulmod(mload(0x2c40), prod, f_q) - mstore(0x3780, prod) - - prod := mulmod(mload(0x2c80), prod, f_q) - mstore(0x37a0, prod) - - prod := mulmod(mload(0x2cc0), prod, f_q) - mstore(0x37c0, prod) - - prod := mulmod(mload(0x2d00), prod, f_q) - mstore(0x37e0, prod) - - prod := mulmod(mload(0x2d40), prod, f_q) - mstore(0x3800, prod) - - prod := mulmod(mload(0x2d80), prod, f_q) - mstore(0x3820, prod) - - prod := mulmod(mload(0x2dc0), prod, f_q) - mstore(0x3840, prod) - - prod := mulmod(mload(0x2e00), prod, f_q) - mstore(0x3860, prod) - - prod := mulmod(mload(0x18e0), prod, f_q) - mstore(0x3880, prod) - - } -mstore(0x38c0, 32) -mstore(0x38e0, 32) -mstore(0x3900, 32) -mstore(0x3920, mload(0x3880)) -mstore(0x3940, 21888242871839275222246405745257275088548364400416034343698204186575808495615) -mstore(0x3960, 21888242871839275222246405745257275088548364400416034343698204186575808495617) -success := and(eq(staticcall(gas(), 0x5, 0x38c0, 0xc0, 0x38a0, 0x20), 1), success) -{ - - let inv := mload(0x38a0) - let v - - v := mload(0x18e0) - mstore(6368, mulmod(mload(0x3860), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2e00) - mstore(11776, mulmod(mload(0x3840), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2dc0) - mstore(11712, mulmod(mload(0x3820), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2d80) - mstore(11648, mulmod(mload(0x3800), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2d40) - mstore(11584, mulmod(mload(0x37e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2d00) - mstore(11520, mulmod(mload(0x37c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2cc0) - mstore(11456, mulmod(mload(0x37a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2c80) - mstore(11392, mulmod(mload(0x3780), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2c40) - mstore(11328, mulmod(mload(0x3760), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2c00) - mstore(11264, mulmod(mload(0x3740), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2bc0) - mstore(11200, mulmod(mload(0x3720), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2b80) - mstore(11136, mulmod(mload(0x3700), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2b40) - mstore(11072, mulmod(mload(0x36e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2b00) - mstore(11008, mulmod(mload(0x36c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2ac0) - mstore(10944, mulmod(mload(0x36a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2a80) - mstore(10880, mulmod(mload(0x3680), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2a40) - mstore(10816, mulmod(mload(0x3660), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2a00) - mstore(10752, mulmod(mload(0x3640), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x29c0) - mstore(10688, mulmod(mload(0x3620), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2980) - mstore(10624, mulmod(mload(0x3600), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2940) - mstore(10560, mulmod(mload(0x35e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2900) - mstore(10496, mulmod(mload(0x35c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x28c0) - mstore(10432, mulmod(mload(0x35a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2880) - mstore(10368, mulmod(mload(0x3580), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2840) - mstore(10304, mulmod(mload(0x3560), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2800) - mstore(10240, mulmod(mload(0x3540), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x27c0) - mstore(10176, mulmod(mload(0x3520), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2780) - mstore(10112, mulmod(mload(0x3500), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2740) - mstore(10048, mulmod(mload(0x34e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2700) - mstore(9984, mulmod(mload(0x34c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x26c0) - mstore(9920, mulmod(mload(0x34a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2680) - mstore(9856, mulmod(mload(0x3480), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2640) - mstore(9792, mulmod(mload(0x3460), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2600) - mstore(9728, mulmod(mload(0x3440), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x25c0) - mstore(9664, mulmod(mload(0x3420), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2580) - mstore(9600, mulmod(mload(0x3400), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2540) - mstore(9536, mulmod(mload(0x33e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2500) - mstore(9472, mulmod(mload(0x33c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x24c0) - mstore(9408, mulmod(mload(0x33a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2480) - mstore(9344, mulmod(mload(0x3380), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2440) - mstore(9280, mulmod(mload(0x3360), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2400) - mstore(9216, mulmod(mload(0x3340), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x23c0) - mstore(9152, mulmod(mload(0x3320), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2380) - mstore(9088, mulmod(mload(0x3300), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2340) - mstore(9024, mulmod(mload(0x32e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2300) - mstore(8960, mulmod(mload(0x32c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x22c0) - mstore(8896, mulmod(mload(0x32a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2280) - mstore(8832, mulmod(mload(0x3280), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2240) - mstore(8768, mulmod(mload(0x3260), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2200) - mstore(8704, mulmod(mload(0x3240), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x21c0) - mstore(8640, mulmod(mload(0x3220), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2180) - mstore(8576, mulmod(mload(0x3200), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2140) - mstore(8512, mulmod(mload(0x31e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2100) - mstore(8448, mulmod(mload(0x31c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x20c0) - mstore(8384, mulmod(mload(0x31a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2080) - mstore(8320, mulmod(mload(0x3180), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2040) - mstore(8256, mulmod(mload(0x3160), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x2000) - mstore(8192, mulmod(mload(0x3140), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1fc0) - mstore(8128, mulmod(mload(0x3120), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1f80) - mstore(8064, mulmod(mload(0x3100), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1f40) - mstore(8000, mulmod(mload(0x30e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1f00) - mstore(7936, mulmod(mload(0x30c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ec0) - mstore(7872, mulmod(mload(0x30a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1e80) - mstore(7808, mulmod(mload(0x3080), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1e40) - mstore(7744, mulmod(mload(0x3060), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1e00) - mstore(7680, mulmod(mload(0x3040), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1dc0) - mstore(7616, mulmod(mload(0x3020), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1d80) - mstore(7552, mulmod(mload(0x3000), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1d40) - mstore(7488, mulmod(mload(0x2fe0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1d00) - mstore(7424, mulmod(mload(0x2fc0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1cc0) - mstore(7360, mulmod(mload(0x2fa0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1c80) - mstore(7296, mulmod(mload(0x2f80), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1c40) - mstore(7232, mulmod(mload(0x2f60), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1c00) - mstore(7168, mulmod(mload(0x2f40), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1bc0) - mstore(7104, mulmod(mload(0x2f20), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1b80) - mstore(7040, mulmod(mload(0x2f00), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1b40) - mstore(6976, mulmod(mload(0x2ee0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1b00) - mstore(6912, mulmod(mload(0x2ec0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ac0) - mstore(6848, mulmod(mload(0x2ea0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1a80) - mstore(6784, mulmod(mload(0x2e80), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1a40) - mstore(6720, mulmod(mload(0x2e60), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1a00) - mstore(6656, mulmod(mload(0x2e40), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x19c0) - mstore(6592, mulmod(mload(0x2e20), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1980) - mstore(6528, mulmod(mload(0x1940), inv, f_q)) - inv := mulmod(v, inv, f_q) - mstore(0x1940, inv) - - } -mstore(0x3980, mulmod(mload(0x1920), mload(0x1940), f_q)) -mstore(0x39a0, mulmod(mload(0x1960), mload(0x1980), f_q)) -mstore(0x39c0, mulmod(mload(0x19a0), mload(0x19c0), f_q)) -mstore(0x39e0, mulmod(mload(0x19e0), mload(0x1a00), f_q)) -mstore(0x3a00, mulmod(mload(0x1a20), mload(0x1a40), f_q)) -mstore(0x3a20, mulmod(mload(0x1a60), mload(0x1a80), f_q)) -mstore(0x3a40, mulmod(mload(0x1aa0), mload(0x1ac0), f_q)) -mstore(0x3a60, mulmod(mload(0x1ae0), mload(0x1b00), f_q)) -mstore(0x3a80, mulmod(mload(0x1b20), mload(0x1b40), f_q)) -mstore(0x3aa0, mulmod(mload(0x1b60), mload(0x1b80), f_q)) -mstore(0x3ac0, mulmod(mload(0x1ba0), mload(0x1bc0), f_q)) -mstore(0x3ae0, mulmod(mload(0x1be0), mload(0x1c00), f_q)) -mstore(0x3b00, mulmod(mload(0x1c20), mload(0x1c40), f_q)) -mstore(0x3b20, mulmod(mload(0x1c60), mload(0x1c80), f_q)) -mstore(0x3b40, mulmod(mload(0x1ca0), mload(0x1cc0), f_q)) -mstore(0x3b60, mulmod(mload(0x1ce0), mload(0x1d00), f_q)) -mstore(0x3b80, mulmod(mload(0x1d20), mload(0x1d40), f_q)) -mstore(0x3ba0, mulmod(mload(0x1d60), mload(0x1d80), f_q)) -mstore(0x3bc0, mulmod(mload(0x1da0), mload(0x1dc0), f_q)) -mstore(0x3be0, mulmod(mload(0x1de0), mload(0x1e00), f_q)) -mstore(0x3c00, mulmod(mload(0x1e20), mload(0x1e40), f_q)) -mstore(0x3c20, mulmod(mload(0x1e60), mload(0x1e80), f_q)) -mstore(0x3c40, mulmod(mload(0x1ea0), mload(0x1ec0), f_q)) -mstore(0x3c60, mulmod(mload(0x1ee0), mload(0x1f00), f_q)) -mstore(0x3c80, mulmod(mload(0x1f20), mload(0x1f40), f_q)) -mstore(0x3ca0, mulmod(mload(0x1f60), mload(0x1f80), f_q)) -mstore(0x3cc0, mulmod(mload(0x1fa0), mload(0x1fc0), f_q)) -mstore(0x3ce0, mulmod(mload(0x1fe0), mload(0x2000), f_q)) -mstore(0x3d00, mulmod(mload(0x2020), mload(0x2040), f_q)) -mstore(0x3d20, mulmod(mload(0x2060), mload(0x2080), f_q)) -mstore(0x3d40, mulmod(mload(0x20a0), mload(0x20c0), f_q)) -mstore(0x3d60, mulmod(mload(0x20e0), mload(0x2100), f_q)) -mstore(0x3d80, mulmod(mload(0x2120), mload(0x2140), f_q)) -mstore(0x3da0, mulmod(mload(0x2160), mload(0x2180), f_q)) -mstore(0x3dc0, mulmod(mload(0x21a0), mload(0x21c0), f_q)) -mstore(0x3de0, mulmod(mload(0x21e0), mload(0x2200), f_q)) -mstore(0x3e00, mulmod(mload(0x2220), mload(0x2240), f_q)) -mstore(0x3e20, mulmod(mload(0x2260), mload(0x2280), f_q)) -mstore(0x3e40, mulmod(mload(0x22a0), mload(0x22c0), f_q)) -mstore(0x3e60, mulmod(mload(0x22e0), mload(0x2300), f_q)) -mstore(0x3e80, mulmod(mload(0x2320), mload(0x2340), f_q)) -mstore(0x3ea0, mulmod(mload(0x2360), mload(0x2380), f_q)) -mstore(0x3ec0, mulmod(mload(0x23a0), mload(0x23c0), f_q)) -mstore(0x3ee0, mulmod(mload(0x23e0), mload(0x2400), f_q)) -mstore(0x3f00, mulmod(mload(0x2420), mload(0x2440), f_q)) -mstore(0x3f20, mulmod(mload(0x2460), mload(0x2480), f_q)) -mstore(0x3f40, mulmod(mload(0x24a0), mload(0x24c0), f_q)) -mstore(0x3f60, mulmod(mload(0x24e0), mload(0x2500), f_q)) -mstore(0x3f80, mulmod(mload(0x2520), mload(0x2540), f_q)) -mstore(0x3fa0, mulmod(mload(0x2560), mload(0x2580), f_q)) -mstore(0x3fc0, mulmod(mload(0x25a0), mload(0x25c0), f_q)) -mstore(0x3fe0, mulmod(mload(0x25e0), mload(0x2600), f_q)) -mstore(0x4000, mulmod(mload(0x2620), mload(0x2640), f_q)) -mstore(0x4020, mulmod(mload(0x2660), mload(0x2680), f_q)) -mstore(0x4040, mulmod(mload(0x26a0), mload(0x26c0), f_q)) -mstore(0x4060, mulmod(mload(0x26e0), mload(0x2700), f_q)) -mstore(0x4080, mulmod(mload(0x2720), mload(0x2740), f_q)) -mstore(0x40a0, mulmod(mload(0x2760), mload(0x2780), f_q)) -mstore(0x40c0, mulmod(mload(0x27a0), mload(0x27c0), f_q)) -mstore(0x40e0, mulmod(mload(0x27e0), mload(0x2800), f_q)) -mstore(0x4100, mulmod(mload(0x2820), mload(0x2840), f_q)) -mstore(0x4120, mulmod(mload(0x2860), mload(0x2880), f_q)) -mstore(0x4140, mulmod(mload(0x28a0), mload(0x28c0), f_q)) -mstore(0x4160, mulmod(mload(0x28e0), mload(0x2900), f_q)) -mstore(0x4180, mulmod(mload(0x2920), mload(0x2940), f_q)) -mstore(0x41a0, mulmod(mload(0x2960), mload(0x2980), f_q)) -mstore(0x41c0, mulmod(mload(0x29a0), mload(0x29c0), f_q)) -mstore(0x41e0, mulmod(mload(0x29e0), mload(0x2a00), f_q)) -mstore(0x4200, mulmod(mload(0x2a20), mload(0x2a40), f_q)) -mstore(0x4220, mulmod(mload(0x2a60), mload(0x2a80), f_q)) -mstore(0x4240, mulmod(mload(0x2aa0), mload(0x2ac0), f_q)) -mstore(0x4260, mulmod(mload(0x2ae0), mload(0x2b00), f_q)) -mstore(0x4280, mulmod(mload(0x2b20), mload(0x2b40), f_q)) -mstore(0x42a0, mulmod(mload(0x2b60), mload(0x2b80), f_q)) -mstore(0x42c0, mulmod(mload(0x2ba0), mload(0x2bc0), f_q)) -mstore(0x42e0, mulmod(mload(0x2be0), mload(0x2c00), f_q)) -mstore(0x4300, mulmod(mload(0x2c20), mload(0x2c40), f_q)) -mstore(0x4320, mulmod(mload(0x2c60), mload(0x2c80), f_q)) -mstore(0x4340, mulmod(mload(0x2ca0), mload(0x2cc0), f_q)) -mstore(0x4360, mulmod(mload(0x2ce0), mload(0x2d00), f_q)) -mstore(0x4380, mulmod(mload(0x2d20), mload(0x2d40), f_q)) -mstore(0x43a0, mulmod(mload(0x2d60), mload(0x2d80), f_q)) -mstore(0x43c0, mulmod(mload(0x2da0), mload(0x2dc0), f_q)) -mstore(0x43e0, mulmod(mload(0x2de0), mload(0x2e00), f_q)) -{ - let result := mulmod(mload(0x3a60), mload(0x20), f_q) -result := addmod(mulmod(mload(0x3a80), mload(0x40), f_q), result, f_q) -result := addmod(mulmod(mload(0x3aa0), mload(0x60), f_q), result, f_q) -result := addmod(mulmod(mload(0x3ac0), mload(0x80), f_q), result, f_q) -result := addmod(mulmod(mload(0x3ae0), mload(0xa0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3b00), mload(0xc0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3b20), mload(0xe0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3b40), mload(0x100), f_q), result, f_q) -result := addmod(mulmod(mload(0x3b60), mload(0x120), f_q), result, f_q) -result := addmod(mulmod(mload(0x3b80), mload(0x140), f_q), result, f_q) -result := addmod(mulmod(mload(0x3ba0), mload(0x160), f_q), result, f_q) -result := addmod(mulmod(mload(0x3bc0), mload(0x180), f_q), result, f_q) -result := addmod(mulmod(mload(0x3be0), mload(0x1a0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3c00), mload(0x1c0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3c20), mload(0x1e0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3c40), mload(0x200), f_q), result, f_q) -result := addmod(mulmod(mload(0x3c60), mload(0x220), f_q), result, f_q) -result := addmod(mulmod(mload(0x3c80), mload(0x240), f_q), result, f_q) -result := addmod(mulmod(mload(0x3ca0), mload(0x260), f_q), result, f_q) -result := addmod(mulmod(mload(0x3cc0), mload(0x280), f_q), result, f_q) -result := addmod(mulmod(mload(0x3ce0), mload(0x2a0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3d00), mload(0x2c0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3d20), mload(0x2e0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3d40), mload(0x300), f_q), result, f_q) -result := addmod(mulmod(mload(0x3d60), mload(0x320), f_q), result, f_q) -result := addmod(mulmod(mload(0x3d80), mload(0x340), f_q), result, f_q) -result := addmod(mulmod(mload(0x3da0), mload(0x360), f_q), result, f_q) -result := addmod(mulmod(mload(0x3dc0), mload(0x380), f_q), result, f_q) -result := addmod(mulmod(mload(0x3de0), mload(0x3a0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3e00), mload(0x3c0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3e20), mload(0x3e0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3e40), mload(0x400), f_q), result, f_q) -result := addmod(mulmod(mload(0x3e60), mload(0x420), f_q), result, f_q) -result := addmod(mulmod(mload(0x3e80), mload(0x440), f_q), result, f_q) -result := addmod(mulmod(mload(0x3ea0), mload(0x460), f_q), result, f_q) -result := addmod(mulmod(mload(0x3ec0), mload(0x480), f_q), result, f_q) -result := addmod(mulmod(mload(0x3ee0), mload(0x4a0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3f00), mload(0x4c0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3f20), mload(0x4e0), f_q), result, f_q) -result := addmod(mulmod(mload(0x3f40), mload(0x500), f_q), result, f_q) -result := addmod(mulmod(mload(0x3f60), mload(0x520), f_q), result, f_q) -result := addmod(mulmod(mload(0x3f80), mload(0x540), f_q), result, f_q) -result := addmod(mulmod(mload(0x3fa0), mload(0x560), f_q), result, f_q) -result := addmod(mulmod(mload(0x3fc0), mload(0x580), f_q), result, f_q) -result := addmod(mulmod(mload(0x3fe0), mload(0x5a0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4000), mload(0x5c0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4020), mload(0x5e0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4040), mload(0x600), f_q), result, f_q) -result := addmod(mulmod(mload(0x4060), mload(0x620), f_q), result, f_q) -result := addmod(mulmod(mload(0x4080), mload(0x640), f_q), result, f_q) -result := addmod(mulmod(mload(0x40a0), mload(0x660), f_q), result, f_q) -result := addmod(mulmod(mload(0x40c0), mload(0x680), f_q), result, f_q) -result := addmod(mulmod(mload(0x40e0), mload(0x6a0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4100), mload(0x6c0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4120), mload(0x6e0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4140), mload(0x700), f_q), result, f_q) -result := addmod(mulmod(mload(0x4160), mload(0x720), f_q), result, f_q) -result := addmod(mulmod(mload(0x4180), mload(0x740), f_q), result, f_q) -result := addmod(mulmod(mload(0x41a0), mload(0x760), f_q), result, f_q) -result := addmod(mulmod(mload(0x41c0), mload(0x780), f_q), result, f_q) -result := addmod(mulmod(mload(0x41e0), mload(0x7a0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4200), mload(0x7c0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4220), mload(0x7e0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4240), mload(0x800), f_q), result, f_q) -result := addmod(mulmod(mload(0x4260), mload(0x820), f_q), result, f_q) -result := addmod(mulmod(mload(0x4280), mload(0x840), f_q), result, f_q) -result := addmod(mulmod(mload(0x42a0), mload(0x860), f_q), result, f_q) -result := addmod(mulmod(mload(0x42c0), mload(0x880), f_q), result, f_q) -result := addmod(mulmod(mload(0x42e0), mload(0x8a0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4300), mload(0x8c0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4320), mload(0x8e0), f_q), result, f_q) -result := addmod(mulmod(mload(0x4340), mload(0x900), f_q), result, f_q) -result := addmod(mulmod(mload(0x4360), mload(0x920), f_q), result, f_q) -result := addmod(mulmod(mload(0x4380), mload(0x940), f_q), result, f_q) -result := addmod(mulmod(mload(0x43a0), mload(0x960), f_q), result, f_q) -result := addmod(mulmod(mload(0x43c0), mload(0x980), f_q), result, f_q) -result := addmod(mulmod(mload(0x43e0), mload(0x9a0), f_q), result, f_q) -mstore(17408, result) - } -mstore(0x4420, mulmod(mload(0xf60), mload(0xf40), f_q)) -mstore(0x4440, addmod(mload(0xf20), mload(0x4420), f_q)) -mstore(0x4460, addmod(mload(0x4440), sub(f_q, mload(0xf80)), f_q)) -mstore(0x4480, mulmod(mload(0x4460), mload(0x1100), f_q)) -mstore(0x44a0, mulmod(mload(0xdc0), mload(0x4480), f_q)) -mstore(0x44c0, mulmod(mload(0xfe0), mload(0xfc0), f_q)) -mstore(0x44e0, addmod(mload(0xfa0), mload(0x44c0), f_q)) -mstore(0x4500, addmod(mload(0x44e0), sub(f_q, mload(0x1000)), f_q)) -mstore(0x4520, mulmod(mload(0x4500), mload(0x1120), f_q)) -mstore(0x4540, addmod(mload(0x44a0), mload(0x4520), f_q)) -mstore(0x4560, mulmod(mload(0xdc0), mload(0x4540), f_q)) -mstore(0x4580, mulmod(mload(0x1060), mload(0x1040), f_q)) -mstore(0x45a0, addmod(mload(0x1020), mload(0x4580), f_q)) -mstore(0x45c0, addmod(mload(0x45a0), sub(f_q, mload(0x1080)), f_q)) -mstore(0x45e0, mulmod(mload(0x45c0), mload(0x1140), f_q)) -mstore(0x4600, addmod(mload(0x4560), mload(0x45e0), f_q)) -mstore(0x4620, mulmod(mload(0xdc0), mload(0x4600), f_q)) -mstore(0x4640, addmod(1, sub(f_q, mload(0x1240)), f_q)) -mstore(0x4660, mulmod(mload(0x4640), mload(0x3a60), f_q)) -mstore(0x4680, addmod(mload(0x4620), mload(0x4660), f_q)) -mstore(0x46a0, mulmod(mload(0xdc0), mload(0x4680), f_q)) -mstore(0x46c0, mulmod(mload(0x1300), mload(0x1300), f_q)) -mstore(0x46e0, addmod(mload(0x46c0), sub(f_q, mload(0x1300)), f_q)) -mstore(0x4700, mulmod(mload(0x46e0), mload(0x3980), f_q)) -mstore(0x4720, addmod(mload(0x46a0), mload(0x4700), f_q)) -mstore(0x4740, mulmod(mload(0xdc0), mload(0x4720), f_q)) -mstore(0x4760, addmod(mload(0x12a0), sub(f_q, mload(0x1280)), f_q)) -mstore(0x4780, mulmod(mload(0x4760), mload(0x3a60), f_q)) -mstore(0x47a0, addmod(mload(0x4740), mload(0x4780), f_q)) -mstore(0x47c0, mulmod(mload(0xdc0), mload(0x47a0), f_q)) -mstore(0x47e0, addmod(mload(0x1300), sub(f_q, mload(0x12e0)), f_q)) -mstore(0x4800, mulmod(mload(0x47e0), mload(0x3a60), f_q)) -mstore(0x4820, addmod(mload(0x47c0), mload(0x4800), f_q)) -mstore(0x4840, mulmod(mload(0xdc0), mload(0x4820), f_q)) -mstore(0x4860, addmod(1, sub(f_q, mload(0x3980)), f_q)) -mstore(0x4880, addmod(mload(0x39a0), mload(0x39c0), f_q)) -mstore(0x48a0, addmod(mload(0x4880), mload(0x39e0), f_q)) -mstore(0x48c0, addmod(mload(0x48a0), mload(0x3a00), f_q)) -mstore(0x48e0, addmod(mload(0x48c0), mload(0x3a20), f_q)) -mstore(0x4900, addmod(mload(0x48e0), mload(0x3a40), f_q)) -mstore(0x4920, addmod(mload(0x4860), sub(f_q, mload(0x4900)), f_q)) -mstore(0x4940, mulmod(mload(0x1180), mload(0xbc0), f_q)) -mstore(0x4960, addmod(mload(0x10c0), mload(0x4940), f_q)) -mstore(0x4980, addmod(mload(0x4960), mload(0xc20), f_q)) -mstore(0x49a0, mulmod(mload(0x11a0), mload(0xbc0), f_q)) -mstore(0x49c0, addmod(mload(0xf20), mload(0x49a0), f_q)) -mstore(0x49e0, addmod(mload(0x49c0), mload(0xc20), f_q)) -mstore(0x4a00, mulmod(mload(0x49e0), mload(0x4980), f_q)) -mstore(0x4a20, mulmod(mload(0x4a00), mload(0x1260), f_q)) -mstore(0x4a40, mulmod(1, mload(0xbc0), f_q)) -mstore(0x4a60, mulmod(mload(0xee0), mload(0x4a40), f_q)) -mstore(0x4a80, addmod(mload(0x10c0), mload(0x4a60), f_q)) -mstore(0x4aa0, addmod(mload(0x4a80), mload(0xc20), f_q)) -mstore(0x4ac0, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0xbc0), f_q)) -mstore(0x4ae0, mulmod(mload(0xee0), mload(0x4ac0), f_q)) -mstore(0x4b00, addmod(mload(0xf20), mload(0x4ae0), f_q)) -mstore(0x4b20, addmod(mload(0x4b00), mload(0xc20), f_q)) -mstore(0x4b40, mulmod(mload(0x4b20), mload(0x4aa0), f_q)) -mstore(0x4b60, mulmod(mload(0x4b40), mload(0x1240), f_q)) -mstore(0x4b80, addmod(mload(0x4a20), sub(f_q, mload(0x4b60)), f_q)) -mstore(0x4ba0, mulmod(mload(0x4b80), mload(0x4920), f_q)) -mstore(0x4bc0, addmod(mload(0x4840), mload(0x4ba0), f_q)) -mstore(0x4be0, mulmod(mload(0xdc0), mload(0x4bc0), f_q)) -mstore(0x4c00, mulmod(mload(0x11c0), mload(0xbc0), f_q)) -mstore(0x4c20, addmod(mload(0xfa0), mload(0x4c00), f_q)) -mstore(0x4c40, addmod(mload(0x4c20), mload(0xc20), f_q)) -mstore(0x4c60, mulmod(mload(0x11e0), mload(0xbc0), f_q)) -mstore(0x4c80, addmod(mload(0x1020), mload(0x4c60), f_q)) -mstore(0x4ca0, addmod(mload(0x4c80), mload(0xc20), f_q)) -mstore(0x4cc0, mulmod(mload(0x4ca0), mload(0x4c40), f_q)) -mstore(0x4ce0, mulmod(mload(0x4cc0), mload(0x12c0), f_q)) -mstore(0x4d00, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0xbc0), f_q)) -mstore(0x4d20, mulmod(mload(0xee0), mload(0x4d00), f_q)) -mstore(0x4d40, addmod(mload(0xfa0), mload(0x4d20), f_q)) -mstore(0x4d60, addmod(mload(0x4d40), mload(0xc20), f_q)) -mstore(0x4d80, mulmod(11166246659983828508719468090013646171463329086121580628794302409516816350802, mload(0xbc0), f_q)) -mstore(0x4da0, mulmod(mload(0xee0), mload(0x4d80), f_q)) -mstore(0x4dc0, addmod(mload(0x1020), mload(0x4da0), f_q)) -mstore(0x4de0, addmod(mload(0x4dc0), mload(0xc20), f_q)) -mstore(0x4e00, mulmod(mload(0x4de0), mload(0x4d60), f_q)) -mstore(0x4e20, mulmod(mload(0x4e00), mload(0x12a0), f_q)) -mstore(0x4e40, addmod(mload(0x4ce0), sub(f_q, mload(0x4e20)), f_q)) -mstore(0x4e60, mulmod(mload(0x4e40), mload(0x4920), f_q)) -mstore(0x4e80, addmod(mload(0x4be0), mload(0x4e60), f_q)) -mstore(0x4ea0, mulmod(mload(0xdc0), mload(0x4e80), f_q)) -mstore(0x4ec0, mulmod(mload(0x1200), mload(0xbc0), f_q)) -mstore(0x4ee0, addmod(mload(0x10a0), mload(0x4ec0), f_q)) -mstore(0x4f00, addmod(mload(0x4ee0), mload(0xc20), f_q)) -mstore(0x4f20, mulmod(mload(0x1220), mload(0xbc0), f_q)) -mstore(0x4f40, addmod(mload(0x4400), mload(0x4f20), f_q)) -mstore(0x4f60, addmod(mload(0x4f40), mload(0xc20), f_q)) -mstore(0x4f80, mulmod(mload(0x4f60), mload(0x4f00), f_q)) -mstore(0x4fa0, mulmod(mload(0x4f80), mload(0x1320), f_q)) -mstore(0x4fc0, mulmod(284840088355319032285349970403338060113257071685626700086398481893096618818, mload(0xbc0), f_q)) -mstore(0x4fe0, mulmod(mload(0xee0), mload(0x4fc0), f_q)) -mstore(0x5000, addmod(mload(0x10a0), mload(0x4fe0), f_q)) -mstore(0x5020, addmod(mload(0x5000), mload(0xc20), f_q)) -mstore(0x5040, mulmod(21134065618345176623193549882539580312263652408302468683943992798037078993309, mload(0xbc0), f_q)) -mstore(0x5060, mulmod(mload(0xee0), mload(0x5040), f_q)) -mstore(0x5080, addmod(mload(0x4400), mload(0x5060), f_q)) -mstore(0x50a0, addmod(mload(0x5080), mload(0xc20), f_q)) -mstore(0x50c0, mulmod(mload(0x50a0), mload(0x5020), f_q)) -mstore(0x50e0, mulmod(mload(0x50c0), mload(0x1300), f_q)) -mstore(0x5100, addmod(mload(0x4fa0), sub(f_q, mload(0x50e0)), f_q)) -mstore(0x5120, mulmod(mload(0x5100), mload(0x4920), f_q)) -mstore(0x5140, addmod(mload(0x4ea0), mload(0x5120), f_q)) -mstore(0x5160, mulmod(mload(0xdc0), mload(0x5140), f_q)) -mstore(0x5180, addmod(1, sub(f_q, mload(0x1340)), f_q)) -mstore(0x51a0, mulmod(mload(0x5180), mload(0x3a60), f_q)) -mstore(0x51c0, addmod(mload(0x5160), mload(0x51a0), f_q)) -mstore(0x51e0, mulmod(mload(0xdc0), mload(0x51c0), f_q)) -mstore(0x5200, mulmod(mload(0x1340), mload(0x1340), f_q)) -mstore(0x5220, addmod(mload(0x5200), sub(f_q, mload(0x1340)), f_q)) -mstore(0x5240, mulmod(mload(0x5220), mload(0x3980), f_q)) -mstore(0x5260, addmod(mload(0x51e0), mload(0x5240), f_q)) -mstore(0x5280, mulmod(mload(0xdc0), mload(0x5260), f_q)) -mstore(0x52a0, addmod(mload(0x1380), mload(0xbc0), f_q)) -mstore(0x52c0, mulmod(mload(0x52a0), mload(0x1360), f_q)) -mstore(0x52e0, addmod(mload(0x13c0), mload(0xc20), f_q)) -mstore(0x5300, mulmod(mload(0x52e0), mload(0x52c0), f_q)) -mstore(0x5320, addmod(mload(0x10a0), mload(0xbc0), f_q)) -mstore(0x5340, mulmod(mload(0x5320), mload(0x1340), f_q)) -mstore(0x5360, addmod(mload(0x10e0), mload(0xc20), f_q)) -mstore(0x5380, mulmod(mload(0x5360), mload(0x5340), f_q)) -mstore(0x53a0, addmod(mload(0x5300), sub(f_q, mload(0x5380)), f_q)) -mstore(0x53c0, mulmod(mload(0x53a0), mload(0x4920), f_q)) -mstore(0x53e0, addmod(mload(0x5280), mload(0x53c0), f_q)) -mstore(0x5400, mulmod(mload(0xdc0), mload(0x53e0), f_q)) -mstore(0x5420, addmod(mload(0x1380), sub(f_q, mload(0x13c0)), f_q)) -mstore(0x5440, mulmod(mload(0x5420), mload(0x3a60), f_q)) -mstore(0x5460, addmod(mload(0x5400), mload(0x5440), f_q)) -mstore(0x5480, mulmod(mload(0xdc0), mload(0x5460), f_q)) -mstore(0x54a0, mulmod(mload(0x5420), mload(0x4920), f_q)) -mstore(0x54c0, addmod(mload(0x1380), sub(f_q, mload(0x13a0)), f_q)) -mstore(0x54e0, mulmod(mload(0x54c0), mload(0x54a0), f_q)) -mstore(0x5500, addmod(mload(0x5480), mload(0x54e0), f_q)) -mstore(0x5520, mulmod(mload(0x18c0), mload(0x18c0), f_q)) -mstore(0x5540, mulmod(mload(0x5520), mload(0x18c0), f_q)) -mstore(0x5560, mulmod(1, mload(0x18c0), f_q)) -mstore(0x5580, mulmod(1, mload(0x5520), f_q)) -mstore(0x55a0, mulmod(mload(0x5500), mload(0x18e0), f_q)) -mstore(0x55c0, mulmod(mload(0x1600), mload(0xee0), f_q)) -mstore(0x55e0, mulmod(mload(0x55c0), mload(0xee0), f_q)) -mstore(0x5600, mulmod(mload(0xee0), 4506835738822104338668100540817374747935106310012997856968187171738630203507, f_q)) -mstore(0x5620, addmod(mload(0x1500), sub(f_q, mload(0x5600)), f_q)) -mstore(0x5640, mulmod(mload(0xee0), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q)) -mstore(0x5660, addmod(mload(0x1500), sub(f_q, mload(0x5640)), f_q)) -mstore(0x5680, mulmod(mload(0xee0), 1, f_q)) -mstore(0x56a0, addmod(mload(0x1500), sub(f_q, mload(0x5680)), f_q)) -mstore(0x56c0, mulmod(mload(0xee0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) -mstore(0x56e0, addmod(mload(0x1500), sub(f_q, mload(0x56c0)), f_q)) -mstore(0x5700, mulmod(mload(0xee0), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) -mstore(0x5720, addmod(mload(0x1500), sub(f_q, mload(0x5700)), f_q)) -mstore(0x5740, mulmod(mload(0xee0), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q)) -mstore(0x5760, addmod(mload(0x1500), sub(f_q, mload(0x5740)), f_q)) -mstore(0x5780, mulmod(13213688729882003894512633350385593288217014177373218494356903340348818451480, mload(0x55c0), f_q)) -mstore(0x57a0, mulmod(mload(0x5780), 1, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x5780), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x57a0)), f_q), result, f_q) -mstore(22464, result) - } -mstore(0x57e0, mulmod(8207090019724696496350398458716998472718344609680392612601596849934418295470, mload(0x55c0), f_q)) -mstore(0x5800, mulmod(mload(0x57e0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x57e0), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5800)), f_q), result, f_q) -mstore(22560, result) - } -mstore(0x5840, mulmod(7391709068497399131897422873231908718558236401035363928063603272120120747483, mload(0x55c0), f_q)) -mstore(0x5860, mulmod(mload(0x5840), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x5840), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5860)), f_q), result, f_q) -mstore(22656, result) - } -mstore(0x58a0, mulmod(19036273796805830823244991598792794567595348772040298280440552631112242221017, mload(0x55c0), f_q)) -mstore(0x58c0, mulmod(mload(0x58a0), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x58a0), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x58c0)), f_q), result, f_q) -mstore(22752, result) - } -mstore(0x5900, mulmod(1, mload(0x56a0), f_q)) -mstore(0x5920, mulmod(mload(0x5900), mload(0x56e0), f_q)) -mstore(0x5940, mulmod(mload(0x5920), mload(0x5720), f_q)) -mstore(0x5960, mulmod(mload(0x5940), mload(0x5760), f_q)) -{ - let result := mulmod(mload(0x1500), 1, f_q) -result := addmod(mulmod(mload(0xee0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q) -mstore(22912, result) - } -mstore(0x59a0, mulmod(8829162144871436359454223005614551490263319522284589706138791622554149795206, mload(0x1600), f_q)) -mstore(0x59c0, mulmod(mload(0x59a0), 1, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x59a0), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x59c0)), f_q), result, f_q) -mstore(23008, result) - } -mstore(0x5a00, mulmod(7521631813486699681549447421085572414068158796105686593554181156957026089108, mload(0x1600), f_q)) -mstore(0x5a20, mulmod(mload(0x5a00), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x5a00), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5a20)), f_q), result, f_q) -mstore(23104, result) - } -mstore(0x5a60, mulmod(17271195128855212178510154473373610729639201669583744426527435765917537447443, mload(0x1600), f_q)) -mstore(0x5a80, mulmod(mload(0x5a60), 4506835738822104338668100540817374747935106310012997856968187171738630203507, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x5a60), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5a80)), f_q), result, f_q) -mstore(23200, result) - } -mstore(0x5ac0, mulmod(mload(0x5920), mload(0x5620), f_q)) -mstore(0x5ae0, mulmod(13513867906530865119835332133273263211836799082674232843258448413103731898271, mload(0xee0), f_q)) -mstore(0x5b00, mulmod(mload(0x5ae0), 1, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x5ae0), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5b00)), f_q), result, f_q) -mstore(23328, result) - } -mstore(0x5b40, mulmod(8374374965308410102411073611984011876711565317741801500439755773472076597346, mload(0xee0), f_q)) -mstore(0x5b60, mulmod(mload(0x5b40), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x5b40), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5b60)), f_q), result, f_q) -mstore(23424, result) - } -mstore(0x5ba0, mulmod(12146688980418810893951125255607130521645347193942732958664170801695864621271, mload(0xee0), f_q)) -mstore(0x5bc0, mulmod(mload(0x5ba0), 1, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x5ba0), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5bc0)), f_q), result, f_q) -mstore(23520, result) - } -mstore(0x5c00, mulmod(9741553891420464328295280489650144566903017206473301385034033384879943874346, mload(0xee0), f_q)) -mstore(0x5c20, mulmod(mload(0x5c00), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q)) -{ - let result := mulmod(mload(0x1500), mload(0x5c00), f_q) -result := addmod(mulmod(mload(0xee0), sub(f_q, mload(0x5c20)), f_q), result, f_q) -mstore(23616, result) - } -mstore(0x5c60, mulmod(mload(0x5900), mload(0x5660), f_q)) -{ - let prod := mload(0x57c0) - - prod := mulmod(mload(0x5820), prod, f_q) - mstore(0x5c80, prod) - - prod := mulmod(mload(0x5880), prod, f_q) - mstore(0x5ca0, prod) - - prod := mulmod(mload(0x58e0), prod, f_q) - mstore(0x5cc0, prod) - - prod := mulmod(mload(0x5980), prod, f_q) - mstore(0x5ce0, prod) - - prod := mulmod(mload(0x5900), prod, f_q) - mstore(0x5d00, prod) - - prod := mulmod(mload(0x59e0), prod, f_q) - mstore(0x5d20, prod) - - prod := mulmod(mload(0x5a40), prod, f_q) - mstore(0x5d40, prod) - - prod := mulmod(mload(0x5aa0), prod, f_q) - mstore(0x5d60, prod) - - prod := mulmod(mload(0x5ac0), prod, f_q) - mstore(0x5d80, prod) - - prod := mulmod(mload(0x5b20), prod, f_q) - mstore(0x5da0, prod) - - prod := mulmod(mload(0x5b80), prod, f_q) - mstore(0x5dc0, prod) - - prod := mulmod(mload(0x5920), prod, f_q) - mstore(0x5de0, prod) - - prod := mulmod(mload(0x5be0), prod, f_q) - mstore(0x5e00, prod) - - prod := mulmod(mload(0x5c40), prod, f_q) - mstore(0x5e20, prod) - - prod := mulmod(mload(0x5c60), prod, f_q) - mstore(0x5e40, prod) - - } -mstore(0x5e80, 32) -mstore(0x5ea0, 32) -mstore(0x5ec0, 32) -mstore(0x5ee0, mload(0x5e40)) -mstore(0x5f00, 21888242871839275222246405745257275088548364400416034343698204186575808495615) -mstore(0x5f20, 21888242871839275222246405745257275088548364400416034343698204186575808495617) -success := and(eq(staticcall(gas(), 0x5, 0x5e80, 0xc0, 0x5e60, 0x20), 1), success) -{ - - let inv := mload(0x5e60) - let v - - v := mload(0x5c60) - mstore(23648, mulmod(mload(0x5e20), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5c40) - mstore(23616, mulmod(mload(0x5e00), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5be0) - mstore(23520, mulmod(mload(0x5de0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5920) - mstore(22816, mulmod(mload(0x5dc0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5b80) - mstore(23424, mulmod(mload(0x5da0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5b20) - mstore(23328, mulmod(mload(0x5d80), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5ac0) - mstore(23232, mulmod(mload(0x5d60), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5aa0) - mstore(23200, mulmod(mload(0x5d40), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5a40) - mstore(23104, mulmod(mload(0x5d20), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x59e0) - mstore(23008, mulmod(mload(0x5d00), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5900) - mstore(22784, mulmod(mload(0x5ce0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5980) - mstore(22912, mulmod(mload(0x5cc0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x58e0) - mstore(22752, mulmod(mload(0x5ca0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5880) - mstore(22656, mulmod(mload(0x5c80), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5820) - mstore(22560, mulmod(mload(0x57c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - mstore(0x57c0, inv) - - } -{ - let result := mload(0x57c0) -result := addmod(mload(0x5820), result, f_q) -result := addmod(mload(0x5880), result, f_q) -result := addmod(mload(0x58e0), result, f_q) -mstore(24384, result) - } -mstore(0x5f60, mulmod(mload(0x5960), mload(0x5900), f_q)) -{ - let result := mload(0x5980) -mstore(24448, result) - } -mstore(0x5fa0, mulmod(mload(0x5960), mload(0x5ac0), f_q)) -{ - let result := mload(0x59e0) -result := addmod(mload(0x5a40), result, f_q) -result := addmod(mload(0x5aa0), result, f_q) -mstore(24512, result) - } -mstore(0x5fe0, mulmod(mload(0x5960), mload(0x5920), f_q)) -{ - let result := mload(0x5b20) -result := addmod(mload(0x5b80), result, f_q) -mstore(24576, result) - } -mstore(0x6020, mulmod(mload(0x5960), mload(0x5c60), f_q)) -{ - let result := mload(0x5be0) -result := addmod(mload(0x5c40), result, f_q) -mstore(24640, result) - } -{ - let prod := mload(0x5f40) - - prod := mulmod(mload(0x5f80), prod, f_q) - mstore(0x6060, prod) - - prod := mulmod(mload(0x5fc0), prod, f_q) - mstore(0x6080, prod) - - prod := mulmod(mload(0x6000), prod, f_q) - mstore(0x60a0, prod) - - prod := mulmod(mload(0x6040), prod, f_q) - mstore(0x60c0, prod) - - } -mstore(0x6100, 32) -mstore(0x6120, 32) -mstore(0x6140, 32) -mstore(0x6160, mload(0x60c0)) -mstore(0x6180, 21888242871839275222246405745257275088548364400416034343698204186575808495615) -mstore(0x61a0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) -success := and(eq(staticcall(gas(), 0x5, 0x6100, 0xc0, 0x60e0, 0x20), 1), success) -{ - - let inv := mload(0x60e0) - let v - - v := mload(0x6040) - mstore(24640, mulmod(mload(0x60a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x6000) - mstore(24576, mulmod(mload(0x6080), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5fc0) - mstore(24512, mulmod(mload(0x6060), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x5f80) - mstore(24448, mulmod(mload(0x5f40), inv, f_q)) - inv := mulmod(v, inv, f_q) - mstore(0x5f40, inv) - - } -mstore(0x61c0, mulmod(mload(0x5f60), mload(0x5f80), f_q)) -mstore(0x61e0, mulmod(mload(0x5fa0), mload(0x5fc0), f_q)) -mstore(0x6200, mulmod(mload(0x5fe0), mload(0x6000), f_q)) -mstore(0x6220, mulmod(mload(0x6020), mload(0x6040), f_q)) -mstore(0x6240, mulmod(mload(0x1400), mload(0x1400), f_q)) -mstore(0x6260, mulmod(mload(0x6240), mload(0x1400), f_q)) -mstore(0x6280, mulmod(mload(0x6260), mload(0x1400), f_q)) -mstore(0x62a0, mulmod(mload(0x6280), mload(0x1400), f_q)) -mstore(0x62c0, mulmod(mload(0x62a0), mload(0x1400), f_q)) -mstore(0x62e0, mulmod(mload(0x62c0), mload(0x1400), f_q)) -mstore(0x6300, mulmod(mload(0x62e0), mload(0x1400), f_q)) -mstore(0x6320, mulmod(mload(0x6300), mload(0x1400), f_q)) -mstore(0x6340, mulmod(mload(0x6320), mload(0x1400), f_q)) -mstore(0x6360, mulmod(mload(0x6340), mload(0x1400), f_q)) -mstore(0x6380, mulmod(mload(0x6360), mload(0x1400), f_q)) -mstore(0x63a0, mulmod(mload(0x6380), mload(0x1400), f_q)) -mstore(0x63c0, mulmod(mload(0x63a0), mload(0x1400), f_q)) -mstore(0x63e0, mulmod(mload(0x63c0), mload(0x1400), f_q)) -mstore(0x6400, mulmod(mload(0x1460), mload(0x1460), f_q)) -mstore(0x6420, mulmod(mload(0x6400), mload(0x1460), f_q)) -mstore(0x6440, mulmod(mload(0x6420), mload(0x1460), f_q)) -mstore(0x6460, mulmod(mload(0x6440), mload(0x1460), f_q)) -{ - let result := mulmod(mload(0xf20), mload(0x57c0), f_q) -result := addmod(mulmod(mload(0xf40), mload(0x5820), f_q), result, f_q) -result := addmod(mulmod(mload(0xf60), mload(0x5880), f_q), result, f_q) -result := addmod(mulmod(mload(0xf80), mload(0x58e0), f_q), result, f_q) -mstore(25728, result) - } -mstore(0x64a0, mulmod(mload(0x6480), mload(0x5f40), f_q)) -mstore(0x64c0, mulmod(sub(f_q, mload(0x64a0)), 1, f_q)) -{ - let result := mulmod(mload(0xfa0), mload(0x57c0), f_q) -result := addmod(mulmod(mload(0xfc0), mload(0x5820), f_q), result, f_q) -result := addmod(mulmod(mload(0xfe0), mload(0x5880), f_q), result, f_q) -result := addmod(mulmod(mload(0x1000), mload(0x58e0), f_q), result, f_q) -mstore(25824, result) - } -mstore(0x6500, mulmod(mload(0x64e0), mload(0x5f40), f_q)) -mstore(0x6520, mulmod(sub(f_q, mload(0x6500)), mload(0x1400), f_q)) -mstore(0x6540, mulmod(1, mload(0x1400), f_q)) -mstore(0x6560, addmod(mload(0x64c0), mload(0x6520), f_q)) -{ - let result := mulmod(mload(0x1020), mload(0x57c0), f_q) -result := addmod(mulmod(mload(0x1040), mload(0x5820), f_q), result, f_q) -result := addmod(mulmod(mload(0x1060), mload(0x5880), f_q), result, f_q) -result := addmod(mulmod(mload(0x1080), mload(0x58e0), f_q), result, f_q) -mstore(25984, result) - } -mstore(0x65a0, mulmod(mload(0x6580), mload(0x5f40), f_q)) -mstore(0x65c0, mulmod(sub(f_q, mload(0x65a0)), mload(0x6240), f_q)) -mstore(0x65e0, mulmod(1, mload(0x6240), f_q)) -mstore(0x6600, addmod(mload(0x6560), mload(0x65c0), f_q)) -mstore(0x6620, mulmod(mload(0x6600), 1, f_q)) -mstore(0x6640, mulmod(mload(0x6540), 1, f_q)) -mstore(0x6660, mulmod(mload(0x65e0), 1, f_q)) -mstore(0x6680, mulmod(1, mload(0x5f60), f_q)) -{ - let result := mulmod(mload(0x10a0), mload(0x5980), f_q) -mstore(26272, result) - } -mstore(0x66c0, mulmod(mload(0x66a0), mload(0x61c0), f_q)) -mstore(0x66e0, mulmod(sub(f_q, mload(0x66c0)), 1, f_q)) -mstore(0x6700, mulmod(mload(0x6680), 1, f_q)) -{ - let result := mulmod(mload(0x13c0), mload(0x5980), f_q) -mstore(26400, result) - } -mstore(0x6740, mulmod(mload(0x6720), mload(0x61c0), f_q)) -mstore(0x6760, mulmod(sub(f_q, mload(0x6740)), mload(0x1400), f_q)) -mstore(0x6780, mulmod(mload(0x6680), mload(0x1400), f_q)) -mstore(0x67a0, addmod(mload(0x66e0), mload(0x6760), f_q)) -{ - let result := mulmod(mload(0x10c0), mload(0x5980), f_q) -mstore(26560, result) - } -mstore(0x67e0, mulmod(mload(0x67c0), mload(0x61c0), f_q)) -mstore(0x6800, mulmod(sub(f_q, mload(0x67e0)), mload(0x6240), f_q)) -mstore(0x6820, mulmod(mload(0x6680), mload(0x6240), f_q)) -mstore(0x6840, addmod(mload(0x67a0), mload(0x6800), f_q)) -{ - let result := mulmod(mload(0x10e0), mload(0x5980), f_q) -mstore(26720, result) - } -mstore(0x6880, mulmod(mload(0x6860), mload(0x61c0), f_q)) -mstore(0x68a0, mulmod(sub(f_q, mload(0x6880)), mload(0x6260), f_q)) -mstore(0x68c0, mulmod(mload(0x6680), mload(0x6260), f_q)) -mstore(0x68e0, addmod(mload(0x6840), mload(0x68a0), f_q)) -{ - let result := mulmod(mload(0x1100), mload(0x5980), f_q) -mstore(26880, result) - } -mstore(0x6920, mulmod(mload(0x6900), mload(0x61c0), f_q)) -mstore(0x6940, mulmod(sub(f_q, mload(0x6920)), mload(0x6280), f_q)) -mstore(0x6960, mulmod(mload(0x6680), mload(0x6280), f_q)) -mstore(0x6980, addmod(mload(0x68e0), mload(0x6940), f_q)) -{ - let result := mulmod(mload(0x1120), mload(0x5980), f_q) -mstore(27040, result) - } -mstore(0x69c0, mulmod(mload(0x69a0), mload(0x61c0), f_q)) -mstore(0x69e0, mulmod(sub(f_q, mload(0x69c0)), mload(0x62a0), f_q)) -mstore(0x6a00, mulmod(mload(0x6680), mload(0x62a0), f_q)) -mstore(0x6a20, addmod(mload(0x6980), mload(0x69e0), f_q)) -{ - let result := mulmod(mload(0x1140), mload(0x5980), f_q) -mstore(27200, result) - } -mstore(0x6a60, mulmod(mload(0x6a40), mload(0x61c0), f_q)) -mstore(0x6a80, mulmod(sub(f_q, mload(0x6a60)), mload(0x62c0), f_q)) -mstore(0x6aa0, mulmod(mload(0x6680), mload(0x62c0), f_q)) -mstore(0x6ac0, addmod(mload(0x6a20), mload(0x6a80), f_q)) -{ - let result := mulmod(mload(0x1180), mload(0x5980), f_q) -mstore(27360, result) - } -mstore(0x6b00, mulmod(mload(0x6ae0), mload(0x61c0), f_q)) -mstore(0x6b20, mulmod(sub(f_q, mload(0x6b00)), mload(0x62e0), f_q)) -mstore(0x6b40, mulmod(mload(0x6680), mload(0x62e0), f_q)) -mstore(0x6b60, addmod(mload(0x6ac0), mload(0x6b20), f_q)) -{ - let result := mulmod(mload(0x11a0), mload(0x5980), f_q) -mstore(27520, result) - } -mstore(0x6ba0, mulmod(mload(0x6b80), mload(0x61c0), f_q)) -mstore(0x6bc0, mulmod(sub(f_q, mload(0x6ba0)), mload(0x6300), f_q)) -mstore(0x6be0, mulmod(mload(0x6680), mload(0x6300), f_q)) -mstore(0x6c00, addmod(mload(0x6b60), mload(0x6bc0), f_q)) -{ - let result := mulmod(mload(0x11c0), mload(0x5980), f_q) -mstore(27680, result) - } -mstore(0x6c40, mulmod(mload(0x6c20), mload(0x61c0), f_q)) -mstore(0x6c60, mulmod(sub(f_q, mload(0x6c40)), mload(0x6320), f_q)) -mstore(0x6c80, mulmod(mload(0x6680), mload(0x6320), f_q)) -mstore(0x6ca0, addmod(mload(0x6c00), mload(0x6c60), f_q)) -{ - let result := mulmod(mload(0x11e0), mload(0x5980), f_q) -mstore(27840, result) - } -mstore(0x6ce0, mulmod(mload(0x6cc0), mload(0x61c0), f_q)) -mstore(0x6d00, mulmod(sub(f_q, mload(0x6ce0)), mload(0x6340), f_q)) -mstore(0x6d20, mulmod(mload(0x6680), mload(0x6340), f_q)) -mstore(0x6d40, addmod(mload(0x6ca0), mload(0x6d00), f_q)) -{ - let result := mulmod(mload(0x1200), mload(0x5980), f_q) -mstore(28000, result) - } -mstore(0x6d80, mulmod(mload(0x6d60), mload(0x61c0), f_q)) -mstore(0x6da0, mulmod(sub(f_q, mload(0x6d80)), mload(0x6360), f_q)) -mstore(0x6dc0, mulmod(mload(0x6680), mload(0x6360), f_q)) -mstore(0x6de0, addmod(mload(0x6d40), mload(0x6da0), f_q)) -{ - let result := mulmod(mload(0x1220), mload(0x5980), f_q) -mstore(28160, result) - } -mstore(0x6e20, mulmod(mload(0x6e00), mload(0x61c0), f_q)) -mstore(0x6e40, mulmod(sub(f_q, mload(0x6e20)), mload(0x6380), f_q)) -mstore(0x6e60, mulmod(mload(0x6680), mload(0x6380), f_q)) -mstore(0x6e80, addmod(mload(0x6de0), mload(0x6e40), f_q)) -mstore(0x6ea0, mulmod(mload(0x5560), mload(0x5f60), f_q)) -mstore(0x6ec0, mulmod(mload(0x5580), mload(0x5f60), f_q)) -{ - let result := mulmod(mload(0x55a0), mload(0x5980), f_q) -mstore(28384, result) - } -mstore(0x6f00, mulmod(mload(0x6ee0), mload(0x61c0), f_q)) -mstore(0x6f20, mulmod(sub(f_q, mload(0x6f00)), mload(0x63a0), f_q)) -mstore(0x6f40, mulmod(mload(0x6680), mload(0x63a0), f_q)) -mstore(0x6f60, mulmod(mload(0x6ea0), mload(0x63a0), f_q)) -mstore(0x6f80, mulmod(mload(0x6ec0), mload(0x63a0), f_q)) -mstore(0x6fa0, addmod(mload(0x6e80), mload(0x6f20), f_q)) -{ - let result := mulmod(mload(0x1160), mload(0x5980), f_q) -mstore(28608, result) - } -mstore(0x6fe0, mulmod(mload(0x6fc0), mload(0x61c0), f_q)) -mstore(0x7000, mulmod(sub(f_q, mload(0x6fe0)), mload(0x63c0), f_q)) -mstore(0x7020, mulmod(mload(0x6680), mload(0x63c0), f_q)) -mstore(0x7040, addmod(mload(0x6fa0), mload(0x7000), f_q)) -mstore(0x7060, mulmod(mload(0x7040), mload(0x1460), f_q)) -mstore(0x7080, mulmod(mload(0x6700), mload(0x1460), f_q)) -mstore(0x70a0, mulmod(mload(0x6780), mload(0x1460), f_q)) -mstore(0x70c0, mulmod(mload(0x6820), mload(0x1460), f_q)) -mstore(0x70e0, mulmod(mload(0x68c0), mload(0x1460), f_q)) -mstore(0x7100, mulmod(mload(0x6960), mload(0x1460), f_q)) -mstore(0x7120, mulmod(mload(0x6a00), mload(0x1460), f_q)) -mstore(0x7140, mulmod(mload(0x6aa0), mload(0x1460), f_q)) -mstore(0x7160, mulmod(mload(0x6b40), mload(0x1460), f_q)) -mstore(0x7180, mulmod(mload(0x6be0), mload(0x1460), f_q)) -mstore(0x71a0, mulmod(mload(0x6c80), mload(0x1460), f_q)) -mstore(0x71c0, mulmod(mload(0x6d20), mload(0x1460), f_q)) -mstore(0x71e0, mulmod(mload(0x6dc0), mload(0x1460), f_q)) -mstore(0x7200, mulmod(mload(0x6e60), mload(0x1460), f_q)) -mstore(0x7220, mulmod(mload(0x6f40), mload(0x1460), f_q)) -mstore(0x7240, mulmod(mload(0x6f60), mload(0x1460), f_q)) -mstore(0x7260, mulmod(mload(0x6f80), mload(0x1460), f_q)) -mstore(0x7280, mulmod(mload(0x7020), mload(0x1460), f_q)) -mstore(0x72a0, addmod(mload(0x6620), mload(0x7060), f_q)) -mstore(0x72c0, mulmod(1, mload(0x5fa0), f_q)) -{ - let result := mulmod(mload(0x1240), mload(0x59e0), f_q) -result := addmod(mulmod(mload(0x1260), mload(0x5a40), f_q), result, f_q) -result := addmod(mulmod(mload(0x1280), mload(0x5aa0), f_q), result, f_q) -mstore(29408, result) - } -mstore(0x7300, mulmod(mload(0x72e0), mload(0x61e0), f_q)) -mstore(0x7320, mulmod(sub(f_q, mload(0x7300)), 1, f_q)) -mstore(0x7340, mulmod(mload(0x72c0), 1, f_q)) -{ - let result := mulmod(mload(0x12a0), mload(0x59e0), f_q) -result := addmod(mulmod(mload(0x12c0), mload(0x5a40), f_q), result, f_q) -result := addmod(mulmod(mload(0x12e0), mload(0x5aa0), f_q), result, f_q) -mstore(29536, result) - } -mstore(0x7380, mulmod(mload(0x7360), mload(0x61e0), f_q)) -mstore(0x73a0, mulmod(sub(f_q, mload(0x7380)), mload(0x1400), f_q)) -mstore(0x73c0, mulmod(mload(0x72c0), mload(0x1400), f_q)) -mstore(0x73e0, addmod(mload(0x7320), mload(0x73a0), f_q)) -mstore(0x7400, mulmod(mload(0x73e0), mload(0x6400), f_q)) -mstore(0x7420, mulmod(mload(0x7340), mload(0x6400), f_q)) -mstore(0x7440, mulmod(mload(0x73c0), mload(0x6400), f_q)) -mstore(0x7460, addmod(mload(0x72a0), mload(0x7400), f_q)) -mstore(0x7480, mulmod(1, mload(0x5fe0), f_q)) -{ - let result := mulmod(mload(0x1300), mload(0x5b20), f_q) -result := addmod(mulmod(mload(0x1320), mload(0x5b80), f_q), result, f_q) -mstore(29856, result) - } -mstore(0x74c0, mulmod(mload(0x74a0), mload(0x6200), f_q)) -mstore(0x74e0, mulmod(sub(f_q, mload(0x74c0)), 1, f_q)) -mstore(0x7500, mulmod(mload(0x7480), 1, f_q)) -{ - let result := mulmod(mload(0x1340), mload(0x5b20), f_q) -result := addmod(mulmod(mload(0x1360), mload(0x5b80), f_q), result, f_q) -mstore(29984, result) - } -mstore(0x7540, mulmod(mload(0x7520), mload(0x6200), f_q)) -mstore(0x7560, mulmod(sub(f_q, mload(0x7540)), mload(0x1400), f_q)) -mstore(0x7580, mulmod(mload(0x7480), mload(0x1400), f_q)) -mstore(0x75a0, addmod(mload(0x74e0), mload(0x7560), f_q)) -mstore(0x75c0, mulmod(mload(0x75a0), mload(0x6420), f_q)) -mstore(0x75e0, mulmod(mload(0x7500), mload(0x6420), f_q)) -mstore(0x7600, mulmod(mload(0x7580), mload(0x6420), f_q)) -mstore(0x7620, addmod(mload(0x7460), mload(0x75c0), f_q)) -mstore(0x7640, mulmod(1, mload(0x6020), f_q)) -{ - let result := mulmod(mload(0x1380), mload(0x5be0), f_q) -result := addmod(mulmod(mload(0x13a0), mload(0x5c40), f_q), result, f_q) -mstore(30304, result) - } -mstore(0x7680, mulmod(mload(0x7660), mload(0x6220), f_q)) -mstore(0x76a0, mulmod(sub(f_q, mload(0x7680)), 1, f_q)) -mstore(0x76c0, mulmod(mload(0x7640), 1, f_q)) -mstore(0x76e0, mulmod(mload(0x76a0), mload(0x6440), f_q)) -mstore(0x7700, mulmod(mload(0x76c0), mload(0x6440), f_q)) -mstore(0x7720, addmod(mload(0x7620), mload(0x76e0), f_q)) -mstore(0x7740, mulmod(1, mload(0x5960), f_q)) -mstore(0x7760, mulmod(1, mload(0x1500), f_q)) -mstore(0x7780, 0x0000000000000000000000000000000000000000000000000000000000000001) - mstore(0x77a0, 0x0000000000000000000000000000000000000000000000000000000000000002) -mstore(0x77c0, mload(0x7720)) -success := and(eq(staticcall(gas(), 0x7, 0x7780, 0x60, 0x7780, 0x40), 1), success) -mstore(0x77e0, mload(0x7780)) - mstore(0x7800, mload(0x77a0)) -mstore(0x7820, mload(0x9c0)) - mstore(0x7840, mload(0x9e0)) -success := and(eq(staticcall(gas(), 0x6, 0x77e0, 0x80, 0x77e0, 0x40), 1), success) -mstore(0x7860, mload(0xa00)) - mstore(0x7880, mload(0xa20)) -mstore(0x78a0, mload(0x6640)) -success := and(eq(staticcall(gas(), 0x7, 0x7860, 0x60, 0x7860, 0x40), 1), success) -mstore(0x78c0, mload(0x77e0)) - mstore(0x78e0, mload(0x7800)) -mstore(0x7900, mload(0x7860)) - mstore(0x7920, mload(0x7880)) -success := and(eq(staticcall(gas(), 0x6, 0x78c0, 0x80, 0x78c0, 0x40), 1), success) -mstore(0x7940, mload(0xa40)) - mstore(0x7960, mload(0xa60)) -mstore(0x7980, mload(0x6660)) -success := and(eq(staticcall(gas(), 0x7, 0x7940, 0x60, 0x7940, 0x40), 1), success) -mstore(0x79a0, mload(0x78c0)) - mstore(0x79c0, mload(0x78e0)) -mstore(0x79e0, mload(0x7940)) - mstore(0x7a00, mload(0x7960)) -success := and(eq(staticcall(gas(), 0x6, 0x79a0, 0x80, 0x79a0, 0x40), 1), success) -mstore(0x7a20, mload(0xa80)) - mstore(0x7a40, mload(0xaa0)) -mstore(0x7a60, mload(0x7080)) -success := and(eq(staticcall(gas(), 0x7, 0x7a20, 0x60, 0x7a20, 0x40), 1), success) -mstore(0x7a80, mload(0x79a0)) - mstore(0x7aa0, mload(0x79c0)) -mstore(0x7ac0, mload(0x7a20)) - mstore(0x7ae0, mload(0x7a40)) -success := and(eq(staticcall(gas(), 0x6, 0x7a80, 0x80, 0x7a80, 0x40), 1), success) -mstore(0x7b00, mload(0xb60)) - mstore(0x7b20, mload(0xb80)) -mstore(0x7b40, mload(0x70a0)) -success := and(eq(staticcall(gas(), 0x7, 0x7b00, 0x60, 0x7b00, 0x40), 1), success) -mstore(0x7b60, mload(0x7a80)) - mstore(0x7b80, mload(0x7aa0)) -mstore(0x7ba0, mload(0x7b00)) - mstore(0x7bc0, mload(0x7b20)) -success := and(eq(staticcall(gas(), 0x6, 0x7b60, 0x80, 0x7b60, 0x40), 1), success) -mstore(0x7be0, 0x02529801904a042ae2e6e0506500939e3e1aae9d8453ca1bc9bdce0e042177e8) - mstore(0x7c00, 0x1c02cafbb17f01639588c4d0380b473fdf417c437b30b6d0b3b5ca0092024766) -mstore(0x7c20, mload(0x70c0)) -success := and(eq(staticcall(gas(), 0x7, 0x7be0, 0x60, 0x7be0, 0x40), 1), success) -mstore(0x7c40, mload(0x7b60)) - mstore(0x7c60, mload(0x7b80)) -mstore(0x7c80, mload(0x7be0)) - mstore(0x7ca0, mload(0x7c00)) -success := and(eq(staticcall(gas(), 0x6, 0x7c40, 0x80, 0x7c40, 0x40), 1), success) -mstore(0x7cc0, 0x03fab5527cc07125117069ef9aaa8d159cbacf20f5a795fb9e9279d3a330df37) - mstore(0x7ce0, 0x0c79716bdab8b8e9064cf0e18fa6ea148b3c2c347d8af670deaab48124f25c19) -mstore(0x7d00, mload(0x70e0)) -success := and(eq(staticcall(gas(), 0x7, 0x7cc0, 0x60, 0x7cc0, 0x40), 1), success) -mstore(0x7d20, mload(0x7c40)) - mstore(0x7d40, mload(0x7c60)) -mstore(0x7d60, mload(0x7cc0)) - mstore(0x7d80, mload(0x7ce0)) -success := and(eq(staticcall(gas(), 0x6, 0x7d20, 0x80, 0x7d20, 0x40), 1), success) -mstore(0x7da0, 0x104921367752748430ed7cd30ff25d3c197ab4c7b8848e6e19c7fffdceaf2952) - mstore(0x7dc0, 0x1768e69d499e4b0b78195ba8650460be7853032e4422619ff3a71866d73e3f61) -mstore(0x7de0, mload(0x7100)) -success := and(eq(staticcall(gas(), 0x7, 0x7da0, 0x60, 0x7da0, 0x40), 1), success) -mstore(0x7e00, mload(0x7d20)) - mstore(0x7e20, mload(0x7d40)) -mstore(0x7e40, mload(0x7da0)) - mstore(0x7e60, mload(0x7dc0)) -success := and(eq(staticcall(gas(), 0x6, 0x7e00, 0x80, 0x7e00, 0x40), 1), success) -mstore(0x7e80, 0x20e969dfec5b4b2628746eaa13552f4da062c8b77aa7f7491ec4ea67ccd06cd8) - mstore(0x7ea0, 0x115c896126f1785878e65c2fa009b4b7eb68db9ec213bcf540489ae74149e2d1) -mstore(0x7ec0, mload(0x7120)) -success := and(eq(staticcall(gas(), 0x7, 0x7e80, 0x60, 0x7e80, 0x40), 1), success) -mstore(0x7ee0, mload(0x7e00)) - mstore(0x7f00, mload(0x7e20)) -mstore(0x7f20, mload(0x7e80)) - mstore(0x7f40, mload(0x7ea0)) -success := and(eq(staticcall(gas(), 0x6, 0x7ee0, 0x80, 0x7ee0, 0x40), 1), success) -mstore(0x7f60, 0x1b1b120eef75878fc4d88fcf5c2a8d27c0e3ff3d48074680849ac386cdac4852) - mstore(0x7f80, 0x268bd68c8051137a1398d395dce4c5d081eb3d275083a2f5d9e1fd8130b564ee) -mstore(0x7fa0, mload(0x7140)) -success := and(eq(staticcall(gas(), 0x7, 0x7f60, 0x60, 0x7f60, 0x40), 1), success) -mstore(0x7fc0, mload(0x7ee0)) - mstore(0x7fe0, mload(0x7f00)) -mstore(0x8000, mload(0x7f60)) - mstore(0x8020, mload(0x7f80)) -success := and(eq(staticcall(gas(), 0x6, 0x7fc0, 0x80, 0x7fc0, 0x40), 1), success) -mstore(0x8040, 0x1963f0599c52648a352eb510c753e922e542763dff76fbb32d098cc201b5a2fc) - mstore(0x8060, 0x29efcbd2af6d9fafc14fc334c92d163d316b6f2497423ba2ef7fb3efc4dda0db) -mstore(0x8080, mload(0x7160)) -success := and(eq(staticcall(gas(), 0x7, 0x8040, 0x60, 0x8040, 0x40), 1), success) -mstore(0x80a0, mload(0x7fc0)) - mstore(0x80c0, mload(0x7fe0)) -mstore(0x80e0, mload(0x8040)) - mstore(0x8100, mload(0x8060)) -success := and(eq(staticcall(gas(), 0x6, 0x80a0, 0x80, 0x80a0, 0x40), 1), success) -mstore(0x8120, 0x141d9b72ee15b4c295f928013de035a1c66ee026065deb2c03b2f50fa518a899) - mstore(0x8140, 0x2742eeb55603d0a1075bd00ce29a56dea927181ef4ffbff4a796e6452712d1c8) -mstore(0x8160, mload(0x7180)) -success := and(eq(staticcall(gas(), 0x7, 0x8120, 0x60, 0x8120, 0x40), 1), success) -mstore(0x8180, mload(0x80a0)) - mstore(0x81a0, mload(0x80c0)) -mstore(0x81c0, mload(0x8120)) - mstore(0x81e0, mload(0x8140)) -success := and(eq(staticcall(gas(), 0x6, 0x8180, 0x80, 0x8180, 0x40), 1), success) -mstore(0x8200, 0x2ca225b95e6bf7dea6c1da59fa8f219e4557d81829867d068edd92a512bab196) - mstore(0x8220, 0x02028e28c6bf82bc05fda0808b71b4e7b4f643a6c90bd9422eb2c7308c74f333) -mstore(0x8240, mload(0x71a0)) -success := and(eq(staticcall(gas(), 0x7, 0x8200, 0x60, 0x8200, 0x40), 1), success) -mstore(0x8260, mload(0x8180)) - mstore(0x8280, mload(0x81a0)) -mstore(0x82a0, mload(0x8200)) - mstore(0x82c0, mload(0x8220)) -success := and(eq(staticcall(gas(), 0x6, 0x8260, 0x80, 0x8260, 0x40), 1), success) -mstore(0x82e0, 0x04fdb5e1380e5c24b89e18fe8350090448fdff68168f30d895b7ceb66e7c1c72) - mstore(0x8300, 0x0e03ff6f5381c65fa8c8034ecdb70142d944ad2376829c442a96e554892a398b) -mstore(0x8320, mload(0x71c0)) -success := and(eq(staticcall(gas(), 0x7, 0x82e0, 0x60, 0x82e0, 0x40), 1), success) -mstore(0x8340, mload(0x8260)) - mstore(0x8360, mload(0x8280)) -mstore(0x8380, mload(0x82e0)) - mstore(0x83a0, mload(0x8300)) -success := and(eq(staticcall(gas(), 0x6, 0x8340, 0x80, 0x8340, 0x40), 1), success) -mstore(0x83c0, 0x14a4136420fd357c9d8b1b12f0af40965f1b0c6ddab81de11d42f1fe5d117d6e) - mstore(0x83e0, 0x0bdc4c68aa97468b20fe6b873aabf6619d92fe21a3e81a9bdc37d8a95b26e68a) -mstore(0x8400, mload(0x71e0)) -success := and(eq(staticcall(gas(), 0x7, 0x83c0, 0x60, 0x83c0, 0x40), 1), success) -mstore(0x8420, mload(0x8340)) - mstore(0x8440, mload(0x8360)) -mstore(0x8460, mload(0x83c0)) - mstore(0x8480, mload(0x83e0)) -success := and(eq(staticcall(gas(), 0x6, 0x8420, 0x80, 0x8420, 0x40), 1), success) -mstore(0x84a0, 0x0afbba6998967360bca4ed453f798405a0f5da3d9fa13221af670c071183caba) - mstore(0x84c0, 0x0ce036829484cbc26d88591f313ebad4b9ce4a11a6e4712fe96670b5736c955c) -mstore(0x84e0, mload(0x7200)) -success := and(eq(staticcall(gas(), 0x7, 0x84a0, 0x60, 0x84a0, 0x40), 1), success) -mstore(0x8500, mload(0x8420)) - mstore(0x8520, mload(0x8440)) -mstore(0x8540, mload(0x84a0)) - mstore(0x8560, mload(0x84c0)) -success := and(eq(staticcall(gas(), 0x6, 0x8500, 0x80, 0x8500, 0x40), 1), success) -mstore(0x8580, mload(0xe00)) - mstore(0x85a0, mload(0xe20)) -mstore(0x85c0, mload(0x7220)) -success := and(eq(staticcall(gas(), 0x7, 0x8580, 0x60, 0x8580, 0x40), 1), success) -mstore(0x85e0, mload(0x8500)) - mstore(0x8600, mload(0x8520)) -mstore(0x8620, mload(0x8580)) - mstore(0x8640, mload(0x85a0)) -success := and(eq(staticcall(gas(), 0x6, 0x85e0, 0x80, 0x85e0, 0x40), 1), success) -mstore(0x8660, mload(0xe40)) - mstore(0x8680, mload(0xe60)) -mstore(0x86a0, mload(0x7240)) -success := and(eq(staticcall(gas(), 0x7, 0x8660, 0x60, 0x8660, 0x40), 1), success) -mstore(0x86c0, mload(0x85e0)) - mstore(0x86e0, mload(0x8600)) -mstore(0x8700, mload(0x8660)) - mstore(0x8720, mload(0x8680)) -success := and(eq(staticcall(gas(), 0x6, 0x86c0, 0x80, 0x86c0, 0x40), 1), success) -mstore(0x8740, mload(0xe80)) - mstore(0x8760, mload(0xea0)) -mstore(0x8780, mload(0x7260)) -success := and(eq(staticcall(gas(), 0x7, 0x8740, 0x60, 0x8740, 0x40), 1), success) -mstore(0x87a0, mload(0x86c0)) - mstore(0x87c0, mload(0x86e0)) -mstore(0x87e0, mload(0x8740)) - mstore(0x8800, mload(0x8760)) -success := and(eq(staticcall(gas(), 0x6, 0x87a0, 0x80, 0x87a0, 0x40), 1), success) -mstore(0x8820, mload(0xd60)) - mstore(0x8840, mload(0xd80)) -mstore(0x8860, mload(0x7280)) -success := and(eq(staticcall(gas(), 0x7, 0x8820, 0x60, 0x8820, 0x40), 1), success) -mstore(0x8880, mload(0x87a0)) - mstore(0x88a0, mload(0x87c0)) -mstore(0x88c0, mload(0x8820)) - mstore(0x88e0, mload(0x8840)) -success := and(eq(staticcall(gas(), 0x6, 0x8880, 0x80, 0x8880, 0x40), 1), success) -mstore(0x8900, mload(0xc60)) - mstore(0x8920, mload(0xc80)) -mstore(0x8940, mload(0x7420)) -success := and(eq(staticcall(gas(), 0x7, 0x8900, 0x60, 0x8900, 0x40), 1), success) -mstore(0x8960, mload(0x8880)) - mstore(0x8980, mload(0x88a0)) -mstore(0x89a0, mload(0x8900)) - mstore(0x89c0, mload(0x8920)) -success := and(eq(staticcall(gas(), 0x6, 0x8960, 0x80, 0x8960, 0x40), 1), success) -mstore(0x89e0, mload(0xca0)) - mstore(0x8a00, mload(0xcc0)) -mstore(0x8a20, mload(0x7440)) -success := and(eq(staticcall(gas(), 0x7, 0x89e0, 0x60, 0x89e0, 0x40), 1), success) -mstore(0x8a40, mload(0x8960)) - mstore(0x8a60, mload(0x8980)) -mstore(0x8a80, mload(0x89e0)) - mstore(0x8aa0, mload(0x8a00)) -success := and(eq(staticcall(gas(), 0x6, 0x8a40, 0x80, 0x8a40, 0x40), 1), success) -mstore(0x8ac0, mload(0xce0)) - mstore(0x8ae0, mload(0xd00)) -mstore(0x8b00, mload(0x75e0)) -success := and(eq(staticcall(gas(), 0x7, 0x8ac0, 0x60, 0x8ac0, 0x40), 1), success) -mstore(0x8b20, mload(0x8a40)) - mstore(0x8b40, mload(0x8a60)) -mstore(0x8b60, mload(0x8ac0)) - mstore(0x8b80, mload(0x8ae0)) -success := and(eq(staticcall(gas(), 0x6, 0x8b20, 0x80, 0x8b20, 0x40), 1), success) -mstore(0x8ba0, mload(0xd20)) - mstore(0x8bc0, mload(0xd40)) -mstore(0x8be0, mload(0x7600)) -success := and(eq(staticcall(gas(), 0x7, 0x8ba0, 0x60, 0x8ba0, 0x40), 1), success) -mstore(0x8c00, mload(0x8b20)) - mstore(0x8c20, mload(0x8b40)) -mstore(0x8c40, mload(0x8ba0)) - mstore(0x8c60, mload(0x8bc0)) -success := and(eq(staticcall(gas(), 0x6, 0x8c00, 0x80, 0x8c00, 0x40), 1), success) -mstore(0x8c80, mload(0xb20)) - mstore(0x8ca0, mload(0xb40)) -mstore(0x8cc0, mload(0x7700)) -success := and(eq(staticcall(gas(), 0x7, 0x8c80, 0x60, 0x8c80, 0x40), 1), success) -mstore(0x8ce0, mload(0x8c00)) - mstore(0x8d00, mload(0x8c20)) -mstore(0x8d20, mload(0x8c80)) - mstore(0x8d40, mload(0x8ca0)) -success := and(eq(staticcall(gas(), 0x6, 0x8ce0, 0x80, 0x8ce0, 0x40), 1), success) -mstore(0x8d60, mload(0x14a0)) - mstore(0x8d80, mload(0x14c0)) -mstore(0x8da0, sub(f_q, mload(0x7740))) -success := and(eq(staticcall(gas(), 0x7, 0x8d60, 0x60, 0x8d60, 0x40), 1), success) -mstore(0x8dc0, mload(0x8ce0)) - mstore(0x8de0, mload(0x8d00)) -mstore(0x8e00, mload(0x8d60)) - mstore(0x8e20, mload(0x8d80)) -success := and(eq(staticcall(gas(), 0x6, 0x8dc0, 0x80, 0x8dc0, 0x40), 1), success) -mstore(0x8e40, mload(0x1540)) - mstore(0x8e60, mload(0x1560)) -mstore(0x8e80, mload(0x7760)) -success := and(eq(staticcall(gas(), 0x7, 0x8e40, 0x60, 0x8e40, 0x40), 1), success) -mstore(0x8ea0, mload(0x8dc0)) - mstore(0x8ec0, mload(0x8de0)) -mstore(0x8ee0, mload(0x8e40)) - mstore(0x8f00, mload(0x8e60)) -success := and(eq(staticcall(gas(), 0x6, 0x8ea0, 0x80, 0x8ea0, 0x40), 1), success) -mstore(0x8f20, mload(0x8ea0)) - mstore(0x8f40, mload(0x8ec0)) -mstore(0x8f60, mload(0x1540)) - mstore(0x8f80, mload(0x1560)) -mstore(0x8fa0, mload(0x1580)) - mstore(0x8fc0, mload(0x15a0)) -mstore(0x8fe0, mload(0x15c0)) - mstore(0x9000, mload(0x15e0)) -mstore(0x9020, keccak256(0x8f20, 256)) -mstore(36928, mod(mload(36896), f_q)) -mstore(0x9060, mulmod(mload(0x9040), mload(0x9040), f_q)) -mstore(0x9080, mulmod(1, mload(0x9040), f_q)) -mstore(0x90a0, mload(0x8fa0)) - mstore(0x90c0, mload(0x8fc0)) -mstore(0x90e0, mload(0x9080)) -success := and(eq(staticcall(gas(), 0x7, 0x90a0, 0x60, 0x90a0, 0x40), 1), success) -mstore(0x9100, mload(0x8f20)) - mstore(0x9120, mload(0x8f40)) -mstore(0x9140, mload(0x90a0)) - mstore(0x9160, mload(0x90c0)) -success := and(eq(staticcall(gas(), 0x6, 0x9100, 0x80, 0x9100, 0x40), 1), success) -mstore(0x9180, mload(0x8fe0)) - mstore(0x91a0, mload(0x9000)) -mstore(0x91c0, mload(0x9080)) -success := and(eq(staticcall(gas(), 0x7, 0x9180, 0x60, 0x9180, 0x40), 1), success) -mstore(0x91e0, mload(0x8f60)) - mstore(0x9200, mload(0x8f80)) -mstore(0x9220, mload(0x9180)) - mstore(0x9240, mload(0x91a0)) -success := and(eq(staticcall(gas(), 0x6, 0x91e0, 0x80, 0x91e0, 0x40), 1), success) -mstore(0x9260, mload(0x9100)) - mstore(0x9280, mload(0x9120)) -mstore(0x92a0, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) - mstore(0x92c0, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) - mstore(0x92e0, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) - mstore(0x9300, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) -mstore(0x9320, mload(0x91e0)) - mstore(0x9340, mload(0x9200)) -mstore(0x9360, 0x0181624e80f3d6ae28df7e01eaeab1c0e919877a3b8a6b7fbc69a6817d596ea2) - mstore(0x9380, 0x1783d30dcb12d259bb89098addf6280fa4b653be7a152542a28f7b926e27e648) - mstore(0x93a0, 0x00ae44489d41a0d179e2dfdc03bddd883b7109f8b6ae316a59e815c1a6b35304) - mstore(0x93c0, 0x0b2147ab62a386bd63e6de1522109b8c9588ab466f5aadfde8c41ca3749423ee) -success := and(eq(staticcall(gas(), 0x8, 0x9260, 0x180, 0x9260, 0x20), 1), success) -success := and(eq(mload(0x9260), 1), success) - - // Revert if anything fails - if iszero(success) { revert(0, 0) } - - // Return empty bytes on success - return(0, 0) - - } - } -} - \ No newline at end of file diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 3da91b35..558cb40b 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -1,6 +1,6 @@ use crate::{ gadget::crypto::{HashInstructions, Sha256ChipWide, ShaBitGateManager, ShaCircuitBuilder}, - poseidon::{fq_array_poseidon, fq_array_poseidon_native}, + poseidon::{fq_array_poseidon_native, fq_array_poseidon}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, sync_step_circuit::clear_3_bits, util::{AppCircuit, CommonGateManager, Eth2ConfigPinning, IntoWitness}, @@ -9,9 +9,7 @@ use crate::{ }; use eth_types::{Field, Spec, LIMB_BITS, NUM_LIMBS}; use halo2_base::{ - gates::{ - circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, RangeInstructions, - }, + gates::{circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, RangeInstructions}, halo2_proofs::{halo2curves::bn256, plonk::Error}, AssignedValue, Context, QuantumCell, }; @@ -36,11 +34,11 @@ impl CommitteeUpdateCircuit { fn synthesize( builder: &mut ShaCircuitBuilder>, fp_chip: &FpChip, - args: &witness::CommitteeRotationArgs, + args: &witness::CommitteeRotationArgs, ) -> Result>, Error> { let range = fp_chip.range(); - let sha256_chip = Sha256ChipWide::new(range, args.randomness); + let sha256_chip = Sha256ChipWide::new(range); let compressed_encodings = args .pubkeys_compressed @@ -58,49 +56,48 @@ impl CommitteeUpdateCircuit { let committee_root_ssz = Self::sync_committee_root_ssz(builder, &sha256_chip, compressed_encodings.clone())?; - // let poseidon_commit = { - // let pubkeys_x = Self::decode_pubkeys_x(builder.main(), fp_chip, compressed_encodings); - // fq_array_poseidon(builder.main(), range.gate(), &pubkeys_x)? - // }; + let poseidon_commit = { + let pubkeys_x = Self::decode_pubkeys_x(builder.main(), fp_chip, compressed_encodings); + fq_array_poseidon(builder.main(), range.gate(), &pubkeys_x)? + }; // Finalized header - // let finalized_slot_bytes: HashInputChunk<_> = args.finalized_header.slot.into_witness(); - // let finalized_state_root = args - // .finalized_header - // .state_root - // .as_ref() - // .iter() - // .map(|v| builder.main().load_witness(F::from(*v as u64))) - // .collect_vec(); - // let finalized_header_root = ssz_merkleize_chunks( - // builder, - // &sha256_chip, - // [ - // finalized_slot_bytes, - // args.finalized_header.proposer_index.into_witness(), - // args.finalized_header.parent_root.as_ref().into_witness(), - // finalized_state_root.clone().into(), - // args.finalized_header.body_root.as_ref().into_witness(), - // ], - // )?; - // // Verify that the sync committee root is in the finalized state root - // verify_merkle_proof( - // builder, - // &sha256_chip, - // args.sync_committee_branch - // .iter() - // .map(|w| w.clone().into_witness()), - // committee_root_ssz.clone().into(), - // &finalized_state_root, - // S::SYNC_COMMITTEE_PUBKEYS_ROOT_INDEX, - // )?; - - // let public_inputs = iter::once(poseidon_commit) - // .chain(committee_root_ssz) - // .chain(finalized_header_root) - // .collect(); - - let public_inputs = vec![]; + let finalized_slot_bytes: HashInputChunk<_> = args.finalized_header.slot.into_witness(); + let finalized_state_root = args + .finalized_header + .state_root + .as_ref() + .iter() + .map(|v| builder.main().load_witness(F::from(*v as u64))) + .collect_vec(); + let finalized_header_root = ssz_merkleize_chunks( + builder, + &sha256_chip, + [ + finalized_slot_bytes, + args.finalized_header.proposer_index.into_witness(), + args.finalized_header.parent_root.as_ref().into_witness(), + finalized_state_root.clone().into(), + args.finalized_header.body_root.as_ref().into_witness(), + ], + )?; + + // Verify that the sync committee root is in the finalized state root + verify_merkle_proof( + builder, + &sha256_chip, + args.sync_committee_branch + .iter() + .map(|w| w.clone().into_witness()), + committee_root_ssz.clone().into(), + &finalized_state_root, + S::SYNC_COMMITTEE_PUBKEYS_ROOT_INDEX, + )?; + + let public_inputs = iter::once(poseidon_commit) + .chain(committee_root_ssz) + .chain(finalized_header_root) + .collect(); Ok(public_inputs) } @@ -159,7 +156,7 @@ impl CommitteeUpdateCircuit { } pub fn instance( - args: &witness::CommitteeRotationArgs, + args: &witness::CommitteeRotationArgs, limb_bits: usize, ) -> Vec> where @@ -203,12 +200,12 @@ impl CommitteeUpdateCircuit { impl AppCircuit for CommitteeUpdateCircuit { type Pinning = Eth2ConfigPinning; - type Witness = witness::CommitteeRotationArgs; + type Witness = witness::CommitteeRotationArgs; fn create_circuit( stage: CircuitBuilderStage, pinning: Option, - witness: &witness::CommitteeRotationArgs, + witness: &witness::CommitteeRotationArgs, k: u32, ) -> Result, Error> { let mut builder = Eth2CircuitBuilder::>::from_stage(stage) @@ -246,8 +243,8 @@ mod tests { use std::fs; use crate::{ - aggregation::AggregationConfigPinning, gadget::crypto::constant_randomness, - util::Halo2ConfigPinning, witness::CommitteeRotationArgs, + aggregation::AggregationConfigPinning, util::Halo2ConfigPinning, + witness::CommitteeRotationArgs, }; use super::*; @@ -266,7 +263,7 @@ mod tests { use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk}; use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, CircuitExt, Snark}; - fn load_circuit_args() -> CommitteeRotationArgs { + fn load_circuit_args() -> CommitteeRotationArgs { #[derive(serde::Deserialize)] struct ArgsJson { finalized_header: BeaconBlockHeader, @@ -282,7 +279,6 @@ mod tests { CommitteeRotationArgs { pubkeys_compressed, - randomness: constant_randomness(), _spec: PhantomData, finalized_header, sync_committee_branch: committee_root_branch, @@ -292,7 +288,7 @@ mod tests { fn gen_application_snark( params: &ParamsKZG, pk: &ProvingKey, - witness: &CommitteeRotationArgs, + witness: &CommitteeRotationArgs, pinning_path: &str, ) -> Snark { CommitteeUpdateCircuit::::gen_snark_shplonk( @@ -340,7 +336,7 @@ mod tests { PKEY_PATH, PINNING_PATH, false, - &CommitteeRotationArgs::::default(), + &CommitteeRotationArgs::::default(), ); let witness = load_circuit_args(); @@ -368,7 +364,7 @@ mod tests { APP_PK_PATH, APP_PINNING_PATH, false, - &CommitteeRotationArgs::::default(), + &CommitteeRotationArgs::::default(), ); let witness = load_circuit_args(); let snark = gen_application_snark(¶ms_app, &pk_app, &witness, APP_PINNING_PATH); @@ -407,7 +403,7 @@ mod tests { APP_PK_PATH, APP_PINNING_PATH, false, - &CommitteeRotationArgs::::default(), + &CommitteeRotationArgs::::default(), ); let witness = load_circuit_args(); @@ -445,7 +441,7 @@ mod tests { let deployment_code = AggregationCircuit::gen_evm_verifier_shplonk( ¶ms, &pk, - Some("contractyul"), + None::, &vec![snark], ) .unwrap(); diff --git a/lightclient-circuits/src/gadget/common.rs b/lightclient-circuits/src/gadget/common.rs index 49bdc324..4ba247ea 100644 --- a/lightclient-circuits/src/gadget/common.rs +++ b/lightclient-circuits/src/gadget/common.rs @@ -1,268 +1,8 @@ //! Utility traits, functions used in the crate. use eth_types::Field; -use halo2_base::{halo2_proofs::plonk::Expression, Context, gates::GateInstructions, AssignedValue, QuantumCell}; +use halo2_base::{Context, gates::GateInstructions, AssignedValue, QuantumCell}; use itertools::Itertools; -/// Returns the sum of the passed in cells -pub mod sum { - use super::{Expr, Expression, Field}; - - /// Returns an expression for the sum of the list of expressions. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { - inputs - .into_iter() - .fold(0.expr(), |acc, input| acc + input.expr()) - } - - /// Returns the sum of the given list of values within the field. - pub fn value(values: &[u8]) -> F { - values - .iter() - .fold(F::ZERO, |acc, value| acc + F::from(*value as u64)) - } -} - -/// Returns `1` when `expr[0] && expr[1] && ... == 1`, and returns `0` -/// otherwise. Inputs need to be boolean -pub mod and { - use super::{Expr, Expression, Field}; - - /// Returns an expression that evaluates to 1 only if all the expressions in - /// the given list are 1, else returns 0. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { - inputs - .into_iter() - .fold(1.expr(), |acc, input| acc * input.expr()) - } - - /// Returns the product of all given values. - pub fn value(inputs: Vec) -> F { - inputs.iter().fold(F::ONE, |acc, input| acc * input) - } -} - -/// Returns `1` when `expr[0] || expr[1] || ... == 1`, and returns `0` -/// otherwise. Inputs need to be boolean -pub mod or { - use super::{and, not}; - use super::{Expr, Expression, Field}; - - /// Returns an expression that evaluates to 1 if any expression in the given - /// list is 1. Returns 0 if all the expressions were 0. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { - not::expr(and::expr(inputs.into_iter().map(not::expr))) - } - - /// Returns the value after passing all given values through the OR gate. - pub fn value(inputs: Vec) -> F { - not::value(and::value(inputs.into_iter().map(not::value).collect())) - } -} - -/// Returns `1` when `b == 0`, and returns `0` otherwise. -/// `b` needs to be boolean -pub mod not { - use super::{Expr, Expression, Field}; - - /// Returns an expression that represents the NOT of the given expression. - pub fn expr>(b: E) -> Expression { - 1.expr() - b.expr() - } - - /// Returns a value that represents the NOT of the given value. - pub fn value(b: F) -> F { - F::ONE - b - } -} - -/// Returns `a ^ b`. -/// `a` and `b` needs to be boolean -pub mod xor { - use super::{Expr, Expression, Field}; - - /// Returns an expression that represents the XOR of the given expression. - pub fn expr>(a: E, b: E) -> Expression { - a.expr() + b.expr() - 2.expr() * a.expr() * b.expr() - } - - /// Returns a value that represents the XOR of the given value. - pub fn value(a: F, b: F) -> F { - a + b - F::from(2u64) * a * b - } -} - -/// Returns `when_true` when `selector == 1`, and returns `when_false` when -/// `selector == 0`. `selector` needs to be boolean. -pub mod select { - use super::{Expr, Expression, Field}; - - /// Returns the `when_true` expression when the selector is true, else - /// returns the `when_false` expression. - pub fn expr( - selector: Expression, - when_true: Expression, - when_false: Expression, - ) -> Expression { - selector.clone() * when_true + (1.expr() - selector) * when_false - } - - /// Returns the `when_true` value when the selector is true, else returns - /// the `when_false` value. - pub fn value(selector: F, when_true: F, when_false: F) -> F { - selector * when_true + (F::ONE - selector) * when_false - } - - /// Returns the `when_true` word when selector is true, else returns the - /// `when_false` word. - pub fn value_word( - selector: F, - when_true: [u8; 32], - when_false: [u8; 32], - ) -> [u8; 32] { - if selector == F::ONE { - when_true - } else { - when_false - } - } -} - -/// Trait that implements functionality to get a constant expression from -/// commonly used types. -pub trait Expr { - /// Returns an expression for the type. - fn expr(&self) -> Expression; -} - -/// Implementation trait `Expr` for type able to be casted to u64 -#[macro_export] -macro_rules! impl_expr { - ($type:ty) => { - impl Expr for $type { - #[inline] - fn expr(&self) -> Expression { - Expression::Constant(F::from(*self as u64)) - } - } - }; - ($type:ty, $method:path) => { - impl $super::Expr for $type { - #[inline] - fn expr(&self) -> Expression { - Expression::Constant(F::from($method(self) as u64)) - } - } - }; -} - -impl_expr!(bool); -impl_expr!(u8); -impl_expr!(u64); -impl_expr!(usize); - -impl Expr for Expression { - #[inline] - fn expr(&self) -> Expression { - self.clone() - } -} - -impl Expr for &Expression { - #[inline] - fn expr(&self) -> Expression { - (*self).clone() - } -} - -impl Expr for i32 { - #[inline] - fn expr(&self) -> Expression { - Expression::Constant( - F::from(self.unsigned_abs() as u64) * if self.is_negative() { -F::ONE } else { F::ONE }, - ) - } -} - -/// Given a bytes-representation of an expression, it computes and returns the -/// single expression. -pub fn expr_from_bytes>(bytes: &[E]) -> Expression { - let mut value = 0.expr(); - let mut multiplier = F::ONE; - for byte in bytes.iter() { - value = value + byte.expr() * multiplier; - multiplier *= F::from(256); - } - value -} - -/// Returns the random linear combination of the inputs. -/// Encoding is done as follows: v_0 * R^0 + v_1 * R^1 + ... -pub mod rlc { - use std::ops::{Add, Mul}; - - use super::{Expr, Expression, Field}; - use halo2_base::{gates::GateInstructions, AssignedValue, Context, QuantumCell}; - - /// Returns an expression that represents the random linear combination. - pub fn expr>(expressions: &[E], randomness: E) -> Expression { - if !expressions.is_empty() { - generic(expressions.iter().map(|e| e.expr()), randomness.expr()) - } else { - 0.expr() - } - } - - /// Returns the random linear combination of the inputs. - pub fn value<'a, F: Field, I>(values: I, randomness: F) -> F - where - I: IntoIterator, - ::IntoIter: DoubleEndedIterator, - { - let values = values - .into_iter() - .map(|v| F::from(*v as u64)) - .collect::>(); - if !values.is_empty() { - generic(values, randomness) - } else { - F::ZERO - } - } - - /// Returns the random linear combination of the halo2-lib assigned values. - pub fn assigned_value( - values: &[AssignedValue], - randomness: &QuantumCell, - gate: &impl GateInstructions, - ctx: &mut Context, - ) -> AssignedValue { - if !values.is_empty() { - let mut values = values.iter(); - let init = values.next().expect("values should not be empty"); - - values.fold(*init, |acc, value| { - gate.mul_add(ctx, acc, *randomness, *value) - }) - } else { - ctx.load_zero() - } - } - - fn generic(values: I, randomness: R) -> V - where - I: IntoIterator, - ::IntoIter: DoubleEndedIterator, - V: Clone + Add + Add + Mul, - R: Clone, - { - // we don't reverse bytes because https://github.com/ChainSafe/Banshee/issues/72 - let mut values = values.into_iter(); - let init = values.next().expect("values should not be empty"); - - values.fold(init, |acc, value| acc * randomness.clone() + value) - } -} - pub fn to_bytes_le( a: &AssignedValue, gate: &impl GateInstructions, @@ -282,7 +22,7 @@ pub fn to_bytes_le( // Constrain poseidon bytes to be equal to the recovered checksum let checksum = gate.inner_product(ctx, assigned_bytes.clone(), byte_bases); - ctx.constrain_equal(&a, &checksum); + ctx.constrain_equal(a, &checksum); assigned_bytes } diff --git a/lightclient-circuits/src/gadget/crypto/builder.rs b/lightclient-circuits/src/gadget/crypto/builder.rs index 0e9254e9..26aca908 100644 --- a/lightclient-circuits/src/gadget/crypto/builder.rs +++ b/lightclient-circuits/src/gadget/crypto/builder.rs @@ -18,7 +18,6 @@ use halo2_base::{ circuit::{Layouter, SimpleFloorPlanner}, plonk::{Circuit, ConstraintSystem, Error}, }, - utils::BigPrimeField, AssignedValue, Context, }; use itertools::Itertools; diff --git a/lightclient-circuits/src/gadget/crypto/mod.rs b/lightclient-circuits/src/gadget/crypto/mod.rs index 46fc5610..69e2f05b 100644 --- a/lightclient-circuits/src/gadget/crypto/mod.rs +++ b/lightclient-circuits/src/gadget/crypto/mod.rs @@ -5,7 +5,6 @@ mod sha256_flex; mod sha256_wide; pub use builder::{SHAConfig, ShaCircuitBuilder}; -use eth_types::Field; use halo2_ecc::{ bigint::ProperCrtUint, bls12_381::{Fp2Chip, Fp2Point, FpChip}, @@ -26,8 +25,3 @@ pub type G1Chip<'chip, F> = EccChip<'chip, F, FpChip<'chip, F>>; pub type G2Chip<'chip, F> = EccChip<'chip, F, Fp2Chip<'chip, F>>; pub use halo2_ecc::ecc::hash_to_curve::HashInstructions; - -// This is a temporary measure. TODO: use challenges API. -pub fn constant_randomness() -> F { - F::from_u128(0xca9d6022267d3bd658bf) -} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs index cf9eb3c9..6f1b902e 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs @@ -4,7 +4,6 @@ use eth_types::Field; use getset::CopyGetters; use halo2_base::{ halo2_proofs::circuit::{Region, Value}, - utils::BigPrimeField, virtual_region::{ copy_constraints::{CopyConstraintManager, SharedCopyConstraintManager}, manager::VirtualRegionManager, diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs index b95d348c..0d670aba 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs @@ -8,7 +8,6 @@ use halo2_base::{ plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, poly::Rotation, }, - utils::BigPrimeField, }; use halo2_base::{ gates::{flex_gate::threads::CommonCircuitBuilder, GateInstructions, RangeInstructions}, diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs index 4e557532..5cd7e7a5 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs @@ -1,52 +1,23 @@ -mod config; mod gate; -mod util; -mod witness; use eth_types::Field; use halo2_base::gates::RangeChip; use halo2_base::{gates::flex_gate::threads::CommonCircuitBuilder, Context}; use itertools::Itertools; +use zkevm_hashes::sha256::vanilla::param::NUM_WORDS_TO_ABSORB; use zkevm_hashes::sha256::vanilla::util::get_num_sha2_blocks; -use zkevm_hashes::{ - sha256::vanilla::{ - util::to_be_bytes, - witness::{generate_witnesses_multi_sha256, generate_witnesses_sha256}, - }, - util::word::Word, -}; +use zkevm_hashes::{sha256::vanilla::witness::generate_witnesses_sha256, util::word::Word}; use crate::witness::HashInput; -use halo2_base::{ - gates::{GateInstructions, RangeInstructions}, - halo2_proofs::plonk::Error, - AssignedValue, QuantumCell, -}; -use sha2::Digest; +use halo2_base::{gates::GateInstructions, halo2_proofs::plonk::Error, AssignedValue, QuantumCell}; pub use self::gate::ShaBitGateManager; -use self::util::{NUM_BYTES_FINAL_HASH, NUM_WORDS_TO_ABSORB}; use super::{HashInstructions, ShaCircuitBuilder}; use crate::gadget::common::to_bytes_le; #[derive(Debug)] pub struct Sha256ChipWide<'a, F: Field> { range: &'a RangeChip, - randomness: F, -} - -#[derive(Clone, Debug)] -pub struct AssignedSha256Round { - /// Whether the row is final. - pub is_final: AssignedValue, - /// Input length at the row. - pub input_len: AssignedValue, - /// Input words at the row. - pub input_rlcs: [AssignedValue; NUM_WORDS_TO_ABSORB], - /// Whether the row is padding. - pub padding_selectors: [[AssignedValue; 4]; NUM_WORDS_TO_ABSORB], - /// Output words at the row. - pub output_rlc: AssignedValue, } impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { @@ -80,11 +51,9 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { ); let input_len = assigned_bytes.len(); - let max_byte_size = assigned_bytes.len(); - let range = &self.range; + let range = self.range; let gate = &range.gate; - let mut virtual_rows = vec![]; let input_bytes = binary_input.to_vec(); @@ -97,35 +66,41 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { let num_input_rounds = num_input_words.div_ceil(NUM_WORDS_TO_ABSORB); let byte_bases = (0..4) - .map(|i| QuantumCell::Constant(gate.pow_of_two()[i * 8])) - .collect_vec(); + .map(|i| QuantumCell::Constant(gate.pow_of_two()[i * 8])) + .collect_vec(); for r in 0..num_input_rounds { for w in 0..(num_input_words - r * NUM_WORDS_TO_ABSORB) { let i = (r * NUM_WORDS_TO_ABSORB + w) * 4; - let checksum = gate.inner_product(builder.main(), assigned_bytes[i..i+4].to_vec(), byte_bases.clone()); - builder.main().constrain_equal(&checksum, &blocks[r].word_values[w]); + let checksum = gate.inner_product( + builder.main(), + assigned_bytes[i..i + 4].to_vec(), + byte_bases.clone(), + ); + builder + .main() + .constrain_equal(&checksum, &blocks[r].word_values[w]); } } - let hash_bytes = word_to_bytes_le(blocks[num_rounds-1].hash, gate, builder.main()); + let hash_bytes = word_to_bytes_le(blocks[num_rounds - 1].hash, gate, builder.main()); Ok(hash_bytes) } fn digest_varlen( &self, - ctx: &mut Self::CircuitBuilder, - input: impl IntoIterator>, - max_input_len: usize, + _ctx: &mut Self::CircuitBuilder, + _input: impl IntoIterator>, + _max_input_len: usize, ) -> Result { unimplemented!() } } impl<'a, F: Field> Sha256ChipWide<'a, F> { - pub fn new(range: &'a RangeChip, randomness: F) -> Self { - Self { range, randomness } + pub fn new(range: &'a RangeChip) -> Self { + Self { range } } } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs deleted file mode 100644 index 63f40414..00000000 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/config.rs +++ /dev/null @@ -1,923 +0,0 @@ -//! The circuit for SHA256 hash function. -//! This implementation is based on: -//! - https://github.com/SoraSuegami/zkevm-circuits/blob/main/zkevm-circuits/src/sha256_circuit/sha256_bit.rs - -use super::{util::*, witness::ShaRow}; -use crate::gadget::crypto::constant_randomness; -use crate::gadget::{and, not, rlc, select, sum, xor, Expr}; -use crate::util::BaseConstraintBuilder; -use crate::util::GateBuilderConfig; -use eth_types::Field; -use halo2_base::virtual_region::copy_constraints::CopyConstraintManager; -use halo2_base::{ - halo2_proofs::{ - circuit::{Layouter, Region, Value}, - plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, - poly::Rotation, - }, - AssignedValue, Context, ContextCell, QuantumCell, -}; -use itertools::Itertools; -use log::debug; -use std::iter; -use std::marker::PhantomData; -use zkevm_hashes::sha256::vanilla::columns::Sha256CircuitConfig; - -impl GateBuilderConfig for Sha256CircuitConfig { - fn configure(meta: &mut ConstraintSystem) -> Self { - Sha256CircuitConfig::new(meta) - } - - fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - Ok(()) - } - - fn annotate_columns_in_region(&self, region: &mut Region) {} -} - -/// Configuration for [`Sha256WideChip`]. -#[derive(Clone, Debug)] -pub struct Sha256BitConfig, CA = Column> { - pub q_enable: CF, - pub q_first: CF, - pub q_extend: CF, - pub q_start: CF, - pub q_compression: CF, - pub q_end: CF, - pub q_padding: CF, - pub q_padding_last: CF, - pub q_squeeze: CF, - pub q_final_word: CF, - pub word_w: [CA; NUM_BITS_PER_WORD_W], - pub word_a: [CA; NUM_BITS_PER_WORD_EXT], - pub word_e: [CA; NUM_BITS_PER_WORD_EXT], - pub is_final: CA, - pub is_paddings: [CA; ABSORB_WIDTH_PER_ROW_BYTES], - pub data_rlcs: [CA; ABSORB_WIDTH_PER_ROW_BYTES], - pub round_cst: CF, - pub h_a: CF, - pub h_e: CF, - - // True when the row is enabled - pub is_enabled: CA, - // The columns for bytes of hash results - pub input_rlc: CA, - // Length of first+second inputs - pub input_len: CA, - // RLC of the hash result - pub hash_rlc: CA, - // Output bytes - pub final_hash_bytes: [CA; NUM_BYTES_FINAL_HASH], - - pub _f: PhantomData, - - pub offset: usize, -} - -impl GateBuilderConfig for Sha256BitConfig { - fn configure(meta: &mut ConstraintSystem) -> Self { - let r: F = constant_randomness(); // TODO: use challenges API - let q_enable = meta.fixed_column(); - let q_first = meta.fixed_column(); - let q_extend = meta.fixed_column(); - let q_start = meta.fixed_column(); - let q_compression = meta.fixed_column(); - let q_end = meta.fixed_column(); - let q_padding = meta.fixed_column(); - let q_padding_last = meta.fixed_column(); - let q_squeeze = meta.fixed_column(); - let q_final_word = meta.fixed_column(); - let word_w = array_init::array_init(|_| meta.advice_column()); - let word_a = array_init::array_init(|_| meta.advice_column()); - let word_e = array_init::array_init(|_| meta.advice_column()); - let is_final = meta.advice_column(); - - let is_paddings = array_init::array_init(|_| meta.advice_column()); - is_paddings - .iter() - .for_each(|&col| meta.enable_equality(col)); - let data_rlcs = array_init::array_init(|_| meta.advice_column()); - - let round_cst = meta.fixed_column(); - let h_a = meta.fixed_column(); - meta.enable_equality(h_a); - let h_e = meta.fixed_column(); - meta.enable_equality(h_e); - - let is_enabled = meta.advice_column(); - meta.enable_equality(is_enabled); - let input_len = meta.advice_column(); - meta.enable_equality(input_len); - let input_rlc = meta.advice_column(); - meta.enable_equality(input_rlc); - let hash_rlc = meta.advice_column(); - meta.enable_equality(hash_rlc); - - let final_hash_bytes = array_init::array_init(|_| meta.advice_column()); - for col in final_hash_bytes.into_iter() { - meta.enable_equality(col); - } - // State bits - let mut w_ext = vec![0u64.expr(); NUM_BITS_PER_WORD_W]; - let mut w_2 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut w_7 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut w_15 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut w_16 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut a = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut b = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut c = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut d = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut e = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut f = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut g = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut h = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut d_64 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut h_64 = vec![0u64.expr(); NUM_BITS_PER_WORD]; - let mut new_a_ext = vec![0u64.expr(); NUM_BITS_PER_WORD_EXT]; - let mut new_e_ext = vec![0u64.expr(); NUM_BITS_PER_WORD_EXT]; - - meta.create_gate("Query state bits", |meta| { - for k in 0..NUM_BITS_PER_WORD_W { - w_ext[k] = meta.query_advice(word_w[k], Rotation(-0)); - } - for i in 0..NUM_BITS_PER_WORD { - let k = i + NUM_BITS_PER_WORD_W - NUM_BITS_PER_WORD; - w_2[i] = meta.query_advice(word_w[k], Rotation(-2)); - w_7[i] = meta.query_advice(word_w[k], Rotation(-7)); - w_15[i] = meta.query_advice(word_w[k], Rotation(-15)); - w_16[i] = meta.query_advice(word_w[k], Rotation(-16)); - let k = i + NUM_BITS_PER_WORD_EXT - NUM_BITS_PER_WORD; - a[i] = meta.query_advice(word_a[k], Rotation(-1)); - b[i] = meta.query_advice(word_a[k], Rotation(-2)); - c[i] = meta.query_advice(word_a[k], Rotation(-3)); - d[i] = meta.query_advice(word_a[k], Rotation(-4)); - e[i] = meta.query_advice(word_e[k], Rotation(-1)); - f[i] = meta.query_advice(word_e[k], Rotation(-2)); - g[i] = meta.query_advice(word_e[k], Rotation(-3)); - h[i] = meta.query_advice(word_e[k], Rotation(-4)); - d_64[i] = meta.query_advice(word_a[k], Rotation(-((NUM_ROUNDS + 4) as i32))); - h_64[i] = meta.query_advice(word_e[k], Rotation(-((NUM_ROUNDS + 4) as i32))); - } - for k in 0..NUM_BITS_PER_WORD_EXT { - new_a_ext[k] = meta.query_advice(word_a[k], Rotation(0)); - new_e_ext[k] = meta.query_advice(word_e[k], Rotation(0)); - } - vec![0u64.expr()] - }); - let w = &w_ext[NUM_BITS_PER_WORD_W - NUM_BITS_PER_WORD..NUM_BITS_PER_WORD_W]; - let new_a = &new_a_ext[NUM_BITS_PER_WORD_EXT - NUM_BITS_PER_WORD..NUM_BITS_PER_WORD_EXT]; - let new_e = &new_e_ext[NUM_BITS_PER_WORD_EXT - NUM_BITS_PER_WORD..NUM_BITS_PER_WORD_EXT]; - - let xor = |a: &[Expression], b: &[Expression]| { - debug_assert_eq!(a.len(), b.len(), "invalid length"); - let mut c = vec![0.expr(); a.len()]; - for (idx, (a, b)) in a.iter().zip(b.iter()).enumerate() { - c[idx] = xor::expr(a, b); - } - c - }; - - let select = - |c: &[Expression], when_true: &[Expression], when_false: &[Expression]| { - debug_assert_eq!(c.len(), when_true.len(), "invalid length"); - debug_assert_eq!(c.len(), when_false.len(), "invalid length"); - let mut r = vec![0.expr(); c.len()]; - for (idx, (c, (when_true, when_false))) in c - .iter() - .zip(when_true.iter().zip(when_false.iter())) - .enumerate() - { - r[idx] = select::expr(c.clone(), when_true.clone(), when_false.clone()); - } - r - }; - - meta.create_gate("input checks", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - for w in w_ext.iter() { - cb.require_boolean("w bit boolean", w.clone()); - } - for a in new_a_ext.iter() { - cb.require_boolean("a bit boolean", a.clone()); - } - for e in new_e_ext.iter() { - cb.require_boolean("e bit boolean", e.clone()); - } - cb.gate(meta.query_fixed(q_enable, Rotation::cur())) - }); - - meta.create_gate("w extend", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let s0 = xor( - &rotate::expr(&w_15, 7), - &xor(&rotate::expr(&w_15, 18), &shift::expr(&w_15, 3)), - ); - let s1 = xor( - &rotate::expr(&w_2, 17), - &xor(&rotate::expr(&w_2, 19), &shift::expr(&w_2, 10)), - ); - let new_w = - decode::expr(&w_16) + decode::expr(&s0) + decode::expr(&w_7) + decode::expr(&s1); - cb.require_equal("w", new_w, decode::expr(&w_ext)); - cb.gate(meta.query_fixed(q_extend, Rotation::cur())) - }); - - meta.create_gate("compression", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let s1 = xor( - &rotate::expr(&e, 6), - &xor(&rotate::expr(&e, 11), &rotate::expr(&e, 25)), - ); - let ch = select(&e, &f, &g); - let temp1 = decode::expr(&h) - + decode::expr(&s1) - + decode::expr(&ch) - + meta.query_fixed(round_cst, Rotation::cur()) - + decode::expr(w); - - let s0 = xor( - &rotate::expr(&a, 2), - &xor(&rotate::expr(&a, 13), &rotate::expr(&a, 22)), - ); - let maj = select(&xor(&b, &c), &a, &b); - let temp2 = decode::expr(&s0) + decode::expr(&maj); - cb.require_equal( - "compress a", - decode::expr(&new_a_ext), - temp1.clone() + temp2, - ); - cb.require_equal( - "compress e", - decode::expr(&new_e_ext), - decode::expr(&d) + temp1, - ); - cb.gate(meta.query_fixed(q_compression, Rotation::cur())) - }); - - meta.create_gate("start", |meta| { - let is_final = meta.query_advice(is_final, Rotation::cur()); - let h_a = meta.query_fixed(h_a, Rotation::cur()); - let h_e = meta.query_fixed(h_e, Rotation::cur()); - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - cb.require_equal( - "start a", - decode::expr(&new_a_ext), - select::expr(is_final.expr(), h_a, decode::expr(&d)), - ); - cb.require_equal( - "start e", - decode::expr(&new_e_ext), - select::expr(is_final.expr(), h_e, decode::expr(&h)), - ); - cb.gate(meta.query_fixed(q_start, Rotation::cur())) - }); - - meta.create_gate("end", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - cb.require_equal( - "end a", - decode::expr(&new_a_ext), - decode::expr(&d) + decode::expr(&d_64), - ); - cb.require_equal( - "end e", - decode::expr(&new_e_ext), - decode::expr(&h) + decode::expr(&h_64), - ); - cb.gate(meta.query_fixed(q_end, Rotation::cur())) - }); - - // Enforce logic for when this block is the last block for a hash - meta.create_gate("is final", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let is_padding = meta.query_advice( - *is_paddings.last().unwrap(), - Rotation(-((NUM_END_ROWS + NUM_ROUNDS - NUM_WORDS_TO_ABSORB) as i32) - 2), - ); - let is_final_prev = meta.query_advice(is_final, Rotation::prev()); - let is_final = meta.query_advice(is_final, Rotation::cur()); - // On the first row is_final needs to be enabled - cb.condition(meta.query_fixed(q_first, Rotation::cur()), |cb| { - cb.require_equal( - "is_final needs to remain the same", - is_final.expr(), - 1.expr(), - ); - }); - // Get the correct is_final state from the padding selector - cb.condition(meta.query_fixed(q_squeeze, Rotation::cur()), |cb| { - cb.require_equal( - "is_final needs to match the padding selector", - is_final.expr(), - is_padding, - ); - }); - // Copy the is_final state to the q_start rows - cb.condition( - meta.query_fixed(q_start, Rotation::cur()) - - meta.query_fixed(q_first, Rotation::cur()), - |cb| { - cb.require_equal( - "is_final needs to remain the same", - is_final.expr(), - is_final_prev, - ); - }, - ); - cb.gate(1.expr()) - }); - - meta.create_gate("is enabled", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let q_squeeze = meta.query_fixed(q_squeeze, Rotation::cur()); - let is_final = meta.query_advice(is_final, Rotation::cur()); - let is_enabled = meta.query_advice(is_enabled, Rotation::cur()); - // Only set is_enabled to true when is_final is true and it's a squeeze row - cb.require_equal( - "is_enabled := q_squeeze && is_final", - is_enabled.expr(), - and::expr(&[q_squeeze.expr(), is_final.expr()]), - ); - cb.gate(meta.query_fixed(q_enable, Rotation::cur())) - }); - - let start_new_hash = |meta: &mut VirtualCells| { - // A new hash is started when the previous hash is done or on the first row - meta.query_advice(is_final, Rotation::cur()) - }; - - // Create bytes from input bits - let input_bytes = to_le_bytes::expr(w); - - // Padding - meta.create_gate("padding", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let prev_is_padding = meta.query_advice(*is_paddings.last().unwrap(), Rotation::prev()); - let q_padding = meta.query_fixed(q_padding, Rotation::cur()); - let q_padding_last = meta.query_fixed(q_padding_last, Rotation::cur()); - let length = meta.query_advice(input_len, Rotation::cur()); - let is_final_padding_row = - meta.query_advice(*is_paddings.last().unwrap(), Rotation(-2)); - // All padding selectors need to be boolean - for is_padding in is_paddings.iter() { - let is_padding = meta.query_advice(*is_padding, Rotation::cur()); - cb.condition(meta.query_fixed(q_enable, Rotation::cur()), |cb| { - cb.require_boolean("is_padding boolean", is_padding); - }); - } - // Now for each padding selector - for idx in 0..is_paddings.len() { - // Previous padding selector can be on the previous row - let is_padding_prev = if idx == 0 { - prev_is_padding.expr() - } else { - meta.query_advice(is_paddings[idx - 1], Rotation::cur()) - }; - let is_padding = meta.query_advice(is_paddings[idx], Rotation::cur()); - let is_first_padding = is_padding.clone() - is_padding_prev.clone(); - // Check padding transition 0 -> 1 done only once - cb.condition(q_padding.expr(), |cb| { - cb.require_boolean("padding step boolean", is_first_padding.clone()); - }); - // Padding start/intermediate byte, all padding rows except the last one - cb.condition( - and::expr([ - (q_padding.expr() - q_padding_last.expr()), - is_padding.expr(), - ]), - |cb| { - // Input bytes need to be zero, or 128 if this is the first padding byte - cb.require_equal( - "padding start/intermediate byte", - input_bytes[idx].clone(), - is_first_padding.expr() * 128.expr(), - ); - }, - ); - // Padding start/intermediate byte, last padding row but not in the final block - cb.condition( - and::expr([ - q_padding_last.expr(), - is_padding.expr(), - not::expr(is_final_padding_row.expr()), - ]), - |cb| { - // Input bytes need to be zero, or 128 if this is the first padding byte - cb.require_equal( - "padding start/intermediate byte", - input_bytes[idx].clone(), - is_first_padding.expr() * 128.expr(), - ); - }, - ); - } - // The last row containing input/padding data in the final block needs to - // contain the length in bits (Only input lengths up to 2**32 - 1 - // bits are supported, which is lower than the spec of 2**64 - 1 bits) - cb.condition( - and::expr([q_padding_last.expr(), is_final_padding_row.expr()]), - |cb| { - cb.require_equal("padding length", decode::expr(w), length.expr() * 8.expr()); - }, - ); - cb.gate(1.expr()) - }); - - // Length and input data rlc - meta.create_gate("length and data rlc", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let q_padding = meta.query_fixed(q_padding, Rotation::cur()); - let start_new_hash = start_new_hash(meta); - let length_prev = meta.query_advice(input_len, Rotation::prev()); - let length = meta.query_advice(input_len, Rotation::cur()); - let data_rlc_prev = meta.query_advice(input_rlc, Rotation::prev()); - let data_rlc = meta.query_advice(input_rlc, Rotation::cur()); - - // Update the length/data_rlc on rows where we absorb data - cb.condition(q_padding.expr(), |cb| { - // Length increases by the number of bytes that aren't padding - // In a new block we have to start from 0 if the previous block was the final - // one - cb.require_equal( - "update length", - length.clone(), - length_prev.clone() * not::expr(start_new_hash.expr()) - + sum::expr(is_paddings.iter().map(|is_padding| { - not::expr(meta.query_advice(*is_padding, Rotation::cur())) - })), - ); - - // Use intermediate cells to keep the degree low - let mut new_data_rlc = data_rlc_prev.clone() * not::expr(start_new_hash.expr()); - - cb.require_equal( - "initial data rlc", - meta.query_advice(data_rlcs[0], Rotation::cur()), - new_data_rlc, - ); - new_data_rlc = meta.query_advice(data_rlcs[0], Rotation::cur()); - - for (idx, (byte, is_padding)) in - input_bytes.iter().zip(is_paddings.iter()).enumerate() - { - new_data_rlc = select::expr( - meta.query_advice(*is_padding, Rotation::cur()), - new_data_rlc.clone(), - new_data_rlc.clone() * r + byte.clone(), - ); - if idx < data_rlcs.len() - 1 { - let next_data_rlc = meta.query_advice(data_rlcs[idx + 1], Rotation::cur()); - cb.require_equal( - "intermediate data rlc", - next_data_rlc.clone(), - new_data_rlc, - ); - new_data_rlc = next_data_rlc; - } - } - - cb.require_equal("update data rlc", data_rlc.clone(), new_data_rlc); - }); - cb.gate(1.expr()) - }); - - // Make sure data is consistent between blocks - meta.create_gate("cross block data consistency", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let start_new_hash = start_new_hash(meta); - let to_const = - |value: &String| -> &'static str { Box::leak(value.clone().into_boxed_str()) }; - let mut add = |name: &'static str, column| { - let last_rot = - Rotation(-((NUM_END_ROWS + NUM_ROUNDS - NUM_WORDS_TO_ABSORB) as i32)); - let value_to_copy = meta.query_advice(column, last_rot); - let prev_value = meta.query_advice(column, Rotation::prev()); - let cur_value = meta.query_advice(column, Rotation::cur()); - // On squeeze rows fetch the last used value - cb.condition(meta.query_fixed(q_squeeze, Rotation::cur()), |cb| { - cb.require_equal( - to_const(&format!("{} copy check", name)), - cur_value.expr(), - value_to_copy.expr(), - ); - }); - // On first rows keep the length the same, or reset the length when starting a - // new hash - cb.condition( - meta.query_fixed(q_start, Rotation::cur()) - - meta.query_fixed(q_first, Rotation::cur()), - |cb| { - cb.require_equal( - to_const(&format!("{} equality check", name)), - cur_value.expr(), - prev_value.expr() * not::expr(start_new_hash.expr()), - ); - }, - ); - // Set the value to zero on the first row - cb.condition(meta.query_fixed(q_first, Rotation::cur()), |cb| { - cb.require_equal( - to_const(&format!("{} initialized to 0", name)), - cur_value.clone(), - 0.expr(), - ); - }); - }; - add("length", input_len); - add("data_rlc", input_rlc); - add("last padding", *is_paddings.last().unwrap()); - - cb.gate(1.expr()) - }); - - // Squeeze - meta.create_gate("squeeze", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - // Squeeze out the hash - let hash_parts = [new_a, &a, &b, &c, new_e, &e, &f, &g]; - let hash_bytes = hash_parts - .iter() - .flat_map(|part| to_le_bytes::expr(part)) - .collect::>(); - let rlc = rlc::expr(&hash_bytes, Expression::Constant(r)); - cb.condition(start_new_hash(meta), |cb| { - cb.require_equal( - "hash rlc check", - rlc, - meta.query_advice(hash_rlc, Rotation::cur()), - ); - }); - cb.gate(meta.query_fixed(q_squeeze, Rotation::cur())) - }); - - meta.create_gate("final_hash_words", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let q_condition = meta.query_fixed(q_final_word, Rotation::cur()); - - let final_word_exprs = (0..NUM_BYTES_FINAL_HASH) - .map(|i| { - meta.query_advice(final_hash_bytes[i], Rotation::cur()) - .expr() - }) - .collect::>>(); - let rlc = rlc::expr(&final_word_exprs, Expression::Constant(r)); - cb.condition(q_condition.clone(), |cb| { - cb.require_equal( - "final hash rlc check", - rlc, - meta.query_advice(hash_rlc, Rotation::cur()), - ); - }); - cb.gate(q_condition) - }); - - debug!("sha256 circuit degree: {}", meta.degree()); - debug!("minimum rows: {}", meta.minimum_rows()); - - Sha256BitConfig { - q_enable, - q_first, - q_extend, - q_start, - q_compression, - q_end, - q_padding, - q_padding_last, - q_squeeze, - q_final_word, - word_w, - word_a, - word_e, - is_final, - is_paddings, - data_rlcs, - round_cst, - h_a, - h_e, - is_enabled, - input_len, - input_rlc, - hash_rlc, - final_hash_bytes, - _f: PhantomData, - offset: Default::default(), - } - } - - fn annotate_columns_in_region(&self, region: &mut Region) { - self.annotations().iter().for_each(|(column, name)| { - region.name_column(|| name, *column); - }); - } - - fn load(&self, _layouter: &mut impl Layouter) -> Result<(), Error> { - Ok(()) - } -} - -impl Sha256BitConfig { - pub fn annotations(&self) -> Vec<(Column, String)> { - let mut annotations = vec![ - (self.q_enable.into(), "q_enabled".to_string()), - (self.q_first.into(), "q_first".to_string()), - (self.q_extend.into(), "q_extend".to_string()), - (self.q_start.into(), "q_start".to_string()), - (self.q_compression.into(), "q_compression".to_string()), - (self.q_end.into(), "q_end".to_string()), - (self.q_padding.into(), "q_padding".to_string()), - (self.q_padding_last.into(), "q_padding_last".to_string()), - (self.q_squeeze.into(), "q_squeeze".to_string()), - (self.q_final_word.into(), "q_final_word".to_string()), - (self.is_final.into(), "is_final".to_string()), - (self.round_cst.into(), "round_cst".to_string()), - (self.h_a.into(), "h_a".to_string()), - (self.h_e.into(), "h_e".to_string()), - (self.is_enabled.into(), "is_enabled".to_string()), - (self.input_len.into(), "input_len".to_string()), - (self.input_rlc.into(), "input_rlc".to_string()), - (self.hash_rlc.into(), "hash_rlc".to_string()), - ]; - - for (i, col) in self.word_w.iter().copied().enumerate() { - annotations.push((col.into(), format!("word_w_{}", i))); - } - for (i, col) in self.word_a.iter().copied().enumerate() { - annotations.push((col.into(), format!("word_a_{}", i))); - } - for (i, col) in self.word_e.iter().copied().enumerate() { - annotations.push((col.into(), format!("word_e_{}", i))); - } - for (i, col) in self.is_paddings.iter().copied().enumerate() { - annotations.push((col.into(), format!("is_paddings_{}", i))); - } - for (i, col) in self.data_rlcs.iter().copied().enumerate() { - annotations.push((col.into(), format!("data_rlcs_{}", i))); - } - for (i, col) in self.final_hash_bytes.iter().copied().enumerate() { - annotations.push((col.into(), format!("final_hash_bytes_{}", i))); - } - - annotations - } -} - -impl Sha256BitConfig, Context> { - pub fn load_sha256_row( - &mut self, - row: &ShaRow, - assigned_rows: &mut Sha256AssignedRows, - ) -> Result>, Error> { - let offset = self.offset; - self.offset += 1; - let round = offset % (NUM_ROUNDS + 8); - // Fixed values - for (ctx, value) in [ - (&mut self.q_enable, F::from(true)), - (&mut self.q_first, F::from(offset == 0)), - ( - &mut self.q_extend, - F::from((4 + 16..4 + NUM_ROUNDS).contains(&round)), - ), - (&mut self.q_start, F::from(round < 4)), - ( - &mut self.q_compression, - F::from((4..NUM_ROUNDS + 4).contains(&round)), - ), - (&mut self.q_end, F::from(round >= NUM_ROUNDS + 4)), - (&mut self.q_padding, F::from((4..20).contains(&round))), - (&mut self.q_padding_last, F::from(round == 19)), - (&mut self.q_squeeze, F::from(round == NUM_ROUNDS + 7)), - ( - &mut self.q_final_word, - F::from(row.is_final && round == NUM_ROUNDS + 7), - ), - ( - &mut self.round_cst, - F::from(if (4..NUM_ROUNDS + 4).contains(&round) { - ROUND_CST[round - 4] as u64 - } else { - 0 - }), - ), - ( - &mut self.h_a, - F::from(if round < 4 { H[3 - round] } else { 0 }), - ), - ( - &mut self.h_e, - F::from(if round < 4 { H[7 - round] } else { 0 }), - ), - ] { - ctx.assign_cell(QuantumCell::Constant(value)); - } - - // Advice values - for (ctxs, values) in [ - ( - self.word_w.iter_mut().collect::>(), - row.w.as_slice(), - ), - ( - self.word_a.iter_mut().collect::>(), - row.a.as_slice(), - ), - ( - self.word_e.iter_mut().collect::>(), - row.e.as_slice(), - ), - (vec![&mut self.is_final], [row.is_final].as_slice()), - ] { - for (value, ctx) in values.iter().zip(ctxs) { - ctx.assign_cell(QuantumCell::Witness(F::from(*value))); - } - } - - let padding_selectors = self - .is_paddings - .iter_mut() - .zip(row.is_paddings) - .map(|(ctx, val)| ctx.load_witness(F::from(val))) - .collect_vec() - .try_into() - .unwrap(); - - // Intermediary data rlcs - for (ctx, data_rlc) in self.data_rlcs.iter_mut().zip(row.intermediary_data_rlcs) { - ctx.assign_cell(QuantumCell::Witness(data_rlc)); - } - - // Hash data - let [is_enabled, input_rlc, input_len, output_rlc] = [ - ( - &mut self.is_enabled, - F::from(row.is_final && round == NUM_ROUNDS + 7), - ), - (&mut self.input_rlc, row.data_rlc), - (&mut self.input_len, F::from(row.length as u64)), - (&mut self.hash_rlc, row.hash_rlc), - ] - .map(|(ctx, value)| ctx.load_witness(value)); - - if (4..20).contains(&round) { - assigned_rows.padding_selectors.push(padding_selectors); - assigned_rows.input_rlc.push(input_rlc); - } - - if row.is_final && round == NUM_ROUNDS + 7 { - assigned_rows.output_rlc.push(output_rlc); - } - - if round == NUM_ROUNDS + 7 { - assigned_rows.is_enabled.push(is_enabled); - assigned_rows.input_len.push(input_len); - } - - if !row.is_final || round != NUM_ROUNDS + 7 { - self.final_hash_bytes - .iter_mut() - .zip(iter::repeat(F::from(0u64))) - .for_each(|(ctx, byte)| { - ctx.assign_cell(QuantumCell::Witness(byte)); - }); - - return Ok(vec![]); - } - - let assigned_hash_bytes = self - .final_hash_bytes - .iter_mut() - .zip(row.final_hash_bytes) - .map(|(ctx, byte)| ctx.load_witness(byte)) - .collect_vec(); - - Ok(assigned_hash_bytes) - } - - #[allow(clippy::type_complexity)] - pub fn assign_in_region( - &self, - region: &mut Region, - config: &Sha256BitConfig, - use_unknown: bool, - mut copy_manager: Option<&mut CopyConstraintManager>, - ) -> Result<(), Error> { - // Fixed values - for (name, column, ctx) in [ - ("q_enable", &config.q_enable, &self.q_enable), - ("q_first", &config.q_first, &self.q_first), - ("q_extend", &config.q_extend, &self.q_extend), - ("q_start", &config.q_start, &self.q_start), - ("q_compression", &config.q_compression, &self.q_compression), - ("q_end", &config.q_end, &self.q_end), - ("q_padding", &config.q_padding, &self.q_padding), - ( - "q_padding_last", - &config.q_padding_last, - &self.q_padding_last, - ), - ("q_squeeze", &config.q_squeeze, &self.q_squeeze), - ("q_final_word", &config.q_final_word, &self.q_final_word), - ("round_cst", &config.round_cst, &self.round_cst), - ("h_a", &config.h_a, &self.h_a), - ("h_e", &config.h_e, &self.h_e), - ] { - for (offset, &val) in ctx.advice.iter().enumerate() { - let cell = region - .assign_fixed(|| name, *column, offset, || Value::known(val))? - .cell(); - - if let Some(copy_manager) = copy_manager.as_mut() { - copy_manager - .assigned_advices - .insert(ContextCell::new(ctx.type_id(), ctx.id(), offset), cell); - } - } - } - - // Advice values - - for (name, column, ctx) in [ - ("is_enabled", &config.is_enabled, &self.is_enabled), - ("input_len", &config.input_len, &self.input_len), - ("input_rlc", &config.input_rlc, &self.input_rlc), - ("hash_rlc", &config.hash_rlc, &self.hash_rlc), - ] { - for (offset, &val) in ctx.advice.iter().enumerate() { - let value = if use_unknown { - Value::unknown() - } else { - Value::known(val) - }; - let cell = region - .assign_advice(|| name, *column, offset, || value)? - .cell(); - - if let Some(copy_manager) = copy_manager.as_mut() { - copy_manager - .assigned_advices - .insert(ContextCell::new(ctx.type_id(), ctx.id(), offset), cell); - } - } - } - - let _ = itertools::multizip(( - config.is_paddings.iter(), - self.is_paddings.iter(), - iter::repeat("is_paddings"), - )) - .chain(itertools::multizip(( - config.data_rlcs.iter(), - self.data_rlcs.iter(), - iter::repeat("data_rlcs"), - ))) - .chain(itertools::multizip(( - config.word_w.iter(), - self.word_w.iter(), - iter::repeat("w word"), - ))) - .chain(itertools::multizip(( - config.word_a.iter(), - self.word_a.iter(), - iter::repeat("a word"), - ))) - .chain(itertools::multizip(( - config.word_e.iter(), - self.word_e.iter(), - iter::repeat("e word"), - ))) - .chain(iter::once((&config.is_final, &self.is_final, "is final"))) - .chain(itertools::multizip(( - config.final_hash_bytes.iter(), - self.final_hash_bytes.iter(), - iter::repeat("final hash bytes"), - ))) - .map(|(column, ctx, name)| { - for (offset, &val) in ctx.advice.iter().enumerate() { - let value = if use_unknown { - Value::unknown() - } else { - Value::known(val) - }; - - let cell = match region.assign_advice(|| name, *column, offset, || value) { - Ok(cell) => cell, - Err(e) => { - return Err(e); - } - } - .cell(); - - if let Some(copy_manager) = copy_manager.as_mut() { - copy_manager - .assigned_advices - .insert(ContextCell::new(ctx.type_id(), ctx.id(), offset), cell); - } - } - - Ok::<_, Error>(()) - }) - .collect::, _>>()?; - - Ok(()) - } -} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs index 68019c5a..047145ad 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs @@ -3,30 +3,24 @@ use eth_types::Field; use getset::CopyGetters; use halo2_base::{ gates::circuit::CircuitBuilderStage, - halo2_proofs::circuit::Region, + halo2_proofs::{circuit::Region, plonk::Error}, virtual_region::{ copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, }, - AssignedValue, Context, }; use itertools::Itertools; -use std::any::TypeId; use zkevm_hashes::{ sha256::{ component::circuit::LoadedSha256, vanilla::{ columns::Sha256CircuitConfig, param::{NUM_START_ROWS, NUM_WORDS_TO_ABSORB, SHA256_NUM_ROWS}, - witness::{AssignedSha256Block, VirtualShaRow}, + witness::VirtualShaRow, }, }, util::word::Word, }; -use super::witness::ShaRow; - -pub const FIRST_PHASE: usize = 0; - #[derive(Clone, Debug, CopyGetters)] pub struct ShaBitGateManager { #[getset(get_copy = "pub")] @@ -55,9 +49,7 @@ impl CommonGateManager for ShaBitGateManager { } } - fn custom_context(&mut self) -> Self::CustomContext<'_> { - () - } + fn custom_context(&mut self) -> Self::CustomContext<'_> {} fn from_stage(stage: CircuitBuilderStage) -> Self { Self::new(stage == CircuitBuilderStage::Prover) @@ -189,3 +181,18 @@ impl ShaBitGateManager { // TODO: set to `self.sha_contexts`. } } + +impl GateBuilderConfig for Sha256CircuitConfig { + fn configure(meta: &mut halo2_base::halo2_proofs::plonk::ConstraintSystem) -> Self { + Sha256CircuitConfig::new(meta) + } + + fn load( + &self, + _: &mut impl halo2_base::halo2_proofs::circuit::Layouter, + ) -> Result<(), Error> { + Ok(()) + } + + fn annotate_columns_in_region(&self, _: &mut Region) {} +} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs deleted file mode 100644 index 0cbb3edd..00000000 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/util.rs +++ /dev/null @@ -1,151 +0,0 @@ -use eth_types::Field; -use halo2_base::AssignedValue; - -pub(crate) const NUM_BITS_PER_BYTE: usize = 8; -pub(crate) const NUM_BYTES_PER_WORD: usize = 4; -pub(crate) const NUM_BITS_PER_WORD: usize = NUM_BYTES_PER_WORD * NUM_BITS_PER_BYTE; -pub(crate) const NUM_BITS_PER_WORD_W: usize = NUM_BITS_PER_WORD + 2; -pub(crate) const NUM_BITS_PER_WORD_EXT: usize = NUM_BITS_PER_WORD + 3; -pub(crate) const NUM_ROUNDS: usize = 64; -pub(crate) const RATE: usize = 16 * NUM_BYTES_PER_WORD; -pub(crate) const RATE_IN_BITS: usize = RATE * NUM_BITS_PER_BYTE; -pub(crate) const NUM_WORDS_TO_ABSORB: usize = 16; -pub(crate) const ABSORB_WIDTH_PER_ROW_BYTES: usize = 4; -pub(crate) const NUM_BITS_PADDING_LENGTH: usize = 64; -pub(crate) const NUM_END_ROWS: usize = 4; -pub(crate) const NUM_BYTES_FINAL_HASH: usize = 32; -pub(crate) const MAX_DEGREE: usize = 5; - -pub(crate) const ROUND_CST: [u32; NUM_ROUNDS] = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, -]; - -/// Init h_in parameters. -pub const H: [u64; 8] = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, -]; - -/// Assigned values for each row. -#[derive(Clone, Debug, Default)] -pub struct Sha256AssignedRows { - // /// Offset of the row. - // pub offset: usize, - /// Input length at the row. - pub input_len: Vec>, - /// Input words at the row. - pub input_rlc: Vec>, - /// Whether the output word is enabled at the row. - pub is_enabled: Vec>, - /// Whether the row is padding. - pub padding_selectors: Vec<[AssignedValue; 4]>, - /// Output words at the row. - pub output_rlc: Vec>, -} - -impl Sha256AssignedRows { - pub fn new() -> Self { - Self { - ..Default::default() - } - } -} - -/// Decodes be bits -pub mod decode { - use eth_types::Field; - use halo2_base::halo2_proofs::plonk::Expression; - - use crate::gadget::Expr; - - pub(crate) fn expr(bits: &[Expression]) -> Expression { - let mut value = 0.expr(); - let mut multiplier = F::ONE; - for bit in bits.iter().rev() { - value = value + bit.expr() * multiplier; - multiplier *= F::from(2); - } - value - } - - pub(crate) fn value(bits: &[u8]) -> u64 { - let mut value = 0u64; - for (idx, &bit) in bits.iter().rev().enumerate() { - value += (bit as u64) << idx; - } - value - } -} - -/// Rotates bits to the right -pub mod rotate { - use eth_types::Field; - use halo2_base::halo2_proofs::plonk::Expression; - - pub(crate) fn expr(bits: &[Expression], count: usize) -> Vec> { - let mut rotated = bits.to_vec(); - rotated.rotate_right(count); - rotated - } - - pub(crate) fn value(value: u64, count: u32) -> u64 { - ((value as u32).rotate_right(count)) as u64 - } -} - -/// Shifts bits to the right -pub mod shift { - use crate::gadget::Expr; - - use super::NUM_BITS_PER_WORD; - use eth_types::Field; - use halo2_base::halo2_proofs::plonk::Expression; - - pub(crate) fn expr(bits: &[Expression], count: usize) -> Vec> { - let mut res = vec![0.expr(); count]; - res.extend_from_slice(&bits[0..NUM_BITS_PER_WORD - count]); - res - } - - pub(crate) fn value(value: u64, count: u32) -> u64 { - ((value as u32) >> count) as u64 - } -} - -/// Convert be bits to le bytes -pub mod to_le_bytes { - use crate::util::to_bytes; - use eth_types::Field; - use halo2_base::halo2_proofs::plonk::Expression; - - pub(crate) fn expr(bits: &[Expression]) -> Vec> { - to_bytes::expr(&bits.iter().rev().cloned().collect::>()) - .into_iter() - .rev() - .collect::>() - } - - pub(crate) fn value(bits: &[u8]) -> Vec { - to_bytes::value(&bits.iter().rev().copied().collect::>()) - .into_iter() - .rev() - .collect::>() - } -} - -/// Converts bytes into bits -pub(crate) fn into_bits(bytes: &[u8]) -> Vec { - let mut bits: Vec = vec![0; bytes.len() * 8]; - for (byte_idx, byte) in bytes.iter().enumerate() { - for idx in 0u64..8 { - bits[byte_idx * 8 + (idx as usize)] = (*byte >> (7 - idx)) & 1; - } - } - bits -} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs deleted file mode 100644 index 34342d99..00000000 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/witness.rs +++ /dev/null @@ -1,292 +0,0 @@ -use super::util::*; -use crate::{gadget::rlc, witness::HashInput}; -use eth_types::Field; -use itertools::Itertools; -use log::debug; - -#[derive(Clone, Debug, PartialEq)] -pub struct ShaRow { - pub(crate) w: [bool; NUM_BITS_PER_WORD_W], - pub(crate) a: [bool; NUM_BITS_PER_WORD_EXT], - pub(crate) e: [bool; NUM_BITS_PER_WORD_EXT], - pub(crate) is_final: bool, - pub(crate) length: usize, - pub(crate) data_rlc: F, - pub(crate) hash_rlc: F, - pub(crate) is_paddings: [bool; ABSORB_WIDTH_PER_ROW_BYTES], - pub(crate) intermediary_data_rlcs: [F; ABSORB_WIDTH_PER_ROW_BYTES], - pub(crate) final_hash_bytes: [F; NUM_BYTES_FINAL_HASH], -} - -pub fn sha256(rows: &mut Vec>, inputs: &[&[u8]; 2], rnd: F) { - let left_bits = into_bits(inputs[0]); - let right_bits = into_bits(inputs[1]); - let input_len = inputs[0].len() + inputs[1].len(); - let mut bits = left_bits.iter().copied().chain(right_bits).collect_vec(); - - // Padding - let length = bits.len(); - let mut length_in_bits = into_bits(&(length as u64).to_be_bytes()); - assert!(length_in_bits.len() == NUM_BITS_PADDING_LENGTH); - bits.push(1); - while (bits.len() + NUM_BITS_PADDING_LENGTH) % RATE_IN_BITS != 0 { - bits.push(0); - } - bits.append(&mut length_in_bits); - assert!(bits.len() % RATE_IN_BITS == 0); - - // Set the initial state - let mut hs: [u64; 8] = H.to_vec().try_into().unwrap(); - let mut length = 0usize; - let mut data_rlc = F::ZERO; - - let mut in_padding = false; - - // Process each block - let chunks = bits.chunks(RATE_IN_BITS); - let num_chunks = chunks.len(); - for (idx, chunk) in chunks.enumerate() { - // Adds a row - let mut add_row = |w: u64, - a: u64, - e: u64, - is_final, - length, - data_rlc, - hash_rlc, - is_paddings, - intermediary_data_rlcs, - final_hash_bytes| { - let word_to_bits = |value: u64, num_bits: usize| { - into_bits(&value.to_be_bytes())[64 - num_bits..64] - .iter() - .map(|b| *b != 0) - .collect::>() - }; - - rows.push(ShaRow { - w: word_to_bits(w, NUM_BITS_PER_WORD_W).try_into().unwrap(), - a: word_to_bits(a, NUM_BITS_PER_WORD_EXT).try_into().unwrap(), - e: word_to_bits(e, NUM_BITS_PER_WORD_EXT).try_into().unwrap(), - is_final, - length, - data_rlc, - hash_rlc, - is_paddings, - intermediary_data_rlcs, - final_hash_bytes, - }); - }; - - // Last block for this hash - let is_final_block = idx == num_chunks - 1; - - // Set the state - let (mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h) = - (hs[0], hs[1], hs[2], hs[3], hs[4], hs[5], hs[6], hs[7]); - - // Add start rows - let mut add_row_start = |a: u64, e: u64, is_final| { - add_row( - 0, - a, - e, - is_final, - length, - data_rlc, - F::ZERO, - [false, false, false, in_padding], - [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES], - [F::ZERO; NUM_BYTES_FINAL_HASH], - ) - }; - add_row_start(d, h, idx == 0); - add_row_start(c, g, idx == 0); - add_row_start(b, f, idx == 0); - add_row_start(a, e, idx == 0); - - let mut ws = Vec::new(); - for (round, round_cst) in ROUND_CST.iter().enumerate() { - // Padding/Length/Data rlc - let mut is_paddings = [false; ABSORB_WIDTH_PER_ROW_BYTES]; - let mut inter_data_rlcs = [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES]; - if round < NUM_WORDS_TO_ABSORB { - // padding/length - for is_padding in is_paddings.iter_mut() { - *is_padding = if length == input_len { - true - } else { - length += 1; - false - }; - } - // data rlc - let input_bytes = to_le_bytes::value(&chunk[round * 32..(round + 1) * 32]); - inter_data_rlcs[0] = data_rlc; - for (idx, (byte, padding)) in input_bytes.iter().zip(is_paddings.iter()).enumerate() - { - if !*padding { - data_rlc = data_rlc * rnd + F::from(*byte as u64); - } - if idx < inter_data_rlcs.len() - 1 { - inter_data_rlcs[idx + 1] = data_rlc; - } - } - in_padding = *is_paddings.last().unwrap(); - } - - // w - let w_ext = if round < NUM_WORDS_TO_ABSORB { - decode::value(&chunk[round * 32..(round + 1) * 32]) - } else { - let get_w = |offset: usize| ws[ws.len() - offset] & 0xFFFFFFFF; - let s0 = rotate::value(get_w(15), 7) - ^ rotate::value(get_w(15), 18) - ^ shift::value(get_w(15), 3); - let s1 = rotate::value(get_w(2), 17) - ^ rotate::value(get_w(2), 19) - ^ shift::value(get_w(2), 10); - get_w(16) + s0 + get_w(7) + s1 - }; - let w = w_ext & 0xFFFFFFFF; - ws.push(w); - - // compression - let s1 = rotate::value(e, 6) ^ rotate::value(e, 11) ^ rotate::value(e, 25); - let ch = (e & f) ^ (!e & g); - let temp1 = h + s1 + ch + (*round_cst as u64) + w; - let s0 = rotate::value(a, 2) ^ rotate::value(a, 13) ^ rotate::value(a, 22); - let maj = (a & b) ^ (a & c) ^ (b & c); - let temp2 = s0 + maj; - - h = g; - g = f; - f = e; - e = d + temp1; - d = c; - c = b; - b = a; - a = temp1 + temp2; - - // Add the row - add_row( - w_ext, - a, - e, - false, - if round < NUM_WORDS_TO_ABSORB { - length - } else { - 0 - }, - if round < NUM_WORDS_TO_ABSORB { - data_rlc - } else { - F::ZERO - }, - F::ZERO, - is_paddings, - inter_data_rlcs, - [F::ZERO; NUM_BYTES_FINAL_HASH], - ); - - // Truncate the newly calculated values - a &= 0xFFFFFFFF; - e &= 0xFFFFFFFF; - } - - // Accumulate - hs[0] += a; - hs[1] += b; - hs[2] += c; - hs[3] += d; - hs[4] += e; - hs[5] += f; - hs[6] += g; - hs[7] += h; - - // Squeeze - - let hash_rlc = if is_final_block { - let hash_bytes = hs - .iter() - .flat_map(|h| (*h as u32).to_be_bytes()) - .collect::>(); - rlc::value(&hash_bytes, rnd) - } else { - F::ZERO - }; - - let final_hash_bytes = if is_final_block { - let mut bytes = [F::ZERO; NUM_BYTES_FINAL_HASH]; - for (i, h) in hs.iter().enumerate() { - for (j, byte) in (*h as u32).to_be_bytes().into_iter().enumerate() { - bytes[4 * i + j] = F::from(byte as u64); - } - } - bytes - } else { - [F::ZERO; NUM_BYTES_FINAL_HASH] - }; - - // Add end rows - let mut add_row_end = |a: u64, e: u64| { - add_row( - 0, - a, - e, - false, - 0, - F::ZERO, - F::ZERO, - [false; ABSORB_WIDTH_PER_ROW_BYTES], - [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES], - [F::ZERO; NUM_BYTES_FINAL_HASH], - ) - }; - add_row_end(hs[3], hs[7]); - add_row_end(hs[2], hs[6]); - add_row_end(hs[1], hs[5]); - - add_row( - 0, - hs[0], - hs[4], - is_final_block, - length, - data_rlc, - hash_rlc, - [false, false, false, in_padding], - [F::ZERO; ABSORB_WIDTH_PER_ROW_BYTES], - final_hash_bytes, - ); - - // Now truncate the results - for h in hs.iter_mut() { - *h &= 0xFFFFFFFF; - } - } - - let hash_bytes = hs - .iter() - .flat_map(|h| (*h as u32).to_be_bytes()) - .collect::>(); - - debug!("hash: {:x?}", &hash_bytes); - debug!("data rlc: {:x?}", data_rlc); -} - -pub fn multi_sha256(inputs: &[HashInput], rnd: F) -> Vec> { - let inputs = inputs - .iter() - .map(|input| match input { - HashInput::Single(inner) => [inner.bytes.as_slice(), &[]], - HashInput::TwoToOne(left, right) => [left.bytes.as_slice(), right.bytes.as_slice()], - }) - .collect_vec(); - let mut rows: Vec> = Vec::new(); - for bytes in inputs { - sha256(&mut rows, &bytes, rnd); - } - rows -} diff --git a/lightclient-circuits/src/poseidon.rs b/lightclient-circuits/src/poseidon.rs index c9c4346a..3bd37087 100644 --- a/lightclient-circuits/src/poseidon.rs +++ b/lightclient-circuits/src/poseidon.rs @@ -9,7 +9,7 @@ use halo2curves::{ group::UncompressedEncoding, }; use itertools::Itertools; -// use pse_poseidon::Poseidon as PoseidonNative; +use pse_poseidon::Poseidon as PoseidonNative; const POSEIDON_SIZE: usize = 16; const R_F: usize = 8; @@ -55,16 +55,16 @@ pub fn fq_array_poseidon_native( .collect_vec() }) .collect_vec(); - // let mut poseidon = PoseidonNative::::new(R_F, R_P); + let mut poseidon = PoseidonNative::::new(R_F, R_P); let mut current_poseidon_hash = None; - // for (i, chunk) in limbs.chunks(POSEIDON_SIZE - 3).enumerate() { - // poseidon.update(chunk); - // if i != 0 { - // poseidon.update(&[current_poseidon_hash.unwrap()]); - // } - // let _ = current_poseidon_hash.insert(poseidon.squeeze()); - // } + for (i, chunk) in limbs.chunks(POSEIDON_SIZE - 3).enumerate() { + poseidon.update(chunk); + if i != 0 { + poseidon.update(&[current_poseidon_hash.unwrap()]); + } + let _ = current_poseidon_hash.insert(poseidon.squeeze()); + } Ok(current_poseidon_hash.unwrap()) } diff --git a/lightclient-circuits/src/ssz_merkle.rs b/lightclient-circuits/src/ssz_merkle.rs index d416c405..3a877ac4 100644 --- a/lightclient-circuits/src/ssz_merkle.rs +++ b/lightclient-circuits/src/ssz_merkle.rs @@ -83,258 +83,10 @@ pub fn verify_merkle_proof>( Ok(()) } -pub const ZERO_HASHES: [[u8; 32]; 64] = [ +pub const ZERO_HASHES: [[u8; 32]; 2] = [ [0; 32], [ 245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169, 39, 89, 251, 75, ], - [ - 219, 86, 17, 78, 0, 253, 212, 193, 248, 92, 137, 43, 243, 90, 201, 168, 146, 137, 170, 236, - 177, 235, 208, 169, 108, 222, 96, 106, 116, 139, 93, 113, - ], - [ - 199, 128, 9, 253, 240, 127, 197, 106, 17, 241, 34, 55, 6, 88, 163, 83, 170, 165, 66, 237, - 99, 228, 76, 75, 193, 95, 244, 205, 16, 90, 179, 60, - ], - [ - 83, 109, 152, 131, 127, 45, 209, 101, 165, 93, 94, 234, 233, 20, 133, 149, 68, 114, 213, - 111, 36, 109, 242, 86, 191, 60, 174, 25, 53, 42, 18, 60, - ], - [ - 158, 253, 224, 82, 170, 21, 66, 159, 174, 5, 186, 212, 208, 177, 215, 198, 77, 166, 77, 3, - 215, 161, 133, 74, 88, 140, 44, 184, 67, 12, 13, 48, - ], - [ - 216, 141, 223, 238, 212, 0, 168, 117, 85, 150, 178, 25, 66, 193, 73, 126, 17, 76, 48, 46, - 97, 24, 41, 15, 145, 230, 119, 41, 118, 4, 31, 161, - ], - [ - 135, 235, 13, 219, 165, 126, 53, 246, 210, 134, 103, 56, 2, 164, 175, 89, 117, 226, 37, 6, - 199, 207, 76, 100, 187, 107, 229, 238, 17, 82, 127, 44, - ], - [ - 38, 132, 100, 118, 253, 95, 197, 74, 93, 67, 56, 81, 103, 201, 81, 68, 242, 100, 63, 83, - 60, 200, 91, 185, 209, 107, 120, 47, 141, 125, 177, 147, - ], - [ - 80, 109, 134, 88, 45, 37, 36, 5, 184, 64, 1, 135, 146, 202, 210, 191, 18, 89, 241, 239, 90, - 165, 248, 135, 225, 60, 178, 240, 9, 79, 81, 225, - ], - [ - 255, 255, 10, 215, 230, 89, 119, 47, 149, 52, 193, 149, 200, 21, 239, 196, 1, 78, 241, 225, - 218, 237, 68, 4, 192, 99, 133, 209, 17, 146, 233, 43, - ], - [ - 108, 240, 65, 39, 219, 5, 68, 28, 216, 51, 16, 122, 82, 190, 133, 40, 104, 137, 14, 67, 23, - 230, 160, 42, 180, 118, 131, 170, 117, 150, 66, 32, - ], - [ - 183, 208, 95, 135, 95, 20, 0, 39, 239, 81, 24, 162, 36, 123, 187, 132, 206, 143, 47, 15, - 17, 35, 98, 48, 133, 218, 247, 150, 12, 50, 159, 95, - ], - [ - 223, 106, 245, 245, 187, 219, 107, 233, 239, 138, 166, 24, 228, 191, 128, 115, 150, 8, 103, - 23, 30, 41, 103, 111, 139, 40, 77, 234, 106, 8, 168, 94, - ], - [ - 181, 141, 144, 15, 94, 24, 46, 60, 80, 239, 116, 150, 158, 161, 108, 119, 38, 197, 73, 117, - 124, 194, 53, 35, 195, 105, 88, 125, 167, 41, 55, 132, - ], - [ - 212, 154, 117, 2, 255, 207, 176, 52, 11, 29, 120, 133, 104, 133, 0, 202, 48, 129, 97, 167, - 249, 107, 98, 223, 157, 8, 59, 113, 252, 200, 242, 187, - ], - [ - 143, 230, 177, 104, 146, 86, 192, 211, 133, 244, 47, 91, 190, 32, 39, 162, 44, 25, 150, - 225, 16, 186, 151, 193, 113, 211, 229, 148, 141, 233, 43, 235, - ], - [ - 141, 13, 99, 195, 158, 186, 222, 133, 9, 224, 174, 60, 156, 56, 118, 251, 95, 161, 18, 190, - 24, 249, 5, 236, 172, 254, 203, 146, 5, 118, 3, 171, - ], - [ - 149, 238, 200, 178, 229, 65, 202, 212, 233, 29, 227, 131, 133, 242, 224, 70, 97, 159, 84, - 73, 108, 35, 130, 203, 108, 172, 213, 185, 140, 38, 245, 164, - ], - [ - 248, 147, 233, 8, 145, 119, 117, 182, 43, 255, 35, 41, 77, 187, 227, 161, 205, 142, 108, - 193, 195, 91, 72, 1, 136, 123, 100, 106, 111, 129, 241, 127, - ], - [ - 205, 219, 167, 181, 146, 227, 19, 51, 147, 193, 97, 148, 250, 199, 67, 26, 191, 47, 84, - 133, 237, 113, 29, 178, 130, 24, 60, 129, 158, 8, 235, 170, - ], - [ - 138, 141, 127, 227, 175, 140, 170, 8, 90, 118, 57, 168, 50, 0, 20, 87, 223, 185, 18, 138, - 128, 97, 20, 42, 208, 51, 86, 41, 255, 35, 255, 156, - ], - [ - 254, 179, 195, 55, 215, 165, 26, 111, 191, 0, 185, 227, 76, 82, 225, 201, 25, 92, 150, 155, - 212, 231, 160, 191, 213, 29, 92, 91, 237, 156, 17, 103, - ], - [ - 231, 31, 10, 168, 60, 195, 46, 223, 190, 250, 159, 77, 62, 1, 116, 202, 133, 24, 46, 236, - 159, 58, 9, 246, 166, 192, 223, 99, 119, 165, 16, 215, - ], - [ - 49, 32, 111, 168, 10, 80, 187, 106, 190, 41, 8, 80, 88, 241, 98, 18, 33, 42, 96, 238, 200, - 240, 73, 254, 203, 146, 216, 200, 224, 168, 75, 192, - ], - [ - 33, 53, 43, 254, 203, 237, 221, 233, 147, 131, 159, 97, 76, 61, 172, 10, 62, 227, 117, 67, - 249, 180, 18, 177, 97, 153, 220, 21, 142, 35, 181, 68, - ], - [ - 97, 158, 49, 39, 36, 187, 109, 124, 49, 83, 237, 157, 231, 145, 215, 100, 163, 102, 179, - 137, 175, 19, 197, 139, 248, 168, 217, 4, 129, 164, 103, 101, - ], - [ - 124, 221, 41, 134, 38, 130, 80, 98, 141, 12, 16, 227, 133, 197, 140, 97, 145, 230, 251, - 224, 81, 145, 188, 192, 79, 19, 63, 44, 234, 114, 193, 196, - ], - [ - 132, 137, 48, 189, 123, 168, 202, 197, 70, 97, 7, 33, 19, 251, 39, 136, 105, 224, 123, 184, - 88, 127, 145, 57, 41, 51, 55, 77, 1, 123, 203, 225, - ], - [ - 136, 105, 255, 44, 34, 178, 140, 193, 5, 16, 217, 133, 50, 146, 128, 51, 40, 190, 79, 176, - 232, 4, 149, 232, 187, 141, 39, 31, 91, 136, 150, 54, - ], - [ - 181, 254, 40, 231, 159, 27, 133, 15, 134, 88, 36, 108, 233, 182, 161, 231, 180, 159, 192, - 109, 183, 20, 62, 143, 224, 180, 242, 176, 197, 82, 58, 92, - ], - [ - 152, 94, 146, 159, 112, 175, 40, 208, 189, 209, 169, 10, 128, 143, 151, 127, 89, 124, 124, - 119, 140, 72, 158, 152, 211, 189, 137, 16, 211, 26, 192, 247, - ], - [ - 198, 246, 126, 2, 230, 228, 225, 189, 239, 185, 148, 198, 9, 137, 83, 243, 70, 54, 186, 43, - 108, 162, 10, 71, 33, 210, 178, 106, 136, 103, 34, 255, - ], - [ - 28, 154, 126, 95, 241, 207, 72, 180, 173, 21, 130, 211, 244, 228, 161, 0, 79, 59, 32, 216, - 197, 162, 183, 19, 135, 164, 37, 74, 217, 51, 235, 197, - ], - [ - 47, 7, 90, 226, 41, 100, 107, 111, 106, 237, 25, 165, 227, 114, 207, 41, 80, 129, 64, 30, - 184, 147, 255, 89, 155, 63, 154, 204, 12, 13, 62, 125, - ], - [ - 50, 137, 33, 222, 181, 150, 18, 7, 104, 1, 232, 205, 97, 89, 33, 7, 181, 198, 124, 121, - 184, 70, 89, 92, 198, 50, 12, 57, 91, 70, 54, 44, - ], - [ - 191, 185, 9, 253, 178, 54, 173, 36, 17, 180, 228, 136, 56, 16, 160, 116, 184, 64, 70, 70, - 137, 152, 108, 63, 138, 128, 145, 130, 126, 23, 195, 39, - ], - [ - 85, 216, 251, 54, 135, 186, 59, 164, 159, 52, 44, 119, 245, 161, 248, 155, 236, 131, 216, - 17, 68, 110, 26, 70, 113, 57, 33, 61, 100, 11, 106, 116, - ], - [ - 247, 33, 13, 79, 142, 126, 16, 57, 121, 14, 123, 244, 239, 162, 7, 85, 90, 16, 166, 219, - 29, 212, 185, 93, 163, 19, 170, 168, 139, 136, 254, 118, - ], - [ - 173, 33, 181, 22, 203, 198, 69, 255, 227, 74, 181, 222, 28, 138, 239, 140, 212, 231, 248, - 210, 181, 30, 142, 20, 86, 173, 199, 86, 60, 218, 32, 111, - ], - [ - 107, 254, 141, 43, 204, 66, 55, 183, 74, 80, 71, 5, 142, 244, 85, 51, 158, 205, 115, 96, - 203, 99, 191, 187, 142, 229, 68, 142, 100, 48, 186, 4, - ], - [ - 167, 242, 60, 233, 24, 23, 64, 220, 34, 12, 129, 71, 130, 101, 79, 238, 106, 206, 185, 241, - 236, 146, 34, 196, 226, 70, 125, 10, 177, 104, 8, 55, - ], - [ - 174, 249, 71, 108, 137, 89, 10, 44, 140, 201, 179, 183, 79, 73, 103, 199, 87, 196, 157, - 152, 102, 164, 75, 172, 242, 31, 162, 237, 103, 93, 223, 162, - ], - [ - 154, 66, 188, 173, 130, 246, 169, 228, 18, 132, 216, 8, 234, 211, 25, 242, 159, 59, 8, 32, - 157, 104, 15, 14, 44, 231, 21, 16, 208, 113, 226, 5, - ], - [ - 209, 166, 109, 53, 74, 103, 185, 207, 23, 149, 113, 216, 229, 249, 119, 146, 113, 110, 141, - 212, 236, 68, 25, 104, 57, 163, 247, 198, 183, 79, 139, 172, - ], - [ - 250, 250, 48, 37, 242, 248, 149, 9, 194, 199, 28, 116, 251, 160, 205, 146, 133, 142, 244, - 155, 7, 128, 251, 84, 121, 116, 108, 138, 155, 252, 179, 70, - ], - [ - 51, 52, 167, 193, 231, 246, 112, 90, 166, 1, 26, 106, 148, 150, 69, 1, 109, 180, 172, 222, - 12, 169, 171, 214, 109, 199, 157, 130, 102, 66, 48, 86, - ], - [ - 7, 150, 253, 117, 102, 79, 174, 247, 68, 238, 78, 82, 215, 39, 30, 43, 187, 118, 159, 145, - 237, 111, 155, 116, 216, 182, 148, 245, 102, 6, 133, 44, - ], - [ - 123, 163, 174, 74, 65, 127, 232, 84, 91, 20, 43, 200, 159, 74, 220, 215, 174, 19, 148, 28, - 186, 183, 117, 11, 131, 233, 240, 166, 109, 22, 190, 100, - ], - [ - 120, 143, 175, 204, 74, 165, 32, 57, 154, 219, 174, 209, 149, 248, 177, 44, 78, 179, 30, - 193, 1, 104, 229, 10, 171, 198, 89, 166, 174, 165, 22, 220, - ], - [ - 232, 51, 215, 166, 113, 96, 230, 139, 244, 201, 4, 74, 83, 7, 125, 242, 114, 122, 208, 12, - 243, 111, 73, 73, 199, 182, 129, 169, 18, 20, 12, 187, - ], - [ - 48, 158, 171, 240, 149, 220, 103, 20, 249, 244, 216, 100, 187, 165, 175, 250, 224, 179, 90, - 226, 245, 227, 86, 91, 204, 58, 71, 178, 18, 118, 119, 1, - ], - [ - 34, 106, 142, 190, 250, 40, 134, 101, 166, 68, 165, 2, 115, 51, 94, 251, 182, 16, 81, 15, - 36, 27, 91, 114, 12, 138, 54, 141, 89, 166, 154, 93, - ], - [ - 65, 171, 253, 153, 84, 37, 130, 118, 37, 147, 129, 49, 175, 12, 79, 51, 254, 11, 212, 104, - 140, 34, 44, 33, 250, 157, 168, 232, 156, 170, 3, 248, - ], - [ - 68, 44, 100, 46, 245, 15, 161, 166, 103, 166, 230, 209, 5, 199, 124, 92, 195, 254, 200, - 215, 170, 37, 112, 207, 26, 48, 119, 181, 3, 195, 128, 105, - ], - [ - 160, 160, 141, 252, 155, 66, 217, 108, 45, 225, 155, 109, 18, 123, 138, 225, 54, 221, 207, - 62, 90, 208, 220, 228, 34, 196, 90, 86, 246, 31, 106, 116, - ], - [ - 125, 52, 131, 130, 175, 9, 109, 190, 11, 240, 134, 199, 187, 57, 178, 162, 192, 188, 54, - 182, 33, 171, 12, 115, 142, 152, 133, 215, 49, 216, 23, 64, - ], - [ - 58, 177, 52, 117, 29, 25, 18, 105, 2, 108, 134, 153, 78, 170, 139, 67, 168, 59, 74, 209, - 246, 208, 231, 115, 129, 196, 226, 151, 74, 251, 200, 246, - ], - [ - 154, 116, 82, 97, 29, 178, 210, 62, 174, 38, 249, 189, 187, 136, 149, 142, 244, 76, 100, - 208, 254, 152, 123, 233, 247, 38, 173, 249, 56, 245, 15, 108, - ], - [ - 114, 92, 127, 129, 96, 55, 191, 228, 82, 205, 30, 123, 163, 90, 196, 126, 220, 180, 154, - 154, 43, 39, 174, 202, 112, 220, 228, 131, 203, 125, 237, 31, - ], - [ - 44, 234, 26, 245, 31, 178, 139, 98, 136, 124, 57, 153, 138, 201, 254, 244, 223, 222, 218, - 31, 7, 224, 113, 186, 85, 138, 23, 58, 253, 6, 203, 195, - ], - [ - 255, 29, 89, 249, 139, 108, 85, 29, 149, 8, 147, 87, 5, 125, 92, 139, 226, 100, 2, 39, 158, - 157, 240, 177, 223, 26, 16, 183, 43, 243, 146, 127, - ], - [ - 47, 138, 24, 31, 124, 153, 221, 33, 90, 117, 41, 191, 226, 150, 169, 96, 58, 20, 70, 115, - 113, 134, 210, 26, 235, 139, 199, 174, 89, 225, 253, 33, - ], - [ - 236, 197, 2, 201, 177, 20, 95, 57, 80, 203, 125, 62, 56, 66, 68, 111, 129, 164, 240, 223, - 29, 245, 55, 206, 225, 57, 239, 100, 234, 152, 75, 217, - ], ]; diff --git a/lightclient-circuits/src/util.rs b/lightclient-circuits/src/util.rs index 4ae8e821..2782f3d1 100644 --- a/lightclient-circuits/src/util.rs +++ b/lightclient-circuits/src/util.rs @@ -3,9 +3,6 @@ mod common; pub use common::*; -mod constraint_builder; -pub(crate) use constraint_builder::*; - mod conversion; pub(crate) use conversion::*; @@ -17,48 +14,6 @@ pub use circuit::*; use eth_types::*; -/// Helper trait that implements functionality to represent a generic type as -/// array of N-bits. -pub trait AsBits { - /// Return the bits of self, starting from the most significant. - fn as_bits(&self) -> [bool; N]; -} - -/// Packs bits into bytes -pub mod to_bytes { - use crate::gadget::Expr; - use eth_types::Field; - use halo2_base::halo2_proofs::plonk::Expression; - - pub(crate) fn expr(bits: &[Expression]) -> Vec> { - debug_assert!(bits.len() % 8 == 0, "bits not a multiple of 8"); - let mut bytes = Vec::new(); - for byte_bits in bits.chunks(8) { - let mut value = 0.expr(); - let mut multiplier = F::ONE; - for byte in byte_bits.iter() { - value = value + byte.expr() * multiplier; - multiplier *= F::from(2); - } - bytes.push(value); - } - bytes - } - - pub(crate) fn value(bits: &[u8]) -> Vec { - debug_assert!(bits.len() % 8 == 0, "bits not a multiple of 8"); - let mut bytes = Vec::new(); - for byte_bits in bits.chunks(8) { - let mut value = 0u8; - for (idx, bit) in byte_bits.iter().enumerate() { - value += *bit << idx; - } - bytes.push(value); - } - bytes - } -} - pub fn bigint_to_le_bytes( limbs: impl IntoIterator, limb_bits: usize, diff --git a/lightclient-circuits/src/util/circuit.rs b/lightclient-circuits/src/util/circuit.rs index f03bad77..126dcb4f 100644 --- a/lightclient-circuits/src/util/circuit.rs +++ b/lightclient-circuits/src/util/circuit.rs @@ -12,7 +12,6 @@ use halo2_base::halo2_proofs::{ poly::commitment::Params, poly::kzg::commitment::ParamsKZG, }; -use halo2_base::utils::BigPrimeField; use serde::{Deserialize, Serialize}; use snark_verifier_sdk::evm::{ encode_calldata, evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk, diff --git a/lightclient-circuits/src/util/common.rs b/lightclient-circuits/src/util/common.rs index 32e18aaf..aa481ec6 100644 --- a/lightclient-circuits/src/util/common.rs +++ b/lightclient-circuits/src/util/common.rs @@ -1,119 +1,16 @@ #![allow(dead_code)] -use crate::gadget::Expr; use eth_types::*; use halo2_base::{ gates::circuit::CircuitBuilderStage, halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, - poly::Rotation, + circuit::{Layouter, Region}, + plonk::{ConstraintSystem, Error}, }, virtual_region::{ copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, }, }; -use std::hash::Hash; - -#[derive(Clone, Debug)] -pub struct Cell { - // expression for constraint - expression: Expression, - column: Column, - // relative position to selector for synthesis - rotation: usize, - cell_column_index: usize, -} - -impl Cell { - pub(crate) fn new( - meta: &mut VirtualCells, - column: Column, - rotation: usize, - cell_column_index: usize, - ) -> Self { - Self { - expression: meta.query_advice(column, Rotation(rotation as i32)), - column, - rotation, - cell_column_index, - } - } - - pub(crate) fn assign( - &self, - region: &mut Region<'_, F>, - offset: usize, - value: Value, - ) -> Result, Error> { - region.assign_advice( - || { - format!( - "Cell column: {:?} and rotation: {}", - self.column, self.rotation - ) - }, - self.column, - offset + self.rotation, - || value, - ) - } -} - -impl Expr for Cell { - fn expr(&self) -> Expression { - self.expression.clone() - } -} - -impl Expr for &Cell { - fn expr(&self) -> Expression { - self.expression.clone() - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum CellType { - StoragePhase1, - StoragePhase2, - StoragePermutation, - LookupByte, - // Lookup(Table), -} - -impl CellType { - // The phase that given `Expression` becomes evaluateable. - fn expr_phase(expr: &Expression) -> u8 { - use Expression::*; - match expr { - Challenge(challenge) => challenge.phase() + 1, - Advice(query) => query.phase(), - Constant(_) | Selector(_) | Fixed(_) | Instance(_) => 0, - Negated(a) | Expression::Scaled(a, _) => Self::expr_phase(a), - Sum(a, b) | Product(a, b) => std::cmp::max(Self::expr_phase(a), Self::expr_phase(b)), - } - } - - /// Return the storage phase of phase - pub(crate) fn storage_for_phase(phase: u8) -> CellType { - match phase { - 0 => CellType::StoragePhase1, - 1 => CellType::StoragePhase2, - _ => unreachable!(), - } - } - - /// Return the storage cell of the expression - pub(crate) fn storage_for_expr(expr: &Expression) -> CellType { - Self::storage_for_phase(Self::expr_phase::(expr)) - } - - /// Return the storage cell of the advice column - pub(crate) fn storage_for_column(col: &Column) -> CellType { - Self::storage_for_phase(col.column_type().phase()) - } -} - pub trait GateBuilderConfig: Clone + Sized { fn configure(meta: &mut ConstraintSystem) -> Self; diff --git a/lightclient-circuits/src/util/constraint_builder.rs b/lightclient-circuits/src/util/constraint_builder.rs deleted file mode 100644 index b62b6e70..00000000 --- a/lightclient-circuits/src/util/constraint_builder.rs +++ /dev/null @@ -1,186 +0,0 @@ -use crate::gadget::Expr; -use eth_types::Field; -use halo2_base::halo2_proofs::plonk::Expression; - -use super::{Cell, CellType}; - -pub(crate) trait ConstrainBuilderCommon { - fn add_constraint(&mut self, name: &'static str, constraint: Expression); - - fn require_zero(&mut self, name: &'static str, constraint: Expression) { - self.add_constraint(name, constraint); - } - - fn require_equal(&mut self, name: &'static str, lhs: Expression, rhs: Expression) { - self.add_constraint(name, lhs - rhs); - } - - fn require_boolean(&mut self, name: &'static str, value: Expression) { - self.add_constraint(name, value.clone() * (1.expr() - value)); - } - - fn require_true(&mut self, name: &'static str, e: Expression) { - self.require_equal(name, e, 1.expr()); - } - - fn require_in_set( - &mut self, - name: &'static str, - value: Expression, - set: Vec>, - ) { - self.add_constraint( - name, - set.iter() - .fold(1.expr(), |acc, item| acc * (value.clone() - item.clone())), - ); - } - - fn add_constraints(&mut self, constraints: Vec<(&'static str, Expression)>) { - for (name, constraint) in constraints { - self.add_constraint(name, constraint); - } - } - - fn condition( - &mut self, - condition: Expression, - constraint: impl FnOnce(&mut Self) -> R, - ) -> R; - - fn query_bool(&mut self) -> Cell { - let cell = self.query_cell(); - self.require_boolean("Constrain cell to be a bool", cell.expr()); - cell - } - - fn query_bytes(&mut self) -> [Cell; N] { - self.query_bytes_dyn(N).try_into().unwrap() - } - - fn query_bytes_dyn(&mut self, count: usize) -> Vec> { - self.query_cells(CellType::LookupByte, count) - } - - fn query_cell(&mut self) -> Cell { - self.query_cell_with_type(CellType::StoragePhase1) - } - - fn query_cell_phase2(&mut self) -> Cell { - self.query_cell_with_type(CellType::StoragePhase2) - } - - fn query_copy_cell(&mut self) -> Cell { - self.query_cell_with_type(CellType::StoragePermutation) - } - - fn query_cell_with_type(&mut self, cell_type: CellType) -> Cell { - self.query_cells(cell_type, 1).first().unwrap().clone() - } - - fn query_cells(&mut self, cell_type: CellType, count: usize) -> Vec>; -} - -#[derive(Default)] -pub struct BaseConstraintBuilder { - pub constraints: Vec<(&'static str, Expression)>, - pub max_degree: usize, - pub condition: Option>, -} - -impl BaseConstraintBuilder { - pub(crate) fn new(max_degree: usize) -> Self { - BaseConstraintBuilder { - constraints: Vec::new(), - max_degree, - condition: None, - } - } - - #[allow(dead_code)] - pub(crate) fn require_zero(&mut self, name: &'static str, constraint: Expression) { - self.add_constraint(name, constraint); - } - - pub(crate) fn require_equal( - &mut self, - name: &'static str, - lhs: Expression, - rhs: Expression, - ) { - self.add_constraint(name, lhs - rhs); - } - - pub(crate) fn require_boolean(&mut self, name: &'static str, value: Expression) { - self.add_constraint(name, value.clone() * (1.expr() - value)); - } - - #[allow(dead_code)] - pub(crate) fn require_in_set( - &mut self, - name: &'static str, - value: Expression, - set: Vec>, - ) { - self.add_constraint( - name, - set.iter() - .fold(1.expr(), |acc, item| acc * (value.clone() - item.clone())), - ); - } - - pub(crate) fn condition( - &mut self, - condition: Expression, - constraint: impl FnOnce(&mut Self) -> R, - ) -> R { - debug_assert!( - self.condition.is_none(), - "Nested condition is not supported" - ); - self.condition = Some(condition); - let ret = constraint(self); - self.condition = None; - ret - } - - #[allow(dead_code)] - pub(crate) fn add_constraints(&mut self, constraints: Vec<(&'static str, Expression)>) { - for (name, constraint) in constraints { - self.add_constraint(name, constraint); - } - } - - pub(crate) fn add_constraint(&mut self, name: &'static str, constraint: Expression) { - let constraint = match &self.condition { - Some(condition) => condition.clone() * constraint, - None => constraint, - }; - self.validate_degree(constraint.degree(), name); - self.constraints.push((name, constraint)); - } - - pub(crate) fn validate_degree(&self, degree: usize, name: &'static str) { - if self.max_degree > 0 { - debug_assert!( - degree <= self.max_degree, - "Expression {} degree too high: {} > {}", - name, - degree, - self.max_degree, - ); - } - } - - pub(crate) fn gate(&self, selector: Expression) -> Vec<(&'static str, Expression)> { - self.constraints - .clone() - .into_iter() - .map(|(name, constraint)| (name, selector.clone() * constraint)) - .filter(|(name, constraint)| { - self.validate_degree(constraint.degree(), name); - true - }) - .collect() - } -} diff --git a/lightclient-circuits/src/witness/rotation.rs b/lightclient-circuits/src/witness/rotation.rs index 5efb889e..309e7a91 100644 --- a/lightclient-circuits/src/witness/rotation.rs +++ b/lightclient-circuits/src/witness/rotation.rs @@ -1,24 +1,21 @@ -use crate::gadget::crypto::constant_randomness; -use eth_types::{Field, Spec}; +use eth_types::Spec; use ethereum_consensus_types::BeaconBlockHeader; use itertools::Itertools; use serde::{Deserialize, Serialize}; use std::{iter, marker::PhantomData}; #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CommitteeRotationArgs { +pub struct CommitteeRotationArgs { pub pubkeys_compressed: Vec>, pub finalized_header: BeaconBlockHeader, pub sync_committee_branch: Vec>, - pub randomness: F, - pub _spec: PhantomData, } -impl Default for CommitteeRotationArgs { +impl Default for CommitteeRotationArgs { fn default() -> Self { let dummy_x_bytes = iter::once(192).pad_using(48, |_| 0).rev().collect(); @@ -29,7 +26,6 @@ impl Default for CommitteeRotationArgs { .take(S::SYNC_COMMITTEE_SIZE) .collect_vec(), sync_committee_branch, - randomness: constant_randomness(), finalized_header: Default::default(), _spec: PhantomData, } diff --git a/preprocessor/src/lib.rs b/preprocessor/src/lib.rs index 97594a12..203346fd 100644 --- a/preprocessor/src/lib.rs +++ b/preprocessor/src/lib.rs @@ -11,7 +11,6 @@ use ethereum_consensus_types::{ LightClientUpdateCapella, Root, }; use itertools::Itertools; -use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use lightclient_circuits::witness::{CommitteeRotationArgs, SyncStepArgs}; use serde::{Deserialize, Serialize}; use ssz_rs::{Node, Vector}; @@ -32,7 +31,7 @@ pub async fn light_client_update_to_args( >, pubkeys_compressed: Vector, domain: [u8; 32], -) -> eyre::Result<(SyncStepArgs, CommitteeRotationArgs)> +) -> eyre::Result<(SyncStepArgs, CommitteeRotationArgs)> where [(); S::SYNC_COMMITTEE_SIZE]:, [(); S::FINALIZED_HEADER_DEPTH]:, diff --git a/preprocessor/src/rotation.rs b/preprocessor/src/rotation.rs index d295aab2..62186a57 100644 --- a/preprocessor/src/rotation.rs +++ b/preprocessor/src/rotation.rs @@ -4,8 +4,7 @@ use beacon_api_client::{BlockId, Client, ClientTypes}; use eth_types::Spec; use ethereum_consensus_types::{BeaconBlockHeader, LightClientUpdateCapella}; use itertools::Itertools; -use lightclient_circuits::halo2_base::halo2_proofs::halo2curves::bn256::Fr; -use lightclient_circuits::{gadget::crypto, witness::CommitteeRotationArgs}; +use lightclient_circuits::witness::CommitteeRotationArgs; use log::debug; use ssz_rs::Merkleized; use tokio::fs; @@ -14,7 +13,7 @@ use crate::{get_block_header, get_light_client_update_at_period}; pub async fn fetch_rotation_args( client: &Client, -) -> eyre::Result> +) -> eyre::Result> where [(); S::SYNC_COMMITTEE_SIZE]:, [(); S::FINALIZED_HEADER_DEPTH]:, @@ -46,7 +45,7 @@ pub async fn rotation_args_from_update( { S::BYTES_PER_LOGS_BLOOM }, { S::MAX_EXTRA_DATA_BYTES }, >, -) -> eyre::Result> +) -> eyre::Result> where [(); S::SYNC_COMMITTEE_SIZE]:, [(); S::FINALIZED_HEADER_DEPTH]:, @@ -88,9 +87,8 @@ where "Execution payload merkle proof verification failed" ); - let args = CommitteeRotationArgs:: { + let args = CommitteeRotationArgs:: { pubkeys_compressed, - randomness: crypto::constant_randomness(), finalized_header: update.attested_header.beacon.clone(), sync_committee_branch: sync_committee_branch .into_iter() @@ -101,9 +99,7 @@ where Ok(args) } -pub async fn read_rotation_args( - path: String, -) -> eyre::Result> { +pub async fn read_rotation_args(path: String) -> eyre::Result> { #[derive(serde::Deserialize)] struct ArgsJson { finalized_header: BeaconBlockHeader, @@ -122,9 +118,8 @@ pub async fn read_rotation_args( ) .map_err(|e| eyre::eyre!("Error decoding witness {}", e))?; - Ok(CommitteeRotationArgs:: { + Ok(CommitteeRotationArgs:: { pubkeys_compressed, - randomness: crypto::constant_randomness(), finalized_header, sync_committee_branch: committee_root_branch, _spec: PhantomData, @@ -176,7 +171,7 @@ mod tests { "../build/sync_step.pkey", CONFIG_PATH, false, - &CommitteeRotationArgs::::default(), + &CommitteeRotationArgs::::default(), ); let client = MainnetClient::new(Url::parse("http://65.109.55.120:9596").unwrap()); let witness = fetch_rotation_args::(&client).await.unwrap(); diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index 8fcc4b82..57e988dd 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -98,10 +98,8 @@ pub(crate) async fn gen_evm_proof_rotation_circuit_handler( Spec::Minimal => { let app_pk_path = PathBuf::from("./build/committee_update_circuit_minimal.pkey"); let client = beacon_api_client::minimal::Client::new(Url::parse(&beacon_api)?); - let witness: lightclient_circuits::witness::CommitteeRotationArgs< - eth_types::Minimal, - Fr, - > = fetch_rotation_args(&client).await?; + let witness: lightclient_circuits::witness::CommitteeRotationArgs = + fetch_rotation_args(&client).await?; gen_app_snark::(app_config_path, app_pk_path, witness)? } Spec::Testnet => { diff --git a/test-utils/src/conversions.rs b/test-utils/src/conversions.rs index 753b45d2..cea03da9 100644 --- a/test-utils/src/conversions.rs +++ b/test-utils/src/conversions.rs @@ -33,7 +33,7 @@ pub fn sync_input_from_args(args: SyncStepArgs) -> } pub fn rotate_input_from_args( - args: CommitteeRotationArgs, + args: CommitteeRotationArgs, ) -> RotateInput where [(); Spec::SYNC_COMMITTEE_SIZE]:, diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index 1e8f1529..52563073 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -10,8 +10,6 @@ use ethereum_consensus_types::BeaconBlockHeader; use ethereum_consensus_types::{ForkData, Root}; use itertools::Itertools; use light_client_verifier::ZiplineUpdateWitnessCapella; -use lightclient_circuits::gadget::crypto; -use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use lightclient_circuits::poseidon::{ poseidon_committee_commitment_from_compressed, poseidon_committee_commitment_from_uncompressed, }; @@ -82,7 +80,7 @@ pub fn valid_updates_from_test_path( pub fn read_test_files_and_gen_witness( path: &Path, -) -> (SyncStepArgs, CommitteeRotationArgs) { +) -> (SyncStepArgs, CommitteeRotationArgs) { let bootstrap: LightClientBootstrap = load_snappy_ssz(path.join("bootstrap.ssz_snappy").to_str().unwrap()).unwrap(); @@ -113,7 +111,7 @@ pub fn read_test_files_and_gen_witness( sync_committee_branch.insert(0, agg_pk.hash_tree_root().unwrap().deref().to_vec()); - let rotation_wit = CommitteeRotationArgs:: { + let rotation_wit = CommitteeRotationArgs:: { pubkeys_compressed: zipline_witness .light_client_update .next_sync_committee @@ -122,7 +120,6 @@ pub fn read_test_files_and_gen_witness( .cloned() .map(|pk| pk.to_bytes().to_vec()) .collect_vec(), - randomness: crypto::constant_randomness(), finalized_header: sync_wit.attested_header.clone(), sync_committee_branch, _spec: Default::default(), From ad2d8ad1387318c68fb4dbac116ac6d0dedf193c Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Mon, 27 Nov 2023 16:27:40 +0100 Subject: [PATCH 19/23] fix endianness --- Cargo.toml | 26 +++++++++---------- .../src/gadget/crypto/sha256_wide.rs | 5 ++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2b0438c1..b72e7da0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,6 @@ ff = "0.12" sha2 = { version = "0.10.6", features = ["compress"] } uint = "0.9.1" ark-std = { version = "0.4.0", features = ["print-trace"] } -# poseidon_native = { git = "https://github.com/axiom-crypto/halo2.git", branch = "axiom/dev", package = "poseidon" } # misc itertools = "0.11.0" @@ -90,23 +89,24 @@ ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa0 [patch."https://github.com/axiom-crypto/halo2-lib"] -# halo2-base = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ -# "halo2-pse", -# "display", -# "jemallocator" -# ] } -# halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/bls12-381-hash2curve", default-features = false, features = [ -# "halo2-pse", -# "jemallocator" -# ] } -halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ +halo2-base = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/zkevm-sha256-builder", default-features = false, features = [ "halo2-pse", "display", + "jemallocator" ] } -halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false, features = [ +halo2-ecc = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/zkevm-sha256-builder", default-features = false, features = [ "halo2-pse", + "jemallocator" ] } -zkevm-hashes = { path = "../halo2-lib/hashes/zkevm", default-features = false } +zkevm-hashes = { git = "https://github.com/timoftime/halo2-lib", branch = "feat/zkevm-sha256-builder", default-features = false } +# halo2-base = { path = "../halo2-lib/halo2-base", default-features = false, features = [ +# "halo2-pse", +# "display", +# ] } +# halo2-ecc = { path = "../halo2-lib/halo2-ecc", default-features = false, features = [ +# "halo2-pse", +# ] } +# zkevm-hashes = { path = "../halo2-lib/hashes/zkevm", default-features = false } [patch."https://github.com/axiom-crypto/snark-verifier.git"] diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs index 5cd7e7a5..ed8a46d6 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs @@ -83,8 +83,9 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { } } - let hash_bytes = word_to_bytes_le(blocks[num_rounds - 1].hash, gate, builder.main()); - + let mut hash_bytes = word_to_bytes_le(blocks[num_rounds - 1].hash, gate, builder.main()); + hash_bytes.reverse(); + Ok(hash_bytes) } From f1d409f913dc754a584620f20efd8d523f8b1b86 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Mon, 27 Nov 2023 22:05:39 +0100 Subject: [PATCH 20/23] remove redundant tests --- .../src/committee_update_circuit.rs | 150 +----------------- 1 file changed, 7 insertions(+), 143 deletions(-) diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 558cb40b..61ac3691 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -349,55 +349,16 @@ mod tests { ) .expect("proof generation & verification should not fail"); } - + #[test] - fn test_circuit_aggregation_proofgen() { - const APP_PINNING_PATH: &str = "./config/committee_update_18.json"; - const APP_PK_PATH: &str = "../build/committee_update_18.pkey"; - const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; + fn test_committee_update_aggregation_evm() { const APP_K: u32 = 18; + const APP_PK_PATH: &str = "../build/committee_update_18.pkey"; + const APP_PINNING_PATH: &str = "./config/committee_update_18.json"; + const AGG_CONFIG_PATH: &str = "./config/committee_update_aggr_25.json"; let params_app = gen_srs(APP_K); - const AGG_K: u32 = 22; - let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( - ¶ms_app, - APP_PK_PATH, - APP_PINNING_PATH, - false, - &CommitteeRotationArgs::::default(), - ); - let witness = load_circuit_args(); - let snark = gen_application_snark(¶ms_app, &pk_app, &witness, APP_PINNING_PATH); - - let params = gen_srs(AGG_K); - println!("agg_params k: {:?}", params.k()); - - let pk = AggregationCircuit::read_or_create_pk( - ¶ms, - "../build/committee_update_aggregation_22.pkey", - AGG_CONFIG_PATH, - false, - &vec![snark.clone()], - ); - - let _ = AggregationCircuit::gen_proof_shplonk( - ¶ms, - &pk, - AGG_CONFIG_PATH, - &vec![snark.clone()], - ) - .expect("proof generation & verification should not fail"); - } - - #[test] - fn test_circuit_aggregation_evm() { - const APP_K: u32 = 21; - const APP_PK_PATH: &str = "../build/committee_update_21.pkey"; - const APP_PINNING_PATH: &str = "./config/committee_update_21.json"; - const AGG_CONFIG_PATH: &str = "./config/committee_update_a.json"; - let params_app = gen_srs(APP_K); - - const AGG_K: u32 = 23; + const AGG_K: u32 = 25; let pk_app = CommitteeUpdateCircuit::::read_or_create_pk( ¶ms_app, APP_PK_PATH, @@ -414,7 +375,7 @@ mod tests { let pk = AggregationCircuit::read_or_create_pk( ¶ms, - "../build/aggregation.pkey", + "../build/aggregation_25.pkey", AGG_CONFIG_PATH, false, &vec![snark.clone()], @@ -448,101 +409,4 @@ mod tests { println!("deployment_code size: {}", deployment_code.len()); evm_verify(deployment_code, instances, proof); } - - // #[test] - // fn test_circuit_aggregation_2_evm() { - // const K0: u32 = 20; - // const K1: u32 = 24; - // const K2: u32 = 24; - - // const APP_CONFIG_PATH: &str = "./config/committee_update_aggregation.json"; - // const AGG_CONFIG_PATH: &str = "./config/committee_update_aggregation_1.json"; - // const AGG_FINAL_CONFIG_PATH: &str = "./config/committee_update_aggregation_2.json"; - - // // Layer 0 snark gen - // let l0_snark = { - // let p0 = gen_srs(K0); - // let pk_l0 = CommitteeUpdateCircuit::::read_or_create_pk( - // &p0, - // "../build/committee_update.pkey", - // APP_CONFIG_PATH, - // false, - // &CommitteeRotationArgs::::default(), - // ); - // let witness = load_circuit_args(); - // let snark = gen_application_snark(&p0, &pk_l0, &witness); - // println!( - // "L0 num instances: {:?}", - // snark.instances.iter().map(|i| i.len()).collect_vec() - // ); - // println!("L0 snark size: {}", snark.proof.len()); - // snark - // }; - - // // Layer 1 snark gen - // let l1_snark = { - // let p1 = gen_srs(K1); - // let pk_l1 = AggregationCircuit::read_or_create_pk( - // &p1, - // "./build/l1_aggregation.pkey", - // AGG_CONFIG_PATH, - // false, - // &vec![l0_snark.clone()], - // ); - - // let pinning = AggregationConfigPinning::from_path(AGG_CONFIG_PATH); - // let lookup_bits = K1 as usize - 1; - // let circuit = AggregationCircuit::create_circuit( - // CircuitBuilderStage::Prover, - // Some(pinning), - // &vec![l0_snark.clone()], - // K1, - // ) - // .unwrap(); - - // println!("L1 Prover num_instances: {:?}", circuit.num_instance()); - // let snark = gen_snark_shplonk(&p1, &pk_l1, circuit, None::); - // println!("L1 snark size: {}", snark.proof.len()); - - // snark - // }; - - // // Layer 2 snark gen - // let (proof, deployment_code, instances) = { - // let p2 = gen_srs(K2); - // let pk_l2 = AggregationCircuit::read_or_create_pk( - // &p2, - // "./build/l2_aggregation.pkey", - // AGG_FINAL_CONFIG_PATH, - // false, - // &vec![l0_snark.clone()], - // ); - // let pinning = AggregationConfigPinning::from_path(AGG_FINAL_CONFIG_PATH); - - // let mut circuit = AggregationCircuit::create_circuit( - // CircuitBuilderStage::Prover, - // Some(pinning), - // &vec![l1_snark.clone()], - // K2, - // ) - // .unwrap(); - // let num_instances = circuit.num_instance(); - - // let deployment_code = gen_evm_verifier_shplonk::( - // &p2, - // pk_l2.get_vk(), - // vec![65], - // Some(&PathBuf::from("contractyul")), - // ); - // let instances = circuit.instances(); - // println!("L2 Prover num_instances: {:?}", num_instances); - - // let proof = gen_evm_proof_shplonk(&p2, &pk_l2, circuit, instances.clone()); - // println!("L2 proof size: {}", proof.len()); - // println!("L2 Deployment Code Size: {}", deployment_code.len()); - // (proof, deployment_code, instances) - // }; - - // evm_verify(deployment_code, instances, proof); - // } } From 60fe3ac160b0f876eb8a18487a5b9364c1e54cba Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Mon, 27 Nov 2023 22:06:36 +0100 Subject: [PATCH 21/23] cargo fix + fmt --- lightclient-circuits/src/committee_update_circuit.rs | 8 +++++--- lightclient-circuits/src/gadget/common.rs | 2 +- lightclient-circuits/src/gadget/crypto/sha256_wide.rs | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 61ac3691..fb77c430 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -1,6 +1,6 @@ use crate::{ gadget::crypto::{HashInstructions, Sha256ChipWide, ShaBitGateManager, ShaCircuitBuilder}, - poseidon::{fq_array_poseidon_native, fq_array_poseidon}, + poseidon::{fq_array_poseidon, fq_array_poseidon_native}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, sync_step_circuit::clear_3_bits, util::{AppCircuit, CommonGateManager, Eth2ConfigPinning, IntoWitness}, @@ -9,7 +9,9 @@ use crate::{ }; use eth_types::{Field, Spec, LIMB_BITS, NUM_LIMBS}; use halo2_base::{ - gates::{circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, RangeInstructions}, + gates::{ + circuit::CircuitBuilderStage, flex_gate::threads::CommonCircuitBuilder, RangeInstructions, + }, halo2_proofs::{halo2curves::bn256, plonk::Error}, AssignedValue, Context, QuantumCell, }; @@ -349,7 +351,7 @@ mod tests { ) .expect("proof generation & verification should not fail"); } - + #[test] fn test_committee_update_aggregation_evm() { const APP_K: u32 = 18; diff --git a/lightclient-circuits/src/gadget/common.rs b/lightclient-circuits/src/gadget/common.rs index 4ba247ea..b1f5dbc1 100644 --- a/lightclient-circuits/src/gadget/common.rs +++ b/lightclient-circuits/src/gadget/common.rs @@ -1,6 +1,6 @@ //! Utility traits, functions used in the crate. use eth_types::Field; -use halo2_base::{Context, gates::GateInstructions, AssignedValue, QuantumCell}; +use halo2_base::{gates::GateInstructions, AssignedValue, Context, QuantumCell}; use itertools::Itertools; pub fn to_bytes_le( diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs index ed8a46d6..8dea7a84 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs @@ -85,7 +85,7 @@ impl<'a, F: Field> HashInstructions for Sha256ChipWide<'a, F> { let mut hash_bytes = word_to_bytes_le(blocks[num_rounds - 1].hash, gate, builder.main()); hash_bytes.reverse(); - + Ok(hash_bytes) } From 4c45ecc0cdea43ce1bc19249ef65c1b6aeb209c8 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Mon, 27 Nov 2023 22:20:20 +0100 Subject: [PATCH 22/23] rename config files --- .../config/committee_update.json | 23 ------------------- .../config/committee_update_18.json | 18 +++++++++++---- .../config/committee_update_20.json | 23 ------------------- .../config/committee_update_21.json | 19 --------------- .../config/committee_update_a.json | 15 ------------ .../config/committee_update_aggregation.json | 21 ----------------- .../config/committee_update_verifier_25.json | 12 ++++++++++ .../{sync_step.json => sync_step_22.json} | 0 .../src/committee_update_circuit.rs | 6 ++--- lightclient-circuits/src/sync_step_circuit.rs | 14 +++++------ lightclient-circuits/tests/step.rs | 16 ++++++------- preprocessor/src/rotation.rs | 4 ++-- preprocessor/src/sync.rs | 4 ++-- 13 files changed, 48 insertions(+), 127 deletions(-) delete mode 100644 lightclient-circuits/config/committee_update.json delete mode 100644 lightclient-circuits/config/committee_update_20.json delete mode 100644 lightclient-circuits/config/committee_update_21.json delete mode 100644 lightclient-circuits/config/committee_update_a.json delete mode 100644 lightclient-circuits/config/committee_update_aggregation.json create mode 100644 lightclient-circuits/config/committee_update_verifier_25.json rename lightclient-circuits/config/{sync_step.json => sync_step_22.json} (100%) diff --git a/lightclient-circuits/config/committee_update.json b/lightclient-circuits/config/committee_update.json deleted file mode 100644 index e0ff3c54..00000000 --- a/lightclient-circuits/config/committee_update.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "params": { - "k": 20, - "num_advice_per_phase": [ - 4 - ], - "num_fixed": 1, - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "lookup_bits": 8, - "num_instance_columns": 1 - }, - "break_points": [ - [ - 1048564, - 1048566, - 1048565 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_18.json b/lightclient-circuits/config/committee_update_18.json index 4649060f..0bfba944 100644 --- a/lightclient-circuits/config/committee_update_18.json +++ b/lightclient-circuits/config/committee_update_18.json @@ -2,11 +2,11 @@ "params": { "k": 18, "num_advice_per_phase": [ - 2 + 12 ], "num_fixed": 1, "num_lookup_advice_per_phase": [ - 0, + 1, 0, 0 ], @@ -15,7 +15,17 @@ }, "break_points": [ [ - 262134 + 262134, + 262132, + 262134, + 262132, + 262133, + 262132, + 262132, + 262133, + 262132, + 262134, + 262133 ] ] -} \ No newline at end of file +} diff --git a/lightclient-circuits/config/committee_update_20.json b/lightclient-circuits/config/committee_update_20.json deleted file mode 100644 index e0ff3c54..00000000 --- a/lightclient-circuits/config/committee_update_20.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "params": { - "k": 20, - "num_advice_per_phase": [ - 4 - ], - "num_fixed": 1, - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "lookup_bits": 8, - "num_instance_columns": 1 - }, - "break_points": [ - [ - 1048564, - 1048566, - 1048565 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_21.json b/lightclient-circuits/config/committee_update_21.json deleted file mode 100644 index fbd8480f..00000000 --- a/lightclient-circuits/config/committee_update_21.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "params": { - "k": 21, - "num_advice_per_phase": [ - 1 - ], - "num_fixed": 1, - "num_lookup_advice_per_phase": [ - 0, - 0, - 0 - ], - "lookup_bits": 8, - "num_instance_columns": 1 - }, - "break_points": [ - [] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_a.json b/lightclient-circuits/config/committee_update_a.json deleted file mode 100644 index 0295772a..00000000 --- a/lightclient-circuits/config/committee_update_a.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "params": { - "degree": 23, - "num_advice": 3, - "num_lookup_advice": 1, - "num_fixed": 1, - "lookup_bits": 8 - }, - "break_points": [ - [ - 8388596, - 8388598 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_aggregation.json b/lightclient-circuits/config/committee_update_aggregation.json deleted file mode 100644 index c2ab190d..00000000 --- a/lightclient-circuits/config/committee_update_aggregation.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "params": { - "degree": 22, - "num_advice": 9, - "num_lookup_advice": 2, - "num_fixed": 1, - "lookup_bits": 8 - }, - "break_points": [ - [ - 4194292, - 4194294, - 4194292, - 4194293, - 4194293, - 4194293, - 4194293, - 4194294 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_verifier_25.json b/lightclient-circuits/config/committee_update_verifier_25.json new file mode 100644 index 00000000..9d724c53 --- /dev/null +++ b/lightclient-circuits/config/committee_update_verifier_25.json @@ -0,0 +1,12 @@ +{ + "params": { + "degree": 25, + "num_advice": 1, + "num_lookup_advice": 1, + "num_fixed": 1, + "lookup_bits": 8 + }, + "break_points": [ + [] + ] + } diff --git a/lightclient-circuits/config/sync_step.json b/lightclient-circuits/config/sync_step_22.json similarity index 100% rename from lightclient-circuits/config/sync_step.json rename to lightclient-circuits/config/sync_step_22.json diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index fb77c430..0c5736a6 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -310,7 +310,7 @@ mod tests { let witness = load_circuit_args(); - let pinning = Eth2ConfigPinning::from_path("./config/committee_update.json"); + let pinning = Eth2ConfigPinning::from_path("./config/committee_update_18.json"); let circuit = CommitteeUpdateCircuit::::create_circuit( CircuitBuilderStage::Mock, Some(pinning), @@ -357,7 +357,7 @@ mod tests { const APP_K: u32 = 18; const APP_PK_PATH: &str = "../build/committee_update_18.pkey"; const APP_PINNING_PATH: &str = "./config/committee_update_18.json"; - const AGG_CONFIG_PATH: &str = "./config/committee_update_aggr_25.json"; + const AGG_CONFIG_PATH: &str = "./config/committee_update_verifier_25.json"; let params_app = gen_srs(APP_K); const AGG_K: u32 = 25; @@ -377,7 +377,7 @@ mod tests { let pk = AggregationCircuit::read_or_create_pk( ¶ms, - "../build/aggregation_25.pkey", + "../build/committee_update_verifier_25.pkey", AGG_CONFIG_PATH, false, &vec![snark.clone()], diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 627a07e9..5d0a3e80 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -439,7 +439,7 @@ mod tests { const K: u32 = 21; let witness = load_circuit_args(); - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + let pinning = Eth2ConfigPinning::from_path("./config/sync_step_21.json"); let circuit = StepCircuit::::create_circuit( CircuitBuilderStage::Mock, @@ -464,8 +464,8 @@ mod tests { let pk = StepCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", - "./config/sync_step.json", + "../build/sync_step_22.pkey", + "./config/sync_step_22.json", false, &SyncStepArgs::::default(), ); @@ -475,7 +475,7 @@ mod tests { let _ = StepCircuit::::gen_proof_shplonk( ¶ms, &pk, - "./config/sync_step.json", + "./config/sync_step_22.json", &witness, ) .expect("proof generation & verification should not fail"); @@ -488,15 +488,15 @@ mod tests { let pk = StepCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", - "./config/sync_step.json", + "../build/sync_step_22.pkey", + "./config/sync_step_22.json", false, &SyncStepArgs::::default(), ); let witness = load_circuit_args(); - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + let pinning = Eth2ConfigPinning::from_path("./config/sync_step_22.json"); let circuit = StepCircuit::::create_circuit( CircuitBuilderStage::Prover, diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index 553535b1..99d13f21 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -39,7 +39,7 @@ fn run_test_eth2_spec_mock(path: PathB let rotation_circuit = { let pinning: Eth2ConfigPinning = - Eth2ConfigPinning::from_path("./config/committee_update.json"); + Eth2ConfigPinning::from_path(format!("./config/committee_update_{K_ROTATION}.json")); CommitteeUpdateCircuit::::create_circuit( CircuitBuilderStage::Mock, @@ -61,7 +61,7 @@ fn run_test_eth2_spec_mock(path: PathB end_timer!(timer); let sync_circuit = { - let pinning: Eth2ConfigPinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + let pinning: Eth2ConfigPinning = Eth2ConfigPinning::from_path(format!("./config/sync_step_{K_SYNC}.json")); StepCircuit::::create_circuit( CircuitBuilderStage::Mock, @@ -94,8 +94,8 @@ fn test_eth2_spec_proofgen( let params = gen_srs(K); let pk = StepCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", - "./config/sync_step.json", + "../build/sync_step_20.pkey", + "./config/sync_step_20.json", false, &SyncStepArgs::::default(), ); @@ -103,7 +103,7 @@ fn test_eth2_spec_proofgen( let _ = StepCircuit::::gen_proof_shplonk( ¶ms, &pk, - "./config/sync_step.json", + "./config/sync_step_20.json", &witness, ) .expect("proof generation & verification should not fail"); @@ -120,15 +120,15 @@ fn test_eth2_spec_evm_verify( let pk = StepCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", - "./config/sync_step.json", + "../build/sync_step_21.pkey", + "./config/sync_step_21.json", false, &SyncStepArgs::::default(), ); let (witness, _) = read_test_files_and_gen_witness(&path); - let pinning = Eth2ConfigPinning::from_path("./config/sync_step.json"); + let pinning = Eth2ConfigPinning::from_path("./config/sync_step_21.json"); let circuit = StepCircuit::::create_circuit( CircuitBuilderStage::Prover, diff --git a/preprocessor/src/rotation.rs b/preprocessor/src/rotation.rs index 62186a57..82458d3b 100644 --- a/preprocessor/src/rotation.rs +++ b/preprocessor/src/rotation.rs @@ -162,13 +162,13 @@ mod tests { #[tokio::test] async fn test_rotation_step_snark_sepolia() { - const CONFIG_PATH: &str = "../lightclient-circuits/config/committee_update.json"; + const CONFIG_PATH: &str = "../lightclient-circuits/config/committee_update_18.json"; const K: u32 = 21; let params = gen_srs(K); let pk = CommitteeUpdateCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", + "../build/sync_step_21.pkey", CONFIG_PATH, false, &CommitteeRotationArgs::::default(), diff --git a/preprocessor/src/sync.rs b/preprocessor/src/sync.rs index 6c8a6c05..82c598e3 100644 --- a/preprocessor/src/sync.rs +++ b/preprocessor/src/sync.rs @@ -199,13 +199,13 @@ mod tests { #[tokio::test] async fn test_sync_step_snark_sepolia() { - const CONFIG_PATH: &str = "../lightclient-circuits/config/sync_step.json"; + const CONFIG_PATH: &str = "../lightclient-circuits/config/sync_step_21.json"; const K: u32 = 21; let params = gen_srs(K); let pk = StepCircuit::::read_or_create_pk( ¶ms, - "../build/sync_step.pkey", + "../build/sync_step_21.pkey", CONFIG_PATH, false, &SyncStepArgs::::default(), From 8a7fa818874d1595684cf1d18a02af21e20b1fbf Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 29 Nov 2023 12:35:08 +0100 Subject: [PATCH 23/23] cargo fix --- lightclient-circuits/src/lib.rs | 3 ++- lightclient-circuits/tests/step.rs | 3 ++- preprocessor/src/lib.rs | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 48c2dded..50a15e00 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -7,6 +7,7 @@ #![feature(generic_arg_infer)] #![feature(return_position_impl_trait_in_trait)] #![allow(clippy::needless_range_loop)] + pub mod gadget; pub mod util; pub mod witness; @@ -20,8 +21,8 @@ mod ssz_merkle; pub use halo2_base; pub use halo2_base::halo2_proofs; - use halo2_base::halo2_proofs::halo2curves::bn256; + #[allow(type_alias_bounds)] pub type Eth2CircuitBuilder> = gadget::crypto::ShaCircuitBuilder; diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index 99d13f21..bbba9385 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -61,7 +61,8 @@ fn run_test_eth2_spec_mock(path: PathB end_timer!(timer); let sync_circuit = { - let pinning: Eth2ConfigPinning = Eth2ConfigPinning::from_path(format!("./config/sync_step_{K_SYNC}.json")); + let pinning: Eth2ConfigPinning = + Eth2ConfigPinning::from_path(format!("./config/sync_step_{K_SYNC}.json")); StepCircuit::::create_circuit( CircuitBuilderStage::Mock, diff --git a/preprocessor/src/lib.rs b/preprocessor/src/lib.rs index 0e1f935b..56475ff4 100644 --- a/preprocessor/src/lib.rs +++ b/preprocessor/src/lib.rs @@ -2,7 +2,6 @@ #![feature(generic_const_exprs)] mod sync; -use std::ops::Deref; use beacon_api_client::{BlockId, Client, ClientTypes, Value, VersionedValue}; use eth_types::Spec; @@ -11,15 +10,16 @@ use ethereum_consensus_types::{ LightClientUpdateCapella, Root, }; use itertools::Itertools; -use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use lightclient_circuits::witness::{CommitteeRotationArgs, SyncStepArgs}; use serde::{Deserialize, Serialize}; use ssz_rs::{Node, Vector}; +use std::ops::Deref; pub use sync::*; mod rotation; pub use rotation::*; use zipline_cryptography::bls::BlsPublicKey; use zipline_cryptography::bls::BlsSignature; + pub async fn light_client_update_to_args( update: &mut LightClientUpdateCapella< { S::SYNC_COMMITTEE_SIZE },