From 94cff9168bda32570e5e80f57a4dc2e1b89596ab Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Thu, 8 Feb 2024 15:00:24 +0100 Subject: [PATCH 01/18] switch to deneb --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fb0ed98..b7cff04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,7 @@ snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git ] } # ethereum types -ethereum-consensus-types = { git = "https://github.com/ChainSafe/ethereum-consensus-types", branch = "capella" } +ethereum-consensus-types = { git = "https://github.com/ChainSafe/ethereum-consensus-types", branch = "deneb" } beacon-api-client = { git = "https://github.com/ralexstokes/ethereum-consensus.git", rev = "f3bff52e9c43866f231ec40c8ab0e34125a8957f" } ssz_rs = "0.9" From 87155f3af50c936743430c8f19a385f6b8d0919e Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Thu, 8 Feb 2024 16:23:57 +0100 Subject: [PATCH 02/18] gen step contract --- contracts/snark-verifiers/sync_step_verifier.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/snark-verifiers/sync_step_verifier.sol b/contracts/snark-verifiers/sync_step_verifier.sol index 28784dc..c546281 100644 --- a/contracts/snark-verifiers/sync_step_verifier.sol +++ b/contracts/snark-verifiers/sync_step_verifier.sol @@ -20,4 +20,4 @@ contract Verifier { for (uint i = 0; i < pubInputs.length; i++) { require(pubInputs[i] < SIZE_LIMIT); } - assembly { 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(0xa0, mod(calldataload(0x4), f_q))mstore(0xc0, mod(calldataload(0x24), f_q))mstore(0xe0, mod(calldataload(0x44), f_q))mstore(0x100, mod(calldataload(0x64), f_q))mstore(0x120, mod(calldataload(0x84), f_q))mstore(0x140, mod(calldataload(0xa4), f_q))mstore(0x160, mod(calldataload(0xc4), f_q))mstore(0x180, mod(calldataload(0xe4), f_q))mstore(0x1a0, mod(calldataload(0x104), f_q))mstore(0x1c0, mod(calldataload(0x124), f_q))mstore(0x1e0, mod(calldataload(0x144), f_q))mstore(0x200, mod(calldataload(0x164), f_q))mstore(0x220, mod(calldataload(0x184), f_q))mstore(0x240, mod(calldataload(0x1a4), f_q))mstore(0x80, 15063357149795515579629705953618634254647589286608361998185212173462665455386) { let x := calldataload(0x204) mstore(0x260, x) let y := calldataload(0x224) mstore(0x280, y) success := and(validate_ec_point(x, y), success) }mstore(0x2a0, keccak256(0x80, 544)){ let hash := mload(0x2a0) mstore(0x2c0, mod(hash, f_q)) mstore(0x2e0, hash) } { let x := calldataload(0x244) mstore(0x300, x) let y := calldataload(0x264) mstore(0x320, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x284) mstore(0x340, x) let y := calldataload(0x2a4) mstore(0x360, y) success := and(validate_ec_point(x, y), success) }mstore(0x380, keccak256(0x2e0, 160)){ let hash := mload(0x380) mstore(0x3a0, mod(hash, f_q)) mstore(0x3c0, hash) }mstore8(0x3e0, 1)mstore(0x3e0, keccak256(0x3c0, 33)){ let hash := mload(0x3e0) mstore(0x400, mod(hash, f_q)) mstore(0x420, hash) } { let x := calldataload(0x2c4) mstore(0x440, x) let y := calldataload(0x2e4) mstore(0x460, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x304) mstore(0x480, x) let y := calldataload(0x324) mstore(0x4a0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x344) mstore(0x4c0, x) let y := calldataload(0x364) mstore(0x4e0, y) success := and(validate_ec_point(x, y), success) }mstore(0x500, keccak256(0x420, 224)){ let hash := mload(0x500) mstore(0x520, mod(hash, f_q)) mstore(0x540, hash) } { let x := calldataload(0x384) mstore(0x560, x) let y := calldataload(0x3a4) mstore(0x580, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x3c4) mstore(0x5a0, x) let y := calldataload(0x3e4) mstore(0x5c0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x404) mstore(0x5e0, x) let y := calldataload(0x424) mstore(0x600, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x444) mstore(0x620, x) let y := calldataload(0x464) mstore(0x640, y) success := and(validate_ec_point(x, y), success) }mstore(0x660, keccak256(0x540, 288)){ let hash := mload(0x660) mstore(0x680, mod(hash, f_q)) mstore(0x6a0, hash) }mstore(0x6c0, mod(calldataload(0x484), f_q))mstore(0x6e0, mod(calldataload(0x4a4), f_q))mstore(0x700, mod(calldataload(0x4c4), f_q))mstore(0x720, mod(calldataload(0x4e4), f_q))mstore(0x740, mod(calldataload(0x504), f_q))mstore(0x760, mod(calldataload(0x524), f_q))mstore(0x780, mod(calldataload(0x544), f_q))mstore(0x7a0, mod(calldataload(0x564), f_q))mstore(0x7c0, mod(calldataload(0x584), f_q))mstore(0x7e0, mod(calldataload(0x5a4), f_q))mstore(0x800, mod(calldataload(0x5c4), f_q))mstore(0x820, mod(calldataload(0x5e4), f_q))mstore(0x840, mod(calldataload(0x604), f_q))mstore(0x860, mod(calldataload(0x624), f_q))mstore(0x880, mod(calldataload(0x644), f_q))mstore(0x8a0, mod(calldataload(0x664), f_q))mstore(0x8c0, mod(calldataload(0x684), f_q))mstore(0x8e0, mod(calldataload(0x6a4), f_q))mstore(0x900, mod(calldataload(0x6c4), f_q))mstore(0x920, keccak256(0x6a0, 640)){ let hash := mload(0x920) mstore(0x940, mod(hash, f_q)) mstore(0x960, hash) }mstore8(0x980, 1)mstore(0x980, keccak256(0x960, 33)){ let hash := mload(0x980) mstore(0x9a0, mod(hash, f_q)) mstore(0x9c0, hash) } { let x := calldataload(0x6e4) mstore(0x9e0, x) let y := calldataload(0x704) mstore(0xa00, y) success := and(validate_ec_point(x, y), success) }mstore(0xa20, keccak256(0x9c0, 96)){ let hash := mload(0xa20) mstore(0xa40, mod(hash, f_q)) mstore(0xa60, hash) } { let x := calldataload(0x724) mstore(0xa80, x) let y := calldataload(0x744) mstore(0xaa0, y) success := and(validate_ec_point(x, y), success) }{ let x := mload(0xa0)x := add(x, shl(88, mload(0xc0)))x := add(x, shl(176, mload(0xe0)))mstore(0xac0, x)let y := mload(0x100)y := add(y, shl(88, mload(0x120)))y := add(y, shl(176, mload(0x140)))mstore(0xae0, y) success := and(validate_ec_point(x, y), success) }{ let x := mload(0x160)x := add(x, shl(88, mload(0x180)))x := add(x, shl(176, mload(0x1a0)))mstore(0xb00, x)let y := mload(0x1c0)y := add(y, shl(88, mload(0x1e0)))y := add(y, shl(176, mload(0x200)))mstore(0xb20, y) success := and(validate_ec_point(x, y), success) }mstore(0xb40, mulmod(mload(0x680), mload(0x680), f_q))mstore(0xb60, mulmod(mload(0xb40), mload(0xb40), f_q))mstore(0xb80, mulmod(mload(0xb60), mload(0xb60), f_q))mstore(0xba0, mulmod(mload(0xb80), mload(0xb80), f_q))mstore(0xbc0, mulmod(mload(0xba0), mload(0xba0), f_q))mstore(0xbe0, mulmod(mload(0xbc0), mload(0xbc0), f_q))mstore(0xc00, mulmod(mload(0xbe0), mload(0xbe0), f_q))mstore(0xc20, mulmod(mload(0xc00), mload(0xc00), f_q))mstore(0xc40, mulmod(mload(0xc20), mload(0xc20), f_q))mstore(0xc60, mulmod(mload(0xc40), mload(0xc40), f_q))mstore(0xc80, mulmod(mload(0xc60), mload(0xc60), f_q))mstore(0xca0, mulmod(mload(0xc80), mload(0xc80), f_q))mstore(0xcc0, mulmod(mload(0xca0), mload(0xca0), f_q))mstore(0xce0, mulmod(mload(0xcc0), mload(0xcc0), f_q))mstore(0xd00, mulmod(mload(0xce0), mload(0xce0), f_q))mstore(0xd20, mulmod(mload(0xd00), mload(0xd00), f_q))mstore(0xd40, mulmod(mload(0xd20), mload(0xd20), f_q))mstore(0xd60, mulmod(mload(0xd40), mload(0xd40), f_q))mstore(0xd80, mulmod(mload(0xd60), mload(0xd60), f_q))mstore(0xda0, mulmod(mload(0xd80), mload(0xd80), f_q))mstore(0xdc0, mulmod(mload(0xda0), mload(0xda0), f_q))mstore(0xde0, mulmod(mload(0xdc0), mload(0xdc0), f_q))mstore(0xe00, mulmod(mload(0xde0), mload(0xde0), f_q))mstore(0xe20, addmod(mload(0xe00), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q))mstore(0xe40, mulmod(mload(0xe20), 21888240262557392955334514970720457388010314637169927192662615958087340972065, f_q))mstore(0xe60, mulmod(mload(0xe40), 4506835738822104338668100540817374747935106310012997856968187171738630203507, f_q))mstore(0xe80, addmod(mload(0x680), 17381407133017170883578305204439900340613258090403036486730017014837178292110, f_q))mstore(0xea0, mulmod(mload(0xe40), 21710372849001950800533397158415938114909991150039389063546734567764856596059, f_q))mstore(0xec0, addmod(mload(0x680), 177870022837324421713008586841336973638373250376645280151469618810951899558, f_q))mstore(0xee0, mulmod(mload(0xe40), 1887003188133998471169152042388914354640772748308168868301418279904560637395, f_q))mstore(0xf00, addmod(mload(0x680), 20001239683705276751077253702868360733907591652107865475396785906671247858222, f_q))mstore(0xf20, mulmod(mload(0xe40), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q))mstore(0xf40, addmod(mload(0x680), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q))mstore(0xf60, mulmod(mload(0xe40), 14655294445420895451632927078981340937842238432098198055057679026789553137428, f_q))mstore(0xf80, addmod(mload(0x680), 7232948426418379770613478666275934150706125968317836288640525159786255358189, f_q))mstore(0xfa0, mulmod(mload(0xe40), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q))mstore(0xfc0, addmod(mload(0x680), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q))mstore(0xfe0, mulmod(mload(0xe40), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q))mstore(0x1000, addmod(mload(0x680), 12146688980418810893951125255607130521645347193942732958664170801695864621270, f_q))mstore(0x1020, mulmod(mload(0xe40), 1, f_q))mstore(0x1040, addmod(mload(0x680), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q))mstore(0x1060, mulmod(mload(0xe40), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q))mstore(0x1080, addmod(mload(0x680), 13513867906530865119835332133273263211836799082674232843258448413103731898270, f_q))mstore(0x10a0, mulmod(mload(0xe40), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q))mstore(0x10c0, addmod(mload(0x680), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q))mstore(0x10e0, mulmod(mload(0xe40), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q))mstore(0x1100, addmod(mload(0x680), 18272764063556419981698118473909131571661591947471949595929891197711371770216, f_q))mstore(0x1120, mulmod(mload(0xe40), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q))mstore(0x1140, addmod(mload(0x680), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q))mstore(0x1160, mulmod(mload(0xe40), 216092043779272773661818549620449970334216366264741118684015851799902419467, f_q))mstore(0x1180, addmod(mload(0x680), 21672150828060002448584587195636825118214148034151293225014188334775906076150, f_q))mstore(0x11a0, mulmod(mload(0xe40), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q))mstore(0x11c0, addmod(mload(0x680), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q))mstore(0x11e0, mulmod(mload(0xe40), 18610195890048912503953886742825279624920778288956610528523679659246523534888, f_q))mstore(0x1200, addmod(mload(0x680), 3278046981790362718292519002431995463627586111459423815174524527329284960729, f_q))mstore(0x1220, mulmod(mload(0xe40), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q))mstore(0x1240, addmod(mload(0x680), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q))mstore(0x1260, mulmod(mload(0xe40), 14875928112196239563830800280253496262679717528621719058794366823499719730250, f_q))mstore(0x1280, addmod(mload(0x680), 7012314759643035658415605465003778825868646871794315284903837363076088765367, f_q))mstore(0x12a0, mulmod(mload(0xe40), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q))mstore(0x12c0, addmod(mload(0x680), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q))mstore(0x12e0, mulmod(mload(0xe40), 5522161504810533295870699551020523636289972223872138525048055197429246400245, f_q))mstore(0x1300, addmod(mload(0x680), 16366081367028741926375706194236751452258392176543895818650148989146562095372, f_q))mstore(0x1320, mulmod(mload(0xe40), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q))mstore(0x1340, addmod(mload(0x680), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q))mstore(0x1360, mulmod(mload(0xe40), 9100833993744738801214480881117348002768153232283708533639316963648253510584, f_q))mstore(0x1380, addmod(mload(0x680), 12787408878094536421031924864139927085780211168132325810058887222927554985033, f_q)){ let prod := mload(0xe80) prod := mulmod(mload(0xec0), prod, f_q) mstore(0x13a0, prod) prod := mulmod(mload(0xf00), prod, f_q) mstore(0x13c0, prod) prod := mulmod(mload(0xf40), prod, f_q) mstore(0x13e0, prod) prod := mulmod(mload(0xf80), prod, f_q) mstore(0x1400, prod) prod := mulmod(mload(0xfc0), prod, f_q) mstore(0x1420, prod) prod := mulmod(mload(0x1000), prod, f_q) mstore(0x1440, prod) prod := mulmod(mload(0x1040), prod, f_q) mstore(0x1460, prod) prod := mulmod(mload(0x1080), prod, f_q) mstore(0x1480, prod) prod := mulmod(mload(0x10c0), prod, f_q) mstore(0x14a0, prod) prod := mulmod(mload(0x1100), prod, f_q) mstore(0x14c0, prod) prod := mulmod(mload(0x1140), prod, f_q) mstore(0x14e0, prod) prod := mulmod(mload(0x1180), prod, f_q) mstore(0x1500, prod) prod := mulmod(mload(0x11c0), prod, f_q) mstore(0x1520, prod) prod := mulmod(mload(0x1200), prod, f_q) mstore(0x1540, prod) prod := mulmod(mload(0x1240), prod, f_q) mstore(0x1560, prod) prod := mulmod(mload(0x1280), prod, f_q) mstore(0x1580, prod) prod := mulmod(mload(0x12c0), prod, f_q) mstore(0x15a0, prod) prod := mulmod(mload(0x1300), prod, f_q) mstore(0x15c0, prod) prod := mulmod(mload(0x1340), prod, f_q) mstore(0x15e0, prod) prod := mulmod(mload(0x1380), prod, f_q) mstore(0x1600, prod) prod := mulmod(mload(0xe20), prod, f_q) mstore(0x1620, prod) }mstore(0x1660, 32)mstore(0x1680, 32)mstore(0x16a0, 32)mstore(0x16c0, mload(0x1620))mstore(0x16e0, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x1700, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x1660, 0xc0, 0x1640, 0x20), 1), success){ let inv := mload(0x1640) let v v := mload(0xe20) mstore(0xe20, mulmod(mload(0x1600), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1380) mstore(0x1380, mulmod(mload(0x15e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1340) mstore(0x1340, mulmod(mload(0x15c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1300) mstore(0x1300, mulmod(mload(0x15a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x12c0) mstore(0x12c0, mulmod(mload(0x1580), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1280) mstore(0x1280, mulmod(mload(0x1560), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1240) mstore(0x1240, mulmod(mload(0x1540), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1200) mstore(0x1200, mulmod(mload(0x1520), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x11c0) mstore(0x11c0, mulmod(mload(0x1500), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1180) mstore(0x1180, mulmod(mload(0x14e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1140) mstore(0x1140, mulmod(mload(0x14c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1100) mstore(0x1100, mulmod(mload(0x14a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x10c0) mstore(0x10c0, mulmod(mload(0x1480), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1080) mstore(0x1080, mulmod(mload(0x1460), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1040) mstore(0x1040, mulmod(mload(0x1440), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1000) mstore(0x1000, mulmod(mload(0x1420), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xfc0) mstore(0xfc0, mulmod(mload(0x1400), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xf80) mstore(0xf80, mulmod(mload(0x13e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xf40) mstore(0xf40, mulmod(mload(0x13c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xf00) mstore(0xf00, mulmod(mload(0x13a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xec0) mstore(0xec0, mulmod(mload(0xe80), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0xe80, inv) }mstore(0x1720, mulmod(mload(0xe60), mload(0xe80), f_q))mstore(0x1740, mulmod(mload(0xea0), mload(0xec0), f_q))mstore(0x1760, mulmod(mload(0xee0), mload(0xf00), f_q))mstore(0x1780, mulmod(mload(0xf20), mload(0xf40), f_q))mstore(0x17a0, mulmod(mload(0xf60), mload(0xf80), f_q))mstore(0x17c0, mulmod(mload(0xfa0), mload(0xfc0), f_q))mstore(0x17e0, mulmod(mload(0xfe0), mload(0x1000), f_q))mstore(0x1800, mulmod(mload(0x1020), mload(0x1040), f_q))mstore(0x1820, mulmod(mload(0x1060), mload(0x1080), f_q))mstore(0x1840, mulmod(mload(0x10a0), mload(0x10c0), f_q))mstore(0x1860, mulmod(mload(0x10e0), mload(0x1100), f_q))mstore(0x1880, mulmod(mload(0x1120), mload(0x1140), f_q))mstore(0x18a0, mulmod(mload(0x1160), mload(0x1180), f_q))mstore(0x18c0, mulmod(mload(0x11a0), mload(0x11c0), f_q))mstore(0x18e0, mulmod(mload(0x11e0), mload(0x1200), f_q))mstore(0x1900, mulmod(mload(0x1220), mload(0x1240), f_q))mstore(0x1920, mulmod(mload(0x1260), mload(0x1280), f_q))mstore(0x1940, mulmod(mload(0x12a0), mload(0x12c0), f_q))mstore(0x1960, mulmod(mload(0x12e0), mload(0x1300), f_q))mstore(0x1980, mulmod(mload(0x1320), mload(0x1340), f_q))mstore(0x19a0, mulmod(mload(0x1360), mload(0x1380), f_q)){ let result := mulmod(mload(0x1800), mload(0xa0), f_q)result := addmod(mulmod(mload(0x1820), mload(0xc0), f_q), result, f_q)result := addmod(mulmod(mload(0x1840), mload(0xe0), f_q), result, f_q)result := addmod(mulmod(mload(0x1860), mload(0x100), f_q), result, f_q)result := addmod(mulmod(mload(0x1880), mload(0x120), f_q), result, f_q)result := addmod(mulmod(mload(0x18a0), mload(0x140), f_q), result, f_q)result := addmod(mulmod(mload(0x18c0), mload(0x160), f_q), result, f_q)result := addmod(mulmod(mload(0x18e0), mload(0x180), f_q), result, f_q)result := addmod(mulmod(mload(0x1900), mload(0x1a0), f_q), result, f_q)result := addmod(mulmod(mload(0x1920), mload(0x1c0), f_q), result, f_q)result := addmod(mulmod(mload(0x1940), mload(0x1e0), f_q), result, f_q)result := addmod(mulmod(mload(0x1960), mload(0x200), f_q), result, f_q)result := addmod(mulmod(mload(0x1980), mload(0x220), f_q), result, f_q)result := addmod(mulmod(mload(0x19a0), mload(0x240), f_q), result, f_q)mstore(0x19c0, result) }mstore(0x19e0, mulmod(mload(0x700), mload(0x6e0), f_q))mstore(0x1a00, addmod(mload(0x6c0), mload(0x19e0), f_q))mstore(0x1a20, addmod(mload(0x1a00), sub(f_q, mload(0x720)), f_q))mstore(0x1a40, mulmod(mload(0x1a20), mload(0x7a0), f_q))mstore(0x1a60, mulmod(mload(0x520), mload(0x1a40), f_q))mstore(0x1a80, addmod(1, sub(f_q, mload(0x840)), f_q))mstore(0x1aa0, mulmod(mload(0x1a80), mload(0x1800), f_q))mstore(0x1ac0, addmod(mload(0x1a60), mload(0x1aa0), f_q))mstore(0x1ae0, mulmod(mload(0x520), mload(0x1ac0), f_q))mstore(0x1b00, mulmod(mload(0x840), mload(0x840), f_q))mstore(0x1b20, addmod(mload(0x1b00), sub(f_q, mload(0x840)), f_q))mstore(0x1b40, mulmod(mload(0x1b20), mload(0x1720), f_q))mstore(0x1b60, addmod(mload(0x1ae0), mload(0x1b40), f_q))mstore(0x1b80, mulmod(mload(0x520), mload(0x1b60), f_q))mstore(0x1ba0, addmod(1, sub(f_q, mload(0x1720)), f_q))mstore(0x1bc0, addmod(mload(0x1740), mload(0x1760), f_q))mstore(0x1be0, addmod(mload(0x1bc0), mload(0x1780), f_q))mstore(0x1c00, addmod(mload(0x1be0), mload(0x17a0), f_q))mstore(0x1c20, addmod(mload(0x1c00), mload(0x17c0), f_q))mstore(0x1c40, addmod(mload(0x1c20), mload(0x17e0), f_q))mstore(0x1c60, addmod(mload(0x1ba0), sub(f_q, mload(0x1c40)), f_q))mstore(0x1c80, mulmod(mload(0x7e0), mload(0x3a0), f_q))mstore(0x1ca0, addmod(mload(0x740), mload(0x1c80), f_q))mstore(0x1cc0, addmod(mload(0x1ca0), mload(0x400), f_q))mstore(0x1ce0, mulmod(mload(0x800), mload(0x3a0), f_q))mstore(0x1d00, addmod(mload(0x6c0), mload(0x1ce0), f_q))mstore(0x1d20, addmod(mload(0x1d00), mload(0x400), f_q))mstore(0x1d40, mulmod(mload(0x1d20), mload(0x1cc0), f_q))mstore(0x1d60, mulmod(mload(0x820), mload(0x3a0), f_q))mstore(0x1d80, addmod(mload(0x19c0), mload(0x1d60), f_q))mstore(0x1da0, addmod(mload(0x1d80), mload(0x400), f_q))mstore(0x1dc0, mulmod(mload(0x1da0), mload(0x1d40), f_q))mstore(0x1de0, mulmod(mload(0x1dc0), mload(0x860), f_q))mstore(0x1e00, mulmod(1, mload(0x3a0), f_q))mstore(0x1e20, mulmod(mload(0x680), mload(0x1e00), f_q))mstore(0x1e40, addmod(mload(0x740), mload(0x1e20), f_q))mstore(0x1e60, addmod(mload(0x1e40), mload(0x400), f_q))mstore(0x1e80, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x3a0), f_q))mstore(0x1ea0, mulmod(mload(0x680), mload(0x1e80), f_q))mstore(0x1ec0, addmod(mload(0x6c0), mload(0x1ea0), f_q))mstore(0x1ee0, addmod(mload(0x1ec0), mload(0x400), f_q))mstore(0x1f00, mulmod(mload(0x1ee0), mload(0x1e60), f_q))mstore(0x1f20, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x3a0), f_q))mstore(0x1f40, mulmod(mload(0x680), mload(0x1f20), f_q))mstore(0x1f60, addmod(mload(0x19c0), mload(0x1f40), f_q))mstore(0x1f80, addmod(mload(0x1f60), mload(0x400), f_q))mstore(0x1fa0, mulmod(mload(0x1f80), mload(0x1f00), f_q))mstore(0x1fc0, mulmod(mload(0x1fa0), mload(0x840), f_q))mstore(0x1fe0, addmod(mload(0x1de0), sub(f_q, mload(0x1fc0)), f_q))mstore(0x2000, mulmod(mload(0x1fe0), mload(0x1c60), f_q))mstore(0x2020, addmod(mload(0x1b80), mload(0x2000), f_q))mstore(0x2040, mulmod(mload(0x520), mload(0x2020), f_q))mstore(0x2060, addmod(1, sub(f_q, mload(0x880)), f_q))mstore(0x2080, mulmod(mload(0x2060), mload(0x1800), f_q))mstore(0x20a0, addmod(mload(0x2040), mload(0x2080), f_q))mstore(0x20c0, mulmod(mload(0x520), mload(0x20a0), f_q))mstore(0x20e0, mulmod(mload(0x880), mload(0x880), f_q))mstore(0x2100, addmod(mload(0x20e0), sub(f_q, mload(0x880)), f_q))mstore(0x2120, mulmod(mload(0x2100), mload(0x1720), f_q))mstore(0x2140, addmod(mload(0x20c0), mload(0x2120), f_q))mstore(0x2160, mulmod(mload(0x520), mload(0x2140), f_q))mstore(0x2180, addmod(mload(0x8c0), mload(0x3a0), f_q))mstore(0x21a0, mulmod(mload(0x2180), mload(0x8a0), f_q))mstore(0x21c0, addmod(mload(0x900), mload(0x400), f_q))mstore(0x21e0, mulmod(mload(0x21c0), mload(0x21a0), f_q))mstore(0x2200, mulmod(mload(0x6c0), mload(0x780), f_q))mstore(0x2220, addmod(mload(0x2200), mload(0x3a0), f_q))mstore(0x2240, mulmod(mload(0x2220), mload(0x880), f_q))mstore(0x2260, addmod(mload(0x760), mload(0x400), f_q))mstore(0x2280, mulmod(mload(0x2260), mload(0x2240), f_q))mstore(0x22a0, addmod(mload(0x21e0), sub(f_q, mload(0x2280)), f_q))mstore(0x22c0, mulmod(mload(0x22a0), mload(0x1c60), f_q))mstore(0x22e0, addmod(mload(0x2160), mload(0x22c0), f_q))mstore(0x2300, mulmod(mload(0x520), mload(0x22e0), f_q))mstore(0x2320, addmod(mload(0x8c0), sub(f_q, mload(0x900)), f_q))mstore(0x2340, mulmod(mload(0x2320), mload(0x1800), f_q))mstore(0x2360, addmod(mload(0x2300), mload(0x2340), f_q))mstore(0x2380, mulmod(mload(0x520), mload(0x2360), f_q))mstore(0x23a0, mulmod(mload(0x2320), mload(0x1c60), f_q))mstore(0x23c0, addmod(mload(0x8c0), sub(f_q, mload(0x8e0)), f_q))mstore(0x23e0, mulmod(mload(0x23c0), mload(0x23a0), f_q))mstore(0x2400, addmod(mload(0x2380), mload(0x23e0), f_q))mstore(0x2420, mulmod(mload(0xe00), mload(0xe00), f_q))mstore(0x2440, mulmod(mload(0x2420), mload(0xe00), f_q))mstore(0x2460, mulmod(mload(0x2440), mload(0xe00), f_q))mstore(0x2480, mulmod(1, mload(0xe00), f_q))mstore(0x24a0, mulmod(1, mload(0x2420), f_q))mstore(0x24c0, mulmod(1, mload(0x2440), f_q))mstore(0x24e0, mulmod(mload(0x2400), mload(0xe20), f_q))mstore(0x2500, mulmod(mload(0xb40), mload(0x680), f_q))mstore(0x2520, mulmod(mload(0x2500), mload(0x680), f_q))mstore(0x2540, mulmod(mload(0x680), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q))mstore(0x2560, addmod(mload(0xa40), sub(f_q, mload(0x2540)), f_q))mstore(0x2580, mulmod(mload(0x680), 1, f_q))mstore(0x25a0, addmod(mload(0xa40), sub(f_q, mload(0x2580)), f_q))mstore(0x25c0, mulmod(mload(0x680), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q))mstore(0x25e0, addmod(mload(0xa40), sub(f_q, mload(0x25c0)), f_q))mstore(0x2600, mulmod(mload(0x680), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q))mstore(0x2620, addmod(mload(0xa40), sub(f_q, mload(0x2600)), f_q))mstore(0x2640, mulmod(mload(0x680), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q))mstore(0x2660, addmod(mload(0xa40), sub(f_q, mload(0x2640)), f_q))mstore(0x2680, mulmod(13213688729882003894512633350385593288217014177373218494356903340348818451480, mload(0x2500), f_q))mstore(0x26a0, mulmod(mload(0x2680), 1, f_q)){ let result := mulmod(mload(0xa40), mload(0x2680), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x26a0)), f_q), result, f_q)mstore(0x26c0, result) }mstore(0x26e0, mulmod(8207090019724696496350398458716998472718344609680392612601596849934418295470, mload(0x2500), f_q))mstore(0x2700, mulmod(mload(0x26e0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)){ let result := mulmod(mload(0xa40), mload(0x26e0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2700)), f_q), result, f_q)mstore(0x2720, result) }mstore(0x2740, mulmod(7391709068497399131897422873231908718558236401035363928063603272120120747483, mload(0x2500), f_q))mstore(0x2760, mulmod(mload(0x2740), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)){ let result := mulmod(mload(0xa40), mload(0x2740), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2760)), f_q), result, f_q)mstore(0x2780, result) }mstore(0x27a0, mulmod(19036273796805830823244991598792794567595348772040298280440552631112242221017, mload(0x2500), f_q))mstore(0x27c0, mulmod(mload(0x27a0), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q)){ let result := mulmod(mload(0xa40), mload(0x27a0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x27c0)), f_q), result, f_q)mstore(0x27e0, result) }mstore(0x2800, mulmod(1, mload(0x25a0), f_q))mstore(0x2820, mulmod(mload(0x2800), mload(0x25e0), f_q))mstore(0x2840, mulmod(mload(0x2820), mload(0x2620), f_q))mstore(0x2860, mulmod(mload(0x2840), mload(0x2660), f_q))mstore(0x2880, mulmod(13513867906530865119835332133273263211836799082674232843258448413103731898271, mload(0x680), f_q))mstore(0x28a0, mulmod(mload(0x2880), 1, f_q)){ let result := mulmod(mload(0xa40), mload(0x2880), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x28a0)), f_q), result, f_q)mstore(0x28c0, result) }mstore(0x28e0, mulmod(8374374965308410102411073611984011876711565317741801500439755773472076597346, mload(0x680), f_q))mstore(0x2900, mulmod(mload(0x28e0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)){ let result := mulmod(mload(0xa40), mload(0x28e0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2900)), f_q), result, f_q)mstore(0x2920, result) }mstore(0x2940, mulmod(12146688980418810893951125255607130521645347193942732958664170801695864621271, mload(0x680), f_q))mstore(0x2960, mulmod(mload(0x2940), 1, f_q)){ let result := mulmod(mload(0xa40), mload(0x2940), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2960)), f_q), result, f_q)mstore(0x2980, result) }mstore(0x29a0, mulmod(9741553891420464328295280489650144566903017206473301385034033384879943874346, mload(0x680), f_q))mstore(0x29c0, mulmod(mload(0x29a0), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q)){ let result := mulmod(mload(0xa40), mload(0x29a0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x29c0)), f_q), result, f_q)mstore(0x29e0, result) }mstore(0x2a00, mulmod(mload(0x2800), mload(0x2560), f_q)){ let result := mulmod(mload(0xa40), 1, f_q)result := addmod(mulmod(mload(0x680), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q)mstore(0x2a20, result) }{ let prod := mload(0x26c0) prod := mulmod(mload(0x2720), prod, f_q) mstore(0x2a40, prod) prod := mulmod(mload(0x2780), prod, f_q) mstore(0x2a60, prod) prod := mulmod(mload(0x27e0), prod, f_q) mstore(0x2a80, prod) prod := mulmod(mload(0x28c0), prod, f_q) mstore(0x2aa0, prod) prod := mulmod(mload(0x2920), prod, f_q) mstore(0x2ac0, prod) prod := mulmod(mload(0x2820), prod, f_q) mstore(0x2ae0, prod) prod := mulmod(mload(0x2980), prod, f_q) mstore(0x2b00, prod) prod := mulmod(mload(0x29e0), prod, f_q) mstore(0x2b20, prod) prod := mulmod(mload(0x2a00), prod, f_q) mstore(0x2b40, prod) prod := mulmod(mload(0x2a20), prod, f_q) mstore(0x2b60, prod) prod := mulmod(mload(0x2800), prod, f_q) mstore(0x2b80, prod) }mstore(0x2bc0, 32)mstore(0x2be0, 32)mstore(0x2c00, 32)mstore(0x2c20, mload(0x2b80))mstore(0x2c40, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x2c60, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x2bc0, 0xc0, 0x2ba0, 0x20), 1), success){ let inv := mload(0x2ba0) let v v := mload(0x2800) mstore(0x2800, mulmod(mload(0x2b60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2a20) mstore(0x2a20, mulmod(mload(0x2b40), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2a00) mstore(0x2a00, mulmod(mload(0x2b20), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x29e0) mstore(0x29e0, mulmod(mload(0x2b00), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2980) mstore(0x2980, mulmod(mload(0x2ae0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2820) mstore(0x2820, mulmod(mload(0x2ac0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2920) mstore(0x2920, mulmod(mload(0x2aa0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x28c0) mstore(0x28c0, mulmod(mload(0x2a80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x27e0) mstore(0x27e0, mulmod(mload(0x2a60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2780) mstore(0x2780, mulmod(mload(0x2a40), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2720) mstore(0x2720, mulmod(mload(0x26c0), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x26c0, inv) }{ let result := mload(0x26c0)result := addmod(mload(0x2720), result, f_q)result := addmod(mload(0x2780), result, f_q)result := addmod(mload(0x27e0), result, f_q)mstore(0x2c80, result) }mstore(0x2ca0, mulmod(mload(0x2860), mload(0x2820), f_q)){ let result := mload(0x28c0)result := addmod(mload(0x2920), result, f_q)mstore(0x2cc0, result) }mstore(0x2ce0, mulmod(mload(0x2860), mload(0x2a00), f_q)){ let result := mload(0x2980)result := addmod(mload(0x29e0), result, f_q)mstore(0x2d00, result) }mstore(0x2d20, mulmod(mload(0x2860), mload(0x2800), f_q)){ let result := mload(0x2a20)mstore(0x2d40, result) }{ let prod := mload(0x2c80) prod := mulmod(mload(0x2cc0), prod, f_q) mstore(0x2d60, prod) prod := mulmod(mload(0x2d00), prod, f_q) mstore(0x2d80, prod) prod := mulmod(mload(0x2d40), prod, f_q) mstore(0x2da0, prod) }mstore(0x2de0, 32)mstore(0x2e00, 32)mstore(0x2e20, 32)mstore(0x2e40, mload(0x2da0))mstore(0x2e60, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x2e80, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x2de0, 0xc0, 0x2dc0, 0x20), 1), success){ let inv := mload(0x2dc0) let v v := mload(0x2d40) mstore(0x2d40, mulmod(mload(0x2d80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2d00) mstore(0x2d00, mulmod(mload(0x2d60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2cc0) mstore(0x2cc0, mulmod(mload(0x2c80), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x2c80, inv) }mstore(0x2ea0, mulmod(mload(0x2ca0), mload(0x2cc0), f_q))mstore(0x2ec0, mulmod(mload(0x2ce0), mload(0x2d00), f_q))mstore(0x2ee0, mulmod(mload(0x2d20), mload(0x2d40), f_q))mstore(0x2f00, mulmod(mload(0x940), mload(0x940), f_q))mstore(0x2f20, mulmod(mload(0x2f00), mload(0x940), f_q))mstore(0x2f40, mulmod(mload(0x2f20), mload(0x940), f_q))mstore(0x2f60, mulmod(mload(0x2f40), mload(0x940), f_q))mstore(0x2f80, mulmod(mload(0x2f60), mload(0x940), f_q))mstore(0x2fa0, mulmod(mload(0x2f80), mload(0x940), f_q))mstore(0x2fc0, mulmod(mload(0x2fa0), mload(0x940), f_q))mstore(0x2fe0, mulmod(mload(0x2fc0), mload(0x940), f_q))mstore(0x3000, mulmod(mload(0x2fe0), mload(0x940), f_q))mstore(0x3020, mulmod(mload(0x9a0), mload(0x9a0), f_q))mstore(0x3040, mulmod(mload(0x3020), mload(0x9a0), f_q))mstore(0x3060, mulmod(mload(0x3040), mload(0x9a0), f_q)){ let result := mulmod(mload(0x6c0), mload(0x26c0), f_q)result := addmod(mulmod(mload(0x6e0), mload(0x2720), f_q), result, f_q)result := addmod(mulmod(mload(0x700), mload(0x2780), f_q), result, f_q)result := addmod(mulmod(mload(0x720), mload(0x27e0), f_q), result, f_q)mstore(0x3080, result) }mstore(0x30a0, mulmod(mload(0x3080), mload(0x2c80), f_q))mstore(0x30c0, mulmod(sub(f_q, mload(0x30a0)), 1, f_q))mstore(0x30e0, mulmod(mload(0x30c0), 1, f_q))mstore(0x3100, mulmod(1, mload(0x2ca0), f_q)){ let result := mulmod(mload(0x840), mload(0x28c0), f_q)result := addmod(mulmod(mload(0x860), mload(0x2920), f_q), result, f_q)mstore(0x3120, result) }mstore(0x3140, mulmod(mload(0x3120), mload(0x2ea0), f_q))mstore(0x3160, mulmod(sub(f_q, mload(0x3140)), 1, f_q))mstore(0x3180, mulmod(mload(0x3100), 1, f_q)){ let result := mulmod(mload(0x880), mload(0x28c0), f_q)result := addmod(mulmod(mload(0x8a0), mload(0x2920), f_q), result, f_q)mstore(0x31a0, result) }mstore(0x31c0, mulmod(mload(0x31a0), mload(0x2ea0), f_q))mstore(0x31e0, mulmod(sub(f_q, mload(0x31c0)), mload(0x940), f_q))mstore(0x3200, mulmod(mload(0x3100), mload(0x940), f_q))mstore(0x3220, addmod(mload(0x3160), mload(0x31e0), f_q))mstore(0x3240, mulmod(mload(0x3220), mload(0x9a0), f_q))mstore(0x3260, mulmod(mload(0x3180), mload(0x9a0), f_q))mstore(0x3280, mulmod(mload(0x3200), mload(0x9a0), f_q))mstore(0x32a0, addmod(mload(0x30e0), mload(0x3240), f_q))mstore(0x32c0, mulmod(1, mload(0x2ce0), f_q)){ let result := mulmod(mload(0x8c0), mload(0x2980), f_q)result := addmod(mulmod(mload(0x8e0), mload(0x29e0), f_q), result, f_q)mstore(0x32e0, result) }mstore(0x3300, mulmod(mload(0x32e0), mload(0x2ec0), f_q))mstore(0x3320, mulmod(sub(f_q, mload(0x3300)), 1, f_q))mstore(0x3340, mulmod(mload(0x32c0), 1, f_q))mstore(0x3360, mulmod(mload(0x3320), mload(0x3020), f_q))mstore(0x3380, mulmod(mload(0x3340), mload(0x3020), f_q))mstore(0x33a0, addmod(mload(0x32a0), mload(0x3360), f_q))mstore(0x33c0, mulmod(1, mload(0x2d20), f_q)){ let result := mulmod(mload(0x900), mload(0x2a20), f_q)mstore(0x33e0, result) }mstore(0x3400, mulmod(mload(0x33e0), mload(0x2ee0), f_q))mstore(0x3420, mulmod(sub(f_q, mload(0x3400)), 1, f_q))mstore(0x3440, mulmod(mload(0x33c0), 1, f_q)){ let result := mulmod(mload(0x740), mload(0x2a20), f_q)mstore(0x3460, result) }mstore(0x3480, mulmod(mload(0x3460), mload(0x2ee0), f_q))mstore(0x34a0, mulmod(sub(f_q, mload(0x3480)), mload(0x940), f_q))mstore(0x34c0, mulmod(mload(0x33c0), mload(0x940), f_q))mstore(0x34e0, addmod(mload(0x3420), mload(0x34a0), f_q)){ let result := mulmod(mload(0x760), mload(0x2a20), f_q)mstore(0x3500, result) }mstore(0x3520, mulmod(mload(0x3500), mload(0x2ee0), f_q))mstore(0x3540, mulmod(sub(f_q, mload(0x3520)), mload(0x2f00), f_q))mstore(0x3560, mulmod(mload(0x33c0), mload(0x2f00), f_q))mstore(0x3580, addmod(mload(0x34e0), mload(0x3540), f_q)){ let result := mulmod(mload(0x780), mload(0x2a20), f_q)mstore(0x35a0, result) }mstore(0x35c0, mulmod(mload(0x35a0), mload(0x2ee0), f_q))mstore(0x35e0, mulmod(sub(f_q, mload(0x35c0)), mload(0x2f20), f_q))mstore(0x3600, mulmod(mload(0x33c0), mload(0x2f20), f_q))mstore(0x3620, addmod(mload(0x3580), mload(0x35e0), f_q)){ let result := mulmod(mload(0x7a0), mload(0x2a20), f_q)mstore(0x3640, result) }mstore(0x3660, mulmod(mload(0x3640), mload(0x2ee0), f_q))mstore(0x3680, mulmod(sub(f_q, mload(0x3660)), mload(0x2f40), f_q))mstore(0x36a0, mulmod(mload(0x33c0), mload(0x2f40), f_q))mstore(0x36c0, addmod(mload(0x3620), mload(0x3680), f_q)){ let result := mulmod(mload(0x7e0), mload(0x2a20), f_q)mstore(0x36e0, result) }mstore(0x3700, mulmod(mload(0x36e0), mload(0x2ee0), f_q))mstore(0x3720, mulmod(sub(f_q, mload(0x3700)), mload(0x2f60), f_q))mstore(0x3740, mulmod(mload(0x33c0), mload(0x2f60), f_q))mstore(0x3760, addmod(mload(0x36c0), mload(0x3720), f_q)){ let result := mulmod(mload(0x800), mload(0x2a20), f_q)mstore(0x3780, result) }mstore(0x37a0, mulmod(mload(0x3780), mload(0x2ee0), f_q))mstore(0x37c0, mulmod(sub(f_q, mload(0x37a0)), mload(0x2f80), f_q))mstore(0x37e0, mulmod(mload(0x33c0), mload(0x2f80), f_q))mstore(0x3800, addmod(mload(0x3760), mload(0x37c0), f_q)){ let result := mulmod(mload(0x820), mload(0x2a20), f_q)mstore(0x3820, result) }mstore(0x3840, mulmod(mload(0x3820), mload(0x2ee0), f_q))mstore(0x3860, mulmod(sub(f_q, mload(0x3840)), mload(0x2fa0), f_q))mstore(0x3880, mulmod(mload(0x33c0), mload(0x2fa0), f_q))mstore(0x38a0, addmod(mload(0x3800), mload(0x3860), f_q))mstore(0x38c0, mulmod(mload(0x2480), mload(0x2d20), f_q))mstore(0x38e0, mulmod(mload(0x24a0), mload(0x2d20), f_q))mstore(0x3900, mulmod(mload(0x24c0), mload(0x2d20), f_q)){ let result := mulmod(mload(0x24e0), mload(0x2a20), f_q)mstore(0x3920, result) }mstore(0x3940, mulmod(mload(0x3920), mload(0x2ee0), f_q))mstore(0x3960, mulmod(sub(f_q, mload(0x3940)), mload(0x2fc0), f_q))mstore(0x3980, mulmod(mload(0x33c0), mload(0x2fc0), f_q))mstore(0x39a0, mulmod(mload(0x38c0), mload(0x2fc0), f_q))mstore(0x39c0, mulmod(mload(0x38e0), mload(0x2fc0), f_q))mstore(0x39e0, mulmod(mload(0x3900), mload(0x2fc0), f_q))mstore(0x3a00, addmod(mload(0x38a0), mload(0x3960), f_q)){ let result := mulmod(mload(0x7c0), mload(0x2a20), f_q)mstore(0x3a20, result) }mstore(0x3a40, mulmod(mload(0x3a20), mload(0x2ee0), f_q))mstore(0x3a60, mulmod(sub(f_q, mload(0x3a40)), mload(0x2fe0), f_q))mstore(0x3a80, mulmod(mload(0x33c0), mload(0x2fe0), f_q))mstore(0x3aa0, addmod(mload(0x3a00), mload(0x3a60), f_q))mstore(0x3ac0, mulmod(mload(0x3aa0), mload(0x3040), f_q))mstore(0x3ae0, mulmod(mload(0x3440), mload(0x3040), f_q))mstore(0x3b00, mulmod(mload(0x34c0), mload(0x3040), f_q))mstore(0x3b20, mulmod(mload(0x3560), mload(0x3040), f_q))mstore(0x3b40, mulmod(mload(0x3600), mload(0x3040), f_q))mstore(0x3b60, mulmod(mload(0x36a0), mload(0x3040), f_q))mstore(0x3b80, mulmod(mload(0x3740), mload(0x3040), f_q))mstore(0x3ba0, mulmod(mload(0x37e0), mload(0x3040), f_q))mstore(0x3bc0, mulmod(mload(0x3880), mload(0x3040), f_q))mstore(0x3be0, mulmod(mload(0x3980), mload(0x3040), f_q))mstore(0x3c00, mulmod(mload(0x39a0), mload(0x3040), f_q))mstore(0x3c20, mulmod(mload(0x39c0), mload(0x3040), f_q))mstore(0x3c40, mulmod(mload(0x39e0), mload(0x3040), f_q))mstore(0x3c60, mulmod(mload(0x3a80), mload(0x3040), f_q))mstore(0x3c80, addmod(mload(0x33a0), mload(0x3ac0), f_q))mstore(0x3ca0, mulmod(1, mload(0x2860), f_q))mstore(0x3cc0, mulmod(1, mload(0xa40), f_q))mstore(0x3ce0, 0x0000000000000000000000000000000000000000000000000000000000000001) mstore(0x3d00, 0x0000000000000000000000000000000000000000000000000000000000000002)mstore(0x3d20, mload(0x3c80))success := and(eq(staticcall(gas(), 0x7, 0x3ce0, 0x60, 0x3ce0, 0x40), 1), success)mstore(0x3d40, mload(0x3ce0)) mstore(0x3d60, mload(0x3d00))mstore(0x3d80, mload(0x260)) mstore(0x3da0, mload(0x280))success := and(eq(staticcall(gas(), 0x6, 0x3d40, 0x80, 0x3d40, 0x40), 1), success)mstore(0x3dc0, mload(0x440)) mstore(0x3de0, mload(0x460))mstore(0x3e00, mload(0x3260))success := and(eq(staticcall(gas(), 0x7, 0x3dc0, 0x60, 0x3dc0, 0x40), 1), success)mstore(0x3e20, mload(0x3d40)) mstore(0x3e40, mload(0x3d60))mstore(0x3e60, mload(0x3dc0)) mstore(0x3e80, mload(0x3de0))success := and(eq(staticcall(gas(), 0x6, 0x3e20, 0x80, 0x3e20, 0x40), 1), success)mstore(0x3ea0, mload(0x480)) mstore(0x3ec0, mload(0x4a0))mstore(0x3ee0, mload(0x3280))success := and(eq(staticcall(gas(), 0x7, 0x3ea0, 0x60, 0x3ea0, 0x40), 1), success)mstore(0x3f00, mload(0x3e20)) mstore(0x3f20, mload(0x3e40))mstore(0x3f40, mload(0x3ea0)) mstore(0x3f60, mload(0x3ec0))success := and(eq(staticcall(gas(), 0x6, 0x3f00, 0x80, 0x3f00, 0x40), 1), success)mstore(0x3f80, mload(0x300)) mstore(0x3fa0, mload(0x320))mstore(0x3fc0, mload(0x3380))success := and(eq(staticcall(gas(), 0x7, 0x3f80, 0x60, 0x3f80, 0x40), 1), success)mstore(0x3fe0, mload(0x3f00)) mstore(0x4000, mload(0x3f20))mstore(0x4020, mload(0x3f80)) mstore(0x4040, mload(0x3fa0))success := and(eq(staticcall(gas(), 0x6, 0x3fe0, 0x80, 0x3fe0, 0x40), 1), success)mstore(0x4060, mload(0x340)) mstore(0x4080, mload(0x360))mstore(0x40a0, mload(0x3ae0))success := and(eq(staticcall(gas(), 0x7, 0x4060, 0x60, 0x4060, 0x40), 1), success)mstore(0x40c0, mload(0x3fe0)) mstore(0x40e0, mload(0x4000))mstore(0x4100, mload(0x4060)) mstore(0x4120, mload(0x4080))success := and(eq(staticcall(gas(), 0x6, 0x40c0, 0x80, 0x40c0, 0x40), 1), success)mstore(0x4140, 0x2a29a92f0d6fe46b79653fbc083c09800aa1b2e56c7973c6c21bfa4c1486e46e) mstore(0x4160, 0x05dfaba6e433c5b30f7097a7792e9013bfb7eb838682517bdf11d68951c90239)mstore(0x4180, mload(0x3b00))success := and(eq(staticcall(gas(), 0x7, 0x4140, 0x60, 0x4140, 0x40), 1), success)mstore(0x41a0, mload(0x40c0)) mstore(0x41c0, mload(0x40e0))mstore(0x41e0, mload(0x4140)) mstore(0x4200, mload(0x4160))success := and(eq(staticcall(gas(), 0x6, 0x41a0, 0x80, 0x41a0, 0x40), 1), success)mstore(0x4220, 0x0ba574041b9acf0b879828f757fdbe006ec303bb00e85d005f97abcd2607422d) mstore(0x4240, 0x25383b7c510633308b668f09fe22cbd16b83d898660128f6f5390ca909c737fa)mstore(0x4260, mload(0x3b20))success := and(eq(staticcall(gas(), 0x7, 0x4220, 0x60, 0x4220, 0x40), 1), success)mstore(0x4280, mload(0x41a0)) mstore(0x42a0, mload(0x41c0))mstore(0x42c0, mload(0x4220)) mstore(0x42e0, mload(0x4240))success := and(eq(staticcall(gas(), 0x6, 0x4280, 0x80, 0x4280, 0x40), 1), success)mstore(0x4300, 0x2791f81a6904461f649d0e9721cb4a56e033e188b17403bab35f964c2933adea) mstore(0x4320, 0x1b957ffe9eee2e38474fc73d00762637eb2f42f93dbd63b07ac3a7a80d01fcd8)mstore(0x4340, mload(0x3b40))success := and(eq(staticcall(gas(), 0x7, 0x4300, 0x60, 0x4300, 0x40), 1), success)mstore(0x4360, mload(0x4280)) mstore(0x4380, mload(0x42a0))mstore(0x43a0, mload(0x4300)) mstore(0x43c0, mload(0x4320))success := and(eq(staticcall(gas(), 0x6, 0x4360, 0x80, 0x4360, 0x40), 1), success)mstore(0x43e0, 0x1c0d239ee9e8daa18d0898f4091a6d571e50441d852906e11d0fae1d1dedb1fb) mstore(0x4400, 0x0749d3ee27e89e899d6b17981c477f185f713dc32c470a6b8ebfae12370a852d)mstore(0x4420, mload(0x3b60))success := and(eq(staticcall(gas(), 0x7, 0x43e0, 0x60, 0x43e0, 0x40), 1), success)mstore(0x4440, mload(0x4360)) mstore(0x4460, mload(0x4380))mstore(0x4480, mload(0x43e0)) mstore(0x44a0, mload(0x4400))success := and(eq(staticcall(gas(), 0x6, 0x4440, 0x80, 0x4440, 0x40), 1), success)mstore(0x44c0, 0x2be7bc0c93949aaf2165975ee11a8dac7a848510b8dbb3d07df1e97bf5c7d299) mstore(0x44e0, 0x2e0a12eab15526f01ee7f16166df315920eae20f49d2507431101ea98f4a17cd)mstore(0x4500, mload(0x3b80))success := and(eq(staticcall(gas(), 0x7, 0x44c0, 0x60, 0x44c0, 0x40), 1), success)mstore(0x4520, mload(0x4440)) mstore(0x4540, mload(0x4460))mstore(0x4560, mload(0x44c0)) mstore(0x4580, mload(0x44e0))success := and(eq(staticcall(gas(), 0x6, 0x4520, 0x80, 0x4520, 0x40), 1), success)mstore(0x45a0, 0x28730fcfa4e1791ce13e428c901bff6c476187f0ea04d422f623f16b58296254) mstore(0x45c0, 0x1872c5dde77a52f2641090fbd7c2a11e8d12f919017d70a4fe57e588ead44527)mstore(0x45e0, mload(0x3ba0))success := and(eq(staticcall(gas(), 0x7, 0x45a0, 0x60, 0x45a0, 0x40), 1), success)mstore(0x4600, mload(0x4520)) mstore(0x4620, mload(0x4540))mstore(0x4640, mload(0x45a0)) mstore(0x4660, mload(0x45c0))success := and(eq(staticcall(gas(), 0x6, 0x4600, 0x80, 0x4600, 0x40), 1), success)mstore(0x4680, 0x02d518a4f6d68ae5997ad24fe8b58068acb972cfe8b250ab82e5390d91914950) mstore(0x46a0, 0x0695bba443e1eeed7cf440186dde2e72ebf1ec3f84d8baf57ee1cbe7f36df70d)mstore(0x46c0, mload(0x3bc0))success := and(eq(staticcall(gas(), 0x7, 0x4680, 0x60, 0x4680, 0x40), 1), success)mstore(0x46e0, mload(0x4600)) mstore(0x4700, mload(0x4620))mstore(0x4720, mload(0x4680)) mstore(0x4740, mload(0x46a0))success := and(eq(staticcall(gas(), 0x6, 0x46e0, 0x80, 0x46e0, 0x40), 1), success)mstore(0x4760, mload(0x560)) mstore(0x4780, mload(0x580))mstore(0x47a0, mload(0x3be0))success := and(eq(staticcall(gas(), 0x7, 0x4760, 0x60, 0x4760, 0x40), 1), success)mstore(0x47c0, mload(0x46e0)) mstore(0x47e0, mload(0x4700))mstore(0x4800, mload(0x4760)) mstore(0x4820, mload(0x4780))success := and(eq(staticcall(gas(), 0x6, 0x47c0, 0x80, 0x47c0, 0x40), 1), success)mstore(0x4840, mload(0x5a0)) mstore(0x4860, mload(0x5c0))mstore(0x4880, mload(0x3c00))success := and(eq(staticcall(gas(), 0x7, 0x4840, 0x60, 0x4840, 0x40), 1), success)mstore(0x48a0, mload(0x47c0)) mstore(0x48c0, mload(0x47e0))mstore(0x48e0, mload(0x4840)) mstore(0x4900, mload(0x4860))success := and(eq(staticcall(gas(), 0x6, 0x48a0, 0x80, 0x48a0, 0x40), 1), success)mstore(0x4920, mload(0x5e0)) mstore(0x4940, mload(0x600))mstore(0x4960, mload(0x3c20))success := and(eq(staticcall(gas(), 0x7, 0x4920, 0x60, 0x4920, 0x40), 1), success)mstore(0x4980, mload(0x48a0)) mstore(0x49a0, mload(0x48c0))mstore(0x49c0, mload(0x4920)) mstore(0x49e0, mload(0x4940))success := and(eq(staticcall(gas(), 0x6, 0x4980, 0x80, 0x4980, 0x40), 1), success)mstore(0x4a00, mload(0x620)) mstore(0x4a20, mload(0x640))mstore(0x4a40, mload(0x3c40))success := and(eq(staticcall(gas(), 0x7, 0x4a00, 0x60, 0x4a00, 0x40), 1), success)mstore(0x4a60, mload(0x4980)) mstore(0x4a80, mload(0x49a0))mstore(0x4aa0, mload(0x4a00)) mstore(0x4ac0, mload(0x4a20))success := and(eq(staticcall(gas(), 0x6, 0x4a60, 0x80, 0x4a60, 0x40), 1), success)mstore(0x4ae0, mload(0x4c0)) mstore(0x4b00, mload(0x4e0))mstore(0x4b20, mload(0x3c60))success := and(eq(staticcall(gas(), 0x7, 0x4ae0, 0x60, 0x4ae0, 0x40), 1), success)mstore(0x4b40, mload(0x4a60)) mstore(0x4b60, mload(0x4a80))mstore(0x4b80, mload(0x4ae0)) mstore(0x4ba0, mload(0x4b00))success := and(eq(staticcall(gas(), 0x6, 0x4b40, 0x80, 0x4b40, 0x40), 1), success)mstore(0x4bc0, mload(0x9e0)) mstore(0x4be0, mload(0xa00))mstore(0x4c00, sub(f_q, mload(0x3ca0)))success := and(eq(staticcall(gas(), 0x7, 0x4bc0, 0x60, 0x4bc0, 0x40), 1), success)mstore(0x4c20, mload(0x4b40)) mstore(0x4c40, mload(0x4b60))mstore(0x4c60, mload(0x4bc0)) mstore(0x4c80, mload(0x4be0))success := and(eq(staticcall(gas(), 0x6, 0x4c20, 0x80, 0x4c20, 0x40), 1), success)mstore(0x4ca0, mload(0xa80)) mstore(0x4cc0, mload(0xaa0))mstore(0x4ce0, mload(0x3cc0))success := and(eq(staticcall(gas(), 0x7, 0x4ca0, 0x60, 0x4ca0, 0x40), 1), success)mstore(0x4d00, mload(0x4c20)) mstore(0x4d20, mload(0x4c40))mstore(0x4d40, mload(0x4ca0)) mstore(0x4d60, mload(0x4cc0))success := and(eq(staticcall(gas(), 0x6, 0x4d00, 0x80, 0x4d00, 0x40), 1), success)mstore(0x4d80, mload(0x4d00)) mstore(0x4da0, mload(0x4d20))mstore(0x4dc0, mload(0xa80)) mstore(0x4de0, mload(0xaa0))mstore(0x4e00, mload(0xac0)) mstore(0x4e20, mload(0xae0))mstore(0x4e40, mload(0xb00)) mstore(0x4e60, mload(0xb20))mstore(0x4e80, keccak256(0x4d80, 256))mstore(0x4ea0, mod(mload(19968), f_q))mstore(0x4ec0, mulmod(mload(0x4ea0), mload(0x4ea0), f_q))mstore(0x4ee0, mulmod(1, mload(0x4ea0), f_q))mstore(0x4f00, mload(0x4e00)) mstore(0x4f20, mload(0x4e20))mstore(0x4f40, mload(0x4ee0))success := and(eq(staticcall(gas(), 0x7, 0x4f00, 0x60, 0x4f00, 0x40), 1), success)mstore(0x4f60, mload(0x4d80)) mstore(0x4f80, mload(0x4da0))mstore(0x4fa0, mload(0x4f00)) mstore(0x4fc0, mload(0x4f20))success := and(eq(staticcall(gas(), 0x6, 0x4f60, 0x80, 0x4f60, 0x40), 1), success)mstore(0x4fe0, mload(0x4e40)) mstore(0x5000, mload(0x4e60))mstore(0x5020, mload(0x4ee0))success := and(eq(staticcall(gas(), 0x7, 0x4fe0, 0x60, 0x4fe0, 0x40), 1), success)mstore(0x5040, mload(0x4dc0)) mstore(0x5060, mload(0x4de0))mstore(0x5080, mload(0x4fe0)) mstore(0x50a0, mload(0x5000))success := and(eq(staticcall(gas(), 0x6, 0x5040, 0x80, 0x5040, 0x40), 1), success)mstore(0x50c0, mload(0x4f60)) mstore(0x50e0, mload(0x4f80))mstore(0x5100, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) mstore(0x5120, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) mstore(0x5140, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) mstore(0x5160, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)mstore(0x5180, mload(0x5040)) mstore(0x51a0, mload(0x5060))mstore(0x51c0, 0x0181624e80f3d6ae28df7e01eaeab1c0e919877a3b8a6b7fbc69a6817d596ea2) mstore(0x51e0, 0x1783d30dcb12d259bb89098addf6280fa4b653be7a152542a28f7b926e27e648) mstore(0x5200, 0x00ae44489d41a0d179e2dfdc03bddd883b7109f8b6ae316a59e815c1a6b35304) mstore(0x5220, 0x0b2147ab62a386bd63e6de1522109b8c9588ab466f5aadfde8c41ca3749423ee)success := and(eq(staticcall(gas(), 0x8, 0x50c0, 0x180, 0x50c0, 0x20), 1), success)success := and(eq(mload(0x50c0), 1), success)} return success; } } + assembly { 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(0xa0, mod(calldataload(0x4), f_q))mstore(0xc0, mod(calldataload(0x24), f_q))mstore(0xe0, mod(calldataload(0x44), f_q))mstore(0x100, mod(calldataload(0x64), f_q))mstore(0x120, mod(calldataload(0x84), f_q))mstore(0x140, mod(calldataload(0xa4), f_q))mstore(0x160, mod(calldataload(0xc4), f_q))mstore(0x180, mod(calldataload(0xe4), f_q))mstore(0x1a0, mod(calldataload(0x104), f_q))mstore(0x1c0, mod(calldataload(0x124), f_q))mstore(0x1e0, mod(calldataload(0x144), f_q))mstore(0x200, mod(calldataload(0x164), f_q))mstore(0x220, mod(calldataload(0x184), f_q))mstore(0x240, mod(calldataload(0x1a4), f_q))mstore(0x80, 16106448136499026851096799321936372170818194453327642173445160481527811968) { let x := calldataload(0x204) mstore(0x260, x) let y := calldataload(0x224) mstore(0x280, y) success := and(validate_ec_point(x, y), success) }mstore(0x2a0, keccak256(0x80, 544)){ let hash := mload(0x2a0) mstore(0x2c0, mod(hash, f_q)) mstore(0x2e0, hash) } { let x := calldataload(0x244) mstore(0x300, x) let y := calldataload(0x264) mstore(0x320, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x284) mstore(0x340, x) let y := calldataload(0x2a4) mstore(0x360, y) success := and(validate_ec_point(x, y), success) }mstore(0x380, keccak256(0x2e0, 160)){ let hash := mload(0x380) mstore(0x3a0, mod(hash, f_q)) mstore(0x3c0, hash) }mstore8(0x3e0, 1)mstore(0x3e0, keccak256(0x3c0, 33)){ let hash := mload(0x3e0) mstore(0x400, mod(hash, f_q)) mstore(0x420, hash) } { let x := calldataload(0x2c4) mstore(0x440, x) let y := calldataload(0x2e4) mstore(0x460, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x304) mstore(0x480, x) let y := calldataload(0x324) mstore(0x4a0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x344) mstore(0x4c0, x) let y := calldataload(0x364) mstore(0x4e0, y) success := and(validate_ec_point(x, y), success) }mstore(0x500, keccak256(0x420, 224)){ let hash := mload(0x500) mstore(0x520, mod(hash, f_q)) mstore(0x540, hash) } { let x := calldataload(0x384) mstore(0x560, x) let y := calldataload(0x3a4) mstore(0x580, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x3c4) mstore(0x5a0, x) let y := calldataload(0x3e4) mstore(0x5c0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x404) mstore(0x5e0, x) let y := calldataload(0x424) mstore(0x600, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x444) mstore(0x620, x) let y := calldataload(0x464) mstore(0x640, y) success := and(validate_ec_point(x, y), success) }mstore(0x660, keccak256(0x540, 288)){ let hash := mload(0x660) mstore(0x680, mod(hash, f_q)) mstore(0x6a0, hash) }mstore(0x6c0, mod(calldataload(0x484), f_q))mstore(0x6e0, mod(calldataload(0x4a4), f_q))mstore(0x700, mod(calldataload(0x4c4), f_q))mstore(0x720, mod(calldataload(0x4e4), f_q))mstore(0x740, mod(calldataload(0x504), f_q))mstore(0x760, mod(calldataload(0x524), f_q))mstore(0x780, mod(calldataload(0x544), f_q))mstore(0x7a0, mod(calldataload(0x564), f_q))mstore(0x7c0, mod(calldataload(0x584), f_q))mstore(0x7e0, mod(calldataload(0x5a4), f_q))mstore(0x800, mod(calldataload(0x5c4), f_q))mstore(0x820, mod(calldataload(0x5e4), f_q))mstore(0x840, mod(calldataload(0x604), f_q))mstore(0x860, mod(calldataload(0x624), f_q))mstore(0x880, mod(calldataload(0x644), f_q))mstore(0x8a0, mod(calldataload(0x664), f_q))mstore(0x8c0, mod(calldataload(0x684), f_q))mstore(0x8e0, mod(calldataload(0x6a4), f_q))mstore(0x900, mod(calldataload(0x6c4), f_q))mstore(0x920, keccak256(0x6a0, 640)){ let hash := mload(0x920) mstore(0x940, mod(hash, f_q)) mstore(0x960, hash) }mstore8(0x980, 1)mstore(0x980, keccak256(0x960, 33)){ let hash := mload(0x980) mstore(0x9a0, mod(hash, f_q)) mstore(0x9c0, hash) } { let x := calldataload(0x6e4) mstore(0x9e0, x) let y := calldataload(0x704) mstore(0xa00, y) success := and(validate_ec_point(x, y), success) }mstore(0xa20, keccak256(0x9c0, 96)){ let hash := mload(0xa20) mstore(0xa40, mod(hash, f_q)) mstore(0xa60, hash) } { let x := calldataload(0x724) mstore(0xa80, x) let y := calldataload(0x744) mstore(0xaa0, y) success := and(validate_ec_point(x, y), success) }{ let x := mload(0xa0)x := add(x, shl(88, mload(0xc0)))x := add(x, shl(176, mload(0xe0)))mstore(0xac0, x)let y := mload(0x100)y := add(y, shl(88, mload(0x120)))y := add(y, shl(176, mload(0x140)))mstore(0xae0, y) success := and(validate_ec_point(x, y), success) }{ let x := mload(0x160)x := add(x, shl(88, mload(0x180)))x := add(x, shl(176, mload(0x1a0)))mstore(0xb00, x)let y := mload(0x1c0)y := add(y, shl(88, mload(0x1e0)))y := add(y, shl(176, mload(0x200)))mstore(0xb20, y) success := and(validate_ec_point(x, y), success) }mstore(0xb40, mulmod(mload(0x680), mload(0x680), f_q))mstore(0xb60, mulmod(mload(0xb40), mload(0xb40), f_q))mstore(0xb80, mulmod(mload(0xb60), mload(0xb60), f_q))mstore(0xba0, mulmod(mload(0xb80), mload(0xb80), f_q))mstore(0xbc0, mulmod(mload(0xba0), mload(0xba0), f_q))mstore(0xbe0, mulmod(mload(0xbc0), mload(0xbc0), f_q))mstore(0xc00, mulmod(mload(0xbe0), mload(0xbe0), f_q))mstore(0xc20, mulmod(mload(0xc00), mload(0xc00), f_q))mstore(0xc40, mulmod(mload(0xc20), mload(0xc20), f_q))mstore(0xc60, mulmod(mload(0xc40), mload(0xc40), f_q))mstore(0xc80, mulmod(mload(0xc60), mload(0xc60), f_q))mstore(0xca0, mulmod(mload(0xc80), mload(0xc80), f_q))mstore(0xcc0, mulmod(mload(0xca0), mload(0xca0), f_q))mstore(0xce0, mulmod(mload(0xcc0), mload(0xcc0), f_q))mstore(0xd00, mulmod(mload(0xce0), mload(0xce0), f_q))mstore(0xd20, mulmod(mload(0xd00), mload(0xd00), f_q))mstore(0xd40, mulmod(mload(0xd20), mload(0xd20), f_q))mstore(0xd60, mulmod(mload(0xd40), mload(0xd40), f_q))mstore(0xd80, mulmod(mload(0xd60), mload(0xd60), f_q))mstore(0xda0, mulmod(mload(0xd80), mload(0xd80), f_q))mstore(0xdc0, mulmod(mload(0xda0), mload(0xda0), f_q))mstore(0xde0, mulmod(mload(0xdc0), mload(0xdc0), f_q))mstore(0xe00, mulmod(mload(0xde0), mload(0xde0), f_q))mstore(0xe20, addmod(mload(0xe00), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q))mstore(0xe40, mulmod(mload(0xe20), 21888240262557392955334514970720457388010314637169927192662615958087340972065, f_q))mstore(0xe60, mulmod(mload(0xe40), 4506835738822104338668100540817374747935106310012997856968187171738630203507, f_q))mstore(0xe80, addmod(mload(0x680), 17381407133017170883578305204439900340613258090403036486730017014837178292110, f_q))mstore(0xea0, mulmod(mload(0xe40), 21710372849001950800533397158415938114909991150039389063546734567764856596059, f_q))mstore(0xec0, addmod(mload(0x680), 177870022837324421713008586841336973638373250376645280151469618810951899558, f_q))mstore(0xee0, mulmod(mload(0xe40), 1887003188133998471169152042388914354640772748308168868301418279904560637395, f_q))mstore(0xf00, addmod(mload(0x680), 20001239683705276751077253702868360733907591652107865475396785906671247858222, f_q))mstore(0xf20, mulmod(mload(0xe40), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q))mstore(0xf40, addmod(mload(0x680), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q))mstore(0xf60, mulmod(mload(0xe40), 14655294445420895451632927078981340937842238432098198055057679026789553137428, f_q))mstore(0xf80, addmod(mload(0x680), 7232948426418379770613478666275934150706125968317836288640525159786255358189, f_q))mstore(0xfa0, mulmod(mload(0xe40), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q))mstore(0xfc0, addmod(mload(0x680), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q))mstore(0xfe0, mulmod(mload(0xe40), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q))mstore(0x1000, addmod(mload(0x680), 12146688980418810893951125255607130521645347193942732958664170801695864621270, f_q))mstore(0x1020, mulmod(mload(0xe40), 1, f_q))mstore(0x1040, addmod(mload(0x680), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q))mstore(0x1060, mulmod(mload(0xe40), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q))mstore(0x1080, addmod(mload(0x680), 13513867906530865119835332133273263211836799082674232843258448413103731898270, f_q))mstore(0x10a0, mulmod(mload(0xe40), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q))mstore(0x10c0, addmod(mload(0x680), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q))mstore(0x10e0, mulmod(mload(0xe40), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q))mstore(0x1100, addmod(mload(0x680), 18272764063556419981698118473909131571661591947471949595929891197711371770216, f_q))mstore(0x1120, mulmod(mload(0xe40), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q))mstore(0x1140, addmod(mload(0x680), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q))mstore(0x1160, mulmod(mload(0xe40), 216092043779272773661818549620449970334216366264741118684015851799902419467, f_q))mstore(0x1180, addmod(mload(0x680), 21672150828060002448584587195636825118214148034151293225014188334775906076150, f_q))mstore(0x11a0, mulmod(mload(0xe40), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q))mstore(0x11c0, addmod(mload(0x680), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q))mstore(0x11e0, mulmod(mload(0xe40), 18610195890048912503953886742825279624920778288956610528523679659246523534888, f_q))mstore(0x1200, addmod(mload(0x680), 3278046981790362718292519002431995463627586111459423815174524527329284960729, f_q))mstore(0x1220, mulmod(mload(0xe40), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q))mstore(0x1240, addmod(mload(0x680), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q))mstore(0x1260, mulmod(mload(0xe40), 14875928112196239563830800280253496262679717528621719058794366823499719730250, f_q))mstore(0x1280, addmod(mload(0x680), 7012314759643035658415605465003778825868646871794315284903837363076088765367, f_q))mstore(0x12a0, mulmod(mload(0xe40), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q))mstore(0x12c0, addmod(mload(0x680), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q))mstore(0x12e0, mulmod(mload(0xe40), 5522161504810533295870699551020523636289972223872138525048055197429246400245, f_q))mstore(0x1300, addmod(mload(0x680), 16366081367028741926375706194236751452258392176543895818650148989146562095372, f_q))mstore(0x1320, mulmod(mload(0xe40), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q))mstore(0x1340, addmod(mload(0x680), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q))mstore(0x1360, mulmod(mload(0xe40), 9100833993744738801214480881117348002768153232283708533639316963648253510584, f_q))mstore(0x1380, addmod(mload(0x680), 12787408878094536421031924864139927085780211168132325810058887222927554985033, f_q)){ let prod := mload(0xe80) prod := mulmod(mload(0xec0), prod, f_q) mstore(0x13a0, prod) prod := mulmod(mload(0xf00), prod, f_q) mstore(0x13c0, prod) prod := mulmod(mload(0xf40), prod, f_q) mstore(0x13e0, prod) prod := mulmod(mload(0xf80), prod, f_q) mstore(0x1400, prod) prod := mulmod(mload(0xfc0), prod, f_q) mstore(0x1420, prod) prod := mulmod(mload(0x1000), prod, f_q) mstore(0x1440, prod) prod := mulmod(mload(0x1040), prod, f_q) mstore(0x1460, prod) prod := mulmod(mload(0x1080), prod, f_q) mstore(0x1480, prod) prod := mulmod(mload(0x10c0), prod, f_q) mstore(0x14a0, prod) prod := mulmod(mload(0x1100), prod, f_q) mstore(0x14c0, prod) prod := mulmod(mload(0x1140), prod, f_q) mstore(0x14e0, prod) prod := mulmod(mload(0x1180), prod, f_q) mstore(0x1500, prod) prod := mulmod(mload(0x11c0), prod, f_q) mstore(0x1520, prod) prod := mulmod(mload(0x1200), prod, f_q) mstore(0x1540, prod) prod := mulmod(mload(0x1240), prod, f_q) mstore(0x1560, prod) prod := mulmod(mload(0x1280), prod, f_q) mstore(0x1580, prod) prod := mulmod(mload(0x12c0), prod, f_q) mstore(0x15a0, prod) prod := mulmod(mload(0x1300), prod, f_q) mstore(0x15c0, prod) prod := mulmod(mload(0x1340), prod, f_q) mstore(0x15e0, prod) prod := mulmod(mload(0x1380), prod, f_q) mstore(0x1600, prod) prod := mulmod(mload(0xe20), prod, f_q) mstore(0x1620, prod) }mstore(0x1660, 32)mstore(0x1680, 32)mstore(0x16a0, 32)mstore(0x16c0, mload(0x1620))mstore(0x16e0, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x1700, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x1660, 0xc0, 0x1640, 0x20), 1), success){ let inv := mload(0x1640) let v v := mload(0xe20) mstore(0xe20, mulmod(mload(0x1600), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1380) mstore(0x1380, mulmod(mload(0x15e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1340) mstore(0x1340, mulmod(mload(0x15c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1300) mstore(0x1300, mulmod(mload(0x15a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x12c0) mstore(0x12c0, mulmod(mload(0x1580), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1280) mstore(0x1280, mulmod(mload(0x1560), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1240) mstore(0x1240, mulmod(mload(0x1540), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1200) mstore(0x1200, mulmod(mload(0x1520), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x11c0) mstore(0x11c0, mulmod(mload(0x1500), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1180) mstore(0x1180, mulmod(mload(0x14e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1140) mstore(0x1140, mulmod(mload(0x14c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1100) mstore(0x1100, mulmod(mload(0x14a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x10c0) mstore(0x10c0, mulmod(mload(0x1480), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1080) mstore(0x1080, mulmod(mload(0x1460), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1040) mstore(0x1040, mulmod(mload(0x1440), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1000) mstore(0x1000, mulmod(mload(0x1420), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xfc0) mstore(0xfc0, mulmod(mload(0x1400), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xf80) mstore(0xf80, mulmod(mload(0x13e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xf40) mstore(0xf40, mulmod(mload(0x13c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xf00) mstore(0xf00, mulmod(mload(0x13a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xec0) mstore(0xec0, mulmod(mload(0xe80), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0xe80, inv) }mstore(0x1720, mulmod(mload(0xe60), mload(0xe80), f_q))mstore(0x1740, mulmod(mload(0xea0), mload(0xec0), f_q))mstore(0x1760, mulmod(mload(0xee0), mload(0xf00), f_q))mstore(0x1780, mulmod(mload(0xf20), mload(0xf40), f_q))mstore(0x17a0, mulmod(mload(0xf60), mload(0xf80), f_q))mstore(0x17c0, mulmod(mload(0xfa0), mload(0xfc0), f_q))mstore(0x17e0, mulmod(mload(0xfe0), mload(0x1000), f_q))mstore(0x1800, mulmod(mload(0x1020), mload(0x1040), f_q))mstore(0x1820, mulmod(mload(0x1060), mload(0x1080), f_q))mstore(0x1840, mulmod(mload(0x10a0), mload(0x10c0), f_q))mstore(0x1860, mulmod(mload(0x10e0), mload(0x1100), f_q))mstore(0x1880, mulmod(mload(0x1120), mload(0x1140), f_q))mstore(0x18a0, mulmod(mload(0x1160), mload(0x1180), f_q))mstore(0x18c0, mulmod(mload(0x11a0), mload(0x11c0), f_q))mstore(0x18e0, mulmod(mload(0x11e0), mload(0x1200), f_q))mstore(0x1900, mulmod(mload(0x1220), mload(0x1240), f_q))mstore(0x1920, mulmod(mload(0x1260), mload(0x1280), f_q))mstore(0x1940, mulmod(mload(0x12a0), mload(0x12c0), f_q))mstore(0x1960, mulmod(mload(0x12e0), mload(0x1300), f_q))mstore(0x1980, mulmod(mload(0x1320), mload(0x1340), f_q))mstore(0x19a0, mulmod(mload(0x1360), mload(0x1380), f_q)){ let result := mulmod(mload(0x1800), mload(0xa0), f_q)result := addmod(mulmod(mload(0x1820), mload(0xc0), f_q), result, f_q)result := addmod(mulmod(mload(0x1840), mload(0xe0), f_q), result, f_q)result := addmod(mulmod(mload(0x1860), mload(0x100), f_q), result, f_q)result := addmod(mulmod(mload(0x1880), mload(0x120), f_q), result, f_q)result := addmod(mulmod(mload(0x18a0), mload(0x140), f_q), result, f_q)result := addmod(mulmod(mload(0x18c0), mload(0x160), f_q), result, f_q)result := addmod(mulmod(mload(0x18e0), mload(0x180), f_q), result, f_q)result := addmod(mulmod(mload(0x1900), mload(0x1a0), f_q), result, f_q)result := addmod(mulmod(mload(0x1920), mload(0x1c0), f_q), result, f_q)result := addmod(mulmod(mload(0x1940), mload(0x1e0), f_q), result, f_q)result := addmod(mulmod(mload(0x1960), mload(0x200), f_q), result, f_q)result := addmod(mulmod(mload(0x1980), mload(0x220), f_q), result, f_q)result := addmod(mulmod(mload(0x19a0), mload(0x240), f_q), result, f_q)mstore(0x19c0, result) }mstore(0x19e0, mulmod(mload(0x700), mload(0x6e0), f_q))mstore(0x1a00, addmod(mload(0x6c0), mload(0x19e0), f_q))mstore(0x1a20, addmod(mload(0x1a00), sub(f_q, mload(0x720)), f_q))mstore(0x1a40, mulmod(mload(0x1a20), mload(0x7a0), f_q))mstore(0x1a60, mulmod(mload(0x520), mload(0x1a40), f_q))mstore(0x1a80, addmod(1, sub(f_q, mload(0x840)), f_q))mstore(0x1aa0, mulmod(mload(0x1a80), mload(0x1800), f_q))mstore(0x1ac0, addmod(mload(0x1a60), mload(0x1aa0), f_q))mstore(0x1ae0, mulmod(mload(0x520), mload(0x1ac0), f_q))mstore(0x1b00, mulmod(mload(0x840), mload(0x840), f_q))mstore(0x1b20, addmod(mload(0x1b00), sub(f_q, mload(0x840)), f_q))mstore(0x1b40, mulmod(mload(0x1b20), mload(0x1720), f_q))mstore(0x1b60, addmod(mload(0x1ae0), mload(0x1b40), f_q))mstore(0x1b80, mulmod(mload(0x520), mload(0x1b60), f_q))mstore(0x1ba0, addmod(1, sub(f_q, mload(0x1720)), f_q))mstore(0x1bc0, addmod(mload(0x1740), mload(0x1760), f_q))mstore(0x1be0, addmod(mload(0x1bc0), mload(0x1780), f_q))mstore(0x1c00, addmod(mload(0x1be0), mload(0x17a0), f_q))mstore(0x1c20, addmod(mload(0x1c00), mload(0x17c0), f_q))mstore(0x1c40, addmod(mload(0x1c20), mload(0x17e0), f_q))mstore(0x1c60, addmod(mload(0x1ba0), sub(f_q, mload(0x1c40)), f_q))mstore(0x1c80, mulmod(mload(0x7e0), mload(0x3a0), f_q))mstore(0x1ca0, addmod(mload(0x740), mload(0x1c80), f_q))mstore(0x1cc0, addmod(mload(0x1ca0), mload(0x400), f_q))mstore(0x1ce0, mulmod(mload(0x800), mload(0x3a0), f_q))mstore(0x1d00, addmod(mload(0x6c0), mload(0x1ce0), f_q))mstore(0x1d20, addmod(mload(0x1d00), mload(0x400), f_q))mstore(0x1d40, mulmod(mload(0x1d20), mload(0x1cc0), f_q))mstore(0x1d60, mulmod(mload(0x820), mload(0x3a0), f_q))mstore(0x1d80, addmod(mload(0x19c0), mload(0x1d60), f_q))mstore(0x1da0, addmod(mload(0x1d80), mload(0x400), f_q))mstore(0x1dc0, mulmod(mload(0x1da0), mload(0x1d40), f_q))mstore(0x1de0, mulmod(mload(0x1dc0), mload(0x860), f_q))mstore(0x1e00, mulmod(1, mload(0x3a0), f_q))mstore(0x1e20, mulmod(mload(0x680), mload(0x1e00), f_q))mstore(0x1e40, addmod(mload(0x740), mload(0x1e20), f_q))mstore(0x1e60, addmod(mload(0x1e40), mload(0x400), f_q))mstore(0x1e80, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x3a0), f_q))mstore(0x1ea0, mulmod(mload(0x680), mload(0x1e80), f_q))mstore(0x1ec0, addmod(mload(0x6c0), mload(0x1ea0), f_q))mstore(0x1ee0, addmod(mload(0x1ec0), mload(0x400), f_q))mstore(0x1f00, mulmod(mload(0x1ee0), mload(0x1e60), f_q))mstore(0x1f20, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x3a0), f_q))mstore(0x1f40, mulmod(mload(0x680), mload(0x1f20), f_q))mstore(0x1f60, addmod(mload(0x19c0), mload(0x1f40), f_q))mstore(0x1f80, addmod(mload(0x1f60), mload(0x400), f_q))mstore(0x1fa0, mulmod(mload(0x1f80), mload(0x1f00), f_q))mstore(0x1fc0, mulmod(mload(0x1fa0), mload(0x840), f_q))mstore(0x1fe0, addmod(mload(0x1de0), sub(f_q, mload(0x1fc0)), f_q))mstore(0x2000, mulmod(mload(0x1fe0), mload(0x1c60), f_q))mstore(0x2020, addmod(mload(0x1b80), mload(0x2000), f_q))mstore(0x2040, mulmod(mload(0x520), mload(0x2020), f_q))mstore(0x2060, addmod(1, sub(f_q, mload(0x880)), f_q))mstore(0x2080, mulmod(mload(0x2060), mload(0x1800), f_q))mstore(0x20a0, addmod(mload(0x2040), mload(0x2080), f_q))mstore(0x20c0, mulmod(mload(0x520), mload(0x20a0), f_q))mstore(0x20e0, mulmod(mload(0x880), mload(0x880), f_q))mstore(0x2100, addmod(mload(0x20e0), sub(f_q, mload(0x880)), f_q))mstore(0x2120, mulmod(mload(0x2100), mload(0x1720), f_q))mstore(0x2140, addmod(mload(0x20c0), mload(0x2120), f_q))mstore(0x2160, mulmod(mload(0x520), mload(0x2140), f_q))mstore(0x2180, addmod(mload(0x8c0), mload(0x3a0), f_q))mstore(0x21a0, mulmod(mload(0x2180), mload(0x8a0), f_q))mstore(0x21c0, addmod(mload(0x900), mload(0x400), f_q))mstore(0x21e0, mulmod(mload(0x21c0), mload(0x21a0), f_q))mstore(0x2200, mulmod(mload(0x6c0), mload(0x780), f_q))mstore(0x2220, addmod(mload(0x2200), mload(0x3a0), f_q))mstore(0x2240, mulmod(mload(0x2220), mload(0x880), f_q))mstore(0x2260, addmod(mload(0x760), mload(0x400), f_q))mstore(0x2280, mulmod(mload(0x2260), mload(0x2240), f_q))mstore(0x22a0, addmod(mload(0x21e0), sub(f_q, mload(0x2280)), f_q))mstore(0x22c0, mulmod(mload(0x22a0), mload(0x1c60), f_q))mstore(0x22e0, addmod(mload(0x2160), mload(0x22c0), f_q))mstore(0x2300, mulmod(mload(0x520), mload(0x22e0), f_q))mstore(0x2320, addmod(mload(0x8c0), sub(f_q, mload(0x900)), f_q))mstore(0x2340, mulmod(mload(0x2320), mload(0x1800), f_q))mstore(0x2360, addmod(mload(0x2300), mload(0x2340), f_q))mstore(0x2380, mulmod(mload(0x520), mload(0x2360), f_q))mstore(0x23a0, mulmod(mload(0x2320), mload(0x1c60), f_q))mstore(0x23c0, addmod(mload(0x8c0), sub(f_q, mload(0x8e0)), f_q))mstore(0x23e0, mulmod(mload(0x23c0), mload(0x23a0), f_q))mstore(0x2400, addmod(mload(0x2380), mload(0x23e0), f_q))mstore(0x2420, mulmod(mload(0xe00), mload(0xe00), f_q))mstore(0x2440, mulmod(mload(0x2420), mload(0xe00), f_q))mstore(0x2460, mulmod(mload(0x2440), mload(0xe00), f_q))mstore(0x2480, mulmod(1, mload(0xe00), f_q))mstore(0x24a0, mulmod(1, mload(0x2420), f_q))mstore(0x24c0, mulmod(1, mload(0x2440), f_q))mstore(0x24e0, mulmod(mload(0x2400), mload(0xe20), f_q))mstore(0x2500, mulmod(mload(0xb40), mload(0x680), f_q))mstore(0x2520, mulmod(mload(0x2500), mload(0x680), f_q))mstore(0x2540, mulmod(mload(0x680), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q))mstore(0x2560, addmod(mload(0xa40), sub(f_q, mload(0x2540)), f_q))mstore(0x2580, mulmod(mload(0x680), 1, f_q))mstore(0x25a0, addmod(mload(0xa40), sub(f_q, mload(0x2580)), f_q))mstore(0x25c0, mulmod(mload(0x680), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q))mstore(0x25e0, addmod(mload(0xa40), sub(f_q, mload(0x25c0)), f_q))mstore(0x2600, mulmod(mload(0x680), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q))mstore(0x2620, addmod(mload(0xa40), sub(f_q, mload(0x2600)), f_q))mstore(0x2640, mulmod(mload(0x680), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q))mstore(0x2660, addmod(mload(0xa40), sub(f_q, mload(0x2640)), f_q))mstore(0x2680, mulmod(13213688729882003894512633350385593288217014177373218494356903340348818451480, mload(0x2500), f_q))mstore(0x26a0, mulmod(mload(0x2680), 1, f_q)){ let result := mulmod(mload(0xa40), mload(0x2680), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x26a0)), f_q), result, f_q)mstore(0x26c0, result) }mstore(0x26e0, mulmod(8207090019724696496350398458716998472718344609680392612601596849934418295470, mload(0x2500), f_q))mstore(0x2700, mulmod(mload(0x26e0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)){ let result := mulmod(mload(0xa40), mload(0x26e0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2700)), f_q), result, f_q)mstore(0x2720, result) }mstore(0x2740, mulmod(7391709068497399131897422873231908718558236401035363928063603272120120747483, mload(0x2500), f_q))mstore(0x2760, mulmod(mload(0x2740), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)){ let result := mulmod(mload(0xa40), mload(0x2740), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2760)), f_q), result, f_q)mstore(0x2780, result) }mstore(0x27a0, mulmod(19036273796805830823244991598792794567595348772040298280440552631112242221017, mload(0x2500), f_q))mstore(0x27c0, mulmod(mload(0x27a0), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q)){ let result := mulmod(mload(0xa40), mload(0x27a0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x27c0)), f_q), result, f_q)mstore(0x27e0, result) }mstore(0x2800, mulmod(1, mload(0x25a0), f_q))mstore(0x2820, mulmod(mload(0x2800), mload(0x25e0), f_q))mstore(0x2840, mulmod(mload(0x2820), mload(0x2620), f_q))mstore(0x2860, mulmod(mload(0x2840), mload(0x2660), f_q))mstore(0x2880, mulmod(13513867906530865119835332133273263211836799082674232843258448413103731898271, mload(0x680), f_q))mstore(0x28a0, mulmod(mload(0x2880), 1, f_q)){ let result := mulmod(mload(0xa40), mload(0x2880), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x28a0)), f_q), result, f_q)mstore(0x28c0, result) }mstore(0x28e0, mulmod(8374374965308410102411073611984011876711565317741801500439755773472076597346, mload(0x680), f_q))mstore(0x2900, mulmod(mload(0x28e0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)){ let result := mulmod(mload(0xa40), mload(0x28e0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2900)), f_q), result, f_q)mstore(0x2920, result) }mstore(0x2940, mulmod(12146688980418810893951125255607130521645347193942732958664170801695864621271, mload(0x680), f_q))mstore(0x2960, mulmod(mload(0x2940), 1, f_q)){ let result := mulmod(mload(0xa40), mload(0x2940), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2960)), f_q), result, f_q)mstore(0x2980, result) }mstore(0x29a0, mulmod(9741553891420464328295280489650144566903017206473301385034033384879943874346, mload(0x680), f_q))mstore(0x29c0, mulmod(mload(0x29a0), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q)){ let result := mulmod(mload(0xa40), mload(0x29a0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x29c0)), f_q), result, f_q)mstore(0x29e0, result) }mstore(0x2a00, mulmod(mload(0x2800), mload(0x2560), f_q)){ let result := mulmod(mload(0xa40), 1, f_q)result := addmod(mulmod(mload(0x680), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q)mstore(0x2a20, result) }{ let prod := mload(0x26c0) prod := mulmod(mload(0x2720), prod, f_q) mstore(0x2a40, prod) prod := mulmod(mload(0x2780), prod, f_q) mstore(0x2a60, prod) prod := mulmod(mload(0x27e0), prod, f_q) mstore(0x2a80, prod) prod := mulmod(mload(0x28c0), prod, f_q) mstore(0x2aa0, prod) prod := mulmod(mload(0x2920), prod, f_q) mstore(0x2ac0, prod) prod := mulmod(mload(0x2820), prod, f_q) mstore(0x2ae0, prod) prod := mulmod(mload(0x2980), prod, f_q) mstore(0x2b00, prod) prod := mulmod(mload(0x29e0), prod, f_q) mstore(0x2b20, prod) prod := mulmod(mload(0x2a00), prod, f_q) mstore(0x2b40, prod) prod := mulmod(mload(0x2a20), prod, f_q) mstore(0x2b60, prod) prod := mulmod(mload(0x2800), prod, f_q) mstore(0x2b80, prod) }mstore(0x2bc0, 32)mstore(0x2be0, 32)mstore(0x2c00, 32)mstore(0x2c20, mload(0x2b80))mstore(0x2c40, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x2c60, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x2bc0, 0xc0, 0x2ba0, 0x20), 1), success){ let inv := mload(0x2ba0) let v v := mload(0x2800) mstore(0x2800, mulmod(mload(0x2b60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2a20) mstore(0x2a20, mulmod(mload(0x2b40), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2a00) mstore(0x2a00, mulmod(mload(0x2b20), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x29e0) mstore(0x29e0, mulmod(mload(0x2b00), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2980) mstore(0x2980, mulmod(mload(0x2ae0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2820) mstore(0x2820, mulmod(mload(0x2ac0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2920) mstore(0x2920, mulmod(mload(0x2aa0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x28c0) mstore(0x28c0, mulmod(mload(0x2a80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x27e0) mstore(0x27e0, mulmod(mload(0x2a60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2780) mstore(0x2780, mulmod(mload(0x2a40), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2720) mstore(0x2720, mulmod(mload(0x26c0), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x26c0, inv) }{ let result := mload(0x26c0)result := addmod(mload(0x2720), result, f_q)result := addmod(mload(0x2780), result, f_q)result := addmod(mload(0x27e0), result, f_q)mstore(0x2c80, result) }mstore(0x2ca0, mulmod(mload(0x2860), mload(0x2820), f_q)){ let result := mload(0x28c0)result := addmod(mload(0x2920), result, f_q)mstore(0x2cc0, result) }mstore(0x2ce0, mulmod(mload(0x2860), mload(0x2a00), f_q)){ let result := mload(0x2980)result := addmod(mload(0x29e0), result, f_q)mstore(0x2d00, result) }mstore(0x2d20, mulmod(mload(0x2860), mload(0x2800), f_q)){ let result := mload(0x2a20)mstore(0x2d40, result) }{ let prod := mload(0x2c80) prod := mulmod(mload(0x2cc0), prod, f_q) mstore(0x2d60, prod) prod := mulmod(mload(0x2d00), prod, f_q) mstore(0x2d80, prod) prod := mulmod(mload(0x2d40), prod, f_q) mstore(0x2da0, prod) }mstore(0x2de0, 32)mstore(0x2e00, 32)mstore(0x2e20, 32)mstore(0x2e40, mload(0x2da0))mstore(0x2e60, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x2e80, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x2de0, 0xc0, 0x2dc0, 0x20), 1), success){ let inv := mload(0x2dc0) let v v := mload(0x2d40) mstore(0x2d40, mulmod(mload(0x2d80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2d00) mstore(0x2d00, mulmod(mload(0x2d60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2cc0) mstore(0x2cc0, mulmod(mload(0x2c80), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x2c80, inv) }mstore(0x2ea0, mulmod(mload(0x2ca0), mload(0x2cc0), f_q))mstore(0x2ec0, mulmod(mload(0x2ce0), mload(0x2d00), f_q))mstore(0x2ee0, mulmod(mload(0x2d20), mload(0x2d40), f_q))mstore(0x2f00, mulmod(mload(0x940), mload(0x940), f_q))mstore(0x2f20, mulmod(mload(0x2f00), mload(0x940), f_q))mstore(0x2f40, mulmod(mload(0x2f20), mload(0x940), f_q))mstore(0x2f60, mulmod(mload(0x2f40), mload(0x940), f_q))mstore(0x2f80, mulmod(mload(0x2f60), mload(0x940), f_q))mstore(0x2fa0, mulmod(mload(0x2f80), mload(0x940), f_q))mstore(0x2fc0, mulmod(mload(0x2fa0), mload(0x940), f_q))mstore(0x2fe0, mulmod(mload(0x2fc0), mload(0x940), f_q))mstore(0x3000, mulmod(mload(0x2fe0), mload(0x940), f_q))mstore(0x3020, mulmod(mload(0x9a0), mload(0x9a0), f_q))mstore(0x3040, mulmod(mload(0x3020), mload(0x9a0), f_q))mstore(0x3060, mulmod(mload(0x3040), mload(0x9a0), f_q)){ let result := mulmod(mload(0x6c0), mload(0x26c0), f_q)result := addmod(mulmod(mload(0x6e0), mload(0x2720), f_q), result, f_q)result := addmod(mulmod(mload(0x700), mload(0x2780), f_q), result, f_q)result := addmod(mulmod(mload(0x720), mload(0x27e0), f_q), result, f_q)mstore(0x3080, result) }mstore(0x30a0, mulmod(mload(0x3080), mload(0x2c80), f_q))mstore(0x30c0, mulmod(sub(f_q, mload(0x30a0)), 1, f_q))mstore(0x30e0, mulmod(mload(0x30c0), 1, f_q))mstore(0x3100, mulmod(1, mload(0x2ca0), f_q)){ let result := mulmod(mload(0x840), mload(0x28c0), f_q)result := addmod(mulmod(mload(0x860), mload(0x2920), f_q), result, f_q)mstore(0x3120, result) }mstore(0x3140, mulmod(mload(0x3120), mload(0x2ea0), f_q))mstore(0x3160, mulmod(sub(f_q, mload(0x3140)), 1, f_q))mstore(0x3180, mulmod(mload(0x3100), 1, f_q)){ let result := mulmod(mload(0x880), mload(0x28c0), f_q)result := addmod(mulmod(mload(0x8a0), mload(0x2920), f_q), result, f_q)mstore(0x31a0, result) }mstore(0x31c0, mulmod(mload(0x31a0), mload(0x2ea0), f_q))mstore(0x31e0, mulmod(sub(f_q, mload(0x31c0)), mload(0x940), f_q))mstore(0x3200, mulmod(mload(0x3100), mload(0x940), f_q))mstore(0x3220, addmod(mload(0x3160), mload(0x31e0), f_q))mstore(0x3240, mulmod(mload(0x3220), mload(0x9a0), f_q))mstore(0x3260, mulmod(mload(0x3180), mload(0x9a0), f_q))mstore(0x3280, mulmod(mload(0x3200), mload(0x9a0), f_q))mstore(0x32a0, addmod(mload(0x30e0), mload(0x3240), f_q))mstore(0x32c0, mulmod(1, mload(0x2ce0), f_q)){ let result := mulmod(mload(0x8c0), mload(0x2980), f_q)result := addmod(mulmod(mload(0x8e0), mload(0x29e0), f_q), result, f_q)mstore(0x32e0, result) }mstore(0x3300, mulmod(mload(0x32e0), mload(0x2ec0), f_q))mstore(0x3320, mulmod(sub(f_q, mload(0x3300)), 1, f_q))mstore(0x3340, mulmod(mload(0x32c0), 1, f_q))mstore(0x3360, mulmod(mload(0x3320), mload(0x3020), f_q))mstore(0x3380, mulmod(mload(0x3340), mload(0x3020), f_q))mstore(0x33a0, addmod(mload(0x32a0), mload(0x3360), f_q))mstore(0x33c0, mulmod(1, mload(0x2d20), f_q)){ let result := mulmod(mload(0x900), mload(0x2a20), f_q)mstore(0x33e0, result) }mstore(0x3400, mulmod(mload(0x33e0), mload(0x2ee0), f_q))mstore(0x3420, mulmod(sub(f_q, mload(0x3400)), 1, f_q))mstore(0x3440, mulmod(mload(0x33c0), 1, f_q)){ let result := mulmod(mload(0x740), mload(0x2a20), f_q)mstore(0x3460, result) }mstore(0x3480, mulmod(mload(0x3460), mload(0x2ee0), f_q))mstore(0x34a0, mulmod(sub(f_q, mload(0x3480)), mload(0x940), f_q))mstore(0x34c0, mulmod(mload(0x33c0), mload(0x940), f_q))mstore(0x34e0, addmod(mload(0x3420), mload(0x34a0), f_q)){ let result := mulmod(mload(0x760), mload(0x2a20), f_q)mstore(0x3500, result) }mstore(0x3520, mulmod(mload(0x3500), mload(0x2ee0), f_q))mstore(0x3540, mulmod(sub(f_q, mload(0x3520)), mload(0x2f00), f_q))mstore(0x3560, mulmod(mload(0x33c0), mload(0x2f00), f_q))mstore(0x3580, addmod(mload(0x34e0), mload(0x3540), f_q)){ let result := mulmod(mload(0x780), mload(0x2a20), f_q)mstore(0x35a0, result) }mstore(0x35c0, mulmod(mload(0x35a0), mload(0x2ee0), f_q))mstore(0x35e0, mulmod(sub(f_q, mload(0x35c0)), mload(0x2f20), f_q))mstore(0x3600, mulmod(mload(0x33c0), mload(0x2f20), f_q))mstore(0x3620, addmod(mload(0x3580), mload(0x35e0), f_q)){ let result := mulmod(mload(0x7a0), mload(0x2a20), f_q)mstore(0x3640, result) }mstore(0x3660, mulmod(mload(0x3640), mload(0x2ee0), f_q))mstore(0x3680, mulmod(sub(f_q, mload(0x3660)), mload(0x2f40), f_q))mstore(0x36a0, mulmod(mload(0x33c0), mload(0x2f40), f_q))mstore(0x36c0, addmod(mload(0x3620), mload(0x3680), f_q)){ let result := mulmod(mload(0x7e0), mload(0x2a20), f_q)mstore(0x36e0, result) }mstore(0x3700, mulmod(mload(0x36e0), mload(0x2ee0), f_q))mstore(0x3720, mulmod(sub(f_q, mload(0x3700)), mload(0x2f60), f_q))mstore(0x3740, mulmod(mload(0x33c0), mload(0x2f60), f_q))mstore(0x3760, addmod(mload(0x36c0), mload(0x3720), f_q)){ let result := mulmod(mload(0x800), mload(0x2a20), f_q)mstore(0x3780, result) }mstore(0x37a0, mulmod(mload(0x3780), mload(0x2ee0), f_q))mstore(0x37c0, mulmod(sub(f_q, mload(0x37a0)), mload(0x2f80), f_q))mstore(0x37e0, mulmod(mload(0x33c0), mload(0x2f80), f_q))mstore(0x3800, addmod(mload(0x3760), mload(0x37c0), f_q)){ let result := mulmod(mload(0x820), mload(0x2a20), f_q)mstore(0x3820, result) }mstore(0x3840, mulmod(mload(0x3820), mload(0x2ee0), f_q))mstore(0x3860, mulmod(sub(f_q, mload(0x3840)), mload(0x2fa0), f_q))mstore(0x3880, mulmod(mload(0x33c0), mload(0x2fa0), f_q))mstore(0x38a0, addmod(mload(0x3800), mload(0x3860), f_q))mstore(0x38c0, mulmod(mload(0x2480), mload(0x2d20), f_q))mstore(0x38e0, mulmod(mload(0x24a0), mload(0x2d20), f_q))mstore(0x3900, mulmod(mload(0x24c0), mload(0x2d20), f_q)){ let result := mulmod(mload(0x24e0), mload(0x2a20), f_q)mstore(0x3920, result) }mstore(0x3940, mulmod(mload(0x3920), mload(0x2ee0), f_q))mstore(0x3960, mulmod(sub(f_q, mload(0x3940)), mload(0x2fc0), f_q))mstore(0x3980, mulmod(mload(0x33c0), mload(0x2fc0), f_q))mstore(0x39a0, mulmod(mload(0x38c0), mload(0x2fc0), f_q))mstore(0x39c0, mulmod(mload(0x38e0), mload(0x2fc0), f_q))mstore(0x39e0, mulmod(mload(0x3900), mload(0x2fc0), f_q))mstore(0x3a00, addmod(mload(0x38a0), mload(0x3960), f_q)){ let result := mulmod(mload(0x7c0), mload(0x2a20), f_q)mstore(0x3a20, result) }mstore(0x3a40, mulmod(mload(0x3a20), mload(0x2ee0), f_q))mstore(0x3a60, mulmod(sub(f_q, mload(0x3a40)), mload(0x2fe0), f_q))mstore(0x3a80, mulmod(mload(0x33c0), mload(0x2fe0), f_q))mstore(0x3aa0, addmod(mload(0x3a00), mload(0x3a60), f_q))mstore(0x3ac0, mulmod(mload(0x3aa0), mload(0x3040), f_q))mstore(0x3ae0, mulmod(mload(0x3440), mload(0x3040), f_q))mstore(0x3b00, mulmod(mload(0x34c0), mload(0x3040), f_q))mstore(0x3b20, mulmod(mload(0x3560), mload(0x3040), f_q))mstore(0x3b40, mulmod(mload(0x3600), mload(0x3040), f_q))mstore(0x3b60, mulmod(mload(0x36a0), mload(0x3040), f_q))mstore(0x3b80, mulmod(mload(0x3740), mload(0x3040), f_q))mstore(0x3ba0, mulmod(mload(0x37e0), mload(0x3040), f_q))mstore(0x3bc0, mulmod(mload(0x3880), mload(0x3040), f_q))mstore(0x3be0, mulmod(mload(0x3980), mload(0x3040), f_q))mstore(0x3c00, mulmod(mload(0x39a0), mload(0x3040), f_q))mstore(0x3c20, mulmod(mload(0x39c0), mload(0x3040), f_q))mstore(0x3c40, mulmod(mload(0x39e0), mload(0x3040), f_q))mstore(0x3c60, mulmod(mload(0x3a80), mload(0x3040), f_q))mstore(0x3c80, addmod(mload(0x33a0), mload(0x3ac0), f_q))mstore(0x3ca0, mulmod(1, mload(0x2860), f_q))mstore(0x3cc0, mulmod(1, mload(0xa40), f_q))mstore(0x3ce0, 0x0000000000000000000000000000000000000000000000000000000000000001) mstore(0x3d00, 0x0000000000000000000000000000000000000000000000000000000000000002)mstore(0x3d20, mload(0x3c80))success := and(eq(staticcall(gas(), 0x7, 0x3ce0, 0x60, 0x3ce0, 0x40), 1), success)mstore(0x3d40, mload(0x3ce0)) mstore(0x3d60, mload(0x3d00))mstore(0x3d80, mload(0x260)) mstore(0x3da0, mload(0x280))success := and(eq(staticcall(gas(), 0x6, 0x3d40, 0x80, 0x3d40, 0x40), 1), success)mstore(0x3dc0, mload(0x440)) mstore(0x3de0, mload(0x460))mstore(0x3e00, mload(0x3260))success := and(eq(staticcall(gas(), 0x7, 0x3dc0, 0x60, 0x3dc0, 0x40), 1), success)mstore(0x3e20, mload(0x3d40)) mstore(0x3e40, mload(0x3d60))mstore(0x3e60, mload(0x3dc0)) mstore(0x3e80, mload(0x3de0))success := and(eq(staticcall(gas(), 0x6, 0x3e20, 0x80, 0x3e20, 0x40), 1), success)mstore(0x3ea0, mload(0x480)) mstore(0x3ec0, mload(0x4a0))mstore(0x3ee0, mload(0x3280))success := and(eq(staticcall(gas(), 0x7, 0x3ea0, 0x60, 0x3ea0, 0x40), 1), success)mstore(0x3f00, mload(0x3e20)) mstore(0x3f20, mload(0x3e40))mstore(0x3f40, mload(0x3ea0)) mstore(0x3f60, mload(0x3ec0))success := and(eq(staticcall(gas(), 0x6, 0x3f00, 0x80, 0x3f00, 0x40), 1), success)mstore(0x3f80, mload(0x300)) mstore(0x3fa0, mload(0x320))mstore(0x3fc0, mload(0x3380))success := and(eq(staticcall(gas(), 0x7, 0x3f80, 0x60, 0x3f80, 0x40), 1), success)mstore(0x3fe0, mload(0x3f00)) mstore(0x4000, mload(0x3f20))mstore(0x4020, mload(0x3f80)) mstore(0x4040, mload(0x3fa0))success := and(eq(staticcall(gas(), 0x6, 0x3fe0, 0x80, 0x3fe0, 0x40), 1), success)mstore(0x4060, mload(0x340)) mstore(0x4080, mload(0x360))mstore(0x40a0, mload(0x3ae0))success := and(eq(staticcall(gas(), 0x7, 0x4060, 0x60, 0x4060, 0x40), 1), success)mstore(0x40c0, mload(0x3fe0)) mstore(0x40e0, mload(0x4000))mstore(0x4100, mload(0x4060)) mstore(0x4120, mload(0x4080))success := and(eq(staticcall(gas(), 0x6, 0x40c0, 0x80, 0x40c0, 0x40), 1), success)mstore(0x4140, 0x2ee1a46553f256c57ee6cb05e97c6b2cee68b52afa6eb9594b0b6bed1a1da16c) mstore(0x4160, 0x155b8cd1fb98f80bd3fd688ce7c4c151ffc80dd80f8bacbf93425a8cc75d4798)mstore(0x4180, mload(0x3b00))success := and(eq(staticcall(gas(), 0x7, 0x4140, 0x60, 0x4140, 0x40), 1), success)mstore(0x41a0, mload(0x40c0)) mstore(0x41c0, mload(0x40e0))mstore(0x41e0, mload(0x4140)) mstore(0x4200, mload(0x4160))success := and(eq(staticcall(gas(), 0x6, 0x41a0, 0x80, 0x41a0, 0x40), 1), success)mstore(0x4220, 0x0ba574041b9acf0b879828f757fdbe006ec303bb00e85d005f97abcd2607422d) mstore(0x4240, 0x25383b7c510633308b668f09fe22cbd16b83d898660128f6f5390ca909c737fa)mstore(0x4260, mload(0x3b20))success := and(eq(staticcall(gas(), 0x7, 0x4220, 0x60, 0x4220, 0x40), 1), success)mstore(0x4280, mload(0x41a0)) mstore(0x42a0, mload(0x41c0))mstore(0x42c0, mload(0x4220)) mstore(0x42e0, mload(0x4240))success := and(eq(staticcall(gas(), 0x6, 0x4280, 0x80, 0x4280, 0x40), 1), success)mstore(0x4300, 0x2791f81a6904461f649d0e9721cb4a56e033e188b17403bab35f964c2933adea) mstore(0x4320, 0x1b957ffe9eee2e38474fc73d00762637eb2f42f93dbd63b07ac3a7a80d01fcd8)mstore(0x4340, mload(0x3b40))success := and(eq(staticcall(gas(), 0x7, 0x4300, 0x60, 0x4300, 0x40), 1), success)mstore(0x4360, mload(0x4280)) mstore(0x4380, mload(0x42a0))mstore(0x43a0, mload(0x4300)) mstore(0x43c0, mload(0x4320))success := and(eq(staticcall(gas(), 0x6, 0x4360, 0x80, 0x4360, 0x40), 1), success)mstore(0x43e0, 0x1c0d239ee9e8daa18d0898f4091a6d571e50441d852906e11d0fae1d1dedb1fb) mstore(0x4400, 0x0749d3ee27e89e899d6b17981c477f185f713dc32c470a6b8ebfae12370a852d)mstore(0x4420, mload(0x3b60))success := and(eq(staticcall(gas(), 0x7, 0x43e0, 0x60, 0x43e0, 0x40), 1), success)mstore(0x4440, mload(0x4360)) mstore(0x4460, mload(0x4380))mstore(0x4480, mload(0x43e0)) mstore(0x44a0, mload(0x4400))success := and(eq(staticcall(gas(), 0x6, 0x4440, 0x80, 0x4440, 0x40), 1), success)mstore(0x44c0, 0x1d06036774832c1ae8b66aedd888bcb23218f6d8919edada11695d2fa45c3c94) mstore(0x44e0, 0x154238d64a88cc1428d92d04c3afa6c43e4335a2729f4e2fb1c537a16939478d)mstore(0x4500, mload(0x3b80))success := and(eq(staticcall(gas(), 0x7, 0x44c0, 0x60, 0x44c0, 0x40), 1), success)mstore(0x4520, mload(0x4440)) mstore(0x4540, mload(0x4460))mstore(0x4560, mload(0x44c0)) mstore(0x4580, mload(0x44e0))success := and(eq(staticcall(gas(), 0x6, 0x4520, 0x80, 0x4520, 0x40), 1), success)mstore(0x45a0, 0x2c7029d9d4be107fa480642e2845a780b55009050482fe811fef42f9b287cc4a) mstore(0x45c0, 0x071603ec9e8ab439219821e1b9d054f627e98591a3101d3c33ece436cd7e1482)mstore(0x45e0, mload(0x3ba0))success := and(eq(staticcall(gas(), 0x7, 0x45a0, 0x60, 0x45a0, 0x40), 1), success)mstore(0x4600, mload(0x4520)) mstore(0x4620, mload(0x4540))mstore(0x4640, mload(0x45a0)) mstore(0x4660, mload(0x45c0))success := and(eq(staticcall(gas(), 0x6, 0x4600, 0x80, 0x4600, 0x40), 1), success)mstore(0x4680, 0x02d518a4f6d68ae5997ad24fe8b58068acb972cfe8b250ab82e5390d91914950) mstore(0x46a0, 0x0695bba443e1eeed7cf440186dde2e72ebf1ec3f84d8baf57ee1cbe7f36df70d)mstore(0x46c0, mload(0x3bc0))success := and(eq(staticcall(gas(), 0x7, 0x4680, 0x60, 0x4680, 0x40), 1), success)mstore(0x46e0, mload(0x4600)) mstore(0x4700, mload(0x4620))mstore(0x4720, mload(0x4680)) mstore(0x4740, mload(0x46a0))success := and(eq(staticcall(gas(), 0x6, 0x46e0, 0x80, 0x46e0, 0x40), 1), success)mstore(0x4760, mload(0x560)) mstore(0x4780, mload(0x580))mstore(0x47a0, mload(0x3be0))success := and(eq(staticcall(gas(), 0x7, 0x4760, 0x60, 0x4760, 0x40), 1), success)mstore(0x47c0, mload(0x46e0)) mstore(0x47e0, mload(0x4700))mstore(0x4800, mload(0x4760)) mstore(0x4820, mload(0x4780))success := and(eq(staticcall(gas(), 0x6, 0x47c0, 0x80, 0x47c0, 0x40), 1), success)mstore(0x4840, mload(0x5a0)) mstore(0x4860, mload(0x5c0))mstore(0x4880, mload(0x3c00))success := and(eq(staticcall(gas(), 0x7, 0x4840, 0x60, 0x4840, 0x40), 1), success)mstore(0x48a0, mload(0x47c0)) mstore(0x48c0, mload(0x47e0))mstore(0x48e0, mload(0x4840)) mstore(0x4900, mload(0x4860))success := and(eq(staticcall(gas(), 0x6, 0x48a0, 0x80, 0x48a0, 0x40), 1), success)mstore(0x4920, mload(0x5e0)) mstore(0x4940, mload(0x600))mstore(0x4960, mload(0x3c20))success := and(eq(staticcall(gas(), 0x7, 0x4920, 0x60, 0x4920, 0x40), 1), success)mstore(0x4980, mload(0x48a0)) mstore(0x49a0, mload(0x48c0))mstore(0x49c0, mload(0x4920)) mstore(0x49e0, mload(0x4940))success := and(eq(staticcall(gas(), 0x6, 0x4980, 0x80, 0x4980, 0x40), 1), success)mstore(0x4a00, mload(0x620)) mstore(0x4a20, mload(0x640))mstore(0x4a40, mload(0x3c40))success := and(eq(staticcall(gas(), 0x7, 0x4a00, 0x60, 0x4a00, 0x40), 1), success)mstore(0x4a60, mload(0x4980)) mstore(0x4a80, mload(0x49a0))mstore(0x4aa0, mload(0x4a00)) mstore(0x4ac0, mload(0x4a20))success := and(eq(staticcall(gas(), 0x6, 0x4a60, 0x80, 0x4a60, 0x40), 1), success)mstore(0x4ae0, mload(0x4c0)) mstore(0x4b00, mload(0x4e0))mstore(0x4b20, mload(0x3c60))success := and(eq(staticcall(gas(), 0x7, 0x4ae0, 0x60, 0x4ae0, 0x40), 1), success)mstore(0x4b40, mload(0x4a60)) mstore(0x4b60, mload(0x4a80))mstore(0x4b80, mload(0x4ae0)) mstore(0x4ba0, mload(0x4b00))success := and(eq(staticcall(gas(), 0x6, 0x4b40, 0x80, 0x4b40, 0x40), 1), success)mstore(0x4bc0, mload(0x9e0)) mstore(0x4be0, mload(0xa00))mstore(0x4c00, sub(f_q, mload(0x3ca0)))success := and(eq(staticcall(gas(), 0x7, 0x4bc0, 0x60, 0x4bc0, 0x40), 1), success)mstore(0x4c20, mload(0x4b40)) mstore(0x4c40, mload(0x4b60))mstore(0x4c60, mload(0x4bc0)) mstore(0x4c80, mload(0x4be0))success := and(eq(staticcall(gas(), 0x6, 0x4c20, 0x80, 0x4c20, 0x40), 1), success)mstore(0x4ca0, mload(0xa80)) mstore(0x4cc0, mload(0xaa0))mstore(0x4ce0, mload(0x3cc0))success := and(eq(staticcall(gas(), 0x7, 0x4ca0, 0x60, 0x4ca0, 0x40), 1), success)mstore(0x4d00, mload(0x4c20)) mstore(0x4d20, mload(0x4c40))mstore(0x4d40, mload(0x4ca0)) mstore(0x4d60, mload(0x4cc0))success := and(eq(staticcall(gas(), 0x6, 0x4d00, 0x80, 0x4d00, 0x40), 1), success)mstore(0x4d80, mload(0x4d00)) mstore(0x4da0, mload(0x4d20))mstore(0x4dc0, mload(0xa80)) mstore(0x4de0, mload(0xaa0))mstore(0x4e00, mload(0xac0)) mstore(0x4e20, mload(0xae0))mstore(0x4e40, mload(0xb00)) mstore(0x4e60, mload(0xb20))mstore(0x4e80, keccak256(0x4d80, 256))mstore(0x4ea0, mod(mload(19968), f_q))mstore(0x4ec0, mulmod(mload(0x4ea0), mload(0x4ea0), f_q))mstore(0x4ee0, mulmod(1, mload(0x4ea0), f_q))mstore(0x4f00, mload(0x4e00)) mstore(0x4f20, mload(0x4e20))mstore(0x4f40, mload(0x4ee0))success := and(eq(staticcall(gas(), 0x7, 0x4f00, 0x60, 0x4f00, 0x40), 1), success)mstore(0x4f60, mload(0x4d80)) mstore(0x4f80, mload(0x4da0))mstore(0x4fa0, mload(0x4f00)) mstore(0x4fc0, mload(0x4f20))success := and(eq(staticcall(gas(), 0x6, 0x4f60, 0x80, 0x4f60, 0x40), 1), success)mstore(0x4fe0, mload(0x4e40)) mstore(0x5000, mload(0x4e60))mstore(0x5020, mload(0x4ee0))success := and(eq(staticcall(gas(), 0x7, 0x4fe0, 0x60, 0x4fe0, 0x40), 1), success)mstore(0x5040, mload(0x4dc0)) mstore(0x5060, mload(0x4de0))mstore(0x5080, mload(0x4fe0)) mstore(0x50a0, mload(0x5000))success := and(eq(staticcall(gas(), 0x6, 0x5040, 0x80, 0x5040, 0x40), 1), success)mstore(0x50c0, mload(0x4f60)) mstore(0x50e0, mload(0x4f80))mstore(0x5100, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) mstore(0x5120, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) mstore(0x5140, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) mstore(0x5160, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)mstore(0x5180, mload(0x5040)) mstore(0x51a0, mload(0x5060))mstore(0x51c0, 0x0181624e80f3d6ae28df7e01eaeab1c0e919877a3b8a6b7fbc69a6817d596ea2) mstore(0x51e0, 0x1783d30dcb12d259bb89098addf6280fa4b653be7a152542a28f7b926e27e648) mstore(0x5200, 0x00ae44489d41a0d179e2dfdc03bddd883b7109f8b6ae316a59e815c1a6b35304) mstore(0x5220, 0x0b2147ab62a386bd63e6de1522109b8c9588ab466f5aadfde8c41ca3749423ee)success := and(eq(staticcall(gas(), 0x8, 0x50c0, 0x180, 0x50c0, 0x20), 1), success)success := and(eq(mload(0x50c0), 1), success)} return success; } } From 3854a6e0a55bf4b8e783b228b5a38aec5c9f2928 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Tue, 20 Feb 2024 15:41:58 +0100 Subject: [PATCH 03/18] switch to latest halo2-lib changes --- Cargo.toml | 34 +- eth-types/src/lib.rs | 2 +- .../src/gadget/crypto/sha256_flex/gate.rs | 4 +- .../src/gadget/crypto/sha256_wide/gate.rs | 36 +- lightclient-circuits/src/poseidon.rs | 12 +- lightclient-circuits/src/sync_step_circuit.rs | 3 +- lightclient-circuits/src/util/circuit.rs | 2 +- lightclient-circuits/tests/step.rs | 364 +++++++++--------- 8 files changed, 246 insertions(+), 211 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fb0ed98..2febf76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,8 @@ members = [ "prover", "preprocessor", "eth-types", - "contract-tests", - "test-utils", + # "contract-tests", + # "test-utils", "contracts", ] @@ -52,17 +52,18 @@ zkevm-hashes = { git = "https://github.com/axiom-crypto/halo2-lib", tag = "v0.4. halo2curves = { package = "halo2curves-axiom", version = "=0.5.2" } # verifier SDK -snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.6", default-features = false, features = [ +snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.7-git", default-features = false, features = [ "display", "loader_halo2", "loader_evm", "halo2-pse", ] } -snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.6", default-features = false, features = [ +snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.7-git", default-features = false, features = [ "display", "loader_halo2", "loader_evm", "halo2-pse", + "revm", ] } # ethereum types @@ -90,16 +91,23 @@ ark-std = { version = "0.4.0", features = ["print-trace"] } [patch.crates-io] ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } -halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } -halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } -zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } +# halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } +# halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } +# zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } +halo2-base = { path = "../halo2-lib/halo2-base" } +halo2-ecc = { path = "../halo2-lib/halo2-ecc" } +zkevm-hashes = { path = "../halo2-lib/hashes/zkevm" } [patch."https://github.com/axiom-crypto/halo2-lib"] -halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } -halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } -zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } +# halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } +# halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } +# zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } +halo2-base = { path = "../halo2-lib/halo2-base" } +halo2-ecc = { path = "../halo2-lib/halo2-ecc" } +zkevm-hashes = { path = "../halo2-lib/hashes/zkevm" } -[patch."https://github.com/axiom-crypto/snark-verifier.git"] -snark-verifier = { git = "https://github.com/nulltea/snark-verifier", branch = "yul-codegen" } -snark-verifier-sdk = { git = "https://github.com/nulltea/snark-verifier", branch = "yul-codegen" } + +# [patch."https://github.com/axiom-crypto/snark-verifier.git"] +# snark-verifier = { git = "https://github.com/nulltea/snark-verifier", branch = "yul-codegen" } +# snark-verifier-sdk = { git = "https://github.com/nulltea/snark-verifier", branch = "yul-codegen" } diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index 240c22e..518fc29 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -12,7 +12,7 @@ use halo2_base::utils::BigPrimeField; use halo2curves::ff::PrimeField; pub use spec::{Mainnet, Minimal, Spec, Testnet}; -pub const NUM_LIMBS: usize = 4; +pub const NUM_LIMBS: usize = 5; pub const LIMB_BITS: usize = 104; /// The field used in circuits. diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs index e5649db..901480a 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs @@ -61,7 +61,7 @@ impl ShaFlexGateManager { self.threads_dense.push(Context::new( self.witness_gen_only(), FIRST_PHASE, - TypeId::of::<(Self, Dence)>(), + "dense", thread_id, self.copy_manager.clone(), )); @@ -73,7 +73,7 @@ impl ShaFlexGateManager { self.threads_spread.push(Context::new( self.witness_gen_only(), FIRST_PHASE, - TypeId::of::<(Self, Spread)>(), + "spead", thread_id, self.copy_manager.clone(), )); diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs index e469cd5..144091e 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs @@ -4,7 +4,7 @@ use crate::util::{CommonGateManager, GateBuilderConfig}; use eth_types::Field; -use getset::CopyGetters; +use getset::{CopyGetters, Getters}; use halo2_base::{ gates::circuit::BaseCircuitParams, halo2_proofs::{ @@ -13,17 +13,14 @@ use halo2_base::{ }, virtual_region::{ copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, - }, + }, AssignedValue, }; use itertools::Itertools; use zkevm_hashes::{ - sha256::{ - component::circuit::LoadedSha256, - vanilla::{ - columns::Sha256CircuitConfig, - param::{NUM_START_ROWS, NUM_WORDS_TO_ABSORB, SHA256_NUM_ROWS}, - witness::VirtualShaRow, - }, + sha256::vanilla::{ + columns::Sha256CircuitConfig, + param::{NUM_START_ROWS, NUM_WORDS_TO_ABSORB, SHA256_NUM_ROWS}, + witness::VirtualShaRow, }, util::word::Word, }; @@ -45,6 +42,27 @@ pub struct ShaBitGateManager { pub copy_manager: SharedCopyConstraintManager, } +/// Witnesses of a sha256 which are necessary to be loaded into halo2-lib. +#[derive(Clone, Copy, Debug, CopyGetters, Getters)] +pub struct LoadedSha256 { + /// bytes_left of the first row of the first round of this keccak_f. This could be used to determine the length of the input. + // #[getset(get_copy = "pub")] + // pub(crate) bytes_left: AssignedValue, + + /// The output of this sha256. is_final/hash_lo/hash_hi come from the first row of the last round(NUM_ROUNDS). + #[getset(get_copy = "pub")] + pub is_final: AssignedValue, + + // Hash word consisting of two limbs - lower 16 bits and the high 16 bits, in big-endian. + #[getset(get = "pub")] + pub hash: Word>, + + /// Input words (u64) of this keccak_f. + #[getset(get = "pub")] + pub word_values: [AssignedValue; NUM_WORDS_TO_ABSORB], + // pub(crate) length: AssignedValue, +} + impl CommonGateManager for ShaBitGateManager { type CustomContext<'a> = (); diff --git a/lightclient-circuits/src/poseidon.rs b/lightclient-circuits/src/poseidon.rs index a5ce234..56f018a 100644 --- a/lightclient-circuits/src/poseidon.rs +++ b/lightclient-circuits/src/poseidon.rs @@ -2,7 +2,7 @@ // Code: https://github.com/ChainSafe/Spectre // SPDX-License-Identifier: LGPL-3.0-only -use eth_types::{Field, LIMB_BITS}; +use eth_types::{Field, LIMB_BITS, NUM_LIMBS}; use halo2_base::{ gates::GateInstructions, halo2_proofs::halo2curves::bn256, halo2_proofs::plonk::Error, poseidon::hasher::PoseidonSponge, AssignedValue, Context, QuantumCell, @@ -48,8 +48,16 @@ pub fn fq_array_poseidon<'a, F: Field>( .into_iter() .flat_map(|f| { // Fold 4 limbs into 2 to reduce number of posedidon inputs in half. - f.limbs() + let (limbs, extra) = f.limbs().split_at(NUM_LIMBS - (NUM_LIMBS % 2)); + assert!(extra.len() <= 1); + if let Some(extra) = extra.first() { + let zero = ctx.load_zero(); + ctx.constrain_equal(extra, &zero); + } + + limbs .chunks(2) + .into_iter() .map(|limbs| gate.inner_product(ctx, limbs.to_vec(), limbs_bases.clone())) .collect_vec() }) diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 80d70c5..19b3ffd 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -475,7 +475,8 @@ mod tests { ) .unwrap(); - let instance = StepCircuit::::get_instances(&witness, LIMB_BITS); + // let instance = StepCircuit::::get_instances(&witness, LIMB_BITS); + let instance = circuit.instances(); let timer = start_timer!(|| "sync_step mock prover"); let prover = MockProver::::run(K, &circuit, instance).unwrap(); diff --git a/lightclient-circuits/src/util/circuit.rs b/lightclient-circuits/src/util/circuit.rs index 030cea3..9f29741 100644 --- a/lightclient-circuits/src/util/circuit.rs +++ b/lightclient-circuits/src/util/circuit.rs @@ -17,7 +17,7 @@ use halo2_base::halo2_proofs::{ }; use serde::{Deserialize, Serialize}; use snark_verifier_sdk::evm::{ - encode_calldata, evm_verify, 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::gen_proof_shplonk; use snark_verifier_sdk::{gen_pk, halo2::gen_snark_shplonk, read_pk}; diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index 0eae2a1..df1d279 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -1,182 +1,182 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -use ark_std::{end_timer, start_timer}; -use eth_types::{Minimal, LIMB_BITS}; -use eth_types::{Spec, NUM_LIMBS}; -use halo2_base::gates::circuit::CircuitBuilderStage; -use halo2_base::halo2_proofs::dev::MockProver; -use halo2_base::halo2_proofs::halo2curves::bn256; -use halo2_base::utils::fs::gen_srs; -use halo2_ecc::bls12_381::FpChip; -use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; -use lightclient_circuits::gadget::crypto::{ShaBitGateManager, ShaFlexGateManager}; -use lightclient_circuits::sync_step_circuit::StepCircuit; -use lightclient_circuits::util::AppCircuit; -use lightclient_circuits::util::Eth2ConfigPinning; -use lightclient_circuits::util::Halo2ConfigPinning; -use lightclient_circuits::witness::CommitteeUpdateArgs; -use lightclient_circuits::witness::SyncStepArgs; -use lightclient_circuits::Eth2CircuitBuilder; -use rstest::rstest; -use snark_verifier_sdk::CircuitExt; -use std::env::var; -use std::path::PathBuf; - -use test_utils::read_test_files_and_gen_witness; - -#[rstest] -fn test_eth2_spec_mock_1( - #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/light_client_sync")] - #[exclude("deneb*")] - path: PathBuf, -) { - run_test_eth2_spec_mock::<18, 19>(path) -} - -// Same as StepCircuit::create_circuit without loading SRS which fails CI. -pub(crate) fn mock_step_circuit( - args: &SyncStepArgs, - k: u32, - lookup_bits: Option, -) -> impl lightclient_circuits::util::PinnableCircuit { - let mut builder = - Eth2CircuitBuilder::>::from_stage(CircuitBuilderStage::Mock) - .use_k(k as usize) - .use_instance_columns(1); - let range = builder.range_chip(lookup_bits.unwrap_or(k as usize - 1)); - let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); - - let assigned_instances = - StepCircuit::::synthesize(&mut builder, &fp_chip, args).unwrap(); - builder.set_instances(0, assigned_instances); - - builder.calculate_params(Some( - var("MINIMUM_ROWS") - .unwrap_or_else(|_| "0".to_string()) - .parse() - .unwrap(), - )); - builder -} - -// Same as CommitteeUpdateCircuit::create_circuit without loading SRS which fails CI. -pub(crate) fn mock_committee_update_circuit( - witness: &CommitteeUpdateArgs, - k: u32, - lookup_bits: Option, -) -> impl lightclient_circuits::util::PinnableCircuit { - let mut builder = - Eth2CircuitBuilder::>::from_stage(CircuitBuilderStage::Mock) - .use_k(k as usize) - .use_instance_columns(1); - let range = builder.range_chip(lookup_bits.unwrap_or(k as usize - 1)); - let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); - - let assigned_instances = - CommitteeUpdateCircuit::::synthesize(&mut builder, &fp_chip, witness) - .unwrap(); - builder.set_instances(0, assigned_instances); - builder.calculate_params(Some( - var("MINIMUM_ROWS") - .unwrap_or_else(|_| "0".to_string()) - .parse() - .unwrap(), - )); - builder -} - -fn run_test_eth2_spec_mock(path: PathBuf) { - let (sync_witness, rotation_witness) = read_test_files_and_gen_witness(&path); - - let rotation_circuit = mock_committee_update_circuit(&rotation_witness, K_ROTATION, None); - - let rotation_instance = - CommitteeUpdateCircuit::::get_instances(&rotation_witness, LIMB_BITS); - let timer = start_timer!(|| "committee_update mock prover run"); - let prover = - MockProver::::run(K_ROTATION, &rotation_circuit, rotation_instance).unwrap(); - prover.assert_satisfied_par(); - end_timer!(timer); - - let sync_circuit = mock_step_circuit(&sync_witness, K_SYNC, None); - - let instance = StepCircuit::::get_instances(&sync_witness, LIMB_BITS); - - let timer = start_timer!(|| "sync_step mock prover run"); - let prover = MockProver::::run(K_SYNC, &sync_circuit, instance).unwrap(); - prover.assert_satisfied_par(); - end_timer!(timer); -} - -#[rstest] -fn test_eth2_spec_proofgen( - #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] - #[exclude("deneb*")] - path: PathBuf, -) { - const K: u32 = 20; - let (witness, _) = read_test_files_and_gen_witness(&path); - - let params = gen_srs(K); - let pk = StepCircuit::::create_pk( - ¶ms, - "../build/sync_step_20.pkey", - "./config/sync_step_20.json", - &SyncStepArgs::::default(), - None, - ); - - let _ = StepCircuit::::gen_proof_shplonk( - ¶ms, - &pk, - "./config/sync_step_20.json", - &witness, - ) - .expect("proof generation & verification should not fail"); -} - -#[rstest] -fn test_eth2_spec_evm_verify( - #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] - #[exclude("deneb*")] - path: PathBuf, -) { - const K: u32 = 21; - let params = gen_srs(K); - - let pk = StepCircuit::::create_pk( - ¶ms, - "../build/sync_step_21.pkey", - "./config/sync_step_21.json", - &SyncStepArgs::::default(), - None, - ); - - let (witness, _) = read_test_files_and_gen_witness(&path); - - let pinning = Eth2ConfigPinning::from_path("./config/sync_step_21.json"); - - let circuit = StepCircuit::::create_circuit( - CircuitBuilderStage::Prover, - Some(pinning), - &witness, - ¶ms, - ) - .unwrap(); - - let instances = circuit.instances(); - let proof = - snark_verifier_sdk::evm::gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); - println!("proof size: {}", proof.len()); - let deployment_code = StepCircuit::::gen_evm_verifier_shplonk( - ¶ms, - &pk, - None::, - &witness, - ) - .unwrap(); - println!("deployment_code size: {}", deployment_code.len()); - snark_verifier_sdk::evm::evm_verify(deployment_code, instances, proof); -} +// // The Licensed Work is (c) 2023 ChainSafe +// // Code: https://github.com/ChainSafe/Spectre +// // SPDX-License-Identifier: LGPL-3.0-only + +// use ark_std::{end_timer, start_timer}; +// use eth_types::{Minimal, LIMB_BITS}; +// use eth_types::{Spec, NUM_LIMBS}; +// use halo2_base::gates::circuit::CircuitBuilderStage; +// use halo2_base::halo2_proofs::dev::MockProver; +// use halo2_base::halo2_proofs::halo2curves::bn256; +// use halo2_base::utils::fs::gen_srs; +// use halo2_ecc::bls12_381::FpChip; +// use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; +// use lightclient_circuits::gadget::crypto::{ShaBitGateManager, ShaFlexGateManager}; +// use lightclient_circuits::sync_step_circuit::StepCircuit; +// use lightclient_circuits::util::AppCircuit; +// use lightclient_circuits::util::Eth2ConfigPinning; +// use lightclient_circuits::util::Halo2ConfigPinning; +// use lightclient_circuits::witness::CommitteeUpdateArgs; +// use lightclient_circuits::witness::SyncStepArgs; +// use lightclient_circuits::Eth2CircuitBuilder; +// use rstest::rstest; +// use snark_verifier_sdk::CircuitExt; +// use std::env::var; +// use std::path::PathBuf; + +// use test_utils::read_test_files_and_gen_witness; + +// #[rstest] +// fn test_eth2_spec_mock_1( +// #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/light_client_sync")] +// #[exclude("deneb*")] +// path: PathBuf, +// ) { +// run_test_eth2_spec_mock::<18, 19>(path) +// } + +// // Same as StepCircuit::create_circuit without loading SRS which fails CI. +// pub(crate) fn mock_step_circuit( +// args: &SyncStepArgs, +// k: u32, +// lookup_bits: Option, +// ) -> impl lightclient_circuits::util::PinnableCircuit { +// let mut builder = +// Eth2CircuitBuilder::>::from_stage(CircuitBuilderStage::Mock) +// .use_k(k as usize) +// .use_instance_columns(1); +// let range = builder.range_chip(lookup_bits.unwrap_or(k as usize - 1)); +// let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); + +// let assigned_instances = +// StepCircuit::::synthesize(&mut builder, &fp_chip, args).unwrap(); +// builder.set_instances(0, assigned_instances); + +// builder.calculate_params(Some( +// var("MINIMUM_ROWS") +// .unwrap_or_else(|_| "0".to_string()) +// .parse() +// .unwrap(), +// )); +// builder +// } + +// // Same as CommitteeUpdateCircuit::create_circuit without loading SRS which fails CI. +// pub(crate) fn mock_committee_update_circuit( +// witness: &CommitteeUpdateArgs, +// k: u32, +// lookup_bits: Option, +// ) -> impl lightclient_circuits::util::PinnableCircuit { +// let mut builder = +// Eth2CircuitBuilder::>::from_stage(CircuitBuilderStage::Mock) +// .use_k(k as usize) +// .use_instance_columns(1); +// let range = builder.range_chip(lookup_bits.unwrap_or(k as usize - 1)); +// let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); + +// let assigned_instances = +// CommitteeUpdateCircuit::::synthesize(&mut builder, &fp_chip, witness) +// .unwrap(); +// builder.set_instances(0, assigned_instances); +// builder.calculate_params(Some( +// var("MINIMUM_ROWS") +// .unwrap_or_else(|_| "0".to_string()) +// .parse() +// .unwrap(), +// )); +// builder +// } + +// fn run_test_eth2_spec_mock(path: PathBuf) { +// let (sync_witness, rotation_witness) = read_test_files_and_gen_witness(&path); + +// let rotation_circuit = mock_committee_update_circuit(&rotation_witness, K_ROTATION, None); + +// let rotation_instance = +// CommitteeUpdateCircuit::::get_instances(&rotation_witness, LIMB_BITS); +// let timer = start_timer!(|| "committee_update mock prover run"); +// let prover = +// MockProver::::run(K_ROTATION, &rotation_circuit, rotation_instance).unwrap(); +// prover.assert_satisfied_par(); +// end_timer!(timer); + +// let sync_circuit = mock_step_circuit(&sync_witness, K_SYNC, None); + +// let instance = StepCircuit::::get_instances(&sync_witness, LIMB_BITS); + +// let timer = start_timer!(|| "sync_step mock prover run"); +// let prover = MockProver::::run(K_SYNC, &sync_circuit, instance).unwrap(); +// prover.assert_satisfied_par(); +// end_timer!(timer); +// } + +// #[rstest] +// fn test_eth2_spec_proofgen( +// #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] +// #[exclude("deneb*")] +// path: PathBuf, +// ) { +// const K: u32 = 20; +// let (witness, _) = read_test_files_and_gen_witness(&path); + +// let params = gen_srs(K); +// let pk = StepCircuit::::create_pk( +// ¶ms, +// "../build/sync_step_20.pkey", +// "./config/sync_step_20.json", +// &SyncStepArgs::::default(), +// None, +// ); + +// let _ = StepCircuit::::gen_proof_shplonk( +// ¶ms, +// &pk, +// "./config/sync_step_20.json", +// &witness, +// ) +// .expect("proof generation & verification should not fail"); +// } + +// #[rstest] +// fn test_eth2_spec_evm_verify( +// #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] +// #[exclude("deneb*")] +// path: PathBuf, +// ) { +// const K: u32 = 21; +// let params = gen_srs(K); + +// let pk = StepCircuit::::create_pk( +// ¶ms, +// "../build/sync_step_21.pkey", +// "./config/sync_step_21.json", +// &SyncStepArgs::::default(), +// None, +// ); + +// let (witness, _) = read_test_files_and_gen_witness(&path); + +// let pinning = Eth2ConfigPinning::from_path("./config/sync_step_21.json"); + +// let circuit = StepCircuit::::create_circuit( +// CircuitBuilderStage::Prover, +// Some(pinning), +// &witness, +// ¶ms, +// ) +// .unwrap(); + +// let instances = circuit.instances(); +// let proof = +// snark_verifier_sdk::evm::gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); +// println!("proof size: {}", proof.len()); +// let deployment_code = StepCircuit::::gen_evm_verifier_shplonk( +// ¶ms, +// &pk, +// None::, +// &witness, +// ) +// .unwrap(); +// println!("deployment_code size: {}", deployment_code.len()); +// snark_verifier_sdk::evm::evm_verify(deployment_code, instances, proof); +// } From 25236573d7879163c80a411f5c0a310d16dd24d1 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Tue, 20 Feb 2024 15:42:38 +0100 Subject: [PATCH 04/18] assert_satisfied_par -> assert_satisfied --- lightclient-circuits/src/committee_update_circuit.rs | 2 +- lightclient-circuits/src/sync_step_circuit.rs | 2 +- lightclient-circuits/src/witness/rotation.rs | 2 +- lightclient-circuits/src/witness/step.rs | 2 +- lightclient-circuits/tests/step.rs | 4 ++-- preprocessor/src/lib.rs | 4 ++-- preprocessor/src/rotation.rs | 2 +- preprocessor/src/step.rs | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index a806572..aa2c13f 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -324,7 +324,7 @@ mod tests { let timer = start_timer!(|| "committee_update mock prover"); let prover = MockProver::::run(K, &circuit, instance).unwrap(); - prover.assert_satisfied_par(); + prover.assert_satisfied(); end_timer!(timer); } diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 19b3ffd..7196018 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -480,7 +480,7 @@ mod tests { let timer = start_timer!(|| "sync_step mock prover"); let prover = MockProver::::run(K, &circuit, instance).unwrap(); - prover.assert_satisfied_par(); + prover.assert_satisfied(); end_timer!(timer); } diff --git a/lightclient-circuits/src/witness/rotation.rs b/lightclient-circuits/src/witness/rotation.rs index e19bf1e..ae8abc3 100644 --- a/lightclient-circuits/src/witness/rotation.rs +++ b/lightclient-circuits/src/witness/rotation.rs @@ -124,6 +124,6 @@ mod tests { .unwrap(); let prover = MockProver::::run(K, &circuit, circuit.instances()).unwrap(); - prover.assert_satisfied_par(); + prover.assert_satisfied(); } } diff --git a/lightclient-circuits/src/witness/step.rs b/lightclient-circuits/src/witness/step.rs index 1e48e0f..3a33cca 100644 --- a/lightclient-circuits/src/witness/step.rs +++ b/lightclient-circuits/src/witness/step.rs @@ -152,6 +152,6 @@ mod tests { .unwrap(); let prover = MockProver::::run(K, &circuit, circuit.instances()).unwrap(); - prover.assert_satisfied_par(); + prover.assert_satisfied(); } } diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index df1d279..dc7d3b1 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -97,7 +97,7 @@ // let timer = start_timer!(|| "committee_update mock prover run"); // let prover = // MockProver::::run(K_ROTATION, &rotation_circuit, rotation_instance).unwrap(); -// prover.assert_satisfied_par(); +// prover.assert_satisfied(); // end_timer!(timer); // let sync_circuit = mock_step_circuit(&sync_witness, K_SYNC, None); @@ -106,7 +106,7 @@ // let timer = start_timer!(|| "sync_step mock prover run"); // let prover = MockProver::::run(K_SYNC, &sync_circuit, instance).unwrap(); -// prover.assert_satisfied_par(); +// prover.assert_satisfied(); // end_timer!(timer); // } diff --git a/preprocessor/src/lib.rs b/preprocessor/src/lib.rs index 468d9e6..cfe6302 100644 --- a/preprocessor/src/lib.rs +++ b/preprocessor/src/lib.rs @@ -277,7 +277,7 @@ mod tests { .unwrap(); let prover = MockProver::::run(K, &circuit, circuit.instances()).unwrap(); - prover.assert_satisfied_par(); + prover.assert_satisfied(); const CONFIG_PATH: &str = "../lightclient-circuits/config/committee_update_testnet.json"; @@ -291,6 +291,6 @@ mod tests { .unwrap(); let prover = MockProver::::run(K, &circuit, circuit.instances()).unwrap(); - prover.assert_satisfied_par(); + prover.assert_satisfied(); } } diff --git a/preprocessor/src/rotation.rs b/preprocessor/src/rotation.rs index 1166356..8c1b146 100644 --- a/preprocessor/src/rotation.rs +++ b/preprocessor/src/rotation.rs @@ -141,7 +141,7 @@ mod tests { .unwrap(); let prover = MockProver::::run(K, &circuit, circuit.instances()).unwrap(); - prover.assert_satisfied_par(); + prover.assert_satisfied(); } #[tokio::test] diff --git a/preprocessor/src/step.rs b/preprocessor/src/step.rs index df207c7..62a8d9b 100644 --- a/preprocessor/src/step.rs +++ b/preprocessor/src/step.rs @@ -192,7 +192,7 @@ mod tests { .unwrap(); let prover = MockProver::::run(K, &circuit, circuit.instances()).unwrap(); - prover.assert_satisfied_par(); + prover.assert_satisfied(); } #[tokio::test] From 23c9aee3ac17f52d1d16ffb62edc579aefd397d0 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 12:06:06 +0100 Subject: [PATCH 05/18] expose finalized_header_root as hi/lo --- .../src/committee_update_circuit.rs | 45 +++++++++---------- lightclient-circuits/src/util/bytes.rs | 30 +++++++++++++ lightclient-circuits/src/util/mod.rs | 3 ++ 3 files changed, 55 insertions(+), 23 deletions(-) create mode 100644 lightclient-circuits/src/util/bytes.rs diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index aa2c13f..f9996be 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -7,7 +7,7 @@ use crate::{ poseidon::{fq_array_poseidon, poseidon_hash_fq_array}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, sync_step_circuit::clear_3_bits, - util::{AppCircuit, CommonGateManager, Eth2ConfigPinning, IntoWitness}, + util::{bytes_be_to_u128, AppCircuit, CommonGateManager, Eth2ConfigPinning, IntoWitness}, witness::{self, HashInput, HashInputChunk}, Eth2CircuitBuilder, }; @@ -19,6 +19,7 @@ use halo2_base::{ plonk::Error, poly::{commitment::Params, kzg::commitment::ParamsKZG}, }, + safe_types::SafeTypeChip, AssignedValue, Context, QuantumCell, }; use halo2_ecc::{ @@ -28,7 +29,7 @@ use halo2_ecc::{ }; use halo2curves::bls12_381; use itertools::Itertools; -use ssz_rs::{Merkleized, Vector}; +use ssz_rs::Merkleized; use std::{env::var, iter, marker::PhantomData, vec}; /// `CommitteeUpdateCircuit` maps next sync committee SSZ root in the finalized state root to the corresponding Poseidon commitment to the public keys. @@ -108,9 +109,16 @@ impl CommitteeUpdateCircuit { S::SYNC_COMMITTEE_PUBKEYS_ROOT_INDEX, )?; + println!("ffinalized_header_root: {:?}", finalized_header_root.iter().map(|v| v.value()).collect_vec()); + + let finalized_header_root_lo_hi = bytes_be_to_u128( + builder.main(), + &range.gate, + SafeTypeChip::unsafe_to_fix_len_bytes_vec(finalized_header_root.clone(), 32).bytes(), + ); + let public_inputs = iter::once(poseidon_commit) - .chain(committee_root_ssz) - .chain(finalized_header_root) + .chain(finalized_header_root_lo_hi.into_iter().rev()) // as hi/lo .collect(); Ok(public_inputs) @@ -189,29 +197,20 @@ impl CommitteeUpdateCircuit { .expect("bad bls12_381::Fq encoding") }); - let poseidon_commitment = poseidon_hash_fq_array::(pubkeys_x, limb_bits); - - let mut pk_vector: Vector, { S::SYNC_COMMITTEE_SIZE }> = args - .pubkeys_compressed - .as_slice() - .iter() - .map(|v| v.as_slice().try_into().unwrap()) - .collect_vec() - .try_into() - .unwrap(); - - let ssz_root = pk_vector.hash_tree_root().unwrap(); + let poseidon_commitment = + poseidon_hash_fq_array::(pubkeys_x, limb_bits - (limb_bits % 2)); let finalized_header_root = args.finalized_header.clone().hash_tree_root().unwrap(); + let finalized_header_root_hilo = { + let bytes = finalized_header_root.as_ref(); + let hash_lo = u128::from_le_bytes(bytes[16..].try_into().unwrap()); + let hash_hi = u128::from_le_bytes(bytes[..16].try_into().unwrap()); + [hash_lo, hash_hi].map(bn256::Fr::from_u128) + }; + 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)), - ) + .chain(finalized_header_root_hilo) .collect(); vec![instance_vec] diff --git a/lightclient-circuits/src/util/bytes.rs b/lightclient-circuits/src/util/bytes.rs new file mode 100644 index 0000000..356b6f1 --- /dev/null +++ b/lightclient-circuits/src/util/bytes.rs @@ -0,0 +1,30 @@ +use halo2_base::{gates::GateInstructions, safe_types::SafeByte, utils::BigPrimeField, AssignedValue, Context, QuantumCell}; +use itertools::Itertools; + +pub fn bytes_be_to_u128( + ctx: &mut Context, + gate: &impl GateInstructions, + bytes: &[SafeByte], +) -> Vec> { + limbs_be_to_u128(ctx, gate, bytes, 8) +} + +pub(crate) fn limbs_be_to_u128( + ctx: &mut Context, + gate: &impl GateInstructions, + limbs: &[impl AsRef>], + limb_bits: usize, +) -> Vec> { + assert!(!limbs.is_empty(), "limbs must not be empty"); + assert_eq!(128 % limb_bits, 0); + limbs + .chunks(128 / limb_bits) + .map(|chunk| { + gate.inner_product( + ctx, + chunk.iter().rev().map(|a| *a.as_ref()), + (0..chunk.len()).map(|idx| QuantumCell::Constant(gate.pow_of_two()[limb_bits * idx])), + ) + }) + .collect_vec() +} diff --git a/lightclient-circuits/src/util/mod.rs b/lightclient-circuits/src/util/mod.rs index 90d4d03..fa6595f 100644 --- a/lightclient-circuits/src/util/mod.rs +++ b/lightclient-circuits/src/util/mod.rs @@ -12,3 +12,6 @@ pub(crate) use conversion::*; mod circuit; pub use circuit::*; + +mod bytes; +pub use bytes::*; From 96097ab62be7bec9286a7ec399d9dff363cef5ab Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 12:06:47 +0100 Subject: [PATCH 06/18] remove halo2-solidity-verified dependency --- prover/Cargo.toml | 3 +-- prover/src/cli.rs | 24 +++--------------------- prover/src/rpc_api.rs | 4 ---- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/prover/Cargo.toml b/prover/Cargo.toml index 24ab8de..798de0c 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -25,7 +25,6 @@ halo2curves.workspace = true # verifier SDK snark-verifier.workspace = true snark-verifier-sdk.workspace = true -halo2_solidity_verifier = { git = "https://github.com/ChainSafe/halo2-solidity-verifier", branch = "yul-to-solidity-parser", optional = true } halo2_solidity_verifier_new = { git = "https://github.com/ChainSafe/halo2-solidity-verifier", branch = "bump-halo2proofs", package = "halo2_solidity_verifier", features = ["evm"], optional = true } # local @@ -55,5 +54,5 @@ futures = "0.3.29" ssz_rs.workspace = true [features] -default = ["halo2_solidity_verifier"] +default = [] experimental = ["halo2_solidity_verifier_new"] diff --git a/prover/src/cli.rs b/prover/src/cli.rs index f5ec859..d6f2b55 100644 --- a/prover/src/cli.rs +++ b/prover/src/cli.rs @@ -6,7 +6,6 @@ use crate::args::BaseArgs; use crate::args::{OperationCmd, ProofCmd}; use ark_std::{end_timer, start_timer}; use lightclient_circuits::aggregation_circuit::AggregationConfigPinning; -use lightclient_circuits::halo2_base::gates::circuit::CircuitBuilderStage; use lightclient_circuits::halo2_base::utils::fs::gen_srs; use lightclient_circuits::{ committee_update_circuit::CommitteeUpdateCircuit, @@ -16,9 +15,7 @@ use lightclient_circuits::{ }; use snark_verifier::loader::halo2::halo2_ecc::halo2_base::halo2_proofs::poly::kzg::commitment::ParamsKZG; use snark_verifier_sdk::halo2::aggregation::AggregationCircuit; -use snark_verifier_sdk::CircuitExt; -use std::path::PathBuf; -use std::{fs::File, io::Write, path::Path}; +use std::path::{Path, PathBuf}; #[cfg(feature = "experimental")] use halo2_solidity_verifier_new::{ @@ -248,31 +245,16 @@ fn gen_evm_verifier( params: &ParamsKZG, pk_path: &Path, cfg_path: &Path, - mut path_out: PathBuf, + path_out: PathBuf, estimate_gas: bool, default_witness: Circuit::Witness, ) -> eyre::Result<()> { let pk = Circuit::read_pk(params, pk_path, cfg_path, &default_witness); - let num_instances = { - let circuit = - Circuit::create_circuit(CircuitBuilderStage::Keygen, None, &default_witness, params) - .unwrap(); - circuit.num_instance().first().map_or(0, |x| *x as u32) - }; - - path_out.set_extension("yul"); let deplyment_code = Circuit::gen_evm_verifier_shplonk(params, &pk, Some(path_out.clone()), &default_witness) .map_err(|e| eyre::eyre!("Failed to EVM verifier: {}", e))?; - println!("yul size: {}", deplyment_code.len()); - - let sol_contract = halo2_solidity_verifier::fix_verifier_sol(path_out.clone(), num_instances) - .map_err(|e| eyre::eyre!("Failed to generate Solidity verifier: {}", e))?; - path_out.set_extension("sol"); - let mut f = File::create(path_out).unwrap(); - f.write(sol_contract.as_bytes()) - .map_err(|e| eyre::eyre!("Failed to write Solidity verifier: {}", e))?; + println!("sol size: {}", deplyment_code.len()); if estimate_gas { let _ = Circuit::gen_evm_proof_shplonk( diff --git a/prover/src/rpc_api.rs b/prover/src/rpc_api.rs index 23adbb7..a65ba17 100644 --- a/prover/src/rpc_api.rs +++ b/prover/src/rpc_api.rs @@ -27,14 +27,10 @@ pub struct GenProofCommitteeUpdateParams { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SyncStepCompressedEvmProofResult { pub proof: Vec, - pub accumulator: [U256; 12], - pub public_inputs: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CommitteeUpdateEvmProofResult { pub proof: Vec, - pub accumulator: [U256; 12], pub committee_poseidon: U256, - pub public_inputs: Vec, } From 23f2143525255d3ddfa7c3e7784094d98de89ed0 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 12:07:20 +0100 Subject: [PATCH 07/18] update halo2-lib dep --- Cargo.toml | 24 +++++------------- justfile | 2 +- .../config/sync_step_testnet.json | 25 ++++++++----------- 3 files changed, 17 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6106a61..abc7fc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,23 +91,11 @@ ark-std = { version = "0.4.0", features = ["print-trace"] } [patch.crates-io] ssz_rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "5f1ec833718efa07bbbff427ab28a1eeaa706164" } -# halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } -# halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } -# zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } -halo2-base = { path = "../halo2-lib/halo2-base" } -halo2-ecc = { path = "../halo2-lib/halo2-ecc" } -zkevm-hashes = { path = "../halo2-lib/hashes/zkevm" } +halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } [patch."https://github.com/axiom-crypto/halo2-lib"] -# halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } -# halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } -# zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/zkevm-sha256-builder" } -halo2-base = { path = "../halo2-lib/halo2-base" } -halo2-ecc = { path = "../halo2-lib/halo2-ecc" } -zkevm-hashes = { path = "../halo2-lib/hashes/zkevm" } - - - -# [patch."https://github.com/axiom-crypto/snark-verifier.git"] -# snark-verifier = { git = "https://github.com/nulltea/snark-verifier", branch = "yul-codegen" } -# snark-verifier-sdk = { git = "https://github.com/nulltea/snark-verifier", branch = "yul-codegen" } +halo2-base = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +halo2-ecc = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } +zkevm-hashes = { git = "https://github.com/nulltea/halo2-lib", branch = "feat/bls12-381-hash2curve" } diff --git a/justfile b/justfile index fb34b02..76a6709 100644 --- a/justfile +++ b/justfile @@ -17,7 +17,7 @@ setup-step network *k='22': cargo run -r -p spectre-prover -- circuit sync-step -p ./build/sync_step_$1.pkey -k $2 setup setup-step-compressed network *k='23': - cargo run -r -p spectre-prover -- circuit sync-step-compressed -k 20 -p ./build/sync_step_$1.pkey \ + cargo run -r -p spectre-prover -- circuit sync-step-compressed -k 21 -p ./build/sync_step_$1.pkey \ -K $2 -P ./build/sync_step_verifier_$1.pkey -L 19 setup setup-committee-update network *k='24': diff --git a/lightclient-circuits/config/sync_step_testnet.json b/lightclient-circuits/config/sync_step_testnet.json index a1396fe..8534ae8 100644 --- a/lightclient-circuits/config/sync_step_testnet.json +++ b/lightclient-circuits/config/sync_step_testnet.json @@ -1,31 +1,26 @@ { "params": { - "k": 20, + "k": 21, "num_advice_per_phase": [ - 12 + 7 ], "num_fixed": 1, "num_lookup_advice_per_phase": [ - 2, + 1, 0, 0 ], - "lookup_bits": 19, + "lookup_bits": 20, "num_instance_columns": 1 }, "break_points": [ [ - 1048566, - 1048564, - 1048566, - 1048566, - 1048565, - 1048566, - 1048566, - 1048566, - 1048564, - 1048566, - 1048566 + 2097142, + 2097142, + 2097141, + 2097142, + 2097142, + 2097140 ] ] } \ No newline at end of file From 8ce967b1d6ca2c4ba82b1410c783a56cc98bb4ef Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 12:07:28 +0100 Subject: [PATCH 08/18] remove contracts dir --- contracts/.gitignore | 12 -- contracts/Cargo.toml | 16 --- contracts/README.md | 66 --------- contracts/foundry.toml | 19 --- contracts/lib/YulDeployer.sol | 37 ----- contracts/lib/forge-std | 1 - contracts/remappings.txt | 2 - contracts/rust-abi/lib.rs | 108 --------------- contracts/script/DeploySpectreLocal.s.sol | 30 ---- contracts/script/DeploySpectreTestnet.s.sol | 30 ---- .../committee_update_verifier.sol | 23 ---- .../snark-verifiers/sync_step_verifier.sol | 23 ---- contracts/src/EndianConversions.sol | 27 ---- contracts/src/RotateLib.sol | 46 ------- contracts/src/Spectre.sol | 130 ------------------ contracts/src/SyncStepLib.sol | 48 ------- .../interfaces/CommitteeUpdateVerifier.sol | 9 -- contracts/src/interfaces/SyncStepVerifier.sol | 13 -- .../src/mocks/CommitteeUpdateMockVerifier.sol | 14 -- contracts/src/mocks/SyncStepMockVerifier.sol | 20 --- contracts/test/RotateExternal.sol | 26 ---- contracts/test/SyncStepExternal.sol | 23 ---- 22 files changed, 723 deletions(-) delete mode 100644 contracts/.gitignore delete mode 100644 contracts/Cargo.toml delete mode 100644 contracts/README.md delete mode 100644 contracts/foundry.toml delete mode 100644 contracts/lib/YulDeployer.sol delete mode 160000 contracts/lib/forge-std delete mode 100644 contracts/remappings.txt delete mode 100644 contracts/rust-abi/lib.rs delete mode 100644 contracts/script/DeploySpectreLocal.s.sol delete mode 100644 contracts/script/DeploySpectreTestnet.s.sol delete mode 100644 contracts/snark-verifiers/committee_update_verifier.sol delete mode 100644 contracts/snark-verifiers/sync_step_verifier.sol delete mode 100644 contracts/src/EndianConversions.sol delete mode 100644 contracts/src/RotateLib.sol delete mode 100644 contracts/src/Spectre.sol delete mode 100644 contracts/src/SyncStepLib.sol delete mode 100644 contracts/src/interfaces/CommitteeUpdateVerifier.sol delete mode 100644 contracts/src/interfaces/SyncStepVerifier.sol delete mode 100644 contracts/src/mocks/CommitteeUpdateMockVerifier.sol delete mode 100644 contracts/src/mocks/SyncStepMockVerifier.sol delete mode 100644 contracts/test/RotateExternal.sol delete mode 100644 contracts/test/SyncStepExternal.sol diff --git a/contracts/.gitignore b/contracts/.gitignore deleted file mode 100644 index 9d91b78..0000000 --- a/contracts/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -# Compiler files -cache/ -out/ - -# Ignores development broadcast logs -broadcast/ - -# Docs -docs/ - -# Dotenv file -.env diff --git a/contracts/Cargo.toml b/contracts/Cargo.toml deleted file mode 100644 index c867fa7..0000000 --- a/contracts/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "contracts" -version = "0.1.0" -edition = "2021" - -[lib] -path = "rust-abi/lib.rs" - -[dependencies] -ethers = "2.0.10" -lightclient-circuits.workspace = true -eth-types.workspace = true -ssz_rs.workspace = true -halo2curves = { workspace = true } -itertools = { workspace = true } -halo2-base = { workspace = true } \ No newline at end of file diff --git a/contracts/README.md b/contracts/README.md deleted file mode 100644 index 9265b45..0000000 --- a/contracts/README.md +++ /dev/null @@ -1,66 +0,0 @@ -## Foundry - -**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** - -Foundry consists of: - -- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). -- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. -- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. -- **Chisel**: Fast, utilitarian, and verbose solidity REPL. - -## Documentation - -https://book.getfoundry.sh/ - -## Usage - -### Build - -```shell -$ forge build -``` - -### Test - -```shell -$ forge test -``` - -### Format - -```shell -$ forge fmt -``` - -### Gas Snapshots - -```shell -$ forge snapshot -``` - -### Anvil - -```shell -$ anvil -``` - -### Deploy - -```shell -$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key -``` - -### Cast - -```shell -$ cast -``` - -### Help - -```shell -$ forge --help -$ anvil --help -$ cast --help -``` diff --git a/contracts/foundry.toml b/contracts/foundry.toml deleted file mode 100644 index ac99a4c..0000000 --- a/contracts/foundry.toml +++ /dev/null @@ -1,19 +0,0 @@ -[profile.default] -src = 'src' -out = 'out' -ffi = true -libs = ['lib'] -optimizer = true -optimizer_runs = 1_000_000_000 -solc = "0.8.19" -fs_permissions = [{ access = "read", path = "./test/data/"}] - -[profile.default.optimizer_details] -constantOptimizer = true -yul = false - -[rpc_endpoints] -mainnet = "${MAINNET_RPC_URL}" -goerli = "${GOERLI_RPC_URL}" -sepolia = "${SEPOLIA_RPC_URL}" -local = "${LOCAL_RPC_URL}" diff --git a/contracts/lib/YulDeployer.sol b/contracts/lib/YulDeployer.sol deleted file mode 100644 index 61e7f8c..0000000 --- a/contracts/lib/YulDeployer.sol +++ /dev/null @@ -1,37 +0,0 @@ -// Source: https://github.com/CodeForcer/foundry-yul -// SPDX-License-Identifier: UNLICENSED -pragma solidity <0.9; - -import "forge-std/Test.sol"; - -contract YulDeployer is Test { - ///@notice Compiles a Yul contract and returns the address that the contract was deployeod to - ///@notice If deployment fails, an error will be thrown - ///@param fileName - The file name of the Yul contract. For example, the file name for "Example.yul" is "Example" - ///@return deployedAddress - The address that the contract was deployed to - function deployContract(string memory fileName) public returns (address) { - string memory bashCommand = string.concat( - 'cast abi-encode "f(bytes)" $(solc --yul snark-verifiers/', string.concat(fileName, ".yul --bin | tail -1)") - ); - - string[] memory inputs = new string[](3); - inputs[0] = "bash"; - inputs[1] = "-c"; - inputs[2] = bashCommand; - - // abi.decode(vm.ffi(inputs), (bytes)) - bytes memory bytecode = vm.ffi(inputs); - - ///@notice deploy the bytecode with the create instruction - address deployedAddress; - assembly { - deployedAddress := create(0, add(bytecode, 0x20), mload(bytecode)) - } - - ///@notice check that the deployment was successful - require(deployedAddress != address(0), "YulDeployer could not deploy contract"); - - ///@notice return the address that the contract was deployed to - return deployedAddress; - } -} diff --git a/contracts/lib/forge-std b/contracts/lib/forge-std deleted file mode 160000 index 1d9650e..0000000 --- a/contracts/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1d9650e951204a0ddce9ff89c32f1997984cef4d diff --git a/contracts/remappings.txt b/contracts/remappings.txt deleted file mode 100644 index 845bd0a..0000000 --- a/contracts/remappings.txt +++ /dev/null @@ -1,2 +0,0 @@ -ds-test/=lib/forge-std/lib/ds-test/src/ -forge-std/=lib/forge-std/src/ diff --git a/contracts/rust-abi/lib.rs b/contracts/rust-abi/lib.rs deleted file mode 100644 index 4016baf..0000000 --- a/contracts/rust-abi/lib.rs +++ /dev/null @@ -1,108 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -#![allow(incomplete_features)] -#![feature(generic_const_exprs)] -use ethers::{contract::abigen, types::U256}; -use itertools::Itertools; -use lightclient_circuits::{ - poseidon::poseidon_committee_commitment_from_compressed, - witness::{CommitteeUpdateArgs, SyncStepArgs}, -}; -use ssz_rs::{Merkleized, Vector}; -use std::ops::Deref; -abigen!( - Spectre, - "./out/Spectre.sol/Spectre.json"; - StepVerifier, - "./out/sync_step_verifier.sol/Verifier.json"; - CommitteeUpdateVerifier, - "./out/committee_update_verifier.sol/Verifier.json"; - SyncStepCompressedMockVerifier, - "./out/SyncStepMockVerifier.sol/SyncStepCompressedMockVerifier.json"; - CommitteeUpdateMockVerifier, - "./out/CommitteeUpdateMockVerifier.sol/CommitteeUpdateMockVerifier.json"; - RotateExternal, - "./out/RotateExternal.sol/RotateExternal.json"; - SyncStepExternal, - "./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() - .deref() - .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, - finalized_header_root, - execution_payload_root, - ..Default::default() - } - } -} - -impl SyncStepInput { - pub fn set_accumulator(&mut self, accumulator: [U256; 12]) { - self.accumulator = accumulator; - } -} - -// CommitteeRotationArgs type produced by abigen macro matches the solidity struct type -impl From> for RotateInput -where - [(); Spec::SYNC_COMMITTEE_SIZE]:, -{ - fn from(args: CommitteeUpdateArgs) -> Self { - let sync_committee_poseidon = poseidon_committee_commitment_from_compressed( - &args.pubkeys_compressed.iter().cloned().collect_vec(), - ); - let sync_committee_poseidon = U256::from_little_endian(&sync_committee_poseidon.to_bytes()); - - 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, - ..Default::default() - } - } -} - -impl RotateInput { - pub fn set_accumulator(&mut self, accumulator: [U256; 12]) { - self.accumulator = accumulator; - } -} diff --git a/contracts/script/DeploySpectreLocal.s.sol b/contracts/script/DeploySpectreLocal.s.sol deleted file mode 100644 index 4a3c6aa..0000000 --- a/contracts/script/DeploySpectreLocal.s.sol +++ /dev/null @@ -1,30 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -import "forge-std/Script.sol"; - -import {Spectre} from "../src/Spectre.sol"; -import {Verifier as CommitteeUpdateVerifier} from "../snark-verifiers/committee_update_verifier.sol"; -import {Verifier as SyncStepVerifier} from "../snark-verifiers/sync_step_verifier.sol"; - -contract DeploySpectre is Script { - - function run() external { - uint256 deployerPrivateKey = vm.envUint("ANVIL_PRIVATE_KEY"); - uint256 initialSyncPeriod = vm.envUint("INITIAL_SYNC_PERIOD"); - uint256 initialCommitteePoseidon = vm.envUint("INITIAL_COMMITTEE_POSEIDON"); - uint256 slotsPerPeriod = vm.envUint("SLOTS_PER_PERIOD"); - - vm.startBroadcast(deployerPrivateKey); - - SyncStepVerifier stepVerifier = new SyncStepVerifier(); - CommitteeUpdateVerifier updateVerifier = new CommitteeUpdateVerifier(); - - Spectre spectre = new Spectre(address(stepVerifier), address(updateVerifier), initialSyncPeriod, initialCommitteePoseidon, slotsPerPeriod); - - vm.stopBroadcast(); - } -} diff --git a/contracts/script/DeploySpectreTestnet.s.sol b/contracts/script/DeploySpectreTestnet.s.sol deleted file mode 100644 index e03c78d..0000000 --- a/contracts/script/DeploySpectreTestnet.s.sol +++ /dev/null @@ -1,30 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -import "forge-std/Script.sol"; - -import {Spectre} from "../src/Spectre.sol"; -import {Verifier as CommitteeUpdateVerifier} from "../snark-verifiers/committee_update_verifier.sol"; -import {Verifier as SyncStepVerifier} from "../snark-verifiers/sync_step_verifier.sol"; - -contract DeploySpectre is Script { - - function run() external { - uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY"); - uint256 initialSyncPeriod = vm.envUint("INITIAL_SYNC_PERIOD"); - uint256 initialCommitteePoseidon = vm.envUint("INITIAL_COMMITTEE_POSEIDON"); - uint256 slotsPerPeriod = vm.envUint("SLOTS_PER_PERIOD"); - - vm.startBroadcast(deployerPrivateKey); - - SyncStepVerifier stepVerifier = new SyncStepVerifier(); - CommitteeUpdateVerifier updateVerifier = new CommitteeUpdateVerifier(); - - Spectre spectre = new Spectre(address(stepVerifier), address(updateVerifier), initialSyncPeriod, initialCommitteePoseidon, slotsPerPeriod); - - vm.stopBroadcast(); - } -} diff --git a/contracts/snark-verifiers/committee_update_verifier.sol b/contracts/snark-verifiers/committee_update_verifier.sol deleted file mode 100644 index 215c09e..0000000 --- a/contracts/snark-verifiers/committee_update_verifier.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -contract Verifier { - - /** - * @notice Bn256 P value - * @dev In order to prevent the verifier from accepting two version of the same pubInput, n and the quantity (n + P), where n + P <= 2^256, we require that all pubInputs are stricly less than P. - * @dev The reason for this is that the assmebly code of the verifier performs all arithmetic operations modulo P and as a consequence can't distinguish between n and n + P values. - */ - - uint256 constant SIZE_LIMIT = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - - function verify( - uint256[77] calldata pubInputs, - bytes calldata proof - ) public view returns (bool) { - bool success = true; - bytes32[969] memory transcript; - for (uint i = 0; i < pubInputs.length; i++) { - require(pubInputs[i] < SIZE_LIMIT); - } - assembly { 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(0xa0, mod(calldataload(0x4), f_q))mstore(0xc0, mod(calldataload(0x24), f_q))mstore(0xe0, mod(calldataload(0x44), f_q))mstore(0x100, mod(calldataload(0x64), f_q))mstore(0x120, mod(calldataload(0x84), f_q))mstore(0x140, mod(calldataload(0xa4), f_q))mstore(0x160, mod(calldataload(0xc4), f_q))mstore(0x180, mod(calldataload(0xe4), f_q))mstore(0x1a0, mod(calldataload(0x104), f_q))mstore(0x1c0, mod(calldataload(0x124), f_q))mstore(0x1e0, mod(calldataload(0x144), f_q))mstore(0x200, mod(calldataload(0x164), f_q))mstore(0x220, mod(calldataload(0x184), f_q))mstore(0x240, mod(calldataload(0x1a4), f_q))mstore(0x260, mod(calldataload(0x1c4), f_q))mstore(0x280, mod(calldataload(0x1e4), f_q))mstore(0x2a0, mod(calldataload(0x204), f_q))mstore(0x2c0, mod(calldataload(0x224), f_q))mstore(0x2e0, mod(calldataload(0x244), f_q))mstore(0x300, mod(calldataload(0x264), f_q))mstore(0x320, mod(calldataload(0x284), f_q))mstore(0x340, mod(calldataload(0x2a4), f_q))mstore(0x360, mod(calldataload(0x2c4), f_q))mstore(0x380, mod(calldataload(0x2e4), f_q))mstore(0x3a0, mod(calldataload(0x304), f_q))mstore(0x3c0, mod(calldataload(0x324), f_q))mstore(0x3e0, mod(calldataload(0x344), f_q))mstore(0x400, mod(calldataload(0x364), f_q))mstore(0x420, mod(calldataload(0x384), f_q))mstore(0x440, mod(calldataload(0x3a4), f_q))mstore(0x460, mod(calldataload(0x3c4), f_q))mstore(0x480, mod(calldataload(0x3e4), f_q))mstore(0x4a0, mod(calldataload(0x404), f_q))mstore(0x4c0, mod(calldataload(0x424), f_q))mstore(0x4e0, mod(calldataload(0x444), f_q))mstore(0x500, mod(calldataload(0x464), f_q))mstore(0x520, mod(calldataload(0x484), f_q))mstore(0x540, mod(calldataload(0x4a4), f_q))mstore(0x560, mod(calldataload(0x4c4), f_q))mstore(0x580, mod(calldataload(0x4e4), f_q))mstore(0x5a0, mod(calldataload(0x504), f_q))mstore(0x5c0, mod(calldataload(0x524), f_q))mstore(0x5e0, mod(calldataload(0x544), f_q))mstore(0x600, mod(calldataload(0x564), f_q))mstore(0x620, mod(calldataload(0x584), f_q))mstore(0x640, mod(calldataload(0x5a4), f_q))mstore(0x660, mod(calldataload(0x5c4), f_q))mstore(0x680, mod(calldataload(0x5e4), f_q))mstore(0x6a0, mod(calldataload(0x604), f_q))mstore(0x6c0, mod(calldataload(0x624), f_q))mstore(0x6e0, mod(calldataload(0x644), f_q))mstore(0x700, mod(calldataload(0x664), f_q))mstore(0x720, mod(calldataload(0x684), f_q))mstore(0x740, mod(calldataload(0x6a4), f_q))mstore(0x760, mod(calldataload(0x6c4), f_q))mstore(0x780, mod(calldataload(0x6e4), f_q))mstore(0x7a0, mod(calldataload(0x704), f_q))mstore(0x7c0, mod(calldataload(0x724), f_q))mstore(0x7e0, mod(calldataload(0x744), f_q))mstore(0x800, mod(calldataload(0x764), f_q))mstore(0x820, mod(calldataload(0x784), f_q))mstore(0x840, mod(calldataload(0x7a4), f_q))mstore(0x860, mod(calldataload(0x7c4), f_q))mstore(0x880, mod(calldataload(0x7e4), f_q))mstore(0x8a0, mod(calldataload(0x804), f_q))mstore(0x8c0, mod(calldataload(0x824), f_q))mstore(0x8e0, mod(calldataload(0x844), f_q))mstore(0x900, mod(calldataload(0x864), f_q))mstore(0x920, mod(calldataload(0x884), f_q))mstore(0x940, mod(calldataload(0x8a4), f_q))mstore(0x960, mod(calldataload(0x8c4), f_q))mstore(0x980, mod(calldataload(0x8e4), f_q))mstore(0x9a0, mod(calldataload(0x904), f_q))mstore(0x9c0, mod(calldataload(0x924), f_q))mstore(0x9e0, mod(calldataload(0x944), f_q))mstore(0xa00, mod(calldataload(0x964), f_q))mstore(0xa20, mod(calldataload(0x984), f_q))mstore(0x80, 11715439634905124192438350817812315705745438828637212350574099994782109495331) { let x := calldataload(0x9e4) mstore(0xa40, x) let y := calldataload(0xa04) mstore(0xa60, y) success := and(validate_ec_point(x, y), success) }mstore(0xa80, keccak256(0x80, 2560)){ let hash := mload(0xa80) mstore(0xaa0, mod(hash, f_q)) mstore(0xac0, hash) } { let x := calldataload(0xa24) mstore(0xae0, x) let y := calldataload(0xa44) mstore(0xb00, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0xa64) mstore(0xb20, x) let y := calldataload(0xa84) mstore(0xb40, y) success := and(validate_ec_point(x, y), success) }mstore(0xb60, keccak256(0xac0, 160)){ let hash := mload(0xb60) mstore(0xb80, mod(hash, f_q)) mstore(0xba0, hash) }mstore8(0xbc0, 1)mstore(0xbc0, keccak256(0xba0, 33)){ let hash := mload(0xbc0) mstore(0xbe0, mod(hash, f_q)) mstore(0xc00, hash) } { let x := calldataload(0xaa4) mstore(0xc20, x) let y := calldataload(0xac4) mstore(0xc40, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0xae4) mstore(0xc60, x) let y := calldataload(0xb04) mstore(0xc80, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0xb24) mstore(0xca0, x) let y := calldataload(0xb44) mstore(0xcc0, y) success := and(validate_ec_point(x, y), success) }mstore(0xce0, keccak256(0xc00, 224)){ let hash := mload(0xce0) mstore(0xd00, mod(hash, f_q)) mstore(0xd20, hash) } { let x := calldataload(0xb64) mstore(0xd40, x) let y := calldataload(0xb84) mstore(0xd60, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0xba4) mstore(0xd80, x) let y := calldataload(0xbc4) mstore(0xda0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0xbe4) mstore(0xdc0, x) let y := calldataload(0xc04) mstore(0xde0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0xc24) mstore(0xe00, x) let y := calldataload(0xc44) mstore(0xe20, y) success := and(validate_ec_point(x, y), success) }mstore(0xe40, keccak256(0xd20, 288)){ let hash := mload(0xe40) mstore(0xe60, mod(hash, f_q)) mstore(0xe80, hash) }mstore(0xea0, mod(calldataload(0xc64), f_q))mstore(0xec0, mod(calldataload(0xc84), f_q))mstore(0xee0, mod(calldataload(0xca4), f_q))mstore(0xf00, mod(calldataload(0xcc4), f_q))mstore(0xf20, mod(calldataload(0xce4), f_q))mstore(0xf40, mod(calldataload(0xd04), f_q))mstore(0xf60, mod(calldataload(0xd24), f_q))mstore(0xf80, mod(calldataload(0xd44), f_q))mstore(0xfa0, mod(calldataload(0xd64), f_q))mstore(0xfc0, mod(calldataload(0xd84), f_q))mstore(0xfe0, mod(calldataload(0xda4), f_q))mstore(0x1000, mod(calldataload(0xdc4), f_q))mstore(0x1020, mod(calldataload(0xde4), f_q))mstore(0x1040, mod(calldataload(0xe04), f_q))mstore(0x1060, mod(calldataload(0xe24), f_q))mstore(0x1080, mod(calldataload(0xe44), f_q))mstore(0x10a0, mod(calldataload(0xe64), f_q))mstore(0x10c0, mod(calldataload(0xe84), f_q))mstore(0x10e0, mod(calldataload(0xea4), f_q))mstore(0x1100, keccak256(0xe80, 640)){ let hash := mload(0x1100) mstore(0x1120, mod(hash, f_q)) mstore(0x1140, hash) }mstore8(0x1160, 1)mstore(0x1160, keccak256(0x1140, 33)){ let hash := mload(0x1160) mstore(0x1180, mod(hash, f_q)) mstore(0x11a0, hash) } { let x := calldataload(0xec4) mstore(0x11c0, x) let y := calldataload(0xee4) mstore(0x11e0, y) success := and(validate_ec_point(x, y), success) }mstore(0x1200, keccak256(0x11a0, 96)){ let hash := mload(0x1200) mstore(0x1220, mod(hash, f_q)) mstore(0x1240, hash) } { let x := calldataload(0xf04) mstore(0x1260, x) let y := calldataload(0xf24) mstore(0x1280, y) success := and(validate_ec_point(x, y), success) }{ let x := mload(0xa0)x := add(x, shl(88, mload(0xc0)))x := add(x, shl(176, mload(0xe0)))mstore(0x12a0, x)let y := mload(0x100)y := add(y, shl(88, mload(0x120)))y := add(y, shl(176, mload(0x140)))mstore(0x12c0, y) success := and(validate_ec_point(x, y), success) }{ let x := mload(0x160)x := add(x, shl(88, mload(0x180)))x := add(x, shl(176, mload(0x1a0)))mstore(0x12e0, x)let y := mload(0x1c0)y := add(y, shl(88, mload(0x1e0)))y := add(y, shl(176, mload(0x200)))mstore(0x1300, y) success := and(validate_ec_point(x, y), success) }mstore(0x1320, mulmod(mload(0xe60), mload(0xe60), f_q))mstore(0x1340, mulmod(mload(0x1320), mload(0x1320), f_q))mstore(0x1360, mulmod(mload(0x1340), mload(0x1340), f_q))mstore(0x1380, mulmod(mload(0x1360), mload(0x1360), f_q))mstore(0x13a0, mulmod(mload(0x1380), mload(0x1380), f_q))mstore(0x13c0, mulmod(mload(0x13a0), mload(0x13a0), f_q))mstore(0x13e0, mulmod(mload(0x13c0), mload(0x13c0), f_q))mstore(0x1400, mulmod(mload(0x13e0), mload(0x13e0), f_q))mstore(0x1420, mulmod(mload(0x1400), mload(0x1400), f_q))mstore(0x1440, mulmod(mload(0x1420), mload(0x1420), f_q))mstore(0x1460, mulmod(mload(0x1440), mload(0x1440), f_q))mstore(0x1480, mulmod(mload(0x1460), mload(0x1460), f_q))mstore(0x14a0, mulmod(mload(0x1480), mload(0x1480), f_q))mstore(0x14c0, mulmod(mload(0x14a0), mload(0x14a0), f_q))mstore(0x14e0, mulmod(mload(0x14c0), mload(0x14c0), f_q))mstore(0x1500, mulmod(mload(0x14e0), mload(0x14e0), f_q))mstore(0x1520, mulmod(mload(0x1500), mload(0x1500), f_q))mstore(0x1540, mulmod(mload(0x1520), mload(0x1520), f_q))mstore(0x1560, mulmod(mload(0x1540), mload(0x1540), f_q))mstore(0x1580, mulmod(mload(0x1560), mload(0x1560), f_q))mstore(0x15a0, mulmod(mload(0x1580), mload(0x1580), f_q))mstore(0x15c0, mulmod(mload(0x15a0), mload(0x15a0), f_q))mstore(0x15e0, mulmod(mload(0x15c0), mload(0x15c0), f_q))mstore(0x1600, mulmod(mload(0x15e0), mload(0x15e0), f_q))mstore(0x1620, addmod(mload(0x1600), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q))mstore(0x1640, mulmod(mload(0x1620), 21888241567198334088790460357988866238279339518792980768180410072331574733841, f_q))mstore(0x1660, mulmod(mload(0x1640), 12929131318670223636853686797196826072950305380535537217467769528748593133487, f_q))mstore(0x1680, addmod(mload(0xe60), 8959111553169051585392718948060449015598059019880497126230434657827215362130, f_q))mstore(0x16a0, mulmod(mload(0x1640), 14655294445420895451632927078981340937842238432098198055057679026789553137428, f_q))mstore(0x16c0, addmod(mload(0xe60), 7232948426418379770613478666275934150706125968317836288640525159786255358189, f_q))mstore(0x16e0, mulmod(mload(0x1640), 12220484078924208264862893648548198807365556694478604924193442790112568454894, f_q))mstore(0x1700, addmod(mload(0xe60), 9667758792915066957383512096709076281182807705937429419504761396463240040723, f_q))mstore(0x1720, mulmod(mload(0x1640), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q))mstore(0x1740, addmod(mload(0xe60), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q))mstore(0x1760, mulmod(mload(0x1640), 7358966525675286471217089135633860168646304224547606326237275077574224349359, f_q))mstore(0x1780, addmod(mload(0xe60), 14529276346163988751029316609623414919902060175868428017460929109001584146258, f_q))mstore(0x17a0, mulmod(mload(0x1640), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q))mstore(0x17c0, addmod(mload(0xe60), 12146688980418810893951125255607130521645347193942732958664170801695864621270, f_q))mstore(0x17e0, mulmod(mload(0x1640), 17329448237240114492580865744088056414251735686965494637158808787419781175510, f_q))mstore(0x1800, addmod(mload(0xe60), 4558794634599160729665540001169218674296628713450539706539395399156027320107, f_q))mstore(0x1820, mulmod(mload(0x1640), 1, f_q))mstore(0x1840, addmod(mload(0xe60), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q))mstore(0x1860, mulmod(mload(0x1640), 11451405578697956743456240853980216273390554734748796433026540431386972584651, f_q))mstore(0x1880, addmod(mload(0xe60), 10436837293141318478790164891277058815157809665667237910671663755188835910966, f_q))mstore(0x18a0, mulmod(mload(0x1640), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q))mstore(0x18c0, addmod(mload(0xe60), 13513867906530865119835332133273263211836799082674232843258448413103731898270, f_q))mstore(0x18e0, mulmod(mload(0x1640), 21490807004895109926141140246143262403290679459142140821740925192625185504522, f_q))mstore(0x1900, addmod(mload(0xe60), 397435866944165296105265499114012685257684941273893521957278993950622991095, f_q))mstore(0x1920, mulmod(mload(0x1640), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q))mstore(0x1940, addmod(mload(0xe60), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q))mstore(0x1960, mulmod(mload(0x1640), 18846108080730935585192484934247867403156699586319724728525857970312957475341, f_q))mstore(0x1980, addmod(mload(0xe60), 3042134791108339637053920811009407685391664814096309615172346216262851020276, f_q))mstore(0x19a0, mulmod(mload(0x1640), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q))mstore(0x19c0, addmod(mload(0xe60), 18272764063556419981698118473909131571661591947471949595929891197711371770216, f_q))mstore(0x19e0, mulmod(mload(0x1640), 21451937155080765789602997556105366785934335730087568134349216848800867145453, f_q))mstore(0x1a00, addmod(mload(0xe60), 436305716758509432643408189151908302614028670328466209348987337774941350164, f_q))mstore(0x1a20, mulmod(mload(0x1640), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q))mstore(0x1a40, addmod(mload(0xe60), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q))mstore(0x1a60, mulmod(mload(0x1640), 13982290267294411190096162596630216412723378687553046594730793425118513274800, f_q))mstore(0x1a80, addmod(mload(0xe60), 7905952604544864032150243148627058675824985712862987748967410761457295220817, f_q))mstore(0x1aa0, mulmod(mload(0x1640), 216092043779272773661818549620449970334216366264741118684015851799902419467, f_q))mstore(0x1ac0, addmod(mload(0xe60), 21672150828060002448584587195636825118214148034151293225014188334775906076150, f_q))mstore(0x1ae0, mulmod(mload(0x1640), 9537783784440837896026284659246718978615447564543116209283382057778110278482, f_q))mstore(0x1b00, addmod(mload(0xe60), 12350459087398437326220121086010556109932916835872918134414822128797698217135, f_q))mstore(0x1b20, mulmod(mload(0x1640), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q))mstore(0x1b40, addmod(mload(0xe60), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q))mstore(0x1b60, mulmod(mload(0x1640), 3947443723575973965644279767310964219908423994086470065513888332899718123222, f_q))mstore(0x1b80, addmod(mload(0xe60), 17940799148263301256602125977946310868639940406329564278184315853676090372395, f_q))mstore(0x1ba0, mulmod(mload(0x1640), 18610195890048912503953886742825279624920778288956610528523679659246523534888, f_q))mstore(0x1bc0, addmod(mload(0xe60), 3278046981790362718292519002431995463627586111459423815174524527329284960729, f_q))mstore(0x1be0, mulmod(mload(0x1640), 1539082509056298927655194235755440186888826897239928178265486731666142403222, f_q))mstore(0x1c00, addmod(mload(0xe60), 20349160362782976294591211509501834901659537503176106165432717454909666092395, f_q))mstore(0x1c20, mulmod(mload(0x1640), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q))mstore(0x1c40, addmod(mload(0xe60), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q))mstore(0x1c60, mulmod(mload(0x1640), 4317410353320599552056040796202302907960891408523818766419977508859423800635, f_q))mstore(0x1c80, addmod(mload(0xe60), 17570832518518675670190364949054972180587472991892215577278226677716384694982, f_q))mstore(0x1ca0, mulmod(mload(0x1640), 14875928112196239563830800280253496262679717528621719058794366823499719730250, f_q))mstore(0x1cc0, addmod(mload(0xe60), 7012314759643035658415605465003778825868646871794315284903837363076088765367, f_q))mstore(0x1ce0, mulmod(mload(0x1640), 2366023502186770334390939928726871658997402416352868340984630739442624219298, f_q))mstore(0x1d00, addmod(mload(0xe60), 19522219369652504887855465816530403429550961984063166002713573447133184276319, f_q))mstore(0x1d20, mulmod(mload(0x1640), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q))mstore(0x1d40, addmod(mload(0xe60), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q))mstore(0x1d60, mulmod(mload(0x1640), 14391499717548074167711220639833994904150450341569029103202493919171555826079, f_q))mstore(0x1d80, addmod(mload(0xe60), 7496743154291201054535185105423280184397914058847005240495710267404252669538, f_q))mstore(0x1da0, mulmod(mload(0x1640), 5522161504810533295870699551020523636289972223872138525048055197429246400245, f_q))mstore(0x1dc0, addmod(mload(0xe60), 16366081367028741926375706194236751452258392176543895818650148989146562095372, f_q))mstore(0x1de0, mulmod(mload(0x1640), 10119780362642123194334092174270235809557798114544683654677907882314807212354, f_q))mstore(0x1e00, addmod(mload(0xe60), 11768462509197152027912313570987039278990566285871350689020296304261001283263, f_q))mstore(0x1e20, mulmod(mload(0x1640), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q))mstore(0x1e40, addmod(mload(0xe60), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q))mstore(0x1e60, mulmod(mload(0x1640), 2080322550956715654503104356805349981348621877591103674778333538652571537127, f_q))mstore(0x1e80, addmod(mload(0xe60), 19807920320882559567743301388451925107199742522824930668919870647923236958490, f_q))mstore(0x1ea0, mulmod(mload(0x1640), 9100833993744738801214480881117348002768153232283708533639316963648253510584, f_q))mstore(0x1ec0, addmod(mload(0xe60), 12787408878094536421031924864139927085780211168132325810058887222927554985033, f_q))mstore(0x1ee0, mulmod(mload(0x1640), 11145214675344139457514777444556774698911688619991656085001542609383151586084, f_q))mstore(0x1f00, addmod(mload(0xe60), 10743028196495135764731628300700500389636675780424378258696661577192656909533, f_q))mstore(0x1f20, mulmod(mload(0x1640), 4245441013247250116003069945606352967193023389718465410501109428393342802981, f_q))mstore(0x1f40, addmod(mload(0xe60), 17642801858592025106243335799650922121355341010697568933197094758182465692636, f_q))mstore(0x1f60, mulmod(mload(0x1640), 19228510170961893342195489288913594506775385223367826565223897736323409650249, f_q))mstore(0x1f80, addmod(mload(0xe60), 2659732700877381880050916456343680581772979177048207778474306450252398845368, f_q))mstore(0x1fa0, mulmod(mload(0x1640), 6132660129994545119218258312491950835441607143741804980633129304664017206141, f_q))mstore(0x1fc0, addmod(mload(0xe60), 15755582741844730103028147432765324253106757256674229363065074881911791289476, f_q))mstore(0x1fe0, mulmod(mload(0x1640), 10094752117139066216691253588991632982053223883646966177987813353508871280747, f_q))mstore(0x2000, addmod(mload(0xe60), 11793490754700209005555152156265642106495140516769068165710390833066937214870, f_q))mstore(0x2020, mulmod(mload(0x1640), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q))mstore(0x2040, addmod(mload(0xe60), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q))mstore(0x2060, mulmod(mload(0x1640), 21346203717540287263608402129024479709126363130664317843105498655869866203005, f_q))mstore(0x2080, addmod(mload(0xe60), 542039154298987958638003616232795379422001269751716500592705530705942292612, f_q))mstore(0x20a0, mulmod(mload(0x1640), 515148244606945972463850631189471072103916690263705052318085725998468254533, f_q))mstore(0x20c0, addmod(mload(0xe60), 21373094627232329249782555114067804016444447710152329291380118460577340241084, f_q))mstore(0x20e0, mulmod(mload(0x1640), 13788243025932779125104144225768424453664118806559109014238064020826883170336, f_q))mstore(0x2100, addmod(mload(0xe60), 8099999845906496097142261519488850634884245593856925329460140165748925325281, f_q))mstore(0x2120, mulmod(mload(0x1640), 5980488956150442207659150513163747165544364597008566989111579977672498964212, f_q))mstore(0x2140, addmod(mload(0xe60), 15907753915688833014587255232093527923003999803407467354586624208903309531405, f_q))mstore(0x2160, mulmod(mload(0x1640), 8561696234966975469289029207282849740510759316794581475824569334969644143582, f_q))mstore(0x2180, addmod(mload(0xe60), 13326546636872299752957376537974425348037605083621452867873634851606164352035, f_q))mstore(0x21a0, mulmod(mload(0x1640), 5223738580615264174925218065001555728265216895679471490312087802465486318994, f_q))mstore(0x21c0, addmod(mload(0xe60), 16664504291224011047321187680255719360283147504736562853386116384110322176623, f_q))mstore(0x21e0, mulmod(mload(0x1640), 3302268277365219249160464068848832456250192077357408622723420445620736662125, f_q))mstore(0x2200, addmod(mload(0xe60), 18585974594474055973085941676408442632298172323058625720974783740955071833492, f_q))mstore(0x2220, mulmod(mload(0x1640), 14557038802599140430182096396825290815503940951075961210638273254419942783582, f_q))mstore(0x2240, addmod(mload(0xe60), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q))mstore(0x2260, mulmod(mload(0x1640), 21631349642691366221117117325940229443266870213711402446456178962469345982255, f_q))mstore(0x2280, addmod(mload(0xe60), 256893229147909001129288419317045645281494186704631897242025224106462513362, f_q))mstore(0x22a0, mulmod(mload(0x1640), 16976236069879939850923145256911338076234942200101755618884183331004076579046, f_q))mstore(0x22c0, addmod(mload(0xe60), 4912006801959335371323260488345937012313422200314278724814020855571731916571, f_q))mstore(0x22e0, mulmod(mload(0x1640), 18106030913818996184930975996483865250387924434749113154514488995517615180373, f_q))mstore(0x2300, addmod(mload(0xe60), 3782211958020279037315429748773409838160439965666921189183715191058193315244, f_q))mstore(0x2320, mulmod(mload(0x1640), 13553911191894110065493137367144919847521088405945523452288398666974237857208, f_q))mstore(0x2340, addmod(mload(0xe60), 8334331679945165156753268378112355241027275994470510891409805519601570638409, f_q))mstore(0x2360, mulmod(mload(0x1640), 15126807493918544618788554261654793824894621953586710625413511093368555507114, f_q))mstore(0x2380, addmod(mload(0xe60), 6761435377920730603457851483602481263653742446829323718284693093207252988503, f_q))mstore(0x23a0, mulmod(mload(0x1640), 12222687719926148270818604386979005738180875192307070468454582955273533101023, f_q))mstore(0x23c0, addmod(mload(0xe60), 9665555151913126951427801358278269350367489208108963875243621231302275394594, f_q))mstore(0x23e0, mulmod(mload(0x1640), 16714975918200644516413377824646615398811161167186708005951772994925725210988, f_q))mstore(0x2400, addmod(mload(0xe60), 5173266953638630705833027920610659689737203233229326337746431191650083284629, f_q))mstore(0x2420, mulmod(mload(0x1640), 9697063347556872083384215826199993067635178715531258559890418744774301211662, f_q))mstore(0x2440, addmod(mload(0xe60), 12191179524282403138862189919057282020913185684884775783807785441801507283955, f_q))mstore(0x2460, mulmod(mload(0x1640), 8232431451150482057473812611943294635402895089782291356256081195754688638419, f_q))mstore(0x2480, addmod(mload(0xe60), 13655811420688793164772593133313980453145469310633742987442122990821119857198, f_q))mstore(0x24a0, mulmod(mload(0x1640), 13783318220968413117070077848579881425001701814458176881760898225529300547844, f_q))mstore(0x24c0, addmod(mload(0xe60), 8104924650870862105176327896677393663546662585957857461937305961046507947773, f_q))mstore(0x24e0, mulmod(mload(0x1640), 17070294809977715215077308683367050851120007385961664319144486981376266100228, f_q))mstore(0x2500, addmod(mload(0xe60), 4817948061861560007169097061890224237428357014454370024553717205199542395389, f_q))mstore(0x2520, mulmod(mload(0x1640), 10807735674816066981985242612061336605021639643453679977988966079770672437131, f_q))mstore(0x2540, addmod(mload(0xe60), 11080507197023208240261163133195938483526724756962354365709238106805136058486, f_q))mstore(0x2560, mulmod(mload(0x1640), 10320222094738691136760616041626757686650252828592064883134944032883139493239, f_q))mstore(0x2580, addmod(mload(0xe60), 11568020777100584085485789703630517401898111571823969460563260153692669002378, f_q))mstore(0x25a0, mulmod(mload(0x1640), 15487660954688013862248478071816391715224351867581977083810729441220383572585, f_q))mstore(0x25c0, addmod(mload(0xe60), 6400581917151261359997927673440883373324012532834057259887474745355424923032, f_q))mstore(0x25e0, mulmod(mload(0x1640), 12896114329936223826328336851156210236116218608332234285980274197209453560736, f_q))mstore(0x2600, addmod(mload(0xe60), 8992128541903051395918068894101064852432145792083800057717929989366354934881, f_q))mstore(0x2620, mulmod(mload(0x1640), 12459868075641381822485233712013080087763946065665469821362892189399541605692, f_q))mstore(0x2640, addmod(mload(0xe60), 9428374796197893399761172033244195000784418334750564522335311997176266889925, f_q))mstore(0x2660, mulmod(mload(0x1640), 19920191427190722095796166662590871096930011470879410060483116711019686308362, f_q))mstore(0x2680, addmod(mload(0xe60), 1968051444648553126450239082666403991618352929536624283215087475556122187255, f_q))mstore(0x26a0, mulmod(mload(0x1640), 12562571400845953139885120066983392294851269266041089223701347829190217414825, f_q))mstore(0x26c0, addmod(mload(0xe60), 9325671470993322082361285678273882793697095134374945119996856357385591080792, f_q))mstore(0x26e0, mulmod(mload(0x1640), 14448452208700780299613904085074562738832656926008536161675287466267527586412, f_q))mstore(0x2700, addmod(mload(0xe60), 7439790663138494922632501660182712349715707474407498182022916720308280909205, f_q))mstore(0x2720, mulmod(mload(0x1640), 16038300751658239075779628684257016433412502747804121525056508685985277092575, f_q))mstore(0x2740, addmod(mload(0xe60), 5849942120181036146466777061000258655135861652611912818641695500590531403042, f_q))mstore(0x2760, mulmod(mload(0x1640), 14084705004012911259675385222203814438408503240448202630833832765018917772160, f_q))mstore(0x2780, addmod(mload(0xe60), 7803537867826363962571020523053460650139861159967831712864371421556890723457, f_q))mstore(0x27a0, mulmod(mload(0x1640), 17665522928519859765452767154433594409738037332395989540221744312194874941704, f_q))mstore(0x27c0, addmod(mload(0xe60), 4222719943319415456793638590823680678810327068020044803476459874380933553913, f_q))mstore(0x27e0, mulmod(mload(0x1640), 16295049735753754081616348893169020553309720529814216200499589072340851153544, f_q))mstore(0x2800, addmod(mload(0xe60), 5593193136085521140630056852088254535238643870601818143198615114234957342073, f_q))mstore(0x2820, mulmod(mload(0x1640), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q))mstore(0x2840, addmod(mload(0xe60), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q))mstore(0x2860, mulmod(mload(0x1640), 14699031513037352720782022637883087576160364237534146709479748594993796784568, f_q))mstore(0x2880, addmod(mload(0xe60), 7189211358801922501464383107374187512388000162881887634218455591582011711049, f_q))mstore(0x28a0, mulmod(mload(0x1640), 1918679275621049296283934091410967415474987212511681231948800935495808101054, f_q))mstore(0x28c0, addmod(mload(0xe60), 19969563596218225925962471653846307673073377187904353111749403251080000394563, f_q))mstore(0x28e0, mulmod(mload(0x1640), 20776965232354160552367722884947240566565796482220309784613818285679578113242, f_q))mstore(0x2900, addmod(mload(0xe60), 1111277639485114669878682860310034521982567918195724559084385900896230382375, f_q))mstore(0x2920, mulmod(mload(0x1640), 13498745591877810872211159461644682954739332524336278910448604883789771736885, f_q))mstore(0x2940, addmod(mload(0xe60), 8389497279961464350035246283612592133809031876079755433249599302786036758732, f_q))mstore(0x2960, mulmod(mload(0x1640), 21158723257009161664752767929965294555629420783981476627372734966438349636085, f_q))mstore(0x2980, addmod(mload(0xe60), 729519614830113557493637815291980532918943616434557716325469220137458859532, f_q))mstore(0x29a0, mulmod(mload(0x1640), 6604851689411953560355663038203889299997924520355363678860500374111951937637, f_q))mstore(0x29c0, addmod(mload(0xe60), 15283391182427321661890742707053385788550439880060670664837703812463856557980, f_q))mstore(0x29e0, mulmod(mload(0x1640), 21702726909732705185590371357192368080626548100357549203145988898368692640320, f_q))mstore(0x2a00, addmod(mload(0xe60), 185515962106570036656034388064907007921816300058485140552215288207115855297, f_q))mstore(0x2a20, mulmod(mload(0x1640), 20345677989844117909528750049476969581182118546166966482506114734614108237981, f_q))mstore(0x2a40, addmod(mload(0xe60), 1542564881995157312717655695780305507366245854249067861192089451961700257636, f_q))mstore(0x2a60, mulmod(mload(0x1640), 16567582365062587108827662340989684267825804507588024377667462437222984777972, f_q))mstore(0x2a80, addmod(mload(0xe60), 5320660506776688113418743404267590820722559892828009966030741749352823717645, f_q))mstore(0x2aa0, mulmod(mload(0x1640), 11244009323710436498447061620026171700033960328162115124806024297270121927878, f_q))mstore(0x2ac0, addmod(mload(0xe60), 10644233548128838723799344125231103388514404072253919218892179889305686567739, f_q))mstore(0x2ae0, mulmod(mload(0x1640), 9706000582800290987287483383922226374157159042727108374973797832689105581010, f_q))mstore(0x2b00, addmod(mload(0xe60), 12182242289038984234958922361335048714391205357688925968724406353886702914607, f_q))mstore(0x2b20, mulmod(mload(0x1640), 790608022292213379425324383664216541739009722347092850716054055768832299157, f_q))mstore(0x2b40, addmod(mload(0xe60), 21097634849547061842821081361593058546809354678068941492982150130806976196460, f_q)){ let prod := mload(0x1680) prod := mulmod(mload(0x16c0), prod, f_q) mstore(0x2b60, prod) prod := mulmod(mload(0x1700), prod, f_q) mstore(0x2b80, prod) prod := mulmod(mload(0x1740), prod, f_q) mstore(0x2ba0, prod) prod := mulmod(mload(0x1780), prod, f_q) mstore(0x2bc0, prod) prod := mulmod(mload(0x17c0), prod, f_q) mstore(0x2be0, prod) prod := mulmod(mload(0x1800), prod, f_q) mstore(0x2c00, prod) prod := mulmod(mload(0x1840), prod, f_q) mstore(0x2c20, prod) prod := mulmod(mload(0x1880), prod, f_q) mstore(0x2c40, prod) prod := mulmod(mload(0x18c0), prod, f_q) mstore(0x2c60, prod) prod := mulmod(mload(0x1900), prod, f_q) mstore(0x2c80, prod) prod := mulmod(mload(0x1940), prod, f_q) mstore(0x2ca0, prod) prod := mulmod(mload(0x1980), prod, f_q) mstore(0x2cc0, prod) prod := mulmod(mload(0x19c0), prod, f_q) mstore(0x2ce0, prod) prod := mulmod(mload(0x1a00), prod, f_q) mstore(0x2d00, prod) prod := mulmod(mload(0x1a40), prod, f_q) mstore(0x2d20, prod) prod := mulmod(mload(0x1a80), prod, f_q) mstore(0x2d40, prod) prod := mulmod(mload(0x1ac0), prod, f_q) mstore(0x2d60, prod) prod := mulmod(mload(0x1b00), prod, f_q) mstore(0x2d80, prod) prod := mulmod(mload(0x1b40), prod, f_q) mstore(0x2da0, prod) prod := mulmod(mload(0x1b80), prod, f_q) mstore(0x2dc0, prod) prod := mulmod(mload(0x1bc0), prod, f_q) mstore(0x2de0, prod) prod := mulmod(mload(0x1c00), prod, f_q) mstore(0x2e00, prod) prod := mulmod(mload(0x1c40), prod, f_q) mstore(0x2e20, prod) prod := mulmod(mload(0x1c80), prod, f_q) mstore(0x2e40, prod) prod := mulmod(mload(0x1cc0), prod, f_q) mstore(0x2e60, prod) prod := mulmod(mload(0x1d00), prod, f_q) mstore(0x2e80, prod) prod := mulmod(mload(0x1d40), prod, f_q) mstore(0x2ea0, prod) prod := mulmod(mload(0x1d80), prod, f_q) mstore(0x2ec0, prod) prod := mulmod(mload(0x1dc0), prod, f_q) mstore(0x2ee0, prod) prod := mulmod(mload(0x1e00), prod, f_q) mstore(0x2f00, prod) prod := mulmod(mload(0x1e40), prod, f_q) mstore(0x2f20, prod) prod := mulmod(mload(0x1e80), prod, f_q) mstore(0x2f40, prod) prod := mulmod(mload(0x1ec0), prod, f_q) mstore(0x2f60, prod) prod := mulmod(mload(0x1f00), prod, f_q) mstore(0x2f80, prod) prod := mulmod(mload(0x1f40), prod, f_q) mstore(0x2fa0, prod) prod := mulmod(mload(0x1f80), prod, f_q) mstore(0x2fc0, prod) prod := mulmod(mload(0x1fc0), prod, f_q) mstore(0x2fe0, prod) prod := mulmod(mload(0x2000), prod, f_q) mstore(0x3000, prod) prod := mulmod(mload(0x2040), prod, f_q) mstore(0x3020, prod) prod := mulmod(mload(0x2080), prod, f_q) mstore(0x3040, prod) prod := mulmod(mload(0x20c0), prod, f_q) mstore(0x3060, prod) prod := mulmod(mload(0x2100), prod, f_q) mstore(0x3080, prod) prod := mulmod(mload(0x2140), prod, f_q) mstore(0x30a0, prod) prod := mulmod(mload(0x2180), prod, f_q) mstore(0x30c0, prod) prod := mulmod(mload(0x21c0), prod, f_q) mstore(0x30e0, prod) prod := mulmod(mload(0x2200), prod, f_q) mstore(0x3100, prod) prod := mulmod(mload(0x2240), prod, f_q) mstore(0x3120, prod) prod := mulmod(mload(0x2280), prod, f_q) mstore(0x3140, prod) prod := mulmod(mload(0x22c0), prod, f_q) mstore(0x3160, prod) prod := mulmod(mload(0x2300), prod, f_q) mstore(0x3180, prod) prod := mulmod(mload(0x2340), prod, f_q) mstore(0x31a0, prod) prod := mulmod(mload(0x2380), prod, f_q) mstore(0x31c0, prod) prod := mulmod(mload(0x23c0), prod, f_q) mstore(0x31e0, prod) prod := mulmod(mload(0x2400), prod, f_q) mstore(0x3200, prod) prod := mulmod(mload(0x2440), prod, f_q) mstore(0x3220, prod) prod := mulmod(mload(0x2480), prod, f_q) mstore(0x3240, prod) prod := mulmod(mload(0x24c0), prod, f_q) mstore(0x3260, prod) prod := mulmod(mload(0x2500), prod, f_q) mstore(0x3280, prod) prod := mulmod(mload(0x2540), prod, f_q) mstore(0x32a0, prod) prod := mulmod(mload(0x2580), prod, f_q) mstore(0x32c0, prod) prod := mulmod(mload(0x25c0), prod, f_q) mstore(0x32e0, prod) prod := mulmod(mload(0x2600), prod, f_q) mstore(0x3300, prod) prod := mulmod(mload(0x2640), prod, f_q) mstore(0x3320, prod) prod := mulmod(mload(0x2680), prod, f_q) mstore(0x3340, prod) prod := mulmod(mload(0x26c0), prod, f_q) mstore(0x3360, prod) prod := mulmod(mload(0x2700), prod, f_q) mstore(0x3380, prod) prod := mulmod(mload(0x2740), prod, f_q) mstore(0x33a0, prod) prod := mulmod(mload(0x2780), prod, f_q) mstore(0x33c0, prod) prod := mulmod(mload(0x27c0), prod, f_q) mstore(0x33e0, prod) prod := mulmod(mload(0x2800), prod, f_q) mstore(0x3400, prod) prod := mulmod(mload(0x2840), prod, f_q) mstore(0x3420, prod) prod := mulmod(mload(0x2880), prod, f_q) mstore(0x3440, prod) prod := mulmod(mload(0x28c0), prod, f_q) mstore(0x3460, prod) prod := mulmod(mload(0x2900), prod, f_q) mstore(0x3480, prod) prod := mulmod(mload(0x2940), prod, f_q) mstore(0x34a0, prod) prod := mulmod(mload(0x2980), prod, f_q) mstore(0x34c0, prod) prod := mulmod(mload(0x29c0), prod, f_q) mstore(0x34e0, prod) prod := mulmod(mload(0x2a00), prod, f_q) mstore(0x3500, prod) prod := mulmod(mload(0x2a40), prod, f_q) mstore(0x3520, prod) prod := mulmod(mload(0x2a80), prod, f_q) mstore(0x3540, prod) prod := mulmod(mload(0x2ac0), prod, f_q) mstore(0x3560, prod) prod := mulmod(mload(0x2b00), prod, f_q) mstore(0x3580, prod) prod := mulmod(mload(0x2b40), prod, f_q) mstore(0x35a0, prod) prod := mulmod(mload(0x1620), prod, f_q) mstore(0x35c0, prod) }mstore(0x3600, 32)mstore(0x3620, 32)mstore(0x3640, 32)mstore(0x3660, mload(0x35c0))mstore(0x3680, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x36a0, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x3600, 0xc0, 0x35e0, 0x20), 1), success){ let inv := mload(0x35e0) let v v := mload(0x1620) mstore(0x1620, mulmod(mload(0x35a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2b40) mstore(0x2b40, mulmod(mload(0x3580), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2b00) mstore(0x2b00, mulmod(mload(0x3560), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2ac0) mstore(0x2ac0, mulmod(mload(0x3540), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2a80) mstore(0x2a80, mulmod(mload(0x3520), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2a40) mstore(0x2a40, mulmod(mload(0x3500), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2a00) mstore(0x2a00, mulmod(mload(0x34e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x29c0) mstore(0x29c0, mulmod(mload(0x34c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2980) mstore(0x2980, mulmod(mload(0x34a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2940) mstore(0x2940, mulmod(mload(0x3480), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2900) mstore(0x2900, mulmod(mload(0x3460), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x28c0) mstore(0x28c0, mulmod(mload(0x3440), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2880) mstore(0x2880, mulmod(mload(0x3420), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2840) mstore(0x2840, mulmod(mload(0x3400), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2800) mstore(0x2800, mulmod(mload(0x33e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x27c0) mstore(0x27c0, mulmod(mload(0x33c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2780) mstore(0x2780, mulmod(mload(0x33a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2740) mstore(0x2740, mulmod(mload(0x3380), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2700) mstore(0x2700, mulmod(mload(0x3360), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x26c0) mstore(0x26c0, mulmod(mload(0x3340), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2680) mstore(0x2680, mulmod(mload(0x3320), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2640) mstore(0x2640, mulmod(mload(0x3300), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2600) mstore(0x2600, mulmod(mload(0x32e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x25c0) mstore(0x25c0, mulmod(mload(0x32c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2580) mstore(0x2580, mulmod(mload(0x32a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2540) mstore(0x2540, mulmod(mload(0x3280), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2500) mstore(0x2500, mulmod(mload(0x3260), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x24c0) mstore(0x24c0, mulmod(mload(0x3240), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2480) mstore(0x2480, mulmod(mload(0x3220), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2440) mstore(0x2440, mulmod(mload(0x3200), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2400) mstore(0x2400, mulmod(mload(0x31e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x23c0) mstore(0x23c0, mulmod(mload(0x31c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2380) mstore(0x2380, mulmod(mload(0x31a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2340) mstore(0x2340, mulmod(mload(0x3180), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2300) mstore(0x2300, mulmod(mload(0x3160), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x22c0) mstore(0x22c0, mulmod(mload(0x3140), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2280) mstore(0x2280, mulmod(mload(0x3120), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2240) mstore(0x2240, mulmod(mload(0x3100), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2200) mstore(0x2200, mulmod(mload(0x30e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x21c0) mstore(0x21c0, mulmod(mload(0x30c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2180) mstore(0x2180, mulmod(mload(0x30a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2140) mstore(0x2140, mulmod(mload(0x3080), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2100) mstore(0x2100, mulmod(mload(0x3060), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x20c0) mstore(0x20c0, mulmod(mload(0x3040), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2080) mstore(0x2080, mulmod(mload(0x3020), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2040) mstore(0x2040, mulmod(mload(0x3000), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2000) mstore(0x2000, mulmod(mload(0x2fe0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1fc0) mstore(0x1fc0, mulmod(mload(0x2fc0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1f80) mstore(0x1f80, mulmod(mload(0x2fa0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1f40) mstore(0x1f40, mulmod(mload(0x2f80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1f00) mstore(0x1f00, mulmod(mload(0x2f60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1ec0) mstore(0x1ec0, mulmod(mload(0x2f40), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1e80) mstore(0x1e80, mulmod(mload(0x2f20), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1e40) mstore(0x1e40, mulmod(mload(0x2f00), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1e00) mstore(0x1e00, mulmod(mload(0x2ee0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1dc0) mstore(0x1dc0, mulmod(mload(0x2ec0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1d80) mstore(0x1d80, mulmod(mload(0x2ea0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1d40) mstore(0x1d40, mulmod(mload(0x2e80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1d00) mstore(0x1d00, mulmod(mload(0x2e60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1cc0) mstore(0x1cc0, mulmod(mload(0x2e40), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1c80) mstore(0x1c80, mulmod(mload(0x2e20), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1c40) mstore(0x1c40, mulmod(mload(0x2e00), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1c00) mstore(0x1c00, mulmod(mload(0x2de0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1bc0) mstore(0x1bc0, mulmod(mload(0x2dc0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1b80) mstore(0x1b80, mulmod(mload(0x2da0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1b40) mstore(0x1b40, mulmod(mload(0x2d80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1b00) mstore(0x1b00, mulmod(mload(0x2d60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1ac0) mstore(0x1ac0, mulmod(mload(0x2d40), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1a80) mstore(0x1a80, mulmod(mload(0x2d20), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1a40) mstore(0x1a40, mulmod(mload(0x2d00), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1a00) mstore(0x1a00, mulmod(mload(0x2ce0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x19c0) mstore(0x19c0, mulmod(mload(0x2cc0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1980) mstore(0x1980, mulmod(mload(0x2ca0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1940) mstore(0x1940, mulmod(mload(0x2c80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1900) mstore(0x1900, mulmod(mload(0x2c60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x18c0) mstore(0x18c0, mulmod(mload(0x2c40), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1880) mstore(0x1880, mulmod(mload(0x2c20), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1840) mstore(0x1840, mulmod(mload(0x2c00), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1800) mstore(0x1800, mulmod(mload(0x2be0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x17c0) mstore(0x17c0, mulmod(mload(0x2bc0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1780) mstore(0x1780, mulmod(mload(0x2ba0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1740) mstore(0x1740, mulmod(mload(0x2b80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1700) mstore(0x1700, mulmod(mload(0x2b60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x16c0) mstore(0x16c0, mulmod(mload(0x1680), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x1680, inv) }mstore(0x36c0, mulmod(mload(0x1660), mload(0x1680), f_q))mstore(0x36e0, mulmod(mload(0x16a0), mload(0x16c0), f_q))mstore(0x3700, mulmod(mload(0x16e0), mload(0x1700), f_q))mstore(0x3720, mulmod(mload(0x1720), mload(0x1740), f_q))mstore(0x3740, mulmod(mload(0x1760), mload(0x1780), f_q))mstore(0x3760, mulmod(mload(0x17a0), mload(0x17c0), f_q))mstore(0x3780, mulmod(mload(0x17e0), mload(0x1800), f_q))mstore(0x37a0, mulmod(mload(0x1820), mload(0x1840), f_q))mstore(0x37c0, mulmod(mload(0x1860), mload(0x1880), f_q))mstore(0x37e0, mulmod(mload(0x18a0), mload(0x18c0), f_q))mstore(0x3800, mulmod(mload(0x18e0), mload(0x1900), f_q))mstore(0x3820, mulmod(mload(0x1920), mload(0x1940), f_q))mstore(0x3840, mulmod(mload(0x1960), mload(0x1980), f_q))mstore(0x3860, mulmod(mload(0x19a0), mload(0x19c0), f_q))mstore(0x3880, mulmod(mload(0x19e0), mload(0x1a00), f_q))mstore(0x38a0, mulmod(mload(0x1a20), mload(0x1a40), f_q))mstore(0x38c0, mulmod(mload(0x1a60), mload(0x1a80), f_q))mstore(0x38e0, mulmod(mload(0x1aa0), mload(0x1ac0), f_q))mstore(0x3900, mulmod(mload(0x1ae0), mload(0x1b00), f_q))mstore(0x3920, mulmod(mload(0x1b20), mload(0x1b40), f_q))mstore(0x3940, mulmod(mload(0x1b60), mload(0x1b80), f_q))mstore(0x3960, mulmod(mload(0x1ba0), mload(0x1bc0), f_q))mstore(0x3980, mulmod(mload(0x1be0), mload(0x1c00), f_q))mstore(0x39a0, mulmod(mload(0x1c20), mload(0x1c40), f_q))mstore(0x39c0, mulmod(mload(0x1c60), mload(0x1c80), f_q))mstore(0x39e0, mulmod(mload(0x1ca0), mload(0x1cc0), f_q))mstore(0x3a00, mulmod(mload(0x1ce0), mload(0x1d00), f_q))mstore(0x3a20, mulmod(mload(0x1d20), mload(0x1d40), f_q))mstore(0x3a40, mulmod(mload(0x1d60), mload(0x1d80), f_q))mstore(0x3a60, mulmod(mload(0x1da0), mload(0x1dc0), f_q))mstore(0x3a80, mulmod(mload(0x1de0), mload(0x1e00), f_q))mstore(0x3aa0, mulmod(mload(0x1e20), mload(0x1e40), f_q))mstore(0x3ac0, mulmod(mload(0x1e60), mload(0x1e80), f_q))mstore(0x3ae0, mulmod(mload(0x1ea0), mload(0x1ec0), f_q))mstore(0x3b00, mulmod(mload(0x1ee0), mload(0x1f00), f_q))mstore(0x3b20, mulmod(mload(0x1f20), mload(0x1f40), f_q))mstore(0x3b40, mulmod(mload(0x1f60), mload(0x1f80), f_q))mstore(0x3b60, mulmod(mload(0x1fa0), mload(0x1fc0), f_q))mstore(0x3b80, mulmod(mload(0x1fe0), mload(0x2000), f_q))mstore(0x3ba0, mulmod(mload(0x2020), mload(0x2040), f_q))mstore(0x3bc0, mulmod(mload(0x2060), mload(0x2080), f_q))mstore(0x3be0, mulmod(mload(0x20a0), mload(0x20c0), f_q))mstore(0x3c00, mulmod(mload(0x20e0), mload(0x2100), f_q))mstore(0x3c20, mulmod(mload(0x2120), mload(0x2140), f_q))mstore(0x3c40, mulmod(mload(0x2160), mload(0x2180), f_q))mstore(0x3c60, mulmod(mload(0x21a0), mload(0x21c0), f_q))mstore(0x3c80, mulmod(mload(0x21e0), mload(0x2200), f_q))mstore(0x3ca0, mulmod(mload(0x2220), mload(0x2240), f_q))mstore(0x3cc0, mulmod(mload(0x2260), mload(0x2280), f_q))mstore(0x3ce0, mulmod(mload(0x22a0), mload(0x22c0), f_q))mstore(0x3d00, mulmod(mload(0x22e0), mload(0x2300), f_q))mstore(0x3d20, mulmod(mload(0x2320), mload(0x2340), f_q))mstore(0x3d40, mulmod(mload(0x2360), mload(0x2380), f_q))mstore(0x3d60, mulmod(mload(0x23a0), mload(0x23c0), f_q))mstore(0x3d80, mulmod(mload(0x23e0), mload(0x2400), f_q))mstore(0x3da0, mulmod(mload(0x2420), mload(0x2440), f_q))mstore(0x3dc0, mulmod(mload(0x2460), mload(0x2480), f_q))mstore(0x3de0, mulmod(mload(0x24a0), mload(0x24c0), f_q))mstore(0x3e00, mulmod(mload(0x24e0), mload(0x2500), f_q))mstore(0x3e20, mulmod(mload(0x2520), mload(0x2540), f_q))mstore(0x3e40, mulmod(mload(0x2560), mload(0x2580), f_q))mstore(0x3e60, mulmod(mload(0x25a0), mload(0x25c0), f_q))mstore(0x3e80, mulmod(mload(0x25e0), mload(0x2600), f_q))mstore(0x3ea0, mulmod(mload(0x2620), mload(0x2640), f_q))mstore(0x3ec0, mulmod(mload(0x2660), mload(0x2680), f_q))mstore(0x3ee0, mulmod(mload(0x26a0), mload(0x26c0), f_q))mstore(0x3f00, mulmod(mload(0x26e0), mload(0x2700), f_q))mstore(0x3f20, mulmod(mload(0x2720), mload(0x2740), f_q))mstore(0x3f40, mulmod(mload(0x2760), mload(0x2780), f_q))mstore(0x3f60, mulmod(mload(0x27a0), mload(0x27c0), f_q))mstore(0x3f80, mulmod(mload(0x27e0), mload(0x2800), f_q))mstore(0x3fa0, mulmod(mload(0x2820), mload(0x2840), f_q))mstore(0x3fc0, mulmod(mload(0x2860), mload(0x2880), f_q))mstore(0x3fe0, mulmod(mload(0x28a0), mload(0x28c0), f_q))mstore(0x4000, mulmod(mload(0x28e0), mload(0x2900), f_q))mstore(0x4020, mulmod(mload(0x2920), mload(0x2940), f_q))mstore(0x4040, mulmod(mload(0x2960), mload(0x2980), f_q))mstore(0x4060, mulmod(mload(0x29a0), mload(0x29c0), f_q))mstore(0x4080, mulmod(mload(0x29e0), mload(0x2a00), f_q))mstore(0x40a0, mulmod(mload(0x2a20), mload(0x2a40), f_q))mstore(0x40c0, mulmod(mload(0x2a60), mload(0x2a80), f_q))mstore(0x40e0, mulmod(mload(0x2aa0), mload(0x2ac0), f_q))mstore(0x4100, mulmod(mload(0x2ae0), mload(0x2b00), f_q))mstore(0x4120, mulmod(mload(0x2b20), mload(0x2b40), f_q)){ let result := mulmod(mload(0x37a0), mload(0xa0), f_q)result := addmod(mulmod(mload(0x37c0), mload(0xc0), f_q), result, f_q)result := addmod(mulmod(mload(0x37e0), mload(0xe0), f_q), result, f_q)result := addmod(mulmod(mload(0x3800), mload(0x100), f_q), result, f_q)result := addmod(mulmod(mload(0x3820), mload(0x120), f_q), result, f_q)result := addmod(mulmod(mload(0x3840), mload(0x140), f_q), result, f_q)result := addmod(mulmod(mload(0x3860), mload(0x160), f_q), result, f_q)result := addmod(mulmod(mload(0x3880), mload(0x180), f_q), result, f_q)result := addmod(mulmod(mload(0x38a0), mload(0x1a0), f_q), result, f_q)result := addmod(mulmod(mload(0x38c0), mload(0x1c0), f_q), result, f_q)result := addmod(mulmod(mload(0x38e0), mload(0x1e0), f_q), result, f_q)result := addmod(mulmod(mload(0x3900), mload(0x200), f_q), result, f_q)result := addmod(mulmod(mload(0x3920), mload(0x220), f_q), result, f_q)result := addmod(mulmod(mload(0x3940), mload(0x240), f_q), result, f_q)result := addmod(mulmod(mload(0x3960), mload(0x260), f_q), result, f_q)result := addmod(mulmod(mload(0x3980), mload(0x280), f_q), result, f_q)result := addmod(mulmod(mload(0x39a0), mload(0x2a0), f_q), result, f_q)result := addmod(mulmod(mload(0x39c0), mload(0x2c0), f_q), result, f_q)result := addmod(mulmod(mload(0x39e0), mload(0x2e0), f_q), result, f_q)result := addmod(mulmod(mload(0x3a00), mload(0x300), f_q), result, f_q)result := addmod(mulmod(mload(0x3a20), mload(0x320), f_q), result, f_q)result := addmod(mulmod(mload(0x3a40), mload(0x340), f_q), result, f_q)result := addmod(mulmod(mload(0x3a60), mload(0x360), f_q), result, f_q)result := addmod(mulmod(mload(0x3a80), mload(0x380), f_q), result, f_q)result := addmod(mulmod(mload(0x3aa0), mload(0x3a0), f_q), result, f_q)result := addmod(mulmod(mload(0x3ac0), mload(0x3c0), f_q), result, f_q)result := addmod(mulmod(mload(0x3ae0), mload(0x3e0), f_q), result, f_q)result := addmod(mulmod(mload(0x3b00), mload(0x400), f_q), result, f_q)result := addmod(mulmod(mload(0x3b20), mload(0x420), f_q), result, f_q)result := addmod(mulmod(mload(0x3b40), mload(0x440), f_q), result, f_q)result := addmod(mulmod(mload(0x3b60), mload(0x460), f_q), result, f_q)result := addmod(mulmod(mload(0x3b80), mload(0x480), f_q), result, f_q)result := addmod(mulmod(mload(0x3ba0), mload(0x4a0), f_q), result, f_q)result := addmod(mulmod(mload(0x3bc0), mload(0x4c0), f_q), result, f_q)result := addmod(mulmod(mload(0x3be0), mload(0x4e0), f_q), result, f_q)result := addmod(mulmod(mload(0x3c00), mload(0x500), f_q), result, f_q)result := addmod(mulmod(mload(0x3c20), mload(0x520), f_q), result, f_q)result := addmod(mulmod(mload(0x3c40), mload(0x540), f_q), result, f_q)result := addmod(mulmod(mload(0x3c60), mload(0x560), f_q), result, f_q)result := addmod(mulmod(mload(0x3c80), mload(0x580), f_q), result, f_q)result := addmod(mulmod(mload(0x3ca0), mload(0x5a0), f_q), result, f_q)result := addmod(mulmod(mload(0x3cc0), mload(0x5c0), f_q), result, f_q)result := addmod(mulmod(mload(0x3ce0), mload(0x5e0), f_q), result, f_q)result := addmod(mulmod(mload(0x3d00), mload(0x600), f_q), result, f_q)result := addmod(mulmod(mload(0x3d20), mload(0x620), f_q), result, f_q)result := addmod(mulmod(mload(0x3d40), mload(0x640), f_q), result, f_q)result := addmod(mulmod(mload(0x3d60), mload(0x660), f_q), result, f_q)result := addmod(mulmod(mload(0x3d80), mload(0x680), f_q), result, f_q)result := addmod(mulmod(mload(0x3da0), mload(0x6a0), f_q), result, f_q)result := addmod(mulmod(mload(0x3dc0), mload(0x6c0), f_q), result, f_q)result := addmod(mulmod(mload(0x3de0), mload(0x6e0), f_q), result, f_q)result := addmod(mulmod(mload(0x3e00), mload(0x700), f_q), result, f_q)result := addmod(mulmod(mload(0x3e20), mload(0x720), f_q), result, f_q)result := addmod(mulmod(mload(0x3e40), mload(0x740), f_q), result, f_q)result := addmod(mulmod(mload(0x3e60), mload(0x760), f_q), result, f_q)result := addmod(mulmod(mload(0x3e80), mload(0x780), f_q), result, f_q)result := addmod(mulmod(mload(0x3ea0), mload(0x7a0), f_q), result, f_q)result := addmod(mulmod(mload(0x3ec0), mload(0x7c0), f_q), result, f_q)result := addmod(mulmod(mload(0x3ee0), mload(0x7e0), f_q), result, f_q)result := addmod(mulmod(mload(0x3f00), mload(0x800), f_q), result, f_q)result := addmod(mulmod(mload(0x3f20), mload(0x820), f_q), result, f_q)result := addmod(mulmod(mload(0x3f40), mload(0x840), f_q), result, f_q)result := addmod(mulmod(mload(0x3f60), mload(0x860), f_q), result, f_q)result := addmod(mulmod(mload(0x3f80), mload(0x880), f_q), result, f_q)result := addmod(mulmod(mload(0x3fa0), mload(0x8a0), f_q), result, f_q)result := addmod(mulmod(mload(0x3fc0), mload(0x8c0), f_q), result, f_q)result := addmod(mulmod(mload(0x3fe0), mload(0x8e0), f_q), result, f_q)result := addmod(mulmod(mload(0x4000), mload(0x900), f_q), result, f_q)result := addmod(mulmod(mload(0x4020), mload(0x920), f_q), result, f_q)result := addmod(mulmod(mload(0x4040), mload(0x940), f_q), result, f_q)result := addmod(mulmod(mload(0x4060), mload(0x960), f_q), result, f_q)result := addmod(mulmod(mload(0x4080), mload(0x980), f_q), result, f_q)result := addmod(mulmod(mload(0x40a0), mload(0x9a0), f_q), result, f_q)result := addmod(mulmod(mload(0x40c0), mload(0x9c0), f_q), result, f_q)result := addmod(mulmod(mload(0x40e0), mload(0x9e0), f_q), result, f_q)result := addmod(mulmod(mload(0x4100), mload(0xa00), f_q), result, f_q)result := addmod(mulmod(mload(0x4120), mload(0xa20), f_q), result, f_q)mstore(0x4140, result) }mstore(0x4160, mulmod(mload(0xee0), mload(0xec0), f_q))mstore(0x4180, addmod(mload(0xea0), mload(0x4160), f_q))mstore(0x41a0, addmod(mload(0x4180), sub(f_q, mload(0xf00)), f_q))mstore(0x41c0, mulmod(mload(0x41a0), mload(0xf80), f_q))mstore(0x41e0, mulmod(mload(0xd00), mload(0x41c0), f_q))mstore(0x4200, addmod(1, sub(f_q, mload(0x1020)), f_q))mstore(0x4220, mulmod(mload(0x4200), mload(0x37a0), f_q))mstore(0x4240, addmod(mload(0x41e0), mload(0x4220), f_q))mstore(0x4260, mulmod(mload(0xd00), mload(0x4240), f_q))mstore(0x4280, mulmod(mload(0x1020), mload(0x1020), f_q))mstore(0x42a0, addmod(mload(0x4280), sub(f_q, mload(0x1020)), f_q))mstore(0x42c0, mulmod(mload(0x42a0), mload(0x36c0), f_q))mstore(0x42e0, addmod(mload(0x4260), mload(0x42c0), f_q))mstore(0x4300, mulmod(mload(0xd00), mload(0x42e0), f_q))mstore(0x4320, addmod(1, sub(f_q, mload(0x36c0)), f_q))mstore(0x4340, addmod(mload(0x36e0), mload(0x3700), f_q))mstore(0x4360, addmod(mload(0x4340), mload(0x3720), f_q))mstore(0x4380, addmod(mload(0x4360), mload(0x3740), f_q))mstore(0x43a0, addmod(mload(0x4380), mload(0x3760), f_q))mstore(0x43c0, addmod(mload(0x43a0), mload(0x3780), f_q))mstore(0x43e0, addmod(mload(0x4320), sub(f_q, mload(0x43c0)), f_q))mstore(0x4400, mulmod(mload(0xfc0), mload(0xb80), f_q))mstore(0x4420, addmod(mload(0xf20), mload(0x4400), f_q))mstore(0x4440, addmod(mload(0x4420), mload(0xbe0), f_q))mstore(0x4460, mulmod(mload(0xfe0), mload(0xb80), f_q))mstore(0x4480, addmod(mload(0xea0), mload(0x4460), f_q))mstore(0x44a0, addmod(mload(0x4480), mload(0xbe0), f_q))mstore(0x44c0, mulmod(mload(0x44a0), mload(0x4440), f_q))mstore(0x44e0, mulmod(mload(0x1000), mload(0xb80), f_q))mstore(0x4500, addmod(mload(0x4140), mload(0x44e0), f_q))mstore(0x4520, addmod(mload(0x4500), mload(0xbe0), f_q))mstore(0x4540, mulmod(mload(0x4520), mload(0x44c0), f_q))mstore(0x4560, mulmod(mload(0x4540), mload(0x1040), f_q))mstore(0x4580, mulmod(1, mload(0xb80), f_q))mstore(0x45a0, mulmod(mload(0xe60), mload(0x4580), f_q))mstore(0x45c0, addmod(mload(0xf20), mload(0x45a0), f_q))mstore(0x45e0, addmod(mload(0x45c0), mload(0xbe0), f_q))mstore(0x4600, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0xb80), f_q))mstore(0x4620, mulmod(mload(0xe60), mload(0x4600), f_q))mstore(0x4640, addmod(mload(0xea0), mload(0x4620), f_q))mstore(0x4660, addmod(mload(0x4640), mload(0xbe0), f_q))mstore(0x4680, mulmod(mload(0x4660), mload(0x45e0), f_q))mstore(0x46a0, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0xb80), f_q))mstore(0x46c0, mulmod(mload(0xe60), mload(0x46a0), f_q))mstore(0x46e0, addmod(mload(0x4140), mload(0x46c0), f_q))mstore(0x4700, addmod(mload(0x46e0), mload(0xbe0), f_q))mstore(0x4720, mulmod(mload(0x4700), mload(0x4680), f_q))mstore(0x4740, mulmod(mload(0x4720), mload(0x1020), f_q))mstore(0x4760, addmod(mload(0x4560), sub(f_q, mload(0x4740)), f_q))mstore(0x4780, mulmod(mload(0x4760), mload(0x43e0), f_q))mstore(0x47a0, addmod(mload(0x4300), mload(0x4780), f_q))mstore(0x47c0, mulmod(mload(0xd00), mload(0x47a0), f_q))mstore(0x47e0, addmod(1, sub(f_q, mload(0x1060)), f_q))mstore(0x4800, mulmod(mload(0x47e0), mload(0x37a0), f_q))mstore(0x4820, addmod(mload(0x47c0), mload(0x4800), f_q))mstore(0x4840, mulmod(mload(0xd00), mload(0x4820), f_q))mstore(0x4860, mulmod(mload(0x1060), mload(0x1060), f_q))mstore(0x4880, addmod(mload(0x4860), sub(f_q, mload(0x1060)), f_q))mstore(0x48a0, mulmod(mload(0x4880), mload(0x36c0), f_q))mstore(0x48c0, addmod(mload(0x4840), mload(0x48a0), f_q))mstore(0x48e0, mulmod(mload(0xd00), mload(0x48c0), f_q))mstore(0x4900, addmod(mload(0x10a0), mload(0xb80), f_q))mstore(0x4920, mulmod(mload(0x4900), mload(0x1080), f_q))mstore(0x4940, addmod(mload(0x10e0), mload(0xbe0), f_q))mstore(0x4960, mulmod(mload(0x4940), mload(0x4920), f_q))mstore(0x4980, mulmod(mload(0xea0), mload(0xf60), f_q))mstore(0x49a0, addmod(mload(0x4980), mload(0xb80), f_q))mstore(0x49c0, mulmod(mload(0x49a0), mload(0x1060), f_q))mstore(0x49e0, addmod(mload(0xf40), mload(0xbe0), f_q))mstore(0x4a00, mulmod(mload(0x49e0), mload(0x49c0), f_q))mstore(0x4a20, addmod(mload(0x4960), sub(f_q, mload(0x4a00)), f_q))mstore(0x4a40, mulmod(mload(0x4a20), mload(0x43e0), f_q))mstore(0x4a60, addmod(mload(0x48e0), mload(0x4a40), f_q))mstore(0x4a80, mulmod(mload(0xd00), mload(0x4a60), f_q))mstore(0x4aa0, addmod(mload(0x10a0), sub(f_q, mload(0x10e0)), f_q))mstore(0x4ac0, mulmod(mload(0x4aa0), mload(0x37a0), f_q))mstore(0x4ae0, addmod(mload(0x4a80), mload(0x4ac0), f_q))mstore(0x4b00, mulmod(mload(0xd00), mload(0x4ae0), f_q))mstore(0x4b20, mulmod(mload(0x4aa0), mload(0x43e0), f_q))mstore(0x4b40, addmod(mload(0x10a0), sub(f_q, mload(0x10c0)), f_q))mstore(0x4b60, mulmod(mload(0x4b40), mload(0x4b20), f_q))mstore(0x4b80, addmod(mload(0x4b00), mload(0x4b60), f_q))mstore(0x4ba0, mulmod(mload(0x1600), mload(0x1600), f_q))mstore(0x4bc0, mulmod(mload(0x4ba0), mload(0x1600), f_q))mstore(0x4be0, mulmod(mload(0x4bc0), mload(0x1600), f_q))mstore(0x4c00, mulmod(1, mload(0x1600), f_q))mstore(0x4c20, mulmod(1, mload(0x4ba0), f_q))mstore(0x4c40, mulmod(1, mload(0x4bc0), f_q))mstore(0x4c60, mulmod(mload(0x4b80), mload(0x1620), f_q))mstore(0x4c80, mulmod(mload(0x1320), mload(0xe60), f_q))mstore(0x4ca0, mulmod(mload(0x4c80), mload(0xe60), f_q))mstore(0x4cc0, mulmod(mload(0xe60), 17329448237240114492580865744088056414251735686965494637158808787419781175510, f_q))mstore(0x4ce0, addmod(mload(0x1220), sub(f_q, mload(0x4cc0)), f_q))mstore(0x4d00, mulmod(mload(0xe60), 1, f_q))mstore(0x4d20, addmod(mload(0x1220), sub(f_q, mload(0x4d00)), f_q))mstore(0x4d40, mulmod(mload(0xe60), 11451405578697956743456240853980216273390554734748796433026540431386972584651, f_q))mstore(0x4d60, addmod(mload(0x1220), sub(f_q, mload(0x4d40)), f_q))mstore(0x4d80, mulmod(mload(0xe60), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q))mstore(0x4da0, addmod(mload(0x1220), sub(f_q, mload(0x4d80)), f_q))mstore(0x4dc0, mulmod(mload(0xe60), 21490807004895109926141140246143262403290679459142140821740925192625185504522, f_q))mstore(0x4de0, addmod(mload(0x1220), sub(f_q, mload(0x4dc0)), f_q))mstore(0x4e00, mulmod(6616149745577394522356295102346368305374051634342887004165528916468992151333, mload(0x4c80), f_q))mstore(0x4e20, mulmod(mload(0x4e00), 1, f_q)){ let result := mulmod(mload(0x1220), mload(0x4e00), f_q)result := addmod(mulmod(mload(0xe60), sub(f_q, mload(0x4e20)), f_q), result, f_q)mstore(0x4e40, result) }mstore(0x4e60, mulmod(530501691302793820034524283154921640443166880847115433758691660016816186416, mload(0x4c80), f_q))mstore(0x4e80, mulmod(mload(0x4e60), 11451405578697956743456240853980216273390554734748796433026540431386972584651, f_q)){ let result := mulmod(mload(0x1220), mload(0x4e60), f_q)result := addmod(mulmod(mload(0xe60), sub(f_q, mload(0x4e80)), f_q), result, f_q)mstore(0x4ea0, result) }mstore(0x4ec0, mulmod(6735468303947967792722299167169712601265763928443086612877978228369959138708, mload(0x4c80), f_q))mstore(0x4ee0, mulmod(mload(0x4ec0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)){ let result := mulmod(mload(0x1220), mload(0x4ec0), f_q)result := addmod(mulmod(mload(0xe60), sub(f_q, mload(0x4ee0)), f_q), result, f_q)mstore(0x4f00, result) }mstore(0x4f20, mulmod(21558793644302942916864965630979640748886316167261336210841195936026980690666, mload(0x4c80), f_q))mstore(0x4f40, mulmod(mload(0x4f20), 21490807004895109926141140246143262403290679459142140821740925192625185504522, f_q)){ let result := mulmod(mload(0x1220), mload(0x4f20), f_q)result := addmod(mulmod(mload(0xe60), sub(f_q, mload(0x4f40)), f_q), result, f_q)mstore(0x4f60, result) }mstore(0x4f80, mulmod(1, mload(0x4d20), f_q))mstore(0x4fa0, mulmod(mload(0x4f80), mload(0x4d60), f_q))mstore(0x4fc0, mulmod(mload(0x4fa0), mload(0x4da0), f_q))mstore(0x4fe0, mulmod(mload(0x4fc0), mload(0x4de0), f_q))mstore(0x5000, mulmod(10436837293141318478790164891277058815157809665667237910671663755188835910967, mload(0xe60), f_q))mstore(0x5020, mulmod(mload(0x5000), 1, f_q)){ let result := mulmod(mload(0x1220), mload(0x5000), f_q)result := addmod(mulmod(mload(0xe60), sub(f_q, mload(0x5020)), f_q), result, f_q)mstore(0x5040, result) }mstore(0x5060, mulmod(11451405578697956743456240853980216273390554734748796433026540431386972584650, mload(0xe60), f_q))mstore(0x5080, mulmod(mload(0x5060), 11451405578697956743456240853980216273390554734748796433026540431386972584651, f_q)){ let result := mulmod(mload(0x1220), mload(0x5060), f_q)result := addmod(mulmod(mload(0xe60), sub(f_q, mload(0x5080)), f_q), result, f_q)mstore(0x50a0, result) }mstore(0x50c0, mulmod(4558794634599160729665540001169218674296628713450539706539395399156027320108, mload(0xe60), f_q))mstore(0x50e0, mulmod(mload(0x50c0), 1, f_q)){ let result := mulmod(mload(0x1220), mload(0x50c0), f_q)result := addmod(mulmod(mload(0xe60), sub(f_q, mload(0x50e0)), f_q), result, f_q)mstore(0x5100, result) }mstore(0x5120, mulmod(17329448237240114492580865744088056414251735686965494637158808787419781175509, mload(0xe60), f_q))mstore(0x5140, mulmod(mload(0x5120), 17329448237240114492580865744088056414251735686965494637158808787419781175510, f_q)){ let result := mulmod(mload(0x1220), mload(0x5120), f_q)result := addmod(mulmod(mload(0xe60), sub(f_q, mload(0x5140)), f_q), result, f_q)mstore(0x5160, result) }mstore(0x5180, mulmod(mload(0x4f80), mload(0x4ce0), f_q)){ let result := mulmod(mload(0x1220), 1, f_q)result := addmod(mulmod(mload(0xe60), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q)mstore(0x51a0, result) }{ let prod := mload(0x4e40) prod := mulmod(mload(0x4ea0), prod, f_q) mstore(0x51c0, prod) prod := mulmod(mload(0x4f00), prod, f_q) mstore(0x51e0, prod) prod := mulmod(mload(0x4f60), prod, f_q) mstore(0x5200, prod) prod := mulmod(mload(0x5040), prod, f_q) mstore(0x5220, prod) prod := mulmod(mload(0x50a0), prod, f_q) mstore(0x5240, prod) prod := mulmod(mload(0x4fa0), prod, f_q) mstore(0x5260, prod) prod := mulmod(mload(0x5100), prod, f_q) mstore(0x5280, prod) prod := mulmod(mload(0x5160), prod, f_q) mstore(0x52a0, prod) prod := mulmod(mload(0x5180), prod, f_q) mstore(0x52c0, prod) prod := mulmod(mload(0x51a0), prod, f_q) mstore(0x52e0, prod) prod := mulmod(mload(0x4f80), prod, f_q) mstore(0x5300, prod) }mstore(0x5340, 32)mstore(0x5360, 32)mstore(0x5380, 32)mstore(0x53a0, mload(0x5300))mstore(0x53c0, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x53e0, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x5340, 0xc0, 0x5320, 0x20), 1), success){ let inv := mload(0x5320) let v v := mload(0x4f80) mstore(0x4f80, mulmod(mload(0x52e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x51a0) mstore(0x51a0, mulmod(mload(0x52c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x5180) mstore(0x5180, mulmod(mload(0x52a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x5160) mstore(0x5160, mulmod(mload(0x5280), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x5100) mstore(0x5100, mulmod(mload(0x5260), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x4fa0) mstore(0x4fa0, mulmod(mload(0x5240), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x50a0) mstore(0x50a0, mulmod(mload(0x5220), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x5040) mstore(0x5040, mulmod(mload(0x5200), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x4f60) mstore(0x4f60, mulmod(mload(0x51e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x4f00) mstore(0x4f00, mulmod(mload(0x51c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x4ea0) mstore(0x4ea0, mulmod(mload(0x4e40), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x4e40, inv) }{ let result := mload(0x4e40)result := addmod(mload(0x4ea0), result, f_q)result := addmod(mload(0x4f00), result, f_q)result := addmod(mload(0x4f60), result, f_q)mstore(0x5400, result) }mstore(0x5420, mulmod(mload(0x4fe0), mload(0x4fa0), f_q)){ let result := mload(0x5040)result := addmod(mload(0x50a0), result, f_q)mstore(0x5440, result) }mstore(0x5460, mulmod(mload(0x4fe0), mload(0x5180), f_q)){ let result := mload(0x5100)result := addmod(mload(0x5160), result, f_q)mstore(0x5480, result) }mstore(0x54a0, mulmod(mload(0x4fe0), mload(0x4f80), f_q)){ let result := mload(0x51a0)mstore(0x54c0, result) }{ let prod := mload(0x5400) prod := mulmod(mload(0x5440), prod, f_q) mstore(0x54e0, prod) prod := mulmod(mload(0x5480), prod, f_q) mstore(0x5500, prod) prod := mulmod(mload(0x54c0), prod, f_q) mstore(0x5520, prod) }mstore(0x5560, 32)mstore(0x5580, 32)mstore(0x55a0, 32)mstore(0x55c0, mload(0x5520))mstore(0x55e0, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x5600, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x5560, 0xc0, 0x5540, 0x20), 1), success){ let inv := mload(0x5540) let v v := mload(0x54c0) mstore(0x54c0, mulmod(mload(0x5500), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x5480) mstore(0x5480, mulmod(mload(0x54e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x5440) mstore(0x5440, mulmod(mload(0x5400), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x5400, inv) }mstore(0x5620, mulmod(mload(0x5420), mload(0x5440), f_q))mstore(0x5640, mulmod(mload(0x5460), mload(0x5480), f_q))mstore(0x5660, mulmod(mload(0x54a0), mload(0x54c0), f_q))mstore(0x5680, mulmod(mload(0x1120), mload(0x1120), f_q))mstore(0x56a0, mulmod(mload(0x5680), mload(0x1120), f_q))mstore(0x56c0, mulmod(mload(0x56a0), mload(0x1120), f_q))mstore(0x56e0, mulmod(mload(0x56c0), mload(0x1120), f_q))mstore(0x5700, mulmod(mload(0x56e0), mload(0x1120), f_q))mstore(0x5720, mulmod(mload(0x5700), mload(0x1120), f_q))mstore(0x5740, mulmod(mload(0x5720), mload(0x1120), f_q))mstore(0x5760, mulmod(mload(0x5740), mload(0x1120), f_q))mstore(0x5780, mulmod(mload(0x5760), mload(0x1120), f_q))mstore(0x57a0, mulmod(mload(0x1180), mload(0x1180), f_q))mstore(0x57c0, mulmod(mload(0x57a0), mload(0x1180), f_q))mstore(0x57e0, mulmod(mload(0x57c0), mload(0x1180), f_q)){ let result := mulmod(mload(0xea0), mload(0x4e40), f_q)result := addmod(mulmod(mload(0xec0), mload(0x4ea0), f_q), result, f_q)result := addmod(mulmod(mload(0xee0), mload(0x4f00), f_q), result, f_q)result := addmod(mulmod(mload(0xf00), mload(0x4f60), f_q), result, f_q)mstore(0x5800, result) }mstore(0x5820, mulmod(mload(0x5800), mload(0x5400), f_q))mstore(0x5840, mulmod(sub(f_q, mload(0x5820)), 1, f_q))mstore(0x5860, mulmod(mload(0x5840), 1, f_q))mstore(0x5880, mulmod(1, mload(0x5420), f_q)){ let result := mulmod(mload(0x1020), mload(0x5040), f_q)result := addmod(mulmod(mload(0x1040), mload(0x50a0), f_q), result, f_q)mstore(0x58a0, result) }mstore(0x58c0, mulmod(mload(0x58a0), mload(0x5620), f_q))mstore(0x58e0, mulmod(sub(f_q, mload(0x58c0)), 1, f_q))mstore(0x5900, mulmod(mload(0x5880), 1, f_q)){ let result := mulmod(mload(0x1060), mload(0x5040), f_q)result := addmod(mulmod(mload(0x1080), mload(0x50a0), f_q), result, f_q)mstore(0x5920, result) }mstore(0x5940, mulmod(mload(0x5920), mload(0x5620), f_q))mstore(0x5960, mulmod(sub(f_q, mload(0x5940)), mload(0x1120), f_q))mstore(0x5980, mulmod(mload(0x5880), mload(0x1120), f_q))mstore(0x59a0, addmod(mload(0x58e0), mload(0x5960), f_q))mstore(0x59c0, mulmod(mload(0x59a0), mload(0x1180), f_q))mstore(0x59e0, mulmod(mload(0x5900), mload(0x1180), f_q))mstore(0x5a00, mulmod(mload(0x5980), mload(0x1180), f_q))mstore(0x5a20, addmod(mload(0x5860), mload(0x59c0), f_q))mstore(0x5a40, mulmod(1, mload(0x5460), f_q)){ let result := mulmod(mload(0x10a0), mload(0x5100), f_q)result := addmod(mulmod(mload(0x10c0), mload(0x5160), f_q), result, f_q)mstore(0x5a60, result) }mstore(0x5a80, mulmod(mload(0x5a60), mload(0x5640), f_q))mstore(0x5aa0, mulmod(sub(f_q, mload(0x5a80)), 1, f_q))mstore(0x5ac0, mulmod(mload(0x5a40), 1, f_q))mstore(0x5ae0, mulmod(mload(0x5aa0), mload(0x57a0), f_q))mstore(0x5b00, mulmod(mload(0x5ac0), mload(0x57a0), f_q))mstore(0x5b20, addmod(mload(0x5a20), mload(0x5ae0), f_q))mstore(0x5b40, mulmod(1, mload(0x54a0), f_q)){ let result := mulmod(mload(0x10e0), mload(0x51a0), f_q)mstore(0x5b60, result) }mstore(0x5b80, mulmod(mload(0x5b60), mload(0x5660), f_q))mstore(0x5ba0, mulmod(sub(f_q, mload(0x5b80)), 1, f_q))mstore(0x5bc0, mulmod(mload(0x5b40), 1, f_q)){ let result := mulmod(mload(0xf20), mload(0x51a0), f_q)mstore(0x5be0, result) }mstore(0x5c00, mulmod(mload(0x5be0), mload(0x5660), f_q))mstore(0x5c20, mulmod(sub(f_q, mload(0x5c00)), mload(0x1120), f_q))mstore(0x5c40, mulmod(mload(0x5b40), mload(0x1120), f_q))mstore(0x5c60, addmod(mload(0x5ba0), mload(0x5c20), f_q)){ let result := mulmod(mload(0xf40), mload(0x51a0), f_q)mstore(0x5c80, result) }mstore(0x5ca0, mulmod(mload(0x5c80), mload(0x5660), f_q))mstore(0x5cc0, mulmod(sub(f_q, mload(0x5ca0)), mload(0x5680), f_q))mstore(0x5ce0, mulmod(mload(0x5b40), mload(0x5680), f_q))mstore(0x5d00, addmod(mload(0x5c60), mload(0x5cc0), f_q)){ let result := mulmod(mload(0xf60), mload(0x51a0), f_q)mstore(0x5d20, result) }mstore(0x5d40, mulmod(mload(0x5d20), mload(0x5660), f_q))mstore(0x5d60, mulmod(sub(f_q, mload(0x5d40)), mload(0x56a0), f_q))mstore(0x5d80, mulmod(mload(0x5b40), mload(0x56a0), f_q))mstore(0x5da0, addmod(mload(0x5d00), mload(0x5d60), f_q)){ let result := mulmod(mload(0xf80), mload(0x51a0), f_q)mstore(0x5dc0, result) }mstore(0x5de0, mulmod(mload(0x5dc0), mload(0x5660), f_q))mstore(0x5e00, mulmod(sub(f_q, mload(0x5de0)), mload(0x56c0), f_q))mstore(0x5e20, mulmod(mload(0x5b40), mload(0x56c0), f_q))mstore(0x5e40, addmod(mload(0x5da0), mload(0x5e00), f_q)){ let result := mulmod(mload(0xfc0), mload(0x51a0), f_q)mstore(0x5e60, result) }mstore(0x5e80, mulmod(mload(0x5e60), mload(0x5660), f_q))mstore(0x5ea0, mulmod(sub(f_q, mload(0x5e80)), mload(0x56e0), f_q))mstore(0x5ec0, mulmod(mload(0x5b40), mload(0x56e0), f_q))mstore(0x5ee0, addmod(mload(0x5e40), mload(0x5ea0), f_q)){ let result := mulmod(mload(0xfe0), mload(0x51a0), f_q)mstore(0x5f00, result) }mstore(0x5f20, mulmod(mload(0x5f00), mload(0x5660), f_q))mstore(0x5f40, mulmod(sub(f_q, mload(0x5f20)), mload(0x5700), f_q))mstore(0x5f60, mulmod(mload(0x5b40), mload(0x5700), f_q))mstore(0x5f80, addmod(mload(0x5ee0), mload(0x5f40), f_q)){ let result := mulmod(mload(0x1000), mload(0x51a0), f_q)mstore(0x5fa0, result) }mstore(0x5fc0, mulmod(mload(0x5fa0), mload(0x5660), f_q))mstore(0x5fe0, mulmod(sub(f_q, mload(0x5fc0)), mload(0x5720), f_q))mstore(0x6000, mulmod(mload(0x5b40), mload(0x5720), f_q))mstore(0x6020, addmod(mload(0x5f80), mload(0x5fe0), f_q))mstore(0x6040, mulmod(mload(0x4c00), mload(0x54a0), f_q))mstore(0x6060, mulmod(mload(0x4c20), mload(0x54a0), f_q))mstore(0x6080, mulmod(mload(0x4c40), mload(0x54a0), f_q)){ let result := mulmod(mload(0x4c60), mload(0x51a0), f_q)mstore(0x60a0, result) }mstore(0x60c0, mulmod(mload(0x60a0), mload(0x5660), f_q))mstore(0x60e0, mulmod(sub(f_q, mload(0x60c0)), mload(0x5740), f_q))mstore(0x6100, mulmod(mload(0x5b40), mload(0x5740), f_q))mstore(0x6120, mulmod(mload(0x6040), mload(0x5740), f_q))mstore(0x6140, mulmod(mload(0x6060), mload(0x5740), f_q))mstore(0x6160, mulmod(mload(0x6080), mload(0x5740), f_q))mstore(0x6180, addmod(mload(0x6020), mload(0x60e0), f_q)){ let result := mulmod(mload(0xfa0), mload(0x51a0), f_q)mstore(0x61a0, result) }mstore(0x61c0, mulmod(mload(0x61a0), mload(0x5660), f_q))mstore(0x61e0, mulmod(sub(f_q, mload(0x61c0)), mload(0x5760), f_q))mstore(0x6200, mulmod(mload(0x5b40), mload(0x5760), f_q))mstore(0x6220, addmod(mload(0x6180), mload(0x61e0), f_q))mstore(0x6240, mulmod(mload(0x6220), mload(0x57c0), f_q))mstore(0x6260, mulmod(mload(0x5bc0), mload(0x57c0), f_q))mstore(0x6280, mulmod(mload(0x5c40), mload(0x57c0), f_q))mstore(0x62a0, mulmod(mload(0x5ce0), mload(0x57c0), f_q))mstore(0x62c0, mulmod(mload(0x5d80), mload(0x57c0), f_q))mstore(0x62e0, mulmod(mload(0x5e20), mload(0x57c0), f_q))mstore(0x6300, mulmod(mload(0x5ec0), mload(0x57c0), f_q))mstore(0x6320, mulmod(mload(0x5f60), mload(0x57c0), f_q))mstore(0x6340, mulmod(mload(0x6000), mload(0x57c0), f_q))mstore(0x6360, mulmod(mload(0x6100), mload(0x57c0), f_q))mstore(0x6380, mulmod(mload(0x6120), mload(0x57c0), f_q))mstore(0x63a0, mulmod(mload(0x6140), mload(0x57c0), f_q))mstore(0x63c0, mulmod(mload(0x6160), mload(0x57c0), f_q))mstore(0x63e0, mulmod(mload(0x6200), mload(0x57c0), f_q))mstore(0x6400, addmod(mload(0x5b20), mload(0x6240), f_q))mstore(0x6420, mulmod(1, mload(0x4fe0), f_q))mstore(0x6440, mulmod(1, mload(0x1220), f_q))mstore(0x6460, 0x0000000000000000000000000000000000000000000000000000000000000001) mstore(0x6480, 0x0000000000000000000000000000000000000000000000000000000000000002)mstore(0x64a0, mload(0x6400))success := and(eq(staticcall(gas(), 0x7, 0x6460, 0x60, 0x6460, 0x40), 1), success)mstore(0x64c0, mload(0x6460)) mstore(0x64e0, mload(0x6480))mstore(0x6500, mload(0xa40)) mstore(0x6520, mload(0xa60))success := and(eq(staticcall(gas(), 0x6, 0x64c0, 0x80, 0x64c0, 0x40), 1), success)mstore(0x6540, mload(0xc20)) mstore(0x6560, mload(0xc40))mstore(0x6580, mload(0x59e0))success := and(eq(staticcall(gas(), 0x7, 0x6540, 0x60, 0x6540, 0x40), 1), success)mstore(0x65a0, mload(0x64c0)) mstore(0x65c0, mload(0x64e0))mstore(0x65e0, mload(0x6540)) mstore(0x6600, mload(0x6560))success := and(eq(staticcall(gas(), 0x6, 0x65a0, 0x80, 0x65a0, 0x40), 1), success)mstore(0x6620, mload(0xc60)) mstore(0x6640, mload(0xc80))mstore(0x6660, mload(0x5a00))success := and(eq(staticcall(gas(), 0x7, 0x6620, 0x60, 0x6620, 0x40), 1), success)mstore(0x6680, mload(0x65a0)) mstore(0x66a0, mload(0x65c0))mstore(0x66c0, mload(0x6620)) mstore(0x66e0, mload(0x6640))success := and(eq(staticcall(gas(), 0x6, 0x6680, 0x80, 0x6680, 0x40), 1), success)mstore(0x6700, mload(0xae0)) mstore(0x6720, mload(0xb00))mstore(0x6740, mload(0x5b00))success := and(eq(staticcall(gas(), 0x7, 0x6700, 0x60, 0x6700, 0x40), 1), success)mstore(0x6760, mload(0x6680)) mstore(0x6780, mload(0x66a0))mstore(0x67a0, mload(0x6700)) mstore(0x67c0, mload(0x6720))success := and(eq(staticcall(gas(), 0x6, 0x6760, 0x80, 0x6760, 0x40), 1), success)mstore(0x67e0, mload(0xb20)) mstore(0x6800, mload(0xb40))mstore(0x6820, mload(0x6260))success := and(eq(staticcall(gas(), 0x7, 0x67e0, 0x60, 0x67e0, 0x40), 1), success)mstore(0x6840, mload(0x6760)) mstore(0x6860, mload(0x6780))mstore(0x6880, mload(0x67e0)) mstore(0x68a0, mload(0x6800))success := and(eq(staticcall(gas(), 0x6, 0x6840, 0x80, 0x6840, 0x40), 1), success)mstore(0x68c0, 0x030dbbd05f2e2c1253c0fe505b5c8aa5f9d65757b8d6688eb05f5b7a7481f5c5) mstore(0x68e0, 0x0334317636ef9a31a90f82857c6abc1f8a8b735638d4699528b70ed33e7dcf36)mstore(0x6900, mload(0x6280))success := and(eq(staticcall(gas(), 0x7, 0x68c0, 0x60, 0x68c0, 0x40), 1), success)mstore(0x6920, mload(0x6840)) mstore(0x6940, mload(0x6860))mstore(0x6960, mload(0x68c0)) mstore(0x6980, mload(0x68e0))success := and(eq(staticcall(gas(), 0x6, 0x6920, 0x80, 0x6920, 0x40), 1), success)mstore(0x69a0, 0x01d98d5263bc490aabe0903ed3464cfbcddf63da8b5276dc21822ce255105f42) mstore(0x69c0, 0x0bf89e789c6428f9fcd86c5b18df6da02b13a6009b3bdf76a15c4408a38f19e3)mstore(0x69e0, mload(0x62a0))success := and(eq(staticcall(gas(), 0x7, 0x69a0, 0x60, 0x69a0, 0x40), 1), success)mstore(0x6a00, mload(0x6920)) mstore(0x6a20, mload(0x6940))mstore(0x6a40, mload(0x69a0)) mstore(0x6a60, mload(0x69c0))success := and(eq(staticcall(gas(), 0x6, 0x6a00, 0x80, 0x6a00, 0x40), 1), success)mstore(0x6a80, 0x26fea4be89252d9352b80dd9885dece3f2c688694aaa29a8025fb63d58b40e4c) mstore(0x6aa0, 0x24ff6fe738f0ddcc46a0ab99cac47b1426cdcc8f2b8804008f0539797dae5388)mstore(0x6ac0, mload(0x62c0))success := and(eq(staticcall(gas(), 0x7, 0x6a80, 0x60, 0x6a80, 0x40), 1), success)mstore(0x6ae0, mload(0x6a00)) mstore(0x6b00, mload(0x6a20))mstore(0x6b20, mload(0x6a80)) mstore(0x6b40, mload(0x6aa0))success := and(eq(staticcall(gas(), 0x6, 0x6ae0, 0x80, 0x6ae0, 0x40), 1), success)mstore(0x6b60, 0x10575040d8d0b2721ffae8380b2430134a0d7fe93ee14614a342c675b913b914) mstore(0x6b80, 0x1936b8b7fa75c8fed7087ac63997986762c1d397eca41b5967b3dbee4b534076)mstore(0x6ba0, mload(0x62e0))success := and(eq(staticcall(gas(), 0x7, 0x6b60, 0x60, 0x6b60, 0x40), 1), success)mstore(0x6bc0, mload(0x6ae0)) mstore(0x6be0, mload(0x6b00))mstore(0x6c00, mload(0x6b60)) mstore(0x6c20, mload(0x6b80))success := and(eq(staticcall(gas(), 0x6, 0x6bc0, 0x80, 0x6bc0, 0x40), 1), success)mstore(0x6c40, 0x12a5bf87de336c4990120a5cd85a02419f13666f9d66cb535e454fd9306edef1) mstore(0x6c60, 0x1b160f576b98fe4b389754bb6363ce360d030c45ca56169d0ef1a6bd5f1925b9)mstore(0x6c80, mload(0x6300))success := and(eq(staticcall(gas(), 0x7, 0x6c40, 0x60, 0x6c40, 0x40), 1), success)mstore(0x6ca0, mload(0x6bc0)) mstore(0x6cc0, mload(0x6be0))mstore(0x6ce0, mload(0x6c40)) mstore(0x6d00, mload(0x6c60))success := and(eq(staticcall(gas(), 0x6, 0x6ca0, 0x80, 0x6ca0, 0x40), 1), success)mstore(0x6d20, 0x2fef334900a272a4ebad08edbc56372c1029303d4b0b5ce6c556b9204cbfecc7) mstore(0x6d40, 0x15f82d8f5bdd521213bf4e0443fdb121bc4a942e225774a58d34d650fa357422)mstore(0x6d60, mload(0x6320))success := and(eq(staticcall(gas(), 0x7, 0x6d20, 0x60, 0x6d20, 0x40), 1), success)mstore(0x6d80, mload(0x6ca0)) mstore(0x6da0, mload(0x6cc0))mstore(0x6dc0, mload(0x6d20)) mstore(0x6de0, mload(0x6d40))success := and(eq(staticcall(gas(), 0x6, 0x6d80, 0x80, 0x6d80, 0x40), 1), success)mstore(0x6e00, 0x22e8ca2ccbc2de3d536b2ebe6c3ad3f99ff0935b154ff3630d3298a2f204afc7) mstore(0x6e20, 0x0a66913d11d12fd0a3801e6afe211964d9e3179abe30dd4ecae3fffdeb65d1dc)mstore(0x6e40, mload(0x6340))success := and(eq(staticcall(gas(), 0x7, 0x6e00, 0x60, 0x6e00, 0x40), 1), success)mstore(0x6e60, mload(0x6d80)) mstore(0x6e80, mload(0x6da0))mstore(0x6ea0, mload(0x6e00)) mstore(0x6ec0, mload(0x6e20))success := and(eq(staticcall(gas(), 0x6, 0x6e60, 0x80, 0x6e60, 0x40), 1), success)mstore(0x6ee0, mload(0xd40)) mstore(0x6f00, mload(0xd60))mstore(0x6f20, mload(0x6360))success := and(eq(staticcall(gas(), 0x7, 0x6ee0, 0x60, 0x6ee0, 0x40), 1), success)mstore(0x6f40, mload(0x6e60)) mstore(0x6f60, mload(0x6e80))mstore(0x6f80, mload(0x6ee0)) mstore(0x6fa0, mload(0x6f00))success := and(eq(staticcall(gas(), 0x6, 0x6f40, 0x80, 0x6f40, 0x40), 1), success)mstore(0x6fc0, mload(0xd80)) mstore(0x6fe0, mload(0xda0))mstore(0x7000, mload(0x6380))success := and(eq(staticcall(gas(), 0x7, 0x6fc0, 0x60, 0x6fc0, 0x40), 1), success)mstore(0x7020, mload(0x6f40)) mstore(0x7040, mload(0x6f60))mstore(0x7060, mload(0x6fc0)) mstore(0x7080, mload(0x6fe0))success := and(eq(staticcall(gas(), 0x6, 0x7020, 0x80, 0x7020, 0x40), 1), success)mstore(0x70a0, mload(0xdc0)) mstore(0x70c0, mload(0xde0))mstore(0x70e0, mload(0x63a0))success := and(eq(staticcall(gas(), 0x7, 0x70a0, 0x60, 0x70a0, 0x40), 1), success)mstore(0x7100, mload(0x7020)) mstore(0x7120, mload(0x7040))mstore(0x7140, mload(0x70a0)) mstore(0x7160, mload(0x70c0))success := and(eq(staticcall(gas(), 0x6, 0x7100, 0x80, 0x7100, 0x40), 1), success)mstore(0x7180, mload(0xe00)) mstore(0x71a0, mload(0xe20))mstore(0x71c0, mload(0x63c0))success := and(eq(staticcall(gas(), 0x7, 0x7180, 0x60, 0x7180, 0x40), 1), success)mstore(0x71e0, mload(0x7100)) mstore(0x7200, mload(0x7120))mstore(0x7220, mload(0x7180)) mstore(0x7240, mload(0x71a0))success := and(eq(staticcall(gas(), 0x6, 0x71e0, 0x80, 0x71e0, 0x40), 1), success)mstore(0x7260, mload(0xca0)) mstore(0x7280, mload(0xcc0))mstore(0x72a0, mload(0x63e0))success := and(eq(staticcall(gas(), 0x7, 0x7260, 0x60, 0x7260, 0x40), 1), success)mstore(0x72c0, mload(0x71e0)) mstore(0x72e0, mload(0x7200))mstore(0x7300, mload(0x7260)) mstore(0x7320, mload(0x7280))success := and(eq(staticcall(gas(), 0x6, 0x72c0, 0x80, 0x72c0, 0x40), 1), success)mstore(0x7340, mload(0x11c0)) mstore(0x7360, mload(0x11e0))mstore(0x7380, sub(f_q, mload(0x6420)))success := and(eq(staticcall(gas(), 0x7, 0x7340, 0x60, 0x7340, 0x40), 1), success)mstore(0x73a0, mload(0x72c0)) mstore(0x73c0, mload(0x72e0))mstore(0x73e0, mload(0x7340)) mstore(0x7400, mload(0x7360))success := and(eq(staticcall(gas(), 0x6, 0x73a0, 0x80, 0x73a0, 0x40), 1), success)mstore(0x7420, mload(0x1260)) mstore(0x7440, mload(0x1280))mstore(0x7460, mload(0x6440))success := and(eq(staticcall(gas(), 0x7, 0x7420, 0x60, 0x7420, 0x40), 1), success)mstore(0x7480, mload(0x73a0)) mstore(0x74a0, mload(0x73c0))mstore(0x74c0, mload(0x7420)) mstore(0x74e0, mload(0x7440))success := and(eq(staticcall(gas(), 0x6, 0x7480, 0x80, 0x7480, 0x40), 1), success)mstore(0x7500, mload(0x7480)) mstore(0x7520, mload(0x74a0))mstore(0x7540, mload(0x1260)) mstore(0x7560, mload(0x1280))mstore(0x7580, mload(0x12a0)) mstore(0x75a0, mload(0x12c0))mstore(0x75c0, mload(0x12e0)) mstore(0x75e0, mload(0x1300))mstore(0x7600, keccak256(0x7500, 256))mstore(0x7620, mod(mload(30080), f_q))mstore(0x7640, mulmod(mload(0x7620), mload(0x7620), f_q))mstore(0x7660, mulmod(1, mload(0x7620), f_q))mstore(0x7680, mload(0x7580)) mstore(0x76a0, mload(0x75a0))mstore(0x76c0, mload(0x7660))success := and(eq(staticcall(gas(), 0x7, 0x7680, 0x60, 0x7680, 0x40), 1), success)mstore(0x76e0, mload(0x7500)) mstore(0x7700, mload(0x7520))mstore(0x7720, mload(0x7680)) mstore(0x7740, mload(0x76a0))success := and(eq(staticcall(gas(), 0x6, 0x76e0, 0x80, 0x76e0, 0x40), 1), success)mstore(0x7760, mload(0x75c0)) mstore(0x7780, mload(0x75e0))mstore(0x77a0, mload(0x7660))success := and(eq(staticcall(gas(), 0x7, 0x7760, 0x60, 0x7760, 0x40), 1), success)mstore(0x77c0, mload(0x7540)) mstore(0x77e0, mload(0x7560))mstore(0x7800, mload(0x7760)) mstore(0x7820, mload(0x7780))success := and(eq(staticcall(gas(), 0x6, 0x77c0, 0x80, 0x77c0, 0x40), 1), success)mstore(0x7840, mload(0x76e0)) mstore(0x7860, mload(0x7700))mstore(0x7880, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) mstore(0x78a0, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) mstore(0x78c0, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) mstore(0x78e0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)mstore(0x7900, mload(0x77c0)) mstore(0x7920, mload(0x77e0))mstore(0x7940, 0x0181624e80f3d6ae28df7e01eaeab1c0e919877a3b8a6b7fbc69a6817d596ea2) mstore(0x7960, 0x1783d30dcb12d259bb89098addf6280fa4b653be7a152542a28f7b926e27e648) mstore(0x7980, 0x00ae44489d41a0d179e2dfdc03bddd883b7109f8b6ae316a59e815c1a6b35304) mstore(0x79a0, 0x0b2147ab62a386bd63e6de1522109b8c9588ab466f5aadfde8c41ca3749423ee)success := and(eq(staticcall(gas(), 0x8, 0x7840, 0x180, 0x7840, 0x20), 1), success)success := and(eq(mload(0x7840), 1), success)} return success; } } diff --git a/contracts/snark-verifiers/sync_step_verifier.sol b/contracts/snark-verifiers/sync_step_verifier.sol deleted file mode 100644 index c546281..0000000 --- a/contracts/snark-verifiers/sync_step_verifier.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -contract Verifier { - - /** - * @notice Bn256 P value - * @dev In order to prevent the verifier from accepting two version of the same pubInput, n and the quantity (n + P), where n + P <= 2^256, we require that all pubInputs are stricly less than P. - * @dev The reason for this is that the assmebly code of the verifier performs all arithmetic operations modulo P and as a consequence can't distinguish between n and n + P values. - */ - - uint256 constant SIZE_LIMIT = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - - function verify( - uint256[14] calldata pubInputs, - bytes calldata proof - ) public view returns (bool) { - bool success = true; - bytes32[653] memory transcript; - for (uint i = 0; i < pubInputs.length; i++) { - require(pubInputs[i] < SIZE_LIMIT); - } - assembly { 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(0xa0, mod(calldataload(0x4), f_q))mstore(0xc0, mod(calldataload(0x24), f_q))mstore(0xe0, mod(calldataload(0x44), f_q))mstore(0x100, mod(calldataload(0x64), f_q))mstore(0x120, mod(calldataload(0x84), f_q))mstore(0x140, mod(calldataload(0xa4), f_q))mstore(0x160, mod(calldataload(0xc4), f_q))mstore(0x180, mod(calldataload(0xe4), f_q))mstore(0x1a0, mod(calldataload(0x104), f_q))mstore(0x1c0, mod(calldataload(0x124), f_q))mstore(0x1e0, mod(calldataload(0x144), f_q))mstore(0x200, mod(calldataload(0x164), f_q))mstore(0x220, mod(calldataload(0x184), f_q))mstore(0x240, mod(calldataload(0x1a4), f_q))mstore(0x80, 16106448136499026851096799321936372170818194453327642173445160481527811968) { let x := calldataload(0x204) mstore(0x260, x) let y := calldataload(0x224) mstore(0x280, y) success := and(validate_ec_point(x, y), success) }mstore(0x2a0, keccak256(0x80, 544)){ let hash := mload(0x2a0) mstore(0x2c0, mod(hash, f_q)) mstore(0x2e0, hash) } { let x := calldataload(0x244) mstore(0x300, x) let y := calldataload(0x264) mstore(0x320, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x284) mstore(0x340, x) let y := calldataload(0x2a4) mstore(0x360, y) success := and(validate_ec_point(x, y), success) }mstore(0x380, keccak256(0x2e0, 160)){ let hash := mload(0x380) mstore(0x3a0, mod(hash, f_q)) mstore(0x3c0, hash) }mstore8(0x3e0, 1)mstore(0x3e0, keccak256(0x3c0, 33)){ let hash := mload(0x3e0) mstore(0x400, mod(hash, f_q)) mstore(0x420, hash) } { let x := calldataload(0x2c4) mstore(0x440, x) let y := calldataload(0x2e4) mstore(0x460, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x304) mstore(0x480, x) let y := calldataload(0x324) mstore(0x4a0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x344) mstore(0x4c0, x) let y := calldataload(0x364) mstore(0x4e0, y) success := and(validate_ec_point(x, y), success) }mstore(0x500, keccak256(0x420, 224)){ let hash := mload(0x500) mstore(0x520, mod(hash, f_q)) mstore(0x540, hash) } { let x := calldataload(0x384) mstore(0x560, x) let y := calldataload(0x3a4) mstore(0x580, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x3c4) mstore(0x5a0, x) let y := calldataload(0x3e4) mstore(0x5c0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x404) mstore(0x5e0, x) let y := calldataload(0x424) mstore(0x600, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x444) mstore(0x620, x) let y := calldataload(0x464) mstore(0x640, y) success := and(validate_ec_point(x, y), success) }mstore(0x660, keccak256(0x540, 288)){ let hash := mload(0x660) mstore(0x680, mod(hash, f_q)) mstore(0x6a0, hash) }mstore(0x6c0, mod(calldataload(0x484), f_q))mstore(0x6e0, mod(calldataload(0x4a4), f_q))mstore(0x700, mod(calldataload(0x4c4), f_q))mstore(0x720, mod(calldataload(0x4e4), f_q))mstore(0x740, mod(calldataload(0x504), f_q))mstore(0x760, mod(calldataload(0x524), f_q))mstore(0x780, mod(calldataload(0x544), f_q))mstore(0x7a0, mod(calldataload(0x564), f_q))mstore(0x7c0, mod(calldataload(0x584), f_q))mstore(0x7e0, mod(calldataload(0x5a4), f_q))mstore(0x800, mod(calldataload(0x5c4), f_q))mstore(0x820, mod(calldataload(0x5e4), f_q))mstore(0x840, mod(calldataload(0x604), f_q))mstore(0x860, mod(calldataload(0x624), f_q))mstore(0x880, mod(calldataload(0x644), f_q))mstore(0x8a0, mod(calldataload(0x664), f_q))mstore(0x8c0, mod(calldataload(0x684), f_q))mstore(0x8e0, mod(calldataload(0x6a4), f_q))mstore(0x900, mod(calldataload(0x6c4), f_q))mstore(0x920, keccak256(0x6a0, 640)){ let hash := mload(0x920) mstore(0x940, mod(hash, f_q)) mstore(0x960, hash) }mstore8(0x980, 1)mstore(0x980, keccak256(0x960, 33)){ let hash := mload(0x980) mstore(0x9a0, mod(hash, f_q)) mstore(0x9c0, hash) } { let x := calldataload(0x6e4) mstore(0x9e0, x) let y := calldataload(0x704) mstore(0xa00, y) success := and(validate_ec_point(x, y), success) }mstore(0xa20, keccak256(0x9c0, 96)){ let hash := mload(0xa20) mstore(0xa40, mod(hash, f_q)) mstore(0xa60, hash) } { let x := calldataload(0x724) mstore(0xa80, x) let y := calldataload(0x744) mstore(0xaa0, y) success := and(validate_ec_point(x, y), success) }{ let x := mload(0xa0)x := add(x, shl(88, mload(0xc0)))x := add(x, shl(176, mload(0xe0)))mstore(0xac0, x)let y := mload(0x100)y := add(y, shl(88, mload(0x120)))y := add(y, shl(176, mload(0x140)))mstore(0xae0, y) success := and(validate_ec_point(x, y), success) }{ let x := mload(0x160)x := add(x, shl(88, mload(0x180)))x := add(x, shl(176, mload(0x1a0)))mstore(0xb00, x)let y := mload(0x1c0)y := add(y, shl(88, mload(0x1e0)))y := add(y, shl(176, mload(0x200)))mstore(0xb20, y) success := and(validate_ec_point(x, y), success) }mstore(0xb40, mulmod(mload(0x680), mload(0x680), f_q))mstore(0xb60, mulmod(mload(0xb40), mload(0xb40), f_q))mstore(0xb80, mulmod(mload(0xb60), mload(0xb60), f_q))mstore(0xba0, mulmod(mload(0xb80), mload(0xb80), f_q))mstore(0xbc0, mulmod(mload(0xba0), mload(0xba0), f_q))mstore(0xbe0, mulmod(mload(0xbc0), mload(0xbc0), f_q))mstore(0xc00, mulmod(mload(0xbe0), mload(0xbe0), f_q))mstore(0xc20, mulmod(mload(0xc00), mload(0xc00), f_q))mstore(0xc40, mulmod(mload(0xc20), mload(0xc20), f_q))mstore(0xc60, mulmod(mload(0xc40), mload(0xc40), f_q))mstore(0xc80, mulmod(mload(0xc60), mload(0xc60), f_q))mstore(0xca0, mulmod(mload(0xc80), mload(0xc80), f_q))mstore(0xcc0, mulmod(mload(0xca0), mload(0xca0), f_q))mstore(0xce0, mulmod(mload(0xcc0), mload(0xcc0), f_q))mstore(0xd00, mulmod(mload(0xce0), mload(0xce0), f_q))mstore(0xd20, mulmod(mload(0xd00), mload(0xd00), f_q))mstore(0xd40, mulmod(mload(0xd20), mload(0xd20), f_q))mstore(0xd60, mulmod(mload(0xd40), mload(0xd40), f_q))mstore(0xd80, mulmod(mload(0xd60), mload(0xd60), f_q))mstore(0xda0, mulmod(mload(0xd80), mload(0xd80), f_q))mstore(0xdc0, mulmod(mload(0xda0), mload(0xda0), f_q))mstore(0xde0, mulmod(mload(0xdc0), mload(0xdc0), f_q))mstore(0xe00, mulmod(mload(0xde0), mload(0xde0), f_q))mstore(0xe20, addmod(mload(0xe00), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q))mstore(0xe40, mulmod(mload(0xe20), 21888240262557392955334514970720457388010314637169927192662615958087340972065, f_q))mstore(0xe60, mulmod(mload(0xe40), 4506835738822104338668100540817374747935106310012997856968187171738630203507, f_q))mstore(0xe80, addmod(mload(0x680), 17381407133017170883578305204439900340613258090403036486730017014837178292110, f_q))mstore(0xea0, mulmod(mload(0xe40), 21710372849001950800533397158415938114909991150039389063546734567764856596059, f_q))mstore(0xec0, addmod(mload(0x680), 177870022837324421713008586841336973638373250376645280151469618810951899558, f_q))mstore(0xee0, mulmod(mload(0xe40), 1887003188133998471169152042388914354640772748308168868301418279904560637395, f_q))mstore(0xf00, addmod(mload(0x680), 20001239683705276751077253702868360733907591652107865475396785906671247858222, f_q))mstore(0xf20, mulmod(mload(0xe40), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q))mstore(0xf40, addmod(mload(0x680), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q))mstore(0xf60, mulmod(mload(0xe40), 14655294445420895451632927078981340937842238432098198055057679026789553137428, f_q))mstore(0xf80, addmod(mload(0x680), 7232948426418379770613478666275934150706125968317836288640525159786255358189, f_q))mstore(0xfa0, mulmod(mload(0xe40), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q))mstore(0xfc0, addmod(mload(0x680), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q))mstore(0xfe0, mulmod(mload(0xe40), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q))mstore(0x1000, addmod(mload(0x680), 12146688980418810893951125255607130521645347193942732958664170801695864621270, f_q))mstore(0x1020, mulmod(mload(0xe40), 1, f_q))mstore(0x1040, addmod(mload(0x680), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q))mstore(0x1060, mulmod(mload(0xe40), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q))mstore(0x1080, addmod(mload(0x680), 13513867906530865119835332133273263211836799082674232843258448413103731898270, f_q))mstore(0x10a0, mulmod(mload(0xe40), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q))mstore(0x10c0, addmod(mload(0x680), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q))mstore(0x10e0, mulmod(mload(0xe40), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q))mstore(0x1100, addmod(mload(0x680), 18272764063556419981698118473909131571661591947471949595929891197711371770216, f_q))mstore(0x1120, mulmod(mload(0xe40), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q))mstore(0x1140, addmod(mload(0x680), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q))mstore(0x1160, mulmod(mload(0xe40), 216092043779272773661818549620449970334216366264741118684015851799902419467, f_q))mstore(0x1180, addmod(mload(0x680), 21672150828060002448584587195636825118214148034151293225014188334775906076150, f_q))mstore(0x11a0, mulmod(mload(0xe40), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q))mstore(0x11c0, addmod(mload(0x680), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q))mstore(0x11e0, mulmod(mload(0xe40), 18610195890048912503953886742825279624920778288956610528523679659246523534888, f_q))mstore(0x1200, addmod(mload(0x680), 3278046981790362718292519002431995463627586111459423815174524527329284960729, f_q))mstore(0x1220, mulmod(mload(0xe40), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q))mstore(0x1240, addmod(mload(0x680), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q))mstore(0x1260, mulmod(mload(0xe40), 14875928112196239563830800280253496262679717528621719058794366823499719730250, f_q))mstore(0x1280, addmod(mload(0x680), 7012314759643035658415605465003778825868646871794315284903837363076088765367, f_q))mstore(0x12a0, mulmod(mload(0xe40), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q))mstore(0x12c0, addmod(mload(0x680), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q))mstore(0x12e0, mulmod(mload(0xe40), 5522161504810533295870699551020523636289972223872138525048055197429246400245, f_q))mstore(0x1300, addmod(mload(0x680), 16366081367028741926375706194236751452258392176543895818650148989146562095372, f_q))mstore(0x1320, mulmod(mload(0xe40), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q))mstore(0x1340, addmod(mload(0x680), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q))mstore(0x1360, mulmod(mload(0xe40), 9100833993744738801214480881117348002768153232283708533639316963648253510584, f_q))mstore(0x1380, addmod(mload(0x680), 12787408878094536421031924864139927085780211168132325810058887222927554985033, f_q)){ let prod := mload(0xe80) prod := mulmod(mload(0xec0), prod, f_q) mstore(0x13a0, prod) prod := mulmod(mload(0xf00), prod, f_q) mstore(0x13c0, prod) prod := mulmod(mload(0xf40), prod, f_q) mstore(0x13e0, prod) prod := mulmod(mload(0xf80), prod, f_q) mstore(0x1400, prod) prod := mulmod(mload(0xfc0), prod, f_q) mstore(0x1420, prod) prod := mulmod(mload(0x1000), prod, f_q) mstore(0x1440, prod) prod := mulmod(mload(0x1040), prod, f_q) mstore(0x1460, prod) prod := mulmod(mload(0x1080), prod, f_q) mstore(0x1480, prod) prod := mulmod(mload(0x10c0), prod, f_q) mstore(0x14a0, prod) prod := mulmod(mload(0x1100), prod, f_q) mstore(0x14c0, prod) prod := mulmod(mload(0x1140), prod, f_q) mstore(0x14e0, prod) prod := mulmod(mload(0x1180), prod, f_q) mstore(0x1500, prod) prod := mulmod(mload(0x11c0), prod, f_q) mstore(0x1520, prod) prod := mulmod(mload(0x1200), prod, f_q) mstore(0x1540, prod) prod := mulmod(mload(0x1240), prod, f_q) mstore(0x1560, prod) prod := mulmod(mload(0x1280), prod, f_q) mstore(0x1580, prod) prod := mulmod(mload(0x12c0), prod, f_q) mstore(0x15a0, prod) prod := mulmod(mload(0x1300), prod, f_q) mstore(0x15c0, prod) prod := mulmod(mload(0x1340), prod, f_q) mstore(0x15e0, prod) prod := mulmod(mload(0x1380), prod, f_q) mstore(0x1600, prod) prod := mulmod(mload(0xe20), prod, f_q) mstore(0x1620, prod) }mstore(0x1660, 32)mstore(0x1680, 32)mstore(0x16a0, 32)mstore(0x16c0, mload(0x1620))mstore(0x16e0, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x1700, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x1660, 0xc0, 0x1640, 0x20), 1), success){ let inv := mload(0x1640) let v v := mload(0xe20) mstore(0xe20, mulmod(mload(0x1600), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1380) mstore(0x1380, mulmod(mload(0x15e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1340) mstore(0x1340, mulmod(mload(0x15c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1300) mstore(0x1300, mulmod(mload(0x15a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x12c0) mstore(0x12c0, mulmod(mload(0x1580), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1280) mstore(0x1280, mulmod(mload(0x1560), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1240) mstore(0x1240, mulmod(mload(0x1540), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1200) mstore(0x1200, mulmod(mload(0x1520), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x11c0) mstore(0x11c0, mulmod(mload(0x1500), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1180) mstore(0x1180, mulmod(mload(0x14e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1140) mstore(0x1140, mulmod(mload(0x14c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1100) mstore(0x1100, mulmod(mload(0x14a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x10c0) mstore(0x10c0, mulmod(mload(0x1480), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1080) mstore(0x1080, mulmod(mload(0x1460), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1040) mstore(0x1040, mulmod(mload(0x1440), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1000) mstore(0x1000, mulmod(mload(0x1420), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xfc0) mstore(0xfc0, mulmod(mload(0x1400), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xf80) mstore(0xf80, mulmod(mload(0x13e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xf40) mstore(0xf40, mulmod(mload(0x13c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xf00) mstore(0xf00, mulmod(mload(0x13a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0xec0) mstore(0xec0, mulmod(mload(0xe80), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0xe80, inv) }mstore(0x1720, mulmod(mload(0xe60), mload(0xe80), f_q))mstore(0x1740, mulmod(mload(0xea0), mload(0xec0), f_q))mstore(0x1760, mulmod(mload(0xee0), mload(0xf00), f_q))mstore(0x1780, mulmod(mload(0xf20), mload(0xf40), f_q))mstore(0x17a0, mulmod(mload(0xf60), mload(0xf80), f_q))mstore(0x17c0, mulmod(mload(0xfa0), mload(0xfc0), f_q))mstore(0x17e0, mulmod(mload(0xfe0), mload(0x1000), f_q))mstore(0x1800, mulmod(mload(0x1020), mload(0x1040), f_q))mstore(0x1820, mulmod(mload(0x1060), mload(0x1080), f_q))mstore(0x1840, mulmod(mload(0x10a0), mload(0x10c0), f_q))mstore(0x1860, mulmod(mload(0x10e0), mload(0x1100), f_q))mstore(0x1880, mulmod(mload(0x1120), mload(0x1140), f_q))mstore(0x18a0, mulmod(mload(0x1160), mload(0x1180), f_q))mstore(0x18c0, mulmod(mload(0x11a0), mload(0x11c0), f_q))mstore(0x18e0, mulmod(mload(0x11e0), mload(0x1200), f_q))mstore(0x1900, mulmod(mload(0x1220), mload(0x1240), f_q))mstore(0x1920, mulmod(mload(0x1260), mload(0x1280), f_q))mstore(0x1940, mulmod(mload(0x12a0), mload(0x12c0), f_q))mstore(0x1960, mulmod(mload(0x12e0), mload(0x1300), f_q))mstore(0x1980, mulmod(mload(0x1320), mload(0x1340), f_q))mstore(0x19a0, mulmod(mload(0x1360), mload(0x1380), f_q)){ let result := mulmod(mload(0x1800), mload(0xa0), f_q)result := addmod(mulmod(mload(0x1820), mload(0xc0), f_q), result, f_q)result := addmod(mulmod(mload(0x1840), mload(0xe0), f_q), result, f_q)result := addmod(mulmod(mload(0x1860), mload(0x100), f_q), result, f_q)result := addmod(mulmod(mload(0x1880), mload(0x120), f_q), result, f_q)result := addmod(mulmod(mload(0x18a0), mload(0x140), f_q), result, f_q)result := addmod(mulmod(mload(0x18c0), mload(0x160), f_q), result, f_q)result := addmod(mulmod(mload(0x18e0), mload(0x180), f_q), result, f_q)result := addmod(mulmod(mload(0x1900), mload(0x1a0), f_q), result, f_q)result := addmod(mulmod(mload(0x1920), mload(0x1c0), f_q), result, f_q)result := addmod(mulmod(mload(0x1940), mload(0x1e0), f_q), result, f_q)result := addmod(mulmod(mload(0x1960), mload(0x200), f_q), result, f_q)result := addmod(mulmod(mload(0x1980), mload(0x220), f_q), result, f_q)result := addmod(mulmod(mload(0x19a0), mload(0x240), f_q), result, f_q)mstore(0x19c0, result) }mstore(0x19e0, mulmod(mload(0x700), mload(0x6e0), f_q))mstore(0x1a00, addmod(mload(0x6c0), mload(0x19e0), f_q))mstore(0x1a20, addmod(mload(0x1a00), sub(f_q, mload(0x720)), f_q))mstore(0x1a40, mulmod(mload(0x1a20), mload(0x7a0), f_q))mstore(0x1a60, mulmod(mload(0x520), mload(0x1a40), f_q))mstore(0x1a80, addmod(1, sub(f_q, mload(0x840)), f_q))mstore(0x1aa0, mulmod(mload(0x1a80), mload(0x1800), f_q))mstore(0x1ac0, addmod(mload(0x1a60), mload(0x1aa0), f_q))mstore(0x1ae0, mulmod(mload(0x520), mload(0x1ac0), f_q))mstore(0x1b00, mulmod(mload(0x840), mload(0x840), f_q))mstore(0x1b20, addmod(mload(0x1b00), sub(f_q, mload(0x840)), f_q))mstore(0x1b40, mulmod(mload(0x1b20), mload(0x1720), f_q))mstore(0x1b60, addmod(mload(0x1ae0), mload(0x1b40), f_q))mstore(0x1b80, mulmod(mload(0x520), mload(0x1b60), f_q))mstore(0x1ba0, addmod(1, sub(f_q, mload(0x1720)), f_q))mstore(0x1bc0, addmod(mload(0x1740), mload(0x1760), f_q))mstore(0x1be0, addmod(mload(0x1bc0), mload(0x1780), f_q))mstore(0x1c00, addmod(mload(0x1be0), mload(0x17a0), f_q))mstore(0x1c20, addmod(mload(0x1c00), mload(0x17c0), f_q))mstore(0x1c40, addmod(mload(0x1c20), mload(0x17e0), f_q))mstore(0x1c60, addmod(mload(0x1ba0), sub(f_q, mload(0x1c40)), f_q))mstore(0x1c80, mulmod(mload(0x7e0), mload(0x3a0), f_q))mstore(0x1ca0, addmod(mload(0x740), mload(0x1c80), f_q))mstore(0x1cc0, addmod(mload(0x1ca0), mload(0x400), f_q))mstore(0x1ce0, mulmod(mload(0x800), mload(0x3a0), f_q))mstore(0x1d00, addmod(mload(0x6c0), mload(0x1ce0), f_q))mstore(0x1d20, addmod(mload(0x1d00), mload(0x400), f_q))mstore(0x1d40, mulmod(mload(0x1d20), mload(0x1cc0), f_q))mstore(0x1d60, mulmod(mload(0x820), mload(0x3a0), f_q))mstore(0x1d80, addmod(mload(0x19c0), mload(0x1d60), f_q))mstore(0x1da0, addmod(mload(0x1d80), mload(0x400), f_q))mstore(0x1dc0, mulmod(mload(0x1da0), mload(0x1d40), f_q))mstore(0x1de0, mulmod(mload(0x1dc0), mload(0x860), f_q))mstore(0x1e00, mulmod(1, mload(0x3a0), f_q))mstore(0x1e20, mulmod(mload(0x680), mload(0x1e00), f_q))mstore(0x1e40, addmod(mload(0x740), mload(0x1e20), f_q))mstore(0x1e60, addmod(mload(0x1e40), mload(0x400), f_q))mstore(0x1e80, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x3a0), f_q))mstore(0x1ea0, mulmod(mload(0x680), mload(0x1e80), f_q))mstore(0x1ec0, addmod(mload(0x6c0), mload(0x1ea0), f_q))mstore(0x1ee0, addmod(mload(0x1ec0), mload(0x400), f_q))mstore(0x1f00, mulmod(mload(0x1ee0), mload(0x1e60), f_q))mstore(0x1f20, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x3a0), f_q))mstore(0x1f40, mulmod(mload(0x680), mload(0x1f20), f_q))mstore(0x1f60, addmod(mload(0x19c0), mload(0x1f40), f_q))mstore(0x1f80, addmod(mload(0x1f60), mload(0x400), f_q))mstore(0x1fa0, mulmod(mload(0x1f80), mload(0x1f00), f_q))mstore(0x1fc0, mulmod(mload(0x1fa0), mload(0x840), f_q))mstore(0x1fe0, addmod(mload(0x1de0), sub(f_q, mload(0x1fc0)), f_q))mstore(0x2000, mulmod(mload(0x1fe0), mload(0x1c60), f_q))mstore(0x2020, addmod(mload(0x1b80), mload(0x2000), f_q))mstore(0x2040, mulmod(mload(0x520), mload(0x2020), f_q))mstore(0x2060, addmod(1, sub(f_q, mload(0x880)), f_q))mstore(0x2080, mulmod(mload(0x2060), mload(0x1800), f_q))mstore(0x20a0, addmod(mload(0x2040), mload(0x2080), f_q))mstore(0x20c0, mulmod(mload(0x520), mload(0x20a0), f_q))mstore(0x20e0, mulmod(mload(0x880), mload(0x880), f_q))mstore(0x2100, addmod(mload(0x20e0), sub(f_q, mload(0x880)), f_q))mstore(0x2120, mulmod(mload(0x2100), mload(0x1720), f_q))mstore(0x2140, addmod(mload(0x20c0), mload(0x2120), f_q))mstore(0x2160, mulmod(mload(0x520), mload(0x2140), f_q))mstore(0x2180, addmod(mload(0x8c0), mload(0x3a0), f_q))mstore(0x21a0, mulmod(mload(0x2180), mload(0x8a0), f_q))mstore(0x21c0, addmod(mload(0x900), mload(0x400), f_q))mstore(0x21e0, mulmod(mload(0x21c0), mload(0x21a0), f_q))mstore(0x2200, mulmod(mload(0x6c0), mload(0x780), f_q))mstore(0x2220, addmod(mload(0x2200), mload(0x3a0), f_q))mstore(0x2240, mulmod(mload(0x2220), mload(0x880), f_q))mstore(0x2260, addmod(mload(0x760), mload(0x400), f_q))mstore(0x2280, mulmod(mload(0x2260), mload(0x2240), f_q))mstore(0x22a0, addmod(mload(0x21e0), sub(f_q, mload(0x2280)), f_q))mstore(0x22c0, mulmod(mload(0x22a0), mload(0x1c60), f_q))mstore(0x22e0, addmod(mload(0x2160), mload(0x22c0), f_q))mstore(0x2300, mulmod(mload(0x520), mload(0x22e0), f_q))mstore(0x2320, addmod(mload(0x8c0), sub(f_q, mload(0x900)), f_q))mstore(0x2340, mulmod(mload(0x2320), mload(0x1800), f_q))mstore(0x2360, addmod(mload(0x2300), mload(0x2340), f_q))mstore(0x2380, mulmod(mload(0x520), mload(0x2360), f_q))mstore(0x23a0, mulmod(mload(0x2320), mload(0x1c60), f_q))mstore(0x23c0, addmod(mload(0x8c0), sub(f_q, mload(0x8e0)), f_q))mstore(0x23e0, mulmod(mload(0x23c0), mload(0x23a0), f_q))mstore(0x2400, addmod(mload(0x2380), mload(0x23e0), f_q))mstore(0x2420, mulmod(mload(0xe00), mload(0xe00), f_q))mstore(0x2440, mulmod(mload(0x2420), mload(0xe00), f_q))mstore(0x2460, mulmod(mload(0x2440), mload(0xe00), f_q))mstore(0x2480, mulmod(1, mload(0xe00), f_q))mstore(0x24a0, mulmod(1, mload(0x2420), f_q))mstore(0x24c0, mulmod(1, mload(0x2440), f_q))mstore(0x24e0, mulmod(mload(0x2400), mload(0xe20), f_q))mstore(0x2500, mulmod(mload(0xb40), mload(0x680), f_q))mstore(0x2520, mulmod(mload(0x2500), mload(0x680), f_q))mstore(0x2540, mulmod(mload(0x680), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q))mstore(0x2560, addmod(mload(0xa40), sub(f_q, mload(0x2540)), f_q))mstore(0x2580, mulmod(mload(0x680), 1, f_q))mstore(0x25a0, addmod(mload(0xa40), sub(f_q, mload(0x2580)), f_q))mstore(0x25c0, mulmod(mload(0x680), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q))mstore(0x25e0, addmod(mload(0xa40), sub(f_q, mload(0x25c0)), f_q))mstore(0x2600, mulmod(mload(0x680), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q))mstore(0x2620, addmod(mload(0xa40), sub(f_q, mload(0x2600)), f_q))mstore(0x2640, mulmod(mload(0x680), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q))mstore(0x2660, addmod(mload(0xa40), sub(f_q, mload(0x2640)), f_q))mstore(0x2680, mulmod(13213688729882003894512633350385593288217014177373218494356903340348818451480, mload(0x2500), f_q))mstore(0x26a0, mulmod(mload(0x2680), 1, f_q)){ let result := mulmod(mload(0xa40), mload(0x2680), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x26a0)), f_q), result, f_q)mstore(0x26c0, result) }mstore(0x26e0, mulmod(8207090019724696496350398458716998472718344609680392612601596849934418295470, mload(0x2500), f_q))mstore(0x2700, mulmod(mload(0x26e0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)){ let result := mulmod(mload(0xa40), mload(0x26e0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2700)), f_q), result, f_q)mstore(0x2720, result) }mstore(0x2740, mulmod(7391709068497399131897422873231908718558236401035363928063603272120120747483, mload(0x2500), f_q))mstore(0x2760, mulmod(mload(0x2740), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)){ let result := mulmod(mload(0xa40), mload(0x2740), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2760)), f_q), result, f_q)mstore(0x2780, result) }mstore(0x27a0, mulmod(19036273796805830823244991598792794567595348772040298280440552631112242221017, mload(0x2500), f_q))mstore(0x27c0, mulmod(mload(0x27a0), 3615478808282855240548287271348143516886772452944084747768312988864436725401, f_q)){ let result := mulmod(mload(0xa40), mload(0x27a0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x27c0)), f_q), result, f_q)mstore(0x27e0, result) }mstore(0x2800, mulmod(1, mload(0x25a0), f_q))mstore(0x2820, mulmod(mload(0x2800), mload(0x25e0), f_q))mstore(0x2840, mulmod(mload(0x2820), mload(0x2620), f_q))mstore(0x2860, mulmod(mload(0x2840), mload(0x2660), f_q))mstore(0x2880, mulmod(13513867906530865119835332133273263211836799082674232843258448413103731898271, mload(0x680), f_q))mstore(0x28a0, mulmod(mload(0x2880), 1, f_q)){ let result := mulmod(mload(0xa40), mload(0x2880), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x28a0)), f_q), result, f_q)mstore(0x28c0, result) }mstore(0x28e0, mulmod(8374374965308410102411073611984011876711565317741801500439755773472076597346, mload(0x680), f_q))mstore(0x2900, mulmod(mload(0x28e0), 8374374965308410102411073611984011876711565317741801500439755773472076597347, f_q)){ let result := mulmod(mload(0xa40), mload(0x28e0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2900)), f_q), result, f_q)mstore(0x2920, result) }mstore(0x2940, mulmod(12146688980418810893951125255607130521645347193942732958664170801695864621271, mload(0x680), f_q))mstore(0x2960, mulmod(mload(0x2940), 1, f_q)){ let result := mulmod(mload(0xa40), mload(0x2940), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2960)), f_q), result, f_q)mstore(0x2980, result) }mstore(0x29a0, mulmod(9741553891420464328295280489650144566903017206473301385034033384879943874346, mload(0x680), f_q))mstore(0x29c0, mulmod(mload(0x29a0), 9741553891420464328295280489650144566903017206473301385034033384879943874347, f_q)){ let result := mulmod(mload(0xa40), mload(0x29a0), f_q)result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x29c0)), f_q), result, f_q)mstore(0x29e0, result) }mstore(0x2a00, mulmod(mload(0x2800), mload(0x2560), f_q)){ let result := mulmod(mload(0xa40), 1, f_q)result := addmod(mulmod(mload(0x680), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q)mstore(0x2a20, result) }{ let prod := mload(0x26c0) prod := mulmod(mload(0x2720), prod, f_q) mstore(0x2a40, prod) prod := mulmod(mload(0x2780), prod, f_q) mstore(0x2a60, prod) prod := mulmod(mload(0x27e0), prod, f_q) mstore(0x2a80, prod) prod := mulmod(mload(0x28c0), prod, f_q) mstore(0x2aa0, prod) prod := mulmod(mload(0x2920), prod, f_q) mstore(0x2ac0, prod) prod := mulmod(mload(0x2820), prod, f_q) mstore(0x2ae0, prod) prod := mulmod(mload(0x2980), prod, f_q) mstore(0x2b00, prod) prod := mulmod(mload(0x29e0), prod, f_q) mstore(0x2b20, prod) prod := mulmod(mload(0x2a00), prod, f_q) mstore(0x2b40, prod) prod := mulmod(mload(0x2a20), prod, f_q) mstore(0x2b60, prod) prod := mulmod(mload(0x2800), prod, f_q) mstore(0x2b80, prod) }mstore(0x2bc0, 32)mstore(0x2be0, 32)mstore(0x2c00, 32)mstore(0x2c20, mload(0x2b80))mstore(0x2c40, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x2c60, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x2bc0, 0xc0, 0x2ba0, 0x20), 1), success){ let inv := mload(0x2ba0) let v v := mload(0x2800) mstore(0x2800, mulmod(mload(0x2b60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2a20) mstore(0x2a20, mulmod(mload(0x2b40), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2a00) mstore(0x2a00, mulmod(mload(0x2b20), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x29e0) mstore(0x29e0, mulmod(mload(0x2b00), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2980) mstore(0x2980, mulmod(mload(0x2ae0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2820) mstore(0x2820, mulmod(mload(0x2ac0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2920) mstore(0x2920, mulmod(mload(0x2aa0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x28c0) mstore(0x28c0, mulmod(mload(0x2a80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x27e0) mstore(0x27e0, mulmod(mload(0x2a60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2780) mstore(0x2780, mulmod(mload(0x2a40), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2720) mstore(0x2720, mulmod(mload(0x26c0), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x26c0, inv) }{ let result := mload(0x26c0)result := addmod(mload(0x2720), result, f_q)result := addmod(mload(0x2780), result, f_q)result := addmod(mload(0x27e0), result, f_q)mstore(0x2c80, result) }mstore(0x2ca0, mulmod(mload(0x2860), mload(0x2820), f_q)){ let result := mload(0x28c0)result := addmod(mload(0x2920), result, f_q)mstore(0x2cc0, result) }mstore(0x2ce0, mulmod(mload(0x2860), mload(0x2a00), f_q)){ let result := mload(0x2980)result := addmod(mload(0x29e0), result, f_q)mstore(0x2d00, result) }mstore(0x2d20, mulmod(mload(0x2860), mload(0x2800), f_q)){ let result := mload(0x2a20)mstore(0x2d40, result) }{ let prod := mload(0x2c80) prod := mulmod(mload(0x2cc0), prod, f_q) mstore(0x2d60, prod) prod := mulmod(mload(0x2d00), prod, f_q) mstore(0x2d80, prod) prod := mulmod(mload(0x2d40), prod, f_q) mstore(0x2da0, prod) }mstore(0x2de0, 32)mstore(0x2e00, 32)mstore(0x2e20, 32)mstore(0x2e40, mload(0x2da0))mstore(0x2e60, 21888242871839275222246405745257275088548364400416034343698204186575808495615)mstore(0x2e80, 21888242871839275222246405745257275088548364400416034343698204186575808495617)success := and(eq(staticcall(gas(), 0x5, 0x2de0, 0xc0, 0x2dc0, 0x20), 1), success){ let inv := mload(0x2dc0) let v v := mload(0x2d40) mstore(0x2d40, mulmod(mload(0x2d80), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2d00) mstore(0x2d00, mulmod(mload(0x2d60), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x2cc0) mstore(0x2cc0, mulmod(mload(0x2c80), inv, f_q)) inv := mulmod(v, inv, f_q) mstore(0x2c80, inv) }mstore(0x2ea0, mulmod(mload(0x2ca0), mload(0x2cc0), f_q))mstore(0x2ec0, mulmod(mload(0x2ce0), mload(0x2d00), f_q))mstore(0x2ee0, mulmod(mload(0x2d20), mload(0x2d40), f_q))mstore(0x2f00, mulmod(mload(0x940), mload(0x940), f_q))mstore(0x2f20, mulmod(mload(0x2f00), mload(0x940), f_q))mstore(0x2f40, mulmod(mload(0x2f20), mload(0x940), f_q))mstore(0x2f60, mulmod(mload(0x2f40), mload(0x940), f_q))mstore(0x2f80, mulmod(mload(0x2f60), mload(0x940), f_q))mstore(0x2fa0, mulmod(mload(0x2f80), mload(0x940), f_q))mstore(0x2fc0, mulmod(mload(0x2fa0), mload(0x940), f_q))mstore(0x2fe0, mulmod(mload(0x2fc0), mload(0x940), f_q))mstore(0x3000, mulmod(mload(0x2fe0), mload(0x940), f_q))mstore(0x3020, mulmod(mload(0x9a0), mload(0x9a0), f_q))mstore(0x3040, mulmod(mload(0x3020), mload(0x9a0), f_q))mstore(0x3060, mulmod(mload(0x3040), mload(0x9a0), f_q)){ let result := mulmod(mload(0x6c0), mload(0x26c0), f_q)result := addmod(mulmod(mload(0x6e0), mload(0x2720), f_q), result, f_q)result := addmod(mulmod(mload(0x700), mload(0x2780), f_q), result, f_q)result := addmod(mulmod(mload(0x720), mload(0x27e0), f_q), result, f_q)mstore(0x3080, result) }mstore(0x30a0, mulmod(mload(0x3080), mload(0x2c80), f_q))mstore(0x30c0, mulmod(sub(f_q, mload(0x30a0)), 1, f_q))mstore(0x30e0, mulmod(mload(0x30c0), 1, f_q))mstore(0x3100, mulmod(1, mload(0x2ca0), f_q)){ let result := mulmod(mload(0x840), mload(0x28c0), f_q)result := addmod(mulmod(mload(0x860), mload(0x2920), f_q), result, f_q)mstore(0x3120, result) }mstore(0x3140, mulmod(mload(0x3120), mload(0x2ea0), f_q))mstore(0x3160, mulmod(sub(f_q, mload(0x3140)), 1, f_q))mstore(0x3180, mulmod(mload(0x3100), 1, f_q)){ let result := mulmod(mload(0x880), mload(0x28c0), f_q)result := addmod(mulmod(mload(0x8a0), mload(0x2920), f_q), result, f_q)mstore(0x31a0, result) }mstore(0x31c0, mulmod(mload(0x31a0), mload(0x2ea0), f_q))mstore(0x31e0, mulmod(sub(f_q, mload(0x31c0)), mload(0x940), f_q))mstore(0x3200, mulmod(mload(0x3100), mload(0x940), f_q))mstore(0x3220, addmod(mload(0x3160), mload(0x31e0), f_q))mstore(0x3240, mulmod(mload(0x3220), mload(0x9a0), f_q))mstore(0x3260, mulmod(mload(0x3180), mload(0x9a0), f_q))mstore(0x3280, mulmod(mload(0x3200), mload(0x9a0), f_q))mstore(0x32a0, addmod(mload(0x30e0), mload(0x3240), f_q))mstore(0x32c0, mulmod(1, mload(0x2ce0), f_q)){ let result := mulmod(mload(0x8c0), mload(0x2980), f_q)result := addmod(mulmod(mload(0x8e0), mload(0x29e0), f_q), result, f_q)mstore(0x32e0, result) }mstore(0x3300, mulmod(mload(0x32e0), mload(0x2ec0), f_q))mstore(0x3320, mulmod(sub(f_q, mload(0x3300)), 1, f_q))mstore(0x3340, mulmod(mload(0x32c0), 1, f_q))mstore(0x3360, mulmod(mload(0x3320), mload(0x3020), f_q))mstore(0x3380, mulmod(mload(0x3340), mload(0x3020), f_q))mstore(0x33a0, addmod(mload(0x32a0), mload(0x3360), f_q))mstore(0x33c0, mulmod(1, mload(0x2d20), f_q)){ let result := mulmod(mload(0x900), mload(0x2a20), f_q)mstore(0x33e0, result) }mstore(0x3400, mulmod(mload(0x33e0), mload(0x2ee0), f_q))mstore(0x3420, mulmod(sub(f_q, mload(0x3400)), 1, f_q))mstore(0x3440, mulmod(mload(0x33c0), 1, f_q)){ let result := mulmod(mload(0x740), mload(0x2a20), f_q)mstore(0x3460, result) }mstore(0x3480, mulmod(mload(0x3460), mload(0x2ee0), f_q))mstore(0x34a0, mulmod(sub(f_q, mload(0x3480)), mload(0x940), f_q))mstore(0x34c0, mulmod(mload(0x33c0), mload(0x940), f_q))mstore(0x34e0, addmod(mload(0x3420), mload(0x34a0), f_q)){ let result := mulmod(mload(0x760), mload(0x2a20), f_q)mstore(0x3500, result) }mstore(0x3520, mulmod(mload(0x3500), mload(0x2ee0), f_q))mstore(0x3540, mulmod(sub(f_q, mload(0x3520)), mload(0x2f00), f_q))mstore(0x3560, mulmod(mload(0x33c0), mload(0x2f00), f_q))mstore(0x3580, addmod(mload(0x34e0), mload(0x3540), f_q)){ let result := mulmod(mload(0x780), mload(0x2a20), f_q)mstore(0x35a0, result) }mstore(0x35c0, mulmod(mload(0x35a0), mload(0x2ee0), f_q))mstore(0x35e0, mulmod(sub(f_q, mload(0x35c0)), mload(0x2f20), f_q))mstore(0x3600, mulmod(mload(0x33c0), mload(0x2f20), f_q))mstore(0x3620, addmod(mload(0x3580), mload(0x35e0), f_q)){ let result := mulmod(mload(0x7a0), mload(0x2a20), f_q)mstore(0x3640, result) }mstore(0x3660, mulmod(mload(0x3640), mload(0x2ee0), f_q))mstore(0x3680, mulmod(sub(f_q, mload(0x3660)), mload(0x2f40), f_q))mstore(0x36a0, mulmod(mload(0x33c0), mload(0x2f40), f_q))mstore(0x36c0, addmod(mload(0x3620), mload(0x3680), f_q)){ let result := mulmod(mload(0x7e0), mload(0x2a20), f_q)mstore(0x36e0, result) }mstore(0x3700, mulmod(mload(0x36e0), mload(0x2ee0), f_q))mstore(0x3720, mulmod(sub(f_q, mload(0x3700)), mload(0x2f60), f_q))mstore(0x3740, mulmod(mload(0x33c0), mload(0x2f60), f_q))mstore(0x3760, addmod(mload(0x36c0), mload(0x3720), f_q)){ let result := mulmod(mload(0x800), mload(0x2a20), f_q)mstore(0x3780, result) }mstore(0x37a0, mulmod(mload(0x3780), mload(0x2ee0), f_q))mstore(0x37c0, mulmod(sub(f_q, mload(0x37a0)), mload(0x2f80), f_q))mstore(0x37e0, mulmod(mload(0x33c0), mload(0x2f80), f_q))mstore(0x3800, addmod(mload(0x3760), mload(0x37c0), f_q)){ let result := mulmod(mload(0x820), mload(0x2a20), f_q)mstore(0x3820, result) }mstore(0x3840, mulmod(mload(0x3820), mload(0x2ee0), f_q))mstore(0x3860, mulmod(sub(f_q, mload(0x3840)), mload(0x2fa0), f_q))mstore(0x3880, mulmod(mload(0x33c0), mload(0x2fa0), f_q))mstore(0x38a0, addmod(mload(0x3800), mload(0x3860), f_q))mstore(0x38c0, mulmod(mload(0x2480), mload(0x2d20), f_q))mstore(0x38e0, mulmod(mload(0x24a0), mload(0x2d20), f_q))mstore(0x3900, mulmod(mload(0x24c0), mload(0x2d20), f_q)){ let result := mulmod(mload(0x24e0), mload(0x2a20), f_q)mstore(0x3920, result) }mstore(0x3940, mulmod(mload(0x3920), mload(0x2ee0), f_q))mstore(0x3960, mulmod(sub(f_q, mload(0x3940)), mload(0x2fc0), f_q))mstore(0x3980, mulmod(mload(0x33c0), mload(0x2fc0), f_q))mstore(0x39a0, mulmod(mload(0x38c0), mload(0x2fc0), f_q))mstore(0x39c0, mulmod(mload(0x38e0), mload(0x2fc0), f_q))mstore(0x39e0, mulmod(mload(0x3900), mload(0x2fc0), f_q))mstore(0x3a00, addmod(mload(0x38a0), mload(0x3960), f_q)){ let result := mulmod(mload(0x7c0), mload(0x2a20), f_q)mstore(0x3a20, result) }mstore(0x3a40, mulmod(mload(0x3a20), mload(0x2ee0), f_q))mstore(0x3a60, mulmod(sub(f_q, mload(0x3a40)), mload(0x2fe0), f_q))mstore(0x3a80, mulmod(mload(0x33c0), mload(0x2fe0), f_q))mstore(0x3aa0, addmod(mload(0x3a00), mload(0x3a60), f_q))mstore(0x3ac0, mulmod(mload(0x3aa0), mload(0x3040), f_q))mstore(0x3ae0, mulmod(mload(0x3440), mload(0x3040), f_q))mstore(0x3b00, mulmod(mload(0x34c0), mload(0x3040), f_q))mstore(0x3b20, mulmod(mload(0x3560), mload(0x3040), f_q))mstore(0x3b40, mulmod(mload(0x3600), mload(0x3040), f_q))mstore(0x3b60, mulmod(mload(0x36a0), mload(0x3040), f_q))mstore(0x3b80, mulmod(mload(0x3740), mload(0x3040), f_q))mstore(0x3ba0, mulmod(mload(0x37e0), mload(0x3040), f_q))mstore(0x3bc0, mulmod(mload(0x3880), mload(0x3040), f_q))mstore(0x3be0, mulmod(mload(0x3980), mload(0x3040), f_q))mstore(0x3c00, mulmod(mload(0x39a0), mload(0x3040), f_q))mstore(0x3c20, mulmod(mload(0x39c0), mload(0x3040), f_q))mstore(0x3c40, mulmod(mload(0x39e0), mload(0x3040), f_q))mstore(0x3c60, mulmod(mload(0x3a80), mload(0x3040), f_q))mstore(0x3c80, addmod(mload(0x33a0), mload(0x3ac0), f_q))mstore(0x3ca0, mulmod(1, mload(0x2860), f_q))mstore(0x3cc0, mulmod(1, mload(0xa40), f_q))mstore(0x3ce0, 0x0000000000000000000000000000000000000000000000000000000000000001) mstore(0x3d00, 0x0000000000000000000000000000000000000000000000000000000000000002)mstore(0x3d20, mload(0x3c80))success := and(eq(staticcall(gas(), 0x7, 0x3ce0, 0x60, 0x3ce0, 0x40), 1), success)mstore(0x3d40, mload(0x3ce0)) mstore(0x3d60, mload(0x3d00))mstore(0x3d80, mload(0x260)) mstore(0x3da0, mload(0x280))success := and(eq(staticcall(gas(), 0x6, 0x3d40, 0x80, 0x3d40, 0x40), 1), success)mstore(0x3dc0, mload(0x440)) mstore(0x3de0, mload(0x460))mstore(0x3e00, mload(0x3260))success := and(eq(staticcall(gas(), 0x7, 0x3dc0, 0x60, 0x3dc0, 0x40), 1), success)mstore(0x3e20, mload(0x3d40)) mstore(0x3e40, mload(0x3d60))mstore(0x3e60, mload(0x3dc0)) mstore(0x3e80, mload(0x3de0))success := and(eq(staticcall(gas(), 0x6, 0x3e20, 0x80, 0x3e20, 0x40), 1), success)mstore(0x3ea0, mload(0x480)) mstore(0x3ec0, mload(0x4a0))mstore(0x3ee0, mload(0x3280))success := and(eq(staticcall(gas(), 0x7, 0x3ea0, 0x60, 0x3ea0, 0x40), 1), success)mstore(0x3f00, mload(0x3e20)) mstore(0x3f20, mload(0x3e40))mstore(0x3f40, mload(0x3ea0)) mstore(0x3f60, mload(0x3ec0))success := and(eq(staticcall(gas(), 0x6, 0x3f00, 0x80, 0x3f00, 0x40), 1), success)mstore(0x3f80, mload(0x300)) mstore(0x3fa0, mload(0x320))mstore(0x3fc0, mload(0x3380))success := and(eq(staticcall(gas(), 0x7, 0x3f80, 0x60, 0x3f80, 0x40), 1), success)mstore(0x3fe0, mload(0x3f00)) mstore(0x4000, mload(0x3f20))mstore(0x4020, mload(0x3f80)) mstore(0x4040, mload(0x3fa0))success := and(eq(staticcall(gas(), 0x6, 0x3fe0, 0x80, 0x3fe0, 0x40), 1), success)mstore(0x4060, mload(0x340)) mstore(0x4080, mload(0x360))mstore(0x40a0, mload(0x3ae0))success := and(eq(staticcall(gas(), 0x7, 0x4060, 0x60, 0x4060, 0x40), 1), success)mstore(0x40c0, mload(0x3fe0)) mstore(0x40e0, mload(0x4000))mstore(0x4100, mload(0x4060)) mstore(0x4120, mload(0x4080))success := and(eq(staticcall(gas(), 0x6, 0x40c0, 0x80, 0x40c0, 0x40), 1), success)mstore(0x4140, 0x2ee1a46553f256c57ee6cb05e97c6b2cee68b52afa6eb9594b0b6bed1a1da16c) mstore(0x4160, 0x155b8cd1fb98f80bd3fd688ce7c4c151ffc80dd80f8bacbf93425a8cc75d4798)mstore(0x4180, mload(0x3b00))success := and(eq(staticcall(gas(), 0x7, 0x4140, 0x60, 0x4140, 0x40), 1), success)mstore(0x41a0, mload(0x40c0)) mstore(0x41c0, mload(0x40e0))mstore(0x41e0, mload(0x4140)) mstore(0x4200, mload(0x4160))success := and(eq(staticcall(gas(), 0x6, 0x41a0, 0x80, 0x41a0, 0x40), 1), success)mstore(0x4220, 0x0ba574041b9acf0b879828f757fdbe006ec303bb00e85d005f97abcd2607422d) mstore(0x4240, 0x25383b7c510633308b668f09fe22cbd16b83d898660128f6f5390ca909c737fa)mstore(0x4260, mload(0x3b20))success := and(eq(staticcall(gas(), 0x7, 0x4220, 0x60, 0x4220, 0x40), 1), success)mstore(0x4280, mload(0x41a0)) mstore(0x42a0, mload(0x41c0))mstore(0x42c0, mload(0x4220)) mstore(0x42e0, mload(0x4240))success := and(eq(staticcall(gas(), 0x6, 0x4280, 0x80, 0x4280, 0x40), 1), success)mstore(0x4300, 0x2791f81a6904461f649d0e9721cb4a56e033e188b17403bab35f964c2933adea) mstore(0x4320, 0x1b957ffe9eee2e38474fc73d00762637eb2f42f93dbd63b07ac3a7a80d01fcd8)mstore(0x4340, mload(0x3b40))success := and(eq(staticcall(gas(), 0x7, 0x4300, 0x60, 0x4300, 0x40), 1), success)mstore(0x4360, mload(0x4280)) mstore(0x4380, mload(0x42a0))mstore(0x43a0, mload(0x4300)) mstore(0x43c0, mload(0x4320))success := and(eq(staticcall(gas(), 0x6, 0x4360, 0x80, 0x4360, 0x40), 1), success)mstore(0x43e0, 0x1c0d239ee9e8daa18d0898f4091a6d571e50441d852906e11d0fae1d1dedb1fb) mstore(0x4400, 0x0749d3ee27e89e899d6b17981c477f185f713dc32c470a6b8ebfae12370a852d)mstore(0x4420, mload(0x3b60))success := and(eq(staticcall(gas(), 0x7, 0x43e0, 0x60, 0x43e0, 0x40), 1), success)mstore(0x4440, mload(0x4360)) mstore(0x4460, mload(0x4380))mstore(0x4480, mload(0x43e0)) mstore(0x44a0, mload(0x4400))success := and(eq(staticcall(gas(), 0x6, 0x4440, 0x80, 0x4440, 0x40), 1), success)mstore(0x44c0, 0x1d06036774832c1ae8b66aedd888bcb23218f6d8919edada11695d2fa45c3c94) mstore(0x44e0, 0x154238d64a88cc1428d92d04c3afa6c43e4335a2729f4e2fb1c537a16939478d)mstore(0x4500, mload(0x3b80))success := and(eq(staticcall(gas(), 0x7, 0x44c0, 0x60, 0x44c0, 0x40), 1), success)mstore(0x4520, mload(0x4440)) mstore(0x4540, mload(0x4460))mstore(0x4560, mload(0x44c0)) mstore(0x4580, mload(0x44e0))success := and(eq(staticcall(gas(), 0x6, 0x4520, 0x80, 0x4520, 0x40), 1), success)mstore(0x45a0, 0x2c7029d9d4be107fa480642e2845a780b55009050482fe811fef42f9b287cc4a) mstore(0x45c0, 0x071603ec9e8ab439219821e1b9d054f627e98591a3101d3c33ece436cd7e1482)mstore(0x45e0, mload(0x3ba0))success := and(eq(staticcall(gas(), 0x7, 0x45a0, 0x60, 0x45a0, 0x40), 1), success)mstore(0x4600, mload(0x4520)) mstore(0x4620, mload(0x4540))mstore(0x4640, mload(0x45a0)) mstore(0x4660, mload(0x45c0))success := and(eq(staticcall(gas(), 0x6, 0x4600, 0x80, 0x4600, 0x40), 1), success)mstore(0x4680, 0x02d518a4f6d68ae5997ad24fe8b58068acb972cfe8b250ab82e5390d91914950) mstore(0x46a0, 0x0695bba443e1eeed7cf440186dde2e72ebf1ec3f84d8baf57ee1cbe7f36df70d)mstore(0x46c0, mload(0x3bc0))success := and(eq(staticcall(gas(), 0x7, 0x4680, 0x60, 0x4680, 0x40), 1), success)mstore(0x46e0, mload(0x4600)) mstore(0x4700, mload(0x4620))mstore(0x4720, mload(0x4680)) mstore(0x4740, mload(0x46a0))success := and(eq(staticcall(gas(), 0x6, 0x46e0, 0x80, 0x46e0, 0x40), 1), success)mstore(0x4760, mload(0x560)) mstore(0x4780, mload(0x580))mstore(0x47a0, mload(0x3be0))success := and(eq(staticcall(gas(), 0x7, 0x4760, 0x60, 0x4760, 0x40), 1), success)mstore(0x47c0, mload(0x46e0)) mstore(0x47e0, mload(0x4700))mstore(0x4800, mload(0x4760)) mstore(0x4820, mload(0x4780))success := and(eq(staticcall(gas(), 0x6, 0x47c0, 0x80, 0x47c0, 0x40), 1), success)mstore(0x4840, mload(0x5a0)) mstore(0x4860, mload(0x5c0))mstore(0x4880, mload(0x3c00))success := and(eq(staticcall(gas(), 0x7, 0x4840, 0x60, 0x4840, 0x40), 1), success)mstore(0x48a0, mload(0x47c0)) mstore(0x48c0, mload(0x47e0))mstore(0x48e0, mload(0x4840)) mstore(0x4900, mload(0x4860))success := and(eq(staticcall(gas(), 0x6, 0x48a0, 0x80, 0x48a0, 0x40), 1), success)mstore(0x4920, mload(0x5e0)) mstore(0x4940, mload(0x600))mstore(0x4960, mload(0x3c20))success := and(eq(staticcall(gas(), 0x7, 0x4920, 0x60, 0x4920, 0x40), 1), success)mstore(0x4980, mload(0x48a0)) mstore(0x49a0, mload(0x48c0))mstore(0x49c0, mload(0x4920)) mstore(0x49e0, mload(0x4940))success := and(eq(staticcall(gas(), 0x6, 0x4980, 0x80, 0x4980, 0x40), 1), success)mstore(0x4a00, mload(0x620)) mstore(0x4a20, mload(0x640))mstore(0x4a40, mload(0x3c40))success := and(eq(staticcall(gas(), 0x7, 0x4a00, 0x60, 0x4a00, 0x40), 1), success)mstore(0x4a60, mload(0x4980)) mstore(0x4a80, mload(0x49a0))mstore(0x4aa0, mload(0x4a00)) mstore(0x4ac0, mload(0x4a20))success := and(eq(staticcall(gas(), 0x6, 0x4a60, 0x80, 0x4a60, 0x40), 1), success)mstore(0x4ae0, mload(0x4c0)) mstore(0x4b00, mload(0x4e0))mstore(0x4b20, mload(0x3c60))success := and(eq(staticcall(gas(), 0x7, 0x4ae0, 0x60, 0x4ae0, 0x40), 1), success)mstore(0x4b40, mload(0x4a60)) mstore(0x4b60, mload(0x4a80))mstore(0x4b80, mload(0x4ae0)) mstore(0x4ba0, mload(0x4b00))success := and(eq(staticcall(gas(), 0x6, 0x4b40, 0x80, 0x4b40, 0x40), 1), success)mstore(0x4bc0, mload(0x9e0)) mstore(0x4be0, mload(0xa00))mstore(0x4c00, sub(f_q, mload(0x3ca0)))success := and(eq(staticcall(gas(), 0x7, 0x4bc0, 0x60, 0x4bc0, 0x40), 1), success)mstore(0x4c20, mload(0x4b40)) mstore(0x4c40, mload(0x4b60))mstore(0x4c60, mload(0x4bc0)) mstore(0x4c80, mload(0x4be0))success := and(eq(staticcall(gas(), 0x6, 0x4c20, 0x80, 0x4c20, 0x40), 1), success)mstore(0x4ca0, mload(0xa80)) mstore(0x4cc0, mload(0xaa0))mstore(0x4ce0, mload(0x3cc0))success := and(eq(staticcall(gas(), 0x7, 0x4ca0, 0x60, 0x4ca0, 0x40), 1), success)mstore(0x4d00, mload(0x4c20)) mstore(0x4d20, mload(0x4c40))mstore(0x4d40, mload(0x4ca0)) mstore(0x4d60, mload(0x4cc0))success := and(eq(staticcall(gas(), 0x6, 0x4d00, 0x80, 0x4d00, 0x40), 1), success)mstore(0x4d80, mload(0x4d00)) mstore(0x4da0, mload(0x4d20))mstore(0x4dc0, mload(0xa80)) mstore(0x4de0, mload(0xaa0))mstore(0x4e00, mload(0xac0)) mstore(0x4e20, mload(0xae0))mstore(0x4e40, mload(0xb00)) mstore(0x4e60, mload(0xb20))mstore(0x4e80, keccak256(0x4d80, 256))mstore(0x4ea0, mod(mload(19968), f_q))mstore(0x4ec0, mulmod(mload(0x4ea0), mload(0x4ea0), f_q))mstore(0x4ee0, mulmod(1, mload(0x4ea0), f_q))mstore(0x4f00, mload(0x4e00)) mstore(0x4f20, mload(0x4e20))mstore(0x4f40, mload(0x4ee0))success := and(eq(staticcall(gas(), 0x7, 0x4f00, 0x60, 0x4f00, 0x40), 1), success)mstore(0x4f60, mload(0x4d80)) mstore(0x4f80, mload(0x4da0))mstore(0x4fa0, mload(0x4f00)) mstore(0x4fc0, mload(0x4f20))success := and(eq(staticcall(gas(), 0x6, 0x4f60, 0x80, 0x4f60, 0x40), 1), success)mstore(0x4fe0, mload(0x4e40)) mstore(0x5000, mload(0x4e60))mstore(0x5020, mload(0x4ee0))success := and(eq(staticcall(gas(), 0x7, 0x4fe0, 0x60, 0x4fe0, 0x40), 1), success)mstore(0x5040, mload(0x4dc0)) mstore(0x5060, mload(0x4de0))mstore(0x5080, mload(0x4fe0)) mstore(0x50a0, mload(0x5000))success := and(eq(staticcall(gas(), 0x6, 0x5040, 0x80, 0x5040, 0x40), 1), success)mstore(0x50c0, mload(0x4f60)) mstore(0x50e0, mload(0x4f80))mstore(0x5100, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) mstore(0x5120, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) mstore(0x5140, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) mstore(0x5160, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)mstore(0x5180, mload(0x5040)) mstore(0x51a0, mload(0x5060))mstore(0x51c0, 0x0181624e80f3d6ae28df7e01eaeab1c0e919877a3b8a6b7fbc69a6817d596ea2) mstore(0x51e0, 0x1783d30dcb12d259bb89098addf6280fa4b653be7a152542a28f7b926e27e648) mstore(0x5200, 0x00ae44489d41a0d179e2dfdc03bddd883b7109f8b6ae316a59e815c1a6b35304) mstore(0x5220, 0x0b2147ab62a386bd63e6de1522109b8c9588ab466f5aadfde8c41ca3749423ee)success := and(eq(staticcall(gas(), 0x8, 0x50c0, 0x180, 0x50c0, 0x20), 1), success)success := and(eq(mload(0x50c0), 1), success)} return success; } } diff --git a/contracts/src/EndianConversions.sol b/contracts/src/EndianConversions.sol deleted file mode 100644 index e12bd7b..0000000 --- a/contracts/src/EndianConversions.sol +++ /dev/null @@ -1,27 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -library EndianConversions { - function toLittleEndian64(uint64 v) internal pure returns (bytes8) { - v = ((v & 0xFF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF) << 8); - v = ((v & 0xFFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF) << 16); - v = ((v & 0xFFFFFFFF00000000) >> 32) | ((v & 0x00000000FFFFFFFF) << 32); - return bytes8(v); - } - - function toLittleEndian(uint256 v) internal pure returns (bytes32) { - v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) - | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); - v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) - | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); - v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) - | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); - v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) - | ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); - v = (v >> 128) | (v << 128); - return bytes32(v); - } -} diff --git a/contracts/src/RotateLib.sol b/contracts/src/RotateLib.sol deleted file mode 100644 index e97a844..0000000 --- a/contracts/src/RotateLib.sol +++ /dev/null @@ -1,46 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -import { EndianConversions } from "./EndianConversions.sol"; - -library RotateLib { - - struct RotateInput { - bytes32 syncCommitteeSSZ; - uint256 syncCommitteePoseidon; - uint256[12] accumulator; - } - - /** - * @notice Compute the public input commitment for the rotation - * This must always match the method used in lightclient-circuits/src/committee_udate_circuit.rs - CommitteeUpdateCircuit::instance() - * @param args The arguments for the sync step - * @return The public input commitment that can be sent to the verifier contract. - */ - function toPublicInputs(RotateInput memory args, bytes32 finalizedHeaderRoot) internal pure returns (uint256[77] memory) { - uint256[77] memory inputs; - - for (uint256 i = 0; i < args.accumulator.length; i++) { - inputs[i] = args.accumulator[i]; - } - - inputs[args.accumulator.length] = args.syncCommitteePoseidon; - - uint256 syncCommitteeSSZNumeric = uint256(args.syncCommitteeSSZ); - for (uint256 i = 0; i < 32; i++) { - inputs[args.accumulator.length + 32 - i] = syncCommitteeSSZNumeric % 2 ** 8; - syncCommitteeSSZNumeric = syncCommitteeSSZNumeric / 2 ** 8; - } - - uint256 finalizedHeaderRootNumeric = uint256(finalizedHeaderRoot); - for (uint256 j = 0; j < 32; j++) { - inputs[args.accumulator.length + 64 - j] = finalizedHeaderRootNumeric % 2 ** 8; - finalizedHeaderRootNumeric = finalizedHeaderRootNumeric / 2 ** 8; - } - - return inputs; - } -} diff --git a/contracts/src/Spectre.sol b/contracts/src/Spectre.sol deleted file mode 100644 index 88ef4d0..0000000 --- a/contracts/src/Spectre.sol +++ /dev/null @@ -1,130 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -import {SyncStepLib} from "./SyncStepLib.sol"; -import {RotateLib} from "./RotateLib.sol"; -import {SyncStepCompressedVerifier} from "./interfaces/SyncStepVerifier.sol"; -import {CommitteeUpdateVerifier} from "./interfaces/CommitteeUpdateVerifier.sol"; - -contract Spectre { - using SyncStepLib for SyncStepLib.SyncStepInput; - using RotateLib for RotateLib.RotateInput; - - uint256 internal immutable SLOTS_PER_PERIOD; - - /// Maps from a sync period to the poseidon commitment for the sync committee. - mapping(uint256 => uint256) public syncCommitteePoseidons; - - /// Maps from a slot to a beacon block header root. - mapping(uint256 => bytes32) public blockHeaderRoots; - - /// Maps from a slot to the current finalized ethereum1 execution state root. - mapping(uint256 => bytes32) public executionPayloadRoots; - - /// The highest slot that has been verified - uint256 public head = 0; - - SyncStepCompressedVerifier public immutable stepVerifier; - CommitteeUpdateVerifier public immutable committeeUpdateVerifier; - - constructor( - address _stepVerifierAddress, - address _committeeUpdateVerifierAddress, - uint256 _initialSyncPeriod, - uint256 _initialSyncCommitteePoseidon, - uint256 _slotsPerPeriod - ) { - stepVerifier = SyncStepCompressedVerifier(_stepVerifierAddress); - committeeUpdateVerifier = CommitteeUpdateVerifier( - _committeeUpdateVerifierAddress - ); - syncCommitteePoseidons[ - _initialSyncPeriod - ] = _initialSyncCommitteePoseidon; - SLOTS_PER_PERIOD = _slotsPerPeriod; - } - - /// @notice Verify that a sync committee has attested to a block that finalizes the given header root and execution payload - /// @param input The input to the sync step. Defines the slot and attestation to verify - /// @param proof The proof for the sync step - function step( - SyncStepLib.SyncStepInput calldata input, - bytes calldata proof - ) external { - uint256 currentPeriod = getSyncCommitteePeriod(input.attestedSlot); - - if (syncCommitteePoseidons[currentPeriod] == 0) { - revert("Sync committee not yet set for this period"); - } - uint256[14] memory pubInputs = input.toPublicInputs( - syncCommitteePoseidons[currentPeriod] - ); - - bool success = stepVerifier.verify(pubInputs, proof); - if (!success) { - revert("Proof verification failed"); - } - - // update the contract state - executionPayloadRoots[input.finalizedSlot] = input.executionPayloadRoot; - blockHeaderRoots[input.finalizedSlot] = input.finalizedHeaderRoot; - head = input.finalizedSlot; - } - - /// @notice Use the current sync committee to verify the transition to a new sync committee - /// @param rotateInput The input to the sync step. - /// @param rotateProof The proof for the rotation - /// @param stepInput The input to the sync step. - /// @param stepProof The proof for the sync step - function rotate( - RotateLib.RotateInput calldata rotateInput, - bytes calldata rotateProof, - SyncStepLib.SyncStepInput calldata stepInput, - bytes calldata stepProof - ) external { - // *step phase* - // This allows trusting that the current sync committee has signed off on the finalizedHeaderRoot which is used as the base of the SSZ proof - // that checks the new committee is in the beacon state 'next_sync_committee' field. It also allows trusting the finalizedSlot which is - // used to calculate the sync period that the new committee belongs to. - uint256 attestingPeriod = getSyncCommitteePeriod( - stepInput.attestedSlot - ); - - uint256[14] memory stepVeriferInputs = stepInput.toPublicInputs( - syncCommitteePoseidons[attestingPeriod] - ); - - bool stepSuccess = stepVerifier.verify(stepVeriferInputs, stepProof); - if (!stepSuccess) { - revert("Step proof verification failed"); - } - - // *rotation phase* - // This proof checks that the given poseidon commitment and SSZ commitment to the sync committee are equivalent and that - // that there exists an SSZ proof that can verify this SSZ commitment to the committee is in the state - uint256 currentPeriod = getSyncCommitteePeriod(stepInput.finalizedSlot); - uint256 nextPeriod = currentPeriod + 1; - uint256[77] memory rotateVerifierInputs = rotateInput.toPublicInputs( - stepInput.finalizedHeaderRoot - ); - bool rotateSuccess = committeeUpdateVerifier.verify( - rotateVerifierInputs, - rotateProof - ); - if (!rotateSuccess) { - revert("Rotation proof verification failed"); - } - - // update the contract state - syncCommitteePoseidons[nextPeriod] = rotateInput.syncCommitteePoseidon; - } - - function getSyncCommitteePeriod( - uint256 slot - ) internal view returns (uint256) { - return slot / SLOTS_PER_PERIOD; - } -} diff --git a/contracts/src/SyncStepLib.sol b/contracts/src/SyncStepLib.sol deleted file mode 100644 index 838de73..0000000 --- a/contracts/src/SyncStepLib.sol +++ /dev/null @@ -1,48 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -import { EndianConversions } from "./EndianConversions.sol"; - -library SyncStepLib { - struct SyncStepInput { - uint64 attestedSlot; - uint64 finalizedSlot; - uint64 participation; - bytes32 finalizedHeaderRoot; - bytes32 executionPayloadRoot; - uint256[12] accumulator; - } - - /** - * @notice Compute the public input commitment for the sync step given this input. - * This must always match the prodecure used in lightclient-circuits/src/sync_step_circuit.rs - SyncStepCircuit::instance() - * @param args The arguments for the sync step - * @return The public input commitment that can be sent to the verifier contract. - */ - function toPublicInputs(SyncStepInput memory args, uint256 syncCommitteePoseidon) internal pure returns (uint256[14] memory) { - uint256[14] memory inputs; - - for (uint256 i = 0; i < args.accumulator.length; i++) { - inputs[i] = args.accumulator[i]; - } - - bytes32 h = sha256(abi.encodePacked( - EndianConversions.toLittleEndian64(args.attestedSlot), - EndianConversions.toLittleEndian64(args.finalizedSlot), - EndianConversions.toLittleEndian64(args.participation), - args.finalizedHeaderRoot, - args.executionPayloadRoot - )); - uint256 commitment = uint256(EndianConversions.toLittleEndian(uint256(h))); - - - - inputs[args.accumulator.length] = commitment & ((uint256(1) << 253) - 1); // truncated to 253 bits - inputs[args.accumulator.length + 1] = syncCommitteePoseidon; - - return inputs; - } -} diff --git a/contracts/src/interfaces/CommitteeUpdateVerifier.sol b/contracts/src/interfaces/CommitteeUpdateVerifier.sol deleted file mode 100644 index 3ca1356..0000000 --- a/contracts/src/interfaces/CommitteeUpdateVerifier.sol +++ /dev/null @@ -1,9 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -interface CommitteeUpdateVerifier { - function verify(uint256[77] calldata pubInputs, bytes calldata proof) external returns (bool); -} diff --git a/contracts/src/interfaces/SyncStepVerifier.sol b/contracts/src/interfaces/SyncStepVerifier.sol deleted file mode 100644 index 354a23a..0000000 --- a/contracts/src/interfaces/SyncStepVerifier.sol +++ /dev/null @@ -1,13 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -interface SyncStepVerifier { - function verify(uint256[2] calldata input, bytes calldata proof) external returns (bool); -} - -interface SyncStepCompressedVerifier { - function verify(uint256[14] calldata pubInputs, bytes calldata proof) external returns (bool); -} diff --git a/contracts/src/mocks/CommitteeUpdateMockVerifier.sol b/contracts/src/mocks/CommitteeUpdateMockVerifier.sol deleted file mode 100644 index 674b1cc..0000000 --- a/contracts/src/mocks/CommitteeUpdateMockVerifier.sol +++ /dev/null @@ -1,14 +0,0 @@ - -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -import { CommitteeUpdateVerifier } from "../interfaces/CommitteeUpdateVerifier.sol"; - -contract CommitteeUpdateMockVerifier is CommitteeUpdateVerifier { - function verify(uint256[77] calldata _input, bytes calldata _proof) external override returns (bool) { - return true; - } -} diff --git a/contracts/src/mocks/SyncStepMockVerifier.sol b/contracts/src/mocks/SyncStepMockVerifier.sol deleted file mode 100644 index c7d1800..0000000 --- a/contracts/src/mocks/SyncStepMockVerifier.sol +++ /dev/null @@ -1,20 +0,0 @@ - -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity ^0.8.0; - -import { SyncStepVerifier, SyncStepCompressedVerifier } from "../interfaces/SyncStepVerifier.sol"; - -contract SyncStepMockVerifier is SyncStepVerifier { - function verify(uint256[2] calldata _input, bytes calldata _proof) external override returns (bool) { - return true; - } -} - -contract SyncStepCompressedMockVerifier is SyncStepCompressedVerifier { - function verify(uint256[14] calldata _input, bytes calldata _proof) external override returns (bool) { - return true; - } -} diff --git a/contracts/test/RotateExternal.sol b/contracts/test/RotateExternal.sol deleted file mode 100644 index e9a29b9..0000000 --- a/contracts/test/RotateExternal.sol +++ /dev/null @@ -1,26 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity 0.8.19; - -import { RotateLib } from "../src/RotateLib.sol"; - -/** -* @title RotateExternal -* @dev This contract exists solely for the purpose of exposing the RotateLib functions -* so they can be used in the Rust test suite. It should not be part of a production deployment -*/ -contract RotateExternal { - using RotateLib for RotateLib.RotateInput; - - function toPublicInputs(RotateLib.RotateInput calldata args, bytes32 finalizedHeaderRoot) public pure returns (uint256[] memory) { - uint256[77] memory commitment = args.toPublicInputs(finalizedHeaderRoot); - // copy all elements into a dynamic array. We need to do this because ethers-rs has a bug that can't support uint256[65] return types - uint256[] memory result = new uint256[](77); - for (uint256 i = 0; i < commitment.length; i++) { - result[i] = commitment[i]; - } - return result; - } -} diff --git a/contracts/test/SyncStepExternal.sol b/contracts/test/SyncStepExternal.sol deleted file mode 100644 index ec021f3..0000000 --- a/contracts/test/SyncStepExternal.sol +++ /dev/null @@ -1,23 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -pragma solidity 0.8.19; - -import {SyncStepLib} from "../src/SyncStepLib.sol"; - -/** - * @title SyncStepExternal - * @dev This contract exists solely for the purpose of exposing the SyncStepLib functions - * so they can be used in the Rust test suite. It should not be part of a production deployment - */ -contract SyncStepExternal { - using SyncStepLib for SyncStepLib.SyncStepInput; - - function toPublicInputs( - SyncStepLib.SyncStepInput calldata args, - uint256 syncCommitteePoseidon - ) public pure returns (uint256[14] memory) { - return args.toPublicInputs(syncCommitteePoseidon); - } -} From 2165bb7f33fce2766f15f4de83161b81e7fea18c Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 12:29:53 +0100 Subject: [PATCH 09/18] add contracts add submodule --- .gitmodules | 6 +++--- Cargo.toml | 2 +- contracts | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) create mode 160000 contracts diff --git a/.gitmodules b/.gitmodules index c65a596..fa69608 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "contracts/lib/forge-std"] - path = contracts/lib/forge-std - url = https://github.com/foundry-rs/forge-std +[submodule "contracts"] + path = contracts + url = https://github.com/ChainSafe/spectre-contracts diff --git a/Cargo.toml b/Cargo.toml index abc7fc0..c8b5a3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ "eth-types", # "contract-tests", # "test-utils", - "contracts", + # "contracts", ] resolver = "2" diff --git a/contracts b/contracts new file mode 160000 index 0000000..9023975 --- /dev/null +++ b/contracts @@ -0,0 +1 @@ +Subproject commit 9023975417b2eae18b54cf02e70e0f35a960e7ed From 376f3e8fefc6c0b87d44c6e0951205b329a3123c Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 12:58:48 +0100 Subject: [PATCH 10/18] contract tests (wip) --- Cargo.toml | 2 +- .../tests/rotation_input_encoding.rs | 109 ------------------ contract-tests/tests/spectre.rs | 10 +- contract-tests/tests/step_input_encoding.rs | 25 ++-- prover/src/rpc.rs | 32 ++--- 5 files changed, 22 insertions(+), 156 deletions(-) delete mode 100644 contract-tests/tests/rotation_input_encoding.rs diff --git a/Cargo.toml b/Cargo.toml index c8b5a3f..5478ac7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = [ "prover", "preprocessor", "eth-types", - # "contract-tests", + "contract-tests", # "test-utils", # "contracts", ] diff --git a/contract-tests/tests/rotation_input_encoding.rs b/contract-tests/tests/rotation_input_encoding.rs deleted file mode 100644 index 7ca77e5..0000000 --- a/contract-tests/tests/rotation_input_encoding.rs +++ /dev/null @@ -1,109 +0,0 @@ -// The Licensed Work is (c) 2023 ChainSafe -// Code: https://github.com/ChainSafe/Spectre -// SPDX-License-Identifier: LGPL-3.0-only - -#![allow(incomplete_features)] -#![feature(generic_const_exprs)] - -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; -use lightclient_circuits::poseidon::poseidon_committee_commitment_from_compressed; -use lightclient_circuits::witness::CommitteeUpdateArgs; -use rstest::rstest; -use ssz_rs::prelude::*; -use ssz_rs::Merkleized; -use std::ops::Deref; -use test_utils::read_test_files_and_gen_witness; - -abigen!( - RotateExternal, - "../contracts/out/RotateExternal.sol/RotateExternal.json" -); - -// CommitteeRotationArgs type produced by abigen macro matches the solidity struct type -impl From> for RotateInput -where - [(); Spec::SYNC_COMMITTEE_SIZE]:, -{ - fn from(args: CommitteeUpdateArgs) -> Self { - let poseidon_commitment = poseidon_committee_commitment_from_compressed( - &args.pubkeys_compressed.iter().cloned().collect_vec(), - ); - let sync_committee_poseidon = - ethers::prelude::U256::from_little_endian(&poseidon_commitment.to_bytes()); - - 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, - // this can be anything.. The test is just checking it gets correctly concatenated to the start of the encoded input - accumulator: Default::default(), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[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<()> { - use contract_tests::decode_solidity_u256_array; - - let (_, witness) = read_test_files_and_gen_witness(&path); - - let instance = - CommitteeUpdateCircuit::::get_instances(&witness, LIMB_BITS); - let finalized_block_root = witness - .finalized_header - .clone() - .hash_tree_root() - .unwrap() - .deref() - .try_into() - .unwrap(); - - let (_anvil_instance, ethclient) = make_client(); - let contract = RotateExternal::deploy(ethclient, ())?.send().await?; - - let rotate_input = RotateInput::from(witness); - let result = contract - .to_public_inputs(rotate_input.clone(), finalized_block_root) - .call() - .await?; - - let result_decoded = decode_solidity_u256_array(&result); - let accumulator = decode_solidity_u256_array(&rotate_input.accumulator); - // The expected result is the concatenation of the accumulator and the instance - let expected: Vec<_> = accumulator.iter().chain(instance[0].iter()).collect(); - assert_eq!(result_decoded.iter().collect::>(), expected); - Ok(()) - } -} diff --git a/contract-tests/tests/spectre.rs b/contract-tests/tests/spectre.rs index 9f9a700..43e006b 100644 --- a/contract-tests/tests/spectre.rs +++ b/contract-tests/tests/spectre.rs @@ -10,9 +10,7 @@ use std::path::PathBuf; use std::sync::Arc; use contract_tests::make_client; -use contracts::{ - CommitteeUpdateMockVerifier, Spectre, SyncStepCompressedMockVerifier, SyncStepInput, -}; +use contracts::{MockVerifier, Spectre}; use ethers::core::types::U256; use ethers::providers::Middleware; use rstest::rstest; @@ -55,7 +53,7 @@ async fn test_contract_initialization_and_first_step( assert_eq!(contract.head().call().await?, U256::from(0)); // call step with the input and proof - let step_input: SyncStepInput = witness.into(); + let step_input: contracts::StepInput = witness.into(); let step_call = contract.step(step_input.clone(), Vec::new().into()); let _receipt = step_call.send().await?.confirmations(1).await?; @@ -85,10 +83,10 @@ async fn deploy_spectre_mock_verifiers( initial_sync_committee_poseidon: U256, slots_per_period: usize, ) -> anyhow::Result> { - let step_verifier = SyncStepCompressedMockVerifier::deploy(ethclient.clone(), ())? + let step_verifier = MockVerifier::deploy(ethclient.clone(), ())? .send() .await?; - let update_verifier = CommitteeUpdateMockVerifier::deploy(ethclient.clone(), ())? + let update_verifier = MockVerifier::deploy(ethclient.clone(), ())? .send() .await?; Ok(Spectre::deploy( diff --git a/contract-tests/tests/step_input_encoding.rs b/contract-tests/tests/step_input_encoding.rs index ac4d0dc..89235ba 100644 --- a/contract-tests/tests/step_input_encoding.rs +++ b/contract-tests/tests/step_input_encoding.rs @@ -9,19 +9,18 @@ use contract_tests::make_client; use eth_types::{Minimal, LIMB_BITS}; use ethers::contract::abigen; use lightclient_circuits::halo2_proofs::halo2curves::bn256; -use lightclient_circuits::sync_step_circuit::StepCircuit; use lightclient_circuits::witness::SyncStepArgs; use rstest::rstest; use ssz_rs::Merkleized; use test_utils::read_test_files_and_gen_witness; abigen!( - SyncStepExternal, - "../contracts/out/SyncStepExternal.sol/SyncStepExternal.json" + StepExternal, + "../contracts/out/StepExternal.sol/StepExternal.json"; ); // SyncStepInput type produced by abigen macro matches the solidity struct type -impl From> for SyncStepInput { +impl From> for StepInput { fn from(args: SyncStepArgs) -> Self { let participation = args .pariticipation_bits @@ -40,13 +39,12 @@ impl From> for SyncStepInput { let execution_payload_root: [u8; 32] = args.execution_payload_root.try_into().unwrap(); - SyncStepInput { + StepInput { attested_slot: args.attested_header.slot, finalized_slot: args.finalized_header.slot, participation, finalized_header_root, execution_payload_root, - accumulator: Default::default(), } } } @@ -59,25 +57,22 @@ async fn test_step_instance_commitment_evm_equivalence( path: PathBuf, ) -> anyhow::Result<()> { use contract_tests::decode_solidity_u256_array; - use ethers::types::U256; let (witness, _) = read_test_files_and_gen_witness(&path); - let instance = StepCircuit::::get_instances(&witness, LIMB_BITS); + let instance = lightclient_circuits::sync_step_circuit::StepCircuit:: ::get_instances(&witness, LIMB_BITS); let (_anvil_instance, ethclient) = make_client(); - let contract = SyncStepExternal::deploy(ethclient, ())?.send().await?; + let contract = StepExternal::deploy(ethclient, ())?.send().await?; let result = contract - .to_public_inputs( - SyncStepInput::from(witness), - U256::from_little_endian(&instance[0][1].to_bytes()), + .to_public_inputs_commitment( + StepInput::from(witness), ) .call() .await?; - let result_decoded = decode_solidity_u256_array(&result); + let result_decoded = decode_solidity_u256_array(&[result]); - assert_eq!(result_decoded[12], instance[0][0]); // public input commitment - assert_eq!(result_decoded[13], instance[0][1]); // committee poseidon + assert_eq!(result_decoded[0], instance[0][0]); // public input commitment Ok(()) } diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index dd41e5c..707886e 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -15,6 +15,7 @@ use lightclient_circuits::halo2_proofs::poly::kzg::commitment::ParamsKZG; use lightclient_circuits::sync_step_circuit::StepCircuit; use lightclient_circuits::{committee_update_circuit::CommitteeUpdateCircuit, util::AppCircuit}; use preprocessor::{rotation_args_from_update, step_args_from_finality_update}; +use snark_verifier_sdk::evm::encode_calldata; use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, Snark}; use spectre_prover::prover::ProverState; use std::path::{Path, PathBuf}; @@ -99,23 +100,13 @@ where ) .map_err(JsonRpcError::internal)?; - // Should be of length 77 initially then 12 after removing the last 65 elements which is the accumulator. - // 12 field elems pairing, 1 byte poseidon commitment, 32 bytes ssz commitment, 32 bytes finalized header root - let mut instances = instances[0] - .iter() - .map(|pi| U256::from_little_endian(&pi.to_bytes())) - .collect_vec(); + let calldata = encode_calldata(&instances, &proof); - let public_inputs = instances.split_off(12); - let accumulator: [U256; 12] = instances.try_into().unwrap(); - - let committee_poseidon = public_inputs[0]; + let committee_poseidon = U256::from_little_endian(&instances[0][12].to_bytes()); Ok(CommitteeUpdateEvmProofResult { - proof, - accumulator, + proof: calldata, committee_poseidon, - public_inputs, }) } @@ -135,6 +126,7 @@ where e ))); }; + let GenProofStepParams { light_client_finality_update, domain, @@ -162,19 +154,9 @@ where ) .map_err(JsonRpcError::internal)?; - let mut instances = instances[0] - .iter() - .map(|pi| U256::from_little_endian(&pi.to_bytes())) - .collect_vec(); + let calldata = encode_calldata(&instances, &proof); - let public_inputs = instances.split_off(12); - let accumulator: [U256; 12] = instances.try_into().unwrap(); - - Ok(SyncStepCompressedEvmProofResult { - proof, - accumulator, - public_inputs, - }) + Ok(SyncStepCompressedEvmProofResult { proof: calldata }) } fn gen_uncompressed_snark( From 5df36c7b8826bbbd32433e333ac2394a0e310ef0 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 14:00:04 +0100 Subject: [PATCH 11/18] update submodule --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 9023975..4418b0d 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 9023975417b2eae18b54cf02e70e0f35a960e7ed +Subproject commit 4418b0d2b4a28a79405558954a1721f1793ddc0d From 5e058f892429bb4c037b71af9ff64729247d5d7b Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 14:04:47 +0100 Subject: [PATCH 12/18] chore --- Cargo.toml | 4 +- contract-tests/tests/spectre.rs | 8 +- contract-tests/tests/step_input_encoding.rs | 9 +- .../src/committee_update_circuit.rs | 2 - .../src/gadget/crypto/sha256_flex/gate.rs | 5 - .../src/gadget/crypto/sha256_wide/gate.rs | 3 +- lightclient-circuits/src/poseidon.rs | 3 +- lightclient-circuits/src/sync_step_circuit.rs | 2 +- lightclient-circuits/src/util/bytes.rs | 8 +- lightclient-circuits/src/util/circuit.rs | 2 +- .../src/witness/multiproof.rs | 4 +- lightclient-circuits/src/witness/rotation.rs | 4 +- lightclient-circuits/tests/step.rs | 364 +++++++++--------- prover/src/rpc.rs | 1 - 14 files changed, 205 insertions(+), 214 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5478ac7..47d4509 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,8 @@ members = [ "preprocessor", "eth-types", "contract-tests", - # "test-utils", - # "contracts", + "test-utils", + "contracts", ] resolver = "2" diff --git a/contract-tests/tests/spectre.rs b/contract-tests/tests/spectre.rs index 43e006b..5637aef 100644 --- a/contract-tests/tests/spectre.rs +++ b/contract-tests/tests/spectre.rs @@ -83,12 +83,8 @@ async fn deploy_spectre_mock_verifiers( initial_sync_committee_poseidon: U256, slots_per_period: usize, ) -> anyhow::Result> { - let step_verifier = MockVerifier::deploy(ethclient.clone(), ())? - .send() - .await?; - let update_verifier = MockVerifier::deploy(ethclient.clone(), ())? - .send() - .await?; + let step_verifier = MockVerifier::deploy(ethclient.clone(), ())?.send().await?; + let update_verifier = MockVerifier::deploy(ethclient.clone(), ())?.send().await?; Ok(Spectre::deploy( ethclient, ( diff --git a/contract-tests/tests/step_input_encoding.rs b/contract-tests/tests/step_input_encoding.rs index 89235ba..cf2c2e6 100644 --- a/contract-tests/tests/step_input_encoding.rs +++ b/contract-tests/tests/step_input_encoding.rs @@ -59,15 +59,16 @@ async fn test_step_instance_commitment_evm_equivalence( use contract_tests::decode_solidity_u256_array; let (witness, _) = read_test_files_and_gen_witness(&path); - let instance = lightclient_circuits::sync_step_circuit::StepCircuit:: ::get_instances(&witness, LIMB_BITS); + let instance = + lightclient_circuits::sync_step_circuit::StepCircuit::::get_instances( + &witness, LIMB_BITS, + ); let (_anvil_instance, ethclient) = make_client(); let contract = StepExternal::deploy(ethclient, ())?.send().await?; let result = contract - .to_public_inputs_commitment( - StepInput::from(witness), - ) + .to_public_inputs_commitment(StepInput::from(witness)) .call() .await?; let result_decoded = decode_solidity_u256_array(&[result]); diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index f9996be..5739cc6 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -109,8 +109,6 @@ impl CommitteeUpdateCircuit { S::SYNC_COMMITTEE_PUBKEYS_ROOT_INDEX, )?; - println!("ffinalized_header_root: {:?}", finalized_header_root.iter().map(|v| v.value()).collect_vec()); - let finalized_header_root_lo_hi = bytes_be_to_u128( builder.main(), &range.gate, diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs index 901480a..a8248ad 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs @@ -2,8 +2,6 @@ // Code: https://github.com/ChainSafe/Spectre // SPDX-License-Identifier: LGPL-3.0-only -use std::any::TypeId; - use eth_types::Field; use getset::CopyGetters; use halo2_base::{ @@ -22,9 +20,6 @@ use super::SpreadConfig; pub const FIRST_PHASE: usize = 0; -struct Dence; -struct Spread; - /// `ShaFlexGateManager` keeps track of halo2-lib virtual cells and assigns them to the region corresponding to the `SpreadConfig`. /// It also loads of the copy (permutation) constraints between halo2-lib and vanilla cells in Plonk table. #[derive(Clone, Debug, Default, CopyGetters)] diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs index 144091e..1037637 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs @@ -13,7 +13,8 @@ use halo2_base::{ }, virtual_region::{ copy_constraints::SharedCopyConstraintManager, manager::VirtualRegionManager, - }, AssignedValue, + }, + AssignedValue, }; use itertools::Itertools; use zkevm_hashes::{ diff --git a/lightclient-circuits/src/poseidon.rs b/lightclient-circuits/src/poseidon.rs index 56f018a..16082d2 100644 --- a/lightclient-circuits/src/poseidon.rs +++ b/lightclient-circuits/src/poseidon.rs @@ -54,10 +54,9 @@ pub fn fq_array_poseidon<'a, F: Field>( let zero = ctx.load_zero(); ctx.constrain_equal(extra, &zero); } - + limbs .chunks(2) - .into_iter() .map(|limbs| gate.inner_product(ctx, limbs.to_vec(), limbs_bases.clone())) .collect_vec() }) diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 7196018..63078d8 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -271,7 +271,7 @@ impl StepCircuit { let poseidon_commitment = poseidon_hash_fq_array::(pubkey_affines.iter().map(|p| p.x), limb_bits); - let mut public_input_commitment = sha2::Sha256::digest(&input).to_vec(); + let mut public_input_commitment = sha2::Sha256::digest(input).to_vec(); // Truncate to 253 bits public_input_commitment[31] &= 0b00011111; diff --git a/lightclient-circuits/src/util/bytes.rs b/lightclient-circuits/src/util/bytes.rs index 356b6f1..6251933 100644 --- a/lightclient-circuits/src/util/bytes.rs +++ b/lightclient-circuits/src/util/bytes.rs @@ -1,4 +1,7 @@ -use halo2_base::{gates::GateInstructions, safe_types::SafeByte, utils::BigPrimeField, AssignedValue, Context, QuantumCell}; +use halo2_base::{ + gates::GateInstructions, safe_types::SafeByte, utils::BigPrimeField, AssignedValue, Context, + QuantumCell, +}; use itertools::Itertools; pub fn bytes_be_to_u128( @@ -23,7 +26,8 @@ pub(crate) fn limbs_be_to_u128( gate.inner_product( ctx, chunk.iter().rev().map(|a| *a.as_ref()), - (0..chunk.len()).map(|idx| QuantumCell::Constant(gate.pow_of_two()[limb_bits * idx])), + (0..chunk.len()) + .map(|idx| QuantumCell::Constant(gate.pow_of_two()[limb_bits * idx])), ) }) .collect_vec() diff --git a/lightclient-circuits/src/util/circuit.rs b/lightclient-circuits/src/util/circuit.rs index 9f29741..030cea3 100644 --- a/lightclient-circuits/src/util/circuit.rs +++ b/lightclient-circuits/src/util/circuit.rs @@ -17,7 +17,7 @@ use halo2_base::halo2_proofs::{ }; use serde::{Deserialize, Serialize}; use snark_verifier_sdk::evm::{ - encode_calldata, evm_verify, 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::gen_proof_shplonk; use snark_verifier_sdk::{gen_pk, halo2::gen_snark_shplonk, read_pk}; diff --git a/lightclient-circuits/src/witness/multiproof.rs b/lightclient-circuits/src/witness/multiproof.rs index a675dad..59ec59f 100644 --- a/lightclient-circuits/src/witness/multiproof.rs +++ b/lightclient-circuits/src/witness/multiproof.rs @@ -149,9 +149,7 @@ pub fn calculate_multi_merkle_root( hasher.update(left_input.as_ref()); hasher.update(right_input.as_ref()); - let parent = objects - .entry(parent_index) - .or_default(); + let parent = objects.entry(parent_index).or_default(); parent.as_mut().copy_from_slice(&hasher.finalize_reset()); keys.push(parent_index); } diff --git a/lightclient-circuits/src/witness/rotation.rs b/lightclient-circuits/src/witness/rotation.rs index ae8abc3..8539b46 100644 --- a/lightclient-circuits/src/witness/rotation.rs +++ b/lightclient-circuits/src/witness/rotation.rs @@ -32,7 +32,7 @@ impl Default for CommitteeUpdateArgs { let sync_committee_branch = vec![vec![0; 32]; S::SYNC_COMMITTEE_PUBKEYS_DEPTH]; let hashed_pk = sha2::Sha256::digest( - &dummy_x_bytes + dummy_x_bytes .iter() .copied() .pad_using(64, |_| 0) @@ -48,7 +48,7 @@ impl Default for CommitteeUpdateArgs { chunks = chunks .into_iter() .tuples() - .map(|(left, right)| sha2::Sha256::digest(&[left, right].concat()).to_vec()) + .map(|(left, right)| sha2::Sha256::digest([left, right].concat()).to_vec()) .collect(); } diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index dc7d3b1..e0797dc 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -1,182 +1,182 @@ -// // The Licensed Work is (c) 2023 ChainSafe -// // Code: https://github.com/ChainSafe/Spectre -// // SPDX-License-Identifier: LGPL-3.0-only - -// use ark_std::{end_timer, start_timer}; -// use eth_types::{Minimal, LIMB_BITS}; -// use eth_types::{Spec, NUM_LIMBS}; -// use halo2_base::gates::circuit::CircuitBuilderStage; -// use halo2_base::halo2_proofs::dev::MockProver; -// use halo2_base::halo2_proofs::halo2curves::bn256; -// use halo2_base::utils::fs::gen_srs; -// use halo2_ecc::bls12_381::FpChip; -// use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; -// use lightclient_circuits::gadget::crypto::{ShaBitGateManager, ShaFlexGateManager}; -// use lightclient_circuits::sync_step_circuit::StepCircuit; -// use lightclient_circuits::util::AppCircuit; -// use lightclient_circuits::util::Eth2ConfigPinning; -// use lightclient_circuits::util::Halo2ConfigPinning; -// use lightclient_circuits::witness::CommitteeUpdateArgs; -// use lightclient_circuits::witness::SyncStepArgs; -// use lightclient_circuits::Eth2CircuitBuilder; -// use rstest::rstest; -// use snark_verifier_sdk::CircuitExt; -// use std::env::var; -// use std::path::PathBuf; - -// use test_utils::read_test_files_and_gen_witness; - -// #[rstest] -// fn test_eth2_spec_mock_1( -// #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/light_client_sync")] -// #[exclude("deneb*")] -// path: PathBuf, -// ) { -// run_test_eth2_spec_mock::<18, 19>(path) -// } - -// // Same as StepCircuit::create_circuit without loading SRS which fails CI. -// pub(crate) fn mock_step_circuit( -// args: &SyncStepArgs, -// k: u32, -// lookup_bits: Option, -// ) -> impl lightclient_circuits::util::PinnableCircuit { -// let mut builder = -// Eth2CircuitBuilder::>::from_stage(CircuitBuilderStage::Mock) -// .use_k(k as usize) -// .use_instance_columns(1); -// let range = builder.range_chip(lookup_bits.unwrap_or(k as usize - 1)); -// let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); - -// let assigned_instances = -// StepCircuit::::synthesize(&mut builder, &fp_chip, args).unwrap(); -// builder.set_instances(0, assigned_instances); - -// builder.calculate_params(Some( -// var("MINIMUM_ROWS") -// .unwrap_or_else(|_| "0".to_string()) -// .parse() -// .unwrap(), -// )); -// builder -// } - -// // Same as CommitteeUpdateCircuit::create_circuit without loading SRS which fails CI. -// pub(crate) fn mock_committee_update_circuit( -// witness: &CommitteeUpdateArgs, -// k: u32, -// lookup_bits: Option, -// ) -> impl lightclient_circuits::util::PinnableCircuit { -// let mut builder = -// Eth2CircuitBuilder::>::from_stage(CircuitBuilderStage::Mock) -// .use_k(k as usize) -// .use_instance_columns(1); -// let range = builder.range_chip(lookup_bits.unwrap_or(k as usize - 1)); -// let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); - -// let assigned_instances = -// CommitteeUpdateCircuit::::synthesize(&mut builder, &fp_chip, witness) -// .unwrap(); -// builder.set_instances(0, assigned_instances); -// builder.calculate_params(Some( -// var("MINIMUM_ROWS") -// .unwrap_or_else(|_| "0".to_string()) -// .parse() -// .unwrap(), -// )); -// builder -// } - -// fn run_test_eth2_spec_mock(path: PathBuf) { -// let (sync_witness, rotation_witness) = read_test_files_and_gen_witness(&path); - -// let rotation_circuit = mock_committee_update_circuit(&rotation_witness, K_ROTATION, None); - -// let rotation_instance = -// CommitteeUpdateCircuit::::get_instances(&rotation_witness, LIMB_BITS); -// let timer = start_timer!(|| "committee_update mock prover run"); -// let prover = -// MockProver::::run(K_ROTATION, &rotation_circuit, rotation_instance).unwrap(); -// prover.assert_satisfied(); -// end_timer!(timer); - -// let sync_circuit = mock_step_circuit(&sync_witness, K_SYNC, None); - -// let instance = StepCircuit::::get_instances(&sync_witness, LIMB_BITS); - -// let timer = start_timer!(|| "sync_step mock prover run"); -// let prover = MockProver::::run(K_SYNC, &sync_circuit, instance).unwrap(); -// prover.assert_satisfied(); -// end_timer!(timer); -// } - -// #[rstest] -// fn test_eth2_spec_proofgen( -// #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] -// #[exclude("deneb*")] -// path: PathBuf, -// ) { -// const K: u32 = 20; -// let (witness, _) = read_test_files_and_gen_witness(&path); - -// let params = gen_srs(K); -// let pk = StepCircuit::::create_pk( -// ¶ms, -// "../build/sync_step_20.pkey", -// "./config/sync_step_20.json", -// &SyncStepArgs::::default(), -// None, -// ); - -// let _ = StepCircuit::::gen_proof_shplonk( -// ¶ms, -// &pk, -// "./config/sync_step_20.json", -// &witness, -// ) -// .expect("proof generation & verification should not fail"); -// } - -// #[rstest] -// fn test_eth2_spec_evm_verify( -// #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] -// #[exclude("deneb*")] -// path: PathBuf, -// ) { -// const K: u32 = 21; -// let params = gen_srs(K); - -// let pk = StepCircuit::::create_pk( -// ¶ms, -// "../build/sync_step_21.pkey", -// "./config/sync_step_21.json", -// &SyncStepArgs::::default(), -// None, -// ); - -// let (witness, _) = read_test_files_and_gen_witness(&path); - -// let pinning = Eth2ConfigPinning::from_path("./config/sync_step_21.json"); - -// let circuit = StepCircuit::::create_circuit( -// CircuitBuilderStage::Prover, -// Some(pinning), -// &witness, -// ¶ms, -// ) -// .unwrap(); - -// let instances = circuit.instances(); -// let proof = -// snark_verifier_sdk::evm::gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); -// println!("proof size: {}", proof.len()); -// let deployment_code = StepCircuit::::gen_evm_verifier_shplonk( -// ¶ms, -// &pk, -// None::, -// &witness, -// ) -// .unwrap(); -// println!("deployment_code size: {}", deployment_code.len()); -// snark_verifier_sdk::evm::evm_verify(deployment_code, instances, proof); -// } +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + +use ark_std::{end_timer, start_timer}; +use eth_types::{Minimal, LIMB_BITS}; +use eth_types::{Spec, NUM_LIMBS}; +use halo2_base::gates::circuit::CircuitBuilderStage; +use halo2_base::halo2_proofs::dev::MockProver; +use halo2_base::halo2_proofs::halo2curves::bn256; +use halo2_base::utils::fs::gen_srs; +use halo2_ecc::bls12_381::FpChip; +use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; +use lightclient_circuits::gadget::crypto::{ShaBitGateManager, ShaFlexGateManager}; +use lightclient_circuits::sync_step_circuit::StepCircuit; +use lightclient_circuits::util::AppCircuit; +use lightclient_circuits::util::Eth2ConfigPinning; +use lightclient_circuits::util::Halo2ConfigPinning; +use lightclient_circuits::witness::CommitteeUpdateArgs; +use lightclient_circuits::witness::SyncStepArgs; +use lightclient_circuits::Eth2CircuitBuilder; +use rstest::rstest; +use snark_verifier_sdk::CircuitExt; +use std::env::var; +use std::path::PathBuf; + +use test_utils::read_test_files_and_gen_witness; + +#[rstest] +fn test_eth2_spec_mock_1( + #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/light_client_sync")] + #[exclude("deneb*")] + path: PathBuf, +) { + run_test_eth2_spec_mock::<18, 19>(path) +} + +// Same as StepCircuit::create_circuit without loading SRS which fails CI. +pub(crate) fn mock_step_circuit( + args: &SyncStepArgs, + k: u32, + lookup_bits: Option, +) -> impl lightclient_circuits::util::PinnableCircuit { + let mut builder = + Eth2CircuitBuilder::>::from_stage(CircuitBuilderStage::Mock) + .use_k(k as usize) + .use_instance_columns(1); + let range = builder.range_chip(lookup_bits.unwrap_or(k as usize - 1)); + let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); + + let assigned_instances = + StepCircuit::::synthesize(&mut builder, &fp_chip, args).unwrap(); + builder.set_instances(0, assigned_instances); + + builder.calculate_params(Some( + var("MINIMUM_ROWS") + .unwrap_or_else(|_| "0".to_string()) + .parse() + .unwrap(), + )); + builder +} + +// Same as CommitteeUpdateCircuit::create_circuit without loading SRS which fails CI. +pub(crate) fn mock_committee_update_circuit( + witness: &CommitteeUpdateArgs, + k: u32, + lookup_bits: Option, +) -> impl lightclient_circuits::util::PinnableCircuit { + let mut builder = + Eth2CircuitBuilder::>::from_stage(CircuitBuilderStage::Mock) + .use_k(k as usize) + .use_instance_columns(1); + let range = builder.range_chip(lookup_bits.unwrap_or(k as usize - 1)); + let fp_chip = FpChip::new(&range, LIMB_BITS, NUM_LIMBS); + + let assigned_instances = + CommitteeUpdateCircuit::::synthesize(&mut builder, &fp_chip, witness) + .unwrap(); + builder.set_instances(0, assigned_instances); + builder.calculate_params(Some( + var("MINIMUM_ROWS") + .unwrap_or_else(|_| "0".to_string()) + .parse() + .unwrap(), + )); + builder +} + +fn run_test_eth2_spec_mock(path: PathBuf) { + let (sync_witness, rotation_witness) = read_test_files_and_gen_witness(&path); + + let rotation_circuit = mock_committee_update_circuit(&rotation_witness, K_ROTATION, None); + + let rotation_instance = + CommitteeUpdateCircuit::::get_instances(&rotation_witness, LIMB_BITS); + let timer = start_timer!(|| "committee_update mock prover run"); + let prover = + MockProver::::run(K_ROTATION, &rotation_circuit, rotation_instance).unwrap(); + prover.assert_satisfied(); + end_timer!(timer); + + let sync_circuit = mock_step_circuit(&sync_witness, K_SYNC, None); + + let instance = StepCircuit::::get_instances(&sync_witness, LIMB_BITS); + + let timer = start_timer!(|| "sync_step mock prover run"); + let prover = MockProver::::run(K_SYNC, &sync_circuit, instance).unwrap(); + prover.assert_satisfied(); + end_timer!(timer); +} + +#[rstest] +fn test_eth2_spec_proofgen( + #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] + #[exclude("deneb*")] + path: PathBuf, +) { + const K: u32 = 20; + let (witness, _) = read_test_files_and_gen_witness(&path); + + let params = gen_srs(K); + let pk = StepCircuit::::create_pk( + ¶ms, + "../build/sync_step_20.pkey", + "./config/sync_step_20.json", + &SyncStepArgs::::default(), + None, + ); + + let _ = StepCircuit::::gen_proof_shplonk( + ¶ms, + &pk, + "./config/sync_step_20.json", + &witness, + ) + .expect("proof generation & verification should not fail"); +} + +#[rstest] +fn test_eth2_spec_evm_verify( + #[files("../consensus-spec-tests/tests/minimal/capella/light_client/sync/pyspec_tests/**")] + #[exclude("deneb*")] + path: PathBuf, +) { + const K: u32 = 21; + let params = gen_srs(K); + + let pk = StepCircuit::::create_pk( + ¶ms, + "../build/sync_step_21.pkey", + "./config/sync_step_21.json", + &SyncStepArgs::::default(), + None, + ); + + let (witness, _) = read_test_files_and_gen_witness(&path); + + let pinning = Eth2ConfigPinning::from_path("./config/sync_step_21.json"); + + let circuit = StepCircuit::::create_circuit( + CircuitBuilderStage::Prover, + Some(pinning), + &witness, + ¶ms, + ) + .unwrap(); + + let instances = circuit.instances(); + let proof = + snark_verifier_sdk::evm::gen_evm_proof_shplonk(¶ms, &pk, circuit, instances.clone()); + println!("proof size: {}", proof.len()); + let deployment_code = StepCircuit::::gen_evm_verifier_shplonk( + ¶ms, + &pk, + None::, + &witness, + ) + .unwrap(); + println!("deployment_code size: {}", deployment_code.len()); + snark_verifier_sdk::evm::evm_verify(deployment_code, instances, proof); +} diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index 707886e..c285cc7 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -5,7 +5,6 @@ use ark_std::{end_timer, start_timer}; use axum::{http::StatusCode, response::IntoResponse, routing::post, Router}; use ethers::prelude::*; -use itertools::Itertools; use jsonrpc_v2::{Data, RequestObject as JsonRpcRequestObject}; use jsonrpc_v2::{Error as JsonRpcError, Params}; use jsonrpc_v2::{MapRouter as JsonRpcMapRouter, Server as JsonRpcServer}; From 81c92d216654012abb46aad3c2e78ad03f17d765 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 15:23:35 +0100 Subject: [PATCH 13/18] fix tests --- Cargo.toml | 2 +- contract-tests/tests/spectre.rs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 47d4509..bdd14a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git ] } # ethereum types -ethereum-consensus-types = { git = "https://github.com/ChainSafe/ethereum-consensus-types", branch = "deneb" } +ethereum-consensus-types = { git = "https://github.com/ChainSafe/ethereum-consensus-types", branch = "capella" } beacon-api-client = { git = "https://github.com/ralexstokes/ethereum-consensus.git", rev = "f3bff52e9c43866f231ec40c8ab0e34125a8957f" } ssz_rs = "0.9" diff --git a/contract-tests/tests/spectre.rs b/contract-tests/tests/spectre.rs index 5637aef..48b2127 100644 --- a/contract-tests/tests/spectre.rs +++ b/contract-tests/tests/spectre.rs @@ -11,14 +11,18 @@ use std::sync::Arc; use contract_tests::make_client; use contracts::{MockVerifier, Spectre}; +use eth_types::{Minimal, LIMB_BITS}; use ethers::core::types::U256; use ethers::providers::Middleware; +use halo2_base::halo2_proofs::halo2curves::bn256::Fr; +use lightclient_circuits::sync_step_circuit::StepCircuit; use rstest::rstest; use test_utils::{get_initial_sync_committee_poseidon, read_test_files_and_gen_witness}; const SLOTS_PER_EPOCH: usize = 8; const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: usize = 8; const SLOTS_PER_SYNC_COMMITTEE_PERIOD: usize = EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH; +const FINALITY_THRESHOLD: usize = 20; // ~ 2/3 of 32 #[tokio::test] async fn test_deploy_spectre() -> anyhow::Result<()> { @@ -52,9 +56,14 @@ async fn test_contract_initialization_and_first_step( // pre conditions assert_eq!(contract.head().call().await?, U256::from(0)); + let instances = StepCircuit::::get_instances(&witness, LIMB_BITS); + // call step with the input and proof let step_input: contracts::StepInput = witness.into(); - let step_call = contract.step(step_input.clone(), Vec::new().into()); + let mut proof = vec![0; 384]; + proof.extend(instances[0][0].to_bytes().into_iter().rev()); + proof.extend(instances[0][1].to_bytes().into_iter().rev()); + let step_call = contract.step(step_input.clone(), proof.into()); let _receipt = step_call.send().await?.confirmations(1).await?; // post conditions @@ -93,6 +102,7 @@ async fn deploy_spectre_mock_verifiers( U256::from(initial_sync_period), initial_sync_committee_poseidon, U256::from(slots_per_period), + U256::from(FINALITY_THRESHOLD) ), )? .send() From 9d5a8594251007bf7a2e1a688a73453431d1c5bd Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 15:34:05 +0100 Subject: [PATCH 14/18] remove unused dep on contracts --- test-utils/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index 70977df..0536fb8 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" lightclient-circuits = { workspace = true } ethereum-consensus-types = { workspace = true } eth-types = { workspace = true } -contracts = { workspace = true } ssz_rs = { workspace = true } halo2curves = { workspace = true } halo2-base = { workspace = true } From c41329f8233f6f8e07f07c4613cb9ef213c115c3 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 15:59:20 +0100 Subject: [PATCH 15/18] init submodules in gh actions --- .github/workflows/tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f1876fd..7e9a828 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -40,12 +40,14 @@ jobs: - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 + - name: init submodules + uses: snickerbockers/submodules-init@v4 + - name: Build contracts run: just build-contracts # skip this in favour of compiling in the `Test` action. # - name: Check # run: cargo check --all - - name: Test run: RUST_LOG="lightclient-circuits=debug" PARAMS_DIR="./test_data" cargo test --release test_eth2_spec_mock_1 -- --nocapture From 986e57f9b38c1de7659a114b18c4ef87f67e29d8 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 16:13:21 +0100 Subject: [PATCH 16/18] fix step circuit test --- lightclient-circuits/src/sync_step_circuit.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 63078d8..8b25db8 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -475,8 +475,7 @@ mod tests { ) .unwrap(); - // let instance = StepCircuit::::get_instances(&witness, LIMB_BITS); - let instance = circuit.instances(); + let instance = StepCircuit::::get_instances(&witness, LIMB_BITS); let timer = start_timer!(|| "sync_step mock prover"); let prover = MockProver::::run(K, &circuit, instance).unwrap(); From ac833064de9752faf1476c7375aff1f9911cdaa7 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 16:16:19 +0100 Subject: [PATCH 17/18] removed commeted code --- lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs index 1037637..5a39849 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs @@ -46,9 +46,6 @@ pub struct ShaBitGateManager { /// Witnesses of a sha256 which are necessary to be loaded into halo2-lib. #[derive(Clone, Copy, Debug, CopyGetters, Getters)] pub struct LoadedSha256 { - /// bytes_left of the first row of the first round of this keccak_f. This could be used to determine the length of the input. - // #[getset(get_copy = "pub")] - // pub(crate) bytes_left: AssignedValue, /// The output of this sha256. is_final/hash_lo/hash_hi come from the first row of the last round(NUM_ROUNDS). #[getset(get_copy = "pub")] @@ -61,7 +58,6 @@ pub struct LoadedSha256 { /// Input words (u64) of this keccak_f. #[getset(get = "pub")] pub word_values: [AssignedValue; NUM_WORDS_TO_ABSORB], - // pub(crate) length: AssignedValue, } impl CommonGateManager for ShaBitGateManager { From afa046af0d8c9fd4ba15e1eb61a593a655da8463 Mon Sep 17 00:00:00 2001 From: Timofey Luin Date: Wed, 21 Feb 2024 16:59:28 +0100 Subject: [PATCH 18/18] fix rotate circuti tests --- lightclient-circuits/src/committee_update_circuit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 5739cc6..ab95f7f 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -202,8 +202,8 @@ impl CommitteeUpdateCircuit { let finalized_header_root_hilo = { let bytes = finalized_header_root.as_ref(); - let hash_lo = u128::from_le_bytes(bytes[16..].try_into().unwrap()); - let hash_hi = u128::from_le_bytes(bytes[..16].try_into().unwrap()); + let hash_lo = u128::from_be_bytes(bytes[16..].try_into().unwrap()); + let hash_hi = u128::from_be_bytes(bytes[..16].try_into().unwrap()); [hash_lo, hash_hi].map(bn256::Fr::from_u128) };