diff --git a/.github/workflows/all-tools.yml b/.github/workflows/all-tools.yml index 380bcdf69..24d8a4a32 100644 --- a/.github/workflows/all-tools.yml +++ b/.github/workflows/all-tools.yml @@ -87,9 +87,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ssh-key: ${{ secrets.SELF_GITHUB_SSH_KEY }} submodules: true - persist-credentials: false - name: Login to Docker Hub uses: docker/login-action@v3 with: diff --git a/.github/workflows/coordinator-testing.yml b/.github/workflows/coordinator-testing.yml index edaf2e582..5758408d1 100644 --- a/.github/workflows/coordinator-testing.yml +++ b/.github/workflows/coordinator-testing.yml @@ -23,9 +23,9 @@ jobs: run-tests: env: COMMIT_TAG: ${{ inputs.commit_tag }} - GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN_RELEASE_ACCESS }} DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} runs-on: gha-runner-scale-set-ubuntu-22.04-amd64-large name: Coordinator tests steps: @@ -76,6 +76,7 @@ jobs: path: | ${{ github.workspace }}/build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml - name: Upload coverage to Codecov + if: ${{ env.CODECOV_TOKEN != '' }} uses: codecov/codecov-action@v5 with: fail_ci_if_error: true diff --git a/.github/workflows/postman-build-and-publish.yml b/.github/workflows/postman-build-and-publish.yml index 698aec842..b4cfca076 100644 --- a/.github/workflows/postman-build-and-publish.yml +++ b/.github/workflows/postman-build-and-publish.yml @@ -69,9 +69,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ssh-key: ${{ secrets.SELF_GITHUB_SSH_KEY }} submodules: true - persist-credentials: false - name: Login to Docker Hub if: ${{ env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }} uses: docker/login-action@v3 diff --git a/.github/workflows/prover-build-and-publish.yml b/.github/workflows/prover-build-and-publish.yml index fd8ad2029..1ebbf780b 100644 --- a/.github/workflows/prover-build-and-publish.yml +++ b/.github/workflows/prover-build-and-publish.yml @@ -72,9 +72,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ssh-key: ${{ secrets.SELF_GITHUB_SSH_KEY }} submodules: true - persist-credentials: false - name: Login to Docker Hub if: ${{ env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }} uses: docker/login-action@v3 diff --git a/.github/workflows/reuse-run-e2e-tests.yml b/.github/workflows/reuse-run-e2e-tests.yml index 44cd6e1da..f02dadf5c 100644 --- a/.github/workflows/reuse-run-e2e-tests.yml +++ b/.github/workflows/reuse-run-e2e-tests.yml @@ -71,7 +71,6 @@ jobs: PROVER_TAG: ${{ inputs.commit_tag }} TRACES_API_TAG: ${{ inputs.commit_tag }} TRANSACTION_EXCLUSION_API_TAG: ${{ inputs.commit_tag }} - GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN_RELEASE_ACCESS }} DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} outputs: diff --git a/.github/workflows/run-smc-tests.yml b/.github/workflows/run-smc-tests.yml index af94f3311..7f29d5386 100644 --- a/.github/workflows/run-smc-tests.yml +++ b/.github/workflows/run-smc-tests.yml @@ -31,6 +31,8 @@ jobs: run-contract-tests: runs-on: [self-hosted, ubuntu-20.04, X64, small] name: Run smart contracts tests + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} steps: - name: Checkout uses: actions/checkout@v4 @@ -69,6 +71,7 @@ jobs: run: pnpm -F contracts run coverage - name: Upload coverage to Codecov + if: ${{ env.CODECOV_TOKEN != '' }} uses: codecov/codecov-action@v5 with: fail_ci_if_error: true diff --git a/Makefile b/Makefile index 0621cca0b..5e8251a43 100644 --- a/Makefile +++ b/Makefile @@ -158,10 +158,12 @@ deploy-l2-evm-opcode-tester: RPC_URL=http:\\localhost:8545/ \ npx ts-node local-deployments-artifacts/deployLondonEvmTestingFramework.ts -execute-all-opcodes: + +evm-opcode-tester-execute-all-opcodes: OPCODE_TEST_CONTRACT_ADDRESS:=0x997FC3aF1F193Cbdc013060076c67A13e218980e +evm-opcode-tester-execute-all-opcodes: # WARNING: FOR LOCAL DEV ONLY - DO NOT REUSE THESE KEYS ELSEWHERE cd contracts/; \ - OPCODE_TEST_CONTRACT_ADDRESS=0x997FC3aF1F193Cbdc013060076c67A13e218980e \ + OPCODE_TEST_CONTRACT_ADDRESS=$(OPCODE_TEST_CONTRACT_ADDRESS) \ NUMBER_OF_RUNS=3 \ PRIVATE_KEY=0x1dd171cec7e2995408b5513004e8207fe88d6820aeff0d82463b3e41df251aae \ RPC_URL=http:\\localhost:8545/ \ @@ -216,11 +218,17 @@ deploy-contracts-minimal: cd .. && \ $(MAKE) -j6 deploy-linea-rollup-v$(L1_CONTRACT_VERSION) deploy-l2messageservice -start-all-staterecover: L1_CONTRACT_VERSION:=6 -start-all-staterecover: COMPOSE_PROFILES:=l1,l2,staterecover -start-all-staterecover: - L1_GENESIS_TIME=$(get_future_time) make start-whole-environment COMPOSE_PROFILES=$(COMPOSE_PROFILES) - make deploy-contracts-minimal L1_CONTRACT_VERSION=$(L1_CONTRACT_VERSION) +fresh-start-all-staterecover: COMPOSE_PROFILES:=l1,l2,staterecover +fresh-start-all-staterecover: L1_CONTRACT_VERSION:=6 +fresh-start-all-staterecover: + make clean-environment + L1_GENESIS_TIME=$(get_future_time) make start-whole-environment-traces-v2 COMPOSE_PROFILES=$(COMPOSE_PROFILES) + $(MAKE) deploy-contracts-minimal L1_CONTRACT_VERSION=$(L1_CONTRACT_VERSION) + +fresh-start-staterecover-for-replay-only: COMPOSE_PROFILES:=l1,staterecover +fresh-start-staterecover-for-replay-only: + make clean-environment + L1_GENESIS_TIME=$(get_future_time) make start-whole-environment-traces-v2 COMPOSE_PROFILES=$(COMPOSE_PROFILES) testnet-start-l2: docker compose -f docker/compose.yml -f docker/compose-testnet-sync.overrides.yml --profile l2 up -d diff --git a/build.gradle b/build.gradle index 46307076e..059745aa2 100644 --- a/build.gradle +++ b/build.gradle @@ -87,7 +87,7 @@ allprojects { systemProperty("L1_RPC_URL", "http://localhost:8445") systemProperty("L2_RPC_URL", "http://localhost:8545") systemProperty("L1_GENESIS", "docker/config/l1-node/el/genesis.json") - systemProperty("L2_GENESIS", "docker/config/linea-local-dev-genesis.json") + systemProperty("L2_GENESIS", "docker/config/linea-local-dev-genesis-PoA.json") systemProperties["junit.jupiter.execution.timeout.default"] = "5 m" // 5 minutes systemProperties["junit.jupiter.execution.parallel.enabled"] = true @@ -203,7 +203,8 @@ dockerCompose { "staterecover" ] useComposeFiles = [ - "${project.rootDir.path}/docker/compose.yml" + "${project.rootDir.path}/docker/compose.yml", + "${project.rootDir.path}/docker/compose-local-dev-traces-v2.overrides.yml" ] waitForHealthyStateTimeout = Duration.ofMinutes(3) waitForTcpPorts = false diff --git a/config/coordinator/coordinator-docker.config.toml b/config/coordinator/coordinator-docker.config.toml index 62ce6851f..781bb0b67 100644 --- a/config/coordinator/coordinator-docker.config.toml +++ b/config/coordinator/coordinator-docker.config.toml @@ -126,8 +126,8 @@ fee-history-reward-percentile=15 last-hash-search-window=25 anchoring-receipt-polling-interval="PT01S" max-receipt-retries=120 -# Number of children blocks to wait before considering a won't be reverted and elegible for conflation. -# this a workaround to mitigate Geth fork issues with Clique PoA +# Number of children blocks to wait before considering they won't be reverted and elegible for conflation. +# this is a workaround to mitigate Geth fork issues with Clique PoA # Coordinator will consider block as finalized after being included in the chain wtih children blocks-to-finalization # Recommended: Geth sequencer minimum of 2, Besu sequencer minimum of 1, 0 is safe localy blocks-to-finalization=0 @@ -155,7 +155,7 @@ aggregation-proofs-limit=3 aggregation-deadline="PT10S" aggregation-coordinator-polling-interval="PT2S" deadline-check-interval="PT8S" -target-end-blocks=[] +#target-end-blocks=[33, 90, 93] [finalization-signer] # Web3j/Web3signer @@ -266,8 +266,8 @@ num-of-blocks-before-latest=4 storage-period="PT2M" [conflation] -blocks-limit=2 -conflation-deadline="PT6S" # =3*l2_block_time +blocks-limit=3 +conflation-deadline="PT6S" conflation-deadline-check-interval="PT3S" conflation-deadline-last-block-confirmation-delay="PT2S" # recommended: at least 2 * blockInterval diff --git a/contracts/contracts/verifiers/PlonkVerifierForDataAggregation.sol b/contracts/contracts/verifiers/PlonkVerifierForDataAggregation.sol index 8670ce2a4..b7bbee3bf 100644 --- a/contracts/contracts/verifiers/PlonkVerifierForDataAggregation.sol +++ b/contracts/contracts/verifiers/PlonkVerifierForDataAggregation.sol @@ -19,29 +19,28 @@ pragma solidity 0.8.26; contract PlonkVerifierForDataAggregation { + uint256 private constant R_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint256 private constant R_MOD_MINUS_ONE = - 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 private constant R_MOD_MINUS_ONE = 21888242871839275222246405745257275088548364400416034343698204186575808495616; uint256 private constant P_MOD = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - + uint256 private constant G2_SRS_0_X_0 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; uint256 private constant G2_SRS_0_X_1 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; uint256 private constant G2_SRS_0_Y_0 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; uint256 private constant G2_SRS_0_Y_1 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; - + uint256 private constant G2_SRS_1_X_0 = 15805639136721018565402881920352193254830339253282065586954346329754995870280; uint256 private constant G2_SRS_1_X_1 = 19089565590083334368588890253123139704298730990782503769911324779715431555531; uint256 private constant G2_SRS_1_Y_0 = 9779648407879205346559610309258181044130619080926897934572699915909528404984; uint256 private constant G2_SRS_1_Y_1 = 6779728121489434657638426458390319301070371227460768374343986326751507916979; - + uint256 private constant G1_SRS_X = 14312776538779914388377568895031746459131577658076416373430523308756343304251; uint256 private constant G1_SRS_Y = 11763105256161367503191792604679297387056316997144156930871823008787082098465; // ----------------------- vk --------------------- uint256 private constant VK_NB_PUBLIC_INPUTS = 1; uint256 private constant VK_DOMAIN_SIZE = 16; - uint256 private constant VK_INV_DOMAIN_SIZE = - 20520227692349320520856005386178695395514091625390032197217066424914820464641; + uint256 private constant VK_INV_DOMAIN_SIZE = 20520227692349320520856005386178695395514091625390032197217066424914820464641; uint256 private constant VK_OMEGA = 14940766826517323942636479241147756311199852622225275649687664389641784935947; uint256 private constant VK_QL_COM_X = 3767637989833674092151354229632559107224950590673664856842061399469467338879; uint256 private constant VK_QL_COM_Y = 18545409996679466114224178746162553880737296402729089689774308937082946761979; @@ -53,21 +52,23 @@ contract PlonkVerifierForDataAggregation { uint256 private constant VK_QO_COM_Y = 10782414695040549646706468913781794882209258381887890407509684555513355143197; uint256 private constant VK_QK_COM_X = 309591480144351325314158474719361148480191595146291661238142838254651436989; uint256 private constant VK_QK_COM_Y = 12063173869829536468830946547606069911666129778788708678515573607390482939756; - + uint256 private constant VK_S1_COM_X = 12287072751694848944507699577006619791724925439540371477056092891137357229312; uint256 private constant VK_S1_COM_Y = 2469356406782415219782253630635766217009619642857495098799013714324696399305; - + uint256 private constant VK_S2_COM_X = 17261757720471042341269061128759148572672168808566386603388432325173708264418; uint256 private constant VK_S2_COM_Y = 20976565876611279190744172824963243461988367679364518747954008723085439460611; - + uint256 private constant VK_S3_COM_X = 18758025488249277181117376239193628449359868741625564388668468130204669284937; uint256 private constant VK_S3_COM_Y = 15566903578741238761792344329051427316196307361197991677131114502821508927172; - + uint256 private constant VK_COSET_SHIFT = 5; - + + uint256 private constant VK_QCP_0_X = 4559262075452024065272338216146989708834054079507534161096300708463935456394; uint256 private constant VK_QCP_0_Y = 1898950104727986554890445533779776634695458253078091580309593009754027486622; - + + uint256 private constant VK_INDEX_COMMIT_API_0 = 5; uint256 private constant VK_NB_CUSTOM_GATES = 1; @@ -77,7 +78,7 @@ contract PlonkVerifierForDataAggregation { uint256 private constant FIXED_PROOF_SIZE = 0x300; // offset proof - + uint256 private constant PROOF_L_COM_X = 0x0; uint256 private constant PROOF_L_COM_Y = 0x20; uint256 private constant PROOF_R_COM_X = 0x40; @@ -121,7 +122,7 @@ contract PlonkVerifierForDataAggregation { // -------- offset state // challenges to check the claimed quotient - + uint256 private constant STATE_ALPHA = 0x0; uint256 private constant STATE_BETA = 0x20; uint256 private constant STATE_GAMMA = 0x40; @@ -152,13 +153,15 @@ contract PlonkVerifierForDataAggregation { // -------- errors uint256 private constant ERROR_STRING_ID = 0x08c379a000000000000000000000000000000000000000000000000000000000; // selector for function Error(string) + // -------- utils (for hash_fr) - uint256 private constant HASH_FR_BB = 340282366920938463463374607431768211456; // 2**128 - uint256 private constant HASH_FR_ZERO_UINT256 = 0; - uint8 private constant HASH_FR_LEN_IN_BYTES = 48; - uint8 private constant HASH_FR_SIZE_DOMAIN = 11; - uint8 private constant HASH_FR_ONE = 1; - uint8 private constant HASH_FR_TWO = 2; + uint256 private constant HASH_FR_BB = 340282366920938463463374607431768211456; // 2**128 + uint256 private constant HASH_FR_ZERO_UINT256 = 0; + uint8 private constant HASH_FR_LEN_IN_BYTES = 48; + uint8 private constant HASH_FR_SIZE_DOMAIN = 11; + uint8 private constant HASH_FR_ONE = 1; + uint8 private constant HASH_FR_TWO = 2; + // -------- precompiles uint8 private constant SHA2 = 0x2; @@ -166,14 +169,17 @@ contract PlonkVerifierForDataAggregation { uint8 private constant EC_ADD = 0x6; uint8 private constant EC_MUL = 0x7; uint8 private constant EC_PAIR = 0x8; - + /// Verify a Plonk proof. /// Reverts if the proof or the public inputs are malformed. /// @param proof serialised plonk proof (using gnark's MarshalSolidity) /// @param public_inputs (must be reduced) /// @return success true if the proof passes false otherwise - function Verify(bytes calldata proof, uint256[] calldata public_inputs) public view returns (bool success) { + function Verify(bytes calldata proof, uint256[] calldata public_inputs) + public view returns(bool success) { + assembly { + let mem := mload(0x40) let freeMem := add(mem, STATE_LAST_MEM) @@ -305,23 +311,20 @@ contract PlonkVerifierForDataAggregation { // end errors ------------------------------------------------- // Beginning checks ------------------------------------------------- - + /// @param s actual number of public inputs function check_number_of_public_inputs(s) { if iszero(eq(s, VK_NB_PUBLIC_INPUTS)) { error_nb_public_inputs() } } - + /// Checks that the public inputs are < R_MOD. /// @param s number of public inputs /// @param p pointer to the public inputs array function check_inputs_size(s, p) { - for { - let i - } lt(i, s) { - i := add(i, 1) - } { + for {let i} lt(i, s) {i:=add(i,1)} + { if gt(calldataload(p), R_MOD_MINUS_ONE) { error_inputs_size() } @@ -332,16 +335,17 @@ contract PlonkVerifierForDataAggregation { /// Checks if the proof is of the correct size /// @param actual_proof_size size of the proof (not the expected size) function check_proof_size(actual_proof_size) { - let expected_proof_size := add(FIXED_PROOF_SIZE, mul(VK_NB_CUSTOM_GATES, 0x60)) + let expected_proof_size := add(FIXED_PROOF_SIZE, mul(VK_NB_CUSTOM_GATES,0x60)) if iszero(eq(actual_proof_size, expected_proof_size)) { - error_proof_size() + error_proof_size() } } - + /// Checks if the multiple openings of the polynomials are < R_MOD. /// @param aproof pointer to the beginning of the proof /// @dev the 'a' prepending proof is to have a local name function check_proof_openings_size(aproof) { + // PROOF_L_AT_ZETA let p := add(aproof, PROOF_L_AT_ZETA) if gt(calldataload(p), R_MOD_MINUS_ONE) { @@ -365,7 +369,7 @@ contract PlonkVerifierForDataAggregation { if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } - + // PROOF_S2_AT_ZETA p := add(aproof, PROOF_S2_AT_ZETA) if gt(calldataload(p), R_MOD_MINUS_ONE) { @@ -379,18 +383,16 @@ contract PlonkVerifierForDataAggregation { } // PROOF_OPENING_QCP_AT_ZETA - + p := add(aproof, PROOF_OPENING_QCP_AT_ZETA) - for { - let i := 0 - } lt(i, VK_NB_CUSTOM_GATES) { - i := add(i, 1) - } { + for {let i:=0} lt(i, VK_NB_CUSTOM_GATES) {i:=add(i,1)} + { if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } p := add(p, 0x20) } + } // end checks ------------------------------------------------- @@ -412,32 +414,34 @@ contract PlonkVerifierForDataAggregation { /// and is encoded as a uint256 number n. In basis b = 256, the number looks like this /// [0 0 0 .. 0x67 0x61 0x6d, 0x6d, 0x61]. The first non zero entry is at position 27=0x1b /// Gamma reduced (the actual challenge) is stored at add(state, state_gamma) - function derive_gamma(aproof, nb_pi, pi) -> gamma_not_reduced { + function derive_gamma(aproof, nb_pi, pi)->gamma_not_reduced { + let state := mload(0x40) let mPtr := add(state, STATE_LAST_MEM) mstore(mPtr, FS_GAMMA) // "gamma" - mstore(add(mPtr, 0x20), VK_S1_COM_X) - mstore(add(mPtr, 0x40), VK_S1_COM_Y) - mstore(add(mPtr, 0x60), VK_S2_COM_X) - mstore(add(mPtr, 0x80), VK_S2_COM_Y) - mstore(add(mPtr, 0xa0), VK_S3_COM_X) - mstore(add(mPtr, 0xc0), VK_S3_COM_Y) - mstore(add(mPtr, 0xe0), VK_QL_COM_X) - mstore(add(mPtr, 0x100), VK_QL_COM_Y) - mstore(add(mPtr, 0x120), VK_QR_COM_X) - mstore(add(mPtr, 0x140), VK_QR_COM_Y) - mstore(add(mPtr, 0x160), VK_QM_COM_X) - mstore(add(mPtr, 0x180), VK_QM_COM_Y) - mstore(add(mPtr, 0x1a0), VK_QO_COM_X) - mstore(add(mPtr, 0x1c0), VK_QO_COM_Y) - mstore(add(mPtr, 0x1e0), VK_QK_COM_X) - mstore(add(mPtr, 0x200), VK_QK_COM_Y) - - mstore(add(mPtr, 0x220), VK_QCP_0_X) - mstore(add(mPtr, 0x240), VK_QCP_0_Y) - + + mstore(add(mPtr, 0x20), VK_S1_COM_X) + mstore(add(mPtr, 0x40), VK_S1_COM_Y) + mstore(add(mPtr, 0x60), VK_S2_COM_X) + mstore(add(mPtr, 0x80), VK_S2_COM_Y) + mstore(add(mPtr, 0xa0), VK_S3_COM_X) + mstore(add(mPtr, 0xc0), VK_S3_COM_Y) + mstore(add(mPtr, 0xe0), VK_QL_COM_X) + mstore(add(mPtr, 0x100), VK_QL_COM_Y) + mstore(add(mPtr, 0x120), VK_QR_COM_X) + mstore(add(mPtr, 0x140), VK_QR_COM_Y) + mstore(add(mPtr, 0x160), VK_QM_COM_X) + mstore(add(mPtr, 0x180), VK_QM_COM_Y) + mstore(add(mPtr, 0x1a0), VK_QO_COM_X) + mstore(add(mPtr, 0x1c0), VK_QO_COM_Y) + mstore(add(mPtr, 0x1e0), VK_QK_COM_X) + mstore(add(mPtr, 0x200), VK_QK_COM_Y) + + mstore(add(mPtr, 0x220), VK_QCP_0_X) + mstore(add(mPtr, 0x240), VK_QCP_0_Y) + // public inputs let _mPtr := add(mPtr, 0x260) let size_pi_in_bytes := mul(nb_pi, 0x20) @@ -454,7 +458,7 @@ contract PlonkVerifierForDataAggregation { // + nb_public_inputs*0x20 // + nb_custom gates*0x40 let size := add(0x2c5, size_pi_in_bytes) - + size := add(size, mul(VK_NB_CUSTOM_GATES, 0x40)) let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1b), size, mPtr, 0x20) //0x1b -> 000.."gamma" if iszero(l_success) { @@ -469,7 +473,8 @@ contract PlonkVerifierForDataAggregation { /// @return beta_not_reduced the next challenge, beta, not reduced /// @notice the transcript consists of the previous challenge only. /// The reduced version of beta is stored at add(state, state_beta) - function derive_beta(gamma_not_reduced) -> beta_not_reduced { + function derive_beta(gamma_not_reduced)->beta_not_reduced{ + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) @@ -490,8 +495,9 @@ contract PlonkVerifierForDataAggregation { /// @return alpha_not_reduced the next challenge, alpha, not reduced /// @notice the transcript consists of the previous challenge (beta) /// not reduced, the commitments to the wires associated to the QCP_i, - /// and the commitment to the grand product polynomial - function derive_alpha(aproof, beta_not_reduced) -> alpha_not_reduced { + /// and the commitment to the grand product polynomial + function derive_alpha(aproof, beta_not_reduced)->alpha_not_reduced { + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) let full_size := 0x65 // size("alpha") + 0x20 (previous challenge) @@ -501,14 +507,14 @@ contract PlonkVerifierForDataAggregation { let _mPtr := add(mPtr, 0x20) mstore(_mPtr, beta_not_reduced) _mPtr := add(_mPtr, 0x20) - + // Bsb22Commitments let proof_bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS) let size_bsb_commitments := mul(0x40, VK_NB_CUSTOM_GATES) calldatacopy(_mPtr, proof_bsb_commitments, size_bsb_commitments) _mPtr := add(_mPtr, size_bsb_commitments) full_size := add(full_size, size_bsb_commitments) - + // [Z], the commitment to the grand product polynomial calldatacopy(_mPtr, add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X), 0x40) let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1b), full_size, mPtr, 0x20) @@ -526,6 +532,7 @@ contract PlonkVerifierForDataAggregation { /// The transcript consists of the previous challenge and the commitment to /// the quotient polynomial h. function derive_zeta(aproof, alpha_not_reduced) { + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) @@ -550,7 +557,8 @@ contract PlonkVerifierForDataAggregation { /// @param n number of public inputs /// @param mPtr free memory /// @return pi_wo_commit public inputs contribution (except the public inputs coming from the custom gate) - function sum_pi_wo_api_commit(ins, n, mPtr) -> pi_wo_commit { + function sum_pi_wo_api_commit(ins, n, mPtr)->pi_wo_commit { + let state := mload(0x40) let z := mload(add(state, STATE_ZETA)) let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)) @@ -559,16 +567,14 @@ contract PlonkVerifierForDataAggregation { batch_compute_lagranges_at_z(z, zpnmo, n, li) let tmp := 0 - for { - let i := 0 - } lt(i, n) { - i := add(i, 1) - } { + for {let i:=0} lt(i,n) {i:=add(i,1)} + { tmp := mulmod(mload(li), calldataload(ins), R_MOD) pi_wo_commit := addmod(pi_wo_commit, tmp, R_MOD) li := add(li, 0x20) ins := add(ins, 0x20) } + } /// batch_compute_lagranges_at_z computes [L_0(z), .., L_{n-1}(z)] @@ -577,32 +583,27 @@ contract PlonkVerifierForDataAggregation { /// @param n_pub number of public inputs (number of Lagranges to compute) /// @param mPtr pointer to which the results are stored function batch_compute_lagranges_at_z(z, zpnmo, n_pub, mPtr) { - let zn := mulmod(zpnmo, VK_INV_DOMAIN_SIZE, R_MOD) // 1/n * (ζⁿ - 1) + let zn := mulmod(zpnmo, VK_INV_DOMAIN_SIZE, R_MOD) // 1/n * (ζⁿ - 1) + let _w := 1 let _mPtr := mPtr - for { - let i := 0 - } lt(i, n_pub) { - i := add(i, 1) - } { - mstore(_mPtr, addmod(z, sub(R_MOD, _w), R_MOD)) + for {let i:=0} lt(i,n_pub) {i:=add(i,1)} + { + mstore(_mPtr, addmod(z,sub(R_MOD, _w), R_MOD)) _w := mulmod(_w, VK_OMEGA, R_MOD) _mPtr := add(_mPtr, 0x20) } batch_invert(mPtr, n_pub, _mPtr) _mPtr := mPtr _w := 1 - for { - let i := 0 - } lt(i, n_pub) { - i := add(i, 1) - } { - mstore(_mPtr, mulmod(mulmod(mload(_mPtr), zn, R_MOD), _w, R_MOD)) + for {let i:=0} lt(i,n_pub) {i:=add(i,1)} + { + mstore(_mPtr, mulmod(mulmod(mload(_mPtr), zn , R_MOD), _w, R_MOD)) _mPtr := add(_mPtr, 0x20) _w := mulmod(_w, VK_OMEGA, R_MOD) } - } + } /// @notice Montgomery trick for batch inversion mod R_MOD /// @param ins pointer to the data to batch invert @@ -611,11 +612,8 @@ contract PlonkVerifierForDataAggregation { function batch_invert(ins, nb_ins, mPtr) { mstore(mPtr, 1) let offset := 0 - for { - let i := 0 - } lt(i, nb_ins) { - i := add(i, 1) - } { + for {let i:=0} lt(i, nb_ins) {i:=add(i,1)} + { let prev := mload(add(mPtr, offset)) let cur := mload(add(ins, offset)) cur := mulmod(prev, cur, R_MOD) @@ -624,12 +622,9 @@ contract PlonkVerifierForDataAggregation { } ins := add(ins, sub(offset, 0x20)) mPtr := add(mPtr, offset) - let inv := pow(mload(mPtr), sub(R_MOD, 2), add(mPtr, 0x20)) - for { - let i := 0 - } lt(i, nb_ins) { - i := add(i, 1) - } { + let inv := pow(mload(mPtr), sub(R_MOD,2), add(mPtr, 0x20)) + for {let i:=0} lt(i, nb_ins) {i:=add(i,1)} + { mPtr := sub(mPtr, 0x20) let tmp := mload(ins) let cur := mulmod(inv, mload(mPtr), R_MOD) @@ -639,12 +634,14 @@ contract PlonkVerifierForDataAggregation { } } + /// Public inputs (the ones coming from the custom gate) contribution /// @param aproof pointer to the proof /// @param nb_public_inputs number of public inputs /// @param mPtr pointer to free memory /// @return pi_commit custom gate public inputs contribution - function sum_pi_commit(aproof, nb_public_inputs, mPtr) -> pi_commit { + function sum_pi_commit(aproof, nb_public_inputs, mPtr)->pi_commit { + let state := mload(0x40) let z := mload(add(state, STATE_ZETA)) let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)) @@ -652,10 +649,14 @@ contract PlonkVerifierForDataAggregation { let p := add(aproof, PROOF_BSB_COMMITMENTS) let h_fr, ith_lagrange - + + h_fr := hash_fr(calldataload(p), calldataload(add(p, 0x20)), mPtr) ith_lagrange := compute_ith_lagrange_at_z(z, zpnmo, add(nb_public_inputs, VK_INDEX_COMMIT_API_0), mPtr) pi_commit := addmod(pi_commit, mulmod(h_fr, ith_lagrange, R_MOD), R_MOD) + + + } /// Computes L_i(zeta) = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) where: @@ -663,14 +664,16 @@ contract PlonkVerifierForDataAggregation { /// @param zpmno ζⁿ-1 /// @param i i-th lagrange /// @param mPtr free memory - /// @return res = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) - function compute_ith_lagrange_at_z(z, zpnmo, i, mPtr) -> res { + /// @return res = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) + function compute_ith_lagrange_at_z(z, zpnmo, i, mPtr)->res { + let w := pow(VK_OMEGA, i, mPtr) // w**i i := addmod(z, sub(R_MOD, w), R_MOD) // z-w**i w := mulmod(w, VK_INV_DOMAIN_SIZE, R_MOD) // w**i/n - i := pow(i, sub(R_MOD, 2), mPtr) // (z-w**i)**-1 + i := pow(i, sub(R_MOD,2), mPtr) // (z-w**i)**-1 w := mulmod(w, i, R_MOD) // w**i/n*(z-w)**-1 res := mulmod(w, zpnmo, R_MOD) + } /// @dev https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 @@ -678,14 +681,15 @@ contract PlonkVerifierForDataAggregation { /// @param y y coordinate of a point on Bn254(𝔽_p) /// @param mPtr free memory /// @return res an element mod R_MOD - function hash_fr(x, y, mPtr) -> res { + function hash_fr(x, y, mPtr)->res { + // [0x00, .. , 0x00 || x, y, || 0, 48, 0, dst, HASH_FR_SIZE_DOMAIN] // <- 64 bytes -> <-64b -> <- 1 bytes each -> // [0x00, .., 0x00] 64 bytes of zero mstore(mPtr, HASH_FR_ZERO_UINT256) mstore(add(mPtr, 0x20), HASH_FR_ZERO_UINT256) - + // msg = x || y , both on 32 bytes mstore(add(mPtr, 0x40), x) mstore(add(mPtr, 0x60), y) @@ -721,7 +725,7 @@ contract PlonkVerifierForDataAggregation { // [b0 || one || dst || HASH_FR_SIZE_DOMAIN] // <-64bytes -> <- 1 byte each -> mstore8(add(mPtr, 0x20), HASH_FR_ONE) // 1 - + mstore8(add(mPtr, 0x21), 0x42) // dst mstore8(add(mPtr, 0x22), 0x53) mstore8(add(mPtr, 0x23), 0x42) @@ -773,8 +777,9 @@ contract PlonkVerifierForDataAggregation { res := mulmod(mload(mPtr), HASH_FR_BB, R_MOD) // <- res = 2**128 * mPtr[:32] let b1 := shr(128, mload(add(mPtr, 0x20))) // b1 <- [0, 0, .., 0 || b2[:16] ] res := addmod(res, b1, R_MOD) - } + } + // END compute_pi ------------------------------------------------- /// @notice compute α² * 1/n * (ζ{n}-1)/(ζ - 1) where @@ -782,7 +787,7 @@ contract PlonkVerifierForDataAggregation { /// * n = vk_domain_size /// * ω = vk_omega (generator of the multiplicative cyclic group of order n in (ℤ/rℤ)*) /// * ζ = zeta (challenge derived with Fiat Shamir) - function compute_alpha_square_lagrange_0() { + function compute_alpha_square_lagrange_0() { let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) @@ -822,7 +827,7 @@ contract PlonkVerifierForDataAggregation { mstore(add(mPtr, 0x100), mload(add(state, STATE_ZETA))) mstore(add(mPtr, 0x120), mload(add(state, STATE_GAMMA_KZG))) let random := staticcall(gas(), SHA2, mPtr, 0x140, mPtr, 0x20) - if iszero(random) { + if iszero(random){ error_random_generation() } random := mod(mload(mPtr), R_MOD) // use the same variable as we are one variable away from getting stack-too-deep error... @@ -871,18 +876,18 @@ contract PlonkVerifierForDataAggregation { mstore(folded_quotients_y, sub(P_MOD, mload(folded_quotients_y))) mstore(mPtr, mload(folded_digests)) - - mstore(add(mPtr, 0x20), mload(add(folded_digests, 0x20))) - mstore(add(mPtr, 0x40), G2_SRS_0_X_0) // the 4 lines are the canonical G2 point on BN254 - mstore(add(mPtr, 0x60), G2_SRS_0_X_1) - mstore(add(mPtr, 0x80), G2_SRS_0_Y_0) - mstore(add(mPtr, 0xa0), G2_SRS_0_Y_1) - mstore(add(mPtr, 0xc0), mload(folded_quotients)) - mstore(add(mPtr, 0xe0), mload(add(folded_quotients, 0x20))) - mstore(add(mPtr, 0x100), G2_SRS_1_X_0) - mstore(add(mPtr, 0x120), G2_SRS_1_X_1) - mstore(add(mPtr, 0x140), G2_SRS_1_Y_0) - mstore(add(mPtr, 0x160), G2_SRS_1_Y_1) + + mstore(add(mPtr, 0x20), mload(add(folded_digests, 0x20))) + mstore(add(mPtr, 0x40), G2_SRS_0_X_0) // the 4 lines are the canonical G2 point on BN254 + mstore(add(mPtr, 0x60), G2_SRS_0_X_1) + mstore(add(mPtr, 0x80), G2_SRS_0_Y_0) + mstore(add(mPtr, 0xa0), G2_SRS_0_Y_1) + mstore(add(mPtr, 0xc0), mload(folded_quotients)) + mstore(add(mPtr, 0xe0), mload(add(folded_quotients, 0x20))) + mstore(add(mPtr, 0x100), G2_SRS_1_X_0) + mstore(add(mPtr, 0x120), G2_SRS_1_X_1) + mstore(add(mPtr, 0x140), G2_SRS_1_Y_0) + mstore(add(mPtr, 0x160), G2_SRS_1_Y_1) check_pairing_kzg(mPtr) } @@ -907,6 +912,7 @@ contract PlonkVerifierForDataAggregation { /// @param aproof pointer to the proof /// acc_gamma stores the γⁱ function fold_state(aproof) { + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) let mPtr20 := add(mPtr, 0x20) @@ -943,14 +949,15 @@ contract PlonkVerifierForDataAggregation { point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_S2_AT_ZETA), acc_gamma) let poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA) - + acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) mstore(mPtr, VK_QCP_0_X) mstore(mPtr20, VK_QCP_0_Y) point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), poqaz, acc_gamma) poqaz := add(poqaz, 0x20) - } + + } /// @notice generate the challenge (using Fiat Shamir) to fold the opening proofs /// at ζ. @@ -968,22 +975,23 @@ contract PlonkVerifierForDataAggregation { /// * Z(ζω) /// @param aproof pointer to the proof function compute_gamma_kzg(aproof) { + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) mstore(mPtr, FS_GAMMA_KZG) // "gamma" mstore(add(mPtr, 0x20), mload(add(state, STATE_ZETA))) - mstore(add(mPtr, 0x40), mload(add(state, STATE_LINEARISED_POLYNOMIAL_X))) - mstore(add(mPtr, 0x60), mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y))) + mstore(add(mPtr,0x40), mload(add(state, STATE_LINEARISED_POLYNOMIAL_X))) + mstore(add(mPtr,0x60), mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y))) calldatacopy(add(mPtr, 0x80), add(aproof, PROOF_L_COM_X), 0xc0) - mstore(add(mPtr, 0x140), VK_S1_COM_X) - mstore(add(mPtr, 0x160), VK_S1_COM_Y) - mstore(add(mPtr, 0x180), VK_S2_COM_X) - mstore(add(mPtr, 0x1a0), VK_S2_COM_Y) - + mstore(add(mPtr,0x140), VK_S1_COM_X) + mstore(add(mPtr,0x160), VK_S1_COM_Y) + mstore(add(mPtr,0x180), VK_S2_COM_X) + mstore(add(mPtr,0x1a0), VK_S2_COM_Y) + let offset := 0x1c0 - - mstore(add(mPtr, offset), VK_QCP_0_X) - mstore(add(mPtr, add(offset, 0x20)), VK_QCP_0_Y) + + mstore(add(mPtr,offset), VK_QCP_0_X) + mstore(add(mPtr,add(offset, 0x20)), VK_QCP_0_Y) offset := add(offset, 0x40) mstore(add(mPtr, offset), mload(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA))) mstore(add(mPtr, add(offset, 0x20)), calldataload(add(aproof, PROOF_L_AT_ZETA))) @@ -994,23 +1002,18 @@ contract PlonkVerifierForDataAggregation { let _mPtr := add(mPtr, add(offset, 0xc0)) + let _poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA) calldatacopy(_mPtr, _poqaz, mul(VK_NB_CUSTOM_GATES, 0x20)) _mPtr := add(_mPtr, mul(VK_NB_CUSTOM_GATES, 0x20)) + mstore(_mPtr, calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA))) let start_input := 0x1b // 00.."gamma" - let size_input := add(0x14, mul(VK_NB_CUSTOM_GATES, 3)) // number of 32bytes elmts = 0x14 (zeta+3*6 for the digests+openings) + 3*VK_NB_CUSTOM_GATES (for the commitments of the selectors) + 1 (opening of Z at ζω) + let size_input := add(0x14, mul(VK_NB_CUSTOM_GATES,3)) // number of 32bytes elmts = 0x14 (zeta+3*6 for the digests+openings) + 3*VK_NB_CUSTOM_GATES (for the commitments of the selectors) + 1 (opening of Z at ζω) size_input := add(0x5, mul(size_input, 0x20)) // size in bytes: 15*32 bytes + 5 bytes for gamma - let check_staticcall := staticcall( - gas(), - SHA2, - add(mPtr, start_input), - size_input, - add(state, STATE_GAMMA_KZG), - 0x20 - ) + let check_staticcall := staticcall(gas(), SHA2, add(mPtr,start_input), size_input, add(state, STATE_GAMMA_KZG), 0x20) if iszero(check_staticcall) { error_verify() } @@ -1018,6 +1021,7 @@ contract PlonkVerifierForDataAggregation { } function compute_commitment_linearised_polynomial_ec(aproof, s1, s2) { + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) @@ -1062,6 +1066,7 @@ contract PlonkVerifierForDataAggregation { add(mPtr, 0x40) ) + let qcp_opening_at_zeta := add(aproof, PROOF_OPENING_QCP_AT_ZETA) let bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS) for { @@ -1080,6 +1085,7 @@ contract PlonkVerifierForDataAggregation { qcp_opening_at_zeta := add(qcp_opening_at_zeta, 0x20) bsb_commitments := add(bsb_commitments, 0x40) } + mstore(mPtr, VK_S3_COM_X) mstore(add(mPtr, 0x20), VK_S3_COM_Y) @@ -1090,11 +1096,10 @@ contract PlonkVerifierForDataAggregation { point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, s2, add(mPtr, 0x40)) point_add( - add(state, STATE_LINEARISED_POLYNOMIAL_X), - add(state, STATE_LINEARISED_POLYNOMIAL_X), - add(state, STATE_FOLDED_H_X), - mPtr - ) + add(state, STATE_LINEARISED_POLYNOMIAL_X), + add(state, STATE_LINEARISED_POLYNOMIAL_X), + add(state, STATE_FOLDED_H_X), + mPtr) } /// @notice Compute the commitment to the linearized polynomial equal to @@ -1161,25 +1166,10 @@ contract PlonkVerifierForDataAggregation { let mPtr := add(mload(0x40), STATE_LAST_MEM) let zeta_power_n_plus_two := pow(mload(add(state, STATE_ZETA)), n_plus_two, mPtr) point_mul_calldata(add(state, STATE_FOLDED_H_X), add(aproof, PROOF_H_2_COM_X), zeta_power_n_plus_two, mPtr) - point_add_calldata( - add(state, STATE_FOLDED_H_X), - add(state, STATE_FOLDED_H_X), - add(aproof, PROOF_H_1_COM_X), - mPtr - ) + point_add_calldata(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), add(aproof, PROOF_H_1_COM_X), mPtr) point_mul(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), zeta_power_n_plus_two, mPtr) - point_add_calldata( - add(state, STATE_FOLDED_H_X), - add(state, STATE_FOLDED_H_X), - add(aproof, PROOF_H_0_COM_X), - mPtr - ) - point_mul( - add(state, STATE_FOLDED_H_X), - add(state, STATE_FOLDED_H_X), - mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)), - mPtr - ) + point_add_calldata(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), add(aproof, PROOF_H_0_COM_X), mPtr) + point_mul(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)), mPtr) let folded_h_y := mload(add(state, STATE_FOLDED_H_Y)) folded_h_y := sub(P_MOD, folded_h_y) mstore(add(state, STATE_FOLDED_H_Y), folded_h_y) @@ -1189,6 +1179,7 @@ contract PlonkVerifierForDataAggregation { /// - [ PI(ζ) - α²*L₁(ζ) + α(l(ζ)+β*s1(ζ)+γ)(r(ζ)+β*s2(ζ)+γ)(o(ζ)+γ)*z(ωζ) ] /// @param aproof pointer to the proof function compute_opening_linearised_polynomial(aproof) { + let state := mload(0x40) // (l(ζ)+β*s1(ζ)+γ) @@ -1224,7 +1215,7 @@ contract PlonkVerifierForDataAggregation { } // BEGINNING utils math functions ------------------------------------------------- - + /// @param dst pointer storing the result /// @param p pointer to the first point /// @param q pointer to the second point @@ -1234,7 +1225,7 @@ contract PlonkVerifierForDataAggregation { mstore(add(mPtr, 0x20), mload(add(p, 0x20))) mstore(add(mPtr, 0x40), mload(q)) mstore(add(mPtr, 0x60), mload(add(q, 0x20))) - let l_success := staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40) + let l_success := staticcall(gas(),EC_ADD,mPtr,0x80,dst,0x40) if iszero(l_success) { error_ec_op() } @@ -1259,11 +1250,11 @@ contract PlonkVerifierForDataAggregation { /// @param src pointer to a point on Bn254(𝔽_p) /// @param s scalar /// @param mPtr free memory - function point_mul(dst, src, s, mPtr) { - mstore(mPtr, mload(src)) - mstore(add(mPtr, 0x20), mload(add(src, 0x20))) - mstore(add(mPtr, 0x40), s) - let l_success := staticcall(gas(), EC_MUL, mPtr, 0x60, dst, 0x40) + function point_mul(dst,src,s, mPtr) { + mstore(mPtr,mload(src)) + mstore(add(mPtr,0x20),mload(add(src,0x20))) + mstore(add(mPtr,0x40),s) + let l_success := staticcall(gas(),EC_MUL,mPtr,0x60,dst,0x40) if iszero(l_success) { error_ec_op() } @@ -1288,14 +1279,14 @@ contract PlonkVerifierForDataAggregation { /// @param src pointer to the point to multiply and add /// @param s scalar /// @param mPtr free memory - function point_acc_mul(dst, src, s, mPtr) { - mstore(mPtr, mload(src)) - mstore(add(mPtr, 0x20), mload(add(src, 0x20))) - mstore(add(mPtr, 0x40), s) - let l_success := staticcall(gas(), 7, mPtr, 0x60, mPtr, 0x40) - mstore(add(mPtr, 0x40), mload(dst)) - mstore(add(mPtr, 0x60), mload(add(dst, 0x20))) - l_success := and(l_success, staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40)) + function point_acc_mul(dst,src,s, mPtr) { + mstore(mPtr,mload(src)) + mstore(add(mPtr,0x20),mload(add(src,0x20))) + mstore(add(mPtr,0x40),s) + let l_success := staticcall(gas(),7,mPtr,0x60,mPtr,0x40) + mstore(add(mPtr,0x40),mload(dst)) + mstore(add(mPtr,0x60),mload(add(dst,0x20))) + l_success := and(l_success, staticcall(gas(),EC_ADD,mPtr,0x80,dst, 0x40)) if iszero(l_success) { error_ec_op() } @@ -1324,7 +1315,7 @@ contract PlonkVerifierForDataAggregation { /// @param src pointer to the scalar to multiply and add (on calldata) /// @param s scalar function fr_acc_mul_calldata(dst, src, s) { - let tmp := mulmod(calldataload(src), s, R_MOD) + let tmp := mulmod(calldataload(src), s, R_MOD) mstore(dst, addmod(mload(dst), tmp, R_MOD)) } @@ -1332,16 +1323,16 @@ contract PlonkVerifierForDataAggregation { /// @param e exponent /// @param mPtr free memory /// @return res x ** e mod r - function pow(x, e, mPtr) -> res { + function pow(x, e, mPtr)->res { mstore(mPtr, 0x20) mstore(add(mPtr, 0x20), 0x20) mstore(add(mPtr, 0x40), 0x20) mstore(add(mPtr, 0x60), x) mstore(add(mPtr, 0x80), e) mstore(add(mPtr, 0xa0), R_MOD) - let check_staticcall := staticcall(gas(), MOD_EXP, mPtr, 0xc0, mPtr, 0x20) + let check_staticcall := staticcall(gas(),MOD_EXP,mPtr,0xc0,mPtr,0x20) if eq(check_staticcall, 0) { - error_mod_exp() + error_mod_exp() } res := mload(mPtr) } diff --git a/contracts/contracts/verifiers/test/TestPlonkVerifierForDataAggregation.sol b/contracts/contracts/verifiers/test/TestPlonkVerifierForDataAggregation.sol index 586ebc211..6619555da 100644 --- a/contracts/contracts/verifiers/test/TestPlonkVerifierForDataAggregation.sol +++ b/contracts/contracts/verifiers/test/TestPlonkVerifierForDataAggregation.sol @@ -19,29 +19,28 @@ pragma solidity 0.8.26; contract TestPlonkVerifierForDataAggregation { + uint256 private constant R_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint256 private constant R_MOD_MINUS_ONE = - 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 private constant R_MOD_MINUS_ONE = 21888242871839275222246405745257275088548364400416034343698204186575808495616; uint256 private constant P_MOD = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - + uint256 private constant G2_SRS_0_X_0 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; uint256 private constant G2_SRS_0_X_1 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; uint256 private constant G2_SRS_0_Y_0 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; uint256 private constant G2_SRS_0_Y_1 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; - + uint256 private constant G2_SRS_1_X_0 = 15805639136721018565402881920352193254830339253282065586954346329754995870280; uint256 private constant G2_SRS_1_X_1 = 19089565590083334368588890253123139704298730990782503769911324779715431555531; uint256 private constant G2_SRS_1_Y_0 = 9779648407879205346559610309258181044130619080926897934572699915909528404984; uint256 private constant G2_SRS_1_Y_1 = 6779728121489434657638426458390319301070371227460768374343986326751507916979; - + uint256 private constant G1_SRS_X = 14312776538779914388377568895031746459131577658076416373430523308756343304251; uint256 private constant G1_SRS_Y = 11763105256161367503191792604679297387056316997144156930871823008787082098465; // ----------------------- vk --------------------- uint256 private constant VK_NB_PUBLIC_INPUTS = 1; uint256 private constant VK_DOMAIN_SIZE = 16; - uint256 private constant VK_INV_DOMAIN_SIZE = - 20520227692349320520856005386178695395514091625390032197217066424914820464641; + uint256 private constant VK_INV_DOMAIN_SIZE = 20520227692349320520856005386178695395514091625390032197217066424914820464641; uint256 private constant VK_OMEGA = 14940766826517323942636479241147756311199852622225275649687664389641784935947; uint256 private constant VK_QL_COM_X = 3767637989833674092151354229632559107224950590673664856842061399469467338879; uint256 private constant VK_QL_COM_Y = 18545409996679466114224178746162553880737296402729089689774308937082946761979; @@ -53,21 +52,23 @@ contract TestPlonkVerifierForDataAggregation { uint256 private constant VK_QO_COM_Y = 10782414695040549646706468913781794882209258381887890407509684555513355143197; uint256 private constant VK_QK_COM_X = 309591480144351325314158474719361148480191595146291661238142838254651436989; uint256 private constant VK_QK_COM_Y = 12063173869829536468830946547606069911666129778788708678515573607390482939756; - + uint256 private constant VK_S1_COM_X = 12287072751694848944507699577006619791724925439540371477056092891137357229312; uint256 private constant VK_S1_COM_Y = 2469356406782415219782253630635766217009619642857495098799013714324696399305; - + uint256 private constant VK_S2_COM_X = 17261757720471042341269061128759148572672168808566386603388432325173708264418; uint256 private constant VK_S2_COM_Y = 20976565876611279190744172824963243461988367679364518747954008723085439460611; - + uint256 private constant VK_S3_COM_X = 18758025488249277181117376239193628449359868741625564388668468130204669284937; uint256 private constant VK_S3_COM_Y = 15566903578741238761792344329051427316196307361197991677131114502821508927172; - + uint256 private constant VK_COSET_SHIFT = 5; - + + uint256 private constant VK_QCP_0_X = 4559262075452024065272338216146989708834054079507534161096300708463935456394; uint256 private constant VK_QCP_0_Y = 1898950104727986554890445533779776634695458253078091580309593009754027486622; - + + uint256 private constant VK_INDEX_COMMIT_API_0 = 5; uint256 private constant VK_NB_CUSTOM_GATES = 1; @@ -77,7 +78,7 @@ contract TestPlonkVerifierForDataAggregation { uint256 private constant FIXED_PROOF_SIZE = 0x300; // offset proof - + uint256 private constant PROOF_L_COM_X = 0x0; uint256 private constant PROOF_L_COM_Y = 0x20; uint256 private constant PROOF_R_COM_X = 0x40; @@ -121,7 +122,7 @@ contract TestPlonkVerifierForDataAggregation { // -------- offset state // challenges to check the claimed quotient - + uint256 private constant STATE_ALPHA = 0x0; uint256 private constant STATE_BETA = 0x20; uint256 private constant STATE_GAMMA = 0x40; @@ -152,13 +153,15 @@ contract TestPlonkVerifierForDataAggregation { // -------- errors uint256 private constant ERROR_STRING_ID = 0x08c379a000000000000000000000000000000000000000000000000000000000; // selector for function Error(string) + // -------- utils (for hash_fr) - uint256 private constant HASH_FR_BB = 340282366920938463463374607431768211456; // 2**128 - uint256 private constant HASH_FR_ZERO_UINT256 = 0; - uint8 private constant HASH_FR_LEN_IN_BYTES = 48; - uint8 private constant HASH_FR_SIZE_DOMAIN = 11; - uint8 private constant HASH_FR_ONE = 1; - uint8 private constant HASH_FR_TWO = 2; + uint256 private constant HASH_FR_BB = 340282366920938463463374607431768211456; // 2**128 + uint256 private constant HASH_FR_ZERO_UINT256 = 0; + uint8 private constant HASH_FR_LEN_IN_BYTES = 48; + uint8 private constant HASH_FR_SIZE_DOMAIN = 11; + uint8 private constant HASH_FR_ONE = 1; + uint8 private constant HASH_FR_TWO = 2; + // -------- precompiles uint8 private constant SHA2 = 0x2; @@ -166,14 +169,17 @@ contract TestPlonkVerifierForDataAggregation { uint8 private constant EC_ADD = 0x6; uint8 private constant EC_MUL = 0x7; uint8 private constant EC_PAIR = 0x8; - + /// Verify a Plonk proof. /// Reverts if the proof or the public inputs are malformed. /// @param proof serialised plonk proof (using gnark's MarshalSolidity) /// @param public_inputs (must be reduced) /// @return success true if the proof passes false otherwise - function Verify(bytes calldata proof, uint256[] calldata public_inputs) public view returns (bool success) { + function Verify(bytes calldata proof, uint256[] calldata public_inputs) + public view returns(bool success) { + assembly { + let mem := mload(0x40) let freeMem := add(mem, STATE_LAST_MEM) @@ -305,23 +311,20 @@ contract TestPlonkVerifierForDataAggregation { // end errors ------------------------------------------------- // Beginning checks ------------------------------------------------- - + /// @param s actual number of public inputs function check_number_of_public_inputs(s) { if iszero(eq(s, VK_NB_PUBLIC_INPUTS)) { error_nb_public_inputs() } } - + /// Checks that the public inputs are < R_MOD. /// @param s number of public inputs /// @param p pointer to the public inputs array function check_inputs_size(s, p) { - for { - let i - } lt(i, s) { - i := add(i, 1) - } { + for {let i} lt(i, s) {i:=add(i,1)} + { if gt(calldataload(p), R_MOD_MINUS_ONE) { error_inputs_size() } @@ -332,16 +335,17 @@ contract TestPlonkVerifierForDataAggregation { /// Checks if the proof is of the correct size /// @param actual_proof_size size of the proof (not the expected size) function check_proof_size(actual_proof_size) { - let expected_proof_size := add(FIXED_PROOF_SIZE, mul(VK_NB_CUSTOM_GATES, 0x60)) + let expected_proof_size := add(FIXED_PROOF_SIZE, mul(VK_NB_CUSTOM_GATES,0x60)) if iszero(eq(actual_proof_size, expected_proof_size)) { - error_proof_size() + error_proof_size() } } - + /// Checks if the multiple openings of the polynomials are < R_MOD. /// @param aproof pointer to the beginning of the proof /// @dev the 'a' prepending proof is to have a local name function check_proof_openings_size(aproof) { + // PROOF_L_AT_ZETA let p := add(aproof, PROOF_L_AT_ZETA) if gt(calldataload(p), R_MOD_MINUS_ONE) { @@ -365,7 +369,7 @@ contract TestPlonkVerifierForDataAggregation { if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } - + // PROOF_S2_AT_ZETA p := add(aproof, PROOF_S2_AT_ZETA) if gt(calldataload(p), R_MOD_MINUS_ONE) { @@ -379,18 +383,16 @@ contract TestPlonkVerifierForDataAggregation { } // PROOF_OPENING_QCP_AT_ZETA - + p := add(aproof, PROOF_OPENING_QCP_AT_ZETA) - for { - let i := 0 - } lt(i, VK_NB_CUSTOM_GATES) { - i := add(i, 1) - } { + for {let i:=0} lt(i, VK_NB_CUSTOM_GATES) {i:=add(i,1)} + { if gt(calldataload(p), R_MOD_MINUS_ONE) { error_proof_openings_size() } p := add(p, 0x20) } + } // end checks ------------------------------------------------- @@ -412,32 +414,34 @@ contract TestPlonkVerifierForDataAggregation { /// and is encoded as a uint256 number n. In basis b = 256, the number looks like this /// [0 0 0 .. 0x67 0x61 0x6d, 0x6d, 0x61]. The first non zero entry is at position 27=0x1b /// Gamma reduced (the actual challenge) is stored at add(state, state_gamma) - function derive_gamma(aproof, nb_pi, pi) -> gamma_not_reduced { + function derive_gamma(aproof, nb_pi, pi)->gamma_not_reduced { + let state := mload(0x40) let mPtr := add(state, STATE_LAST_MEM) mstore(mPtr, FS_GAMMA) // "gamma" - mstore(add(mPtr, 0x20), VK_S1_COM_X) - mstore(add(mPtr, 0x40), VK_S1_COM_Y) - mstore(add(mPtr, 0x60), VK_S2_COM_X) - mstore(add(mPtr, 0x80), VK_S2_COM_Y) - mstore(add(mPtr, 0xa0), VK_S3_COM_X) - mstore(add(mPtr, 0xc0), VK_S3_COM_Y) - mstore(add(mPtr, 0xe0), VK_QL_COM_X) - mstore(add(mPtr, 0x100), VK_QL_COM_Y) - mstore(add(mPtr, 0x120), VK_QR_COM_X) - mstore(add(mPtr, 0x140), VK_QR_COM_Y) - mstore(add(mPtr, 0x160), VK_QM_COM_X) - mstore(add(mPtr, 0x180), VK_QM_COM_Y) - mstore(add(mPtr, 0x1a0), VK_QO_COM_X) - mstore(add(mPtr, 0x1c0), VK_QO_COM_Y) - mstore(add(mPtr, 0x1e0), VK_QK_COM_X) - mstore(add(mPtr, 0x200), VK_QK_COM_Y) - - mstore(add(mPtr, 0x220), VK_QCP_0_X) - mstore(add(mPtr, 0x240), VK_QCP_0_Y) - + + mstore(add(mPtr, 0x20), VK_S1_COM_X) + mstore(add(mPtr, 0x40), VK_S1_COM_Y) + mstore(add(mPtr, 0x60), VK_S2_COM_X) + mstore(add(mPtr, 0x80), VK_S2_COM_Y) + mstore(add(mPtr, 0xa0), VK_S3_COM_X) + mstore(add(mPtr, 0xc0), VK_S3_COM_Y) + mstore(add(mPtr, 0xe0), VK_QL_COM_X) + mstore(add(mPtr, 0x100), VK_QL_COM_Y) + mstore(add(mPtr, 0x120), VK_QR_COM_X) + mstore(add(mPtr, 0x140), VK_QR_COM_Y) + mstore(add(mPtr, 0x160), VK_QM_COM_X) + mstore(add(mPtr, 0x180), VK_QM_COM_Y) + mstore(add(mPtr, 0x1a0), VK_QO_COM_X) + mstore(add(mPtr, 0x1c0), VK_QO_COM_Y) + mstore(add(mPtr, 0x1e0), VK_QK_COM_X) + mstore(add(mPtr, 0x200), VK_QK_COM_Y) + + mstore(add(mPtr, 0x220), VK_QCP_0_X) + mstore(add(mPtr, 0x240), VK_QCP_0_Y) + // public inputs let _mPtr := add(mPtr, 0x260) let size_pi_in_bytes := mul(nb_pi, 0x20) @@ -454,7 +458,7 @@ contract TestPlonkVerifierForDataAggregation { // + nb_public_inputs*0x20 // + nb_custom gates*0x40 let size := add(0x2c5, size_pi_in_bytes) - + size := add(size, mul(VK_NB_CUSTOM_GATES, 0x40)) let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1b), size, mPtr, 0x20) //0x1b -> 000.."gamma" if iszero(l_success) { @@ -469,7 +473,8 @@ contract TestPlonkVerifierForDataAggregation { /// @return beta_not_reduced the next challenge, beta, not reduced /// @notice the transcript consists of the previous challenge only. /// The reduced version of beta is stored at add(state, state_beta) - function derive_beta(gamma_not_reduced) -> beta_not_reduced { + function derive_beta(gamma_not_reduced)->beta_not_reduced{ + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) @@ -490,8 +495,9 @@ contract TestPlonkVerifierForDataAggregation { /// @return alpha_not_reduced the next challenge, alpha, not reduced /// @notice the transcript consists of the previous challenge (beta) /// not reduced, the commitments to the wires associated to the QCP_i, - /// and the commitment to the grand product polynomial - function derive_alpha(aproof, beta_not_reduced) -> alpha_not_reduced { + /// and the commitment to the grand product polynomial + function derive_alpha(aproof, beta_not_reduced)->alpha_not_reduced { + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) let full_size := 0x65 // size("alpha") + 0x20 (previous challenge) @@ -501,14 +507,14 @@ contract TestPlonkVerifierForDataAggregation { let _mPtr := add(mPtr, 0x20) mstore(_mPtr, beta_not_reduced) _mPtr := add(_mPtr, 0x20) - + // Bsb22Commitments let proof_bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS) let size_bsb_commitments := mul(0x40, VK_NB_CUSTOM_GATES) calldatacopy(_mPtr, proof_bsb_commitments, size_bsb_commitments) _mPtr := add(_mPtr, size_bsb_commitments) full_size := add(full_size, size_bsb_commitments) - + // [Z], the commitment to the grand product polynomial calldatacopy(_mPtr, add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X), 0x40) let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1b), full_size, mPtr, 0x20) @@ -526,6 +532,7 @@ contract TestPlonkVerifierForDataAggregation { /// The transcript consists of the previous challenge and the commitment to /// the quotient polynomial h. function derive_zeta(aproof, alpha_not_reduced) { + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) @@ -550,7 +557,8 @@ contract TestPlonkVerifierForDataAggregation { /// @param n number of public inputs /// @param mPtr free memory /// @return pi_wo_commit public inputs contribution (except the public inputs coming from the custom gate) - function sum_pi_wo_api_commit(ins, n, mPtr) -> pi_wo_commit { + function sum_pi_wo_api_commit(ins, n, mPtr)->pi_wo_commit { + let state := mload(0x40) let z := mload(add(state, STATE_ZETA)) let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)) @@ -559,16 +567,14 @@ contract TestPlonkVerifierForDataAggregation { batch_compute_lagranges_at_z(z, zpnmo, n, li) let tmp := 0 - for { - let i := 0 - } lt(i, n) { - i := add(i, 1) - } { + for {let i:=0} lt(i,n) {i:=add(i,1)} + { tmp := mulmod(mload(li), calldataload(ins), R_MOD) pi_wo_commit := addmod(pi_wo_commit, tmp, R_MOD) li := add(li, 0x20) ins := add(ins, 0x20) } + } /// batch_compute_lagranges_at_z computes [L_0(z), .., L_{n-1}(z)] @@ -577,32 +583,27 @@ contract TestPlonkVerifierForDataAggregation { /// @param n_pub number of public inputs (number of Lagranges to compute) /// @param mPtr pointer to which the results are stored function batch_compute_lagranges_at_z(z, zpnmo, n_pub, mPtr) { - let zn := mulmod(zpnmo, VK_INV_DOMAIN_SIZE, R_MOD) // 1/n * (ζⁿ - 1) + let zn := mulmod(zpnmo, VK_INV_DOMAIN_SIZE, R_MOD) // 1/n * (ζⁿ - 1) + let _w := 1 let _mPtr := mPtr - for { - let i := 0 - } lt(i, n_pub) { - i := add(i, 1) - } { - mstore(_mPtr, addmod(z, sub(R_MOD, _w), R_MOD)) + for {let i:=0} lt(i,n_pub) {i:=add(i,1)} + { + mstore(_mPtr, addmod(z,sub(R_MOD, _w), R_MOD)) _w := mulmod(_w, VK_OMEGA, R_MOD) _mPtr := add(_mPtr, 0x20) } batch_invert(mPtr, n_pub, _mPtr) _mPtr := mPtr _w := 1 - for { - let i := 0 - } lt(i, n_pub) { - i := add(i, 1) - } { - mstore(_mPtr, mulmod(mulmod(mload(_mPtr), zn, R_MOD), _w, R_MOD)) + for {let i:=0} lt(i,n_pub) {i:=add(i,1)} + { + mstore(_mPtr, mulmod(mulmod(mload(_mPtr), zn , R_MOD), _w, R_MOD)) _mPtr := add(_mPtr, 0x20) _w := mulmod(_w, VK_OMEGA, R_MOD) } - } + } /// @notice Montgomery trick for batch inversion mod R_MOD /// @param ins pointer to the data to batch invert @@ -611,11 +612,8 @@ contract TestPlonkVerifierForDataAggregation { function batch_invert(ins, nb_ins, mPtr) { mstore(mPtr, 1) let offset := 0 - for { - let i := 0 - } lt(i, nb_ins) { - i := add(i, 1) - } { + for {let i:=0} lt(i, nb_ins) {i:=add(i,1)} + { let prev := mload(add(mPtr, offset)) let cur := mload(add(ins, offset)) cur := mulmod(prev, cur, R_MOD) @@ -624,12 +622,9 @@ contract TestPlonkVerifierForDataAggregation { } ins := add(ins, sub(offset, 0x20)) mPtr := add(mPtr, offset) - let inv := pow(mload(mPtr), sub(R_MOD, 2), add(mPtr, 0x20)) - for { - let i := 0 - } lt(i, nb_ins) { - i := add(i, 1) - } { + let inv := pow(mload(mPtr), sub(R_MOD,2), add(mPtr, 0x20)) + for {let i:=0} lt(i, nb_ins) {i:=add(i,1)} + { mPtr := sub(mPtr, 0x20) let tmp := mload(ins) let cur := mulmod(inv, mload(mPtr), R_MOD) @@ -639,12 +634,14 @@ contract TestPlonkVerifierForDataAggregation { } } + /// Public inputs (the ones coming from the custom gate) contribution /// @param aproof pointer to the proof /// @param nb_public_inputs number of public inputs /// @param mPtr pointer to free memory /// @return pi_commit custom gate public inputs contribution - function sum_pi_commit(aproof, nb_public_inputs, mPtr) -> pi_commit { + function sum_pi_commit(aproof, nb_public_inputs, mPtr)->pi_commit { + let state := mload(0x40) let z := mload(add(state, STATE_ZETA)) let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)) @@ -652,10 +649,14 @@ contract TestPlonkVerifierForDataAggregation { let p := add(aproof, PROOF_BSB_COMMITMENTS) let h_fr, ith_lagrange - + + h_fr := hash_fr(calldataload(p), calldataload(add(p, 0x20)), mPtr) ith_lagrange := compute_ith_lagrange_at_z(z, zpnmo, add(nb_public_inputs, VK_INDEX_COMMIT_API_0), mPtr) pi_commit := addmod(pi_commit, mulmod(h_fr, ith_lagrange, R_MOD), R_MOD) + + + } /// Computes L_i(zeta) = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) where: @@ -663,14 +664,16 @@ contract TestPlonkVerifierForDataAggregation { /// @param zpmno ζⁿ-1 /// @param i i-th lagrange /// @param mPtr free memory - /// @return res = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) - function compute_ith_lagrange_at_z(z, zpnmo, i, mPtr) -> res { + /// @return res = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) + function compute_ith_lagrange_at_z(z, zpnmo, i, mPtr)->res { + let w := pow(VK_OMEGA, i, mPtr) // w**i i := addmod(z, sub(R_MOD, w), R_MOD) // z-w**i w := mulmod(w, VK_INV_DOMAIN_SIZE, R_MOD) // w**i/n - i := pow(i, sub(R_MOD, 2), mPtr) // (z-w**i)**-1 + i := pow(i, sub(R_MOD,2), mPtr) // (z-w**i)**-1 w := mulmod(w, i, R_MOD) // w**i/n*(z-w)**-1 res := mulmod(w, zpnmo, R_MOD) + } /// @dev https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 @@ -678,14 +681,15 @@ contract TestPlonkVerifierForDataAggregation { /// @param y y coordinate of a point on Bn254(𝔽_p) /// @param mPtr free memory /// @return res an element mod R_MOD - function hash_fr(x, y, mPtr) -> res { + function hash_fr(x, y, mPtr)->res { + // [0x00, .. , 0x00 || x, y, || 0, 48, 0, dst, HASH_FR_SIZE_DOMAIN] // <- 64 bytes -> <-64b -> <- 1 bytes each -> // [0x00, .., 0x00] 64 bytes of zero mstore(mPtr, HASH_FR_ZERO_UINT256) mstore(add(mPtr, 0x20), HASH_FR_ZERO_UINT256) - + // msg = x || y , both on 32 bytes mstore(add(mPtr, 0x40), x) mstore(add(mPtr, 0x60), y) @@ -721,7 +725,7 @@ contract TestPlonkVerifierForDataAggregation { // [b0 || one || dst || HASH_FR_SIZE_DOMAIN] // <-64bytes -> <- 1 byte each -> mstore8(add(mPtr, 0x20), HASH_FR_ONE) // 1 - + mstore8(add(mPtr, 0x21), 0x42) // dst mstore8(add(mPtr, 0x22), 0x53) mstore8(add(mPtr, 0x23), 0x42) @@ -773,8 +777,9 @@ contract TestPlonkVerifierForDataAggregation { res := mulmod(mload(mPtr), HASH_FR_BB, R_MOD) // <- res = 2**128 * mPtr[:32] let b1 := shr(128, mload(add(mPtr, 0x20))) // b1 <- [0, 0, .., 0 || b2[:16] ] res := addmod(res, b1, R_MOD) - } + } + // END compute_pi ------------------------------------------------- /// @notice compute α² * 1/n * (ζ{n}-1)/(ζ - 1) where @@ -782,7 +787,7 @@ contract TestPlonkVerifierForDataAggregation { /// * n = vk_domain_size /// * ω = vk_omega (generator of the multiplicative cyclic group of order n in (ℤ/rℤ)*) /// * ζ = zeta (challenge derived with Fiat Shamir) - function compute_alpha_square_lagrange_0() { + function compute_alpha_square_lagrange_0() { let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) @@ -822,7 +827,7 @@ contract TestPlonkVerifierForDataAggregation { mstore(add(mPtr, 0x100), mload(add(state, STATE_ZETA))) mstore(add(mPtr, 0x120), mload(add(state, STATE_GAMMA_KZG))) let random := staticcall(gas(), SHA2, mPtr, 0x140, mPtr, 0x20) - if iszero(random) { + if iszero(random){ error_random_generation() } random := mod(mload(mPtr), R_MOD) // use the same variable as we are one variable away from getting stack-too-deep error... @@ -871,18 +876,18 @@ contract TestPlonkVerifierForDataAggregation { mstore(folded_quotients_y, sub(P_MOD, mload(folded_quotients_y))) mstore(mPtr, mload(folded_digests)) - - mstore(add(mPtr, 0x20), mload(add(folded_digests, 0x20))) - mstore(add(mPtr, 0x40), G2_SRS_0_X_0) // the 4 lines are the canonical G2 point on BN254 - mstore(add(mPtr, 0x60), G2_SRS_0_X_1) - mstore(add(mPtr, 0x80), G2_SRS_0_Y_0) - mstore(add(mPtr, 0xa0), G2_SRS_0_Y_1) - mstore(add(mPtr, 0xc0), mload(folded_quotients)) - mstore(add(mPtr, 0xe0), mload(add(folded_quotients, 0x20))) - mstore(add(mPtr, 0x100), G2_SRS_1_X_0) - mstore(add(mPtr, 0x120), G2_SRS_1_X_1) - mstore(add(mPtr, 0x140), G2_SRS_1_Y_0) - mstore(add(mPtr, 0x160), G2_SRS_1_Y_1) + + mstore(add(mPtr, 0x20), mload(add(folded_digests, 0x20))) + mstore(add(mPtr, 0x40), G2_SRS_0_X_0) // the 4 lines are the canonical G2 point on BN254 + mstore(add(mPtr, 0x60), G2_SRS_0_X_1) + mstore(add(mPtr, 0x80), G2_SRS_0_Y_0) + mstore(add(mPtr, 0xa0), G2_SRS_0_Y_1) + mstore(add(mPtr, 0xc0), mload(folded_quotients)) + mstore(add(mPtr, 0xe0), mload(add(folded_quotients, 0x20))) + mstore(add(mPtr, 0x100), G2_SRS_1_X_0) + mstore(add(mPtr, 0x120), G2_SRS_1_X_1) + mstore(add(mPtr, 0x140), G2_SRS_1_Y_0) + mstore(add(mPtr, 0x160), G2_SRS_1_Y_1) check_pairing_kzg(mPtr) } @@ -907,6 +912,7 @@ contract TestPlonkVerifierForDataAggregation { /// @param aproof pointer to the proof /// acc_gamma stores the γⁱ function fold_state(aproof) { + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) let mPtr20 := add(mPtr, 0x20) @@ -943,14 +949,15 @@ contract TestPlonkVerifierForDataAggregation { point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_S2_AT_ZETA), acc_gamma) let poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA) - + acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) mstore(mPtr, VK_QCP_0_X) mstore(mPtr20, VK_QCP_0_Y) point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), poqaz, acc_gamma) poqaz := add(poqaz, 0x20) - } + + } /// @notice generate the challenge (using Fiat Shamir) to fold the opening proofs /// at ζ. @@ -968,22 +975,23 @@ contract TestPlonkVerifierForDataAggregation { /// * Z(ζω) /// @param aproof pointer to the proof function compute_gamma_kzg(aproof) { + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) mstore(mPtr, FS_GAMMA_KZG) // "gamma" mstore(add(mPtr, 0x20), mload(add(state, STATE_ZETA))) - mstore(add(mPtr, 0x40), mload(add(state, STATE_LINEARISED_POLYNOMIAL_X))) - mstore(add(mPtr, 0x60), mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y))) + mstore(add(mPtr,0x40), mload(add(state, STATE_LINEARISED_POLYNOMIAL_X))) + mstore(add(mPtr,0x60), mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y))) calldatacopy(add(mPtr, 0x80), add(aproof, PROOF_L_COM_X), 0xc0) - mstore(add(mPtr, 0x140), VK_S1_COM_X) - mstore(add(mPtr, 0x160), VK_S1_COM_Y) - mstore(add(mPtr, 0x180), VK_S2_COM_X) - mstore(add(mPtr, 0x1a0), VK_S2_COM_Y) - + mstore(add(mPtr,0x140), VK_S1_COM_X) + mstore(add(mPtr,0x160), VK_S1_COM_Y) + mstore(add(mPtr,0x180), VK_S2_COM_X) + mstore(add(mPtr,0x1a0), VK_S2_COM_Y) + let offset := 0x1c0 - - mstore(add(mPtr, offset), VK_QCP_0_X) - mstore(add(mPtr, add(offset, 0x20)), VK_QCP_0_Y) + + mstore(add(mPtr,offset), VK_QCP_0_X) + mstore(add(mPtr,add(offset, 0x20)), VK_QCP_0_Y) offset := add(offset, 0x40) mstore(add(mPtr, offset), mload(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA))) mstore(add(mPtr, add(offset, 0x20)), calldataload(add(aproof, PROOF_L_AT_ZETA))) @@ -994,23 +1002,18 @@ contract TestPlonkVerifierForDataAggregation { let _mPtr := add(mPtr, add(offset, 0xc0)) + let _poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA) calldatacopy(_mPtr, _poqaz, mul(VK_NB_CUSTOM_GATES, 0x20)) _mPtr := add(_mPtr, mul(VK_NB_CUSTOM_GATES, 0x20)) + mstore(_mPtr, calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA))) let start_input := 0x1b // 00.."gamma" - let size_input := add(0x14, mul(VK_NB_CUSTOM_GATES, 3)) // number of 32bytes elmts = 0x14 (zeta+3*6 for the digests+openings) + 3*VK_NB_CUSTOM_GATES (for the commitments of the selectors) + 1 (opening of Z at ζω) + let size_input := add(0x14, mul(VK_NB_CUSTOM_GATES,3)) // number of 32bytes elmts = 0x14 (zeta+3*6 for the digests+openings) + 3*VK_NB_CUSTOM_GATES (for the commitments of the selectors) + 1 (opening of Z at ζω) size_input := add(0x5, mul(size_input, 0x20)) // size in bytes: 15*32 bytes + 5 bytes for gamma - let check_staticcall := staticcall( - gas(), - SHA2, - add(mPtr, start_input), - size_input, - add(state, STATE_GAMMA_KZG), - 0x20 - ) + let check_staticcall := staticcall(gas(), SHA2, add(mPtr,start_input), size_input, add(state, STATE_GAMMA_KZG), 0x20) if iszero(check_staticcall) { error_verify() } @@ -1018,6 +1021,7 @@ contract TestPlonkVerifierForDataAggregation { } function compute_commitment_linearised_polynomial_ec(aproof, s1, s2) { + let state := mload(0x40) let mPtr := add(mload(0x40), STATE_LAST_MEM) @@ -1062,6 +1066,7 @@ contract TestPlonkVerifierForDataAggregation { add(mPtr, 0x40) ) + let qcp_opening_at_zeta := add(aproof, PROOF_OPENING_QCP_AT_ZETA) let bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS) for { @@ -1080,6 +1085,7 @@ contract TestPlonkVerifierForDataAggregation { qcp_opening_at_zeta := add(qcp_opening_at_zeta, 0x20) bsb_commitments := add(bsb_commitments, 0x40) } + mstore(mPtr, VK_S3_COM_X) mstore(add(mPtr, 0x20), VK_S3_COM_Y) @@ -1090,11 +1096,10 @@ contract TestPlonkVerifierForDataAggregation { point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, s2, add(mPtr, 0x40)) point_add( - add(state, STATE_LINEARISED_POLYNOMIAL_X), - add(state, STATE_LINEARISED_POLYNOMIAL_X), - add(state, STATE_FOLDED_H_X), - mPtr - ) + add(state, STATE_LINEARISED_POLYNOMIAL_X), + add(state, STATE_LINEARISED_POLYNOMIAL_X), + add(state, STATE_FOLDED_H_X), + mPtr) } /// @notice Compute the commitment to the linearized polynomial equal to @@ -1161,25 +1166,10 @@ contract TestPlonkVerifierForDataAggregation { let mPtr := add(mload(0x40), STATE_LAST_MEM) let zeta_power_n_plus_two := pow(mload(add(state, STATE_ZETA)), n_plus_two, mPtr) point_mul_calldata(add(state, STATE_FOLDED_H_X), add(aproof, PROOF_H_2_COM_X), zeta_power_n_plus_two, mPtr) - point_add_calldata( - add(state, STATE_FOLDED_H_X), - add(state, STATE_FOLDED_H_X), - add(aproof, PROOF_H_1_COM_X), - mPtr - ) + point_add_calldata(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), add(aproof, PROOF_H_1_COM_X), mPtr) point_mul(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), zeta_power_n_plus_two, mPtr) - point_add_calldata( - add(state, STATE_FOLDED_H_X), - add(state, STATE_FOLDED_H_X), - add(aproof, PROOF_H_0_COM_X), - mPtr - ) - point_mul( - add(state, STATE_FOLDED_H_X), - add(state, STATE_FOLDED_H_X), - mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)), - mPtr - ) + point_add_calldata(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), add(aproof, PROOF_H_0_COM_X), mPtr) + point_mul(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)), mPtr) let folded_h_y := mload(add(state, STATE_FOLDED_H_Y)) folded_h_y := sub(P_MOD, folded_h_y) mstore(add(state, STATE_FOLDED_H_Y), folded_h_y) @@ -1189,6 +1179,7 @@ contract TestPlonkVerifierForDataAggregation { /// - [ PI(ζ) - α²*L₁(ζ) + α(l(ζ)+β*s1(ζ)+γ)(r(ζ)+β*s2(ζ)+γ)(o(ζ)+γ)*z(ωζ) ] /// @param aproof pointer to the proof function compute_opening_linearised_polynomial(aproof) { + let state := mload(0x40) // (l(ζ)+β*s1(ζ)+γ) @@ -1224,7 +1215,7 @@ contract TestPlonkVerifierForDataAggregation { } // BEGINNING utils math functions ------------------------------------------------- - + /// @param dst pointer storing the result /// @param p pointer to the first point /// @param q pointer to the second point @@ -1234,7 +1225,7 @@ contract TestPlonkVerifierForDataAggregation { mstore(add(mPtr, 0x20), mload(add(p, 0x20))) mstore(add(mPtr, 0x40), mload(q)) mstore(add(mPtr, 0x60), mload(add(q, 0x20))) - let l_success := staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40) + let l_success := staticcall(gas(),EC_ADD,mPtr,0x80,dst,0x40) if iszero(l_success) { error_ec_op() } @@ -1259,11 +1250,11 @@ contract TestPlonkVerifierForDataAggregation { /// @param src pointer to a point on Bn254(𝔽_p) /// @param s scalar /// @param mPtr free memory - function point_mul(dst, src, s, mPtr) { - mstore(mPtr, mload(src)) - mstore(add(mPtr, 0x20), mload(add(src, 0x20))) - mstore(add(mPtr, 0x40), s) - let l_success := staticcall(gas(), EC_MUL, mPtr, 0x60, dst, 0x40) + function point_mul(dst,src,s, mPtr) { + mstore(mPtr,mload(src)) + mstore(add(mPtr,0x20),mload(add(src,0x20))) + mstore(add(mPtr,0x40),s) + let l_success := staticcall(gas(),EC_MUL,mPtr,0x60,dst,0x40) if iszero(l_success) { error_ec_op() } @@ -1288,14 +1279,14 @@ contract TestPlonkVerifierForDataAggregation { /// @param src pointer to the point to multiply and add /// @param s scalar /// @param mPtr free memory - function point_acc_mul(dst, src, s, mPtr) { - mstore(mPtr, mload(src)) - mstore(add(mPtr, 0x20), mload(add(src, 0x20))) - mstore(add(mPtr, 0x40), s) - let l_success := staticcall(gas(), 7, mPtr, 0x60, mPtr, 0x40) - mstore(add(mPtr, 0x40), mload(dst)) - mstore(add(mPtr, 0x60), mload(add(dst, 0x20))) - l_success := and(l_success, staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40)) + function point_acc_mul(dst,src,s, mPtr) { + mstore(mPtr,mload(src)) + mstore(add(mPtr,0x20),mload(add(src,0x20))) + mstore(add(mPtr,0x40),s) + let l_success := staticcall(gas(),7,mPtr,0x60,mPtr,0x40) + mstore(add(mPtr,0x40),mload(dst)) + mstore(add(mPtr,0x60),mload(add(dst,0x20))) + l_success := and(l_success, staticcall(gas(),EC_ADD,mPtr,0x80,dst, 0x40)) if iszero(l_success) { error_ec_op() } @@ -1324,7 +1315,7 @@ contract TestPlonkVerifierForDataAggregation { /// @param src pointer to the scalar to multiply and add (on calldata) /// @param s scalar function fr_acc_mul_calldata(dst, src, s) { - let tmp := mulmod(calldataload(src), s, R_MOD) + let tmp := mulmod(calldataload(src), s, R_MOD) mstore(dst, addmod(mload(dst), tmp, R_MOD)) } @@ -1332,16 +1323,16 @@ contract TestPlonkVerifierForDataAggregation { /// @param e exponent /// @param mPtr free memory /// @return res x ** e mod r - function pow(x, e, mPtr) -> res { + function pow(x, e, mPtr)->res { mstore(mPtr, 0x20) mstore(add(mPtr, 0x20), 0x20) mstore(add(mPtr, 0x40), 0x20) mstore(add(mPtr, 0x60), x) mstore(add(mPtr, 0x80), e) mstore(add(mPtr, 0xa0), R_MOD) - let check_staticcall := staticcall(gas(), MOD_EXP, mPtr, 0xc0, mPtr, 0x20) + let check_staticcall := staticcall(gas(),MOD_EXP,mPtr,0xc0,mPtr,0x20) if eq(check_staticcall, 0) { - error_mod_exp() + error_mod_exp() } res := mload(mPtr) } diff --git a/contracts/test/testData/compressedData/aggregatedProof-1-155.json b/contracts/test/testData/compressedData/aggregatedProof-1-155.json index 7b39731f1..c7735172c 100644 --- a/contracts/test/testData/compressedData/aggregatedProof-1-155.json +++ b/contracts/test/testData/compressedData/aggregatedProof-1-155.json @@ -1,7 +1,7 @@ { "finalShnarf": "0xdf1e9f621e3a89f02d44dbc266056d50d5d1524dc4d135f93b81619f3d674b7c", "parentAggregationFinalShnarf": "0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f", - "aggregatedProof": "0x2e6431c2cbb8021cc213885d08b39ccb38215789c2fdced773bd4d46d41a6b8217d476fbffa85477a18981fe0ec8c776171a656b8a12a746a3319e2b54c87a400f102032e51da42427391a70286fbc85fd0dd0a49c5ae890e485ff64c0b8ab9d14ec859fdf2eaeff4997e0eb0f429bda9cdf4afef98021dab7853ede9bf3983d28d3b6b08cc253e8ac6dfd36da607ac729f97bfe52da6722c9b9b994db805934143c5c006b101df5174557240204dec4a34cacf76108e7899304c565ac4d6a18086d779a0f60c70925556824c13ac6c269eefc7aa1c1c71b9d534c5e3da6663b04d66f0539ba5396c86e1a823874b7930cd5e5e724456401bc4ec78fef893f7603312b8200ff4885183eb18caa39f3cc5addf3fa269ac3779d2e3147ef8c2e3b2e8a57e79f5817343b1a003c3aff6a8c1472b43c7bb4294ef21e8c6b32e374f901f8067adb88e2fa5acfab716e76c16c25ab3b65cbfcb45b20c376de1b52849316fdca7b5b33aa27b93047fabd81c90de25f77af21746e9323857db6c2228bf12e642cdee60640d21c1fa93085a188757e4d1af7979797c8009d2e94ae08201712498ebb4ba0dd28ce715c09af2849d9b5f3b52f366be9f677291a7adc16e13127a5d239e8a0f92ee532763c46ea4736067653048c57e2b195a73abbdbdf487f2c5fd68152c9df7e5f1bfe20c650b3db1c2c0a595df56221295092bc5847326c1779d7179390ee89f6167e3ab5af2e7183fab9e9e7790c78f0068ee2c958b20f05a975167f7e6b69c1a780b05e9b0dd82ed462bde24a9e0aee2efcbc6c28f4bb199070367e57150fcb771669cf4ba8bc68085ab13e92f1866fba6c3bea5b2e2201a4de8bece0731c62ee90a9d701ac99645f15ead828cb880f8b35f6036e463e12cc0a7c346ba3b8803e53d119d8543569d743723d88e99a4154871153d37399173bd6539f441ca603501f8f402e7b5836c7960550e137dbef5bc7c8c20d7da823aa871781f2f61565ef75bbcb703f3d7dff21322921d93e5c7a071778576aa3180c347201bfcac60ffe35ee3b5054ddf149af7a841a05fcdc7b554cbea8d6362635ba41d6b779fc01e850b450f576a34c528e850868d43764dd71755d4fe770010928c3f6c62450523d5bdfbdda93586d6dfc3ec9e685e2d247502d3836fc7910db1865595094ec3c49a5ab8f84b9c432bc1d6191354dfed12feb07415fc3fa", + "aggregatedProof": "0x07355eb937c8508eec66315f4dd00809eab5d8ba3c6925d37edde93fc248e28c2dcbf2f29c3c0c60ada0c0ceac4c1c975f6887a7ced528804bb7a325e27b083012495f11884b911377a39f615feace8faf16dfc9f09ea7d0d0965d341b15b98c1610eff44a2a0d49e0dfc890c1d644e985579d6f489e4d8c21d8be5ff34deb9f179a29899b9eb178c33d2c433dc5e41b66f559f9b6f5e352778623a2b1ee77a51a11fea1a2dfb86dc3823c2e3e6601f9db41feab3de68c78c40a492781f2d7860451260674f076a9c8904a4d27a3b97511926950dfbebfd0a229cbe7c4d1ef6f26305ca8ee096bf2811669ca7b92a1d855c9fb11f42f0600f1775a2c745f523d0639fc44208a1ca5a955afc117fd47d7140f848171cbffb2e3a2af1523df73912fa007d9bde44a42529a3190c549a24be7947d7595d07fa2b1db6a741e955ca52c752c5953a87568229e7b2b54cafd00826fd4f048c662f7449aae87e42294d0063216d8c848ef8078771d255d5301c4a3dea3b3297d1c27eb535019518c3ad709770da25f7d789926c583295940405cbf2d1dad4de41e5ad63d2f0273a8febc2a704b00af0e74f7a4f25a35830b8f7d7e32b86546dfa931ec39db123d40e4c205266587fb9763785bb4494a1bc48b586e5ec8b417207b9458a3e6b09539d07929604002ae4c2b5492c7e191628206381eea6b19bfb15350760e10e2e8f2341f1f042a8800ed238a0372f91cb257c7f534f39d3b285e951c1d737a737390a43a26f56a0f11f32a194a85132f65e6487a391e244c21f1b848297728e277fb3c7d1815881d4d3745e91644d58b1a08b958cf0ff004d6cf3b7fe2c127012c797df01133268df0088e623dbff2e96a221e87ab909530bcb268721bf9bbe172a990322d5ff2132fce29d2d65b73697461280ad9bc0a9133a8802e0c0dcecdd6f09baa0512c4466c1848edc04e7d6a615050c10c13c6d7d600be64df9e8aa0bb371d0b0413d35d18cc70887b13c6f6e7ccbc2363f8dd60ebe93d51c15ce5601312981e200f0c9d52d84c8e7e62295db03e47c0b68e71bbe244405c4ab2eef2c524989f21d4bec0c7b91db34c06ec92226bc4845e21777c65d72c731801c576f7945f301f9aa761d088f427fbd1672cefe35a13a899ae2d52673823f11e0a34d4f849802e367e4d5c92e09a8f6309c75af52fae72040e5708080541c3ff745c2375cdc6", "aggregatedProverVersion": "test", "aggregatedVerifierIndex": 1, "aggregatedProofPublicInput": "0x233fd3d94f86264d6b666cdcb455c1cb144d3dc399edc9d17bd50aa42ae789a2", diff --git a/contracts/test/testData/compressedData/multipleProofs/aggregatedProof-1-81.json b/contracts/test/testData/compressedData/multipleProofs/aggregatedProof-1-81.json index 289db3244..5c004275a 100644 --- a/contracts/test/testData/compressedData/multipleProofs/aggregatedProof-1-81.json +++ b/contracts/test/testData/compressedData/multipleProofs/aggregatedProof-1-81.json @@ -1,7 +1,7 @@ { "finalShnarf": "0x6d2b3535e06f4778e03c8439145dd9b8e4ae312953b9ccc154ef73b8a00c26c1", "parentAggregationFinalShnarf": "0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f", - "aggregatedProof": "0x008e483358dc0ac1d3f6a27b43f6332e88c4196151b2a1ce6c8575013cec2cbe2f666e5649165dfc5a88ede985203341f5910ec2f4e3d4e9fa2a0a2621e4b0a70a91e0f995a8d754a3ddec1698800be83da8815650488540d2ffb699eaf3518d14bff479974f1f5f8bef7687f89c6301247cd92a4ccfa76a868bd24090a670f20eb06513431e74411648ab8c02a270353146bc759451d00cf2a59477d6106b9d11df3e18bca0d3a36951e31699b21a73e22a77fb7fe43a33b717a23dd06a889a102e4143d1e024e053e4318f903c3dbd0ec0f6e49672dd0ccb10749ac00adaf311149a24bf2c2ee4cfe7ed1db713526c6f7c0893f2ec153e5f55a4b390ce135a0d3ebe372c1beea8142afebdc96fe2764b8b5a33efc0457b9ad65f678c8b9ede196eb1fe34a82e0f370fe1d53e5cfc34bc77f38a64eddbb74f6530a82feb0e0a148de4d309b179697ff8a3c97a5516a1bbffc36d8cf153e9f5ee8fdc98002fd1136a2a12603aa1c7a985b34c5dc6774a5efd6270eac180406b4f03c7ef08eee428bb45d04a3c6635a0225aae76c0522049df5080045629cd6a686c2d50d8b7fe10e6facded652c8d75d4a67d5f8f4c3c6b491f44cc23c307064ec94f7c3a44eb1d1dcd369464960e54a88ad3f9edbdd818f2ac711d6c8f49efe224fb2616f2ac0005ca0c753c801d9e2df1133cdd4de5e54554197ac3e2f42d0b140261a12796050d64ec14bb22355173d157a7a2a9a5c0a20d47430819b4c106fda54923f9bf273cbc4145962e07b853279e64e198d3da5919814935c4cf12ffc03128d0e4fc24e8f35180d257253c0ce33725cb665a81141f16418fb20cf2abb96fa65a03bc0fa8e1e842123e2a2590f423e34c1db2c51c9e872ea41942d44d94d735cf8b4b0ccc265c6bdc41dd6f1167da133450a5ea0c07ea4704c9ca377cd201d8a63f932f7d4c9edb88269008bfe08d91d576cbf1a46c2da88b13d2a38e68f66f330552114f37a226c38ed3a9acd35b75f5852e6879eb3c8746ed2676f9e3957d32bbee1493ac055f03a56e964c4ea278d323abde55b36439b5460897771bf5ef3be1992448a5479f3515d5605d403a51391c6c6db94a90b3353aa956a5ba6f7b951fee2b7657ab431f90220c84820c2db8e4b57eaa5c3ea13e8d1f4ed31b9434c5df5c083dbb24fdf9dc5a64ba7416e6d154e6b17727a3acaa9f59820e926196efd232", + "aggregatedProof": "0x24a763a8f31f6fc38a69c22e50e52834ec7d81dec39a242788f2d58346cf26a012f9746c9b1a1495044290332e888efd1b2d2aa2c725b8bab9c144fd7aae58b40516025862d6f66f14a94fa21056ff77852b13f490f464a72c6761f9fbaeaabd129cf08f08e796cda5731ab08ce868b3188c749363ecea66e940fa5ae7d1ac7d2a50649642f8b92a0da2e46e428c9b7e0d690ab1b55fc94166b8b8e13af5bd5c2098836444656fcc2d5bf4ba30b334685bf8c8386a5ace5110c16ea47e425b4b098fe4587fe3477eac40fb3b044ce3c9ac3c8c63c2e0b9053e5bdc835d89f9dd114f6c6781bade139e4126c3aa018d4f8277d31bdb677d202bb88308248e67ee1db7a1c7735107ea60a9136e7a4d28984152f3ec601706761bdc2942afe4860e2ae4392e300e00fd27ed3736334320874bc118a135712bc92dee276b73b5715c218f03c694d832d1b10cbc2900d09fb3df9b7b8da7639c0db268074ff046affc11bb6b6699c06792e2dfeefb27d5145375850e34b1eb984dc2c87611952d9f872dba5559b64bdaee265c91a3b4f4c01c40f75381b6a2b99468364b1056a2cf3304e1c4622cf393a2a04c8dfba895c54b97cd081d0df7457fb35954740a16f97d2828a085da44352389651ddf83ef47152e5087d94b8475ba6772d2d37502a5ae1093727448560d452f7bd77f48e114855fe255a100f3d16199d8179876aa62ba1ea4af6ac5db7007410c09d970de717777db53739c5338347e9b9a5d24787239223bbe47ee17a38e3877d004f16e1c1ecd18ab12b163fd27b6beddca3700c7ec1470e3e921d13b8e705d4cf2511441e96b3391e1e53f4dee129481a9a9307c5911a0a8eec252ee62d1ce5823d24b152ebf9763d6a95c0cdf42fd00a45056f10025521191435a9f6b48c54e67ed081b8780ffcea6cf3c1cc8aa0159af38d599162216923680b8ee251ba11ccdd12f2bcf36eaa70892096a40847aada1b64de98e1e3b7a46c11f6e9908882d44adb3195766b316a84ceac2dcc88f987db38fe01f10bfd9d877bef3590ec9186a0ad140a3818818592e1377c2d03068118abbb17c210058369bf284117a6b8431967496b5c4ad4c48db1817e2b32fbb45a57f3f2c04cfba2a9cc42b95bc194c67dcedf375fadc10ffa3c697491220ffb5a780ab07220e499810f28776110f19a92490c51df664197f281aa5491dafb6bcf5bedf47", "aggregatedProverVersion": "test", "aggregatedVerifierIndex": 1, "aggregatedProofPublicInput": "0x216ea864c4d4392d0315997af776dbc1856686e376a07c85ed67f8509c14328e", diff --git a/contracts/test/testData/compressedData/multipleProofs/aggregatedProof-82-153.json b/contracts/test/testData/compressedData/multipleProofs/aggregatedProof-82-153.json index c2c7f80b2..dca994eb1 100644 --- a/contracts/test/testData/compressedData/multipleProofs/aggregatedProof-82-153.json +++ b/contracts/test/testData/compressedData/multipleProofs/aggregatedProof-82-153.json @@ -1,7 +1,7 @@ { "finalShnarf": "0x4b7f110cbe7fcab315cd99683b2c7864bff2615903a3230d5bf2222b7a71a756", "parentAggregationFinalShnarf": "0x6d2b3535e06f4778e03c8439145dd9b8e4ae312953b9ccc154ef73b8a00c26c1", - "aggregatedProof": "0x2ccd7bc052a4a3347fd0fc9134d62c37208cbf5af79ceda0a62bde3861db8329195f5d25f8fee76a7d37c45055766e059dd3750dec0b903783b5928b8a5e8c830a5336cd5876cb7c1a4cb5cf329f1f6c932a38121778a56a2a80d41cf75da03013a32e6ef9159e335e8943fd9daba6d58f48a68f47dd24585cf59e50ce79cf300d84d08f9db0c62db91f0b00f410acd88e1f6217ae3565db6535a086b781038d15bdb30229a0e1a191d5ea26f38cc27bec2ac3b9ddc00ca88ce0b27a745a7b271eb64a673306440b812ac79c53c345adb2c4a7d6d983dab3e8b00e83fc36e0ba3018527b30a861d10944d6d05b295a3dcfe956da4a6b42610ec703ffe74248fb0154a0dfc7bdc8dedcfc4e6bc884a10ba3aa3073efcacd66cf7d59e38a74aa1000a36354762974e610be1ee6988f91f58ea4fa7f3335736a8af7075ffb10ea2a0bede1074f138237a509373679a8d781308401b1ac283772ce163ad1efc5af2216899a8499375154809be8367318d7916933a34f02cf76d20d7715a289c174580229d78df12a39593212751e2e70f26909f7fafc6d63bc877d28278049406f3104b870a14218cf11b2422bb46dafb11aa4fecac8d7bd8570eb72b955688bbfc80cb0fb367fddb4826b6ff2285ddf6d147f38ba068e3d35cf0568a8141e3871b61eeabdbab18df69f0e8087484c2fa7eb15241b8d0e40d2883daf1addff7691e3241ad52968445fb97749bbe4ab7ab2e31717ed545c9d078a57eab2de9cd9db982377d1ba338e35fe231a05a1b81b4c9d4d1332c97cdfc1d0b6e3c6f190c932f201e8814a714bff8c37e80b1aac4ae26c8fe4fa68ca041713aacd705b3306926617503f4eca6c1893e6f5ced6ece0614e66624b9b817c664bc26e3bda711501980cf48324ee61112ac8105e1d645dd72ea6f99312a9f99f37e156b54f4d07f65c2d2dea5a66368fe0d42efbeb6983c81622c5e25eae779dd9ae3be074ca9772be1e65c0906da0e0f408b3daee7d505b99cfabaa3427a9a1abbfe78d273275fe2606f9e57936aad44f500f8ade2e3c0c350dcfbbeba3218205ee74818376bc87f70d0bb1ba55e09ba360aa28037bd8d99ba3ff700045c525b6c8a08acddbaf75d12e3a7863068be75c7e889962d10b6e0d40e0ae9c8334be7597e45936a12249ea0578371f6f0bc77cffeb47527760fcd3ead96ec5349779e8142b8cf6a9304eba", + "aggregatedProof": "0x3058be439578068164e57d400f4fb99fef6e787c4776d5a6ede3a472eb9db8550e7c675c2a6119e7fb9bbf689d106351f7258c1afb0a14e5698f8d7837dda0a7264718b9fe77f2c85fb9d470626a6879aa8c5606b319661ed6f473ffa904e18326aed08ba42ed28ddf241680eb7b91150829e103ca86fa0e8a5173a2d4df3db20290db040fdca9b1d110ed72785ea3136cabc7081086ff9bfa3ad5d888bb862c2fed2ebfa5dc1f369fec685b5186ab236749bfec901b401a0589034f9d91f23a01bf0d48361c739752d2ad2e126afe5cdd279f405686efe04534fa763f2228c0160be2ad00b52ea64866cc91f05b8c5a5ab13a2a7db94fdaca44dcfac37d882e074fbbfc17f2d31fdbcad3f64ac3dc97d7d0c75e1a0bc0f24fa6a61e04784e6c0d6a29ad5deaebce34f6baa476b04338db1b98fcbe6b304b444eaf2576fbf9de02071a9423b3180d56cc391aa53f897fa6c0680fc1da36e3987b8184be8d49ed1c25f3c6d1743818dedf5354b3dcdd4b0a3fe9eff46bff11de89ca345fde57b405d575c99531f75245753564e0e28bf79031680d5c49488ce3c53efdc7b9bbdb22b9edefd5cdf97d930bbe9a50da99e64b5681f916f5fbf3518d2268369437fa02634b634cc719745541d74c0b8931bcdfd0f58f242b42c523d172e7aadff17706dfcfb36d31bd7f47e9ce133b7fc8bfcb1fea34a663248f7a7cd2f0bc13013701d351aa4dbb5092ee7def90e9dbe4c2a5720f8a6124b173ac125bc7e0f5dcd42f011af66bc76e7eb4ebef3133f6a8bf64e53f66dfe4f87d3c526c7d227a860f21a8f1370c88e918332e9bccb39f447a09972b0354f23dc3e6b5f158d1ebac961b2739fe7f83f2b6ef3d123de66d542a3f34d4f9c78e1e2658510552d65fafb60078682146f1d4a0722af05a330e19c6d023e0df11049ff27353687f423c422f1785bbb23741318c996131bf1cd56e944bce6d30eef3c02eeb2340cdfe6e3b1616f4099da8287d8a583ffb9c8c1b3062000e4d02179c75c242d54bd5bda7e2fe23a3e64e83aeaf582ed679728a26b149dcfcf4ba430229eaf003ac9c45623efb0436569a67bab0e32235c2b17dd21ea42fd284c99d8645fce7f0d4cfd90ef5850c5dbd74eb3d464ae8331eab5c18309db40d731c6c21985890d86e839f0f244e163dfb108c8829e096308b53b143ab8bc0ad83eee2ddcdd9c1815fa634f5f9f4", "aggregatedProverVersion": "test", "aggregatedVerifierIndex": 1, "aggregatedProofPublicInput": "0x0ecda6d6b122aa50210c937e14351066a6e98db71c066ace19abb75a3abdfda8", diff --git a/contracts/test/testData/compressedData/test/aggregatedProof-1-46.json b/contracts/test/testData/compressedData/test/aggregatedProof-1-46.json index 8d8e761ab..74879611b 100644 --- a/contracts/test/testData/compressedData/test/aggregatedProof-1-46.json +++ b/contracts/test/testData/compressedData/test/aggregatedProof-1-46.json @@ -1,7 +1,7 @@ { "finalShnarf": "0x9562fa89830a0ba0063a636ca96e52ce2f032b855336c95dd788321f4e193419", "parentAggregationFinalShnarf": "0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f", - "aggregatedProof": "0x2b8a08e4b319c731ae97081a486f1194d72740fa1bc4a4bdcd310ddf50a75c2f02e6ae770debd31337489d9655d16ab026af7219695762a2475a4875263aa2c120fc987bcfb7e9fdeac64a1db6bc5c9d4d7731a583d84a5d8db3e69132b5583116bb7a6ac8f081a1c33fecf42b51b7f8f827066b79e19d45d587d368ebfee5421e6a8a0d63a2fe696e647088d81c1b6c96190432f42bf5f7cdedddc3fd0698581dc557b353523782c2f137f71cd76f790f4b8be7c5d3f200befaaca4cf95366328cc64b4c98566701bde2e5710cc84dbbaa50e2d1f29147bcbc506924adfd30e016218b1f40bcc6a0bac3faa9023f6855e217a5d98ac9fc7f14005adfc18d52c1368b188aaacf77ec4bbf81a6ebc567330eb405db0effdc9447f744d0595732b19322fcdba4be23e05844ecbda382ba93730fc21d9d12200f0bc625a2f5350840348893f7a0600fdd932e86a2b6c28500fb40eb578563061ce1a27bb401eb7f128233c28ecf4e3e35ed53657aaf820a4cfe9a4057c496e95fc23031c2717bf761fb7a6e471e57990f36187c93c8159929a0141ed568eb05b68dad58fc826c3f90364821de7e0cefeff209bcd7f5250efed7cb3d6ad435fc774161cfb6787916a0f669b7c1668e79d160c0e680d674279217c40b662ee91b5165f94d6939e2a5a05ab12b274c697e35d60943be8aa53ff762c1d52d3390a80f76664737de582e72430b98e07146717df294d8eb5ca704444917c6c9c3f819b929af0e44e34e9dd23c7fd04a541107fb3c74bd1fb583aaf401b6fde6a48e4d8fcb0347d04d73a280c7c5f2807c540474634d323d23d8fde9173b98008d03273a55a1d023093c4730a6ce93a60ee79aa6942c159a3ddf086311e51eafbc90fb81b919a0d588c8c6529f0df37ab008b965e10f1c6560063f0b07bc2299d519bfed68b7c45953726e90997da2b84436f4906546770fe651041208734586c090efa87488dd09ccec05b12f68cfa5f2984f4970801179d5335b2f28dc9303375811736d12041580abc0b10d35acfe032f08ead34481e70668c0efed88d5461529d24352fd6f6071e363703661d460e7edec53cc933b778ddabfab152a4d7aa736b3a361534aece194b15258a67556f07fe55fe84206331187ed3bc909775fb5b4174f16475fdba91a1e9037b49216246e4658fcf5a0b026a70a6316fa0c93f196c6b4cd4eea3904067d3", + "aggregatedProof": "0x2719f74a584ca862fc2c3b582e511bad7a37e5210741e66bc14e5d1665f3a28f0b7edd2bbb775c65515f5dd0a9b293a0f96a0146976829724cf703fa8aac0c7a22eb77c319a866b6b4c975c68ab99edb61a6d212701a3c72fd275b4b918d6449244e7f50d0e466ad3542f6174287d23ae83eb96eebded41e4ca5d7f89465663019fde4dd5409b006adac5b20f6195b68c0756d9261e3c2b16355c66f0f33e3492efc72c0571ea43547d6f724b3440239cc041d7b6aa210c165c63b5d63aec1101e4f24ad4e5d4fc96ffc727fe9e6d2453627e63140442ea4e9bdd30779a3cad11c11d5599c083d81273843eaa1f7eb12161adedc5ebd46eea265acbd7a9dc02b216acb6fca1aab70e89c445d41c6e851ba5dc2ab8d3512adbc383436da05d136102023ba2509c9de41512cdae952bf525d6629796551c0be80efb55976ee13c216353cc1d4d44768939ab9c4ce48a6b76e48fa8c194d49f0dec1d252b44439d3232f9db504aa9924083b63c1a00743132310b3963170d9e597403627971a0f742f67e29f6fb7f9d52f0a0b1472b4e7f228a65efd44b34e2021b19ff2db69540f2ae932f236b10d7644b921bbae4b9f72facfc16d431f83eeb02ac166947061360a48a6415092fd1724c710cd7301702ec8f203f5e34543f938ab08c081d12d73055c482d0960c3d55f0307fadcbb97de81865bb8ee801baa4ecd9e287950ae5328f7878b4479ee246095288b28c7a17de05ab2e1b567dcf0a1c375286ca149f2077f97cf81e28fd43e0015ec3258c607815c3efc00303b3a0ca3c9f58fecf1c72165546b105f6b603107c3f6bc9d0f16bef422d4f22c94a8cba572a588c6ea9027265a18fd4ec6f760af1a61ac048a964062967c26e4d52bf0057ee481420e0c09451b3db190d4aed0f934518b34ed70cf8653f6b324ae220a967dfb5b9a9e832e156fe1c51f961457f3f6406d1c9fa5c8f4b2620a69b93f27981e0b2d194bc3085ce2856619424a24094d151baf119c6d5bddfadaf68f499ff776a06f6740d013241fd4063c9d516f0261a69e1969b4a22c8c070afbe96f5a8d8cab1c06ede512fd0c2bafabcb388536b881ccae4dc666d6b5543d1c5bdf9d06124c880f76b90e673bd2fd9e64de2675def256eaaab7c8ff19172f1680cb4ac61292aafaa93d171abdc4169cd1cb83b1acd1328e3194b40ddfd19d12f77cbc9ccdb694f9e39b", "aggregatedProverVersion": "test", "aggregatedVerifierIndex": 1, "aggregatedProofPublicInput": "0x1e77e4d1bba517cf992e7788a104fc5612e539ea2b459b532d69efe6c416235a", diff --git a/contracts/test/testData/compressedDataEip4844/aggregatedProof-1-155.json b/contracts/test/testData/compressedDataEip4844/aggregatedProof-1-155.json index 59db1f159..617e1ba58 100644 --- a/contracts/test/testData/compressedDataEip4844/aggregatedProof-1-155.json +++ b/contracts/test/testData/compressedDataEip4844/aggregatedProof-1-155.json @@ -1,7 +1,7 @@ { "finalShnarf": "0x602c8eeedd7f6dbb7bc0348da1b0dced846acf09586c9f27aa06b494a1c49249", "parentAggregationFinalShnarf": "0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f", - "aggregatedProof": "0x1ef8ad12dc4e4b2e4e8979994ab16e0e907e3d594600fe66dff8cc3c25be910508ed51fed1de1cbc4d07869125eb137ede8f908cba8a1a97e26fb666a8ac1db02480bb12080c5ff9900b12963e3dd8a7d5719b3339326232465b232a4ba53c740860893232dc4545ad6b03bb56229a56dcc186710cf398525c18caa05f915459128d2f40878e15c9911904e3c3248d259993386f56c9929d81a3f4cf4b3305931e01e03e83334d62d8581fd5b510a37403e6f53d7b6ec7299ff1bba9f2b110812de395d4b19022f90760db5046e7305620dc64f52c4096d46729b01a397bb7b72cd3d6c66c24a5eef10d3ce870f0486d83c8ec0a9817ce0af0a1b9aa9c5792230469e2cf6d693e10d8a17d60985c9e3782f33fecbd6ed02a251815da2f4e2fc4147df40a7d4e2ceea00758ccd3df17cc20585327a9820d0108dd574f1fcf896c170deac4012eb89e3540a39f3a2b73bb449e9a46bfb9c991819cdf2905398ae00e6958a50ea58f137ec3c99d1a8877e3507920f55c317d6a5fc6718ea3bc255300f1d6325be2b5a5399562a4ffbd5059a483dfc807125d7cd75dd6d668b052cf2dbe0cd5dc3a93b6d9800bde7ba796a080a5281e7b42c38963e7a1e6647ec1eb219587e94ce96c3c258828fadaa0b76bc13f9194e120c3fa8f56847b136fcdd712851a384d0d3b5975152df354ec74847395dd3f6dd4c853f258d7a855fdb12c120c46b74b715273386a5ed3c44407797fbd09f0985c177137957a1342f38e9b090be0e96f7397b6eb380544923497f8dab1c0ef4fc1553bdbcc0fcdbcda8e8604ac0162ee8c60145e4b2fa05b4d3a0e748b6e4128a29842cbffd2992f6520a0163cac4f3fe3af4f901841db9b0a22f5882d3736a498aea2c787269fbc4589c42d71fd3a43dd1b31e8f2be1af62d75172daf970241448b44a91015a7ae4e18250cf54afc8cf67756f524a1bc245c72e2dc48cece0a18f810242f37ea2d9d26460f42e555df9e183031499fd813e666939759661eb772e077150bdfc4e5d1565a2e1e957b787fdda6b1defede8aa1405a9e376212f1be6a685f2bca487440d6f20141d2969b8a40a4144675c0eea6e13512d9c85bea1d6da212f50c5ee5b4e97e29f5131c114e0a3ef0e5702c56f61c0c6fee904aa873fd7d34301d909e9dfbe306ee6a593c2e33a691b3cc62b548c35fedf1761d856e54cf9483cc32b9849ecd", + "aggregatedProof": "0x0906688e6a1a937a5c699d7b8f19e13e959de6fc80d7da1c8299128e234310be272b5717e590f87c2132f4c71ec27f878b91e173590ea629ee56686a3a1d778522a4a4773e3df38af03c94dbf0ecf748dcbb37ef6eb39a94eaeb8b2475026a8909c380f50cb9bb8597ff47ee3dcef700a2d77382c6e700c615366497b880719b159661c3ed861a6978ceabf7c561bbf4a52e9ec784e757d62edfe3aa43efab36179fac19d79b8e2c99512b94312171b737f38e1c968429dd8995134e7daeb04a1edc9232884f434cc4c1fd797362a5200c04c9e930752027e503a8510ea25cb5257b6fa29629a3a0df4b467fd7bd6c3d16a82aee1ab66d1c616783b5c4ec9be30a07d5c76f3c8df8b32079ae8037ae5f4c27264e12fba2813d510ed3dd2de6ec080311df054fe5c3e356abd96de784cfac558c6b9b3547f5d17075caefb8e14b1d3ed6738602aa069e4f65f0a551e345c2d9272ef8bb3f6022c6b02f8f1cbcc02741dee96850cf09543a51e934502c0f3fdcdc357b61e4db2a279fa329fe708417c76e452a74e90a802f9181fc25a61f87a3a6d5d5bf49436f9045e884a29d9d0a0cda05bdbb88f4f10ad3c6141acdb82234624c6fe32e829e6d5b3877c061c60561f5c65055898a07bf00c71c7b86979b1c852725cdeb2bed3acb3bf3a51e5914f659346a2369a48697e58567fb65efcb7b35c2c53a8aff45f685f01671b6bd069d5d8c37e5219a2bfa88549693b0a2ce149a05423ca548c0fde4d18754a87a2ef4129038070351fbb496d47f0373e00177c117e1553eaed26e6a91f669795b0dbc0bc20697632cda6d3aa62497bc3b2b87378a7d6da71337586586676126c50a0af8221bcc5a24b21bb28788399eb50888cc48699fe7a2eb212a82efb552072dc6e2ed532b4ed115cc22ac05282530594b9b5036a0665a6f51114ae3b9a8310ab0c7f8ef62dd67260a2f00b203ebaa1c10308e231eb01581bc45c139e47a321ae6121cde0cb0c30924c27bc39387f19486e96076a703749e3bf4774eb4199419874514ea4fb276831fbe497a282d0d76677d71569e7fe121fd20ac16c1b42c25d3475a987e038f4f0714fc92150f56e40639ad88b4a5de092749854e5a5dbb28c633425d0d0886eb0ac24dacd849c5bd7be6a3e456d57a39ba07e8933234792708a29f3317dd2527f0c4ef68b60d78510d57eb2ea8bd8f9d8fc8eac8ce5de6", "aggregatedProverVersion": "test", "aggregatedVerifierIndex": 1, "aggregatedProofPublicInput": "0x1538dc88156cbdf280326f52e33192924ff311be4abc0dede43a14fbfb160a55", diff --git a/contracts/test/testData/compressedDataEip4844/multipleProofs/aggregatedProof-1-81.json b/contracts/test/testData/compressedDataEip4844/multipleProofs/aggregatedProof-1-81.json index 600960d2b..8acd29507 100644 --- a/contracts/test/testData/compressedDataEip4844/multipleProofs/aggregatedProof-1-81.json +++ b/contracts/test/testData/compressedDataEip4844/multipleProofs/aggregatedProof-1-81.json @@ -1,7 +1,7 @@ { "finalShnarf": "0xfd910670a8da6aaaf2431ce7345a605dc15dc41298b9410065d2f7bb1ba99fea", "parentAggregationFinalShnarf": "0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f", - "aggregatedProof": "0x1bf64c1edf68a488be4029c17e6237e73300a294e09230f0d91265f00645526c2a1c08eaa28e37ac60621b21a3b592a7c65fd9809ef8ddec93050b384c78a03b253f40adaf8ec9ea0993ffbdb305ca570117c90f5b77b810f9f2fc46613dd7010ca7906b191f1658bcc6de9f22867053f26cc13dc34861a7a3934bcd328c97380c785972db98482eaf11c2f48acbb2e5e4291e77c81fe880a1eae39aa7e9b3640c3671c11caf5a72acefbd4455c8a329c7960149a9f87f71a9277a086820dd21074cca6872707e321a20dc2d9e4cca74e7e3be89035b131f8c8686510d369551120eab67ad7ab41337d4c497f7fa19f52ae643b5a5d5fe7bb4bd24f8721bbecc1d12fc89733af07f053d734e4224ed3e456eb4e3a77a0670521106792120c2451407b05a4a6848f0493e1d6e23042ca01eae8f8dfb8b2428482de113e6aa42901ce2a8417b812c67ece9a691e7cf663daa87f5453cd3dc2d738ec604fe6d7d5d0d71f96cb9df2cecd6b1cb0cc35bca85b464dac2c8f28580fe40399fa16488f00dfaacdf58ffc8e28d4a814a2ba70daad9f97c5d693a0e8bedbca897f3aa296907dfb6d1aa8b6803c5bf6d0feb7c2626719b752f0431961c5e16691a296da61a04d6253f5385c32144b0823c31b3fa6be1b6482b89941ceb5dc1ac128a36b7432cbd7de4f3acfb2aaf0e5621dd426882efbfb5b3552c079a0428fe0b0dd5b32e168db05568b22a25aa60b6f4601c918e76e7d508f32e88477f16dbff877acb6e13d99b4015b3b72255294f45b3b1d1ecad980ba0965e69ed99d5ae91d8284db00a387835b71a2afb1a3a9f0efec6c1e377229b1916a1a57b0f559bab41e7813113551b91607348eabfbfe6c4c465caad663e58b200cf8be71bdbb6f47571a94c2863bc18f4b1a7efa4f4be94400047414bf124d0f3a6c62bb329e28ee8c4bf2915b943a77934996c61a4bce84fd66ad709d30c6dfa32735bd502dad08cdf8ecd163615f6a5b1f1cbfe593aaed6dd393bcd9161ffdb8ee755035e033dc2b20d32043f12a37dd340e31d7caf70772766d83e643e3f28f0182180189911c2ba4c7f1184dfbc48d8a49f61b4447f07e3f3d7ebb35632c52de7c953a25d9643b560be02146a8064709ff90f5aee2e0cd9177442788f4548708817d3e6352078dd8a6f2fa628982fb431153c1a2b71f86627ab10026f46a35409bde3da57650eae74ae", + "aggregatedProof": "0x183f7ee0db45f17d02d4684cd659ead8f6878db6bb04d65ac30afcf702e4bd90130bc3e0c5519918df18c17c53283c36527063f7c83f676aaed3c1f6810f324922ec77ca53cf3211859775c594b1b99475d500a9801216c255b8273943c862aa1610cbfd2e8fb97d09f2a2a6c4dcea0d8e79b03b1f71257fea10582fa0e5ba9b1fe9de72729b19d9af9964b69e6580dd8ede5276bf904af0b0ff5ebfeb55951f1c3ea4233a450dc55a32e78b847b9d640f2e488f9a75f1426a974ebe85d262511bab1d0a63cc55eae774c73ad242f87033601eb2ecbaaa7fd386c8fe6aaa6631065f352aa3bb3c83b0941f2334f82a2f26ab9e6e4b9f2ef2298ef33565b0a96d2c2d76f0fce111fdfbfde8b253b211bfb5c9a0bd86d8b4d4d0b601f0bf8a0d40212beb9449b029d1c0ae293e0eae2badaaea56b869702b6bdc675281ac6f1a642c194c8a60c26dbe3a47ea105e8b93ee1d7d06cb5cd1f7f3567d0317883f9162176101be8d18fb7f7967c0faaa3b73a0a553f381aa6285197cae19df5b1886b222a89a8d01ce300701b4612e74e78bf4c19ce826dc07e0722f9f637818867598172229da2d98a53f77b72059b44119f4b8a4325e8088c8113205f97d8a6c98bc08c0d61fd392a0898aa2ab17b0c5c97743d5a8dda58fb7fa4c2ca0dc0b6e29b00488b1fa2ee99db2d883390efc6253291571071c9872a7128442e1653b71e515013653f00a535949a2cbaf08054eb858fa07113c920a4d43d7df01a28798c02c06855f361ab0b5332cdb1ded52352a25bcb4132193157c8be961272f34e2ff3f228ff8b914befd57a205934c95a7dd2f51df3d6c5154e856e8909f7c7c66f03215fac0ac620dbb10b60c3c0309ac06fc1a6483b98d4fab851539d3e96ac2a1cf2e847951877939666df9b67667f49fbf84e75edbf64f8af62751b01b39da54e8160a3b7e7cc46c0aef5bc9c27b2dcababa958531c529d7259f3e96138653656416b8e4a4a04245e5597ea79a779dc184ee4a99854fe493305bfe95fb106d155600c1bd6457506789323204f13e27ef53433f1d33bc52e2a150b82dee2bdfbcbb129bfe038db976ec2e85b305f963fdca3fba87889728258290b1ac1de8b297411846a69fbba38bd7eea0b67ea02d4fc0f7a88f2a21796033fb26fd042d2c105b12c6df3cc02c14989b9936bf0f5232a2fa75dc761b404a0cbcd5b0aae736155e", "aggregatedProverVersion": "test", "aggregatedVerifierIndex": 1, "aggregatedProofPublicInput": "0x02df9c4f607afe80ac52003978e4a9e197a7a0b61b6601d5e0788a6fdec1c08d", diff --git a/contracts/test/testData/compressedDataEip4844/multipleProofs/aggregatedProof-82-153.json b/contracts/test/testData/compressedDataEip4844/multipleProofs/aggregatedProof-82-153.json index 63b5ef67b..dc004f2f5 100644 --- a/contracts/test/testData/compressedDataEip4844/multipleProofs/aggregatedProof-82-153.json +++ b/contracts/test/testData/compressedDataEip4844/multipleProofs/aggregatedProof-82-153.json @@ -1,7 +1,7 @@ { "finalShnarf": "0x42d7511a7a880ac5c3a61a0f480e95ec7b0e2cfff1aa106ea0256aa94bf2b865", "parentAggregationFinalShnarf": "0xfd910670a8da6aaaf2431ce7345a605dc15dc41298b9410065d2f7bb1ba99fea", - "aggregatedProof": "0x004d079dc1a3b7ab15b4180dfb1248061c53baf123b0b01cb317dfc6a79ede6104ae63614c13729ff4e937991ca9484d493750ed188427fbf2f80666289623fc1ef6e53c9123bccb4c4a3cf72f62d1e45b01b9d90e5b860c683523c108eeaa1c0364e7a18f985c6db601f25830015918cb61d5bac4f167d9180497242cda9e7315067a4af58faffdc88c8dd1ea503fb97a37b83821bc5c2c5abf2335680468810f3d56de44a398f6b81afc44cb088cf146d03570fed3a3e2fcbdafe62a1febd2211f6c32e6ccf9aabac8dfd8a45be5826e5275ff5e1ff5ee48055fd7f0d050881db23c024fe39e1e774dc5cc697bbe8340f84a1fdbbd4ca898067b51a69f7737017f66c55bb7caef98d7074c6abe644b45ce4d6b9e409f8be2bc75c8d6aa85d110413355c49ca3dd62221d4a8f0719ec633d9a6dcdaafeb2a8ddd93443302b9914b94cce67a74fe652760599efc1791dee4d81aad1244a02dc532340f0a1b31f1be9ca611ee98ba83d730ebcc68547926ce95cf6f9cc26ef67492f97d6f98dd229b9d895c6fd268ffab58751b60a3cb48db3b76f985923fef11e1de0a635616724c69edd2854429298d41e9c46c9282dbb503e26463b19d28a1d05958247899408e549c63032890a253b4c0baa0e34d89c66333ec7dbbbb3aeee1e910fba34ec01b0e31aa1a8b825f794b7f7acb0b6cbbe881ee99aa24fa1bca50f59ab5f31e7259ff3c6b279b2bc1f86e1e5d04d67feee7a4fd338fa0c1d9e1911582347c76317696ecc2a8ae3bf70b666636eb9f1ba0a4422757104c991f6f60d3454bb5fad222e14b451d5d5a0b217582cfd72e3f60e5b748d7b3ba9038cdeffae11170c062dd588da6de561ef8173474a2ac39b73e47fec9968773dec18875754ed40e91021d40b19f9a97bb95ff5531f5addb0331b70e8550614b209a2667ada653a6a18189bff192b99c946dd54dabc4f6c836c28750770484d2dd84b28cad3b2e2dd5b2d8536e48921ad151cc05fe0b9412b95dbbe631cf7484ad7f114e2222339d4fe0555cf70048fc7e1658fbf306e8c4d58b9a8e70707588a7ac8e4b393f13dba5e25b2070532365c46ad698e16b979f96cab0026c5c47fd8cbc1b2365fa94857780c5f581a30150ee802fd84ec53cf6a74ba390746d42147eb0e7132a8a61408f9016202b8704661389696d88ff769f9eaf48e84b0e3988e541e8a9d687a0d3910", + "aggregatedProof": "0x2a17576d9d695ec8bf824e897f07985be74e72a2a6f2c7d61d90fcdd100f301f120e42bcd2b39e1f12da4b006d2d67873c782edb54cb1abf79484c2541446db10dcc8684ca8b8d550ba27af2c718f48865b7358d5c8a49ecf8ac03dee69a0131242cf022404bee6441da3ae2ca740957379f897c77a8d23ffc4948371128af1305aa161d8721ea7ae2169f4e201a81e7dfdb0a768e13e3bd346b39061f15f2022dd77ee57331f7a9e0627a1148b76f1a2e691ed4a3d85129d813ad63471343bd03daad3c9866f4309d4deef03ddccc8edb93988f4d386943189440588b6dd066208b7b94ec3d5798758cf38d9a0ac9c835d736eb167b7616e572cc75ffbd287d287fb5a0ff50776148588014646b8bf0e34146c2db5567d9d0a72a7ed1f13714105a95cce24ad13141755c42bc24606e45d5b93da7b879cafdebbb5916aa0c0d22b193d5028703ec64043fbad6075c951c8a7faf68a99f707b347fc5741e1514141fd66bd2388c79de651091e5192440ab30eec03c8bb1ecc8c40f69eaf28e6d2fe183a379502565318a455e063468f7884795dd61267e045905e622fedb200f1d411a66637da04ec62bdaabb678b4af4e652b2cc58e68a0229f9ce457dc11372333ada4102a256fe38603955a12c033aec79c4f753c647a5bcf33e3e8d2d8140b09b157334aa51bb3e2ea074e082482d9bf4af75fbcf326445e5955b67c7d0b1b6d3119021fd0679ff81eef3916df35a0b782a0524efc860d44e4379a0d27811474ad4d645e6004c6f06deac43fbc5c815bf83171ee98066793e44b567b17fa1f1e0462073d07cd7e720ef2ab6cb97feaf5abaaefe4228bb643e79a46192c761ebf38d352855abd70b5ec007f5cd4dcc7b31c59ce05f3949d1515be529bf40301e9079fa20ba69e730693e28d9aa70eb6cd27f08d98ef9c3196e1219b6f2dd30f4d0ba156146d2d07a64d0cf0ac815ff23cdfb797116b8e6e91fb9904b827300281965dee3dfd20a1f666acd1da14c0e8fd8c5684e630f3f70e6b1fda8d145619af2d92c32f547e4a8cbc39b482dc507f4d039e241015e3f1fd1b92268e43f117fdb8a5c745b56b76f15b3e4d46a5522a183711f94c9b3cdafdc6baf5000d7624390c7d37b24373cfdf9e8501c2d89a0a6d4ce4b96f1d3d022ece0d91fbc5bf22a29b2f9f8ce2f7008c7c1cead9dee92fdfd935cd5076b788eb17b7444bb595", "aggregatedProverVersion": "test", "aggregatedVerifierIndex": 1, "aggregatedProofPublicInput": "0x23151dfee9756b7eb4a018d5ef30730f20e05edfd3ce67a8f898c46cb2d79341", diff --git a/contracts/test/testData/compressedDataEip4844/test/aggregatedProof-1-46.json b/contracts/test/testData/compressedDataEip4844/test/aggregatedProof-1-46.json index 8b0eb4976..8fb235411 100644 --- a/contracts/test/testData/compressedDataEip4844/test/aggregatedProof-1-46.json +++ b/contracts/test/testData/compressedDataEip4844/test/aggregatedProof-1-46.json @@ -1,7 +1,7 @@ { "finalShnarf": "0x4e584b910dc758442e58e56e0bb46c001addaffe770fb740ea0e1b90c0e2b056", "parentAggregationFinalShnarf": "0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f", - "aggregatedProof": "0x22d33dbcffa57ac78ac3b3b3a2ff52d9304eecb1073c3675fcf8225048b47aa1123499604ff2c96d334772b6d94e661c7a1fbf7e99b3b4fa1f0b8a3febca98762a5734908afa886b37351314dd68ba2f7ceaf08bef33f52d463d64a23f8523572505e5aedf7e24f132e5f21c1e0577b19081113824788bc47e3fe90d5b3da24a0f9270bd3bcac9309b715f64336c1d124a177fee676d52ef87a76bcf71d3f6a8043d5203fd92a92f2a9590e93cdf904228ebf5589c2afe45014398f5035a07c4076050fab21846b77729fdfef13d0903a4baac5a30abf986f08e11d00fa64fd420247c7ae09b7cecca8e8ca928c8ce80689a8c90d86cc3c1494d98fdf37436000c9e5d3389ac4961e8b8e9ffe1059eb34c74d61d94e23c492f24b2199f18bd180f985d8108884282fec6aeee6d59821d2186978bda855f85cd265c56903a814a2975c552578b532a84e41d71cf78cbecbef72dc374862bc692d5959b84f595612b4d55bd40e8d7261eade62c2a1bba2af2c7ba507abda5cc5f09c625ff4746d92b4588f864863a1f7806aebebc5b09bbd845d200f6a1811fb82867c8ada8656422a312841a269a6a4e628ab52eb5b0cf7329c7f876116b178ff28c4c6f0768871eea9236e28a1142df986b01fbce5c7aedd0ccd27a87a4321321c9bf1bf28f7e1365c364a0e2b4806926a18df6ca43f69b967c0473b55d74a1866bb33bc292a4006487ecb843bd209697f55dcc96ee8e15199c988f9abea42d4ddf00204627891f56f82954d1021bf869508fc3c7d0459dc9ab3bbe8b7e0a8e02675bd59a583c234417b8ac05872b5015ef665da3fca0f966d40d6988777c5def1dd834b94da10d95547edf4d56dccbbaf06f0d24ffb20799e3679a06d4748b16c5dafe7c9ba300ed0e4d01ea54fa447318721bf1e3931b9c6e059bee4bbad9976f28f531a420244395e60823940a36bd202d82578420bce7e97b2edc3021e9951c54953a4f2119d6c8912675f81fcd4a3e679f6c88e4be02cfa91f7d311e140736b8b26ceb500c7e6439c1220d645711e9017027f5a078bfffb612a9bce540229148411804d621af256389ef537ace447641bf21b5ea16d0ccf290f6979d2cdd1b26d2f8c20b047cd1d430cd6a77512006fa547193400a34561883693dda58980cbd770af4a22b132ea5302357e3ad0daf767c7b7c4106ff9e33463ccf4feff85933c87faac0", + "aggregatedProof": "0x0b8bf5b2f5f68976b8fe683f68760defd695d2d10174a1e60fb11fb4a899bba327b6a0c38c9aca130f081a9dbaca2a4d374cff4e90663e2a717548e4fd417b02022017d0c46140df4d71941e70e32c77f2658a56a7d0c19f2754a6a12c7e159b14a578ea8487e9a500d21a596b6a848f5f1b4c5c86bed63e24341909e4f5af2c08cae0ed5c77c07a8d12e8c8db26ab1c859ba3f81be0c76fedb168c5ef6d2f670c0ba48016685b8b819c390de0027b9a052fc2618de7db4fb91c49ce4fd4944a1807307baf4c6c9df6db41c131971b2fd7f20447519a98185e0a9ee36b3b24d12ebd28942e577ac2a291b99b5276c5ef90b7b87cf2c0345f9d1f1a208718fbe52b4531348aa7684c1f87decbd82891b42b94b4a929fe064ddbebf1e9d0f7e9c62c96dad0f7a01a04efe951a08b3e3f01d73ca50f5e99b630f6d43a7521af04f313c5b5d64b38a40c1c2f790d6c2ae6693b248dc0751b00dae32fe636f06a82702852ac98790c94892251d4d57e2fc920bd8ce814fa05a7245fd2ddd775f679720d649052e70cb93a922ecbdfc42f3a24440f79045232d2726754f22c840e551d0e17b0290f34fdb4914f65e3a94bd8c98ae6f46ed848c3a7c3287644e5ba1a9116e5c0c6c3db9bf0c49fcdc46be713064ab2aad6397336b38ded36a60354a34a291c86708f79ecdd2d6a0ce0c1570ca6521bb6f3c8d2f11e68fe5dbb5f5a9092191a47f88f88ba0aa1bb9ca8b0addbab07a611bfb3ebf0b5e17e4b29a59472172523c8da1da79e75c42e8900b5322c7d8d988061e9b5bd67541cd76984f3130a0796fa53a7fc1aba307034a35305256e8fd70d4bc940d54b2e7f3f29f5712e6f146ccf06f05565401075657e6151059097c2d131ab799b6dc53384fc84c938e90add4a680d396da5ed790ba89068e04b600340d2c830b923bd53c808722d396c1fedaa9940d698a442caac2ad53d290adf26132928be8e876b7a1779b3a6910224119aab5da0a20b2eb1bd8195a4b99007d4a2b76bff16b38844cfcf2b9a8ffb26b39457e600db2ef22817d530603dcb78728a50d8a6996737b85092ac741fab05cdc5f5d781705c984765274fb7592087b18056fba9bb64403710ea35abe18406cb4ed9d94a62f435a425b9973d20f41f9d03867c1cf9b0f2c3ca5734e6040c009d2d968c55e42543ddd08b6956852bb69bd9b0a5d0cdd080d7d5e59bbe9c29", "aggregatedProverVersion": "test", "aggregatedVerifierIndex": 1, "aggregatedProofPublicInput": "0x0c16c609b50fbc6f660b3fe38c5989ce059ea171048c99c0dad306cea570df61", diff --git a/coordinator/app/src/main/kotlin/linea/coordinator/config/ConfigLoader.kt b/coordinator/app/src/main/kotlin/linea/coordinator/config/ConfigLoader.kt new file mode 100644 index 000000000..d80c1c1d5 --- /dev/null +++ b/coordinator/app/src/main/kotlin/linea/coordinator/config/ConfigLoader.kt @@ -0,0 +1,136 @@ +package linea.coordinator.config + +import com.github.michaelbull.result.Err +import com.github.michaelbull.result.Ok +import com.github.michaelbull.result.Result +import com.github.michaelbull.result.get +import com.github.michaelbull.result.getOrElse +import com.sksamuel.hoplite.ConfigLoaderBuilder +import com.sksamuel.hoplite.addPathSource +import net.consensys.linea.traces.TracesCountersV1 +import net.consensys.linea.traces.TracesCountersV2 +import net.consensys.zkevm.coordinator.app.config.CoordinatorConfig +import net.consensys.zkevm.coordinator.app.config.CoordinatorConfigTomlDto +import net.consensys.zkevm.coordinator.app.config.GasPriceCapTimeOfDayMultipliersConfig +import net.consensys.zkevm.coordinator.app.config.SmartContractErrorCodesConfig +import net.consensys.zkevm.coordinator.app.config.TracesLimitsV1ConfigFile +import net.consensys.zkevm.coordinator.app.config.TracesLimitsV2ConfigFile +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import java.nio.file.Path + +inline fun loadConfigsOrError( + configFiles: List +): Result { + val confBuilder: ConfigLoaderBuilder = ConfigLoaderBuilder.Companion.empty().addDefaults() + for (configFile in configFiles.reversed()) { + // files must be added in reverse order for overriding + confBuilder.addPathSource(configFile, false) + } + + return confBuilder.build().loadConfig(emptyList()).let { config -> + if (config.isInvalid()) { + Err(config.getInvalidUnsafe().description()) + } else { + Ok(config.getUnsafe()) + } + } +} + +fun logErrorIfPresent( + configName: String, + configFiles: List, + configLoadingResult: Result, + logger: Logger +) { + if (configLoadingResult is Err) { + logger.error("Failed to load $configName from files=$configFiles with error=${configLoadingResult.error}") + } +} + +inline fun loadConfigsAndLogErrors( + configFiles: List, + configName: String, + logger: Logger = LogManager.getLogger("linea.coordinator.config") +): Result { + return loadConfigsOrError(configFiles) + .also { logErrorIfPresent(configName, configFiles, it, logger) } +} + +fun loadConfigsOrError( + coordinatorConfigFiles: List, + tracesLimitsFileV1: Path?, + tracesLimitsFileV2: Path?, + gasPriceCapTimeOfDayMultipliersFile: Path, + smartContractErrorsFile: Path, + logger: Logger = LogManager.getLogger("linea.coordinator.config") +): Result { + val coordinatorBaseConfigs = + loadConfigsAndLogErrors(coordinatorConfigFiles, "coordinator", logger) + val tracesLimitsV1Configs = tracesLimitsFileV1 + ?.let { loadConfigsAndLogErrors(listOf(it), "traces limit v1", logger) } + val tracesLimitsV2Configs = tracesLimitsFileV2 + ?.let { loadConfigsAndLogErrors(listOf(it), "traces limits v2", logger) } + val gasPriceCapTimeOfDayMultipliersConfig = + loadConfigsAndLogErrors( + listOf(gasPriceCapTimeOfDayMultipliersFile), + "l1 submission gas prices caps", + logger + ) + val smartContractErrorsConfig = loadConfigsAndLogErrors( + listOf(smartContractErrorsFile), + "smart contract errors", + logger + ) + val configError = listOf( + coordinatorBaseConfigs, + tracesLimitsV1Configs, + tracesLimitsV1Configs, + gasPriceCapTimeOfDayMultipliersConfig, + smartContractErrorsConfig + ) + .find { it is Err } + + if (configError != null) { + @Suppress("UNCHECKED_CAST") + return configError as Result + } + + val baseConfig = coordinatorBaseConfigs.get()!! + val finalConfig = baseConfig.copy( + conflation = baseConfig.conflation.copy( + _tracesLimitsV1 = tracesLimitsV1Configs?.get()?.tracesLimits?.let { TracesCountersV1(it) }, + _tracesLimitsV2 = tracesLimitsV2Configs?.get()?.tracesLimits?.let { TracesCountersV2(it) }, + _smartContractErrors = smartContractErrorsConfig.get()!!.smartContractErrors + ), + l1DynamicGasPriceCapService = baseConfig.l1DynamicGasPriceCapService.copy( + gasPriceCapCalculation = baseConfig.l1DynamicGasPriceCapService.gasPriceCapCalculation.copy( + timeOfDayMultipliers = gasPriceCapTimeOfDayMultipliersConfig.get()?.gasPriceCapTimeOfDayMultipliers + ) + ) + ) + return Ok(finalConfig) +} + +fun loadConfigs( + coordinatorConfigFiles: List, + tracesLimitsFileV1: Path?, + tracesLimitsFileV2: Path?, + gasPriceCapTimeOfDayMultipliersFile: Path, + smartContractErrorsFile: Path, + logger: Logger = LogManager.getLogger("linea.coordinator.config") +): CoordinatorConfig { + loadConfigsOrError( + coordinatorConfigFiles, + tracesLimitsFileV1, + tracesLimitsFileV2, + gasPriceCapTimeOfDayMultipliersFile, + smartContractErrorsFile, + logger + ).let { + return it + .getOrElse { + throw RuntimeException("Invalid configurations: $it") + }.reified() + } +} diff --git a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorAppCli.kt b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorAppCli.kt index e552add8c..febd8afec 100644 --- a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorAppCli.kt +++ b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorAppCli.kt @@ -1,21 +1,6 @@ package net.consensys.zkevm.coordinator.app -import com.github.michaelbull.result.Err -import com.github.michaelbull.result.Ok -import com.github.michaelbull.result.Result -import com.github.michaelbull.result.get -import com.github.michaelbull.result.getError -import com.github.michaelbull.result.onFailure -import com.sksamuel.hoplite.ConfigLoaderBuilder -import com.sksamuel.hoplite.addFileSource -import net.consensys.linea.traces.TracesCountersV1 -import net.consensys.linea.traces.TracesCountersV2 import net.consensys.zkevm.coordinator.app.config.CoordinatorConfig -import net.consensys.zkevm.coordinator.app.config.CoordinatorConfigTomlDto -import net.consensys.zkevm.coordinator.app.config.GasPriceCapTimeOfDayMultipliersConfig -import net.consensys.zkevm.coordinator.app.config.SmartContractErrorCodesConfig -import net.consensys.zkevm.coordinator.app.config.TracesLimitsV1ConfigFile -import net.consensys.zkevm.coordinator.app.config.TracesLimitsV2ConfigFile import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger import picocli.CommandLine @@ -115,13 +100,14 @@ internal constructor(private val errorWriter: PrintWriter, private val startActi } } - val configs = validateConfigs( - tracesLimitsFile, - tracesLimitsV2File, - smartContractErrorsFile, - gasPriceCapTimeOfDayMultipliersFile, - configFiles - ) ?: return 1 + val configs = linea.coordinator.config.loadConfigs( + coordinatorConfigFiles = configFiles.map { it.toPath() }, + tracesLimitsFileV1 = tracesLimitsFile?.toPath(), + tracesLimitsFileV2 = tracesLimitsV2File?.toPath(), + smartContractErrorsFile = smartContractErrorsFile.toPath(), + gasPriceCapTimeOfDayMultipliersFile = gasPriceCapTimeOfDayMultipliersFile.toPath(), + logger = logger + ) if (checkConfigsOnly) { logger.info("All configs are valid. Final configs: {}", configs) @@ -144,7 +130,7 @@ internal constructor(private val errorWriter: PrintWriter, private val startActi } fun reportUserError(ex: Throwable) { - logger.fatal(ex.message, ex) + logger.fatal(ex.message) errorWriter.println(ex.message) printUsage(errorWriter) } @@ -155,97 +141,6 @@ internal constructor(private val errorWriter: PrintWriter, private val startActi outputWriter.println(COMMAND_NAME + " --help") } - private fun validateConfigs( - tracesLimitsFile: File?, - tracesLimitsV2File: File?, - smartContractErrorsFile: File, - gasPriceCapTimeOfDayMultipliersFile: File, - coordinatorConfigFiles: List - ): CoordinatorConfig? { - var hasConfigError = false - val tracesLimitsV1Configs = if (tracesLimitsFile == null) { - null - } else { - loadConfigsOrError(listOf(tracesLimitsFile)) - } - - val tracesLimitsV2Configs = if (tracesLimitsV2File == null) { - null - } else { - loadConfigsOrError(listOf(tracesLimitsV2File)) - } - - val smartContractErrorCodes = - loadConfigsOrError(listOf(smartContractErrorsFile)) - - val gasPriceCapTimeOfDayMultipliers = - loadConfigsOrError(listOf(gasPriceCapTimeOfDayMultipliersFile)) - - val configs = loadConfigsOrError(coordinatorConfigFiles) - - if (tracesLimitsV1Configs is Err) { - hasConfigError = true - logger.error("Reading {} failed: {}", tracesLimitsFile, tracesLimitsV1Configs.getError()) - } else if (tracesLimitsV1Configs is Ok) { - runCatching { - TracesCountersV1(tracesLimitsV1Configs.get()!!.tracesLimits) - }.getOrElse { - hasConfigError = true - logger.error("Traces limits file {} is incomplete. {}", tracesLimitsFile, it.message) - } - } - - if (tracesLimitsV2Configs is Err) { - hasConfigError = true - logger.error("Reading {} failed: {}", tracesLimitsV2File, tracesLimitsV2Configs.getError()) - } else if (tracesLimitsV2Configs is Ok) { - runCatching { - TracesCountersV2(tracesLimitsV2Configs.get()!!.tracesLimits) - }.getOrElse { - hasConfigError = true - logger.error("Traces limits file {} is incomplete. {}", tracesLimitsV2File, it.message) - } - } - - if (smartContractErrorCodes is Err) { - hasConfigError = true - logger.error("Reading {} failed: {}", smartContractErrorsFile, smartContractErrorCodes.getError()) - } - - if (gasPriceCapTimeOfDayMultipliers is Err) { - hasConfigError = true - logger.error( - "Reading {} failed: {}", - gasPriceCapTimeOfDayMultipliersFile, - gasPriceCapTimeOfDayMultipliers.getError() - ) - } - - if (configs is Err) { - hasConfigError = true - logger.error("Reading {} failed: {}", configFiles, configs.getError()) - } - - return if (hasConfigError) { - null - } else { - configs.get()?.let { config: CoordinatorConfigTomlDto -> - config.copy( - conflation = config.conflation.copy( - _tracesLimitsV1 = tracesLimitsV1Configs?.get()?.tracesLimits?.let { TracesCountersV1(it) }, - _tracesLimitsV2 = tracesLimitsV2Configs?.get()?.tracesLimits?.let { TracesCountersV2(it) }, - _smartContractErrors = smartContractErrorCodes.get()?.smartContractErrors - ), - l1DynamicGasPriceCapService = config.l1DynamicGasPriceCapService.copy( - gasPriceCapCalculation = config.l1DynamicGasPriceCapService.gasPriceCapCalculation.copy( - timeOfDayMultipliers = gasPriceCapTimeOfDayMultipliers.get()?.gasPriceCapTimeOfDayMultipliers - ) - ) - ).reified() - } - } - } - /** * Not using a static field for this log instance because some code in this class executes prior * to the logging configuration being applied so it's not always safe to use the logger. @@ -267,29 +162,5 @@ internal constructor(private val errorWriter: PrintWriter, private val startActi val errorWriter = PrintWriter(System.err, true, Charset.defaultCharset()) return CoordinatorAppCli(errorWriter, startAction) } - - inline fun loadConfigs(configFiles: List, errorWriter: PrintWriter): T? { - return loadConfigsOrError(configFiles).onFailure { error -> - errorWriter.println(error) - }.get() - } - - inline fun loadConfigsOrError( - configFiles: List - ): Result { - val confBuilder: ConfigLoaderBuilder = ConfigLoaderBuilder.Companion.empty().addDefaults() - for (configFile in configFiles.reversed()) { - // files must be added in reverse order for overriding - confBuilder.addFileSource(configFile, false) - } - - return confBuilder.build().loadConfig(emptyList()).let { config -> - if (config.isInvalid()) { - Err(config.getInvalidUnsafe().description()) - } else { - Ok(config.getUnsafe()) - } - } - } } } diff --git a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt index 9986f7d07..4b286a997 100644 --- a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt +++ b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt @@ -4,15 +4,14 @@ import build.linea.clients.StateManagerClientV1 import build.linea.clients.StateManagerV1JsonRpcClient import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly +import build.linea.web3j.Web3JLogsClient import io.vertx.core.Vertx import kotlinx.datetime.Clock import linea.encoding.BlockRLPEncoder import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.blob.ShnarfCalculatorVersion -import net.consensys.linea.contract.LineaRollupAsyncFriendly import net.consensys.linea.contract.Web3JL2MessageService import net.consensys.linea.contract.Web3JL2MessageServiceLogsClient -import net.consensys.linea.contract.Web3JLogsClient import net.consensys.linea.contract.l1.GenesisStateProvider import net.consensys.linea.ethereum.gaspricing.BoundableFeeCalculator import net.consensys.linea.ethereum.gaspricing.FeesCalculator @@ -220,20 +219,19 @@ class L1DependentApp( ) ) - private val l1FinalizationMonitor = run { - // To avoid setDefaultBlockParameter clashes - val contractClient: LineaRollupSmartContractClientReadOnly = Web3JLineaRollupSmartContractClientReadOnly( - contractAddress = configs.l1.zkEvmContractAddress, - web3j = l1Web3jClient - ) + private val lineaRollupClient: LineaRollupSmartContractClientReadOnly = Web3JLineaRollupSmartContractClientReadOnly( + contractAddress = configs.l1.zkEvmContractAddress, + web3j = l1Web3jClient + ) + private val l1FinalizationMonitor = run { FinalizationMonitorImpl( config = FinalizationMonitorImpl.Config( pollingInterval = configs.l1.finalizationPollingInterval.toKotlinDuration(), l1QueryBlockTag = configs.l1.l1QueryBlockTag ), - contract = contractClient, + contract = lineaRollupClient, l2Client = l2Web3jClient, vertx = vertx ) @@ -922,17 +920,9 @@ class L1DependentApp( } private fun lastFinalizedBlock(): SafeFuture { - val zkEvmClient: LineaRollupAsyncFriendly = instantiateZkEvmContractClient( - configs.l1, - finalizationTransactionManager, - feesFetcher, - l1MinPriorityFeeCalculator, - l1Web3jClient, - smartContractErrors - ) val l1BasedLastFinalizedBlockProvider = L1BasedLastFinalizedBlockProvider( vertx, - zkEvmClient, + lineaRollupClient, configs.conflation.consistentNumberOfBlocksOnL1ToWait.toUInt() ) return l1BasedLastFinalizedBlockProvider.getLastFinalizedBlock() diff --git a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/LastFinalizedBlockProvider.kt b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/LastFinalizedBlockProvider.kt index 74987b5d9..cefdeff19 100644 --- a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/LastFinalizedBlockProvider.kt +++ b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/LastFinalizedBlockProvider.kt @@ -1,14 +1,12 @@ package net.consensys.zkevm.coordinator.app -import build.linea.contract.LineaRollupV5 +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly import io.vertx.core.Vertx +import net.consensys.linea.BlockParameter import net.consensys.linea.async.AsyncRetryer -import net.consensys.toULong import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger -import org.web3j.protocol.core.DefaultBlockParameterName import tech.pegasys.teku.infrastructure.async.SafeFuture -import java.math.BigInteger import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicReference import kotlin.time.Duration @@ -26,7 +24,7 @@ interface LastFinalizedBlockProvider { */ class L1BasedLastFinalizedBlockProvider( private val vertx: Vertx, - private val lineaRollupSmartContractWeb3jClient: LineaRollupV5, + private val lineaRollupSmartContractClient: LineaRollupSmartContractClientReadOnly, private val consistentNumberOfBlocksOnL1: UInt, private val numberOfRetries: UInt = Int.MAX_VALUE.toUInt(), private val pollingInterval: Duration = 2.seconds @@ -34,42 +32,33 @@ class L1BasedLastFinalizedBlockProvider( private val log: Logger = LogManager.getLogger(this::class.java) override fun getLastFinalizedBlock(): SafeFuture { - lineaRollupSmartContractWeb3jClient.setDefaultBlockParameter(DefaultBlockParameterName.LATEST) - - return SafeFuture.of(lineaRollupSmartContractWeb3jClient.currentL2BlockNumber().sendAsync()) - .thenCompose { blockNumber -> + val lastObservedBlock = AtomicReference(null) + val numberOfObservations = AtomicInteger(1) + val isConsistentEnough = { lastPolledBlockNumber: ULong -> + if (lastPolledBlockNumber == lastObservedBlock.get()) { + numberOfObservations.incrementAndGet().toUInt() >= consistentNumberOfBlocksOnL1 + } else { log.info( - "Rollup lastFinalizedBlockNumber={} waiting {} blocks for confirmation for no updates", - blockNumber, + "Rollup finalized block updated from {} to {}, waiting {} blocks for confirmation", + lastObservedBlock.get(), + lastPolledBlockNumber, consistentNumberOfBlocksOnL1 ) - val lastObservedBlock = AtomicReference(blockNumber) - val numberOfObservations = AtomicInteger(1) - val isConsistentEnough = { lasPolledBlockNumber: BigInteger -> - if (lasPolledBlockNumber == lastObservedBlock.get()) { - numberOfObservations.incrementAndGet().toUInt() >= consistentNumberOfBlocksOnL1 - } else { - log.info( - "Rollup finalized block updated from {} to {}, waiting {} blocks for confirmation", - blockNumber, - lasPolledBlockNumber, - consistentNumberOfBlocksOnL1 - ) - numberOfObservations.set(1) - lastObservedBlock.set(lasPolledBlockNumber) - false - } - } - - AsyncRetryer.retry( - vertx, - maxRetries = numberOfRetries.toInt(), - backoffDelay = pollingInterval, - stopRetriesPredicate = isConsistentEnough - ) { - SafeFuture.of(lineaRollupSmartContractWeb3jClient.currentL2BlockNumber().sendAsync()) - } + numberOfObservations.set(1) + lastObservedBlock.set(lastPolledBlockNumber) + false } - .thenApply { it.toULong() } + } + + return AsyncRetryer.retry( + vertx, + maxRetries = numberOfRetries.toInt(), + backoffDelay = pollingInterval, + stopRetriesPredicate = isConsistentEnough + ) { + lineaRollupSmartContractClient.finalizedL2BlockNumber( + blockParameter = BlockParameter.Tag.LATEST + ) + } } } diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/L1BasedLastFinalizedBlockProviderTest.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/L1BasedLastFinalizedBlockProviderTest.kt index 6632e7e3a..e9a655e99 100644 --- a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/L1BasedLastFinalizedBlockProviderTest.kt +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/L1BasedLastFinalizedBlockProviderTest.kt @@ -1,42 +1,39 @@ package net.consensys.zkevm.coordinator.app -import build.linea.contract.LineaRollupV5 +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly import io.vertx.core.Vertx +import net.consensys.linea.BlockParameter import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import org.mockito.kotlin.doReturn +import org.mockito.Mockito +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.whenever -import org.web3j.protocol.core.RemoteFunctionCall -import java.math.BigInteger -import java.util.concurrent.CompletableFuture +import tech.pegasys.teku.infrastructure.async.SafeFuture import kotlin.time.Duration.Companion.milliseconds class L1BasedLastFinalizedBlockProviderTest { - private lateinit var lineaRollupSmartContractWeb3jClient: LineaRollupV5 + private lateinit var lineaRollupClient: LineaRollupSmartContractClientReadOnly @BeforeEach fun beforeEach() { - lineaRollupSmartContractWeb3jClient = mock() + lineaRollupClient = + mock(defaultAnswer = Mockito.RETURNS_DEEP_STUBS) } @Test fun `shall wait number of blocks before returning for consistency`() { - val replies = listOf( - mockRemoteFnCallWithBlockNumber(100), - mockRemoteFnCallWithBlockNumber(100), - mockRemoteFnCallWithBlockNumber(101), - mockRemoteFnCallWithBlockNumber(101), - mockRemoteFnCallWithBlockNumber(101), - mockRemoteFnCallWithBlockNumber(101) - ) - whenever(lineaRollupSmartContractWeb3jClient.currentL2BlockNumber()) - .thenReturn(replies[0], *replies.subList(1, replies.size).toTypedArray()) + val replies = listOf(100UL, 100UL, 101UL, 101UL, 101UL, 101UL) + whenever(lineaRollupClient.finalizedL2BlockNumber(eq(BlockParameter.Tag.LATEST))) + .thenReturn( + SafeFuture.completedFuture(replies[0]), + *replies.subList(1, replies.size).map { SafeFuture.completedFuture(it) }.toTypedArray() + ) val resumerCalculator = L1BasedLastFinalizedBlockProvider( Vertx.vertx(), - lineaRollupSmartContractWeb3jClient, + lineaRollupClient, consistentNumberOfBlocksOnL1 = 3u, numberOfRetries = 50u, pollingInterval = 10.milliseconds @@ -44,11 +41,4 @@ class L1BasedLastFinalizedBlockProviderTest { assertThat(resumerCalculator.getLastFinalizedBlock().get()).isEqualTo(101.toULong()) } - - private fun mockRemoteFnCallWithBlockNumber(blockNumber: Long): RemoteFunctionCall { - return mock>() { - on { send() } doReturn (BigInteger.valueOf(blockNumber)) - on { sendAsync() } doReturn (CompletableFuture.completedFuture(BigInteger.valueOf(blockNumber))) - } - } } diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/SwitchProviderImplTest.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/SwitchProviderImplTest.kt index 03c3d81ab..8e6b0d012 100644 --- a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/SwitchProviderImplTest.kt +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/SwitchProviderImplTest.kt @@ -2,12 +2,12 @@ package net.consensys.zkevm.coordinator.app +import build.linea.web3j.Web3JLogsClient import io.vertx.junit5.Timeout import io.vertx.junit5.VertxExtension import io.vertx.junit5.VertxTestContext import net.consensys.linea.contract.EIP1559GasProvider import net.consensys.linea.contract.L2MessageService -import net.consensys.linea.contract.Web3JLogsClient import net.consensys.toULong import net.consensys.zkevm.ethereum.coordination.conflation.upgrade.SwitchProvider import net.consensys.zkevm.ethereum.signing.ECKeypairSigner diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt index 33005abe6..3b62a295a 100644 --- a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt @@ -1,10 +1,9 @@ package net.consensys.zkevm.coordinator.app.config -import com.github.michaelbull.result.get import com.github.michaelbull.result.getError -import com.github.michaelbull.result.onFailure -import com.github.michaelbull.result.onSuccess import com.sksamuel.hoplite.Masked +import linea.coordinator.config.loadConfigs +import linea.coordinator.config.loadConfigsOrError import net.consensys.linea.BlockParameter import net.consensys.linea.blob.BlobCompressorVersion import net.consensys.linea.ethereum.gaspricing.BoundableFeeCalculator @@ -15,178 +14,39 @@ import net.consensys.linea.ethereum.gaspricing.staticcap.MinerExtraDataV1Calcula import net.consensys.linea.ethereum.gaspricing.staticcap.TransactionCostCalculator import net.consensys.linea.ethereum.gaspricing.staticcap.VariableFeesCalculator import net.consensys.linea.jsonrpc.client.RequestRetryConfig -import net.consensys.linea.traces.TracesCountersV1 -import net.consensys.linea.traces.TracesCountersV2 -import net.consensys.linea.traces.TracingModuleV1 -import net.consensys.linea.traces.TracingModuleV2 -import net.consensys.linea.web3j.SmartContractErrors -import net.consensys.zkevm.coordinator.app.CoordinatorAppCli import net.consensys.zkevm.coordinator.app.L2NetworkGasPricingService import net.consensys.zkevm.coordinator.clients.prover.FileBasedProverConfig import net.consensys.zkevm.coordinator.clients.prover.ProverConfig import net.consensys.zkevm.coordinator.clients.prover.ProversConfig import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.fail import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows -import java.io.File import java.math.BigInteger import java.net.URI import java.nio.file.Path +import java.nio.file.Paths import java.time.Duration import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds class CoordinatorConfigTest { companion object { - private val apiConfig = ApiConfig(9545U) - private val conflationConfig = ConflationConfig( consistentNumberOfBlocksOnL1ToWait = 1, conflationDeadline = Duration.parse("PT6S"), conflationDeadlineCheckInterval = Duration.parse("PT3S"), conflationDeadlineLastBlockConfirmationDelay = Duration.parse("PT2S"), blocksLimit = 2, - _tracesLimitsV1 = TracesCountersV1( - mapOf( - TracingModuleV1.ADD to 524288U, - TracingModuleV1.BIN to 262144U, - TracingModuleV1.BIN_RT to 262144U, - TracingModuleV1.EC_DATA to 4096U, - TracingModuleV1.EXT to 131072U, - TracingModuleV1.HUB to 2097152U, - TracingModuleV1.INSTRUCTION_DECODER to 512U, - TracingModuleV1.MMIO to 131072U, - TracingModuleV1.MMU to 131072U, - TracingModuleV1.MMU_ID to 131072U, - TracingModuleV1.MOD to 131072U, - TracingModuleV1.MUL to 65536U, - TracingModuleV1.MXP to 524288U, - TracingModuleV1.PHONEY_RLP to 32768U, - TracingModuleV1.PUB_HASH to 32768U, - TracingModuleV1.PUB_HASH_INFO to 32768U, - TracingModuleV1.PUB_LOG to 16384U, - TracingModuleV1.PUB_LOG_INFO to 16384U, - TracingModuleV1.RLP to 512U, - TracingModuleV1.ROM to 4194304U, - TracingModuleV1.SHF to 65536U, - TracingModuleV1.SHF_RT to 4096U, - TracingModuleV1.TX_RLP to 131072U, - TracingModuleV1.WCP to 262144U, - TracingModuleV1.BLOCK_TX to 200U, - TracingModuleV1.BLOCK_L2L1LOGS to 16U, - TracingModuleV1.BLOCK_KECCAK to 8192U, - TracingModuleV1.PRECOMPILE_ECRECOVER to 10000U, - TracingModuleV1.PRECOMPILE_SHA2 to 10000U, - TracingModuleV1.PRECOMPILE_RIPEMD to 10000U, - TracingModuleV1.PRECOMPILE_IDENTITY to 10000U, - TracingModuleV1.PRECOMPILE_MODEXP to 10000U, - TracingModuleV1.PRECOMPILE_ECADD to 10000U, - TracingModuleV1.PRECOMPILE_ECMUL to 10000U, - TracingModuleV1.PRECOMPILE_ECPAIRING to 10000U, - TracingModuleV1.PRECOMPILE_BLAKE2F to 512U - ) - ), - _tracesLimitsV2 = TracesCountersV2( - mapOf( - TracingModuleV2.ADD to 524288u, - TracingModuleV2.BIN to 262144u, - TracingModuleV2.BLAKE_MODEXP_DATA to 16384u, - TracingModuleV2.BLOCK_DATA to 1024u, - TracingModuleV2.BLOCK_HASH to 512u, - TracingModuleV2.EC_DATA to 262144u, - TracingModuleV2.EUC to 65536u, - TracingModuleV2.EXP to 8192u, - TracingModuleV2.EXT to 1048576u, - TracingModuleV2.GAS to 65536u, - TracingModuleV2.HUB to 2097152u, - TracingModuleV2.LOG_DATA to 65536u, - TracingModuleV2.LOG_INFO to 4096u, - TracingModuleV2.MMIO to 4194304u, - TracingModuleV2.MMU to 4194304u, - TracingModuleV2.MOD to 131072u, - TracingModuleV2.MUL to 65536u, - TracingModuleV2.MXP to 524288u, - TracingModuleV2.OOB to 262144u, - TracingModuleV2.RLP_ADDR to 4096u, - TracingModuleV2.RLP_TXN to 131072u, - TracingModuleV2.RLP_TXN_RCPT to 65536u, - TracingModuleV2.ROM to 4194304u, - TracingModuleV2.ROM_LEX to 1024u, - TracingModuleV2.SHAKIRA_DATA to 32768u, - TracingModuleV2.SHF to 65536u, - TracingModuleV2.STP to 16384u, - TracingModuleV2.TRM to 32768u, - TracingModuleV2.TXN_DATA to 8192u, - TracingModuleV2.WCP to 262144u, - TracingModuleV2.BIN_REFERENCE_TABLE to 4294967295u, - TracingModuleV2.SHF_REFERENCE_TABLE to 4294967295u, - TracingModuleV2.INSTRUCTION_DECODER to 4294967295u, - TracingModuleV2.PRECOMPILE_ECRECOVER_EFFECTIVE_CALLS to 128u, - TracingModuleV2.PRECOMPILE_SHA2_BLOCKS to 671u, - TracingModuleV2.PRECOMPILE_RIPEMD_BLOCKS to 671u, - TracingModuleV2.PRECOMPILE_MODEXP_EFFECTIVE_CALLS to 4u, - TracingModuleV2.PRECOMPILE_ECADD_EFFECTIVE_CALLS to 16384u, - TracingModuleV2.PRECOMPILE_ECMUL_EFFECTIVE_CALLS to 32u, - TracingModuleV2.PRECOMPILE_ECPAIRING_FINAL_EXPONENTIATIONS to 16u, - TracingModuleV2.PRECOMPILE_ECPAIRING_G2_MEMBERSHIP_CALLS to 64u, - TracingModuleV2.PRECOMPILE_ECPAIRING_MILLER_LOOPS to 64u, - TracingModuleV2.PRECOMPILE_BLAKE_EFFECTIVE_CALLS to 600u, - TracingModuleV2.PRECOMPILE_BLAKE_ROUNDS to 600u, - TracingModuleV2.BLOCK_KECCAK to 8192u, - TracingModuleV2.BLOCK_L1_SIZE to 1000000u, - TracingModuleV2.BLOCK_L2_L1_LOGS to 16u, - TracingModuleV2.BLOCK_TRANSACTIONS to 200u - ) - ), + _tracesLimitsV1 = expectedTracesCountersV1, + _tracesLimitsV2 = expectedTracesLimitsV2, _smartContractErrors = mapOf( // L1 Linea Rollup "0f06cd15" to "DataAlreadySubmitted", "c01eab56" to "EmptySubmissionData", - "abefa5e8" to "DataStartingBlockDoesNotMatch", - "5548c6b3" to "DataParentHasEmptyShnarf", - "36459fa0" to "L1RollingHashDoesNotExistOnL1", - "cbbd7953" to "FirstBlockGreaterThanFinalBlock", - "a386ed70" to "FirstBlockLessThanOrEqualToLastFinalizedBlock", - "70614405" to "FinalBlockNumberLessThanOrEqualToLastFinalizedBlock", - "2898482a" to "FinalBlockStateEqualsZeroHash", - "bf81c6e0" to "FinalizationInTheFuture", - "0c256592" to "MissingMessageNumberForRollingHash", - "5228f4c8" to "MissingRollingHashForMessageNumber", - "729eebce" to "FirstByteIsNotZero", - "6426c6c5" to "BytesLengthNotMultipleOf32", - "68dcad5f" to "PointEvaluationResponseInvalid", - "f75db381" to "PrecompileReturnDataLengthWrong", - "a71194af" to "PointEvaluationFailed", - "2f22b98a" to "LastFinalizedShnarfWrong", - "7dc2487d" to "SnarkHashIsZeroHash", - "bc5aad11" to "FinalizationStateIncorrect", - "b1504a5f" to "BlobSubmissionDataIsMissing", - "c0e41e1d" to "EmptyBlobDataAtIndex", - "fb4cd6ef" to "FinalBlockDoesNotMatchShnarfFinalBlock", - "2526F108" to "ShnarfAndFinalBlockNumberLengthsMismatched", - "d3664fb3" to "FinalShnarfWrong", - "4e686675" to "L2MerkleRootDoesNotExist", - "e5d14425" to "L2MerkleRootAlreadyAnchored", - "0c91d776" to "BytesLengthNotMultipleOfTwo", - "ead4c30e" to "StartingRootHashDoesNotMatch", - "7907d79b" to "ProofIsEmpty", - "69ed70ab" to "InvalidProofType", - "09bde339" to "InvalidProof", - "db246dde" to "IsPaused", - "b015579f" to "IsNotPaused", - "3b174434" to "MessageHashesListLengthHigherThanOneHundred", - "ca389c44" to "InvalidProofOrProofVerificationRanOutOfGas", - "42ab979d" to "ParentBlobNotSubmitted", - "edeae83c" to "FinalBlobNotSubmitted", - // L2 Message Service - "6446cc9c" to "MessageHashesListLengthIsZero", - "d39e75f9" to "L1MessageNumberSynchronizationWrong", - "7557a60a" to "L1RollingHashSynchronizationWrong", - "36a4bb94" to "FinalRollingHashIsZero" + "abefa5e8" to "DataStartingBlockDoesNotMatch" ), fetchBlocksLimit = 4000 ) @@ -478,176 +338,7 @@ class CoordinatorConfigTest { gasPriceCapsCheckCoefficient = 0.9, historicBaseFeePerBlobGasLowerBound = 100_000_000u, historicAvgRewardConstant = 100_000_000u, - timeOfDayMultipliers = mapOf( - "SUNDAY_0" to 1.7489178377946066, - "SUNDAY_1" to 1.7494632175198737, - "SUNDAY_2" to 1.75, - "SUNDAY_3" to 1.733166295438555, - "SUNDAY_4" to 1.6993775444542885, - "SUNDAY_5" to 1.6350086618091364, - "SUNDAY_6" to 1.5627740860151331, - "SUNDAY_7" to 1.4831149222064164, - "SUNDAY_8" to 1.4101476768256929, - "SUNDAY_9" to 1.370085278922007, - "SUNDAY_10" to 1.3516015544068651, - "SUNDAY_11" to 1.3482404546676368, - "SUNDAY_12" to 1.3580905751578942, - "SUNDAY_13" to 1.3775497419563296, - "SUNDAY_14" to 1.3700255667542938, - "SUNDAY_15" to 1.2642948506461285, - "SUNDAY_16" to 1.2794806131912935, - "SUNDAY_17" to 1.2750892256476676, - "SUNDAY_18" to 1.2919720208955585, - "SUNDAY_19" to 1.317984990098603, - "SUNDAY_20" to 1.4433501639513178, - "SUNDAY_21" to 1.4705921238901998, - "SUNDAY_22" to 1.515043370430801, - "SUNDAY_23" to 1.5556742617266397, - "MONDAY_0" to 1.5381562278760164, - "MONDAY_1" to 1.5423761828433993, - "MONDAY_2" to 1.539015963719092, - "MONDAY_3" to 1.487676153648977, - "MONDAY_4" to 1.430973985132037, - "MONDAY_5" to 1.4656765439056292, - "MONDAY_6" to 1.4484298622828233, - "MONDAY_7" to 1.4459076216659752, - "MONDAY_8" to 1.4899061835032241, - "MONDAY_9" to 1.5249733712852067, - "MONDAY_10" to 1.511367489481033, - "MONDAY_11" to 1.4225695658047797, - "MONDAY_12" to 1.2887291896624584, - "MONDAY_13" to 1.1460926897291355, - "MONDAY_14" to 1.0004897955233254, - "MONDAY_15" to 0.8694664537368378, - "MONDAY_16" to 0.8270273375962802, - "MONDAY_17" to 0.7868289022833883, - "MONDAY_18" to 0.7780303121746551, - "MONDAY_19" to 0.7756215256634205, - "MONDAY_20" to 0.7984895728860915, - "MONDAY_21" to 0.8918589268832423, - "MONDAY_22" to 0.9967716668541272, - "MONDAY_23" to 1.0973334887144106, - "TUESDAY_0" to 1.2233064209957951, - "TUESDAY_1" to 1.3238883432855082, - "TUESDAY_2" to 1.3874518307497257, - "TUESDAY_3" to 1.463621147171298, - "TUESDAY_4" to 1.4975989065490154, - "TUESDAY_5" to 1.481679186141442, - "TUESDAY_6" to 1.452778387763161, - "TUESDAY_7" to 1.3414858185569951, - "TUESDAY_8" to 1.2869454637983988, - "TUESDAY_9" to 1.249347290389873, - "TUESDAY_10" to 1.196488297386161, - "TUESDAY_11" to 1.1136140507034202, - "TUESDAY_12" to 0.9867528660797885, - "TUESDAY_13" to 0.8018989158195754, - "TUESDAY_14" to 0.6173048748109258, - "TUESDAY_15" to 0.46718586671750373, - "TUESDAY_16" to 0.4103633833041902, - "TUESDAY_17" to 0.4871260756989506, - "TUESDAY_18" to 0.5667378483016126, - "TUESDAY_19" to 0.6464203510900723, - "TUESDAY_20" to 0.7780268325299871, - "TUESDAY_21" to 0.8995921101255763, - "TUESDAY_22" to 1.0077600114996088, - "TUESDAY_23" to 1.1109769960680498, - "WEDNESDAY_0" to 1.2097668746150059, - "WEDNESDAY_1" to 1.2631002319009361, - "WEDNESDAY_2" to 1.2912775191940549, - "WEDNESDAY_3" to 1.3229785939630059, - "WEDNESDAY_4" to 1.3428607301494424, - "WEDNESDAY_5" to 1.3750788517823973, - "WEDNESDAY_6" to 1.3752344527256497, - "WEDNESDAY_7" to 1.3505490078766218, - "WEDNESDAY_8" to 1.2598503219367945, - "WEDNESDAY_9" to 1.2051668977452374, - "WEDNESDAY_10" to 1.0320896222195326, - "WEDNESDAY_11" to 0.8900138031631949, - "WEDNESDAY_12" to 0.6341155208698448, - "WEDNESDAY_13" to 0.48337590254714624, - "WEDNESDAY_14" to 0.2903189399226416, - "WEDNESDAY_15" to 0.25, - "WEDNESDAY_16" to 0.25711039485046006, - "WEDNESDAY_17" to 0.37307641907591793, - "WEDNESDAY_18" to 0.45280799454961196, - "WEDNESDAY_19" to 0.5631397823847637, - "WEDNESDAY_20" to 0.6285005244224133, - "WEDNESDAY_21" to 0.6671897537279405, - "WEDNESDAY_22" to 0.7268406397452634, - "WEDNESDAY_23" to 0.8068904097486369, - "THURSDAY_0" to 0.9021601102971811, - "THURSDAY_1" to 1.023741688964238, - "THURSDAY_2" to 1.1340689935096755, - "THURSDAY_3" to 1.2530130345819006, - "THURSDAY_4" to 1.3163421664973542, - "THURSDAY_5" to 1.3536343767230727, - "THURSDAY_6" to 1.3432290485306728, - "THURSDAY_7" to 1.2864983218982178, - "THURSDAY_8" to 1.2320488534113174, - "THURSDAY_9" to 1.1984530721079034, - "THURSDAY_10" to 1.0877338251341975, - "THURSDAY_11" to 0.9999324929016475, - "THURSDAY_12" to 0.87536726762619, - "THURSDAY_13" to 0.6560822412167919, - "THURSDAY_14" to 0.44836474861432074, - "THURSDAY_15" to 0.36145134935025247, - "THURSDAY_16" to 0.2695997829759713, - "THURSDAY_17" to 0.2898426312618241, - "THURSDAY_18" to 0.3970093434340387, - "THURSDAY_19" to 0.5193273246848977, - "THURSDAY_20" to 0.6426415257034419, - "THURSDAY_21" to 0.800685718218497, - "THURSDAY_22" to 0.9215516833839711, - "THURSDAY_23" to 1.053701659160912, - "FRIDAY_0" to 1.149649788723893, - "FRIDAY_1" to 1.2046315447861193, - "FRIDAY_2" to 1.2724031281576726, - "FRIDAY_3" to 1.3525693456352732, - "FRIDAY_4" to 1.3746126314960814, - "FRIDAY_5" to 1.3744591862592468, - "FRIDAY_6" to 1.3297812543035683, - "FRIDAY_7" to 1.2762064429631657, - "FRIDAY_8" to 1.235662409263294, - "FRIDAY_9" to 1.2171558028785991, - "FRIDAY_10" to 1.182722399785398, - "FRIDAY_11" to 1.137345538963285, - "FRIDAY_12" to 0.9999308422620752, - "FRIDAY_13" to 0.8055000309055653, - "FRIDAY_14" to 0.5667135273493851, - "FRIDAY_15" to 0.4081529603000651, - "FRIDAY_16" to 0.3987031354907009, - "FRIDAY_17" to 0.5030075499003412, - "FRIDAY_18" to 0.6518159532641841, - "FRIDAY_19" to 0.8733483414970974, - "FRIDAY_20" to 1.0496224913080463, - "FRIDAY_21" to 1.1820684558591705, - "FRIDAY_22" to 1.2561688567574458, - "FRIDAY_23" to 1.3204704912328773, - "SATURDAY_0" to 1.3832230236620218, - "SATURDAY_1" to 1.4632908341022142, - "SATURDAY_2" to 1.5019230781315296, - "SATURDAY_3" to 1.5437332506007084, - "SATURDAY_4" to 1.5934153179751855, - "SATURDAY_5" to 1.6245578072557723, - "SATURDAY_6" to 1.6294919789890665, - "SATURDAY_7" to 1.6027665451672717, - "SATURDAY_8" to 1.6068061069158674, - "SATURDAY_9" to 1.624257927970777, - "SATURDAY_10" to 1.5996112411089, - "SATURDAY_11" to 1.5659672993092648, - "SATURDAY_12" to 1.5333537902522736, - "SATURDAY_13" to 1.445292929996356, - "SATURDAY_14" to 1.2966021477035259, - "SATURDAY_15" to 1.250999408961155, - "SATURDAY_16" to 1.2535364828163025, - "SATURDAY_17" to 1.2736456128871074, - "SATURDAY_18" to 1.3348268054897328, - "SATURDAY_19" to 1.4571388900094875, - "SATURDAY_20" to 1.5073787902995706, - "SATURDAY_21" to 1.5605139580010123, - "SATURDAY_22" to 1.5885303316932382, - "SATURDAY_23" to 1.6169891066719597 - ) + timeOfDayMultipliers = expectedTimeOfDayMultipliers ), feeHistoryFetcher = L1DynamicGasPriceCapServiceConfig.FeeHistoryFetcher( fetchInterval = Duration.parse("PT1S"), @@ -689,201 +380,141 @@ class CoordinatorConfigTest { private data class TestConfig(val extraField: String) @Test - fun parsesValidConfig() { - val smartContractErrorConfig = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/smart-contract-errors.toml")) - ) - val timeOfDayMultipliers = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/gas-price-cap-time-of-day-multipliers.toml")) - ) - val tracesLimitsConfigs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v1.toml")) - ) - val tracesLimitsV2Configs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v2.toml")) - ) - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/coordinator/coordinator-docker.config.toml")) - ) - .onFailure { error: String -> fail(error) } - .onSuccess { config: CoordinatorConfigTomlDto -> - val configs = config.copy( - conflation = config.conflation.copy( - _tracesLimitsV1 = tracesLimitsConfigs.get()?.tracesLimits?.let { TracesCountersV1(it) }, - _tracesLimitsV2 = tracesLimitsV2Configs.get()?.tracesLimits?.let { TracesCountersV2(it) }, - _smartContractErrors = smartContractErrorConfig.get()!!.smartContractErrors - ), - l1DynamicGasPriceCapService = config.l1DynamicGasPriceCapService.copy( - gasPriceCapCalculation = config.l1DynamicGasPriceCapService.gasPriceCapCalculation.copy( - timeOfDayMultipliers = timeOfDayMultipliers.get()?.gasPriceCapTimeOfDayMultipliers - ) - ) - ) - assertEquals(coordinatorConfig, configs.reified()) - assertEquals(coordinatorConfig.l1.rpcEndpoint, coordinatorConfig.l1.ethFeeHistoryEndpoint) - } + fun `should keep local stack testing configs uptodate with the code`() { + // Just assert that Files have been loaded and parsed correctly + // This is to prevent Code changes in coordinator and forgetting to update config files used in the local stack + loadConfigs( + coordinatorConfigFiles = listOf( + Path.of("../../config/coordinator/coordinator-docker.config.toml"), + Path.of("../../config/coordinator/coordinator-docker-traces-v2-override.config.toml"), + Path.of("../../config/coordinator/coordinator-docker-web3signer-override.config.toml"), + Path.of("../../config/coordinator/coordinator-local-dev.config.overrides.toml"), + Path.of("../../config/coordinator/coordinator-local-dev.config-traces-v2.overrides.toml") + ), + tracesLimitsFileV1 = Path.of("../../config/common/traces-limits-v1.toml"), + tracesLimitsFileV2 = Path.of("../../config/common/traces-limits-v2.toml"), + gasPriceCapTimeOfDayMultipliersFile = Path.of("../../config/common/gas-price-cap-time-of-day-multipliers.toml"), + smartContractErrorsFile = Path.of("../../config/common/smart-contract-errors.toml") + ) + } + + private fun pathToResource(resource: String): Path { + return Paths.get( + this::class.java.classLoader.getResource(resource)?.toURI() + ?: error("Resource not found: $resource") + ) } @Test - fun parsesValidWeb3SignerConfigOverride() { - val smartContractErrorCodes: SmartContractErrors = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/smart-contract-errors.toml")) - ).get()!!.smartContractErrors - val timeOfDayMultipliers = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/gas-price-cap-time-of-day-multipliers.toml")) - ) - val tracesLimitsConfigs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v1.toml")) - ) - val tracesLimitsV2Configs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v2.toml")) - ) + fun `should parse and consolidate configs`() { + val configs = loadConfigs( + coordinatorConfigFiles = listOf(pathToResource("configs/coordinator.config.toml")), + tracesLimitsFileV1 = pathToResource("configs/traces-limits-v1.toml"), + tracesLimitsFileV2 = pathToResource("configs/traces-limits-v2.toml"), + gasPriceCapTimeOfDayMultipliersFile = pathToResource("configs/gas-price-cap-time-of-day-multipliers.toml"), + smartContractErrorsFile = pathToResource("configs/smart-contract-errors.toml") + ) - CoordinatorAppCli.loadConfigsOrError( - listOf( - File("../../config/coordinator/coordinator-docker.config.toml"), - File("../../config/coordinator/coordinator-docker-web3signer-override.config.toml") - ) + assertEquals(coordinatorConfig, configs) + assertEquals(coordinatorConfig.l1.rpcEndpoint, coordinatorConfig.l1.ethFeeHistoryEndpoint) + } + + @Test + fun parsesValidWeb3SignerConfigOverride() { + val config = loadConfigs( + coordinatorConfigFiles = listOf( + pathToResource("configs/coordinator.config.toml"), + pathToResource("configs/coordinator-web3signer-override.config.toml") + ), + tracesLimitsFileV1 = pathToResource("configs/traces-limits-v1.toml"), + tracesLimitsFileV2 = pathToResource("configs/traces-limits-v2.toml"), + gasPriceCapTimeOfDayMultipliersFile = pathToResource("configs/gas-price-cap-time-of-day-multipliers.toml"), + smartContractErrorsFile = pathToResource("configs/smart-contract-errors.toml") ) - .onFailure { error: String -> fail(error) } - .onSuccess { - val configs = it.copy( - conflation = it.conflation.copy( - _tracesLimitsV1 = tracesLimitsConfigs.get()?.tracesLimits?.let { TracesCountersV1(it) }, - _tracesLimitsV2 = tracesLimitsV2Configs.get()?.tracesLimits?.let { TracesCountersV2(it) }, - _smartContractErrors = smartContractErrorCodes - ), - l1DynamicGasPriceCapService = it.l1DynamicGasPriceCapService.copy( - gasPriceCapCalculation = it.l1DynamicGasPriceCapService.gasPriceCapCalculation.copy( - timeOfDayMultipliers = timeOfDayMultipliers.get()?.gasPriceCapTimeOfDayMultipliers - ) - ) - ) - val expectedConfig = - coordinatorConfig.copy( - finalizationSigner = finalizationSigner.copy(type = SignerConfig.Type.Web3Signer), - dataSubmissionSigner = dataSubmissionSigner.copy(type = SignerConfig.Type.Web3Signer), - l2Signer = l2SignerConfig.copy(type = SignerConfig.Type.Web3Signer) - ) + val expectedConfig = + coordinatorConfig.copy( + finalizationSigner = finalizationSigner.copy(type = SignerConfig.Type.Web3Signer), + dataSubmissionSigner = dataSubmissionSigner.copy(type = SignerConfig.Type.Web3Signer), + l2Signer = l2SignerConfig.copy(type = SignerConfig.Type.Web3Signer) + ) - assertEquals(expectedConfig, configs.reified()) - } + assertThat(config).isEqualTo(expectedConfig) } @Test fun parsesValidTracesV2ConfigOverride() { - val smartContractErrorCodes: SmartContractErrors = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/smart-contract-errors.toml")) - ).get()!!.smartContractErrors - val timeOfDayMultipliers = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/gas-price-cap-time-of-day-multipliers.toml")) - ) - val tracesLimitsConfigs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v1.toml")) - ) - val tracesLimitsV2Configs = - CoordinatorAppCli.loadConfigsOrError( - listOf(File("../../config/common/traces-limits-v2.toml")) - ) - - CoordinatorAppCli.loadConfigsOrError( - listOf( - File("../../config/coordinator/coordinator-docker.config.toml"), - File("../../config/coordinator/coordinator-docker-traces-v2-override.config.toml") - ) + val config = loadConfigs( + coordinatorConfigFiles = listOf( + pathToResource("configs/coordinator.config.toml"), + pathToResource("configs/coordinator-traces-v2-override.config.toml") + ), + tracesLimitsFileV1 = pathToResource("configs/traces-limits-v1.toml"), + tracesLimitsFileV2 = pathToResource("configs/traces-limits-v2.toml"), + gasPriceCapTimeOfDayMultipliersFile = pathToResource("configs/gas-price-cap-time-of-day-multipliers.toml"), + smartContractErrorsFile = pathToResource("configs/smart-contract-errors.toml") ) - .onFailure { error: String -> fail(error) } - .onSuccess { - val configs = it.copy( - conflation = it.conflation.copy( - _tracesLimitsV1 = tracesLimitsConfigs.get()?.tracesLimits?.let { TracesCountersV1(it) }, - _tracesLimitsV2 = tracesLimitsV2Configs.get()?.tracesLimits?.let { TracesCountersV2(it) }, - _smartContractErrors = smartContractErrorCodes + + val expectedConfig = + coordinatorConfig.copy( + zkTraces = zkTracesConfig.copy(ethApi = URI("http://traces-node-v2:8545").toURL()), + l2NetworkGasPricingService = l2NetworkGasPricingServiceConfig.copy( + legacy = + l2NetworkGasPricingServiceConfig.legacy.copy( + transactionCostCalculatorConfig = + l2NetworkGasPricingServiceConfig.legacy.transactionCostCalculatorConfig?.copy( + compressedTxSize = 350, + expectedGas = 29400 + ) + ) + ), + traces = tracesConfig.copy( + switchToLineaBesu = true, + blobCompressorVersion = BlobCompressorVersion.V1_0_1, + expectedTracesApiVersionV2 = "v0.8.0-rc8", + conflationV2 = tracesConfig.conflation.copy( + endpoints = listOf(URI("http://traces-node-v2:8545/").toURL()), + requestLimitPerEndpoint = 1U ), - l1DynamicGasPriceCapService = it.l1DynamicGasPriceCapService.copy( - gasPriceCapCalculation = it.l1DynamicGasPriceCapService.gasPriceCapCalculation.copy( - timeOfDayMultipliers = timeOfDayMultipliers.get()?.gasPriceCapTimeOfDayMultipliers + countersV2 = TracesConfig.FunctionalityEndpoint( + listOf( + URI("http://traces-node-v2:8545/").toURL() + ), + requestLimitPerEndpoint = 1U, + requestRetry = RequestRetryConfigTomlFriendly( + backoffDelay = Duration.parse("PT1S"), + failuresWarningThreshold = 2 ) ) - ) - - val expectedConfig = - coordinatorConfig.copy( - zkTraces = zkTracesConfig.copy(ethApi = URI("http://traces-node-v2:8545").toURL()), - l2NetworkGasPricingService = l2NetworkGasPricingServiceConfig.copy( - legacy = - l2NetworkGasPricingServiceConfig.legacy.copy( - transactionCostCalculatorConfig = - l2NetworkGasPricingServiceConfig.legacy.transactionCostCalculatorConfig?.copy( - compressedTxSize = 350, - expectedGas = 29400 - ) - ) + ), + proversConfig = proversConfig.copy( + proverA = proversConfig.proverA.copy( + execution = proversConfig.proverA.execution.copy( + requestsDirectory = Path.of("/data/prover/v3/execution/requests"), + responsesDirectory = Path.of("/data/prover/v3/execution/responses") ), - traces = tracesConfig.copy( - switchToLineaBesu = true, - blobCompressorVersion = BlobCompressorVersion.V1_0_1, - expectedTracesApiVersionV2 = "v0.8.0-rc8", - conflationV2 = tracesConfig.conflation.copy( - endpoints = listOf(URI("http://traces-node-v2:8545/").toURL()), - requestLimitPerEndpoint = 1U - ), - countersV2 = TracesConfig.FunctionalityEndpoint( - listOf( - URI("http://traces-node-v2:8545/").toURL() - ), - requestLimitPerEndpoint = 1U, - requestRetry = RequestRetryConfigTomlFriendly( - backoffDelay = Duration.parse("PT1S"), - failuresWarningThreshold = 2 - ) - ) + blobCompression = proversConfig.proverA.blobCompression.copy( + requestsDirectory = Path.of("/data/prover/v3/compression/requests"), + responsesDirectory = Path.of("/data/prover/v3/compression/responses") ), - proversConfig = proversConfig.copy( - proverA = proversConfig.proverA.copy( - execution = proversConfig.proverA.execution.copy( - requestsDirectory = Path.of("/data/prover/v3/execution/requests"), - responsesDirectory = Path.of("/data/prover/v3/execution/responses") - ), - blobCompression = proversConfig.proverA.blobCompression.copy( - requestsDirectory = Path.of("/data/prover/v3/compression/requests"), - responsesDirectory = Path.of("/data/prover/v3/compression/responses") - ), - proofAggregation = proversConfig.proverA.proofAggregation.copy( - requestsDirectory = Path.of("/data/prover/v3/aggregation/requests"), - responsesDirectory = Path.of("/data/prover/v3/aggregation/responses") - ) - ) + proofAggregation = proversConfig.proverA.proofAggregation.copy( + requestsDirectory = Path.of("/data/prover/v3/aggregation/requests"), + responsesDirectory = Path.of("/data/prover/v3/aggregation/responses") ) ) + ) + ) - assertEquals(expectedConfig, configs.reified()) - } + assertThat(config).isEqualTo(expectedConfig) } @Test fun invalidConfigReturnsErrorResult() { - val configs = - CoordinatorAppCli.loadConfigsOrError( - listOf( - File("../../config/coordinator/coordinator-docker.config.toml"), - File("../../config/coordinator/coordinator-docker-web3signer-override.config.toml") - ) - ) + val configsResult = loadConfigsOrError( + configFiles = listOf(pathToResource("configs/coordinator.config.toml")) + ) - assertThat(configs.getError()).contains("'extraField': Missing from config") + assertThat(configsResult.getError()).contains("'extraField': Missing from config") } @Test @@ -930,8 +561,7 @@ class CoordinatorConfigTest { } @Test - fun testValidAggregationAndConflationByTargetBlockNumberWhenL2InclusiveBlockNumberToStopAndFlushAggregationSpecified - () { + fun testValidAggrAndConflationByTargetBlockNumberWhenL2InclusiveBlockNumberToStopAndFlushAggregationSpecified() { val aggregationConfigWithoutSwithBlockNumber = aggregationConfig.copy( _targetEndBlocks = listOf(10L, 100L) ) diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedGasPriceMultipliers.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedGasPriceMultipliers.kt new file mode 100644 index 000000000..d872e96a1 --- /dev/null +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedGasPriceMultipliers.kt @@ -0,0 +1,172 @@ +package net.consensys.zkevm.coordinator.app.config + +val expectedTimeOfDayMultipliers = mapOf( + "SUNDAY_0" to 1.7489178377946066, + "SUNDAY_1" to 1.7494632175198737, + "SUNDAY_2" to 1.75, + "SUNDAY_3" to 1.733166295438555, + "SUNDAY_4" to 1.6993775444542885, + "SUNDAY_5" to 1.6350086618091364, + "SUNDAY_6" to 1.5627740860151331, + "SUNDAY_7" to 1.4831149222064164, + "SUNDAY_8" to 1.4101476768256929, + "SUNDAY_9" to 1.370085278922007, + "SUNDAY_10" to 1.3516015544068651, + "SUNDAY_11" to 1.3482404546676368, + "SUNDAY_12" to 1.3580905751578942, + "SUNDAY_13" to 1.3775497419563296, + "SUNDAY_14" to 1.3700255667542938, + "SUNDAY_15" to 1.2642948506461285, + "SUNDAY_16" to 1.2794806131912935, + "SUNDAY_17" to 1.2750892256476676, + "SUNDAY_18" to 1.2919720208955585, + "SUNDAY_19" to 1.317984990098603, + "SUNDAY_20" to 1.4433501639513178, + "SUNDAY_21" to 1.4705921238901998, + "SUNDAY_22" to 1.515043370430801, + "SUNDAY_23" to 1.5556742617266397, + "MONDAY_0" to 1.5381562278760164, + "MONDAY_1" to 1.5423761828433993, + "MONDAY_2" to 1.539015963719092, + "MONDAY_3" to 1.487676153648977, + "MONDAY_4" to 1.430973985132037, + "MONDAY_5" to 1.4656765439056292, + "MONDAY_6" to 1.4484298622828233, + "MONDAY_7" to 1.4459076216659752, + "MONDAY_8" to 1.4899061835032241, + "MONDAY_9" to 1.5249733712852067, + "MONDAY_10" to 1.511367489481033, + "MONDAY_11" to 1.4225695658047797, + "MONDAY_12" to 1.2887291896624584, + "MONDAY_13" to 1.1460926897291355, + "MONDAY_14" to 1.0004897955233254, + "MONDAY_15" to 0.8694664537368378, + "MONDAY_16" to 0.8270273375962802, + "MONDAY_17" to 0.7868289022833883, + "MONDAY_18" to 0.7780303121746551, + "MONDAY_19" to 0.7756215256634205, + "MONDAY_20" to 0.7984895728860915, + "MONDAY_21" to 0.8918589268832423, + "MONDAY_22" to 0.9967716668541272, + "MONDAY_23" to 1.0973334887144106, + "TUESDAY_0" to 1.2233064209957951, + "TUESDAY_1" to 1.3238883432855082, + "TUESDAY_2" to 1.3874518307497257, + "TUESDAY_3" to 1.463621147171298, + "TUESDAY_4" to 1.4975989065490154, + "TUESDAY_5" to 1.481679186141442, + "TUESDAY_6" to 1.452778387763161, + "TUESDAY_7" to 1.3414858185569951, + "TUESDAY_8" to 1.2869454637983988, + "TUESDAY_9" to 1.249347290389873, + "TUESDAY_10" to 1.196488297386161, + "TUESDAY_11" to 1.1136140507034202, + "TUESDAY_12" to 0.9867528660797885, + "TUESDAY_13" to 0.8018989158195754, + "TUESDAY_14" to 0.6173048748109258, + "TUESDAY_15" to 0.46718586671750373, + "TUESDAY_16" to 0.4103633833041902, + "TUESDAY_17" to 0.4871260756989506, + "TUESDAY_18" to 0.5667378483016126, + "TUESDAY_19" to 0.6464203510900723, + "TUESDAY_20" to 0.7780268325299871, + "TUESDAY_21" to 0.8995921101255763, + "TUESDAY_22" to 1.0077600114996088, + "TUESDAY_23" to 1.1109769960680498, + "WEDNESDAY_0" to 1.2097668746150059, + "WEDNESDAY_1" to 1.2631002319009361, + "WEDNESDAY_2" to 1.2912775191940549, + "WEDNESDAY_3" to 1.3229785939630059, + "WEDNESDAY_4" to 1.3428607301494424, + "WEDNESDAY_5" to 1.3750788517823973, + "WEDNESDAY_6" to 1.3752344527256497, + "WEDNESDAY_7" to 1.3505490078766218, + "WEDNESDAY_8" to 1.2598503219367945, + "WEDNESDAY_9" to 1.2051668977452374, + "WEDNESDAY_10" to 1.0320896222195326, + "WEDNESDAY_11" to 0.8900138031631949, + "WEDNESDAY_12" to 0.6341155208698448, + "WEDNESDAY_13" to 0.48337590254714624, + "WEDNESDAY_14" to 0.2903189399226416, + "WEDNESDAY_15" to 0.25, + "WEDNESDAY_16" to 0.25711039485046006, + "WEDNESDAY_17" to 0.37307641907591793, + "WEDNESDAY_18" to 0.45280799454961196, + "WEDNESDAY_19" to 0.5631397823847637, + "WEDNESDAY_20" to 0.6285005244224133, + "WEDNESDAY_21" to 0.6671897537279405, + "WEDNESDAY_22" to 0.7268406397452634, + "WEDNESDAY_23" to 0.8068904097486369, + "THURSDAY_0" to 0.9021601102971811, + "THURSDAY_1" to 1.023741688964238, + "THURSDAY_2" to 1.1340689935096755, + "THURSDAY_3" to 1.2530130345819006, + "THURSDAY_4" to 1.3163421664973542, + "THURSDAY_5" to 1.3536343767230727, + "THURSDAY_6" to 1.3432290485306728, + "THURSDAY_7" to 1.2864983218982178, + "THURSDAY_8" to 1.2320488534113174, + "THURSDAY_9" to 1.1984530721079034, + "THURSDAY_10" to 1.0877338251341975, + "THURSDAY_11" to 0.9999324929016475, + "THURSDAY_12" to 0.87536726762619, + "THURSDAY_13" to 0.6560822412167919, + "THURSDAY_14" to 0.44836474861432074, + "THURSDAY_15" to 0.36145134935025247, + "THURSDAY_16" to 0.2695997829759713, + "THURSDAY_17" to 0.2898426312618241, + "THURSDAY_18" to 0.3970093434340387, + "THURSDAY_19" to 0.5193273246848977, + "THURSDAY_20" to 0.6426415257034419, + "THURSDAY_21" to 0.800685718218497, + "THURSDAY_22" to 0.9215516833839711, + "THURSDAY_23" to 1.053701659160912, + "FRIDAY_0" to 1.149649788723893, + "FRIDAY_1" to 1.2046315447861193, + "FRIDAY_2" to 1.2724031281576726, + "FRIDAY_3" to 1.3525693456352732, + "FRIDAY_4" to 1.3746126314960814, + "FRIDAY_5" to 1.3744591862592468, + "FRIDAY_6" to 1.3297812543035683, + "FRIDAY_7" to 1.2762064429631657, + "FRIDAY_8" to 1.235662409263294, + "FRIDAY_9" to 1.2171558028785991, + "FRIDAY_10" to 1.182722399785398, + "FRIDAY_11" to 1.137345538963285, + "FRIDAY_12" to 0.9999308422620752, + "FRIDAY_13" to 0.8055000309055653, + "FRIDAY_14" to 0.5667135273493851, + "FRIDAY_15" to 0.4081529603000651, + "FRIDAY_16" to 0.3987031354907009, + "FRIDAY_17" to 0.5030075499003412, + "FRIDAY_18" to 0.6518159532641841, + "FRIDAY_19" to 0.8733483414970974, + "FRIDAY_20" to 1.0496224913080463, + "FRIDAY_21" to 1.1820684558591705, + "FRIDAY_22" to 1.2561688567574458, + "FRIDAY_23" to 1.3204704912328773, + "SATURDAY_0" to 1.3832230236620218, + "SATURDAY_1" to 1.4632908341022142, + "SATURDAY_2" to 1.5019230781315296, + "SATURDAY_3" to 1.5437332506007084, + "SATURDAY_4" to 1.5934153179751855, + "SATURDAY_5" to 1.6245578072557723, + "SATURDAY_6" to 1.6294919789890665, + "SATURDAY_7" to 1.6027665451672717, + "SATURDAY_8" to 1.6068061069158674, + "SATURDAY_9" to 1.624257927970777, + "SATURDAY_10" to 1.5996112411089, + "SATURDAY_11" to 1.5659672993092648, + "SATURDAY_12" to 1.5333537902522736, + "SATURDAY_13" to 1.445292929996356, + "SATURDAY_14" to 1.2966021477035259, + "SATURDAY_15" to 1.250999408961155, + "SATURDAY_16" to 1.2535364828163025, + "SATURDAY_17" to 1.2736456128871074, + "SATURDAY_18" to 1.3348268054897328, + "SATURDAY_19" to 1.4571388900094875, + "SATURDAY_20" to 1.5073787902995706, + "SATURDAY_21" to 1.5605139580010123, + "SATURDAY_22" to 1.5885303316932382, + "SATURDAY_23" to 1.6169891066719597 +) diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV1.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV1.kt new file mode 100644 index 000000000..f9ac7b943 --- /dev/null +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV1.kt @@ -0,0 +1,48 @@ +package net.consensys.zkevm.coordinator.app.config + +import net.consensys.linea.traces.TracesCountersV1 +import net.consensys.linea.traces.TracingModuleV1 + +val expectedTracesCountersV1 = TracesCountersV1( + mapOf( + // EVM Arithmetization Limits + TracingModuleV1.ADD to 1U, + TracingModuleV1.BIN to 2U, + TracingModuleV1.BIN_RT to 3U, + TracingModuleV1.EC_DATA to 4U, + TracingModuleV1.EXT to 5U, + TracingModuleV1.HUB to 6U, + TracingModuleV1.INSTRUCTION_DECODER to 7U, + TracingModuleV1.MMIO to 8U, + TracingModuleV1.MMU to 9U, + TracingModuleV1.MMU_ID to 10U, + TracingModuleV1.MOD to 11U, + TracingModuleV1.MUL to 12U, + TracingModuleV1.MXP to 13U, + TracingModuleV1.PHONEY_RLP to 14U, + TracingModuleV1.PUB_HASH to 15U, + TracingModuleV1.PUB_HASH_INFO to 16U, + TracingModuleV1.PUB_LOG to 17U, + TracingModuleV1.PUB_LOG_INFO to 18U, + TracingModuleV1.RLP to 19U, + TracingModuleV1.ROM to 20U, + TracingModuleV1.SHF to 21U, + TracingModuleV1.SHF_RT to 22U, + TracingModuleV1.TX_RLP to 23U, + TracingModuleV1.WCP to 24U, + // Block Limits + TracingModuleV1.BLOCK_TX to 25U, + TracingModuleV1.BLOCK_L2L1LOGS to 26U, + TracingModuleV1.BLOCK_KECCAK to 27U, + // Precompile Limits + TracingModuleV1.PRECOMPILE_ECRECOVER to 28U, + TracingModuleV1.PRECOMPILE_SHA2 to 29U, + TracingModuleV1.PRECOMPILE_RIPEMD to 30U, + TracingModuleV1.PRECOMPILE_IDENTITY to 31U, + TracingModuleV1.PRECOMPILE_MODEXP to 32U, + TracingModuleV1.PRECOMPILE_ECADD to 32U, + TracingModuleV1.PRECOMPILE_ECMUL to 34U, + TracingModuleV1.PRECOMPILE_ECPAIRING to 35U, + TracingModuleV1.PRECOMPILE_BLAKE2F to 36U + ) +) diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV2.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV2.kt new file mode 100644 index 000000000..82f6447f9 --- /dev/null +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/ExpectedTracesLimitsV2.kt @@ -0,0 +1,60 @@ +package net.consensys.zkevm.coordinator.app.config + +import net.consensys.linea.traces.TracesCountersV2 +import net.consensys.linea.traces.TracingModuleV2 + +val expectedTracesLimitsV2 = TracesCountersV2( + mapOf( + TracingModuleV2.ADD to 1u, + TracingModuleV2.BIN to 2u, + TracingModuleV2.BLAKE_MODEXP_DATA to 3u, + TracingModuleV2.BLOCK_DATA to 4u, + TracingModuleV2.BLOCK_HASH to 5u, + TracingModuleV2.EC_DATA to 6u, + TracingModuleV2.EUC to 7u, + TracingModuleV2.EXP to 8u, + TracingModuleV2.EXT to 9u, + TracingModuleV2.GAS to 10u, + TracingModuleV2.HUB to 11u, + TracingModuleV2.LOG_DATA to 12u, + TracingModuleV2.LOG_INFO to 13u, + TracingModuleV2.MMIO to 14u, + TracingModuleV2.MMU to 15u, + TracingModuleV2.MOD to 16u, + TracingModuleV2.MUL to 18u, + TracingModuleV2.MXP to 19u, + TracingModuleV2.OOB to 20u, + TracingModuleV2.RLP_ADDR to 21u, + TracingModuleV2.RLP_TXN to 22u, + TracingModuleV2.RLP_TXN_RCPT to 23u, + TracingModuleV2.ROM to 24u, + TracingModuleV2.ROM_LEX to 25u, + TracingModuleV2.SHAKIRA_DATA to 26u, + TracingModuleV2.SHF to 27u, + TracingModuleV2.STP to 28u, + TracingModuleV2.TRM to 29u, + TracingModuleV2.TXN_DATA to 30u, + TracingModuleV2.WCP to 31u, + // Reference table limits, set to UInt.MAX_VALUE + TracingModuleV2.BIN_REFERENCE_TABLE to 32u, + TracingModuleV2.INSTRUCTION_DECODER to 33u, + TracingModuleV2.SHF_REFERENCE_TABLE to 34u, + // Precompiles limits + TracingModuleV2.PRECOMPILE_BLAKE_EFFECTIVE_CALLS to 35u, + TracingModuleV2.PRECOMPILE_BLAKE_ROUNDS to 36u, + TracingModuleV2.PRECOMPILE_ECADD_EFFECTIVE_CALLS to 37u, + TracingModuleV2.PRECOMPILE_ECMUL_EFFECTIVE_CALLS to 38u, + TracingModuleV2.PRECOMPILE_ECPAIRING_FINAL_EXPONENTIATIONS to 39u, + TracingModuleV2.PRECOMPILE_ECPAIRING_G2_MEMBERSHIP_CALLS to 40u, + TracingModuleV2.PRECOMPILE_ECPAIRING_MILLER_LOOPS to 41u, + TracingModuleV2.PRECOMPILE_ECRECOVER_EFFECTIVE_CALLS to 42u, + TracingModuleV2.PRECOMPILE_MODEXP_EFFECTIVE_CALLS to 43u, + TracingModuleV2.PRECOMPILE_RIPEMD_BLOCKS to 44u, + TracingModuleV2.PRECOMPILE_SHA2_BLOCKS to 45u, + // Block limits + TracingModuleV2.BLOCK_KECCAK to 46u, + TracingModuleV2.BLOCK_L1_SIZE to 47u, + TracingModuleV2.BLOCK_L2_L1_LOGS to 48u, + TracingModuleV2.BLOCK_TRANSACTIONS to 49u + ) +) diff --git a/coordinator/app/src/test/resources/configs/coordinator-traces-v2-override.config.toml b/coordinator/app/src/test/resources/configs/coordinator-traces-v2-override.config.toml new file mode 100644 index 000000000..c9e01f473 --- /dev/null +++ b/coordinator/app/src/test/resources/configs/coordinator-traces-v2-override.config.toml @@ -0,0 +1,40 @@ +[prover] +[prover.execution] +fs-requests-directory = "/data/prover/v3/execution/requests" +fs-responses-directory = "/data/prover/v3/execution/responses" +[prover.blob-compression] +fs-requests-directory = "/data/prover/v3/compression/requests" +fs-responses-directory = "/data/prover/v3/compression/responses" +[prover.proof-aggregation] +fs-requests-directory = "/data/prover/v3/aggregation/requests" +fs-responses-directory = "/data/prover/v3/aggregation/responses" + +[zk-traces] +eth-api="http://traces-node-v2:8545" + +[traces] +switch-to-linea-besu=true +blob-compressor-version="V1_0_1" +expected-traces-api-version-v2="v0.8.0-rc8" +[traces.counters-v2] +endpoints=["http://traces-node-v2:8545/"] +request-limit-per-endpoint=1 +request-retry.backoff-delay="PT1S" +request-retry.failures-warning-threshold=2 +[traces.conflation-v2] +endpoints=["http://traces-node-v2:8545/"] +request-limit-per-endpoint=1 +request-retry.backoff-delay="PT1S" +request-retry.failures-warning-threshold=2 + +[l2-network-gas-pricing.json-rpc-pricing-propagation] +geth-gas-price-update-recipients=[ + "http://l2-node:8545/" +] + +[l2-network-gas-pricing.legacy.sample-transaction-gas-pricing] +plain-transfer-cost-multiplier=1.0 +# Ratio of 350 / 29400 is based on data from Mainnet. Only 0.3% of transactions are less profitable than this +# Meaning 99.7% of transactions will be includable if priced using eth_gasPrice +compressed-tx-size=350 +expected-gas=29400 diff --git a/coordinator/app/src/test/resources/configs/coordinator-web3signer-override.config.toml b/coordinator/app/src/test/resources/configs/coordinator-web3signer-override.config.toml new file mode 100644 index 000000000..b5fd4ef35 --- /dev/null +++ b/coordinator/app/src/test/resources/configs/coordinator-web3signer-override.config.toml @@ -0,0 +1,13 @@ +[finalization-signer] +# Web3j/Web3signer +type="Web3Signer" + +[data-submission-signer] +# Web3j/Web3signer +type="Web3Signer" + +[l2-signer] +# Web3j/Web3signer +type="Web3Signer" + + diff --git a/coordinator/app/src/test/resources/configs/coordinator.config.toml b/coordinator/app/src/test/resources/configs/coordinator.config.toml new file mode 100644 index 000000000..62ce6851f --- /dev/null +++ b/coordinator/app/src/test/resources/configs/coordinator.config.toml @@ -0,0 +1,292 @@ +testL1Disabled=false + +duplicated-logs-debounce-time="PT15S" + +eip4844-switch-l2-block-number=0 + +[prover] +fs-inprogress-request-writing-suffix = ".inprogress_coordinator_writing" +fs-inprogress-proving-suffix-pattern = ".*\\.inprogress\\.prover.*" +fs-polling-interval = "PT1S" +fs-polling-timeout = "PT10M" +[prover.execution] +fs-requests-directory = "/data/prover/v2/execution/requests" +fs-responses-directory = "/data/prover/v2/execution/responses" +[prover.blob-compression] +fs-requests-directory = "/data/prover/v2/compression/requests" +fs-responses-directory = "/data/prover/v2/compression/responses" +[prover.proof-aggregation] +fs-requests-directory = "/data/prover/v2/aggregation/requests" +fs-responses-directory = "/data/prover/v2/aggregation/responses" +#[prover.new] +#switch-block-number-inclusive=1000 +#[prover.new.execution] +#fs-requests-directory = "/data/prover/v3/execution/requests" +#fs-responses-directory = "/data/prover/v3/execution/responses" +#[prover.new.blob-compression] +#fs-requests-directory = "/data/prover/v3/compression/requests" +#fs-responses-directory = "/data/prover/v3/compression/responses" +#[prover.new.proof-aggregation] +#fs-requests-directory = "/data/prover/v3/aggregation/requests" +#fs-responses-directory = "/data/prover/v3/aggregation/responses" + +[blob-compression] +blob-size-limit=102400 # 100KB +handler-polling-interval="PT1S" +# default batches limit is aggregation-proofs-limit -1 +# batches-limit must be less than or equal to aggregation-proofs-limit-1 +batches-limit=1 + +[zk-traces] +eth-api="http://traces-node:8545" +new-block-polling-interval="PT1S" + +[traces] +switch-to-linea-besu=false +blob-compressor-version="V0_1_0" +raw-execution-traces-version="0.2.0" +expected-traces-api-version="0.2.0" +[traces.counters] +endpoints=["http://traces-api:8080/"] +request-limit-per-endpoint=2 +request-retry.backoff-delay="PT1S" +request-retry.failures-warning-threshold=2 +[traces.conflation] +endpoints=["http://traces-api:8080/"] +request-limit-per-endpoint=2 +request-retry.backoff-delay="PT1S" +request-retry.failures-warning-threshold=2 + + +[traces.file-manager] +traces-file-extension="json.gz" +raw-traces-directory="/data/traces/raw" +non-canonical-raw-traces-directory="/data/traces/raw-non-canonical" +create-non-canonical-directory=true +polling-interval="PT1S" +traces-file-creation-wait-timeout="PT2M" + +[state-manager] +version="2.3.0" +endpoints=["http://shomei:8888/"] +request-limit-per-endpoint=2 +request-retry.backoff-delay="PT2S" +request-retry.failures-warning-threshold=2 + +[type2-state-proof-provider] +endpoints=["http://shomei-frontend:8888/"] +request-retry.backoff-delay="PT1S" +request-retry.failures-warning-threshold=2 + +[api] +observability_port=9545 + +[l1] +rpc-endpoint="http://l1-el-node:8545" +zk-evm-contract-address="0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9" +finalization-polling-interval="PT6S" +l1-query-block-tag="latest" +gas-limit=10000000 +fee-history-block-count=10 +fee-history-reward-percentile=15 +# Global caps of maxFeePerGas, maxFeePerBlobGas, and maxPriorityFeePerGas +# for L1 transactions regardless of L1 dynamic gas price cap is enabled or not +max-fee-per-gas-cap=100000000000 +max-fee-per-blob-gas-cap=100000000000 +max-priority-fee-per-gas-cap=20000000000 +# The multiplier of global caps for L1 finalization transaction +# E.g. if set as 2.0, it means the global caps of finalization txn +# will always be 2 times higher than that of blob submission txn +gas-price-cap-multiplier-for-finalization=2.0 +# blocks are 2s, this may catch in between blocks +send-message-event-polling-interval="PT1S" +# 10 blocks worth at 2s per block +max-event-scraping-time="PT5S" +# An optional config to define the L1 block time with default as PT12S +block-time="PT1S" # set the same as local L1 block time +block-range-loop-limit=500 +max-messages-to-collect=1000 +finalized-block-tag="latest" +# reset this once we know what to do on dev/UAT +earliest-block=0 +genesis-state-root-hash="0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd" +# shnarf for contract V5 +# Keccak256(parentShnarf="0x00...00", snarkHash="0x00...00", +# parentStateRootHash="0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd", +# evaludationClaim="0x00...00", evaludationPoint="0x00...00") +genesis-shnarf-v5="0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f" + +[l2] +rpc-endpoint="http://sequencer:8545" +message-service-address="0xe537D669CA013d86EBeF1D64e40fC74CADC91987" +gas-limit=10000000 +max-fee-per-gas-cap=100000000000 +fee-history-block-count=4 +fee-history-reward-percentile=15 +last-hash-search-window=25 +anchoring-receipt-polling-interval="PT01S" +max-receipt-retries=120 +# Number of children blocks to wait before considering a won't be reverted and elegible for conflation. +# this a workaround to mitigate Geth fork issues with Clique PoA +# Coordinator will consider block as finalized after being included in the chain wtih children blocks-to-finalization +# Recommended: Geth sequencer minimum of 2, Besu sequencer minimum of 1, 0 is safe localy +blocks-to-finalization=0 + +[blob-submission] +disabled=true +db-polling-interval="PT1S" +max-blobs-to-return=100 +proof-submission-delay="PT1S" +max-blobs-to-submit-per-tick=10 +# These lower and upper bounds will be effective only if L1 dynamic +# gas price cap is disabled or during fallback when there's insufficient +# cached fee history data to compute dynamic gas price caps +priority-fee-per-gas-upper-bound=2000000000 # 2 GWEI +priority-fee-per-gas-lower-bound=200000000 # 0.2 GWEI + +[aggregation-finalization] +disabled=false +db-polling-interval="PT1S" +max-aggregations-to-finalize-per-tick=1 +proof-submission-delay="PT1S" + +[proof-aggregation] +aggregation-proofs-limit=3 +aggregation-deadline="PT10S" +aggregation-coordinator-polling-interval="PT2S" +deadline-check-interval="PT8S" +target-end-blocks=[] + +[finalization-signer] +# Web3j/Web3signer +type="Web3j" + +[finalization-signer.web3j] +private-key="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + +[finalization-signer.web3signer] +endpoint="http://web3signer:9000" +max-pool-size=10 +keep-alive=true +public-key="ba5734d8f7091719471e7f7ed6b9df170dc70cc661ca05e688601ad984f068b0d67351e5f06073092499336ab0839ef8a521afd334e53807205fa2f08eec74f4" + +[data-submission-signer] +# Web3j/Web3signer +type="Web3j" + +# The account with this private key is in genesis file +[data-submission-signer.web3j] +private-key="0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" + +[data-submission-signer.web3signer] +endpoint="http://web3signer:9000" +max-pool-size=10 +keep-alive=true +public-key="9d9031e97dd78ff8c15aa86939de9b1e791066a0224e331bc962a2099a7b1f0464b8bbafe1535f2301c72c2cb3535b172da30b02686ab0393d348614f157fbdb" + +[l2-signer] +# Web3j/Web3signer +type="Web3j" + +[l2-signer.web3j] +private-key="0x4d01ae6487860981699236a58b68f807ee5f17b12df5740b85cf4c4653be0f55" + +[l2-signer.web3signer] +endpoint="http://web3signer:9000" +max-pool-size=10 +keep-alive=true +public-key="4a788ad6fa008beed58de6418369717d7492f37d173d70e2c26d9737e2c6eeae929452ef8602a19410844db3e200a0e73f5208fd76259a8766b73953fc3e7023" + +[message-anchoring-service] +disabled=false +polling-interval="PT1S" +max-messages-to-anchor=100 + +[l2-network-gas-pricing] +disabled = false +price-update-interval = "PT12S" + +fee-history-block-count = 50 +fee-history-reward-percentile = 15 + +blob-submission-expected-execution-gas = 213000.0 # Lower to 120k as we improve efficiency +# Defaults to expected-blob-gas +#bytes-per-data-submission=131072.0 # 2^17 +l1-blob-gas = 131072 # 2^17 + +[l2-network-gas-pricing.request-retry] +max-retries = 3 +timeout = "PT6S" +backoff-delay = "PT1S" +failures-warning-threshold = 2 + +[l2-network-gas-pricing.variable-cost-pricing] +gas-price-fixed-cost = 3000000 +legacy-fees-multiplier = 1.2 +margin = 4.0 +variable-cost-upper-bound = 10000000001 # ~10 GWEI +variable-cost-lower-bound = 90000001 # ~0.09 GWEI + +[l2-network-gas-pricing.extra-data-pricing-propagation] +extra-data-update-recipient = "http://sequencer:8545/" + +[l2-network-gas-pricing.legacy] +type="SampleTransaction" +gas-price-upper-bound = 10000000000 # 10 GWEI +gas-price-lower-bound = 90000000 # 0.09 GWEI + +[l2-network-gas-pricing.json-rpc-pricing-propagation] +geth-gas-price-update-recipients = [ + "http://l2-node:8545/" +] +besu-gas-price-update-recipients = [] + +[l1-dynamic-gas-price-cap-service] +disabled=false +[l1-dynamic-gas-price-cap-service.gas-price-cap-calculation] +adjustment-constant=25 +blob-adjustment-constant=25 +finalization-target-max-delay="PT30S" +gas-fee-percentile-window="PT1M" +gas-fee-percentile-window-leeway="PT10S" +gas-fee-percentile=10 +gas-price-caps-check-coefficient=0.9 +# The lower bound of the "historic base fee per blob gas" used in +# the L1 dynamic gas price cap equation +historic-base-fee-per-blob-gas-lower-bound=100000000 # 0.1 GWEI +# An optional config to replace the "historic average reward" used in +# the L1 dynamic gas price cap equation +historic-avg-reward-constant=100000000 # 0.1 GWEI +[l1-dynamic-gas-price-cap-service.fee-history-fetcher] +fetch-interval="PT1S" +max-block-count=1000 +reward-percentiles=[10,20,30,40,50,60,70,80,90,100] +num-of-blocks-before-latest=4 +[l1-dynamic-gas-price-cap-service.fee-history-storage] +storage-period="PT2M" + +[conflation] +blocks-limit=2 +conflation-deadline="PT6S" # =3*l2_block_time +conflation-deadline-check-interval="PT3S" +conflation-deadline-last-block-confirmation-delay="PT2S" # recommended: at least 2 * blockInterval + +# This is to prevent inflight trasactions that may change Smart contract state while coordinator is restarted. +# Queries SMC for last finalised block, and keeps polling until this number of blocks observe the same state. +# If state is updated meanwhile, it resets counter and restarts the polling. +consistent-number-of-blocks-on-l1-to-wait=1 +fetch-blocks-limit=4000 + +[database] +host="postgres" +port="5432" +username="postgres" +password="postgres" +schema="linea_coordinator" +read_pool_size=10 +read_pipelining_limit=10 +transactional_pool_size=10 + +[persistence-retry] +#max-retries = 10 commented as can be null +backoff-delay = "PT1S" diff --git a/coordinator/app/src/test/resources/configs/gas-price-cap-time-of-day-multipliers.toml b/coordinator/app/src/test/resources/configs/gas-price-cap-time-of-day-multipliers.toml new file mode 100644 index 000000000..36155bd6b --- /dev/null +++ b/coordinator/app/src/test/resources/configs/gas-price-cap-time-of-day-multipliers.toml @@ -0,0 +1,184 @@ +## +# Time of day multipliers for dynamic gas price cap calculation: +# +# TDM stands for "Time of Day Mutliplier" and has a range of values between 0.25 - 1.75. +# +# When we expect the L1 gas price to be low, for example on a Saturday night, the TDM will be at it's highest because +# we want to increase the rate at which we increase the threshold to try and settle within this time window. +# The value will be at it's lowest during peak L1 gas price times, for example, on a Tuesday afternoon, because we +# know it is likely to be expensive during this window. +# +# The values for the TDM based on the 90D of L1 gas price real world data. It is expected that every few months +# we will update this table with the latest data to account for any notable changes in the trends of L1 gas prices. +# It does not account for public holidays yet. +## + +[gas-price-cap-time-of-day-multipliers] +SUNDAY_0 = 1.7489178377946066 +SUNDAY_1 = 1.7494632175198737 +SUNDAY_2 = 1.75 +SUNDAY_3 = 1.733166295438555 +SUNDAY_4 = 1.6993775444542885 +SUNDAY_5 = 1.6350086618091364 +SUNDAY_6 = 1.5627740860151331 +SUNDAY_7 = 1.4831149222064164 +SUNDAY_8 = 1.4101476768256929 +SUNDAY_9 = 1.370085278922007 +SUNDAY_10 = 1.3516015544068651 +SUNDAY_11 = 1.3482404546676368 +SUNDAY_12 = 1.3580905751578942 +SUNDAY_13 = 1.3775497419563296 +SUNDAY_14 = 1.3700255667542938 +SUNDAY_15 = 1.2642948506461285 +SUNDAY_16 = 1.2794806131912935 +SUNDAY_17 = 1.2750892256476676 +SUNDAY_18 = 1.2919720208955585 +SUNDAY_19 = 1.317984990098603 +SUNDAY_20 = 1.4433501639513178 +SUNDAY_21 = 1.4705921238901998 +SUNDAY_22 = 1.515043370430801 +SUNDAY_23 = 1.5556742617266397 +MONDAY_0 = 1.5381562278760164 +MONDAY_1 = 1.5423761828433993 +MONDAY_2 = 1.539015963719092 +MONDAY_3 = 1.487676153648977 +MONDAY_4 = 1.430973985132037 +MONDAY_5 = 1.4656765439056292 +MONDAY_6 = 1.4484298622828233 +MONDAY_7 = 1.4459076216659752 +MONDAY_8 = 1.4899061835032241 +MONDAY_9 = 1.5249733712852067 +MONDAY_10 = 1.511367489481033 +MONDAY_11 = 1.4225695658047797 +MONDAY_12 = 1.2887291896624584 +MONDAY_13 = 1.1460926897291355 +MONDAY_14 = 1.0004897955233254 +MONDAY_15 = 0.8694664537368378 +MONDAY_16 = 0.8270273375962802 +MONDAY_17 = 0.7868289022833883 +MONDAY_18 = 0.7780303121746551 +MONDAY_19 = 0.7756215256634205 +MONDAY_20 = 0.7984895728860915 +MONDAY_21 = 0.8918589268832423 +MONDAY_22 = 0.9967716668541272 +MONDAY_23 = 1.0973334887144106 +TUESDAY_0 = 1.2233064209957951 +TUESDAY_1 = 1.3238883432855082 +TUESDAY_2 = 1.3874518307497257 +TUESDAY_3 = 1.463621147171298 +TUESDAY_4 = 1.4975989065490154 +TUESDAY_5 = 1.481679186141442 +TUESDAY_6 = 1.452778387763161 +TUESDAY_7 = 1.3414858185569951 +TUESDAY_8 = 1.2869454637983988 +TUESDAY_9 = 1.249347290389873 +TUESDAY_10 = 1.196488297386161 +TUESDAY_11 = 1.1136140507034202 +TUESDAY_12 = 0.9867528660797885 +TUESDAY_13 = 0.8018989158195754 +TUESDAY_14 = 0.6173048748109258 +TUESDAY_15 = 0.46718586671750373 +TUESDAY_16 = 0.4103633833041902 +TUESDAY_17 = 0.4871260756989506 +TUESDAY_18 = 0.5667378483016126 +TUESDAY_19 = 0.6464203510900723 +TUESDAY_20 = 0.7780268325299871 +TUESDAY_21 = 0.8995921101255763 +TUESDAY_22 = 1.0077600114996088 +TUESDAY_23 = 1.1109769960680498 +WEDNESDAY_0 = 1.2097668746150059 +WEDNESDAY_1 = 1.2631002319009361 +WEDNESDAY_2 = 1.2912775191940549 +WEDNESDAY_3 = 1.3229785939630059 +WEDNESDAY_4 = 1.3428607301494424 +WEDNESDAY_5 = 1.3750788517823973 +WEDNESDAY_6 = 1.3752344527256497 +WEDNESDAY_7 = 1.3505490078766218 +WEDNESDAY_8 = 1.2598503219367945 +WEDNESDAY_9 = 1.2051668977452374 +WEDNESDAY_10 = 1.0320896222195326 +WEDNESDAY_11 = 0.8900138031631949 +WEDNESDAY_12 = 0.6341155208698448 +WEDNESDAY_13 = 0.48337590254714624 +WEDNESDAY_14 = 0.2903189399226416 +WEDNESDAY_15 = 0.25 +WEDNESDAY_16 = 0.25711039485046006 +WEDNESDAY_17 = 0.37307641907591793 +WEDNESDAY_18 = 0.45280799454961196 +WEDNESDAY_19 = 0.5631397823847637 +WEDNESDAY_20 = 0.6285005244224133 +WEDNESDAY_21 = 0.6671897537279405 +WEDNESDAY_22 = 0.7268406397452634 +WEDNESDAY_23 = 0.8068904097486369 +THURSDAY_0 = 0.9021601102971811 +THURSDAY_1 = 1.023741688964238 +THURSDAY_2 = 1.1340689935096755 +THURSDAY_3 = 1.2530130345819006 +THURSDAY_4 = 1.3163421664973542 +THURSDAY_5 = 1.3536343767230727 +THURSDAY_6 = 1.3432290485306728 +THURSDAY_7 = 1.2864983218982178 +THURSDAY_8 = 1.2320488534113174 +THURSDAY_9 = 1.1984530721079034 +THURSDAY_10 = 1.0877338251341975 +THURSDAY_11 = 0.9999324929016475 +THURSDAY_12 = 0.87536726762619 +THURSDAY_13 = 0.6560822412167919 +THURSDAY_14 = 0.44836474861432074 +THURSDAY_15 = 0.36145134935025247 +THURSDAY_16 = 0.2695997829759713 +THURSDAY_17 = 0.2898426312618241 +THURSDAY_18 = 0.3970093434340387 +THURSDAY_19 = 0.5193273246848977 +THURSDAY_20 = 0.6426415257034419 +THURSDAY_21 = 0.800685718218497 +THURSDAY_22 = 0.9215516833839711 +THURSDAY_23 = 1.053701659160912 +FRIDAY_0 = 1.149649788723893 +FRIDAY_1 = 1.2046315447861193 +FRIDAY_2 = 1.2724031281576726 +FRIDAY_3 = 1.3525693456352732 +FRIDAY_4 = 1.3746126314960814 +FRIDAY_5 = 1.3744591862592468 +FRIDAY_6 = 1.3297812543035683 +FRIDAY_7 = 1.2762064429631657 +FRIDAY_8 = 1.235662409263294 +FRIDAY_9 = 1.2171558028785991 +FRIDAY_10 = 1.182722399785398 +FRIDAY_11 = 1.137345538963285 +FRIDAY_12 = 0.9999308422620752 +FRIDAY_13 = 0.8055000309055653 +FRIDAY_14 = 0.5667135273493851 +FRIDAY_15 = 0.4081529603000651 +FRIDAY_16 = 0.3987031354907009 +FRIDAY_17 = 0.5030075499003412 +FRIDAY_18 = 0.6518159532641841 +FRIDAY_19 = 0.8733483414970974 +FRIDAY_20 = 1.0496224913080463 +FRIDAY_21 = 1.1820684558591705 +FRIDAY_22 = 1.2561688567574458 +FRIDAY_23 = 1.3204704912328773 +SATURDAY_0 = 1.3832230236620218 +SATURDAY_1 = 1.4632908341022142 +SATURDAY_2 = 1.5019230781315296 +SATURDAY_3 = 1.5437332506007084 +SATURDAY_4 = 1.5934153179751855 +SATURDAY_5 = 1.6245578072557723 +SATURDAY_6 = 1.6294919789890665 +SATURDAY_7 = 1.6027665451672717 +SATURDAY_8 = 1.6068061069158674 +SATURDAY_9 = 1.624257927970777 +SATURDAY_10 = 1.5996112411089 +SATURDAY_11 = 1.5659672993092648 +SATURDAY_12 = 1.5333537902522736 +SATURDAY_13 = 1.445292929996356 +SATURDAY_14 = 1.2966021477035259 +SATURDAY_15 = 1.250999408961155 +SATURDAY_16 = 1.2535364828163025 +SATURDAY_17 = 1.2736456128871074 +SATURDAY_18 = 1.3348268054897328 +SATURDAY_19 = 1.4571388900094875 +SATURDAY_20 = 1.5073787902995706 +SATURDAY_21 = 1.5605139580010123 +SATURDAY_22 = 1.5885303316932382 +SATURDAY_23 = 1.6169891066719597 diff --git a/coordinator/app/src/test/resources/configs/smart-contract-errors.toml b/coordinator/app/src/test/resources/configs/smart-contract-errors.toml new file mode 100644 index 000000000..1de93403e --- /dev/null +++ b/coordinator/app/src/test/resources/configs/smart-contract-errors.toml @@ -0,0 +1,10 @@ +## +# Smart contract error codes from: +# https://www.notion.so/consensys/Smart-Contracts-Error-Code-Registry-bb4bd68f8ddf4b0ba90000d1136e42ef +## + +[smart-contract-errors] +# L1 Linea Rollup +"0f06cd15" = "DataAlreadySubmitted" +"c01eab56" = "EmptySubmissionData" +"abefa5e8" = "DataStartingBlockDoesNotMatch" diff --git a/coordinator/app/src/test/resources/configs/traces-limits-v1.toml b/coordinator/app/src/test/resources/configs/traces-limits-v1.toml new file mode 100644 index 000000000..e7c727a80 --- /dev/null +++ b/coordinator/app/src/test/resources/configs/traces-limits-v1.toml @@ -0,0 +1,40 @@ +[traces-limits] +# EVM Arithmetization Limits +ADD = 1 +BIN = 2 +BIN_RT = 3 +EC_DATA = 4 +EXT = 5 +HUB = 6 +INSTRUCTION_DECODER = 7 +MMIO = 8 +MMU = 9 +MMU_ID = 10 +MOD = 11 +MUL = 12 +MXP = 13 +PHONEY_RLP = 14 +PUB_HASH = 15 +PUB_HASH_INFO = 16 +PUB_LOG = 17 +PUB_LOG_INFO = 18 +RLP = 19 +ROM = 20 +SHF = 21 +SHF_RT = 22 +TX_RLP = 23 +WCP = 24 +# Block Limits +BLOCK_TX = 25 +BLOCK_L2L1LOGS = 26 +BLOCK_KECCAK = 27 +# Precompile Limits +PRECOMPILE_ECRECOVER = 28 +PRECOMPILE_SHA2 = 29 +PRECOMPILE_RIPEMD = 30 +PRECOMPILE_IDENTITY = 31 +PRECOMPILE_MODEXP = 32 +PRECOMPILE_ECADD = 32 +PRECOMPILE_ECMUL = 34 +PRECOMPILE_ECPAIRING = 35 +PRECOMPILE_BLAKE2F = 36 diff --git a/coordinator/app/src/test/resources/configs/traces-limits-v2.toml b/coordinator/app/src/test/resources/configs/traces-limits-v2.toml new file mode 100644 index 000000000..5ece38b4b --- /dev/null +++ b/coordinator/app/src/test/resources/configs/traces-limits-v2.toml @@ -0,0 +1,53 @@ +[traces-limits] +# Arithmetization module limits +ADD = 1 +BIN = 2 +BLAKE_MODEXP_DATA = 3 +BLOCK_DATA = 4 +BLOCK_HASH = 5 +EC_DATA = 6 +EUC = 7 +EXP = 8 +EXT = 9 +GAS = 10 +HUB = 11 +LOG_DATA = 12 +LOG_INFO = 13 +MMIO = 14 +MMU = 15 +MOD = 16 +MUL = 18 +MXP = 19 +OOB = 20 +RLP_ADDR = 21 +RLP_TXN = 22 +RLP_TXN_RCPT = 23 +ROM = 24 +ROM_LEX = 25 +SHAKIRA_DATA = 26 +SHF = 27 +STP = 28 +TRM = 29 +TXN_DATA = 30 +WCP = 31 +# Reference table limits, set to UInt.MAX_VALUE +BIN_REFERENCE_TABLE = 32 +INSTRUCTION_DECODER = 33 +SHF_REFERENCE_TABLE = 34 +# Precompiles limits +PRECOMPILE_BLAKE_EFFECTIVE_CALLS = 35 +PRECOMPILE_BLAKE_ROUNDS = 36 +PRECOMPILE_ECADD_EFFECTIVE_CALLS = 37 +PRECOMPILE_ECMUL_EFFECTIVE_CALLS = 38 +PRECOMPILE_ECPAIRING_FINAL_EXPONENTIATIONS = 39 +PRECOMPILE_ECPAIRING_G2_MEMBERSHIP_CALLS = 40 +PRECOMPILE_ECPAIRING_MILLER_LOOPS = 41 +PRECOMPILE_ECRECOVER_EFFECTIVE_CALLS = 42 +PRECOMPILE_MODEXP_EFFECTIVE_CALLS = 43 +PRECOMPILE_RIPEMD_BLOCKS = 44 +PRECOMPILE_SHA2_BLOCKS = 45 +# Block limits +BLOCK_KECCAK = 46 +BLOCK_L1_SIZE = 47 +BLOCK_L2_L1_LOGS = 48 +BLOCK_TRANSACTIONS = 49 diff --git a/coordinator/clients/prover-client/file-based-client/src/main/kotlin/net/consensys/zkevm/coordinator/clients/prover/FileBasedExecutionProverClientV2.kt b/coordinator/clients/prover-client/file-based-client/src/main/kotlin/net/consensys/zkevm/coordinator/clients/prover/FileBasedExecutionProverClientV2.kt index c1f34bd22..294c577b4 100644 --- a/coordinator/clients/prover-client/file-based-client/src/main/kotlin/net/consensys/zkevm/coordinator/clients/prover/FileBasedExecutionProverClientV2.kt +++ b/coordinator/clients/prover-client/file-based-client/src/main/kotlin/net/consensys/zkevm/coordinator/clients/prover/FileBasedExecutionProverClientV2.kt @@ -57,7 +57,7 @@ internal class ExecutionProofRequestDataDecorator( return SafeFuture.collectAll(bridgeLogsSfList.stream()) .thenCombine( - getBlockStateRootHash(request.blocks.first().number.toULong() - 1UL) + getBlockStateRootHash(request.blocks.first().number - 1UL) ) { blocksAndBridgeLogs, previousKeccakStateRootHash -> BatchExecutionProofRequestDto( zkParentStateRootHash = request.type2StateData.zkParentStateRootHash.encodeHex(), diff --git a/coordinator/clients/smart-contract-client/build.gradle b/coordinator/clients/smart-contract-client/build.gradle index f1418d28b..5851971dd 100644 --- a/coordinator/clients/smart-contract-client/build.gradle +++ b/coordinator/clients/smart-contract-client/build.gradle @@ -4,7 +4,7 @@ plugins { dependencies { implementation project(":jvm-libs:generic:extensions:kotlin") - implementation project(':jvm-libs:linea:web3j-extensions') + api project(':jvm-libs:linea:web3j-extensions') api project(':jvm-libs:linea:clients:linea-l1-contract-client') api 'build.linea:l2-message-service-contract-client:0.0.1' @@ -15,5 +15,4 @@ dependencies { implementation project(path: ':coordinator:core') implementation project(path: ':coordinator:ethereum:common') testImplementation "io.vertx:vertx-junit5" - testImplementation "com.github.tomakehurst:wiremock-jre8:${libs.versions.wiremock.get()}" } diff --git a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JContractAsyncHelper.kt b/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JContractAsyncHelper.kt index 2dbf36d8b..f90df0c54 100644 --- a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JContractAsyncHelper.kt +++ b/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JContractAsyncHelper.kt @@ -254,7 +254,7 @@ class Web3JContractAsyncHelper( dynamicMaxFeePerGas: ULong?, dynamicMaxFeePerBlobGas: ULong? = null ) { - val withBlob = maxFeePerBlobGas != null && dynamicMaxFeePerBlobGas != null + val withBlob = maxFeePerBlobGas != null || dynamicMaxFeePerBlobGas != null log.info( "$logMessagePrefix gas price caps: " + "blobCarrying=$withBlob " + @@ -263,8 +263,8 @@ class Web3JContractAsyncHelper( "maxFeePerGas=${maxFeePerGas.toGWei()} GWei, " + "dynamicMaxFeePerGas=${dynamicMaxFeePerGas?.toGWei()} GWei, " + if (withBlob) { - "maxFeePerBlobGas=${maxFeePerBlobGas!!.toGWei()} GWei, " + - "dynamicMaxFeePerBlobGas=${dynamicMaxFeePerBlobGas!!.toGWei()} GWei" + "maxFeePerBlobGas=${maxFeePerBlobGas?.toGWei()} GWei, " + + "dynamicMaxFeePerBlobGas=${dynamicMaxFeePerBlobGas?.toGWei()} GWei" } else { "" } diff --git a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JL2MessageServiceLogsClient.kt b/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JL2MessageServiceLogsClient.kt index c41bb8b4e..ee174c634 100644 --- a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JL2MessageServiceLogsClient.kt +++ b/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JL2MessageServiceLogsClient.kt @@ -1,5 +1,6 @@ package net.consensys.linea.contract +import build.linea.web3j.Web3JLogsClient import net.consensys.toULong import net.consensys.zkevm.coordinator.clients.L2MessageServiceLogsClient import net.consensys.zkevm.domain.BridgeLogsData diff --git a/coordinator/ethereum/blob-submitter/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/finalization/BlobAndAggregationFinalizationIntTest.kt b/coordinator/ethereum/blob-submitter/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/finalization/BlobAndAggregationFinalizationIntTest.kt index 51733bbd5..88876b55e 100644 --- a/coordinator/ethereum/blob-submitter/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/finalization/BlobAndAggregationFinalizationIntTest.kt +++ b/coordinator/ethereum/blob-submitter/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/finalization/BlobAndAggregationFinalizationIntTest.kt @@ -185,7 +185,8 @@ class BlobAndAggregationFinalizationIntTest : CleanDbTestSuiteParallel() { val blobsEndTime = blobs.last().endBlockTime val endTime = if (aggEndTime > blobsEndTime) aggEndTime else blobsEndTime - fakeClock.setTimeTo(endTime.plus(10.seconds)) + // submission do the cutoff by minutes, so we need to add 1 minute to the end time + fakeClock.setTimeTo(endTime.plus(1.minutes)) blobSubmissionCoordinator.start() aggregationFinalizationCoordinator.start() diff --git a/coordinator/ethereum/blob-submitter/src/main/kotlin/net/consensys/zkevm/ethereum/submission/SwitchProviderImpl.kt b/coordinator/ethereum/blob-submitter/src/main/kotlin/net/consensys/zkevm/ethereum/submission/SwitchProviderImpl.kt index 666f0b600..9dae2b93b 100644 --- a/coordinator/ethereum/blob-submitter/src/main/kotlin/net/consensys/zkevm/ethereum/submission/SwitchProviderImpl.kt +++ b/coordinator/ethereum/blob-submitter/src/main/kotlin/net/consensys/zkevm/ethereum/submission/SwitchProviderImpl.kt @@ -2,8 +2,8 @@ package net.consensys.zkevm.ethereum.submission +import build.linea.web3j.Web3JLogsClient import net.consensys.linea.contract.L2MessageService -import net.consensys.linea.contract.Web3JLogsClient import net.consensys.toULong import net.consensys.zkevm.ethereum.coordination.conflation.upgrade.SwitchProvider import org.apache.logging.log4j.LogManager diff --git a/coordinator/ethereum/gas-pricing/static-cap/src/main/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/FeeHistoryFetcherImpl.kt b/coordinator/ethereum/gas-pricing/static-cap/src/main/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/FeeHistoryFetcherImpl.kt index a2ee341a2..147fc03d8 100644 --- a/coordinator/ethereum/gas-pricing/static-cap/src/main/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/FeeHistoryFetcherImpl.kt +++ b/coordinator/ethereum/gas-pricing/static-cap/src/main/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/FeeHistoryFetcherImpl.kt @@ -31,7 +31,7 @@ class FeeHistoryFetcherImpl( } private var cacheIsValidForBlockNumber: BigInteger = BigInteger.ZERO - private var feesCache: FeeHistory = getRecentFees().get() + private lateinit var feesCache: FeeHistory private fun getRecentFees(): SafeFuture { val blockNumberFuture = web3jClient.ethBlockNumber().sendAsync() diff --git a/coordinator/ethereum/test-utils/build.gradle b/coordinator/ethereum/test-utils/build.gradle index 68156f416..2ca613168 100644 --- a/coordinator/ethereum/test-utils/build.gradle +++ b/coordinator/ethereum/test-utils/build.gradle @@ -9,6 +9,7 @@ dependencies { implementation(project(":coordinator:core")) implementation(project(":coordinator:clients:smart-contract-client")) implementation(project(":jvm-libs:linea:web3j-extensions")) + implementation(testFixtures(project(":jvm-libs:linea:web3j-extensions"))) implementation(project(":coordinator:ethereum:common")) implementation(project(":jvm-libs:linea:testing:file-system")) implementation("org.web3j:core:${libs.versions.web3j.get()}") { diff --git a/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt b/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt index 36611739f..1dda586bd 100644 --- a/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt +++ b/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/AccountManager.kt @@ -3,6 +3,7 @@ package net.consensys.zkevm.ethereum import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import kotlinx.datetime.Clock +import linea.web3j.waitForTxReceipt import net.consensys.linea.contract.AsyncFriendlyTransactionManager import net.consensys.linea.jsonrpc.JsonRpcErrorResponseException import net.consensys.linea.testing.filesystem.getPathTo @@ -228,7 +229,7 @@ object L1AccountManager : AccountManager by WhaleBasedAccountManager( object L2AccountManager : AccountManager by WhaleBasedAccountManager( web3jClient = Web3jClientManager.l2Client, - genesisFile = getPathTo(System.getProperty("L2_GENESIS", "docker/config/linea-local-dev-genesis.json")), + genesisFile = getPathTo(System.getProperty("L2_GENESIS", "docker/config/linea-local-dev-genesis-PoA.json")), log = LogManager.getLogger(L2AccountManager::class.java) ) diff --git a/docker/compose.yml b/docker/compose.yml index 3084a9f20..d9ce8ac3f 100644 --- a/docker/compose.yml +++ b/docker/compose.yml @@ -408,6 +408,11 @@ services: condition: service_healthy l1-node-genesis-generator: condition: service_completed_successfully + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:4000/eth/v1/node/health || exit 1"] + interval: 1s + timeout: 1s + retries: 120 command: [ "--config-file=/config/config-file.yaml" ] volumes: - ./config/l1-node/cl/teku.key:/config/keys/teku.key:ro @@ -644,6 +649,10 @@ services: condition: service_healthy redis: condition: service_healthy + l1-cl-node: + condition: service_healthy + l1-el-node: + condition: service_healthy blobscan-indexer: container_name: blobscan-indexer @@ -662,6 +671,10 @@ services: condition: service_healthy blobscan-api: condition: service_started + l1-cl-node: + condition: service_healthy + l1-el-node: + condition: service_healthy redis: container_name: redis @@ -684,6 +697,95 @@ services: l1network: ipv4_address: 10.10.10.205 + zkbesu-shomei-sr: + image: consensys/linea-besu-package:${SEQUENCER_TAG:-devnet-811f30b} + hostname: zkbesu-shomei-sr + container_name: zkbesu-shomei-sr + profiles: [ "external-to-monorepo", "staterecover" ] + privileged: true +# restart: none + user: root + ports: + - "9145:8545" # http + - "9146:8546" # websockets + - "9150:8550" + - "10545:9545" + healthcheck: + test: [ "CMD-SHELL", "bash -c \"[ -f /tmp/pid ]\"" ] + interval: 1s + timeout: 1s + retries: 120 + restart: "no" + networks: + l1network: + ipv4_address: 10.10.10.206 + linea: + ipv4_address: 11.11.11.116 + environment: + LOG4J_CONFIGURATION_FILE: /var/lib/besu/log4j.xml + L1_ROLLUP_CONTRACT_ADDRESS: ${L1_ROLLUP_CONTRACT_ADDRESS:-0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9} + entrypoint: + - /bin/bash + - -c + - | + chown -R besu:besu /opt/besu/plugins && \ + ls -lh /opt/besu/plugins && \ + sed -i '/^CLASSPATH/c\CLASSPATH=/opt/besu/lib/\*' /opt/besu/bin/besu && \ + /opt/besu/bin/besu \ + --config-file=/var/lib/besu/zkbesu-config.toml \ + --genesis-file=/var/lib/besu/genesis.json \ + --plugins=BesuShomeiRpcPlugin,ZkTrieLogPlugin,LineaStateRecoverPlugin \ + --rpc-http-api=ADMIN,DEBUG,NET,ETH,WEB3,PLUGINS,MINER,SHOMEI \ + --Xbonsai-limit-trie-logs-enabled=false \ + --plugin-shomei-http-host="11.11.11.117" \ + --plugin-shomei-http-port=8888 \ + --plugin-staterecovery-l1-rpc-endpoint=http://l1-el-node:8545 \ + --plugin-staterecovery-shomei-endpoint=http://shomei-sr:8888 \ + --plugin-staterecovery-blobscan-endpoint=http://blobscan-api:4001 \ + --plugin-staterecovery-linea-sequencer-beneficiary-address=0x6d976c9b8ceee705d4fe8699b44e5eb58242f484 \ + --plugin-staterecovery-overriding-recovery-start-block-number=1 \ + --plugin-staterecovery-l1-polling-interval=PT1S + volumes: + - ./config/zkbesu-shomei/zkbesu-config.toml:/var/lib/besu/zkbesu-config.toml:ro + - ./config/zkbesu-shomei/log4j-staterecovery.xml:/var/lib/besu/log4j.xml:ro + - ./config/linea-local-dev-genesis-PoA-besu.json/:/var/lib/besu/genesis.json:ro + - ../state-recover/besu-plugin/build/libs/linea-staterecover-plugin-0.0.1-rc2.jar:/opt/besu/lib/linea-staterecover-plugin-0.0.1-rc2.jar + - ../state-recover/besu-plugin/build/libs/linea-staterecover-plugin-0.0.1-rc2.jar:/opt/besu/plugins/linea-staterecover-plugin-0.0.1-rc2.jar + + shomei-sr: + image: consensys/linea-shomei:2.3.0 + hostname: shomei-sr + container_name: shomei-sr + profiles: [ "external-to-monorepo", "staterecover" ] + depends_on: + zkbesu-shomei-sr: + condition: service_started + privileged: true + user: root + ports: + - "8890:8888" + healthcheck: + test: [ "CMD-SHELL", "bash -c \"[ -f /data/shomei/LOCK ]\"" ] + interval: 1s + timeout: 1s + retries: 60 + networks: + linea: + ipv4_address: 11.11.11.117 + environment: + LOG4J_CONFIGURATION_FILE: /log4j.xml + command: + - --besu-rpc-http-host=11.11.11.116 + - --besu-rpc-http-port=8545 + - --rpc-http-host=11.11.11.117 + - --rpc-http-host-allow-list=* + - --rpc-http-port=8888 + - --min-confirmations-before-importing=0 + - --trace-start-block-number=0 + volumes: + - ./config/shomei/log4j.xml:/log4j.xml:ro + # - ../tmp/local/shomei:/data/shomei/:z + ######################## # Observability stack ######################## diff --git a/docker/config/linea-local-dev-genesis.json b/docker/config/linea-local-dev-genesis.json deleted file mode 100644 index b4d149078..000000000 --- a/docker/config/linea-local-dev-genesis.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "@WARNING": "THIS FILE IS FOR LOCAL DEVELOPMENT ONLY! DO NOT REUSE ELSEWHERE", - "config": { - "chainId": 1337, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "parisBlock": 0, - "terminalTotalDifficulty": 0, - "clique": { - "period": 2, - "epoch": 30000 - } - }, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x1", - "extraData": "0x00000000000000000000000000000000000000000000000000000000000000005064f2bafb300be5ea73aed3f4835e1a0256a5b30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "gasLimit": "0xa00000", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0", - "timestamp": "0x645580D1", - "@WARNING": "FOR LOCAL DEV ONLY - DO NOT REUSE THESE KEYS ELSEWHERE", - "alloc": { - "1b9abeec3215d8ade8a33607f2cf0f4f60e5f0d0": { - "privateKey": "0x1dd171cec7e2995408b5513004e8207fe88d6820aeff0d82463b3e41df251aae", - "comment": "Contract deployer account", - "balance": "90000000000000000000000" - }, - "fe3b557e8fb62b89f4916b721be55ceb828dbd73": { - "privateKey": "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", - "comment": "account 1, can be used as end user", - "balance": "90000000000000000000001" - }, - "627306090abaB3A6e1400e9345bC60c78a8BEf57": { - "privateKey": "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3", - "comment": "account 2, can be used as end user", - "balance": "90000000000000000000002" - }, - "f17f52151EbEF6C7334FAD080c5704D77216b732": { - "privateKey": "ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f", - "comment": "account 3, can be used as end user", - "balance": "90000000000000000000003" - }, - "6d26dcc30a1693043aefa35ed9171c16da53f275": { - "privateKey": "0x47629fbb4a7ad7772b4d1cc92f26b325577b70f1ed5940e1859b92d690f8a2bf", - "comment": "account 4, can be used as end user", - "balance": "90000000000000000000004" - }, - "e00cad48944330a60bbaedfbf2e0ac97e9762a1e": { - "privateKey": "0x4f78823f38639b9ef15392eb8024ace1d7b991ea820b0dd36a15d14d1a6785", - "comment": "account 5, can be used as end user", - "balance": "90000000000000000000005" - }, - "2257ae433e214df824eb2ade79d2b305ca61a4f4": { - "privateKey": "0x327456c797d6300e11051c0c19b9dbe480fe57cdfcb8033d313e80c7c2e10369", - "comment": "account 6, can be used as end user", - "balance": "90000000000000000000006" - }, - "0d4278da2f55cf21a014b7fee0a2cb799ce17ede": { - "privateKey": "0x9ffda2814ee771e0af8018aeea65f9eabd47ea9f2a5b628a4571adeafea692d1", - "comment": "account 7, can be used as end user", - "balance": "90000000000000000000007" - }, - "994f4c82683f666d13d03a131078f1b94777790c": { - "privateKey": "0xcd3a170ec22b2f3e4aee76356df0c34712db8c24f8d836bce1e4a79299c87053", - "comment": "account 8, can be used as end user", - "balance": "90000000000000000000008" - }, - "9d14ef14d4c90436a062efd7dc8354a7ded9712e": { - "privateKey": "0x4a954bb197f7a27a5427f29180fbfd0b32ee0344b4f85c8184ca593cf152866a", - "comment": "account 9, can be used as end user", - "balance": "90000000000000000000009" - }, - "29a6b94168f04956c6fd1a2c3fdd1f6f7c468148": { - "privateKey": "0x745dda33b5d813bda7f52d646a56498c1539290f59d064b13161f84a1f0a7b4b", - "comment": "account 10, can be used as end user", - "balance": "900000000000000000000010" - }, - "dca74800d7ce103a5e6a3f6028ab0963c46e7422": { - "privateKey": "0x75b9700016469b0d7f12c0d6a0225cd9a59818a4bd1437cf9583ca0ffa1d111a", - "comment": "account 11, can be used as end user", - "balance": "900000000000000000000011" - }, - "9ad149426800dc9e65754a5ceab6bc1f41cc92a7": { - "privateKey": "0xe08f03f96ff2f4e107a50da222e281db39cd528c8c35e25a17f0a71a4d279da5", - "comment": "account 12, can be used as end user", - "balance": "900000000000000000000012" - }, - "b3c150df38e91149e260c3233f3121810d4d2976": { - "privateKey": "0x7303d2fadd895018075cbe76d8a700bc65b4a1b8641b97d660533f0e029e3954", - "comment": "account 13, can be used as end user", - "balance": "900000000000000000000013" - }, - "42232eab8cfd6b489efe79d3bdcc12f07a9fbac6": { - "privateKey": "0xc5453712de35e7dc2c599b5f86df5d4f0de442d86a2865cfe557acd6d131aa6f", - "comment": "account 14, can be used as end user", - "balance": "900000000000000000000014" - }, - "30b080749e44112c3e679c5e4117dd2d884ec7da": { - "privateKey": "0xa8cc1b4bf5cd228cfe63c1b73a5515721e72b487cf8b82a285023aa0ed1ef839", - "comment": "account 15, can be used as end user", - "balance": "900000000000000000000015" - }, - "82f93ea98b24441dc3e0b2413cc1cbb02f33d7e5": { - "privateKey": "0x8c1c8a65947b79ef919261364e9044d89ffe26fb764d8cd72db0446d6cf56664", - "comment": "account 16, can be used as end user", - "balance": "900000000000000000000016" - }, - "bae3c3fcd73ccf7755ec8a10664f218ad6bbc775": { - "privateKey": "0xb35972d9380d1be620a2c61da77f68f127ef248ec55e1bc6033d20a7e13ef3fa", - "comment": "account 17, can be used as end user", - "balance": "900000000000000000000017" - }, - "54d450f4d728da50f1271a1700b42657940324aa": { - "privateKey": "0x234d87442cf7d43841fbe280febcdfabfb646added67bc19f7e42a5483f614c4", - "comment": "account 18, can be used as end user", - "balance": "900000000000000000000018" - }, - "d42e308fc964b71e18126df469c21b0d7bcb86cc": { - "privateKey": "0x4d01ae6487860981699236a58b68f807ee5f17b12df5740b85cf4c4653be0f55", - "comment": "Message anchorer account", - "balance": "900000000000000000000019" - }, - "c8c92fe825d8930b9357c006e0af160dfa727a62": { - "privateKey": "0xfcf854e0a0bc6fd7e97d7050e61a362c915cecd6767a32267b22e8b7af572e58", - "comment": "account 20, can be used as end user", - "balance": "900000000000000000000020" - }, - "8cdcc370846c9f669489227465f80e6cc4ecd050": { - "privateKey": "0xb17202c37cce9498e6f7dcdc1abd207802d09b5eee96677ea219ac867a198b91", - "comment": "Account used for smart contract deployment on L1 and L2", - "balance": "90000000000000000000000" - }, - "d0584d4d37157f7105a4b41ed8ecbdfafdb2547f": { - "privateKey": "0x202454d1b4e72c41ebf58150030f649648d3cf5590297fb6718e27039ed9c86d", - "comment": "Operator account", - "balance": "90000000000000000000000" - } - } -} diff --git a/docker/config/shomei/log4j.xml b/docker/config/shomei/log4j.xml index 15df621c1..46bc5b2f8 100644 --- a/docker/config/shomei/log4j.xml +++ b/docker/config/shomei/log4j.xml @@ -6,7 +6,7 @@ - + diff --git a/docker/config/traces-node-v2/log4j.xml b/docker/config/traces-node-v2/log4j.xml index 4fce5c508..f7d311869 100644 --- a/docker/config/traces-node-v2/log4j.xml +++ b/docker/config/traces-node-v2/log4j.xml @@ -25,7 +25,7 @@ - + diff --git a/docker/config/traces-node-v2/traces-node-v2-config.toml b/docker/config/traces-node-v2/traces-node-v2-config.toml index a38c5d8e7..09ca48cd2 100644 --- a/docker/config/traces-node-v2/traces-node-v2-config.toml +++ b/docker/config/traces-node-v2/traces-node-v2-config.toml @@ -38,7 +38,7 @@ data-storage-format="BONSAI" # plugins plugins=["TracerReadinessPlugin","TracesEndpointServicePlugin","LineCountsEndpointServicePlugin","CaptureEndpointServicePlugin"] plugin-linea-conflated-trace-generation-traces-output-path="/data/traces/v2/conflated" -plugin-linea-rpc-concurrent-requests-limit=1 +plugin-linea-rpc-concurrent-requests-limit=2 plugin-linea-tracer-readiness-server-host="0.0.0.0" plugin-linea-tracer-readiness-server-port=8548 plugin-linea-tracer-readiness-max-blocks-behind=5 diff --git a/docker/config/zkbesu-shomei/log4j-staterecovery.xml b/docker/config/zkbesu-shomei/log4j-staterecovery.xml new file mode 100644 index 000000000..6e5ada67a --- /dev/null +++ b/docker/config/zkbesu-shomei/log4j-staterecovery.xml @@ -0,0 +1,53 @@ + + + + INFO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docker/config/zkbesu-shomei/log4j.xml b/docker/config/zkbesu-shomei/log4j.xml index 56c746fb5..144906b8d 100644 --- a/docker/config/zkbesu-shomei/log4j.xml +++ b/docker/config/zkbesu-shomei/log4j.xml @@ -1,7 +1,7 @@ - WARN + INFO diff --git a/docker/linea-sepolia/genesis.json b/docker/linea-sepolia/genesis.json index 037bd7a2c..09f520d32 100644 --- a/docker/linea-sepolia/genesis.json +++ b/docker/linea-sepolia/genesis.json @@ -19,7 +19,7 @@ "nonce": "0x0", "timestamp": "0x6391BFF3", "extraData": "0x00000000000000000000000000000000000000000000000000000000000000004D517Aef039A48b3B6bF921e210b7551C8E371070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "gasLimit": "0x1C9C380", + "gasLimit": "0x3a2c940", "difficulty": "0x1", "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", @@ -814,4 +814,4 @@ "number": "0x0", "gasUsed": "0x0", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } \ No newline at end of file + } diff --git a/docker/scripts/file-downloader.sh b/docker/scripts/file-downloader.sh deleted file mode 100644 index 1de52d8e7..000000000 --- a/docker/scripts/file-downloader.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -if [ $# -lt 2 ]; then - echo "Usage: $0 file_url destination_folder" - echo "Example: $0 https://example.com/somefile.txt /path/to/destination/" - exit -fi - -check_and_download_file() { - local file_url="$1" - local directory="$2" - local filename="${file_url##*/}" # Extracts the filename from the URL - - # Check if the file exists in the directory - if [[ ! -f "$directory/$filename" ]]; then - # File does not exist, download it - echo "Downloading $file_url ..." - wget "$file_url" -P "$directory" - echo "Download complete!" - else - echo "File $filename already exists in $directory." - fi -} -echo "$0 $1 $2" -check_and_download_file "$1" "$2" diff --git a/finalized-tag-updater/build.gradle b/finalized-tag-updater/build.gradle index 93f922a19..ad44e7f66 100644 --- a/finalized-tag-updater/build.gradle +++ b/finalized-tag-updater/build.gradle @@ -40,7 +40,7 @@ dependencies { implementation project(':jvm-libs:linea:core:long-running-service') implementation project(':jvm-libs:generic:extensions:futures') implementation project(':jvm-libs:linea:web3j-extensions') - implementation 'build.linea:l1-rollup-contract-client:6.0.0-rc2' + implementation project(':jvm-libs:linea:clients:linea-l1-contract-client') implementation ("org.web3j:core:${libs.versions.web3j.get()}") { exclude group: 'org.slf4j', module: 'slf4j-nop' } diff --git a/finalized-tag-updater/src/main/kotlin/net/consensys/linea/FinalizationUpdatePoller.kt b/finalized-tag-updater/src/main/kotlin/net/consensys/linea/FinalizationUpdatePoller.kt index c67889061..57cffeca6 100644 --- a/finalized-tag-updater/src/main/kotlin/net/consensys/linea/FinalizationUpdatePoller.kt +++ b/finalized-tag-updater/src/main/kotlin/net/consensys/linea/FinalizationUpdatePoller.kt @@ -1,14 +1,13 @@ package net.consensys.zkevm.ethereum.finalization -import build.linea.contract.LineaRollupV5 +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly import io.vertx.core.Vertx +import net.consensys.linea.BlockParameter +import net.consensys.linea.async.AsyncRetryer import net.consensys.linea.async.toSafeFuture -import net.consensys.toULong import net.consensys.zkevm.PeriodicPollingService import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger -import org.web3j.protocol.core.DefaultBlockParameter -import org.web3j.protocol.core.DefaultBlockParameterName import tech.pegasys.teku.infrastructure.async.SafeFuture import java.util.concurrent.CompletableFuture import java.util.concurrent.atomic.AtomicReference @@ -17,24 +16,19 @@ import kotlin.time.Duration.Companion.seconds data class FinalizationUpdatePollerConfig( val pollingInterval: Duration = 12.seconds, - val blockTag: String + val blockTag: BlockParameter ) { init { require(pollingInterval >= 0.seconds) { "pollingInterval must be greater than 0" } - - require(DefaultBlockParameterName.fromString(blockTag) != null) { - "Invalid blockTag='$blockTag', " + - "valid values: ${DefaultBlockParameterName.values().joinToString(", ")}" - } } } class FinalizationUpdatePoller( - vertx: Vertx, - config: FinalizationUpdatePollerConfig, - private val lineaRollup: LineaRollupV5, + private val vertx: Vertx, + private val config: FinalizationUpdatePollerConfig, + private val lineaRollup: Web3JLineaRollupSmartContractClientReadOnly, private val finalizationHandler: (ULong) -> CompletableFuture<*>, private val log: Logger = LogManager.getLogger(FinalizationUpdatePoller::class.java) ) : PeriodicPollingService( @@ -44,22 +38,23 @@ class FinalizationUpdatePoller( ) { private val lastFinalizationRef: AtomicReference = AtomicReference(null) - init { - lineaRollup.setDefaultBlockParameter(DefaultBlockParameter.valueOf(config.blockTag)) - } - override fun action(): SafeFuture<*> { - return lineaRollup.currentL2BlockNumber().sendAsync() - .thenCompose { lineaFinalizedBlockNumber -> - val prevFinalizedBlockNumber = lastFinalizationRef.get() - lastFinalizationRef.set(lineaFinalizedBlockNumber.toULong()) - if (prevFinalizedBlockNumber != lineaFinalizedBlockNumber.toULong()) { - finalizationHandler(lineaFinalizedBlockNumber.toULong()).thenApply { Unit } - } else { - CompletableFuture.completedFuture(Unit) + return AsyncRetryer.retry( + vertx, + backoffDelay = config.pollingInterval + ) { + lineaRollup.finalizedL2BlockNumber(config.blockTag) + .thenCompose { lineaFinalizedBlockNumber -> + val prevFinalizedBlockNumber = lastFinalizationRef.get() + lastFinalizationRef.set(lineaFinalizedBlockNumber.toULong()) + if (prevFinalizedBlockNumber != lineaFinalizedBlockNumber.toULong()) { + finalizationHandler(lineaFinalizedBlockNumber.toULong()).thenApply { Unit } + } else { + CompletableFuture.completedFuture(Unit) + } } - } - .toSafeFuture() + .toSafeFuture() + } } override fun handleError(error: Throwable) { diff --git a/finalized-tag-updater/src/main/kotlin/net/consensys/linea/LineaL1FinalizationUpdaterService.kt b/finalized-tag-updater/src/main/kotlin/net/consensys/linea/LineaL1FinalizationUpdaterService.kt index a1585ea9a..75674a236 100644 --- a/finalized-tag-updater/src/main/kotlin/net/consensys/linea/LineaL1FinalizationUpdaterService.kt +++ b/finalized-tag-updater/src/main/kotlin/net/consensys/linea/LineaL1FinalizationUpdaterService.kt @@ -1,6 +1,6 @@ package net.consensys.linea -import build.linea.contract.LineaRollupV5 +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly import io.vertx.core.Vertx import net.consensys.linea.consensus.EngineBlockTagUpdater import net.consensys.linea.web3j.okHttpClientBuilder @@ -8,15 +8,11 @@ import net.consensys.zkevm.LongRunningService import net.consensys.zkevm.ethereum.finalization.FinalizationUpdatePoller import net.consensys.zkevm.ethereum.finalization.FinalizationUpdatePollerConfig import org.apache.logging.log4j.LogManager -import org.apache.tuweni.bytes.Bytes import org.hyperledger.besu.plugin.services.BlockchainService import org.slf4j.Logger import org.slf4j.LoggerFactory -import org.web3j.crypto.Credentials import org.web3j.protocol.Web3j import org.web3j.protocol.http.HttpService -import org.web3j.tx.gas.StaticGasProvider -import java.math.BigInteger import java.util.concurrent.CompletableFuture class LineaBesuEngineBlockTagUpdater(private val blockchainService: BlockchainService) : EngineBlockTagUpdater { @@ -27,7 +23,11 @@ class LineaBesuEngineBlockTagUpdater(private val blockchainService: BlockchainSe if (!finalizedBlock.isEmpty) { try { val blockHash = finalizedBlock.get().blockHeader.blockHash - log.info("Linea safe/finalized block update: blockNumber={} blockHash={}", finalizedBlockNumber, blockHash) + log.info( + "Linea safe/finalized block update: blockNumber={} blockHash={}", + finalizedBlockNumber, + blockHash + ) blockchainService.setSafeBlock(blockHash) blockchainService.setFinalizedBlock(blockHash) return true @@ -86,18 +86,16 @@ class LineaL1FinalizationUpdaterService( okHttpClientBuilder(LogManager.getLogger("clients.l1")).build() ) ) - private val lineaRollup = LineaRollupV5.load( - config.l1SmartContractAddress.toHexString(), - web3j, - Credentials.create(Bytes.random(64).toHexString()), - StaticGasProvider(BigInteger.valueOf(50000000000L), BigInteger.valueOf(60000000L)) + private val lineaRollup = Web3JLineaRollupSmartContractClientReadOnly( + contractAddress = config.l1SmartContractAddress.toHexString(), + web3j = web3j ) private val updater = LineaL1FinalizationUpdater(engineBlockTagUpdater) private val poller = FinalizationUpdatePoller( vertx, FinalizationUpdatePollerConfig( pollingInterval = config.l1PollingInterval, - blockTag = "finalized" + blockTag = BlockParameter.Tag.FINALIZED ), lineaRollup, updater::handleL1Finalization, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 670b1201d..509df13fd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ jreleaser = { group = "org.jreleaser", name = "jreleaser-gradle-plugin", version [versions] besu = "24.12.2" +bouncycastle = "1.79" caffeine = "3.1.6" hoplite = "2.7.5" jackson = "2.18.0" @@ -19,7 +20,7 @@ ktlint = "0.47.0" log4j = "2.20.0" micrometer = "1.8.4" netty = "4.1.92.Final" -picoli = "4.7.1" +picoli = "4.7.6" restassured = "5.3.0" teku = "23.1.1" tuweni = "2.4.2" @@ -28,5 +29,6 @@ vertx = "4.5.0" web3j = "4.12.2" wiremock = "3.0.1" jsonUnit = "3.4.1" +slf4j="1.7.36" blobCompressor = "0.0.4" blobShnarfCalculator = "0.0.4" diff --git a/jvm-libs/generic/extensions/kotlin/src/main/kotlin/net/consensys/TypingsExtensions.kt b/jvm-libs/generic/extensions/kotlin/src/main/kotlin/net/consensys/TypingsExtensions.kt index 650de984b..5114a4429 100644 --- a/jvm-libs/generic/extensions/kotlin/src/main/kotlin/net/consensys/TypingsExtensions.kt +++ b/jvm-libs/generic/extensions/kotlin/src/main/kotlin/net/consensys/TypingsExtensions.kt @@ -66,6 +66,16 @@ fun ULong.toGWei(): Double = this.toDouble().toGWei() */ fun ULong.Companion.fromHexString(value: String): ULong = value.removePrefix("0x").toULong(16) +fun ULongRange.intersection(other: ULongRange): ULongRange { + val start = maxOf(this.first, other.first) + val end = minOf(this.last, other.last) + return if (start <= end) { + start..end + } else { + ULongRange.EMPTY + } +} + fun > ClosedRange.toIntervalString(): String { val size = if (start <= endInclusive) { this.endInclusive.toString().toBigDecimal() - this.start.toString().toBigDecimal() + 1.toBigDecimal() diff --git a/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt b/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt index 64921a6b7..44e9591b2 100644 --- a/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt +++ b/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt @@ -31,7 +31,7 @@ open class TestingJsonRpcServer( port: Int = 0, val apiPath: String = "/", val recordRequestsResponses: Boolean = false, - val serverName: String = "FakeJsonRpcServer", + val serverName: String = "TestingJsonRpcServer", loggerName: String = serverName, val vertx: Vertx = Vertx.vertx(), val responseObjectMapper: ObjectMapper = jacksonObjectMapper(), diff --git a/jvm-libs/generic/logging/src/main/kotlin/linea/logging/TimeMeasureLogger.kt b/jvm-libs/generic/logging/src/main/kotlin/linea/logging/TimeMeasureLogger.kt new file mode 100644 index 000000000..72ddf85dd --- /dev/null +++ b/jvm-libs/generic/logging/src/main/kotlin/linea/logging/TimeMeasureLogger.kt @@ -0,0 +1,38 @@ +package linea.logging + +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.Logger +import kotlin.time.measureTime + +/** + * This is more for debugging purposes, to measure the time taken by a certain action and log it. + * For production code, consider using metrics. + */ +fun measureTimeAndLog( + logger: Logger, + logLevel: Level = Level.DEBUG, + logMessageProvider: (duration: kotlin.time.Duration, result: T) -> String, + action: () -> T +): T { + var value: T + val duration = measureTime { + value = action() + } + if (logger.isEnabled(logLevel)) { + logger.log(logLevel, logMessageProvider(duration, value)) + } + return value +} + +class MeasureLogger( + private val logger: Logger, + private val logLevel: Level = Level.DEBUG +) { + fun measureTimeAndLog( + logLevel: Level = this.logLevel, + logMessageProvider: (duration: kotlin.time.Duration, result: T) -> String, + action: () -> T + ): T { + return measureTimeAndLog(logger, logLevel, logMessageProvider, action) + } +} diff --git a/jvm-libs/generic/logging/src/main/kotlin/net/consensys/linea/logging/JsonRpcRequestResponseLogger.kt b/jvm-libs/generic/logging/src/main/kotlin/net/consensys/linea/logging/JsonRpcRequestResponseLogger.kt index c47ecf817..f761174cb 100644 --- a/jvm-libs/generic/logging/src/main/kotlin/net/consensys/linea/logging/JsonRpcRequestResponseLogger.kt +++ b/jvm-libs/generic/logging/src/main/kotlin/net/consensys/linea/logging/JsonRpcRequestResponseLogger.kt @@ -26,12 +26,11 @@ class MinimalInLineJsonRpcLogger( ) : JsonRpcRequestResponseLogger { private fun logRequestOnLevel(level: Level, endpoint: String, jsonBody: String, throwable: Throwable?) { - val message = if (throwable == null) { - "--> {} {}" + if (throwable == null) { + logger.log(level, "--> {} {}", endpoint, jsonBody) } else { - "--> {} {} failed with error={}" + logger.log(level, "--> {} {} failed with error={}", endpoint, jsonBody, throwable.message, throwable) } - logger.log(level, message, endpoint, jsonBody, throwable?.message, throwable) } override fun logRequest(endpoint: String, jsonBody: String, throwable: Throwable?) { @@ -54,19 +53,23 @@ class MinimalInLineJsonRpcLogger( logRequestOnLevel(logLevel, maskedEndpoint, requestBody, null) } - val message = if (failureCause == null) { - "<-- {} {} {}" + if (failureCause == null) { + logger.log( + logLevel, + "<-- {} {} {}", + maskedEndpoint, + responseStatusCode, + responseBody + ) } else { - "<-- {} {} {} failed with error={}" + logger.log( + logLevel, + "<-- {} {} {} failed with error={}", + maskedEndpoint, + responseStatusCode, + responseBody, + failureCause.message + ) } - - logger.log( - logLevel, - message, - maskedEndpoint, - responseStatusCode, - responseBody, - failureCause?.message - ) } } diff --git a/jvm-libs/generic/logging/src/test/kotlin/net/consensys/linea/logging/MinimalInLineJsonRpcLoggerTest.kt b/jvm-libs/generic/logging/src/test/kotlin/net/consensys/linea/logging/MinimalInLineJsonRpcLoggerTest.kt index 680ab3111..dc3dd24b0 100644 --- a/jvm-libs/generic/logging/src/test/kotlin/net/consensys/linea/logging/MinimalInLineJsonRpcLoggerTest.kt +++ b/jvm-libs/generic/logging/src/test/kotlin/net/consensys/linea/logging/MinimalInLineJsonRpcLoggerTest.kt @@ -36,7 +36,7 @@ class MinimalInLineJsonRpcLoggerTest { fun `logRequest logs request with correct level and format`() { minimalInLineJsonRpcLogger.logRequest("testEndpoint", jsonRequestBody) - verify(logger).log(eq(Level.DEBUG), eq("--> {} {}"), eq("testEndpoint"), eq(jsonRequestBody), eq(null), eq(null)) + verify(logger).log(eq(Level.DEBUG), eq("--> {} {}"), eq("testEndpoint"), eq(jsonRequestBody)) } @Test @@ -63,8 +63,7 @@ class MinimalInLineJsonRpcLoggerTest { eq("<-- {} {} {}"), eq("testEndpoint"), eq(200), - eq(jsonSuccessResponse), - eq(null) + eq(jsonSuccessResponse) ) } @@ -73,7 +72,7 @@ class MinimalInLineJsonRpcLoggerTest { val exception = RuntimeException("Test exception") minimalInLineJsonRpcLogger.logResponse("testEndpoint", 500, jsonRequestBody, jsonErrorResponse, exception) - verify(logger).log(eq(Level.WARN), eq("--> {} {}"), eq("testEndpoint"), eq(jsonRequestBody), eq(null), eq(null)) + verify(logger).log(eq(Level.WARN), eq("--> {} {}"), eq("testEndpoint"), eq(jsonRequestBody)) verify(logger).log( eq(Level.WARN), eq("<-- {} {} {} failed with error={}"), diff --git a/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDe.kt b/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDe.kt new file mode 100644 index 000000000..533d0abb1 --- /dev/null +++ b/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDe.kt @@ -0,0 +1,21 @@ +package build.linea.s11n.jackson + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JsonDeserializer +import com.fasterxml.jackson.databind.JsonSerializer +import com.fasterxml.jackson.databind.SerializerProvider +import kotlinx.datetime.Instant + +object InstantAsHexNumberSerializer : JsonSerializer() { + override fun serialize(value: Instant, gen: JsonGenerator, serializers: SerializerProvider) { + gen.writeString("0x${value.epochSeconds.toString(16)}") + } +} + +object InstantAsHexNumberDeserializer : JsonDeserializer() { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Instant { + return Instant.fromEpochSeconds(p.text.replace("0x", "").toLong(16)) + } +} diff --git a/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantISO8601SerDe.kt b/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantISO8601SerDe.kt index 3c1d671ec..f16752206 100644 --- a/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantISO8601SerDe.kt +++ b/jvm-libs/generic/serialization/jackson/src/main/kotlin/build/linea/s11n/jackson/InstantISO8601SerDe.kt @@ -14,7 +14,6 @@ object InstantISO8601Serializer : JsonSerializer() { } } -// To uncomment and add the tests when necessary object InstantISO8601Deserializer : JsonDeserializer() { override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Instant { return Instant.parse(p.text) diff --git a/jvm-libs/generic/serialization/jackson/src/test/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDeTest.kt b/jvm-libs/generic/serialization/jackson/src/test/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDeTest.kt new file mode 100644 index 000000000..16b702b9b --- /dev/null +++ b/jvm-libs/generic/serialization/jackson/src/test/kotlin/build/linea/s11n/jackson/InstantAsHexNumberSerDeTest.kt @@ -0,0 +1,56 @@ +package build.linea.s11n.jackson + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import kotlinx.datetime.Instant +import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +class InstantAsHexNumberSerDeTest { + private lateinit var objectMapper: ObjectMapper + + @BeforeEach + fun setUp() { + objectMapper = jacksonObjectMapper() + .registerModules( + SimpleModule().apply { + this.addSerializer(Instant::class.java, InstantAsHexNumberSerializer) + this.addDeserializer(Instant::class.java, InstantAsHexNumberDeserializer) + } + ) + } + + @Test + fun instantSerDeDeSerialization() { + data class SomeObject( + // Int + val instantNull: Instant? = null, + // 2021-01-02T09:00:45Z UTC, + val instantUTC: Instant = Instant.fromEpochSeconds(1609578045), + // 2021-07-01T08:00:45Z UTC + val instantUTCDST: Instant = Instant.fromEpochSeconds(1625126445), + // 2021-01-02T09:00:45+01:30 UTC+01:30, + val instantUTCPlus: Instant = Instant.fromEpochSeconds(1609572645), + // 2021-01-02T09:00:45-01:30" UTC-01:30 + val instantUTCMinus: Instant = Instant.fromEpochSeconds(1609583445) + ) + + val expectedJson = """ + { + "instantNull": null, + "instantUTC": "0x5ff0363d", + "instantUTCDST": "0x60dd762d", + "instantUTCPlus": "0x5ff02125", + "instantUTCMinus": "0x5ff04b55" + } + """.trimIndent() + + // assert serialization + assertThatJson(objectMapper.writeValueAsString(SomeObject())).isEqualTo(expectedJson) + + // assert deserialization + assertThatJson(objectMapper.readValue(expectedJson, SomeObject::class.java)).isEqualTo(SomeObject()) + } +} diff --git a/jvm-libs/linea/besu-libs/build.gradle b/jvm-libs/linea/besu-libs/build.gradle index e9b797c88..4c91d9662 100644 --- a/jvm-libs/linea/besu-libs/build.gradle +++ b/jvm-libs/linea/besu-libs/build.gradle @@ -3,27 +3,30 @@ plugins { id 'java-library' } -def besuArtifactGroup="org.hyperledger.besu" +//def besuArtifactGroup="org.hyperledger.besu" +//def besuVersion=libs.versions.besu.get() +def besuArtifactGroup="io.consensys.linea-besu" +def besuVersion="24.12-develop-2098dd2" dependencies { - api("${besuArtifactGroup}:besu-datatypes:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}:besu-datatypes:${besuVersion}") { transitive = false } - api("${besuArtifactGroup}:evm:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}:evm:${besuVersion}") { transitive = false } - api("${besuArtifactGroup}.internal:core:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}.internal:core:${besuVersion}") { transitive = false } - api("${besuArtifactGroup}.internal:algorithms:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}.internal:algorithms:${besuVersion}") { transitive = false } - api("${besuArtifactGroup}:plugin-api:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}:plugin-api:${besuVersion}") { transitive = false } - api("${besuArtifactGroup}.internal:rlp:${libs.versions.besu.get()}") { + api("${besuArtifactGroup}.internal:rlp:${besuVersion}") { transitive = false } @@ -34,4 +37,11 @@ dependencies { api("io.tmio:tuweni-units:${libs.versions.tuweni.get()}") { transitive = false } + + implementation("org.bouncycastle:bcpkix-jdk18on:${libs.versions.bouncycastle.get()}") { + because "necessary for besu Transaction object that verifies signatures" + } + implementation("org.bouncycastle:bcprov-jdk18on:${libs.versions.bouncycastle.get()}") { + because "necessary for besu Transaction object that verifies signatures" + } } diff --git a/jvm-libs/linea/besu-rlp-and-mappers/build.gradle b/jvm-libs/linea/besu-rlp-and-mappers/build.gradle index 3e1576a6b..7e3bbea5c 100644 --- a/jvm-libs/linea/besu-rlp-and-mappers/build.gradle +++ b/jvm-libs/linea/besu-rlp-and-mappers/build.gradle @@ -7,5 +7,8 @@ dependencies { api(project(':jvm-libs:generic:extensions:futures')) api(project(':jvm-libs:linea:core:domain-models')) api(project(':jvm-libs:linea:besu-libs')) + implementation("org.slf4j:slf4j-api:${libs.versions.slf4j.get()}") { + because("Besu RLP uses SLF4J") + } api "io.vertx:vertx-core" } diff --git a/jvm-libs/linea/blob-compressor/build.gradle b/jvm-libs/linea/blob-compressor/build.gradle index 647c19cd8..68139ec08 100644 --- a/jvm-libs/linea/blob-compressor/build.gradle +++ b/jvm-libs/linea/blob-compressor/build.gradle @@ -11,7 +11,11 @@ dependencies { implementation project(":jvm-libs:generic:extensions:kotlin") implementation "org.apache.logging.log4j:log4j-api:${libs.versions.log4j.get()}" implementation "org.apache.logging.log4j:log4j-core:${libs.versions.log4j.get()}" + testImplementation project(":jvm-libs:linea:blob-shnarf-calculator") + testFixturesImplementation project(':jvm-libs:linea:besu-libs') + testFixturesImplementation project(':jvm-libs:linea:besu-rlp-and-mappers') + testFixturesImplementation(project(":jvm-libs:linea:testing:file-system")) } jar { diff --git a/jvm-libs/linea/blob-compressor/src/main/kotlin/linea/blob/BlobCompressor.kt b/jvm-libs/linea/blob-compressor/src/main/kotlin/linea/blob/BlobCompressor.kt index dc272c896..58f36cccf 100644 --- a/jvm-libs/linea/blob-compressor/src/main/kotlin/linea/blob/BlobCompressor.kt +++ b/jvm-libs/linea/blob-compressor/src/main/kotlin/linea/blob/BlobCompressor.kt @@ -24,6 +24,12 @@ interface BlobCompressor { fun getCompressedData(): ByteArray fun reset() + fun getCompressedDataAndReset(): ByteArray { + val compressedData = getCompressedData() + reset() + return compressedData + } + data class AppendResult( // returns false if last chunk would go over dataLimit. Does not append last block. val blockAppended: Boolean, diff --git a/jvm-libs/linea/blob-compressor/src/test/kotlin/linea/blob/GoBackedBlobCompressorTest.kt b/jvm-libs/linea/blob-compressor/src/test/kotlin/linea/blob/GoBackedBlobCompressorTest.kt index 83e3cd30d..faf20dd1b 100644 --- a/jvm-libs/linea/blob-compressor/src/test/kotlin/linea/blob/GoBackedBlobCompressorTest.kt +++ b/jvm-libs/linea/blob-compressor/src/test/kotlin/linea/blob/GoBackedBlobCompressorTest.kt @@ -12,7 +12,7 @@ import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) class GoBackedBlobCompressorTest { companion object { - private const val DATA_LIMIT = 16 * 1024 + private const val DATA_LIMIT = 24 * 1024 private val TEST_DATA = CompressorTestData.blocksRlpEncoded private val compressor = GoBackedBlobCompressor.getInstance(BlobCompressorVersion.V0_1_0, DATA_LIMIT.toUInt()) } @@ -41,14 +41,20 @@ class GoBackedBlobCompressorTest { @Test fun `test compression data limit exceeded`() { - val blocks = TEST_DATA.iterator() + var blocks = TEST_DATA.iterator() var result = compressor.appendBlock(blocks.next()) - while (result.blockAppended && blocks.hasNext()) { + // at least one block should be appended + assertThat(result.blockAppended).isTrue() + while (result.blockAppended) { val blockRlp = blocks.next() val canAppend = compressor.canAppendBlock(blockRlp) result = compressor.appendBlock(blockRlp) // assert consistency between canAppendBlock and appendBlock assertThat(canAppend).isEqualTo(result.blockAppended) + if (!blocks.hasNext()) { + // recompress again, until the limit is reached + blocks = TEST_DATA.iterator() + } } assertThat(result.blockAppended).isFalse() assertThat(result.compressedSizeBefore).isGreaterThan(0) diff --git a/jvm-libs/linea/blob-compressor/src/test/kotlin/net/consensys/linea/blob/GoNativeCompressorAndShnarfCalculatorIntTest.kt b/jvm-libs/linea/blob-compressor/src/test/kotlin/net/consensys/linea/blob/GoNativeCompressorAndShnarfCalculatorIntTest.kt index 1f58c75b1..efcbb3bb9 100644 --- a/jvm-libs/linea/blob-compressor/src/test/kotlin/net/consensys/linea/blob/GoNativeCompressorAndShnarfCalculatorIntTest.kt +++ b/jvm-libs/linea/blob-compressor/src/test/kotlin/net/consensys/linea/blob/GoNativeCompressorAndShnarfCalculatorIntTest.kt @@ -12,7 +12,7 @@ import java.util.Base64 import kotlin.random.Random class GoNativeCompressorAndShnarfCalculatorIntTest { - private val DATA_LIMIT = 16 * 1024 + private val DATA_LIMIT = 128 * 1024 private lateinit var compressor: GoNativeBlobCompressor private lateinit var shnarfCalculator: GoNativeBlobShnarfCalculator @@ -44,7 +44,7 @@ class GoNativeCompressorAndShnarfCalculatorIntTest { @Test fun `compressed size estimation should be consistent with blob maker output`() { - testCompressedSizeSstimationIsConsistentWithBlobMakerOutput() + testCompressedSizeEstimationIsConsistentWithBlobMakerOutput() } } @@ -72,7 +72,7 @@ class GoNativeCompressorAndShnarfCalculatorIntTest { @Test fun `compressed size estimation should be consistent with blob maker output`() { - testCompressedSizeSstimationIsConsistentWithBlobMakerOutput() + testCompressedSizeEstimationIsConsistentWithBlobMakerOutput() } } @@ -201,7 +201,7 @@ class GoNativeCompressorAndShnarfCalculatorIntTest { resultAsserterFn(result) } - fun testCompressedSizeSstimationIsConsistentWithBlobMakerOutput() { + fun testCompressedSizeEstimationIsConsistentWithBlobMakerOutput() { val block = CompressorTestData.blocksRlpEncoded.first() // Write the block to the blob maker and get the effective compressed size @@ -225,6 +225,6 @@ class GoNativeCompressorAndShnarfCalculatorIntTest { // min compressed size should always be strictly bigger than the size returned // by the blob maker minus the header size - assertTrue((compressedSizeWithHeader - estimatedHeaderSizePacked) < compressedSize) + assertThat(compressedSizeWithHeader - estimatedHeaderSizePacked).isLessThanOrEqualTo(compressedSize) } } diff --git a/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/CompressorTestData.kt b/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/CompressorTestData.kt index e284425ef..92ffb697a 100644 --- a/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/CompressorTestData.kt +++ b/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/CompressorTestData.kt @@ -1,33 +1,13 @@ package net.consensys.linea.nativecompressor -import java.nio.ByteBuffer -import java.nio.ByteOrder +import linea.rlp.RLP object CompressorTestData { - val blocksRlpEncoded: Array = loadTestData() + val blocksRlpEncoded: List = RLP.decodeList(readResourcesFile("blocks_rlp.bin")) - private fun loadTestData(): Array { - val data = Thread.currentThread().getContextClassLoader().getResourceAsStream("rlp_blocks.bin")!!.readAllBytes() - - // first 4 bytes are the number of blocks - val numBlocks = ByteBuffer.wrap(data, 0, 4).order(ByteOrder.LITTLE_ENDIAN).int - - // the rest of the file is the blocks - // (we repeat them to fill more data) - val blocks = Array(numBlocks * 2) { ByteArray(0) } - - for (j in 0 until 2) { - var offset = 4 - for (i in 0 until numBlocks) { - // first 4 bytes are the length of the block - val blockLen = ByteBuffer.wrap(data, offset, 4).order(ByteOrder.LITTLE_ENDIAN).int - - // the rest of the block is the block - blocks[i + j * numBlocks] = ByteArray(blockLen) - System.arraycopy(data, offset + 4, blocks[i + j * numBlocks], 0, blockLen) - offset += 4 + blockLen - } - } - return blocks + private fun readResourcesFile(fileName: String): ByteArray { + return Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName) + ?.readAllBytes() + ?: throw IllegalArgumentException("File not found in jar resources: file=$fileName") } } diff --git a/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/TestDataGeneratorHelper.kt b/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/TestDataGeneratorHelper.kt new file mode 100644 index 000000000..47d9729ce --- /dev/null +++ b/jvm-libs/linea/blob-compressor/src/testFixtures/kotlin/net/consensys/linea/nativecompressor/TestDataGeneratorHelper.kt @@ -0,0 +1,70 @@ +package net.consensys.linea.nativecompressor + +import io.vertx.core.json.JsonObject +import linea.rlp.RLP +import net.consensys.decodeHex +import net.consensys.encodeHex +import net.consensys.linea.testing.filesystem.getPathTo +import org.hyperledger.besu.ethereum.core.Block +import java.nio.file.Files +import java.nio.file.Path + +fun loadBlocksFromProverRequests( + proverExecutionRequestsFolder: Path +): List> { + val blocks = Files + .list(proverExecutionRequestsFolder) + .toList() + .map { file -> + JsonObject(Files.readString(file)) + .getJsonArray("blocksData") + .map { block -> + block as JsonObject + // block RLP encoded + val rlp = block.getString("rlp").decodeHex() + RLP.decodeBlockWithMainnetFunctions(rlp) to rlp + } + } + .toList() + .flatten() + return blocks + .sortedBy { it.first.header.number } + .also { + it.forEach { + println("block=${it.first.header} rlp=${it.second.encodeHex()}") + } + } +} + +fun generateEncodeBlocksToBinaryFromProverRequests( + proverExecutionRequestsFolder: Path, + outputFilePath: Path +) { + val blocks = loadBlocksFromProverRequests(proverExecutionRequestsFolder) + Files.write(outputFilePath, RLP.encodeList(blocks.map { it.second })) +} + +fun loadBlocksRlpEncoded( + binFile: Path +): List { + return RLP.decodeList(Files.readAllBytes(binFile)) +} + +fun main() { + val proverExecutionRequestsDir = getPathTo("tmp/local/prover/v3/execution/requests-done/") + val destFile = getPathTo("jvm-libs/linea/blob-compressor/src/testFixtures/resources") + .resolve("blocks_rlp.bin") + + generateEncodeBlocksToBinaryFromProverRequests( + proverExecutionRequestsDir, + destFile + ) + + // Just a visual indicator that it can read/decode again + println("\n\n") + loadBlocksRlpEncoded(destFile) + .map(RLP::decodeBlockWithMainnetFunctions) + .forEach { + println("block=$it") + } +} diff --git a/jvm-libs/linea/blob-compressor/src/testFixtures/resources/blocks_rlp.bin b/jvm-libs/linea/blob-compressor/src/testFixtures/resources/blocks_rlp.bin new file mode 100644 index 000000000..dc13c4de8 Binary files /dev/null and b/jvm-libs/linea/blob-compressor/src/testFixtures/resources/blocks_rlp.bin differ diff --git a/jvm-libs/linea/blob-compressor/src/testFixtures/resources/rlp_blocks.bin b/jvm-libs/linea/blob-compressor/src/testFixtures/resources/rlp_blocks.bin deleted file mode 100644 index 82c04c3ff..000000000 Binary files a/jvm-libs/linea/blob-compressor/src/testFixtures/resources/rlp_blocks.bin and /dev/null differ diff --git a/jvm-libs/linea/blob-decompressor/src/test/kotlin/net/consensys/linea/blob/GoNativeBlobDecompressorTest.kt b/jvm-libs/linea/blob-decompressor/src/test/kotlin/net/consensys/linea/blob/GoNativeBlobDecompressorTest.kt index 0d1454d8e..946575b99 100644 --- a/jvm-libs/linea/blob-decompressor/src/test/kotlin/net/consensys/linea/blob/GoNativeBlobDecompressorTest.kt +++ b/jvm-libs/linea/blob-decompressor/src/test/kotlin/net/consensys/linea/blob/GoNativeBlobDecompressorTest.kt @@ -7,7 +7,7 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test class GoNativeBlobDecompressorTest { - private val blobCompressedLimit = 10 * 1024 + private val blobCompressedLimit = 30 * 1024 private lateinit var compressor: GoNativeBlobCompressor private lateinit var decompressor: BlobDecompressor diff --git a/jvm-libs/linea/clients/interfaces/src/main/kotlin/linea/EthLogsSearcher.kt b/jvm-libs/linea/clients/interfaces/src/main/kotlin/linea/EthLogsSearcher.kt new file mode 100644 index 000000000..c2b524c7d --- /dev/null +++ b/jvm-libs/linea/clients/interfaces/src/main/kotlin/linea/EthLogsSearcher.kt @@ -0,0 +1,32 @@ +package linea + +import net.consensys.linea.BlockParameter +import tech.pegasys.teku.infrastructure.async.SafeFuture + +enum class SearchDirection { + FORWARD, + BACKWARD +} + +interface EthLogsSearcher { + /** + * Shall search for the Log until shallContinueToSearchPredicate returns null. + * if fromBlock..toBlock range is too large, it shall break into smaller chunks + * and perform a binary search; + */ + fun findLog( + fromBlock: BlockParameter, + toBlock: BlockParameter, + chunkSize: Int = 1000, + address: String, + topics: List, + shallContinueToSearch: (build.linea.domain.EthLog) -> SearchDirection? // null means stop searching + ): SafeFuture + + fun getLogs( + fromBlock: BlockParameter, + toBlock: BlockParameter, + address: String, + topics: List + ): SafeFuture> +} diff --git a/jvm-libs/linea/clients/linea-l1-contract-client/src/main/kotlin/build/linea/contract/l1/Web3JLineaRollupSmartContractClientReadOnly.kt b/jvm-libs/linea/clients/linea-l1-contract-client/src/main/kotlin/build/linea/contract/l1/Web3JLineaRollupSmartContractClientReadOnly.kt index 0d74736ef..34c05faef 100644 --- a/jvm-libs/linea/clients/linea-l1-contract-client/src/main/kotlin/build/linea/contract/l1/Web3JLineaRollupSmartContractClientReadOnly.kt +++ b/jvm-libs/linea/clients/linea-l1-contract-client/src/main/kotlin/build/linea/contract/l1/Web3JLineaRollupSmartContractClientReadOnly.kt @@ -63,8 +63,7 @@ open class Web3JLineaRollupSmartContractClientReadOnly( } as T } - protected val smartContractVersionCache: AtomicReference = - AtomicReference(fetchSmartContractVersion().get()) + private val smartContractVersionCache = AtomicReference(null) private fun getSmartContractVersion(): SafeFuture { return if (smartContractVersionCache.get() == LineaContractVersion.V6) { @@ -73,7 +72,9 @@ open class Web3JLineaRollupSmartContractClientReadOnly( } else { fetchSmartContractVersion() .thenPeek { contractLatestVersion -> - if (contractLatestVersion != smartContractVersionCache.get()) { + if (smartContractVersionCache.get() != null && + contractLatestVersion != smartContractVersionCache.get() + ) { log.info( "Smart contract upgraded: prevVersion={} upgradedVersion={}", smartContractVersionCache.get(), diff --git a/jvm-libs/linea/core/domain-models/src/main/kotlin/linea/domain/RetryConfig.kt b/jvm-libs/linea/core/domain-models/src/main/kotlin/linea/domain/RetryConfig.kt new file mode 100644 index 000000000..7b9dd7fa2 --- /dev/null +++ b/jvm-libs/linea/core/domain-models/src/main/kotlin/linea/domain/RetryConfig.kt @@ -0,0 +1,32 @@ +package linea.domain + +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds + +data class RetryConfig( + val maxRetries: UInt? = null, + val timeout: Duration? = null, + val backoffDelay: Duration = 100.milliseconds, + val failuresWarningThreshold: UInt = 0u +) { + val isRetryDisabled = maxRetries == 0u || timeout == 0.milliseconds + val isRetryEnabled: Boolean = !isRetryDisabled + + init { + maxRetries?.also { + require(maxRetries >= failuresWarningThreshold) { + "maxRetries must be greater or equal than failuresWarningThreshold." + + " maxRetries=$maxRetries, failuresWarningThreshold=$failuresWarningThreshold" + } + } + timeout?.also { + require(timeout > 0.milliseconds) { "timeout must be >= 1ms. value=$timeout" } + } + + require(backoffDelay > 0.milliseconds) { "backoffDelay must be >= 1ms. value=$timeout" } + } + + companion object { + val noRetries = RetryConfig(maxRetries = 0u) + } +} diff --git a/jvm-libs/linea/core/domain-models/src/test/kotlin/linea/domain/RetryConfigTest.kt b/jvm-libs/linea/core/domain-models/src/test/kotlin/linea/domain/RetryConfigTest.kt new file mode 100644 index 000000000..16a8afeae --- /dev/null +++ b/jvm-libs/linea/core/domain-models/src/test/kotlin/linea/domain/RetryConfigTest.kt @@ -0,0 +1,58 @@ +package linea.domain + +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.Test +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds + +class RetryConfigTest { + @Test + fun `should support no retries`() { + val notRetryConfig = RetryConfig(maxRetries = 0u) + assertThat(notRetryConfig.isRetryDisabled).isTrue() + assertThat(notRetryConfig.isRetryEnabled).isFalse() + assertThat(notRetryConfig.timeout).isNull() + assertThat(notRetryConfig.maxRetries).isEqualTo(0u) + assertThat(notRetryConfig.failuresWarningThreshold).isEqualTo(0u) + assertThat(RetryConfig.noRetries).isEqualTo(notRetryConfig) + } + + @Test + fun `should support retries with timeout only`() { + val notRetryConfig = RetryConfig(timeout = 2.seconds) + assertThat(notRetryConfig.isRetryDisabled).isFalse() + assertThat(notRetryConfig.isRetryEnabled).isTrue() + assertThat(notRetryConfig.timeout).isEqualTo(2.seconds) + assertThat(notRetryConfig.maxRetries).isNull() + assertThat(notRetryConfig.failuresWarningThreshold).isEqualTo(0u) + } + + @Test + fun `should support retries with maxRetries only`() { + val notRetryConfig = RetryConfig(maxRetries = 10u) + assertThat(notRetryConfig.isRetryDisabled).isFalse() + assertThat(notRetryConfig.isRetryEnabled).isTrue() + assertThat(notRetryConfig.timeout).isNull() + assertThat(notRetryConfig.maxRetries).isEqualTo(10u) + assertThat(notRetryConfig.failuresWarningThreshold).isEqualTo(0u) + } + + @Test + fun `should support retries with timeout and maxRetries`() { + val notRetryConfig = RetryConfig(maxRetries = 10u, timeout = 20.seconds, backoffDelay = 1500.milliseconds) + assertThat(notRetryConfig.isRetryDisabled).isFalse() + assertThat(notRetryConfig.isRetryEnabled).isTrue() + assertThat(notRetryConfig.timeout).isEqualTo(20.seconds) + assertThat(notRetryConfig.maxRetries).isEqualTo(10u) + assertThat(notRetryConfig.backoffDelay).isEqualTo(1500.milliseconds) + assertThat(notRetryConfig.failuresWarningThreshold).isEqualTo(0u) + } + + @Test + fun `should throw exception when timeout is less than 1ms`() { + assertThatThrownBy { + RetryConfig(timeout = 0.milliseconds) + }.isInstanceOf(IllegalArgumentException::class.java) + } +} diff --git a/jvm-libs/linea/testing/file-system/src/main/kotlin/net/consensys/linea/testing/filesystem/Files.kt b/jvm-libs/linea/testing/file-system/src/main/kotlin/net/consensys/linea/testing/filesystem/Files.kt index 7d0d56a16..a05d35969 100644 --- a/jvm-libs/linea/testing/file-system/src/main/kotlin/net/consensys/linea/testing/filesystem/Files.kt +++ b/jvm-libs/linea/testing/file-system/src/main/kotlin/net/consensys/linea/testing/filesystem/Files.kt @@ -39,5 +39,5 @@ fun getPathTo( lookupParentDir: Boolean = true ): Path { return findPathTo(targetFileOrDir, lookupDir, lookupParentDir) - ?: throw IllegalArgumentException("Could not find file or directory in path: $lookupDir or its parent directories") + ?: throw IllegalArgumentException("Could not find $targetFileOrDir in path: $lookupDir or its parent directories") } diff --git a/jvm-libs/linea/testing/l1-blob-and-proof-submission/build.gradle b/jvm-libs/linea/testing/l1-blob-and-proof-submission/build.gradle index 86a3fbd41..0679f81a7 100644 --- a/jvm-libs/linea/testing/l1-blob-and-proof-submission/build.gradle +++ b/jvm-libs/linea/testing/l1-blob-and-proof-submission/build.gradle @@ -8,6 +8,8 @@ dependencies { api(project(':jvm-libs:linea:core:domain-models')) implementation(project(':jvm-libs:generic:extensions:kotlin')) implementation(project(':jvm-libs:linea:testing:file-system')) + implementation(project(':jvm-libs:linea:web3j-extensions')) + implementation(testFixtures(project(':jvm-libs:linea:web3j-extensions'))) implementation(project(':coordinator:clients:prover-client:serialization')) implementation(testFixtures(project(":coordinator:core"))) } diff --git a/jvm-libs/linea/testing/l1-blob-and-proof-submission/src/main/kotlin/net/consensys/linea/testing/submission/SubmissionTestHelper.kt b/jvm-libs/linea/testing/l1-blob-and-proof-submission/src/main/kotlin/net/consensys/linea/testing/submission/SubmissionTestHelper.kt index a6b95d316..9934ad45f 100644 --- a/jvm-libs/linea/testing/l1-blob-and-proof-submission/src/main/kotlin/net/consensys/linea/testing/submission/SubmissionTestHelper.kt +++ b/jvm-libs/linea/testing/l1-blob-and-proof-submission/src/main/kotlin/net/consensys/linea/testing/submission/SubmissionTestHelper.kt @@ -1,8 +1,11 @@ package net.consensys.linea.testing.submission +import linea.web3j.waitForTxReceipt import net.consensys.zkevm.coordinator.clients.smartcontract.LineaRollupSmartContractClient import net.consensys.zkevm.domain.Aggregation -import tech.pegasys.teku.infrastructure.async.SafeFuture +import org.web3j.protocol.Web3j +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes /** * Submits blobs respecting aggregation boundaries @@ -18,10 +21,9 @@ fun submitBlobs( return aggregationsAndBlobs .map { (_, aggBlobs) -> val blobChunks = aggBlobs.chunked(blobChunksSize) - blobChunks.map { blobs -> contractClient.submitBlobs(blobs, gasPriceCaps = null) } + blobChunks.map { blobs -> contractClient.submitBlobs(blobs, gasPriceCaps = null).get() } } .flatten() - .let { SafeFuture.collectAll(it.stream()).get() } } /** @@ -34,13 +36,13 @@ data class SubmissionTxHashes( val blobTxHashes: List, val aggregationTxHashes: List ) + fun submitBlobsAndAggregations( contractClient: LineaRollupSmartContractClient, aggregationsAndBlobs: List, blobChunksSize: Int = 6 ): SubmissionTxHashes { val blobSubmissionTxHashes = submitBlobs(contractClient, aggregationsAndBlobs, blobChunksSize) - return aggregationsAndBlobs .filter { it.aggregation != null } .mapIndexed { index, (aggregation, aggBlobs) -> @@ -53,8 +55,33 @@ fun submitBlobsAndAggregations( parentL1RollingHash = parentAgg?.aggregationProof?.l1RollingHash ?: ByteArray(32), parentL1RollingHashMessageNumber = parentAgg?.aggregationProof?.l1RollingHashMessageNumber ?: 0L, gasPriceCaps = null - ) + ).get() } - .let { SafeFuture.collectAll(it.stream()).get() } .let { SubmissionTxHashes(blobSubmissionTxHashes, it) } } + +fun submitBlobsAndAggregationsAndWaitExecution( + contractClient: LineaRollupSmartContractClient, + aggregationsAndBlobs: List, + blobChunksSize: Int = 6, + l1Web3jClient: Web3j, + waitTimeout: Duration = 2.minutes +) { + val submissionTxHashes = submitBlobsAndAggregations( + contractClient = contractClient, + aggregationsAndBlobs = aggregationsAndBlobs, + blobChunksSize = blobChunksSize + ) + + l1Web3jClient.waitForTxReceipt( + txHash = submissionTxHashes.aggregationTxHashes.last(), + timeout = waitTimeout + ).also { txReceipt -> + if (txReceipt.status != "0x1") { + val lastAggregation = aggregationsAndBlobs.findLast { it.aggregation != null }!!.aggregation!! + throw IllegalStateException( + "latest finalization=${lastAggregation.intervalString()} failed on L1. receipt=$txReceipt" + ) + } + } +} diff --git a/jvm-libs/linea/web3j-extensions/build.gradle b/jvm-libs/linea/web3j-extensions/build.gradle index 16d1caf69..43b311d77 100644 --- a/jvm-libs/linea/web3j-extensions/build.gradle +++ b/jvm-libs/linea/web3j-extensions/build.gradle @@ -9,17 +9,20 @@ description="Web3j extensions for Linea" dependencies { api "org.web3j:core:${libs.versions.web3j.get()}" api project(':jvm-libs:linea:core:domain-models') + api project(':jvm-libs:linea:clients:interfaces') api project(':jvm-libs:generic:logging') + api project(":jvm-libs:generic:extensions:kotlin") + api project(':jvm-libs:generic:extensions:futures') api project(':jvm-libs:linea:besu-libs') - implementation project(":jvm-libs:generic:extensions:kotlin") - implementation project(":jvm-libs:generic:extensions:futures") implementation "tech.pegasys.teku.internal:bytes:${libs.versions.teku.get()}" implementation "tech.pegasys.teku.internal:jackson:${libs.versions.teku.get()}" implementation "tech.pegasys.teku.internal:unsigned:${libs.versions.teku.get()}" + testImplementation(testFixtures(project(":jvm-libs:generic:json-rpc"))) testImplementation "org.apache.logging.log4j:log4j-slf4j2-impl:${libs.versions.log4j.get()}" testImplementation "com.fasterxml.jackson.core:jackson-annotations:${libs.versions.jackson.get()}" testImplementation "com.fasterxml.jackson.core:jackson-databind:${libs.versions.jackson.get()}" + testImplementation "com.github.tomakehurst:wiremock-jre8:${libs.versions.wiremock.get()}" testImplementation project(":jvm-libs:linea:besu-rlp-and-mappers") } diff --git a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JLogsClient.kt b/jvm-libs/linea/web3j-extensions/src/main/kotlin/build/linea/web3j/Web3JLogsClient.kt similarity index 98% rename from coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JLogsClient.kt rename to jvm-libs/linea/web3j-extensions/src/main/kotlin/build/linea/web3j/Web3JLogsClient.kt index ed24214b7..a56b92e94 100644 --- a/coordinator/clients/smart-contract-client/src/main/kotlin/net/consensys/linea/contract/Web3JLogsClient.kt +++ b/jvm-libs/linea/web3j-extensions/src/main/kotlin/build/linea/web3j/Web3JLogsClient.kt @@ -1,4 +1,4 @@ -package net.consensys.linea.contract +package build.linea.web3j import io.vertx.core.Vertx import net.consensys.linea.async.AsyncRetryer diff --git a/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/SearchCursor.kt b/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/SearchCursor.kt new file mode 100644 index 000000000..0b4eddcfb --- /dev/null +++ b/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/SearchCursor.kt @@ -0,0 +1,87 @@ +package linea.web3j + +import linea.SearchDirection + +internal fun rangeChunks( + start: ULong, + end: ULong, + chunkSize: Int +): List { + return (start..end step chunkSize.toLong()) + .map { chunkStart -> + val chunkEnd = (chunkStart + chunkSize.toUInt() - 1u).coerceAtMost(end) + ULongRange(chunkStart, chunkEnd) + } +} + +/** + * SearchCursor is a helper class to iterate over a range of ULong values in a binary search manner. + * When search is not provided returns the next unsearched chunk without moving left or right cursors because + * no direction is provided, but flags the chunk as searched to not go over again. + * + * This caveat is because when searching for EthLogs on L1, a blockInterval (represend by chunk here) may not have logs + * so the search predicate cannot tell what direction to go next, so we need to flag the chunk as searched and try the + * next chunk. + */ +internal class SearchCursor( + val from: ULong, + val to: ULong, + val chunkSize: Int +) { + private data class Chunk(val interval: Pair, var searched: Boolean = false) + + private val searchChunks = rangeChunks(from, to, chunkSize) + .map { chunkInterval -> Chunk(chunkInterval.first to chunkInterval.endInclusive, searched = false) } + private var left = 0 + private var right = searchChunks.size - 1 + private var prevCursor: Int? = null + + @Synchronized + fun next(searchDirection: SearchDirection?): Pair? { + return if (left > right) { + null + } else { + if (prevCursor == null) { + // 1st call, lets start in the middle + val mid = left + (right - left) / 2 + searchChunks[mid] to mid + } else { + if (searchDirection == null) { + findLeftNextUnsearchedChunkAndUpdateLeftLimit() + } else { + if (searchDirection == SearchDirection.FORWARD) { + left = prevCursor!! + 1 + } else { + right = prevCursor!! - 1 + } + if (left > right) { + null + } else { + val mid = left + (right - left) / 2 + val chunk = searchChunks[mid] + if (chunk.searched) { + // we have already searched this chunk, lets find next unsearched + findLeftNextUnsearchedChunkAndUpdateLeftLimit() + } else { + chunk to mid + } + } + } + }?.let { (chunk, index) -> + prevCursor = index + chunk.searched = true + chunk.interval + } + } + } + + private fun findLeftNextUnsearchedChunkAndUpdateLeftLimit(): Pair? { + for (i in left..right) { + if (!searchChunks[i].searched) { + left = i + return searchChunks[i] to i + } + } + return null + } +} diff --git a/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/Web3JLogsSearcher.kt b/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/Web3JLogsSearcher.kt new file mode 100644 index 000000000..d13dbcf26 --- /dev/null +++ b/jvm-libs/linea/web3j-extensions/src/main/kotlin/linea/web3j/Web3JLogsSearcher.kt @@ -0,0 +1,222 @@ +package linea.web3j + +import build.linea.web3j.domain.toDomain +import build.linea.web3j.domain.toWeb3j +import io.vertx.core.Vertx +import linea.EthLogsSearcher +import linea.SearchDirection +import linea.domain.RetryConfig +import net.consensys.linea.BlockParameter +import net.consensys.linea.BlockParameter.Companion.toBlockParameter +import net.consensys.linea.CommonDomainFunctions +import net.consensys.linea.async.AsyncRetryer +import net.consensys.linea.async.toSafeFuture +import net.consensys.toULong +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import org.web3j.protocol.Web3j +import org.web3j.protocol.core.methods.request.EthFilter +import org.web3j.protocol.core.methods.response.EthLog +import org.web3j.protocol.core.methods.response.Log +import tech.pegasys.teku.infrastructure.async.SafeFuture +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds + +private sealed interface SearchResult { + data class ItemFound(val log: build.linea.domain.EthLog) : SearchResult + data class KeepSearching(val direction: SearchDirection) : SearchResult + data object NoResultsInInterval : SearchResult +} + +class Web3JLogsSearcher( + val vertx: Vertx, + val web3jClient: Web3j, + val config: Config = Config(), + val log: Logger = LogManager.getLogger(Web3JLogsSearcher::class.java) +) : EthLogsSearcher { + data class Config( + val backoffDelay: Duration = 100.milliseconds, + val requestRetryConfig: RetryConfig = RetryConfig() + ) + + override fun findLog( + fromBlock: BlockParameter, + toBlock: BlockParameter, + chunkSize: Int, + address: String, + topics: List, + shallContinueToSearch: (build.linea.domain.EthLog) -> SearchDirection? + ): SafeFuture { + require(chunkSize > 0) { "chunkSize=$chunkSize must be greater than 0" } + + return getAbsoluteBlockNumbers(fromBlock, toBlock) + .thenCompose { (start, end) -> + findLogLoop( + start, + end, + chunkSize, + address, + topics, + shallContinueToSearch + ) + } + } + + private fun findLogLoop( + fromBlock: ULong, + toBlock: ULong, + chunkSize: Int, + address: String, + topics: List, + shallContinueToSearchPredicate: (build.linea.domain.EthLog) -> SearchDirection? + ): SafeFuture { + val cursor = SearchCursor(fromBlock, toBlock, chunkSize) + log.trace("searching between blocks={}", CommonDomainFunctions.blockIntervalString(fromBlock, toBlock)) + + var nextChunkToSearch: Pair? = cursor.next(searchDirection = SearchDirection.FORWARD) + return AsyncRetryer.retry( + vertx, + backoffDelay = config.backoffDelay, + stopRetriesPredicate = { it is SearchResult.ItemFound || nextChunkToSearch == null } + ) { + val (chunkStart, chunkEnd) = nextChunkToSearch!! + log.trace("searching in chunk={}", CommonDomainFunctions.blockIntervalString(chunkStart, chunkEnd)) + findLogInInterval(chunkStart, chunkEnd, address, topics, shallContinueToSearchPredicate) + .thenPeek { result -> + if (result is SearchResult.NoResultsInInterval) { + nextChunkToSearch = cursor.next(searchDirection = null) + } else if (result is SearchResult.KeepSearching) { + // need to search in the same chunk + nextChunkToSearch = cursor.next(searchDirection = result.direction) + } + } + }.thenApply { either -> + when (either) { + is SearchResult.ItemFound -> either.log + else -> null + } + } + } + + private fun findLogInInterval( + fromBlock: ULong, + toBlock: ULong, + address: String, + topics: List, + shallContinueToSearchPredicate: (build.linea.domain.EthLog) -> SearchDirection? + ): SafeFuture { + return getLogs( + fromBlock = fromBlock.toBlockParameter(), + toBlock = toBlock.toBlockParameter(), + address = address, + topics = topics + ) + .thenApply { logs -> + if (logs.isEmpty()) { + SearchResult.NoResultsInInterval + } else { + var nextSearchDirection: SearchDirection? = null + val item = logs.find { + nextSearchDirection = shallContinueToSearchPredicate(it) + nextSearchDirection == null + } + if (item != null) { + SearchResult.ItemFound(item) + } else { + SearchResult.KeepSearching(nextSearchDirection!!) + } + } + } + } + + override fun getLogs( + fromBlock: BlockParameter, + toBlock: BlockParameter, + address: String, + topics: List + ): SafeFuture> { + return if (config.requestRetryConfig.isRetryEnabled) { + AsyncRetryer.retry( + vertx = vertx, + backoffDelay = config.requestRetryConfig.backoffDelay, + timeout = config.requestRetryConfig.timeout, + maxRetries = config.requestRetryConfig.maxRetries?.toInt() + ) { + getLogsInternal(fromBlock, toBlock, address, topics) + } + } else { + getLogsInternal(fromBlock, toBlock, address, topics) + } + } + + private fun getLogsInternal( + fromBlock: BlockParameter, + toBlock: BlockParameter, + address: String, + topics: List + ): SafeFuture> { + val ethFilter = EthFilter( + /*fromBlock*/ fromBlock.toWeb3j(), + /*toBlock*/ toBlock.toWeb3j(), + /*address*/ address + ).apply { + topics.forEach { addSingleTopic(it) } + } + + return web3jClient + .ethGetLogs(ethFilter) + .sendAsync() + .toSafeFuture() + .thenCompose { + if (it.hasError()) { + SafeFuture.failedFuture( + RuntimeException( + "json-rpc error: code=${it.error.code} message=${it.error.message} " + + "data=${it.error.data}" + ) + ) + } else { + val logs = if (it.logs != null) { + @Suppress("UNCHECKED_CAST") + (it.logs as List>) + .map { logResult -> + logResult.get().toDomain() + } + } else { + emptyList() + } + + SafeFuture.completedFuture(logs) + } + } + } + + private fun getAbsoluteBlockNumbers( + fromBlock: BlockParameter, + toBlock: BlockParameter + ): SafeFuture> { + return if (fromBlock is BlockParameter.BlockNumber && toBlock is BlockParameter.BlockNumber) { + return SafeFuture.completedFuture(Pair(fromBlock.getNumber(), toBlock.getNumber())) + } else { + AsyncRetryer.retry( + vertx = vertx, + backoffDelay = config.backoffDelay, + stopRetriesPredicate = { (fromBlockResponse, toBlockResponse) -> + fromBlockResponse?.block?.number != null && toBlockResponse?.block?.number != null + }, + action = { + SafeFuture.collectAll( + web3jClient.ethGetBlockByNumber(fromBlock.toWeb3j(), false).sendAsync().toSafeFuture(), + web3jClient.ethGetBlockByNumber(toBlock.toWeb3j(), false).sendAsync().toSafeFuture() + ) + } + ) + .thenApply { (fromBlockResponse, toBlockResponse) -> + Pair( + fromBlockResponse.block.number.toULong(), + toBlockResponse.block.number.toULong() + ) + } + } + } +} diff --git a/coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientIntTest.kt b/jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientIntTest.kt similarity index 99% rename from coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientIntTest.kt rename to jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientIntTest.kt index 2b9c85598..578dc543d 100644 --- a/coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientIntTest.kt +++ b/jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientIntTest.kt @@ -1,4 +1,4 @@ -package net.consensys.linea.contract +package build.linea.web3j import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock.aResponse diff --git a/coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientTest.kt b/jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientTest.kt similarity index 99% rename from coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientTest.kt rename to jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientTest.kt index 06112face..4204c65c3 100644 --- a/coordinator/clients/smart-contract-client/src/test/kotlin/net/consensys/linea/contract/Web3JLogsClientTest.kt +++ b/jvm-libs/linea/web3j-extensions/src/test/kotlin/build/linea/web3j/Web3JLogsClientTest.kt @@ -1,4 +1,4 @@ -package net.consensys.linea.contract +package build.linea.web3j import io.vertx.core.Vertx import org.assertj.core.api.Assertions.assertThat diff --git a/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/SearchCursorTest.kt b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/SearchCursorTest.kt new file mode 100644 index 000000000..4266e6db6 --- /dev/null +++ b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/SearchCursorTest.kt @@ -0,0 +1,191 @@ +package linea.web3j + +import linea.SearchDirection +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class SearchCursorTest { + + @Test + fun `should calculate range chunks correctly`() { + assertThat(rangeChunks(0uL, 50uL, 10)).containsExactly( + 0UL..9UL, + 10UL..19UL, + 20UL..29UL, + 30UL..39UL, + 40UL..49UL, + 50UL..50UL + ) + + assertThat(rangeChunks(0uL, 45uL, 10)).containsExactly( + 0UL..9UL, + 10UL..19UL, + 20UL..29UL, + 30UL..39UL, + 40UL..45UL + ) + } + + @Test + fun `next starts in the middle regardless of direction`() { + assertThat( + SearchCursor( + from = 1uL, + to = 100uL, + chunkSize = 10 + ).next(searchDirection = null) + ).isEqualTo(41UL to 50UL) + assertThat( + SearchCursor( + from = 1uL, + to = 100uL, + chunkSize = 10 + ).next(searchDirection = SearchDirection.FORWARD) + ).isEqualTo(41UL to 50UL) + assertThat( + SearchCursor( + from = 1uL, + to = 100uL, + chunkSize = 10 + ).next(searchDirection = SearchDirection.BACKWARD) + ).isEqualTo(41UL to 50UL) + } + + @Test + fun `next follows binary search when direction is FORWARD`() { + val searchCursor = SearchCursor(from = 1uL, to = 100uL, chunkSize = 10) + + assertThat(searchCursor.next(SearchDirection.FORWARD)).isEqualTo(41UL to 50UL) + assertThat(searchCursor.next(SearchDirection.FORWARD)).isEqualTo(71UL to 80UL) + assertThat(searchCursor.next(SearchDirection.FORWARD)).isEqualTo(81UL to 90UL) + assertThat(searchCursor.next(SearchDirection.FORWARD)).isEqualTo(91UL to 100UL) + } + + @Test + fun `next follows binary search when direction is BACKWARD`() { + val searchCursor = SearchCursor(from = 1uL, to = 100uL, chunkSize = 10) + + assertThat(searchCursor.next(SearchDirection.BACKWARD)).isEqualTo(41UL to 50UL) + assertThat(searchCursor.next(SearchDirection.BACKWARD)).isEqualTo(11UL to 20UL) + assertThat(searchCursor.next(SearchDirection.BACKWARD)).isEqualTo(1UL to 10UL) + } + + @Test + fun `next follows binary search when direction is null`() { + val searchCursor = SearchCursor(from = 1uL, to = 100uL, chunkSize = 10) + + assertThat(searchCursor.next(null)).isEqualTo(41UL to 50UL) + assertThat(searchCursor.next(null)).isEqualTo(1UL to 10UL) + assertThat(searchCursor.next(null)).isEqualTo(11UL to 20UL) + assertThat(searchCursor.next(null)).isEqualTo(21UL to 30UL) + assertThat(searchCursor.next(null)).isEqualTo(31UL to 40UL) + assertThat(searchCursor.next(null)).isEqualTo(51UL to 60UL) + assertThat(searchCursor.next(null)).isEqualTo(61UL to 70UL) + assertThat(searchCursor.next(null)).isEqualTo(71UL to 80UL) + assertThat(searchCursor.next(null)).isEqualTo(81UL to 90UL) + assertThat(searchCursor.next(null)).isEqualTo(91UL to 100UL) + } + + @Test + fun `next iterates over chunks when no direction is provided`() { + val searchCursor = SearchCursor(from = 1uL, to = 100uL, chunkSize = 10) + val chunks = mutableListOf>() + var next = searchCursor.next(searchDirection = null) + + while (next != null) { + chunks.add(next) + next = searchCursor.next(searchDirection = null) + } + + assertThat(chunks.sortedBy { it.first }).containsExactly( + 1UL to 10UL, + 11UL to 20UL, + 21UL to 30UL, + 31UL to 40UL, + 41UL to 50UL, + 51UL to 60UL, + 61UL to 70UL, + 71UL to 80UL, + 81UL to 90UL, + 91UL to 100UL + ) + } + + @Test + fun `next iterates over chunks when no direction is provided and follows direction when provided`() { + val searchCursor = SearchCursor(from = 1uL, to = 200uL, chunkSize = 10) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(91UL to 100UL) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(1UL to 10UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isNull() + } + + @Test + fun `next iterates follows direction without repeating`() { + val searchCursor = SearchCursor(from = 1uL, to = 200uL, chunkSize = 10) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(91UL to 100UL) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(1UL to 10UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(101UL to 110UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isEqualTo(51UL to 60UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(11UL to 20UL) + // This backward is not technically valid in a typical binary search, + // but it is a valid use case for this cursor because when searching for logs + // the predicate can try to go back but search chunks are exhausted + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isNull() + } + + @Test + fun `next iterates follows direction without repeating - forward`() { + val searchCursor = SearchCursor(from = 1uL, to = 200uL, chunkSize = 10) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(91UL to 100UL) + + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(141UL to 150UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(171UL to 180UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(151UL to 160UL) + // This backward is not technically valid in a typical binary search, + // but it is a valid use case for this cursor because when searching for logs + // the predicate can try to go back but search chunks are exhausted + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isNull() + } + + @Test + fun `next iterates follows direction without repeating - forward 2`() { + val searchCursor = SearchCursor(from = 1uL, to = 200uL, chunkSize = 10) + + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(91UL to 100UL) + + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isEqualTo(41UL to 50UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(61UL to 70UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(71UL to 80UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(81UL to 90UL) + assertThat(searchCursor.next(searchDirection = null)).isNull() + // This backward is not technically valid in a typical binary search, + // but it is a valid use case for this cursor because when searching for logs + // the predicate can try to go back but search chunks are exauhsted + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isNull() + } + + @Test + fun `next iterates follows direction without repeating - forward 3`() { + val searchCursor = SearchCursor(from = 0uL, to = 100uL, chunkSize = 5) + // chunks: + // 0..4, 5..9, 10..14, 15..19, 20..24, 25..29, 30..34, 35..39, 40..44, 45..49, + // 50..54, + // 55..59, 60..64, 65..69, 70..74, 75..79, 80..84, 85..89, 90..94, 95..99, 100..100 + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(50UL to 54UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.BACKWARD)).isEqualTo(20UL to 24UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(0UL to 4UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(5UL to 9UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(10UL to 14UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(30UL to 34UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(15UL to 19UL) + assertThat(searchCursor.next(searchDirection = SearchDirection.FORWARD)).isEqualTo(25UL to 29UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(35UL to 39UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(40UL to 44UL) + assertThat(searchCursor.next(searchDirection = null)).isEqualTo(45UL to 49UL) + } +} diff --git a/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/ULongRangesHelperTest.kt b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/ULongRangesHelperTest.kt new file mode 100644 index 000000000..82bd7b2b3 --- /dev/null +++ b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/ULongRangesHelperTest.kt @@ -0,0 +1,117 @@ +package linea.web3j + +import net.consensys.intersection +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal fun generateEffectiveIntervals( + blocksWithLogs: List, + filterFromBlock: ULong, + filterToBlock: ULong +): List { + // if blocksWithLogs is [10..19, 25..29, 40..49] and filter.fromBlock=15 and filter.toBlock=45 + // then we will return logs for blocks [15..19, 25..29, 40..45] + val fromToRange = filterFromBlock..filterToBlock + + return blocksWithLogs + .map { it.intersection(fromToRange) } + .filter { !it.isEmpty() } + .map { range -> (range.first.coerceAtLeast(filterFromBlock))..(range.last.coerceAtMost(filterToBlock)) } +} + +class ULongRangesHelperTest { + + @Test + fun `generateEffectiveIntervals returns effective intervals for given blocks with logs and filter`() { + val blocksWithLogs = listOf(10UL..19UL, 40UL..49UL, 60UL..69UL) + + // before range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 0UL, + filterToBlock = 9UL + ) + .also { + assertThat(it).isEmpty() + } + + // intersect 1st half of range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 0UL, + filterToBlock = 15UL + ) + .also { + assertThat(it).containsExactly(10UL..15UL) + } + // intersect 2st half of range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 15UL, + filterToBlock = 25UL + ) + .also { + assertThat(it).containsExactly(15UL..19UL) + } + + // overlapping single range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 0UL, + filterToBlock = 25UL + ) + .also { + assertThat(it).containsExactly(10UL..19UL) + } + + // within single range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 42UL, + filterToBlock = 45UL + ) + .also { + assertThat(it).containsExactly(42UL..45UL) + } + + // after the range + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 50UL, + filterToBlock = 55UL + ) + .also { + assertThat(it).isEmpty() + } + + // overlapping all ranges + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 0UL, + filterToBlock = 100UL + ) + .also { + assertThat(it).containsExactly(10UL..19UL, 40UL..49UL, 60UL..69UL) + } + + // overlapping middle ranges and intersect 1st half and 2nd of edge ranges + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 15UL, + filterToBlock = 65UL + ) + .also { + assertThat(it).containsExactly(15UL..19UL, 40UL..49UL, 60UL..65UL) + } + + // intersect 1st half and 2nd of ranges + generateEffectiveIntervals( + blocksWithLogs = blocksWithLogs, + filterFromBlock = 15UL, + filterToBlock = 45UL + ) + .also { + assertThat(it).containsExactly(15UL..19UL, 40UL..45UL) + } + } +} diff --git a/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/Web3JLogsSearcherIntTest.kt b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/Web3JLogsSearcherIntTest.kt new file mode 100644 index 000000000..5b9c15b63 --- /dev/null +++ b/jvm-libs/linea/web3j-extensions/src/test/kotlin/linea/web3j/Web3JLogsSearcherIntTest.kt @@ -0,0 +1,501 @@ +package linea.web3j + +import build.linea.domain.EthLog +import com.github.tomakehurst.wiremock.WireMockServer +import com.github.tomakehurst.wiremock.client.WireMock.aResponse +import com.github.tomakehurst.wiremock.client.WireMock.containing +import com.github.tomakehurst.wiremock.client.WireMock.post +import com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo +import com.github.tomakehurst.wiremock.core.WireMockConfiguration +import io.vertx.core.Vertx +import linea.SearchDirection +import linea.domain.RetryConfig +import linea.jsonrpc.TestingJsonRpcServer +import linea.log4j.configureLoggers +import net.consensys.encodeHex +import net.consensys.fromHexString +import net.consensys.linea.BlockParameter.Companion.toBlockParameter +import net.consensys.linea.jsonrpc.JsonRpcError +import net.consensys.linea.jsonrpc.JsonRpcRequest +import net.consensys.toHexString +import net.consensys.toHexStringUInt256 +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.web3j.protocol.Web3j +import org.web3j.protocol.http.HttpService +import java.net.URI +import kotlin.random.Random +import kotlin.time.Duration.Companion.milliseconds + +internal data class EthGetLogsRequest( + val fromBlock: ULong, + val toBlock: ULong, + val topics: List, + val address: List +) + +class Web3JLogsSearcherIntTest { + private lateinit var web3jClient: Web3j + private lateinit var logsClient: Web3JLogsSearcher + private lateinit var vertx: Vertx + private lateinit var wireMockServer: WireMockServer + private lateinit var TestingJsonRpcServer: TestingJsonRpcServer + private val address = "0x508ca82df566dcd1b0de8296e70a96332cd644ec" + private val log = LogManager.getLogger("test.case.Web3JLogsSearcherIntTest") + + @BeforeEach + fun beforeEach() { + vertx = Vertx.vertx() + configureLoggers( + rootLevel = Level.INFO, + log.name to Level.DEBUG, + "test.case.Web3JLogsSearcher" to Level.DEBUG + ) + } + + @AfterEach + fun tearDown() { + vertx.close() + } + + private fun setupClientWithWireMockServer( + retryConfig: RetryConfig = RetryConfig.noRetries + ) { + wireMockServer = WireMockServer(WireMockConfiguration.options().dynamicPort()) + wireMockServer.start() + + web3jClient = Web3j.build(HttpService(URI("http://127.0.0.1:" + wireMockServer.port()).toURL().toString())) + vertx = Vertx.vertx() + logsClient = Web3JLogsSearcher( + vertx, + web3jClient, + config = Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = retryConfig + ) + ) + } + + private fun setupClientWithTestingJsonRpcServer( + retryConfig: RetryConfig = RetryConfig.noRetries, + subsetOfBlocksWithLogs: List? = null + ) { + TestingJsonRpcServer = TestingJsonRpcServer( + vertx = vertx, + serverName = "fake-execution-layer-log-searcher", + recordRequestsResponses = true + ) + setUpFakeLogsServerToHandleEthLogs(TestingJsonRpcServer, subsetOfBlocksWithLogs) + logsClient = Web3JLogsSearcher( + vertx, + web3jClient = Web3j.build(HttpService(URI("http://127.0.0.1:" + TestingJsonRpcServer.boundPort).toString())), + config = Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = retryConfig + ), + log = LogManager.getLogger("test.case.Web3JLogsSearcher") + ) + } + + private fun replyEthGetLogsWith(statusCode: Int, responseBody: String) { + wireMockServer.stubFor( + post(urlEqualTo("/")) + .withRequestBody(containing("eth_getLogs")) + .willReturn( + aResponse() + .withStatus(statusCode) + .withBody(responseBody) + .withHeader("Content-Type", "application/json") + ) + ) + } + + @Test + fun `when eth_getLogs returns json-rpc error shall return failed promise`() { + setupClientWithWireMockServer() + replyEthGetLogsWith( + statusCode = 200, + responseBody = """ + { + "jsonrpc": "2.0", + "error": { + "code": -32000, + "message": "Error: unable to retrieve logs" + }, + "id": 1 + } + """.trimIndent() + ) + + assertThatThrownBy { + logsClient.getLogs( + 0UL.toBlockParameter(), + 20UL.toBlockParameter(), + address = address, + topics = emptyList() + ).get() + } + .hasCauseInstanceOf(RuntimeException::class.java) + .hasMessageContaining("json-rpc error: code=-32000 message=Error: unable to retrieve logs") + } + + @Test + fun `when eth_getLogs returns invalid json-rpc result shall return error instead of infinite retry`() { + setupClientWithWireMockServer() + replyEthGetLogsWith( + statusCode = 200, + responseBody = """ + { + "jsonrpc": "2.0", + "id": 1, + "result": [{ + "address": "0x508ca82df566dcd1b0de8296e70a96332cd644ec", + "blockHash": "0x216a74dcf", + "blockNumber": "0x864b52", + "data": "0x", + "logIndex": "0x0", + "removed": false, + "topics": ["0xe856c2b8bd4eb0027ce32eeaf595c21b0b6b4644b326e5b7bd80a1cf8db72e6c"], + "transactionHash": "0xfcff12cba7002ec38f391f2452", + "transactionIndex": "0x0" + }] + } + """.trimIndent() + ) + + assertThatThrownBy { + logsClient.getLogs( + 0UL.toBlockParameter(), + 20UL.toBlockParameter(), + address = address, + topics = emptyList() + ).get() + } + } + + @Test + fun `when eth_getLogs request fails shall retry request until it succeeds`() { + setupClientWithTestingJsonRpcServer( + retryConfig = RetryConfig( + backoffDelay = 1.milliseconds, + maxRetries = 4u + ) + ) + + TestingJsonRpcServer.handle("eth_getLogs", { _ -> + // simulate 2 failures + log.debug("eth_getLogs callCount=${TestingJsonRpcServer.callCountByMethod("eth_getLogs")}") + if (TestingJsonRpcServer.callCountByMethod("eth_getLogs") < 2) { + throw JsonRpcError.internalError().asException() + } else { + generateLogsForBlockRange(fromBlock = 10, toBlock = 15) + } + }) + + val getLogsFuture = logsClient.getLogs( + 0UL.toBlockParameter(), + 20UL.toBlockParameter(), + address = address, + topics = emptyList() + ) + + getLogsFuture.get().also { logs -> + assertThat(logs).hasSize(6) + } + } + + @Test + fun `when eth_getLogs gets an HTTP error shall return failed promise`() { + setupClientWithWireMockServer() + + replyEthGetLogsWith( + statusCode = 500, + responseBody = "Internal Server Error" + ) + + assertThatThrownBy { + logsClient.getLogs( + 0UL.toBlockParameter(), + 20UL.toBlockParameter(), + address = address, + topics = emptyList() + ).get() + } + .hasCauseInstanceOf(org.web3j.protocol.exceptions.ClientConnectionException::class.java) + .hasMessageContaining("Invalid response received: 500; Internal Server Error") + } + + @Test + fun `when eth_getLogs gets a DNS error shall return failed promise`() { + val randomHostname = "nowhere-${Random.nextBytes(20).encodeHex()}.local" + web3jClient = Web3j.build(HttpService("http://$randomHostname:1234")) + vertx = Vertx.vertx() + logsClient = Web3JLogsSearcher( + vertx, + web3jClient, + config = Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = RetryConfig.noRetries + ) + ) + + assertThatThrownBy { + logsClient.getLogs( + 0UL.toBlockParameter(), + 20UL.toBlockParameter(), + address = address, + topics = emptyList() + ).get() + } + .hasCauseInstanceOf(java.net.UnknownHostException::class.java) + .hasMessageContaining("$randomHostname") + vertx.close() + } + + private fun shallContinueToSearch( + ethLog: EthLog, + targetNumber: ULong + ): SearchDirection? { + val number = ULong.fromHexString(ethLog.topics[1].encodeHex()) + val direction = when { + number < targetNumber -> SearchDirection.FORWARD + number > targetNumber -> SearchDirection.BACKWARD + else -> null + } + log.debug( + "EthLog{blockNumber={} number={}} targetNumber={} direction={}", + ethLog.blockNumber, + number, + targetNumber, + direction + ) + return direction + } + + @Test + fun `findLogs searches and returns log when found`() { + setupClientWithTestingJsonRpcServer() + + (100..200) + .forEach { number -> + logsClient.findLog( + fromBlock = 100UL.toBlockParameter(), + toBlock = 200UL.toBlockParameter(), + address = address, + topics = listOf("0xffaabbcc"), + chunkSize = 10, + shallContinueToSearch = { ethLog -> + shallContinueToSearch(ethLog, targetNumber = number.toULong()) + } + ) + .get() + .also { log -> + assertThat(log).isNotNull() + assertThat(log!!.topics[1].encodeHex()).isEqualTo(number.toULong().toHexStringUInt256()) + } + } + } + + @Test + fun `findLogs searches L1 and returns null when not found - target before fromBlock`() { + setupClientWithTestingJsonRpcServer() + val logsEvaluated = mutableListOf() + + logsClient.findLog( + fromBlock = 100UL.toBlockParameter(), + toBlock = 200UL.toBlockParameter(), + address = address, + topics = listOf("0xffaabbcc"), + chunkSize = 10, + shallContinueToSearch = { ethLog -> + logsEvaluated.add(ethLog.blockNumber) + shallContinueToSearch(ethLog, targetNumber = 89UL) + } + ) + .get() + .also { log -> + assertThat(log).isNull() + assertThat(TestingJsonRpcServer.callCountByMethod("eth_getLogs")).isBetween(1, 4) + assertThat(logsEvaluated).hasSameElementsAs(logsEvaluated.toSet()) + } + } + + // REFERENCE: + @Test + fun `findLogs searches L1 and returns null when not found - target expected in chunk that has no logs`() { + setupClientWithTestingJsonRpcServer( + subsetOfBlocksWithLogs = listOf(100UL..109UL, 150UL..159UL) + ) + val logsEvaluated = mutableListOf() + + logsClient.findLog( + fromBlock = 100UL.toBlockParameter(), + toBlock = 200UL.toBlockParameter(), + address = address, + topics = listOf("0xffaabbcc"), + chunkSize = 10, + shallContinueToSearch = { ethLog -> + shallContinueToSearch(ethLog, targetNumber = 120UL) + } + ) + .get() + .also { log -> + assertThat(log).isNull() + assertThat(logsEvaluated).hasSameElementsAs(logsEvaluated.toSet()) + } + } + + @Test + fun `findLogs searches L1 and returns null when not found - target is after toBlock`() { + setupClientWithTestingJsonRpcServer( + subsetOfBlocksWithLogs = listOf(100UL..109UL, 150UL..200UL) + ) + val logsEvaluated = mutableListOf() + + logsClient.findLog( + fromBlock = 100UL.toBlockParameter(), + toBlock = 200UL.toBlockParameter(), + address = address, + topics = listOf("0xffaabbcc"), + chunkSize = 10, + shallContinueToSearch = { ethLog -> + shallContinueToSearch(ethLog, targetNumber = 250UL) + } + ) + .get() + .also { log -> + assertThat(log).isNull() + assertThat(TestingJsonRpcServer.callCountByMethod("eth_getLogs")).isBetween(1, 4) + assertThat(logsEvaluated).hasSameElementsAs(logsEvaluated.toSet()) + } + } + + // REFERECE 2: + @Test + fun `findLogs searches L1 and returns item when - target found an chunk in the middle`() { + setupClientWithTestingJsonRpcServer( + subsetOfBlocksWithLogs = listOf(10UL..19UL, 30UL..37UL, 50UL..100UL) + ) + val logsEvaluated = mutableListOf() + logsClient.findLog( + fromBlock = 0UL.toBlockParameter(), + toBlock = 100UL.toBlockParameter(), + address = address, + topics = listOf("0xffaabbcc"), + chunkSize = 5, + shallContinueToSearch = { ethLog -> + shallContinueToSearch(ethLog, targetNumber = 35UL) + } + ) + .get() + .also { log -> + assertThat(log).isNotNull() + assertThat(ULong.fromHexString(log!!.topics[1].encodeHex())).isEqualTo(35UL) + assertThat(TestingJsonRpcServer.callCountByMethod("eth_getLogs")).isBetween(1, 11) + assertThat(logsEvaluated).hasSameElementsAs(logsEvaluated.toSet()) + } + } + + companion object { + private fun generateLogsForBlockRange( + fromBlock: Int, + toBlock: Int, + stepSize: Int = 1, + topic: String = "0x" + ): List> { + return (fromBlock..toBlock step stepSize) + .map { + generateLogJson( + blockNumber = it, + topic = topic + ) + } + } + + private fun generateLogJson( + blockNumber: Int, + topic: String = "0x", + transactionHash: String = "0x" + ): Map { + val topics = listOf( + topic, + blockNumber.toULong().toHexStringUInt256() + ) + return mapOf( + "address" to "0x", + "blockHash" to "${blockNumber.toULong().toHexStringUInt256()}", + "blockNumber" to "${blockNumber.toULong().toHexString()}", + "data" to "0x", + "logIndex" to "0x0", + "removed" to false, + "topics" to topics, + "transactionHash" to transactionHash, + "transactionIndex" to "0x0" + ) + } + + internal fun generateLogs( + blocksWithLogs: List, + filter: EthGetLogsRequest + ): List> { + return generateEffectiveIntervals(blocksWithLogs, filter.fromBlock, filter.toBlock) + // .also { + // println( + // "filter=${CommonDomainFunctions.blockIntervalString(filter.fromBlock, filter.toBlock)} logs=$it" + // ) + // } + .flatMap { + generateLogsForBlockRange(it.first.toInt(), it.last.toInt(), topic = filter.topics[0]) + } + } + + @Suppress("UNCHECKED_CAST") + private fun parseEthLogsRequest(request: JsonRpcRequest): EthGetLogsRequest { + /** eth_getLogs request example + { + "jsonrpc": "2.0", + "method": "eth_getLogs", + "params": [{ + "topics": ["0xa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60cb", "0xa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60ff"], + "fromBlock": "earliest", + "toBlock": "latest", + "address": ["0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9"] + }], + }*/ + val logsFilter = (request.params as List)[0] as Map + val fromBlock = ULong.fromHexString(logsFilter["fromBlock"] as String) + val toBlock = ULong.fromHexString(logsFilter["toBlock"] as String) + val topics = logsFilter["topics"] as List + return EthGetLogsRequest( + fromBlock = fromBlock, + toBlock = toBlock, + topics = topics, + address = logsFilter["address"] as List + ) + } + + private fun setUpFakeLogsServerToHandleEthLogs( + TestingJsonRpcServer: TestingJsonRpcServer, + subsetOfBlocksWithLogs: List? + ) { + TestingJsonRpcServer.apply { + this.handle("eth_getLogs", { request -> + val filter = parseEthLogsRequest(request) + subsetOfBlocksWithLogs + ?.let { + generateLogs(subsetOfBlocksWithLogs, filter) + } ?: generateLogsForBlockRange( + fromBlock = filter.fromBlock.toInt(), + toBlock = filter.toBlock.toInt(), + topic = filter.topics[0] + ) + }) + } + } + } +} diff --git a/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/CommonUtils.kt b/jvm-libs/linea/web3j-extensions/src/testFixtures/kotlin/linea/web3j/Pollers.kt similarity index 97% rename from coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/CommonUtils.kt rename to jvm-libs/linea/web3j-extensions/src/testFixtures/kotlin/linea/web3j/Pollers.kt index 86e77af0b..be14355af 100644 --- a/coordinator/ethereum/test-utils/src/main/kotlin/net/consensys/zkevm/ethereum/CommonUtils.kt +++ b/jvm-libs/linea/web3j-extensions/src/testFixtures/kotlin/linea/web3j/Pollers.kt @@ -1,4 +1,4 @@ -package net.consensys.zkevm.ethereum +package linea.web3j import org.web3j.protocol.Web3j import org.web3j.protocol.core.methods.response.TransactionReceipt diff --git a/prover/backend/execution/testcase_gen/rand_gen.go b/prover/backend/execution/testcase_gen/rand_gen.go index 0160855f9..2f63dd0c5 100644 --- a/prover/backend/execution/testcase_gen/rand_gen.go +++ b/prover/backend/execution/testcase_gen/rand_gen.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" "math/big" - "math/rand" + "math/rand/v2" "github.com/consensys/linea-monorepo/prover/backend/ethereum" "github.com/consensys/linea-monorepo/prover/backend/execution" @@ -30,7 +30,7 @@ type RandGen struct { // Create a generator from the CLI func MakeGeneratorFromCLI() (res RandGen) { // #nosec G404 --we don't need a cryptographic RNG for testing purpose - res = RandGen{Rand: *rand.New(rand.NewSource(Seed()))} + res = RandGen{Rand: *rand.New(utils.NewRandSource(Seed()))} res.Params.SupTxPerBlock = MaxTxPerBlock() + 1 res.Params.SupL2L1LogsPerBlock = MaxL2L1LogsPerBlock() + 1 res.Params.SupMsgReceiptPerBlock = MaxL1L2ReceiptPerBlock() + 1 @@ -39,7 +39,7 @@ func MakeGeneratorFromCLI() (res RandGen) { // Returns an non-zero integer in the range func (g *RandGen) PositiveInt(sup int) int { - return utils.Max(1, g.Intn(sup)) + return utils.Max(1, g.IntN(sup)) } // Returns a random hex string representing n bytes @@ -70,7 +70,7 @@ func (g *RandGen) TxRlp(numTxs int) ([]string, []uint16) { var receptionPos []uint16 // overwrite one of the tx with a receipt confirmation one - txPos := g.Intn(numTxs) + txPos := g.IntN(numTxs) rlpTxs[txPos] = g.MsgReceiptConfirmationTx() receptionPos = append(receptionPos, utils.ToUint16(txPos)) @@ -136,13 +136,13 @@ func (g *RandGen) PopulateBlockData( func (g *RandGen) Bytes(nb int) []byte { res := make([]byte, nb) - g.Read(res) + utils.ReadPseudoRand(&g.Rand, res) return res } // Generates a tx of any type func (g *RandGen) AnyTypeTxRlp() (res string) { - switch g.Intn(3) { + switch g.IntN(3) { case 0: res = g.LegacyTxRLP() case 1: @@ -256,7 +256,7 @@ func (g *RandGen) MsgReceiptConfirmationTx() string { // Craft the transaction, randomly from any of var tx ethtypes.TxData - switch g.Intn(3) { + switch g.IntN(3) { case 0: tx = ðtypes.LegacyTx{ Nonce: g.Nonce(), @@ -338,7 +338,7 @@ func (g *RandGen) Nonce() uint64 { // Generates a random tx value func (g *RandGen) Value() *big.Int { - return big.NewInt(g.Int63n(1_000_000)) + return big.NewInt(g.Int64N(1_000_000)) } // Generate a random tx gas limit @@ -348,13 +348,13 @@ func (g *RandGen) Gas() uint64 { // Generate a random big int func (g *RandGen) BigInt(n int64) *big.Int { - return big.NewInt(g.Int63n(n)) + return big.NewInt(g.Int64N(n)) } // Generates a list of L2 msg logs func (g *RandGen) L2L1MsgHashes() (hashes []types.FullBytes32) { hashes = []types.FullBytes32{} - n := g.Intn(g.Params.SupL2L1LogsPerBlock) + n := g.IntN(g.Params.SupL2L1LogsPerBlock) for i := 0; i < n; i++ { hashes = append(hashes, types.FullBytes32FromHex(g.HexStringForNBytes(32))) } diff --git a/prover/circuits/execution/pi_wizard_extraction.go b/prover/circuits/execution/pi_wizard_extraction.go index e564320c4..3a14b7ee3 100644 --- a/prover/circuits/execution/pi_wizard_extraction.go +++ b/prover/circuits/execution/pi_wizard_extraction.go @@ -28,7 +28,7 @@ func checkPublicInputs( // functional input (the txnrlp is incorrect). It should be converted into // an [api.AssertIsEqual] once this is resolved. // - shouldBeEqual(api, execDataHash, gnarkFuncInp.DataChecksum) + api.AssertIsEqual(execDataHash, gnarkFuncInp.DataChecksum) api.AssertIsEqual( wvc.GetPublicInput(api, publicInput.L2MessageHash), @@ -154,10 +154,3 @@ func execDataHash( return hsh.Sum() } - -// shouldBeEqual is a placeholder dummy function that generate fake constraints -// as a replacement for what should be an api.AssertIsEqual. If we just commented -// out the api.AssertIsEqual we might have an unconstrained variable. -func shouldBeEqual(api frontend.API, a, b frontend.Variable) { - _ = api.Sub(a, b) -} diff --git a/prover/crypto/keccak/hash_test.go b/prover/crypto/keccak/hash_test.go index 3af8a8e99..9580dce14 100644 --- a/prover/crypto/keccak/hash_test.go +++ b/prover/crypto/keccak/hash_test.go @@ -1,10 +1,11 @@ package keccak_test import ( - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/crypto/keccak" + "github.com/consensys/linea-monorepo/prover/utils" "github.com/stretchr/testify/require" ) @@ -12,14 +13,14 @@ func TestTraces(t *testing.T) { numCases := 100 // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rng := rand.New(rand.NewSource(0)) + rng := rand.New(rand.NewChaCha8([32]byte{})) maxSize := 1024 for i := 0; i < numCases; i++ { // Populate a random string - data := make([]byte, rng.Intn(maxSize)) - rng.Read(data) + data := make([]byte, rng.IntN(maxSize)) + utils.ReadPseudoRand(rng, data) // Initialize an empty trace traces := keccak.PermTraces{} diff --git a/prover/crypto/keccak/reference_test.go b/prover/crypto/keccak/reference_test.go index f97128962..b14806abf 100644 --- a/prover/crypto/keccak/reference_test.go +++ b/prover/crypto/keccak/reference_test.go @@ -2,10 +2,11 @@ package keccak_test import ( "fmt" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/crypto/keccak" + "github.com/consensys/linea-monorepo/prover/utils" "github.com/stretchr/testify/require" "golang.org/x/crypto/sha3" ) @@ -18,7 +19,7 @@ func TestFullHashAgainstRef(t *testing.T) { // Create a deterministic random number generator for reproducibility. // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rng := rand.New(rand.NewSource(0)) + rng := rand.New(rand.NewChaCha8([32]byte{})) refHasher := sha3.NewLegacyKeccak256() numCases := 50 @@ -30,7 +31,7 @@ func TestFullHashAgainstRef(t *testing.T) { for _n := 0; _n < numCases; _n++ { // Populate the sample with random values inp := make([]byte, s) - _, err := rng.Read(inp) + _, err := utils.ReadPseudoRand(rng, inp) require.NoError(t, err) // Hash the input stream using the reference hasher @@ -56,15 +57,15 @@ func TestFullHashAgainstRefFullRand(t *testing.T) { // Create a deterministic random number generator for reproducibility. // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rng := rand.New(rand.NewSource(0)) + rng := rand.New(rand.NewChaCha8([32]byte{})) refHasher := sha3.NewLegacyKeccak256() numCases := 500 maxSize := 1024 for _n := 0; _n < numCases; _n++ { // Populate the sample with random values - inp := make([]byte, rng.Intn(maxSize)) - _, err := rng.Read(inp) + inp := make([]byte, rng.IntN(maxSize)) + _, err := utils.ReadPseudoRand(rng, inp) require.NoError(t, err) // Hash the input stream using the reference hasher diff --git a/prover/crypto/ringsis/ringsis_32_8/limb_decompose_test.go b/prover/crypto/ringsis/ringsis_32_8/limb_decompose_test.go index 031dddf0a..7cfe3c2ac 100644 --- a/prover/crypto/ringsis/ringsis_32_8/limb_decompose_test.go +++ b/prover/crypto/ringsis/ringsis_32_8/limb_decompose_test.go @@ -4,7 +4,7 @@ package ringsis_32_8 import ( "math/big" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/maths/field" @@ -15,14 +15,14 @@ func TestLimbDecompose(t *testing.T) { var ( limbs = make([]int64, 32) - rng = rand.New(rand.NewSource(98790)) + rng = rand.New(rand.NewChaCha8([32]byte{})) inputs = make([]field.Element, 1) obtainedLimbs = make([]field.Element, 32) ) for i := range limbs { if i%32 > 31 { - limbs[i] = int64(rng.Intn(1 << 8)) + limbs[i] = int64(rng.IntN(1 << 8)) } } diff --git a/prover/crypto/ringsis/ringsis_32_8/transversal_hash_test.go b/prover/crypto/ringsis/ringsis_32_8/transversal_hash_test.go index a166bb4c2..d1e2df41c 100644 --- a/prover/crypto/ringsis/ringsis_32_8/transversal_hash_test.go +++ b/prover/crypto/ringsis/ringsis_32_8/transversal_hash_test.go @@ -4,7 +4,7 @@ package ringsis_32_8_test import ( "fmt" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" @@ -31,7 +31,7 @@ func randomRegularRow(rng *rand.Rand, size int) smartvectors.SmartVector { func fullyRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector { list := make([]smartvectors.SmartVector, numRow) for i := range list { - coin := rng.Intn(2) + coin := rng.IntN(2) switch { case coin == 0: list[i] = randomConstRow(rng, numCols) @@ -63,7 +63,7 @@ func TestSmartVectorTransversalSisHash(t *testing.T) { var ( numReps = 64 numCols = 16 - rng = rand.New(rand.NewSource(786868)) + rng = rand.New(rand.NewChaCha8([32]byte{})) domain = fft.NewDomain(32, fft.WithShift(wfft.GetOmega(32*2))) twiddles = ringsis_32_8.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen) params = ringsis.Params{LogTwoBound: 8, LogTwoDegree: 5} diff --git a/prover/crypto/ringsis/ringsis_64_16/limb_decompose_test.go b/prover/crypto/ringsis/ringsis_64_16/limb_decompose_test.go index 53e0e045f..1eb0de45f 100644 --- a/prover/crypto/ringsis/ringsis_64_16/limb_decompose_test.go +++ b/prover/crypto/ringsis/ringsis_64_16/limb_decompose_test.go @@ -4,7 +4,7 @@ package ringsis_64_16 import ( "math/big" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/maths/field" @@ -15,14 +15,14 @@ func TestLimbDecompose(t *testing.T) { var ( limbs = make([]int64, 64) - rng = rand.New(rand.NewSource(98790)) + rng = rand.New(rand.NewChaCha8([32]byte{})) inputs = make([]field.Element, 4) obtainedLimbs = make([]field.Element, 64) ) for i := range limbs { if i%16 > 15 { - limbs[i] = int64(rng.Intn(1 << 16)) + limbs[i] = int64(rng.IntN(1 << 16)) } } diff --git a/prover/crypto/ringsis/ringsis_64_16/transerval_hash_bench_test.go b/prover/crypto/ringsis/ringsis_64_16/transerval_hash_bench_test.go index ac27170de..67e1d8e0a 100644 --- a/prover/crypto/ringsis/ringsis_64_16/transerval_hash_bench_test.go +++ b/prover/crypto/ringsis/ringsis_64_16/transerval_hash_bench_test.go @@ -2,7 +2,7 @@ package ringsis_64_16_test import ( "fmt" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" @@ -11,6 +11,7 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" wfft "github.com/consensys/linea-monorepo/prover/maths/fft" "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/utils" ) func BenchmarkTransversalHash(b *testing.B) { @@ -18,7 +19,7 @@ func BenchmarkTransversalHash(b *testing.B) { var ( numRow = 1024 numCols = 1024 - rng = rand.New(rand.NewSource(786868)) // nolint + rng = rand.New(utils.NewRandSource(786868)) // nolint domain = fft.NewDomain(64, fft.WithShift(wfft.GetOmega(64*2))) twiddles = ringsis_64_16.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen) params = ringsis.Params{LogTwoBound: 16, LogTwoDegree: 6} diff --git a/prover/crypto/ringsis/ringsis_64_16/transversal_hash_test.go b/prover/crypto/ringsis/ringsis_64_16/transversal_hash_test.go index 3a12670de..1c17fc6be 100644 --- a/prover/crypto/ringsis/ringsis_64_16/transversal_hash_test.go +++ b/prover/crypto/ringsis/ringsis_64_16/transversal_hash_test.go @@ -4,7 +4,7 @@ package ringsis_64_16_test import ( "fmt" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" @@ -31,7 +31,7 @@ func randomRegularRow(rng *rand.Rand, size int) smartvectors.SmartVector { func fullyRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector { list := make([]smartvectors.SmartVector, numRow) for i := range list { - coin := rng.Intn(2) + coin := rng.IntN(2) switch { case coin == 0: list[i] = randomConstRow(rng, numCols) @@ -63,7 +63,7 @@ func TestSmartVectorTransversalSisHash(t *testing.T) { var ( numReps = 64 numCols = 16 - rng = rand.New(rand.NewSource(786868)) + rng = rand.New(rand.NewChaCha8([32]byte{})) domain = fft.NewDomain(64, fft.WithShift(wfft.GetOmega(64*2))) twiddles = ringsis_64_16.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen) params = ringsis.Params{LogTwoBound: 16, LogTwoDegree: 6} diff --git a/prover/crypto/ringsis/ringsis_64_8/limb_decompose_test.go b/prover/crypto/ringsis/ringsis_64_8/limb_decompose_test.go index b27b32570..c9e7d9004 100644 --- a/prover/crypto/ringsis/ringsis_64_8/limb_decompose_test.go +++ b/prover/crypto/ringsis/ringsis_64_8/limb_decompose_test.go @@ -4,7 +4,7 @@ package ringsis_64_8 import ( "math/big" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/maths/field" @@ -15,14 +15,14 @@ func TestLimbDecompose(t *testing.T) { var ( limbs = make([]int64, 64) - rng = rand.New(rand.NewSource(98790)) + rng = rand.New(rand.NewChaCha8([32]byte{})) inputs = make([]field.Element, 2) obtainedLimbs = make([]field.Element, 64) ) for i := range limbs { if i%32 > 31 { - limbs[i] = int64(rng.Intn(1 << 8)) + limbs[i] = int64(rng.IntN(1 << 8)) } } diff --git a/prover/crypto/ringsis/ringsis_64_8/transversal_hash_test.go b/prover/crypto/ringsis/ringsis_64_8/transversal_hash_test.go index 786a5b798..d431a2767 100644 --- a/prover/crypto/ringsis/ringsis_64_8/transversal_hash_test.go +++ b/prover/crypto/ringsis/ringsis_64_8/transversal_hash_test.go @@ -4,7 +4,7 @@ package ringsis_64_8_test import ( "fmt" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" @@ -31,7 +31,7 @@ func randomRegularRow(rng *rand.Rand, size int) smartvectors.SmartVector { func fullyRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector { list := make([]smartvectors.SmartVector, numRow) for i := range list { - coin := rng.Intn(2) + coin := rng.IntN(2) switch { case coin == 0: list[i] = randomConstRow(rng, numCols) @@ -63,7 +63,7 @@ func TestSmartVectorTransversalSisHash(t *testing.T) { var ( numReps = 64 numCols = 16 - rng = rand.New(rand.NewSource(786868)) + rng = rand.New(rand.NewChaCha8([32]byte{})) domain = fft.NewDomain(64, fft.WithShift(wfft.GetOmega(64*2))) twiddles = ringsis_64_8.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen) params = ringsis.Params{LogTwoBound: 8, LogTwoDegree: 6} diff --git a/prover/crypto/ringsis/templates/limb_decompose_test.go.tmpl b/prover/crypto/ringsis/templates/limb_decompose_test.go.tmpl index a4e9e4c83..814bff605 100644 --- a/prover/crypto/ringsis/templates/limb_decompose_test.go.tmpl +++ b/prover/crypto/ringsis/templates/limb_decompose_test.go.tmpl @@ -2,7 +2,7 @@ package ringsis_{{.ModulusDegree}}_{{.LogTwoBound}} import ( "math/big" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/maths/field" @@ -18,14 +18,14 @@ func TestLimbDecompose(t *testing.T) { var ( limbs = make([]int64, {{.ModulusDegree}}) - rng = rand.New(rand.NewSource(98790)) + rng = rand.New(rand.NewChaCha8([32]byte{})) inputs = make([]field.Element, {{$fieldPerPoly}}) obtainedLimbs = make([]field.Element, {{.ModulusDegree}}) ) for i := range limbs { if i%{{$limbPerField}} > {{sub $limbPerField 1}} { - limbs[i] = int64(rng.Intn(1 << {{.LogTwoBound}})) + limbs[i] = int64(rng.IntN(1 << {{.LogTwoBound}})) } } diff --git a/prover/crypto/ringsis/templates/transversal_hash_test.go.tmpl b/prover/crypto/ringsis/templates/transversal_hash_test.go.tmpl index 206716380..5c31b5cb7 100644 --- a/prover/crypto/ringsis/templates/transversal_hash_test.go.tmpl +++ b/prover/crypto/ringsis/templates/transversal_hash_test.go.tmpl @@ -2,7 +2,7 @@ package ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}_test import ( "fmt" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" @@ -33,7 +33,7 @@ func randomRegularRow(rng *rand.Rand, size int) smartvectors.SmartVector { func fullyRandomTestVector(rng *rand.Rand, numRow, numCols int) []smartvectors.SmartVector { list := make([]smartvectors.SmartVector, numRow) for i := range list { - coin := rng.Intn(2) + coin := rng.IntN(2) switch { case coin == 0: list[i] = randomConstRow(rng, numCols) @@ -65,7 +65,7 @@ func TestSmartVectorTransversalSisHash(t *testing.T) { var ( numReps = 64 numCols = 16 - rng = rand.New(rand.NewSource(786868)) + rng = rand.New(rand.NewChaCha8([32]byte{})) domain = fft.NewDomain({{.ModulusDegree}}, fft.WithShift(wfft.GetOmega({{.ModulusDegree}}*2))) twiddles = ringsis_{{.ModulusDegree}}_{{.LogTwoBound}}.PrecomputeTwiddlesCoset(domain.Generator, domain.FrMultiplicativeGen) params = ringsis.Params{LogTwoBound: {{.LogTwoBound}}, LogTwoDegree: {{log2 .ModulusDegree}}} diff --git a/prover/crypto/sha2/sha2_test.go b/prover/crypto/sha2/sha2_test.go index 9c2e53ba8..cc72f7774 100644 --- a/prover/crypto/sha2/sha2_test.go +++ b/prover/crypto/sha2/sha2_test.go @@ -2,9 +2,10 @@ package sha2 import ( "crypto/sha256" - "math/rand" + "math/rand/v2" "testing" + "github.com/consensys/linea-monorepo/prover/utils" "github.com/stretchr/testify/assert" ) @@ -18,7 +19,7 @@ func TestHash(t *testing.T) { var ( maxSizeByte = 1000 // #nosec G404 -- we don't need a cryptographic PRNG for testing purposes - rng = rand.New(rand.NewSource(212678)) + rng = rand.New(rand.NewChaCha8([32]byte{})) ) for sizeByte := 0; sizeByte < maxSizeByte; sizeByte++ { @@ -37,7 +38,7 @@ func TestHash(t *testing.T) { func genTestCase(rng *rand.Rand, sizeByte int) testCase { stream := make([]byte, sizeByte) - rng.Read(stream) + utils.ReadPseudoRand(rng, stream) return testCase{ Stream: stream, diff --git a/prover/lib/compressor/blob/v0/blob_maker_test.go b/prover/lib/compressor/blob/v0/blob_maker_test.go index ff37f6760..b05454976 100644 --- a/prover/lib/compressor/blob/v0/blob_maker_test.go +++ b/prover/lib/compressor/blob/v0/blob_maker_test.go @@ -8,16 +8,17 @@ import ( "encoding/json" "errors" "fmt" - "github.com/consensys/linea-monorepo/prover/lib/compressor/blob/dictionary" - encodeTesting "github.com/consensys/linea-monorepo/prover/lib/compressor/blob/encode/test_utils" - "github.com/consensys/linea-monorepo/prover/utils" "io" "math/big" - "math/rand" + "math/rand/v2" "os" "slices" "testing" + "github.com/consensys/linea-monorepo/prover/lib/compressor/blob/dictionary" + encodeTesting "github.com/consensys/linea-monorepo/prover/lib/compressor/blob/encode/test_utils" + "github.com/consensys/linea-monorepo/prover/utils" + "github.com/consensys/linea-monorepo/prover/lib/compressor/blob/v0/compress/lzss" "github.com/consensys/linea-monorepo/prover/backend/ethereum" @@ -194,7 +195,7 @@ func TestCanWrite(t *testing.T) { cptBlock := 0 for i, block := range testBlocks { // get a random from 1 to 5 - bSize := rand.Intn(3) + 1 // #nosec G404 -- false positive + bSize := rand.IntN(3) + 1 // #nosec G404 -- false positive if cptBlock > bSize && i%3 == 0 { nbBlocksPerBatch = append(nbBlocksPerBatch, uint16(cptBlock)) @@ -279,7 +280,7 @@ func TestCompressorWithBatches(t *testing.T) { for i, block := range testBlocks { t.Logf("processing block %d over %d", i, len(testBlocks)) // get a random from 1 to 5 - bSize := rand.Intn(5) + 1 // #nosec G404 -- false positive + bSize := rand.IntN(5) + 1 // #nosec G404 -- false positive if cptBlock > bSize && i%3 == 0 { nbBlocksPerBatch = append(nbBlocksPerBatch, uint16(cptBlock)) @@ -726,17 +727,18 @@ func craftExpandingInput(dict []byte, size int) []byte { func TestPack(t *testing.T) { assert := require.New(t) var buf bytes.Buffer + var rng = rand.New(rand.NewChaCha8([32]byte{})) for i := 0; i < 100; i++ { // create 2 random slices - n1 := rand.Intn(100) + 1 // #nosec G404 -- false positive - n2 := rand.Intn(100) + 1 // #nosec G404 -- false positive + n1 := rng.IntN(100) + 1 // #nosec G404 -- false positive + n2 := rng.IntN(100) + 1 // #nosec G404 -- false positive s1 := make([]byte, n1) s2 := make([]byte, n2) - rand.Read(s1) - rand.Read(s2) + utils.ReadPseudoRand(rng, s1) + utils.ReadPseudoRand(rng, s2) // pack them buf.Reset() diff --git a/prover/lib/compressor/blob/v0/compress/stream_test.go b/prover/lib/compressor/blob/v0/compress/stream_test.go index afda67de6..3c433b1af 100644 --- a/prover/lib/compressor/blob/v0/compress/stream_test.go +++ b/prover/lib/compressor/blob/v0/compress/stream_test.go @@ -1,7 +1,7 @@ package compress import ( - "math/rand" + "math/rand/v2" "testing" "github.com/stretchr/testify/assert" @@ -11,8 +11,8 @@ func TestMarshalRoundTrip(t *testing.T) { d := make([]int, 1000) for i := 0; i < 1000; i++ { var s Stream - s.D = d[:rand.Intn(len(d))+1] //#nosec G404 weak rng is fine here - s.NbSymbs = rand.Intn(510) + 2 //#nosec G404 weak rng is fine here + s.D = d[:rand.IntN(len(d))+1] //#nosec G404 weak rng is fine here + s.NbSymbs = rand.IntN(510) + 2 //#nosec G404 weak rng is fine here testMarshal(t, s) } @@ -28,6 +28,6 @@ func testMarshal(t *testing.T, s Stream) { func fillRandom(s Stream) { for i := range s.D { - s.D[i] = rand.Intn(s.NbSymbs) //#nosec G404 weak rng is fine here + s.D[i] = rand.IntN(s.NbSymbs) //#nosec G404 weak rng is fine here } } diff --git a/prover/lib/compressor/blob/v1/blob_maker_test.go b/prover/lib/compressor/blob/v1/blob_maker_test.go index cfb008f49..cdf387c6e 100644 --- a/prover/lib/compressor/blob/v1/blob_maker_test.go +++ b/prover/lib/compressor/blob/v1/blob_maker_test.go @@ -8,7 +8,7 @@ import ( "encoding/binary" "encoding/hex" "math/big" - "math/rand" + "math/rand/v2" "os" "path/filepath" "testing" @@ -151,7 +151,7 @@ func TestCanWrite(t *testing.T) { cptBlock := 0 for i, block := range testBlocks { // get a random from 1 to 5 - bSize := rand.Intn(3) + 1 // #nosec G404 -- false positive + bSize := rand.IntN(3) + 1 // #nosec G404 -- false positive if cptBlock > bSize && i%3 == 0 { nbBlocksPerBatch = append(nbBlocksPerBatch, uint16(cptBlock)) @@ -236,7 +236,7 @@ func TestCompressorWithBatches(t *testing.T) { for i, block := range testBlocks { t.Logf("processing block %d over %d", i, len(testBlocks)) // get a random from 1 to 5 - bSize := rand.Intn(5) + 1 // #nosec G404 -- false positive + bSize := rand.IntN(5) + 1 // #nosec G404 -- false positive if cptBlock > bSize && i%3 == 0 { nbBlocksPerBatch = append(nbBlocksPerBatch, uint16(cptBlock)) @@ -624,8 +624,8 @@ func TestPack(t *testing.T) { for i := 0; i < 100; i++ { // create 2 random slices - n1 := rand.Intn(100) + 1 // #nosec G404 -- false positive - n2 := rand.Intn(100) + 1 // #nosec G404 -- false positive + n1 := rand.IntN(100) + 1 // #nosec G404 -- false positive + n2 := rand.IntN(100) + 1 // #nosec G404 -- false positive s1 := make([]byte, n1) s2 := make([]byte, n2) diff --git a/prover/maths/common/polyext/gnarkpoly.go b/prover/maths/common/polyext/gnarkpoly.go new file mode 100644 index 000000000..039df446a --- /dev/null +++ b/prover/maths/common/polyext/gnarkpoly.go @@ -0,0 +1,48 @@ +package polyext + +import ( + "github.com/consensys/gnark/frontend" + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/maths/field/fext/gnarkfext" +) + +// EvaluateLagrangeAnyDomainGnark mirrors [EvaluateLagrangesAnyDomain] but in +// a gnark circuit. The same usage precautions applies for it. +func EvaluateLagrangeAnyDomainGnark(api frontend.API, domain []gnarkfext.Variable, x gnarkfext.Variable) []gnarkfext.Variable { + + outerAPI := gnarkfext.API{Inner: api} + lagrange := make([]gnarkfext.Variable, len(domain)) + + for i, hi := range domain { + lhix := gnarkfext.Variable{field.One(), field.Zero()} + for j, hj := range domain { + if i == j { + // Skip it + continue + } + // more convenient to store -h instead of h + factor := outerAPI.Sub(x, hj) + den := outerAPI.Sub(hi, hj) // so x - h + den = outerAPI.Inverse(den) + + // accumulate the product + lhix = outerAPI.Mul(lhix, factor, den) + } + lagrange[i] = lhix + } + + return lagrange + +} + +// EvaluateUnivariateGnark evaluate a univariate polynomial in a gnark circuit. +// It mirrors [EvalUnivariate]. +func EvaluateUnivariateGnark(api frontend.API, pol []gnarkfext.Variable, x gnarkfext.Variable) gnarkfext.Variable { + res := gnarkfext.Variable{frontend.Variable(0), frontend.Variable(0)} + outerAPI := gnarkfext.API{Inner: api} + for i := len(pol) - 1; i >= 0; i-- { + res = outerAPI.Mul(res, x) + res = outerAPI.Add(res, pol[i]) + } + return res +} diff --git a/prover/maths/common/polyext/gnarkpoly_test.go b/prover/maths/common/polyext/gnarkpoly_test.go new file mode 100644 index 000000000..9867ab7de --- /dev/null +++ b/prover/maths/common/polyext/gnarkpoly_test.go @@ -0,0 +1,99 @@ +package polyext + +import ( + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext/gnarkfext" + "testing" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/linea-monorepo/prover/utils/gnarkutil" + "github.com/stretchr/testify/require" +) + +func TestGnarkEval(t *testing.T) { + + t.Run("normal-poly", func(t *testing.T) { + + def := func(api frontend.API) error { + outerAPI := gnarkfext.API{Inner: api} + var ( + pol = vectorext.IntoGnarkAssignment(vectorext.ForTestFromPairs(1, 2, 3, 4, -1, -2)) + x = gnarkfext.Variable{2, 1} + expected = gnarkfext.Variable{ + -5*fext.RootPowers[1] + 3, + -2*fext.RootPowers[1] + 1, + } + res = EvaluateUnivariateGnark(api, pol, x) + ) + outerAPI.AssertIsEqual(expected, res) + return nil + } + + gnarkutil.AssertCircuitSolved(t, def) + }) + + t.Run("empty-poly", func(t *testing.T) { + def := func(api frontend.API) error { + outerAPI := gnarkfext.API{Inner: api} + var ( + pol = vectorext.IntoGnarkAssignment([]fext.Element{}) + x = gnarkfext.Variable{2, 3} + expected = gnarkfext.NewZero() + res = EvaluateUnivariateGnark(api, pol, x) + ) + outerAPI.AssertIsEqual(expected, res) + return nil + } + gnarkutil.AssertCircuitSolved(t, def) + }) + +} + +func TestGnarkEvalAnyDomain(t *testing.T) { + + t.Run("single-variable", func(t *testing.T) { + + def := func(api frontend.API) error { + outerAPI := gnarkfext.API{Inner: api} + var ( + domain = vectorext.IntoGnarkAssignment(vectorext.ForTestFromPairs(0, 0)) + x = gnarkfext.Variable{42, 0} + expected = vectorext.IntoGnarkAssignment(vectorext.ForTestFromPairs(1, 0)) + res = EvaluateLagrangeAnyDomainGnark(api, domain, x) + ) + + require.Len(t, res, len(expected)) + for i := range expected { + outerAPI.AssertIsEqual(expected[i], res[i]) + } + + return nil + } + + gnarkutil.AssertCircuitSolved(t, def) + }) + + t.Run("multiple-variable", func(t *testing.T) { + + def := func(api frontend.API) error { + outerAPI := gnarkfext.API{Inner: api} + var ( + domain = vectorext.IntoGnarkAssignment(vectorext.ForTestFromPairs(0, 0, 1, 0)) + x = gnarkfext.Variable{42, 0} + expected = vectorext.IntoGnarkAssignment(vectorext.ForTestFromPairs(-41, 0, 42, 0)) + res = EvaluateLagrangeAnyDomainGnark(api, domain, x) + ) + + require.Len(t, res, len(expected)) + for i := range expected { + outerAPI.AssertIsEqual(expected[i], res[i]) + } + + return nil + } + + gnarkutil.AssertCircuitSolved(t, def) + }) + +} diff --git a/prover/maths/common/polyext/poly.go b/prover/maths/common/polyext/poly.go index dd2e5b297..b9abea59f 100644 --- a/prover/maths/common/polyext/poly.go +++ b/prover/maths/common/polyext/poly.go @@ -1,7 +1,8 @@ package polyext import ( - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/maths/field/fext" "github.com/consensys/linea-monorepo/prover/utils" ) @@ -22,6 +23,11 @@ func EvalUnivariate(pol []fext.Element, x fext.Element) fext.Element { return res } +func EvalUnivariateBase(pol []fext.Element, x field.Element) fext.Element { + wrappedX := fext.Element{x, field.Zero()} + return EvalUnivariate(pol, wrappedX) +} + // Mul multiplies two polynomials expressed by their coefficients using the // naive method and writes the result in res. `a` and `b` may have distinct // degrees and the result is returned in a slice of size len(a) + len(b) - 1. diff --git a/prover/maths/common/polyext/poly_test.go b/prover/maths/common/polyext/poly_test.go new file mode 100644 index 000000000..89d6d5411 --- /dev/null +++ b/prover/maths/common/polyext/poly_test.go @@ -0,0 +1,249 @@ +package polyext_test + +import ( + "github.com/consensys/linea-monorepo/prover/maths/common/polyext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "github.com/consensys/linea-monorepo/prover/utils" + "math/rand/v2" + "testing" + + "github.com/consensys/linea-monorepo/prover/maths/field" + + "github.com/stretchr/testify/require" +) + +func TestEvalUnivariate(t *testing.T) { + // Just a simple test vector + // (1+a)+(2+2a)X+(5+a)X^2+(12+2a)X^3 + testVec := []fext.Element{ + fext.NewElement(1, 1), + fext.NewElement(2, 2), + fext.NewElement(5, 1), + fext.NewElement(12, 2), + } + + x := fext.NewElement(3, 4) + + y := polyext.EvalUnivariate(testVec, x) + // expanded form of the polynomial 128 a^4 + 1072 a^3 + 2056 a^2 + 1494 a + 376 + first := 128*fext.RootPowers[1]*fext.RootPowers[1] + 2056*fext.RootPowers[1] + 376 + second := 1072*fext.RootPowers[1] + 1494 + require.Equal(t, y, *new(fext.Element).SetInt64Pair(int64(first), int64(second))) +} + +func TestMul(t *testing.T) { + + t.Run("same-size", func(t *testing.T) { + var ( + a = vectorext.ForTestFromPairs(1, 1, 2, 3) // (1+a)+(2+3a)*X + b = vectorext.ForTestFromPairs(-1, -1, 1, -2) // (-1-a)+(1-2a)*X + expected = vectorext.ForTestFromPairs( + -fext.RootPowers[1]-1, + -2, + -5*fext.RootPowers[1]-1, + -6, + -6*fext.RootPowers[1]+2, + -1, + ) // (-6a^2-a+2) X^2 + (-5a^2-6a-1)X - a^2 - 2a - 1 + res = polyext.Mul(a, b) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) + + t.Run("a-is-smaller", func(t *testing.T) { + var ( + a = vectorext.ForTestFromPairs(1, 1, -1, -2) // (1+a)+(-1-2a)*X + b = vectorext.ForTestFromPairs(-1, -2, 0, 1, 2, -2) // (-1-2a)+aX+(2-2a)X^2 + expected = vectorext.ForTestFromPairs( + -2*fext.RootPowers[1]-1, + -3, + 5*fext.RootPowers[1]+1, + 5, + -4*fext.RootPowers[1]+2, + -1, + 4*fext.RootPowers[1]-2, + -2, + ) // (4a^2-2a-2)X^3+(-4a^2-a+2) X^2+(5a^2+5a+1)X-2a^2-3a-1 + res = polyext.Mul(a, b) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) + + t.Run("a-is-larger", func(t *testing.T) { + var ( + a = vectorext.ForTestFromPairs(-1, 1, 0, 0, 1, 2) // (-1+a)+(1+2a)Xˆ2 + b = vectorext.ForTestFromPairs(1, 1, 2, -1) // (1+a)+(2-a)X + expected = vectorext.ForTestFromPairs( + -1+fext.RootPowers[1], + 0, + -fext.RootPowers[1]-2, + 3, + 2*fext.RootPowers[1]+1, + 3, + -2*fext.RootPowers[1]+2, + 3, + ) // (2+3a-2a^2)X^3+(1+3a+2a^2)Xˆ2+(-2+3a-aˆ2)X+(-1+a^2) + res = polyext.Mul(a, b) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) + + t.Run("a-is-empty", func(t *testing.T) { + var ( + a = vectorext.ForTestFromPairs() + b = vectorext.ForTestFromPairs(1, 1, 2, 2) + expected = vectorext.ForTestFromPairs() + res = polyext.Mul(a, b) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) + + t.Run("b-is-empty", func(t *testing.T) { + var ( + a = vectorext.ForTestFromPairs(1, 1, 2, 2) + b = vectorext.ForTestFromPairs() + expected = vectorext.ForTestFromPairs() + res = polyext.Mul(a, b) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) +} + +func TestAdd(t *testing.T) { + + t.Run("same-size", func(t *testing.T) { + var ( + a = vectorext.ForTestFromPairs(1, 1, 2, 1) + b = vectorext.ForTestFromPairs(-1, 1, 3, 3) + expected = vectorext.ForTestFromPairs(0, 2, 5, 4) + res = polyext.Add(a, b) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) + + t.Run("a-is-smaller", func(t *testing.T) { + var ( + a = vectorext.ForTestFromPairs(1, 1, 2, 2) + b = vectorext.ForTestFromPairs(1, 1, 1, 1, 3, 2, 7, 8) + expected = vectorext.ForTestFromPairs(2, 2, 3, 3, 3, 2, 7, 8) + res = polyext.Add(a, b) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) + + t.Run("a-is-larger", func(t *testing.T) { + var ( + a = vectorext.ForTestFromPairs(1, 1, 1, 1, 2, 2, 3, 3) + b = vectorext.ForTestFromPairs(1, 1, 4, 4) + expected = vectorext.ForTestFromPairs(2, 2, 5, 5, 2, 2, 3, 3) + res = polyext.Add(a, b) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) + + t.Run("a-is-empty", func(t *testing.T) { + var ( + a = vectorext.ForTestFromPairs() + b = vectorext.ForTestFromPairs(1, 1, 2, 2) + expected = vectorext.ForTestFromPairs(1, 1, 2, 2) + res = polyext.Add(a, b) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) + + t.Run("b-is-empty", func(t *testing.T) { + var ( + a = vectorext.ForTestFromPairs(1, 1, 2, 2) + b = vectorext.ForTestFromPairs() + expected = vectorext.ForTestFromPairs(1, 1, 2, 2) + res = polyext.Add(a, b) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) +} + +func TestScalarMul(t *testing.T) { + + t.Run("normal-vec", func(t *testing.T) { + var ( + vec = vectorext.ForTestFromPairs(1, 2, 3, 4, 2, 1) + x = fext.NewElement(2, 1) + expected = vectorext.ForTestFromPairs( + 2+2*fext.RootPowers[1], + 5, + 6+4*fext.RootPowers[1], + 11, + 4+fext.RootPowers[1], + 4, + ) + res = polyext.ScalarMul(vec, x) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) + + t.Run("empty-vec", func(t *testing.T) { + var ( + vec = vectorext.ForTestFromPairs() + x = fext.NewElement(2, 2) + expected = vectorext.ForTestFromPairs() + res = polyext.ScalarMul(vec, x) + ) + require.Equal(t, vectorext.Prettify(expected), vectorext.Prettify(res)) + }) + +} + +func TestEvaluateLagrangeAnyDomain(t *testing.T) { + + t.Run("single-point-domain", func(t *testing.T) { + var ( + domain = []fext.Element{{field.Zero(), field.Zero()}} + x = fext.NewElement(42, 42) + ys = polyext.EvaluateLagrangesAnyDomain(domain, x) + expected = vectorext.ForTestFromPairs(1, 0) + ) + require.Equal(t, expected, ys) + }) + + t.Run("many-point-domain", func(t *testing.T) { + var ( + // the first lagrange poly is 1-X and the second one is X + domain = vectorext.ForTestFromPairs(0, 0, 1, 0) + x = fext.NewElement(42, 0) + ys = polyext.EvaluateLagrangesAnyDomain(domain, x) + expected = vectorext.ForTestFromPairs(-41, 0, 42, 0) + ) + require.Equal(t, expected, ys) + }) + + t.Run("many-point-domain-random", func(t *testing.T) { + // #nosec G404 -- we don't need a cryptographic PRNG for testing purposes + rng := rand.New(utils.NewRandSource((43))) + rand := []fext.Element{fext.PseudoRand(rng), fext.PseudoRand(rng), fext.PseudoRand(rng)} + randX := fext.PseudoRand(rng) + expectedYs := []fext.Element{} + for i, coord := range rand { + var term1, term2, aux, y fext.Element + // compute the first term + term1.Sub(&randX, &rand[(i+3+1)%3]) + aux.Sub(&coord, &rand[(i+3+1)%3]) + term1.Div(&term1, &aux) + // compute the second term + term2.Sub(&randX, &rand[(i+3-1)%3]) + aux.Sub(&coord, &rand[(i+3-1)%3]) + term2.Div(&term2, &aux) + // add the expected y term to expectedYs + y.Mul(&term1, &term2) + expectedYs = append(expectedYs, y) + } + var ( + domain = rand + x = randX + ys = polyext.EvaluateLagrangesAnyDomain(domain, x) + expected = expectedYs + ) + require.Equal(t, expected, ys) + }) + +} diff --git a/prover/maths/common/smartvectors/arithmetic_test.go b/prover/maths/common/smartvectors/arithmetic_test.go index 4d9b24a9e..2b2541d81 100644 --- a/prover/maths/common/smartvectors/arithmetic_test.go +++ b/prover/maths/common/smartvectors/arithmetic_test.go @@ -15,7 +15,7 @@ import ( func TestFuzzProduct(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForProd() success := t.Run(tcase.name, func(t *testing.T) { @@ -36,7 +36,7 @@ func TestFuzzProduct(t *testing.T) { } func TestFuzzLinComb(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForLinComb() success := t.Run(tcase.name, func(t *testing.T) { @@ -57,7 +57,7 @@ func TestFuzzLinComb(t *testing.T) { } func TestFuzzPolyEval(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForPolyEval() success := t.Run(tcase.name, func(t *testing.T) { @@ -80,7 +80,7 @@ func TestFuzzPolyEval(t *testing.T) { func TestFuzzProductWithPool(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForProd() success := t.Run(tcase.name, func(t *testing.T) { @@ -107,7 +107,7 @@ func TestFuzzProductWithPool(t *testing.T) { func TestFuzzProductWithPoolCompare(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForProd() success := t.Run(tcase.name, func(t *testing.T) { @@ -137,7 +137,7 @@ func TestFuzzProductWithPoolCompare(t *testing.T) { func TestFuzzLinCombWithPool(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForLinComb() success := t.Run(tcase.name, func(t *testing.T) { @@ -163,7 +163,7 @@ func TestFuzzLinCombWithPool(t *testing.T) { func TestFuzzLinCombWithPoolCompare(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForLinComb() success := t.Run(tcase.name, func(t *testing.T) { @@ -285,7 +285,7 @@ func TestScalarMul(t *testing.T) { } func TestFuzzPolyEvalWithPool(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForPolyEval() success := t.Run(tcase.name, func(t *testing.T) { @@ -310,7 +310,7 @@ func TestFuzzPolyEvalWithPool(t *testing.T) { } func TestFuzzPolyEvalWithPoolCompare(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForPolyEval() success := t.Run(tcase.name, func(t *testing.T) { diff --git a/prover/maths/common/smartvectors/fft_test.go b/prover/maths/common/smartvectors/fft_test.go index 568e577cc..009b1c8d9 100644 --- a/prover/maths/common/smartvectors/fft_test.go +++ b/prover/maths/common/smartvectors/fft_test.go @@ -15,7 +15,7 @@ import ( func TestFFTFuzzyDIFDIT(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { // We reuse the test case generator for linear combinations. We only // care about the first vector. builder := newTestBuilder(i) @@ -27,12 +27,12 @@ func TestFFTFuzzyDIFDIT(t *testing.T) { v := tcase.svecs[0] // Test the consistency of the FFT - oncoset := builder.gen.Intn(2) == 0 + oncoset := builder.gen.IntN(2) == 0 ratio, cosetID := 0, 0 if oncoset { - ratio = 1 << builder.gen.Intn(4) - cosetID = builder.gen.Intn(ratio) + ratio = 1 << builder.gen.IntN(4) + cosetID = builder.gen.IntN(ratio) } t.Logf("Parameters are (vec %v - ratio %v - cosetID %v", v.Pretty(), ratio, cosetID) @@ -54,7 +54,7 @@ func TestFFTFuzzyDIFDIT(t *testing.T) { func TestFFTFuzzyDITDIF(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { // We reuse the test case generator for linear combinations. We only // care about the first vector. builder := newTestBuilder(i) @@ -66,12 +66,12 @@ func TestFFTFuzzyDITDIF(t *testing.T) { v := tcase.svecs[0] // Test the consistency of the FFT - oncoset := builder.gen.Intn(2) == 0 + oncoset := builder.gen.IntN(2) == 0 ratio, cosetID := 0, 0 if oncoset { - ratio = 1 << builder.gen.Intn(4) - cosetID = builder.gen.Intn(ratio) + ratio = 1 << builder.gen.IntN(4) + cosetID = builder.gen.IntN(ratio) } t.Logf("Parameters are (vec %v - ratio %v - cosetID %v", v.Pretty(), ratio, cosetID) @@ -93,7 +93,7 @@ func TestFFTFuzzyDITDIF(t *testing.T) { func TestFFTFuzzyDIFDITBitReverse(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { // We reuse the test case generator for linear combinations. We only // care about the first vector. builder := newTestBuilder(i) @@ -105,12 +105,12 @@ func TestFFTFuzzyDIFDITBitReverse(t *testing.T) { v := tcase.svecs[0] // Test the consistency of the FFT - oncoset := builder.gen.Intn(2) == 0 + oncoset := builder.gen.IntN(2) == 0 ratio, cosetID := 0, 0 if oncoset { - ratio = 1 << builder.gen.Intn(4) - cosetID = builder.gen.Intn(ratio) + ratio = 1 << builder.gen.IntN(4) + cosetID = builder.gen.IntN(ratio) } t.Logf("Parameters are (vec %v - ratio %v - cosetID %v", v.Pretty(), ratio, cosetID) @@ -132,7 +132,7 @@ func TestFFTFuzzyDIFDITBitReverse(t *testing.T) { func TestFFTFuzzyDITDIFBitReverse(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { // We reuse the test case generator for linear combinations. We only // care about the first vector. builder := newTestBuilder(i) @@ -144,12 +144,12 @@ func TestFFTFuzzyDITDIFBitReverse(t *testing.T) { v := tcase.svecs[0] // Test the consistency of the FFT - oncoset := builder.gen.Intn(2) == 0 + oncoset := builder.gen.IntN(2) == 0 ratio, cosetID := 0, 0 if oncoset { - ratio = 1 << builder.gen.Intn(4) - cosetID = builder.gen.Intn(ratio) + ratio = 1 << builder.gen.IntN(4) + cosetID = builder.gen.IntN(ratio) } t.Logf("Parameters are (vec %v - ratio %v - cosetID %v", v.Pretty(), ratio, cosetID) @@ -171,7 +171,7 @@ func TestFFTFuzzyDITDIFBitReverse(t *testing.T) { func TestFFTFuzzyEvaluation(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { // We reuse the test case generator for linear combinations. We only // care about the first vector. builder := newTestBuilder(i) @@ -183,19 +183,19 @@ func TestFFTFuzzyEvaluation(t *testing.T) { coeffs := tcase.svecs[0] // Test the consistency of the FFT - oncoset := builder.gen.Intn(2) == 0 + oncoset := builder.gen.IntN(2) == 0 ratio, cosetID := 0, 0 if oncoset { - ratio = 1 << builder.gen.Intn(4) - cosetID = builder.gen.Intn(ratio) + ratio = 1 << builder.gen.IntN(4) + cosetID = builder.gen.IntN(ratio) } // ====== With bit reverse ====== // FFT DIT and IFFT DIF should be the identity evals := FFT(coeffs, fft.DIT, true, ratio, cosetID, nil) - i := builder.gen.Intn(coeffs.Len()) + i := builder.gen.IntN(coeffs.Len()) t.Logf("Parameters are (vec %v - ratio %v - cosetID %v - evalAt %v", coeffs.Pretty(), ratio, cosetID, i) x := fft.GetOmega(evals.Len()) @@ -223,7 +223,7 @@ func TestFFTFuzzyEvaluation(t *testing.T) { func TestFFTFuzzyConsistWithInterpolation(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { // We reuse the test case generator for linear combinations. We only // care about the first vector. builder := newTestBuilder(i) @@ -235,19 +235,19 @@ func TestFFTFuzzyConsistWithInterpolation(t *testing.T) { coeffs := tcase.svecs[0] // Test the consistency of the FFT - oncoset := builder.gen.Intn(2) == 0 + oncoset := builder.gen.IntN(2) == 0 ratio, cosetID := 0, 0 if oncoset { - ratio = 1 << builder.gen.Intn(4) - cosetID = builder.gen.Intn(ratio) + ratio = 1 << builder.gen.IntN(4) + cosetID = builder.gen.IntN(ratio) } // ====== With bit reverse ====== // FFT DIT and IFFT DIF should be the identity evals := FFT(coeffs, fft.DIT, true, ratio, cosetID, nil) - i := builder.gen.Intn(coeffs.Len()) + i := builder.gen.IntN(coeffs.Len()) t.Logf("Parameters are (vec %v - ratio %v - cosetID %v - evalAt %v", coeffs.Pretty(), ratio, cosetID, i) var xCoeff field.Element diff --git a/prover/maths/common/smartvectors/fuzzing.go b/prover/maths/common/smartvectors/fuzzing.go index efe60e3d4..9050d0de9 100644 --- a/prover/maths/common/smartvectors/fuzzing.go +++ b/prover/maths/common/smartvectors/fuzzing.go @@ -3,7 +3,7 @@ package smartvectors import ( "fmt" "math/big" - "math/rand" + "math/rand/v2" "github.com/consensys/linea-monorepo/prover/maths/common/poly" "github.com/consensys/linea-monorepo/prover/maths/common/vector" @@ -61,24 +61,24 @@ func newTestBuilder(seed int) *testCaseGen { // Use a deterministic randomness source res := &testCaseGen{seed: seed} // #nosec G404 --we don't need a cryptographic RNG for fuzzing purpose - res.gen = rand.New(rand.NewSource(int64(seed))) + res.gen = rand.New(utils.NewRandSource(int64(seed))) // We should have some quarantee that the length is not too small // for the test generation - res.fullLen = 1 << (res.gen.Intn(5) + 3) - res.numVec = res.gen.Intn(8) + 1 + res.fullLen = 1 << (res.gen.IntN(5) + 3) + res.numVec = res.gen.IntN(8) + 1 // In the test, we may restrict the inputs vectors to have a certain type allowedTypes := append([]smartVecType{}, smartVecTypeList...) res.gen.Shuffle(len(allowedTypes), func(i, j int) { allowedTypes[i], allowedTypes[j] = allowedTypes[j], allowedTypes[i] }) - res.allowedTypes = allowedTypes[:res.gen.Intn(len(allowedTypes)-1)+1] + res.allowedTypes = allowedTypes[:res.gen.IntN(len(allowedTypes)-1)+1] // Generating the window : it should be roughly half of the total length // this aims at maximizing the coverage. - res.windowWithLen = res.gen.Intn(res.fullLen-4)/2 + 2 - res.windowMustStartAfter = res.gen.Intn(res.fullLen) + res.windowWithLen = res.gen.IntN(res.fullLen-4)/2 + 2 + res.windowMustStartAfter = res.gen.IntN(res.fullLen) return res } @@ -104,8 +104,8 @@ func (gen *testCaseGen) NewTestCaseForProd() (tcase testCase) { for i := 0; i < gen.numVec; i++ { // Generate one by one the different vectors val := gen.genValue() - tcase.coeffs[i] = gen.gen.Intn(5) - chosenType := gen.allowedTypes[gen.gen.Intn(len(gen.allowedTypes))] + tcase.coeffs[i] = gen.gen.IntN(5) + chosenType := gen.allowedTypes[gen.gen.IntN(len(gen.allowedTypes))] maxType = utils.Max(maxType, chosenType) // Update the expected res value @@ -184,8 +184,8 @@ func (gen *testCaseGen) NewTestCaseForLinComb() (tcase testCase) { for i := 0; i < gen.numVec; i++ { // Generate one by one the different vectors val := gen.genValue() - tcase.coeffs[i] = gen.gen.Intn(10) - 5 - chosenType := gen.allowedTypes[gen.gen.Intn(len(gen.allowedTypes))] + tcase.coeffs[i] = gen.gen.IntN(10) - 5 + chosenType := gen.allowedTypes[gen.gen.IntN(len(gen.allowedTypes))] maxType = utils.Max(maxType, chosenType) // Update the expected res value @@ -258,8 +258,8 @@ func (gen *testCaseGen) NewTestCaseForPolyEval() (tcase testCase) { // Generate one by one the different vectors val := gen.genValue() vals = append(vals, val) - tcase.coeffs[i] = gen.gen.Intn(10) - 5 - chosenType := gen.allowedTypes[gen.gen.Intn(len(gen.allowedTypes))] + tcase.coeffs[i] = gen.gen.IntN(10) - 5 + chosenType := gen.allowedTypes[gen.gen.IntN(len(gen.allowedTypes))] maxType = utils.Max(maxType, chosenType) switch chosenType { @@ -304,7 +304,7 @@ func (gen *testCaseGen) NewTestCaseForPolyEval() (tcase testCase) { func (gen *testCaseGen) genValue() field.Element { // May increase the ceil of the generator to increase the probability to pick // an actually random value. - switch gen.gen.Intn(4) { + switch gen.gen.IntN(4) { case 0: return field.Zero() case 1: @@ -316,9 +316,9 @@ func (gen *testCaseGen) genValue() field.Element { } func (gen *testCaseGen) genWindow(val, paddingVal field.Element) *PaddedCircularWindow { - start := gen.windowMustStartAfter + gen.gen.Intn(gen.windowWithLen)/2 + start := gen.windowMustStartAfter + gen.gen.IntN(gen.windowWithLen)/2 maxStop := gen.windowWithLen + gen.windowMustStartAfter - winLen := gen.gen.Intn(maxStop - start) + winLen := gen.gen.IntN(maxStop - start) if winLen == 0 { winLen = 1 } @@ -330,6 +330,6 @@ func (gen *testCaseGen) genRegular(val field.Element) *Regular { } func (gen *testCaseGen) genRotated(val field.Element) *Rotated { - offset := gen.gen.Intn(gen.fullLen) + offset := gen.gen.IntN(gen.fullLen) return NewRotated(*gen.genRegular(val), offset) } diff --git a/prover/maths/common/smartvectors/fuzzing_heavy.go b/prover/maths/common/smartvectors/fuzzing_heavy.go index e88aad63a..e9901f08f 100644 --- a/prover/maths/common/smartvectors/fuzzing_heavy.go +++ b/prover/maths/common/smartvectors/fuzzing_heavy.go @@ -2,4 +2,4 @@ package smartvectors -const fuzzIteration int = 20000 +const FuzzIteration int = 20000 diff --git a/prover/maths/common/smartvectors/fuzzing_light.go b/prover/maths/common/smartvectors/fuzzing_light.go index 978c94468..e1e23d330 100644 --- a/prover/maths/common/smartvectors/fuzzing_light.go +++ b/prover/maths/common/smartvectors/fuzzing_light.go @@ -2,4 +2,4 @@ package smartvectors -const fuzzIteration int = 100 +const FuzzIteration int = 100 diff --git a/prover/maths/common/smartvectors/polynomial_test.go b/prover/maths/common/smartvectors/polynomial_test.go index c883b96cf..de66b58ec 100644 --- a/prover/maths/common/smartvectors/polynomial_test.go +++ b/prover/maths/common/smartvectors/polynomial_test.go @@ -49,7 +49,7 @@ func TestRuffini(t *testing.T) { func TestFuzzPolynomial(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { // We reuse the test-case generator of lincomb but we only // use the first generated edge-case for each. The fact that diff --git a/prover/maths/common/smartvectors/smartvector_test.go b/prover/maths/common/smartvectors/smartvector_test.go index 6fb5014f1..b04b9be94 100644 --- a/prover/maths/common/smartvectors/smartvector_test.go +++ b/prover/maths/common/smartvectors/smartvector_test.go @@ -12,7 +12,7 @@ import ( ) func TestWriteInSlice(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { // We reuse the test case generator for linear combinations. We only // care about the first vector. builder := newTestBuilder(i) @@ -32,7 +32,7 @@ func TestWriteInSlice(t *testing.T) { } // write in a random place of the slice - randPos := builder.gen.Intn(v.Len()) + randPos := builder.gen.IntN(v.Len()) slice[randPos].SetRandom() x := v.Get(randPos) require.NotEqual(t, x.String(), randPos, "forbidden shallow copy") @@ -44,7 +44,7 @@ func TestWriteInSlice(t *testing.T) { } func TestShiftingTest(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { // We reuse the test case generator for linear combinations. We only // care about the first vector. builder := newTestBuilder(i) @@ -55,7 +55,7 @@ func TestShiftingTest(t *testing.T) { func(t *testing.T) { v := tcase.svecs[0] - offset := builder.gen.Intn(v.Len()) + offset := builder.gen.IntN(v.Len()) shifted := v.RotateRight(offset) revShifted := v.RotateRight(-offset) @@ -78,7 +78,7 @@ func TestShiftingTest(t *testing.T) { func TestSubvectorFuzzy(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < FuzzIteration; i++ { // We reuse the test case generator for linear combinations. We only // care about the first vector. @@ -91,8 +91,8 @@ func TestSubvectorFuzzy(t *testing.T) { v := tcase.svecs[0] length := v.Len() // generate the subvector window - stop := 1 + builder.gen.Intn(length-1) - start := builder.gen.Intn(stop) + stop := 1 + builder.gen.IntN(length-1) + start := builder.gen.IntN(stop) sub := v.SubVector(start, stop) diff --git a/prover/maths/common/smartvectors/smartvectors.go b/prover/maths/common/smartvectors/smartvectors.go index 4a735c775..bd513fd97 100644 --- a/prover/maths/common/smartvectors/smartvectors.go +++ b/prover/maths/common/smartvectors/smartvectors.go @@ -2,8 +2,9 @@ package smartvectors import ( "fmt" + "math/rand/v2" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" - "math/rand" "github.com/consensys/gnark/frontend" "github.com/consensys/linea-monorepo/prover/maths/common/vector" diff --git a/prover/maths/common/smartvectorsext/arithmetic_basic_ext.go b/prover/maths/common/smartvectorsext/arithmetic_basic.go similarity index 98% rename from prover/maths/common/smartvectorsext/arithmetic_basic_ext.go rename to prover/maths/common/smartvectorsext/arithmetic_basic.go index 1dc550f02..8c0257f13 100644 --- a/prover/maths/common/smartvectorsext/arithmetic_basic_ext.go +++ b/prover/maths/common/smartvectorsext/arithmetic_basic.go @@ -3,7 +3,7 @@ package smartvectorsext import ( "github.com/consensys/linea-monorepo/prover/maths/common/mempoolext" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field/fext" "github.com/consensys/linea-monorepo/prover/utils" ) diff --git a/prover/maths/common/smartvectorsext/arithmetic_basic_test.go b/prover/maths/common/smartvectorsext/arithmetic_basic_test.go index 2eeb74f2f..38ea27cb1 100644 --- a/prover/maths/common/smartvectorsext/arithmetic_basic_test.go +++ b/prover/maths/common/smartvectorsext/arithmetic_basic_test.go @@ -3,10 +3,10 @@ package smartvectorsext import ( "fmt" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field/fext" "testing" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" "github.com/stretchr/testify/assert" ) diff --git a/prover/maths/common/smartvectorsext/arithmetic_op.go b/prover/maths/common/smartvectorsext/arithmetic_op.go index 964787fa3..04ada093e 100644 --- a/prover/maths/common/smartvectorsext/arithmetic_op.go +++ b/prover/maths/common/smartvectorsext/arithmetic_op.go @@ -1,7 +1,7 @@ package smartvectorsext import ( - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field/fext" "math/big" ) diff --git a/prover/maths/common/smartvectorsext/arithmetic_ext_test.go b/prover/maths/common/smartvectorsext/arithmetic_test.go similarity index 89% rename from prover/maths/common/smartvectorsext/arithmetic_ext_test.go rename to prover/maths/common/smartvectorsext/arithmetic_test.go index 79e8983b2..b5ecd8fe7 100644 --- a/prover/maths/common/smartvectorsext/arithmetic_ext_test.go +++ b/prover/maths/common/smartvectorsext/arithmetic_test.go @@ -4,18 +4,20 @@ package smartvectorsext import ( "fmt" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "math/big" + "testing" + "github.com/consensys/linea-monorepo/prover/maths/common/mempoolext" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field/fext" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "testing" ) func TestFuzzProduct(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < smartvectors.FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForProd() success := t.Run(tcase.name, func(t *testing.T) { @@ -36,7 +38,7 @@ func TestFuzzProduct(t *testing.T) { } func TestFuzzLinComb(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < smartvectors.FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForLinComb() success := t.Run(tcase.name, func(t *testing.T) { @@ -57,7 +59,7 @@ func TestFuzzLinComb(t *testing.T) { } func TestFuzzPolyEval(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < smartvectors.FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForPolyEval() success := t.Run(tcase.name, func(t *testing.T) { @@ -80,7 +82,7 @@ func TestFuzzPolyEval(t *testing.T) { func TestFuzzProductWithPool(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < smartvectors.FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForProd() success := t.Run(tcase.name, func(t *testing.T) { @@ -107,7 +109,7 @@ func TestFuzzProductWithPool(t *testing.T) { func TestFuzzProductWithPoolCompare(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < smartvectors.FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForProd() success := t.Run(tcase.name, func(t *testing.T) { @@ -137,7 +139,7 @@ func TestFuzzProductWithPoolCompare(t *testing.T) { func TestFuzzLinCombWithPool(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < smartvectors.FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForLinComb() success := t.Run(tcase.name, func(t *testing.T) { @@ -163,7 +165,7 @@ func TestFuzzLinCombWithPool(t *testing.T) { func TestFuzzLinCombWithPoolCompare(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < smartvectors.FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForLinComb() success := t.Run(tcase.name, func(t *testing.T) { @@ -193,6 +195,7 @@ func TestFuzzLinCombWithPoolCompare(t *testing.T) { func TestOpBasicEdgeCases(t *testing.T) { two := fext.NewElement(2, fieldPaddingInt()) + eight := new(fext.Element).Exp(two, big.NewInt(3)) testCases := []struct { explainer string @@ -207,7 +210,7 @@ func TestOpBasicEdgeCases(t *testing.T) { LeftPadded(vectorext.Repeat(two, 12), two, 16), RightPadded(vectorext.Repeat(two, 12), two, 16), }, - expectedRes: NewRegularExt(vectorext.Repeat(fext.NewElement(6, fieldPaddingInt()), 16)), + expectedRes: NewRegularExt(vectorext.Repeat(fext.NewElement(6, 3*fieldPaddingInt()), 16)), fn: Add, }, { @@ -217,7 +220,7 @@ func TestOpBasicEdgeCases(t *testing.T) { LeftPadded(vectorext.Repeat(two, 12), two, 16), RightPadded(vectorext.Repeat(two, 12), two, 16), }, - expectedRes: NewRegularExt(vectorext.Repeat(fext.NewElement(8, fieldPaddingInt()), 16)), + expectedRes: NewRegularExt(vectorext.Repeat(*eight, 16)), fn: Mul, }, { @@ -228,7 +231,7 @@ func TestOpBasicEdgeCases(t *testing.T) { RightPadded(vectorext.Repeat(two, 12), two, 16), NewRegularExt(vectorext.Repeat(two, 16)), }, - expectedRes: NewRegularExt(vectorext.Repeat(fext.NewElement(8, fieldPaddingInt()), 16)), + expectedRes: NewRegularExt(vectorext.Repeat(fext.NewElement(8, 4*fieldPaddingInt()), 16)), fn: Add, }, } @@ -244,14 +247,18 @@ func TestOpBasicEdgeCases(t *testing.T) { } func TestInnerProduct(t *testing.T) { + a := ForTestFromPairs(1, 1, 2, 1, 1, 1, 2, 1, 1, 1) + b := ForTestFromPairs(1, 1, -1, 1, 2, 1, -1, 1, 2, 1) + sum := new(fext.Element).SetInt64Pair(int64(1+5*fext.RootPowers[1]), 10) + testCases := []struct { a, b smartvectors.SmartVector y fext.Element }{ { - a: ForTestExt(1, 2, 1, 2, 1), - b: ForTestExt(1, -1, 2, -1, 2), - y: fext.NewElement(1, fieldPaddingInt()), + a: a, + b: b, + y: *sum, }, } @@ -271,7 +278,12 @@ func TestScalarMul(t *testing.T) { }{ { a: ForTestExt(1, 2, 1, 2, 1), - b: fext.NewElement(3, fieldPaddingInt()), + b: fext.NewElement(3, 1), + y: ForTestFromPairs(3, 1, 6, 2, 3, 1, 6, 2, 3, 1), + }, + { + a: ForTestExt(1, 2, 1, 2, 1), + b: fext.NewElement(3, 0), y: ForTestExt(3, 6, 3, 6, 3), }, } @@ -285,7 +297,7 @@ func TestScalarMul(t *testing.T) { } func TestFuzzPolyEvalWithPool(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < smartvectors.FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForPolyEval() success := t.Run(tcase.name, func(t *testing.T) { @@ -310,7 +322,7 @@ func TestFuzzPolyEvalWithPool(t *testing.T) { } func TestFuzzPolyEvalWithPoolCompare(t *testing.T) { - for i := 0; i < fuzzIteration; i++ { + for i := 0; i < smartvectors.FuzzIteration; i++ { tcase := newTestBuilder(i).NewTestCaseForPolyEval() success := t.Run(tcase.name, func(t *testing.T) { diff --git a/prover/maths/common/smartvectorsext/constant_ext.go b/prover/maths/common/smartvectorsext/constant.go similarity index 100% rename from prover/maths/common/smartvectorsext/constant_ext.go rename to prover/maths/common/smartvectorsext/constant.go diff --git a/prover/maths/common/smartvectorsext/fuzzing_ext.go b/prover/maths/common/smartvectorsext/fuzzing.go similarity index 91% rename from prover/maths/common/smartvectorsext/fuzzing_ext.go rename to prover/maths/common/smartvectorsext/fuzzing.go index 4a5cd0bfb..285fc8b94 100644 --- a/prover/maths/common/smartvectorsext/fuzzing_ext.go +++ b/prover/maths/common/smartvectorsext/fuzzing.go @@ -2,12 +2,13 @@ package smartvectorsext import ( "fmt" + "math/big" + "math/rand/v2" + "github.com/consensys/linea-monorepo/prover/maths/common/polyext" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field/fext" - "math/big" - "math/rand" "github.com/consensys/linea-monorepo/prover/utils" ) @@ -62,24 +63,24 @@ func newTestBuilder(seed int) *testCaseGen { // Use a deterministic randomness source res := &testCaseGen{seed: seed} // #nosec G404 --we don't need a cryptographic RNG for fuzzing purpose - res.gen = rand.New(rand.NewSource(int64(seed))) + res.gen = rand.New(utils.NewRandSource(int64(seed))) // We should have some quarantee that the length is not too small // for the test generation - res.fullLen = 1 << (res.gen.Intn(5) + 3) - res.numVec = res.gen.Intn(8) + 1 + res.fullLen = 1 << (res.gen.IntN(5) + 3) + res.numVec = res.gen.IntN(8) + 1 // In the test, we may restrict the inputs vectors to have a certain type allowedTypes := append([]smartVecType{}, smartVecTypeList...) res.gen.Shuffle(len(allowedTypes), func(i, j int) { allowedTypes[i], allowedTypes[j] = allowedTypes[j], allowedTypes[i] }) - res.allowedTypes = allowedTypes[:res.gen.Intn(len(allowedTypes)-1)+1] + res.allowedTypes = allowedTypes[:res.gen.IntN(len(allowedTypes)-1)+1] // Generating the window : it should be roughly half of the total length // this aims at maximizing the coverage. - res.windowWithLen = res.gen.Intn(res.fullLen-4)/2 + 2 - res.windowMustStartAfter = res.gen.Intn(res.fullLen) + res.windowWithLen = res.gen.IntN(res.fullLen-4)/2 + 2 + res.windowMustStartAfter = res.gen.IntN(res.fullLen) return res } @@ -105,8 +106,8 @@ func (gen *testCaseGen) NewTestCaseForProd() (tcase testCase) { for i := 0; i < gen.numVec; i++ { // Generate one by one the different vectors val := gen.genValue() - tcase.coeffs[i] = gen.gen.Intn(5) - chosenType := gen.allowedTypes[gen.gen.Intn(len(gen.allowedTypes))] + tcase.coeffs[i] = gen.gen.IntN(5) + chosenType := gen.allowedTypes[gen.gen.IntN(len(gen.allowedTypes))] maxType = utils.Max(maxType, chosenType) // Update the expected res value @@ -185,8 +186,8 @@ func (gen *testCaseGen) NewTestCaseForLinComb() (tcase testCase) { for i := 0; i < gen.numVec; i++ { // Generate one by one the different vectors val := gen.genValue() - tcase.coeffs[i] = gen.gen.Intn(10) - 5 - chosenType := gen.allowedTypes[gen.gen.Intn(len(gen.allowedTypes))] + tcase.coeffs[i] = gen.gen.IntN(10) - 5 + chosenType := gen.allowedTypes[gen.gen.IntN(len(gen.allowedTypes))] maxType = utils.Max(maxType, chosenType) // Update the expected res value @@ -259,8 +260,8 @@ func (gen *testCaseGen) NewTestCaseForPolyEval() (tcase testCase) { // Generate one by one the different vectors val := gen.genValue() vals = append(vals, val) - tcase.coeffs[i] = gen.gen.Intn(10) - 5 - chosenType := gen.allowedTypes[gen.gen.Intn(len(gen.allowedTypes))] + tcase.coeffs[i] = gen.gen.IntN(10) - 5 + chosenType := gen.allowedTypes[gen.gen.IntN(len(gen.allowedTypes))] maxType = utils.Max(maxType, chosenType) switch chosenType { @@ -304,7 +305,7 @@ func (gen *testCaseGen) NewTestCaseForPolyEval() (tcase testCase) { func (gen *testCaseGen) genValue() fext.Element { // May increase the ceil of the generator to increase the probability to pick // an actually random value. - switch gen.gen.Intn(4) { + switch gen.gen.IntN(4) { case 0: return fext.Zero() case 1: @@ -316,9 +317,9 @@ func (gen *testCaseGen) genValue() fext.Element { } func (gen *testCaseGen) genWindow(val, paddingVal fext.Element) *PaddedCircularWindowExt { - start := gen.windowMustStartAfter + gen.gen.Intn(gen.windowWithLen)/2 + start := gen.windowMustStartAfter + gen.gen.IntN(gen.windowWithLen)/2 maxStop := gen.windowWithLen + gen.windowMustStartAfter - winLen := gen.gen.Intn(maxStop - start) + winLen := gen.gen.IntN(maxStop - start) if winLen == 0 { winLen = 1 } @@ -330,6 +331,6 @@ func (gen *testCaseGen) genRegularExt(val fext.Element) *RegularExt { } func (gen *testCaseGen) genRotatedExt(val fext.Element) *RotatedExt { - offset := gen.gen.Intn(gen.fullLen) + offset := gen.gen.IntN(gen.fullLen) return NewRotatedExt(*gen.genRegularExt(val), offset) } diff --git a/prover/maths/common/smartvectorsext/fuzzing_heavy.go b/prover/maths/common/smartvectorsext/fuzzing_heavy.go deleted file mode 100644 index d20307a2f..000000000 --- a/prover/maths/common/smartvectorsext/fuzzing_heavy.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build !fuzzlight - -package smartvectorsext - -const fuzzIteration int = 20000 diff --git a/prover/maths/common/smartvectorsext/temp_parameters.go b/prover/maths/common/smartvectorsext/padding_parameters.go similarity index 100% rename from prover/maths/common/smartvectorsext/temp_parameters.go rename to prover/maths/common/smartvectorsext/padding_parameters.go diff --git a/prover/maths/common/smartvectorsext/polynomial.go b/prover/maths/common/smartvectorsext/polynomial.go new file mode 100644 index 000000000..17ac4c7f3 --- /dev/null +++ b/prover/maths/common/smartvectorsext/polynomial.go @@ -0,0 +1,266 @@ +package smartvectorsext + +import ( + "github.com/consensys/linea-monorepo/prover/maths/common/polyext" + "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/fft/fastpolyext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "math/big" + + "github.com/consensys/linea-monorepo/prover/maths/fft" + "github.com/consensys/linea-monorepo/prover/utils" + "github.com/consensys/linea-monorepo/prover/utils/parallel" +) + +// Add two vectors representing polynomials in coefficient form. +// a and b may have different sizes +func PolyAdd(a, b smartvectors.SmartVector) smartvectors.SmartVector { + + small, large := a, b + if a.Len() > b.Len() { + small, large = large, small + } + + res := make([]fext.Element, large.Len()) + large.WriteInSliceExt(res) + for i := 0; i < small.Len(); i++ { + x := small.GetExt(i) + res[i].Add(&res[i], &x) + } + + return NewRegularExt(res) +} + +func PolySub(a, b smartvectors.SmartVector) smartvectors.SmartVector { + + maxLen := utils.Max(a.Len(), b.Len()) + res := make([]fext.Element, maxLen) + a.WriteInSliceExt(res[:a.Len()]) + + for i := 0; i < b.Len(); i++ { + bi := b.GetExt(i) + res[i].Sub(&res[i], &bi) + } + + return NewRegularExt(res) +} + +/* +Ruffini division + - p polynomial in coefficient form + - q field.Element, caracterizing the divisor X - q + - quo quotient polynomial in coefficient form, result will be passed + here. quo is truncated of its first entry in the process + - expected to be at least as large as `p` + +- rem, remainder also equals to P(r) + +Supports &p == quo +*/ +func RuffiniQuoRem(p smartvectors.SmartVector, q fext.Element) (quo smartvectors.SmartVector, rem fext.Element) { + + // The case where "p" is zero is assumed to be impossible as every type of + // smart-vector strongly forbid dealing with zero length smart-vectors. + if p.Len() == 0 { + panic("Zero-length smart-vectors are forbidden") + } + + // If p has length 1, then the general case algorithm does not work + if p.Len() == 1 { + quo = NewConstantExt(fext.Zero(), 1) + rem = p.GetExt(0) + return quo, rem + } + + quo_ := make([]fext.Element, p.Len()) + + // Pass the last coefficient + quo_[p.Len()-1] = p.GetExt(p.Len() - 1) + + for i := p.Len() - 2; i >= 0; i-- { + var c fext.Element + c.Mul(&quo_[i+1], &q) + pi := p.GetExt(i) + quo_[i].Add(&c, &pi) + } + + // As we employ custom allocation, we should not pass x[1:] + rem = quo_[0] + quo = NewRegularExt(quo_[1:]) + + return quo, rem +} + +// Evaluate a polynomial in Lagrange basis +func Interpolate(v smartvectors.SmartVector, x fext.Element, oncoset ...bool) fext.Element { + switch con := v.(type) { + case *ConstantExt: + return con.val + } + + // Maybe there is an optim for windowed here + res := make([]fext.Element, v.Len()) + v.WriteInSliceExt(res) + return fastpolyext.Interpolate(res, x, oncoset...) +} + +// Batch-evaluate polynomials in Lagrange basis +func BatchInterpolate(vs []smartvectors.SmartVector, x fext.Element, oncoset ...bool) []fext.Element { + + var ( + polys = make([][]fext.Element, len(vs)) + results = make([]fext.Element, len(vs)) + computed = make([]bool, len(vs)) + totalConstant = 0 + ) + + // smartvector to []fr.element + parallel.Execute(len(vs), func(start, stop int) { + for i := start; i < stop; i++ { + switch con := vs[i].(type) { + case *ConstantExt: + // constant vectors + results[i] = con.val + computed[i] = true + totalConstant++ + continue + } + + // non-constant vectors + polys[i] = vs[i].IntoRegVecSaveAllocExt() + } + }) + + if totalConstant == len(vs) { + return results + } + + return batchInterpolateSV(results, computed, polys, x, oncoset...) +} + +// Optimized batch interpolate for smart vectors. +// This reduces the number of computation by pre-processing +// constant vectors in advance in BatchInterpolate() +func batchInterpolateSV(results []fext.Element, computed []bool, polys [][]fext.Element, x fext.Element, oncoset ...bool) []fext.Element { + + n := 0 + for i := range polys { + if len(polys[i]) > 0 { + n = len(polys[i]) + } + } + + if n == 0 { + // that's a possible edge-case and it can happen if all the input polys + // are constant smart-vectors. This is should be prevented by the the + // caller. + return results + } + + if !utils.IsPowerOfTwo(n) { + utils.Panic("only support powers of two but poly has length %v", len(polys)) + } + + domain := fft.NewDomain(n) + denominator := make([]fext.Element, n) + + one := fext.One() + + if len(oncoset) > 0 && oncoset[0] { + x.MulByBase(&x, &domain.FrMultiplicativeGenInv) + } + + /* + First, we compute the denominator, + + D_x = \frac{X}{x} - g for x \in H + where H is the subgroup of the roots of unity (not the coset) + and g a field element such that gH is the coset + */ + denominator[0] = x + for i := 1; i < n; i++ { + denominator[i].MulByBase(&denominator[i-1], &domain.GeneratorInv) + } + + for i := 0; i < n; i++ { + denominator[i].Sub(&denominator[i], &one) + + if denominator[i].IsZero() { + // edge-case : x is a root of unity of the domain. In this case, we can just return + // the associated value for poly + + for k := range polys { + if computed[k] { + continue + } + results[k] = polys[k][i] + } + + return results + } + } + + /* + Then, we compute the sum between the inverse of the denominator + and the poly + + \sum_{x \in H}\frac{P(gx)}{D_x} + */ + denominator = fext.BatchInvert(denominator) + + // Precompute the value of x^n once outside the loop + xN := new(fext.Element).Exp(x, big.NewInt(int64(n))) + + // Precompute the value of domain.CardinalityInv outside the loop + cardinalityInv := &domain.CardinalityInv + + // Compute factor as (x^n - 1) * (1 / domain.Cardinality). + factor := new(fext.Element).Sub(xN, &one) + factor.MulByBase(factor, cardinalityInv) + + parallel.Execute(len(polys), func(start, stop int) { + for k := start; k < stop; k++ { + + if computed[k] { + continue + } + // Compute the scalar product. + res := vectorext.ScalarProd(polys[k], denominator) + + // Multiply res with factor. + res.Mul(&res, factor) + + // Store the result. + results[k] = res + } + }) + + return results +} + +// Evaluate a polynomial in coefficient basis +func EvalCoeff(v smartvectors.SmartVector, x fext.Element) fext.Element { + // Maybe there is an optim for windowed here + res := make([]fext.Element, v.Len()) + v.WriteInSliceExt(res) + return polyext.EvalUnivariate(res, x) +} + +func EvalCoeffBivariate(v smartvectors.SmartVector, x fext.Element, numCoeffX int, y fext.Element) fext.Element { + + if v.Len()%numCoeffX != 0 { + panic("size of v and nb coeff x are inconsistent") + } + + // naive evaluation : we think it is not performance critical + slice := make([]fext.Element, v.Len()) + v.WriteInSliceExt(slice) + + foldOnX := make([]fext.Element, len(slice)/numCoeffX) + for i := 0; i < len(slice); i += numCoeffX { + foldOnX[i/numCoeffX] = polyext.EvalUnivariate(slice[i:i+numCoeffX], x) + } + + return polyext.EvalUnivariate(foldOnX, y) +} diff --git a/prover/maths/common/smartvectorsext/polynomial_test.go b/prover/maths/common/smartvectorsext/polynomial_test.go new file mode 100644 index 000000000..849f8a6bb --- /dev/null +++ b/prover/maths/common/smartvectorsext/polynomial_test.go @@ -0,0 +1,326 @@ +//go:build !race + +package smartvectorsext + +import ( + "fmt" + "github.com/consensys/linea-monorepo/prover/maths/common/polyext" + "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/fft/fastpolyext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "testing" + + "github.com/consensys/linea-monorepo/prover/maths/fft" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRuffini(t *testing.T) { + + testCases := []struct { + q fext.Element + p smartvectors.SmartVector + expectedQuo smartvectors.SmartVector + expectedRem fext.Element + }{ + { + q: fext.NewElement(1, 0), + p: ForTestFromPairs(3, 0, 0, 0, 1, 0), + expectedQuo: ForTestFromPairs(1, 0, 1, 0), + expectedRem: fext.NewElement(4, 0), + }, + { + // 3 = 0 * (X - 1) + 3 + q: fext.NewElement(1, 0), + p: ForTestFromPairs(3, 0), + expectedQuo: NewConstantExt(fext.Zero(), 1), + expectedRem: fext.NewElement(3, 0), + }, + { + // -α^2 - 3 α + α x^3 + x^3 - α^2 x^2 - 2 α x^2 - x^2 + α x + 2 x + 3 = + // (x-(1+alpha))(x^2*(1+alpha)+(2+alpha))+5 + // alpha is a square root used to build the extension field, i.e. alpha^2=fext.RootPowers[1] + q: fext.NewElement(1, 1), + p: ForTestFromPairs(-fext.RootPowers[1]+3, -3, 2, 1, -1-fext.RootPowers[1], -2, 1, 1), + expectedQuo: ForTestFromPairs(2, 1, 0, 0, 1, 1), + expectedRem: fext.NewElement(5, 0), + }, + } + + for _, testCase := range testCases { + + quo, rem := RuffiniQuoRem(testCase.p, testCase.q) + require.Equal(t, testCase.expectedQuo.Pretty(), quo.Pretty()) + require.Equal(t, testCase.expectedRem.String(), rem.String()) + } + +} + +func TestFuzzPolynomial(t *testing.T) { + + for i := 0; i < smartvectors.FuzzIteration; i++ { + + // We reuse the test-case generator of lincomb but we only + // use the first generated edge-case for each. The fact that + // we use two test-cases gives a and b of different length. + tcaseA := newTestBuilder(2 * i).NewTestCaseForLinComb() + tcaseB := newTestBuilder(2*i + 1).NewTestCaseForLinComb() + + success := t.Run(fmt.Sprintf("fuzz-poly-%v", i), func(t *testing.T) { + + a := tcaseA.svecs[0] + b := tcaseB.svecs[0] + + // Try interpolating by one (should return the first element) + xa := Interpolate(a, fext.One()) + expecteda0 := a.GetExt(0) + assert.Equal(t, xa.String(), expecteda0.String()) + + // Get a random x to use as an evaluation point to check polynomial + // identities + var x fext.Element + x.SetRandom() + aX := EvalCoeff(a, x) + bX := EvalCoeff(b, x) + + // Get the evaluations of a-n, b-a, a+b + var aSubBx, bSubAx, aPlusBx fext.Element + aSubBx.Sub(&aX, &bX) + bSubAx.Sub(&bX, &aX) + aPlusBx.Add(&aX, &bX) + + // And evaluate the corresponding polynomials to compare + // with the above values + aSubb := PolySub(a, b) + bSuba := PolySub(b, a) + aPlusb := PolyAdd(a, b) + bPlusa := PolyAdd(b, a) + + aSubBxActual := EvalCoeff(aSubb, x) + bSubAxActual := EvalCoeff(bSuba, x) + aPlusbxActual := EvalCoeff(aPlusb, x) + bPlusaxActual := EvalCoeff(bPlusa, x) + + t.Logf( + "Len of a %v, b %v, a+b %v, a-b %v, b-a %v", + a.Len(), b.Len(), aPlusb.Len(), aSubb.Len(), bSuba.Len(), + ) + + require.Equal(t, aSubBx.String(), aSubBxActual.String()) + require.Equal(t, bSubAx.String(), bSubAxActual.String()) + require.Equal(t, aPlusBx.String(), aPlusbxActual.String()) + require.Equal(t, aPlusBx.String(), bPlusaxActual.String()) + }) + + if !success { + t.Logf("TEST CASE %v\n", i) + t.FailNow() + } + } +} + +func TestBivariatePolynomial(t *testing.T) { + + testCases := []struct { + v smartvectors.SmartVector + x fext.Element + y fext.Element + numCoeffX int + res fext.Element + }{ + { + // P(X) = P1(X)+Y*P2(X) = (1+4)+(3+8)Y = 5+11Y = 5+33 = 38 + v: ForTestExt(1, 2, 3, 4), + x: fext.NewElement(2, 0), + y: fext.NewElement(3, 0), + numCoeffX: 2, + res: fext.NewElement(38, 0), + }, + { + // P(X) = P1(X)+Y*P2(X) + v: ForTestFromPairs(1, 1, 2, 2, 3, 3, 4, 4), + x: fext.NewElement(2, 1), + y: fext.NewElement(3, 2), + numCoeffX: 2, + res: *new(fext.Element). + SetInt64Pair( + int64(44*fext.RootPowers[1]+38), + int64(8*fext.RootPowers[1]+74)), + }, + } + + for i, testCase := range testCases { + + t.Run(fmt.Sprintf("case-%v", i), func(t *testing.T) { + res := EvalCoeffBivariate( + testCase.v, + testCase.x, + testCase.numCoeffX, + testCase.y, + ) + + require.Equal(t, testCase.res.String(), res.String()) + }) + } + +} + +func TestBatchInterpolationWithConstantVector(t *testing.T) { + n := 4 + randPoly := vectorext.ForTest(1, 2, 3, 4) + randPoly2 := vectorext.ForTest(1, 1, 1, 1) + + x := fext.NewElement(51, fieldPaddingInt()) + + expectedY := polyext.EvalUnivariate(randPoly, x) + expectedY2 := polyext.EvalUnivariate(randPoly2, x) + domain := fft.NewDomain(n).WithCoset() + + /* + Test without coset + */ + onRoots := vectorext.DeepCopy(randPoly) + onRoots2 := vectorext.DeepCopy(randPoly2) + polys := make([][]fext.Element, 2) + polys[0] = onRoots + polys[1] = onRoots2 + + domain.FFTExt(polys[0], fft.DIF) + domain.FFTExt(polys[1], fft.DIF) + fft.BitReverseExt(polys[0]) + fft.BitReverseExt(polys[1]) + + yOnRoots := fastpolyext.BatchInterpolate(polys, x) + require.Equal(t, expectedY.String(), yOnRoots[0].String()) + require.Equal(t, expectedY2.String(), yOnRoots[1].String()) + + /* + Test with coset + */ + onCoset := vectorext.DeepCopy(randPoly) + onCoset2 := vectorext.DeepCopy(randPoly2) + onCosets := make([][]fext.Element, 2) + onCosets[0] = onCoset + onCosets[1] = onCoset2 + + domain.FFTExt(onCosets[0], fft.DIF, fft.OnCoset()) + domain.FFTExt(onCosets[1], fft.DIF, fft.OnCoset()) + fft.BitReverseExt(onCosets[0]) + fft.BitReverseExt(onCosets[1]) + + yOnCosets := fastpolyext.BatchInterpolate(onCosets, x, true) + require.Equal(t, expectedY.String(), yOnCosets[0].String()) + require.Equal(t, expectedY2.String(), yOnCosets[1].String()) + +} + +func TestBatchInterpolateOnlyConstantVector(t *testing.T) { + n := 4 + randPoly := vectorext.ForTest(1, 1, 1, 1) + randPoly2 := vectorext.ForTest(2, 2, 2, 2) + x := fext.NewElement(51, fieldPaddingInt()) + + expectedY := polyext.EvalUnivariate(randPoly, x) + expectedY2 := polyext.EvalUnivariate(randPoly2, x) + domain := fft.NewDomain(n).WithCoset() + + /* + Test without coset + */ + onRoots := vectorext.DeepCopy(randPoly) + onRoots2 := vectorext.DeepCopy(randPoly2) + polys := make([][]fext.Element, 2) + polys[0] = onRoots + polys[1] = onRoots2 + + domain.FFTExt(polys[0], fft.DIF) + domain.FFTExt(polys[1], fft.DIF) + fft.BitReverseExt(polys[0]) + fft.BitReverseExt(polys[1]) + + yOnRoots := fastpolyext.BatchInterpolate(polys, x) + require.Equal(t, expectedY.String(), yOnRoots[0].String()) + require.Equal(t, expectedY2.String(), yOnRoots[1].String()) + + /* + Test with coset + */ + onCoset := vectorext.DeepCopy(randPoly) + onCoset2 := vectorext.DeepCopy(randPoly2) + onCosets := make([][]fext.Element, 2) + onCosets[0] = onCoset + onCosets[1] = onCoset2 + + domain.FFTExt(onCosets[0], fft.DIF, fft.OnCoset()) + domain.FFTExt(onCosets[1], fft.DIF, fft.OnCoset()) + fft.BitReverseExt(onCosets[0]) + fft.BitReverseExt(onCosets[1]) + + yOnCosets := fastpolyext.BatchInterpolate(onCosets, x, true) + require.Equal(t, expectedY.String(), yOnCosets[0].String()) + require.Equal(t, expectedY2.String(), yOnCosets[1].String()) +} + +// three vectors to see if range check and continue statement +// for edge cases works as expected +func TestBatchInterpolationThreeVectors(t *testing.T) { + n := 4 + randPoly := vectorext.ForTest(1, 2, 3, 4) + randPoly2 := vectorext.ForTest(1, 1, 1, 1) + randPoly3 := vectorext.ForTest(1, 2, 3, 4) + + x := fext.NewElement(51, fieldPaddingInt()) + + expectedY := polyext.EvalUnivariate(randPoly, x) + expectedY2 := polyext.EvalUnivariate(randPoly2, x) + expectedY3 := polyext.EvalUnivariate(randPoly3, x) + domain := fft.NewDomain(n).WithCoset() + + /* + Test without coset + */ + onRoots := vectorext.DeepCopy(randPoly) + onRoots2 := vectorext.DeepCopy(randPoly2) + onRoots3 := vectorext.DeepCopy(randPoly3) + polys := make([][]fext.Element, 3) + polys[0] = onRoots + polys[1] = onRoots2 + polys[2] = onRoots3 + + domain.FFTExt(polys[0], fft.DIF) + domain.FFTExt(polys[1], fft.DIF) + domain.FFTExt(polys[2], fft.DIF) + fft.BitReverseExt(polys[0]) + fft.BitReverseExt(polys[1]) + fft.BitReverseExt(polys[2]) + + yOnRoots := fastpolyext.BatchInterpolate(polys, x) + require.Equal(t, expectedY.String(), yOnRoots[0].String()) + require.Equal(t, expectedY2.String(), yOnRoots[1].String()) + require.Equal(t, expectedY3.String(), yOnRoots[2].String()) + + /* + Test with coset + */ + onCoset := vectorext.DeepCopy(randPoly) + onCoset2 := vectorext.DeepCopy(randPoly2) + onCoset3 := vectorext.DeepCopy(randPoly3) + onCosets := make([][]fext.Element, 3) + onCosets[0] = onCoset + onCosets[1] = onCoset2 + onCosets[2] = onCoset3 + + domain.FFTExt(onCosets[0], fft.DIF, fft.OnCoset()) + domain.FFTExt(onCosets[1], fft.DIF, fft.OnCoset()) + domain.FFTExt(onCosets[2], fft.DIF, fft.OnCoset()) + fft.BitReverseExt(onCosets[0]) + fft.BitReverseExt(onCosets[1]) + fft.BitReverseExt(onCosets[2]) + + yOnCosets := fastpolyext.BatchInterpolate(onCosets, x, true) + require.Equal(t, expectedY.String(), yOnCosets[0].String()) + require.Equal(t, expectedY2.String(), yOnCosets[1].String()) + require.Equal(t, expectedY3.String(), yOnCosets[2].String()) + +} diff --git a/prover/maths/common/smartvectorsext/regular_ext.go b/prover/maths/common/smartvectorsext/regular.go similarity index 90% rename from prover/maths/common/smartvectorsext/regular_ext.go rename to prover/maths/common/smartvectorsext/regular.go index d11fc98a9..bcd42dc5a 100644 --- a/prover/maths/common/smartvectorsext/regular_ext.go +++ b/prover/maths/common/smartvectorsext/regular.go @@ -3,7 +3,7 @@ package smartvectorsext import ( "fmt" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field/fext" "github.com/consensys/linea-monorepo/prover/maths/common/mempoolext" @@ -13,10 +13,10 @@ import ( const conversionError = "smartvector holds field extensions, but a base element was requested" -// It's normal vector in a nutshell +// RegularExt is s normal vector in a nutshell type RegularExt []fext.Element -// Instanstiate a new regular from a slice. Returns a pointer so that the result +// NewRegularExt instanstiate a new regular from a slice. Returns a pointer so that the result // can be reused without referencing as a SmartVector. func NewRegularExt(v []fext.Element) *RegularExt { assertStrictPositiveLen(len(v)) @@ -24,10 +24,10 @@ func NewRegularExt(v []fext.Element) *RegularExt { return &res } -// Returns the length of the regular vector +// Len returns the length of the regular vector func (r *RegularExt) Len() int { return len(*r) } -// Returns a particular element of the vector +// GetBase returns a particular element of the vector func (r *RegularExt) GetBase(n int) (field.Element, error) { return field.Zero(), fmt.Errorf(conversionError) } @@ -44,7 +44,7 @@ func (r *RegularExt) Get(n int) field.Element { return res } -// Returns a subvector of the regular +// SubVector returns a subvector of the regular type func (r *RegularExt) SubVector(start, stop int) smartvectors.SmartVector { if start > stop { utils.Panic("Negative length are not allowed") @@ -56,7 +56,7 @@ func (r *RegularExt) SubVector(start, stop int) smartvectors.SmartVector { return &res } -// Rotates the vector into a new one +// RotateRight rotates the vector into a new one func (r *RegularExt) RotateRight(offset int) smartvectors.SmartVector { resSlice := make(RegularExt, r.Len()) @@ -87,14 +87,14 @@ func (r *RegularExt) RotateRight(offset int) smartvectors.SmartVector { } func (r *RegularExt) WriteInSlice(s []field.Element) { - panic("conversionError") + panic(conversionError) } func (r *RegularExt) WriteInSliceExt(s []fext.Element) { assertHasLength(len(s), len(*r)) for i := 0; i < len(s); i++ { - elem, _ := r.GetBase(i) - s[i].SetFromBase(&elem) + elem := r.GetExt(i) + s[i].Set(&elem) } } diff --git a/prover/maths/common/smartvectorsext/rotated_ext.go b/prover/maths/common/smartvectorsext/rotated.go similarity index 98% rename from prover/maths/common/smartvectorsext/rotated_ext.go rename to prover/maths/common/smartvectorsext/rotated.go index 22c8e3e41..bfa354aa1 100644 --- a/prover/maths/common/smartvectorsext/rotated_ext.go +++ b/prover/maths/common/smartvectorsext/rotated.go @@ -3,7 +3,7 @@ package smartvectorsext import ( "fmt" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/maths/field/fext" "github.com/consensys/linea-monorepo/prover/utils" diff --git a/prover/maths/common/smartvectorsext/rotated_ext_test.go b/prover/maths/common/smartvectorsext/rotated_test.go similarity index 97% rename from prover/maths/common/smartvectorsext/rotated_ext_test.go rename to prover/maths/common/smartvectorsext/rotated_test.go index 839ecaede..0159538e4 100644 --- a/prover/maths/common/smartvectorsext/rotated_ext_test.go +++ b/prover/maths/common/smartvectorsext/rotated_test.go @@ -2,7 +2,7 @@ package smartvectorsext import ( "fmt" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field/fext" "testing" diff --git a/prover/maths/common/smartvectorsext/smartvector_test.go b/prover/maths/common/smartvectorsext/smartvector_test.go new file mode 100644 index 000000000..0ff371e3b --- /dev/null +++ b/prover/maths/common/smartvectorsext/smartvector_test.go @@ -0,0 +1,113 @@ +//go:build !race + +package smartvectorsext + +import ( + "fmt" + "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "testing" + + "github.com/consensys/linea-monorepo/prover/utils" + "github.com/stretchr/testify/require" +) + +func TestWriteInSlice(t *testing.T) { + for i := 0; i < smartvectors.FuzzIteration; i++ { + // We reuse the test case generator for linear combinations. We only + // care about the first vector. + builder := newTestBuilder(i) + tcase := builder.NewTestCaseForLinComb() + + success := t.Run( + fmt.Sprintf("fuzzy-write-in-slice-%v", i), + func(t *testing.T) { + v := tcase.svecs[0] + + slice := make([]fext.Element, v.Len()) + v.WriteInSliceExt(slice) + + for j := range slice { + x := v.GetExt(j) + require.Equal(t, x.String(), slice[j].String()) + } + + // write in a random place of the slice + randPos := builder.gen.IntN(v.Len()) + slice[randPos].SetRandom() + x := v.GetExt(randPos) + require.NotEqual(t, x.String(), randPos, "forbidden shallow copy") + }, + ) + + require.True(t, success) + } +} + +func TestShiftingTest(t *testing.T) { + for i := 0; i < smartvectors.FuzzIteration; i++ { + // We reuse the test case generator for linear combinations. We only + // care about the first vector. + builder := newTestBuilder(i) + tcase := builder.NewTestCaseForLinComb() + + success := t.Run( + fmt.Sprintf("fuzzy-shifting-%v", i), + func(t *testing.T) { + v := tcase.svecs[0] + + offset := builder.gen.IntN(v.Len()) + + shifted := v.RotateRight(offset) + revShifted := v.RotateRight(-offset) + + for i := 0; i < v.Len(); i++ { + x := v.GetExt(i) + xR := shifted.GetExt(utils.PositiveMod(i+offset, v.Len())) + xL := revShifted.GetExt(utils.PositiveMod(i-offset, v.Len())) + + require.Equal(t, x.String(), xL.String()) + require.Equal(t, x.String(), xR.String()) + } + }, + ) + + require.True(t, success) + } + +} + +func TestSubvectorFuzzy(t *testing.T) { + + for i := 0; i < smartvectors.FuzzIteration; i++ { + + // We reuse the test case generator for linear combinations. We only + // care about the first vector. + builder := newTestBuilder(i) + tcase := builder.NewTestCaseForLinComb() + + success := t.Run( + fmt.Sprintf("fuzzy-shifting-%v", i), + func(t *testing.T) { + v := tcase.svecs[0] + length := v.Len() + // generate the subvector window + stop := 1 + builder.gen.IntN(length-1) + start := builder.gen.IntN(stop) + + sub := v.SubVector(start, stop) + + require.Equal(t, stop-start, sub.Len(), "subvector has wrong size") + + for i := 0; i < stop-start; i++ { + expected := v.GetExt(start + i) + actual := sub.GetExt(i) + require.Equal(t, expected.String(), actual.String(), "Start %v, Stop %v, i %v", start, stop, i) + } + + }, + ) + + require.True(t, success) + } +} diff --git a/prover/maths/common/smartvectorsext/smartvectors_op.go b/prover/maths/common/smartvectorsext/smartvectors_op.go index 0cfceb359..24e4b25b0 100644 --- a/prover/maths/common/smartvectorsext/smartvectors_op.go +++ b/prover/maths/common/smartvectorsext/smartvectors_op.go @@ -4,26 +4,41 @@ import ( "fmt" "github.com/consensys/gnark/frontend" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext/gnarkfext" "github.com/consensys/linea-monorepo/prover/utils" ) -// ForTest returns a witness from a explicit litteral assignement +// ForTestExt returns a regular smartvector with field extensions of the vector xs +// The field extensions are simple wrappers of the base field, padded with 0s func ForTestExt(xs ...int) smartvectors.SmartVector { return NewRegularExt(vectorext.ForTest(xs...)) } +// ForTestFromVect computes a regular smartvector of field extensions, +// where each field extension is populated using one vector of size [fext.ExtensionDegree] +func ForTestFromVect(xs ...[fext.ExtensionDegree]int) smartvectors.SmartVector { + return NewRegularExt(vectorext.ForTestFromVect(xs...)) +} + +// ForTestFromPairs groups the inputs into pairs and computes a regular smartvector of +// field extensions, where each field extension has only the first two coordinates populated. +func ForTestFromPairs(xs ...int) smartvectors.SmartVector { + return NewRegularExt(vectorext.ForTestFromPairs(xs...)) +} + // IntoRegVec converts a smart-vector into a normal vec. The resulting vector // is always reallocated and can be safely mutated without side-effects // on s. func IntoRegVec(s smartvectors.SmartVector) []field.Element { - res := make([]field.Element, s.Len()) - s.WriteInSlice(res) - return res + panic(conversionError) } +// IntoRegVecExt converts a smart-vector into a normal vector of field extensions. +// The resulting vector is always reallocated and can be safely mutated without side-effects +// on s. func IntoRegVecExt(s smartvectors.SmartVector) []fext.Element { res := make([]fext.Element, s.Len()) s.WriteInSliceExt(res) @@ -31,18 +46,13 @@ func IntoRegVecExt(s smartvectors.SmartVector) []fext.Element { } // IntoGnarkAssignment converts a smart-vector into a gnark assignment -func IntoGnarkAssignment(sv smartvectors.SmartVector) []frontend.Variable { - res := make([]frontend.Variable, sv.Len()) - _, err := sv.GetBase(0) - if err == nil { - for i := range res { - elem, _ := sv.GetBase(i) - res[i] = elem - } - } else { - for i := range res { - elem := sv.GetExt(i) - res[i] = elem +func IntoGnarkAssignment(sv smartvectors.SmartVector) []gnarkfext.Variable { + res := make([]gnarkfext.Variable, sv.Len()) + for i := range res { + elem := sv.GetExt(i) + res[i] = gnarkfext.Variable{ + A0: frontend.Variable(elem.A0), + A1: frontend.Variable(elem.A1), } } return res diff --git a/prover/maths/common/smartvectorsext/windowed_ext.go b/prover/maths/common/smartvectorsext/windowed.go similarity index 99% rename from prover/maths/common/smartvectorsext/windowed_ext.go rename to prover/maths/common/smartvectorsext/windowed.go index 6e2ef8013..97a155aac 100644 --- a/prover/maths/common/smartvectorsext/windowed_ext.go +++ b/prover/maths/common/smartvectorsext/windowed.go @@ -3,7 +3,7 @@ package smartvectorsext import ( "fmt" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/maths/field/fext" "github.com/consensys/linea-monorepo/prover/utils" diff --git a/prover/maths/common/smartvectorsext/windowed_ext_test.go b/prover/maths/common/smartvectorsext/windowed_test.go similarity index 96% rename from prover/maths/common/smartvectorsext/windowed_ext_test.go rename to prover/maths/common/smartvectorsext/windowed_test.go index 64e7207ac..dc0e78ff5 100644 --- a/prover/maths/common/smartvectorsext/windowed_ext_test.go +++ b/prover/maths/common/smartvectorsext/windowed_test.go @@ -2,7 +2,7 @@ package smartvectorsext import ( "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" "github.com/consensys/linea-monorepo/prover/maths/field/fext" "testing" diff --git a/prover/maths/common/vector/vector.go b/prover/maths/common/vector/vector.go index 3bee37017..610a1ffd9 100644 --- a/prover/maths/common/vector/vector.go +++ b/prover/maths/common/vector/vector.go @@ -4,7 +4,7 @@ package vector import ( "fmt" - "math/rand" + "math/rand/v2" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark/frontend" diff --git a/prover/maths/common/smartvectors/vectorext/vector.go b/prover/maths/common/vectorext/vector.go similarity index 89% rename from prover/maths/common/smartvectors/vectorext/vector.go rename to prover/maths/common/vectorext/vector.go index 56993d597..6494e9998 100644 --- a/prover/maths/common/smartvectors/vectorext/vector.go +++ b/prover/maths/common/vectorext/vector.go @@ -122,29 +122,38 @@ func (vector *Vector) AsyncReadFrom(r io.Reader) (int64, error, chan error) { var cptErrors uint64 // process the elements in parallel execute(int(sliceLen), func(start, end int) { - - subElems := make([]fr.Element, 2) for i := start; i < end; i++ { - // we have to set vector[i] - for j := 0; j < 2; j++ { - var z fr.Element - bstart := (i + j) * frBytes - bend := bstart + frBytes - b := bSlice[bstart:bend] - z[0] = binary.BigEndian.Uint64(b[24:32]) - z[1] = binary.BigEndian.Uint64(b[16:24]) - z[2] = binary.BigEndian.Uint64(b[8:16]) - z[3] = binary.BigEndian.Uint64(b[0:8]) - - if !fext.SmallerThanModulus(&z) { - atomic.AddUint64(&cptErrors, 1) - return - } - fext.ToMont(&z) - subElems[j] = z + var z fr.Element + bstart := i * 2 * frBytes + bend := bstart + frBytes + b := bSlice[bstart:bend] + z[0] = binary.BigEndian.Uint64(b[24:32]) + z[1] = binary.BigEndian.Uint64(b[16:24]) + z[2] = binary.BigEndian.Uint64(b[8:16]) + z[3] = binary.BigEndian.Uint64(b[0:8]) + + if !fext.SmallerThanModulus(&z) { + atomic.AddUint64(&cptErrors, 1) + return + } + fext.ToMont(&z) + (*vector)[i].A0.Set(&z) + // set second coordinate + var w fr.Element + cstart := (i*2 + 1) * frBytes + cend := cstart + frBytes + c := bSlice[cstart:cend] + w[0] = binary.BigEndian.Uint64(c[24:32]) + w[1] = binary.BigEndian.Uint64(c[16:24]) + w[2] = binary.BigEndian.Uint64(c[8:16]) + w[3] = binary.BigEndian.Uint64(c[0:8]) + + if !fext.SmallerThanModulus(&w) { + atomic.AddUint64(&cptErrors, 1) + return } - zExt := fext.Element{subElems[0], subElems[1]} - (*vector)[i] = zExt + fext.ToMont(&w) + (*vector)[i].A1.Set(&w) } }) diff --git a/prover/maths/common/smartvectors/vectorext/vector_ops.go b/prover/maths/common/vectorext/vector_ops.go similarity index 100% rename from prover/maths/common/smartvectors/vectorext/vector_ops.go rename to prover/maths/common/vectorext/vector_ops.go diff --git a/prover/maths/common/vectorext/vector_test.go b/prover/maths/common/vectorext/vector_test.go new file mode 100644 index 000000000..eece78b5f --- /dev/null +++ b/prover/maths/common/vectorext/vector_test.go @@ -0,0 +1,199 @@ +package vectorext_test + +import ( + "fmt" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestVectors(t *testing.T) { + + var ( + // a, b and x are very common vectors in all the tests + a = vectorext.ForTestFromPairs(1, 2, 3, 4, 5, 6) + b = vectorext.ForTestFromPairs(3, 4, 5, 6, 7, 8) + x = fext.NewElement(2, 0) + + // aBAndXMustNotChange asserts that a and b did not change as this is + // a very common check in all the sub-tests. + aBAndXMustNotChange = func(t *testing.T) { + require.Equal(t, vectorext.ForTestFromPairs(1, 2, 3, 4, 5, 6), a, "a must not change") + require.Equal(t, vectorext.ForTestFromPairs(3, 4, 5, 6, 7, 8), b, "b must not change") + require.Equal(t, "2+0*u", x.String(), "x must not change") + } + ) + + t.Run("DeepCopy", func(t *testing.T) { + c := vectorext.DeepCopy(a) + assert.Equal(t, a, c, "the deep copied vector must be equal") + c[0] = fext.NewElement(40, 0) + aBAndXMustNotChange(t) + }) + + t.Run("ScalarMul", func(t *testing.T) { + c := vectorext.DeepCopy(a) + vectorext.ScalarMul(c, b, x) + assert.Equal(t, vectorext.ForTestFromPairs(6, 8, 10, 12, 14, 16), c, "c must be equal to 2*b") + vectorext.ScalarMul(c, c, x) + assert.Equal(t, vectorext.ForTestFromPairs(12, 16, 20, 24, 28, 32), c, "c must be equal to 4*b") + aBAndXMustNotChange(t) + }) + + t.Run("ScalarProd", func(t *testing.T) { + c := vectorext.ScalarProd(a, b) + assert.Equal(t, fmt.Sprintf("%d+%d*u", 80*fext.RootPowers[1]+53, 130), c.String()) + aBAndXMustNotChange(t) + }) + + t.Run("Rand", func(t *testing.T) { + c, d := vectorext.Rand(5), vectorext.Rand(5) + assert.NotEqual(t, c, d, "Rand should not return twice the same value") + }) + + t.Run("MulElementWise", func(t *testing.T) { + c := vectorext.DeepCopy(b) + vectorext.MulElementWise(c, b, a) + assert.Equal(t, vectorext.ForTestFromPairs( + 3+8*fext.RootPowers[1], + 10, + 24*fext.RootPowers[1]+15, + 38, + 35+48*fext.RootPowers[1], + 82, + ), c) + + c = vectorext.DeepCopy(b) + vectorext.MulElementWise(c, c, a) + assert.Equal(t, vectorext.ForTestFromPairs( + 3+8*fext.RootPowers[1], + 10, + 24*fext.RootPowers[1]+15, + 38, + 35+48*fext.RootPowers[1], + 82, + ), c) + + aBAndXMustNotChange(t) + }) + + t.Run("Prettify", func(t *testing.T) { + assert.Equal(t, "[1+2*u, 3+4*u, 5+6*u]", vectorext.Prettify(a)) + aBAndXMustNotChange(t) + }) + + t.Run("Reverse", func(t *testing.T) { + c := vectorext.DeepCopy(a) + vectorext.Reverse(c) + // we invert the order of the pairs, but not the order inside the pairs as that + // would lead to different field extensions + assert.Equal(t, vectorext.ForTestFromPairs(5, 6, 3, 4, 1, 2), c) + aBAndXMustNotChange(t) + }) + + t.Run("Repeat", func(t *testing.T) { + y := fext.NewElement(1, 2) + c := vectorext.Repeat(y, 4) + assert.Equal(t, vectorext.ForTestFromPairs(1, 2, 1, 2, 1, 2, 1, 2), c) + aBAndXMustNotChange(t) + }) + + t.Run("Add", func(t *testing.T) { + c := vectorext.DeepCopy(a) + vectorext.Add(c, a, b) + assert.Equal(t, vectorext.ForTestFromPairs(4, 6, 8, 10, 12, 14), c) + + c = vectorext.DeepCopy(a) + vectorext.Add(c, c, b) + assert.Equal(t, vectorext.ForTestFromPairs(4, 6, 8, 10, 12, 14), c) + + c = vectorext.DeepCopy(a) + vectorext.Add(c, a, b, a) + assert.Equal(t, vectorext.ForTestFromPairs(5, 8, 11, 14, 17, 20), c) + aBAndXMustNotChange(t) + }) + + t.Run("Sub", func(t *testing.T) { + c := vectorext.DeepCopy(a) + vectorext.Sub(c, b, a) + assert.Equal(t, vectorext.ForTestFromPairs(2, 2, 2, 2, 2, 2), c) + + c = vectorext.DeepCopy(a) + vectorext.Sub(c, b, c) + assert.Equal(t, vectorext.ForTestFromPairs(2, 2, 2, 2, 2, 2), c) + + c = vectorext.DeepCopy(b) + vectorext.Sub(c, c, a) + assert.Equal(t, vectorext.ForTestFromPairs(2, 2, 2, 2, 2, 2), c) + aBAndXMustNotChange(t) + }) + + t.Run("ZeroPad", func(t *testing.T) { + c := vectorext.ZeroPad(a, 5) + assert.Equal(t, vectorext.ForTestFromPairs(1, 2, 3, 4, 5, 6, 0, 0, 0, 0), c) + aBAndXMustNotChange(t) + }) + + t.Run("Interleave", func(t *testing.T) { + c := vectorext.Interleave(a, b) + assert.Equal(t, vectorext.ForTestFromPairs(1, 2, 3, 4, 3, 4, 5, 6, 5, 6, 7, 8), c) + aBAndXMustNotChange(t) + }) + + t.Run("Fill", func(t *testing.T) { + c := vectorext.DeepCopy(a) + vectorext.Fill(c, x) + assert.Equal(t, vectorext.ForTestFromPairs(2, 0, 2, 0, 2, 0), c) + aBAndXMustNotChange(t) + }) + + t.Run("PowerVec", func(t *testing.T) { + c := vectorext.PowerVec(x, 5) + assert.Equal(t, vectorext.ForTestFromPairs(1, 0, 2, 0, 4, 0, 8, 0, 16, 0), c) + }) + + t.Run("IntoGnarkAssignment", func(t *testing.T) { + c := vectorext.IntoGnarkAssignment(a) + for i := range c { + first := c[i].A0.(field.Element) + second := c[i].A1.(field.Element) + assert.Equal(t, a[i].A0.String(), first.String()) + assert.Equal(t, a[i].A1.String(), second.String()) + } + aBAndXMustNotChange(t) + }) + +} + +func TestReverse(t *testing.T) { + vec := []fext.Element{ + fext.NewElement(0, 0), + fext.NewElement(1, 0), + fext.NewElement(2, 0), + } + vectorext.Reverse(vec) + require.Equal(t, vec[0], fext.NewElement(2, 0)) + require.Equal(t, vec[1], fext.NewElement(1, 0)) + require.Equal(t, vec[2], fext.NewElement(0, 0)) +} + +func TestScalarProd(t *testing.T) { + require.Equal(t, + vectorext.ScalarProd( + vectorext.ForTest(1, 2, 3, 4), + vectorext.ForTest(1, 2, 3, 4), + ), + fext.NewElement(30, 0), + ) +} + +func TestForTest(t *testing.T) { + testcase := vectorext.ForTest(-1, 0, 1) + require.Equal(t, testcase[0].String(), "-1+0*u") + require.Equal(t, testcase[1].String(), "0+0*u") + require.Equal(t, testcase[2].String(), "1+0*u") +} diff --git a/prover/maths/common/vectorext/vector_utils_test.go b/prover/maths/common/vectorext/vector_utils_test.go new file mode 100644 index 000000000..3dcf5b198 --- /dev/null +++ b/prover/maths/common/vectorext/vector_utils_test.go @@ -0,0 +1,70 @@ +// Copyright 2020-2024 Consensys Software Inc. +// Licensed under the Apache License, Version 2.0. See the LICENSE file for details. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package vectorext + +import ( + "bytes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "reflect" + "testing" +) + +const fuzzIteration = 20 + +func TestVectorRoundTrip(t *testing.T) { + for it := 0; it < fuzzIteration; it++ { + + v := make(Vector, 10) + for i := 0; i < 10; i++ { + v[i].SetRandom() + } + + b, err := v.MarshalBinary() + assert.NoError(t, err) + + var w1, w2 Vector + + err = w1.UnmarshalBinary(b) + assert.NoError(t, err) + + err = w2.unmarshalBinaryAsync(b) + assert.NoError(t, err) + + assert.True(t, reflect.DeepEqual(v, w1)) + assert.True(t, reflect.DeepEqual(v, w2)) + } + +} + +func TestVectorEmptyRoundTrip(t *testing.T) { + assert := require.New(t) + + v1 := make(Vector, 0) + + b, err := v1.MarshalBinary() + assert.NoError(err) + + var v2, v3 Vector + + err = v2.UnmarshalBinary(b) + assert.NoError(err) + + err = v3.unmarshalBinaryAsync(b) + assert.NoError(err) + + assert.True(reflect.DeepEqual(v1, v2)) + assert.True(reflect.DeepEqual(v3, v2)) +} + +func (vector *Vector) unmarshalBinaryAsync(data []byte) error { + r := bytes.NewReader(data) + _, err, chErr := vector.AsyncReadFrom(r) + if err != nil { + return err + } + return <-chErr +} diff --git a/prover/maths/common/smartvectors/vectorext/vectorext.go b/prover/maths/common/vectorext/vectorext.go similarity index 84% rename from prover/maths/common/smartvectors/vectorext/vectorext.go rename to prover/maths/common/vectorext/vectorext.go index 73c34f196..72e96ed52 100644 --- a/prover/maths/common/smartvectors/vectorext/vectorext.go +++ b/prover/maths/common/vectorext/vectorext.go @@ -4,10 +4,11 @@ package vectorext import ( "fmt" - "github.com/consensys/linea-monorepo/prover/maths/field/fext" - "math/rand" + "math/rand/v2" "github.com/consensys/gnark/frontend" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext/gnarkfext" "github.com/consensys/linea-monorepo/prover/utils" ) @@ -103,6 +104,30 @@ func ForTest(xs ...int) []fext.Element { return res } +// ForTestFromVect computes a vector of field extensions, +// where each field extension is populated using one vector of size [fext.ExtensionDegree] +func ForTestFromVect(xs ...[fext.ExtensionDegree]int) []fext.Element { + res := make([]fext.Element, len(xs)) + for i, x := range xs { + res[i].SetFromVector(x) + } + return res +} + +// ForTestFromPairs groups the input into pairs. Each pair populates the first two +// coordinates of a field extension, and the function then +// returns a vector instantiated these field extension elements. +func ForTestFromPairs(xs ...int) []fext.Element { + if len(xs)%2 != 0 { + panic("ForTestFromPairs must receive an even-length input vector") + } + res := make([]fext.Element, len(xs)/2) + for i := 0; i < len(res); i++ { + res[i].SetInt64Pair(int64(xs[2*i]), int64(xs[2*i+1])) + } + return res +} + // Add adds two vectors `a` and `b` and put the result in `res` // `res` must be pre-allocated by the caller and res, a and b must all have // the same size. @@ -221,10 +246,10 @@ func PowerVec(x fext.Element, n int) []fext.Element { // IntoGnarkAssignment converts an array of field.Element into an array of // frontend.Variable that can be used to assign a vector of frontend.Variable // in a circuit or to generate a vector of constant in the circuit definition. -func IntoGnarkAssignment(msgData []fext.Element) []frontend.Variable { - assignedMsg := []frontend.Variable{} +func IntoGnarkAssignment(msgData []fext.Element) []gnarkfext.Variable { + assignedMsg := []gnarkfext.Variable{} for _, x := range msgData { - assignedMsg = append(assignedMsg, frontend.Variable(x)) + assignedMsg = append(assignedMsg, gnarkfext.Variable{frontend.Variable(x.A0), frontend.Variable(x.A1)}) } return assignedMsg } diff --git a/prover/maths/fft/bitreverseext.go b/prover/maths/fft/bitreverseext.go new file mode 100644 index 000000000..61131b7cb --- /dev/null +++ b/prover/maths/fft/bitreverseext.go @@ -0,0 +1,23 @@ +package fft + +import ( + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" +) + +// BitReverseExt applies the bit-reversal permutation to v. +// len(v) must be a power of 2 +func BitReverseExt(v []fext.Element) { + firstCoord := make([]field.Element, len(v)) + secondCoord := make([]field.Element, len(v)) + for i := 0; i < len(v); i++ { + firstCoord[i].Set(&v[i].A0) + secondCoord[i].Set(&v[i].A1) + } + BitReverse(firstCoord) + BitReverse(secondCoord) + for i := 0; i < len(v); i++ { + v[i].A0.Set(&firstCoord[i]) + v[i].A1.Set(&secondCoord[i]) + } +} diff --git a/prover/maths/fft/fastpoly/fastpoly_test.go b/prover/maths/fft/fastpoly/fastpoly_test.go index fdbfadfc7..ea9e09272 100644 --- a/prover/maths/fft/fastpoly/fastpoly_test.go +++ b/prover/maths/fft/fastpoly/fastpoly_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestMulitplication(t *testing.T) { +func TestMultiplication(t *testing.T) { n := 8 // smallN := 6 diff --git a/prover/maths/fft/fastpolyext/fastpoly.go b/prover/maths/fft/fastpolyext/fastpoly.go new file mode 100644 index 000000000..6a5c4138a --- /dev/null +++ b/prover/maths/fft/fastpolyext/fastpoly.go @@ -0,0 +1,50 @@ +package fastpolyext + +import ( + "fmt" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + + "github.com/consensys/linea-monorepo/prover/maths/fft" +) + +// Multiply twi polynomial modulo X^n - 1 +// a and b must be in coefficient form, the result is in coefficient +// form +// a and b are destroyed during the operation +func MultModXMinus1(domain *fft.Domain, res, a, b []fext.Element) { + // All the item must be of the right size + if len(a) != len(b) || len(a) != len(res) || uint64(len(a)) != domain.Cardinality { + panic( + fmt.Sprintf("All items should have the right size %v %v %v %v", + domain.Cardinality, len(res), len(a), len(b)), + ) + } + + domain.FFTExt(a, fft.DIF) + domain.FFTExt(b, fft.DIF) + vectorext.MulElementWise(res, a, b) + domain.FFTInverseExt(res, fft.DIT) + +} + +// Multiply two polynomials modulo X^n - 1 +// `a` must be in coefficient form +// `precomp` must be in evaluation form over the domain (DIT) +// `res` can be either `a` or any pre-allocated array +// res must pre-allocated in all cases +// a is destroyed during the operation +func MultModXnMinus1Precomputed(domain *fft.Domain, res, a, precomp []fext.Element) { + + // All the item must be of the right size + if len(a) != len(precomp) || len(a) != len(res) || uint64(len(a)) != domain.Cardinality { + panic( + fmt.Sprintf("All items should have the right size %v %v %v %v", + domain.Cardinality, len(res), len(a), len(precomp)), + ) + } + + domain.FFTExt(a, fft.DIF) + vectorext.MulElementWise(res, a, precomp) + domain.FFTInverseExt(res, fft.DIT) +} diff --git a/prover/maths/fft/fastpolyext/fastpoly_test.go b/prover/maths/fft/fastpolyext/fastpoly_test.go new file mode 100644 index 000000000..1bda0d5b7 --- /dev/null +++ b/prover/maths/fft/fastpolyext/fastpoly_test.go @@ -0,0 +1,76 @@ +package fastpolyext_test + +import ( + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/fft/fastpolyext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "testing" + + "github.com/consensys/linea-monorepo/prover/maths/fft" + "github.com/stretchr/testify/require" +) + +func TestMultiplication(t *testing.T) { + + n := 8 + // smallN := 6 + domain := fft.NewDomain(n) + + // Unitary X : multiplying by it results in identity + { + unit := make([]fext.Element, n) + unit[0].SetOne() + + vec := vectorext.Rand(n) + vecBackup := vectorext.DeepCopy(vec) + res := make([]fext.Element, n) + fastpolyext.MultModXMinus1(domain, res, vec, unit) + + require.Equal(t, vectorext.Prettify(vecBackup), vectorext.Prettify(res)) + } + + // Unitary X : multiplying by it results in identity + // With precomputation + { + unit := make([]fext.Element, n) + unit[0].SetOne() + domain.FFTExt(unit, fft.DIF) + + vec := vectorext.Rand(n) + vecBackup := vectorext.DeepCopy(vec) + res := make([]fext.Element, n) + fastpolyext.MultModXnMinus1Precomputed(domain, res, vec, unit) + + require.Equal(t, vectorext.Prettify(vecBackup), vectorext.Prettify(res)) + } + + // Polynomial X : multiplying by it results in "circular" permutation + { + shift := make([]fext.Element, n) + shift[1].SetOne() + + vec := vectorext.Rand(n) + vecBackup := vectorext.DeepCopy(vec) + res := make([]fext.Element, n) + fastpolyext.MultModXMinus1(domain, res, vec, shift) + + require.Equal(t, vectorext.Prettify(res[1:]), vectorext.Prettify(vecBackup[:n-1])) + require.Equal(t, res[0].String(), vecBackup[n-1].String()) + } + + // Polynomial X : multiplication with precomputation + { + shift := make([]fext.Element, n) + shift[1].SetOne() + domain.FFTExt(shift, fft.DIF) + + vec := vectorext.Rand(n) + vecBackup := vectorext.DeepCopy(vec) + res := make([]fext.Element, n) + fastpolyext.MultModXnMinus1Precomputed(domain, res, vec, shift) + + require.Equal(t, vectorext.Prettify(res[1:]), vectorext.Prettify(vecBackup[:n-1])) + require.Equal(t, res[0].String(), vecBackup[n-1].String()) + + } +} diff --git a/prover/maths/fft/fastpolyext/gnark_interpolation.go b/prover/maths/fft/fastpolyext/gnark_interpolation.go new file mode 100644 index 000000000..2d55d2b23 --- /dev/null +++ b/prover/maths/fft/fastpolyext/gnark_interpolation.go @@ -0,0 +1,102 @@ +package fastpolyext + +import ( + "github.com/consensys/linea-monorepo/prover/maths/fft" + "github.com/consensys/linea-monorepo/prover/maths/field/fext/gnarkfext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext/gnarkutilext" + "github.com/consensys/linea-monorepo/prover/utils" +) + +// Evaluate a polynomial in lagrange basis on a gnark circuit +func InterpolateGnark(api gnarkfext.API, poly []gnarkfext.Variable, x gnarkfext.Variable) gnarkfext.Variable { + + if !utils.IsPowerOfTwo(len(poly)) { + utils.Panic("only support powers of two but poly has length %v", len(poly)) + } + + // When the poly is of length 1 it means it is a constant polynomial and its + // evaluation is trivial. + if len(poly) == 1 { + return poly[0] + } + + n := len(poly) + domain := fft.NewDomain(n) + one := gnarkfext.One() + + // Test that x is not a root of unity. In the other case, we would + // have to divide by zero. In practice this constraint is not necessary + // (because the division constraint would be non-satisfiable anyway) + // But doing an explicit check clarifies the need. + xN := gnarkutilext.Exp(api, x, n) + api.AssertIsDifferent(xN, gnarkfext.One()) + + // Compute the term-wise summand of the interpolation formula. + // This will allow the gnark solver to process the expensive + // inverses in parallel. + terms := make([]gnarkfext.Variable, n) + skip := make([]bool, n) + + // omegaMinI carries the domain's inverse root of unity generator raised to + // the power I in the following loop. It is initialized with omega**0 = 1. + // omegaI := frontend.Variable(1) + omegaI := gnarkfext.One() + //wrappedGeneratorInv := fext.Element{domain.GeneratorInv, 0} + + for i := 0; i < n; i++ { + + if i > 0 { + omegaI = api.MulByBase(omegaI, domain.GeneratorInv) + } + + // If the current term is the constant zero, we continue without generating + // constraints. As a result, 'terms' may contain nil elements. Therefore, + // we will need to remove them later + c1, isC1 := api.Inner.Compiler().ConstantValue(poly[i].A0) + c2, isC2 := api.Inner.Compiler().ConstantValue(poly[i].A1) + if isC1 && c1.IsInt64() && c1.Int64() == 0 && isC2 && c2.IsInt64() && c2.Int64() == 0 { + skip[i] = true + continue + } + + xOmegaN := api.Mul(x, omegaI) + terms[i] = api.Sub(xOmegaN, gnarkfext.One()) + // No point doing a batch inverse in a circuit + terms[i] = api.Inverse(terms[i]) + terms[i] = api.Mul(terms[i], poly[i]) + } + + nonNilTerms := make([]gnarkfext.Variable, 0, len(terms)) + for i := range terms { + if skip[i] { + continue + } + + nonNilTerms = append(nonNilTerms, terms[i]) + } + + // Then sum all the terms + var res gnarkfext.Variable + + switch { + case len(nonNilTerms) == 0: + res = gnarkfext.NewZero() + case len(nonNilTerms) == 1: + res = nonNilTerms[0] + case len(nonNilTerms) == 2: + res = api.Add(nonNilTerms[0], nonNilTerms[1]) + default: + res = api.Add(nonNilTerms[0], nonNilTerms[1], nonNilTerms[2:]...) + } + + /* + Then multiply the res by a factor \frac{g^{1 - n}X^n -g}{n} + */ + factor := xN + factor = api.Sub(factor, one) + factor = api.MulByBase(factor, domain.CardinalityInv) + res = api.Mul(res, factor) + + return res + +} diff --git a/prover/maths/fft/fastpolyext/gnark_poly_test.go b/prover/maths/fft/fastpolyext/gnark_poly_test.go new file mode 100644 index 000000000..162e5715a --- /dev/null +++ b/prover/maths/fft/fastpolyext/gnark_poly_test.go @@ -0,0 +1,43 @@ +package fastpolyext_test + +import ( + "fmt" + "github.com/consensys/gnark/frontend" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/fft/fastpolyext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext/gnarkfext" + "testing" + + "github.com/consensys/linea-monorepo/prover/utils/gnarkutil" +) + +func TestGnarkInterpolate(t *testing.T) { + + testCases := [][]fext.Element{ + vectorext.ForTest(0, 0, 0, 0), + vectorext.ForTest(1, 0, 1, 0), + vectorext.ForTest(1, 1, 1, 1), + } + + for i := range testCases { + + t.Run(fmt.Sprintf("test-cases-%v", i), func(t *testing.T) { + + def := func(api frontend.API) error { + outerApi := gnarkfext.API{Inner: api} + var ( + x = fext.NewElement(42, 0) + vec = vectorext.IntoGnarkAssignment(testCases[i]) + expectedY = fastpolyext.Interpolate(testCases[i], x) + computedY = fastpolyext.InterpolateGnark(outerApi, vec, gnarkfext.ExtToVariable(x)) + ) + outerApi.AssertIsEqualToField(expectedY, computedY) + return nil + } + + gnarkutil.AssertCircuitSolved(t, def) + }) + } + +} diff --git a/prover/maths/fft/fastpolyext/interpolation.go b/prover/maths/fft/fastpolyext/interpolation.go new file mode 100644 index 000000000..398a9e66d --- /dev/null +++ b/prover/maths/fft/fastpolyext/interpolation.go @@ -0,0 +1,173 @@ +package fastpolyext + +import ( + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "math/big" + + "github.com/consensys/linea-monorepo/prover/maths/fft" + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/utils" + "github.com/consensys/linea-monorepo/prover/utils/parallel" +) + +/* +Given the evaluations of a polynomial on a domain (whose +size must be a power of two, or panic), return an evaluation +at a chosen x. + +As an input the user can specify that the inputs are given +on a coset. +*/ +func Interpolate(poly []fext.Element, x fext.Element, oncoset ...bool) fext.Element { + + if !utils.IsPowerOfTwo(len(poly)) { + utils.Panic("only support powers of two but poly has length %v", len(poly)) + } + + n := len(poly) + + domain := fft.NewDomain(n) + denominator := make([]fext.Element, n) + + one := fext.One() + + wrappedFrMultiplicativeGenInv := fext.Element{domain.FrMultiplicativeGenInv, field.Zero()} + + if len(oncoset) > 0 && oncoset[0] { + x.Mul(&x, &wrappedFrMultiplicativeGenInv) + } + + /* + First, we compute the denominator, + + D_x = \frac{X}{x} - g for x \in H + where H is the subgroup of the roots of unity (not the coset) + and g a field element such that gH is the coset + */ + denominator[0] = x + wrappedGeneratorInv := fext.Element{domain.GeneratorInv, field.Zero()} + for i := 1; i < n; i++ { + denominator[i].Mul(&denominator[i-1], &wrappedGeneratorInv) + } + + for i := 0; i < n; i++ { + denominator[i].Sub(&denominator[i], &one) + if denominator[i].IsZero() { + // edge-case : x is a root of unity of the domain. In this case, we can just return + // the associated value for poly + return poly[i] + } + } + + /* + Then, we compute the sum between the inverse of the denominator + and the poly + + \sum_{x \in H}\frac{P(gx)}{D_x} + */ + denominator = fext.BatchInvert(denominator) + res := vectorext.ScalarProd(poly, denominator) + + /* + Then multiply the res by a factor \frac{g^{1 - n}X^n -g}{n} + */ + wrappedCardinalityInv := fext.Element{domain.CardinalityInv, field.Zero()} + + var factor fext.Element + factor.Exp(x, big.NewInt(int64(n))) + factor.Sub(&factor, &one) + factor.Mul(&factor, &wrappedCardinalityInv) + res.Mul(&res, &factor) + + return res + +} + +// Batch version of Interpolate +func BatchInterpolate(polys [][]fext.Element, x fext.Element, oncoset ...bool) []fext.Element { + + results := make([]fext.Element, len(polys)) + poly := polys[0] + + if !utils.IsPowerOfTwo(len(poly)) { + utils.Panic("only support powers of two but poly has length %v", len(poly)) + } + + n := len(poly) + + domain := fft.NewDomain(n) + denominator := make([]fext.Element, n) + + one := fext.One() + + wrappedFrMultiplicativeGenInv := fext.Element{domain.FrMultiplicativeGenInv, field.Zero()} + + if len(oncoset) > 0 && oncoset[0] { + x.Mul(&x, &wrappedFrMultiplicativeGenInv) + } + + /* + First, we compute the denominator, + + D_x = \frac{X}{x} - g for x \in H + where H is the subgroup of the roots of unity (not the coset) + and g a field element such that gH is the coset + */ + wrappedGeneratorInv := fext.Element{domain.GeneratorInv, field.Zero()} + + denominator[0] = x + for i := 1; i < n; i++ { + denominator[i].Mul(&denominator[i-1], &wrappedGeneratorInv) + } + + for i := 0; i < n; i++ { + denominator[i].Sub(&denominator[i], &one) + + if denominator[i].IsZero() { + // edge-case : x is a root of unity of the domain. In this case, we can just return + // the associated value for poly + + for k := range polys { + results[k] = polys[k][i] + } + + return results + } + } + + /* + Then, we compute the sum between the inverse of the denominator + and the poly + + \sum_{x \in H}\frac{P(gx)}{D_x} + */ + denominator = fext.BatchInvert(denominator) + + // Precompute the value of x^n once outside the loop + xN := new(fext.Element).Exp(x, big.NewInt(int64(n))) + + // Precompute the value of domain.CardinalityInv outside the loop + + wrappedCardinalityInv := fext.Element{domain.CardinalityInv, field.Zero()} + + // Compute factor as (x^n - 1) * (1 / domain.Cardinality). + factor := new(fext.Element).Sub(xN, &one) + factor.Mul(factor, &wrappedCardinalityInv) + + parallel.Execute(len(polys), func(start, stop int) { + for k := start; k < stop; k++ { + + // Compute the scalar product. + res := vectorext.ScalarProd(polys[k], denominator) + + // Multiply res with factor. + res.Mul(&res, factor) + + // Store the result. + results[k] = res + } + }) + + return results +} diff --git a/prover/maths/fft/fastpolyext/interpolation_test.go b/prover/maths/fft/fastpolyext/interpolation_test.go new file mode 100644 index 000000000..884cf5d36 --- /dev/null +++ b/prover/maths/fft/fastpolyext/interpolation_test.go @@ -0,0 +1,139 @@ +package fastpolyext + +import ( + "github.com/consensys/linea-monorepo/prover/maths/common/polyext" + "github.com/consensys/linea-monorepo/prover/maths/common/vectorext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "testing" + + "github.com/consensys/linea-monorepo/prover/maths/fft" + "github.com/stretchr/testify/require" +) + +func TestInterpolation(t *testing.T) { + n := 4 + randPoly := vectorext.ForTest(1, 2, 3, 4) + x := fext.NewElement(51, 0) + expectedY := polyext.EvalUnivariate(randPoly, x) + domain := fft.NewDomain(n).WithCoset() + + /* + Test without coset + */ + onRoots := vectorext.DeepCopy(randPoly) + domain.FFTExt(onRoots, fft.DIF) + + fft.BitReverseExt(onRoots) + yOnRoots := Interpolate(onRoots, x) + require.Equal(t, expectedY.String(), yOnRoots.String()) + + /* + Test with coset + */ + onCoset := vectorext.DeepCopy(randPoly) + domain.FFTExt(onCoset, fft.DIF, fft.OnCoset()) + fft.BitReverseExt(onCoset) + yOnCoset := Interpolate(onCoset, x, true) + require.Equal(t, expectedY.String(), yOnCoset.String()) + +} + +func TestBatchInterpolation(t *testing.T) { + n := 4 + randPoly := vectorext.ForTest(1, 2, 3, 4) + randPoly2 := vectorext.ForTest(5, 6, 7, 8) + x := fext.NewElement(51, 0) + + expectedY := polyext.EvalUnivariate(randPoly, x) + expectedY2 := polyext.EvalUnivariate(randPoly2, x) + domain := fft.NewDomain(n).WithCoset() + + /* + Test without coset + */ + onRoots := vectorext.DeepCopy(randPoly) + onRoots2 := vectorext.DeepCopy(randPoly2) + polys := make([][]fext.Element, 2) + polys[0] = onRoots + polys[1] = onRoots2 + + domain.FFTExt(polys[0], fft.DIF) + domain.FFTExt(polys[1], fft.DIF) + fft.BitReverseExt(polys[0]) + fft.BitReverseExt(polys[1]) + + yOnRoots := BatchInterpolate(polys, x) + require.Equal(t, expectedY.String(), yOnRoots[0].String()) + require.Equal(t, expectedY2.String(), yOnRoots[1].String()) + + /* + Test with coset + */ + onCoset := vectorext.DeepCopy(randPoly) + onCoset2 := vectorext.DeepCopy(randPoly2) + onCosets := make([][]fext.Element, 2) + onCosets[0] = onCoset + onCosets[1] = onCoset2 + + domain.FFTExt(onCosets[0], fft.DIF, fft.OnCoset()) + domain.FFTExt(onCosets[1], fft.DIF, fft.OnCoset()) + fft.BitReverseExt(onCosets[0]) + fft.BitReverseExt(onCosets[1]) + + yOnCosets := BatchInterpolate(onCosets, x, true) + require.Equal(t, expectedY.String(), yOnCosets[0].String()) + require.Equal(t, expectedY2.String(), yOnCosets[1].String()) + +} + +// edge-case : x is a root of unity of the domain. In this case, we can just return +// the associated value for poly +func TestBatchInterpolationRootOfUnity(t *testing.T) { + n := 4 + randPoly := vectorext.ForTest(1, 2, 3, 4) + randPoly2 := vectorext.ForTest(5, 6, 7, 8) + + // define x as a root of unity + x := fext.One() + + expectedY := polyext.EvalUnivariate(randPoly, x) + expectedY2 := polyext.EvalUnivariate(randPoly2, x) + domain := fft.NewDomain(n).WithCoset() + + /* + Test without coset + */ + onRoots := vectorext.DeepCopy(randPoly) + onRoots2 := vectorext.DeepCopy(randPoly2) + polys := make([][]fext.Element, 2) + polys[0] = onRoots + polys[1] = onRoots2 + + domain.FFTExt(polys[0], fft.DIF) + domain.FFTExt(polys[1], fft.DIF) + fft.BitReverseExt(polys[0]) + fft.BitReverseExt(polys[1]) + + yOnRoots := BatchInterpolate(polys, x) + require.Equal(t, expectedY.String(), yOnRoots[0].String()) + require.Equal(t, expectedY2.String(), yOnRoots[1].String()) + + /* + Test with coset + */ + onCoset := vectorext.DeepCopy(randPoly) + onCoset2 := vectorext.DeepCopy(randPoly2) + onCosets := make([][]fext.Element, 2) + onCosets[0] = onCoset + onCosets[1] = onCoset2 + + domain.FFTExt(onCosets[0], fft.DIF, fft.OnCoset()) + domain.FFTExt(onCosets[1], fft.DIF, fft.OnCoset()) + fft.BitReverseExt(onCosets[0]) + fft.BitReverseExt(onCosets[1]) + + yOnCosets := BatchInterpolate(onCosets, x, true) + require.Equal(t, expectedY.String(), yOnCosets[0].String()) + require.Equal(t, expectedY2.String(), yOnCosets[1].String()) + +} diff --git a/prover/maths/fft/fft_test.go b/prover/maths/fft/fft_test.go index 88959c4f7..e0c061366 100644 --- a/prover/maths/fft/fft_test.go +++ b/prover/maths/fft/fft_test.go @@ -274,7 +274,7 @@ func BenchmarkFFTDITCosetReference(b *testing.B) { pol[i] = pol[i-1] } - domain := NewDomain(maxSize) + domain := NewDomain(maxSize).WithCoset() b.ResetTimer() for j := 0; j < b.N; j++ { diff --git a/prover/maths/fft/fftext.go b/prover/maths/fft/fftext.go new file mode 100644 index 000000000..6b7602b7e --- /dev/null +++ b/prover/maths/fft/fftext.go @@ -0,0 +1,268 @@ +package fft + +import ( + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "github.com/consensys/linea-monorepo/prover/utils/parallel" + "math/bits" + + "github.com/consensys/linea-monorepo/prover/maths/field" +) + +func (domain *Domain) FFTExt(a []fext.Element, decimation Decimation, opts ...Option) { + + opt := fftOptions(opts...) + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(uint64(opt.nbTasks))) + if opt.nbTasks == 1 { + maxSplits = -1 + } + + // if coset != 0, scale by coset table + if opt.coset { + scale := func(cosetTable []field.Element) { + for i := 0; i < len(a); i++ { + // scale the first coordinate + a[i].A0.Mul(&a[i].A0, &cosetTable[i]) + // scale the second coordinate + a[i].A1.Mul(&a[i].A1, &cosetTable[i]) + } + } + if decimation == DIT { + scale(domain.CosetTableReversed) + + } else { + scale(domain.CosetTable) + } + } + + switch decimation { + case DIF: + difFFTExt(a, domain.Twiddles, 0, maxSplits, nil, opt.nbTasks) + case DIT: + ditFFTExt(a, domain.Twiddles, 0, maxSplits, nil, opt.nbTasks) + default: + panic("not implemented") + } +} + +// FFTInverseExt computes (recursively) the inverse discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +func (domain *Domain) FFTInverseExt(a []fext.Element, decimation Decimation, opts ...Option) { + + opt := fftOptions(opts...) + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(ecc.NextPowerOfTwo(uint64(opt.nbTasks))) + if opt.nbTasks == 1 { + maxSplits = -1 + } + + switch decimation { + case DIF: + difFFTExt(a, domain.TwiddlesInv, 0, maxSplits, nil, opt.nbTasks) + case DIT: + ditFFTExt(a, domain.TwiddlesInv, 0, maxSplits, nil, opt.nbTasks) + default: + panic("not implemented") + } + + // scale by CardinalityInv + if !opt.coset { + for i := 0; i < len(a); i++ { + // process first coordinate + a[i].A0.Mul(&a[i].A0, &domain.CardinalityInv) + // process second coordinate + a[i].A1.Mul(&a[i].A1, &domain.CardinalityInv) + } + return + } + + scale := func(cosetTable []field.Element) { + for i := 0; i < len(a); i++ { + // process first coordinate + a[i].A0.Mul(&a[i].A0, &cosetTable[i]). + Mul(&a[i].A0, &domain.CardinalityInv) + // process second coordinate + a[i].A1.Mul(&a[i].A1, &cosetTable[i]). + Mul(&a[i].A1, &domain.CardinalityInv) + } + } + if decimation == DIT { + scale(domain.CosetTableInv) + return + } + + // decimation == DIF + scale(domain.CosetTableInvReversed) + +} + +func difFFTExt(a []fext.Element, twiddles [][]field.Element, stage int, maxSplits int, chDone chan struct{}, nbTasks int) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 256 { + kerDIFNP_256Ext(a, twiddles, stage) + return + } + + m := n >> 1 + + parallelButterfly := (m > butterflyThreshold) && (stage < maxSplits) + + // i == 0 + if parallelButterfly { + parallel.Execute(m, func(start, end int) { + innerDIFWithTwiddlesExt(a, twiddles[stage], start, end, m) + }, nbTasks/(1<<(stage))) + } else { + innerDIFWithTwiddlesExt(a, twiddles[stage], 0, m, m) + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFTExt(a[m:n], twiddles, nextStage, maxSplits, chDone, nbTasks) + difFFTExt(a[0:m], twiddles, nextStage, maxSplits, nil, nbTasks) + <-chDone + } else { + difFFTExt(a[0:m], twiddles, nextStage, maxSplits, nil, nbTasks) + difFFTExt(a[m:n], twiddles, nextStage, maxSplits, nil, nbTasks) + } +} + +func ditFFTExt(a []fext.Element, twiddles [][]field.Element, stage int, maxSplits int, chDone chan struct{}, nbTasks int) { + if chDone != nil { + defer close(chDone) + } + + n := len(a) + if n == 1 { + return + } else if n == 256 { + kerDITNP_256Ext(a, twiddles, stage) + return + } + + m := n >> 1 + + parallelButterfly := (m > butterflyThreshold) && (stage < maxSplits) + + nextStage := stage + 1 + + if stage < maxSplits { + // that's the only time we fire go routines + chDone := make(chan struct{}, 1) + go ditFFTExt(a[m:n], twiddles, nextStage, maxSplits, chDone, nbTasks) + ditFFTExt(a[0:m], twiddles, nextStage, maxSplits, nil, nbTasks) + <-chDone + } else { + ditFFTExt(a[0:m], twiddles, nextStage, maxSplits, nil, nbTasks) + ditFFTExt(a[m:n], twiddles, nextStage, maxSplits, nil, nbTasks) + } + + if parallelButterfly { + parallel.Execute(m, func(start, end int) { + innerDITWithTwiddlesExt(a, twiddles[stage], start, end, m) + }, nbTasks/(1<<(stage))) + } else { + innerDITWithTwiddlesExt(a, twiddles[stage], 0, m, m) + } +} + +func innerDIFWithTwiddlesExt(a []fext.Element, twiddles []field.Element, start, end, m int) { + if start == 0 { + fext.Butterfly(&a[0], &a[m]) + start++ + } + for i := start; i < end; i++ { + fext.Butterfly(&a[i], &a[i+m]) + // process the first coordinate + a[i+m].A0.Mul(&a[i+m].A0, &twiddles[i]) + // process the second coordinate + a[i+m].A1.Mul(&a[i+m].A1, &twiddles[i]) + } +} + +func innerDITWithTwiddlesExt(a []fext.Element, twiddles []field.Element, start, end, m int) { + if start == 0 { + fext.Butterfly(&a[0], &a[m]) + start++ + } + for i := start; i < end; i++ { + // process the first coordinate + a[i+m].A0.Mul(&a[i+m].A0, &twiddles[i]) + // process the second coordinate + a[i+m].A1.Mul(&a[i+m].A1, &twiddles[i]) + fext.Butterfly(&a[i], &a[i+m]) + } +} + +func kerDIFNP_256Ext(a []fext.Element, twiddles [][]field.Element, stage int) { + // code unrolled & generated by internal/generator/fft/template/fft.go.tmpl + + innerDIFWithTwiddlesExt(a[:256], twiddles[stage+0], 0, 128, 128) + for offset := 0; offset < 256; offset += 128 { + innerDIFWithTwiddlesExt(a[offset:offset+128], twiddles[stage+1], 0, 64, 64) + } + for offset := 0; offset < 256; offset += 64 { + innerDIFWithTwiddlesExt(a[offset:offset+64], twiddles[stage+2], 0, 32, 32) + } + for offset := 0; offset < 256; offset += 32 { + innerDIFWithTwiddlesExt(a[offset:offset+32], twiddles[stage+3], 0, 16, 16) + } + for offset := 0; offset < 256; offset += 16 { + innerDIFWithTwiddlesExt(a[offset:offset+16], twiddles[stage+4], 0, 8, 8) + } + for offset := 0; offset < 256; offset += 8 { + innerDIFWithTwiddlesExt(a[offset:offset+8], twiddles[stage+5], 0, 4, 4) + } + for offset := 0; offset < 256; offset += 4 { + innerDIFWithTwiddlesExt(a[offset:offset+4], twiddles[stage+6], 0, 2, 2) + } + for offset := 0; offset < 256; offset += 2 { + fext.Butterfly(&a[offset], &a[offset+1]) + } +} + +func kerDITNP_256Ext(a []fext.Element, twiddles [][]field.Element, stage int) { + // code unrolled & generated by internal/generator/fft/template/fft.go.tmpl + + for offset := 0; offset < 256; offset += 2 { + fext.Butterfly(&a[offset], &a[offset+1]) + } + for offset := 0; offset < 256; offset += 4 { + innerDITWithTwiddlesExt(a[offset:offset+4], twiddles[stage+6], 0, 2, 2) + } + for offset := 0; offset < 256; offset += 8 { + innerDITWithTwiddlesExt(a[offset:offset+8], twiddles[stage+5], 0, 4, 4) + } + for offset := 0; offset < 256; offset += 16 { + innerDITWithTwiddlesExt(a[offset:offset+16], twiddles[stage+4], 0, 8, 8) + } + for offset := 0; offset < 256; offset += 32 { + innerDITWithTwiddlesExt(a[offset:offset+32], twiddles[stage+3], 0, 16, 16) + } + for offset := 0; offset < 256; offset += 64 { + innerDITWithTwiddlesExt(a[offset:offset+64], twiddles[stage+2], 0, 32, 32) + } + for offset := 0; offset < 256; offset += 128 { + innerDITWithTwiddlesExt(a[offset:offset+128], twiddles[stage+1], 0, 64, 64) + } + innerDITWithTwiddlesExt(a[:256], twiddles[stage+0], 0, 128, 128) +} diff --git a/prover/maths/fft/fftext_test.go b/prover/maths/fft/fftext_test.go new file mode 100644 index 000000000..215ec1a57 --- /dev/null +++ b/prover/maths/fft/fftext_test.go @@ -0,0 +1,290 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "github.com/consensys/linea-monorepo/prover/maths/common/polyext" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" + "math/big" + "strconv" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" + "github.com/leanovate/gopter/prop" +) + +func TestFFTExt(t *testing.T) { + const maxSize = 1 << 10 + + nbCosets := 3 + domainWithPrecompute := NewDomain(maxSize).WithCoset() + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 5 + + properties := gopter.NewProperties(parameters) + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + testA := func(ithpower int) bool { + + pol := make([]fext.Element, maxSize) + backupPol := make([]fext.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domainWithPrecompute.FFTExt(pol, DIF) + BitReverseExt(pol) + + sample := domainWithPrecompute.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := polyext.EvalUnivariateBase(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + } + + testA(53) + + properties.Property("DIF FFT on cosets should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fext.Element, maxSize) + backupPol := make([]fext.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domainWithPrecompute.FFTExt(pol, DIF, OnCoset()) + BitReverseExt(pol) + + sample := domainWithPrecompute.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))). + Mul(&sample, &domainWithPrecompute.FrMultiplicativeGen) + + eval := polyext.EvalUnivariateBase(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("DIT FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fext.Element, maxSize) + backupPol := make([]fext.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverseExt(pol) + domainWithPrecompute.FFTExt(pol, DIT) + + sample := domainWithPrecompute.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := polyext.EvalUnivariateBase(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("bitReverse(DIF FFT(DIT FFT (bitReverse))))==id", prop.ForAll( + + func() bool { + + pol := make([]fext.Element, maxSize) + backupPol := make([]fext.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverseExt(pol) + domainWithPrecompute.FFTExt(pol, DIT) + domainWithPrecompute.FFTInverseExt(pol, DIF) + BitReverseExt(pol) + + check := true + for i := 0; i < len(pol); i++ { + check = check && pol[i].Equal(&backupPol[i]) + } + return check + }, + )) + + properties.Property("bitReverse(DIF FFT(DIT FFT (bitReverse))))==id on cosets", prop.ForAll( + + func() bool { + + pol := make([]fext.Element, maxSize) + backupPol := make([]fext.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + check := true + + for i := 1; i <= nbCosets; i++ { + + BitReverseExt(pol) + domainWithPrecompute.FFTExt(pol, DIT, OnCoset()) + domainWithPrecompute.FFTInverseExt(pol, DIF, OnCoset()) + BitReverseExt(pol) + + for i := 0; i < len(pol); i++ { + check = check && pol[i].Equal(&backupPol[i]) + } + } + + return check + }, + )) + + properties.Property("DIT FFT(DIF FFT)==id", prop.ForAll( + + func() bool { + + pol := make([]fext.Element, maxSize) + backupPol := make([]fext.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domainWithPrecompute.FFTInverseExt(pol, DIF) + domainWithPrecompute.FFTExt(pol, DIT) + + check := true + for i := 0; i < len(pol); i++ { + check = check && (pol[i] == backupPol[i]) + } + return check + }, + )) + + properties.Property("DIT FFT(DIF FFT)==id on cosets", prop.ForAll( + + func() bool { + + pol := make([]fext.Element, maxSize) + backupPol := make([]fext.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domainWithPrecompute.FFTInverseExt(pol, DIF, OnCoset()) + domainWithPrecompute.FFTExt(pol, DIT, OnCoset()) + + check := true + for i := 0; i < len(pol); i++ { + check = check && (pol[i] == backupPol[i]) + } + return check + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + +} + +// -------------------------------------------------------------------- +// benches +func BenchmarkFFTExt(b *testing.B) { + + const maxSize = 1 << 20 + + pol := make([]fext.Element, maxSize) + pol[0].SetRandom() + for i := 1; i < maxSize; i++ { + pol[i] = pol[i-1] + } + + for i := 8; i < 20; i++ { + sizeDomain := 1 << i + b.Run("fft 2**"+strconv.Itoa(i), func(b *testing.B) { + domain := NewDomain(sizeDomain).WithCoset() + b.ResetTimer() + for j := 0; j < b.N; j++ { + domain.FFTExt(pol[:sizeDomain], DIT) + } + }) + // b.Run("fft 2**"+strconv.Itoa(i)+"(coset)", func(b *testing.B) { + // domain := NewDomain(uint64(sizeDomain)) + // b.ResetTimer() + // for j := 0; j < b.N; j++ { + // domain.FFT(pol[:sizeDomain], DIT, true) + // } + // }) + } + +} + +func BenchmarkFFTDITCosetReferenceExt(b *testing.B) { + const maxSize = 1 << 20 + + pol := make([]fext.Element, maxSize) + pol[0].SetRandom() + for i := 1; i < maxSize; i++ { + pol[i] = pol[i-1] + } + + domain := NewDomain(maxSize).WithCoset() + + b.ResetTimer() + for j := 0; j < b.N; j++ { + domain.FFTExt(pol, DIT, OnCoset()) + } +} + +func BenchmarkFFTDIFReferenceExt(b *testing.B) { + const maxSize = 1 << 20 + + pol := make([]fext.Element, maxSize) + pol[0].SetRandom() + for i := 1; i < maxSize; i++ { + pol[i] = pol[i-1] + } + + domain := NewDomain(maxSize) + + b.ResetTimer() + for j := 0; j < b.N; j++ { + domain.FFTExt(pol, DIF) + } +} diff --git a/prover/maths/field/bls12_377.go b/prover/maths/field/bls12_377.go index 37722f0f9..ab1f0ddeb 100644 --- a/prover/maths/field/bls12_377.go +++ b/prover/maths/field/bls12_377.go @@ -2,11 +2,13 @@ package field import ( "math/big" - "math/rand" + "math/rand/v2" + "unsafe" + + "math/bits" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/linea-monorepo/prover/utils" - "math/bits" ) // Element aliases [fr.Element] and represents a field element in the scalar @@ -113,15 +115,36 @@ func ExpToInt(z *Element, x Element, k int) *Element { return z } -// PseudoRandom generates a field using a pseudo-random number generator +// PseudoRand generates a field using a pseudo-random number generator func PseudoRand(rng *rand.Rand) Element { + var ( - slice = make([]byte, Bytes) - bigInt = &big.Int{} - res = Element{} + bigInt = &big.Int{} + res = Element{} + bareU64 = [4]uint64{rng.Uint64(), rng.Uint64(), rng.Uint64(), rng.Uint64()} + bareBytes = *(*[32]byte)(unsafe.Pointer(&bareU64)) ) - rng.Read(slice) - bigInt.SetBytes(slice).Mod(bigInt, Modulus()) + + bigInt.SetBytes(bareBytes[:]).Mod(bigInt, Modulus()) + res.SetBigInt(bigInt) + return res +} + +// PseudoRandTruncated generates a field using a pseudo-random number generator +func PseudoRandTruncated(rng *rand.Rand, sizeByte int) Element { + + if sizeByte > 32 { + utils.Panic("supplied a byteSize larger than 32 (%v), this must be a mistake. Please check that the supplied value is not instead a BIT-size.", sizeByte) + } + + var ( + bigInt = &big.Int{} + res = Element{} + bareU64 = [4]uint64{rng.Uint64(), rng.Uint64(), rng.Uint64(), rng.Uint64()} + bareBytes = *(*[32]byte)(unsafe.Pointer(&bareU64)) + ) + + bigInt.SetBytes(bareBytes[:sizeByte]).Mod(bigInt, Modulus()) res.SetBigInt(bigInt) return res } diff --git a/prover/maths/field/fext/additional.go b/prover/maths/field/fext/additional.go index 4a8aff633..227c11fbb 100644 --- a/prover/maths/field/fext/additional.go +++ b/prover/maths/field/fext/additional.go @@ -8,23 +8,42 @@ import ( // SetUint64 sets z to v and returns z func (z *Element) SetUint64(v uint64) *Element { // sets z LSB to v (non-Montgomery form) and convert z to Montgomery form - var x fr.Element - x.SetUint64(v) - y := field.Zero() - z = &Element{x, y} + z.A0.SetUint64(v) + z.A1.SetZero() return z // z.toMont() } // SetInt64 sets z to v and returns z func (z *Element) SetInt64(v int64) *Element { + z.A0.SetInt64(v) + z.A1.SetZero() + return z // z.toMont() +} + +func (z *Element) SetFromVector(inp [ExtensionDegree]int) *Element { + z.A0.SetInt64(int64(inp[0])) + z.A1.SetInt64(int64(inp[1])) + return z // z.toMont() +} - var x fr.Element - x.SetInt64(v) - y := field.Zero() - z = &Element{x, y} +// SetInt64Pair sets z to the int64 pair corresponding to (v1, v2) and returns z +func (z *Element) SetInt64Pair(v1, v2 int64) *Element { + z.A0.SetInt64(v1) + z.A1.SetInt64(v2) return z // z.toMont() } func (z *Element) Uint64() (uint64, uint64) { return z.A0.Bits()[0], z.A1.Bits()[0] } + +func Butterfly(a, b *Element) { + field.Butterfly(&a.A0, &b.A0) + field.Butterfly(&a.A1, &b.A1) +} + +func (z *Element) MulByBase(first *Element, second *fr.Element) *Element { + z.A0.Mul(&first.A0, second) + z.A1.Mul(&first.A1, second) + return z +} diff --git a/prover/maths/field/fext/doc.go b/prover/maths/field/fext/doc.go new file mode 100644 index 000000000..e2c37d020 --- /dev/null +++ b/prover/maths/field/fext/doc.go @@ -0,0 +1,5 @@ +// Package extensions implements the fields arithmetic of the 𝔽r² extension used in +// the BLS12-377 curve. +// +// 𝔽r²[u] = 𝔽r/u²+11 +package fext diff --git a/prover/maths/field/fext/e12.go b/prover/maths/field/fext/e12.go deleted file mode 100644 index 2ea78fc96..000000000 --- a/prover/maths/field/fext/e12.go +++ /dev/null @@ -1,866 +0,0 @@ -// Copyright 2020 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fext - -import ( - "errors" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - "math/big" - "sync" -) - -var bigIntPool = sync.Pool{ - New: func() interface{} { - return new(big.Int) - }, -} - -// E12 is a degree two finite field extension of fp6 -type E12 struct { - C0, C1 E6 -} - -// Equal returns true if z equals x, false otherwise -func (z *E12) Equal(x *E12) bool { - return z.C0.Equal(&x.C0) && z.C1.Equal(&x.C1) -} - -// String puts E12 in string form -func (z *E12) String() string { - return z.C0.String() + "+(" + z.C1.String() + ")*w" -} - -// SetString sets a E12 from string -func (z *E12) SetString(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 string) *E12 { - z.C0.SetString(s0, s1, s2, s3, s4, s5) - z.C1.SetString(s6, s7, s8, s9, s10, s11) - return z -} - -// Set copies x into z and returns z -func (z *E12) Set(x *E12) *E12 { - z.C0 = x.C0 - z.C1 = x.C1 - return z -} - -// SetOne sets z to 1 in Montgomery form and returns z -func (z *E12) SetOne() *E12 { - *z = E12{} - z.C0.B0.A0.SetOne() - return z -} - -// Add sets z=x+y in E12 and returns z -func (z *E12) Add(x, y *E12) *E12 { - z.C0.Add(&x.C0, &y.C0) - z.C1.Add(&x.C1, &y.C1) - return z -} - -// Sub sets z to x-y and returns z -func (z *E12) Sub(x, y *E12) *E12 { - z.C0.Sub(&x.C0, &y.C0) - z.C1.Sub(&x.C1, &y.C1) - return z -} - -// Double sets z=2*x and returns z -func (z *E12) Double(x *E12) *E12 { - z.C0.Double(&x.C0) - z.C1.Double(&x.C1) - return z -} - -// SetRandom used only in tests -func (z *E12) SetRandom() (*E12, error) { - if _, err := z.C0.SetRandom(); err != nil { - return nil, err - } - if _, err := z.C1.SetRandom(); err != nil { - return nil, err - } - return z, nil -} - -// IsZero returns true if z is zero, false otherwise -func (z *E12) IsZero() bool { - return z.C0.IsZero() && z.C1.IsZero() -} - -// IsOne returns true if z is one, false otherwise -func (z *E12) IsOne() bool { - return z.C0.IsOne() && z.C1.IsZero() -} - -// Mul sets z=x*y in E12 and returns z -func (z *E12) Mul(x, y *E12) *E12 { - var a, b, c E6 - a.Add(&x.C0, &x.C1) - b.Add(&y.C0, &y.C1) - a.Mul(&a, &b) - b.Mul(&x.C0, &y.C0) - c.Mul(&x.C1, &y.C1) - z.C1.Sub(&a, &b).Sub(&z.C1, &c) - z.C0.MulByNonResidue(&c).Add(&z.C0, &b) - return z -} - -// Square sets z=x*x in E12 and returns z -func (z *E12) Square(x *E12) *E12 { - - //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf - var c0, c2, c3 E6 - c0.Sub(&x.C0, &x.C1) - c3.MulByNonResidue(&x.C1).Neg(&c3).Add(&x.C0, &c3) - c2.Mul(&x.C0, &x.C1) - c0.Mul(&c0, &c3).Add(&c0, &c2) - z.C1.Double(&c2) - c2.MulByNonResidue(&c2) - z.C0.Add(&c0, &c2) - - return z -} - -// Karabina's compressed cyclotomic square -// https://eprint.iacr.org/2010/542.pdf -// Th. 3.2 with minor modifications to fit our tower -func (z *E12) CyclotomicSquareCompressed(x *E12) *E12 { - - var t [7]E2 - - // t0 = g1^2 - t[0].Square(&x.C0.B1) - // t1 = g5^2 - t[1].Square(&x.C1.B2) - // t5 = g1 + g5 - t[5].Add(&x.C0.B1, &x.C1.B2) - // t2 = (g1 + g5)^2 - t[2].Square(&t[5]) - - // t3 = g1^2 + g5^2 - t[3].Add(&t[0], &t[1]) - // t5 = 2 * g1 * g5 - t[5].Sub(&t[2], &t[3]) - - // t6 = g3 + g2 - t[6].Add(&x.C1.B0, &x.C0.B2) - // t3 = (g3 + g2)^2 - t[3].Square(&t[6]) - // t2 = g3^2 - t[2].Square(&x.C1.B0) - - // t6 = 2 * nr * g1 * g5 - t[6].MulByNonResidue(&t[5]) - // t5 = 4 * nr * g1 * g5 + 2 * g3 - t[5].Add(&t[6], &x.C1.B0). - Double(&t[5]) - // z3 = 6 * nr * g1 * g5 + 2 * g3 - z.C1.B0.Add(&t[5], &t[6]) - - // t4 = nr * g5^2 - t[4].MulByNonResidue(&t[1]) - // t5 = nr * g5^2 + g1^2 - t[5].Add(&t[0], &t[4]) - // t6 = nr * g5^2 + g1^2 - g2 - t[6].Sub(&t[5], &x.C0.B2) - - // t1 = g2^2 - t[1].Square(&x.C0.B2) - - // t6 = 2 * nr * g5^2 + 2 * g1^2 - 2*g2 - t[6].Double(&t[6]) - // z2 = 3 * nr * g5^2 + 3 * g1^2 - 2*g2 - z.C0.B2.Add(&t[6], &t[5]) - - // t4 = nr * g2^2 - t[4].MulByNonResidue(&t[1]) - // t5 = g3^2 + nr * g2^2 - t[5].Add(&t[2], &t[4]) - // t6 = g3^2 + nr * g2^2 - g1 - t[6].Sub(&t[5], &x.C0.B1) - // t6 = 2 * g3^2 + 2 * nr * g2^2 - 2 * g1 - t[6].Double(&t[6]) - // z1 = 3 * g3^2 + 3 * nr * g2^2 - 2 * g1 - z.C0.B1.Add(&t[6], &t[5]) - - // t0 = g2^2 + g3^2 - t[0].Add(&t[2], &t[1]) - // t5 = 2 * g3 * g2 - t[5].Sub(&t[3], &t[0]) - // t6 = 2 * g3 * g2 + g5 - t[6].Add(&t[5], &x.C1.B2) - // t6 = 4 * g3 * g2 + 2 * g5 - t[6].Double(&t[6]) - // z5 = 6 * g3 * g2 + 2 * g5 - z.C1.B2.Add(&t[5], &t[6]) - - return z -} - -// DecompressKarabina Karabina's cyclotomic square result -// if g3 != 0 -// -// g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 -// -// if g3 == 0 -// -// g4 = 2g1g5/g2 -// -// if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) -// Theorem 3.1 is well-defined for all x in Gϕₙ\{1} -func (z *E12) DecompressKarabina(x *E12) *E12 { - - var t [3]E2 - var one E2 - one.SetOne() - - if x.C1.B2.IsZero() /* g3 == 0 */ { - t[0].Mul(&x.C0.B1, &x.C1.B2). - Double(&t[0]) - // t1 = g2 - t[1].Set(&x.C0.B2) - - if t[1].IsZero() /* g2 == g3 == 0 */ { - return z.SetOne() - } - } else /* g3 != 0 */ { - - // t0 = g1^2 - t[0].Square(&x.C0.B1) - // t1 = 3 * g1^2 - 2 * g2 - t[1].Sub(&t[0], &x.C0.B2). - Double(&t[1]). - Add(&t[1], &t[0]) - // t0 = E * g5^2 + t1 - t[2].Square(&x.C1.B2) - t[0].MulByNonResidue(&t[2]). - Add(&t[0], &t[1]) - // t1 = 4 * g3 - t[1].Double(&x.C1.B0). - Double(&t[1]) - } - - // z4 = g4 - z.C1.B1.Div(&t[0], &t[1]) // costly - - // t1 = g2 * g1 - t[1].Mul(&x.C0.B2, &x.C0.B1) - // t2 = 2 * g4^2 - 3 * g2 * g1 - t[2].Square(&z.C1.B1). - Sub(&t[2], &t[1]). - Double(&t[2]). - Sub(&t[2], &t[1]) - // t1 = g3 * g5 (g3 can be 0) - t[1].Mul(&x.C1.B0, &x.C1.B2) - // c_0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 - t[2].Add(&t[2], &t[1]) - z.C0.B0.MulByNonResidue(&t[2]). - Add(&z.C0.B0, &one) - - z.C0.B1.Set(&x.C0.B1) - z.C0.B2.Set(&x.C0.B2) - z.C1.B0.Set(&x.C1.B0) - z.C1.B2.Set(&x.C1.B2) - - return z -} - -// BatchDecompressKarabina multiple Karabina's cyclotomic square results -// if g3 != 0 -// -// g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 -// -// if g3 == 0 -// -// g4 = 2g1g5/g2 -// -// if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) -// Theorem 3.1 is well-defined for all x in Gϕₙ\{1} -// -// Divisions by 4g3 or g2 is batched using Montgomery batch inverse -func BatchDecompressKarabina(x []E12) []E12 { - - n := len(x) - if n == 0 { - return x - } - - t0 := make([]E2, n) - t1 := make([]E2, n) - t2 := make([]E2, n) - zeroes := make([]bool, n) - - var one E2 - one.SetOne() - - for i := 0; i < n; i++ { - if x[i].C1.B2.IsZero() /* g3 == 0 */ { - t0[i].Mul(&x[i].C0.B1, &x[i].C1.B2). - Double(&t0[i]) - // t1 = g2 - t1[i].Set(&x[i].C0.B2) - - if t1[i].IsZero() /* g3 == g2 == 0 */ { - x[i].SetOne() - zeroes[i] = true - continue - } - } else /* g3 != 0 */ { - // t0 = g1^2 - t0[i].Square(&x[i].C0.B1) - // t1 = 3 * g1^2 - 2 * g2 - t1[i].Sub(&t0[i], &x[i].C0.B2). - Double(&t1[i]). - Add(&t1[i], &t0[i]) - // t0 = E * g5^2 + t1 - t2[i].Square(&x[i].C1.B2) - t0[i].MulByNonResidue(&t2[i]). - Add(&t0[i], &t1[i]) - // t1 = 4 * g3 - t1[i].Double(&x[i].C1.B0). - Double(&t1[i]) - } - } - - t1 = BatchInvertE2(t1) // costs 1 inverse - - for i := 0; i < n; i++ { - if zeroes[i] { - continue - } - - // z4 = g4 - x[i].C1.B1.Mul(&t0[i], &t1[i]) - - // t1 = g2 * g1 - t1[i].Mul(&x[i].C0.B2, &x[i].C0.B1) - // t2 = 2 * g4^2 - 3 * g2 * g1 - t2[i].Square(&x[i].C1.B1) - t2[i].Sub(&t2[i], &t1[i]) - t2[i].Double(&t2[i]) - t2[i].Sub(&t2[i], &t1[i]) - - // t1 = g3 * g5 (g3s can be 0s) - t1[i].Mul(&x[i].C1.B0, &x[i].C1.B2) - // z0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 - t2[i].Add(&t2[i], &t1[i]) - x[i].C0.B0.MulByNonResidue(&t2[i]). - Add(&x[i].C0.B0, &one) - } - - return x -} - -// Granger-Scott's cyclotomic square -// https://eprint.iacr.org/2009/565.pdf, 3.2 -func (z *E12) CyclotomicSquare(x *E12) *E12 { - - // x=(x0,x1,x2,x3,x4,x5,x6,x7) in E2^6 - // cyclosquare(x)=(3*x4^2*u + 3*x0^2 - 2*x0, - // 3*x2^2*u + 3*x3^2 - 2*x1, - // 3*x5^2*u + 3*x1^2 - 2*x2, - // 6*x1*x5*u + 2*x3, - // 6*x0*x4 + 2*x4, - // 6*x2*x3 + 2*x5) - - var t [9]E2 - - t[0].Square(&x.C1.B1) - t[1].Square(&x.C0.B0) - t[6].Add(&x.C1.B1, &x.C0.B0).Square(&t[6]).Sub(&t[6], &t[0]).Sub(&t[6], &t[1]) // 2*x4*x0 - t[2].Square(&x.C0.B2) - t[3].Square(&x.C1.B0) - t[7].Add(&x.C0.B2, &x.C1.B0).Square(&t[7]).Sub(&t[7], &t[2]).Sub(&t[7], &t[3]) // 2*x2*x3 - t[4].Square(&x.C1.B2) - t[5].Square(&x.C0.B1) - t[8].Add(&x.C1.B2, &x.C0.B1).Square(&t[8]).Sub(&t[8], &t[4]).Sub(&t[8], &t[5]).MulByNonResidue(&t[8]) // 2*x5*x1*u - - t[0].MulByNonResidue(&t[0]).Add(&t[0], &t[1]) // x4^2*u + x0^2 - t[2].MulByNonResidue(&t[2]).Add(&t[2], &t[3]) // x2^2*u + x3^2 - t[4].MulByNonResidue(&t[4]).Add(&t[4], &t[5]) // x5^2*u + x1^2 - - z.C0.B0.Sub(&t[0], &x.C0.B0).Double(&z.C0.B0).Add(&z.C0.B0, &t[0]) - z.C0.B1.Sub(&t[2], &x.C0.B1).Double(&z.C0.B1).Add(&z.C0.B1, &t[2]) - z.C0.B2.Sub(&t[4], &x.C0.B2).Double(&z.C0.B2).Add(&z.C0.B2, &t[4]) - - z.C1.B0.Add(&t[8], &x.C1.B0).Double(&z.C1.B0).Add(&z.C1.B0, &t[8]) - z.C1.B1.Add(&t[6], &x.C1.B1).Double(&z.C1.B1).Add(&z.C1.B1, &t[6]) - z.C1.B2.Add(&t[7], &x.C1.B2).Double(&z.C1.B2).Add(&z.C1.B2, &t[7]) - - return z -} - -// Inverse sets z to the inverse of x in E12 and returns z -// -// if x == 0, sets and returns z = x -func (z *E12) Inverse(x *E12) *E12 { - // Algorithm 23 from https://eprint.iacr.org/2010/354.pdf - - var t0, t1, tmp E6 - t0.Square(&x.C0) - t1.Square(&x.C1) - tmp.MulByNonResidue(&t1) - t0.Sub(&t0, &tmp) - t1.Inverse(&t0) - z.C0.Mul(&x.C0, &t1) - z.C1.Mul(&x.C1, &t1).Neg(&z.C1) - - return z -} - -// BatchInvertE12 returns a new slice with every element in a inverted. -// It uses Montgomery batch inversion trick. -// -// if a[i] == 0, returns result[i] = a[i] -func BatchInvertE12(a []E12) []E12 { - res := make([]E12, len(a)) - if len(a) == 0 { - return res - } - - zeroes := make([]bool, len(a)) - var accumulator E12 - accumulator.SetOne() - - for i := 0; i < len(a); i++ { - if a[i].IsZero() { - zeroes[i] = true - continue - } - res[i].Set(&accumulator) - accumulator.Mul(&accumulator, &a[i]) - } - - accumulator.Inverse(&accumulator) - - for i := len(a) - 1; i >= 0; i-- { - if zeroes[i] { - continue - } - res[i].Mul(&res[i], &accumulator) - accumulator.Mul(&accumulator, &a[i]) - } - - return res -} - -// Exp sets z=xᵏ (mod q¹²) and returns it -// uses 2-bits windowed method -func (z *E12) Exp(x E12, k *big.Int) *E12 { - if k.IsUint64() && k.Uint64() == 0 { - return z.SetOne() - } - - e := k - if k.Sign() == -1 { - // negative k, we invert - // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) - x.Inverse(&x) - - // we negate k in a temp big.Int since - // Int.Bit(_) of k and -k is different - e = bigIntPool.Get().(*big.Int) - defer bigIntPool.Put(e) - e.Neg(k) - } - - var res E12 - var ops [3]E12 - - res.SetOne() - ops[0].Set(&x) - ops[1].Square(&ops[0]) - ops[2].Set(&ops[0]).Mul(&ops[2], &ops[1]) - - b := e.Bytes() - for i := range b { - w := b[i] - mask := byte(0xc0) - for j := 0; j < 4; j++ { - res.Square(&res).Square(&res) - c := (w & mask) >> (6 - 2*j) - if c != 0 { - res.Mul(&res, &ops[c-1]) - } - mask = mask >> 2 - } - } - z.Set(&res) - - return z -} - -// CyclotomicExp sets z=xᵏ (mod q¹²) and returns it -// uses 2-NAF decomposition -// x must be in the cyclotomic subgroup -// TODO: use a windowed method -func (z *E12) CyclotomicExp(x E12, k *big.Int) *E12 { - if k.IsUint64() && k.Uint64() == 0 { - return z.SetOne() - } - - e := k - if k.Sign() == -1 { - // negative k, we invert (=conjugate) - // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) - x.Conjugate(&x) - - // we negate k in a temp big.Int since - // Int.Bit(_) of k and -k is different - e = bigIntPool.Get().(*big.Int) - defer bigIntPool.Put(e) - e.Neg(k) - } - - var res, xInv E12 - xInv.InverseUnitary(&x) - res.SetOne() - eNAF := make([]int8, e.BitLen()+3) - n := ecc.NafDecomposition(e, eNAF[:]) - for i := n - 1; i >= 0; i-- { - res.CyclotomicSquare(&res) - if eNAF[i] == 1 { - res.Mul(&res, &x) - } else if eNAF[i] == -1 { - res.Mul(&res, &xInv) - } - } - z.Set(&res) - return z -} - -// ExpGLV sets z=xᵏ (q¹²) and returns it -// uses 2-dimensional GLV with 2-bits windowed method -// x must be in GT -// TODO: use 2-NAF -// TODO: use higher dimensional decomposition -func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { - if k.IsUint64() && k.Uint64() == 0 { - return z.SetOne() - } - - e := k - if k.Sign() == -1 { - // negative k, we invert (=conjugate) - // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) - x.Conjugate(&x) - - // we negate k in a temp big.Int since - // Int.Bit(_) of k and -k is different - e = bigIntPool.Get().(*big.Int) - defer bigIntPool.Put(e) - e.Neg(k) - } - - var table [15]E12 - var res E12 - var s1, s2 fr.Element - - res.SetOne() - - // table[b3b2b1b0-1] = b3b2*Frobinius(x) + b1b0*x - table[0].Set(&x) - table[3].Frobenius(&x) - - // split the scalar, modifies ±x, Frob(x) accordingly - s := ecc.SplitScalar(e, &glvBasis) - - if s[0].Sign() == -1 { - s[0].Neg(&s[0]) - table[0].InverseUnitary(&table[0]) - } - if s[1].Sign() == -1 { - s[1].Neg(&s[1]) - table[3].InverseUnitary(&table[3]) - } - - // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2*Frobenius(x) + b1b0*x if b3b2b1b0 != 0 - table[1].CyclotomicSquare(&table[0]) - table[2].Mul(&table[1], &table[0]) - table[4].Mul(&table[3], &table[0]) - table[5].Mul(&table[3], &table[1]) - table[6].Mul(&table[3], &table[2]) - table[7].CyclotomicSquare(&table[3]) - table[8].Mul(&table[7], &table[0]) - table[9].Mul(&table[7], &table[1]) - table[10].Mul(&table[7], &table[2]) - table[11].Mul(&table[7], &table[3]) - table[12].Mul(&table[11], &table[0]) - table[13].Mul(&table[11], &table[1]) - table[14].Mul(&table[11], &table[2]) - - // bounds on the lattice base vectors guarantee that s1, s2 are len(r)/2 bits long max - s1 = s1.SetBigInt(&s[0]).Bits() - s2 = s2.SetBigInt(&s[1]).Bits() - - maxBit := s1.BitLen() - if s2.BitLen() > maxBit { - maxBit = s2.BitLen() - } - hiWordIndex := (maxBit - 1) / 64 - - // loop starts from len(s1)/2 due to the bounds - for i := hiWordIndex; i >= 0; i-- { - mask := uint64(3) << 62 - for j := 0; j < 32; j++ { - res.CyclotomicSquare(&res).CyclotomicSquare(&res) - b1 := (s1[i] & mask) >> (62 - 2*j) - b2 := (s2[i] & mask) >> (62 - 2*j) - if b1|b2 != 0 { - s := (b2<<2 | b1) - res.Mul(&res, &table[s-1]) - } - mask = mask >> 2 - } - } - - z.Set(&res) - return z -} - -// InverseUnitary inverses a unitary element -func (z *E12) InverseUnitary(x *E12) *E12 { - return z.Conjugate(x) -} - -// Conjugate sets z to x conjugated and returns z -func (z *E12) Conjugate(x *E12) *E12 { - *z = *x - z.C1.Neg(&z.C1) - return z -} - -// SizeOfGT represents the size in bytes that a GT element need in binary form -const SizeOfGT = 48 * 12 - -// Marshal converts z to a byte slice -func (z *E12) Marshal() []byte { - b := z.Bytes() - return b[:] -} - -// Unmarshal is an alias to SetBytes() -func (z *E12) Unmarshal(buf []byte) error { - return z.SetBytes(buf) -} - -// Bytes returns the regular (non montgomery) value -// of z as a big-endian byte array. -// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... -func (z *E12) Bytes() (r [SizeOfGT]byte) { - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[528:528+fp.Bytes]), z.C0.B0.A0) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[480:480+fp.Bytes]), z.C0.B0.A1) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[432:432+fp.Bytes]), z.C0.B1.A0) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[384:384+fp.Bytes]), z.C0.B1.A1) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[336:336+fp.Bytes]), z.C0.B2.A0) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[288:288+fp.Bytes]), z.C0.B2.A1) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[240:240+fp.Bytes]), z.C1.B0.A0) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[192:192+fp.Bytes]), z.C1.B0.A1) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[144:144+fp.Bytes]), z.C1.B1.A0) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[96:96+fp.Bytes]), z.C1.B1.A1) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[48:48+fp.Bytes]), z.C1.B2.A0) - fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[0:0+fp.Bytes]), z.C1.B2.A1) - - return -} - -// SetBytes interprets e as the bytes of a big-endian GT -// sets z to that value (in Montgomery form), and returns z. -// size(e) == 48 * 12 -// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... -func (z *E12) SetBytes(e []byte) error { - if len(e) != SizeOfGT { - return errors.New("invalid buffer size") - } - if err := z.C0.B0.A0.SetBytesCanonical(e[528 : 528+fp.Bytes]); err != nil { - return err - } - if err := z.C0.B0.A1.SetBytesCanonical(e[480 : 480+fp.Bytes]); err != nil { - return err - } - if err := z.C0.B1.A0.SetBytesCanonical(e[432 : 432+fp.Bytes]); err != nil { - return err - } - if err := z.C0.B1.A1.SetBytesCanonical(e[384 : 384+fp.Bytes]); err != nil { - return err - } - if err := z.C0.B2.A0.SetBytesCanonical(e[336 : 336+fp.Bytes]); err != nil { - return err - } - if err := z.C0.B2.A1.SetBytesCanonical(e[288 : 288+fp.Bytes]); err != nil { - return err - } - if err := z.C1.B0.A0.SetBytesCanonical(e[240 : 240+fp.Bytes]); err != nil { - return err - } - if err := z.C1.B0.A1.SetBytesCanonical(e[192 : 192+fp.Bytes]); err != nil { - return err - } - if err := z.C1.B1.A0.SetBytesCanonical(e[144 : 144+fp.Bytes]); err != nil { - return err - } - if err := z.C1.B1.A1.SetBytesCanonical(e[96 : 96+fp.Bytes]); err != nil { - return err - } - if err := z.C1.B2.A0.SetBytesCanonical(e[48 : 48+fp.Bytes]); err != nil { - return err - } - if err := z.C1.B2.A1.SetBytesCanonical(e[0 : 0+fp.Bytes]); err != nil { - return err - } - - return nil -} - -// IsInSubGroup ensures GT/E12 is in correct subgroup -func (z *E12) IsInSubGroup() bool { - var a, b E12 - - // check z^(phi_k(p)) == 1 - a.FrobeniusSquare(z) - b.FrobeniusSquare(&a).Mul(&b, z) - - if !a.Equal(&b) { - return false - } - - // check z^(p+1-t) == 1 - a.Frobenius(z) - b.Expt(z) - - return a.Equal(&b) -} - -// CompressTorus GT/E12 element to half its size -// z must be in the cyclotomic subgroup -// i.e. z^(p^4-p^2+1)=1 -// e.g. GT -// "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG -// z.C1 == 0 only when z \in {-1,1} -func (z *E12) CompressTorus() (E6, error) { - - if z.C1.IsZero() { - return E6{}, errors.New("invalid input") - } - - var res, tmp, one E6 - one.SetOne() - tmp.Inverse(&z.C1) - res.Add(&z.C0, &one). - Mul(&res, &tmp) - - return res, nil -} - -// BatchCompressTorus GT/E12 elements to half their size using a batch inversion. -// -// if len(x) == 0 or if any of the x[i].C1 coordinate is 0, this function returns an error. -func BatchCompressTorus(x []E12) ([]E6, error) { - - n := len(x) - if n == 0 { - return nil, errors.New("invalid input size") - } - - var one E6 - one.SetOne() - res := make([]E6, n) - - for i := 0; i < n; i++ { - res[i].Set(&x[i].C1) - // throw an error if any of the x[i].C1 is 0 - if res[i].IsZero() { - return nil, errors.New("invalid input; C1 is 0") - } - } - - t := BatchInvertE6(res) // costs 1 inverse - - for i := 0; i < n; i++ { - res[i].Add(&x[i].C0, &one). - Mul(&res[i], &t[i]) - } - - return res, nil -} - -// DecompressTorus GT/E12 a compressed element -// element must be in the cyclotomic subgroup -// "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG -func (z *E6) DecompressTorus() E12 { - - var res, num, denum E12 - num.C0.Set(z) - num.C1.SetOne() - denum.C0.Set(z) - denum.C1.SetOne().Neg(&denum.C1) - res.Inverse(&denum). - Mul(&res, &num) - - return res -} - -// BatchDecompressTorus GT/E12 compressed elements -// using a batch inversion -func BatchDecompressTorus(x []E6) ([]E12, error) { - - n := len(x) - if n == 0 { - return []E12{}, errors.New("invalid input size") - } - - res := make([]E12, n) - num := make([]E12, n) - denum := make([]E12, n) - - for i := 0; i < n; i++ { - num[i].C0.Set(&x[i]) - num[i].C1.SetOne() - denum[i].C0.Set(&x[i]) - denum[i].C1.SetOne().Neg(&denum[i].C1) - } - - denum = BatchInvertE12(denum) // costs 1 inverse - - for i := 0; i < n; i++ { - res[i].Mul(&num[i], &denum[i]) - } - - return res, nil -} - -// Select is conditional move. -// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. -func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { - //Might be able to save a nanosecond or two by an aggregate implementation - - z.C0.Select(cond, &caseZ.C0, &caseNz.C0) - z.C1.Select(cond, &caseZ.C1, &caseNz.C1) - - return z -} - -// Div divides an element in E12 by an element in E12 -func (z *E12) Div(x *E12, y *E12) *E12 { - var r E12 - r.Inverse(y).Mul(x, &r) - return z.Set(&r) -} diff --git a/prover/maths/field/fext/e12_pairing.go b/prover/maths/field/fext/e12_pairing.go deleted file mode 100644 index 209791448..000000000 --- a/prover/maths/field/fext/e12_pairing.go +++ /dev/null @@ -1,107 +0,0 @@ -package fext - -func (z *E12) nSquare(n int) { - for i := 0; i < n; i++ { - z.CyclotomicSquare(z) - } -} - -func (z *E12) nSquareCompressed(n int) { - for i := 0; i < n; i++ { - z.CyclotomicSquareCompressed(z) - } -} - -// Expt set z to x^t in E12 and return z -func (z *E12) Expt(x *E12) *E12 { - // const tAbsVal uint64 = 9586122913090633729 - // tAbsVal in binary: 1000010100001000110000000000000000000000000000000000000000000001 - // drop the low 46 bits (all 0 except the least significant bit): 100001010000100011 = 136227 - // Shortest addition chains can be found at https://wwwhomes.uni-bielefeld.de/achim/addition_chain.html - - var result, x33 E12 - - // a shortest addition chain for 136227 - result.Set(x) - result.nSquare(5) - result.Mul(&result, x) - x33.Set(&result) - result.nSquare(7) - result.Mul(&result, &x33) - result.nSquare(4) - result.Mul(&result, x) - result.CyclotomicSquare(&result) - result.Mul(&result, x) - - // the remaining 46 bits - result.nSquareCompressed(46) - result.DecompressKarabina(&result) - result.Mul(&result, x) - - z.Set(&result) - return z -} - -// MulBy034 multiplication by sparse element (c0,0,0,c3,c4,0) -func (z *E12) MulBy034(c0, c3, c4 *E2) *E12 { - - var a, b, d E6 - - a.MulByE2(&z.C0, c0) - - b.Set(&z.C1) - b.MulBy01(c3, c4) - - var d0 E2 - d0.Add(c0, c3) - d.Add(&z.C0, &z.C1) - d.MulBy01(&d0, c4) - - z.C1.Add(&a, &b).Neg(&z.C1).Add(&z.C1, &d) - z.C0.MulByNonResidue(&b).Add(&z.C0, &a) - - return z -} - -// MulBy34 multiplication by sparse element (1,0,0,c3,c4,0) -func (z *E12) MulBy34(c3, c4 *E2) *E12 { - - var a, b, d E6 - - a.Set(&z.C0) - - b.Set(&z.C1) - b.MulBy01(c3, c4) - - var d0 E2 - d0.SetOne().Add(&d0, c3) - d.Add(&z.C0, &z.C1) - d.MulBy01(&d0, c4) - - z.C1.Add(&a, &b).Neg(&z.C1).Add(&z.C1, &d) - z.C0.MulByNonResidue(&b).Add(&z.C0, &a) - - return z -} - -// MulBy01234 multiplies z by an E12 sparse element of the form (x0, x1, x2, x3, x4, 0) -func (z *E12) MulBy01234(x *[5]E2) *E12 { - var c1, a, b, c, z0, z1 E6 - c0 := &E6{B0: x[0], B1: x[1], B2: x[2]} - c1.B0 = x[3] - c1.B1 = x[4] - a.Add(&z.C0, &z.C1) - b.Add(c0, &c1) - a.Mul(&a, &b) - b.Mul(&z.C0, c0) - c.Set(&z.C1).MulBy01(&x[3], &x[4]) - z1.Sub(&a, &b) - z1.Sub(&z1, &c) - z0.MulByNonResidue(&c) - z0.Add(&z0, &b) - - z.C0 = z0 - z.C1 = z1 - - return z -} diff --git a/prover/maths/field/fext/e12_test.go b/prover/maths/field/fext/e12_test.go deleted file mode 100644 index 3406e7b30..000000000 --- a/prover/maths/field/fext/e12_test.go +++ /dev/null @@ -1,569 +0,0 @@ -// Copyright 2020 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fext - -import ( - "math/big" - "testing" - - "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" - "github.com/leanovate/gopter" - "github.com/leanovate/gopter/prop" -) - -// ------------------------------------------------------------ -// tests - -func TestE12Serialization(t *testing.T) { - - t.Parallel() - parameters := gopter.DefaultTestParameters() - if testing.Short() { - parameters.MinSuccessfulTests = nbFuzzShort - } else { - parameters.MinSuccessfulTests = nbFuzz - } - - properties := gopter.NewProperties(parameters) - - genA := GenE12() - - properties.Property("[BLS12-377] SetBytes(Bytes()) should stay constant", prop.ForAll( - func(a *E12) bool { - var b E12 - buf := a.Bytes() - if err := b.SetBytes(buf[:]); err != nil { - return false - } - return a.Equal(&b) - }, - genA, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} - -func TestE12ReceiverIsOperand(t *testing.T) { - - parameters := gopter.DefaultTestParameters() - if testing.Short() { - parameters.MinSuccessfulTests = nbFuzzShort - } else { - parameters.MinSuccessfulTests = nbFuzz - } - - properties := gopter.NewProperties(parameters) - - genA := GenE12() - genB := GenE12() - - properties.Property("[BLS12-377] Having the receiver as operand (addition) should output the same result", prop.ForAll( - func(a, b *E12) bool { - var c, d E12 - d.Set(a) - c.Add(a, b) - a.Add(a, b) - b.Add(&d, b) - return a.Equal(b) && a.Equal(&c) && b.Equal(&c) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (sub) should output the same result", prop.ForAll( - func(a, b *E12) bool { - var c, d E12 - d.Set(a) - c.Sub(a, b) - a.Sub(a, b) - b.Sub(&d, b) - return a.Equal(b) && a.Equal(&c) && b.Equal(&c) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (mul) should output the same result", prop.ForAll( - func(a, b *E12) bool { - var c, d E12 - d.Set(a) - c.Mul(a, b) - a.Mul(a, b) - b.Mul(&d, b) - return a.Equal(b) && a.Equal(&c) && b.Equal(&c) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (square) should output the same result", prop.ForAll( - func(a *E12) bool { - var b E12 - b.Square(a) - a.Square(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (double) should output the same result", prop.ForAll( - func(a *E12) bool { - var b E12 - b.Double(a) - a.Double(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( - func(a *E12) bool { - var b E12 - b.Inverse(a) - a.Inverse(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (Cyclotomic square) should output the same result", prop.ForAll( - func(a *E12) bool { - var b E12 - b.CyclotomicSquare(a) - a.CyclotomicSquare(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( - func(a *E12) bool { - var b E12 - b.Conjugate(a) - a.Conjugate(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (Frobenius) should output the same result", prop.ForAll( - func(a *E12) bool { - var b E12 - b.Frobenius(a) - a.Frobenius(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (FrobeniusSquare) should output the same result", prop.ForAll( - func(a *E12) bool { - var b E12 - b.FrobeniusSquare(a) - a.FrobeniusSquare(a) - return a.Equal(&b) - }, - genA, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} - -func TestE12Ops(t *testing.T) { - - parameters := gopter.DefaultTestParameters() - if testing.Short() { - parameters.MinSuccessfulTests = nbFuzzShort - } else { - parameters.MinSuccessfulTests = nbFuzz - } - - properties := gopter.NewProperties(parameters) - - genA := GenE12() - genB := GenE12() - genExp := GenFp() - - properties.Property("[BLS12-377] sub & add should leave an element invariant", prop.ForAll( - func(a, b *E12) bool { - var c E12 - c.Set(a) - c.Add(&c, b).Sub(&c, b) - return c.Equal(a) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] mul & inverse should leave an element invariant", prop.ForAll( - func(a, b *E12) bool { - var c, d E12 - d.Inverse(b) - c.Set(a) - c.Mul(&c, b).Mul(&c, &d) - return c.Equal(a) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] inverse twice should leave an element invariant", prop.ForAll( - func(a *E12) bool { - var b E12 - b.Inverse(a).Inverse(&b) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] square and mul should output the same result", prop.ForAll( - func(a *E12) bool { - var b, c E12 - b.Mul(a, a) - c.Square(a) - return b.Equal(&c) - }, - genA, - )) - - properties.Property("[BLS12-377] a + pi(a), a-pi(a) should be real", prop.ForAll( - func(a *E12) bool { - var b, c, d E12 - var e, f, g E6 - b.Conjugate(a) - c.Add(a, &b) - d.Sub(a, &b) - e.Double(&a.C0) - f.Double(&a.C1) - return c.C1.Equal(&g) && d.C0.Equal(&g) && e.Equal(&c.C0) && f.Equal(&d.C1) - }, - genA, - )) - - properties.Property("[BLS12-377] Torus-based Compress/decompress E12 elements in the cyclotomic subgroup", prop.ForAll( - func(a *E12) bool { - var b E12 - b.Conjugate(a) - a.Inverse(a) - b.Mul(&b, a) - a.FrobeniusSquare(&b).Mul(a, &b) - - c, _ := a.CompressTorus() - d := c.DecompressTorus() - return a.Equal(&d) - }, - genA, - )) - - properties.Property("[BLS12-377] Torus-based batch Compress/decompress E12 elements in the cyclotomic subgroup", prop.ForAll( - func(a, e, f *E12) bool { - var b E12 - b.Conjugate(a) - a.Inverse(a) - b.Mul(&b, a) - a.FrobeniusSquare(&b).Mul(a, &b) - - e.CyclotomicSquare(a) - f.CyclotomicSquare(e) - - c, _ := BatchCompressTorus([]E12{*a, *e, *f}) - d, _ := BatchDecompressTorus(c) - return a.Equal(&d[0]) && e.Equal(&d[1]) && f.Equal(&d[2]) - }, - genA, - genA, - genA, - )) - - properties.Property("[BLS12-377] pi**12=id", prop.ForAll( - func(a *E12) bool { - var b E12 - b.Frobenius(a). - Frobenius(&b). - Frobenius(&b). - Frobenius(&b). - Frobenius(&b). - Frobenius(&b). - Frobenius(&b). - Frobenius(&b). - Frobenius(&b). - Frobenius(&b). - Frobenius(&b). - Frobenius(&b) - return b.Equal(a) - }, - genA, - )) - - properties.Property("[BLS12-377] (pi**2)**6=id", prop.ForAll( - func(a *E12) bool { - var b E12 - b.FrobeniusSquare(a). - FrobeniusSquare(&b). - FrobeniusSquare(&b). - FrobeniusSquare(&b). - FrobeniusSquare(&b). - FrobeniusSquare(&b) - return b.Equal(a) - }, - genA, - )) - - properties.Property("[BLS12-377] cyclotomic square (Granger-Scott) and square should be the same in the cyclotomic subgroup", prop.ForAll( - func(a *E12) bool { - var b, c, d E12 - b.Conjugate(a) - a.Inverse(a) - b.Mul(&b, a) - a.FrobeniusSquare(&b).Mul(a, &b) - c.Square(a) - d.CyclotomicSquare(a) - return c.Equal(&d) - }, - genA, - )) - - properties.Property("[BLS12-377] compressed cyclotomic square (Karabina) and square should be the same in the cyclotomic subgroup", prop.ForAll( - func(a *E12) bool { - var _a, b, c, d, _c, _d E12 - _a.SetOne().Double(&_a) - - // put a and _a in the cyclotomic subgroup - // a (g3 != 0 probably) - b.Conjugate(a) - a.Inverse(a) - b.Mul(&b, a) - a.FrobeniusSquare(&b).Mul(a, &b) - // _a (g3 == 0) - b.Conjugate(&_a) - _a.Inverse(&_a) - b.Mul(&b, &_a) - _a.FrobeniusSquare(&b).Mul(&_a, &b) - - // case g3 != 0 - c.Square(a) - d.CyclotomicSquareCompressed(a).DecompressKarabina(&d) - - // case g3 == 0 - _c.Square(&_a) - _d.CyclotomicSquareCompressed(&_a).DecompressKarabina(&_d) - - return c.Equal(&d) - }, - genA, - )) - - properties.Property("[BLS12-377] batch decompress and individual decompress (Karabina) should be the same", prop.ForAll( - func(a *E12) bool { - var _a, b E12 - _a.SetOne().Double(&_a) - - // put a and _a in the cyclotomic subgroup - // a (g3 !=0 probably) - b.Conjugate(a) - a.Inverse(a) - b.Mul(&b, a) - a.FrobeniusSquare(&b).Mul(a, &b) - // _a (g3 == 0) - b.Conjugate(&_a) - _a.Inverse(&_a) - b.Mul(&b, &_a) - _a.FrobeniusSquare(&b).Mul(&_a, &b) - - var a2, a4, a17 E12 - a2.Set(&_a) - a4.Set(a) - a17.Set(a) - a2.nSquareCompressed(2) // case g3 == 0 - a4.nSquareCompressed(4) - a17.nSquareCompressed(17) - batch := BatchDecompressKarabina([]E12{a2, a4, a17}) - a2.DecompressKarabina(&a2) - a4.DecompressKarabina(&a4) - a17.DecompressKarabina(&a17) - - return a2.Equal(&batch[0]) && a4.Equal(&batch[1]) && a17.Equal(&batch[2]) - }, - genA, - )) - - properties.Property("[BLS12-377] Exp and CyclotomicExp results must be the same in the cyclotomic subgroup", prop.ForAll( - func(a *E12, e fp.Element) bool { - var b, c, d E12 - // put in the cyclo subgroup - b.Conjugate(a) - a.Inverse(a) - b.Mul(&b, a) - a.FrobeniusSquare(&b).Mul(a, &b) - - var _e big.Int - k := new(big.Int).SetUint64(12) - e.Exp(e, k) - e.BigInt(&_e) - - c.Exp(*a, &_e) - d.CyclotomicExp(*a, &_e) - - return c.Equal(&d) - }, - genA, - genExp, - )) - - properties.Property("[BLS12-377] Frobenius of x in E12 should be equal to x^q", prop.ForAll( - func(a *E12) bool { - var b, c E12 - q := fp.Modulus() - b.Frobenius(a) - c.Exp(*a, q) - return c.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] FrobeniusSquare of x in E12 should be equal to x^(q^2)", prop.ForAll( - func(a *E12) bool { - var b, c E12 - q := fp.Modulus() - b.FrobeniusSquare(a) - c.Exp(*a, q).Exp(c, q) - return c.Equal(&b) - }, - genA, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) - -} - -// ------------------------------------------------------------ -// benches - -func BenchmarkE12Add(b *testing.B) { - var a, c E12 - _, _ = a.SetRandom() - _, _ = c.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Add(&a, &c) - } -} - -func BenchmarkE12Sub(b *testing.B) { - var a, c E12 - _, _ = a.SetRandom() - _, _ = c.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Sub(&a, &c) - } -} - -func BenchmarkE12Mul(b *testing.B) { - var a, c E12 - _, _ = a.SetRandom() - _, _ = c.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Mul(&a, &c) - } -} - -func BenchmarkE12Cyclosquare(b *testing.B) { - var a E12 - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.CyclotomicSquare(&a) - } -} - -func BenchmarkE12Square(b *testing.B) { - var a E12 - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Square(&a) - } -} - -func BenchmarkE12Inverse(b *testing.B) { - var a E12 - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Inverse(&a) - } -} - -func BenchmarkE12Conjugate(b *testing.B) { - var a E12 - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Conjugate(&a) - } -} - -func BenchmarkE12Frobenius(b *testing.B) { - var a E12 - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Frobenius(&a) - } -} - -func BenchmarkE12FrobeniusSquare(b *testing.B) { - var a E12 - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.FrobeniusSquare(&a) - } -} - -func BenchmarkE12Expt(b *testing.B) { - var a E12 - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Expt(&a) - } -} - -func TestE12Div(t *testing.T) { - - parameters := gopter.DefaultTestParameters() - properties := gopter.NewProperties(parameters) - - genA := GenE12() - genB := GenE12() - - properties.Property("[BLS12-377] dividing then multiplying by the same element does nothing", prop.ForAll( - func(a, b *E12) bool { - var c E12 - c.Div(a, b) - c.Mul(&c, b) - return c.Equal(a) - }, - genA, - genB, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} diff --git a/prover/maths/field/fext/e2.go b/prover/maths/field/fext/e2.go index 3863d5025..c44d564a1 100644 --- a/prover/maths/field/fext/e2.go +++ b/prover/maths/field/fext/e2.go @@ -1,29 +1,16 @@ -// Copyright 2020 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - package fext import ( - "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" ) -// E2 is a degree two finite field extension of fp.Element +const ExtensionDegree int = 2 + +// E2 is a degree two finite field extension of fr.Element type E2 struct { - A0, A1 fp.Element + A0, A1 fr.Element } // Equal returns true if z equals x, false otherwise @@ -31,15 +18,6 @@ func (z *E2) Equal(x *E2) bool { return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1) } -// Bits -// TODO @gbotrel fixme this shouldn't return a E2 -func (z *E2) Bits() E2 { - r := E2{} - r.A0 = z.A0.Bits() - r.A1 = z.A1.Bits() - return r -} - // Cmp compares (lexicographic order) z and x and returns: // // -1 if z < x @@ -63,17 +41,10 @@ func (z *E2) LexicographicallyLargest() bool { } // SetString sets a E2 element from strings -func (z *E2) SetString(s1, s2 string) (*E2, error) { - _, err := z.A0.SetString(s1) - if err != nil { - return nil, err - } - - _, err = z.A1.SetString(s2) - if err != nil { - return nil, err - } - return z, nil +func (z *E2) SetString(s1, s2 string) *E2 { + z.A0.SetString(s1) + z.A1.SetString(s2) + return z } // SetZero sets an E2 elmt to zero @@ -120,25 +91,29 @@ func (z *E2) IsOne() bool { // Add adds two elements of E2 func (z *E2) Add(x, y *E2) *E2 { - addE2(z, x, y) + z.A0.Add(&x.A0, &y.A0) + z.A1.Add(&x.A1, &y.A1) return z } // Sub subtracts two elements of E2 func (z *E2) Sub(x, y *E2) *E2 { - subE2(z, x, y) + z.A0.Sub(&x.A0, &y.A0) + z.A1.Sub(&x.A1, &y.A1) return z } // Double doubles an E2 element func (z *E2) Double(x *E2) *E2 { - doubleE2(z, x) + z.A0.Double(&x.A0) + z.A1.Double(&x.A1) return z } // Neg negates an E2 element func (z *E2) Neg(x *E2) *E2 { - negE2(z, x) + z.A0.Neg(&x.A0) + z.A1.Neg(&x.A1) return z } @@ -147,9 +122,9 @@ func (z *E2) String() string { return z.A0.String() + "+" + z.A1.String() + "*u" } -// MulByElement multiplies an element in E2 by an element in fp -func (z *E2) MulByElement(x *E2, y *fp.Element) *E2 { - var yCopy fp.Element +// MulByElement multiplies an element in E2 by an element in fr +func (z *E2) MulByElement(x *E2, y *fr.Element) *E2 { + var yCopy fr.Element yCopy.Set(y) z.A0.Mul(&x.A0, &yCopy) z.A1.Mul(&x.A1, &yCopy) @@ -171,7 +146,7 @@ func (z *E2) Halve() { // Legendre returns the Legendre symbol of z func (z *E2) Legendre() int { - var n fp.Element + var n fr.Element z.norm(&n) return n.Legendre() } @@ -219,12 +194,12 @@ func (z *E2) Sqrt(x *E2) *E2 { // precomputation var b, c, d, e, f, x0 E2 - var _b, o fp.Element + var _b, o fr.Element // c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently) c.A1.SetOne() - q := fp.Modulus() + q := fr.Modulus() var exp, one big.Int one.SetUint64(1) exp.Set(q).Sub(&exp, &one).Rsh(&exp, 1) diff --git a/prover/maths/field/fext/e2_bls377.go b/prover/maths/field/fext/e2_bls377.go index 694b73034..d67a9da57 100644 --- a/prover/maths/field/fext/e2_bls377.go +++ b/prover/maths/field/fext/e2_bls377.go @@ -1,52 +1,43 @@ -// Copyright 2020 ConsenSys AG -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package fext import ( - "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" ) +// MulBy11 x *= 11 (mod r) +func MulBy11(x *fr.Element) { + y := fr.Element{ + 1855201571499933546, + 8511318076631809892, + 6222514765367795509, + 1122129207579058019, + } + x.Mul(x, &y) +} + // Mul sets z to the E2-product of x,y, returns z func (z *E2) Mul(x, y *E2) *E2 { - var a, b, c fp.Element + var a, b, c fr.Element a.Add(&x.A0, &x.A1) b.Add(&y.A0, &y.A1) a.Mul(&a, &b) b.Mul(&x.A0, &y.A0) c.Mul(&x.A1, &y.A1) z.A1.Sub(&a, &b).Sub(&z.A1, &c) - fp.MulBy5(&c) + MulBy11(&c) z.A0.Sub(&b, &c) return z } // Square sets z to the E2-product of x,x returns z func (z *E2) Square(x *E2) *E2 { - //algo 22 https://eprint.iacr.org/2010/354.pdf - var c0, c2 fp.Element - c0.Add(&x.A0, &x.A1) - c2.Neg(&x.A1) - fp.MulBy5(&c2) - c2.Add(&c2, &x.A0) - - c0.Mul(&c0, &c2) // (x1+x2)*(x1+(u**2)x2) - c2.Mul(&x.A0, &x.A1).Double(&c2) - z.A1 = c2 - c2.Double(&c2) - z.A0.Add(&c0, &c2) - + var a, b, c fr.Element + a.Mul(&x.A0, &x.A1).Double(&a) + c.Square(&x.A0) + b.Square(&x.A1) + MulBy11(&b) + z.A0.Sub(&c, &b) + z.A1 = a return z } @@ -54,7 +45,7 @@ func (z *E2) Square(x *E2) *E2 { func (z *E2) MulByNonResidue(x *E2) *E2 { a := x.A0 b := x.A1 // fetching x.A1 in the function below is slower - fp.MulBy5(&b) + MulBy11(&b) z.A0.Neg(&b) z.A1 = a return z @@ -62,17 +53,15 @@ func (z *E2) MulByNonResidue(x *E2) *E2 { // MulByNonResidueInv multiplies a E2 by (0,1)^{-1} func (z *E2) MulByNonResidueInv(x *E2) *E2 { - //z.A1.MulByNonResidueInv(&x.A0) a := x.A1 - fiveinv := fp.Element{ - 330620507644336508, - 9878087358076053079, - 11461392860540703536, - 6973035786057818995, - 8846909097162646007, - 104838758629667239, + // 1/11 mod r + elevenInv := fr.Element{ + 7989155441247042094, + 18276457113184108543, + 17999817914616464103, + 943187440870955565, } - z.A1.Mul(&x.A0, &fiveinv).Neg(&z.A1) + z.A1.Mul(&x.A0, &elevenInv).Neg(&z.A1) z.A0 = a return z } @@ -80,14 +69,13 @@ func (z *E2) MulByNonResidueInv(x *E2) *E2 { // Inverse sets z to the E2-inverse of x, returns z func (z *E2) Inverse(x *E2) *E2 { // Algorithm 8 from https://eprint.iacr.org/2010/354.pdf - //var a, b, t0, t1, tmp fp.Element - var t0, t1, tmp fp.Element + var t0, t1, tmp fr.Element a := &x.A0 // creating the buffers a, b is faster than querying &x.A0, &x.A1 in the functions call below b := &x.A1 t0.Square(a) t1.Square(b) tmp.Set(&t1) - fp.MulBy5(&tmp) + MulBy11(&tmp) t0.Add(&t0, &tmp) t1.Inverse(&t0) z.A0.Mul(a, &t1) @@ -97,21 +85,10 @@ func (z *E2) Inverse(x *E2) *E2 { } // norm sets x to the norm of z -func (z *E2) norm(x *fp.Element) { - var tmp fp.Element +func (z *E2) norm(x *fr.Element) { + var tmp fr.Element x.Square(&z.A1) tmp.Set(x) - fp.MulBy5(&tmp) + MulBy11(&tmp) x.Square(&z.A0).Add(x, &tmp) } - -// MulBybTwistCurveCoeff multiplies by 1/(0,1) -func (z *E2) MulBybTwistCurveCoeff(x *E2) *E2 { - - var res E2 - res.A0.Set(&x.A1) - res.A1.MulByNonResidueInv(&x.A0) - z.Set(&res) - - return z -} diff --git a/prover/maths/field/fext/e2_fallback.go b/prover/maths/field/fext/e2_fallback.go deleted file mode 100644 index fd8d703f4..000000000 --- a/prover/maths/field/fext/e2_fallback.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2020 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fext - -func addE2(z, x, y *E2) { - z.A0.Add(&x.A0, &y.A0) - z.A1.Add(&x.A1, &y.A1) -} - -func subE2(z, x, y *E2) { - z.A0.Sub(&x.A0, &y.A0) - z.A1.Sub(&x.A1, &y.A1) -} - -func doubleE2(z, x *E2) { - z.A0.Double(&x.A0) - z.A1.Double(&x.A1) -} - -func negE2(z, x *E2) { - z.A0.Neg(&x.A0) - z.A1.Neg(&x.A1) -} diff --git a/prover/maths/field/fext/e2_fallback_new.go b/prover/maths/field/fext/e2_fallback_new.go deleted file mode 100644 index 7567bc99d..000000000 --- a/prover/maths/field/fext/e2_fallback_new.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2020 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fext - -func addE2New(z, x, y *Element) { - z.A0.Add(&x.A0, &y.A0) - z.A1.Add(&x.A1, &y.A1) -} - -func subE2New(z, x, y *Element) { - z.A0.Sub(&x.A0, &y.A0) - z.A1.Sub(&x.A1, &y.A1) -} - -func doubleE2New(z, x *Element) { - z.A0.Double(&x.A0) - z.A1.Double(&x.A1) -} - -func negE2New(z, x *Element) { - z.A0.Neg(&x.A0) - z.A1.Neg(&x.A1) -} diff --git a/prover/maths/field/fext/e2_test.go b/prover/maths/field/fext/e2_test.go index 6f36b3c7a..48d5142dd 100644 --- a/prover/maths/field/fext/e2_test.go +++ b/prover/maths/field/fext/e2_test.go @@ -1,26 +1,10 @@ -// Copyright 2020 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - package fext import ( "crypto/rand" "testing" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -47,7 +31,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA := GenE2() genB := GenE2() - genfp := GenFp() + genfr := GenFr() properties.Property("[BLS12-377] Having the receiver as operand (addition) should output the same result", prop.ForAll( func(a, b *E2) bool { @@ -159,14 +143,14 @@ func TestE2ReceiverIsOperand(t *testing.T) { )) properties.Property("[BLS12-377] Having the receiver as operand (mul by element) should output the same result", prop.ForAll( - func(a *E2, b fp.Element) bool { + func(a *E2, b fr.Element) bool { var c E2 c.MulByElement(a, &b) a.MulByElement(a, &b) return a.Equal(&c) }, genA, - genfp, + genfr, )) properties.Property("[BLS12-377] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( @@ -194,27 +178,25 @@ func TestE2ReceiverIsOperand(t *testing.T) { func TestE2MulMaxed(t *testing.T) { // let's pick a and b, with maxed A0 and A1 var a, b E2 - fpMaxValue := fp.Element{ - 9586122913090633729, - 1660523435060625408, - 2230234197602682880, - 1883307231910630287, - 14284016967150029115, - 121098312706494698, + frMaxValue := fr.Element{ + 725501752471715841, + 6461107452199829505, + 6968279316240510977, + 1345280370688173398, } - fpMaxValue[0]-- + frMaxValue[0]-- - a.A0 = fpMaxValue - a.A1 = fpMaxValue - b.A0 = fpMaxValue - b.A1 = fpMaxValue + a.A0 = frMaxValue + a.A1 = frMaxValue + b.A0 = frMaxValue + b.A1 = frMaxValue var c, d E2 d.Inverse(&b) c.Set(&a) c.Mul(&c, &b).Mul(&c, &d) if !c.Equal(&a) { - t.Fatal("mul with max fp failed") + t.Fatal("mul with max fr failed") } } @@ -232,7 +214,7 @@ func TestE2Ops(t *testing.T) { genA := GenE2() genB := GenE2() - genfp := GenFp() + genfr := GenFr() properties.Property("[BLS12-377] sub & add should leave an element invariant", prop.ForAll( func(a, b *E2) bool { @@ -300,21 +282,21 @@ func TestE2Ops(t *testing.T) { )) properties.Property("[BLS12-377] MulByElement MulByElement inverse should leave an element invariant", prop.ForAll( - func(a *E2, b fp.Element) bool { + func(a *E2, b fr.Element) bool { var c E2 - var d fp.Element + var d fr.Element d.Inverse(&b) c.MulByElement(a, &b).MulByElement(&c, &d) return c.Equal(a) }, genA, - genfp, + genfr, )) properties.Property("[BLS12-377] Double and mul by 2 should output the same result", prop.ForAll( func(a *E2) bool { var b E2 - var c fp.Element + var c fr.Element c.SetUint64(2) b.Double(a) a.MulByElement(a, &c) @@ -335,7 +317,7 @@ func TestE2Ops(t *testing.T) { properties.Property("[BLS12-377] a + pi(a), a-pi(a) should be real", prop.ForAll( func(a *E2) bool { var b, c, d E2 - var e, f fp.Element + var e, f fr.Element b.Conjugate(a) c.Add(a, &b) d.Sub(a, &b) @@ -435,7 +417,7 @@ func BenchmarkE2Mul(b *testing.B) { func BenchmarkE2MulByElement(b *testing.B) { var a E2 - var c fp.Element + var c fr.Element _, _ = c.SetRandom() _, _ = a.SetRandom() b.ResetTimer() @@ -465,7 +447,7 @@ func BenchmarkE2Sqrt(b *testing.B) { func BenchmarkE2Exp(b *testing.B) { var x E2 _, _ = x.SetRandom() - b1, _ := rand.Int(rand.Reader, fp.Modulus()) + b1, _ := rand.Int(rand.Reader, fr.Modulus()) b.ResetTimer() for i := 0; i < b.N; i++ { x.Exp(x, b1) diff --git a/prover/maths/field/fext/e2new.go b/prover/maths/field/fext/e2new.go deleted file mode 100644 index e85f0766f..000000000 --- a/prover/maths/field/fext/e2new.go +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2020 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fext - -import ( - "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - "github.com/consensys/linea-monorepo/prover/maths/field" - "math/big" - "math/rand" -) - -const noQNR = 11 - -// Element is a degree two finite field extension of fr.Element -type Element struct { - A0, A1 fr.Element -} - -// Equal returns true if z equals x, false otherwise -func (z *Element) Equal(x *Element) bool { - return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1) -} - -// Bits -// TODO @gbotrel fixme this shouldn't return a Element -func (z *Element) Bits() Element { - r := Element{} - r.A0 = z.A0.Bits() - r.A1 = z.A1.Bits() - return r -} - -// Cmp compares (lexicographic order) z and x and returns: -// -// -1 if z < x -// 0 if z == x -// +1 if z > x -func (z *Element) Cmp(x *Element) int { - if a1 := z.A1.Cmp(&x.A1); a1 != 0 { - return a1 - } - return z.A0.Cmp(&x.A0) -} - -// LexicographicallyLargest returns true if this element is strictly lexicographically -// larger than its negation, false otherwise -func (z *Element) LexicographicallyLargest() bool { - // adapted from github.com/zkcrypto/bls12_381 - if z.A1.IsZero() { - return z.A0.LexicographicallyLargest() - } - return z.A1.LexicographicallyLargest() -} - -// SetString sets a Element element from strings -func (z *Element) SetString(s1, s2 string) (*Element, error) { - _, err := z.A0.SetString(s1) - if err != nil { - return z, err - } - - _, err = z.A1.SetString(s2) - if err != nil { - return z, err - } - return z, nil -} - -// SetZero sets an Element elmt to zero -func (z *Element) SetZero() *Element { - z.A0.SetZero() - z.A1.SetZero() - return z -} - -// Set sets an Element from x -func (z *Element) Set(x *Element) *Element { - z.A0 = x.A0 - z.A1 = x.A1 - return z -} - -// SetOne sets z to 1 in Montgomery form and returns z -func (z *Element) SetOne() *Element { - z.A0.SetOne() - z.A1.SetZero() - return z -} - -// SetRandom sets a0 and a1 to random values -func (z *Element) SetRandom() (*Element, error) { - if _, err := z.A0.SetRandom(); err != nil { - return nil, err - } - if _, err := z.A1.SetRandom(); err != nil { - return nil, err - } - return z, nil -} - -// IsZero returns true if z is zero, false otherwise -func (z *Element) IsZero() bool { - return z.A0.IsZero() && z.A1.IsZero() -} - -// IsOne returns true if z is one, false otherwise -func (z *Element) IsOne() bool { - return z.A0.IsOne() && z.A1.IsZero() -} - -// Add adds two elements of Element -func (z *Element) Add(x, y *Element) *Element { - addE2New(z, x, y) - return z -} - -// Sub subtracts two elements of Element -func (z *Element) Sub(x, y *Element) *Element { - subE2New(z, x, y) - return z -} - -// Double doubles an Element element -func (z *Element) Double(x *Element) *Element { - doubleE2New(z, x) - return z -} - -// Neg negates an Element element -func (z *Element) Neg(x *Element) *Element { - negE2New(z, x) - return z -} - -// String implements Stringer interface for fancy printing -func (z *Element) String() string { - return z.A0.String() + "+" + z.A1.String() + "*u" -} - -// MulByElement multiplies an element in Element by an element in fp -func (z *Element) MulByElement(x *Element, y *fr.Element) *Element { - var yCopy fr.Element - yCopy.Set(y) - z.A0.Mul(&x.A0, &yCopy) - z.A1.Mul(&x.A1, &yCopy) - return z -} - -// Conjugate conjugates an element in Element -func (z *Element) Conjugate(x *Element) *Element { - z.A0 = x.A0 - z.A1.Neg(&x.A1) - return z -} - -// Halve sets z to z / 2 -func (z *Element) Halve() { - z.A0.Halve() - z.A1.Halve() -} - -// Legendre returns the Legendre symbol of z -func (z *Element) Legendre() int { - var n fr.Element - z.norm(&n) - return n.Legendre() -} - -// Exp sets z=xᵏ (mod q²) and returns it -func (z *Element) Exp(x Element, k *big.Int) *Element { - if k.IsUint64() && k.Uint64() == 0 { - return z.SetOne() - } - - e := k - if k.Sign() == -1 { - // negative k, we invert - // if k < 0: xᵏ (mod q²) == (x⁻¹)ᵏ (mod q²) - x.Inverse(&x) - - // we negate k in a temp big.Int since - // Int.Bit(_) of k and -k is different - e = bigIntPool.Get().(*big.Int) - defer bigIntPool.Put(e) - e.Neg(k) - } - - z.SetOne() - b := e.Bytes() - for i := 0; i < len(b); i++ { - w := b[i] - for j := 0; j < 8; j++ { - z.Square(z) - if (w & (0b10000000 >> j)) != 0 { - z.Mul(z, &x) - } - } - } - - return z -} - -// Sqrt sets z to the square root of and returns z -// The function does not test whether the square root -// exists or not, it's up to the caller to call -// Legendre beforehand. -// cf https://eprint.iacr.org/2012/685.pdf (algo 10) -func (z *Element) Sqrt(x *Element) *Element { - - // precomputation - var b, c, d, e, f, x0 Element - var _b, o fr.Element - - // c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently) - c.A1.SetOne() - - q := fp.Modulus() - var exp, one big.Int - one.SetUint64(1) - exp.Set(q).Sub(&exp, &one).Rsh(&exp, 1) - d.Exp(c, &exp) - e.Mul(&d, &c).Inverse(&e) - f.Mul(&d, &c).Square(&f) - - // computation - exp.Rsh(&exp, 1) - b.Exp(*x, &exp) - b.norm(&_b) - o.SetOne() - if _b.Equal(&o) { - x0.Square(&b).Mul(&x0, x) - _b.Set(&x0.A0).Sqrt(&_b) - z.Conjugate(&b).MulByElement(z, &_b) - return z - } - x0.Square(&b).Mul(&x0, x).Mul(&x0, &f) - _b.Set(&x0.A0).Sqrt(&_b) - z.Conjugate(&b).MulByElement(z, &_b).Mul(z, &e) - - return z -} - -// BatchInvertE2New returns a new slice with every element in a inverted. -// It uses Montgomery batch inversion trick. -// -// if a[i] == 0, returns result[i] = a[i] -func BatchInvertE2New(a []Element) []Element { - res := make([]Element, len(a)) - if len(a) == 0 { - return res - } - - zeroes := make([]bool, len(a)) - var accumulator Element - accumulator.SetOne() - - for i := 0; i < len(a); i++ { - if a[i].IsZero() { - zeroes[i] = true - continue - } - res[i].Set(&accumulator) - accumulator.Mul(&accumulator, &a[i]) - } - - accumulator.Inverse(&accumulator) - - for i := len(a) - 1; i >= 0; i-- { - if zeroes[i] { - continue - } - res[i].Mul(&res[i], &accumulator) - accumulator.Mul(&accumulator, &a[i]) - } - - return res -} - -// Select is conditional move. -// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. -func (z *Element) Select(cond int, caseZ *Element, caseNz *Element) *Element { - //Might be able to save a nanosecond or two by an aggregate implementation - - z.A0.Select(cond, &caseZ.A0, &caseNz.A0) - z.A1.Select(cond, &caseZ.A1, &caseNz.A1) - - return z -} - -// Div divides an element in Element by an element in Element -func (z *Element) Div(x *Element, y *Element) *Element { - var r Element - r.Inverse(y).Mul(x, &r) - return z.Set(&r) -} - -func PseudoRand(rng *rand.Rand) Element { - x := field.PseudoRand(rng) - y := field.PseudoRand(rng) - result := new(Element).SetZero() - return *result.Add(result, &Element{x, y}) -} diff --git a/prover/maths/field/fext/e2new_bls377.go b/prover/maths/field/fext/e2new_bls377.go deleted file mode 100644 index 028adcb86..000000000 --- a/prover/maths/field/fext/e2new_bls377.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2020 ConsenSys AG -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package fext - -import ( - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" -) - -// Mul sets z to the Element-product of x,y, returns z -func (z *Element) Mul(x, y *Element) *Element { - var a, b, c fr.Element - a.Add(&x.A0, &x.A1) - b.Add(&y.A0, &y.A1) - a.Mul(&a, &b) - b.Mul(&x.A0, &y.A0) - c.Mul(&x.A1, &y.A1) - z.A1.Sub(&a, &b).Sub(&z.A1, &c) - MulByQnr(&c) - z.A0.Sub(&b, &c) - return z -} - -// Square sets z to the Element-product of x,x returns z -func (z *Element) Square(x *Element) *Element { - //algo 22 https://eprint.iacr.org/2010/354.pdf - z.Mul(x, x) - return z -} - -// MulByNonResidue multiplies a Element by (0,1) -func (z *Element) MulByNonResidue(x *Element) *Element { - a := x.A0 - b := x.A1 // fetching x.A1 in the function below is slower - MulByQnr(&b) - z.A0.Neg(&b) - z.A1 = a - return z -} - -// MulByNonResidueInv multiplies a Element by (0,1)^{-1} -func (z *Element) MulByNonResidueInv(x *Element) *Element { - //z.A1.MulByNonResidueInv(&x.A0) - a := x.A1 - qnr := new(fr.Element).SetInt64(noQNR) - var qnrInv fr.Element - qnrInv.Inverse(qnr) - z.A1.Mul(&x.A0, &qnrInv).Neg(&z.A1) - z.A0 = a - return z -} - -// Inverse sets z to the Element-inverse of x, returns z -func (z *Element) Inverse(x *Element) *Element { - // Algorithm 8 from https://eprint.iacr.org/2010/354.pdf - //var a, b, t0, t1, tmp fr.Element - var t0, t1, tmp fr.Element - a := &x.A0 // creating the buffers a, b is faster than querying &x.A0, &x.A1 in the functions call below - b := &x.A1 - t0.Square(a) - t1.Square(b) - tmp.Set(&t1) - MulByQnr(&tmp) - t0.Add(&t0, &tmp) - t1.Inverse(&t0) - z.A0.Mul(a, &t1) - z.A1.Mul(b, &t1).Neg(&z.A1) - - return z -} - -// norm sets x to the norm of z -func (z *Element) norm(x *fr.Element) { - var tmp fr.Element - x.Square(&z.A1) - tmp.Set(x) - MulByQnr(&tmp) - x.Square(&z.A0).Add(x, &tmp) - // A0^2+A1^2*QNR -} -func MulByQnr(x *fr.Element) { - old := new(fr.Element).Set(x) - for i := 0; i < noQNR-1; i++ { - x.Add(x, old) - } -} - -/* -// MulBybTwistCurveCoeff multiplies by 1/(0,1) -func (z *Element) MulBybTwistCurveCoeff(x *Element) *Element { - - var res Element - res.A0.Set(&x.A1) - res.A1.MulByNonResidueInv(&x.A0) - z.Set(&res) - - return z -} -*/ diff --git a/prover/maths/field/fext/e2new_test.go b/prover/maths/field/fext/e2new_test.go deleted file mode 100644 index f58c8880e..000000000 --- a/prover/maths/field/fext/e2new_test.go +++ /dev/null @@ -1,600 +0,0 @@ -// Copyright 2020 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fext - -import ( - "crypto/rand" - "fmt" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - "testing" - - "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" - "github.com/leanovate/gopter" - "github.com/leanovate/gopter/prop" -) - -// ------------------------------------------------------------ -// tests - -func GenFr() gopter.Gen { - return func(genParams *gopter.GenParameters) *gopter.GenResult { - var elmt fr.Element - - if _, err := elmt.SetRandom(); err != nil { - panic(err) - } - genResult := gopter.NewGenResult(elmt, gopter.NoShrinker) - return genResult - } -} - -func GenE2New() gopter.Gen { - return gopter.CombineGens( - GenFr(), - GenFr(), - ).Map(func(values []interface{}) *Element { - return &Element{A0: values[0].(fr.Element), A1: values[1].(fr.Element)} - }) -} - -func TestE2NewNewReceiverIsOperand(t *testing.T) { - - t.Parallel() - parameters := gopter.DefaultTestParameters() - if testing.Short() { - parameters.MinSuccessfulTests = nbFuzzShort - } else { - parameters.MinSuccessfulTests = nbFuzz - } - - properties := gopter.NewProperties(parameters) - - genA := GenE2New() - genB := GenE2New() - GenFr := GenFr() - - properties.Property("[BLS12-377] Having the receiver as operand (addition) should output the same result", prop.ForAll( - func(a, b *Element) bool { - var c, d Element - d.Set(a) - c.Add(a, b) - a.Add(a, b) - b.Add(&d, b) - return a.Equal(b) && a.Equal(&c) && b.Equal(&c) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (sub) should output the same result", prop.ForAll( - func(a, b *Element) bool { - var c, d Element - d.Set(a) - c.Sub(a, b) - a.Sub(a, b) - b.Sub(&d, b) - return a.Equal(b) && a.Equal(&c) && b.Equal(&c) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (mul) should output the same result", prop.ForAll( - func(a, b *Element) bool { - var c, d Element - d.Set(a) - c.Mul(a, b) - a.Mul(a, b) - b.Mul(&d, b) - return a.Equal(b) && a.Equal(&c) && b.Equal(&c) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (square) should output the same result", prop.ForAll( - func(a *Element) bool { - var b Element - b.Square(a) - a.Square(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (neg) should output the same result", prop.ForAll( - func(a *Element) bool { - var b Element - b.Neg(a) - a.Neg(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (double) should output the same result", prop.ForAll( - func(a *Element) bool { - var b Element - b.Double(a) - a.Double(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( - func(a *Element) bool { - var b Element - b.MulByNonResidue(a) - a.MulByNonResidue(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (mul by non residue inverse) should output the same result", prop.ForAll( - func(a *Element) bool { - var b Element - b.MulByNonResidueInv(a) - a.MulByNonResidueInv(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( - func(a *Element) bool { - var b Element - b.Inverse(a) - a.Inverse(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( - func(a *Element) bool { - var b Element - b.Conjugate(a) - a.Conjugate(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (mul by element) should output the same result", prop.ForAll( - func(a *Element, b fr.Element) bool { - var c Element - c.MulByElement(a, &b) - a.MulByElement(a, &b) - return a.Equal(&c) - }, - genA, - GenFr, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( - func(a *Element) bool { - var b, c, d, s Element - - s.Square(a) - a.Set(&s) - b.Set(&s) - - a.Sqrt(a) - b.Sqrt(&b) - - c.Square(a) - d.Square(&b) - return c.Equal(&d) - }, - genA, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) - -} - -/* -func TestE2NewMulMaxed(t *testing.T) { - // let's pick a and b, with maxed A0 and A1 - var a, b Element - fpMaxValue := fp.Element{ - 9586122913090633729, - 1660523435060625408, - 2230234197602682880, - 1883307231910630287, - 14284016967150029115, - 121098312706494698, - } - fpMaxValue[0]-- - - a.A0 = fpMaxValue - a.A1 = fpMaxValue - b.A0 = fpMaxValue - b.A1 = fpMaxValue - - var c, d Element - d.Inverse(&b) - c.Set(&a) - c.Mul(&c, &b).Mul(&c, &d) - if !c.Equal(&a) { - t.Fatal("mul with max fp failed") - } -}*/ - -func TestE2NewOps(t *testing.T) { - - t.Parallel() - parameters := gopter.DefaultTestParameters() - if testing.Short() { - parameters.MinSuccessfulTests = nbFuzzShort - } else { - parameters.MinSuccessfulTests = nbFuzz - } - - properties := gopter.NewProperties(parameters) - - genA := GenE2New() - genB := GenE2New() - GenFr := GenFr() - - properties.Property("[BLS12-377] sub & add should leave an element invariant", prop.ForAll( - func(a, b *Element) bool { - var c Element - c.Set(a) - c.Add(&c, b).Sub(&c, b) // a+b-b - return c.Equal(a) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] mul & inverse should leave an element invariant", prop.ForAll( - func(a, b *Element) bool { - var c, d Element - d.Inverse(b) - c.Set(a) - c.Mul(&c, b).Mul(&c, &d) - return c.Equal(a) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] BatchInvertE2New should output the same result as Inverse", prop.ForAll( - func(a, b, c *Element) bool { - - batch := BatchInvertE2New([]Element{*a, *b, *c}) - a.Inverse(a) - b.Inverse(b) - c.Inverse(c) - return a.Equal(&batch[0]) && b.Equal(&batch[1]) && c.Equal(&batch[2]) - }, - genA, - genA, - genA, - )) - - properties.Property("[BLS12-377] inverse twice should leave an element invariant", prop.ForAll( - func(a *Element) bool { - var b Element - b.Inverse(a).Inverse(&b) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] neg twice should leave an element invariant", prop.ForAll( - func(a *Element) bool { - var b Element - b.Neg(a).Neg(&b) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] square and mul should output the same result", prop.ForAll( - func(a *Element) bool { - var b, c Element - b.Mul(a, a) - c.Square(a) - res := b.Equal(&c) - fmt.Println("square and mul should output the same result———", res) - return b.Equal(&c) - }, - genA, - )) - - properties.Property("[BLS12-377] MulByElement MulByElement inverse should leave an element invariant", prop.ForAll( - func(a *Element, b fr.Element) bool { - var c Element - var d fr.Element - d.Inverse(&b) - c.MulByElement(a, &b).MulByElement(&c, &d) - return c.Equal(a) - }, - genA, - GenFr, - )) - - properties.Property("[BLS12-377] Double and mul by 2 should output the same result", prop.ForAll( - func(a *Element) bool { - var b Element - var c fr.Element - c.SetUint64(2) - b.Double(a) - a.MulByElement(a, &c) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Mulbynonres mulbynonresinv should leave the element invariant", prop.ForAll( - func(a *Element) bool { - var b Element - b.MulByNonResidue(a).MulByNonResidueInv(&b) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] a + pi(a), a-pi(a) should be real", prop.ForAll( - func(a *Element) bool { - var b, c, d Element - var e, f fr.Element - b.Conjugate(a) - c.Add(a, &b) - d.Sub(a, &b) - e.Double(&a.A0) - f.Double(&a.A1) - return c.A1.IsZero() && d.A0.IsZero() && e.Equal(&c.A0) && f.Equal(&d.A1) - }, - genA, - )) - - properties.Property("[BLS12-377] Legendre on square should output 1", prop.ForAll( - func(a *Element) bool { - var b Element - b.Mul(a, a) - c := b.Legendre() - fmt.Println("DEBUG MESSAGE ", c) - return c == 1 - }, - genA, - )) - - /* - properties.Property("[BLS12-377] square(sqrt) should leave an element invariant", prop.ForAll( - func(a *Element) bool { - var b, c, d, e Element - b.Square(a) - c.Sqrt(&b) - d.Square(&c) - e.Neg(a) - return (c.Equal(a) || c.Equal(&e)) && d.Equal(&b) - }, - genA, - )) - - */ - - properties.Property("[BLS12-377] neg(Element) == neg(Element.A0, Element.A1)", prop.ForAll( - func(a *Element) bool { - var b, c Element - b.Neg(a) - c.A0.Neg(&a.A0) - c.A1.Neg(&a.A1) - return c.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Cmp and LexicographicallyLargest should be consistent", prop.ForAll( - func(a *Element) bool { - var negA Element - negA.Neg(a) - cmpResult := a.Cmp(&negA) - lResult := a.LexicographicallyLargest() - if lResult && cmpResult == 1 { - return true - } - if !lResult && cmpResult != 1 { - return true - } - return false - }, - genA, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) - -} - -// ------------------------------------------------------------ -// benches - -func BenchmarkE2NewAdd(b *testing.B) { - var a, c Element - _, _ = a.SetRandom() - _, _ = c.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Add(&a, &c) - } -} - -func BenchmarkE2NewSub(b *testing.B) { - var a, c Element - _, _ = a.SetRandom() - _, _ = c.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Sub(&a, &c) - } -} - -func BenchmarkE2NewMul(b *testing.B) { - var a, c Element - _, _ = a.SetRandom() - _, _ = c.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Mul(&a, &c) - } -} - -func BenchmarkE2NewMulByElement(b *testing.B) { - var a Element - var c fr.Element - _, _ = c.SetRandom() - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.MulByElement(&a, &c) - } -} - -func BenchmarkE2NewSquare(b *testing.B) { - var a Element - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Square(&a) - } -} - -func BenchmarkE2NewSqrt(b *testing.B) { - var a Element - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Sqrt(&a) - } -} - -func BenchmarkE2NewExp(b *testing.B) { - var x Element - _, _ = x.SetRandom() - b1, _ := rand.Int(rand.Reader, fp.Modulus()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - x.Exp(x, b1) - } -} - -func BenchmarkE2NewInverse(b *testing.B) { - var a Element - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Inverse(&a) - } -} - -func BenchmarkE2NewMulNonRes(b *testing.B) { - var a Element - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.MulByNonResidue(&a) - } -} - -func BenchmarkE2NewMulNonResInv(b *testing.B) { - var a Element - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.MulByNonResidueInv(&a) - } -} - -func BenchmarkE2NewConjugate(b *testing.B) { - var a Element - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Conjugate(&a) - } -} - -func TestE2NewDiv(t *testing.T) { - - parameters := gopter.DefaultTestParameters() - properties := gopter.NewProperties(parameters) - - genA := GenE2New() - genB := GenE2New() - - properties.Property("[BLS12-377] dividing then multiplying by the same element does nothing", prop.ForAll( - func(a, b *Element) bool { - var c Element - c.Div(a, b) - c.Mul(&c, b) - return c.Equal(a) - }, - genA, - genB, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} - -func TestBasicQnrEquality(t *testing.T) { - var xCoeff = [...]int64{1, 3, 3} - var yCoeff = [...]int64{2, 1, 2} - var zCoeff = [...]int64{-43, -2, -35} - var wCoeff = [...]int64{4, 6, 12} - - for i := 0; i < len(xCoeff); i++ { - x := new(fr.Element).SetInt64(xCoeff[i]) - y := new(fr.Element).SetInt64(yCoeff[i]) - z := new(fr.Element).SetInt64(zCoeff[i]) - w := new(fr.Element).SetInt64(wCoeff[i]) - a := Element{*x, *y} - c := new(Element) - c.Mul(&a, &a) - d := Element{*z, *w} - res := c.Equal(&d) - fmt.Println(res) - } - -} - -func TestBasicQnrEqualitySquare(t *testing.T) { - var xCoeff = [...]int64{1, 3, 3} - var yCoeff = [...]int64{2, 1, 2} - var zCoeff = [...]int64{-43, -2, -35} - var wCoeff = [...]int64{4, 6, 12} - for i := 0; i < len(xCoeff); i++ { - x := new(fr.Element).SetInt64(xCoeff[i]) - y := new(fr.Element).SetInt64(yCoeff[i]) - z := new(fr.Element).SetInt64(zCoeff[i]) - w := new(fr.Element).SetInt64(wCoeff[i]) - a := Element{*x, *y} - c := new(Element) - c.Square(&a) - d := Element{*z, *w} - res := c.Equal(&d) - //fmt.Println(c.A0.String(), c.A1.String()) - fmt.Println(c.String()) - fmt.Println(d.String()) - fmt.Println(res) - } - -} diff --git a/prover/maths/field/fext/e6.go b/prover/maths/field/fext/e6.go deleted file mode 100644 index 06fa573bc..000000000 --- a/prover/maths/field/fext/e6.go +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright 2020 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fext - -// E6 is a degree three finite field extension of fp2 -type E6 struct { - B0, B1, B2 E2 -} - -// Equal returns true if z equals x, false otherwise -func (z *E6) Equal(x *E6) bool { - return z.B0.Equal(&x.B0) && z.B1.Equal(&x.B1) && z.B2.Equal(&x.B2) -} - -// SetString sets a E6 elmt from stringf -func (z *E6) SetString(s1, s2, s3, s4, s5, s6 string) *E6 { - z.B0.SetString(s1, s2) - z.B1.SetString(s3, s4) - z.B2.SetString(s5, s6) - return z -} - -// Set Sets a E6 elmt form another E6 elmt -func (z *E6) Set(x *E6) *E6 { - z.B0 = x.B0 - z.B1 = x.B1 - z.B2 = x.B2 - return z -} - -// SetOne sets z to 1 in Montgomery form and returns z -func (z *E6) SetOne() *E6 { - *z = E6{} - z.B0.A0.SetOne() - return z -} - -// SetRandom set z to a random elmt -func (z *E6) SetRandom() (*E6, error) { - if _, err := z.B0.SetRandom(); err != nil { - return nil, err - } - if _, err := z.B1.SetRandom(); err != nil { - return nil, err - } - if _, err := z.B2.SetRandom(); err != nil { - return nil, err - } - return z, nil -} - -// IsZero returns true if z is zero, false otherwise -func (z *E6) IsZero() bool { - return z.B0.IsZero() && z.B1.IsZero() && z.B2.IsZero() -} - -// IsOne returns true if z is one, false otherwise -func (z *E6) IsOne() bool { - return z.B0.IsOne() && z.B1.IsZero() && z.B2.IsZero() -} - -// Add adds two elements of E6 -func (z *E6) Add(x, y *E6) *E6 { - z.B0.Add(&x.B0, &y.B0) - z.B1.Add(&x.B1, &y.B1) - z.B2.Add(&x.B2, &y.B2) - return z -} - -// Neg negates the E6 number -func (z *E6) Neg(x *E6) *E6 { - z.B0.Neg(&x.B0) - z.B1.Neg(&x.B1) - z.B2.Neg(&x.B2) - return z -} - -// Sub subtracts two elements of E6 -func (z *E6) Sub(x, y *E6) *E6 { - z.B0.Sub(&x.B0, &y.B0) - z.B1.Sub(&x.B1, &y.B1) - z.B2.Sub(&x.B2, &y.B2) - return z -} - -// Double doubles an element in E6 -func (z *E6) Double(x *E6) *E6 { - z.B0.Double(&x.B0) - z.B1.Double(&x.B1) - z.B2.Double(&x.B2) - return z -} - -// String puts E6 elmt in string form -func (z *E6) String() string { - return z.B0.String() + "+(" + z.B1.String() + ")*v+(" + z.B2.String() + ")*v**2" -} - -// MulByNonResidue mul x by (0,1,0) -func (z *E6) MulByNonResidue(x *E6) *E6 { - z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 - z.B0.MulByNonResidue(&z.B0) - return z -} - -// MulByE2 multiplies an element in E6 by an element in E2 -func (z *E6) MulByE2(x *E6, y *E2) *E6 { - var yCopy E2 - yCopy.Set(y) - z.B0.Mul(&x.B0, &yCopy) - z.B1.Mul(&x.B1, &yCopy) - z.B2.Mul(&x.B2, &yCopy) - return z -} - -// MulBy12 multiplication by sparse element (0,b1,b2) -func (x *E6) MulBy12(b1, b2 *E2) *E6 { - var t1, t2, c0, tmp, c1, c2 E2 - t1.Mul(&x.B1, b1) - t2.Mul(&x.B2, b2) - c0.Add(&x.B1, &x.B2) - tmp.Add(b1, b2) - c0.Mul(&c0, &tmp) - c0.Sub(&c0, &t1) - c0.Sub(&c0, &t2) - c0.MulByNonResidue(&c0) - c1.Add(&x.B0, &x.B1) - c1.Mul(&c1, b1) - c1.Sub(&c1, &t1) - tmp.MulByNonResidue(&t2) - c1.Add(&c1, &tmp) - tmp.Add(&x.B0, &x.B2) - c2.Mul(b2, &tmp) - c2.Sub(&c2, &t2) - c2.Add(&c2, &t1) - - x.B0 = c0 - x.B1 = c1 - x.B2 = c2 - - return x -} - -// MulBy01 multiplication by sparse element (c0,c1,0) -func (z *E6) MulBy01(c0, c1 *E2) *E6 { - - var a, b, tmp, t0, t1, t2 E2 - - a.Mul(&z.B0, c0) - b.Mul(&z.B1, c1) - - tmp.Add(&z.B1, &z.B2) - t0.Mul(c1, &tmp) - t0.Sub(&t0, &b) - t0.MulByNonResidue(&t0) - t0.Add(&t0, &a) - - tmp.Add(&z.B0, &z.B2) - t2.Mul(c0, &tmp) - t2.Sub(&t2, &a) - t2.Add(&t2, &b) - - t1.Add(c0, c1) - tmp.Add(&z.B0, &z.B1) - t1.Mul(&t1, &tmp) - t1.Sub(&t1, &a) - t1.Sub(&t1, &b) - - z.B0.Set(&t0) - z.B1.Set(&t1) - z.B2.Set(&t2) - - return z -} - -// MulBy1 multiplication of E6 by sparse element (0, c1, 0) -func (z *E6) MulBy1(c1 *E2) *E6 { - - var b, tmp, t0, t1 E2 - b.Mul(&z.B1, c1) - - tmp.Add(&z.B1, &z.B2) - t0.Mul(c1, &tmp) - t0.Sub(&t0, &b) - t0.MulByNonResidue(&t0) - - tmp.Add(&z.B0, &z.B1) - t1.Mul(c1, &tmp) - t1.Sub(&t1, &b) - - z.B0.Set(&t0) - z.B1.Set(&t1) - z.B2.Set(&b) - - return z -} - -// Mul sets z to the E6 product of x,y, returns z -func (z *E6) Mul(x, y *E6) *E6 { - // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf - var t0, t1, t2, c0, c1, c2, tmp E2 - t0.Mul(&x.B0, &y.B0) - t1.Mul(&x.B1, &y.B1) - t2.Mul(&x.B2, &y.B2) - - c0.Add(&x.B1, &x.B2) - tmp.Add(&y.B1, &y.B2) - c0.Mul(&c0, &tmp).Sub(&c0, &t1).Sub(&c0, &t2).MulByNonResidue(&c0).Add(&c0, &t0) - - c1.Add(&x.B0, &x.B1) - tmp.Add(&y.B0, &y.B1) - c1.Mul(&c1, &tmp).Sub(&c1, &t0).Sub(&c1, &t1) - tmp.MulByNonResidue(&t2) - c1.Add(&c1, &tmp) - - tmp.Add(&x.B0, &x.B2) - c2.Add(&y.B0, &y.B2).Mul(&c2, &tmp).Sub(&c2, &t0).Sub(&c2, &t2).Add(&c2, &t1) - - z.B0.Set(&c0) - z.B1.Set(&c1) - z.B2.Set(&c2) - - return z -} - -// Square sets z to the E6 product of x,x, returns z -func (z *E6) Square(x *E6) *E6 { - - // Algorithm 16 from https://eprint.iacr.org/2010/354.pdf - var c4, c5, c1, c2, c3, c0 E2 - c4.Mul(&x.B0, &x.B1).Double(&c4) - c5.Square(&x.B2) - c1.MulByNonResidue(&c5).Add(&c1, &c4) - c2.Sub(&c4, &c5) - c3.Square(&x.B0) - c4.Sub(&x.B0, &x.B1).Add(&c4, &x.B2) - c5.Mul(&x.B1, &x.B2).Double(&c5) - c4.Square(&c4) - c0.MulByNonResidue(&c5).Add(&c0, &c3) - z.B2.Add(&c2, &c4).Add(&z.B2, &c5).Sub(&z.B2, &c3) - z.B0.Set(&c0) - z.B1.Set(&c1) - - return z -} - -// Inverse an element in E6 -// -// if x == 0, sets and returns z = x -func (z *E6) Inverse(x *E6) *E6 { - // Algorithm 17 from https://eprint.iacr.org/2010/354.pdf - // step 9 is wrong in the paper it's t1-t4 - var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 - t0.Square(&x.B0) - t1.Square(&x.B1) - t2.Square(&x.B2) - t3.Mul(&x.B0, &x.B1) - t4.Mul(&x.B0, &x.B2) - t5.Mul(&x.B1, &x.B2) - c0.MulByNonResidue(&t5).Neg(&c0).Add(&c0, &t0) - c1.MulByNonResidue(&t2).Sub(&c1, &t3) - c2.Sub(&t1, &t4) - t6.Mul(&x.B0, &c0) - d1.Mul(&x.B2, &c1) - d2.Mul(&x.B1, &c2) - d1.Add(&d1, &d2).MulByNonResidue(&d1) - t6.Add(&t6, &d1) - t6.Inverse(&t6) - z.B0.Mul(&c0, &t6) - z.B1.Mul(&c1, &t6) - z.B2.Mul(&c2, &t6) - - return z -} - -// BatchInvertE6 returns a new slice with every element in a inverted. -// It uses Montgomery batch inversion trick. -// -// if a[i] == 0, returns result[i] = a[i] -func BatchInvertE6(a []E6) []E6 { - res := make([]E6, len(a)) - if len(a) == 0 { - return res - } - - zeroes := make([]bool, len(a)) - var accumulator E6 - accumulator.SetOne() - - for i := 0; i < len(a); i++ { - if a[i].IsZero() { - zeroes[i] = true - continue - } - res[i].Set(&accumulator) - accumulator.Mul(&accumulator, &a[i]) - } - - accumulator.Inverse(&accumulator) - - for i := len(a) - 1; i >= 0; i-- { - if zeroes[i] { - continue - } - res[i].Mul(&res[i], &accumulator) - accumulator.Mul(&accumulator, &a[i]) - } - - return res -} - -// Select is conditional move. -// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. -func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { - //Might be able to save a nanosecond or two by an aggregate implementation - - z.B0.Select(cond, &caseZ.B0, &caseNz.B0) - z.B1.Select(cond, &caseZ.B1, &caseNz.B1) - z.B2.Select(cond, &caseZ.B2, &caseNz.B2) - - return z -} - -// Div divides an element in E6 by an element in E6 -func (z *E6) Div(x *E6, y *E6) *E6 { - var r E6 - r.Inverse(y).Mul(x, &r) - return z.Set(&r) -} diff --git a/prover/maths/field/fext/e6_test.go b/prover/maths/field/fext/e6_test.go deleted file mode 100644 index afe22556b..000000000 --- a/prover/maths/field/fext/e6_test.go +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright 2020 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fext - -import ( - "testing" - - "github.com/leanovate/gopter" - "github.com/leanovate/gopter/prop" -) - -// ------------------------------------------------------------ -// tests - -func TestE6ReceiverIsOperand(t *testing.T) { - - t.Parallel() - parameters := gopter.DefaultTestParameters() - if testing.Short() { - parameters.MinSuccessfulTests = nbFuzzShort - } else { - parameters.MinSuccessfulTests = nbFuzz - } - - properties := gopter.NewProperties(parameters) - - genA := GenE6() - genB := GenE6() - genE2 := GenE2() - - properties.Property("[BLS12-377] Having the receiver as operand (addition) should output the same result", prop.ForAll( - func(a, b *E6) bool { - var c, d E6 - d.Set(a) - c.Add(a, b) - a.Add(a, b) - b.Add(&d, b) - return a.Equal(b) && a.Equal(&c) && b.Equal(&c) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (sub) should output the same result", prop.ForAll( - func(a, b *E6) bool { - var c, d E6 - d.Set(a) - c.Sub(a, b) - a.Sub(a, b) - b.Sub(&d, b) - return a.Equal(b) && a.Equal(&c) && b.Equal(&c) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (mul) should output the same result", prop.ForAll( - func(a, b *E6) bool { - var c, d E6 - d.Set(a) - c.Mul(a, b) - a.Mul(a, b) - b.Mul(&d, b) - return a.Equal(b) && a.Equal(&c) && b.Equal(&c) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (square) should output the same result", prop.ForAll( - func(a *E6) bool { - var b E6 - b.Square(a) - a.Square(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (neg) should output the same result", prop.ForAll( - func(a *E6) bool { - var b E6 - b.Neg(a) - a.Neg(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (double) should output the same result", prop.ForAll( - func(a *E6) bool { - var b E6 - b.Double(a) - a.Double(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( - func(a *E6) bool { - var b E6 - b.MulByNonResidue(a) - a.MulByNonResidue(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( - func(a *E6) bool { - var b E6 - b.Inverse(a) - a.Inverse(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Having the receiver as operand (mul by E2) should output the same result", prop.ForAll( - func(a *E6, b *E2) bool { - var c E6 - c.MulByE2(a, b) - a.MulByE2(a, b) - return a.Equal(&c) - }, - genA, - genE2, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} - -func TestE6Ops(t *testing.T) { - - t.Parallel() - parameters := gopter.DefaultTestParameters() - if testing.Short() { - parameters.MinSuccessfulTests = nbFuzzShort - } else { - parameters.MinSuccessfulTests = nbFuzz - } - - properties := gopter.NewProperties(parameters) - - genA := GenE6() - genB := GenE6() - genE2 := GenE2() - - properties.Property("[BLS12-377] sub & add should leave an element invariant", prop.ForAll( - func(a, b *E6) bool { - var c E6 - c.Set(a) - c.Add(&c, b).Sub(&c, b) - return c.Equal(a) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] mul & inverse should leave an element invariant", prop.ForAll( - func(a, b *E6) bool { - var c, d E6 - d.Inverse(b) - c.Set(a) - c.Mul(&c, b).Mul(&c, &d) - return c.Equal(a) - }, - genA, - genB, - )) - - properties.Property("[BLS12-377] inverse twice should leave an element invariant", prop.ForAll( - func(a *E6) bool { - var b E6 - b.Inverse(a).Inverse(&b) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] BatchInvertE6 should output the same result as Inverse", prop.ForAll( - func(a, b, c *E6) bool { - - batch := BatchInvertE6([]E6{*a, *b, *c}) - a.Inverse(a) - b.Inverse(b) - c.Inverse(c) - return a.Equal(&batch[0]) && b.Equal(&batch[1]) && c.Equal(&batch[2]) - }, - genA, - genA, - genA, - )) - - properties.Property("[BLS12-377] neg twice should leave an element invariant", prop.ForAll( - func(a *E6) bool { - var b E6 - b.Neg(a).Neg(&b) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] square and mul should output the same result", prop.ForAll( - func(a *E6) bool { - var b, c E6 - b.Mul(a, a) - c.Square(a) - return b.Equal(&c) - }, - genA, - )) - - properties.Property("[BLS12-377] Double and add twice should output the same result", prop.ForAll( - func(a *E6) bool { - var b E6 - b.Add(a, a) - a.Double(a) - return a.Equal(&b) - }, - genA, - )) - - properties.Property("[BLS12-377] Mul by non residue should be the same as multiplying by (0,1,0)", prop.ForAll( - func(a *E6) bool { - var b, c E6 - b.B1.A0.SetOne() - c.Mul(a, &b) - a.MulByNonResidue(a) - return a.Equal(&c) - }, - genA, - )) - - properties.Property("[BLS12-377] MulByE2 MulByE2 inverse should leave an element invariant", prop.ForAll( - func(a *E6, b *E2) bool { - var c E6 - var d E2 - d.Inverse(b) - c.MulByE2(a, b).MulByE2(&c, &d) - return c.Equal(a) - }, - genA, - genE2, - )) - - properties.Property("[BLS12-377] Mul and MulBy01 should output the same result", prop.ForAll( - func(a *E6, c0, c1 *E2) bool { - var b E6 - b.B0.Set(c0) - b.B1.Set(c1) - b.Mul(&b, a) - a.MulBy01(c0, c1) - return b.Equal(a) - }, - genA, - genE2, - genE2, - )) - - properties.Property("[BLS12-377] Mul and MulBy1 should output the same result", prop.ForAll( - func(a *E6, c1 *E2) bool { - var b E6 - b.B1.Set(c1) - b.Mul(&b, a) - a.MulBy1(c1) - return b.Equal(a) - }, - genA, - genE2, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) - -} - -// ------------------------------------------------------------ -// benches - -func BenchmarkE6Add(b *testing.B) { - var a, c E6 - _, _ = a.SetRandom() - _, _ = c.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Add(&a, &c) - } -} - -func BenchmarkE6Sub(b *testing.B) { - var a, c E6 - _, _ = a.SetRandom() - _, _ = c.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Sub(&a, &c) - } -} - -func BenchmarkE6Mul(b *testing.B) { - var a, c E6 - _, _ = a.SetRandom() - _, _ = c.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Mul(&a, &c) - } -} - -func BenchmarkE6Square(b *testing.B) { - var a E6 - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Square(&a) - } -} - -func BenchmarkE6Inverse(b *testing.B) { - var a E6 - _, _ = a.SetRandom() - b.ResetTimer() - for i := 0; i < b.N; i++ { - a.Inverse(&a) - } -} - -func TestE6Div(t *testing.T) { - - parameters := gopter.DefaultTestParameters() - properties := gopter.NewProperties(parameters) - - genA := GenE6() - genB := GenE6() - - properties.Property("[BLS12-377] dividing then multiplying by the same element does nothing", prop.ForAll( - func(a, b *E6) bool { - var c E6 - c.Div(a, b) - c.Mul(&c, b) - return c.Equal(a) - }, - genA, - genB, - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} diff --git a/prover/maths/field/fext/element.go b/prover/maths/field/fext/element.go index 5ff220fee..9e2d98ced 100644 --- a/prover/maths/field/fext/element.go +++ b/prover/maths/field/fext/element.go @@ -23,6 +23,8 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/field" "math/big" "math/bits" + "math/rand/v2" + "strings" "github.com/bits-and-blooms/bitset" @@ -32,6 +34,10 @@ const ( frBytes = 32 // number of bytes needed to represent a Element ) +var RootPowers = []int{1, -11} + +type Element = E2 // type alias + func NewElement(v1 uint64, v2 uint64) Element { z1 := fr.Element{v1} z1.Mul(&z1, &rSquare) @@ -351,3 +357,10 @@ func ExpToInt(z *Element, x Element, k int) *Element { return z } + +func PseudoRand(rng *rand.Rand) Element { + x := field.PseudoRand(rng) + y := field.PseudoRand(rng) + result := new(Element).SetZero() + return *result.Add(result, &Element{x, y}) +} diff --git a/prover/maths/field/fext/frobenius.go b/prover/maths/field/fext/frobenius.go deleted file mode 100644 index 9174b40d3..000000000 --- a/prover/maths/field/fext/frobenius.go +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2020 ConsenSys AG -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package fext - -import "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" - -// Frobenius set z to Frobenius(x), return z -func (z *E12) Frobenius(x *E12) *E12 { - // Algorithm 28 from https://eprint.iacr.org/2010/354.pdf (beware typos!) - var t [6]E2 - - // Frobenius acts on fp2 by conjugation - t[0].Conjugate(&x.C0.B0) - t[1].Conjugate(&x.C0.B1) - t[2].Conjugate(&x.C0.B2) - t[3].Conjugate(&x.C1.B0) - t[4].Conjugate(&x.C1.B1) - t[5].Conjugate(&x.C1.B2) - - t[1].MulByNonResidue1Power2(&t[1]) - t[2].MulByNonResidue1Power4(&t[2]) - t[3].MulByNonResidue1Power1(&t[3]) - t[4].MulByNonResidue1Power3(&t[4]) - t[5].MulByNonResidue1Power5(&t[5]) - - z.C0.B0 = t[0] - z.C0.B1 = t[1] - z.C0.B2 = t[2] - z.C1.B0 = t[3] - z.C1.B1 = t[4] - z.C1.B2 = t[5] - - return z -} - -// FrobeniusSquare set z to Frobenius^2(x), and return z -func (z *E12) FrobeniusSquare(x *E12) *E12 { - // Algorithm 29 from https://eprint.iacr.org/2010/354.pdf (beware typos!) - var t [6]E2 - - t[1].MulByNonResidue2Power2(&x.C0.B1) - t[2].MulByNonResidue2Power4(&x.C0.B2) - t[3].MulByNonResidue2Power1(&x.C1.B0) - t[4].MulByNonResidue2Power3(&x.C1.B1) - t[5].MulByNonResidue2Power5(&x.C1.B2) - - z.C0.B0 = x.C0.B0 - z.C0.B1 = t[1] - z.C0.B2 = t[2] - z.C1.B0 = t[3] - z.C1.B1 = t[4] - z.C1.B2 = t[5] - - return z -} - -// MulByNonResidue1Power1 set z=x*(0,1)^(1*(p^1-1)/6) and return z -func (z *E2) MulByNonResidue1Power1(x *E2) *E2 { - // 92949345220277864758624960506473182677953048909283248980960104381795901929519566951595905490535835115111760994353 - b := fp.Element{ - 7981638599956744862, - 11830407261614897732, - 6308788297503259939, - 10596665404780565693, - 11693741422477421038, - 61545186993886319, - } - z.A0.Mul(&x.A0, &b) - z.A1.Mul(&x.A1, &b) - return z -} - -// MulByNonResidue1Power2 set z=x*(0,1)^(2*(p^1-1)/6) and return z -func (z *E2) MulByNonResidue1Power2(x *E2) *E2 { - // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946 - b := fp.Element{ - 6382252053795993818, - 1383562296554596171, - 11197251941974877903, - 6684509567199238270, - 6699184357838251020, - 19987743694136192, - } - z.A0.Mul(&x.A0, &b) - z.A1.Mul(&x.A1, &b) - return z -} - -// MulByNonResidue1Power3 set z=x*(0,1)^(3*(p^1-1)/6) and return z -func (z *E2) MulByNonResidue1Power3(x *E2) *E2 { - // 216465761340224619389371505802605247630151569547285782856803747159100223055385581585702401816380679166954762214499 - b := fp.Element{ - 10965161018967488287, - 18251363109856037426, - 7036083669251591763, - 16109345360066746489, - 4679973768683352764, - 96952949334633821, - } - z.A0.Mul(&x.A0, &b) - z.A1.Mul(&x.A1, &b) - return z -} - -// MulByNonResidue1Power4 set z=x*(0,1)^(4*(p^1-1)/6) and return z -func (z *E2) MulByNonResidue1Power4(x *E2) *E2 { - // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945 - b := fp.Element{ - 15766275933608376691, - 15635974902606112666, - 1934946774703877852, - 18129354943882397960, - 15437979634065614942, - 101285514078273488, - } - z.A0.Mul(&x.A0, &b) - z.A1.Mul(&x.A1, &b) - return z -} - -// MulByNonResidue1Power5 set z=x*(0,1)^(5*(p^1-1)/6) and return z -func (z *E2) MulByNonResidue1Power5(x *E2) *E2 { - // 123516416119946754630746545296132064952198520638002533875843642777304321125866014634106496325844844051843001220146 - b := fp.Element{ - 2983522419010743425, - 6420955848241139694, - 727295371748331824, - 5512679955286180796, - 11432976419915483342, - 35407762340747501, - } - z.A0.Mul(&x.A0, &b) - z.A1.Mul(&x.A1, &b) - return z -} - -// MulByNonResidue2Power1 set z=x*(0,1)^(1*(p^2-1)/6) and return z -func (z *E2) MulByNonResidue2Power1(x *E2) *E2 { - // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946 - b := fp.Element{ - 6382252053795993818, - 1383562296554596171, - 11197251941974877903, - 6684509567199238270, - 6699184357838251020, - 19987743694136192, - } - z.A0.Mul(&x.A0, &b) - z.A1.Mul(&x.A1, &b) - return z -} - -// MulByNonResidue2Power2 set z=x*(0,1)^(2*(p^2-1)/6) and return z -func (z *E2) MulByNonResidue2Power2(x *E2) *E2 { - // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945 - b := fp.Element{ - 15766275933608376691, - 15635974902606112666, - 1934946774703877852, - 18129354943882397960, - 15437979634065614942, - 101285514078273488, - } - z.A0.Mul(&x.A0, &b) - z.A1.Mul(&x.A1, &b) - return z -} - -// MulByNonResidue2Power3 set z=x*(0,1)^(3*(p^2-1)/6) and return z -func (z *E2) MulByNonResidue2Power3(x *E2) *E2 { - // 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458176 - b := fp.Element{ - 9384023879812382873, - 14252412606051516495, - 9184438906438551565, - 11444845376683159689, - 8738795276227363922, - 81297770384137296, - } - z.A0.Mul(&x.A0, &b) - z.A1.Mul(&x.A1, &b) - return z -} - -// MulByNonResidue2Power4 set z=x*(0,1)^(4*(p^2-1)/6) and return z -func (z *E2) MulByNonResidue2Power4(x *E2) *E2 { - // 258664426012969093929703085429980814127835149614277183275038967946009968870203535512256352201271898244626862047231 - b := fp.Element{ - 3203870859294639911, - 276961138506029237, - 9479726329337356593, - 13645541738420943632, - 7584832609311778094, - 101110569012358506, - } - z.A0.Mul(&x.A0, &b) - z.A1.Mul(&x.A1, &b) - return z -} - -// MulByNonResidue2Power5 set z=x*(0,1)^(5*(p^2-1)/6) and return z -func (z *E2) MulByNonResidue2Power5(x *E2) *E2 { - // 258664426012969093929703085429980814127835149614277183275038967946009968870203535512256352201271898244626862047232 - b := fp.Element{ - 12266591053191808654, - 4471292606164064357, - 295287422898805027, - 2200696361737783943, - 17292781406793965788, - 19812798628221209, - } - z.A0.Mul(&x.A0, &b) - z.A1.Mul(&x.A1, &b) - return z -} diff --git a/prover/maths/field/fext/generators_test.go b/prover/maths/field/fext/generators_test.go deleted file mode 100644 index 547770b34..000000000 --- a/prover/maths/field/fext/generators_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package fext - -import ( - "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" - "github.com/leanovate/gopter" -) - -// Fp generates an Fp element -func GenFp() gopter.Gen { - return func(genParams *gopter.GenParameters) *gopter.GenResult { - var elmt fp.Element - - if _, err := elmt.SetRandom(); err != nil { - panic(err) - } - genResult := gopter.NewGenResult(elmt, gopter.NoShrinker) - return genResult - } -} - -// E2 generates an E2 elmt -func GenE2() gopter.Gen { - return gopter.CombineGens( - GenFp(), - GenFp(), - ).Map(func(values []interface{}) *E2 { - return &E2{A0: values[0].(fp.Element), A1: values[1].(fp.Element)} - }) -} - -// E6 generates an E6 elmt -func GenE6() gopter.Gen { - return gopter.CombineGens( - GenE2(), - GenE2(), - GenE2(), - ).Map(func(values []interface{}) *E6 { - return &E6{B0: *values[0].(*E2), B1: *values[1].(*E2), B2: *values[2].(*E2)} - }) -} - -// E12 generates an E6 elmt -func GenE12() gopter.Gen { - return gopter.CombineGens( - GenE6(), - GenE6(), - ).Map(func(values []interface{}) *E12 { - return &E12{C0: *values[0].(*E6), C1: *values[1].(*E6)} - }) -} diff --git a/prover/maths/field/fext/gnarkfext/api.go b/prover/maths/field/fext/gnarkfext/api.go new file mode 100644 index 000000000..d5b8db93f --- /dev/null +++ b/prover/maths/field/fext/gnarkfext/api.go @@ -0,0 +1,213 @@ +package gnarkfext + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark/frontend" + "github.com/consensys/linea-monorepo/prover/maths/field/fext" +) + +// API is a wrapper of [frontend.API] with methods specialized for field +// extension operations. +type API struct { + Inner frontend.API +} + +// Variable element in a quadratic extension +type Variable struct { + A0, A1 frontend.Variable +} + +func NewZero() Variable { + return Variable{ + A0: 0, + A1: 0, + } +} + +// SetOne returns a newly allocated element equal to 1 +func One() Variable { + return Variable{ + A0: 1, + A1: 0, + } +} + +// IsZero returns 1 if the element is equal to 0 and 0 otherwise +func (api *API) IsZero(e Variable) frontend.Variable { + return api.Inner.And(api.Inner.IsZero(e.A0), api.Inner.IsZero(e.A1)) +} + +func (api *API) IsEqual(a, b Variable) frontend.Variable { + return api.Inner.Sub(1, api.IsZero(api.Sub(a, b))) +} + +// Neg negates a e2 elmt +func (api *API) Neg(e1 Variable) Variable { + return Variable{ + A0: api.Inner.Sub(0, e1.A0), + A1: api.Inner.Sub(0, e1.A1), + } +} + +// Add e2 elmts +func (api *API) Add(e1, e2 Variable, in ...Variable) Variable { + A0 := api.Inner.Add(e1.A0, e2.A0) + A1 := api.Inner.Add(e1.A1, e2.A1) + + for i := 0; i < len(in); i++ { + A0 = api.Inner.Add(A0, in[i].A0) + A1 = api.Inner.Add(A1, in[i].A1) + } + return Variable{ + A0: A0, + A1: A1, + } +} + +// Double e2 elmt +func (api *API) Double(e1 Variable) Variable { + return Variable{ + A0: api.Inner.Mul(e1.A0, 2), + A1: api.Inner.Mul(e1.A1, 2), + } +} + +// Sub e2 elmts +func (api *API) Sub(e1, e2 Variable) Variable { + return Variable{ + A0: api.Inner.Sub(e1.A0, e2.A0), + A1: api.Inner.Sub(e1.A1, e2.A1), + } +} + +// Mul e2 elmts +func (api *API) Mul(x, y Variable, in ...Variable) Variable { + + a := api.Inner.Add(x.A0, x.A1) + b := api.Inner.Add(y.A0, y.A1) + a = api.Inner.Mul(a, b) + + b = api.Inner.Mul(x.A0, y.A0) + c := api.Inner.Mul(x.A1, y.A1) + + res := Variable{ + A0: api.Inner.Sub(b, api.Inner.Mul(11, c)), + A1: api.Inner.Sub(a, b, c), + } + if len(in) > 0 { + return api.Mul(res, in[0], in[1:]...) + } else { + return res + } +} + +// Square e2 elt +func (api_ *API) Square(x Variable) Variable { + + var a, b, c frontend.Variable + api := api_.Inner + + a = api.Mul(2, x.A0, x.A1) + + c = api.Mul(x.A0, x.A0) + b = api.Mul(x.A1, x.A1, 11) + + return Variable{ + A0: api.Sub(c, b), + A1: a, + } +} + +// MulByFp multiplies an fp2 elmt by an fp elmt +func (api *API) MulByBase(e1 Variable, c frontend.Variable) Variable { + return Variable{ + A0: api.Inner.Mul(e1.A0, c), + A1: api.Inner.Mul(e1.A1, c), + } +} + +// MulByNonResidue multiplies an fp2 elmt by the imaginary elmt +// ext.uSquare is the square of the imaginary root +func (api *API) MulByNonResidue(e1 Variable) Variable { + return Variable{ + A0: api.Inner.Mul(e1.A1, -11), + A1: e1.A0, + } +} + +// Conjugate conjugation of an e2 elmt +func (api *API) Conjugate(e1 Variable) Variable { + return Variable{ + A0: e1.A0, + A1: api.Inner.Sub(0, e1.A1), + } +} + +// Inverse e2 elmts +func (api_ *API) Inverse(x Variable) Variable { + + api := api_.Inner + + a := x.A0 // creating the buffers a, b is faster than querying &x.A0, &x.A1 in the functions call below + b := x.A1 + t0 := api.Mul(a, a) + t1 := api.Mul(b, b) + tmp := t1 + tmp = api.Mul(tmp, 11) + t0 = api.Add(t0, tmp) + t1 = api.Inverse(t0) + + return Variable{ + A0: api.Mul(a, t1), + A1: api.Mul(b, t1, -1), + } +} + +// Assign a value to self (witness assignment) +func Assign(a *fext.Element) Variable { + return Variable{ + A0: (fr.Element)(a.A0), + A1: (fr.Element)(a.A1), + } +} + +// AssertIsEqual constraint self to be equal to other into the given constraint system +func (api *API) AssertIsEqual(e, other Variable) { + api.Inner.AssertIsEqual(e.A0, other.A0) + api.Inner.AssertIsEqual(e.A1, other.A1) +} + +// AssertIsEqual constraint self to be equal to other into the given constraint system +func (api *API) AssertIsEqualToField(other fext.E2, e Variable) { + api.Inner.AssertIsEqual(e.A0, other.A0) + api.Inner.AssertIsEqual(e.A1, other.A1) +} + +// Select sets e to r1 if b=1, r2 otherwise +func (api *API) Select(b frontend.Variable, r1, r2 Variable) Variable { + return Variable{ + A0: api.Inner.Select(b, r1.A0, r2.A0), + A1: api.Inner.Select(b, r1.A1, r2.A1), + } +} + +// Lookup2 implements two-bit lookup. It returns: +// - r1 if b1=0 and b2=0, +// - r2 if b1=0 and b2=1, +// - r3 if b1=1 and b2=0, +// - r3 if b1=1 and b2=1. +func (api *API) Lookup2(b1, b2 frontend.Variable, r1, r2, r3, r4 Variable) Variable { + return Variable{ + A0: api.Inner.Lookup2(b1, b2, r1.A0, r2.A0, r3.A0, r4.A0), + A1: api.Inner.Lookup2(b1, b2, r1.A1, r2.A1, r3.A1, r4.A1), + } +} + +func (api *API) AssertIsDifferent(i1, i2 Variable) { + mustBeOne := api.IsEqual(i1, i2) + api.Inner.AssertIsEqual(mustBeOne, 1) +} + +func ExtToVariable(origin fext.Element) Variable { + return Variable{origin.A0, origin.A1} +} diff --git a/prover/maths/field/fext/gnarkutilext/arith.go b/prover/maths/field/fext/gnarkutilext/arith.go new file mode 100644 index 000000000..0dc350288 --- /dev/null +++ b/prover/maths/field/fext/gnarkutilext/arith.go @@ -0,0 +1,37 @@ +package gnarkutilext + +import ( + "github.com/consensys/linea-monorepo/prover/maths/field/fext/gnarkfext" +) + +/* +exponentiation in gnark circuit, using the fast exponentiation +*/ +func Exp(api gnarkfext.API, x gnarkfext.Variable, n int) gnarkfext.Variable { + + if n < 0 { + x = api.Inverse(x) + return Exp(api, x, -n) + } + + if n == 0 { + return gnarkfext.One() + } + + if n == 1 { + return x + } + + if n%2 == 0 { + x2 := api.Mul(x, x) + return Exp(api, x2, n/2) + } + + if n%2 == 1 { + x2 := api.Mul(x, x) + res := Exp(api, x2, (n-1)/2) + return api.Mul(res, x) + } + + panic("unreachable") +} diff --git a/prover/maths/field/fext/parameters.go b/prover/maths/field/fext/parameters.go deleted file mode 100644 index 67406061d..000000000 --- a/prover/maths/field/fext/parameters.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2020 ConsenSys AG -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package fext - -import ( - "math/big" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" -) - -// generator of the curve -var xGen big.Int - -var glvBasis ecc.Lattice - -func init() { - xGen.SetString("9586122913090633729", 10) - _r := fr.Modulus() - ecc.PrecomputeLattice(_r, &xGen, &glvBasis) -} diff --git a/prover/maths/field/fext/utils.go b/prover/maths/field/fext/utils.go new file mode 100644 index 000000000..30f5a934e --- /dev/null +++ b/prover/maths/field/fext/utils.go @@ -0,0 +1,38 @@ +package fext + +import ( + "math/big" + "sync" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/leanovate/gopter" +) + +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + +// Fr generates an Fr element +func GenFr() gopter.Gen { + return func(genParams *gopter.GenParameters) *gopter.GenResult { + var elmt fr.Element + + if _, err := elmt.SetRandom(); err != nil { + panic(err) + } + genResult := gopter.NewGenResult(elmt, gopter.NoShrinker) + return genResult + } +} + +// E2 generates an E2 elmt +func GenE2() gopter.Gen { + return gopter.CombineGens( + GenFr(), + GenFr(), + ).Map(func(values []interface{}) *E2 { + return &E2{A0: values[0].(fr.Element), A1: values[1].(fr.Element)} + }) +} diff --git a/prover/protocol/compiler/lookup/lookup_test.go b/prover/protocol/compiler/lookup/lookup_test.go index 26f2d3932..8e07f9a55 100644 --- a/prover/protocol/compiler/lookup/lookup_test.go +++ b/prover/protocol/compiler/lookup/lookup_test.go @@ -2,7 +2,7 @@ package lookup import ( "fmt" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" @@ -58,7 +58,7 @@ func TestExhaustive(t *testing.T) { var ( // #nosec G404 -- we don't need a cryptographic PRNG for testing purposes - rng = rand.New(rand.NewSource(43)) + rng = rand.New(rand.NewChaCha8([32]byte{})) smallNumbers = smartvectors.ForTest(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) xorTable = [3]smartvectors.SmartVector{ smartvectors.ForTest(0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3), @@ -114,7 +114,7 @@ func TestExhaustive(t *testing.T) { for i := range cols { vec := make([]int, size) for j := range vec { - vec[j] = rng.Intn(2) + vec[j] = rng.IntN(2) } run.AssignColumn(cols[i].GetColID(), smartvectors.ForTest(vec...)) } @@ -126,7 +126,7 @@ func TestExhaustive(t *testing.T) { for i := range cols { vec := make([]int, size) for j := range vec { - vec[j] = rng.Intn(4) + vec[j] = rng.IntN(4) } run.AssignColumn(cols[i].GetColID(), smartvectors.ForTest(vec...)) } @@ -140,7 +140,7 @@ func TestExhaustive(t *testing.T) { size := cols[0].Size() vecs := [3][]int{} for j := 0; j < size; j++ { - x, y := rng.Intn(4), rng.Intn(4) + x, y := rng.IntN(4), rng.IntN(4) z := x ^ y vecs[0] = append(vecs[0], x) vecs[1] = append(vecs[1], y) diff --git a/prover/utils/csvtraces/csvtraces.go b/prover/utils/csvtraces/csvtraces.go index a5d2f1ca4..033e739c7 100644 --- a/prover/utils/csvtraces/csvtraces.go +++ b/prover/utils/csvtraces/csvtraces.go @@ -20,6 +20,7 @@ type cfg struct { nbRows int skipPrePaddingZero bool filterOn ifaces.Column + inHex bool } type Option func(*cfg) error @@ -47,6 +48,12 @@ func FilterOn(col ifaces.Column) Option { } } +// InHex sets the CSV printer to print the values in hexadecimal +func InHex(c *cfg) error { + c.inHex = true + return nil +} + type CsvTrace struct { mapped map[string][]field.Element @@ -109,12 +116,7 @@ func FmtCsv(w io.Writer, run *wizard.ProverRuntime, cols []ifaces.Column, option allZeroes = false } - if assignment[c][r].IsUint64() { - fmtVals = append(fmtVals, assignment[c][r].String()) - continue - } - - fmtVals = append(fmtVals, "0x"+assignment[c][r].Text(16)) + fmtVals = append(fmtVals, fmtFieldElement(cfg.inHex, assignment[c][r])) } if !allZeroes { @@ -250,3 +252,31 @@ func (c *CsvTrace) Len() int { func (c *CsvTrace) LenPadded() int { return utils.NextPowerOfTwo(c.nbRows) } + +// WritesExplicit format value-provided columns into a csv file. Unlike [FmtCsv] +// it does not need the columns to be registered as the assignmet of a wizard. +// It is suitable for test-case generation. +func WriteExplicit(w io.Writer, names []string, cols [][]field.Element, inHex bool) { + + fmt.Fprintf(w, "%v\n", strings.Join(names, ",")) + + for i := range cols[0] { + + row := []string{} + for j := range cols { + row = append(row, fmtFieldElement(inHex, cols[j][i])) + } + + fmt.Fprintf(w, "%v\n", strings.Join(row, ",")) + } + +} + +func fmtFieldElement(inHex bool, x field.Element) string { + + if inHex || (x.IsUint64() && x.Uint64() < 1<<10) { + return x.String() + } + + return "0x" + x.Text(16) +} diff --git a/prover/utils/rand.go b/prover/utils/rand.go new file mode 100644 index 000000000..519b45d01 --- /dev/null +++ b/prover/utils/rand.go @@ -0,0 +1,35 @@ +package utils + +import ( + "math/rand/v2" + "unsafe" +) + +// NewRandSource returns a [rand.ChaCha8] initialized with an integer seed. The +// function is meant to sugar-coat the numerous testcases of the repo. +func NewRandSource(seed int64) *rand.ChaCha8 { + + if seed < 0 { + seed = -seed + } + + var ( + seedU64 = uint64(seed) + seed8Bytes = *(*[8]byte)(unsafe.Pointer(&seedU64)) + seed32Bytes = [32]byte{} + ) + + copy(seed32Bytes[:], seed8Bytes[:]) + return rand.NewChaCha8(seed32Bytes) +} + +// ReadPseudoRand populate slices with bytes generated from rand. It returns the +// number of bytes read and an error to match with [io.Read]. This function is +// intended as a drop-in replacement for [math/rand.Read]. `n` is always the +// len(slice) and err is always `nil`. +func ReadPseudoRand(rng *rand.Rand, slice []byte) (n int, err error) { + for i := range slice { + slice[i] = byte(rng.Uint32() & 0xff) + } + return len(slice), nil +} diff --git a/prover/utils/types/common_test.go b/prover/utils/types/common_test.go index 538122305..dc43f5655 100644 --- a/prover/utils/types/common_test.go +++ b/prover/utils/types/common_test.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/hex" "math/big" - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/utils/types" @@ -64,10 +64,10 @@ func TestReadWriteInt64(t *testing.T) { const nIterations = 100 // #nosec G404 -- no need for a cryptographically strong PRNG for testing purposes - rng := rand.New(rand.NewSource(0)) + rng := rand.New(rand.NewChaCha8([32]byte{})) for _i := 0; _i < nIterations; _i++ { - n := rng.Int63() + n := rng.Int64() buffer := &bytes.Buffer{} types.WriteInt64On32Bytes(buffer, n) n2, _, err := types.ReadInt64On32Bytes(buffer) @@ -81,10 +81,10 @@ func TestReadWriteBigInt(t *testing.T) { const nIterations = 100 // #nosec G404 -- no need for a cryptographically strong PRNG for testing purposes - rng := rand.New(rand.NewSource(0)) + rng := rand.New(rand.NewChaCha8([32]byte{})) for _i := 0; _i < nIterations; _i++ { - n := big.NewInt(rng.Int63()) + n := big.NewInt(rng.Int64()) buffer := &bytes.Buffer{} types.WriteBigIntOn32Bytes(buffer, n) n2, err := types.ReadBigIntOn32Bytes(buffer) diff --git a/prover/zkevm/prover/common/hilo.go b/prover/zkevm/prover/common/hilo.go new file mode 100644 index 000000000..3b7eecd5a --- /dev/null +++ b/prover/zkevm/prover/common/hilo.go @@ -0,0 +1,67 @@ +package common + +import ( + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" + "github.com/consensys/linea-monorepo/prover/utils/types" +) + +// HiLoColumns represents a pair of column representing a sequence of bytes32 +// element that do not fit in a single field element. The Hi columns stores the +// first 16 bytes of the column. And the Lo columns stores the last 16 bytes. +type HiLoColumns struct { + Hi, Lo ifaces.Column +} + +// NewHiLoColumns returns a new HiLoColumns with initialized and unconstrained +// columns. +func NewHiLoColumns(comp *wizard.CompiledIOP, size int, name string) HiLoColumns { + return HiLoColumns{ + Hi: comp.InsertCommit( + 0, + ifaces.ColIDf("STATE_SUMMARY_%v_HI", name), + size, + ), + Lo: comp.InsertCommit( + 0, + ifaces.ColIDf("STATE_SUMMARY_%v_LO", name), + size, + ), + } +} + +// HiLoAssignmentBuilder is a convenience structure storing the column builders +// relating to an HiLoColumns. +type HiLoAssignmentBuilder struct { + Hi, Lo *VectorBuilder +} + +// NewHiLoAssignmentBuilder returns a fresh [hiLoAssignmentBuilder] +func NewHiLoAssignmentBuilder(hiLo HiLoColumns) HiLoAssignmentBuilder { + return HiLoAssignmentBuilder{ + Hi: NewVectorBuilder(hiLo.Hi), + Lo: NewVectorBuilder(hiLo.Lo), + } +} + +// Push pushes a row representing `fb` onto `hl` +func (hl *HiLoAssignmentBuilder) Push(fb types.FullBytes32) { + hl.Hi.PushHi(fb) + hl.Lo.PushLo(fb) +} + +// PushZeroes pushes a row representing 0 onto `hl` +func (hl *HiLoAssignmentBuilder) PushZeroes() { + hl.Hi.PushZero() + hl.Lo.PushZero() +} + +// PadAssign pads `hl` with `fb` and assigns the resulting columns into `run`. +func (hl *HiLoAssignmentBuilder) PadAssign(run *wizard.ProverRuntime, fb types.FullBytes32) { + var f field.Element + f.SetBytes(fb[:16]) + hl.Hi.PadAndAssign(run, f) + f.SetBytes(fb[16:]) + hl.Lo.PadAndAssign(run, f) +} diff --git a/prover/zkevm/prover/ecpair/ecpair.go b/prover/zkevm/prover/ecpair/ecpair.go index ab2fdcb20..52f882d0a 100644 --- a/prover/zkevm/prover/ecpair/ecpair.go +++ b/prover/zkevm/prover/ecpair/ecpair.go @@ -108,11 +108,12 @@ func newECPair(comp *wizard.CompiledIOP, limits *Limits, ecSource *ECPairSource) res.csInstanceIDChangeWhenNewInstance(comp) res.csAccumulatorInit(comp) res.csAccumulatorConsistency(comp) + res.csTotalPairs(comp) res.csLastPairToFinalExp(comp) res.csIndexConsistency(comp) res.csAccumulatorMask(comp) // only Unaligned Pairing data or G2 membership data is active at a time - res.csExclusiveUnalignedDatas(comp) + res.csPairingDataOrMembershipActive(comp) // only to Miller loop or to FinalExp res.csExclusivePairingCircuitMasks(comp) @@ -241,6 +242,7 @@ type UnalignedPairingData struct { ToMillerLoopCircuitMask ifaces.Column ToFinalExpCircuitMask ifaces.Column + IsResultOfInstance ifaces.Column IsFirstLineOfInstance ifaces.Column IsFirstLineOfPrevAccumulator ifaces.Column IsFirstLineOfCurrAccumulator ifaces.Column @@ -263,6 +265,7 @@ func newUnalignedPairingData(comp *wizard.CompiledIOP, limits *Limits) *Unaligne IsFirstLineOfInstance: createCol("IS_FIRST_LINE_OF_INSTANCE"), IsFirstLineOfPrevAccumulator: createCol("IS_FIRST_LINE_OF_PREV_ACC"), IsFirstLineOfCurrAccumulator: createCol("IS_FIRST_LINE_OF_CURR_ACC"), + IsResultOfInstance: createCol("IS_RESULT"), IsAccumulatorPrev: createCol("IS_ACCUMULATOR_PREV"), IsAccumulatorCurr: createCol("IS_ACCUMULATOR_CURR"), IsAccumulatorInit: createCol("IS_ACCUMULATOR_INIT"), diff --git a/prover/zkevm/prover/ecpair/ecpair_assignment.go b/prover/zkevm/prover/ecpair/ecpair_assignment.go index ba1e28b6a..2cc78dcfa 100644 --- a/prover/zkevm/prover/ecpair/ecpair_assignment.go +++ b/prover/zkevm/prover/ecpair/ecpair_assignment.go @@ -88,10 +88,18 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { dstIndex = common.NewVectorBuilder(ec.UnalignedPairingData.Index) dstIsFirstPrev = common.NewVectorBuilder(ec.UnalignedPairingData.IsFirstLineOfPrevAccumulator) dstIsFirstCurr = common.NewVectorBuilder(ec.UnalignedPairingData.IsFirstLineOfCurrAccumulator) + dstIsResult = common.NewVectorBuilder(ec.UnalignedPairingData.IsResultOfInstance) ) for currPos := 0; currPos < len(srcLimbs); { - // we need to check if the current position is a pairing or not. If not, then skip it. + // we need to check if the current position is a pairing or not. If not, + // then skip it. + // + // this also skips inputs to the current pairing instance which do not + // require passing to the pairing circuit (full-trivial or half-trivial + // inputs). But this is fine as it doesn't change the result as trivial + // result ML is 1. Only non-trivial input pairs affect the pairing check + // result. if srcIsPairing[currPos].IsZero() { currPos++ continue @@ -100,28 +108,42 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { // input data. We iterate over the data to get the number of pairing // inputs. nbInputs := 1 // we start with 1 because we always have at least one pairing input + // we may have trivial input pairs in-between the non-trivial ones. We + // mark which inputs we are interested in. + actualInputs := []int{0} // we started when isPairing is 1, this means that we have non-trivial input. for { if srcIsRes[currPos+nbInputs*(nbG1Limbs+nbG2Limbs)].IsOne() { break } + if srcIsPairing[currPos+nbInputs*(nbG1Limbs+nbG2Limbs)].IsOne() { + actualInputs = append(actualInputs, nbInputs) + } nbInputs++ } + nbActualTotalPairs := len(actualInputs) // now, we have continous chunk of data that is for the pairing. Prepare it for processing. - pairingInG1 = make([][nbG1Limbs]field.Element, nbInputs) - pairingInG2 = make([][nbG2Limbs]field.Element, nbInputs) - for i := 0; i < nbInputs; i++ { + pairingInG1 = make([][nbG1Limbs]field.Element, nbActualTotalPairs) + pairingInG2 = make([][nbG2Limbs]field.Element, nbActualTotalPairs) + for ii, i := range actualInputs { for j := 0; j < nbG1Limbs; j++ { - pairingInG1[i][j] = srcLimbs[currPos+i*(nbG1Limbs+nbG2Limbs)+j] + pairingInG1[ii][j] = srcLimbs[currPos+i*(nbG1Limbs+nbG2Limbs)+j] } for j := 0; j < nbG2Limbs; j++ { - pairingInG2[i][j] = srcLimbs[currPos+i*(nbG1Limbs+nbG2Limbs)+nbG1Limbs+j] + pairingInG2[ii][j] = srcLimbs[currPos+i*(nbG1Limbs+nbG2Limbs)+nbG1Limbs+j] } - inputResult[0] = srcLimbs[currPos+(i+1)*(nbG1Limbs+nbG2Limbs)] - inputResult[1] = srcLimbs[currPos+(i+1)*(nbG1Limbs+nbG2Limbs)+1] } + inputResult[0] = srcLimbs[currPos+nbInputs*(nbG1Limbs+nbG2Limbs)] + inputResult[1] = srcLimbs[currPos+nbInputs*(nbG1Limbs+nbG2Limbs)+1] limbs := processPairingData(pairingInG1, pairingInG2, inputResult) instanceId := srcID[currPos] // processed data has the input limbs, but we have entered the intermediate Gt accumulator values + + // generic assignment. We push the static values for the current instance: + // - the limbs (interleaved with accumulator values) + // - indicator for the first row of the whole pairingcheck instance + // - the instance id + // - the index of the current limb + // - activeness of the submodule for i := 0; i < len(limbs); i++ { dstLimb.PushField(limbs[i]) if i == 0 { @@ -133,15 +155,24 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { dstIndex.PushInt(i) dstIsActive.PushOne() } - for i := 0; i < nbInputs-1; i++ { + // now we push the dynamic values per Miller loop. We send all valid + // pairs except the last to Miller loop (not Miller loop + finalexp!) + // circuit. Keep in mind if there is only a single valid pair then this + // loop is skipped. + for ii := range actualInputs[:len(actualInputs)-1] { + // first we indicate for the accumulator if it is the first one, previous or current for j := 0; j < nbGtLimbs; j++ { dstIsComputed.PushOne() dstIsPulling.PushZero() - if i == 0 { + if ii == 0 { + // we handle first accumulator separately to be able to + // constrain that the initial accumulator value is correct. dstIsAccInit.PushOne() dstIsAccPrev.PushZero() dstIsFirstPrev.PushZero() } else { + // we're not in the first pair of points, so we indicate + // that the accumulator consistency needs to be checked. dstIsAccInit.PushZero() if j == 0 { dstIsFirstPrev.PushOne() @@ -153,6 +184,8 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { dstIsAccCurr.PushZero() dstIsFirstCurr.PushZero() } + // now we push the dynamic values for the actual inputs to the pairing check circuit (coming from the arithmetization). + // essentially we only mark that this limb came directly from arithmetization. for j := nbGtLimbs; j < nbGtLimbs+nbG1Limbs+nbG2Limbs; j++ { dstIsPulling.PushOne() dstIsComputed.PushZero() @@ -162,6 +195,7 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { dstIsFirstPrev.PushZero() dstIsFirstCurr.PushZero() } + // finally, we need to indicate that the next limbs are for the current accumulator for j := nbGtLimbs + nbG1Limbs + nbG2Limbs; j < 2*nbGtLimbs+nbG1Limbs+nbG2Limbs; j++ { dstIsComputed.PushOne() dstIsPulling.PushZero() @@ -175,54 +209,92 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { } dstIsAccCurr.PushOne() } + // we also set the static values for all limbs in this pairs of points. These are: + // - true mark for miller loop circuit + // - false mark for the ML+finalexp circuit + // - the pair ID + // - the total number of pairs + // - false mark that current limb is for the result for j := 0; j < nbG1Limbs+nbG2Limbs+2*nbGtLimbs; j++ { dstToMillerLoop.PushOne() dstToFinalExp.PushZero() - dstPairId.PushInt(i + 1) - dstTotalPairs.PushInt(nbInputs) + dstPairId.PushInt(ii + 1) + dstTotalPairs.PushInt(nbActualTotalPairs) + dstIsResult.PushZero() } } + // we need to handle the final pair of points separately. The + // ML+finalexp circuit does not take the current accumulator as an + // input, but rather the expected pairing check result. + // + // first we set the masks for the accumulator limbs. for j := 0; j < nbGtLimbs; j++ { dstIsComputed.PushOne() dstIsPulling.PushZero() - dstPairId.PushInt(nbInputs) - dstIsAccInit.PushZero() - dstIsAccPrev.PushOne() + dstPairId.PushInt(nbActualTotalPairs) + // handle separately the case when there is only one valid input + // pair. In this case, the first valid pair also includes the + // accumulator initialization. + if nbActualTotalPairs == 1 { + dstIsAccInit.PushOne() + dstIsAccPrev.PushZero() + } else { + dstIsAccInit.PushZero() + dstIsAccPrev.PushOne() + } dstIsAccCurr.PushZero() if j == 0 { - dstIsFirstPrev.PushOne() + // handle separately the case when there is only one valid + // input. In this case we don't have the previous accumulator. + if nbActualTotalPairs == 1 { + dstIsFirstPrev.PushZero() + } else { + dstIsFirstPrev.PushOne() + } } else { dstIsFirstPrev.PushZero() } dstIsFirstCurr.PushZero() + dstIsResult.PushZero() } + // similarly for the final pair of points, we need to indicate that the + // G1/G2 points come directly from the arithmetization. for j := nbGtLimbs; j < nbGtLimbs+nbG1Limbs+nbG2Limbs; j++ { dstIsPulling.PushOne() dstIsComputed.PushZero() - dstPairId.PushInt(nbInputs) + dstPairId.PushInt(nbActualTotalPairs) dstIsAccInit.PushZero() dstIsAccPrev.PushZero() dstIsAccCurr.PushZero() dstIsFirstPrev.PushZero() dstIsFirstCurr.PushZero() + dstIsResult.PushZero() } + // finally, we need to indicate that the result of the pairing check + // comes directly from the arithmetization. this is a bit explicit loop, + // but it's easier to understand. for j := nbGtLimbs + nbG1Limbs + nbG2Limbs; j < nbGtLimbs+nbG1Limbs+nbG2Limbs+2; j++ { dstIsPulling.PushOne() dstIsComputed.PushZero() + // NB! for the result the Pair ID is 0. This is important to keep in + // mind as we set some constraints based on this. dstPairId.PushZero() dstIsAccInit.PushZero() dstIsAccPrev.PushZero() dstIsAccCurr.PushZero() dstIsFirstPrev.PushZero() dstIsFirstCurr.PushZero() + dstIsResult.PushOne() } + // finally we set the static masks for the final pair of points. for j := 0; j < nbG1Limbs+nbG2Limbs+nbGtLimbs+2; j++ { dstToFinalExp.PushOne() dstToMillerLoop.PushZero() - dstTotalPairs.PushInt(nbInputs) + dstTotalPairs.PushInt(nbActualTotalPairs) } currPos += nbInputs*(nbG1Limbs+nbG2Limbs) + 2 } + // Finally, we pad and assign the assigned data. dstIsActive.PadAndAssign(run, field.Zero()) dstLimb.PadAndAssign(run, field.Zero()) dstPairId.PadAndAssign(run, field.Zero()) @@ -239,6 +311,7 @@ func (ec *ECPair) assignPairingData(run *wizard.ProverRuntime) { dstIndex.PadAndAssign(run, field.Zero()) dstIsFirstPrev.PadAndAssign(run, field.Zero()) dstIsFirstCurr.PadAndAssign(run, field.Zero()) + dstIsResult.PadAndAssign(run, field.Zero()) } func processPairingData(pairingInG1 [][nbG1Limbs]field.Element, pairingInG2 [][nbG2Limbs]field.Element, inputResult [2]field.Element) []field.Element { diff --git a/prover/zkevm/prover/ecpair/ecpair_constraints.go b/prover/zkevm/prover/ecpair/ecpair_constraints.go index 932cca482..cae32bf68 100644 --- a/prover/zkevm/prover/ecpair/ecpair_constraints.go +++ b/prover/zkevm/prover/ecpair/ecpair_constraints.go @@ -55,8 +55,8 @@ func (ec *ECPair) csProjections(comp *wizard.CompiledIOP) { // we project data from the arithmetization correctly to the unaligned part of the circuit projection.InsertProjection( comp, ifaces.QueryIDf("%v_PROJECTION_PAIRING", nameECPair), - []ifaces.Column{ec.ECPairSource.Limb, ec.ECPairSource.AccPairings, ec.ECPairSource.TotalPairings, ec.ECPairSource.ID}, - []ifaces.Column{ec.UnalignedPairingData.Limb, ec.UnalignedPairingData.PairID, ec.UnalignedPairingData.TotalPairs, ec.UnalignedPairingData.InstanceID}, + []ifaces.Column{ec.ECPairSource.Limb, ec.ECPairSource.ID, ec.ECPairSource.IsEcPairingResult}, + []ifaces.Column{ec.UnalignedPairingData.Limb, ec.UnalignedPairingData.InstanceID, ec.UnalignedPairingData.IsResultOfInstance}, ec.ECPairSource.CsEcpairing, ec.UnalignedPairingData.IsPulling, ) @@ -159,6 +159,23 @@ func (ec *ECPair) csAccumulatorConsistency(comp *wizard.CompiledIOP) { ) } +func (ec *ECPair) csTotalPairs(comp *wizard.CompiledIOP) { + // total pairs corresponds to the number of pairs in the instance. for this + // we check that when the limb corresponds to the result, then the PairID of + // the shifted by two corresponds to the total pairs. the limb corresponds + // to the result when its PairID is 0 (for input pairs the indexing starts + // from 1). + comp.InsertGlobal( + roundNr, + ifaces.QueryIDf("%v_TOTAL_PAIRS", nameECPair), + sym.Mul( + ec.UnalignedPairingData.IsActive, + ec.UnalignedPairingData.IsResultOfInstance, + sym.Sub(ec.UnalignedPairingData.TotalPairs, column.Shift(ec.UnalignedPairingData.PairID, -2)), // we have two limbs for the result, shift by two gets to the input + ), + ) +} + func (ec *ECPair) csLastPairToFinalExp(comp *wizard.CompiledIOP) { // if the last pair then the final exp circuit should be active @@ -191,7 +208,6 @@ func (ec *ECPair) csIndexConsistency(comp *wizard.CompiledIOP) { ifaces.QueryIDf("%v_INDEX_INCREMENT", nameECPair), sym.Mul( ec.UnalignedPairingData.IsActive, - sym.Sub(1, ec.UnalignedG2MembershipData.IsPulling, ec.UnalignedG2MembershipData.IsComputed), // we dont use index in the G2 membership check sym.Sub(1, ec.UnalignedPairingData.IsFirstLineOfInstance), sym.Sub(ec.UnalignedPairingData.Index, column.Shift(ec.UnalignedPairingData.Index, -1), 1), ), @@ -276,11 +292,19 @@ func (ec *ECPair) csAccumulatorMask(comp *wizard.CompiledIOP) { ) } -func (ec *ECPair) csExclusiveUnalignedDatas(comp *wizard.CompiledIOP) { - common.MustBeMutuallyExclusiveBinaryFlags(comp, ec.IsActive, []ifaces.Column{ - ec.UnalignedG2MembershipData.ToG2MembershipCircuitMask, - ec.UnalignedPairingData.IsActive, - }) +func (ec *ECPair) csPairingDataOrMembershipActive(comp *wizard.CompiledIOP) { + // when module is active, then either pairing data or membership data is + // active. Can also be both. + comp.InsertGlobal( + roundNr, + ifaces.QueryIDf("%v_PAIRING_OR_MEMBERSHIP_ACTIVE", nameECPair), + sym.Add( + ec.IsActive, + sym.Neg(ec.UnalignedPairingData.IsActive), + sym.Neg(ec.UnalignedG2MembershipData.ToG2MembershipCircuitMask), + sym.Mul(ec.UnalignedPairingData.IsActive, ec.UnalignedG2MembershipData.ToG2MembershipCircuitMask), + ), + ) } func (ec *ECPair) csExclusivePairingCircuitMasks(comp *wizard.CompiledIOP) { diff --git a/prover/zkevm/prover/ecpair/ecpair_test.go b/prover/zkevm/prover/ecpair/ecpair_test.go index 50fa06f29..21e1f4822 100644 --- a/prover/zkevm/prover/ecpair/ecpair_test.go +++ b/prover/zkevm/prover/ecpair/ecpair_test.go @@ -1,10 +1,12 @@ package ecpair import ( + "os" "testing" "github.com/consensys/linea-monorepo/prover/protocol/compiler/dummy" "github.com/consensys/linea-monorepo/prover/protocol/dedicated/plonk" + "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/protocol/wizard" "github.com/consensys/linea-monorepo/prover/utils/csvtraces" ) @@ -49,17 +51,25 @@ var pairingDataTestCases = []pairingDataTestCase{ { // empty input to test edge case and input fillers InputFName: "testdata/ecpair_empty.csv", - ModuleFName: "", + ModuleFName: "testdata/ecpair_empty_module.csv", NbMillerLoops: 2, NbFinalExps: 2, }, { // trace test InputFName: "testdata/ecpair_trace_input.csv", - ModuleFName: "", + ModuleFName: "testdata/ecpair_trace_module.csv", NbMillerLoops: 2, NbFinalExps: 1, }, + { + // regression test in Linea Sepolia transaction 0x7afcf5eddbe09d85c8d0b1e3608b755b9baed1a59d8589ebcaf50e7603074139 + InputFName: "testdata/ecpair_regression_1_input.csv", + ModuleFName: "testdata/ecpair_regression_1_module.csv", + NbMillerLoops: 2, + NbFinalExps: 1, + NbSubgroupChecks: 1, + }, } func testModule(t *testing.T, tc pairingDataTestCase, withPairingCircuit, withG2MembershipCircuit bool, checkPairingModule, checkSubgroupModule bool) { @@ -149,6 +159,7 @@ func testModule(t *testing.T, tc pairingDataTestCase, withPairingCircuit, withG2 "ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV", "ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC", "ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR", + "ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT", "ECPAIR_UNALIGNED_PAIRING_DATA_LIMB", "ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT", "ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT", @@ -205,3 +216,58 @@ func TestMembership(t *testing.T) { testModule(t, tc, false, false, false, true) } } + +func writeModule(t *testing.T, run *wizard.ProverRuntime, outFile string, mod *ECPair) { + // this is utility function for being able to write the module output to a + // file. it is useful for testcase generation. NB! when generating testcase + // then manually check the correctness of the file before committing it. + w, err := os.Create(outFile) + if err != nil { + t.Fatal(err) + } + defer w.Close() + csvtraces.FmtCsv(w, run, []ifaces.Column{ + // // module activation + // mod.IsActive, + + // // source + // mod.ECPairSource.ID, + // mod.ECPairSource.Index, + // mod.ECPairSource.Limb, + // mod.ECPairSource.SuccessBit, + // mod.ECPairSource.AccPairings, + // mod.ECPairSource.TotalPairings, + // mod.ECPairSource.IsEcPairingData, + // mod.ECPairSource.IsEcPairingResult, + // mod.ECPairSource.CsEcpairing, + // mod.ECPairSource.CsG2Membership, + + // // for pairing module test + // mod.UnalignedPairingData.IsActive, + // mod.UnalignedPairingData.Index, + // mod.UnalignedPairingData.InstanceID, + // mod.UnalignedPairingData.IsFirstLineOfInstance, + // mod.UnalignedPairingData.IsAccumulatorInit, + // mod.UnalignedPairingData.IsFirstLineOfPrevAccumulator, + // mod.UnalignedPairingData.IsAccumulatorPrev, + // mod.UnalignedPairingData.IsFirstLineOfCurrAccumulator, + // mod.UnalignedPairingData.IsAccumulatorCurr, + // mod.UnalignedPairingData.IsResultOfInstance, + // mod.UnalignedPairingData.IsComputed, + // mod.UnalignedPairingData.IsPulling, + // mod.UnalignedPairingData.PairID, + // mod.UnalignedPairingData.TotalPairs, + // mod.UnalignedPairingData.Limb, + // mod.UnalignedPairingData.ToMillerLoopCircuitMask, + // mod.UnalignedPairingData.ToFinalExpCircuitMask, + + // // for subgroup module module test + // mod.UnalignedG2MembershipData.IsComputed, + // mod.UnalignedG2MembershipData.IsPulling, + // mod.UnalignedG2MembershipData.Limb, + // mod.UnalignedG2MembershipData.SuccessBit, + // mod.UnalignedG2MembershipData.ToG2MembershipCircuitMask, + }, + []csvtraces.Option{csvtraces.InHex}, + ) +} diff --git a/prover/zkevm/prover/ecpair/ecpair_with_circuit_test.go b/prover/zkevm/prover/ecpair/ecpair_with_circuit_test.go index f7df56d7f..4af8dacd6 100644 --- a/prover/zkevm/prover/ecpair/ecpair_with_circuit_test.go +++ b/prover/zkevm/prover/ecpair/ecpair_with_circuit_test.go @@ -3,7 +3,12 @@ package ecpair import ( + "os" + "path/filepath" + "strings" "testing" + + "github.com/consensys/linea-monorepo/prover/utils/parallel" ) func TestPairingDataCircuit(t *testing.T) { @@ -17,3 +22,29 @@ func TestMembershipCircuit(t *testing.T) { testModule(t, tc, false, true, false, true) } } + +func TestGeneratedData(t *testing.T) { + // in order to run the test, you need to have generated the different test + // cases. Run the test [TestGenerateECPairTestCases] at + // prover/zkevm/prover/ecpair/testdata/testdata_generator_test.go to + // generate all inputs. + t.Skip("long test, run manually when needed") + var generatedData []pairingDataTestCase + filepath.Walk("testdata/generated", func(path string, info os.FileInfo, err error) error { + if strings.HasSuffix(path, "input.csv") { + tc := pairingDataTestCase{ + InputFName: path, + NbMillerLoops: 5, + NbFinalExps: 1, + NbSubgroupChecks: 5, + } + generatedData = append(generatedData, tc) + } + return nil + }) + parallel.Execute(len(generatedData), func(start, end int) { + for i := start; i < end; i++ { + testModule(t, generatedData[i], true, true, true, true) + } + }) +} diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_double_pair_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_double_pair_module.csv index bcef32bda..033e3a876 100644 --- a/prover/zkevm/prover/ecpair/testdata/ecpair_double_pair_module.csv +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_double_pair_module.csv @@ -1,129 +1,129 @@ -ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT -0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 -0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13364879816394e38a2d72bde23bda93,0x1,0x0 -0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xcd39885c6bfdedbc45e6bafcfc8fa685,0x1,0x0 -0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe0e4c9d03746d287b341d52461946a1,0x1,0x0 -0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xc865002c35ba9bd6b789fc26a526d121,0x1,0x0 -0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0e82be8514331e947408a3a27a54d580,0x1,0x0 -0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 -0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0f89c9a7bb2eb9418d2d89310306196d,0x1,0x0 -0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 -0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 -0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 -0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 -0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 -0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x0,0x1,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x1,0x0 -0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x4c95627608bdbb0235762c7048400f93,0x1,0x0 -0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x1,0x0 -0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x1,0x0 -0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x1,0x0 -0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x1,0x0 -0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2b45ce688738a571621b63dba9880856,0x1,0x0 -0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x1,0x0 -0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x653b8af047158278411df902874a82a,0x1,0x0 -0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x1,0x0 -0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1373a842ceca78f2ae076804f168559c,0x1,0x0 -0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x1,0x0 -0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x1,0x0 -0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2f12833bfd8a1711d7947461776699df,0x1,0x0 -0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x1,0x0 -0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x1,0x0 -0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x1,0x0 -0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x1,0x0 -0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x22af99c52785193aa8920826c0d96380,0x1,0x0 -0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x1,0x0 -0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x1,0x0 -0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x217f227c48e2682613693d3afb8231e,0x1,0x0 -0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x5641ef4d251e87484afef7cae876258,0x1,0x0 -0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x1,0x0 -0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x0,0x1 -0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x4c95627608bdbb0235762c7048400f93,0x0,0x1 -0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x0,0x1 -0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x0,0x1 -0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x0,0x1 -0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x0,0x1 -0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2b45ce688738a571621b63dba9880856,0x0,0x1 -0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x0,0x1 -0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x653b8af047158278411df902874a82a,0x0,0x1 -0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x0,0x1 -0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1373a842ceca78f2ae076804f168559c,0x0,0x1 -0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x0,0x1 -0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x0,0x1 -0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2f12833bfd8a1711d7947461776699df,0x0,0x1 -0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x0,0x1 -0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x0,0x1 -0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x0,0x1 -0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x0,0x1 -0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x22af99c52785193aa8920826c0d96380,0x0,0x1 -0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x0,0x1 -0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x0,0x1 -0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x217f227c48e2682613693d3afb8231e,0x0,0x1 -0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x5641ef4d251e87484afef7cae876258,0x0,0x1 -0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x0,0x1 -0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xb9624a62e115247146d4643e8d4daf0,0x0,0x1 -0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 -0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 -0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 -0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2977858b214a3cb43fa4024976dd1675,0x0,0x1 -0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9b1bf5367e6318da3545e697b9931671,0x0,0x1 -0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x06fcfd4b9ca03fb145ff273e480efda3,0x0,0x1 -0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc8a7aef64882efcbd8920b4458e1ef3d,0x0,0x1 -0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x281508326108309778f9cdf9c39a4c4d,0x0,0x1 -0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc90a405c0cfbfd5d20fec4e47acce66f,0x0,0x1 -0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10d24b6f0b87c1e3f78b80b967bac765,0x0,0x1 -0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x763f38c53a4377e9a97e2761758a92f1,0x0,0x1 -0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x0,0x1 -0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x1,0x0,0x1 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 +0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13364879816394e38a2d72bde23bda93,0x1,0x0 +0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xcd39885c6bfdedbc45e6bafcfc8fa685,0x1,0x0 +0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe0e4c9d03746d287b341d52461946a1,0x1,0x0 +0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xc865002c35ba9bd6b789fc26a526d121,0x1,0x0 +0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe82be8514331e947408a3a27a54d580,0x1,0x0 +0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 +0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf89c9a7bb2eb9418d2d89310306196d,0x1,0x0 +0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 +0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 +0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 +0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 +0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 +0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x1,0x0 +0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x4c95627608bdbb0235762c7048400f93,0x1,0x0 +0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x1,0x0 +0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x1,0x0 +0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x1,0x0 +0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x1,0x0 +0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2b45ce688738a571621b63dba9880856,0x1,0x0 +0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x1,0x0 +0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x653b8af047158278411df902874a82a,0x1,0x0 +0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x1,0x0 +0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1373a842ceca78f2ae076804f168559c,0x1,0x0 +0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x1,0x0 +0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x1,0x0 +0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2f12833bfd8a1711d7947461776699df,0x1,0x0 +0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x1,0x0 +0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x1,0x0 +0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x1,0x0 +0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x1,0x0 +0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x22af99c52785193aa8920826c0d96380,0x1,0x0 +0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x1,0x0 +0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x1,0x0 +0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x217f227c48e2682613693d3afb8231e,0x1,0x0 +0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x5641ef4d251e87484afef7cae876258,0x1,0x0 +0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x1,0x0 +0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x0,0x1 +0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x4c95627608bdbb0235762c7048400f93,0x0,0x1 +0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x0,0x1 +0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x0,0x1 +0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x0,0x1 +0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x0,0x1 +0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2b45ce688738a571621b63dba9880856,0x0,0x1 +0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x0,0x1 +0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x653b8af047158278411df902874a82a,0x0,0x1 +0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x0,0x1 +0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1373a842ceca78f2ae076804f168559c,0x0,0x1 +0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x0,0x1 +0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x0,0x1 +0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2f12833bfd8a1711d7947461776699df,0x0,0x1 +0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x0,0x1 +0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x0,0x1 +0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x0,0x1 +0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x0,0x1 +0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x22af99c52785193aa8920826c0d96380,0x0,0x1 +0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x0,0x1 +0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x0,0x1 +0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x217f227c48e2682613693d3afb8231e,0x0,0x1 +0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x5641ef4d251e87484afef7cae876258,0x0,0x1 +0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x0,0x1 +0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xb9624a62e115247146d4643e8d4daf0,0x0,0x1 +0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 +0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 +0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 +0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2977858b214a3cb43fa4024976dd1675,0x0,0x1 +0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9b1bf5367e6318da3545e697b9931671,0x0,0x1 +0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x6fcfd4b9ca03fb145ff273e480efda3,0x0,0x1 +0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc8a7aef64882efcbd8920b4458e1ef3d,0x0,0x1 +0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x281508326108309778f9cdf9c39a4c4d,0x0,0x1 +0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc90a405c0cfbfd5d20fec4e47acce66f,0x0,0x1 +0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10d24b6f0b87c1e3f78b80b967bac765,0x0,0x1 +0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x763f38c53a4377e9a97e2761758a92f1,0x0,0x1 +0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x1,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_empty_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_empty_module.csv new file mode 100644 index 000000000..0b22726c4 --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_empty_module.csv @@ -0,0 +1 @@ +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_failing_double_pair_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_failing_double_pair_module.csv index 0d7099470..602be4f74 100644 --- a/prover/zkevm/prover/ecpair/testdata/ecpair_failing_double_pair_module.csv +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_failing_double_pair_module.csv @@ -1,129 +1,129 @@ -ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT -0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 -0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x219db76fd15c77e92376ec7ccdf3795a,0x1,0x0 -0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x96b20b521116027d63df9d7a4d76bcef,0x1,0x0 -0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0692f74fd48f12f945546eb1daaa688b,0x1,0x0 -0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe31ef7b9f6338c8c452d69a386f0a098,0x1,0x0 -0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0f679eca6f21e702c5613627661a31b7,0x1,0x0 -0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa5b99a766175a8ceebadf12135d8c0a0,0x1,0x0 -0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0a23a4431ea9ca09eb5787a8a0a7bb52,0x1,0x0 -0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x30a7cf5dc4fbf71edbda6ae0faca4000,0x1,0x0 -0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0715261e3e5eb7991d5dbe83f4cd963c,0x1,0x0 -0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xd8eb1975c583801573dc432c2c677165,0x1,0x0 -0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x142ed84e025468f2aa7a6fe50839c23a,0x1,0x0 -0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa3e99559088d53289092e02ffd59e84d,0x1,0x0 -0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x0,0x1,0x2,0x2519fb9fc917e5401ef8ae1dc4e0fcf6,0x1,0x0 -0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xe73ec610c73dedfaecdc78b4cfed5fae,0x1,0x0 -0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x532dd87a224b3c74c0972336084d8cf,0x1,0x0 -0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xd63ea1761e1b3eb06330f9a70a334bb3,0x1,0x0 -0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1be66119d8e9cb15799f97c5765a4f8f,0x1,0x0 -0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x7945a28f14dda8ff8d91e8e7472250dc,0x1,0x0 -0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1445016cdd9b1f1521bc8554163ed0d8,0x1,0x0 -0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1d69bb89e43261ea0cd55460902d1502,0x1,0x0 -0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x27c2852669c9bb985bb057af1b521490,0x1,0x0 -0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x9e44217a7c12ccc32c1a38dfddb3e4f9,0x1,0x0 -0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x213cd09f21a19a3ba7bf07cfb2af15db,0x1,0x0 -0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x484f312ecb72e9937bb9d118dc40bb98,0x1,0x0 -0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x278d3989a6a313a5ae46832637fb035d,0x1,0x0 -0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x27160f6e52a0177a893c3b8cfc3a16dd,0x1,0x0 -0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xf2867d79c66c1b03b24b76190f1cddb,0x1,0x0 -0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x507f66b1e126b7d5f6b8fb575b98f4e3,0x1,0x0 -0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x190f41a349878e7007fa72a919920ebe,0x1,0x0 -0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x4afaca4694c9b0a0848e46598d1f80fd,0x1,0x0 -0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x274ebf234ca143dd8a07c1ffff2ed891,0x1,0x0 -0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xb7638a696e66fe108cb6a122e36c2c9d,0x1,0x0 -0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x26f9711c5e431d68483d1c20ad498818,0x1,0x0 -0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2f3ae73e50cb72160c69a85e3b6cf774,0x1,0x0 -0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x967d0cd5a60dd7aedeb12ef807e2ce8,0x1,0x0 -0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x43aad3aff198259e8706389ab5add7c1,0x1,0x0 -0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2519fb9fc917e5401ef8ae1dc4e0fcf6,0x0,0x1 -0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xe73ec610c73dedfaecdc78b4cfed5fae,0x0,0x1 -0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x532dd87a224b3c74c0972336084d8cf,0x0,0x1 -0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xd63ea1761e1b3eb06330f9a70a334bb3,0x0,0x1 -0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1be66119d8e9cb15799f97c5765a4f8f,0x0,0x1 -0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x7945a28f14dda8ff8d91e8e7472250dc,0x0,0x1 -0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1445016cdd9b1f1521bc8554163ed0d8,0x0,0x1 -0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1d69bb89e43261ea0cd55460902d1502,0x0,0x1 -0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x27c2852669c9bb985bb057af1b521490,0x0,0x1 -0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x9e44217a7c12ccc32c1a38dfddb3e4f9,0x0,0x1 -0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x213cd09f21a19a3ba7bf07cfb2af15db,0x0,0x1 -0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x484f312ecb72e9937bb9d118dc40bb98,0x0,0x1 -0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x278d3989a6a313a5ae46832637fb035d,0x0,0x1 -0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x27160f6e52a0177a893c3b8cfc3a16dd,0x0,0x1 -0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xf2867d79c66c1b03b24b76190f1cddb,0x0,0x1 -0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x507f66b1e126b7d5f6b8fb575b98f4e3,0x0,0x1 -0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x190f41a349878e7007fa72a919920ebe,0x0,0x1 -0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x4afaca4694c9b0a0848e46598d1f80fd,0x0,0x1 -0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x274ebf234ca143dd8a07c1ffff2ed891,0x0,0x1 -0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xb7638a696e66fe108cb6a122e36c2c9d,0x0,0x1 -0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x26f9711c5e431d68483d1c20ad498818,0x0,0x1 -0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2f3ae73e50cb72160c69a85e3b6cf774,0x0,0x1 -0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x967d0cd5a60dd7aedeb12ef807e2ce8,0x0,0x1 -0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x43aad3aff198259e8706389ab5add7c1,0x0,0x1 -0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1ae800da67a6c22f94d05578d1361f25,0x0,0x1 -0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x422a9f478669101d5b117f57fcb741e1,0x0,0x1 -0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x15ded9e40e5489c82b473115f1d4b409,0x0,0x1 -0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9e93aa996ad2346e8b46a2aa0db7832c,0x0,0x1 -0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2e1b4d36165dbb3f03664c4e77181c95,0x0,0x1 -0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x285a1f1bb08fac1599d9c06095085cf0,0x0,0x1 -0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x286dcf3fe302f14b9df2d19119a97c81,0x0,0x1 -0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x70a68443dafe5001dcc450abf66cb1b9,0x0,0x1 -0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x23e5cf5e441d3d12e4b63d4d16eea2dd,0x0,0x1 -0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xdc6005a79a59c812fbd4050870691a91,0x0,0x1 -0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x11cfc60ff4ceb85b8af413347b760f13,0x0,0x1 -0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x4325aead086b2761e0a16039ab1f12aa,0x0,0x1 -0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x0,0x1 -0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x0,0x1 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 +0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x219db76fd15c77e92376ec7ccdf3795a,0x1,0x0 +0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x96b20b521116027d63df9d7a4d76bcef,0x1,0x0 +0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x692f74fd48f12f945546eb1daaa688b,0x1,0x0 +0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe31ef7b9f6338c8c452d69a386f0a098,0x1,0x0 +0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf679eca6f21e702c5613627661a31b7,0x1,0x0 +0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa5b99a766175a8ceebadf12135d8c0a0,0x1,0x0 +0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa23a4431ea9ca09eb5787a8a0a7bb52,0x1,0x0 +0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x30a7cf5dc4fbf71edbda6ae0faca4000,0x1,0x0 +0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x715261e3e5eb7991d5dbe83f4cd963c,0x1,0x0 +0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xd8eb1975c583801573dc432c2c677165,0x1,0x0 +0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x142ed84e025468f2aa7a6fe50839c23a,0x1,0x0 +0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa3e99559088d53289092e02ffd59e84d,0x1,0x0 +0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x2,0x2519fb9fc917e5401ef8ae1dc4e0fcf6,0x1,0x0 +0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xe73ec610c73dedfaecdc78b4cfed5fae,0x1,0x0 +0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x532dd87a224b3c74c0972336084d8cf,0x1,0x0 +0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd63ea1761e1b3eb06330f9a70a334bb3,0x1,0x0 +0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1be66119d8e9cb15799f97c5765a4f8f,0x1,0x0 +0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x7945a28f14dda8ff8d91e8e7472250dc,0x1,0x0 +0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1445016cdd9b1f1521bc8554163ed0d8,0x1,0x0 +0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1d69bb89e43261ea0cd55460902d1502,0x1,0x0 +0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x27c2852669c9bb985bb057af1b521490,0x1,0x0 +0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x9e44217a7c12ccc32c1a38dfddb3e4f9,0x1,0x0 +0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x213cd09f21a19a3ba7bf07cfb2af15db,0x1,0x0 +0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x484f312ecb72e9937bb9d118dc40bb98,0x1,0x0 +0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x278d3989a6a313a5ae46832637fb035d,0x1,0x0 +0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x27160f6e52a0177a893c3b8cfc3a16dd,0x1,0x0 +0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xf2867d79c66c1b03b24b76190f1cddb,0x1,0x0 +0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x507f66b1e126b7d5f6b8fb575b98f4e3,0x1,0x0 +0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x190f41a349878e7007fa72a919920ebe,0x1,0x0 +0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x4afaca4694c9b0a0848e46598d1f80fd,0x1,0x0 +0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x274ebf234ca143dd8a07c1ffff2ed891,0x1,0x0 +0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xb7638a696e66fe108cb6a122e36c2c9d,0x1,0x0 +0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x26f9711c5e431d68483d1c20ad498818,0x1,0x0 +0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2f3ae73e50cb72160c69a85e3b6cf774,0x1,0x0 +0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x967d0cd5a60dd7aedeb12ef807e2ce8,0x1,0x0 +0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x43aad3aff198259e8706389ab5add7c1,0x1,0x0 +0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2519fb9fc917e5401ef8ae1dc4e0fcf6,0x0,0x1 +0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xe73ec610c73dedfaecdc78b4cfed5fae,0x0,0x1 +0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x532dd87a224b3c74c0972336084d8cf,0x0,0x1 +0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd63ea1761e1b3eb06330f9a70a334bb3,0x0,0x1 +0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1be66119d8e9cb15799f97c5765a4f8f,0x0,0x1 +0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x7945a28f14dda8ff8d91e8e7472250dc,0x0,0x1 +0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1445016cdd9b1f1521bc8554163ed0d8,0x0,0x1 +0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1d69bb89e43261ea0cd55460902d1502,0x0,0x1 +0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x27c2852669c9bb985bb057af1b521490,0x0,0x1 +0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x9e44217a7c12ccc32c1a38dfddb3e4f9,0x0,0x1 +0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x213cd09f21a19a3ba7bf07cfb2af15db,0x0,0x1 +0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x484f312ecb72e9937bb9d118dc40bb98,0x0,0x1 +0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x278d3989a6a313a5ae46832637fb035d,0x0,0x1 +0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x27160f6e52a0177a893c3b8cfc3a16dd,0x0,0x1 +0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xf2867d79c66c1b03b24b76190f1cddb,0x0,0x1 +0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x507f66b1e126b7d5f6b8fb575b98f4e3,0x0,0x1 +0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x190f41a349878e7007fa72a919920ebe,0x0,0x1 +0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x4afaca4694c9b0a0848e46598d1f80fd,0x0,0x1 +0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x274ebf234ca143dd8a07c1ffff2ed891,0x0,0x1 +0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xb7638a696e66fe108cb6a122e36c2c9d,0x0,0x1 +0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x26f9711c5e431d68483d1c20ad498818,0x0,0x1 +0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2f3ae73e50cb72160c69a85e3b6cf774,0x0,0x1 +0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x967d0cd5a60dd7aedeb12ef807e2ce8,0x0,0x1 +0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x43aad3aff198259e8706389ab5add7c1,0x0,0x1 +0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1ae800da67a6c22f94d05578d1361f25,0x0,0x1 +0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x422a9f478669101d5b117f57fcb741e1,0x0,0x1 +0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x15ded9e40e5489c82b473115f1d4b409,0x0,0x1 +0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9e93aa996ad2346e8b46a2aa0db7832c,0x0,0x1 +0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2e1b4d36165dbb3f03664c4e77181c95,0x0,0x1 +0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x285a1f1bb08fac1599d9c06095085cf0,0x0,0x1 +0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x286dcf3fe302f14b9df2d19119a97c81,0x0,0x1 +0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x70a68443dafe5001dcc450abf66cb1b9,0x0,0x1 +0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x23e5cf5e441d3d12e4b63d4d16eea2dd,0x0,0x1 +0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xdc6005a79a59c812fbd4050870691a91,0x0,0x1 +0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x11cfc60ff4ceb85b8af413347b760f13,0x0,0x1 +0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x4325aead086b2761e0a16039ab1f12aa,0x0,0x1 +0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_input.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_input.csv new file mode 100644 index 000000000..278d9801b --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_input.csv @@ -0,0 +1,51 @@ +ECDATA_CS_PAIRING,ECDATA_ID,ECDATA_LIMB,ECDATA_SUCCESS_BIT,ECDATA_INDEX,ECDATA_IS_DATA,ECDATA_IS_RES,ECDATA_ACC_PAIRINGS,ECDATA_TOTAL_PAIRINGS,ECDATA_CS_G2_MEMBERSHIP +0,29563,0x0,1,0,1,0,1,4,0 +0,29563,0x0,1,1,1,0,1,4,0 +0,29563,0x0,1,2,1,0,1,4,0 +0,29563,0x0,1,3,1,0,1,4,0 +0,29563,0x0,1,4,1,0,1,4,0 +0,29563,0x0,1,5,1,0,1,4,0 +0,29563,0x0,1,6,1,0,1,4,0 +0,29563,0x0,1,7,1,0,1,4,0 +0,29563,0x0,1,8,1,0,1,4,0 +0,29563,0x0,1,9,1,0,1,4,0 +0,29563,0x0,1,10,1,0,1,4,0 +0,29563,0x0,1,11,1,0,1,4,0 +1,29563,0x27c69626be302e46df0af1982d621c7b,1,12,1,0,2,4,0 +1,29563,0x358571d44f0c65c9207af46b2e4b9594,1,13,1,0,2,4,0 +1,29563,0x120b258a7d2bb21e213159d01dd4364f,1,14,1,0,2,4,0 +1,29563,0xa11f02c47337b94e73ce1ad65ee10ada,1,15,1,0,2,4,0 +1,29563,0xb7c8b8c2f08ad05c14efdb53212ef50,1,16,1,0,2,4,0 +1,29563,0x1ac66ce991a90c10c22608a6ef0c6daf,1,17,1,0,2,4,0 +1,29563,0xda86f1aa7f003fc49ba5257f6a1a31b,1,18,1,0,2,4,0 +1,29563,0x762fb2a71e26b2bf972ad9c5ce50aabd,1,19,1,0,2,4,0 +1,29563,0x20b3c0f5090994b976afe7fa30002668,1,20,1,0,2,4,0 +1,29563,0x9547288c6611bf5bb913d706309817fc,1,21,1,0,2,4,0 +1,29563,0x1b55dc31de4c20571c178adea2e97fc6,1,22,1,0,2,4,0 +1,29563,0xb5745f4727165ab056c3150134fa6856,1,23,1,0,2,4,0 +1,29563,0x1996a3bf3f09f5c3d609d0341d07a22a,1,24,1,0,3,4,0 +1,29563,0x30cc16bfe7e74afdd0770ff169502c92,1,25,1,0,3,4,0 +1,29563,0x2c8c2d7e802418dea505c1856cb9f95b,1,26,1,0,3,4,0 +1,29563,0x1ca0a26bec7e4f73d03e9958dff2081a,1,27,1,0,3,4,0 +1,29563,0x198e9393920d483a7260bfb731fb5d25,1,28,1,0,3,4,0 +1,29563,0xf1aa493335a9e71297e485b7aef312c2,1,29,1,0,3,4,0 +1,29563,0x1800deef121f1e76426a00665e5c4479,1,30,1,0,3,4,0 +1,29563,0x674322d4f75edadd46debd5cd992f6ed,1,31,1,0,3,4,0 +1,29563,0x90689d0585ff075ec9e99ad690c3395,1,32,1,0,3,4,0 +1,29563,0xbc4b313370b38ef355acdadcd122975b,1,33,1,0,3,4,0 +1,29563,0x12c85ea5db8c6deb4aab71808dcb408f,1,34,1,0,3,4,0 +1,29563,0xe3d1e7690c43d37b4ce6cc0166fa7daa,1,35,1,0,3,4,0 +0,29563,0x0,1,36,1,0,4,4,0 +0,29563,0x0,1,37,1,0,4,4,0 +0,29563,0x0,1,38,1,0,4,4,0 +0,29563,0x0,1,39,1,0,4,4,0 +0,29563,0xed5b8a199985a625f5a0b6a44275b4c,1,40,1,0,4,4,1 +0,29563,0x48874ea094387e322a9a65548e55baaf,1,41,1,0,4,4,1 +0,29563,0x14c46c51fbb5b9e3d065addbcdd76571,1,42,1,0,4,4,1 +0,29563,0x12f73bbcdfecec743c83cd36cd6a11a0,1,43,1,0,4,4,1 +0,29563,0xa898f0e4144460a4a5a7018ceea8ab5,1,44,1,0,4,4,1 +0,29563,0x6732baf61e32b9873d6cef5cb8457cbe,1,45,1,0,4,4,1 +0,29563,0x3f6ad521b15ce41febd3ec0579fa48f,1,46,1,0,4,4,1 +0,29563,0xd563b64f31711e6e2b133b1fc2dd4588,1,47,1,0,4,4,1 +1,29563,0,1,0,0,1,0,4,0 +1,29563,0,1,1,0,1,0,4,0 \ No newline at end of file diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_module.csv new file mode 100644 index 000000000..1e68c3596 --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_regression_1_module.csv @@ -0,0 +1,129 @@ +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x737b,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x1,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 +0x1,0x1,0x2,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x3,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x4,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x5,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x6,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x7,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x8,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x9,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xa,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xb,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xc,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xd,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xe,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xf,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x10,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x11,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x12,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x13,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x14,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x15,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x16,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x17,0x737b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x18,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x27c69626be302e46df0af1982d621c7b,0x1,0x0 +0x1,0x1,0x19,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x358571d44f0c65c9207af46b2e4b9594,0x1,0x0 +0x1,0x1,0x1a,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x120b258a7d2bb21e213159d01dd4364f,0x1,0x0 +0x1,0x1,0x1b,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa11f02c47337b94e73ce1ad65ee10ada,0x1,0x0 +0x1,0x1,0x1c,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xb7c8b8c2f08ad05c14efdb53212ef50,0x1,0x0 +0x1,0x1,0x1d,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x1ac66ce991a90c10c22608a6ef0c6daf,0x1,0x0 +0x1,0x1,0x1e,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xda86f1aa7f003fc49ba5257f6a1a31b,0x1,0x0 +0x1,0x1,0x1f,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x762fb2a71e26b2bf972ad9c5ce50aabd,0x1,0x0 +0x1,0x1,0x20,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x20b3c0f5090994b976afe7fa30002668,0x1,0x0 +0x1,0x1,0x21,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9547288c6611bf5bb913d706309817fc,0x1,0x0 +0x1,0x1,0x22,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x1b55dc31de4c20571c178adea2e97fc6,0x1,0x0 +0x1,0x1,0x23,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xb5745f4727165ab056c3150134fa6856,0x1,0x0 +0x1,0x1,0x24,0x737b,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x2,0x1137fc12353dc8b52b4a9fddbbaa3a5b,0x1,0x0 +0x1,0x1,0x25,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x17cbb12b76d31ccc72553270b505ac54,0x1,0x0 +0x1,0x1,0x26,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x759e8fb6f8a80d8fce8efdbd26d82e4,0x1,0x0 +0x1,0x1,0x27,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x11a5b0cf036373ff04fa1590f8535f43,0x1,0x0 +0x1,0x1,0x28,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x28cb8ef1fb08ff271b49d1816a451dbd,0x1,0x0 +0x1,0x1,0x29,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x24cb561c666914c1966961e99226a0e7,0x1,0x0 +0x1,0x1,0x2a,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x269a2a32ca8a7ead6dc1acb9b671d45b,0x1,0x0 +0x1,0x1,0x2b,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd93846bfa6f32f7eb9458a7a98963640,0x1,0x0 +0x1,0x1,0x2c,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2eba69ac1e7fa1147b1dbdfde9190ebf,0x1,0x0 +0x1,0x1,0x2d,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x92b120d2f924214364944984c66619c9,0x1,0x0 +0x1,0x1,0x2e,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xb3539f69dc72810362b4aa2260e18cf,0x1,0x0 +0x1,0x1,0x2f,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x6e6230b3b5c234758d6944d67b361bfb,0x1,0x0 +0x1,0x1,0x30,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2ef88e7bca3f69d2612b56ce9699615f,0x1,0x0 +0x1,0x1,0x31,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x12f87428792a957fd1737013855ac876,0x1,0x0 +0x1,0x1,0x32,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x24f79206d5cb177e64b4d9053151ce77,0x1,0x0 +0x1,0x1,0x33,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xa45dabb1095f36a6edc58f5114644398,0x1,0x0 +0x1,0x1,0x34,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1db7f080e67a26c52952d71c7331ffbe,0x1,0x0 +0x1,0x1,0x35,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xdc137df9f4dd59feeb25c4f70d2ac3f5,0x1,0x0 +0x1,0x1,0x36,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1ad6a825f36bc860b8696c73736d33f8,0x1,0x0 +0x1,0x1,0x37,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd82bd185f505f0ff786cf2e68ba47da6,0x1,0x0 +0x1,0x1,0x38,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1606a45c154325213c755b01be9903fa,0x1,0x0 +0x1,0x1,0x39,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x419de110d5c0cce0a57990de0a7d1413,0x1,0x0 +0x1,0x1,0x3a,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x8646892bb422186785938a4e3b5d520,0x1,0x0 +0x1,0x1,0x3b,0x737b,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xb7a6a2366c9bac68585391b8bd024367,0x1,0x0 +0x1,0x1,0x3c,0x737b,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1137fc12353dc8b52b4a9fddbbaa3a5b,0x0,0x1 +0x1,0x1,0x3d,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x17cbb12b76d31ccc72553270b505ac54,0x0,0x1 +0x1,0x1,0x3e,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x759e8fb6f8a80d8fce8efdbd26d82e4,0x0,0x1 +0x1,0x1,0x3f,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x11a5b0cf036373ff04fa1590f8535f43,0x0,0x1 +0x1,0x1,0x40,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x28cb8ef1fb08ff271b49d1816a451dbd,0x0,0x1 +0x1,0x1,0x41,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x24cb561c666914c1966961e99226a0e7,0x0,0x1 +0x1,0x1,0x42,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x269a2a32ca8a7ead6dc1acb9b671d45b,0x0,0x1 +0x1,0x1,0x43,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd93846bfa6f32f7eb9458a7a98963640,0x0,0x1 +0x1,0x1,0x44,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2eba69ac1e7fa1147b1dbdfde9190ebf,0x0,0x1 +0x1,0x1,0x45,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x92b120d2f924214364944984c66619c9,0x0,0x1 +0x1,0x1,0x46,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xb3539f69dc72810362b4aa2260e18cf,0x0,0x1 +0x1,0x1,0x47,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x6e6230b3b5c234758d6944d67b361bfb,0x0,0x1 +0x1,0x1,0x48,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2ef88e7bca3f69d2612b56ce9699615f,0x0,0x1 +0x1,0x1,0x49,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x12f87428792a957fd1737013855ac876,0x0,0x1 +0x1,0x1,0x4a,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x24f79206d5cb177e64b4d9053151ce77,0x0,0x1 +0x1,0x1,0x4b,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xa45dabb1095f36a6edc58f5114644398,0x0,0x1 +0x1,0x1,0x4c,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1db7f080e67a26c52952d71c7331ffbe,0x0,0x1 +0x1,0x1,0x4d,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xdc137df9f4dd59feeb25c4f70d2ac3f5,0x0,0x1 +0x1,0x1,0x4e,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1ad6a825f36bc860b8696c73736d33f8,0x0,0x1 +0x1,0x1,0x4f,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd82bd185f505f0ff786cf2e68ba47da6,0x0,0x1 +0x1,0x1,0x50,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1606a45c154325213c755b01be9903fa,0x0,0x1 +0x1,0x1,0x51,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x419de110d5c0cce0a57990de0a7d1413,0x0,0x1 +0x1,0x1,0x52,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x8646892bb422186785938a4e3b5d520,0x0,0x1 +0x1,0x1,0x53,0x737b,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xb7a6a2366c9bac68585391b8bd024367,0x0,0x1 +0x1,0x1,0x54,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1996a3bf3f09f5c3d609d0341d07a22a,0x0,0x1 +0x1,0x1,0x55,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x30cc16bfe7e74afdd0770ff169502c92,0x0,0x1 +0x1,0x1,0x56,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2c8c2d7e802418dea505c1856cb9f95b,0x0,0x1 +0x1,0x1,0x57,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1ca0a26bec7e4f73d03e9958dff2081a,0x0,0x1 +0x1,0x1,0x58,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x198e9393920d483a7260bfb731fb5d25,0x0,0x1 +0x1,0x1,0x59,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xf1aa493335a9e71297e485b7aef312c2,0x0,0x1 +0x1,0x1,0x5a,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1800deef121f1e76426a00665e5c4479,0x0,0x1 +0x1,0x1,0x5b,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x674322d4f75edadd46debd5cd992f6ed,0x0,0x1 +0x1,0x1,0x5c,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x90689d0585ff075ec9e99ad690c3395,0x0,0x1 +0x1,0x1,0x5d,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xbc4b313370b38ef355acdadcd122975b,0x0,0x1 +0x1,0x1,0x5e,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x12c85ea5db8c6deb4aab71808dcb408f,0x0,0x1 +0x1,0x1,0x5f,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xe3d1e7690c43d37b4ce6cc0166fa7daa,0x0,0x1 +0x1,0x1,0x60,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x1,0x1,0x61,0x737b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_trace_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_trace_module.csv new file mode 100644 index 000000000..6426b4188 --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_trace_module.csv @@ -0,0 +1,257 @@ +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x3f,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x1,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x1,0x1,0x0 +0x1,0x1,0x2,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x3,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x4,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x5,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x6,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x7,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x8,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x9,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xa,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xb,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xc,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xd,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xe,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xf,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x10,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x11,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x12,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x13,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x14,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x15,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x16,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x17,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x18,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x1395d002b3ca9180fb924650ef0656e,0x1,0x0 +0x1,0x1,0x19,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xad838fd027d487fed681de0d674c30da,0x1,0x0 +0x1,0x1,0x1a,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x97c3a9a072f9c85edf7a36812f8ee05,0x1,0x0 +0x1,0x1,0x1b,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xe2cc73140749dcd7d29ceb34a8412188,0x1,0x0 +0x1,0x1,0x1c,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x2bd3295ff81c577fe772543783411c36,0x1,0x0 +0x1,0x1,0x1d,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xf463676d9692ca4250588fbad0b44dc7,0x1,0x0 +0x1,0x1,0x1e,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x7d8d8329e62324af8091e3a4ffe5a57,0x1,0x0 +0x1,0x1,0x1f,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xcb8664d1f5f6838c55261177118e9313,0x1,0x0 +0x1,0x1,0x20,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x230f1851ba0d3d7d36c8603c7118c86b,0x1,0x0 +0x1,0x1,0x21,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xd2b6a7a1610c4af9e907cb702beff1d8,0x1,0x0 +0x1,0x1,0x22,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x12843e703009c1c1a2f1088dcf4d91e9,0x1,0x0 +0x1,0x1,0x23,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xed43189aa6327cae9a68be22a1aee5cb,0x1,0x0 +0x1,0x1,0x24,0x3f,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x3,0x1cf132423a3757d094ef99ada67c9cbb,0x1,0x0 +0x1,0x1,0x25,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xc05ccf866f830043032e06e07dd88a31,0x1,0x0 +0x1,0x1,0x26,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xe30c42cccdf4b6d6c6b05a463b60438,0x1,0x0 +0x1,0x1,0x27,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x170d4ed7935fd1235d19cfc5ee258ba9,0x1,0x0 +0x1,0x1,0x28,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2cf4fca7e570f69fd5ff51d0d0424699,0x1,0x0 +0x1,0x1,0x29,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x54f670cce3aa1a95a1e3609a24de1507,0x1,0x0 +0x1,0x1,0x2a,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2e3f1c8b74e6d5303c5dade8d1338d3c,0x1,0x0 +0x1,0x1,0x2b,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x4a0d2a9c4be4cbecd7975385e41cf3b,0x1,0x0 +0x1,0x1,0x2c,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x1841621784db87a58dfc93fd299f7b3e,0x1,0x0 +0x1,0x1,0x2d,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xf0e2f3f8f2a9afca5ce416419edefc72,0x1,0x0 +0x1,0x1,0x2e,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2f3f5baa49d8c5f9e7b7ae29843c5d35,0x1,0x0 +0x1,0x1,0x2f,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x5f953e4c1e0813885afc2291cd154ede,0x1,0x0 +0x1,0x1,0x30,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x1510a127c5c44cbd93e51dea529b9321,0x1,0x0 +0x1,0x1,0x31,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x50cf06bd0bb7688b9965b90bcedc1af9,0x1,0x0 +0x1,0x1,0x32,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xc9593cee20457e4c62ab5da575f2647,0x1,0x0 +0x1,0x1,0x33,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xf06055f2fd530e59c2896039eab80ee7,0x1,0x0 +0x1,0x1,0x34,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x1b3b112aba7d3a132fcb8c05ae86b218,0x1,0x0 +0x1,0x1,0x35,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x4f132790848da73fa7883daae019a05c,0x1,0x0 +0x1,0x1,0x36,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x233fc6eac88cfd1649495fdf1acdd1b,0x1,0x0 +0x1,0x1,0x37,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xe5d86687e5043ba455a40e42f7d63e3b,0x1,0x0 +0x1,0x1,0x38,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x24a697c910c684744ebad59980360b2c,0x1,0x0 +0x1,0x1,0x39,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xf19c2c4ffd895fb7e84e7aaaf658b917,0x1,0x0 +0x1,0x1,0x3a,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x1834997d6a586ada4ad6e9cf19b11316,0x1,0x0 +0x1,0x1,0x3b,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xd0eae21499fa324cad4e71e9c7c2c161,0x1,0x0 +0x1,0x1,0x3c,0x3f,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1cf132423a3757d094ef99ada67c9cbb,0x1,0x0 +0x1,0x1,0x3d,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xc05ccf866f830043032e06e07dd88a31,0x1,0x0 +0x1,0x1,0x3e,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xe30c42cccdf4b6d6c6b05a463b60438,0x1,0x0 +0x1,0x1,0x3f,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x170d4ed7935fd1235d19cfc5ee258ba9,0x1,0x0 +0x1,0x1,0x40,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2cf4fca7e570f69fd5ff51d0d0424699,0x1,0x0 +0x1,0x1,0x41,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x54f670cce3aa1a95a1e3609a24de1507,0x1,0x0 +0x1,0x1,0x42,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2e3f1c8b74e6d5303c5dade8d1338d3c,0x1,0x0 +0x1,0x1,0x43,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x4a0d2a9c4be4cbecd7975385e41cf3b,0x1,0x0 +0x1,0x1,0x44,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1841621784db87a58dfc93fd299f7b3e,0x1,0x0 +0x1,0x1,0x45,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xf0e2f3f8f2a9afca5ce416419edefc72,0x1,0x0 +0x1,0x1,0x46,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2f3f5baa49d8c5f9e7b7ae29843c5d35,0x1,0x0 +0x1,0x1,0x47,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x5f953e4c1e0813885afc2291cd154ede,0x1,0x0 +0x1,0x1,0x48,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1510a127c5c44cbd93e51dea529b9321,0x1,0x0 +0x1,0x1,0x49,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x50cf06bd0bb7688b9965b90bcedc1af9,0x1,0x0 +0x1,0x1,0x4a,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xc9593cee20457e4c62ab5da575f2647,0x1,0x0 +0x1,0x1,0x4b,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xf06055f2fd530e59c2896039eab80ee7,0x1,0x0 +0x1,0x1,0x4c,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1b3b112aba7d3a132fcb8c05ae86b218,0x1,0x0 +0x1,0x1,0x4d,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x4f132790848da73fa7883daae019a05c,0x1,0x0 +0x1,0x1,0x4e,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x233fc6eac88cfd1649495fdf1acdd1b,0x1,0x0 +0x1,0x1,0x4f,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xe5d86687e5043ba455a40e42f7d63e3b,0x1,0x0 +0x1,0x1,0x50,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x24a697c910c684744ebad59980360b2c,0x1,0x0 +0x1,0x1,0x51,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xf19c2c4ffd895fb7e84e7aaaf658b917,0x1,0x0 +0x1,0x1,0x52,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1834997d6a586ada4ad6e9cf19b11316,0x1,0x0 +0x1,0x1,0x53,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xd0eae21499fa324cad4e71e9c7c2c161,0x1,0x0 +0x1,0x1,0x54,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x5dcb6449ff95e1a04c3132ce3be82a8,0x1,0x0 +0x1,0x1,0x55,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x97811d2087e082e0399985449942a45b,0x1,0x0 +0x1,0x1,0x56,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0xcb5122006e9b7ceb5307fa4015b132b,0x1,0x0 +0x1,0x1,0x57,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x3945bb972c83459f598659fc4b5a9d32,0x1,0x0 +0x1,0x1,0x58,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x12618811f3e9fa06644d43cfe3f69c6c,0x1,0x0 +0x1,0x1,0x59,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x17a738128de60f8f3ebb4266bab29be6,0x1,0x0 +0x1,0x1,0x5a,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0xa5a6c2ec01c4d1374078ae1bbea91d,0x1,0x0 +0x1,0x1,0x5b,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0xea8e938c1275226a1ce51db5e7de53d1,0x1,0x0 +0x1,0x1,0x5c,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x2da43ecc11a0095a72454bb08fb4d111,0x1,0x0 +0x1,0x1,0x5d,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x6facadcab482a1107ae67a12bb3c19f2,0x1,0x0 +0x1,0x1,0x5e,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x1e2f128bf79945a370324b82c36c1e63,0x1,0x0 +0x1,0x1,0x5f,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x509b122c023bd8163495526bb030a216,0x1,0x0 +0x1,0x1,0x60,0x3f,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x2,0x3,0x292cd168c3ef2c37a8f27c5bbe7c2dff,0x1,0x0 +0x1,0x1,0x61,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x5a46ba655fbb57ec5efc46b9973b7d65,0x1,0x0 +0x1,0x1,0x62,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x2cb7ca0140a3f91e02d365e4c31275f8,0x1,0x0 +0x1,0x1,0x63,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xc1856d0a6cb28650b2d9266980ca00ef,0x1,0x0 +0x1,0x1,0x64,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x19814a3786275c07e02bd384361d4b7e,0x1,0x0 +0x1,0x1,0x65,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x6f30fe1bc74fb180719d75ef9a9609d3,0x1,0x0 +0x1,0x1,0x66,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x17bf6e240bd7895eddbf10206905e6ad,0x1,0x0 +0x1,0x1,0x67,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xffed4359fee5622b68a81e6314f292ce,0x1,0x0 +0x1,0x1,0x68,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xff7294fed8bd9ec7e86e15b083c00b2,0x1,0x0 +0x1,0x1,0x69,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x927517d94b16c0133605486bfd90e477,0x1,0x0 +0x1,0x1,0x6a,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x191e2bbfd9f4989a3d1a54d21470f96e,0x1,0x0 +0x1,0x1,0x6b,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xfbf902cf06d4d6d995258e0ea9a9df06,0x1,0x0 +0x1,0x1,0x6c,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x141076b6ccff6c662090b71a1af7c79f,0x1,0x0 +0x1,0x1,0x6d,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x26700ab52e2da324955b3865ef94f595,0x1,0x0 +0x1,0x1,0x6e,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xfac823941439c8120d2c0a637e63e45,0x1,0x0 +0x1,0x1,0x6f,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x832bca89f3a3bf0132fc34d8a9ba3c22,0x1,0x0 +0x1,0x1,0x70,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xe3ab8880e570c3e1871ccac25453c9d,0x1,0x0 +0x1,0x1,0x71,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x9da82ce39eb65dcda6b5e65d7f37e82e,0x1,0x0 +0x1,0x1,0x72,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x3a1a183f2a698f9d2f14235c7c4e1fc,0x1,0x0 +0x1,0x1,0x73,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x5e2ce6aad082abaeb72e02c435c01ff3,0x1,0x0 +0x1,0x1,0x74,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x13b007062ca2e328423d9f6e4afbcdb5,0x1,0x0 +0x1,0x1,0x75,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xcb16f68b149ea5375803535399011725,0x1,0x0 +0x1,0x1,0x76,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x19523563e9858fcfded6c6ab452074cb,0x1,0x0 +0x1,0x1,0x77,0x3f,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xdb8f9c7ee417eb2ae8917809a44547ff,0x1,0x0 +0x1,0x1,0x78,0x3f,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x292cd168c3ef2c37a8f27c5bbe7c2dff,0x0,0x1 +0x1,0x1,0x79,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x5a46ba655fbb57ec5efc46b9973b7d65,0x0,0x1 +0x1,0x1,0x7a,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x2cb7ca0140a3f91e02d365e4c31275f8,0x0,0x1 +0x1,0x1,0x7b,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xc1856d0a6cb28650b2d9266980ca00ef,0x0,0x1 +0x1,0x1,0x7c,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x19814a3786275c07e02bd384361d4b7e,0x0,0x1 +0x1,0x1,0x7d,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x6f30fe1bc74fb180719d75ef9a9609d3,0x0,0x1 +0x1,0x1,0x7e,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x17bf6e240bd7895eddbf10206905e6ad,0x0,0x1 +0x1,0x1,0x7f,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xffed4359fee5622b68a81e6314f292ce,0x0,0x1 +0x1,0x1,0x80,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xff7294fed8bd9ec7e86e15b083c00b2,0x0,0x1 +0x1,0x1,0x81,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x927517d94b16c0133605486bfd90e477,0x0,0x1 +0x1,0x1,0x82,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x191e2bbfd9f4989a3d1a54d21470f96e,0x0,0x1 +0x1,0x1,0x83,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xfbf902cf06d4d6d995258e0ea9a9df06,0x0,0x1 +0x1,0x1,0x84,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x141076b6ccff6c662090b71a1af7c79f,0x0,0x1 +0x1,0x1,0x85,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x26700ab52e2da324955b3865ef94f595,0x0,0x1 +0x1,0x1,0x86,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xfac823941439c8120d2c0a637e63e45,0x0,0x1 +0x1,0x1,0x87,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x832bca89f3a3bf0132fc34d8a9ba3c22,0x0,0x1 +0x1,0x1,0x88,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xe3ab8880e570c3e1871ccac25453c9d,0x0,0x1 +0x1,0x1,0x89,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x9da82ce39eb65dcda6b5e65d7f37e82e,0x0,0x1 +0x1,0x1,0x8a,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x3a1a183f2a698f9d2f14235c7c4e1fc,0x0,0x1 +0x1,0x1,0x8b,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x5e2ce6aad082abaeb72e02c435c01ff3,0x0,0x1 +0x1,0x1,0x8c,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x13b007062ca2e328423d9f6e4afbcdb5,0x0,0x1 +0x1,0x1,0x8d,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xcb16f68b149ea5375803535399011725,0x0,0x1 +0x1,0x1,0x8e,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x19523563e9858fcfded6c6ab452074cb,0x0,0x1 +0x1,0x1,0x8f,0x3f,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xdb8f9c7ee417eb2ae8917809a44547ff,0x0,0x1 +0x1,0x1,0x90,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x1296d042f33ccbb814746e187aa20af4,0x0,0x1 +0x1,0x1,0x91,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x9bd503356de4846abee08da9e32ae2ac,0x0,0x1 +0x1,0x1,0x92,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xb980019d2af83b353aa8c2efda45f16,0x0,0x1 +0x1,0x1,0x93,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xce523b99452118be7ae5dd1e92e0e4ec,0x0,0x1 +0x1,0x1,0x94,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x12cd1b1242354b35cd8d2493c487b52,0x0,0x1 +0x1,0x1,0x95,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x411d111c80e8cfb97080e2db1af5f705,0x0,0x1 +0x1,0x1,0x96,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x20ca232ed2582feeca2d56a589eec30c,0x0,0x1 +0x1,0x1,0x97,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x27075a44aced8382d87cd43c011aeeb0,0x0,0x1 +0x1,0x1,0x98,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x2df7d0d9ae47467ca500b528f38ac384,0x0,0x1 +0x1,0x1,0x99,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x33885d6a59db6ecd7d27d37145e75360,0x0,0x1 +0x1,0x1,0x9a,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x1e4d8d4d8878cad4de8dbb31ec11d1ec,0x0,0x1 +0x1,0x1,0x9b,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xd7b40617c46bb7189ccab201b9bdbaab,0x0,0x1 +0x1,0x1,0x9c,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x3,0x0,0x0,0x1 +0x1,0x1,0x9d,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x3,0x1,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_triple_pair_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_triple_pair_module.csv index 1ef3848fe..a59d72f85 100644 --- a/prover/zkevm/prover/ecpair/testdata/ecpair_triple_pair_module.csv +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_triple_pair_module.csv @@ -1,257 +1,257 @@ -ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT -0x1,0x1,0x0,0x0,0x1,0x3,0x1,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x1,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x1,0x0 -0x1,0x1,0x2,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x3,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x4,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x5,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x6,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x7,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x8,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x9,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xa,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xb,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xc,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xd,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xe,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0xf,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x10,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x11,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x12,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x13,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x14,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x15,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x16,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x17,0x0,0x1,0x3,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0 -0x1,0x1,0x18,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x100fb2006c3a4409ce06f6c2d535564c,0x1,0x0 -0x1,0x1,0x19,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x92e592aeb426d6c035bb8c0a50202e6d,0x1,0x0 -0x1,0x1,0x1a,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1275964141a90f3170592ade82174d09,0x1,0x0 -0x1,0x1,0x1b,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xde3cc7f5b79f260f51c143e3268ba06d,0x1,0x0 -0x1,0x1,0x1c,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2e607689d1161c5cb3d6ed870a5b6f47,0x1,0x0 -0x1,0x1,0x1d,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xb19627c2c51d3d2eb72f81c540ff9f9d,0x1,0x0 -0x1,0x1,0x1e,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x09d2b2eb399326d9cc552e9753afaeab,0x1,0x0 -0x1,0x1,0x1f,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xbb29985def8b5800f32145223ff61d48,0x1,0x0 -0x1,0x1,0x20,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x03a5907084b1f9ee93a1fa011b31b383,0x1,0x0 -0x1,0x1,0x21,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x60b7d50b789fbe32d3733176ffd9d46a,0x1,0x0 -0x1,0x1,0x22,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2e8b82b3506125e8b67bb867604a8892,0x1,0x0 -0x1,0x1,0x23,0x0,0x1,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x7b9695a8d131627503a0f63bfe5d0cca,0x1,0x0 -0x1,0x1,0x24,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3b453509cb62c429d8a86ea1cf46897,0x1,0x0 -0x1,0x1,0x25,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xfc8f75a5184afbfee72be2a8ac39ab6,0x1,0x0 -0x1,0x1,0x26,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x258732ffd31c5ae816e163e3458108dd,0x1,0x0 -0x1,0x1,0x27,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x99caaa2e258abab37bb4b1e675e792b4,0x1,0x0 -0x1,0x1,0x28,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x8dc4617a012a931507f27b285f48a99,0x1,0x0 -0x1,0x1,0x29,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2c0cc58a0906a3a6ef6e5378a04addf2,0x1,0x0 -0x1,0x1,0x2a,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x185514250c1eaff2fdc813fd31c55772,0x1,0x0 -0x1,0x1,0x2b,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x81316979a26c9fdb191f6abac2a0bcf2,0x1,0x0 -0x1,0x1,0x2c,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x26a52e43327b03b40c3b36854698ed02,0x1,0x0 -0x1,0x1,0x2d,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x572116a2bc8995a07550a2c11b3f1bb3,0x1,0x0 -0x1,0x1,0x2e,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x22a813b81101fa27e07888a4c1ee151b,0x1,0x0 -0x1,0x1,0x2f,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xd5c7de0e174ce72545ed2796a057e0f5,0x1,0x0 -0x1,0x1,0x30,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1755fc232224e41b6b375a49c842eed,0x1,0x0 -0x1,0x1,0x31,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe4e0cf3cce99d1664c5e8489205e9461,0x1,0x0 -0x1,0x1,0x32,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2b80c453b72e713a9ee7304f7c598ebe,0x1,0x0 -0x1,0x1,0x33,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe28aeb3c386d4c2dfe575197636a578b,0x1,0x0 -0x1,0x1,0x34,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x225235e07cb0c897a4d26f2f76019f3,0x1,0x0 -0x1,0x1,0x35,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xec0c5349a3d4d57e9ab9e9b48f3ba9b3,0x1,0x0 -0x1,0x1,0x36,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2864b7882cf2e11ed3bffbff7cb788ca,0x1,0x0 -0x1,0x1,0x37,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x30f1e0743e45d9900320f9e6890f6817,0x1,0x0 -0x1,0x1,0x38,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x29293f07fccd8ac29bf0501e823696f,0x1,0x0 -0x1,0x1,0x39,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x71ba1b75f369441cf66cb0c6d8127ad0,0x1,0x0 -0x1,0x1,0x3a,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x15d7ace2db3651ba26cc0852ffa53be9,0x1,0x0 -0x1,0x1,0x3b,0x0,0x1,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x40a41876d29c7d3d9efea184a2f58712,0x1,0x0 -0x1,0x1,0x3c,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x3b453509cb62c429d8a86ea1cf46897,0x1,0x0 -0x1,0x1,0x3d,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xfc8f75a5184afbfee72be2a8ac39ab6,0x1,0x0 -0x1,0x1,0x3e,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x258732ffd31c5ae816e163e3458108dd,0x1,0x0 -0x1,0x1,0x3f,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x99caaa2e258abab37bb4b1e675e792b4,0x1,0x0 -0x1,0x1,0x40,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x8dc4617a012a931507f27b285f48a99,0x1,0x0 -0x1,0x1,0x41,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2c0cc58a0906a3a6ef6e5378a04addf2,0x1,0x0 -0x1,0x1,0x42,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x185514250c1eaff2fdc813fd31c55772,0x1,0x0 -0x1,0x1,0x43,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x81316979a26c9fdb191f6abac2a0bcf2,0x1,0x0 -0x1,0x1,0x44,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x26a52e43327b03b40c3b36854698ed02,0x1,0x0 -0x1,0x1,0x45,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x572116a2bc8995a07550a2c11b3f1bb3,0x1,0x0 -0x1,0x1,0x46,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x22a813b81101fa27e07888a4c1ee151b,0x1,0x0 -0x1,0x1,0x47,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xd5c7de0e174ce72545ed2796a057e0f5,0x1,0x0 -0x1,0x1,0x48,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1755fc232224e41b6b375a49c842eed,0x1,0x0 -0x1,0x1,0x49,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xe4e0cf3cce99d1664c5e8489205e9461,0x1,0x0 -0x1,0x1,0x4a,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2b80c453b72e713a9ee7304f7c598ebe,0x1,0x0 -0x1,0x1,0x4b,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xe28aeb3c386d4c2dfe575197636a578b,0x1,0x0 -0x1,0x1,0x4c,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x225235e07cb0c897a4d26f2f76019f3,0x1,0x0 -0x1,0x1,0x4d,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xec0c5349a3d4d57e9ab9e9b48f3ba9b3,0x1,0x0 -0x1,0x1,0x4e,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2864b7882cf2e11ed3bffbff7cb788ca,0x1,0x0 -0x1,0x1,0x4f,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x30f1e0743e45d9900320f9e6890f6817,0x1,0x0 -0x1,0x1,0x50,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x29293f07fccd8ac29bf0501e823696f,0x1,0x0 -0x1,0x1,0x51,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x71ba1b75f369441cf66cb0c6d8127ad0,0x1,0x0 -0x1,0x1,0x52,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x15d7ace2db3651ba26cc0852ffa53be9,0x1,0x0 -0x1,0x1,0x53,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x40a41876d29c7d3d9efea184a2f58712,0x1,0x0 -0x1,0x1,0x54,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1f5ca3dcd416ce988b93b505e473fbc8,0x1,0x0 -0x1,0x1,0x55,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xa510b9a25ba4af91a01cbf2d66496ba7,0x1,0x0 -0x1,0x1,0x56,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2ab07af451260653f5d92e48135636fe,0x1,0x0 -0x1,0x1,0x57,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x6e69bfad773e8c1806b4e4bb128048f9,0x1,0x0 -0x1,0x1,0x58,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1e311797d9d7b0c3b1658f72e16632e3,0x1,0x0 -0x1,0x1,0x59,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x927ad04f742ded7fe801e8df6e137325,0x1,0x0 -0x1,0x1,0x5a,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1d0510803ef7512c7915a6879d460c72,0x1,0x0 -0x1,0x1,0x5b,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x27480a98574d5d306828694e1640ec2b,0x1,0x0 -0x1,0x1,0x5c,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0bb8fd9936c7a8c8f4a3d9ce97735df5,0x1,0x0 -0x1,0x1,0x5d,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x41af0c73696dff5f92c6eb248f949a18,0x1,0x0 -0x1,0x1,0x5e,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x15f8308390c00f0a0e1ebcd08626f1ec,0x1,0x0 -0x1,0x1,0x5f,0x0,0x2,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x57a14cac88cd49f9d0e3caaa20ce36e9,0x1,0x0 -0x1,0x1,0x60,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x152e268cc785bd6c948a88b3091ef9a3,0x1,0x0 -0x1,0x1,0x61,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x708426323c268b89b2a5e02478ccdda6,0x1,0x0 -0x1,0x1,0x62,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2f6d0a4127a8a6f986490f9f8322397c,0x1,0x0 -0x1,0x1,0x63,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x82c9cdc9f0d6ec378eda15ec3dc78b6f,0x1,0x0 -0x1,0x1,0x64,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x21da9702fb1d05b6c0a1007d0b9c160e,0x1,0x0 -0x1,0x1,0x65,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x9d8d0a02fedddd4bce9598f5787c284,0x1,0x0 -0x1,0x1,0x66,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2b46be639fc122126b7e0efbc5398fe8,0x1,0x0 -0x1,0x1,0x67,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x67d9dd3ecc9160db686aaed5bbbd2cbc,0x1,0x0 -0x1,0x1,0x68,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x20d3e1ac646cf95fbf02ad4589eb173d,0x1,0x0 -0x1,0x1,0x69,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x8501b392226c7a7e7818b5781887ef0e,0x1,0x0 -0x1,0x1,0x6a,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xcb19e117479b79a6b64d592612adf5d,0x1,0x0 -0x1,0x1,0x6b,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xaacf84e0e323906338a778d53c6d57d2,0x1,0x0 -0x1,0x1,0x6c,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1dd39eb06e7c88b5e3fea51f0bcefc0d,0x1,0x0 -0x1,0x1,0x6d,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xb11c23cd9f2f7108861555162026536d,0x1,0x0 -0x1,0x1,0x6e,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x290860069e0d24d4363147d4f3d6760a,0x1,0x0 -0x1,0x1,0x6f,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x4fb8917396a450547f84fb7e70c9999f,0x1,0x0 -0x1,0x1,0x70,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2ca828fba83798a17db205631e9903d,0x1,0x0 -0x1,0x1,0x71,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe19924a9209f0fe7c06025b0851fbfe9,0x1,0x0 -0x1,0x1,0x72,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x6f263094fe06ea7acc71974bc64d7dd,0x1,0x0 -0x1,0x1,0x73,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xf167b0ea71dc77d57f39fd46d42db5e4,0x1,0x0 -0x1,0x1,0x74,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x12809c90c9533ba0d7159a9631812b01,0x1,0x0 -0x1,0x1,0x75,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xef3180f718d6e3693eeaf24f05ff6804,0x1,0x0 -0x1,0x1,0x76,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1821399d4a5711ca9d4e6b605b0c6ff2,0x1,0x0 -0x1,0x1,0x77,0x0,0x2,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x89ca237ebf99d460e8d0a9301e74a664,0x1,0x0 -0x1,0x1,0x78,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x152e268cc785bd6c948a88b3091ef9a3,0x0,0x1 -0x1,0x1,0x79,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x708426323c268b89b2a5e02478ccdda6,0x0,0x1 -0x1,0x1,0x7a,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2f6d0a4127a8a6f986490f9f8322397c,0x0,0x1 -0x1,0x1,0x7b,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x82c9cdc9f0d6ec378eda15ec3dc78b6f,0x0,0x1 -0x1,0x1,0x7c,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x21da9702fb1d05b6c0a1007d0b9c160e,0x0,0x1 -0x1,0x1,0x7d,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x9d8d0a02fedddd4bce9598f5787c284,0x0,0x1 -0x1,0x1,0x7e,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2b46be639fc122126b7e0efbc5398fe8,0x0,0x1 -0x1,0x1,0x7f,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x67d9dd3ecc9160db686aaed5bbbd2cbc,0x0,0x1 -0x1,0x1,0x80,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x20d3e1ac646cf95fbf02ad4589eb173d,0x0,0x1 -0x1,0x1,0x81,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x8501b392226c7a7e7818b5781887ef0e,0x0,0x1 -0x1,0x1,0x82,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xcb19e117479b79a6b64d592612adf5d,0x0,0x1 -0x1,0x1,0x83,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xaacf84e0e323906338a778d53c6d57d2,0x0,0x1 -0x1,0x1,0x84,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1dd39eb06e7c88b5e3fea51f0bcefc0d,0x0,0x1 -0x1,0x1,0x85,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xb11c23cd9f2f7108861555162026536d,0x0,0x1 -0x1,0x1,0x86,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x290860069e0d24d4363147d4f3d6760a,0x0,0x1 -0x1,0x1,0x87,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x4fb8917396a450547f84fb7e70c9999f,0x0,0x1 -0x1,0x1,0x88,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x2ca828fba83798a17db205631e9903d,0x0,0x1 -0x1,0x1,0x89,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xe19924a9209f0fe7c06025b0851fbfe9,0x0,0x1 -0x1,0x1,0x8a,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x6f263094fe06ea7acc71974bc64d7dd,0x0,0x1 -0x1,0x1,0x8b,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xf167b0ea71dc77d57f39fd46d42db5e4,0x0,0x1 -0x1,0x1,0x8c,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x12809c90c9533ba0d7159a9631812b01,0x0,0x1 -0x1,0x1,0x8d,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0xef3180f718d6e3693eeaf24f05ff6804,0x0,0x1 -0x1,0x1,0x8e,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1821399d4a5711ca9d4e6b605b0c6ff2,0x0,0x1 -0x1,0x1,0x8f,0x0,0x3,0x3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x89ca237ebf99d460e8d0a9301e74a664,0x0,0x1 -0x1,0x1,0x90,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0c8671a7e8f372087c46b7b82c53c183,0x0,0x1 -0x1,0x1,0x91,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xd09453270e38045cb7372662d4716f8d,0x0,0x1 -0x1,0x1,0x92,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x20dd05e87836797d4507cc8917ed1079,0x0,0x1 -0x1,0x1,0x93,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0xa10fe34dc7536969843e4cbe868a64ac,0x0,0x1 -0x1,0x1,0x94,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x24e48d89873ad5ebcf0f7022c01020b5,0x0,0x1 -0x1,0x1,0x95,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x10458a3dfc798231e6b5d5f17c8c9e1c,0x0,0x1 -0x1,0x1,0x96,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2f3ba4b3c58fd37398ceef826e29c853,0x0,0x1 -0x1,0x1,0x97,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x7048f7fec19180f89f4961bf0b00e9c1,0x0,0x1 -0x1,0x1,0x98,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2ed87dc23279bee95b8caada387b5f5e,0x0,0x1 -0x1,0x1,0x99,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x04fdd666fda2df2aac57457ecfb62014,0x0,0x1 -0x1,0x1,0x9a,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1b77c09a4389d4d50e5b78a8dca80583,0x0,0x1 -0x1,0x1,0x9b,0x0,0x3,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1056618bfe329ac4dcc8ee73ec818284,0x0,0x1 -0x1,0x1,0x9c,0x0,0x0,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1 -0x1,0x1,0x9d,0x0,0x0,0x3,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x1,0x1,0x0 +0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x3,0x0,0x1,0x0 +0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x100fb2006c3a4409ce06f6c2d535564c,0x1,0x0 +0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x92e592aeb426d6c035bb8c0a50202e6d,0x1,0x0 +0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x1275964141a90f3170592ade82174d09,0x1,0x0 +0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xde3cc7f5b79f260f51c143e3268ba06d,0x1,0x0 +0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x2e607689d1161c5cb3d6ed870a5b6f47,0x1,0x0 +0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xb19627c2c51d3d2eb72f81c540ff9f9d,0x1,0x0 +0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x9d2b2eb399326d9cc552e9753afaeab,0x1,0x0 +0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0xbb29985def8b5800f32145223ff61d48,0x1,0x0 +0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x3a5907084b1f9ee93a1fa011b31b383,0x1,0x0 +0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x60b7d50b789fbe32d3733176ffd9d46a,0x1,0x0 +0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x2e8b82b3506125e8b67bb867604a8892,0x1,0x0 +0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x3,0x7b9695a8d131627503a0f63bfe5d0cca,0x1,0x0 +0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x3,0x3b453509cb62c429d8a86ea1cf46897,0x1,0x0 +0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xfc8f75a5184afbfee72be2a8ac39ab6,0x1,0x0 +0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x258732ffd31c5ae816e163e3458108dd,0x1,0x0 +0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x99caaa2e258abab37bb4b1e675e792b4,0x1,0x0 +0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x8dc4617a012a931507f27b285f48a99,0x1,0x0 +0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2c0cc58a0906a3a6ef6e5378a04addf2,0x1,0x0 +0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x185514250c1eaff2fdc813fd31c55772,0x1,0x0 +0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x81316979a26c9fdb191f6abac2a0bcf2,0x1,0x0 +0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x26a52e43327b03b40c3b36854698ed02,0x1,0x0 +0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x572116a2bc8995a07550a2c11b3f1bb3,0x1,0x0 +0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x22a813b81101fa27e07888a4c1ee151b,0x1,0x0 +0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xd5c7de0e174ce72545ed2796a057e0f5,0x1,0x0 +0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x1755fc232224e41b6b375a49c842eed,0x1,0x0 +0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xe4e0cf3cce99d1664c5e8489205e9461,0x1,0x0 +0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2b80c453b72e713a9ee7304f7c598ebe,0x1,0x0 +0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xe28aeb3c386d4c2dfe575197636a578b,0x1,0x0 +0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x225235e07cb0c897a4d26f2f76019f3,0x1,0x0 +0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0xec0c5349a3d4d57e9ab9e9b48f3ba9b3,0x1,0x0 +0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x2864b7882cf2e11ed3bffbff7cb788ca,0x1,0x0 +0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x30f1e0743e45d9900320f9e6890f6817,0x1,0x0 +0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x29293f07fccd8ac29bf0501e823696f,0x1,0x0 +0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x71ba1b75f369441cf66cb0c6d8127ad0,0x1,0x0 +0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x15d7ace2db3651ba26cc0852ffa53be9,0x1,0x0 +0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x3,0x40a41876d29c7d3d9efea184a2f58712,0x1,0x0 +0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x3b453509cb62c429d8a86ea1cf46897,0x1,0x0 +0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xfc8f75a5184afbfee72be2a8ac39ab6,0x1,0x0 +0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x258732ffd31c5ae816e163e3458108dd,0x1,0x0 +0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x99caaa2e258abab37bb4b1e675e792b4,0x1,0x0 +0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x8dc4617a012a931507f27b285f48a99,0x1,0x0 +0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2c0cc58a0906a3a6ef6e5378a04addf2,0x1,0x0 +0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x185514250c1eaff2fdc813fd31c55772,0x1,0x0 +0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x81316979a26c9fdb191f6abac2a0bcf2,0x1,0x0 +0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x26a52e43327b03b40c3b36854698ed02,0x1,0x0 +0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x572116a2bc8995a07550a2c11b3f1bb3,0x1,0x0 +0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x22a813b81101fa27e07888a4c1ee151b,0x1,0x0 +0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xd5c7de0e174ce72545ed2796a057e0f5,0x1,0x0 +0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x1755fc232224e41b6b375a49c842eed,0x1,0x0 +0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xe4e0cf3cce99d1664c5e8489205e9461,0x1,0x0 +0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2b80c453b72e713a9ee7304f7c598ebe,0x1,0x0 +0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xe28aeb3c386d4c2dfe575197636a578b,0x1,0x0 +0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x225235e07cb0c897a4d26f2f76019f3,0x1,0x0 +0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0xec0c5349a3d4d57e9ab9e9b48f3ba9b3,0x1,0x0 +0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x2864b7882cf2e11ed3bffbff7cb788ca,0x1,0x0 +0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x30f1e0743e45d9900320f9e6890f6817,0x1,0x0 +0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x29293f07fccd8ac29bf0501e823696f,0x1,0x0 +0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x71ba1b75f369441cf66cb0c6d8127ad0,0x1,0x0 +0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x15d7ace2db3651ba26cc0852ffa53be9,0x1,0x0 +0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x3,0x40a41876d29c7d3d9efea184a2f58712,0x1,0x0 +0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x1f5ca3dcd416ce988b93b505e473fbc8,0x1,0x0 +0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0xa510b9a25ba4af91a01cbf2d66496ba7,0x1,0x0 +0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x2ab07af451260653f5d92e48135636fe,0x1,0x0 +0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x6e69bfad773e8c1806b4e4bb128048f9,0x1,0x0 +0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x1e311797d9d7b0c3b1658f72e16632e3,0x1,0x0 +0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x927ad04f742ded7fe801e8df6e137325,0x1,0x0 +0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x1d0510803ef7512c7915a6879d460c72,0x1,0x0 +0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x27480a98574d5d306828694e1640ec2b,0x1,0x0 +0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0xbb8fd9936c7a8c8f4a3d9ce97735df5,0x1,0x0 +0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x41af0c73696dff5f92c6eb248f949a18,0x1,0x0 +0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x15f8308390c00f0a0e1ebcd08626f1ec,0x1,0x0 +0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x57a14cac88cd49f9d0e3caaa20ce36e9,0x1,0x0 +0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x2,0x3,0x152e268cc785bd6c948a88b3091ef9a3,0x1,0x0 +0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x708426323c268b89b2a5e02478ccdda6,0x1,0x0 +0x1,0x1,0x62,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x2f6d0a4127a8a6f986490f9f8322397c,0x1,0x0 +0x1,0x1,0x63,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x82c9cdc9f0d6ec378eda15ec3dc78b6f,0x1,0x0 +0x1,0x1,0x64,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x21da9702fb1d05b6c0a1007d0b9c160e,0x1,0x0 +0x1,0x1,0x65,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x9d8d0a02fedddd4bce9598f5787c284,0x1,0x0 +0x1,0x1,0x66,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x2b46be639fc122126b7e0efbc5398fe8,0x1,0x0 +0x1,0x1,0x67,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x67d9dd3ecc9160db686aaed5bbbd2cbc,0x1,0x0 +0x1,0x1,0x68,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x20d3e1ac646cf95fbf02ad4589eb173d,0x1,0x0 +0x1,0x1,0x69,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x8501b392226c7a7e7818b5781887ef0e,0x1,0x0 +0x1,0x1,0x6a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xcb19e117479b79a6b64d592612adf5d,0x1,0x0 +0x1,0x1,0x6b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xaacf84e0e323906338a778d53c6d57d2,0x1,0x0 +0x1,0x1,0x6c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x1dd39eb06e7c88b5e3fea51f0bcefc0d,0x1,0x0 +0x1,0x1,0x6d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xb11c23cd9f2f7108861555162026536d,0x1,0x0 +0x1,0x1,0x6e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x290860069e0d24d4363147d4f3d6760a,0x1,0x0 +0x1,0x1,0x6f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x4fb8917396a450547f84fb7e70c9999f,0x1,0x0 +0x1,0x1,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x2ca828fba83798a17db205631e9903d,0x1,0x0 +0x1,0x1,0x71,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xe19924a9209f0fe7c06025b0851fbfe9,0x1,0x0 +0x1,0x1,0x72,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x6f263094fe06ea7acc71974bc64d7dd,0x1,0x0 +0x1,0x1,0x73,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xf167b0ea71dc77d57f39fd46d42db5e4,0x1,0x0 +0x1,0x1,0x74,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x12809c90c9533ba0d7159a9631812b01,0x1,0x0 +0x1,0x1,0x75,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0xef3180f718d6e3693eeaf24f05ff6804,0x1,0x0 +0x1,0x1,0x76,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x1821399d4a5711ca9d4e6b605b0c6ff2,0x1,0x0 +0x1,0x1,0x77,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x3,0x89ca237ebf99d460e8d0a9301e74a664,0x1,0x0 +0x1,0x1,0x78,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x152e268cc785bd6c948a88b3091ef9a3,0x0,0x1 +0x1,0x1,0x79,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x708426323c268b89b2a5e02478ccdda6,0x0,0x1 +0x1,0x1,0x7a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x2f6d0a4127a8a6f986490f9f8322397c,0x0,0x1 +0x1,0x1,0x7b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x82c9cdc9f0d6ec378eda15ec3dc78b6f,0x0,0x1 +0x1,0x1,0x7c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x21da9702fb1d05b6c0a1007d0b9c160e,0x0,0x1 +0x1,0x1,0x7d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x9d8d0a02fedddd4bce9598f5787c284,0x0,0x1 +0x1,0x1,0x7e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x2b46be639fc122126b7e0efbc5398fe8,0x0,0x1 +0x1,0x1,0x7f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x67d9dd3ecc9160db686aaed5bbbd2cbc,0x0,0x1 +0x1,0x1,0x80,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x20d3e1ac646cf95fbf02ad4589eb173d,0x0,0x1 +0x1,0x1,0x81,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x8501b392226c7a7e7818b5781887ef0e,0x0,0x1 +0x1,0x1,0x82,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xcb19e117479b79a6b64d592612adf5d,0x0,0x1 +0x1,0x1,0x83,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xaacf84e0e323906338a778d53c6d57d2,0x0,0x1 +0x1,0x1,0x84,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x1dd39eb06e7c88b5e3fea51f0bcefc0d,0x0,0x1 +0x1,0x1,0x85,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xb11c23cd9f2f7108861555162026536d,0x0,0x1 +0x1,0x1,0x86,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x290860069e0d24d4363147d4f3d6760a,0x0,0x1 +0x1,0x1,0x87,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x4fb8917396a450547f84fb7e70c9999f,0x0,0x1 +0x1,0x1,0x88,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x2ca828fba83798a17db205631e9903d,0x0,0x1 +0x1,0x1,0x89,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xe19924a9209f0fe7c06025b0851fbfe9,0x0,0x1 +0x1,0x1,0x8a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x6f263094fe06ea7acc71974bc64d7dd,0x0,0x1 +0x1,0x1,0x8b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xf167b0ea71dc77d57f39fd46d42db5e4,0x0,0x1 +0x1,0x1,0x8c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x12809c90c9533ba0d7159a9631812b01,0x0,0x1 +0x1,0x1,0x8d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0xef3180f718d6e3693eeaf24f05ff6804,0x0,0x1 +0x1,0x1,0x8e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x1821399d4a5711ca9d4e6b605b0c6ff2,0x0,0x1 +0x1,0x1,0x8f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x3,0x3,0x89ca237ebf99d460e8d0a9301e74a664,0x0,0x1 +0x1,0x1,0x90,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xc8671a7e8f372087c46b7b82c53c183,0x0,0x1 +0x1,0x1,0x91,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xd09453270e38045cb7372662d4716f8d,0x0,0x1 +0x1,0x1,0x92,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x20dd05e87836797d4507cc8917ed1079,0x0,0x1 +0x1,0x1,0x93,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0xa10fe34dc7536969843e4cbe868a64ac,0x0,0x1 +0x1,0x1,0x94,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x24e48d89873ad5ebcf0f7022c01020b5,0x0,0x1 +0x1,0x1,0x95,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x10458a3dfc798231e6b5d5f17c8c9e1c,0x0,0x1 +0x1,0x1,0x96,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x2f3ba4b3c58fd37398ceef826e29c853,0x0,0x1 +0x1,0x1,0x97,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x7048f7fec19180f89f4961bf0b00e9c1,0x0,0x1 +0x1,0x1,0x98,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x2ed87dc23279bee95b8caada387b5f5e,0x0,0x1 +0x1,0x1,0x99,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x4fdd666fda2df2aac57457ecfb62014,0x0,0x1 +0x1,0x1,0x9a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x1b77c09a4389d4d50e5b78a8dca80583,0x0,0x1 +0x1,0x1,0x9b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3,0x3,0x1056618bfe329ac4dcc8ee73ec818284,0x0,0x1 +0x1,0x1,0x9c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x3,0x0,0x0,0x1 +0x1,0x1,0x9d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x3,0x1,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/ecpair_two_pairings_module.csv b/prover/zkevm/prover/ecpair/testdata/ecpair_two_pairings_module.csv index 9a5b8368f..1ac1becf5 100644 --- a/prover/zkevm/prover/ecpair/testdata/ecpair_two_pairings_module.csv +++ b/prover/zkevm/prover/ecpair/testdata/ecpair_two_pairings_module.csv @@ -1,257 +1,257 @@ -ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT -0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 -0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13364879816394e38a2d72bde23bda93,0x1,0x0 -0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xcd39885c6bfdedbc45e6bafcfc8fa685,0x1,0x0 -0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0e0e4c9d03746d287b341d52461946a1,0x1,0x0 -0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xc865002c35ba9bd6b789fc26a526d121,0x1,0x0 -0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0e82be8514331e947408a3a27a54d580,0x1,0x0 -0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 -0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0f89c9a7bb2eb9418d2d89310306196d,0x1,0x0 -0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 -0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 -0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 -0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 -0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 -0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x0,0x1,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x1,0x0 -0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x4c95627608bdbb0235762c7048400f93,0x1,0x0 -0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x1,0x0 -0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x1,0x0 -0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x1,0x0 -0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x1,0x0 -0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2b45ce688738a571621b63dba9880856,0x1,0x0 -0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x1,0x0 -0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x653b8af047158278411df902874a82a,0x1,0x0 -0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x1,0x0 -0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1373a842ceca78f2ae076804f168559c,0x1,0x0 -0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x1,0x0 -0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x1,0x0 -0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2f12833bfd8a1711d7947461776699df,0x1,0x0 -0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x1,0x0 -0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x1,0x0 -0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x1,0x0 -0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x1,0x0 -0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x22af99c52785193aa8920826c0d96380,0x1,0x0 -0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x1,0x0 -0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x1,0x0 -0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x217f227c48e2682613693d3afb8231e,0x1,0x0 -0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x5641ef4d251e87484afef7cae876258,0x1,0x0 -0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x1,0x0 -0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x0,0x1 -0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x4c95627608bdbb0235762c7048400f93,0x0,0x1 -0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x0,0x1 -0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x0,0x1 -0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x0,0x1 -0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x0,0x1 -0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2b45ce688738a571621b63dba9880856,0x0,0x1 -0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x0,0x1 -0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x653b8af047158278411df902874a82a,0x0,0x1 -0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x0,0x1 -0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1373a842ceca78f2ae076804f168559c,0x0,0x1 -0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x0,0x1 -0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x0,0x1 -0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2f12833bfd8a1711d7947461776699df,0x0,0x1 -0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x0,0x1 -0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x0,0x1 -0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x0,0x1 -0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x0,0x1 -0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x22af99c52785193aa8920826c0d96380,0x0,0x1 -0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x0,0x1 -0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x0,0x1 -0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x217f227c48e2682613693d3afb8231e,0x0,0x1 -0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x5641ef4d251e87484afef7cae876258,0x0,0x1 -0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x0,0x1 -0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x0b9624a62e115247146d4643e8d4daf0,0x0,0x1 -0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 -0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 -0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 -0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2977858b214a3cb43fa4024976dd1675,0x0,0x1 -0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9b1bf5367e6318da3545e697b9931671,0x0,0x1 -0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x06fcfd4b9ca03fb145ff273e480efda3,0x0,0x1 -0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc8a7aef64882efcbd8920b4458e1ef3d,0x0,0x1 -0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x281508326108309778f9cdf9c39a4c4d,0x0,0x1 -0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc90a405c0cfbfd5d20fec4e47acce66f,0x0,0x1 -0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10d24b6f0b87c1e3f78b80b967bac765,0x0,0x1 -0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x763f38c53a4377e9a97e2761758a92f1,0x0,0x1 -0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x0,0x1 -0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x1,0x0,0x1 -0x1,0x1,0x0,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x1,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 -0x1,0x1,0x2,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x3,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x4,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x5,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x6,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x7,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x8,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x9,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xa,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xb,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xc,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xd,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xe,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0xf,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x10,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x11,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x12,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x13,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x14,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x15,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x16,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x17,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 -0x1,0x1,0x18,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0b9624a62e115247146d4643e8d4daf0,0x1,0x0 -0x1,0x1,0x19,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x1,0x0 -0x1,0x1,0x1a,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13aabde6da726f8fc6fcc33f7156267a,0x1,0x0 -0x1,0x1,0x1b,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x7a7f3ccb21010e7a2e2f3e67e154cc63,0x1,0x0 -0x1,0x1,0x1c,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0e82be8514331e947408a3a27a54d580,0x1,0x0 -0x1,0x1,0x1d,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 -0x1,0x1,0x1e,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x0f89c9a7bb2eb9418d2d89310306196d,0x1,0x0 -0x1,0x1,0x1f,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 -0x1,0x1,0x20,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 -0x1,0x1,0x21,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 -0x1,0x1,0x22,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 -0x1,0x1,0x23,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 -0x1,0x1,0x24,0x1,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x0,0x1,0x2,0x1d986c0862b80ece8d231a383cb73943,0x1,0x0 -0x1,0x1,0x25,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x3dbbc8770d85f0584f6dc86875624cea,0x1,0x0 -0x1,0x1,0x26,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x3c51f8072e2a8a07f6a06f5088e9ab2,0x1,0x0 -0x1,0x1,0x27,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xdbc106c833cd19dffcb9e1073ec1805c,0x1,0x0 -0x1,0x1,0x28,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x24ef30331e45aacaa2c0db503198129d,0x1,0x0 -0x1,0x1,0x29,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x698da943542b3b26946e11a08dc6144,0x1,0x0 -0x1,0x1,0x2a,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x229bffeec7cae24f754f3353492e06b7,0x1,0x0 -0x1,0x1,0x2b,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x38b7714ed0c32e48e7afaf62a4efa110,0x1,0x0 -0x1,0x1,0x2c,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x10bc1cc6e37e745faa3ed918cc36edc9,0x1,0x0 -0x1,0x1,0x2d,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x21edc644688a0705476f795d39af8b66,0x1,0x0 -0x1,0x1,0x2e,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2adcf726eec4f68995c3207f92aea375,0x1,0x0 -0x1,0x1,0x2f,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xfcd13ed4fe7b43ad615735680a4485e7,0x1,0x0 -0x1,0x1,0x30,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1f0e7e775eefc2a5672928b4efc2c508,0x1,0x0 -0x1,0x1,0x31,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xd1b9522023a1105027220223481cad5e,0x1,0x0 -0x1,0x1,0x32,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x241401f805f060cf5e55b76d0a1d9703,0x1,0x0 -0x1,0x1,0x33,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x623d8250a84288f9a9d6b32e4a79ab25,0x1,0x0 -0x1,0x1,0x34,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2aefa1de34a54b19496ac527550823fc,0x1,0x0 -0x1,0x1,0x35,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x4b742adbe4a5e836b5a4c3c601d721be,0x1,0x0 -0x1,0x1,0x36,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x2feeac4095267db703b602ff985fc423,0x1,0x0 -0x1,0x1,0x37,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x235e6c11ea98a28c6a34a72c6ee2ddc,0x1,0x0 -0x1,0x1,0x38,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x1d75dcc79d6ddd435182ca5de99635c0,0x1,0x0 -0x1,0x1,0x39,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x212f3e7e80bdfa698ac725005f8dae63,0x1,0x0 -0x1,0x1,0x3a,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0x5aeef8c0490c8356ffdd4913155eb21,0x1,0x0 -0x1,0x1,0x3b,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x2,0xd66a1367a4c8c3f6c041b4227c1bf352,0x1,0x0 -0x1,0x1,0x3c,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1d986c0862b80ece8d231a383cb73943,0x0,0x1 -0x1,0x1,0x3d,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x3dbbc8770d85f0584f6dc86875624cea,0x0,0x1 -0x1,0x1,0x3e,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x3c51f8072e2a8a07f6a06f5088e9ab2,0x0,0x1 -0x1,0x1,0x3f,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xdbc106c833cd19dffcb9e1073ec1805c,0x0,0x1 -0x1,0x1,0x40,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x24ef30331e45aacaa2c0db503198129d,0x0,0x1 -0x1,0x1,0x41,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x698da943542b3b26946e11a08dc6144,0x0,0x1 -0x1,0x1,0x42,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x229bffeec7cae24f754f3353492e06b7,0x0,0x1 -0x1,0x1,0x43,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x38b7714ed0c32e48e7afaf62a4efa110,0x0,0x1 -0x1,0x1,0x44,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x10bc1cc6e37e745faa3ed918cc36edc9,0x0,0x1 -0x1,0x1,0x45,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x21edc644688a0705476f795d39af8b66,0x0,0x1 -0x1,0x1,0x46,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2adcf726eec4f68995c3207f92aea375,0x0,0x1 -0x1,0x1,0x47,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xfcd13ed4fe7b43ad615735680a4485e7,0x0,0x1 -0x1,0x1,0x48,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1f0e7e775eefc2a5672928b4efc2c508,0x0,0x1 -0x1,0x1,0x49,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xd1b9522023a1105027220223481cad5e,0x0,0x1 -0x1,0x1,0x4a,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x241401f805f060cf5e55b76d0a1d9703,0x0,0x1 -0x1,0x1,0x4b,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x623d8250a84288f9a9d6b32e4a79ab25,0x0,0x1 -0x1,0x1,0x4c,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2aefa1de34a54b19496ac527550823fc,0x0,0x1 -0x1,0x1,0x4d,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x4b742adbe4a5e836b5a4c3c601d721be,0x0,0x1 -0x1,0x1,0x4e,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x2feeac4095267db703b602ff985fc423,0x0,0x1 -0x1,0x1,0x4f,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x235e6c11ea98a28c6a34a72c6ee2ddc,0x0,0x1 -0x1,0x1,0x50,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x1d75dcc79d6ddd435182ca5de99635c0,0x0,0x1 -0x1,0x1,0x51,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x212f3e7e80bdfa698ac725005f8dae63,0x0,0x1 -0x1,0x1,0x52,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0x5aeef8c0490c8356ffdd4913155eb21,0x0,0x1 -0x1,0x1,0x53,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x0,0x2,0x2,0xd66a1367a4c8c3f6c041b4227c1bf352,0x0,0x1 -0x1,0x1,0x54,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x0b9624a62e115247146d4643e8d4daf0,0x0,0x1 -0x1,0x1,0x55,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 -0x1,0x1,0x56,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 -0x1,0x1,0x57,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 -0x1,0x1,0x58,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x0e82be8514331e947408a3a27a54d580,0x0,0x1 -0x1,0x1,0x59,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x0,0x1 -0x1,0x1,0x5a,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x0f89c9a7bb2eb9418d2d89310306196d,0x0,0x1 -0x1,0x1,0x5b,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x0,0x1 -0x1,0x1,0x5c,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x0,0x1 -0x1,0x1,0x5d,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x0,0x1 -0x1,0x1,0x5e,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x11497987c563ade267b3bdfcc9c04022,0x0,0x1 -0x1,0x1,0x5f,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x0,0x1 -0x1,0x1,0x60,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x0,0x1 -0x1,0x1,0x61,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x2,0x1,0x0,0x1 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +ECPAIR_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACTIVE,ECPAIR_UNALIGNED_PAIRING_DATA_INDEX,ECPAIR_UNALIGNED_PAIRING_DATA_INSTANCE_ID,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_INSTANCE,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_INIT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_PREV_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_PREV,ECPAIR_UNALIGNED_PAIRING_DATA_IS_FIRST_LINE_OF_CURR_ACC,ECPAIR_UNALIGNED_PAIRING_DATA_IS_ACCUMULATOR_CURR,ECPAIR_UNALIGNED_PAIRING_DATA_IS_RESULT,ECPAIR_UNALIGNED_PAIRING_DATA_IS_COMPUTED,ECPAIR_UNALIGNED_PAIRING_DATA_IS_PULLING,ECPAIR_UNALIGNED_PAIRING_DATA_PAIR_ID,ECPAIR_UNALIGNED_PAIRING_DATA_TOTAL_PAIRS,ECPAIR_UNALIGNED_PAIRING_DATA_LIMB,ECPAIR_UNALIGNED_PAIRING_DATA_TO_MILLER_LOOP_CIRCUIT,ECPAIR_UNALIGNED_PAIRING_DATA_TO_FINAL_EXP_CIRCUIT +0x1,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x1,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 +0x1,0x1,0x2,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x4,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x5,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x6,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x7,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x8,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x9,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xa,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xb,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xc,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xd,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xe,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xf,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x10,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x11,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x13,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x14,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x15,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x17,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13364879816394e38a2d72bde23bda93,0x1,0x0 +0x1,0x1,0x19,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xcd39885c6bfdedbc45e6bafcfc8fa685,0x1,0x0 +0x1,0x1,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe0e4c9d03746d287b341d52461946a1,0x1,0x0 +0x1,0x1,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xc865002c35ba9bd6b789fc26a526d121,0x1,0x0 +0x1,0x1,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe82be8514331e947408a3a27a54d580,0x1,0x0 +0x1,0x1,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 +0x1,0x1,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf89c9a7bb2eb9418d2d89310306196d,0x1,0x0 +0x1,0x1,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 +0x1,0x1,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 +0x1,0x1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 +0x1,0x1,0x22,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 +0x1,0x1,0x23,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 +0x1,0x1,0x24,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x1,0x0 +0x1,0x1,0x25,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x4c95627608bdbb0235762c7048400f93,0x1,0x0 +0x1,0x1,0x26,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x1,0x0 +0x1,0x1,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x1,0x0 +0x1,0x1,0x28,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x1,0x0 +0x1,0x1,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x1,0x0 +0x1,0x1,0x2a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2b45ce688738a571621b63dba9880856,0x1,0x0 +0x1,0x1,0x2b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x1,0x0 +0x1,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x653b8af047158278411df902874a82a,0x1,0x0 +0x1,0x1,0x2d,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x1,0x0 +0x1,0x1,0x2e,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1373a842ceca78f2ae076804f168559c,0x1,0x0 +0x1,0x1,0x2f,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x1,0x0 +0x1,0x1,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x1,0x0 +0x1,0x1,0x31,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2f12833bfd8a1711d7947461776699df,0x1,0x0 +0x1,0x1,0x32,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x1,0x0 +0x1,0x1,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x1,0x0 +0x1,0x1,0x34,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x1,0x0 +0x1,0x1,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x1,0x0 +0x1,0x1,0x36,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x22af99c52785193aa8920826c0d96380,0x1,0x0 +0x1,0x1,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x1,0x0 +0x1,0x1,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x1,0x0 +0x1,0x1,0x39,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x217f227c48e2682613693d3afb8231e,0x1,0x0 +0x1,0x1,0x3a,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x5641ef4d251e87484afef7cae876258,0x1,0x0 +0x1,0x1,0x3b,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x1,0x0 +0x1,0x1,0x3c,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1fc57e97fc7f579bbc2ba220d9b10d46,0x0,0x1 +0x1,0x1,0x3d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x4c95627608bdbb0235762c7048400f93,0x0,0x1 +0x1,0x1,0x3e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2b4305dcdfcf51d41a169cbe7b4e89d4,0x0,0x1 +0x1,0x1,0x3f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x59f4578a51cdbe050925fc0b9312aa86,0x0,0x1 +0x1,0x1,0x40,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1133d6c9d0cacf4e7cd03b8ae8654f3b,0x0,0x1 +0x1,0x1,0x41,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xfbfc80323c91c70825d4aa8accfd77b8,0x0,0x1 +0x1,0x1,0x42,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2b45ce688738a571621b63dba9880856,0x0,0x1 +0x1,0x1,0x43,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x9dd4ff917cefc257d7cfe3ea571e206a,0x0,0x1 +0x1,0x1,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x653b8af047158278411df902874a82a,0x0,0x1 +0x1,0x1,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x401206aafb12aa7c2d704f51f115d8c2,0x0,0x1 +0x1,0x1,0x46,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1373a842ceca78f2ae076804f168559c,0x0,0x1 +0x1,0x1,0x47,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1781cbb3451085c1166bdadbc7c92688,0x0,0x1 +0x1,0x1,0x48,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2c8c1f272129cf6b0866ad1d8f3ac818,0x0,0x1 +0x1,0x1,0x49,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2f12833bfd8a1711d7947461776699df,0x0,0x1 +0x1,0x1,0x4a,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x16e10599cfcd3537d808d197ce64c2c5,0x0,0x1 +0x1,0x1,0x4b,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xdaf005b2c0be94b08c52e30acfb098e,0x0,0x1 +0x1,0x1,0x4c,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd5d04cfad426760d9019d3d15b98aee,0x0,0x1 +0x1,0x1,0x4d,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x8c37f28a10bb3cfa2f3971505c77db23,0x0,0x1 +0x1,0x1,0x4e,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x22af99c52785193aa8920826c0d96380,0x0,0x1 +0x1,0x1,0x4f,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xe8213976bbbab27922a2cd8c8fe4adeb,0x0,0x1 +0x1,0x1,0x50,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xa6356a8a0caaec7d1a28661b990a20b,0x0,0x1 +0x1,0x1,0x51,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x217f227c48e2682613693d3afb8231e,0x0,0x1 +0x1,0x1,0x52,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x5641ef4d251e87484afef7cae876258,0x0,0x1 +0x1,0x1,0x53,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xc199d8553a68a9408d2603bd9ff29c36,0x0,0x1 +0x1,0x1,0x54,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xb9624a62e115247146d4643e8d4daf0,0x0,0x1 +0x1,0x1,0x55,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 +0x1,0x1,0x56,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 +0x1,0x1,0x57,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 +0x1,0x1,0x58,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x2977858b214a3cb43fa4024976dd1675,0x0,0x1 +0x1,0x1,0x59,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9b1bf5367e6318da3545e697b9931671,0x0,0x1 +0x1,0x1,0x5a,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x6fcfd4b9ca03fb145ff273e480efda3,0x0,0x1 +0x1,0x1,0x5b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc8a7aef64882efcbd8920b4458e1ef3d,0x0,0x1 +0x1,0x1,0x5c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x281508326108309778f9cdf9c39a4c4d,0x0,0x1 +0x1,0x1,0x5d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xc90a405c0cfbfd5d20fec4e47acce66f,0x0,0x1 +0x1,0x1,0x5e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10d24b6f0b87c1e3f78b80b967bac765,0x0,0x1 +0x1,0x1,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x763f38c53a4377e9a97e2761758a92f1,0x0,0x1 +0x1,0x1,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x1,0x1,0x61,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x1,0x0,0x1 +0x1,0x1,0x0,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x1,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x1,0x1,0x0 +0x1,0x1,0x2,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x3,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x4,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x5,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x6,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x7,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x8,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x9,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xa,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xb,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xc,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xd,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xe,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0xf,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x10,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x11,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x12,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x13,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x14,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x15,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x16,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x17,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x2,0x0,0x1,0x0 +0x1,0x1,0x18,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xb9624a62e115247146d4643e8d4daf0,0x1,0x0 +0x1,0x1,0x19,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x1,0x0 +0x1,0x1,0x1a,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x13aabde6da726f8fc6fcc33f7156267a,0x1,0x0 +0x1,0x1,0x1b,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x7a7f3ccb21010e7a2e2f3e67e154cc63,0x1,0x0 +0x1,0x1,0x1c,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xe82be8514331e947408a3a27a54d580,0x1,0x0 +0x1,0x1,0x1d,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x1,0x0 +0x1,0x1,0x1e,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf89c9a7bb2eb9418d2d89310306196d,0x1,0x0 +0x1,0x1,0x1f,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x1,0x0 +0x1,0x1,0x20,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x1,0x0 +0x1,0x1,0x21,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x1,0x0 +0x1,0x1,0x22,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x11497987c563ade267b3bdfcc9c04022,0x1,0x0 +0x1,0x1,0x23,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x1,0x0 +0x1,0x1,0x24,0x1,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x1,0x0,0x1,0x2,0x1d986c0862b80ece8d231a383cb73943,0x1,0x0 +0x1,0x1,0x25,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x3dbbc8770d85f0584f6dc86875624cea,0x1,0x0 +0x1,0x1,0x26,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x3c51f8072e2a8a07f6a06f5088e9ab2,0x1,0x0 +0x1,0x1,0x27,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xdbc106c833cd19dffcb9e1073ec1805c,0x1,0x0 +0x1,0x1,0x28,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x24ef30331e45aacaa2c0db503198129d,0x1,0x0 +0x1,0x1,0x29,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x698da943542b3b26946e11a08dc6144,0x1,0x0 +0x1,0x1,0x2a,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x229bffeec7cae24f754f3353492e06b7,0x1,0x0 +0x1,0x1,0x2b,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x38b7714ed0c32e48e7afaf62a4efa110,0x1,0x0 +0x1,0x1,0x2c,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x10bc1cc6e37e745faa3ed918cc36edc9,0x1,0x0 +0x1,0x1,0x2d,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x21edc644688a0705476f795d39af8b66,0x1,0x0 +0x1,0x1,0x2e,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2adcf726eec4f68995c3207f92aea375,0x1,0x0 +0x1,0x1,0x2f,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xfcd13ed4fe7b43ad615735680a4485e7,0x1,0x0 +0x1,0x1,0x30,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1f0e7e775eefc2a5672928b4efc2c508,0x1,0x0 +0x1,0x1,0x31,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd1b9522023a1105027220223481cad5e,0x1,0x0 +0x1,0x1,0x32,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x241401f805f060cf5e55b76d0a1d9703,0x1,0x0 +0x1,0x1,0x33,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x623d8250a84288f9a9d6b32e4a79ab25,0x1,0x0 +0x1,0x1,0x34,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2aefa1de34a54b19496ac527550823fc,0x1,0x0 +0x1,0x1,0x35,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x4b742adbe4a5e836b5a4c3c601d721be,0x1,0x0 +0x1,0x1,0x36,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x2feeac4095267db703b602ff985fc423,0x1,0x0 +0x1,0x1,0x37,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x235e6c11ea98a28c6a34a72c6ee2ddc,0x1,0x0 +0x1,0x1,0x38,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x1d75dcc79d6ddd435182ca5de99635c0,0x1,0x0 +0x1,0x1,0x39,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x212f3e7e80bdfa698ac725005f8dae63,0x1,0x0 +0x1,0x1,0x3a,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0x5aeef8c0490c8356ffdd4913155eb21,0x1,0x0 +0x1,0x1,0x3b,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x2,0xd66a1367a4c8c3f6c041b4227c1bf352,0x1,0x0 +0x1,0x1,0x3c,0x1,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1d986c0862b80ece8d231a383cb73943,0x0,0x1 +0x1,0x1,0x3d,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x3dbbc8770d85f0584f6dc86875624cea,0x0,0x1 +0x1,0x1,0x3e,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x3c51f8072e2a8a07f6a06f5088e9ab2,0x0,0x1 +0x1,0x1,0x3f,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xdbc106c833cd19dffcb9e1073ec1805c,0x0,0x1 +0x1,0x1,0x40,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x24ef30331e45aacaa2c0db503198129d,0x0,0x1 +0x1,0x1,0x41,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x698da943542b3b26946e11a08dc6144,0x0,0x1 +0x1,0x1,0x42,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x229bffeec7cae24f754f3353492e06b7,0x0,0x1 +0x1,0x1,0x43,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x38b7714ed0c32e48e7afaf62a4efa110,0x0,0x1 +0x1,0x1,0x44,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x10bc1cc6e37e745faa3ed918cc36edc9,0x0,0x1 +0x1,0x1,0x45,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x21edc644688a0705476f795d39af8b66,0x0,0x1 +0x1,0x1,0x46,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2adcf726eec4f68995c3207f92aea375,0x0,0x1 +0x1,0x1,0x47,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xfcd13ed4fe7b43ad615735680a4485e7,0x0,0x1 +0x1,0x1,0x48,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1f0e7e775eefc2a5672928b4efc2c508,0x0,0x1 +0x1,0x1,0x49,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd1b9522023a1105027220223481cad5e,0x0,0x1 +0x1,0x1,0x4a,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x241401f805f060cf5e55b76d0a1d9703,0x0,0x1 +0x1,0x1,0x4b,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x623d8250a84288f9a9d6b32e4a79ab25,0x0,0x1 +0x1,0x1,0x4c,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2aefa1de34a54b19496ac527550823fc,0x0,0x1 +0x1,0x1,0x4d,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x4b742adbe4a5e836b5a4c3c601d721be,0x0,0x1 +0x1,0x1,0x4e,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x2feeac4095267db703b602ff985fc423,0x0,0x1 +0x1,0x1,0x4f,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x235e6c11ea98a28c6a34a72c6ee2ddc,0x0,0x1 +0x1,0x1,0x50,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x1d75dcc79d6ddd435182ca5de99635c0,0x0,0x1 +0x1,0x1,0x51,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x212f3e7e80bdfa698ac725005f8dae63,0x0,0x1 +0x1,0x1,0x52,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0x5aeef8c0490c8356ffdd4913155eb21,0x0,0x1 +0x1,0x1,0x53,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x2,0x2,0xd66a1367a4c8c3f6c041b4227c1bf352,0x0,0x1 +0x1,0x1,0x54,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xb9624a62e115247146d4643e8d4daf0,0x0,0x1 +0x1,0x1,0x55,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x7ff180000fcf9f02c84cc5692b2c0526,0x0,0x1 +0x1,0x1,0x56,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1cb9908c06bf3099f1538277102b31e3,0x0,0x1 +0x1,0x1,0x57,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x1d022dc64770bc130df14daef72830e4,0x0,0x1 +0x1,0x1,0x58,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xe82be8514331e947408a3a27a54d580,0x0,0x1 +0x1,0x1,0x59,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x9866db37d74db5abc7de8f0d3d0f7ee3,0x0,0x1 +0x1,0x1,0x5a,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xf89c9a7bb2eb9418d2d89310306196d,0x0,0x1 +0x1,0x1,0x5b,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xf1ae8d9de0173f3e1151487bb5157cd7,0x0,0x1 +0x1,0x1,0x5c,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x10b30b9925aace81dcec2ccce77c3eea,0x0,0x1 +0x1,0x1,0x5d,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0xa949c366d7cd71a6a6748bcdd996b762,0x0,0x1 +0x1,0x1,0x5e,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x11497987c563ade267b3bdfcc9c04022,0x0,0x1 +0x1,0x1,0x5f,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x2,0x3e25664c3bcdd28858b1daa7ac249034,0x0,0x1 +0x1,0x1,0x60,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x0,0x0,0x1 +0x1,0x1,0x61,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x2,0x1,0x0,0x1 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 diff --git a/prover/zkevm/prover/ecpair/testdata/testdata_generator_manual_test.go b/prover/zkevm/prover/ecpair/testdata/testdata_generator_manual_test.go new file mode 100644 index 000000000..7f0eb91a3 --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/testdata_generator_manual_test.go @@ -0,0 +1,765 @@ +package testdata + +import ( + "crypto/rand" + "fmt" + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/test" +) + +func TestPairingCheckData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + _, _, p, q := bn254.Generators() + + var u, v fr.Element + u.SetInt64(1234) + v.SetInt64(5678) + // u.SetRandom() + // v.SetRandom() + + p.ScalarMultiplication(&p, u.BigInt(new(big.Int))) + q.ScalarMultiplication(&q, v.BigInt(new(big.Int))) + + var p1, p2 bn254.G1Affine + var q1, q2 bn254.G2Affine + p1.Double(&p) + p2.Neg(&p) + q1.Set(&q) + q2.Double(&q) + + ok, err := bn254.PairingCheck([]bn254.G1Affine{p1, p2}, []bn254.G2Affine{q1, q2}) + assert.NoError(err) + assert.True(ok) + + px := p1.X.Bytes() + py := p1.Y.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n", px[0:16], px[16:32], py[0:16], py[16:32]) + qxre := q1.X.A0.Bytes() + qxim := q1.X.A1.Bytes() + qyre := q1.Y.A0.Bytes() + qyim := q1.Y.A1.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n", + qxre[0:16], qxre[16:32], qxim[0:16], qxim[16:32], qyre[0:16], qyre[16:32], qyim[0:16], qyim[16:32]) + + p2x := p2.X.Bytes() + p2y := p2.Y.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n", p2x[0:16], p2x[16:32], p2y[0:16], p2y[16:32]) + q2xre := q2.X.A0.Bytes() + q2xim := q2.X.A1.Bytes() + q2yre := q2.Y.A0.Bytes() + q2yim := q2.Y.A1.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n", + q2xre[0:16], q2xre[16:32], q2xim[0:16], q2xim[16:32], q2yre[0:16], q2yre[16:32], q2yim[0:16], q2yim[16:32]) +} + +func TestPairingFailingCheckData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + var p2 bn254.G1Affine + var q2 bn254.G2Affine + _, _, p, q := bn254.Generators() + + var u, v fr.Element + u.SetInt64(6235) + v.SetInt64(76235) + // u.SetRandom() + // v.SetRandom() + + p.ScalarMultiplication(&p, big.NewInt(12390)) + q.ScalarMultiplication(&q, big.NewInt(12489)) + p2.ScalarMultiplicationBase(big.NewInt(79975)) + q2.ScalarMultiplicationBase(big.NewInt(48916)) + + ok, err := bn254.PairingCheck([]bn254.G1Affine{p, p2}, []bn254.G2Affine{q, q2}) + assert.NoError(err) + assert.False(ok) + + px := p.X.Bytes() + py := p.Y.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n", px[0:16], px[16:32], py[0:16], py[16:32]) + qxre := q.X.A0.Bytes() + qxim := q.X.A1.Bytes() + qyre := q.Y.A0.Bytes() + qyim := q.Y.A1.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n", + qxre[0:16], qxre[16:32], qxim[0:16], qxim[16:32], qyre[0:16], qyre[16:32], qyim[0:16], qyim[16:32]) + + p2x := p2.X.Bytes() + p2y := p2.Y.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n", p2x[0:16], p2x[16:32], p2y[0:16], p2y[16:32]) + q2xre := q2.X.A0.Bytes() + q2xim := q2.X.A1.Bytes() + q2yre := q2.Y.A0.Bytes() + q2yim := q2.Y.A1.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n", + q2xre[0:16], q2xre[16:32], q2xim[0:16], q2xim[16:32], q2yre[0:16], q2yre[16:32], q2yim[0:16], q2yim[16:32]) +} + +func TestAddData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + for i := 0; i < 4; i++ { + var p, q bn254.G1Affine + s1, err := rand.Int(rand.Reader, fr.Modulus()) + if err != nil { + t.Fatal(err) + } + s2, err := rand.Int(rand.Reader, fr.Modulus()) + if err != nil { + t.Fatal(err) + } + // s1 = big.NewInt(0) + // s2 = big.NewInt(0) + p.ScalarMultiplicationBase(s1) + q.ScalarMultiplicationBase(s2) + var r bn254.G1Affine + r.Add(&p, &q) + + pxb := p.X.Bytes() + pyb := p.Y.Bytes() + qxb := q.X.Bytes() + qyb := q.Y.Bytes() + rxb := r.X.Bytes() + ryb := r.Y.Bytes() + fmt.Println(i) + fmt.Printf("PXHI=0x%x\nPXLO=0x%x\nPYHI=0x%x\nPYLO=0x%x\nQXHI=0x%x\nQXLO=0x%x\nQYHI=0x%x\nQYLO=0x%x\nQXHI=0x%x\nQXLO=0x%x\nRYHI=0x%x\nRYLO=0x%x\n", + pxb[0:16], pxb[16:32], + pyb[0:16], pyb[16:32], + qxb[0:16], qxb[16:32], + qyb[0:16], qyb[16:32], + rxb[0:16], rxb[16:32], + ryb[0:16], ryb[16:32], + ) + } +} + +// small points +// malformed +// large coordinates +// coordinates in range but not satisfying the curve equation +// well-formed +// just a few points of the C1 curve drawn at random +// large points +// malformed +// large coordinates +// small coordinates but not satisfying the curve equation +// small coordinates, satisfying the curve equation but not belonging to the G2 subgroup +// well-formed +// just a few points on G2 drawn at random + +func TestDataSmallMalformedLarge(t *testing.T) { + t.Skip("skipping test, called manually when needed") + fmt.Println("fp = ", fp.Modulus()) + _, _, p, _ := bn254.Generators() + // var px [32]byte + // p.X.BigInt(new(big.Int)).FillBytes(px[:]) + // pb := p.X.Bytes() + // if !bytes.Equal(pb[:], px[:]) { + // t.Fatal("failed to marshal point") + // } + + // bound 2^256-modulus + bound := new(big.Int).Lsh(big.NewInt(1), 256) + bound.Sub(bound, fp.Modulus()) + + var buf [32]byte + + // test 1, X large and Y in range + x, _ := rand.Int(rand.Reader, bound) + x.Add(x, fp.Modulus()) + y, _ := rand.Int(rand.Reader, fp.Modulus()) + fmt.Println("= X large and Y in range (not necessarily satisfying curve equation) =") + x.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + y.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + + // test 2, X large and Y in range + x, _ = rand.Int(rand.Reader, fp.Modulus()) + y, _ = rand.Int(rand.Reader, bound) + y.Add(y, fp.Modulus()) + fmt.Println("= X in range and Y large (not necessarily satisfying curve equation) =") + x.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + y.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + + // test 3, X large and Y large + x, _ = rand.Int(rand.Reader, bound) + x.Add(x, fp.Modulus()) + y, _ = rand.Int(rand.Reader, bound) + y.Add(y, fp.Modulus()) + fmt.Println("= X large and Y large (not necessarily satisfying curve equation) =") + x.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + y.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + + // test 4 - test 1 but satisfying curve equation + s, _ := rand.Int(rand.Reader, fr.Modulus()) + p.ScalarMultiplicationBase(s) + px := p.X.BigInt(new(big.Int)) + px.Add(px, fp.Modulus()) + fmt.Println("= X large and Y in range (satisfying curve equation) =") + px.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + p.Y.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + + // test 5 - test 2 but satisfying curve equation + s, _ = rand.Int(rand.Reader, fr.Modulus()) + p.ScalarMultiplicationBase(s) + py := p.X.BigInt(new(big.Int)) + py.Add(py, fp.Modulus()) + fmt.Println("= X in range and Y large (satisfying curve equation) =") + p.X.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + py.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + + // test 6 - test 3 but satisfying curve equation + s, _ = rand.Int(rand.Reader, fr.Modulus()) + p.ScalarMultiplicationBase(s) + px = p.X.BigInt(new(big.Int)) + px.Add(px, fp.Modulus()) + py = p.Y.BigInt(new(big.Int)) + py.Add(py, fp.Modulus()) + fmt.Println("= X large and Y large (satisfying curve equation) =") + px.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + py.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) +} + +func TestDataSmallMalformedNotCurve(t *testing.T) { + t.Skip("skipping test, called manually when needed") + px, _ := rand.Int(rand.Reader, fp.Modulus()) + py, _ := rand.Int(rand.Reader, fp.Modulus()) + var p bn254.G1Affine + p.X.SetBigInt(px) + p.Y.SetBigInt(py) + if p.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= X and Y in range but not satisfying curve equation =") + var buf [32]byte + px.FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + py.FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) +} + +func TestDataSmallWell(t *testing.T) { + t.Skip("skipping test, called manually when needed") + for i := 0; i < 5; i++ { + var p bn254.G1Affine + s, _ := rand.Int(rand.Reader, fr.Modulus()) + p.ScalarMultiplicationBase(s) + fmt.Println("= random point in G1 =") + var buf [32]byte + p.X.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("X = 0x%x\n", buf[:]) + p.Y.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("Y = 0x%x\n", buf[:]) + } +} + +func TestDataLargeMalformedLarge(t *testing.T) { + t.Skip("skipping test, called manually when needed") + // bound 2^256-modulus + bound := new(big.Int).Lsh(big.NewInt(1), 256) + bound.Sub(bound, fp.Modulus()) + + var buf [32]byte + + // test 1, XA large, XB in range, YA in range, YB in range + xa, _ := rand.Int(rand.Reader, bound) + xa.Add(xa, fp.Modulus()) + xb, _ := rand.Int(rand.Reader, fp.Modulus()) + ya, _ := rand.Int(rand.Reader, fp.Modulus()) + yb, _ := rand.Int(rand.Reader, fp.Modulus()) + var q bn254.G2Affine + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= XA large, XB in range, YA in range, YB in range =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) + + // test 2, XA in range, XB large, YA in range, YB in range + xa, _ = rand.Int(rand.Reader, fp.Modulus()) + xb, _ = rand.Int(rand.Reader, bound) + xb.Add(xb, fp.Modulus()) + ya, _ = rand.Int(rand.Reader, fp.Modulus()) + yb, _ = rand.Int(rand.Reader, fp.Modulus()) + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= XA in range, XB large, YA in range, YB in range =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) + + // test 3, XA in range, XB in range, YA large, YB in range + xa, _ = rand.Int(rand.Reader, fp.Modulus()) + xb, _ = rand.Int(rand.Reader, fp.Modulus()) + ya, _ = rand.Int(rand.Reader, bound) + ya.Add(ya, fp.Modulus()) + yb, _ = rand.Int(rand.Reader, fp.Modulus()) + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= XA in range, XB in range, YA large, YB in range =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) + + // test 4, XA in range, XB in range, YA in range, YB large + xa, _ = rand.Int(rand.Reader, fp.Modulus()) + xb, _ = rand.Int(rand.Reader, fp.Modulus()) + ya, _ = rand.Int(rand.Reader, fp.Modulus()) + yb, _ = rand.Int(rand.Reader, bound) + yb.Add(yb, fp.Modulus()) + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= XA in range, XB in range, YA in range, YB large =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) + + // test 5, point in subgroup, but overflowing + s, _ := rand.Int(rand.Reader, fr.Modulus()) + q.ScalarMultiplicationBase(s) + xa = q.X.A0.BigInt(new(big.Int)) + xa.Add(xa, fp.Modulus()) + xb = q.X.A1.BigInt(new(big.Int)) + xb.Add(xb, fp.Modulus()) + ya = q.Y.A0.BigInt(new(big.Int)) + ya.Add(ya, fp.Modulus()) + yb = q.Y.A1.BigInt(new(big.Int)) + yb.Add(yb, fp.Modulus()) + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if !q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= point in subgroup, but overflowing =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) +} + +func TestDataLargeMalformedNotCurve(t *testing.T) { + t.Skip("skipping test, called manually when needed") + var q bn254.G2Affine + var buf [32]byte + xa, _ := rand.Int(rand.Reader, fp.Modulus()) + xb, _ := rand.Int(rand.Reader, fp.Modulus()) + ya, _ := rand.Int(rand.Reader, fp.Modulus()) + yb, _ := rand.Int(rand.Reader, fp.Modulus()) + yb.Add(yb, fp.Modulus()) + q.X.A0.SetBigInt(xa) + q.X.A1.SetBigInt(xb) + q.Y.A0.SetBigInt(ya) + q.Y.A1.SetBigInt(yb) + if q.IsOnCurve() { + t.Fatal("point is on curve") + } + fmt.Println("= point not on curve =") + xa.FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + xb.FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + ya.FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + yb.FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) +} + +func TestDataLargeMalformedNotSubgroup(t *testing.T) { + t.Skip("skipping test, called manually when needed") + var x, right, left, tmp, z, ZZ bn254.E2 + for { + xa, _ := rand.Int(rand.Reader, fp.Modulus()) + xb, _ := rand.Int(rand.Reader, fp.Modulus()) + x.A0.SetBigInt(xa) + x.A1.SetBigInt(xb) + za, _ := rand.Int(rand.Reader, fp.Modulus()) + zb, _ := rand.Int(rand.Reader, fp.Modulus()) + z.A0.SetBigInt(za) + z.A1.SetBigInt(zb) + right.Square(&x).Mul(&right, &x) + ZZ.Square(&z) + tmp.Square(&ZZ).Mul(&tmp, &ZZ) + tmp.MulBybTwistCurveCoeff(&tmp) + right.Add(&right, &tmp) + if right.Legendre() == 1 { + break + } + } + left.Sqrt(&right) + QJac := bn254.G2Jac{ + X: x, + Y: left, + Z: z, + } + if !QJac.IsOnCurve() { + t.Fatal("point is not on curve Jac") + } + var q bn254.G2Affine + q.FromJacobian(&QJac) + if !q.IsOnCurve() { + t.Fatal("point is not on curve") + } + if q.IsInSubGroup() { + t.Fatal("point is in subgroup") + } + + var buf [32]byte + fmt.Println("= point not in subgroup but on curve =") + q.X.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + q.X.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + q.Y.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + q.Y.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) +} + +func TestDataLargeWell(t *testing.T) { + t.Skip("skipping test, called manually when needed") + for i := 0; i < 5; i++ { + var q bn254.G2Affine + s, _ := rand.Int(rand.Reader, fr.Modulus()) + q.ScalarMultiplicationBase(s) + fmt.Println("= random point in G2 =") + var buf [32]byte + q.X.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("XA = 0x%x\n", buf[:]) + q.X.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("XB = 0x%x\n", buf[:]) + q.Y.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("YA = 0x%x\n", buf[:]) + q.Y.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("YB = 0x%x\n", buf[:]) + } +} + +func TestDataValidPairing(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + // pairing where result is 1. Two pairs of inputs + + // sp1 * sq1 + sp2 * sq2 == 0 + // sq2 = (-sp1 * sq1) / sp2 + var p1, p2 bn254.G1Affine + var q1, q2 bn254.G2Affine + sp1, _ := rand.Int(rand.Reader, fr.Modulus()) + sp2, _ := rand.Int(rand.Reader, fr.Modulus()) + sq1, _ := rand.Int(rand.Reader, fr.Modulus()) + tmp := new(big.Int) + tmp.ModInverse(sp2, fr.Modulus()) + tmp.Mul(tmp, sp1) + tmp.Mul(tmp, sq1) + tmp.Neg(tmp) + sq2 := new(big.Int).Mod(tmp, fr.Modulus()) + + p1.ScalarMultiplicationBase(sp1) + p2.ScalarMultiplicationBase(sp2) + q1.ScalarMultiplicationBase(sq1) + q2.ScalarMultiplicationBase(sq2) + ok, err := bn254.PairingCheck([]bn254.G1Affine{p1, p2}, []bn254.G2Affine{q1, q2}) + assert.NoError(err) + assert.True(ok) + fmt.Println("= double successful pairing =") + printP(p1) + printQ(q1) + fmt.Println() + printP(p2) + printQ(q2) + + // pairing where result is 1. Three pairs of inputs + // e(a, 2b) * e(2a, 2b) * e(-2a, 3b) == 1 + // 2 + 4 - 6 == 0 + var p3 bn254.G1Affine + var q3 bn254.G2Affine + sq2, _ = rand.Int(rand.Reader, fr.Modulus()) + sp3, _ := rand.Int(rand.Reader, fr.Modulus()) + n := new(big.Int) + n.Add(n, new(big.Int).Mul(sp1, sq1)) + n.Add(n, new(big.Int).Mul(sp2, sq2)) + tmp.ModInverse(sp3, fr.Modulus()) + tmp.Mul(tmp, n) + tmp.Neg(tmp) + sq3 := new(big.Int).Mod(tmp, fr.Modulus()) + + p1.ScalarMultiplicationBase(sp1) + p2.ScalarMultiplicationBase(sp2) + p3.ScalarMultiplicationBase(sp3) + q1.ScalarMultiplicationBase(sq1) + q2.ScalarMultiplicationBase(sq2) + q3.ScalarMultiplicationBase(sq3) + ok, err = bn254.PairingCheck([]bn254.G1Affine{p1, p2, p3}, []bn254.G2Affine{q1, q2, q3}) + assert.NoError(err) + assert.True(ok) + fmt.Print("\n\n") + fmt.Println("= triple successful pairing =") + printP(p1) + printQ(q1) + fmt.Println() + printP(p2) + printQ(q2) + fmt.Println() + printP(p3) + printQ(q3) + + printPLimbs(p1) + printQLimbs(q1) + printPLimbs(p2) + printQLimbs(q2) + printPLimbs(p3) + printQLimbs(q3) + + // pairing where result is 1. Four pairs of inputs + // e(a, 2b) * e(3a, b) * e(a, 5b) * e(-2a, 5b) == 1 + // 2 + 3 + 5 - 10 == 0 + var p4 bn254.G1Affine + var q4 bn254.G2Affine + sq3, _ = rand.Int(rand.Reader, fr.Modulus()) + sp4, _ := rand.Int(rand.Reader, fr.Modulus()) + n = new(big.Int) + n.Add(n, new(big.Int).Mul(sp1, sq1)) + n.Add(n, new(big.Int).Mul(sp2, sq2)) + n.Add(n, new(big.Int).Mul(sp3, sq3)) + tmp.ModInverse(sp4, fr.Modulus()) + tmp.Mul(tmp, n) + tmp.Neg(tmp) + sq4 := new(big.Int).Mod(tmp, fr.Modulus()) + + p1.ScalarMultiplicationBase(sp1) + p2.ScalarMultiplicationBase(sp2) + p3.ScalarMultiplicationBase(sp3) + p4.ScalarMultiplicationBase(sp4) + q1.ScalarMultiplicationBase(sq1) + q2.ScalarMultiplicationBase(sq2) + q3.ScalarMultiplicationBase(sq3) + q4.ScalarMultiplicationBase(sq4) + ok, err = bn254.PairingCheck([]bn254.G1Affine{p1, p2, p3, p4}, []bn254.G2Affine{q1, q2, q3, q4}) + assert.NoError(err) + assert.True(ok) + fmt.Print("\n\n") + fmt.Println("= quadruple successful pairing =") + printP(p1) + printQ(q1) + fmt.Println() + printP(p2) + printQ(q2) + fmt.Println() + printP(p3) + printQ(q3) + fmt.Println() + printP(p4) + printQ(q4) +} + +func TestG2TestData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + // test for a point not on the curve + var Q bn254.G2Affine + _, err := Q.X.A0.SetString("0x119606e6d3ea97cea4eff54433f5c7dbc026b8d0670ddfbe6441e31225028d31") + assert.NoError(err) + _, err = Q.X.A1.SetString("0x1d3df5be6084324da6333a6ad1367091ca9fbceb70179ec484543a58b8cb5d63") + assert.NoError(err) + _, err = Q.Y.A0.SetString("0x1b9a36ea373fe2c5b713557042ce6deb2907d34e12be595f9bbe84c144de86ef") + assert.NoError(err) + _, err = Q.Y.A1.SetString("0x49fe60975e8c78b7b31a6ed16a338ac8b28cf6a065cfd2ca47e9402882518ba0") + assert.NoError(err) + assert.False(Q.IsOnCurve()) + printQLimbs(Q) + + // test for a point on curve not in G2 + _, err = Q.X.A0.SetString("0x07192b9fd0e2a32e3e1caa8e59462b757326d48f641924e6a1d00d66478913eb") + assert.NoError(err) + _, err = Q.X.A1.SetString("0x15ce93f1b1c4946dd6cfbb3d287d9c9a1cdedb264bda7aada0844416d8a47a63") + assert.NoError(err) + _, err = Q.Y.A0.SetString("0x0fa65a9b48ba018361ed081e3b9e958451de5d9e8ae0bd251833ebb4b2fafc96") + assert.NoError(err) + _, err = Q.Y.A1.SetString("0x06e1f5e20f68f6dfa8a91a3bea048df66d9eaf56cc7f11215401f7e05027e0c6") + assert.NoError(err) + assert.True(Q.IsOnCurve()) + assert.False(Q.IsInSubGroup()) + printQLimbs(Q) + + // test for a point in G2 + Q.ScalarMultiplicationBase(big.NewInt(5678)) + printQLimbs(Q) +} + +func TestDummyMillerLoopData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + _, _, p, q := bn254.Generators() + lines := bn254.PrecomputeLines(q) + mlres, err := bn254.MillerLoopFixedQ( + []bn254.G1Affine{p}, + [][2][len(bn254.LoopCounter)]bn254.LineEvaluationAff{lines}, + ) + assert.NoError(err) + var one bn254.GT + one.SetOne() + printTLimbs(one) + fmt.Println() + printPLimbs(p) + fmt.Println() + printQLimbs(q) + fmt.Println() + printTLimbs(mlres) +} + +func TestDummyMillerLoopFinalExpData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + _, _, p, q := bn254.Generators() + var negP bn254.G1Affine + negP.ScalarMultiplicationBase(big.NewInt(-1)) + lines := bn254.PrecomputeLines(q) + mlres, err := bn254.MillerLoopFixedQ( + []bn254.G1Affine{negP}, + [][2][len(bn254.LoopCounter)]bn254.LineEvaluationAff{lines}, + ) + printTLimbs(mlres) + assert.NoError(err) + + mlres2, err := bn254.MillerLoopFixedQ( + []bn254.G1Affine{p}, + [][2][len(bn254.LoopCounter)]bn254.LineEvaluationAff{lines}, + ) + assert.NoError(err) + mlres.Mul(&mlres, &mlres2) + res := bn254.FinalExponentiation(&mlres) + assert.True(res.IsOne()) + assert.NoError(err) + // var one bn254.GT + fmt.Println() + printPLimbs(p) + fmt.Println() + printQLimbs(q) + // fmt.Println() + // printTLimbs(mlres) +} + +func TestDummyG2CheckData(t *testing.T) { + t.Skip("skipping test, called manually when needed") + assert := test.NewAssert(t) + _, _, _, q := bn254.Generators() + ok := q.IsInSubGroup() + assert.True(ok) + printQLimbs(q) +} + +func printP(P bn254.G1Affine) { + var buf [32]byte + P.X.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("Ax = 0x%x\n", buf[:]) + P.Y.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("Ay = 0x%x\n", buf[:]) +} + +func printQ(Q bn254.G2Affine) { + var buf [32]byte + Q.X.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("BxRe = 0x%x\n", buf[:]) + Q.X.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("BxIm = 0x%x\n", buf[:]) + Q.Y.A0.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("ByRe = 0x%x\n", buf[:]) + Q.Y.A1.BigInt(new(big.Int)).FillBytes(buf[:]) + fmt.Printf("ByIm = 0x%x\n", buf[:]) +} + +func printPLimbs(P bn254.G1Affine) { + px := P.X.Bytes() + py := P.Y.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n", px[0:16], px[16:32], py[0:16], py[16:32]) +} + +func printQLimbs(Q bn254.G2Affine) { + qxre := Q.X.A0.Bytes() + qxim := Q.X.A1.Bytes() + qyre := Q.Y.A0.Bytes() + qyim := Q.Y.A1.Bytes() + fmt.Printf("0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n0x%x\n", + qxre[0:16], qxre[16:32], qxim[0:16], qxim[16:32], qyre[0:16], qyre[16:32], qyim[0:16], qyim[16:32]) +} + +func printTLimbs(T bn254.GT) { + for i, bb := range [][32]byte{ + T.C0.B0.A0.Bytes(), + T.C0.B0.A1.Bytes(), + T.C0.B1.A0.Bytes(), + T.C0.B1.A1.Bytes(), + T.C0.B2.A0.Bytes(), + T.C0.B2.A1.Bytes(), + T.C1.B0.A0.Bytes(), + T.C1.B0.A1.Bytes(), + T.C1.B1.A0.Bytes(), + T.C1.B1.A1.Bytes(), + T.C1.B2.A0.Bytes(), + T.C1.B2.A1.Bytes(), + } { + _ = i + fmt.Printf("0x%x\n0x%x\n", bb[0:16], bb[16:32]) + } +} diff --git a/prover/zkevm/prover/ecpair/testdata/testdata_generator_test.go b/prover/zkevm/prover/ecpair/testdata/testdata_generator_test.go new file mode 100644 index 000000000..483ddd902 --- /dev/null +++ b/prover/zkevm/prover/ecpair/testdata/testdata_generator_test.go @@ -0,0 +1,583 @@ +package testdata + +import ( + "crypto/rand" + "encoding/csv" + "fmt" + "math/big" + "os" + "strconv" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type inputType int + +const ( + fullTrivial inputType = iota // (0, 0) + leftTrivialValid // (0, Q) + leftTrivialInvalid // (0, Q') where Q' is not in G2 + rightTrivialValid // (P, 0) + rightTrivialInvalid // (P', 0) where P' is not in G1 + nonTrivialLeftInvalid // (P, Q) where P is not in G1 + nonTrivialRightInvalid // (P, Q) where Q is not in G2 + fullInvalid // (P, Q) where P and Q not in G1 and G2 respectively + nonTrivial // (P, Q) +) + +var choices = []inputType{fullTrivial, leftTrivialValid, leftTrivialInvalid, rightTrivialValid, rightTrivialInvalid, nonTrivialLeftInvalid, nonTrivialRightInvalid, fullInvalid, nonTrivial} + +func (i inputType) String() string { + switch i { + case fullTrivial: + return "full-trivial" + case leftTrivialValid: + return "left-trivial-valid" + case leftTrivialInvalid: + return "left-trivial-invalid" + case rightTrivialValid: + return "right-trivial-valid" + case rightTrivialInvalid: + return "right-trivial-invalid" + case nonTrivialLeftInvalid: + return "non-trivial-left-invalid" + case nonTrivialRightInvalid: + return "non-trivial-right-invalid" + case fullInvalid: + return "full-invalid" + case nonTrivial: + return "non-trivial" + default: + panic("unknown") + } +} + +func generateG1Infinity() bn254.G1Affine { + var p bn254.G1Affine + p.SetInfinity() + return p +} + +func generateG2Infinity() bn254.G2Affine { + var q bn254.G2Affine + q.SetInfinity() + return q +} + +func generateG1Invalid() bn254.G1Affine { + var p bn254.G1Affine + for { + px, _ := rand.Int(rand.Reader, fp.Modulus()) + py, _ := rand.Int(rand.Reader, fp.Modulus()) + p.X.SetBigInt(px) + p.Y.SetBigInt(py) + if !p.IsOnCurve() { + return p + } + } +} + +func generateG2Invalid() bn254.G2Affine { + var x, right, left, tmp, z, ZZ bn254.E2 + for { + xa, _ := rand.Int(rand.Reader, fp.Modulus()) + xb, _ := rand.Int(rand.Reader, fp.Modulus()) + x.A0.SetBigInt(xa) + x.A1.SetBigInt(xb) + za, _ := rand.Int(rand.Reader, fp.Modulus()) + zb, _ := rand.Int(rand.Reader, fp.Modulus()) + z.A0.SetBigInt(za) + z.A1.SetBigInt(zb) + right.Square(&x).Mul(&right, &x) + ZZ.Square(&z) + tmp.Square(&ZZ).Mul(&tmp, &ZZ) + tmp.MulBybTwistCurveCoeff(&tmp) + right.Add(&right, &tmp) + if right.Legendre() != 1 { + continue + } + left.Sqrt(&right) + QJac := bn254.G2Jac{ + X: x, + Y: left, + Z: z, + } + if !QJac.IsOnCurve() { + panic("point is not on curve Jac") + } + var q bn254.G2Affine + q.FromJacobian(&QJac) + if !q.IsOnCurve() { + continue + } + if q.IsInSubGroup() { + continue + } + return q + } +} + +func generateG1Valid() bn254.G1Affine { + var p bn254.G1Affine + var s fr.Element + s.SetRandom() + p.ScalarMultiplicationBase(s.BigInt(new(big.Int))) + return p +} + +func generateG2Valid() bn254.G2Affine { + var q bn254.G2Affine + var s fr.Element + s.SetRandom() + q.ScalarMultiplicationBase(s.BigInt(new(big.Int))) + return q +} + +func (i inputType) generatePair() (generatedPair inputPair) { + // here the pairingResult return value indicates if this input pair is + // invalid, i.e. it makes the whole pairing check to fail + // + // the cancelMemberships indicates if we should cancel the membership checks + // for other inputs in the pairing check. This is usually when G1 point is + // invalid in which case we don't need to check other G2 points. + var ip inputPair + ip.inputType = i + switch i { + case fullTrivial: + ip.P = generateG1Infinity() + ip.Q = generateG2Infinity() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = false + ip.MembershipSuccess = true + return ip + case leftTrivialValid: + ip.P = generateG1Infinity() + ip.Q = generateG2Valid() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = true + ip.MembershipSuccess = true + return ip + case leftTrivialInvalid: + ip.P = generateG1Infinity() + ip.Q = generateG2Invalid() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = true + ip.MembershipSuccess = false + return ip + case rightTrivialValid: + ip.P = generateG1Valid() + ip.Q = generateG2Infinity() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = false + ip.MembershipSuccess = true + return ip + case rightTrivialInvalid: + ip.P = generateG1Invalid() + ip.Q = generateG2Infinity() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = false + ip.MembershipSuccess = false + return ip + case nonTrivialLeftInvalid: + ip.P = generateG1Invalid() + ip.Q = generateG2Valid() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = false + ip.MembershipSuccess = false + return ip + case nonTrivialRightInvalid: + ip.P = generateG1Valid() + ip.Q = generateG2Invalid() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = true + ip.MembershipSuccess = false + return ip + case fullInvalid: + ip.P = generateG1Invalid() + ip.Q = generateG2Invalid() + ip.ToPairingCircuit = false + ip.ToMembershipCircuit = false + ip.MembershipSuccess = false + return ip + case nonTrivial: + ip.P = generateG1Valid() + ip.Q = generateG2Valid() + ip.ToPairingCircuit = true + ip.ToMembershipCircuit = false + ip.MembershipSuccess = false + return ip + default: + panic("not handled") + } +} + +type inputs []inputType + +type inputPair struct { + P bn254.G1Affine + Q bn254.G2Affine + + ToPairingCircuit bool + ToMembershipCircuit bool + + MembershipSuccess bool + + inputType inputType +} + +type testCase struct { + inputPairs []inputPair + inputs inputs + result bool +} + +func (l inputs) nbNonTrivial() int { + count := 0 + for _, input := range l { + if input == nonTrivial { + count++ + } + } + return count +} + +func (l inputs) generateValidInputs() []inputPair { + nb := l.nbNonTrivial() + sp := make([]fr.Element, nb) + sq := make([]fr.Element, nb) + for i := 0; i < nb; i++ { + sp[i].SetRandom() + sq[i].SetRandom() + } + var acc, tmp fr.Element + for i := 0; i < nb-1; i++ { + tmp.Mul(&sp[i], &sq[i]) + acc.Add(&acc, &tmp) + } + acc.Neg(&acc) + sq[nb-1].Div(&acc, &sp[nb-1]) + + pairs := make([]inputPair, nb) + var Ps []bn254.G1Affine + var Qs []bn254.G2Affine + bi := new(big.Int) + for i := 0; i < nb; i++ { + pairs[i].P.ScalarMultiplicationBase(sp[i].BigInt(bi)) + pairs[i].Q.ScalarMultiplicationBase(sq[i].BigInt(bi)) + pairs[i].ToPairingCircuit = true + pairs[i].ToMembershipCircuit = false + pairs[i].inputType = nonTrivial + pairs[i].MembershipSuccess = true + // for sanity check + Ps = append(Ps, pairs[i].P) + Qs = append(Qs, pairs[i].Q) + } + // sanity check + ok, err := bn254.PairingCheck(Ps, Qs) + if err != nil { + panic(err) + } + if !ok { + panic("invalid pairing") + } + return pairs +} + +func (l inputs) generateInvalidInputs() []inputPair { + nb := l.nbNonTrivial() + var s fr.Element + pairs := make([]inputPair, nb) + for i := 0; i < nb; i++ { + s.SetRandom() + pairs[i].P.ScalarMultiplicationBase(s.BigInt(new(big.Int))) + s.SetRandom() + pairs[i].Q.ScalarMultiplicationBase(s.BigInt(new(big.Int))) + pairs[i].ToPairingCircuit = true + pairs[i].ToMembershipCircuit = false + pairs[i].inputType = nonTrivial + pairs[i].MembershipSuccess = true + } + return pairs +} + +func (l inputs) generateTestCase() []testCase { + // count how many instances of what we have + counts := make(map[inputType]int) + for _, input := range l { + counts[input]++ + } + pairs := make([]inputPair, len(l)) + // if there is any invalid G1 point, we don't need to run anything + if counts[rightTrivialInvalid] > 0 || counts[nonTrivialLeftInvalid] > 0 || counts[fullInvalid] > 0 { + for i, input := range l { + pairs[i] = input.generatePair() + pairs[i].ToPairingCircuit = false + pairs[i].ToMembershipCircuit = false + pairs[i].MembershipSuccess = false + } + return []testCase{{inputPairs: pairs, result: false, inputs: l}} + } + // if there is any invalid G2 point, we only need to run membership check for that point + if counts[leftTrivialInvalid] > 0 || counts[nonTrivialRightInvalid] > 0 { + isFirstInvalid := true + for i, input := range l { + pairs[i] = input.generatePair() + pairs[i].ToPairingCircuit = false + if input == leftTrivialInvalid || input == nonTrivialRightInvalid { + pairs[i].ToMembershipCircuit = true + pairs[i].MembershipSuccess = false + if isFirstInvalid { + isFirstInvalid = false + } else { + pairs[i].ToPairingCircuit = false + } + } else { + pairs[i].ToMembershipCircuit = false + } + } + return []testCase{{inputPairs: pairs, result: false, inputs: l}} + } + // if for all points G2 are 0, we don't need to run anything + if counts[rightTrivialValid] == len(l) { + for i, input := range l { + pairs[i] = input.generatePair() + } + return []testCase{{inputPairs: pairs, result: true, inputs: l}} + } + + if l.nbNonTrivial() == 0 { + // should be combination of fullTrivial and leftTrivialValid. Then the G2 points need to go to the membership circuit + for i, input := range l { + pairs[i] = input.generatePair() + } + return []testCase{{inputPairs: pairs, result: true, inputs: l}} + } + if l.nbNonTrivial() == 1 { + invalidInputs := l.generateInvalidInputs() + for i, input := range l { + if input == nonTrivial { + pairs[i] = invalidInputs[0] + } else { + pairs[i] = input.generatePair() + } + } + return []testCase{{inputPairs: pairs, result: false, inputs: l}} + } + if l.nbNonTrivial() > 1 { + validInputs := l.generateValidInputs() + invalidInputs := l.generateInvalidInputs() + validPairs := make([]inputPair, len(l)) + invalidPairs := make([]inputPair, len(l)) + for i, input := range l { + if input == nonTrivial { + validPairs[i] = validInputs[0] + invalidPairs[i] = invalidInputs[0] + validInputs = validInputs[1:] + invalidInputs = invalidInputs[1:] + } else { + validPairs[i] = input.generatePair() + invalidPairs[i] = input.generatePair() + } + } + return []testCase{{inputPairs: validPairs, result: true, inputs: l}, {inputPairs: invalidPairs, result: false, inputs: l}} + } + panic("unexpected 2") +} + +func (ip *inputPair) WriteCSV(w *csv.Writer, ecdataId, ecDataIndex, acc, total int) (newIndex int, err error) { + // split G1 and G2 into limbs + px := ip.P.X.Bytes() + py := ip.P.Y.Bytes() + qxre := ip.Q.X.A0.Bytes() + qxim := ip.Q.X.A1.Bytes() + qyre := ip.Q.Y.A0.Bytes() + qyim := ip.Q.Y.A1.Bytes() + + limbs := []string{ + fmt.Sprintf("0x%x", px[0:16]), + fmt.Sprintf("0x%x", px[16:32]), + fmt.Sprintf("0x%x", py[0:16]), + fmt.Sprintf("0x%x", py[16:32]), + fmt.Sprintf("0x%x", qxim[0:16]), + fmt.Sprintf("0x%x", qxim[16:32]), + fmt.Sprintf("0x%x", qxre[0:16]), + fmt.Sprintf("0x%x", qxre[16:32]), + fmt.Sprintf("0x%x", qyim[0:16]), + fmt.Sprintf("0x%x", qyim[16:32]), + fmt.Sprintf("0x%x", qyre[0:16]), + fmt.Sprintf("0x%x", qyre[16:32]), + } + records := make([][]string, len(limbs)) + var ( + inputPairSuccess = formatBoolAsInt(ip.MembershipSuccess) + ToPairingCircuit = formatBoolAsInt(ip.ToPairingCircuit) + ) + for i, limb := range limbs { + isG2Part := i >= 4 + records[i] = []string{ + strconv.Itoa(ecdataId), + limb, + inputPairSuccess, + strconv.Itoa(ecDataIndex + i), + "1", + "0", + strconv.Itoa(acc), + strconv.Itoa(total), + ToPairingCircuit, + formatBoolAsInt(ip.ToMembershipCircuit && isG2Part), + } + } + if err := w.WriteAll(records); err != nil { + return ecDataIndex, err + } + return ecDataIndex + len(limbs), nil +} + +func (tc *testCase) WriteCSV(w *csv.Writer, ecdataId int) error { + var err error + var hasPairing bool + index := 0 + for i, ip := range tc.inputPairs { + if index, err = ip.WriteCSV(w, ecdataId, index, i+1, len(tc.inputPairs)); err != nil { + return err + } + hasPairing = hasPairing || ip.ToPairingCircuit + } + // write result + if err = w.Write([]string{ + strconv.Itoa(ecdataId), + "0", + formatBoolAsInt(tc.result), + "0", + "0", + "1", + "0", + strconv.Itoa(len(tc.inputPairs)), + formatBoolAsInt(hasPairing), + "0", + }); err != nil { + return err + } + if err = w.Write([]string{ + strconv.Itoa(ecdataId), + formatBoolAsInt(tc.result), + formatBoolAsInt(tc.result), + "1", + "0", + "1", + "0", + strconv.Itoa(len(tc.inputPairs)), + formatBoolAsInt(hasPairing), + "0", + }); err != nil { + return err + } + return nil +} + +func writeHeader(w *csv.Writer) error { + // record is + // - ECDATA_ID (int random increasing) + // - ECDATA_LIMB (int 128 bits) + // - ECDATA_SUCCESS_BIT (bool) + // - ECDATA_INDEX (int) + // - ECDATA_IS_DATA (bool) + // - ECDATA_IS_RES (bool) + // - ECDATA_ACC_PAIRINGS (int) + // - ECDATA_TOTAL_PAIRINGS (int) + // - ECDATA_CS_PAIRING (bool) + // - ECDATA_CS_G2_MEMBERSHIP (bool) + return w.Write([]string{ + "ECDATA_ID", + "ECDATA_LIMB", + "ECDATA_SUCCESS_BIT", + "ECDATA_INDEX", + "ECDATA_IS_DATA", + "ECDATA_IS_RES", + "ECDATA_ACC_PAIRINGS", + "ECDATA_TOTAL_PAIRINGS", + "ECDATA_CS_PAIRING", + "ECDATA_CS_G2_MEMBERSHIP", + }) +} + +func formatBoolAsInt(b bool) string { + if b { + return "1" + } + return "0" +} + +func generateTestCases(length int) []testCase { + // generate all possible combinations of inputs + // for each combination, generate all possible test cases + cartesianProduct := func(list []inputs) []inputs { + var ret []inputs + if len(list) == 0 { + for _, input := range choices { + ret = append(ret, inputs{input}) + } + return ret + } + for _, curr := range list { + for _, input := range choices { + newCurr := make(inputs, len(curr), len(curr)+1) + copy(newCurr, curr) + ret = append(ret, append(newCurr, input)) + } + } + return ret + } + cases := cartesianProduct(nil) + for i := 1; i < length; i++ { + cases = cartesianProduct(cases) + } + var allTestCases []testCase + for _, tc := range cases { + allTestCases = append(allTestCases, tc.generateTestCase()...) + } + return allTestCases +} + +func TestGenerateECPairTestCases(t *testing.T) { + t.Skip("long test, run manually when needed") + var generatedCases []testCase + for i := 1; i <= 5; i++ { + generatedCases = append(generatedCases, generateTestCases(i)...) + } + for i, tc := range generatedCases { + f, err := os.Create(fmt.Sprintf("generated/case-%06d_input.csv", i+1)) + if err != nil { + t.Fatal(err) + } + defer f.Close() + w := csv.NewWriter(f) + defer w.Flush() + if err := writeHeader(w); err != nil { + t.Fatal(err) + } + if err := tc.WriteCSV(w, i+1); err != nil { + t.Fatal(err) + } + } + fmt.Println(len(generatedCases)) +} + +func TestWriteTestCase(t *testing.T) { + // sanity test that nothing fails/panics etc + input := inputs{nonTrivial, nonTrivial, nonTrivial} + w := csv.NewWriter(os.Stdout) + if err := writeHeader(w); err != nil { + panic(err) + } + defer w.Flush() + testCases := input.generateTestCase() + for i, tc := range testCases { + if err := tc.WriteCSV(w, i); err != nil { + panic(err) + } + } +} diff --git a/prover/zkevm/prover/hash/generic/testdata/gen.go b/prover/zkevm/prover/hash/generic/testdata/gen.go index 65f0d9602..474b9b9a1 100644 --- a/prover/zkevm/prover/hash/generic/testdata/gen.go +++ b/prover/zkevm/prover/hash/generic/testdata/gen.go @@ -2,12 +2,13 @@ package testdata import ( "fmt" - "math/rand" + "math/rand/v2" "github.com/consensys/linea-monorepo/prover/backend/files" "github.com/consensys/linea-monorepo/prover/crypto/keccak" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/wizard" + "github.com/consensys/linea-monorepo/prover/utils" "github.com/consensys/linea-monorepo/prover/zkevm/prover/common" "github.com/consensys/linea-monorepo/prover/zkevm/prover/hash/generic" ) @@ -23,7 +24,7 @@ func GenerateAndAssignGenDataModule(run *wizard.ProverRuntime, gdm *generic.GenD toHash = make([]field.Element, size) index = make([]field.Element, size) hashNum = make([]field.Element, size) - rng = rand.New(rand.NewSource(68768)) + rng = rand.New(rand.NewChaCha8([32]byte{})) nByteCol = common.NewVectorBuilder(gdm.NBytes) limbCol = common.NewVectorBuilder(gdm.Limb) @@ -95,7 +96,7 @@ func randNBytes(rng *rand.Rand) (int, field.Element) { // nBytesInt must be in 1..=16 var ( - nBytesInt = rng.Int31n(16) + 1 + nBytesInt = rng.Int32N(16) + 1 nBytesF = field.NewElement(uint64(nBytesInt)) ) @@ -106,7 +107,7 @@ func randLimbs(rng *rand.Rand, nBytes int) field.Element { var ( resBytes = make([]byte, 16) - _, _ = rng.Read(resBytes[:nBytes]) + _, _ = utils.ReadPseudoRand(rng, resBytes[:nBytes]) res = new(field.Element).SetBytes(resBytes) ) diff --git a/prover/zkevm/prover/hash/importpad/testdata/gen.go b/prover/zkevm/prover/hash/importpad/testdata/gen.go index 426d39f60..78b9348fb 100644 --- a/prover/zkevm/prover/hash/importpad/testdata/gen.go +++ b/prover/zkevm/prover/hash/importpad/testdata/gen.go @@ -2,10 +2,11 @@ package main import ( "fmt" - "math/rand" + "math/rand/v2" "github.com/consensys/linea-monorepo/prover/backend/files" "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/utils" ) func main() { @@ -16,7 +17,7 @@ func main() { toHash = make([]field.Element, 32) index = make([]field.Element, 32) hashNum = make([]field.Element, 32) - rng = rand.New(rand.NewSource(68768)) + rng = rand.New(rand.NewChaCha8([32]byte{})) hashNums = []int{0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0} toHashInt = []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0} oF = files.MustOverwrite("./testdata/input.csv") @@ -71,7 +72,7 @@ func randLimbs(rng *rand.Rand, nBytes int) field.Element { var ( resBytes = make([]byte, 16) - _, _ = rng.Read(resBytes[:nBytes]) + _, _ = utils.ReadPseudoRand(rng, resBytes[:nBytes]) res = new(field.Element).SetBytes(resBytes) ) diff --git a/prover/zkevm/prover/hash/keccak/base_conversion/bc_output_test.go b/prover/zkevm/prover/hash/keccak/base_conversion/bc_output_test.go index 16372071f..12b8b9d08 100644 --- a/prover/zkevm/prover/hash/keccak/base_conversion/bc_output_test.go +++ b/prover/zkevm/prover/hash/keccak/base_conversion/bc_output_test.go @@ -1,7 +1,7 @@ package base_conversion import ( - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/maths/field" @@ -53,6 +53,7 @@ func makeTestCaseBaseConversionOutput() ( } return define, prover } + func TestBaseConversionOutput(t *testing.T) { define, prover := makeTestCaseBaseConversionOutput() comp := wizard.Compile(define, dummy.Compile) @@ -73,18 +74,15 @@ func (b *hashBaseConversion) assignInputs(run *wizard.ProverRuntime) { sliceLoB[j] = common.NewVectorBuilder(b.Inputs.LimbsLoB[j]) } + // #nosec G404 -- we don't need a cryptographic PRNG for testing purposes + rng := rand.New(utils.NewRandSource(678988)) + max := keccakf.BaseBPow4 for j := range sliceHiB { for row := 0; row < size; row++ { // generate a random value in baseB - // #nosec G404 -- we don't need a cryptographic PRNG for testing purposes - rng := rand.New(rand.NewSource(int64(row * j))) - // #nosec G404 -- we don't need a cryptographic PRNG for testing purposes - rngm := rand.New(rand.NewSource(int64((row + 3) * j))) - n := rng.Intn(max) + 1 - m := rngm.Intn(max) + 1 - sliceHiB[j].PushInt(n) - sliceLoB[j].PushInt(m) + sliceHiB[j].PushInt(rng.IntN(max)) + sliceLoB[j].PushInt(rng.IntN(max)) } } diff --git a/prover/zkevm/prover/hash/keccak/base_conversion/decompose_be_test.go b/prover/zkevm/prover/hash/keccak/base_conversion/decompose_be_test.go index d630e99d3..f6d716c9b 100644 --- a/prover/zkevm/prover/hash/keccak/base_conversion/decompose_be_test.go +++ b/prover/zkevm/prover/hash/keccak/base_conversion/decompose_be_test.go @@ -1,13 +1,14 @@ package base_conversion import ( - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/compiler/dummy" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/protocol/wizard" + "github.com/consensys/linea-monorepo/prover/utils" "github.com/consensys/linea-monorepo/prover/zkevm/prover/common" "github.com/stretchr/testify/assert" ) @@ -16,6 +17,8 @@ func makeTestCaseDecomposeBE() ( define wizard.DefineFunc, prover wizard.ProverStep, ) { + // #nosec G404 --we don't need a cryptographic RNG for testing purpose + rand := rand.New(utils.NewRandSource(0)) size := 16 d := &decompositionCtx{} define = func(build *wizard.Builder) { @@ -35,7 +38,7 @@ func makeTestCaseDecomposeBE() ( ) for row := 0; row < size; row++ { b := make([]byte, 8) - rand.Read(b) //nolint + utils.ReadPseudoRand(rand, b) f := *new(field.Element).SetBytes(b) col.PushField(f) } diff --git a/prover/zkevm/prover/hash/keccak/keccakf/io_test.go b/prover/zkevm/prover/hash/keccak/keccakf/io_test.go index 80a4e424c..51c1ed041 100644 --- a/prover/zkevm/prover/hash/keccak/keccakf/io_test.go +++ b/prover/zkevm/prover/hash/keccak/keccakf/io_test.go @@ -1,13 +1,14 @@ package keccakf import ( - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/crypto/keccak" "github.com/consensys/linea-monorepo/prover/protocol/compiler/dummy" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/protocol/wizard" + "github.com/consensys/linea-monorepo/prover/utils" "github.com/stretchr/testify/assert" ) @@ -40,7 +41,7 @@ func MakeTestCaseInputOutputModule(maxNumKeccakF int) ( func TestInputOutputModule(t *testing.T) { // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rng := rand.New(rand.NewSource(0)) + rng := rand.New(rand.NewChaCha8([32]byte{})) numCases := 2 maxNumKeccakf := 64 // The -1 is here to prevent the generation of a padding block @@ -51,9 +52,9 @@ func TestInputOutputModule(t *testing.T) { for i := 0; i < numCases; i++ { // Generate a random piece of data - dataSize := rng.Intn(maxInputSize + 1) + dataSize := rng.IntN(maxInputSize + 1) data := make([]byte, dataSize) - rng.Read(data) + utils.ReadPseudoRand(rng, data) // Generate permutation traces for the data traces := keccak.PermTraces{} diff --git a/prover/zkevm/prover/hash/keccak/keccakf/keccakf_test.go b/prover/zkevm/prover/hash/keccak/keccakf/keccakf_test.go index 68f1d5df2..36f4994d9 100644 --- a/prover/zkevm/prover/hash/keccak/keccakf/keccakf_test.go +++ b/prover/zkevm/prover/hash/keccak/keccakf/keccakf_test.go @@ -4,7 +4,7 @@ package keccakf import ( "fmt" - "math/rand" + "math/rand/v2" "sync" "testing" @@ -15,6 +15,7 @@ import ( "github.com/consensys/linea-monorepo/prover/protocol/compiler/permutation" "github.com/consensys/linea-monorepo/prover/protocol/compiler/specialqueries" "github.com/consensys/linea-monorepo/prover/protocol/wizard" + "github.com/consensys/linea-monorepo/prover/utils" "github.com/stretchr/testify/assert" ) @@ -72,7 +73,7 @@ func keccakfTestingModule( func TestKeccakf(t *testing.T) { // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rng := rand.New(rand.NewSource(0)) + rng := rand.New(rand.NewChaCha8([32]byte{})) numCases := 15 maxNumKeccakf := 5 // The -1 is here to prevent the generation of a padding block @@ -83,9 +84,9 @@ func TestKeccakf(t *testing.T) { for i := 0; i < numCases; i++ { // Generate a random piece of data - dataSize := rng.Intn(maxInputSize + 1) + dataSize := rng.IntN(maxInputSize + 1) data := make([]byte, dataSize) - rng.Read(data) + utils.ReadPseudoRand(rng, data) // Generate permutation traces for the data traces := keccak.PermTraces{} diff --git a/prover/zkevm/prover/hash/keccak/keccakf/pichiiota_test.go b/prover/zkevm/prover/hash/keccak/keccakf/pichiiota_test.go index 36404e39f..737bac65a 100644 --- a/prover/zkevm/prover/hash/keccak/keccakf/pichiiota_test.go +++ b/prover/zkevm/prover/hash/keccak/keccakf/pichiiota_test.go @@ -3,7 +3,7 @@ package keccakf import ( - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/crypto/keccak" @@ -141,7 +141,7 @@ func TestPiChiIota(t *testing.T) { maxKeccaf := 10 // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rnd := rand.New(rand.NewSource(0)) + rnd := rand.New(rand.NewChaCha8([32]byte{})) // Every time the prover function is called, the traces will be updated. // Likewise, run will be set by the prover. diff --git a/prover/zkevm/prover/hash/keccak/keccakf/rho_test.go b/prover/zkevm/prover/hash/keccak/keccakf/rho_test.go index b31cbb03d..29f752a94 100644 --- a/prover/zkevm/prover/hash/keccak/keccakf/rho_test.go +++ b/prover/zkevm/prover/hash/keccak/keccakf/rho_test.go @@ -3,7 +3,7 @@ package keccakf import ( - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/crypto/keccak" @@ -145,7 +145,7 @@ func TestRho(t *testing.T) { maxKeccaf := 10 // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rnd := rand.New(rand.NewSource(0)) + rnd := rand.New(rand.NewChaCha8([32]byte{})) // Every time the prover function is called, the traces will be updated. // Likewise, run will be set by the prover. diff --git a/prover/zkevm/prover/hash/keccak/keccakf/theta_test.go b/prover/zkevm/prover/hash/keccak/keccakf/theta_test.go index 0c18d6055..b01b46a72 100644 --- a/prover/zkevm/prover/hash/keccak/keccakf/theta_test.go +++ b/prover/zkevm/prover/hash/keccak/keccakf/theta_test.go @@ -3,7 +3,7 @@ package keccakf import ( - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/crypto/keccak" @@ -90,9 +90,9 @@ func testInputProvider(rnd *rand.Rand, maxNumKeccakf int) InputWitnessProvider { for len(res.Blocks) < effNumKeccak { // Each hash is for a random string taking at most 3 permutations - streamLen := rnd.Intn(3*keccak.Rate-1) + 1 + streamLen := rnd.IntN(3*keccak.Rate-1) + 1 stream := make([]byte, streamLen) - rnd.Read(stream) + utils.ReadPseudoRand(rnd, stream) for i := 0; i < effNumKeccak; i++ { keccak.Hash(stream, &res) @@ -119,7 +119,7 @@ func TestTheta(t *testing.T) { maxKeccaf := 10 // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rnd := rand.New(rand.NewSource(0)) + rnd := rand.New(rand.NewChaCha8([32]byte{})) // Every time the prover function is called, the traces will be updated. // Likewise, run will be set by the prover. diff --git a/prover/zkevm/prover/hash/keccak/keccakf/utils_test.go b/prover/zkevm/prover/hash/keccak/keccakf/utils_test.go index 6b4322641..8d6ae4734 100644 --- a/prover/zkevm/prover/hash/keccak/keccakf/utils_test.go +++ b/prover/zkevm/prover/hash/keccak/keccakf/utils_test.go @@ -3,7 +3,7 @@ package keccakf import ( - "math/rand" + "math/rand/v2" "testing" "github.com/consensys/linea-monorepo/prover/maths/field" @@ -15,7 +15,7 @@ func TestU64FromToBase(t *testing.T) { const numCases int = 100 // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rnd := rand.New(rand.NewSource(0)) + rnd := rand.New(rand.NewChaCha8([32]byte{})) base1 := field.NewElement(uint64(BaseA)) base2 := field.NewElement(uint64(BaseB)) @@ -61,7 +61,7 @@ func TestBaseDecomposeRecompose(t *testing.T) { const numCases int = 100 // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rnd := rand.New(rand.NewSource(0)) + rnd := rand.New(rand.NewChaCha8([32]byte{})) base1 := field.NewElement(uint64(BaseA)) base2 := field.NewElement(uint64(BaseB)) @@ -93,7 +93,7 @@ func TestDecomposeInSlice(t *testing.T) { const numCases int = 100 // #nosec G404 --we don't need a cryptographic RNG for testing purpose - rnd := rand.New(rand.NewSource(0)) + rnd := rand.New(rand.NewChaCha8([32]byte{})) base1 := field.NewElement(uint64(BaseA)) base2 := field.NewElement(uint64(BaseB)) diff --git a/prover/zkevm/prover/hash/packing/utils_for_test.go b/prover/zkevm/prover/hash/packing/utils_for_test.go index 0e715258c..0c80eb7f2 100644 --- a/prover/zkevm/prover/hash/packing/utils_for_test.go +++ b/prover/zkevm/prover/hash/packing/utils_for_test.go @@ -1,7 +1,7 @@ package packing import ( - "math/rand" + "math/rand/v2" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/common/vector" @@ -27,6 +27,7 @@ func table(t *dataTraceImported, numHash, blockSize, size int) [][]byte { limbs = make([][][]byte, numHash) nByte = make([][]int, numHash) isNewHash = make([][]int, numHash) + rand = rand.New(utils.NewRandSource(0)) // nolint ) // build the stream for each hash. @@ -39,17 +40,17 @@ func table(t *dataTraceImported, numHash, blockSize, size int) [][]byte { m := size / (numHash * 15) // number of limbs for the current hash // added +1 to prevent edge-cases - nlimb := rand.Intn(m) + 1 //nolint + nlimb := rand.IntN(m) + 1 //nolint s[i] = 0 for j := 0; j < nlimb; j++ { // generate random bytes // choose a random length for the slice - length := rand.Intn(MAXNBYTE) + 1 //nolint + length := rand.IntN(MAXNBYTE) + 1 //nolint // generate random bytes slice := make([]byte, length) - _, err := rand.Read(slice) //nolint + _, err := utils.ReadPseudoRand(rand, slice) if err != nil { logrus.Fatalf("error while generating random bytes: %s", err) } @@ -77,7 +78,7 @@ func table(t *dataTraceImported, numHash, blockSize, size int) [][]byte { for n > MAXNBYTE { // generate random bytes slice := make([]byte, MAXNBYTE) - _, err := rand.Read(slice) //nolint + _, err := utils.ReadPseudoRand(rand, slice) if err != nil { logrus.Fatalf("error while generating random bytes: %s", err) } @@ -93,7 +94,7 @@ func table(t *dataTraceImported, numHash, blockSize, size int) [][]byte { } // generate random bytes slice := make([]byte, n) - _, err := rand.Read(slice) //nolint + _, err := utils.ReadPseudoRand(rand, slice) if err != nil { logrus.Fatalf("error while generating random bytes: %s", err) } diff --git a/prover/zkevm/prover/modexp/testdata/main.go b/prover/zkevm/prover/modexp/testdata/main.go index 25592da11..a0fc78138 100644 --- a/prover/zkevm/prover/modexp/testdata/main.go +++ b/prover/zkevm/prover/modexp/testdata/main.go @@ -4,7 +4,7 @@ import ( "fmt" "io" "math/big" - "math/rand" + "math/rand/v2" "github.com/consensys/gnark/std/math/emulated/emparams" "github.com/consensys/linea-monorepo/prover/backend/files" @@ -29,7 +29,7 @@ var testCases = []struct { var ( tab = make([][]*big.Int, 5) - rng = rand.New(rand.NewSource(87987559)) + rng = rand.New(rand.NewChaCha8([32]byte{})) inst = createRandomModexp(rng, false) ) @@ -43,7 +43,7 @@ var testCases = []struct { var ( tab = make([][]*big.Int, 5) - rng = rand.New(rand.NewSource(324480342)) + rng = rand.New(rand.NewChaCha8([32]byte{})) inst = createRandomModexp(rng, true) ) diff --git a/prover/zkevm/prover/statemanager/codehashconsistency/assign.go b/prover/zkevm/prover/statemanager/codehashconsistency/assign.go new file mode 100644 index 000000000..d46554f7f --- /dev/null +++ b/prover/zkevm/prover/statemanager/codehashconsistency/assign.go @@ -0,0 +1,198 @@ +package codehashconsistency + +import ( + "slices" + + "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" + "github.com/consensys/linea-monorepo/prover/zkevm/prover/common" +) + +// Assign assigns the columns internally defined in `mod` into `run`. +func (mod Module) Assign(run *wizard.ProverRuntime) { + + var ( + ssInput = mod.StateSummaryInput + mchInput = mod.MimcCodeHashInput + ) + + externalSs := struct { + IsActive smartvectors.SmartVector + IsStorage smartvectors.SmartVector + InitMiMC smartvectors.SmartVector + InitKeccakLo smartvectors.SmartVector + InitKeccakHi smartvectors.SmartVector + FinalMiMC smartvectors.SmartVector + FinalKeccakLo smartvectors.SmartVector + FinalKeccakHi smartvectors.SmartVector + }{ + IsActive: ssInput.IsActive.GetColAssignment(run), + IsStorage: ssInput.IsStorage.GetColAssignment(run), + InitMiMC: ssInput.Account.Initial.MiMCCodeHash.GetColAssignment(run), + InitKeccakHi: ssInput.Account.Initial.KeccakCodeHash.Hi.GetColAssignment(run), + InitKeccakLo: ssInput.Account.Initial.KeccakCodeHash.Lo.GetColAssignment(run), + FinalMiMC: ssInput.Account.Final.MiMCCodeHash.GetColAssignment(run), + FinalKeccakHi: ssInput.Account.Final.KeccakCodeHash.Hi.GetColAssignment(run), + FinalKeccakLo: ssInput.Account.Final.KeccakCodeHash.Lo.GetColAssignment(run), + } + + externalRom := struct { + IsActive smartvectors.SmartVector + IsHashEnd smartvectors.SmartVector + NewState smartvectors.SmartVector + CodeHashHi smartvectors.SmartVector + CodeHashLo smartvectors.SmartVector + }{ + IsActive: mchInput.IsActive.GetColAssignment(run), + IsHashEnd: mchInput.IsHashEnd.GetColAssignment(run), + NewState: mchInput.NewState.GetColAssignment(run), + CodeHashHi: mchInput.CodeHashHi.GetColAssignment(run), + CodeHashLo: mchInput.CodeHashLo.GetColAssignment(run), + } + + var ( + ssData = make([][3]field.Element, 0, 2*externalSs.InitMiMC.Len()) + romData = make([][3]field.Element, 0, externalRom.IsHashEnd.Len()) + ) + + for i := 0; i < externalSs.InitMiMC.Len(); i++ { + + if isActive := externalSs.IsActive.Get(i); isActive.IsZero() { + break + } + + if isStorage := externalSs.IsStorage.Get(i); isStorage.IsOne() { + continue + } + + ssData = append(ssData, + [3]field.Element{ + externalSs.InitMiMC.Get(i), + externalSs.InitKeccakHi.Get(i), + externalSs.InitKeccakLo.Get(i), + }, + [3]field.Element{ + externalSs.FinalMiMC.Get(i), + externalSs.FinalKeccakHi.Get(i), + externalSs.FinalKeccakLo.Get(i), + }, + ) + } + + for i := 0; i < externalRom.NewState.Len(); i++ { + + if isActive := externalRom.IsActive.Get(i); isActive.IsZero() { + break + } + + if isHashEnd := externalRom.IsHashEnd.Get(i); isHashEnd.IsZero() { + continue + } + + romData = append(romData, + [3]field.Element{ + externalRom.NewState.Get(i), + externalRom.CodeHashHi.Get(i), + externalRom.CodeHashLo.Get(i), + }, + ) + } + + cmp := func(a, b [3]field.Element) int { + if res := a[1].Cmp(&b[1]); res != 0 { + return res + } + return a[2].Cmp(&b[2]) + } + + slices.SortFunc(ssData, cmp) + slices.SortFunc(romData, cmp) + ssData = slices.Compact(ssData) + romData = slices.Compact(romData) + ssData = slices.Clip(ssData) + romData = slices.Clip(romData) + + assignment := struct { + IsActive *common.VectorBuilder + StateSumKeccak common.HiLoAssignmentBuilder + StateSumMiMC *common.VectorBuilder + RomKeccak common.HiLoAssignmentBuilder + RomMiMC *common.VectorBuilder + RomOngoing *common.VectorBuilder + StateSumOngoing *common.VectorBuilder + }{ + IsActive: common.NewVectorBuilder(mod.IsActive), + StateSumKeccak: common.NewHiLoAssignmentBuilder(mod.StateSumKeccak), + RomKeccak: common.NewHiLoAssignmentBuilder(mod.RomKeccak), + StateSumMiMC: common.NewVectorBuilder(mod.StateSumMiMC), + RomMiMC: common.NewVectorBuilder(mod.RomMiMC), + RomOngoing: common.NewVectorBuilder(mod.RomOngoing), + StateSumOngoing: common.NewVectorBuilder(mod.StateSumOngoing), + } + + var ( + cRom int = 0 + cSS int = 0 + nbRowMax = len(romData) + len(ssData) + ) + +assign_loop: + for i := 0; i < nbRowMax; i++ { + + var ( + romRow = romData[cRom] + ssRow = ssData[cSS] + romCmpSs = cmp(romRow, ssRow) + ) + + assignment.IsActive.PushOne() + assignment.RomMiMC.PushField(romRow[0]) + assignment.RomKeccak.Hi.PushField(romRow[1]) + assignment.RomKeccak.Lo.PushField(romRow[2]) + assignment.RomOngoing.PushBoolean(cRom < len(romData)-1) + assignment.StateSumMiMC.PushField(ssRow[0]) + assignment.StateSumKeccak.Hi.PushField(ssRow[1]) + assignment.StateSumKeccak.Lo.PushField(ssRow[2]) + assignment.StateSumOngoing.PushBoolean(cSS < len(ssData)-1) + + var ( + isLastSS = cSS >= len(ssData)-1 + isLastRom = cRom >= len(romData)-1 + ) + + switch { + case isLastSS && isLastRom: + break assign_loop + case !isLastSS && isLastRom: + cSS++ + case isLastSS && !isLastRom: + cRom++ + case romCmpSs < 0: + cRom++ + case romCmpSs == 0: + cRom++ + cSS++ + case romCmpSs > 0: + cSS++ + } + } + + assignment.IsActive.PadAndAssign(run, field.Zero()) + assignment.RomMiMC.PadAndAssign(run, field.Zero()) + assignment.RomKeccak.Hi.PadAndAssign(run, field.Zero()) + assignment.RomKeccak.Lo.PadAndAssign(run, field.Zero()) + assignment.RomOngoing.PadAndAssign(run, field.Zero()) + assignment.StateSumMiMC.PadAndAssign(run, field.Zero()) + assignment.StateSumKeccak.Hi.PadAndAssign(run, field.Zero()) + assignment.StateSumKeccak.Lo.PadAndAssign(run, field.Zero()) + assignment.StateSumOngoing.PadAndAssign(run, field.Zero()) + + mod.CptStateSumKeccakLimbsHi.Run(run) + mod.CptStateSumKeccakLimbsLo.Run(run) + mod.CptRomKeccakLimbsHi.Run(run) + mod.CptRomKeccakLimbsLo.Run(run) + mod.CmpStateSumLimbs.Run(run) + mod.CmpRomLimbs.Run(run) + mod.CmpRomVsStateSumLimbs.Run(run) +} diff --git a/prover/zkevm/prover/statemanager/codehashconsistency/consistency.go b/prover/zkevm/prover/statemanager/codehashconsistency/consistency.go new file mode 100644 index 000000000..bc1fe0f90 --- /dev/null +++ b/prover/zkevm/prover/statemanager/codehashconsistency/consistency.go @@ -0,0 +1,307 @@ +// codehashconsistency implements the necessary constraints to enforce consistency +// between the mimccodehash module and the statesummary module. The constraints +// generated in this package essentially aim at ensuring that +package codehashconsistency + +import ( + "github.com/consensys/linea-monorepo/prover/protocol/column" + "github.com/consensys/linea-monorepo/prover/protocol/dedicated/byte32cmp" + "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" + sym "github.com/consensys/linea-monorepo/prover/symbolic" + "github.com/consensys/linea-monorepo/prover/zkevm/prover/common" + commonconstraints "github.com/consensys/linea-monorepo/prover/zkevm/prover/common/common_constraints" + "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/mimccodehash" + "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/statesummary" +) + +// Module stores the column expressing the consistency between the +// [mimccodehash.Module] (computing the MiMCCodeHash from the code in the ROM +// module and exposing the corresponding codehash) and the [statesummary.Module] +// (recording the access to the state, thus holding the KeccakCodeHash and the +// MiMCCode hash of the registered contracts). The consistency check is achieved +// by ensuring that if a Keccak is present in both the MiMCCodeHash and the +// StateSummary, then the corresponding KeccakCodeHash must be equal. This +// ensures that code exposed in the ROM module is the same as what is in the +// state. +type Module struct { + StateSummaryInput *statesummary.Module + MimcCodeHashInput *mimccodehash.Module + + IsActive ifaces.Column + StateSumKeccak common.HiLoColumns + StateSumMiMC ifaces.Column + StateSumOngoing ifaces.Column + RomKeccak common.HiLoColumns + RomMiMC ifaces.Column + RomOngoing ifaces.Column + + StateSumKeccakLimbs byte32cmp.LimbColumns + RomKeccakLimbs byte32cmp.LimbColumns + + CptStateSumKeccakLimbsHi wizard.ProverAction + CptStateSumKeccakLimbsLo wizard.ProverAction + CptRomKeccakLimbsHi wizard.ProverAction + CptRomKeccakLimbsLo wizard.ProverAction + CmpStateSumLimbs wizard.ProverAction + CmpRomLimbs wizard.ProverAction + CmpRomVsStateSumLimbs wizard.ProverAction + + StateSumIsGtRom, StateSumIsEqRom, StateSumIsLtRom ifaces.Column + StateSumIsConst, StateSumIncreased ifaces.Column + RomIsConst, RomIncreased ifaces.Column +} + +// NewModule returns a constrained [Module] connecting `ss` with `mch`. `name` +// is used as a prefix for the name of all the generated columns and constraints. +func NewModule(comp *wizard.CompiledIOP, name string, ss *statesummary.Module, mch *mimccodehash.Module) Module { + + name = name + "_CODEHASH_CONSISTENCY" + size := ss.IsActive.Size() + mch.IsActive.Size() + + ch := Module{ + StateSummaryInput: ss, + MimcCodeHashInput: mch, + IsActive: comp.InsertCommit(0, ifaces.ColIDf(name+"_IS_ACTIVE"), size), + StateSumKeccak: common.NewHiLoColumns(comp, size, name+"_STATE_SUMMARY_KECCAK"), + RomKeccak: common.NewHiLoColumns(comp, size, name+"_ROM_KECCAK"), + StateSumMiMC: comp.InsertCommit(0, ifaces.ColID(name+"_STATE_SUMMARY_MIMC"), size), + RomMiMC: comp.InsertCommit(0, ifaces.ColID(name+"_ROM_MIMC"), size), + RomOngoing: comp.InsertCommit(0, ifaces.ColID(name+"_ROM_ONGOING"), size), + StateSumOngoing: comp.InsertCommit(0, ifaces.ColID(name+"_STATE_SUM_ONGOING"), size), + } + + commonconstraints.MustBeActivationColumns(comp, ch.IsActive) + commonconstraints.MustBeActivationColumns(comp, ch.RomOngoing) + commonconstraints.MustBeActivationColumns(comp, ch.StateSumOngoing) + + commonconstraints.MustZeroWhenInactive(comp, ch.IsActive, + ch.StateSumKeccak.Hi, + ch.StateSumKeccak.Lo, + ch.StateSumMiMC, + ch.StateSumOngoing, + ch.RomKeccak.Hi, + ch.RomKeccak.Lo, + ch.RomMiMC, + ch.RomOngoing, + ) + + var ( + romDecreased ifaces.Column + stateSumDecreased ifaces.Column + romLimbsHi, romLimbsLo byte32cmp.LimbColumns + stateSumLimbsHi, stateSumLimbsLo byte32cmp.LimbColumns + ) + + romLimbsHi, ch.CptRomKeccakLimbsHi = byte32cmp.Decompose(comp, ch.RomKeccak.Hi, 8, 16) + romLimbsLo, ch.CptRomKeccakLimbsLo = byte32cmp.Decompose(comp, ch.RomKeccak.Lo, 8, 16) + stateSumLimbsHi, ch.CptStateSumKeccakLimbsHi = byte32cmp.Decompose(comp, ch.StateSumKeccak.Hi, 8, 16) + stateSumLimbsLo, ch.CptStateSumKeccakLimbsLo = byte32cmp.Decompose(comp, ch.StateSumKeccak.Lo, 8, 16) + ch.RomKeccakLimbs = byte32cmp.FuseLimbs(romLimbsLo, romLimbsHi) + ch.StateSumKeccakLimbs = byte32cmp.FuseLimbs(stateSumLimbsLo, stateSumLimbsHi) + + ch.RomIncreased, ch.RomIsConst, romDecreased, ch.CmpRomLimbs = byte32cmp.CmpMultiLimbs( + comp, + ch.RomKeccakLimbs, + ch.RomKeccakLimbs.Shift(-1), + ) + + ch.StateSumIncreased, ch.StateSumIsConst, stateSumDecreased, ch.CmpStateSumLimbs = byte32cmp.CmpMultiLimbs( + comp, + ch.StateSumKeccakLimbs, + ch.StateSumKeccakLimbs.Shift(-1), + ) + + ch.StateSumIsGtRom, ch.StateSumIsEqRom, ch.StateSumIsLtRom, ch.CmpRomVsStateSumLimbs = byte32cmp.CmpMultiLimbs( + comp, + ch.StateSumKeccakLimbs, + ch.RomKeccakLimbs, + ) + + comp.InsertGlobal( + 0, + ifaces.QueryID(name+"_ROM_IS_SORTED"), + sym.Mul(ch.IsActive, romDecreased), + ) + + comp.InsertGlobal( + 0, + ifaces.QueryID(name+"_STATE_SUMMARY_IS_SORTED"), + sym.Mul(ch.IsActive, stateSumDecreased), + ) + + // This constraint ensures that the state summary cursor. Is correctly + // updated. It follows the following rules: + // + // NB: Since we have sorting constraints. We know that ROM and SS may + // only increase or stay constant. Therefore, enforcing the constant + // + // switch { + // case IsActive == 0: + // // No constraints applied + // case IsSSOngoing == 0: + // assert ssMustBeConstant == 1 + // case ss > rom: + // assert ssMustBeConstant == 1 + // else: + // assert ssMustBeConstant == 0 + // } + // + // The reciproqual constraint is enforced over the ROM module. + comp.InsertGlobal( + 0, + ifaces.QueryID(name+"_STATE_SUM_STAY_SAME"), + sym.Mul( + ch.IsActive, + sym.Sub( + column.Shift(ch.StateSumIsConst, 1), + sym.Mul( + ch.RomOngoing, + sym.Add( + sym.Sub(1, ch.StateSumOngoing), + sym.Mul( + ch.StateSumOngoing, + ch.StateSumIsGtRom, + ), + ), + ), + ), + ), + ) + + comp.InsertGlobal( + 0, + ifaces.QueryID(name+"_ROM_STAY_SAME"), + sym.Mul( + ch.IsActive, + sym.Sub( + ch.RomIsConst, + sym.Mul( + column.Shift(ch.StateSumOngoing, -1), + sym.Add( + sym.Sub(1, column.Shift(ch.RomOngoing, -1)), + sym.Mul( + column.Shift(ch.RomOngoing, -1), + column.Shift(ch.StateSumIsLtRom, -1), + ), + ), + ), + ), + ), + ) + + comp.InsertGlobal( + 0, + ifaces.QueryID(name+"_KECCAK_CONSISTENCY_HI"), + sym.Mul( + ch.StateSumIsEqRom, + sym.Sub(ch.RomKeccak.Hi, ch.StateSumKeccak.Hi), + ), + ) + + comp.InsertGlobal( + 0, + ifaces.QueryID(name+"_KECCAK_CONSISTENCY_LO"), + sym.Mul( + ch.StateSumIsEqRom, + sym.Sub(ch.RomKeccak.Lo, ch.StateSumKeccak.Lo), + ), + ) + + comp.GenericFragmentedConditionalInclusion( + 0, + ifaces.QueryID(name+"_IMPORT_STATE_SUMMARY_BACK"), + [][]ifaces.Column{ + { + ss.Account.Initial.MiMCCodeHash, + ss.Account.Initial.KeccakCodeHash.Hi, + ss.Account.Initial.KeccakCodeHash.Lo, + }, + { + ss.Account.Final.MiMCCodeHash, + ss.Account.Final.KeccakCodeHash.Hi, + ss.Account.Final.KeccakCodeHash.Lo, + }, + }, + []ifaces.Column{ + ch.StateSumMiMC, + ch.StateSumKeccak.Hi, + ch.StateSumKeccak.Lo, + }, + []ifaces.Column{ + ss.IsActive, + ss.IsActive, + }, + ch.IsActive, + ) + + comp.InsertInclusionDoubleConditional( + 0, + ifaces.QueryIDf(name+"_IMPORT_STATE_SUMMARY_FORTH_INITIAL"), + []ifaces.Column{ + ch.StateSumMiMC, + ch.StateSumKeccak.Hi, + ch.StateSumKeccak.Lo, + }, + []ifaces.Column{ + ss.Account.Initial.MiMCCodeHash, + ss.Account.Initial.KeccakCodeHash.Hi, + ss.Account.Initial.KeccakCodeHash.Lo, + }, + ch.IsActive, + ss.IsActive, + ) + + comp.InsertInclusionDoubleConditional( + 0, + ifaces.QueryIDf(name+"_IMPORT_STATE_SUMMARY_FORTH_FINAL"), + []ifaces.Column{ + ch.StateSumMiMC, + ch.StateSumKeccak.Hi, + ch.StateSumKeccak.Lo, + }, + []ifaces.Column{ + ss.Account.Final.MiMCCodeHash, + ss.Account.Final.KeccakCodeHash.Hi, + ss.Account.Final.KeccakCodeHash.Lo, + }, + ch.IsActive, + ss.IsActive, + ) + + comp.InsertInclusionDoubleConditional( + 0, + ifaces.QueryIDf(name+"_IMPORT_MIMC_CODE_HASH_FORTH"), + []ifaces.Column{ + ch.RomMiMC, + ch.RomKeccak.Hi, + ch.RomKeccak.Lo, + }, + []ifaces.Column{ + mch.NewState, + mch.CodeHashHi, + mch.CodeHashLo, + }, + ch.IsActive, + mch.IsHashEnd, + ) + + comp.InsertInclusionDoubleConditional( + 0, + ifaces.QueryIDf(name+"_IMPORT_MIMC_CODE_HASH_BACK"), + []ifaces.Column{ + mch.NewState, + mch.CodeHashHi, + mch.CodeHashLo, + }, + []ifaces.Column{ + ch.RomMiMC, + ch.RomKeccak.Hi, + ch.RomKeccak.Lo, + }, + mch.IsHashEnd, + ch.IsActive, + ) + + return ch +} diff --git a/prover/zkevm/prover/statemanager/codehashconsistency/consistency_test.go b/prover/zkevm/prover/statemanager/codehashconsistency/consistency_test.go new file mode 100644 index 000000000..79039067f --- /dev/null +++ b/prover/zkevm/prover/statemanager/codehashconsistency/consistency_test.go @@ -0,0 +1,240 @@ +package codehashconsistency + +import ( + "fmt" + "math/rand/v2" + "slices" + "testing" + + "github.com/consensys/linea-monorepo/prover/backend/files" + "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/dummy" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" + "github.com/consensys/linea-monorepo/prover/utils" + "github.com/consensys/linea-monorepo/prover/utils/csvtraces" + "github.com/consensys/linea-monorepo/prover/zkevm/prover/common" + "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/mimccodehash" + "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/statesummary" +) + +func TestConsistency(t *testing.T) { + + var ( + stateSummary *statesummary.Module + mimcCodeHash *mimccodehash.Module + consistency Module + sizeStateSummary = 128 + sizeMimcCodeHash = 128 + ) + + define := func(b *wizard.Builder) { + + stateSummary = &statesummary.Module{ + IsActive: b.InsertCommit(0, "SS_IS_ACTIVE", sizeStateSummary), + IsStorage: b.InsertCommit(0, "SS_IS_STORAGE", sizeStateSummary), + Account: statesummary.AccountPeek{ + Initial: statesummary.Account{ + KeccakCodeHash: common.NewHiLoColumns(b.CompiledIOP, sizeStateSummary, "SS_INITIAL_KECCAK"), + MiMCCodeHash: b.InsertCommit(0, "SS_INITIAL_MIMC", sizeStateSummary), + }, + Final: statesummary.Account{ + KeccakCodeHash: common.NewHiLoColumns(b.CompiledIOP, sizeStateSummary, "SS_FINAL_KECCAK"), + MiMCCodeHash: b.InsertCommit(0, "SS_FINAL_MIMC", sizeStateSummary), + }, + }, + } + + mimcCodeHash = &mimccodehash.Module{ + IsActive: b.InsertCommit(0, "MCH_IS_ACTIVE", sizeMimcCodeHash), + IsHashEnd: b.InsertCommit(0, "MCH_IS_HASH_END", sizeMimcCodeHash), + NewState: b.InsertCommit(0, "MCH_NEW_STATE", sizeMimcCodeHash), + CodeHashHi: b.InsertCommit(0, "MCH_KECCAK_HI", sizeMimcCodeHash), + CodeHashLo: b.InsertCommit(0, "MCH_KECCAK_LO", sizeMimcCodeHash), + } + + consistency = NewModule(b.CompiledIOP, "CONSISTENCY", stateSummary, mimcCodeHash) + } + + prover := func(run *wizard.ProverRuntime) { + + mchCt := csvtraces.MustOpenCsvFile("testdata/mimc-codehash.csv") + ssCt := csvtraces.MustOpenCsvFile("testdata/state-summary.csv") + + run.AssignColumn(mimcCodeHash.IsActive.GetColID(), smartvectors.RightZeroPadded(mchCt.Get("IS_ACTIVE"), sizeMimcCodeHash)) + run.AssignColumn(mimcCodeHash.IsHashEnd.GetColID(), smartvectors.RightZeroPadded(mchCt.Get("IS_HASH_END"), sizeMimcCodeHash)) + run.AssignColumn(mimcCodeHash.NewState.GetColID(), smartvectors.RightZeroPadded(mchCt.Get("NEW_STATE"), sizeMimcCodeHash)) + run.AssignColumn(mimcCodeHash.CodeHashHi.GetColID(), smartvectors.RightZeroPadded(mchCt.Get("KECCAK_HI"), sizeMimcCodeHash)) + run.AssignColumn(mimcCodeHash.CodeHashLo.GetColID(), smartvectors.RightZeroPadded(mchCt.Get("KECCAK_LO"), sizeMimcCodeHash)) + + run.AssignColumn(stateSummary.IsActive.GetColID(), smartvectors.RightZeroPadded(ssCt.Get("IS_ACTIVE"), sizeStateSummary)) + run.AssignColumn(stateSummary.IsStorage.GetColID(), smartvectors.RightZeroPadded(ssCt.Get("IS_STORAGE"), sizeStateSummary)) + run.AssignColumn(stateSummary.Account.Initial.MiMCCodeHash.GetColID(), smartvectors.RightZeroPadded(ssCt.Get("INITIAL_MIMC"), sizeStateSummary)) + run.AssignColumn(stateSummary.Account.Final.MiMCCodeHash.GetColID(), smartvectors.RightZeroPadded(ssCt.Get("FINAL_MIMC"), sizeStateSummary)) + run.AssignColumn(stateSummary.Account.Initial.KeccakCodeHash.Hi.GetColID(), smartvectors.RightZeroPadded(ssCt.Get("INITIAL_KECCAK_HI"), sizeStateSummary)) + run.AssignColumn(stateSummary.Account.Final.KeccakCodeHash.Hi.GetColID(), smartvectors.RightZeroPadded(ssCt.Get("FINAL_KECCAK_HI"), sizeStateSummary)) + run.AssignColumn(stateSummary.Account.Initial.KeccakCodeHash.Lo.GetColID(), smartvectors.RightZeroPadded(ssCt.Get("INITIAL_KECCAK_LO"), sizeStateSummary)) + run.AssignColumn(stateSummary.Account.Final.KeccakCodeHash.Lo.GetColID(), smartvectors.RightZeroPadded(ssCt.Get("FINAL_KECCAK_LO"), sizeStateSummary)) + + consistency.Assign(run) + } + + comp := wizard.Compile(define, dummy.CompileAtProverLvl) + _ = wizard.Prove(comp, prover) + +} + +// TestCaseGeneration generates testdata csv and does not test anything per se. +// To re-generate the testcases, you need to unskip it. +func TestCaseGeneration(t *testing.T) { + + t.Skip() + + var ( + rng = rand.New(utils.NewRandSource(67569)) // nolint + shared = [][3]field.Element{} + numSharedRow = 1 + numStateSummaryRow = 128 + numCodeHashRow = 128 + ) + + randRow := func() [3]field.Element { + row := [3]field.Element{} + row[0] = field.PseudoRand(rng) + row[1] = field.PseudoRandTruncated(rng, 16) + row[2] = field.PseudoRandTruncated(rng, 16) + return row + } + + for i := 0; i < numSharedRow; i++ { + shared = append(shared, randRow()) + } + + var ( + ssIsActive = make([]field.Element, 0) + ssIsStorage = make([]field.Element, 0) + ssInitMimc = make([]field.Element, 0) + ssInitKeccakHi = make([]field.Element, 0) + ssInitKeccakLo = make([]field.Element, 0) + ssFinalMimc = make([]field.Element, 0) + ssFinalKeccakHi = make([]field.Element, 0) + ssFinalKeccakLo = make([]field.Element, 0) + ) + + for i := 0; i < numStateSummaryRow; i++ { + + c := rng.IntN(4) + + if i == 0 { + c = 0 + } + + switch { + + default: + + ssIsActive = append(ssIsActive, field.One()) + ssIsStorage = append(ssIsStorage, field.One()) + ssInitMimc = append(ssInitMimc, ssInitMimc[i-1]) + ssInitKeccakHi = append(ssInitKeccakHi, ssInitKeccakHi[i-1]) + ssInitKeccakLo = append(ssInitKeccakLo, ssInitKeccakLo[i-1]) + ssFinalMimc = append(ssFinalMimc, ssFinalMimc[i-1]) + ssFinalKeccakHi = append(ssFinalKeccakHi, ssFinalKeccakHi[i-1]) + ssFinalKeccakLo = append(ssFinalKeccakLo, ssFinalKeccakLo[i-1]) + + case c == 0 || c == 1: + + var newInit, newFinal [3]field.Element + + if c == 0 { + newInit = randRow() + newFinal = randRow() + } + + if c == 1 { + fmt.Printf("row %v of state summary is shared\n", i) + newInit = randChoose(rng, shared) + newFinal = randChoose(rng, shared) + } + + ssIsActive = append(ssIsActive, field.One()) + ssIsStorage = append(ssIsStorage, field.Zero()) + ssInitMimc = append(ssInitMimc, newInit[0]) + ssInitKeccakHi = append(ssInitKeccakHi, newInit[1]) + ssInitKeccakLo = append(ssInitKeccakLo, newInit[2]) + ssFinalMimc = append(ssFinalMimc, newFinal[0]) + ssFinalKeccakHi = append(ssFinalKeccakHi, newFinal[1]) + ssFinalKeccakLo = append(ssFinalKeccakLo, newFinal[2]) + + } + } + + csvtraces.WriteExplicit( + files.MustOverwrite("./testdata/state-summary.csv"), + []string{"IS_ACTIVE", "IS_STORAGE", "INITIAL_MIMC", "INITIAL_KECCAK_HI", "INITIAL_KECCAK_LO", "FINAL_MIMC", "FINAL_KECCAK_HI", "FINAL_KECCAK_LO"}, + [][]field.Element{ssIsActive, ssIsStorage, ssInitMimc, ssInitKeccakHi, ssInitKeccakLo, ssFinalMimc, ssFinalKeccakHi, ssFinalKeccakLo}, + false, + ) + + /* + For the codehash module, the rows are generated in reverse order and + then reverted. + */ + + var ( + romIsActive = make([]field.Element, 0) + romIsHashEnd = make([]field.Element, 0) + romNewState = make([]field.Element, 0) + romKeccakHi = make([]field.Element, 0) + romKeccakLo = make([]field.Element, 0) + ) + + for i := 0; i < numCodeHashRow; i++ { + + c0 := rng.Int64N(4) + + switch { + + case c0 == 0 || c0 == 1 || i == 0: + + row := randRow() + + if c0 == 0 { + fmt.Printf("row %v of rom is shared\n", i) + row = randChoose(rng, shared) + } + + romIsActive = append(romIsActive, field.One()) + romIsHashEnd = append(romIsHashEnd, field.One()) + romNewState = append(romNewState, row[0]) + romKeccakHi = append(romKeccakHi, row[1]) + romKeccakLo = append(romKeccakLo, row[2]) + + default: + + romIsActive = append(romIsActive, field.One()) + romIsHashEnd = append(romIsHashEnd, field.Zero()) + romNewState = append(romNewState, field.PseudoRand(rng)) + romKeccakHi = append(romKeccakHi, romKeccakHi[i-1]) + romKeccakLo = append(romKeccakLo, romKeccakLo[i-1]) + + } + } + + slices.Reverse(romIsActive) + slices.Reverse(romIsHashEnd) + slices.Reverse(romNewState) + slices.Reverse(romKeccakHi) + slices.Reverse(romKeccakLo) + + csvtraces.WriteExplicit( + files.MustOverwrite("./testdata/mimc-codehash.csv"), + []string{"IS_ACTIVE", "IS_HASH_END", "NEW_STATE", "KECCAK_HI", "KECCAK_LO"}, + [][]field.Element{romIsActive, romIsHashEnd, romNewState, romKeccakHi, romKeccakLo}, + false, + ) +} + +func randChoose[T any](rand *rand.Rand, slice []T) T { + return slice[rand.IntN(len(slice))] +} diff --git a/prover/zkevm/prover/statemanager/codehashconsistency/testdata/mimc-codehash.csv b/prover/zkevm/prover/statemanager/codehashconsistency/testdata/mimc-codehash.csv new file mode 100644 index 000000000..ca7682206 --- /dev/null +++ b/prover/zkevm/prover/statemanager/codehashconsistency/testdata/mimc-codehash.csv @@ -0,0 +1,129 @@ +IS_ACTIVE,IS_HASH_END,NEW_STATE,KECCAK_HI,KECCAK_LO +1,1,0x2832c4ca6424810b7f8962bc82b269b30ba0ef55d7af69bf1b477ab403738c2,0x14aea944ed77b7b1fe8683f5bceacf51,0xd781f7985b442e59127381e5e1c05ade +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x2d349ff43a8c9e143fb581eb8525fae26eb4698c2227dcf0934b4daa8c011c7,0x79714203be4ed636b9108ae8d2374bf0,0x9550a055dc182cc874974f93de508583 +1,0,0x9cea234e3013dfff332601b7a571d594e2fe104822879fc503287528b9fc229,0x79714203be4ed636b9108ae8d2374bf0,0x9550a055dc182cc874974f93de508583 +1,1,0x2e84cb4461e289664e59e3d9689d1ab5a64224aee8929d13df4b726a594cfa1,0x79714203be4ed636b9108ae8d2374bf0,0x9550a055dc182cc874974f93de508583 +1,1,0x83610901e4d6e423b977de6696ae0f49d777231edb2444e9f5fd85e2b8ea60e,0x62024c1946f6ef2cca948fff887bf5e6,0x265d12d57cae301508760a4347fd49e0 +1,1,0x4ab59828ffb92e9f4f98b451e5e21bc24ef98aa84e0727dd95a9546f8c3d304,0xf254e78911585001cb46af647d7622c8,0x7415588aae25591d2596e6dca43a7ddf +1,0,0x95cabdc9867300211ab7dbe40ba6558a34373fc43e3a8afff2aa7edf84d53fd,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x86d360f854e36ef6aa79ecb4d254ecc393b7295b3d8b642abb002067aa35c9,0xff3b4bbf1228d0c66480ca570c0e2836,0xc489dc71db537c73d66b87d03bdbadc8 +1,1,0x5b3e9eca9a53197f90ddee92b9b14f8f6b910df230d2815a256406d0cdd8cc6,0xff3b4bbf1228d0c66480ca570c0e2836,0xc489dc71db537c73d66b87d03bdbadc8 +1,1,0xc0fd1538796df9e10ece1c3f56ed3786b2bd0a88b2213cb34e1e2c60940b8a4,0x9c61c6bd7f2a04447c79a8fc9b0c2542,0x8adf86a6f00a42efe3c59de42cb52954 +1,1,0xb659e67c989e3042f5dcde437847ca8fb3c8d61a3ece108ffa6f30f1d85ce91,0xe979e4e4fa4dcdfe83b9a7e45ff551f5,0x84f1e54c209cf5cee0ecec07201fbef5 +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x9f6797210b6ad51600bea6b7c84f6a8edf91528ecc39f2a64e76d1f653d92c4,0x66d12a9ed27c6badbdd47d6f9f694f56,0xa4e060f3be117d1aaddd96ee3cb14b2d +1,1,0x8b1bd6f6d708525938bb8a0f7bbe7ef1be37360cb77eb5eac04fa4948bd8878,0x66d12a9ed27c6badbdd47d6f9f694f56,0xa4e060f3be117d1aaddd96ee3cb14b2d +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xeb866994597936bcb901c618e2a33b2dc0124e176405a5d264da72940cc2bb0,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x3a43057017bfbe3358f142dd414030e7c0bfe7565317a69c6883720c28a8f3a,0xd8d36d61114978569cfb0199ee1d7f89,0x79370627678d3ce3d0336b5d09979af2 +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xc49ebe8cc964ee24639ff4e52c053e2406265248c2f6e80dc9b094546c21c29,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xdc33289e546f939ce305d269f858d8da8764c5ef76831e2cb256115a65d4223,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x4c5a10ed4d4b1b04e2de461cf74c2b44d8a5f0d3463b1c1d7af87a1ca586f61,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xba751799d1bf7693ed86043ed16cec019bc1b5417f30fb81064347b8627dba9,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x43b9a75a4215934287b0ea6d936e1744d66af5eef2eec8eaa5c66a2b271757f,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xe91925d8b82ef3c5c634087e397067b68b37db97863c1f5f7ac9462fb9a0b7d,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xf855e8e20a4867d003c3ad42629898ad85bc647adc3051ae64da9f3b8f32889,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0xfd076eea08f46488cd6ae79d08e6fefd9d82b2045971a5a52c2b0e5698bb460,0xafe9d65cfc166cfd7bf46af3ff89bbd9,0xa996ba5b978e216f47c131e3da674bfd +1,0,0x1e4527158c19df59e9c4c108043e5524dd230d3919e83cc319285064e39a74,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x651f9296bb93ebc637cd3c26379038cd54f07953f233aebddb79e5503fdb356,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xf1446709c16ae1525f9660abd09488d2b47179c36be377a29a90fa99196c35c,0x1855a6982578165d87740597f9b5b35d,0x6d23598e46804cd51ffdd3d0feb3932b +1,0,0x12a77a3afbf21a1e416da88d9de3d75626cde62980c668699fd6d4f09351306b,0x1855a6982578165d87740597f9b5b35d,0x6d23598e46804cd51ffdd3d0feb3932b +1,1,0x30138b2bae643aaaab03506a166acff657d24dfe95c0a67f9723b2e6ed23767,0x1855a6982578165d87740597f9b5b35d,0x6d23598e46804cd51ffdd3d0feb3932b +1,0,0x8d0bca599168c0b59da7079fca9b61ccc5d21b83c99dc82a0bd8092eedb4445,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0xe252ff12f3524c3745525008b71ae2092eba2f4b4bf6d0b8ab3889403d3cd1a,0xda6e402480a0e50b12c65f6cc8031e1d,0xa2c277adb351c991bcf6439af30e4f12 +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x71dafcf5ec63b13644306bb71c4ac57d8e470342e9bcd552c326c5a17ceff37,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x58ebd1e380fe9eda18409805958f386cb28cb422bf89af79e0721cbf4f79d5a,0xcfaa71df93a51358961acd94eade8647,0xccaaf1c0ace15f2125c4e5cda0b0d7b8 +1,0,0xf7744edaa8ace0b289f7e9751e18fafc3913d5a4b06eb4a06c28d6eae237499,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xe1d6cfb1b4787f2d032eb859ecc832bc3d0e3c5aff68652dabbc4571f6ee860,0x52c3503b81f0862b427f462e5826de1d,0x4111819ba5d8cb87a26d03d9b824cd11 +1,1,0xf5613c070ed5380836be1c4c23564fd5cfe5f8a153b64fd540c7b8a005a85f3,0x52c3503b81f0862b427f462e5826de1d,0x4111819ba5d8cb87a26d03d9b824cd11 +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x59dc511f08afcdd19fa81e7cbcdaab89a34ff15e7a8f8361819f091e03f066f,0x608dcc50caf131c863f66fb8803b946e,0x81ecbb30d1d80da792a099ce60d9f23d +1,0,0xb8a7c39e258ac5156860e807482ac85380cc92e30bc5d30493337ed7e882085,0xbe9c605d31cc61d1a80abfba34c23f7d,0xe2222969e82cdebfc3606f0cd8fd3210 +1,0,0x4824ba59ac9dd9ef4ec514375da692dadfff09657152d62fc1e163d02ee8e62,0xbe9c605d31cc61d1a80abfba34c23f7d,0xe2222969e82cdebfc3606f0cd8fd3210 +1,0,0x12789c7d8d39b691ad989a220caa122bb6ad0cb758c3cfae3ae87f1079173340,0xbe9c605d31cc61d1a80abfba34c23f7d,0xe2222969e82cdebfc3606f0cd8fd3210 +1,0,0x24a2a8dcb04e3d9ccd7bb9163cf0a8ea48f52e10e40b7577468f50c1fb1d23b,0xbe9c605d31cc61d1a80abfba34c23f7d,0xe2222969e82cdebfc3606f0cd8fd3210 +1,0,0x594d891d759672cf94399400de941b2aca2f8c12893cb4fd9ce023bc24d5884,0xbe9c605d31cc61d1a80abfba34c23f7d,0xe2222969e82cdebfc3606f0cd8fd3210 +1,1,0x35d6dd9683da65772f1e94409da6f6d6153fc0149b221ee21c86fd2a62b7907,0xbe9c605d31cc61d1a80abfba34c23f7d,0xe2222969e82cdebfc3606f0cd8fd3210 +1,0,0xb265295621dfe78b8cd5baf103d03bd525f44a438041dc910724747045839ce,0xd184c3b234abf9c001aa33dc2da38984,0xe9590400e3371e7cc35ce26d137c8655 +1,1,0x86eb194f9fea4a90bfaf01b0f812f9c26e2ce828be66e212fd5cceed0d63dd3,0xd184c3b234abf9c001aa33dc2da38984,0xe9590400e3371e7cc35ce26d137c8655 +1,0,0x6b4c61b9fd915922206c893c488f5c773715b8d5f07273afc55d4bf56cd9b56,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x7c1b86150ee642073eb503a5416fc7b7ec037684d4386dc2c01fa823080a3d0,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x30fe890ea08bc033002c91aef5d7cc556a941fbe05be35beda3f2792b76e689,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xae4c7e0fbc1ca6e498e22367231f377539b60418424cd46f59d83b39c56a434,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x12629f3ce50315c2dd153299044e6c74dea3f414bde707d799f4a371786aae3a,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x7dc13a4d0d87827524316d2e28ee9351dc15b86911fa4bf9dbc74ec2d79648a,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x1007f4cd6fddb73047e02851a2fba9a25942480f8945aff4e8f4b0d73c3d8b48,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x8b97314bc36f5c77fa6e8a005116f1c264323ab93c100cfb3a1830c963d4e92,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x1037c9be0c5abfdb9ee38744b7b53864eecc01a04ed41c7b61d69a5f6c20402d,0x2800fbee4994e5e87413b6ac81b9ab33,0x19dd84f1d070a2db6ae6eb2f9eea3ae4 +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x61e24f2334904bddfd66fe043b63adb4b2582fbe6acf5ddb84726dfa4b1071f,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x4c236e58bc754d17fb43941b01e5be3b4b52c1af40c8cf29ca9033c989dc9a,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x121ff96f89ed40a36ce111a38ffe904cfcddd7e7337f243541b34ea9aa8f114d,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xdb64780ef5a0c9ed256b6cc259a64e19c842b145a737901953df038123315cd,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xc40360e0769872ad1c2e6fd332de00fd88ee10422f6bf5dd7af31d3189d70e7,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0xd7b1393e1e10f8b6f7ae30e6edf0a29ff16bbf91f4ee62a117b5fc71d3c1762,0x895fd61778a1fb4ecb2eaa07e76b9048,0xfe50740d246929507c4701670384acd2 +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xfa51ed33ff85797588f9db0733813388a2c87cf8f354ea7d0537dc39967a94c,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x9add699ee09c7b36455fb469e1f0e84c5df2604f497b47e4fec29fff6c0a908,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x688fa1ce962785323203f46b0bcf99b04ed43c65c4ccedb3887f81ba6acbf0e,0xa25a50884042ccead0659689eb4836d9,0xbf9ff925a22083ed7916037b9da66bee +1,1,0x5ab9709a7210e8db93a6ace274ff2760d073ed6102614de4012901dcdd90563,0xa25a50884042ccead0659689eb4836d9,0xbf9ff925a22083ed7916037b9da66bee +1,0,0x122aa98ee30bd3e306fe937f893f99185b64cfb07c35e08203ad9a51a1aed0ec,0xbe393e3c4c4bb3b10890a940dae5efe3,0x836c13ad4c6e5581ff3b2ef1fe19f685 +1,0,0x26dce12d58f59f8464459acfbb4040f5abd91a2b9d329f26524c51697b70058,0xbe393e3c4c4bb3b10890a940dae5efe3,0x836c13ad4c6e5581ff3b2ef1fe19f685 +1,1,0x124eb7f29335d8149a9e4e71194ffd5d7379191c42956374def956fce3a71833,0xbe393e3c4c4bb3b10890a940dae5efe3,0x836c13ad4c6e5581ff3b2ef1fe19f685 +1,0,0xf56f0485ab4e4ea657419840b5323b32f7d0d988cffbae8427f7afc13b1d024,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0xe1bb796d962bb290a645cde8ce683bfbfcaa56245aa5223dcc4c31894e098a4,0x12d63513c76806cdb4df3bb326575ccd,0x226178f429eec54cd1e4da4b37fd621b +1,1,0xce9b88aa3c262a5295a454260226a95ea0a399b1a1b9b313300214d044d339,0x870492b3dba022a599dd29ca7688cb75,0x25bf2cf3bd683b15631ebbb2babf22cb +1,1,0x28ae6bf753e791cba13ec56a48f13d0b11a0af096247bb06a1d0373ce20873,0xe7ed1ae880b7667448c35beeff2723e7,0x76f9e61f4ed0a432f60aa572e4d69903 +1,1,0x7d4fc138a20dec39e390409e7b0cae755d87ca94374170d10849478986ac60f,0x3024311e834a44d1e2fe9d46a5cc830a,0x766b8d0479e1ea7b8bc29da84082aef8 +1,0,0x10002fec9e939c164aa8a413624fe966f1eb5f31a68d7a2b0c663519b7662d8d,0x93941c0cab71d164faa91d2e3bb94c38,0xda9848e163c53204dab35252d3b52373 +1,0,0x10f2d45d2d7f035f8f5a8ac37af77afb43712598b2d598abf83c07b3f3b30d9,0x93941c0cab71d164faa91d2e3bb94c38,0xda9848e163c53204dab35252d3b52373 +1,0,0x1030809553bbc7c634d10ec575a5fde6c85c180e71802f1b9950327ff0f61a9e,0x93941c0cab71d164faa91d2e3bb94c38,0xda9848e163c53204dab35252d3b52373 +1,0,0x9deb075d4a655b278c11c69e23c9daa80c7f3c3eef51af9b519d53d01228e0,0x93941c0cab71d164faa91d2e3bb94c38,0xda9848e163c53204dab35252d3b52373 +1,0,0x4a9fd78a2ba6f48f1a7629320acd8772b3fbdcb8f48febd34434710513a50fa,0x93941c0cab71d164faa91d2e3bb94c38,0xda9848e163c53204dab35252d3b52373 +1,1,0x598b4ac7f2ccbe02940bd695f1156ac10a0f02add432be8119c98f60ec48c3c,0x93941c0cab71d164faa91d2e3bb94c38,0xda9848e163c53204dab35252d3b52373 +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x414094feb06c95dfb5e0a54135627948184ea8a340f01910d873f2439f2a5cb,0x10b75bce54bfe41f2a00a9d265f320a1,0x46c1ded4ac951b6b38af3acde8d790f9 +1,0,0xfaf6558dced12d5503800ab05da53d90664f8399806d7cba504f45c76871817,0x891c6d0bb61e20dad44e37bc8e85ad8c,0xeff2652d4ebc6743ccd98fbb233eadd2 +1,1,0x93709de64583017b641980a46d2800db0bedcc92dca3f606160f653d0fb226c,0x891c6d0bb61e20dad44e37bc8e85ad8c,0xeff2652d4ebc6743ccd98fbb233eadd2 +1,0,0x1146d904e61299dc2def3be6874903c8de1bb2f0a5202d6fefab8ae10245fe4d,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xb4bd12340567230d6fd81f56b05559a67c5d3a3685ec316b4b7482fd8a1d57b,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x83b248f95f4e2ff4b5416e516448fdfd6bb332c9037f11c155f402f402fcaf2,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x21e2c254f6f4524b3d5b715033fcd7b80673f257030c774683d702f73499cb7,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xe91be4276dfcef9c93f11bbd80236d2f9a0f1c1ac59059e71c5ba9b2fa6f1d2,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x8f2e54463630382f8d99954382e04e14cc66c91f2ce2d5ecefd1ed4e3b8e71,0x7d2dd654c588edca159208df14d2026,0x4eca3a942d95b81d30c81254ed3ac29e +1,1,0x133afb2a15866f07b49b94ec54890a4a3ed007fbd291c5dbc3b67d3d6f29e9c,0xb5e69ec4b627b34b6937443ae4d900b,0x6ee7ec06d37c2c28de50e3c98402ba08 +1,0,0x69502ff78daf1e979011b944d272eb7abf23743dc46786dbf7c455de3a52c28,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x12914cc25732698a08ef4ff1740332aa05812a190765c8ab783e4a1c86e9a7a7,0xaf13f09c633136ebdf27cb5dab11db05,0xc7fe7e16f4e5a51d079a248d3cd2df0e diff --git a/prover/zkevm/prover/statemanager/codehashconsistency/testdata/state-summary.csv b/prover/zkevm/prover/statemanager/codehashconsistency/testdata/state-summary.csv new file mode 100644 index 000000000..827022038 --- /dev/null +++ b/prover/zkevm/prover/statemanager/codehashconsistency/testdata/state-summary.csv @@ -0,0 +1,129 @@ +IS_ACTIVE,IS_STORAGE,INITIAL_MIMC,INITIAL_KECCAK_HI,INITIAL_KECCAK_LO,FINAL_MIMC,FINAL_KECCAK_HI,FINAL_KECCAK_LO +1,0,0xf35f15cf8427806f2171633219038109a5f43284b97203f6c20e732726ec472,0xf67d4416da001d26653dd55376e67fee,0xe2ce9b5328ce33d0182d1c75c8fc25a3,0x2db71270903377ab92fc264fb9dc5b99e1fe19ba86ac18e4a46a0c0a5a9c4c3,0x5495f91c99165c6995f8ffe1451683f7,0x372bb525661a23dc742314241b4655eb +1,0,0x11a963f7c703bf098a29118e4d106429943393dd7a484487ba81dd928e314bd1,0x40e87503291ddfc9b2f71747668dc2b8,0xb476de901cb5ad656dbde606e9e7f28f,0x5d6f176a0bbd09237f1bda1639f17e936ba71ab877dd92ed53182dd0e0b74c0,0x3a43fa28fed192571758c03fb025ff34,0xcb2ac05bcdf8762915f005b05b7c84d7 +1,1,0x11a963f7c703bf098a29118e4d106429943393dd7a484487ba81dd928e314bd1,0x40e87503291ddfc9b2f71747668dc2b8,0xb476de901cb5ad656dbde606e9e7f28f,0x5d6f176a0bbd09237f1bda1639f17e936ba71ab877dd92ed53182dd0e0b74c0,0x3a43fa28fed192571758c03fb025ff34,0xcb2ac05bcdf8762915f005b05b7c84d7 +1,1,0x11a963f7c703bf098a29118e4d106429943393dd7a484487ba81dd928e314bd1,0x40e87503291ddfc9b2f71747668dc2b8,0xb476de901cb5ad656dbde606e9e7f28f,0x5d6f176a0bbd09237f1bda1639f17e936ba71ab877dd92ed53182dd0e0b74c0,0x3a43fa28fed192571758c03fb025ff34,0xcb2ac05bcdf8762915f005b05b7c84d7 +1,1,0x11a963f7c703bf098a29118e4d106429943393dd7a484487ba81dd928e314bd1,0x40e87503291ddfc9b2f71747668dc2b8,0xb476de901cb5ad656dbde606e9e7f28f,0x5d6f176a0bbd09237f1bda1639f17e936ba71ab877dd92ed53182dd0e0b74c0,0x3a43fa28fed192571758c03fb025ff34,0xcb2ac05bcdf8762915f005b05b7c84d7 +1,0,0x1d9d872e460e7c37df10661add2d6dbcc7a0db609ea345c9fe4fb679918ee6c,0x54df737ac005b708c1f320f8348b57c4,0x4f76a3e23b164eb958d985d00c464fce,0x104ccc9396a119a0bbe6c11033863e8c17819aaa4735190e2dcb4031fe748d8c,0x5e414bac8de6484b16c268906d21bfe6,0x64075d8db57307612ce42d52e4e13c74 +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xc9ff2cb2ef8742d36f339e7034bda0c15daeefcb805548d9d9ce25aa2ffd4ef,0x7886f8ca4e034b7332123cee9d1777ea,0x566fa42788136176f7ae63016b12e2d8,0x1196860c768f1938d1da9c555b43352712bb4ddda46a4c840bfed2900341e55d,0x5c8257ad42351127abeb7228d64739bb,0x5b60fc5da377a2e2305d9d59b4cb8bb1 +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xa0a821a3015df739289796a6dd9292052601bd4ded9d610329b60761d5153d,0x5eaccff3dd532e06b282e833ef119894,0xf6a3655bcb792dbc7acd191b76a8eb51,0xac2042d01900e17f4a2d1a25146b4442d4aaab042d81688369f14476e6923a8,0x8dd5dd3ac2363989d6e8567a4614ae5e,0x11a2f1dba2c693f34d45bc5ccd772a68 +1,0,0xfece0dc962f980f98a40191def18ed12f5dae99402b8aac05e233ab908863e2,0x8e99ef8b7a659d365cd2e719e538ffa7,0xf69a644e48c8cba797b25bb44188f288,0x35ac282e8a94049f433423418ae6351d914d7a75b012ae5b9ec67df4c9406fc,0xf92a4e441a309d3510bfc5d4eb306186,0x1693b964f6e528063804cc04422dc3df +1,1,0xfece0dc962f980f98a40191def18ed12f5dae99402b8aac05e233ab908863e2,0x8e99ef8b7a659d365cd2e719e538ffa7,0xf69a644e48c8cba797b25bb44188f288,0x35ac282e8a94049f433423418ae6351d914d7a75b012ae5b9ec67df4c9406fc,0xf92a4e441a309d3510bfc5d4eb306186,0x1693b964f6e528063804cc04422dc3df +1,0,0x119419c6075b4599366943f66ecfc8c0815d244ff6cf3e9c6116b39f7ec1a953,0x4225a554197ee72cc6bd8e093bb53d16,0xae97f0821c43cf8718bb82c5f674e7a,0xa8765f64bdb87e1ad5f03d3d7f3b01cdc6636df1bc2a69461c7fdc9e2045df,0xfd6875223bcb0ea15b6d0c35a6725347,0x59a83d5e3e0f5ebdec57a05e2ea6e740 +1,1,0x119419c6075b4599366943f66ecfc8c0815d244ff6cf3e9c6116b39f7ec1a953,0x4225a554197ee72cc6bd8e093bb53d16,0xae97f0821c43cf8718bb82c5f674e7a,0xa8765f64bdb87e1ad5f03d3d7f3b01cdc6636df1bc2a69461c7fdc9e2045df,0xfd6875223bcb0ea15b6d0c35a6725347,0x59a83d5e3e0f5ebdec57a05e2ea6e740 +1,1,0x119419c6075b4599366943f66ecfc8c0815d244ff6cf3e9c6116b39f7ec1a953,0x4225a554197ee72cc6bd8e093bb53d16,0xae97f0821c43cf8718bb82c5f674e7a,0xa8765f64bdb87e1ad5f03d3d7f3b01cdc6636df1bc2a69461c7fdc9e2045df,0xfd6875223bcb0ea15b6d0c35a6725347,0x59a83d5e3e0f5ebdec57a05e2ea6e740 +1,1,0x119419c6075b4599366943f66ecfc8c0815d244ff6cf3e9c6116b39f7ec1a953,0x4225a554197ee72cc6bd8e093bb53d16,0xae97f0821c43cf8718bb82c5f674e7a,0xa8765f64bdb87e1ad5f03d3d7f3b01cdc6636df1bc2a69461c7fdc9e2045df,0xfd6875223bcb0ea15b6d0c35a6725347,0x59a83d5e3e0f5ebdec57a05e2ea6e740 +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x389b7c5e99d95d5bc81560caeab92f2871ab9357d4b75d8086ee85d25d13c61,0xa7fe20bbd3d3d8bf38bbba8bb767ddbc,0x69fa5906065ce2221ec867b3a8feaa20,0x48753db4c02bc3d7276488a335047033452c4e157bc7947337c1bdef49dbe29,0xde70496580bb8d949ceaa1eb86bb1b9b,0x90d49841377cb7e56ee771f68678299d +1,0,0xd63f76d025aad66c2e4637ffee81facc45d14a98494c0a876039297c0a8fb92,0x7b48e49951fb6ad5611a60f42eff4088,0xf5bb6cf530e7f1c44ea0044a9e12fa59,0x10b6c895212308d986f73f5987c6ac81b1c002afdfe374958fb5a84162baca5d,0xffb53b21b460953150751c841b3644ef,0x613d1ac523717f3b11bc6c3f837ce54b +1,0,0x10296e8da0aec25fee074b440964b2a1094056a0f31ba142e30089882155760e,0x95831128725c2b8e58eb85bb882d67e9,0x74a7d2db75ce50157cc057c2373581d7,0x22f2e52458e2f998998cf74206fe267cd3e79efefefcd17994285cee84e5a50,0x8902fc6c126f2045ce6c52618b5051bf,0xb2668ae6fd2462a8d96f71e51e8d164e +1,0,0x10d8562b94171f2dc124d4f5f9e83bf59ae831889792a12ec64e526a60c0971f,0x68028375c1cc6f4760037a584069cdd6,0x184890773df97552959f05c995c318c5,0x6d30229fd84d07298c7286d5600102d9627652db2667b04835f4d93586203dd,0xb782c18785d08f2d49739dd829ecc8ff,0x5915e72b790cf4cc918d315d4825139b +1,1,0x10d8562b94171f2dc124d4f5f9e83bf59ae831889792a12ec64e526a60c0971f,0x68028375c1cc6f4760037a584069cdd6,0x184890773df97552959f05c995c318c5,0x6d30229fd84d07298c7286d5600102d9627652db2667b04835f4d93586203dd,0xb782c18785d08f2d49739dd829ecc8ff,0x5915e72b790cf4cc918d315d4825139b +1,0,0xae81ebef405850eecf8717d7faea3dbd6a37d35d063d0367064880086a7a300,0x20c80df7e34096a6c0d73232df167e1a,0x32820e71aa1363f92a402f075777a37b,0xcbf0ece3106425fa5b6ee414fcc0b36e25957de00b49112e2d613105c248d55,0x7cbf1978c6635b53ef61e85fc4a88414,0x9231fa09e75f1b16b23225161bd15fe9 +1,1,0xae81ebef405850eecf8717d7faea3dbd6a37d35d063d0367064880086a7a300,0x20c80df7e34096a6c0d73232df167e1a,0x32820e71aa1363f92a402f075777a37b,0xcbf0ece3106425fa5b6ee414fcc0b36e25957de00b49112e2d613105c248d55,0x7cbf1978c6635b53ef61e85fc4a88414,0x9231fa09e75f1b16b23225161bd15fe9 +1,1,0xae81ebef405850eecf8717d7faea3dbd6a37d35d063d0367064880086a7a300,0x20c80df7e34096a6c0d73232df167e1a,0x32820e71aa1363f92a402f075777a37b,0xcbf0ece3106425fa5b6ee414fcc0b36e25957de00b49112e2d613105c248d55,0x7cbf1978c6635b53ef61e85fc4a88414,0x9231fa09e75f1b16b23225161bd15fe9 +1,0,0xf3379db7f2f8d74284712d99bf6b643a1e66f6d7e524384981550cf41ea2bbb,0x1e9b3ea8bae6461f76bc37f85c6f132e,0x17892407267738f48a0ae6c9e0999b95,0xc100a2fdcc4ec6657590effb1548813ff5e05d554623e9f1852e275d3f3bfc,0x99f65bee59ffa8f01819f6f7e7ca86a3,0x56d14a8af29b2e5517ef2158285dc744 +1,1,0xf3379db7f2f8d74284712d99bf6b643a1e66f6d7e524384981550cf41ea2bbb,0x1e9b3ea8bae6461f76bc37f85c6f132e,0x17892407267738f48a0ae6c9e0999b95,0xc100a2fdcc4ec6657590effb1548813ff5e05d554623e9f1852e275d3f3bfc,0x99f65bee59ffa8f01819f6f7e7ca86a3,0x56d14a8af29b2e5517ef2158285dc744 +1,1,0xf3379db7f2f8d74284712d99bf6b643a1e66f6d7e524384981550cf41ea2bbb,0x1e9b3ea8bae6461f76bc37f85c6f132e,0x17892407267738f48a0ae6c9e0999b95,0xc100a2fdcc4ec6657590effb1548813ff5e05d554623e9f1852e275d3f3bfc,0x99f65bee59ffa8f01819f6f7e7ca86a3,0x56d14a8af29b2e5517ef2158285dc744 +1,1,0xf3379db7f2f8d74284712d99bf6b643a1e66f6d7e524384981550cf41ea2bbb,0x1e9b3ea8bae6461f76bc37f85c6f132e,0x17892407267738f48a0ae6c9e0999b95,0xc100a2fdcc4ec6657590effb1548813ff5e05d554623e9f1852e275d3f3bfc,0x99f65bee59ffa8f01819f6f7e7ca86a3,0x56d14a8af29b2e5517ef2158285dc744 +1,1,0xf3379db7f2f8d74284712d99bf6b643a1e66f6d7e524384981550cf41ea2bbb,0x1e9b3ea8bae6461f76bc37f85c6f132e,0x17892407267738f48a0ae6c9e0999b95,0xc100a2fdcc4ec6657590effb1548813ff5e05d554623e9f1852e275d3f3bfc,0x99f65bee59ffa8f01819f6f7e7ca86a3,0x56d14a8af29b2e5517ef2158285dc744 +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xeba5a7f494bb2b134d0909f243adac86042f21fe7f5137180a52a331ccd14e3,0x3868c49f634d7e9e9848d1051ee638ca,0xeaf936be0f8de68b2df4389a6afa26ba,0x1f5ea3f47bf1bbc6ccd74fd280c92dc7148a823c104358e5a45e421baf4636f,0xda1ec13c405e5051bbb067d8abec1ed6,0xfa36e89d0255e89fc077770733552310 +1,1,0xeba5a7f494bb2b134d0909f243adac86042f21fe7f5137180a52a331ccd14e3,0x3868c49f634d7e9e9848d1051ee638ca,0xeaf936be0f8de68b2df4389a6afa26ba,0x1f5ea3f47bf1bbc6ccd74fd280c92dc7148a823c104358e5a45e421baf4636f,0xda1ec13c405e5051bbb067d8abec1ed6,0xfa36e89d0255e89fc077770733552310 +1,1,0xeba5a7f494bb2b134d0909f243adac86042f21fe7f5137180a52a331ccd14e3,0x3868c49f634d7e9e9848d1051ee638ca,0xeaf936be0f8de68b2df4389a6afa26ba,0x1f5ea3f47bf1bbc6ccd74fd280c92dc7148a823c104358e5a45e421baf4636f,0xda1ec13c405e5051bbb067d8abec1ed6,0xfa36e89d0255e89fc077770733552310 +1,1,0xeba5a7f494bb2b134d0909f243adac86042f21fe7f5137180a52a331ccd14e3,0x3868c49f634d7e9e9848d1051ee638ca,0xeaf936be0f8de68b2df4389a6afa26ba,0x1f5ea3f47bf1bbc6ccd74fd280c92dc7148a823c104358e5a45e421baf4636f,0xda1ec13c405e5051bbb067d8abec1ed6,0xfa36e89d0255e89fc077770733552310 +1,1,0xeba5a7f494bb2b134d0909f243adac86042f21fe7f5137180a52a331ccd14e3,0x3868c49f634d7e9e9848d1051ee638ca,0xeaf936be0f8de68b2df4389a6afa26ba,0x1f5ea3f47bf1bbc6ccd74fd280c92dc7148a823c104358e5a45e421baf4636f,0xda1ec13c405e5051bbb067d8abec1ed6,0xfa36e89d0255e89fc077770733552310 +1,1,0xeba5a7f494bb2b134d0909f243adac86042f21fe7f5137180a52a331ccd14e3,0x3868c49f634d7e9e9848d1051ee638ca,0xeaf936be0f8de68b2df4389a6afa26ba,0x1f5ea3f47bf1bbc6ccd74fd280c92dc7148a823c104358e5a45e421baf4636f,0xda1ec13c405e5051bbb067d8abec1ed6,0xfa36e89d0255e89fc077770733552310 +1,0,0x9497ed240a9c6e514c4dbd8e8164567504ace21dc6eb2b9f5f1ae2d5c1b0f22,0x2c20de668dcf93f6fd69f831358e3571,0x70f3d9a00b479d23014c16a17d3766de,0x26a96dc9d5dcab27131cea3781d9da59c033eee779c5ddae1714eb0dd4e5865,0x61e187a78b8461acc9e5af545bcb8852,0x59522414883bb2377e76680454c8acc3 +1,1,0x9497ed240a9c6e514c4dbd8e8164567504ace21dc6eb2b9f5f1ae2d5c1b0f22,0x2c20de668dcf93f6fd69f831358e3571,0x70f3d9a00b479d23014c16a17d3766de,0x26a96dc9d5dcab27131cea3781d9da59c033eee779c5ddae1714eb0dd4e5865,0x61e187a78b8461acc9e5af545bcb8852,0x59522414883bb2377e76680454c8acc3 +1,0,0x11dda97ffc1f7983ee52f7151c9303949b96de1c3ab8ba4d516122654e224647,0x68c466a3d0174b37b01a580a93d87fb2,0xe7d224676a2dffbbdd7f0e1e45cff7d5,0x40438172179d1952eb1ad99de5fe2c3763d17745b06a25793a9074380998114,0xb9117278fdeabb73206750b1996195ef,0x59dd2585b0b99f49609523ca09ce2f5e +1,0,0xf7fd0ff4d444bccb25eadb72ef91461ed68c8b0532be9040027b66fe9aeffcc,0xc4b793be5461375947575c0e7597b3fb,0xa165463eedd4dfaeeea186bc18ff03fd,0xb274c198dc60bd5a0c51ebc7e31cb8e06268dd2c3bdd7ca102c9224be74a733,0x6f6ee35f78e9136da33fc53515fb6aa,0x5c70b7e2444c5494b2cc6b29acf386ac +1,1,0xf7fd0ff4d444bccb25eadb72ef91461ed68c8b0532be9040027b66fe9aeffcc,0xc4b793be5461375947575c0e7597b3fb,0xa165463eedd4dfaeeea186bc18ff03fd,0xb274c198dc60bd5a0c51ebc7e31cb8e06268dd2c3bdd7ca102c9224be74a733,0x6f6ee35f78e9136da33fc53515fb6aa,0x5c70b7e2444c5494b2cc6b29acf386ac +1,1,0xf7fd0ff4d444bccb25eadb72ef91461ed68c8b0532be9040027b66fe9aeffcc,0xc4b793be5461375947575c0e7597b3fb,0xa165463eedd4dfaeeea186bc18ff03fd,0xb274c198dc60bd5a0c51ebc7e31cb8e06268dd2c3bdd7ca102c9224be74a733,0x6f6ee35f78e9136da33fc53515fb6aa,0x5c70b7e2444c5494b2cc6b29acf386ac +1,1,0xf7fd0ff4d444bccb25eadb72ef91461ed68c8b0532be9040027b66fe9aeffcc,0xc4b793be5461375947575c0e7597b3fb,0xa165463eedd4dfaeeea186bc18ff03fd,0xb274c198dc60bd5a0c51ebc7e31cb8e06268dd2c3bdd7ca102c9224be74a733,0x6f6ee35f78e9136da33fc53515fb6aa,0x5c70b7e2444c5494b2cc6b29acf386ac +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xeb96584feee735187fdfe6dca08405d0d5a5bcfd4e2be9da5dcae918289df88,0x67d154ee86baa855d8e1411e1b3a67e6,0xb736d099be0a74bbca098273ccdb94d0,0xda7a44e1ba86663370ef02b5e2a881e2888a05d4576b90fa6ff90fa50f9f2a4,0x1b4ac2371564eb5947b11bbcfa5365ec,0x2b2270e5bc144097708c79ade1db19b4 +1,0,0xf4d62210aacfc47e33ac92588c56b322f90a4799062ebe005f52ef53fc4895b,0xb8eb745804c277dc8191729edd21776b,0x34ff0cf91f5d648aab5bf04b0f188710,0x88251783290549e6a3699c01b7d32219645207463a3b039f70a47082dd670a1,0x6fc458a5fd0fd081b8a92d855b77df3d,0x1d4b7830391d7dbe32365b83723891eb +1,1,0xf4d62210aacfc47e33ac92588c56b322f90a4799062ebe005f52ef53fc4895b,0xb8eb745804c277dc8191729edd21776b,0x34ff0cf91f5d648aab5bf04b0f188710,0x88251783290549e6a3699c01b7d32219645207463a3b039f70a47082dd670a1,0x6fc458a5fd0fd081b8a92d855b77df3d,0x1d4b7830391d7dbe32365b83723891eb +1,0,0x71443b42281d3358b22b9351b1fa56fc127b292f6dbdb913abb347ca497b28e,0x996677f0735322cf140c1981e51b67c7,0xefad2dffd7c676bdfb330b3a7e81f4f8,0xbfd86dee7d8d5a4eadf820d382b714f9b44d7f803b837f366cab8a984c40843,0xab60ad87028de4629952162c92cbe4b0,0xbae39935070b91b395c012c10e89e4ce +1,1,0x71443b42281d3358b22b9351b1fa56fc127b292f6dbdb913abb347ca497b28e,0x996677f0735322cf140c1981e51b67c7,0xefad2dffd7c676bdfb330b3a7e81f4f8,0xbfd86dee7d8d5a4eadf820d382b714f9b44d7f803b837f366cab8a984c40843,0xab60ad87028de4629952162c92cbe4b0,0xbae39935070b91b395c012c10e89e4ce +1,1,0x71443b42281d3358b22b9351b1fa56fc127b292f6dbdb913abb347ca497b28e,0x996677f0735322cf140c1981e51b67c7,0xefad2dffd7c676bdfb330b3a7e81f4f8,0xbfd86dee7d8d5a4eadf820d382b714f9b44d7f803b837f366cab8a984c40843,0xab60ad87028de4629952162c92cbe4b0,0xbae39935070b91b395c012c10e89e4ce +1,0,0xb06d8370b09f3ff606cbb032910e052a6e4c26e10c17d1fb4b9359cd7fbe24f,0x97f5fcd4008138508bf9038464cd9c99,0x408c6dd51203a28c0c6bd70a92b9cdeb,0x399d9f32081d01c83dddff43f46ba0b25e0686d3d81e219f37bdfc88de99c4c,0x176d53e8613d4f918eed1da5daf1ae3c,0xc22b82581a5c4dc3eb803bcfede92b4c +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xe65b3f3cb539f3ca72c26a5596475fbbbe8d6f582711383643a23220127d24d,0xaaf4faa1ae7c5ebf57efe71bcfb60e4f,0x4bdf2d4302bd5ab2ee330e6dfdae2ba0,0x67dee9731332c7fb1d32ef8009f8451b90acff8ca4e0a70950c1f6887cb115e,0x10f15d0c2d8e18c83cf98c35286a904,0x3b0702c068c3dce99a14dbf35878fa56 +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x7f7975790e2cb0878d7eb8254173635b9cae59655d237539a1c9974a0581379,0x253528e4920284996a8925cefeeb0e6a,0x458606fd053a274064093569604f8e6e,0x27fe459b2bd85ef08ba7284be6a1b4fa9b4a545e59d261287ac028e35f6e82b,0x893a596ec6b203bf83584d8f2f4f02be,0xad76cab1a21ca92e17dd2ae037626842 +1,1,0x7f7975790e2cb0878d7eb8254173635b9cae59655d237539a1c9974a0581379,0x253528e4920284996a8925cefeeb0e6a,0x458606fd053a274064093569604f8e6e,0x27fe459b2bd85ef08ba7284be6a1b4fa9b4a545e59d261287ac028e35f6e82b,0x893a596ec6b203bf83584d8f2f4f02be,0xad76cab1a21ca92e17dd2ae037626842 +1,1,0x7f7975790e2cb0878d7eb8254173635b9cae59655d237539a1c9974a0581379,0x253528e4920284996a8925cefeeb0e6a,0x458606fd053a274064093569604f8e6e,0x27fe459b2bd85ef08ba7284be6a1b4fa9b4a545e59d261287ac028e35f6e82b,0x893a596ec6b203bf83584d8f2f4f02be,0xad76cab1a21ca92e17dd2ae037626842 +1,0,0xd99a7da9e56fb98b4ea6eed3c97850cb421c0c9677b1ea3b63e0c01c4b483ce,0x34fa32e467be6484e68a4161ac4c5e4a,0x2719eea179e0b75a5d46f518e9351695,0xaf8e105eaad4d16fca08d01c00fd61aaf123407d64915027112b3c60cfd8831,0x93e25146b19d25035c45442b7f816564,0xfdd7f4f78ecf1751db322e4f433ebddb +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x5bea17a563b11a2269eb0f03ad5640c66575c8bae12198b49231d8f31ecd0b2,0x1ff3ae2c5fc2d6ad2ff3dc351037ac48,0xf3554d4be537e7149f0270673d57603e,0x26837f96bf42dfb9a3d712aec8a78efede1c2338dc39b0242de37fea474921b,0x4e9372bf2252d05c0db52ea436e3041c,0x5a713dec54f94b5f7dc61cdb72b1d4e4 +1,0,0xa1cc247b921723ca53a59d813f2adb7ca47f8eff00ba49e55550e1f1e544241,0x213aecda3ce19fb0b492f2d261020584,0x1ac635fdda33542e83a1fe01fd6b31d0,0xa3c2340721f49260c1bfe6f137f4b47931e5e10a3783b38d6217452c5e3631b,0x6e9d2bbb52f7afa4b0f564fd8caab588,0x221b66157dade849dedb61e4320e84aa +1,1,0xa1cc247b921723ca53a59d813f2adb7ca47f8eff00ba49e55550e1f1e544241,0x213aecda3ce19fb0b492f2d261020584,0x1ac635fdda33542e83a1fe01fd6b31d0,0xa3c2340721f49260c1bfe6f137f4b47931e5e10a3783b38d6217452c5e3631b,0x6e9d2bbb52f7afa4b0f564fd8caab588,0x221b66157dade849dedb61e4320e84aa +1,0,0x796ae7f0e7768674a2636592ea0bca75714cb4d4c3f7136485959f676f7c5e7,0xec791d783bdfbfba883e15d0ee0dfda4,0x6e075d26559c95292b391dcd90bacae2,0xacd579a3134ccf1d08f14c0e5d4de343266be87db4912debc405af578b7dcee,0xcccb598ed1a6a22627830dabe31ad2d9,0x98c4bf81d0af2bd0bd53664239dc195a +1,0,0x116239c90f29dea8eb2eb35ce5d58473547a3a9ed792e4d6290f835d6bb5784,0x822d955a6ed1f14ba562bd305aa42637,0x9f9958424fbb5350bf6f30b0613b2bfb,0x17b347f7033c75fd492236e39d09e5cc2c69efdae6769eb9f79f33b1bb115fb,0x87cbb16677016c9697796469e2147c37,0xbffa57a3216752a0ee51fa1db31f57c7 +1,1,0x116239c90f29dea8eb2eb35ce5d58473547a3a9ed792e4d6290f835d6bb5784,0x822d955a6ed1f14ba562bd305aa42637,0x9f9958424fbb5350bf6f30b0613b2bfb,0x17b347f7033c75fd492236e39d09e5cc2c69efdae6769eb9f79f33b1bb115fb,0x87cbb16677016c9697796469e2147c37,0xbffa57a3216752a0ee51fa1db31f57c7 +1,1,0x116239c90f29dea8eb2eb35ce5d58473547a3a9ed792e4d6290f835d6bb5784,0x822d955a6ed1f14ba562bd305aa42637,0x9f9958424fbb5350bf6f30b0613b2bfb,0x17b347f7033c75fd492236e39d09e5cc2c69efdae6769eb9f79f33b1bb115fb,0x87cbb16677016c9697796469e2147c37,0xbffa57a3216752a0ee51fa1db31f57c7 +1,1,0x116239c90f29dea8eb2eb35ce5d58473547a3a9ed792e4d6290f835d6bb5784,0x822d955a6ed1f14ba562bd305aa42637,0x9f9958424fbb5350bf6f30b0613b2bfb,0x17b347f7033c75fd492236e39d09e5cc2c69efdae6769eb9f79f33b1bb115fb,0x87cbb16677016c9697796469e2147c37,0xbffa57a3216752a0ee51fa1db31f57c7 +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xd1d5e6d96a0e33007d3daebfa972d03b7bb67b8a4fba812376fafd30b814704,0x367de3aa93d6405aa1979452414d0cdc,0x6bf078a86cb81f1183a28736513743d,0x9cd2fb59f7dad863b6b37a8c3c9528f06ec271a54c93a71092721eec697ac27,0xbfe496d60e90db539af391782c0670fe,0xa4f0d1cab3eec2f400490037c5ba0169 +1,1,0xd1d5e6d96a0e33007d3daebfa972d03b7bb67b8a4fba812376fafd30b814704,0x367de3aa93d6405aa1979452414d0cdc,0x6bf078a86cb81f1183a28736513743d,0x9cd2fb59f7dad863b6b37a8c3c9528f06ec271a54c93a71092721eec697ac27,0xbfe496d60e90db539af391782c0670fe,0xa4f0d1cab3eec2f400490037c5ba0169 +1,1,0xd1d5e6d96a0e33007d3daebfa972d03b7bb67b8a4fba812376fafd30b814704,0x367de3aa93d6405aa1979452414d0cdc,0x6bf078a86cb81f1183a28736513743d,0x9cd2fb59f7dad863b6b37a8c3c9528f06ec271a54c93a71092721eec697ac27,0xbfe496d60e90db539af391782c0670fe,0xa4f0d1cab3eec2f400490037c5ba0169 +1,1,0xd1d5e6d96a0e33007d3daebfa972d03b7bb67b8a4fba812376fafd30b814704,0x367de3aa93d6405aa1979452414d0cdc,0x6bf078a86cb81f1183a28736513743d,0x9cd2fb59f7dad863b6b37a8c3c9528f06ec271a54c93a71092721eec697ac27,0xbfe496d60e90db539af391782c0670fe,0xa4f0d1cab3eec2f400490037c5ba0169 +1,1,0xd1d5e6d96a0e33007d3daebfa972d03b7bb67b8a4fba812376fafd30b814704,0x367de3aa93d6405aa1979452414d0cdc,0x6bf078a86cb81f1183a28736513743d,0x9cd2fb59f7dad863b6b37a8c3c9528f06ec271a54c93a71092721eec697ac27,0xbfe496d60e90db539af391782c0670fe,0xa4f0d1cab3eec2f400490037c5ba0169 +1,0,0x420d1987d554b6040ffba354fd3a6576573e7f3810ba3b3b2f736e2c00e9dda,0x45f250aaf0d881ad86fd62235b890968,0x161cfd2a0b591cdec5d674da238d44ec,0x81014394cb2b477fdf0397ba51717657ed1a993e7e63adec55566a48b8514e3,0xa42d146920d3d2b1c04e35e6d5e9ac35,0x538bcdb7739f910e8a0f6fe3debc5b63 +1,0,0xf145fbeb995facc396b62d73b9e1c297c83d119979e46ae16c4c0ba90e9e7f0,0xc18d0cb6b60e7b046159269197812020,0x58219a1662aaf165a8ab4347b2ebb7cb,0x793fd3a2d8d31c45f9a7a6061e30e86f155b66c957857d3d9730a89838e0005,0x1218bf4befbdf3e2ed280eee79c6244b,0xb87e7320bd4f43381dd6fab8225ee35b +1,0,0xd6a6e52cbcaa5cae42454038466557a5cd4abb2f1f506c38058f99534656c2b,0x693ffec3234e977ec90a1621671fc139,0xab030541519cc12965b9a5cbf2c77a1e,0xddd15c05722d7a7dc6bdfd70148fb4e3c7def7827ee62ae03ef58254ff2606d,0x1890b5f936f617ac7113888c43869db5,0x7d23a9e21d81075a387f257cef69fe5c +1,1,0xd6a6e52cbcaa5cae42454038466557a5cd4abb2f1f506c38058f99534656c2b,0x693ffec3234e977ec90a1621671fc139,0xab030541519cc12965b9a5cbf2c77a1e,0xddd15c05722d7a7dc6bdfd70148fb4e3c7def7827ee62ae03ef58254ff2606d,0x1890b5f936f617ac7113888c43869db5,0x7d23a9e21d81075a387f257cef69fe5c +1,1,0xd6a6e52cbcaa5cae42454038466557a5cd4abb2f1f506c38058f99534656c2b,0x693ffec3234e977ec90a1621671fc139,0xab030541519cc12965b9a5cbf2c77a1e,0xddd15c05722d7a7dc6bdfd70148fb4e3c7def7827ee62ae03ef58254ff2606d,0x1890b5f936f617ac7113888c43869db5,0x7d23a9e21d81075a387f257cef69fe5c +1,0,0x8f086a265ddaf5da1a35f983e62bbec4ec4dfdf413039443259f52fb23ea4eb,0xfd91aec846780f1852cd426d65d44855,0xe718a2a754d056208c69b68459c3b26f,0xc946b7b62e3bca7c3f058a6f859e049360260f986fc355cd1cbea6ac1fd8fb,0x99ab3b350754f7e6ce970feda3d868d1,0x25eaa8907d9362650dafa0ccf15a92ee +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x4e2c8d4fabfff1e591ab2acdd75674750c586ecc05f542cfb86233dc2ed5eaa,0x9e41a5832437ba0671ae6d781779d3d7,0x29f117b1828ab9c05f55d192b367e7be,0x69a4895fc7362c6c7798ad803b824c400b247fae0fbcfeda2b416fdec3c716f,0x969a1b2e513f1ddbb09b13ebb6b89bc6,0xbccff59d5aedff5844b8dcc41e9c0f1f +1,1,0x4e2c8d4fabfff1e591ab2acdd75674750c586ecc05f542cfb86233dc2ed5eaa,0x9e41a5832437ba0671ae6d781779d3d7,0x29f117b1828ab9c05f55d192b367e7be,0x69a4895fc7362c6c7798ad803b824c400b247fae0fbcfeda2b416fdec3c716f,0x969a1b2e513f1ddbb09b13ebb6b89bc6,0xbccff59d5aedff5844b8dcc41e9c0f1f +1,0,0x2862cfaf050a1d322c3f7d18d456beb01be8ba64ad1264470c30c17e7e1790e,0x261e5ce06c9c233678bd07d3e525811d,0x85b04ea749f468f87cc2a5b094573cd4,0x121121cf43252bc791c61474300d6f0b2e20c3b0a3f83abef1d3f2b624501aa3,0x4fec8a94b5955ef50c4bc2938adc5b43,0x51f54908c4ec3ff9edbe10f6eb2258a2 +1,0,0x5a5d5dec422a16c0c12c66b484e8fc60548e70be104d8ef619d41897ca2eebe,0xd0def8949c5f9ec76796b37b49fb50a1,0x367c115fbc0d7ccb87ef7ed68916a6c4,0x3fb628afd3f9b4f19d5d7796090d2ad6f54b1847f500f05c84e1ee7132738df,0xf2ced2092bce766fcbeeb41786388267,0x9ecfa5aa99914e46fde587c3e3297d92 +1,0,0x3070970d5198b56e2eecc42efee353fdf0e43695bf647d9f09ea2d1764409c8,0x812fe3c9b5d115fa99cd91af1e9d5845,0x9b3848d64d3c8886632807df3bef85ac,0x3427471c4b44e9a3b05d740e993b2fb2be6eae715b36d6f84424769c4d79566,0x2c3ba52aa2c409fcb2195d8cbf7f3a91,0x44d41978512d9944495774ad0de481c +1,1,0x3070970d5198b56e2eecc42efee353fdf0e43695bf647d9f09ea2d1764409c8,0x812fe3c9b5d115fa99cd91af1e9d5845,0x9b3848d64d3c8886632807df3bef85ac,0x3427471c4b44e9a3b05d740e993b2fb2be6eae715b36d6f84424769c4d79566,0x2c3ba52aa2c409fcb2195d8cbf7f3a91,0x44d41978512d9944495774ad0de481c +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xe81a73fb7fc1d5f975a0de58e37a3b32e77aa8e1ebf824828010167b7d2e596,0x7c2d2cada376264dc0d4c2817d81c4cc,0xe4cb9b7db79b0d56d57cd4d431ac0dc4,0x371a1c7d8773ffc74132a9b5b4a29cc42426066f085347901ba75d2baf8e4a8,0x41e7bc4990bbfa88b2a2d2f5947c7b02,0x3cb483e4076d7dc2913f20ef5483ea80 +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0xa9792e72211e53e07acc386714411841e3e18857851749e1db4a8534521ab3b,0xea43ba6d00ff5ff081c2a2f50871046a,0xa659b39355270b717571c1c037aa746b,0x5b8ed2eb2864e98cce0e9a02cabfd8602747c9a693f90dcd12dca32080729f9,0xa2a469704b2f6ea77e4261cca30328ce,0x51bc6a4e45ea73ead9a9707672edef88 +1,1,0xa9792e72211e53e07acc386714411841e3e18857851749e1db4a8534521ab3b,0xea43ba6d00ff5ff081c2a2f50871046a,0xa659b39355270b717571c1c037aa746b,0x5b8ed2eb2864e98cce0e9a02cabfd8602747c9a693f90dcd12dca32080729f9,0xa2a469704b2f6ea77e4261cca30328ce,0x51bc6a4e45ea73ead9a9707672edef88 +1,0,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,1,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee,0x11f4cf9cf92cbd4e55cb49097909d1eb7ef4e232efd287a7ce617ea2fdf5e218,0x7b58305eb2aa3ff8e9b49192b4822685,0x84e6417582b82df64c84659a39513fee +1,0,0x71ba533388576c9a957c746457e4feb21de3260fa61c5230fb40c59f2534493,0x30a7c00888e0041fedddd38732d3af98,0xa287c298774bc224c4ec8aac432d3474,0x6e437929ba3096222cc08f6a10bfca20537ba78298548dc76126ee83960be74,0xdb637f3876071b109b6a9e4fbb961259,0xf841c2c1c3fa07ae3984fac6a8ad4ddb +1,1,0x71ba533388576c9a957c746457e4feb21de3260fa61c5230fb40c59f2534493,0x30a7c00888e0041fedddd38732d3af98,0xa287c298774bc224c4ec8aac432d3474,0x6e437929ba3096222cc08f6a10bfca20537ba78298548dc76126ee83960be74,0xdb637f3876071b109b6a9e4fbb961259,0xf841c2c1c3fa07ae3984fac6a8ad4ddb +1,1,0x71ba533388576c9a957c746457e4feb21de3260fa61c5230fb40c59f2534493,0x30a7c00888e0041fedddd38732d3af98,0xa287c298774bc224c4ec8aac432d3474,0x6e437929ba3096222cc08f6a10bfca20537ba78298548dc76126ee83960be74,0xdb637f3876071b109b6a9e4fbb961259,0xf841c2c1c3fa07ae3984fac6a8ad4ddb +1,1,0x71ba533388576c9a957c746457e4feb21de3260fa61c5230fb40c59f2534493,0x30a7c00888e0041fedddd38732d3af98,0xa287c298774bc224c4ec8aac432d3474,0x6e437929ba3096222cc08f6a10bfca20537ba78298548dc76126ee83960be74,0xdb637f3876071b109b6a9e4fbb961259,0xf841c2c1c3fa07ae3984fac6a8ad4ddb +1,0,0x9348320796205bdacdf734d12dd7d0add3ac27e87caddf99f1765bb89886a5a,0x3de923a685d5e3f2d634b891db64403d,0xe8460a5be4c18d2f5fc5ca8c6e0ef209,0x249cb31042b5b8b0f19a18a04239ae5691442c48b329e488680be2897b4f839,0x66f127bb16fe5c6d85fe3fe55c1adadb,0x87b6a3c85d0b22d5ffaad98f65515163 diff --git a/prover/zkevm/prover/statemanager/lookups.go b/prover/zkevm/prover/statemanager/lookups.go deleted file mode 100644 index 75e681662..000000000 --- a/prover/zkevm/prover/statemanager/lookups.go +++ /dev/null @@ -1,36 +0,0 @@ -package statemanager - -import ( - "github.com/consensys/linea-monorepo/prover/protocol/ifaces" - "github.com/consensys/linea-monorepo/prover/protocol/wizard" - mimcCodeHash "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/mimccodehash" - "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/statesummary" -) - -// lookupStateSummaryCodeHash adds the lookup constraints to ensure the MiMC -// CodeHash module and the StateSummary module contains consistent consistent -// pairs of (MiMCCodeHash, KeccakCodeHash) -func lookupStateSummaryCodeHash(comp *wizard.CompiledIOP, - accountPeek *statesummary.AccountPeek, - codeHash *mimcCodeHash.Module) { - // All the state manager operations are performed in round zero - round := 0 - - // Lookup between code hashes (Keccak and MiMC) between state summary initial account and MiMC code hash module - comp.InsertInclusionDoubleConditional(round, - ifaces.QueryID("LOOKUP_MIMC_CODEHASH_INITIAL_ACCOUNT_INTO_STATE_SUMMARY"), - []ifaces.Column{accountPeek.Initial.KeccakCodeHash.Hi, accountPeek.Initial.KeccakCodeHash.Lo, accountPeek.Initial.MiMCCodeHash, accountPeek.Initial.CodeSize}, - []ifaces.Column{codeHash.CodeHashHi, codeHash.CodeHashLo, codeHash.NewState, codeHash.CodeSize}, - accountPeek.Initial.ExistsAndHasNonEmptyCodeHash, - codeHash.IsHashEnd, - ) - - // Lookup between code hashes (Keccak and MiMC) between state summary final account and MiMC code hash module - comp.InsertInclusionDoubleConditional(round, - ifaces.QueryIDf("LOOKUP_MIMC_CODEHASH_FINAL_ACCOUNT_INTO_STATE_SUMMARY"), - []ifaces.Column{accountPeek.Final.KeccakCodeHash.Hi, accountPeek.Final.KeccakCodeHash.Lo, accountPeek.Final.MiMCCodeHash, accountPeek.Final.CodeSize}, - []ifaces.Column{codeHash.CodeHashHi, codeHash.CodeHashLo, codeHash.NewState, codeHash.CodeSize}, - accountPeek.Final.ExistsAndHasNonEmptyCodeHash, - codeHash.IsHashEnd, - ) -} diff --git a/prover/zkevm/prover/statemanager/state_manager.go b/prover/zkevm/prover/statemanager/state_manager.go index a115ba281..76c416fff 100644 --- a/prover/zkevm/prover/statemanager/state_manager.go +++ b/prover/zkevm/prover/statemanager/state_manager.go @@ -6,6 +6,7 @@ import ( "github.com/consensys/linea-monorepo/prover/utils" "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/accumulator" "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/accumulatorsummary" + "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/codehashconsistency" "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/mimccodehash" "github.com/consensys/linea-monorepo/prover/zkevm/prover/statemanager/statesummary" ) @@ -18,6 +19,7 @@ type StateManager struct { accumulatorSummaryConnector accumulatorsummary.Module StateSummary statesummary.Module // exported because needed by the public input module mimcCodeHash mimccodehash.Module + codeHashConsistency codehashconsistency.Module } // Settings stores all the setting to construct a StateManager and is passed to @@ -51,7 +53,7 @@ func NewStateManager(comp *wizard.CompiledIOP, settings Settings) *StateManager sm.accumulatorSummaryConnector.ConnectToStateSummary(comp, &sm.StateSummary) sm.mimcCodeHash.ConnectToRom(comp, rom(comp), romLex(comp)) sm.StateSummary.ConnectToHub(comp, acp(comp), scp(comp)) - lookupStateSummaryCodeHash(comp, &sm.StateSummary.Account, &sm.mimcCodeHash) + sm.codeHashConsistency = codehashconsistency.NewModule(comp, "CODEHASHCONSISTENCY", &sm.StateSummary, &sm.mimcCodeHash) return sm } @@ -79,10 +81,7 @@ func NewStateManagerNoHub(comp *wizard.CompiledIOP, settings Settings) *StateMan sm.accumulatorSummaryConnector.ConnectToStateSummary(comp, &sm.StateSummary) sm.mimcCodeHash.ConnectToRom(comp, rom(comp), romLex(comp)) - - // Waiting for the resolution of the mimc code hash issue - // - // lookupStateSummaryCodeHash(comp, &sm.StateSummary.Account, &sm.mimcCodeHash) + sm.codeHashConsistency = codehashconsistency.NewModule(comp, "CODEHASHCONSISTENCY", &sm.StateSummary, &sm.mimcCodeHash) return sm } @@ -95,6 +94,7 @@ func (sm *StateManager) Assign(run *wizard.ProverRuntime, shomeiTraces [][]state sm.accumulator.Assign(run, utils.Join(shomeiTraces...)) sm.accumulatorSummaryConnector.Assign(run) sm.mimcCodeHash.Assign(run) + sm.codeHashConsistency.Assign(run) } diff --git a/prover/zkevm/prover/statemanager/statesummary/account_peek.go b/prover/zkevm/prover/statemanager/statesummary/account_peek.go index fc1dadf91..97c234dc0 100644 --- a/prover/zkevm/prover/statemanager/statesummary/account_peek.go +++ b/prover/zkevm/prover/statemanager/statesummary/account_peek.go @@ -151,7 +151,7 @@ type Account struct { // single column each. Exists, Nonce, Balance, MiMCCodeHash, CodeSize, StorageRoot ifaces.Column // KeccakCodeHash stores the keccak code hash of the account. - KeccakCodeHash HiLoColumns + KeccakCodeHash common.HiLoColumns // HasEmptyCodeHash is an indicator column indicating whether the current // account has an empty codehash HasEmptyCodeHash ifaces.Column @@ -178,7 +178,7 @@ func newAccount(comp *wizard.CompiledIOP, size int, name string) Account { MiMCCodeHash: createCol("MIMC_CODEHASH"), CodeSize: createCol("CODESIZE"), StorageRoot: createCol("STORAGE_ROOT"), - KeccakCodeHash: newHiLoColumns(comp, size, name+"_KECCAK_CODE_HASH"), + KeccakCodeHash: common.NewHiLoColumns(comp, size, name+"_KECCAK_CODE_HASH"), ExistsAndHasNonEmptyCodeHash: createCol("EXISTS_AND_NON_EMPTY_CODEHASH"), } @@ -231,7 +231,7 @@ func newAccountPeekAssignmentBuilder(ap *AccountPeek) accountPeekAssignmentBuild // builders relating to the an Account. type accountAssignmentBuilder struct { exists, nonce, balance, miMCCodeHash, codeSize, storageRoot *common.VectorBuilder - keccakCodeHash hiLoAssignmentBuilder + keccakCodeHash common.HiLoAssignmentBuilder existsAndHasNonEmptyCodeHash *common.VectorBuilder } @@ -246,7 +246,7 @@ func newAccountAssignmentBuilder(ap *Account) accountAssignmentBuilder { codeSize: common.NewVectorBuilder(ap.CodeSize), storageRoot: common.NewVectorBuilder(ap.StorageRoot), existsAndHasNonEmptyCodeHash: common.NewVectorBuilder(ap.ExistsAndHasNonEmptyCodeHash), - keccakCodeHash: newHiLoAssignmentBuilder(ap.KeccakCodeHash), + keccakCodeHash: common.NewHiLoAssignmentBuilder(ap.KeccakCodeHash), } } @@ -261,11 +261,11 @@ func (ss *accountAssignmentBuilder) pushAll(acc types.Account) { if accountExists { ss.balance.PushBytes32(types.LeftPadToBytes32(acc.Balance.Bytes())) ss.exists.PushOne() - ss.keccakCodeHash.push(acc.KeccakCodeHash) + ss.keccakCodeHash.Push(acc.KeccakCodeHash) } else { ss.balance.PushZero() ss.exists.PushZero() - ss.keccakCodeHash.push(types.FullBytes32(statemanager.LEGACY_KECCAK_EMPTY_CODEHASH)) + ss.keccakCodeHash.Push(types.FullBytes32(statemanager.LEGACY_KECCAK_EMPTY_CODEHASH)) } ss.codeSize.PushInt(int(acc.CodeSize)) @@ -289,11 +289,11 @@ func (ss *accountAssignmentBuilder) pushOverrideStorageRoot( if accountExists { ss.balance.PushBytes32(types.LeftPadToBytes32(acc.Balance.Bytes())) ss.exists.PushOne() - ss.keccakCodeHash.push(acc.KeccakCodeHash) + ss.keccakCodeHash.Push(acc.KeccakCodeHash) } else { ss.balance.PushZero() ss.exists.PushZero() - ss.keccakCodeHash.push(types.FullBytes32(statemanager.LEGACY_KECCAK_EMPTY_CODEHASH)) + ss.keccakCodeHash.Push(types.FullBytes32(statemanager.LEGACY_KECCAK_EMPTY_CODEHASH)) } ss.codeSize.PushInt(int(acc.CodeSize)) @@ -309,7 +309,7 @@ func (ss *accountAssignmentBuilder) PadAndAssign(run *wizard.ProverRuntime) { ss.exists.PadAndAssign(run) ss.nonce.PadAndAssign(run) ss.balance.PadAndAssign(run) - ss.keccakCodeHash.padAssign(run, types.FullBytes32{}) + ss.keccakCodeHash.PadAssign(run, types.FullBytes32{}) ss.miMCCodeHash.PadAndAssign(run) ss.storageRoot.PadAndAssign(run) ss.codeSize.PadAndAssign(run) diff --git a/prover/zkevm/prover/statemanager/statesummary/hilo.go b/prover/zkevm/prover/statemanager/statesummary/hilo.go deleted file mode 100644 index 44b422c13..000000000 --- a/prover/zkevm/prover/statemanager/statesummary/hilo.go +++ /dev/null @@ -1,68 +0,0 @@ -package statesummary - -import ( - "github.com/consensys/linea-monorepo/prover/maths/field" - "github.com/consensys/linea-monorepo/prover/protocol/ifaces" - "github.com/consensys/linea-monorepo/prover/protocol/wizard" - "github.com/consensys/linea-monorepo/prover/utils/types" - "github.com/consensys/linea-monorepo/prover/zkevm/prover/common" -) - -// HiLoColumns represents a pair of column representing a sequence of bytes32 -// element that do not fit in a single field element. The Hi columns stores the -// first 16 bytes of the column. And the Lo columns stores the last 16 bytes. -type HiLoColumns struct { - Hi, Lo ifaces.Column -} - -// newHiLoColumns returns a new HiLoColumns with initialized and unconstrained -// columns. -func newHiLoColumns(comp *wizard.CompiledIOP, size int, name string) HiLoColumns { - return HiLoColumns{ - Hi: comp.InsertCommit( - 0, - ifaces.ColIDf("STATE_SUMMARY_%v_HI", name), - size, - ), - Lo: comp.InsertCommit( - 0, - ifaces.ColIDf("STATE_SUMMARY_%v_LO", name), - size, - ), - } -} - -// hiLoAssignmentBuilder is a convenience structure storing the column builders -// relating to an HiLoColumns. -type hiLoAssignmentBuilder struct { - hi, lo *common.VectorBuilder -} - -// newHiLoAssignmentBuilder returns a fresh [hiLoAssignmentBuilder] -func newHiLoAssignmentBuilder(hiLo HiLoColumns) hiLoAssignmentBuilder { - return hiLoAssignmentBuilder{ - hi: common.NewVectorBuilder(hiLo.Hi), - lo: common.NewVectorBuilder(hiLo.Lo), - } -} - -// push pushes a row representing `fb` onto `hl` -func (hl *hiLoAssignmentBuilder) push(fb types.FullBytes32) { - hl.hi.PushHi(fb) - hl.lo.PushLo(fb) -} - -// pushZeroes pushes a row representing 0 onto `hl` -func (hl *hiLoAssignmentBuilder) pushZeroes() { - hl.hi.PushZero() - hl.lo.PushZero() -} - -// padAssign pads `hl` with `fb` and assigns the resulting columns into `run`. -func (hl *hiLoAssignmentBuilder) padAssign(run *wizard.ProverRuntime, fb types.FullBytes32) { - var f field.Element - f.SetBytes(fb[:16]) - hl.hi.PadAndAssign(run, f) - f.SetBytes(fb[16:]) - hl.lo.PadAndAssign(run, f) -} diff --git a/prover/zkevm/prover/statemanager/statesummary/storage_peek.go b/prover/zkevm/prover/statemanager/statesummary/storage_peek.go index af6fb5fb5..a132c6ec0 100644 --- a/prover/zkevm/prover/statemanager/statesummary/storage_peek.go +++ b/prover/zkevm/prover/statemanager/statesummary/storage_peek.go @@ -16,11 +16,11 @@ import ( // slot. type StoragePeek struct { // StorageKey stores the storage key of the peeked slot - Key HiLoColumns + Key common.HiLoColumns // OldValue represents the storage value that is being peeked at. - OldValue HiLoColumns + OldValue common.HiLoColumns // NewValue represents the new value of the storage slot. - NewValue HiLoColumns + NewValue common.HiLoColumns // OldValueIsZero and NewValueIsZero are indicator columns set to 1 when the // old/new value is set to zero and 0 otherwise. @@ -71,9 +71,9 @@ type StoragePeek struct { // unconstrained columns. func newStoragePeek(comp *wizard.CompiledIOP, size int, name string) StoragePeek { res := StoragePeek{ - Key: newHiLoColumns(comp, size, name+"_KEY"), - OldValue: newHiLoColumns(comp, size, name+"_OLD_VALUE"), - NewValue: newHiLoColumns(comp, size, name+"_NEW_VALUE"), + Key: common.NewHiLoColumns(comp, size, name+"_KEY"), + OldValue: common.NewHiLoColumns(comp, size, name+"_OLD_VALUE"), + NewValue: common.NewHiLoColumns(comp, size, name+"_NEW_VALUE"), } res.OldValueHash, res.ComputeOldValueHash = common.HashOf( @@ -128,63 +128,63 @@ func newStoragePeek(comp *wizard.CompiledIOP, size int, name string) StoragePeek // storagePeekAssignmentBuilder is a convenience structure storing the column // builders relating to a StoragePeek. type storagePeekAssignmentBuilder struct { - key, oldValue, newValue hiLoAssignmentBuilder + key, oldValue, newValue common.HiLoAssignmentBuilder } // newStoragePeekAssignmentBuilder constructs a fresh [storagePeekAssignmentBuilder] // with empty columns. func newStoragePeekAssignmentBuilder(sp *StoragePeek) storagePeekAssignmentBuilder { return storagePeekAssignmentBuilder{ - key: newHiLoAssignmentBuilder(sp.Key), - oldValue: newHiLoAssignmentBuilder(sp.OldValue), - newValue: newHiLoAssignmentBuilder(sp.NewValue), + key: common.NewHiLoAssignmentBuilder(sp.Key), + oldValue: common.NewHiLoAssignmentBuilder(sp.OldValue), + newValue: common.NewHiLoAssignmentBuilder(sp.NewValue), } } // pushAllZeroes pushes a zero row onto the receiver func (sh *storagePeekAssignmentBuilder) pushAllZeroes() { - sh.key.pushZeroes() - sh.oldValue.pushZeroes() - sh.newValue.pushZeroes() + sh.key.PushZeroes() + sh.oldValue.PushZeroes() + sh.newValue.PushZeroes() } // pushOnlyKey pushes the key onto the the "key" columns builder and zero on // the others func (sh *storagePeekAssignmentBuilder) pushOnlyKey(key types.FullBytes32) { - sh.key.push(key) - sh.oldValue.pushZeroes() - sh.newValue.pushZeroes() + sh.key.Push(key) + sh.oldValue.PushZeroes() + sh.newValue.PushZeroes() } // pushOnlyOld pushes a row where the keys and the old value are the one provided // by the caller and the new value is zero. func (sh *storagePeekAssignmentBuilder) pushOnlyOld(key, oldVal types.FullBytes32) { - sh.key.push(key) - sh.oldValue.push(oldVal) - sh.newValue.pushZeroes() + sh.key.Push(key) + sh.oldValue.Push(oldVal) + sh.newValue.PushZeroes() } // pushOnlyNew pushes a row where the key and the new value are the one provided // by the caller and the old value is set to zero. func (sh *storagePeekAssignmentBuilder) pushOnlyNew(key, newVal types.FullBytes32) { - sh.key.push(key) - sh.oldValue.pushZeroes() - sh.newValue.push(newVal) + sh.key.Push(key) + sh.oldValue.PushZeroes() + sh.newValue.Push(newVal) } // push pushes a row where the key, the old value and the new value are the // one provided by the caller. func (sh *storagePeekAssignmentBuilder) push(key, oldVal, newVal types.FullBytes32) { - sh.key.push(key) - sh.oldValue.push(oldVal) - sh.newValue.push(newVal) + sh.key.Push(key) + sh.oldValue.Push(oldVal) + sh.newValue.Push(newVal) } // padAssign pads and assigns the columns of the storage peek into `run`. func (sh *storagePeekAssignmentBuilder) padAssign(run *wizard.ProverRuntime) { - sh.key.padAssign(run, types.FullBytes32{}) - sh.oldValue.padAssign(run, types.FullBytes32{}) - sh.newValue.padAssign(run, types.FullBytes32{}) + sh.key.PadAssign(run, types.FullBytes32{}) + sh.oldValue.PadAssign(run, types.FullBytes32{}) + sh.newValue.PadAssign(run, types.FullBytes32{}) } // hashOfZeroStorage returns the hash of (0, 0) which is what we use for empty diff --git a/prover/zkevm/zkevm.go b/prover/zkevm/zkevm.go index f3633e903..b17f5c229 100644 --- a/prover/zkevm/zkevm.go +++ b/prover/zkevm/zkevm.go @@ -7,6 +7,7 @@ import ( "github.com/consensys/linea-monorepo/prover/zkevm/arithmetization" "github.com/consensys/linea-monorepo/prover/zkevm/prover/ecarith" "github.com/consensys/linea-monorepo/prover/zkevm/prover/ecdsa" + "github.com/consensys/linea-monorepo/prover/zkevm/prover/ecpair" "github.com/consensys/linea-monorepo/prover/zkevm/prover/hash/keccak" "github.com/consensys/linea-monorepo/prover/zkevm/prover/hash/sha2" "github.com/consensys/linea-monorepo/prover/zkevm/prover/modexp" @@ -41,7 +42,7 @@ type ZkEvm struct { ecmul *ecarith.EcMul // ecpair is the module responsible for the proving the calls the ecpairing // precompile - // ecpair *ecpair.ECPair + ecpair *ecpair.ECPair // sha2 is the module responsible for doing the computation of the sha2 // precompile. sha2 *sha2.Sha2SingleProvider @@ -99,9 +100,9 @@ func newZkEVM(b *wizard.Builder, s *Settings) *ZkEvm { modexp = modexp.NewModuleZkEvm(comp, s.Modexp) ecadd = ecarith.NewEcAddZkEvm(comp, &s.Ecadd) ecmul = ecarith.NewEcMulZkEvm(comp, &s.Ecmul) - // ecpair = ecpair.NewECPairZkEvm(comp, &s.Ecpair) - sha2 = sha2.NewSha2ZkEvm(comp, s.Sha2) - publicInput = publicInput.NewPublicInputZkEVM(comp, &s.PublicInput, &stateManager.StateSummary) + ecpair = ecpair.NewECPairZkEvm(comp, &s.Ecpair) + sha2 = sha2.NewSha2ZkEvm(comp, s.Sha2) + publicInput = publicInput.NewPublicInputZkEVM(comp, &s.PublicInput, &stateManager.StateSummary) ) return &ZkEvm{ @@ -112,9 +113,9 @@ func newZkEVM(b *wizard.Builder, s *Settings) *ZkEvm { modexp: modexp, ecadd: ecadd, ecmul: ecmul, - // ecpair: ecpair, - sha2: sha2, - PublicInput: &publicInput, + ecpair: ecpair, + sha2: sha2, + PublicInput: &publicInput, } } @@ -135,7 +136,7 @@ func (z *ZkEvm) prove(input *Witness) (prover wizard.ProverStep) { z.modexp.Assign(run) z.ecadd.Assign(run) z.ecmul.Assign(run) - // z.ecpair.Assign(run) + z.ecpair.Assign(run) z.sha2.Run(run) z.PublicInput.Assign(run, input.L2BridgeAddress) } diff --git a/settings.gradle b/settings.gradle index 8ac12e88e..9007998c9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -66,9 +66,11 @@ include 'transaction-exclusion-api:app' include 'transaction-exclusion-api:core' include 'transaction-exclusion-api:persistence:rejectedtransaction' -include 'state-recover:appcore:logic' -include 'state-recover:appcore:domain-models' include 'state-recover:appcore:clients-interfaces' +include 'state-recover:appcore:domain-models' +include 'state-recover:appcore:logic' +include 'state-recover:besu-plugin' include 'state-recover:clients:blobscan-client' include 'state-recover:clients:execution-layer-json-rpc-client' include 'state-recover:clients:eth-api' +include 'state-recover:test-cases' diff --git a/state-recover/appcore/clients-interfaces/build.gradle b/state-recover/appcore/clients-interfaces/build.gradle index 081b3e53a..77d31c11e 100644 --- a/state-recover/appcore/clients-interfaces/build.gradle +++ b/state-recover/appcore/clients-interfaces/build.gradle @@ -6,6 +6,7 @@ group = 'build.linea.staterecover' dependencies { api(project(':jvm-libs:generic:extensions:kotlin')) + api(project(':jvm-libs:generic:serialization:jackson')) api(project(':jvm-libs:linea:core:domain-models')) api(project(':state-recover:appcore:domain-models')) } diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/ExecutionLayerClient.kt b/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/ExecutionLayerClient.kt deleted file mode 100644 index 97b9d40a1..000000000 --- a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/ExecutionLayerClient.kt +++ /dev/null @@ -1,12 +0,0 @@ -package build.linea.staterecover.clients - -import build.linea.staterecover.BlockL1RecoveredData -import net.consensys.linea.BlockNumberAndHash -import net.consensys.linea.BlockParameter -import tech.pegasys.teku.infrastructure.async.SafeFuture - -interface ExecutionLayerClient { - fun getBlockNumberAndHash(blockParameter: BlockParameter): SafeFuture - fun lineaEngineImportBlocksFromBlob(blocks: List): SafeFuture - fun lineaEngineForkChoiceUpdated(headBlockHash: ByteArray, finalizedBlockHash: ByteArray): SafeFuture -} diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/BlobFetcher.kt b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/BlobFetcher.kt similarity index 81% rename from state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/BlobFetcher.kt rename to state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/BlobFetcher.kt index 71523de7f..c3f42d66a 100644 --- a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/BlobFetcher.kt +++ b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/BlobFetcher.kt @@ -1,4 +1,4 @@ -package build.linea.staterecover.clients +package linea.staterecover import tech.pegasys.teku.infrastructure.async.SafeFuture diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/ExecutionLayerClient.kt b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/ExecutionLayerClient.kt new file mode 100644 index 000000000..cab9ad994 --- /dev/null +++ b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/ExecutionLayerClient.kt @@ -0,0 +1,16 @@ +package linea.staterecover + +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import tech.pegasys.teku.infrastructure.async.SafeFuture + +data class StateRecoveryStatus( + val headBlockNumber: ULong, + val stateRecoverStartBlockNumber: ULong? +) +interface ExecutionLayerClient { + fun getBlockNumberAndHash(blockParameter: BlockParameter): SafeFuture + fun lineaEngineImportBlocksFromBlob(blocks: List): SafeFuture + fun lineaGetStateRecoveryStatus(): SafeFuture + fun lineaEnableStateRecovery(stateRecoverStartBlockNumber: ULong): SafeFuture +} diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/RecoveryStatusPersistence.kt b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/RecoveryStatusPersistence.kt new file mode 100644 index 000000000..238a39ac6 --- /dev/null +++ b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/RecoveryStatusPersistence.kt @@ -0,0 +1,81 @@ +package linea.staterecover + +import com.fasterxml.jackson.core.JacksonException +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import java.nio.file.Path + +interface RecoveryStatusPersistence { + fun saveRecoveryStartBlockNumber(recoveryStartBlockNumber: ULong) + fun getRecoveryStartBlockNumber(): ULong? +} + +class InMemoryRecoveryStatus : RecoveryStatusPersistence { + private var recoveryStartBlockNumber: ULong? = null + + @Synchronized + override fun saveRecoveryStartBlockNumber(recoveryStartBlockNumber: ULong) { + this.recoveryStartBlockNumber = recoveryStartBlockNumber + } + + @Synchronized + override fun getRecoveryStartBlockNumber(): ULong? { + return recoveryStartBlockNumber + } +} + +class FileBasedRecoveryStatusPersistence( + filePath: Path +) : RecoveryStatusPersistence { + // A little future proofing in case we need to change the file format in the future + private enum class FileVersion { + V1 // note: do not rename because it will fail to parse the file if already written + } + + private data class RecoveryStatusEnvelopeDto( + val version: FileVersion, + val recoveryStatus: RecoveryStatusV1Dto? + ) + + private data class RecoveryStatusV1Dto( + val recoveryStartBlockNumber: ULong + ) + private val objectMapper = jacksonObjectMapper() + private val file = filePath.toFile() + private var currentStatus: RecoveryStatusV1Dto? = loadStatusFromFileOrCreateIfDoesNotExist() + + private fun saveToFile(status: RecoveryStatusV1Dto?) { + file.writeText( + objectMapper.writeValueAsString( + RecoveryStatusEnvelopeDto(FileVersion.V1, status) + ) + ) + } + + private fun loadStatusFromFileOrCreateIfDoesNotExist(): RecoveryStatusV1Dto? { + // eager file write because if we cannot read/write the file, then application shall throw and fail early + return if (!file.exists()) { + // Create the file with an empty status + saveToFile(status = null) + null + } else { + // read status from file + val envelope = try { + objectMapper.readValue(file, RecoveryStatusEnvelopeDto::class.java) + } catch (e: JacksonException) { + throw IllegalStateException("failed to parse recovery status file: ${file.absolutePath} ", e) + } + envelope.recoveryStatus + } + } + + @Synchronized + override fun saveRecoveryStartBlockNumber(recoveryStartBlockNumber: ULong) { + saveToFile(status = RecoveryStatusV1Dto(recoveryStartBlockNumber)) + currentStatus = RecoveryStatusV1Dto(recoveryStartBlockNumber) + } + + @Synchronized + override fun getRecoveryStartBlockNumber(): ULong? { + return currentStatus?.recoveryStartBlockNumber + } +} diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/TransactionDetailsClient.kt b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/TransactionDetailsClient.kt new file mode 100644 index 000000000..f8e9c42da --- /dev/null +++ b/state-recover/appcore/clients-interfaces/src/main/kotlin/linea/staterecover/TransactionDetailsClient.kt @@ -0,0 +1,7 @@ +package linea.staterecover + +import tech.pegasys.teku.infrastructure.async.SafeFuture + +interface TransactionDetailsClient { + fun getBlobVersionedHashesByTransactionHash(transactionHash: ByteArray): SafeFuture> +} diff --git a/state-recover/appcore/clients-interfaces/src/test/kotlin/linea/staterecover/FileRecoveryStatusPersistenceTest.kt b/state-recover/appcore/clients-interfaces/src/test/kotlin/linea/staterecover/FileRecoveryStatusPersistenceTest.kt new file mode 100644 index 000000000..2ec00e8cc --- /dev/null +++ b/state-recover/appcore/clients-interfaces/src/test/kotlin/linea/staterecover/FileRecoveryStatusPersistenceTest.kt @@ -0,0 +1,87 @@ +package linea.staterecover + +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.attribute.PosixFilePermissions + +class FileRecoveryStatusPersistenceTest { + private lateinit var recoveryStatusPersistence: RecoveryStatusPersistence + + @Test + fun `should return null when no recovery start block number is saved`( + @TempDir tempDir: Path + ) { + val recoveryStatusPersistence = FileBasedRecoveryStatusPersistence(tempDir.resolve("recovery-status.json")) + assertThat(recoveryStatusPersistence.getRecoveryStartBlockNumber()).isNull() + } + + @Test + fun `should return the saved recovery start block number`( + @TempDir tempDir: Path + ) { + FileBasedRecoveryStatusPersistence(tempDir.resolve("recovery-status.json")) + .also { persistence -> + assertThat(persistence.saveRecoveryStartBlockNumber(10U)) + assertThat(persistence.getRecoveryStartBlockNumber()).isEqualTo(10UL) + } + + // simulate application restart, the saved recovery start block number should be loaded from file OK + FileBasedRecoveryStatusPersistence(tempDir.resolve("recovery-status.json")) + .also { persistence -> + assertThat(persistence.getRecoveryStartBlockNumber()).isEqualTo(10UL) + assertThat(persistence.saveRecoveryStartBlockNumber(11U)) + assertThat(persistence.getRecoveryStartBlockNumber()).isEqualTo(11UL) + } + + // simulate application restart, the saved recovery start block number should be loaded from file OK + FileBasedRecoveryStatusPersistence(tempDir.resolve("recovery-status.json")) + .also { persistence -> + assertThat(persistence.getRecoveryStartBlockNumber()).isEqualTo(11UL) + } + } + + @Test + fun `shall throw when it cannot create the file`( + @TempDir tempDir: Path + ) { + val dirWithoutWritePermissions = tempDir.resolve("dir-without-write-permissions") + + Files.createDirectory(dirWithoutWritePermissions) + Files.setPosixFilePermissions(dirWithoutWritePermissions, PosixFilePermissions.fromString("r-xr-xr-x")) + + val file = dirWithoutWritePermissions.resolve("recovery-status.json") + + assertThatThrownBy { + recoveryStatusPersistence = FileBasedRecoveryStatusPersistence(file) + } + .hasMessageContaining(file.toString()) + .hasMessageContaining("Permission denied") + } + + @Test + fun `should throw error when file version is not supported`( + @TempDir tempDir: Path + ) { + val invalidJsonPayload = """ + { + "version": "2", + "recoveryStatus": { + "recoveryStartBlockNumber": 10 + } + } + """.trimIndent() + val file = tempDir.resolve("recovery-status.json") + Files.write(file, invalidJsonPayload.toByteArray()) + + assertThatThrownBy { + recoveryStatusPersistence = FileBasedRecoveryStatusPersistence(file) + } + .isInstanceOf(IllegalStateException::class.java) + .hasMessageContaining(file.toString()) + .hasMessageContaining("parse") + } +} diff --git a/state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/TransactionL1RecoveredData.kt b/state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/TransactionL1RecoveredData.kt deleted file mode 100644 index cd09e2a78..000000000 --- a/state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/TransactionL1RecoveredData.kt +++ /dev/null @@ -1,74 +0,0 @@ -package build.linea.staterecover - -import java.math.BigInteger - -data class TransactionL1RecoveredData( - val type: UByte, - val nonce: ULong, - val maxPriorityFeePerGas: BigInteger, - val maxFeePerGas: BigInteger, - val gasLimit: ULong, - val from: ByteArray, - val to: ByteArray, - val value: BigInteger, - val data: ByteArray, - val accessList: List -) { - - data class AccessTuple( - val address: ByteArray, - val storageKeys: List - ) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as AccessTuple - - if (!address.contentEquals(other.address)) return false - if (storageKeys != other.storageKeys) return false - - return true - } - - override fun hashCode(): Int { - var result = address.contentHashCode() - result = 31 * result + storageKeys.hashCode() - return result - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as TransactionL1RecoveredData - - if (type != other.type) return false - if (nonce != other.nonce) return false - if (maxPriorityFeePerGas != other.maxPriorityFeePerGas) return false - if (maxFeePerGas != other.maxFeePerGas) return false - if (gasLimit != other.gasLimit) return false - if (!from.contentEquals(other.from)) return false - if (!to.contentEquals(other.to)) return false - if (value != other.value) return false - if (!data.contentEquals(other.data)) return false - if (accessList != other.accessList) return false - - return true - } - - override fun hashCode(): Int { - var result = type.hashCode() - result = 31 * result + nonce.hashCode() - result = 31 * result + maxPriorityFeePerGas.hashCode() - result = 31 * result + maxFeePerGas.hashCode() - result = 31 * result + gasLimit.hashCode() - result = 31 * result + from.contentHashCode() - result = 31 * result + to.contentHashCode() - result = 31 * result + value.hashCode() - result = 31 * result + data.contentHashCode() - result = 31 * result + accessList.hashCode() - return result - } -} diff --git a/state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/BlockL1RecoveredData.kt b/state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/BlockFromL1RecoveredData.kt similarity index 68% rename from state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/BlockL1RecoveredData.kt rename to state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/BlockFromL1RecoveredData.kt index be0eef8f2..4e65a6a95 100644 --- a/state-recover/appcore/domain-models/src/main/kotlin/build/linea/staterecover/BlockL1RecoveredData.kt +++ b/state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/BlockFromL1RecoveredData.kt @@ -1,44 +1,21 @@ -package build.linea.staterecover +package linea.staterecover import kotlinx.datetime.Instant import net.consensys.encodeHex -data class BlockExtraData( - val beneficiary: ByteArray -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as BlockExtraData - - return beneficiary.contentEquals(other.beneficiary) - } - - override fun hashCode(): Int { - return beneficiary.contentHashCode() - } - - override fun toString(): String { - return "BlockExtraData(beneficiary=${beneficiary.encodeHex()})" - } -} - -data class BlockL1RecoveredData( +data class BlockHeaderFromL1RecoveredData( val blockNumber: ULong, val blockHash: ByteArray, val coinbase: ByteArray, val blockTimestamp: Instant, val gasLimit: ULong, - val difficulty: ULong, - val extraData: BlockExtraData, - val transactions: List + val difficulty: ULong ) { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false - other as BlockL1RecoveredData + other as BlockHeaderFromL1RecoveredData if (blockNumber != other.blockNumber) return false if (!blockHash.contentEquals(other.blockHash)) return false @@ -46,8 +23,6 @@ data class BlockL1RecoveredData( if (blockTimestamp != other.blockTimestamp) return false if (gasLimit != other.gasLimit) return false if (difficulty != other.difficulty) return false - if (extraData != other.extraData) return false - if (transactions != other.transactions) return false return true } @@ -59,20 +34,44 @@ data class BlockL1RecoveredData( result = 31 * result + blockTimestamp.hashCode() result = 31 * result + gasLimit.hashCode() result = 31 * result + difficulty.hashCode() - result = 31 * result + extraData.hashCode() - result = 31 * result + transactions.hashCode() return result } override fun toString(): String { - return "BlockL1RecoveredData(" + + return "BlockHeaderFromL1RecoveredData(" + "blockNumber=$blockNumber, " + "blockHash=${blockHash.encodeHex()}, " + - "coinbase=${coinbase.encodeHex()}, " + + "coinbase=${coinbase.encodeHex()}," + "blockTimestamp=$blockTimestamp, " + "gasLimit=$gasLimit, " + - "difficulty=$difficulty, " + - "extraData=$extraData, " + - "transactions=$transactions)" + "difficulty=$difficulty" + + ")" + } +} + +data class BlockFromL1RecoveredData( + val header: BlockHeaderFromL1RecoveredData, + val transactions: List +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as BlockFromL1RecoveredData + + if (header != other.header) return false + if (transactions != other.transactions) return false + + return true + } + + override fun hashCode(): Int { + var result = header.hashCode() + result = 31 * result + transactions.hashCode() + return result + } + + override fun toString(): String { + return "BlockFromL1RecoveredData(header=$header, transactions=$transactions)" } } diff --git a/state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/TransactionFromL1RecoveredData.kt b/state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/TransactionFromL1RecoveredData.kt new file mode 100644 index 000000000..3b21faaa3 --- /dev/null +++ b/state-recover/appcore/domain-models/src/main/kotlin/linea/staterecover/TransactionFromL1RecoveredData.kt @@ -0,0 +1,103 @@ +package linea.staterecover + +import net.consensys.encodeHex +import java.math.BigInteger + +data class TransactionFromL1RecoveredData( + val type: UByte, + val nonce: ULong, + val maxPriorityFeePerGas: BigInteger?, + val maxFeePerGas: BigInteger?, + val gasPrice: BigInteger?, + val gasLimit: ULong, + val from: ByteArray, + val to: ByteArray?, + val value: BigInteger, + val data: ByteArray?, + val accessList: List? +) { + + data class AccessTuple( + val address: ByteArray, + val storageKeys: List + ) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as AccessTuple + + if (!address.contentEquals(other.address)) return false + if (storageKeys != other.storageKeys) return false + + return true + } + + override fun hashCode(): Int { + var result = address.contentHashCode() + result = 31 * result + storageKeys.hashCode() + return result + } + + override fun toString(): String { + return "AccessTuple(address=${address.encodeHex()}, storageKeys=$storageKeys)" + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as TransactionFromL1RecoveredData + + if (type != other.type) return false + if (nonce != other.nonce) return false + if (maxPriorityFeePerGas != other.maxPriorityFeePerGas) return false + if (maxFeePerGas != other.maxFeePerGas) return false + if (gasPrice != other.gasPrice) return false + if (gasLimit != other.gasLimit) return false + if (!from.contentEquals(other.from)) return false + if (to != null) { + if (other.to == null) return false + if (!to.contentEquals(other.to)) return false + } else if (other.to != null) return false + if (value != other.value) return false + if (data != null) { + if (other.data == null) return false + if (!data.contentEquals(other.data)) return false + } else if (other.data != null) return false + if (accessList != other.accessList) return false + + return true + } + + override fun hashCode(): Int { + var result = type.hashCode() + result = 31 * result + nonce.hashCode() + result = 31 * result + (maxPriorityFeePerGas?.hashCode() ?: 0) + result = 31 * result + (maxFeePerGas?.hashCode() ?: 0) + result = 31 * result + (gasPrice?.hashCode() ?: 0) + result = 31 * result + gasLimit.hashCode() + result = 31 * result + from.contentHashCode() + result = 31 * result + (to?.contentHashCode() ?: 0) + result = 31 * result + value.hashCode() + result = 31 * result + (data?.contentHashCode() ?: 0) + result = 31 * result + (accessList?.hashCode() ?: 0) + return result + } + + override fun toString(): String { + return "TransactionL1RecoveredData(" + + "type=$type, " + + "nonce=$nonce, " + + "maxPriorityFeePerGas=$maxPriorityFeePerGas, " + + "maxFeePerGas=$maxFeePerGas, " + + "gasPrice=$gasPrice, " + + "gasLimit=$gasLimit, " + + "from=${from.encodeHex()}, " + + "to=${to?.encodeHex()}, " + + "value=$value, " + + "data=${data?.encodeHex()}, " + + "accessList=$accessList)" + } +} diff --git a/state-recover/appcore/logic/build.gradle b/state-recover/appcore/logic/build.gradle new file mode 100644 index 000000000..09a7e0800 --- /dev/null +++ b/state-recover/appcore/logic/build.gradle @@ -0,0 +1,27 @@ +plugins { + id 'net.consensys.zkevm.kotlin-library-conventions' +} + +group = 'build.linea.staterecover' + +dependencies { + api("io.vertx:vertx-core:${libs.versions.vertx.get()}") + api(project(':jvm-libs:generic:extensions:kotlin')) + api(project(':jvm-libs:generic:logging')) + api(project(':jvm-libs:linea:core:domain-models')) + api(project(':jvm-libs:linea:core:long-running-service')) + api(project(':jvm-libs:linea:clients:interfaces')) + api(project(':jvm-libs:linea:clients:linea-state-manager')) + api(project(':jvm-libs:linea:blob-decompressor')) + api(project(':state-recover:appcore:clients-interfaces')) + api(project(':state-recover:appcore:domain-models')) + api project(':jvm-libs:linea:besu-rlp-and-mappers') + api project(':jvm-libs:linea:besu-libs') + + testImplementation(project(":jvm-libs:linea:testing:file-system")) + testImplementation(testFixtures(project(":jvm-libs:linea:blob-compressor"))) + testImplementation("org.bouncycastle:bcprov-jdk18on:1.78.1") + testImplementation("org.apache.logging.log4j:log4j-slf4j2-impl:${libs.versions.log4j.get()}") { + because "besu libs in the tests use slf4j" + } +} diff --git a/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlobDecompressorAndDeserializer.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlobDecompressorAndDeserializer.kt new file mode 100644 index 000000000..fabe322bd --- /dev/null +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlobDecompressorAndDeserializer.kt @@ -0,0 +1,144 @@ +package linea.staterecover + +import io.vertx.core.Vertx +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import linea.domain.BinaryDecoder +import linea.rlp.BesuRlpBlobDecoder +import linea.rlp.RLP +import net.consensys.decodeHex +import net.consensys.encodeHex +import net.consensys.linea.CommonDomainFunctions +import net.consensys.linea.async.toSafeFuture +import net.consensys.linea.blob.BlobDecompressor +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import org.hyperledger.besu.ethereum.core.Block +import tech.pegasys.teku.infrastructure.async.SafeFuture +import java.util.concurrent.Callable +import kotlin.jvm.optionals.getOrNull + +interface BlobDecompressorAndDeserializer { + /** + * Decompresses the EIP4844 blobs and deserializes them into domain objects. + */ + fun decompress( + startBlockNumber: ULong, + blobs: List + ): SafeFuture> +} + +data class BlockHeaderStaticFields( + val coinbase: ByteArray, + val gasLimit: ULong = 61_000_000UL, + val difficulty: ULong = 2UL +) { + companion object { + val mainnet = BlockHeaderStaticFields( + coinbase = "0x8F81e2E3F8b46467523463835F965fFE476E1c9E".decodeHex() + ) + val sepolia = BlockHeaderStaticFields( + coinbase = "0x4D517Aef039A48b3B6bF921e210b7551C8E37107".decodeHex() + ) + val localDev = BlockHeaderStaticFields( + coinbase = "0x6d976c9b8ceee705d4fe8699b44e5eb58242f484".decodeHex() + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as BlockHeaderStaticFields + + if (!coinbase.contentEquals(other.coinbase)) return false + if (gasLimit != other.gasLimit) return false + if (difficulty != other.difficulty) return false + + return true + } + + override fun hashCode(): Int { + var result = coinbase.contentHashCode() + result = 31 * result + gasLimit.hashCode() + result = 31 * result + difficulty.hashCode() + return result + } + + override fun toString(): String { + return "BlockHeaderStaticFields(coinbase=${coinbase.encodeHex()}, gasLimit=$gasLimit, difficulty=$difficulty)" + } +} + +class BlobDecompressorToDomainV1( + val decompressor: BlobDecompressor, + val staticFields: BlockHeaderStaticFields, + val vertx: Vertx, + val decoder: BinaryDecoder = BesuRlpBlobDecoder, + val logger: Logger = LogManager.getLogger(BlobDecompressorToDomainV1::class.java) +) : BlobDecompressorAndDeserializer { + override fun decompress( + startBlockNumber: ULong, + blobs: List + ): SafeFuture> { + var blockNumber = startBlockNumber + val startTime = Clock.System.now() + logger.debug("start decompressing blobs: startBlockNumber={} {} blobs", startBlockNumber, blobs.size) + val decompressedBlobs = blobs.map { decompressor.decompress(it) } + return SafeFuture + .collectAll(decompressedBlobs.map(::decodeBlocksAsync).stream()) + .thenApply { blobsBlocks: List> -> + blobsBlocks.flatten().map { block -> + val header = BlockHeaderFromL1RecoveredData( + blockNumber = blockNumber++, + blockHash = block.header.hash.toArray(), + coinbase = staticFields.coinbase, + blockTimestamp = Instant.fromEpochSeconds(block.header.timestamp), + gasLimit = this.staticFields.gasLimit, + difficulty = this.staticFields.difficulty + ) + val transactions = block.body.transactions.map { transaction -> + TransactionFromL1RecoveredData( + type = transaction.type.serializedType.toUByte(), + from = transaction.sender.toArray(), + nonce = transaction.nonce.toULong(), + gasLimit = transaction.gasLimit.toULong(), + maxFeePerGas = transaction.maxFeePerGas.getOrNull()?.asBigInteger, + maxPriorityFeePerGas = transaction.maxPriorityFeePerGas.getOrNull()?.asBigInteger, + gasPrice = transaction.gasPrice.getOrNull()?.asBigInteger, + to = transaction.to.getOrNull()?.toArray(), + value = transaction.value.asBigInteger, + data = transaction.payload.toArray(), + accessList = transaction.accessList.getOrNull()?.map { accessTuple -> + TransactionFromL1RecoveredData.AccessTuple( + address = accessTuple.address.toArray(), + storageKeys = accessTuple.storageKeys.map { it.toArray() } + ) + } + ) + } + BlockFromL1RecoveredData( + header = header, + transactions = transactions + ) + } + }.thenPeek { + val endTime = Clock.System.now() + logger.debug( + "blobs decompressed and serialized: duration={} blobsCount={} blocks={}", + endTime - startTime, + blobs.size, + CommonDomainFunctions.blockIntervalString(startBlockNumber, blockNumber - 1UL) + ) + } + } + + private fun decodeBlocksAsync(blocksRLP: ByteArray): SafeFuture> { + return vertx.executeBlocking( + Callable { RLP.decodeList(blocksRLP).map(decoder::decode) }, + false + ) + .onFailure(logger::error) + .toSafeFuture() + } +} diff --git a/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlockImporter.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlockImporter.kt new file mode 100644 index 000000000..404f3cdb5 --- /dev/null +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/BlockImporter.kt @@ -0,0 +1,77 @@ +package linea.staterecover + +import build.linea.clients.StateManagerClientV1 +import build.linea.domain.BlockInterval +import io.vertx.core.Vertx +import net.consensys.linea.async.AsyncRetryer +import tech.pegasys.teku.infrastructure.async.SafeFuture +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +data class ImportResult( + val blockNumber: ULong, + val zkStateRootHash: ByteArray +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ImportResult + + if (blockNumber != other.blockNumber) return false + if (!zkStateRootHash.contentEquals(other.zkStateRootHash)) return false + + return true + } + + override fun hashCode(): Int { + var result = blockNumber.hashCode() + result = 31 * result + zkStateRootHash.contentHashCode() + return result + } +} + +interface BlockImporterAndStateVerifier { + fun importBlocks(blocks: List): SafeFuture +} + +class BlockImporterAndStateVerifierV1( + private val vertx: Vertx, + private val elClient: ExecutionLayerClient, + private val stateManagerClient: StateManagerClientV1, + private val stateManagerImportTimeoutPerBlock: Duration +) : BlockImporterAndStateVerifier { + override fun importBlocks(blocks: List): SafeFuture { + return elClient + .lineaEngineImportBlocksFromBlob(blocks) + .thenCompose { + getBlockStateRootHash( + blockNumber = blocks.last().header.blockNumber, + timeout = stateManagerImportTimeoutPerBlock.times(blocks.size) + ) + } + .thenApply { stateRootHash -> + ImportResult( + blockNumber = blocks.last().header.blockNumber, + zkStateRootHash = stateRootHash + ) + } + } + + private fun getBlockStateRootHash( + blockNumber: ULong, + timeout: Duration + ): SafeFuture { + return AsyncRetryer + .retry( + vertx, + backoffDelay = 1.seconds, + timeout = timeout, + stopRetriesPredicate = { headBlockNumber -> headBlockNumber >= blockNumber }, + action = { stateManagerClient.rollupGetHeadBlockNumber() } + ) + .thenCompose { + stateManagerClient.rollupGetStateMerkleProof(BlockInterval(blockNumber, blockNumber)) + }.thenApply { proofResponse -> proofResponse.zkEndStateRootHash } + } +} diff --git a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/LineaSubmissionEventsClient.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClient.kt similarity index 94% rename from state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/LineaSubmissionEventsClient.kt rename to state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClient.kt index 789e3a38d..be4006fe0 100644 --- a/state-recover/appcore/clients-interfaces/src/main/kotlin/build/linea/staterecover/clients/LineaSubmissionEventsClient.kt +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClient.kt @@ -1,4 +1,4 @@ -package build.linea.staterecover.clients +package linea.staterecover import build.linea.domain.BlockInterval import build.linea.domain.EthLog @@ -14,6 +14,7 @@ data class DataSubmittedV3( val finalStateRootHash: ByteArray ) { companion object { + val topic = "0x55f4c645c36aa5cd3f443d6be44d7a7a5df9d2100d7139dfc69d4289ee072319" fun fromEthLog(ethLog: EthLog): EthLogEvent { // DataSubmittedV3(bytes32 parentShnarf, bytes32 indexed shnarf, bytes32 finalStateRootHash); return EthLogEvent( @@ -63,6 +64,7 @@ data class DataFinalizedV3( val finalStateRootHash: ByteArray ) : BlockInterval { companion object { + val topic = "0xa0262dc79e4ccb71ceac8574ae906311ae338aa4a2044fd4ec4b99fad5ab60cb" fun fromEthLog(ethLog: EthLog): EthLogEvent { /**event DataFinalizedV3( uint256 indexed startBlockNumber, @@ -126,7 +128,7 @@ data class FinalizationAndDataEventsV3( interface LineaRollupSubmissionEventsClient { fun findDataFinalizedEventByStartBlockNumber( - l2BlockNumber: ULong + l2StartBlockNumberInclusive: ULong ): SafeFuture?> fun findDataFinalizedEventContainingBlock( diff --git a/state-recover/clients/smartcontract/src/main/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientWeb3jIpml.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClientImpl.kt similarity index 54% rename from state-recover/clients/smartcontract/src/main/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientWeb3jIpml.kt rename to state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClientImpl.kt index 7d7da3e57..f3f96a4c2 100644 --- a/state-recover/clients/smartcontract/src/main/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientWeb3jIpml.kt +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/LineaSubmissionEventsClientImpl.kt @@ -1,41 +1,48 @@ -package linea.build.staterecover.clients.smartcontract +package linea.staterecover -import build.linea.contract.LineaRollupV6 import build.linea.domain.EthLogEvent -import build.linea.staterecover.clients.DataFinalizedV3 -import build.linea.staterecover.clients.DataSubmittedV3 -import build.linea.staterecover.clients.FinalizationAndDataEventsV3 -import build.linea.staterecover.clients.LineaRollupSubmissionEventsClient -import build.linea.web3j.domain.toDomain -import build.linea.web3j.domain.toWeb3j +import linea.EthLogsSearcher +import linea.SearchDirection import net.consensys.encodeHex import net.consensys.linea.BlockParameter import net.consensys.linea.BlockParameter.Companion.toBlockParameter -import net.consensys.linea.contract.Web3JLogsClient import net.consensys.toHexStringUInt256 -import org.web3j.abi.EventEncoder -import org.web3j.protocol.core.methods.request.EthFilter -import org.web3j.protocol.core.methods.response.Log import tech.pegasys.teku.infrastructure.async.SafeFuture -class LineaSubmissionEventsClientWeb3jIpml( - private val logsClient: Web3JLogsClient, +class LineaSubmissionEventsClientImpl( + private val logsSearcher: EthLogsSearcher, private val smartContractAddress: String, - private val mostRecentBlockTag: BlockParameter = BlockParameter.Tag.FINALIZED + private val l1EarliestSearchBlock: BlockParameter = BlockParameter.Tag.EARLIEST, + private val l1LatestSearchBlock: BlockParameter = BlockParameter.Tag.FINALIZED, + private val logsBlockChunkSize: Int = 1000 ) : LineaRollupSubmissionEventsClient { - - override fun findDataFinalizedEventContainingBlock(l2BlockNumber: ULong): SafeFuture?> { - TODO("Not yet implemented") + override fun findDataFinalizedEventContainingBlock( + l2BlockNumber: ULong + ): SafeFuture?> { + return logsSearcher.findLog( + fromBlock = l1EarliestSearchBlock, + toBlock = l1LatestSearchBlock, + address = smartContractAddress, + topics = listOf(DataFinalizedV3.topic), + chunkSize = logsBlockChunkSize, + shallContinueToSearch = { log -> + val (event) = DataFinalizedV3.fromEthLog(log) + when { + l2BlockNumber < event.startBlockNumber -> SearchDirection.BACKWARD + l2BlockNumber > event.endBlockNumber -> SearchDirection.FORWARD + else -> null + } + } + ).thenApply { it?.let { DataFinalizedV3.fromEthLog(it) } } } override fun findDataFinalizedEventByStartBlockNumber( - l2BlockNumber: ULong + l2StartBlockNumberInclusive: ULong ): SafeFuture?> { - // TODO: be less eager on block range to search return findDataFinalizedV3Event( - fromL1BlockNumber = BlockParameter.Tag.EARLIEST, - toL1BlockNumber = mostRecentBlockTag, - startBlockNumber = l2BlockNumber + fromL1BlockNumber = l1EarliestSearchBlock, + toL1BlockNumber = l1LatestSearchBlock, + startBlockNumber = l2StartBlockNumberInclusive ) } @@ -43,8 +50,8 @@ class LineaSubmissionEventsClientWeb3jIpml( l2StartBlockNumberInclusive: ULong ): SafeFuture { return findDataFinalizedV3Event( - fromL1BlockNumber = BlockParameter.Tag.EARLIEST, - toL1BlockNumber = mostRecentBlockTag, + fromL1BlockNumber = l1EarliestSearchBlock, + toL1BlockNumber = l1LatestSearchBlock, startBlockNumber = l2StartBlockNumberInclusive ) .thenCompose { finalizationEvent -> @@ -69,40 +76,37 @@ class LineaSubmissionEventsClientWeb3jIpml( "Either startBlockNumber or endBlockNumber must be provided" } - val ethFilter = - EthFilter( - fromL1BlockNumber.toWeb3j(), - toL1BlockNumber.toWeb3j(), - smartContractAddress - ).apply { - /** - event DataFinalizedV3( - uint256 indexed startBlockNumber, - uint256 indexed endBlockNumber, - bytes32 indexed shnarf, - bytes32 parentStateRootHash, - bytes32 finalStateRootHash - ); - */ - addSingleTopic(EventEncoder.encode(LineaRollupV6.DATAFINALIZEDV3_EVENT)) - addSingleTopic(startBlockNumber?.toHexStringUInt256()) - addSingleTopic(endBlockNumber?.toHexStringUInt256()) - } - - return logsClient - .getLogs(ethFilter) - .thenApply(Companion::parseDataFinalizedV3) - .thenCompose { finalizedEvents -> - if (finalizedEvents.size > 1) { - // just a safety check - // this should never happen: Finalization events shall be sequential and deterministic - val errorMessage = - "More than one DataFinalizedV3 event found for startBlockNumber=$startBlockNumber events=$finalizedEvents" - SafeFuture.failedFuture(IllegalStateException(errorMessage)) - } else { - SafeFuture.completedFuture(finalizedEvents.firstOrNull()) - } + /** + event DataFinalizedV3( + uint256 indexed startBlockNumber, + uint256 indexed endBlockNumber, + bytes32 indexed shnarf, + bytes32 parentStateRootHash, + bytes32 finalStateRootHash + ); + */ + return logsSearcher.getLogs( + fromBlock = fromL1BlockNumber, + toBlock = toL1BlockNumber, + address = smartContractAddress, + topics = listOf( + DataFinalizedV3.topic, + startBlockNumber?.toHexStringUInt256(), + endBlockNumber?.toHexStringUInt256() + ) + ).thenCompose { rawLogs -> + val finalizedEvents = rawLogs.map(DataFinalizedV3::fromEthLog) + + if (finalizedEvents.size > 1) { + // just a safety check + // this should never happen: Finalization events shall be sequential and deterministic + val errorMessage = + "More than one DataFinalizedV3 event found for startBlockNumber=$startBlockNumber events=$finalizedEvents" + SafeFuture.failedFuture(IllegalStateException(errorMessage)) + } else { + SafeFuture.completedFuture(finalizedEvents.firstOrNull()) } + } } private fun findAggregationDataSubmittedV3Events( @@ -154,21 +158,18 @@ class LineaSubmissionEventsClientWeb3jIpml( tol1BlockParameter: BlockParameter, shnarf: ByteArray ): SafeFuture?> { - val ethFilter = - EthFilter( - fromL1BlockParameter.toWeb3j(), - tol1BlockParameter.toWeb3j(), - smartContractAddress - ).apply { - // event DataSubmittedV3(bytes32 parentShnarf, bytes32 indexed shnarf, bytes32 finalStateRootHash); - addSingleTopic(EventEncoder.encode(LineaRollupV6.DATASUBMITTEDV3_EVENT)) - addSingleTopic(shnarf.encodeHex()) // shnarf - } - - return logsClient - .getLogs(ethFilter) - .thenApply(Companion::parseDataSubmittedV3) - .thenApply { events -> + return logsSearcher + .getLogs( + fromBlock = fromL1BlockParameter, + toBlock = tol1BlockParameter, + address = smartContractAddress, + topics = listOf( + DataSubmittedV3.topic, + shnarf.encodeHex() + ) + ) + .thenApply { rawLogs -> + val events = rawLogs.map(DataSubmittedV3::fromEthLog) if (events.size > 1) { // just a safety check // this should never happen: having more than blob with the same shnarf @@ -180,14 +181,4 @@ class LineaSubmissionEventsClientWeb3jIpml( } } } - - companion object { - private fun parseDataSubmittedV3(logs: List): List> { - return logs.map { log -> DataSubmittedV3.fromEthLog(log.toDomain()) } - } - - private fun parseDataFinalizedV3(logs: List): List> { - return logs.map { log -> DataFinalizedV3.fromEthLog(log.toDomain()) } - } - } } diff --git a/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateRecoverApp.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateRecoverApp.kt new file mode 100644 index 000000000..4213edbd8 --- /dev/null +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateRecoverApp.kt @@ -0,0 +1,197 @@ +package linea.staterecover + +import build.linea.clients.StateManagerClientV1 +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly +import build.linea.domain.EthLogEvent +import io.vertx.core.Vertx +import linea.EthLogsSearcher +import net.consensys.linea.BlockParameter +import net.consensys.linea.BlockParameter.Companion.toBlockParameter +import net.consensys.linea.async.AsyncRetryer +import net.consensys.linea.blob.BlobDecompressorVersion +import net.consensys.linea.blob.GoNativeBlobDecompressorFactory +import net.consensys.zkevm.LongRunningService +import org.apache.logging.log4j.LogManager +import tech.pegasys.teku.infrastructure.async.SafeFuture +import java.util.concurrent.CompletableFuture +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +class StateRecoverApp( + private val vertx: Vertx, + // Driving Ports + private val lineaContractClient: LineaRollupSmartContractClientReadOnly, + private val ethLogsSearcher: EthLogsSearcher, + // Driven Ports + private val blobFetcher: BlobFetcher, + private val elClient: ExecutionLayerClient, + private val stateManagerClient: StateManagerClientV1, + private val transactionDetailsClient: TransactionDetailsClient, + private val blockHeaderStaticFields: BlockHeaderStaticFields, + // configs + private val config: Config = Config.lineaMainnet +) : LongRunningService { + data class Config( + val smartContractAddress: String, + val l1EarliestSearchBlock: BlockParameter = BlockParameter.Tag.EARLIEST, + val l1LatestSearchBlock: BlockParameter = BlockParameter.Tag.FINALIZED, + val l1PollingInterval: Duration = 12.seconds, + val executionClientPollingInterval: Duration = 1.seconds, + val blobDecompressorVersion: BlobDecompressorVersion = BlobDecompressorVersion.V1_1_0, + val logsBlockChunkSize: UInt = 1000u, + /** + * The block number at which the recovery mode will start overriding the recovery start block number + * this is meant for testing purposes, not production + */ + val overridingRecoveryStartBlockNumber: ULong? = null + ) { + companion object { + val lineaMainnet = Config( + smartContractAddress = "0xd19d4b5d358258f05d7b411e21a1460d11b0876f", + // TODO: set block of V6 Upgrade + l1EarliestSearchBlock = 1UL.toBlockParameter(), + l1LatestSearchBlock = BlockParameter.Tag.FINALIZED, + executionClientPollingInterval = 10.seconds, + l1PollingInterval = 12.seconds + ) + val lineaSepolia = Config( + smartContractAddress = "0xb218f8a4bc926cf1ca7b3423c154a0d627bdb7e5", + l1EarliestSearchBlock = 7164537UL.toBlockParameter(), + l1LatestSearchBlock = BlockParameter.Tag.FINALIZED, + executionClientPollingInterval = 10.seconds, + l1PollingInterval = 12.seconds + ) + } + } + + init { + require(config.smartContractAddress.lowercase() == lineaContractClient.getAddress().lowercase()) { + "contract address mismatch: config=${config.smartContractAddress} client=${lineaContractClient.getAddress()}" + } + } + private val l1EventsClient = LineaSubmissionEventsClientImpl( + logsSearcher = ethLogsSearcher, + smartContractAddress = config.smartContractAddress, + l1EarliestSearchBlock = config.l1EarliestSearchBlock, + l1LatestSearchBlock = config.l1LatestSearchBlock, + logsBlockChunkSize = config.logsBlockChunkSize.toInt() + ) + private val log = LogManager.getLogger(this::class.java) + private val blockImporterAndStateVerifier = BlockImporterAndStateVerifierV1( + vertx = vertx, + elClient = elClient, + stateManagerClient = stateManagerClient, + stateManagerImportTimeoutPerBlock = 2.seconds + ) + private val blobDecompressor: BlobDecompressorAndDeserializer = BlobDecompressorToDomainV1( + decompressor = GoNativeBlobDecompressorFactory.getInstance(config.blobDecompressorVersion), + staticFields = blockHeaderStaticFields, + vertx = vertx + ) + private val stateSynchronizerService = StateSynchronizerService( + vertx = vertx, + elClient = elClient, + submissionEventsClient = l1EventsClient, + blobsFetcher = blobFetcher, + transactionDetailsClient = transactionDetailsClient, + blobDecompressor = blobDecompressor, + blockImporterAndStateVerifier = blockImporterAndStateVerifier, + pollingInterval = config.l1PollingInterval + ) + val lastSuccessfullyRecoveredFinalization: EthLogEvent? + get() = stateSynchronizerService.lastSuccessfullyProcessedFinalization + val stateRootMismatchFound: Boolean + get() = stateSynchronizerService.stateRootMismatchFound + + fun trySetRecoveryModeAtBlockHeight(stateRecoverStartBlockNumber: ULong): SafeFuture { + return elClient + .lineaGetStateRecoveryStatus() + .thenCompose { statusBeforeUpdate -> + elClient + .lineaEnableStateRecovery(stateRecoverStartBlockNumber) + .thenPeek { newStatus -> + val updateLabel = if (statusBeforeUpdate.stateRecoverStartBlockNumber == null) "Enabled" else "Updated" + log.info( + "Recovery mode was {}: headBlockNumber={} " + + "prevStartBlockNumber={} newStartBlockNumber={}", + updateLabel, + newStatus.headBlockNumber, + statusBeforeUpdate.stateRecoverStartBlockNumber, + newStatus.stateRecoverStartBlockNumber + ) + } + } + } + + private fun enableRecoveryMode(): SafeFuture<*> { + if (config.overridingRecoveryStartBlockNumber != null) { + return trySetRecoveryModeAtBlockHeight(config.overridingRecoveryStartBlockNumber) + } + + return elClient + .lineaGetStateRecoveryStatus() + .thenCompose { status -> + if (status.stateRecoverStartBlockNumber != null) { + // already enabled, let's just resume from where we left off + log.info( + "starting recovery mode already enabled: stateRecoverStartBlockNumber={} headBlockNumber={}", + status.stateRecoverStartBlockNumber, + status.headBlockNumber + ) + SafeFuture.completedFuture(Unit) + } else { + lineaContractClient.finalizedL2BlockNumber(blockParameter = config.l1LatestSearchBlock) + .thenCompose { lastFinalizedBlockNumber -> + val stateRecoverStartBlockNumber = when { + status.headBlockNumber >= lastFinalizedBlockNumber -> status.headBlockNumber + 1UL + else -> lastFinalizedBlockNumber + 1UL + } + log.info( + "Starting enabling recovery mode: stateRecoverStartBlockNumber={} headBlockNumber={} " + + "L1 lastFinalizedBlockNumber={}", + stateRecoverStartBlockNumber, + status.headBlockNumber, + lastFinalizedBlockNumber + ) + elClient.lineaEnableStateRecovery(stateRecoverStartBlockNumber) + }.thenApply { } + } + } + } + + private fun waitForSyncUntilStateRecoverBlock(): SafeFuture { + return AsyncRetryer.retry( + vertx = vertx, + backoffDelay = config.executionClientPollingInterval, + stopRetriesPredicate = { recoveryStatus -> + log.debug( + "waiting for node to sync until stateRecoverStartBlockNumber={} headBlockNumber={}", + recoveryStatus.stateRecoverStartBlockNumber, + recoveryStatus.headBlockNumber + ) + // headBlockNumber shall be at least 1 block behind of stateRecoverStartBlockNumber + // if it is after it means it was already enabled + recoveryStatus.stateRecoverStartBlockNumber?.let { startBlockNumber -> + recoveryStatus.headBlockNumber + 1u >= startBlockNumber + } ?: false + } + ) { + elClient.lineaGetStateRecoveryStatus() + } + } + + override fun start(): CompletableFuture { + log.warn("Starting StateRecoverApp") + val enablementFuture = enableRecoveryMode() + + enablementFuture + .thenCompose { waitForSyncUntilStateRecoverBlock() } + .thenCompose { stateSynchronizerService.start() } + + return enablementFuture.thenApply { } + } + + override fun stop(): CompletableFuture { + return stateSynchronizerService.stop() + } +} diff --git a/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateSynchronizerService.kt b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateSynchronizerService.kt new file mode 100644 index 000000000..88b2ba9e8 --- /dev/null +++ b/state-recover/appcore/logic/src/main/kotlin/linea/staterecover/StateSynchronizerService.kt @@ -0,0 +1,179 @@ +package linea.staterecover + +import build.linea.domain.EthLogEvent +import io.vertx.core.Vertx +import net.consensys.encodeHex +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import net.consensys.linea.CommonDomainFunctions +import net.consensys.zkevm.PeriodicPollingService +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import tech.pegasys.teku.infrastructure.async.SafeFuture +import kotlin.time.Duration + +class StateSynchronizerService( + private val vertx: Vertx, + private val elClient: ExecutionLayerClient, + private val submissionEventsClient: LineaRollupSubmissionEventsClient, + private val blobsFetcher: BlobFetcher, + private val transactionDetailsClient: TransactionDetailsClient, + private val blobDecompressor: BlobDecompressorAndDeserializer, + private val blockImporterAndStateVerifier: BlockImporterAndStateVerifier, + private val pollingInterval: Duration, + private val log: Logger = LogManager.getLogger(StateSynchronizerService::class.java) +) : PeriodicPollingService( + vertx = vertx, + log = log, + pollingIntervalMs = pollingInterval.inWholeMilliseconds +) { + private data class DataSubmittedEventAndBlobs( + val ethLogEvent: EthLogEvent, + val blobs: List + ) + + var lastSuccessfullyProcessedFinalization: EthLogEvent? = null + var stateRootMismatchFound: Boolean = false + private set(value) { + field = value + } + + private fun findNextFinalization(): SafeFuture?> { + return if (lastSuccessfullyProcessedFinalization != null) { + submissionEventsClient + .findDataFinalizedEventByStartBlockNumber( + l2StartBlockNumberInclusive = lastSuccessfullyProcessedFinalization!!.event.endBlockNumber + 1UL + ) + } else { + elClient.getBlockNumberAndHash(blockParameter = BlockParameter.Tag.LATEST) + .thenCompose { headBlock -> + // 1st, assuming head matches a prev finalization, + val nextBlockToImport = headBlock.number + 1UL + submissionEventsClient + .findDataFinalizedEventByStartBlockNumber(l2StartBlockNumberInclusive = nextBlockToImport) + .thenCompose { finalizationEvent -> + if (finalizationEvent != null) { + SafeFuture.completedFuture(finalizationEvent) + } else { + // 2nd: otherwise, local head may be in between, let's find corresponding finalization + submissionEventsClient + .findDataFinalizedEventContainingBlock(l2BlockNumber = nextBlockToImport) + } + } + } + } + } + + override fun action(): SafeFuture { + if (stateRootMismatchFound) { + return SafeFuture.failedFuture(IllegalStateException("state root mismatch found cannot continue")) + } + + return findNextFinalization() + .thenCompose { nextFinalization -> + if (nextFinalization == null) { + // nothing to do for now + SafeFuture.completedFuture(null) + } else { + submissionEventsClient + .findDataSubmittedV3EventsUntilNextFinalization( + l2StartBlockNumberInclusive = nextFinalization.event.startBlockNumber + ) + } + } + .thenCompose { submissionEvents -> + if (submissionEvents == null) { + SafeFuture.completedFuture("No new events") + } else { + getBlobsForEvents(submissionEvents.dataSubmittedEvents) + .thenCompose { dataSubmissionsWithBlobs -> + updateNodeWithBlobsAndVerifyState(dataSubmissionsWithBlobs, submissionEvents.dataFinalizedEvent.event) + } + .thenApply { + lastSuccessfullyProcessedFinalization = submissionEvents.dataFinalizedEvent + } + } + } + } + + private fun getBlobsForEvents( + events: List> + ): SafeFuture> { + return SafeFuture.collectAll( + events + .map { dataSubmittedEvent -> + transactionDetailsClient + .getBlobVersionedHashesByTransactionHash(dataSubmittedEvent.log.transactionHash) + .thenCompose(blobsFetcher::fetchBlobsByHash) + .thenApply { blobs -> DataSubmittedEventAndBlobs(dataSubmittedEvent, blobs) } + }.stream() + ) + } + + private fun updateNodeWithBlobsAndVerifyState( + dataSubmissions: List, + dataFinalizedV3: DataFinalizedV3 + ): SafeFuture { + return blobDecompressor + .decompress( + startBlockNumber = dataFinalizedV3.startBlockNumber, + blobs = dataSubmissions.flatMap { it.blobs } + ) + .thenCompose(this::filterOutBlocksAlreadyImported) + .thenCompose { decompressedBlocks: List -> + val blockInterval = CommonDomainFunctions.blockIntervalString( + decompressedBlocks.first().header.blockNumber, + decompressedBlocks.last().header.blockNumber + ) + log.debug("importing blocks={} from finalization={}", blockInterval, dataFinalizedV3.intervalString()) + blockImporterAndStateVerifier + .importBlocks(decompressedBlocks) + .thenCompose { importResult -> + log.debug("imported blocks={}", dataFinalizedV3.intervalString()) + assertStateMatches(importResult, dataFinalizedV3) + } + .thenApply { + BlockNumberAndHash( + number = decompressedBlocks.last().header.blockNumber, + hash = decompressedBlocks.last().header.blockHash + ) + } + } + } + + private fun filterOutBlocksAlreadyImported( + blocks: List + ): SafeFuture> { + return elClient.getBlockNumberAndHash(blockParameter = BlockParameter.Tag.LATEST) + .thenApply { headBlock -> + blocks.dropWhile { it.header.blockNumber <= headBlock.number } + } + } + + private fun assertStateMatches( + importResult: ImportResult, + finalizedV3: DataFinalizedV3 + ): SafeFuture { + return if (importResult.zkStateRootHash.contentEquals(finalizedV3.finalStateRootHash)) { + log.info( + "state recovered up to block={} zkStateRootHash={} finalization={}", + importResult.blockNumber, + importResult.zkStateRootHash.encodeHex(), + finalizedV3.intervalString() + ) + SafeFuture.completedFuture(Unit) + } else { + log.error( + "stopping data recovery from L1, stateRootHash mismatch: " + + "finalization={} recoveredStateRootHash={} expected block={} to have l1 proven stateRootHash={}", + finalizedV3.intervalString(), + finalizedV3.finalStateRootHash.encodeHex(), + importResult.zkStateRootHash.encodeHex(), + finalizedV3.endBlockNumber + ) + stateRootMismatchFound = true + this.stop() + SafeFuture.completedFuture(Unit) + } + } +} diff --git a/state-recover/appcore/logic/src/test/kotlin/linea/staterecover/BlobDecompressorAndDeserializerV1Test.kt b/state-recover/appcore/logic/src/test/kotlin/linea/staterecover/BlobDecompressorAndDeserializerV1Test.kt new file mode 100644 index 000000000..2229c49b9 --- /dev/null +++ b/state-recover/appcore/logic/src/test/kotlin/linea/staterecover/BlobDecompressorAndDeserializerV1Test.kt @@ -0,0 +1,137 @@ +package linea.staterecover + +import io.vertx.core.Vertx +import kotlinx.datetime.Instant +import linea.blob.BlobCompressor +import linea.blob.GoBackedBlobCompressor +import linea.rlp.RLP +import net.consensys.encodeHex +import net.consensys.linea.blob.BlobCompressorVersion +import net.consensys.linea.blob.BlobDecompressorVersion +import net.consensys.linea.blob.GoNativeBlobDecompressorFactory +import net.consensys.linea.nativecompressor.CompressorTestData +import org.apache.tuweni.bytes.Bytes32 +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.fail +import org.hyperledger.besu.datatypes.Address +import org.hyperledger.besu.ethereum.core.Block +import org.hyperledger.besu.ethereum.core.Transaction +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.opentest4j.AssertionFailedError +import kotlin.jvm.optionals.getOrNull + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class BlobDecompressorAndDeserializerV1Test { + private lateinit var compressor: BlobCompressor + private val blockStaticFields = BlockHeaderStaticFields( + coinbase = Address.ZERO.toArray(), + gasLimit = 30_000_000UL, + difficulty = 0UL + ) + private lateinit var decompressorToDomain: BlobDecompressorAndDeserializer + private lateinit var vertx: Vertx + + @BeforeEach + fun setUp() { + vertx = Vertx.vertx() + compressor = GoBackedBlobCompressor.getInstance( + compressorVersion = BlobCompressorVersion.V1_0_1, + dataLimit = 124u * 1024u + ) + val decompressor = GoNativeBlobDecompressorFactory.getInstance(BlobDecompressorVersion.V1_1_0) + decompressorToDomain = BlobDecompressorToDomainV1(decompressor, blockStaticFields, vertx) + } + + @AfterEach + fun afterEach() { + vertx.close() + } + + @Test + fun `should decompress block and transactions`() { + val blocksRLP = CompressorTestData.blocksRlpEncoded + assertBlockCompressionAndDecompression(blocksRLP) + } + + private fun assertBlockCompressionAndDecompression( + blocksRLP: List + ) { + val blocks = blocksRLP.map(RLP::decodeBlockWithMainnetFunctions) + val startingBlockNumber = blocks[0].header.number.toULong() + + val blobs = blocks.chunked(2).map { compressBlocks(it) } + + val recoveredBlocks = decompressorToDomain.decompress( + startBlockNumber = startingBlockNumber, + blobs = blobs + ).get() + assertThat(recoveredBlocks[0].header.blockNumber).isEqualTo(startingBlockNumber) + + recoveredBlocks.zip(blocks) { recoveredBlock, originalBlock -> + assertBlockData(recoveredBlock, originalBlock) + } + } + + private fun assertBlockData( + uncompressed: BlockFromL1RecoveredData, + original: Block + ) { + try { + assertThat(uncompressed.header.blockNumber).isEqualTo(original.header.number.toULong()) + assertThat(uncompressed.header.blockHash.encodeHex()).isEqualTo(original.header.hash.toArray().encodeHex()) + assertThat(uncompressed.header.coinbase).isEqualTo(blockStaticFields.coinbase) + assertThat(uncompressed.header.blockTimestamp).isEqualTo(Instant.fromEpochSeconds(original.header.timestamp)) + assertThat(uncompressed.header.gasLimit).isEqualTo(blockStaticFields.gasLimit) + assertThat(uncompressed.header.difficulty).isEqualTo(blockStaticFields.difficulty) + uncompressed.transactions.zip(original.body.transactions) { uncompressedTransaction, originalTransaction -> + assertTransactionData(uncompressedTransaction, originalTransaction) + } + } catch (e: AssertionFailedError) { + fail( + "uncompressed block does not match expected original: blockNumber: ${e.message} " + + "\n original =$original " + + "\n uncompressed=$uncompressed ", + e + ) + } + } + + private fun assertTransactionData( + uncompressed: TransactionFromL1RecoveredData, + original: Transaction + ) { + assertThat(uncompressed.type).isEqualTo(original.type.serializedType.toUByte()) + assertThat(uncompressed.from).isEqualTo(original.sender.toArray()) + assertThat(uncompressed.nonce).isEqualTo(original.nonce.toULong()) + assertThat(uncompressed.to).isEqualTo(original.to.getOrNull()?.toArray()) + assertThat(uncompressed.gasLimit).isEqualTo(original.gasLimit.toULong()) + assertThat(uncompressed.maxFeePerGas).isEqualTo(original.maxFeePerGas.getOrNull()?.asBigInteger) + assertThat(uncompressed.maxPriorityFeePerGas).isEqualTo(original.maxPriorityFeePerGas.getOrNull()?.asBigInteger) + assertThat(uncompressed.gasPrice).isEqualTo(original.gasPrice.getOrNull()?.asBigInteger) + assertThat(uncompressed.value).isEqualTo(original.value.asBigInteger) + assertThat(uncompressed.data?.encodeHex()).isEqualTo(original.payload?.toArray()?.encodeHex()) + if (uncompressed.accessList.isNullOrEmpty() != original.accessList.getOrNull().isNullOrEmpty()) { + assertThat(uncompressed.accessList).isEqualTo(original.accessList.getOrNull()) + } else { + uncompressed.accessList?.zip(original.accessList.getOrNull()!!) { a, b -> + assertThat(a.address).isEqualTo(b.address.toArray()) + assertThat(a.storageKeys.map { Bytes32.wrap(it) }).isEqualTo(b.storageKeys) + } + } + } + + private fun compressBlocks(blocks: List): ByteArray { + return compress(blocks.map { block -> block.toRlp().toArray() }) + } + + private fun compress(blocks: List): ByteArray { + blocks.forEach { blockRlp -> + compressor.appendBlock(blockRlp) + } + + return compressor.getCompressedDataAndReset() + } +} diff --git a/state-recover/besu-plugin/build.gradle b/state-recover/besu-plugin/build.gradle new file mode 100644 index 000000000..b8a9c92f2 --- /dev/null +++ b/state-recover/besu-plugin/build.gradle @@ -0,0 +1,71 @@ +plugins { + id 'net.consensys.zkevm.kotlin-library-conventions' + id 'com.gradleup.shadow' version '8.3.5' +} + +group = 'build.linea.staterecover' +archivesBaseName = 'linea-staterecover-plugin' +version = '0.0.1-rc2' + +dependencies { + compileOnly("info.picocli:picocli:${libs.versions.picoli.get()}") { + because 'Required for command line parsing. Provided by Besu at runtime.' + } + implementation "org.jetbrains.kotlin:kotlin-reflect:1.9.21" + api(project(":jvm-libs:generic:serialization:jackson")) + api(project(":jvm-libs:linea:clients:linea-l1-contract-client")) + api(project(":jvm-libs:linea:web3j-extensions")) + api(project(":state-recover:appcore:logic")) + api(project(":state-recover:clients:blobscan-client")) + api(project(":state-recover:clients:eth-api")) + api(project(":state-recover:clients:execution-layer-json-rpc-client")) +} + +ext.groupsToIncludeInShadow = [ + "build.linea.*", + "io.micrometer.*", + "org.jetbrains.kotlin:kotlin-reflect.*", + "org.jetbrains.kotlinx:kotlinx-datetime.*", + "tech.pegasys.teku.internal:async", + "io.vertx.*", + // this can be removed once Besu updates to Vertx 4.12+ + "com.michael-bull.kotlin-result:kotlin-result.*", + "com.fasterxml.jackson.module:jackson-module-kotlin", +] + +def canIncludeLib(String lib) { + def allowed = groupsToIncludeInShadow.find { libAllowed -> + lib.matches(libAllowed) + } != null + allowed +} + +tasks.create("testLibsInclusion", Task) { + // def lib = "build.linea.internal:kotlin-extensions" + doLast { + def lib = "com.michael-bull.kotlin-result:kotlin-result" + println("Can include $lib: ${canIncludeLib(lib)}") + } +} + +shadowJar { + if ("${project.version}" != 'unspecified') { + archiveClassifier.set('') + archiveVersion.set("${project.version}") + } + + dependencies { + exclude { dependency -> + !canIncludeLib("${dependency.moduleGroup}:${dependency.moduleName}") + } + } + + manifest { + attributes( + 'Specification-Title': archiveBaseName, + 'Specification-Version': project.version, + 'Implementation-Title': archiveBaseName, + 'Implementation-Version': project.version, + ) + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/clients/ExecutionLayerInProcessClient.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/clients/ExecutionLayerInProcessClient.kt new file mode 100644 index 000000000..0b6e51918 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/clients/ExecutionLayerInProcessClient.kt @@ -0,0 +1,110 @@ +package linea.staterecover.clients + +import linea.staterecover.BlockFromL1RecoveredData +import linea.staterecover.ExecutionLayerClient +import linea.staterecover.RecoveryStatusPersistence +import linea.staterecover.StateRecoveryStatus +import linea.staterecover.plugin.BlockImporter +import linea.staterecover.plugin.RecoveryModeManager +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import org.apache.logging.log4j.LogManager +import org.hyperledger.besu.plugin.data.BlockHeader +import org.hyperledger.besu.plugin.services.BlockSimulationService +import org.hyperledger.besu.plugin.services.BlockchainService +import org.hyperledger.besu.plugin.services.sync.SynchronizationService +import tech.pegasys.teku.infrastructure.async.SafeFuture +import kotlin.jvm.optionals.getOrNull + +class ExecutionLayerInProcessClient( + private val blockchainService: BlockchainService, + private val stateRecoveryModeManager: RecoveryModeManager, + private val stateRecoveryStatusPersistence: RecoveryStatusPersistence, + private val blockImporter: BlockImporter +) : ExecutionLayerClient { + companion object { + fun create( + blockchainService: BlockchainService, + simulatorService: BlockSimulationService, + synchronizationService: SynchronizationService, + stateRecoveryModeManager: RecoveryModeManager, + stateRecoveryStatusPersistence: RecoveryStatusPersistence + ): ExecutionLayerInProcessClient { + return ExecutionLayerInProcessClient( + blockchainService = blockchainService, + stateRecoveryModeManager = stateRecoveryModeManager, + stateRecoveryStatusPersistence = stateRecoveryStatusPersistence, + blockImporter = BlockImporter( + blockchainService = blockchainService, + simulatorService = simulatorService, + synchronizationService = synchronizationService + ) + ) + } + } + + private val log = LogManager.getLogger(ExecutionLayerInProcessClient::class.java) + + override fun getBlockNumberAndHash(blockParameter: BlockParameter): SafeFuture { + val blockHeader: BlockHeader? = when (blockParameter) { + is BlockParameter.Tag -> when { + blockParameter == BlockParameter.Tag.LATEST -> blockchainService.chainHeadHeader + else -> throw IllegalArgumentException("Unsupported block parameter: $blockParameter") + } + + is BlockParameter.BlockNumber -> + blockchainService + .getBlockByNumber(blockParameter.getNumber().toLong()) + .map { it.blockHeader } + .getOrNull() + } + + return blockHeader + ?.let { + SafeFuture.completedFuture( + BlockNumberAndHash( + it.number.toULong(), + it.blockHash.toArray() + ) + ) + } + ?: SafeFuture.failedFuture(IllegalArgumentException("Block not found for parameter: $blockParameter")) + } + + override fun lineaEngineImportBlocksFromBlob(blocks: List): SafeFuture { + logBlockImport(blocks) + return kotlin.runCatching { + blocks.map { blockImporter.importBlock(it) } + SafeFuture.completedFuture(Unit) + }.getOrElse { th -> SafeFuture.failedFuture(th) } + } + + override fun lineaGetStateRecoveryStatus(): SafeFuture { + return SafeFuture + .completedFuture( + StateRecoveryStatus( + headBlockNumber = stateRecoveryModeManager.headBlockNumber, + stateRecoverStartBlockNumber = stateRecoveryModeManager.targetBlockNumber + ) + ) + } + + override fun lineaEnableStateRecovery(stateRecoverStartBlockNumber: ULong): SafeFuture { + stateRecoveryModeManager.setTargetBlockNumber(stateRecoverStartBlockNumber) + + return SafeFuture.completedFuture( + StateRecoveryStatus( + headBlockNumber = stateRecoveryModeManager.headBlockNumber, + stateRecoverStartBlockNumber = stateRecoveryStatusPersistence.getRecoveryStartBlockNumber() + ) + ) + } + + private fun logBlockImport(blocks: List) { + if (log.isTraceEnabled) { + log.trace("importing blocks from blob: blocks={}", blocks) + } else { + log.debug("importing blocks from blob: blocks={}", blocks.map { it.header.blockNumber }) + } + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt new file mode 100644 index 000000000..e7b25bec2 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt @@ -0,0 +1,93 @@ +package linea.staterecover.plugin + +import build.linea.clients.StateManagerClientV1 +import build.linea.clients.StateManagerV1JsonRpcClient +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly +import io.micrometer.core.instrument.MeterRegistry +import io.vertx.core.Vertx +import io.vertx.micrometer.backends.BackendRegistries +import linea.build.staterecover.clients.VertxTransactionDetailsClient +import linea.staterecover.BlockHeaderStaticFields +import linea.staterecover.ExecutionLayerClient +import linea.staterecover.StateRecoverApp +import linea.staterecover.TransactionDetailsClient +import linea.staterecover.clients.blobscan.BlobScanClient +import linea.web3j.Web3JLogsSearcher +import linea.web3j.createWeb3jHttpClient +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import org.apache.logging.log4j.LogManager +import java.net.URI +import kotlin.time.Duration.Companion.seconds + +fun createAppAllInProcess( + vertx: Vertx = Vertx.vertx(), + meterRegistry: MeterRegistry = BackendRegistries.getDefaultNow(), + elClient: ExecutionLayerClient, + stateManagerClientEndpoint: URI, + l1RpcEndpoint: URI, + blobScanEndpoint: URI, + blockHeaderStaticFields: BlockHeaderStaticFields, + appConfig: StateRecoverApp.Config +): StateRecoverApp { + val lineaContractClient = Web3JLineaRollupSmartContractClientReadOnly( + contractAddress = appConfig.smartContractAddress, + web3j = createWeb3jHttpClient( + rpcUrl = l1RpcEndpoint.toString(), + log = LogManager.getLogger("linea.plugin.staterecover.clients.l1.smart-contract") + ) + ) + val ethLogsSearcher = run { + val log = LogManager.getLogger("linea.plugin.staterecover.clients.l1.logs-searcher") + Web3JLogsSearcher( + vertx = vertx, + web3jClient = createWeb3jHttpClient( + rpcUrl = l1RpcEndpoint.toString(), + log = log + ), + log = log + ) + } + val blobScanClient = BlobScanClient.create( + vertx = vertx, + endpoint = blobScanEndpoint, + requestRetryConfig = RequestRetryConfig( + backoffDelay = 1.seconds + ), + logger = LogManager.getLogger("linea.plugin.staterecover.clients.l1.blob-scan") + ) + val jsonRpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, meterRegistry) + val stateManagerClient: StateManagerClientV1 = StateManagerV1JsonRpcClient.create( + rpcClientFactory = jsonRpcClientFactory, + endpoints = listOf(stateManagerClientEndpoint), + maxInflightRequestsPerClient = 10u, + requestRetry = RequestRetryConfig( + backoffDelay = 1.seconds + ), + zkStateManagerVersion = "2.3.0", + logger = LogManager.getLogger("linea.plugin.staterecover.clients.state-manager") + ) + + val transactionDetailsClient: TransactionDetailsClient = VertxTransactionDetailsClient.create( + jsonRpcClientFactory = jsonRpcClientFactory, + endpoint = l1RpcEndpoint, + retryConfig = RequestRetryConfig( + backoffDelay = 1.seconds + ), + logger = LogManager.getLogger("linea.plugin.staterecover.clients.l1.transaction-details") + ) + + val app = StateRecoverApp( + vertx = vertx, + lineaContractClient = lineaContractClient, + ethLogsSearcher = ethLogsSearcher, + blobFetcher = blobScanClient, + elClient = elClient, + stateManagerClient = stateManagerClient, + transactionDetailsClient = transactionDetailsClient, + blockHeaderStaticFields = blockHeaderStaticFields, + config = appConfig + ) + + return app +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockContextData.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockContextData.kt new file mode 100644 index 000000000..cb8501952 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockContextData.kt @@ -0,0 +1,13 @@ +package linea.staterecover.plugin + +import org.hyperledger.besu.plugin.data.BlockBody +import org.hyperledger.besu.plugin.data.BlockContext +import org.hyperledger.besu.plugin.data.BlockHeader + +data class BlockContextData( + private val blockHeader: BlockHeader, + private val blockBody: BlockBody +) : BlockContext { + override fun getBlockHeader(): BlockHeader = blockHeader + override fun getBlockBody(): BlockBody = blockBody +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockImporter.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockImporter.kt new file mode 100644 index 000000000..1f8e39487 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/BlockImporter.kt @@ -0,0 +1,122 @@ +package linea.staterecover.plugin + +import linea.staterecover.BlockFromL1RecoveredData +import net.consensys.encodeHex +import net.consensys.toBigInteger +import net.consensys.toULong +import org.apache.logging.log4j.LogManager +import org.apache.tuweni.bytes.Bytes32 +import org.hyperledger.besu.datatypes.AccountOverrideMap +import org.hyperledger.besu.datatypes.Address +import org.hyperledger.besu.datatypes.Hash +import org.hyperledger.besu.plugin.data.BlockContext +import org.hyperledger.besu.plugin.data.BlockHeader +import org.hyperledger.besu.plugin.data.BlockOverrides +import org.hyperledger.besu.plugin.data.PluginBlockSimulationResult +import org.hyperledger.besu.plugin.services.BlockSimulationService +import org.hyperledger.besu.plugin.services.BlockchainService +import org.hyperledger.besu.plugin.services.sync.SynchronizationService + +class BlockImporter( + private val blockchainService: BlockchainService, + private val simulatorService: BlockSimulationService, + private val synchronizationService: SynchronizationService +) { + private val log = LogManager.getLogger(BlockImporter::class.java) + private val chainId = blockchainService.chainId.orElseThrow().toULong() + + fun importBlock(block: BlockFromL1RecoveredData): PluginBlockSimulationResult { + val executedBlockResult = executeBlockWithTransactionsWithoutSignature(block) + return importBlock(BlockContextData(executedBlockResult.blockHeader, executedBlockResult.blockBody)) + } + + private fun executeBlockWithTransactionsWithoutSignature( + block: BlockFromL1RecoveredData + ): PluginBlockSimulationResult { + log.debug( + "simulating import block={} blockHash={}", + block.header.blockNumber, + block.header.blockHash.encodeHex() + ) + val transactions = TransactionMapper.mapToBesu( + block.transactions, + chainId + ) + val parentBlockNumber = block.header.blockNumber.toLong() - 1 + + val executedBlockResult = + simulatorService.simulate( + parentBlockNumber, + transactions, + createOverrides(block), + AccountOverrideMap() + ) + + log.debug( + " import simulation result: block={} blockHeader={}", + executedBlockResult.blockHeader.number, + executedBlockResult.blockHeader + ) + return executedBlockResult + } + + private fun createOverrides(blockFromBlob: BlockFromL1RecoveredData): BlockOverrides { + return BlockOverrides.builder() + .blockHash(Hash.wrap(Bytes32.wrap(blockFromBlob.header.blockHash))) + .feeRecipient(Address.fromHexString(blockFromBlob.header.coinbase.encodeHex())) + .blockNumber(blockFromBlob.header.blockNumber.toLong()) + .gasLimit(blockFromBlob.header.gasLimit.toLong()) + .timestamp(blockFromBlob.header.blockTimestamp.epochSeconds) + .difficulty(blockFromBlob.header.difficulty.toBigInteger()) + .mixHashOrPrevRandao(Hash.ZERO) + .build() + } + + fun importBlock(context: BlockContext): PluginBlockSimulationResult { + log.debug( + "calling simulateAndPersistWorldState block={} blockHeader={}", + context.blockHeader.number, + context.blockHeader + ) + val parentBlockNumber = context.blockHeader.number - 1 + val importedBlockResult = + simulatorService.simulateAndPersistWorldState( + parentBlockNumber, + context.blockBody.transactions, + createOverrides(context.blockHeader), + AccountOverrideMap() + ) + log.debug( + "simulateAndPersistWorldState result: block={} blockHeader={}", + context.blockHeader.number, + importedBlockResult.blockHeader + ) + storeAndSetHead(importedBlockResult) + return importedBlockResult + } + + private fun createOverrides(blockHeader: BlockHeader): BlockOverrides { + return BlockOverrides.builder() + .feeRecipient(blockHeader.coinbase) + .blockNumber(blockHeader.number) + .gasLimit(blockHeader.gasLimit) + .timestamp(blockHeader.timestamp) + .difficulty(blockHeader.difficulty.asBigInteger) + .stateRoot(blockHeader.stateRoot) + .mixHashOrPrevRandao(Hash.ZERO) + .build() + } + + private fun storeAndSetHead(block: PluginBlockSimulationResult) { + log.debug( + "storeAndSetHead result: blockHeader={}", + block.blockHeader + ) + blockchainService.storeBlock( + block.blockHeader, + block.blockBody, + block.receipts + ) + synchronizationService.setHeadUnsafe(block.blockHeader, block.blockBody) + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/LineaStateRecoverPlugin.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/LineaStateRecoverPlugin.kt new file mode 100644 index 000000000..cbc3e7189 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/LineaStateRecoverPlugin.kt @@ -0,0 +1,127 @@ +package linea.staterecover.plugin + +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import io.vertx.core.Vertx +import linea.staterecover.BlockHeaderStaticFields +import linea.staterecover.FileBasedRecoveryStatusPersistence +import linea.staterecover.RecoveryStatusPersistence +import linea.staterecover.StateRecoverApp +import linea.staterecover.clients.ExecutionLayerInProcessClient +import net.consensys.linea.async.get +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import org.hyperledger.besu.plugin.BesuPlugin +import org.hyperledger.besu.plugin.ServiceManager +import org.hyperledger.besu.plugin.services.BesuConfiguration +import org.hyperledger.besu.plugin.services.BesuEvents +import org.hyperledger.besu.plugin.services.BesuService +import org.hyperledger.besu.plugin.services.BlockSimulationService +import org.hyperledger.besu.plugin.services.BlockchainService +import org.hyperledger.besu.plugin.services.PicoCLIOptions +import org.hyperledger.besu.plugin.services.mining.MiningService +import org.hyperledger.besu.plugin.services.p2p.P2PService +import org.hyperledger.besu.plugin.services.sync.SynchronizationService + +fun ServiceManager.getServiceOrThrow(clazz: Class): T { + return this.getService(clazz) + .orElseThrow { IllegalStateException("${clazz.name} is not present in BesuContext") } +} + +open class LineaStateRecoverPlugin : BesuPlugin { + private val log: Logger = LogManager.getLogger(LineaStateRecoverPlugin::class.java) + private val vertx = Vertx.vertx() + private val cliOptions = PluginCliOptions() + private lateinit var serviceManager: ServiceManager + private lateinit var recoveryModeManager: RecoveryModeManager + private lateinit var recoveryStatusPersistence: RecoveryStatusPersistence + private lateinit var stateRecoverApp: StateRecoverApp + + override fun register(serviceManager: ServiceManager) { + log.debug("registering") + this.serviceManager = serviceManager + serviceManager + .getServiceOrThrow(PicoCLIOptions::class.java) + .addPicoCLIOptions(PluginCliOptions.cliOptionsPrefix, cliOptions) + log.debug("registered") + } + + override fun start() { + val config = cliOptions.getConfig() + val blockchainService = serviceManager.getServiceOrThrow(BlockchainService::class.java) + val blockHeaderStaticFields = BlockHeaderStaticFields( + coinbase = config.lineaSequencerBeneficiaryAddress.toArray(), + gasLimit = blockchainService.chainHeadHeader.gasLimit.toULong(), + difficulty = 2UL // Note, this will need to change once we move to QBFT + ) + this.recoveryStatusPersistence = FileBasedRecoveryStatusPersistence( + serviceManager.getServiceOrThrow(BesuConfiguration::class.java) + .dataPath + .resolve("plugin-staterecovery-status.json") + ) + log.info( + "starting: config={} blockHeaderStaticFields={} previousRecoveryStartBlockNumber={}", + config, + blockHeaderStaticFields, + this.recoveryStatusPersistence.getRecoveryStartBlockNumber() + ) + + val synchronizationService = serviceManager.getServiceOrThrow(SynchronizationService::class.java) + this.recoveryModeManager = RecoveryModeManager( + p2pService = serviceManager.getServiceOrThrow(P2PService::class.java), + miningService = serviceManager.getServiceOrThrow(MiningService::class.java), + recoveryStatePersistence = this.recoveryStatusPersistence, + synchronizationService = synchronizationService + ) + val simulatorService = serviceManager.getServiceOrThrow(BlockSimulationService::class.java) + val executionLayerClient = ExecutionLayerInProcessClient.create( + blockchainService = blockchainService, + stateRecoveryModeManager = this.recoveryModeManager, + stateRecoveryStatusPersistence = this.recoveryStatusPersistence, + simulatorService = simulatorService, + synchronizationService = synchronizationService + ) + + this.stateRecoverApp = run { + createAppAllInProcess( + vertx = vertx, + // Metrics won't be exposed. Needs proper integration with Besu Metrics, not priority now. + meterRegistry = SimpleMeterRegistry(), + elClient = executionLayerClient, + stateManagerClientEndpoint = config.shomeiEndpoint, + l1RpcEndpoint = config.l1RpcEndpoint, + blobScanEndpoint = config.blobscanEndpoint, + blockHeaderStaticFields = blockHeaderStaticFields, + appConfig = StateRecoverApp.Config( + smartContractAddress = config.l1SmartContractAddress.toString(), + l1LatestSearchBlock = net.consensys.linea.BlockParameter.Tag.LATEST, + overridingRecoveryStartBlockNumber = config.overridingRecoveryStartBlockNumber, + l1PollingInterval = config.l1PollingInterval + ) + ) + } + // add recoverty mode manager as listener to block added events + // so it stops P2P sync when it got target block + serviceManager + .getServiceOrThrow(BesuEvents::class.java) + .addBlockAddedListener(recoveryModeManager) + this.stateRecoverApp.start().get() + log.info( + "started: recoveryStartBlockNumber={}", + this.recoveryStatusPersistence.getRecoveryStartBlockNumber() + ) + } + + override fun afterExternalServicePostMainLoop() { + } + + override fun stop() { + stateRecoverApp.stop() + .whenComplete { _, throwable -> + vertx.close().get() + if (throwable != null) { + throw throwable + } + } + .get() + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/PluginOptions.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/PluginOptions.kt new file mode 100644 index 000000000..745191467 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/PluginOptions.kt @@ -0,0 +1,107 @@ +package linea.staterecover.plugin + +import org.hyperledger.besu.datatypes.Address +import picocli.CommandLine +import java.net.URI +import java.time.Duration +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toKotlinDuration + +data class PluginConfig( + val lineaSequencerBeneficiaryAddress: Address, + val l1SmartContractAddress: Address, + val l1RpcEndpoint: URI, + val blobscanEndpoint: URI, + val shomeiEndpoint: URI, + val l1PollingInterval: kotlin.time.Duration, + val overridingRecoveryStartBlockNumber: ULong? = null +) { + init { + require(l1PollingInterval >= 1.seconds) { "Polling interval=$l1PollingInterval must be greater that 1s." } + } +} + +class PluginCliOptions { + companion object { + const val cliOptionsPrefix = "plugin-staterecovery" + } + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-l1-smart-contract-address"], + description = ["L1 smart contract address"], + required = true, + converter = [AddressConverter::class], + defaultValue = "\${env:L1_ROLLUP_CONTRACT_ADDRESS}" + ) + lateinit var l1SmartContractAddress: Address + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-linea-sequencer-beneficiary-address"], + description = ["Linea sequencer beneficiary address"], + required = true, + converter = [AddressConverter::class], + defaultValue = "\${env:LINEA_SEQUENCER_BENEFICIARY_ADDRESS}" + ) + lateinit var lineaSequencerBeneficiaryAddress: Address + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-l1-rpc-endpoint"], + description = ["L1 RPC endpoint"], + required = true + ) + lateinit var l1RpcEndpoint: URI + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-shomei-endpoint"], + description = ["shomei (state manager) endpoint"], + required = true + ) + lateinit var shomeiEndpoint: URI + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-blobscan-endpoint"], + description = ["blobscan api endpoint"], + required = true + ) + lateinit var blobscanEndpoint: URI + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-l1-polling-interval"], + description = ["L1 polling interval for new finalized blobs"], + required = false + ) + var l1PollingInterval: Duration = Duration.ofSeconds(12) + + @CommandLine.Option( + names = ["--$cliOptionsPrefix-overriding-recovery-start-block-number"], + description = [ + "Tries to force the recovery start block number to the given value. " + + "This is mean for testing purposes, not production. Must be greater than or equal to 1." + ], + required = false + ) + var overridingRecoveryStartBlockNumber: Long? = null + + fun getConfig(): PluginConfig { + require(overridingRecoveryStartBlockNumber == null || overridingRecoveryStartBlockNumber!! >= 1) { + "overridingRecoveryStartBlockNumber=$overridingRecoveryStartBlockNumber must be greater than or equal to 1" + } + return PluginConfig( + lineaSequencerBeneficiaryAddress = lineaSequencerBeneficiaryAddress, + l1SmartContractAddress = l1SmartContractAddress, + l1RpcEndpoint = l1RpcEndpoint, + blobscanEndpoint = blobscanEndpoint, + shomeiEndpoint = shomeiEndpoint, + l1PollingInterval = l1PollingInterval.toKotlinDuration(), + overridingRecoveryStartBlockNumber = overridingRecoveryStartBlockNumber?.toULong() + ) + } + + class AddressConverter : CommandLine.ITypeConverter
{ + override fun convert(value: String): Address { + return Address.fromHexString(value) ?: throw CommandLine.TypeConversionException( + "Invalid address: $value" + ) + } + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/RecoveryModeManager.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/RecoveryModeManager.kt new file mode 100644 index 000000000..26a043166 --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/RecoveryModeManager.kt @@ -0,0 +1,94 @@ +package linea.staterecover.plugin + +import linea.staterecover.RecoveryStatusPersistence +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import org.hyperledger.besu.plugin.data.AddedBlockContext +import org.hyperledger.besu.plugin.services.BesuEvents +import org.hyperledger.besu.plugin.services.mining.MiningService +import org.hyperledger.besu.plugin.services.p2p.P2PService +import org.hyperledger.besu.plugin.services.sync.SynchronizationService +import java.util.concurrent.atomic.AtomicBoolean + +class RecoveryModeManager( + private val synchronizationService: SynchronizationService, + private val p2pService: P2PService, + private val miningService: MiningService, + private val recoveryStatePersistence: RecoveryStatusPersistence +) : + BesuEvents.BlockAddedListener { + private val log: Logger = LogManager.getLogger(RecoveryModeManager::class.java.name) + private val recoveryModeTriggered = AtomicBoolean(false) + private var currentBlockNumber: ULong = 0u + val targetBlockNumber: ULong? + get() = recoveryStatePersistence.getRecoveryStartBlockNumber() + + val headBlockNumber: ULong + get() = currentBlockNumber + + /** + * Called when a block is added. + * + * @param addedBlockContext the context of the added block + */ + @Synchronized + override fun onBlockAdded(addedBlockContext: AddedBlockContext) { + val blockNumber = addedBlockContext.blockHeader.number + currentBlockNumber = blockNumber.toULong() + if (!recoveryModeTriggered.get() && hasReachedTargetBlock()) { + switchToRecoveryMode() + } + } + + private fun hasReachedTargetBlock(): Boolean { + return currentBlockNumber >= ((targetBlockNumber ?: ULong.MAX_VALUE) - 1u) + } + + /** + * Sets the target block number for switching to recovery mode. + * + * @param targetBlockNumber the target block number to set + */ + @Synchronized + fun setTargetBlockNumber(targetBlockNumber: ULong) { + check(!recoveryModeTriggered.get()) { + "Cannot set target block number after recovery mode has been triggered" + } + val effectiveRecoveryStartBlockNumber = if (targetBlockNumber <= currentBlockNumber + 1u) { + log.warn( + "targetBlockNumber={} is less than or equal to headBlockNumber={}" + + " enabling recovery mode immediately at blockNumber={}", + targetBlockNumber, + currentBlockNumber, + currentBlockNumber + 1u + + ) + switchToRecoveryMode() + currentBlockNumber + 1u + } else { + targetBlockNumber + } + recoveryStatePersistence.saveRecoveryStartBlockNumber(effectiveRecoveryStartBlockNumber) + } + + /** Switches the node to recovery mode. */ + private fun switchToRecoveryMode() { + check(!recoveryModeTriggered.get()) { + "cannot enable already enabled recovery mode" + } + log.warn("Stopping synchronization service") + synchronizationService.stop() + + log.warn("Stopping P2P discovery service") + p2pService.disableDiscovery() + + log.warn("Stopping mining service") + miningService.stop() + + log.info( + "Switched to state recovery mode at block={}", + headBlockNumber + ) + recoveryModeTriggered.set(true) + } +} diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/TransactionMapper.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/TransactionMapper.kt new file mode 100644 index 000000000..b609f2e3d --- /dev/null +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/TransactionMapper.kt @@ -0,0 +1,75 @@ +package linea.staterecover.plugin + +import linea.staterecover.TransactionFromL1RecoveredData +import linea.staterecover.TransactionFromL1RecoveredData.AccessTuple +import net.consensys.encodeHex +import net.consensys.toBigInteger +import org.apache.tuweni.bytes.Bytes +import org.hyperledger.besu.crypto.SECPSignature +import org.hyperledger.besu.datatypes.AccessListEntry +import org.hyperledger.besu.datatypes.Address +import org.hyperledger.besu.datatypes.Wei +import org.hyperledger.besu.ethereum.core.Transaction +import java.math.BigInteger +import java.util.* + +fun ByteArray.toBesuAddress(): Address = Address.wrap(Bytes.wrap(this)) + +object TransactionMapper { + /** + * Constructs a Transaction object from the given Transaction recovered from L1 and chainId. + * + * @param transaction the parameters for the transaction + * @param chainId the chain ID for the transaction + * @return a constructed Transaction object + */ + fun mapToBesu( + transaction: TransactionFromL1RecoveredData, + chainId: ULong + ): Transaction { + val builder = Transaction.builder() + + builder + .sender(Address.fromHexString(transaction.from.encodeHex())) + .gasLimit(transaction.gasLimit.toLong()) + .value(Wei.of(transaction.value)) + .payload(Bytes.wrap()) + .chainId(chainId.toBigInteger()) + + transaction.data?.let { data -> builder.payload(Bytes.wrap(data)) } + transaction.to?.let { builder.to(Address.fromHexString(it.encodeHex())) } + transaction.gasPrice?.let { builder.gasPrice(Wei.of(it)) } + transaction.maxPriorityFeePerGas?.let { builder.maxPriorityFeePerGas(Wei.of(it)) } + transaction.maxFeePerGas?.let { builder.maxFeePerGas(Wei.of(it)) } + transaction.accessList?.let { builder.accessList(mapAccessListEntries(it)) } + builder.signature(SECPSignature(BigInteger.ZERO, BigInteger.ZERO, 0.toByte())) + return builder.build() + } + + private fun mapAccessListEntries( + accessList: List? + ): List? { + return accessList + ?.map { accessTupleParameter -> + AccessListEntry.createAccessListEntry( + accessTupleParameter.address.toBesuAddress(), + accessTupleParameter.storageKeys.map { it.encodeHex() } + ) + } + } + + /** + * Converts a list of TransactionParameters from an ImportBlockFromBlobParameter into a list of + * Transactions. + * + * @param importBlockFromBlobParameter the import block parameter containing transactions + * @param defaultChainId the default chain ID to use for transactions + * @return a list of constructed Transaction objects + */ + fun mapToBesu( + transactions: List, + defaultChainId: ULong + ): List { + return transactions.map { tx -> mapToBesu(tx, defaultChainId) } + } +} diff --git a/state-recover/besu-plugin/src/main/resources/META-INF/services/org.hyperledger.besu.plugin.BesuPlugin b/state-recover/besu-plugin/src/main/resources/META-INF/services/org.hyperledger.besu.plugin.BesuPlugin new file mode 100644 index 000000000..2b678e147 --- /dev/null +++ b/state-recover/besu-plugin/src/main/resources/META-INF/services/org.hyperledger.besu.plugin.BesuPlugin @@ -0,0 +1 @@ +linea.staterecover.plugin.LineaStateRecoverPlugin diff --git a/state-recover/clients/blobscan-client/build.gradle b/state-recover/clients/blobscan-client/build.gradle index caa6d00f8..f497bd97e 100644 --- a/state-recover/clients/blobscan-client/build.gradle +++ b/state-recover/clients/blobscan-client/build.gradle @@ -21,7 +21,7 @@ dependencies { implementation("io.vertx:vertx-web-client:${libs.versions.vertx}") testImplementation "com.github.tomakehurst:wiremock-jre8:${libs.versions.wiremock.get()}" - testImplementation "org.slf4j:slf4j-api:1.7.30" + testImplementation "org.slf4j:slf4j-api:${libs.versions.slf4j.get()}" testImplementation "org.apache.logging.log4j:log4j-slf4j-impl:${libs.versions.log4j}" testImplementation "org.apache.logging.log4j:log4j-core:${libs.versions.log4j}" } diff --git a/state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClient.kt b/state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/BlobScanClient.kt similarity index 82% rename from state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClient.kt rename to state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/BlobScanClient.kt index 0091c94b0..c881c623d 100644 --- a/state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClient.kt +++ b/state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/BlobScanClient.kt @@ -1,10 +1,10 @@ -package build.linea.staterecover.clients.blobscan +package linea.staterecover.clients.blobscan -import build.linea.staterecover.clients.BlobFetcher import io.vertx.core.Vertx import io.vertx.core.json.JsonObject import io.vertx.ext.web.client.WebClient import io.vertx.ext.web.client.WebClientOptions +import linea.staterecover.BlobFetcher import net.consensys.decodeHex import net.consensys.encodeHex import net.consensys.linea.jsonrpc.client.RequestRetryConfig @@ -41,14 +41,18 @@ class BlobScanClient( fun create( vertx: Vertx, endpoint: URI, - requestRetryConfig: RequestRetryConfig + requestRetryConfig: RequestRetryConfig, + logger: Logger = LogManager.getLogger(BlobScanClient::class.java), + responseLogMaxSize: UInt? = 1000u ): BlobScanClient { val restClient = VertxRestClient( vertx = vertx, webClient = WebClient.create(vertx, WebClientOptions().setDefaultsFrom(endpoint)), responseParser = { it.toJsonObject() }, retryableErrorCodes = setOf(429, 503, 504), - requestRetryConfig = requestRetryConfig + requestRetryConfig = requestRetryConfig, + log = logger, + responseLogMaxSize = responseLogMaxSize ) return BlobScanClient(restClient) } diff --git a/state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/VertxRestClient.kt b/state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/VertxRestClient.kt similarity index 52% rename from state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/VertxRestClient.kt rename to state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/VertxRestClient.kt index e3b581d0e..7a4f08041 100644 --- a/state-recover/clients/blobscan-client/src/main/kotlin/build/linea/staterecover/clients/blobscan/VertxRestClient.kt +++ b/state-recover/clients/blobscan-client/src/main/kotlin/linea/staterecover/clients/blobscan/VertxRestClient.kt @@ -1,4 +1,4 @@ -package build.linea.staterecover.clients.blobscan +package linea.staterecover.clients.blobscan import io.vertx.core.Vertx import io.vertx.core.buffer.Buffer @@ -8,6 +8,9 @@ import io.vertx.ext.web.client.WebClient import net.consensys.linea.async.AsyncRetryer import net.consensys.linea.async.toSafeFuture import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger import tech.pegasys.teku.infrastructure.async.SafeFuture // TODO: move to a common module @@ -33,7 +36,11 @@ class VertxRestClient( timeout = requestRetryConfig.timeout, vertx = vertx ), - private val requestHeaders: Map = mapOf("Accept" to "application/json") + private val requestHeaders: Map = mapOf("Accept" to "application/json"), + private val log: Logger = LogManager.getLogger(VertxRestClient::class.java), + private val requestResponseLogLevel: Level = Level.TRACE, + private val failuresLogLevel: Level = Level.DEBUG, + private val responseLogMaxSize: UInt? = null ) : RestClient { private fun makeRequestWithRetry( request: HttpRequest @@ -44,7 +51,10 @@ class VertxRestClient( response.statusCode() !in retryableErrorCodes } ) { + logRequest(request) request.send().toSafeFuture() + .thenPeek { response -> logResponse(request, response) } + .whenException { error -> logResponse(request = request, failureCause = error) } } } @@ -60,6 +70,46 @@ class VertxRestClient( } } + private fun logRequest(request: HttpRequest, level: Level = requestResponseLogLevel) { + log.log(level, "--> {} {}", request.method(), request.uri()) + } + + private fun logResponse( + request: HttpRequest, + response: HttpResponse? = null, + failureCause: Throwable? = null + ) { + val isError = response?.statusCode()?.let(::isNotSuccessStatusCode) ?: true + val logLevel = if (isError) failuresLogLevel else requestResponseLogLevel + if (isError && log.level != requestResponseLogLevel) { + // in case of error, log the request that originated the error + // to help replicate and debug later + logRequest(request, logLevel) + } + + val responseToLog = response?.bodyAsString()?.let { bodyStr -> + if (responseLogMaxSize != null) { + bodyStr.take(responseLogMaxSize.toInt()) + "..." + "(contentLength=${response.getHeader("Content-Length")})" + } else { + bodyStr + } + } + + log.log( + logLevel, + "<-- {} {} {} {} {}", + request.method(), + request.uri(), + response?.statusCode(), + responseToLog, + failureCause?.message ?: "" + ) + } + + private fun isNotSuccessStatusCode(statusCode: Int): Boolean { + return statusCode !in 200..299 + } + companion object { val DEFAULT_RETRY_HTTP_CODES = setOf(429, 500, 503, 504) } diff --git a/state-recover/clients/blobscan-client/src/test/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClientTest.kt b/state-recover/clients/blobscan-client/src/test/kotlin/linea/staterecover/clients/blobscan/BlobScanClientTest.kt similarity index 99% rename from state-recover/clients/blobscan-client/src/test/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClientTest.kt rename to state-recover/clients/blobscan-client/src/test/kotlin/linea/staterecover/clients/blobscan/BlobScanClientTest.kt index a8ab315fe..660aa8e2f 100644 --- a/state-recover/clients/blobscan-client/src/test/kotlin/build/linea/staterecover/clients/blobscan/BlobScanClientTest.kt +++ b/state-recover/clients/blobscan-client/src/test/kotlin/linea/staterecover/clients/blobscan/BlobScanClientTest.kt @@ -1,4 +1,4 @@ -package build.linea.staterecover.clients.blobscan +package linea.staterecover.clients.blobscan import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock diff --git a/state-recover/clients/eth-api/build.gradle b/state-recover/clients/eth-api/build.gradle new file mode 100644 index 000000000..61ff45635 --- /dev/null +++ b/state-recover/clients/eth-api/build.gradle @@ -0,0 +1,11 @@ +plugins { + id 'net.consensys.zkevm.kotlin-library-conventions' +} + +dependencies { + implementation(project(':jvm-libs:generic:extensions:kotlin')) + implementation(project(':jvm-libs:linea:web3j-extensions')) + implementation(project(':jvm-libs:generic:serialization:jackson')) + api(project(':jvm-libs:generic:json-rpc')) + implementation(project(':state-recover:appcore:clients-interfaces')) +} diff --git a/state-recover/clients/eth-api/src/main/kotlin/linea/build/staterecover/clients/VertxTransactionDetailsClient.kt b/state-recover/clients/eth-api/src/main/kotlin/linea/build/staterecover/clients/VertxTransactionDetailsClient.kt new file mode 100644 index 000000000..4ec7cf22c --- /dev/null +++ b/state-recover/clients/eth-api/src/main/kotlin/linea/build/staterecover/clients/VertxTransactionDetailsClient.kt @@ -0,0 +1,50 @@ +package linea.build.staterecover.clients + +import com.fasterxml.jackson.databind.JsonNode +import com.github.michaelbull.result.Err +import linea.staterecover.TransactionDetailsClient +import net.consensys.decodeHex +import net.consensys.linea.jsonrpc.client.JsonRpcClientFactory +import net.consensys.linea.jsonrpc.client.JsonRpcV2Client +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger +import tech.pegasys.teku.infrastructure.async.SafeFuture +import java.net.URI + +class VertxTransactionDetailsClient internal constructor( + private val jsonRpcClient: JsonRpcV2Client +) : TransactionDetailsClient { + + companion object { + fun create( + jsonRpcClientFactory: JsonRpcClientFactory, + endpoint: URI, + retryConfig: RequestRetryConfig, + logger: Logger = LogManager.getLogger(TransactionDetailsClient::class.java) + ): VertxTransactionDetailsClient { + return VertxTransactionDetailsClient( + jsonRpcClientFactory.createJsonRpcV2Client( + endpoints = listOf(endpoint), + retryConfig = retryConfig, + log = logger + ) + ) + } + } + + override fun getBlobVersionedHashesByTransactionHash(transactionHash: ByteArray): SafeFuture> { + return jsonRpcClient.makeRequest( + "eth_getTransactionByHash", + listOf(transactionHash), + shallRetryRequestPredicate = { it is Err }, + resultMapper = { + it as JsonNode + it.get("blobVersionedHashes") + ?.toList() + ?.map { it.asText().decodeHex() } + ?: emptyList() + } + ) + } +} diff --git a/state-recover/clients/execution-layer-json-rpc-client/src/main/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClient.kt b/state-recover/clients/execution-layer-json-rpc-client/src/main/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClient.kt index 813c0e2ed..c2792c413 100644 --- a/state-recover/clients/execution-layer-json-rpc-client/src/main/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClient.kt +++ b/state-recover/clients/execution-layer-json-rpc-client/src/main/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClient.kt @@ -1,17 +1,24 @@ package build.linea.staterecover.clients.el +import build.linea.s11n.jackson.InstantAsHexNumberDeserializer +import build.linea.s11n.jackson.InstantAsHexNumberSerializer import build.linea.s11n.jackson.ethApiObjectMapper -import build.linea.staterecover.BlockL1RecoveredData -import build.linea.staterecover.clients.ExecutionLayerClient +import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.module.SimpleModule +import kotlinx.datetime.Instant +import linea.staterecover.BlockFromL1RecoveredData +import linea.staterecover.ExecutionLayerClient +import linea.staterecover.StateRecoveryStatus import net.consensys.decodeHex -import net.consensys.encodeHex import net.consensys.fromHexString import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.BlockParameter import net.consensys.linea.jsonrpc.client.JsonRpcClientFactory import net.consensys.linea.jsonrpc.client.JsonRpcV2Client import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger import tech.pegasys.teku.infrastructure.async.SafeFuture import java.net.URI @@ -33,38 +40,65 @@ class ExecutionLayerJsonRpcClient internal constructor( } } - override fun lineaEngineImportBlocksFromBlob(blocks: List): SafeFuture { + override fun lineaEngineImportBlocksFromBlob(blocks: List): SafeFuture { return rpcClient .makeRequest( - method = "linea_engine_importBlocksFromBlob", + method = "linea_importBlocksFromBlob", params = blocks, resultMapper = { Unit } ) } - override fun lineaEngineForkChoiceUpdated( - headBlockHash: ByteArray, - finalizedBlockHash: ByteArray - ): SafeFuture { + override fun lineaGetStateRecoveryStatus(): SafeFuture { return rpcClient .makeRequest( - method = "linea_engine_importForkChoiceUpdated", - params = listOf(headBlockHash, finalizedBlockHash).map { it.encodeHex() }, - resultMapper = { Unit } + method = "linea_getStateRecoveryStatus", + params = emptyList(), + resultMapper = ::stateRecoveryStatusFromJsonNode + ) + } + + override fun lineaEnableStateRecovery(stateRecoverStartBlockNumber: ULong): SafeFuture { + return rpcClient + .makeRequest( + method = "linea_enableStateRecovery", + params = listOf(stateRecoverStartBlockNumber), + resultMapper = ::stateRecoveryStatusFromJsonNode ) } companion object { + fun stateRecoveryStatusFromJsonNode(result: Any?): StateRecoveryStatus { + @Suppress("UNCHECKED_CAST") + result as JsonNode + return StateRecoveryStatus( + headBlockNumber = ULong.fromHexString(result.get("headBlockNumber").asText()), + stateRecoverStartBlockNumber = result.get("recoveryStartBlockNumber") + ?.let { if (it.isNull) null else ULong.fromHexString(it.asText()) } + ) + } + fun create( rpcClientFactory: JsonRpcClientFactory, endpoint: URI, - requestRetryConfig: RequestRetryConfig + requestRetryConfig: RequestRetryConfig, + logger: Logger = LogManager.getLogger(ExecutionLayerJsonRpcClient::class.java) ): ExecutionLayerClient { + val objectManager = ethApiObjectMapper + .copy() + .registerModules( + SimpleModule().apply { + this.addSerializer(Instant::class.java, InstantAsHexNumberSerializer) + this.addDeserializer(Instant::class.java, InstantAsHexNumberDeserializer) + } + ) + .setSerializationInclusion(JsonInclude.Include.NON_NULL) return ExecutionLayerJsonRpcClient( rpcClient = rpcClientFactory.createJsonRpcV2Client( endpoints = listOf(endpoint), retryConfig = requestRetryConfig, - requestObjectMapper = ethApiObjectMapper + requestObjectMapper = objectManager, + log = logger ) ) } diff --git a/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt b/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt index 9b4ddad4d..f59bd27c1 100644 --- a/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt +++ b/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt @@ -1,9 +1,5 @@ package build.linea.staterecover.clients.el -import build.linea.staterecover.BlockExtraData -import build.linea.staterecover.BlockL1RecoveredData -import build.linea.staterecover.TransactionL1RecoveredData -import build.linea.staterecover.clients.ExecutionLayerClient import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock.containing import com.github.tomakehurst.wiremock.client.WireMock.post @@ -12,6 +8,11 @@ import com.github.tomakehurst.wiremock.core.WireMockConfiguration import io.micrometer.core.instrument.simple.SimpleMeterRegistry import io.vertx.junit5.VertxExtension import kotlinx.datetime.Instant +import linea.staterecover.BlockFromL1RecoveredData +import linea.staterecover.BlockHeaderFromL1RecoveredData +import linea.staterecover.ExecutionLayerClient +import linea.staterecover.StateRecoveryStatus +import linea.staterecover.TransactionFromL1RecoveredData import net.consensys.decodeHex import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.BlockParameter @@ -108,7 +109,7 @@ class ExecutionLayerJsonRpcClientTest { } @Test - fun `lineaEngineImportBlocksFromBlob`() { + fun `lineaImportBlocksFromBlob`() { replyRequestWith( 200, """ @@ -119,18 +120,21 @@ class ExecutionLayerJsonRpcClientTest { } """.trimIndent() ) - val block1 = BlockL1RecoveredData( - blockNumber = 0xa001u, - blockHash = "0xa011".decodeHex(), - coinbase = "0xa022".decodeHex(), - blockTimestamp = Instant.parse("2024-07-01T11:22:33Z"), - gasLimit = 0x1c9c380u, - difficulty = 0u, - extraData = BlockExtraData(beneficiary = "0x6265617665726275696c642e6f7267".decodeHex()), + + val block1 = BlockFromL1RecoveredData( + header = BlockHeaderFromL1RecoveredData( + blockNumber = 0xa001u, + blockHash = "0xa011".decodeHex(), + coinbase = "0x6265617665726275696c642e6f7267".decodeHex(), + blockTimestamp = Instant.fromEpochSeconds(1719828000), // 2024-07-01T11:00:00Z UTC + gasLimit = 0x1c9c380u, + difficulty = 0u + ), transactions = listOf( - TransactionL1RecoveredData( + TransactionFromL1RecoveredData( type = 0x01u, nonce = 0xb010u, + gasPrice = null, maxPriorityFeePerGas = "b010011".toBigInteger(16), maxFeePerGas = "b0100ff".toBigInteger(16), gasLimit = 0xb0100aau, @@ -139,11 +143,24 @@ class ExecutionLayerJsonRpcClientTest { value = 123.toBigInteger(), data = "0xb013".decodeHex(), accessList = listOf( - TransactionL1RecoveredData.AccessTuple( + TransactionFromL1RecoveredData.AccessTuple( address = "0xb014".decodeHex(), storageKeys = listOf("0xb015".decodeHex(), "0xb015".decodeHex()) ) ) + ), + TransactionFromL1RecoveredData( + type = 0x0u, + nonce = 0xb020u, + gasPrice = "b0100ff".toBigInteger(16), + maxPriorityFeePerGas = null, + maxFeePerGas = null, + gasLimit = 0xb0100aau, + from = "0xb011".decodeHex(), + to = "0xb012".decodeHex(), + value = 123.toBigInteger(), + data = null, + accessList = null ) ) ) @@ -156,16 +173,15 @@ class ExecutionLayerJsonRpcClientTest { """{ "jsonrpc":"2.0", "id":"${'$'}{json-unit.any-number}", - "method":"linea_engine_importBlocksFromBlob", + "method":"linea_importBlocksFromBlob", "params":[{ - "blockNumber": "0xa001", - "blockHash": "0xa011", - "coinbase": "0xa022", - "blockTimestamp": "2024-07-01T11:22:33Z", - "gasLimit": "0x1c9c380", - "difficulty": "0x0", - "extraData": { - "beneficiary": "0x6265617665726275696c642e6f7267" + "header": { + "blockNumber": "0xa001", + "blockHash": "0xa011", + "coinbase": "0x6265617665726275696c642e6f7267", + "blockTimestamp": "0x66827e20", + "gasLimit": "0x1c9c380", + "difficulty": "0x0" }, "transactions": [{ "type": "0x01", @@ -186,12 +202,101 @@ class ExecutionLayerJsonRpcClientTest { ] } ] + }, { + "type": "0x00", + "nonce": "0xb020", + "gasPrice": "0xb0100ff", + "gasLimit": "0xb0100aa", + "from": "0xb011", + "to": "0xb012", + "value": "0x7b" }] }] }""" ) } + @Test + fun `lineaGetStateRecoveryStatus_enabledStatus`() { + replyRequestWith( + 200, + """{"jsonrpc": "2.0", "id": 1, "result": { "recoveryStartBlockNumber": "0x5", "headBlockNumber": "0xa"}}""" + ) + + assertThat(client.lineaGetStateRecoveryStatus().get()) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = 0xa.toULong(), + stateRecoverStartBlockNumber = 0x5.toULong() + ) + ) + + val requestJson = wiremock.serveEvents.serveEvents.first().request.bodyAsString + assertThatJson(requestJson) + .isEqualTo( + """{ + "jsonrpc":"2.0", + "id":"${'$'}{json-unit.any-number}", + "method":"linea_getStateRecoveryStatus", + "params":[] + }""" + ) + } + + @Test + fun `lineaGetStateRecoveryStatus_disabledStatus`() { + replyRequestWith( + 200, + """{"jsonrpc": "2.0", "id": 1, "result": { "recoveryStartBlockNumber": null, "headBlockNumber": "0xa"}}""" + ) + + assertThat(client.lineaGetStateRecoveryStatus().get()) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = 0xa.toULong(), + stateRecoverStartBlockNumber = null + ) + ) + + val requestJson = wiremock.serveEvents.serveEvents.first().request.bodyAsString + assertThatJson(requestJson) + .isEqualTo( + """{ + "jsonrpc":"2.0", + "id":"${'$'}{json-unit.any-number}", + "method":"linea_getStateRecoveryStatus", + "params":[] + }""" + ) + } + + @Test + fun `lineaEnableStateRecoveryStatus`() { + replyRequestWith( + 200, + """{"jsonrpc": "2.0", "id": 1, "result": { "recoveryStartBlockNumber": "0xff", "headBlockNumber": "0xa"}}""" + ) + + assertThat(client.lineaEnableStateRecovery(stateRecoverStartBlockNumber = 5UL).get()) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = 0xa.toULong(), + stateRecoverStartBlockNumber = 0xff.toULong() + ) + ) + + val requestJson = wiremock.serveEvents.serveEvents.first().request.bodyAsString + assertThatJson(requestJson) + .isEqualTo( + """{ + "jsonrpc":"2.0", + "id":"${'$'}{json-unit.any-number}", + "method":"linea_enableStateRecovery", + "params":["0x5"] + }""" + ) + } + private fun replyRequestWith(statusCode: Int, body: String?) { wiremock.stubFor( post("/") diff --git a/state-recover/clients/smartcontract/src/integrationTest/resources/log4j2.xml b/state-recover/clients/smartcontract/src/integrationTest/resources/log4j2.xml deleted file mode 100644 index 63ca5f6ca..000000000 --- a/state-recover/clients/smartcontract/src/integrationTest/resources/log4j2.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/state-recover/test-cases/build.gradle b/state-recover/test-cases/build.gradle new file mode 100644 index 000000000..658a2cca5 --- /dev/null +++ b/state-recover/test-cases/build.gradle @@ -0,0 +1,82 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent + +plugins { + id 'net.consensys.zkevm.kotlin-library-conventions' +} + +group = 'build.linea.staterecover' + +dependencies { + implementation("io.vertx:vertx-core:${libs.versions.vertx.get()}") + api(project(':jvm-libs:generic:extensions:kotlin')) + api(project(':jvm-libs:linea:core:domain-models')) + api(project(':jvm-libs:linea:core:long-running-service')) + api(project(':jvm-libs:linea:clients:interfaces')) + api(project(':jvm-libs:linea:clients:linea-l1-contract-client')) + api(project(':jvm-libs:linea:clients:linea-state-manager')) + api(project(':jvm-libs:linea:blob-decompressor')) + api(project(':state-recover:appcore:clients-interfaces')) + api(project(':state-recover:appcore:domain-models')) + api(project(':state-recover:appcore:logic')) + + implementation project(':jvm-libs:linea:besu-libs') + implementation(testFixtures(project(':jvm-libs:generic:json-rpc'))) + implementation(project(':state-recover:clients:eth-api')) + implementation(project(':state-recover:clients:blobscan-client')) + implementation(project(':state-recover:clients:execution-layer-json-rpc-client')) + implementation(project(':coordinator:clients:smart-contract-client')) + implementation(project(':jvm-libs:linea:linea-contracts:l1-rollup')) + implementation('build.linea:l1-rollup-contract-client:6.0.0') + implementation(project(':coordinator:core')) + implementation(project(":coordinator:ethereum:test-utils")) + implementation(project(":jvm-libs:linea:testing:l1-blob-and-proof-submission")) + implementation(testFixtures(project(":jvm-libs:linea:blob-compressor"))) + testImplementation("io.vertx:vertx-junit5") +} + +sourceSets { + integrationTest { + kotlin { + compileClasspath += sourceSets.main.output + sourceSets.main.compileClasspath + sourceSets.test.compileClasspath + runtimeClasspath += sourceSets.main.output + sourceSets.main.runtimeClasspath + sourceSets.test.runtimeClasspath + } + compileClasspath += sourceSets.main.output + sourceSets.main.compileClasspath + sourceSets.test.compileClasspath + runtimeClasspath += sourceSets.main.output + sourceSets.main.runtimeClasspath + sourceSets.test.runtimeClasspath + } +} + +test { + systemProperty "vertx.parameter.filename", project.projectDir.toPath() + .resolve("src/test/resources/vertx-options.json") + .toAbsolutePath().toString() +} + +task integrationTest(type: Test) { test -> + systemProperty "vertx.parameter.filename", project.projectDir.toPath() + .resolve("src/test/resources/vertx-options.json") + .toAbsolutePath().toString() + + description = "Runs integration tests." + group = "verification" + useJUnitPlatform() + + classpath = sourceSets.integrationTest.runtimeClasspath + testClassesDirs = sourceSets.integrationTest.output.classesDirs + + // dependsOn(":localStackForStateRecoverComposeUp") + + testLogging { + events TestLogEvent.FAILED, + TestLogEvent.SKIPPED, + TestLogEvent.STANDARD_ERROR, + TestLogEvent.STARTED, + TestLogEvent.PASSED + exceptionFormat TestExceptionFormat.FULL + showCauses true + showExceptions true + showStackTraces true + // set showStandardStreams if you need to see test logs + showStandardStreams true + } +} diff --git a/state-recover/clients/smartcontract/src/integrationTest/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/LineaSubmissionEventsClientIntTest.kt similarity index 88% rename from state-recover/clients/smartcontract/src/integrationTest/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientIntTest.kt rename to state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/LineaSubmissionEventsClientIntTest.kt index 745032e07..41e1af26d 100644 --- a/state-recover/clients/smartcontract/src/integrationTest/kotlin/linea/build/staterecover/clients/smartcontract/LineaSubmissionEventsClientIntTest.kt +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/LineaSubmissionEventsClientIntTest.kt @@ -1,15 +1,13 @@ -package linea.build.staterecover.clients.smartcontract +package linea.staterecover import build.linea.contract.l1.LineaContractVersion -import build.linea.staterecover.clients.DataFinalizedV3 -import build.linea.staterecover.clients.DataSubmittedV3 -import build.linea.staterecover.clients.LineaRollupSubmissionEventsClient import io.vertx.core.Vertx import io.vertx.junit5.Timeout import io.vertx.junit5.VertxExtension import io.vertx.junit5.VertxTestContext +import linea.domain.RetryConfig +import linea.web3j.Web3JLogsSearcher import net.consensys.linea.BlockParameter -import net.consensys.linea.contract.Web3JLogsClient import net.consensys.linea.testing.submission.AggregationAndBlobs import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped import net.consensys.linea.testing.submission.submitBlobsAndAggregations @@ -24,7 +22,8 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import java.util.concurrent.TimeUnit -import kotlin.time.Duration.Companion.seconds +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes import kotlin.time.toJavaDuration @ExtendWith(VertxExtension::class) @@ -57,18 +56,19 @@ class LineaSubmissionEventsClientIntTest { requestResponseLogLevel = Level.INFO, failuresLogLevel = Level.WARN ) - submissionEventsFetcher = LineaSubmissionEventsClientWeb3jIpml( - logsClient = Web3JLogsClient( + submissionEventsFetcher = LineaSubmissionEventsClientImpl( + logsSearcher = Web3JLogsSearcher( vertx = vertx, web3jClient = eventsFetcherWeb3jClient, - config = Web3JLogsClient.Config( - timeout = 30.seconds, - backoffDelay = 1.seconds, - lookBackRange = 100 + config = Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = RetryConfig.noRetries ) ), smartContractAddress = rollupDeploymentResult.contractAddress, - mostRecentBlockTag = BlockParameter.Tag.LATEST + l1EarliestSearchBlock = BlockParameter.Tag.EARLIEST, + l1LatestSearchBlock = BlockParameter.Tag.LATEST, + logsBlockChunkSize = 100 ) } @@ -96,7 +96,7 @@ class LineaSubmissionEventsClientIntTest { // wait for all finalizations Txs to be mined Web3jClientManager.l1Client.waitForTxReceipt( txHash = submissionTxHashes.aggregationTxHashes.last(), - timeout = 20.seconds + timeout = 2.minutes ) val expectedSubmissionEventsToFind: List>> = @@ -110,7 +110,7 @@ class LineaSubmissionEventsClientIntTest { l2StartBlockNumberInclusive = expectedFinalizationEvent.startBlockNumber ) ) - .succeedsWithin(30.seconds.toJavaDuration()) + .succeedsWithin(1.minutes.toJavaDuration()) .extracting { submissionEvents -> val dataFinalizedEvent = submissionEvents?.dataFinalizedEvent?.event val dataSubmittedEvents = submissionEvents?.dataSubmittedEvents?.map { it.event } diff --git a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt new file mode 100644 index 000000000..6c4510205 --- /dev/null +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt @@ -0,0 +1,193 @@ +package linea.staterecover + +import build.linea.clients.StateManagerClientV1 +import build.linea.clients.StateManagerV1JsonRpcClient +import build.linea.contract.l1.LineaContractVersion +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly +import build.linea.staterecover.clients.el.ExecutionLayerJsonRpcClient +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import io.vertx.core.Vertx +import io.vertx.junit5.VertxExtension +import linea.build.staterecover.clients.VertxTransactionDetailsClient +import linea.domain.RetryConfig +import linea.log4j.configureLoggers +import linea.staterecover.clients.blobscan.BlobScanClient +import linea.web3j.Web3JLogsSearcher +import net.consensys.linea.BlockParameter +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.testing.submission.AggregationAndBlobs +import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped +import net.consensys.linea.testing.submission.submitBlobsAndAggregationsAndWaitExecution +import net.consensys.zkevm.coordinator.clients.smartcontract.LineaRollupSmartContractClient +import net.consensys.zkevm.ethereum.ContractsManager +import net.consensys.zkevm.ethereum.Web3jClientManager +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.Awaitility.await +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import java.net.URI +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration + +@ExtendWith(VertxExtension::class) +class StateRecoverAppIntTest { + private val log = LogManager.getLogger("test.case.StateRecoverAppIntTest") + private lateinit var stateRecoverApp: StateRecoverApp + private lateinit var aggregationsAndBlobs: List + private lateinit var executionLayerClient: ExecutionLayerClient + private lateinit var stateManagerClient: StateManagerClientV1 + private lateinit var transactionDetailsClient: TransactionDetailsClient + private lateinit var lineaContractClient: LineaRollupSmartContractClientReadOnly + + private lateinit var contractClientForSubmissions: LineaRollupSmartContractClient + + private val testDataDir = "testdata/coordinator/prover/v3/" + + private val l1RpcUrl = "http://localhost:8445" + private val blobScanUrl = "http://localhost:4001" + private val executionClientUrl = "http://localhost:9145" + private val stateManagerUrl = "http://localhost:8890" + + @BeforeEach + fun beforeEach(vertx: Vertx) { + val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + aggregationsAndBlobs = loadBlobsAndAggregationsSortedAndGrouped( + blobsResponsesDir = "$testDataDir/compression/responses", + aggregationsResponsesDir = "$testDataDir/aggregation/responses" + ) + executionLayerClient = ExecutionLayerJsonRpcClient.create( + rpcClientFactory = jsonRpcFactory, + endpoint = URI(executionClientUrl), + requestRetryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds, + maxRetries = 4u, + failuresWarningThreshold = 1U + ), + logger = LogManager.getLogger("test.clients.l1.executionlayer") + ) + stateManagerClient = StateManagerV1JsonRpcClient.create( + rpcClientFactory = jsonRpcFactory, + endpoints = listOf(URI(stateManagerUrl)), + maxInflightRequestsPerClient = 1U, + requestRetry = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + zkStateManagerVersion = "2.3.0", + logger = LogManager.getLogger("test.clients.l1.state-manager") + ) + transactionDetailsClient = VertxTransactionDetailsClient.create( + jsonRpcClientFactory = jsonRpcFactory, + endpoint = URI(l1RpcUrl), + retryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + logger = LogManager.getLogger("test.clients.l1.transaction-details") + ) + + val rollupDeploymentResult = ContractsManager.get() + .deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V6).get() + + lineaContractClient = Web3JLineaRollupSmartContractClientReadOnly( + web3j = Web3jClientManager.buildL1Client( + log = LogManager.getLogger("test.clients.l1.linea-contract"), + requestResponseLogLevel = Level.INFO, + failuresLogLevel = Level.WARN + ), + contractAddress = rollupDeploymentResult.contractAddress + ) + val logsSearcher = run { + val log = LogManager.getLogger("test.clients.l1.events-fetcher") + Web3JLogsSearcher( + vertx = vertx, + web3jClient = Web3jClientManager.buildL1Client( + log = log, + requestResponseLogLevel = Level.TRACE, + failuresLogLevel = Level.WARN + ), + Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = RetryConfig.noRetries + ), + log = log + ) + } + + contractClientForSubmissions = rollupDeploymentResult.rollupOperatorClient + val blobScanClient = BlobScanClient.create( + vertx = vertx, + endpoint = URI(blobScanUrl), + requestRetryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + logger = LogManager.getLogger("test.clients.l1.blobscan") + ) + + configureLoggers( + rootLevel = Level.INFO, + "test.clients.l1.executionlayer" to Level.INFO, + "test.clients.l1.web3j-default" to Level.INFO, + "test.clients.l1.state-manager" to Level.INFO, + "test.clients.l1.transaction-details" to Level.INFO, + "test.clients.l1.linea-contract" to Level.INFO, + "test.clients.l1.events-fetcher" to Level.INFO, + "test.clients.l1.blobscan" to Level.INFO, + "net.consensys.linea.contract.l1" to Level.INFO + ) + + stateRecoverApp = StateRecoverApp( + vertx = vertx, + elClient = executionLayerClient, + blobFetcher = blobScanClient, + ethLogsSearcher = logsSearcher, + stateManagerClient = stateManagerClient, + transactionDetailsClient = transactionDetailsClient, + blockHeaderStaticFields = BlockHeaderStaticFields.localDev, + lineaContractClient = lineaContractClient, + config = StateRecoverApp.Config( + l1LatestSearchBlock = BlockParameter.Tag.LATEST, + l1PollingInterval = 5.seconds, + executionClientPollingInterval = 1.seconds, + smartContractAddress = lineaContractClient.getAddress(), + logsBlockChunkSize = 100_000u + ) + ) + } + + @Test + fun `state recovery from genesis`() { + stateRecoverApp.start().get() + + submitBlobsAndAggregationsAndWaitExecution( + contractClient = contractClientForSubmissions, + aggregationsAndBlobs = aggregationsAndBlobs, + l1Web3jClient = Web3jClientManager.l1Client + ) + + val lastAggregation = aggregationsAndBlobs.findLast { it.aggregation != null }!!.aggregation!! + await() + .atMost(4.minutes.toJavaDuration()) + .untilAsserted { + assertThat(stateRecoverApp.lastSuccessfullyRecoveredFinalization?.event?.endBlockNumber) + .isEqualTo(lastAggregation.endBlockNumber) + } + + assertThat(executionLayerClient.lineaGetStateRecoveryStatus().get()) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = lastAggregation.endBlockNumber, + stateRecoverStartBlockNumber = 1UL + ) + ) + } +} diff --git a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt new file mode 100644 index 000000000..efd811266 --- /dev/null +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt @@ -0,0 +1,367 @@ +package linea.staterecover + +import build.linea.contract.l1.LineaContractVersion +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import io.vertx.core.Vertx +import io.vertx.junit5.VertxExtension +import linea.build.staterecover.clients.VertxTransactionDetailsClient +import linea.domain.RetryConfig +import linea.log4j.configureLoggers +import linea.staterecover.clients.blobscan.BlobScanClient +import linea.staterecover.test.FakeExecutionLayerClient +import linea.staterecover.test.FakeStateManagerClient +import linea.staterecover.test.FakeStateManagerClientBasedOnBlobsRecords +import linea.web3j.Web3JLogsSearcher +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.testing.submission.AggregationAndBlobs +import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped +import net.consensys.linea.testing.submission.submitBlobsAndAggregationsAndWaitExecution +import net.consensys.zkevm.coordinator.clients.smartcontract.LineaRollupSmartContractClient +import net.consensys.zkevm.ethereum.ContractsManager +import net.consensys.zkevm.ethereum.Web3jClientManager +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.Awaitility.await +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import java.net.URI +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration + +@ExtendWith(VertxExtension::class) +class StateRecoverAppWithFakeExecutionClientIntTest { + private val log = LogManager.getLogger("test.case.StateRecoverAppWithFakeExecutionClientIntTest") + private lateinit var stateRecoverApp: StateRecoverApp + private lateinit var aggregationsAndBlobs: List + private lateinit var executionLayerClient: FakeExecutionLayerClient + private lateinit var fakeStateManagerClient: FakeStateManagerClient + private lateinit var transactionDetailsClient: TransactionDetailsClient + private lateinit var lineaContractClient: LineaRollupSmartContractClientReadOnly + + private lateinit var contractClientForSubmissions: LineaRollupSmartContractClient + private val testDataDir = run { + "testdata/coordinator/prover/v3" + } + + private val l1RpcUrl = "http://localhost:8445" + private val blobScanUrl = "http://localhost:4001" + + @BeforeEach + fun beforeEach(vertx: Vertx) { + val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + aggregationsAndBlobs = loadBlobsAndAggregationsSortedAndGrouped( + blobsResponsesDir = "$testDataDir/compression/responses", + aggregationsResponsesDir = "$testDataDir/aggregation/responses" + ) + executionLayerClient = FakeExecutionLayerClient( + headBlock = BlockNumberAndHash(number = 0uL, hash = ByteArray(32) { 0 }), + initialStateRecoverStartBlockNumber = null, + loggerName = "test.fake.clients.l1.fake-execution-layer" + ) + fakeStateManagerClient = + FakeStateManagerClientBasedOnBlobsRecords(blobRecords = aggregationsAndBlobs.flatMap { it.blobs }) + transactionDetailsClient = VertxTransactionDetailsClient.create( + jsonRpcClientFactory = jsonRpcFactory, + endpoint = URI(l1RpcUrl), + retryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + logger = LogManager.getLogger("test.clients.l1.transaction-details") + ) + + val rollupDeploymentResult = ContractsManager.get() + .deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V6).get() + + lineaContractClient = Web3JLineaRollupSmartContractClientReadOnly( + web3j = Web3jClientManager.buildL1Client( + log = LogManager.getLogger("test.clients.l1.linea-contract"), + requestResponseLogLevel = Level.INFO, + failuresLogLevel = Level.WARN + ), + contractAddress = rollupDeploymentResult.contractAddress + ) + val logsSearcher = Web3JLogsSearcher( + vertx = vertx, + web3jClient = Web3jClientManager.buildL1Client( + log = LogManager.getLogger("test.clients.l1.events-fetcher"), + requestResponseLogLevel = Level.TRACE, + failuresLogLevel = Level.WARN + ), + Web3JLogsSearcher.Config( + backoffDelay = 1.milliseconds, + requestRetryConfig = RetryConfig.noRetries + ), + log = LogManager.getLogger("test.clients.l1.events-fetcher") + ) + + contractClientForSubmissions = rollupDeploymentResult.rollupOperatorClient + val blobScanClient = BlobScanClient.create( + vertx = vertx, + endpoint = URI(blobScanUrl), + requestRetryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + responseLogMaxSize = 1000u, + logger = LogManager.getLogger("test.clients.l1.blobscan") + ) + + stateRecoverApp = StateRecoverApp( + vertx = vertx, + elClient = executionLayerClient, + blobFetcher = blobScanClient, + ethLogsSearcher = logsSearcher, + stateManagerClient = fakeStateManagerClient, + transactionDetailsClient = transactionDetailsClient, + blockHeaderStaticFields = BlockHeaderStaticFields.localDev, + lineaContractClient = lineaContractClient, + config = StateRecoverApp.Config( + l1LatestSearchBlock = BlockParameter.Tag.LATEST, + l1PollingInterval = 10.milliseconds, + executionClientPollingInterval = 1.seconds, + smartContractAddress = lineaContractClient.getAddress() + ) + ) + + configureLoggers( + rootLevel = Level.INFO, + log.name to Level.INFO, + "net.consensys.linea.contract.Web3JContractAsyncHelper" to Level.WARN, // silence noisy gasPrice Caps logs + "test.clients.l1.executionlayer" to Level.DEBUG, + "test.clients.l1.web3j-default" to Level.INFO, + "test.clients.l1.state-manager" to Level.INFO, + "test.clients.l1.transaction-details" to Level.INFO, + "test.clients.l1.linea-contract" to Level.INFO, + "test.clients.l1.events-fetcher" to Level.INFO, + "test.clients.l1.blobscan" to Level.INFO, + "net.consensys.linea.contract.l1" to Level.INFO, + "test.fake.clients.l1.fake-execution-layer" to Level.INFO + ) + } + + private fun submitDataToL1ContactAndWaitExecution( + contractClient: LineaRollupSmartContractClient = contractClientForSubmissions, + aggregationsAndBlobs: List = this.aggregationsAndBlobs, + blobChunksSize: Int = 6, + waitTimeout: Duration = 2.minutes + ) { + submitBlobsAndAggregationsAndWaitExecution( + contractClient = contractClient, + aggregationsAndBlobs = aggregationsAndBlobs, + blobChunksSize = blobChunksSize, + waitTimeout = waitTimeout, + l1Web3jClient = Web3jClientManager.l1Client + ) + } + + /* + 1. when state recovery disabled: enables with lastFinalizedBlock + 1 + 1.1 no finalizations and start from genesis + 1.2 headBlockNumber > lastFinalizedBlock -> enable with headBlockNumber + 1 + 1.3 headBlockNumber < lastFinalizedBlock -> enable with lastFinalizedBlock + 1 + + 2. when state recovery enabled: + 2.1 recoveryStartBlockNumber > headBlockNumber: pull for head block number until is reached and start recovery there + 2.2 recoveryStartBlockNumber <= headBlockNumber: resume recovery from headBlockNumber + */ + @Test + fun `when state recovery disabled and is starting from genesis`() { + stateRecoverApp.start().get() + submitDataToL1ContactAndWaitExecution() + + val lastAggregation = aggregationsAndBlobs.findLast { it.aggregation != null }!!.aggregation + await() + .atMost(1.minutes.toJavaDuration()) + .untilAsserted { + assertThat(stateRecoverApp.lastSuccessfullyRecoveredFinalization?.event?.endBlockNumber) + .isEqualTo(lastAggregation!!.endBlockNumber) + } + + assertThat(executionLayerClient.lineaGetStateRecoveryStatus().get()) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = lastAggregation!!.endBlockNumber, + stateRecoverStartBlockNumber = 1UL + ) + ) + } + + @Test + fun `when recovery is disabled and headBlock is before lastFinalizedBlock resumes from lastFinalizedBlock+1`() { + val finalizationToResumeFrom = aggregationsAndBlobs.get(1).aggregation!! + // assert that the finalization event to resume from has at least 1 middle block + assertThat(finalizationToResumeFrom.endBlockNumber) + .isGreaterThan(finalizationToResumeFrom.startBlockNumber + 1UL) + .withFailMessage("finalizationEventToResumeFrom must at least 3 blocks for this test") + + val finalizationsBeforeCutOff = aggregationsAndBlobs + .filter { it.aggregation != null } + .filter { it.aggregation!!.endBlockNumber < finalizationToResumeFrom.startBlockNumber } + + val finalizationsAfterCutOff = aggregationsAndBlobs + .filter { it.aggregation != null } + .filter { it.aggregation!!.startBlockNumber >= finalizationToResumeFrom.startBlockNumber } + + log.debug( + "finalizations={} finalizationToStartRecoveryFrom={}", + aggregationsAndBlobs.map { it.aggregation?.intervalString() }, + finalizationToResumeFrom.intervalString() + ) + + submitDataToL1ContactAndWaitExecution( + aggregationsAndBlobs = finalizationsBeforeCutOff + ) + + executionLayerClient.headBlock = BlockNumberAndHash( + number = 1UL, + hash = ByteArray(32) { 0 } + ) + + val lastFinalizedBlockNumber = finalizationsBeforeCutOff.last().aggregation!!.endBlockNumber + val expectedStateRecoverStartBlockNumber = lastFinalizedBlockNumber + 1UL + stateRecoverApp.start().get() + + await() + .atMost(4.minutes.toJavaDuration()) + .pollInterval(1.seconds.toJavaDuration()) + .untilAsserted { + assertThat(executionLayerClient.stateRecoverStatus).isEqualTo( + StateRecoveryStatus( + headBlockNumber = 1UL, + stateRecoverStartBlockNumber = expectedStateRecoverStartBlockNumber + ) + ) + log.info("stateRecoverStatus={}", executionLayerClient.stateRecoverStatus) + } + + // simulate that execution client has synced up to the last finalized block through P2P network + executionLayerClient.headBlock = BlockNumberAndHash( + number = lastFinalizedBlockNumber, + hash = ByteArray(32) { 0 } + ) + + // continue finalizing the rest of the aggregations + submitDataToL1ContactAndWaitExecution( + aggregationsAndBlobs = finalizationsAfterCutOff + ) + + val lastAggregation = aggregationsAndBlobs.findLast { it.aggregation != null }!!.aggregation + await() + .atMost(1.minutes.toJavaDuration()) + .pollInterval(1.seconds.toJavaDuration()) + .untilAsserted { + assertThat(executionLayerClient.headBlock.number).isEqualTo(lastAggregation!!.endBlockNumber) + } + + // assert it imports correct blocks + val importedBlocks = executionLayerClient.importedBlockNumbersInRecoveryMode + assertThat(importedBlocks.first()).isEqualTo(expectedStateRecoverStartBlockNumber) + assertThat(importedBlocks.last()).isEqualTo(lastAggregation!!.endBlockNumber) + } + + @Test + fun `when node starts with headblock greater lastFinalizedBlock`() { + val finalizationToResumeFrom = aggregationsAndBlobs.get(1).aggregation!! + // assert that the finalization event to resume from has at least 1 middle block + assertThat(finalizationToResumeFrom.endBlockNumber) + .isGreaterThan(finalizationToResumeFrom.startBlockNumber + 1UL) + .withFailMessage("finalizationEventToResumeFrom must at least 3 blocks for this test") + + val finalizationsBeforeCutOff = aggregationsAndBlobs + .filter { it.aggregation != null } + .filter { it.aggregation!!.endBlockNumber < finalizationToResumeFrom.startBlockNumber } + + val finalizationsAfterCutOff = aggregationsAndBlobs + .filter { it.aggregation != null } + .filter { it.aggregation!!.startBlockNumber >= finalizationToResumeFrom.startBlockNumber } + + log.debug( + "finalizations={} finalizationToStartRecoveryFrom={}", + aggregationsAndBlobs.map { it.aggregation?.intervalString() }, + finalizationToResumeFrom.intervalString() + ) + + submitDataToL1ContactAndWaitExecution( + aggregationsAndBlobs = finalizationsBeforeCutOff + ) + + // set execution layer head block after latest finalization + val headBlockNumberAtStart = finalizationsBeforeCutOff.last().aggregation!!.endBlockNumber + 1UL + executionLayerClient.headBlock = BlockNumberAndHash( + number = headBlockNumberAtStart, + hash = ByteArray(32) { 0 } + ) + + stateRecoverApp.start().get() + await() + .atMost(2.minutes.toJavaDuration()) + .pollInterval(1.seconds.toJavaDuration()) + .untilAsserted { + assertThat(executionLayerClient.stateRecoverStatus).isEqualTo( + StateRecoveryStatus( + headBlockNumber = headBlockNumberAtStart, + stateRecoverStartBlockNumber = headBlockNumberAtStart + 1UL + ) + ) + log.debug("stateRecoverStatus={}", executionLayerClient.stateRecoverStatus) + } + + // continue finalizing the rest of the aggregations + submitDataToL1ContactAndWaitExecution( + aggregationsAndBlobs = finalizationsAfterCutOff + ) + + val lastAggregation = aggregationsAndBlobs.findLast { it.aggregation != null }!!.aggregation + await() + .atMost(2.minutes.toJavaDuration()) + .pollInterval(1.seconds.toJavaDuration()) + .untilAsserted { + assertThat(executionLayerClient.stateRecoverStatus) + .isEqualTo( + StateRecoveryStatus( + headBlockNumber = lastAggregation!!.endBlockNumber, + stateRecoverStartBlockNumber = headBlockNumberAtStart + 1UL + ) + ) + } + // assert it does not try to import blocks behind the head block + assertThat(executionLayerClient.importedBlockNumbersInRecoveryMode.minOrNull()) + .isEqualTo(headBlockNumberAtStart + 1UL) + } + + @Test + fun `should stop recovery as soon as stateroot mismatches`() { + fakeStateManagerClient.setBlockStateRootHash( + aggregationsAndBlobs[1].aggregation!!.endBlockNumber, + ByteArray(32) { 1 } + ) + log.debug( + "aggregations={} forcedMismatchAggregation={}", + aggregationsAndBlobs.map { it.aggregation?.intervalString() }, + aggregationsAndBlobs[1].aggregation!!.intervalString() + ) + + stateRecoverApp.start().get() + submitDataToL1ContactAndWaitExecution() + + await() + .atMost(1.minutes.toJavaDuration()) + .untilAsserted { + assertThat(stateRecoverApp.stateRootMismatchFound).isTrue() + } + + assertThat(executionLayerClient.headBlock.number) + .isEqualTo(aggregationsAndBlobs[1].aggregation!!.endBlockNumber) + } +} diff --git a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt new file mode 100644 index 000000000..ee120c173 --- /dev/null +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt @@ -0,0 +1,139 @@ +package linea.staterecover + +import build.linea.clients.StateManagerClientV1 +import build.linea.clients.StateManagerV1JsonRpcClient +import build.linea.contract.l1.LineaContractVersion +import build.linea.domain.BlockInterval +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import io.vertx.core.Vertx +import io.vertx.junit5.VertxExtension +import linea.log4j.configureLoggers +import linea.web3j.createWeb3jHttpClient +import net.consensys.linea.BlockParameter +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.testing.submission.AggregationAndBlobs +import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped +import net.consensys.linea.testing.submission.submitBlobsAndAggregationsAndWaitExecution +import net.consensys.toULong +import net.consensys.zkevm.ethereum.ContractsManager +import net.consensys.zkevm.ethereum.LineaRollupDeploymentResult +import net.consensys.zkevm.ethereum.Web3jClientManager +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.Awaitility.await +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import java.net.URI +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration + +@ExtendWith(VertxExtension::class) +class StateRecoveryManualReplayToLocalStackIntTest { + private val log = LogManager.getLogger("test.case.StateRecoverAppWithLocalStackIntTest") + private lateinit var stateManagerClient: StateManagerClientV1 + private val testDataDir = "testdata/coordinator/prover/v3" + + private val stateManagerUrl = "http://localhost:8890" + + @BeforeEach + fun beforeEach(vertx: Vertx) { + val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + + stateManagerClient = StateManagerV1JsonRpcClient.create( + rpcClientFactory = jsonRpcFactory, + endpoints = listOf(URI(stateManagerUrl)), + maxInflightRequestsPerClient = 1U, + requestRetry = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 2.seconds + ), + zkStateManagerVersion = "2.3.0", + logger = LogManager.getLogger("test.clients.l1.state-manager") + ) + } + + private lateinit var rollupDeploymentResult: LineaRollupDeploymentResult + + @Test + fun setupDeployContractForL2L1StateReplay() { + configureLoggers( + rootLevel = Level.INFO, + "test.clients.l1.executionlayer" to Level.INFO, + "test.clients.l1.web3j-default" to Level.INFO, + "test.clients.l1.state-manager" to Level.DEBUG, + "test.clients.l1.transaction-details" to Level.INFO, + "test.clients.l1.linea-contract" to Level.INFO, + "test.clients.l1.events-fetcher" to Level.INFO, + "test.clients.l1.blobscan" to Level.INFO, + "net.consensys.linea.contract.l1" to Level.INFO + ) + val aggregationsAndBlobs: List = loadBlobsAndAggregationsSortedAndGrouped( + blobsResponsesDir = "$testDataDir/compression/responses", + aggregationsResponsesDir = "$testDataDir/aggregation/responses" + ) + + this.rollupDeploymentResult = ContractsManager.get() + .deployLineaRollup(numberOfOperators = 2, contractVersion = LineaContractVersion.V6).get() + log.info("""LineaRollup address=${rollupDeploymentResult.contractAddress}""") + log.info( + """ + Start state recovery besu and shomei with the following configuration: + + ./gradlew state-recover:besu-plugin:shadowJar \ + && docker compose -f docker/compose.yml down zkbesu-shomei-sr shomei-sr \ + && L1_ROLLUP_CONTRACT_ADDRESS=${rollupDeploymentResult.contractAddress} docker compose -f docker/compose.yml up zkbesu-shomei-sr shomei-sr + + """.trimIndent() + ) + + val web3jElClient = createWeb3jHttpClient("http://localhost:9145") + + // wait for statemanager to be up and running + await() + .pollInterval(1.seconds.toJavaDuration()) + .atMost(5.minutes.toJavaDuration()) + .untilAsserted { + kotlin.runCatching { + assertThat(web3jElClient.ethBlockNumber().send().blockNumber.toLong()).isGreaterThanOrEqualTo(0L) + }.getOrElse { + log.info("could not connect to stateManager $stateManagerUrl") + throw AssertionError("could not connect to stateManager $stateManagerUrl", it) + } + } + + val lastAggregationAndBlobs = aggregationsAndBlobs.findLast { it.aggregation != null }!! + val lastAggregation = lastAggregationAndBlobs.aggregation!! + // wait until state recovery Besu and Shomei are up + submitBlobsAndAggregationsAndWaitExecution( + contractClient = rollupDeploymentResult.rollupOperatorClient, + aggregationsAndBlobs = aggregationsAndBlobs, + blobChunksSize = 6, + l1Web3jClient = Web3jClientManager.l1Client + ) + log.info("finalization={} executed on l1", lastAggregation.intervalString()) + + await() + .untilAsserted { + assertThat( + rollupDeploymentResult.rollupOperatorClient + .finalizedL2BlockNumber(blockParameter = BlockParameter.Tag.LATEST).get() + ).isGreaterThanOrEqualTo(lastAggregation.endBlockNumber) + } + + val expectedZkEndStateRootHash = lastAggregationAndBlobs.blobs.last().blobCompressionProof!!.finalStateRootHash + await() + .atMost(5.minutes.toJavaDuration()) + .untilAsserted { + assertThat(web3jElClient.ethBlockNumber().send().blockNumber.toULong()) + .isGreaterThanOrEqualTo(lastAggregation.endBlockNumber) + val blockInterval = BlockInterval(lastAggregation.endBlockNumber, lastAggregation.endBlockNumber) + assertThat(stateManagerClient.rollupGetStateMerkleProof(blockInterval).get().zkEndStateRootHash) + .isEqualTo(expectedZkEndStateRootHash) + } + } +} diff --git a/state-recover/test-cases/src/integrationTest/resources/log4j2.xml b/state-recover/test-cases/src/integrationTest/resources/log4j2.xml new file mode 100644 index 000000000..dfe733a31 --- /dev/null +++ b/state-recover/test-cases/src/integrationTest/resources/log4j2.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeExecutionLayerClient.kt b/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeExecutionLayerClient.kt new file mode 100644 index 000000000..72efdc702 --- /dev/null +++ b/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeExecutionLayerClient.kt @@ -0,0 +1,81 @@ +package linea.staterecover.test + +import linea.staterecover.BlockFromL1RecoveredData +import linea.staterecover.ExecutionLayerClient +import linea.staterecover.StateRecoveryStatus +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import net.consensys.linea.CommonDomainFunctions +import org.apache.logging.log4j.LogManager +import tech.pegasys.teku.infrastructure.async.SafeFuture + +class FakeExecutionLayerClient( + headBlock: BlockNumberAndHash = BlockNumberAndHash(number = 0uL, hash = ByteArray(32) { 0 }), + initialStateRecoverStartBlockNumber: ULong? = null, + loggerName: String? = null +) : ExecutionLayerClient { + private val log = loggerName + ?.let { LogManager.getLogger(loggerName) } + ?: LogManager.getLogger(FakeExecutionLayerClient::class.java) + + private val _importedBlocksInRecoveryMode = mutableListOf() + + val importedBlocksInRecoveryMode: List + get() = _importedBlocksInRecoveryMode.toList() + val importedBlockNumbersInRecoveryMode: List + get() = _importedBlocksInRecoveryMode.map { it.header.blockNumber } + + @get:Synchronized @set:Synchronized + var headBlock: BlockNumberAndHash = headBlock + + @get:Synchronized @set:Synchronized + var stateRecoverStartBlockNumber = initialStateRecoverStartBlockNumber + + @get:Synchronized + val stateRecoverStatus: StateRecoveryStatus + get() = StateRecoveryStatus( + headBlockNumber = headBlock.number, + stateRecoverStartBlockNumber = stateRecoverStartBlockNumber + ) + + @Synchronized + override fun lineaEngineImportBlocksFromBlob( + blocks: List + ): SafeFuture { + if (log.isTraceEnabled) { + log.trace("lineaEngineImportBlocksFromBlob($blocks)") + } else { + val interval = CommonDomainFunctions.blockIntervalString( + blocks.first().header.blockNumber, + blocks.last().header.blockNumber + ) + log.debug("lineaEngineImportBlocksFromBlob(interval=$interval)") + } + _importedBlocksInRecoveryMode.addAll(blocks) + headBlock = blocks.last().let { BlockNumberAndHash(it.header.blockNumber, it.header.blockHash) } + return SafeFuture.completedFuture(Unit) + } + + @Synchronized + override fun getBlockNumberAndHash( + blockParameter: BlockParameter + ): SafeFuture { + log.trace("getBlockNumberAndHash($blockParameter): $headBlock") + return SafeFuture.completedFuture(headBlock) + } + + @Synchronized + override fun lineaGetStateRecoveryStatus(): SafeFuture { + log.trace("lineaGetStateRecoveryStatus()= $stateRecoverStatus") + return SafeFuture.completedFuture(stateRecoverStatus) + } + + @Synchronized + override fun lineaEnableStateRecovery( + stateRecoverStartBlockNumber: ULong + ): SafeFuture { + this.stateRecoverStartBlockNumber = stateRecoverStartBlockNumber + log.debug("lineaEnableStateRecovery($stateRecoverStartBlockNumber) = $stateRecoverStatus") + return SafeFuture.completedFuture(stateRecoverStatus) + } +} diff --git a/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeStateManagerClientBasedOnBlobsRecords.kt b/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeStateManagerClientBasedOnBlobsRecords.kt new file mode 100644 index 000000000..4f2a15ac5 --- /dev/null +++ b/state-recover/test-cases/src/main/kotlin/linea/staterecover/test/FakeStateManagerClientBasedOnBlobsRecords.kt @@ -0,0 +1,91 @@ +package linea.staterecover.test + +import build.linea.clients.GetZkEVMStateMerkleProofResponse +import build.linea.clients.StateManagerClientV1 +import build.linea.clients.StateManagerErrorType +import build.linea.domain.BlockInterval +import com.fasterxml.jackson.databind.node.ArrayNode +import com.github.michaelbull.result.Ok +import com.github.michaelbull.result.Result +import linea.EthLogsSearcher +import linea.staterecover.DataFinalizedV3 +import net.consensys.linea.BlockParameter +import net.consensys.linea.errors.ErrorResponse +import net.consensys.toHexStringUInt256 +import net.consensys.zkevm.domain.BlobRecord +import tech.pegasys.teku.infrastructure.async.SafeFuture + +open class FakeStateManagerClient( + private val blocksStateRootHashes: MutableMap = mutableMapOf(), + var headBlockNumber: ULong = blocksStateRootHashes.keys.maxOrNull() ?: 0UL +) : StateManagerClientV1 { + + fun setBlockStateRootHash(blockNumber: ULong, stateRootHash: ByteArray) { + blocksStateRootHashes[blockNumber] = stateRootHash + headBlockNumber = blocksStateRootHashes.keys.maxOrNull() ?: 0UL + } + + open fun getStateRootHash(blockNumber: ULong): SafeFuture { + return blocksStateRootHashes[blockNumber] + ?.let { SafeFuture.completedFuture(it) } + ?: SafeFuture.failedFuture(RuntimeException("StateRootHash not found for block=$blockNumber")) + } + + override fun rollupGetHeadBlockNumber(): SafeFuture { + return SafeFuture.completedFuture(headBlockNumber) + } + + override fun rollupGetStateMerkleProofWithTypedError( + blockInterval: BlockInterval + ): SafeFuture>> { + // For state recovery, we just need the endStateRootHash + return getStateRootHash(blockInterval.endBlockNumber) + .thenApply { stateRootHash -> + Ok( + GetZkEVMStateMerkleProofResponse( + zkStateMerkleProof = ArrayNode(null), + zkParentStateRootHash = ByteArray(32), + zkEndStateRootHash = stateRootHash, + zkStateManagerVersion = "fake-version" + ) + ) + } + } +} + +class FakeStateManagerClientBasedOnBlobsRecords( + val blobRecords: List +) : FakeStateManagerClient( + blocksStateRootHashes = blobRecords + .associate { it.endBlockNumber to it.blobCompressionProof!!.finalStateRootHash }.toMutableMap() +) + +class FakeStateManagerClientReadFromL1( + headBlockNumber: ULong, + val logsSearcher: EthLogsSearcher, + val contractAddress: String +) : FakeStateManagerClient( + headBlockNumber = headBlockNumber +) { + + override fun getStateRootHash(blockNumber: ULong): SafeFuture { + return super + .getStateRootHash(blockNumber) + .exceptionallyCompose { + logsSearcher + .getLogs( + fromBlock = BlockParameter.Tag.EARLIEST, + toBlock = BlockParameter.Tag.FINALIZED, + address = contractAddress, + topics = listOf( + DataFinalizedV3.topic, + null, + blockNumber.toHexStringUInt256() + ) + ).thenApply { logs -> + val logEvent = DataFinalizedV3.fromEthLog(logs.first()) + logEvent.event.finalStateRootHash + } + } + } +} diff --git a/state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt b/state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt new file mode 100644 index 000000000..dfc1c4dc8 --- /dev/null +++ b/state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt @@ -0,0 +1,171 @@ +package linea.staterecover + +import build.linea.clients.StateManagerClientV1 +import build.linea.contract.l1.LineaRollupSmartContractClientReadOnly +import build.linea.contract.l1.Web3JLineaRollupSmartContractClientReadOnly +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import io.vertx.core.Vertx +import io.vertx.junit5.VertxExtension +import linea.EthLogsSearcher +import linea.build.staterecover.clients.VertxTransactionDetailsClient +import linea.domain.RetryConfig +import linea.log4j.configureLoggers +import linea.staterecover.clients.blobscan.BlobScanClient +import linea.staterecover.test.FakeExecutionLayerClient +import linea.staterecover.test.FakeStateManagerClientReadFromL1 +import linea.web3j.Web3JLogsSearcher +import net.consensys.linea.BlockNumberAndHash +import net.consensys.linea.BlockParameter +import net.consensys.linea.jsonrpc.client.RequestRetryConfig +import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.zkevm.ethereum.Web3jClientManager.buildWeb3Client +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.assertj.core.api.Assertions.assertThat +import org.awaitility.Awaitility.await +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.extension.ExtendWith +import java.net.URI +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration + +@ExtendWith(VertxExtension::class) +class StateRecoverSepoliaWithFakeExecutionClientIntTest { + private val log = LogManager.getLogger("test.case.StateRecoverSepoliaWithFakeExecutionClientIntTest") + private lateinit var stateRecoverApp: StateRecoverApp + private lateinit var logsSearcher: EthLogsSearcher + private lateinit var executionLayerClient: FakeExecutionLayerClient + private lateinit var blobFetcher: BlobFetcher + private lateinit var fakeStateManagerClient: StateManagerClientV1 + private lateinit var transactionDetailsClient: TransactionDetailsClient + private lateinit var lineaContractClient: LineaRollupSmartContractClientReadOnly + private val infuraAppKey = System.getenv("INFURA_APP_KEY") + .also { + assertThat(it) + .withFailMessage("Please define INFURA_APP_KEY environment variable") + .isNotEmpty() + } + private val l1RpcUrl = "https://sepolia.infura.io/v3/$infuraAppKey" + private val blobScanUrl = "https://api.sepolia.blobscan.com/" + + @BeforeEach + fun beforeEach(vertx: Vertx) { + val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + executionLayerClient = FakeExecutionLayerClient( + headBlock = BlockNumberAndHash(number = 0uL, hash = ByteArray(32) { 0 }), + initialStateRecoverStartBlockNumber = null, + loggerName = "test.fake.clients.execution-layer" + ) + blobFetcher = BlobScanClient.create( + vertx = vertx, + endpoint = URI(blobScanUrl), + requestRetryConfig = RequestRetryConfig( + backoffDelay = 10.milliseconds, + timeout = 5.seconds + ), + logger = LogManager.getLogger("test.clients.l1.blobscan"), + responseLogMaxSize = 100u + ) + logsSearcher = Web3JLogsSearcher( + vertx = vertx, + web3jClient = buildWeb3Client( + rpcUrl = l1RpcUrl, + log = LogManager.getLogger("test.clients.l1.events-fetcher"), + requestResponseLogLevel = Level.TRACE, + failuresLogLevel = Level.DEBUG + ), + Web3JLogsSearcher.Config( + backoffDelay = 400.milliseconds, + requestRetryConfig = RetryConfig( + backoffDelay = 1.seconds + ) + ), + log = LogManager.getLogger("test.clients.l1.events-fetcher") + ) + fakeStateManagerClient = FakeStateManagerClientReadFromL1( + headBlockNumber = ULong.MAX_VALUE, + logsSearcher = logsSearcher, + contractAddress = StateRecoverApp.Config.lineaSepolia.smartContractAddress + ) + transactionDetailsClient = VertxTransactionDetailsClient.create( + jsonRpcClientFactory = jsonRpcFactory, + endpoint = URI(l1RpcUrl), + retryConfig = RequestRetryConfig( + backoffDelay = 1.seconds + ), + logger = LogManager.getLogger("test.clients.l1.transaction-details") + ) + + lineaContractClient = Web3JLineaRollupSmartContractClientReadOnly( + web3j = buildWeb3Client( + rpcUrl = l1RpcUrl, + log = LogManager.getLogger("test.clients.l1.linea-contract"), + requestResponseLogLevel = Level.INFO, + failuresLogLevel = Level.DEBUG + ), + contractAddress = StateRecoverApp.Config.lineaSepolia.smartContractAddress + ) + + stateRecoverApp = StateRecoverApp( + vertx = vertx, + elClient = executionLayerClient, + blobFetcher = blobFetcher, + ethLogsSearcher = logsSearcher, + stateManagerClient = fakeStateManagerClient, + transactionDetailsClient = transactionDetailsClient, + blockHeaderStaticFields = BlockHeaderStaticFields.localDev, + lineaContractClient = lineaContractClient, + config = StateRecoverApp.Config( + l1LatestSearchBlock = BlockParameter.Tag.LATEST, + l1PollingInterval = 5.seconds, + executionClientPollingInterval = 1.seconds, + smartContractAddress = lineaContractClient.getAddress(), + logsBlockChunkSize = 5000u + ) + ) + configureLoggers( + rootLevel = Level.INFO, + "test.clients.l1.execution-layer" to Level.INFO, + "test.clients.l1.web3j-default" to Level.DEBUG, + "test.clients.l1.transaction-details" to Level.INFO, + "test.clients.l1.linea-contract" to Level.INFO, + "test.clients.l1.events-fetcher" to Level.DEBUG, + "test.clients.l1.blobscan" to Level.INFO, + "net.consensys.linea.contract.l1" to Level.DEBUG + ) + } + + // "Disabled because it is for local testing and debug purposes" +// @Test + fun `simulate recovery from given point`() { + val finalizationEvents = logsSearcher + .getLogs( + fromBlock = BlockParameter.Tag.EARLIEST, + toBlock = BlockParameter.Tag.LATEST, + address = lineaContractClient.getAddress(), + topics = listOf(DataFinalizedV3.topic) + ) + .get() + val firstFinalizationEvent = DataFinalizedV3.fromEthLog(finalizationEvents.first()) + val lastFinalizationEvent = DataFinalizedV3.fromEthLog(finalizationEvents.last()) + log.info("First finalization event: $firstFinalizationEvent") + log.info("Latest finalization event: $lastFinalizationEvent") + + executionLayerClient.headBlock = BlockNumberAndHash( + number = firstFinalizationEvent.event.startBlockNumber - 1UL, + hash = ByteArray(32) { 0 } + ) + stateRecoverApp.trySetRecoveryModeAtBlockHeight(firstFinalizationEvent.event.startBlockNumber).get() + stateRecoverApp.start().get() + + await() + .atMost(10.minutes.toJavaDuration()) + .pollInterval(10.seconds.toJavaDuration()) + .untilAsserted { + val updatedStatus = executionLayerClient.lineaGetStateRecoveryStatus().get() + assertThat(updatedStatus.headBlockNumber).isGreaterThan(lastFinalizationEvent.event.endBlockNumber) + } + } +} diff --git a/state-recover/test-cases/src/test/resources/vertx-options.json b/state-recover/test-cases/src/test/resources/vertx-options.json new file mode 100644 index 000000000..15cb81ab6 --- /dev/null +++ b/state-recover/test-cases/src/test/resources/vertx-options.json @@ -0,0 +1,15 @@ +{ + "blockedThreadCheckInterval": 5, + "blockedThreadCheckIntervalUnit": "MINUTES", + "maxEventLoopExecuteTime": 2, + "maxEventLoopExecuteTimeUnit": "MINUTES", + "maxWorkerExecuteTime": 5, + "maxWorkerExecuteTimeUnit": "MINUTES", + "metricsOptions": { + "enabled": true, + "prometheusOptions": { + "publishQuantiles": true, + "enabled": true + } + } +} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/1-3-c582331fee9d97bf39b11a6681579c5478097d4af5eb2c97e872c798b03287eb-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/1-3-c582331fee9d97bf39b11a6681579c5478097d4af5eb2c97e872c798b03287eb-getZkAggregatedProof.json new file mode 100644 index 000000000..ad848c214 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/1-3-c582331fee9d97bf39b11a6681579c5478097d4af5eb2c97e872c798b03287eb-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xc185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977","parentAggregationFinalShnarf":"0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f","aggregatedProof":"0x2fce59e8ff9585ec54b9a65ef16689ac01b95a970b87f453621a67a6e43598ea13e050036085b8976063645febf63e6bd68711de8074aca1e50844a541a13e1706342123781363103b4d11463e4e19b399c6b2bc0aa0a958ecf17c5f6052adb612b100900ab5a6fbdcb8bd8771d94a3c152a551bb449f140196dba27f2b5f4591af3af628c1cc32eda5450d9281542198df8c799ab79b17d35e84b81ae116c701eaf6a1f1c406d505167c42b9536dc4bb4cddba008358481cd899ff43a72eaba14861c88cbb5c8b346ae3b89720b828f8019d488fe7218c1fa2bf6c7ee83d8c927a7131ff16fe07fad81aacf3d30a2a7b7b6d1c3cfbd8d76fec0e801aac9b05926e55a1c68af58690f81b1f4901249055b6ac6a0b07c161d0bd1ec2d7810febe2ab6d0aac357996416eef005dfa6eed5b84217734a4ec35f5e0f6a93cd3e922c1a78230a1f77fe4119004a36e6f8102268351daced3a1400e8dbc31fdab7e9ed233b54717044c411575b622db9911ea357618c9756f9e159db55503c1d9249d80b5f797925359e87ef33584af680fef9b03fa484596c864c858a83608f3359f51472226a15cab2906a875d74f7a3b1bf78a2c5c5f13e5781076590c5d083719929ba53673b8ddc3562fa2af2c16e9da83c71d7a1d28a49c210b45cea3dc593d22ca8d13342f07f98fc3170e035254c4732c8c9fc0a489c97fd38d11b6f765ca82e37b29c1dda62b6734f96373761fa242ec920a1919e837bfdd96b778832140f0067a3f503680e53a94157865bdd6dc5631b06900dc74b99488ed9ca2008f265030fcf8ede7ecfdc474063f163f00c3c879d58d3b56909632cb29be9035b9eac15c76a0b16c1a548379336da4d1109c570ce8e376448fe9788df96fcf7261b08249d6bebe9c2962c47b0ac0a8e9c83d7c42e129182001089e5791b72994bfd01242d887d15f028c7c5b7429d8b84eadc76253569b09f040335ec8736e601256b0c67c4529a046fab2ed1ef8128f27a531bf8c978dfacdbb2d45b57f638159d8d16c3b8c0238c6b019715cfd406ee4a43fdff2c1ddb494c4851c57ead7c87a57a02cc50a74782bb3806bdfffc5a63e4c416ea087d5d864687915491076cea7a572d22d5fd79af0e8397e8cee8153655b0b277e9cf08e29b3d1e603e1f6ff27ae722910b6cc936a66e7ed831280fdf22fb3b308a5ea19582a20b796dbb4bbbc310","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x0ba9370c3f9cd0e53ec8d54dd1db4cfcdc058586bd3d96ebb2c7fbed5e52b8ec","dataHashes":["0x01f48456f10caa5029fed9b89cc5d2b3853af3a1b76f0deae6ebb5a2dd1e9ea2"],"dataParentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentStateRootHash":"0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd","parentAggregationLastBlockTimestamp":1683325137,"lastFinalizedBlockNumber":0,"finalTimestamp":1736794040,"finalBlockNumber":3,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/11-13-523fe0caa8ea09a3787268f8bc8cfdbf9005d1e527ed656c4efd1ec39e60dee1-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/11-13-523fe0caa8ea09a3787268f8bc8cfdbf9005d1e527ed656c4efd1ec39e60dee1-getZkAggregatedProof.json new file mode 100644 index 000000000..e5d37d4e9 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/11-13-523fe0caa8ea09a3787268f8bc8cfdbf9005d1e527ed656c4efd1ec39e60dee1-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xe5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7","parentAggregationFinalShnarf":"0xe6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7","aggregatedProof":"0x24a4e08e2510e67497a9bf54aeb7dcb4e332dde5d9cb7adccba02bb84cbc4b1726dcae96eb0d405af285c3d74e734ca03f86e756bd6fe8ef1debca98aa8e57320d52ce7fb0dfa443e3f83f03a0eda48a6ca4519a98847696b534a5dbb73d1c3410623dffdb10e816a1e60b42c748fcc75b8130ff36d0df6f37f431beafb10fe20e2f610c2dbef1cf7ae6be41442583d02f5781eaae326b0e05156caccb0ef8ef152945136a3fd7b2d4f5b578eb5ba0a47a8e0ba792baa8e26b6c5736335088ee10ac33056a58d18a85747936cb2a8d35f80ba24bbddbd71e39774ffbe3de37ae26dc6a391d549a2bce509a754aac4b19d898905ff9bd2b8bc95272322c501be717f680a296bb049da5d2aaaa5c2869f5bb6e50a956b9d409adee84aead6b831001a623f3ba483d00028a2ae874bc3f3b0a720b3df5bdda5cf18433bea97d21f21c3b6ed2af242fe42443a7805e2c1b8c806be9a374aeaccf59126e63170fc9c82a2a9aba194ec376e917288ba3158a48f7bc7c73cc0277cd81356a58497562bc16dee2091f035d9e3fd384dd1ebbaae08f39fc0c54681583c30dfe531c5576362c7ac33ae42859454dad8bb0368ae6251763d42179b1b32e71f7eacb2d9c9ac72f2aad843d875ee2fcfa6678f11bd398b3484979cec2074bbe4973ed2c5168030ec9913624814a1592c3e1657bf1c8752df6577f686bacfecb51d2817bc13e51163c5f64fe1b28b0df2873bdf9c4bf7415d4092c69b879f91b07fe19d9801b4225526b1a10af347bb0f3108a18b47ada60522c1c3485a7ef9657fa6753c5b0c51a015870ecc86f6b28a437f5cdd02666e1cc6d1636b4aeaeef525c9f5f98343616f20c994c94f84f0bd7630c30cc910e55b225c1e05125ac7365ad5cb2da23c92b8c3b7284190fc1553e3bcc0f6110f689bca2bd100e74046e92af842d84f78f2c10b572e8313875b537c9c8a60c4d81c09985f1734314f889643997457e4ef81b022c04a4aa593553c63985ee25db2b4b609b7775bddff0e09c24d7c62204ef0635355fa248defec23d7ec4654b564570b4cce30f1ee79d65eb490ae977a5321ebf7a482ba551a5e801998c6f1c4af44de96f2b25a7719ccba69f90fcfee5212619753e68c001a24926de6c0ccd20d43757021d0aa915998d66cb0b5dcb9ff10c2c9daa1ab74083542ad6064b5a9d84ddc46f642a6a7305289c7a38ed63c459","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x2a00a4c1d13bc8f8034ebcf9723e330967c7a08289b9475539bb3c01ca0d6985","dataHashes":["0x01f05738e04c668af5ca1887f52528ccb9eef7cc90afd73c9c23c14550021323"],"dataParentHash":"0x01c993ae52495203ab88827c3111fcf3b09c16655c392dbdaac614dc00473c32","parentStateRootHash":"0x06dfd5bf00ac76bece68984bced5f376d4a62abc03b56472959bf804c547d574","parentAggregationLastBlockTimestamp":1736794163,"lastFinalizedBlockNumber":10,"finalTimestamp":1736794176,"finalBlockNumber":13,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/14-16-193b46cfdb687e208772c266f87c91e78a3edb1e02de9888b0ed37bf8560eb30-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/14-16-193b46cfdb687e208772c266f87c91e78a3edb1e02de9888b0ed37bf8560eb30-getZkAggregatedProof.json new file mode 100644 index 000000000..34892c047 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/14-16-193b46cfdb687e208772c266f87c91e78a3edb1e02de9888b0ed37bf8560eb30-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c","parentAggregationFinalShnarf":"0xe5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7","aggregatedProof":"0x12594e0c4b4af367a2b24f097cb834477248479b2036687d3133112dc93364740718680307433007f39d2b6641fc451a7c8efa3cc5bd25a3ce01f2087ad4161c0c729a0f996b90bea7939b4cdc5692651679167e4b4744f55d3e8262f97e8f981bb01b9f6ffb5a253c40ae0a90980cf32578b364029a7cd7f57d78e27e88082d2f27271285e4e092c67f08a2aed485ce6e9f80a0c4cd8e8879616160c3faed300724963bc87d12e8e9403df2fd576ac5e4580b64c810fb0788e34fcc992520f40ef8cda4e3dd51129a2a82a45dac501c42e7dc8a9c0316f56626e47ee242cbb91d3dc8e18ee276f2fb9b84551bb11b584d4662fa703f4efa9a050ead916ef708038f49aa25ac389fa29bff91930747ac1ca378aa16a494a620d5b1d98125dc8716441b728afe09ce6b08753517076f52a40d90423a8ac9e0e10f73310d18642005cb2e9ce7acfc99dcaee41d28236248d8f79e144eab14a0e2aa318bbdac930c1e5b0c7c986c9d9df0da2bd84258bc422e0bb6704b3b8f2e03a475790ebefe44005d95028da5aacf102e19caceb2ed3973beec18b65966b7e83a35178191cdf42510edc449e51c3646417034733451635f3842df96668d7997d444cbf648ce5204cd7dc27b7dbb795e1d429ed949c4089daf38b202af7f3b7321aaa0d6d6c8972617451f3ae97386a88572e4a748b59eb10299b2638ee8548d35c2ce9f02d02c1afdb6fac9df48c936206e013fece225e97fccf483c6609839c80ca83401d578301a89aba444d1f4494c8ac11b933c71605ad718778c0b8570de450fe2f24f0125166ed94151cf455f81539d77832ff2fd6c2ce3738900710095a37e21a0686b0a5b24376437fed1f3700776bf9d0f829d20836f5170da3bb8b630dac8be5154054ee536afcb92ec353e4a2354c9a291ba134c1cd33564ecb7f160aa0a67af3b09fb710442e57342dac3941045d412d0fa2ebe17a331f5fb83697cff45002bb02e5027aefbbd95ef8c79b71c65a123f3ac9d55521272ca5f7f2f8912be7098482b0452a8efcc295fa06b81daa1ca6cdae18d45622d013e9ae528cb267c750b9105b464fcf8ac9310ba53c479c698ebd3cb93823535519bc06537515028c858ce11fe9a193cf833b6df7c96da1fc6c7dde75f7e4be18eaf0409a258e46aff9a012b3002a445063d2711453d94858130569d002f0a1935b161328d4a072df8ff82","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x213e0703c2e3906c3be01622e765c4c65ba823b38c907692be17df3eaf5052b0","dataHashes":["0x0117ba7a785df44964e79ee97cf056d3af4ab463f1a4f30ae273f37cd5caf211"],"dataParentHash":"0x01f05738e04c668af5ca1887f52528ccb9eef7cc90afd73c9c23c14550021323","parentStateRootHash":"0x093fd331edcf516c7e6805250bb7b6b56131fc20921916096e4a8a71d0612167","parentAggregationLastBlockTimestamp":1736794176,"lastFinalizedBlockNumber":13,"finalTimestamp":1736794188,"finalBlockNumber":16,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/17-19-b615854a9075e73fdbdb0f22367d8e48c36997b28857712f018ba10e05f52759-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/17-19-b615854a9075e73fdbdb0f22367d8e48c36997b28857712f018ba10e05f52759-getZkAggregatedProof.json new file mode 100644 index 000000000..e6b198ff7 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/17-19-b615854a9075e73fdbdb0f22367d8e48c36997b28857712f018ba10e05f52759-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837","parentAggregationFinalShnarf":"0x8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c","aggregatedProof":"0x0edf53a96a2e976e3d6b53d6bc915136815b322a6a5e585abb4b02d46a3e62cc056d1147586f036627fa7a814845a0a932270ca94bc74cb507a0100c977621261e8334bf6c1a7ff2d67215f3cbfd04be0312b5bd0fbe8dd479e6dc4ad745f4a41718dea11a13a50e7402b630b00daff9c8e251cde4596f53734ab488e56800f32686b1d8fe6ea469c6d37173e25eaea6c609c79fdf3402dd399f4d40944d342e2dd5e16c82ebfbd9ac041f1d0695c904bd0025ca8215eb8f737c66e5a7a15f2e0e1c8c5b817b132bc2928213fb0689db24641d56cb3cd9900aec1e4f14d17e0827e8eefb7b4e5469283e29a125bc69ed0fd06d73be2d243e5b75b9ded4d959721b416b64722b52ad3e67aada91b41e97fb36d025572f0bd4b02080d3647dbf44125a3b4591112c459f91785c0515699d3e7a0cf8efde11c882b171493a8f73f113f9fa2a36ce1da183ea1e8b85ca56fd5685c8ba808a31427e64c2364b25d61b21bbe92558fad3a7d5625e827ff57ee4c1a3bba4cb5336a33bbaa1583b5cb6b605e585339289d33047ed85963e7d8b7b57a6eaa13af83debe692d7ef9ded956d2bfed7685f60d5f1bd0f9a2fb1e5d788525abf450086ed82ac9c3f24904325a01d31f4b0310d0f0da51b1fe4ad5a2393bfe5287ee07ab9d8b35ffd65297b8b4424d4825c022e75891a81d1dc156bc2783355134f6b1864b3133f6391db1d256e25246502cd491073beca3bafe84b0b215454f586c916c07702ea3014a80be8772a5afc2dca1693af1aa908630e892140e685ed8b5852e03aa15f98a5373c79901a76bad0d8076fc20d421e62aeb182d6881d829b1770c2cd5be02a6dceb4ed0704587f81188cf93de74d1389d454d73a0e7c47d0d5bd786df7e1cfc1da51414913efea98a6d90a9f29a18047d7a3849eb649e23e047b2b5a89ccda39766d43240788699a39ab5e7c65fbe0fbc4c70f9705b8babc79e1c3b3d3dd99e87b922ca921afb351a94c16556098454c545fe618b8ed4f80ffa4e1a7cc78f43c225d87980af32f5895a7eafece87f1d4ee3febf294adc915146dccdd7f07905b40f3d85203bffab40af6c19b736d6a4651102c3fb735601525ca0e36bebf5e88984e2f59254b4b5d91374755a58820770416eb12c020df54d8f5de00e1d62e129cedb3bb230eadbe5bb0d8f065e51acd7f694f8dee6bf1a7607a91851c0fbb75f28bd255","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x29b9d593344364a7c40bc0d045897a8187213391a50af436df38c60f8f7bbb48","dataHashes":["0x011494f735f62294281086b6b718118dc25868b6df1ee20fea3a37d254c3f1c1"],"dataParentHash":"0x0117ba7a785df44964e79ee97cf056d3af4ab463f1a4f30ae273f37cd5caf211","parentStateRootHash":"0x026a0d5bb730f4867e5e9d696d6dcb4a028cbb918549565e9cdcb6b42f839573","parentAggregationLastBlockTimestamp":1736794188,"lastFinalizedBlockNumber":16,"finalTimestamp":1736794200,"finalBlockNumber":19,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/20-22-9e033347194ecf686585d4ddc81a602edc9afa61c9d8437c69a1f0981e66fb78-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/20-22-9e033347194ecf686585d4ddc81a602edc9afa61c9d8437c69a1f0981e66fb78-getZkAggregatedProof.json new file mode 100644 index 000000000..74c0b6a98 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/20-22-9e033347194ecf686585d4ddc81a602edc9afa61c9d8437c69a1f0981e66fb78-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xaea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7","parentAggregationFinalShnarf":"0x343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837","aggregatedProof":"0x2230b32e3a65e9592595864aebe3d985e2acc2524a17f20f9cd8f0d28894cc3f0dbc5786ca09449661e6696385b6fc165ac27a0b64848ef98ff1d0ef627dd59a1070e81062466d84feb95356e8317f4770610afa13c636779b3b00de491915780a2b5df0944142092d73a32a4ac56e479b0ded304feb00be9aa674ebf153d7f11d1e15548655f51eef49a2f19cd198edcfbca80df8df3c309224c838a715158d00c83b5bd9fc710400ebe8e0b6169d66a9dfce0db0fb493bdeb90f3c29cdfafd0930d710d2430039358be5b36df0f5edaf630bb3c3c8f12e94a273e79f2a46f81899152085c9bbaafc653c495e35aaa24fca7ff2355821665bffd4c167cee2f711e42d43f468d71a0427e96746239733a95d43da022eb1dfcee0f38e063d6735086fe08a9b7acf7da4a576e3070ee5dbdd1b30040af7e6cfb18f4fb855bccf952e72981a6f0eae07154d91cd6c8b4e34747ff7a8641281f4ffcda9f8c7fb4cf527a15e8f2eb68f56c4532f217630345db20408e6b7622ef0aaf88fb53d584902256e3612bb40a8c680763406b8baa315d250c840fab1e1b00699608929031b5112b5712bb925806f22afb6c82078bb9939228247e8f5fb34fee153e0e4bb10d3094d514114bb6832bc9b43bad66f1004ce90509e1ef6e268aa9e9ed46e9f6bed0378e994d8d0a15d9e4199b3a88cf0e7f9b47f008e04e3d219124915b3de2d5d0d9854b43d92f0af4f96d23f954775b9c4fde7e3e3928e5e957f0ceb97a81852147c326b51ced6ccd1992087555aa7f4d9b9624610c6771f5ce9b74b5fcc66681f6711b65319c3768709aa028f1cea7f3751b2cedcf6065de0f9b64d0a52c08f0b29b80fbb9e4d2b3e332f34e07156f5934fdbd1603740261a8a1fd449f786a41ebec7f529195879a38cc8fc773a8fc285cebb370a8489e268853bce28a11d280deb1dcc80389a0b426cce069718b90f066acb0a8e0fabf3862f76b957d205750a8d3af9ad462e36791c62d6db7c2608e2f62dcf56b0e74b5ea3082cbc6eb5e3140ef004a0bf32e3946f134326ac51d22702de96b2a18c6f6d78508036d3169f01313a4b4316017a54f9de635490da4ac1bc02027d31fcb4832df5a28b608bc22e4c3639c48a272a85c1c7d993951d6b7ae044b381e1d4b38f586ed45927b0f6246b99b4e85d044c7ad9d61786e7868e90ead53754c56572041eb464d06b55bc","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x28d8d27645cf1f2bb8527770fb5810c016ded63deafa33d385ea7610da4f6f45","dataHashes":["0x0146d216177763b2ddaf338614ac3c621b193019f04145d45ea58dc381c910b1"],"dataParentHash":"0x011494f735f62294281086b6b718118dc25868b6df1ee20fea3a37d254c3f1c1","parentStateRootHash":"0x0cdab0bfb220ab9c5b2199486f2e828cc1c2b350410dad11102dc3e1f333dfb8","parentAggregationLastBlockTimestamp":1736794200,"lastFinalizedBlockNumber":19,"finalTimestamp":1736794213,"finalBlockNumber":22,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/23-25-1cdd5b5dd6cf38f123b1de80eb1d86ce47ba28a9689930db69175cc9976f4fa4-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/23-25-1cdd5b5dd6cf38f123b1de80eb1d86ce47ba28a9689930db69175cc9976f4fa4-getZkAggregatedProof.json new file mode 100644 index 000000000..d0555d391 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/23-25-1cdd5b5dd6cf38f123b1de80eb1d86ce47ba28a9689930db69175cc9976f4fa4-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b","parentAggregationFinalShnarf":"0xaea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7","aggregatedProof":"0x1b1ffc9faa35df9ca75c70806193dcdfebc2674b7d9bbd3fd98c51ff8ffd0b2321a587e8112706244802a9a461e9a374c85272be5627d4baee48f763795411cb268164698dede7b284796427f22a6d1336d37bcf946bc6234b1398ce9f7b4e6814158401076cd470571a97f9d8737750d70e21e6449520cc42de4a107531bbe8082e5ead0b128facfd749de504e98ab99f322a04b01d6a32d8a90e1c139d8b4b2264119c174627a59ddca3b94bee51e00e5b82780846947c07411376f1f907280e480eb6cd0de73c5ead2d5d6250757e315014a6a8afea8339e298daad0e625b01397f8c6183b60993480ecaf794236507ae9e5b167dcc013e522d918c9bf50208cb16689e2a0475a394f421a62e51126b3552745410253f3fd72aff21c825931a231a770fdecaffd51c1d3fe6f0fa7ef78a25adf501f59a661482d20fbb51d5185f080c4644b00227d4c7439f73b763cdd3ba90bf4c1ba39d716582d75599152690f2ec8c5c71bf5a4e221fe42b61d0f3818c95cba3fda91c03aea056610e7d047453c276e60985f97bf8b06117dd2e8d5f9cd61bcb5ba77a811cceba76f3460c8158a23676ea3de96dd6d888d45d49450a1f81e9b27fe8ad7137f695aabed72b22ad39385e7b5bc97735a787511ea395046f00dac60fdb05611d44851e1fc92c6362892536a9329b905f14a9dac0fcfb86d6b9a853a64665303f6da8ae959e0da84f5219477242a2d2b66f214f91711cccd1080647cfd0ada288cb6f69db741065e63aa901e09bd447ced598fef91f4d4afe7ac903f6f2997cc58191d7888c263456e64179ab53d37e5098bf431d8d4b4e3953e1d771e351634f7b730b6e3420b2dedfcae4e9d833fc9f7d64de05ce00d707e25aab821016619e5e554952490006059506061e641d58946b52606ae810154e38de8c65b4ea8441dd4654c26f03dc1cea0d66a394caaa260ba0bddee02f411d89f5468a23a53a3fcae6c6fb7b1b95709b8371f24b9289f69ba2652f94c9847ff33ecf946a588236cd4af82c0e16a103a37b3f2abe4285922963c3b974a5eabe96779a9152d23d8e559457edd61be5083e4f3426c2e69bbc5c823872bfbf2769238310e0220ae52d209f2cb5b423b82bb90b671bdd70ce60874dd6709df57df42874b861e552e24713776bfa730c718f7e7db9c9ec6d4dd47e6c53831d4e305d41871e0c23b356df7c047a583b","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x05e4bd2b1655c0d801dae28d6acd4b2813c04638bf0c3b5c92ba9fd9b62c3255","dataHashes":["0x011c205cb61ad36b464d88916e02f3979b79b042c8cab3658900d36046c4aaf1"],"dataParentHash":"0x0146d216177763b2ddaf338614ac3c621b193019f04145d45ea58dc381c910b1","parentStateRootHash":"0x0bab6a28cfabc29cf1e284145b39f5b37ad04ca0d85cf878943fd066b3c8fb10","parentAggregationLastBlockTimestamp":1736794213,"lastFinalizedBlockNumber":22,"finalTimestamp":1736794225,"finalBlockNumber":25,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/26-28-655573aeabb826867531dedc1510fd1c7540e871ce2da96641b2e59ca659669a-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/26-28-655573aeabb826867531dedc1510fd1c7540e871ce2da96641b2e59ca659669a-getZkAggregatedProof.json new file mode 100644 index 000000000..9130be99c --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/26-28-655573aeabb826867531dedc1510fd1c7540e871ce2da96641b2e59ca659669a-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d","parentAggregationFinalShnarf":"0x268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b","aggregatedProof":"0x0c8d8a4fce1dc63af90bd6a1b42f2dc179a8b26cdfb84b3918f15db6a26e0aad0f546bee463e0d31619fd294163103d73e23c04d74f0c72de1d2b86e09d27b360db752631205422657c134135b5b85f781341548886d177c2c62abfd9562d28a1c40ddcbcda071b65b514d742124918d2d2d505856765ceb7ccd882929734d122cf1003251c80dbf6db9dbcb6213b2a4678fc3fb73c5fcb89f3278476989f98d2f336baef3d1bf1cb321079ac35c7ca19c536e01a385513e32f270e5757995bd2eee67d1cfcdc604a14d442d39b6eea8ab1d70387b47944bd15f60981482e1e11d7d42e7a61f6909b62e170ab5ea24de56c6cb7f3ea071ff0953be3fbc84301c24434f62b2bb9800759a5d270d1a3dc73fc98f6985ce5f4b9626c5f2a2204d0f2d5840b46d4703324623d8b5eb1db08816952f5202900a2b5a1a62b15912304e2448d55ca7cd0cc57d31d4282ff256d45cbabd1f9d58651c2c1af61cbcc8aaf8228a4611eefd1722bca1935c379149bab6e9db6538106ef18fe7c2a5d366777c1317e7ca505579cc3ca99a2936009d4a7b4e84d964700fe400c35a305adf87a615167ecc73f685922dabc170a798f28c72303214b5759f6ae79395df3a27e5da2208bbdb8a9609887a4ab859edf8a02b48e4f114b37e2b5b9c01f5fc29a6e9fb0acf253763440a59ceeb34e77a267b90a27ea86b1a1c952db48307922c7b27401b57f798520c64e593bc220c5878dddb9b6661b103f685c113e0d44cd9c348bd015380a937b6060e9da216f8c2edfabd500e1a9020961c4f28d08fcee20d60eb0750a46ce2d4c8877cf81fdee89df6aa7a338faf65fe598f905d82b0edc2fac50ad66950c554c77875481d19c52419684f30ee8aa0906d2482e02bd69672399a14134c8aad90b4614487784ee14c2f6da543d19ade5cc0cb80252396b74bf07c027e93ca5bacfe6f64f9f7d409e5a987d65aa49419a058eec16bec19c1bc37b921c9bc0c5ef210f64c2e31e91d12d5b83da0d2bf56f9dad7ce8bf23407e81beb1aaaedd527cb8ef7964e0fa61d5f7a9f403125bc25a6c066fc6a36b26650acdc1bcafadc2d267a4526fd294bbf2cdd5040f86da7c9929b98de06d0ceb8dc53dd182e5b4eb0c2385de9d9bb7ee758e187aa21611793e9e27bd994988d9d9389bb2c39cfd59a4635e8ccccd6da21b99234d31fb10dd2904f29d6645ed160584cfc","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x0fe1ef2bbc51ac7b6a60b74ab010168ff75c9f752acf5aea8642b2e9cb1582e2","dataHashes":["0x01a4531284372a882e18672608435a88af99893b303a0238bbe3f8c95d44e18e"],"dataParentHash":"0x011c205cb61ad36b464d88916e02f3979b79b042c8cab3658900d36046c4aaf1","parentStateRootHash":"0x0fbfde9208962103fca09983aa7a7692edf9a9db2376cfcb92f6b4ad19bda51f","parentAggregationLastBlockTimestamp":1736794225,"lastFinalizedBlockNumber":25,"finalTimestamp":1736794242,"finalBlockNumber":28,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/29-31-411b174b8760f03354ec0ae215a6caae21472b0788600ab1df3d6da896186a1e-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/29-31-411b174b8760f03354ec0ae215a6caae21472b0788600ab1df3d6da896186a1e-getZkAggregatedProof.json new file mode 100644 index 000000000..9284f2541 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/29-31-411b174b8760f03354ec0ae215a6caae21472b0788600ab1df3d6da896186a1e-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c","parentAggregationFinalShnarf":"0x06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d","aggregatedProof":"0x09d7081d343e34b72625a7fcd1467d939e8b421e8330d804b9582bb55f1a859716fdb1e4882a40b10b8fdb58170506537a187e0334f95a387a05d708d36d450c0c98c42d5af3fe6689df96ce786c52242d8b7dcd062c1a35f9cc5875605723b10a7625accfce23bf5a3f5216966f2e93c2c2c6e90a7b608a546e73676097af8e2b3381194d8f2b24c1e628850a885ca9194ba531b2f7e03a241b6b0b11dd82db159452fae5cb3fef9baed07e7736c31112c7c6cff5c7dfbd3aa112d3bc99adce1e930d16eaf0d07ada518d829275e9537c977af6fab33fe6a76bd2b42696d6a9235201371f53bbbca9040333bd42d0921377861a53dc0f702491e3f3870ae9eb2956f6000f9ea8464c0fbac8f922fb9819eaf65658e8a655842e1832b24001802cd356a9f0195f64a5a7a189d86832de8844297d2bbebc9ab54576911c0c0dd31fc7329218557a228a0e15e43c1a225f1a73eeaeb0514163d2c7198fdbe4794614f72b106154eecfdeffb289b94583c0bf890bbc76566dd6f1c319ebe210897a04dc786a2e850b024f842a2912a1381aa153b91e9a463d8207bdfdca25b39628266cff483901cdc3625b3a333516008465c86a49bf840e10468c3cae4b52f27c12d9bd1416190ca6221a44832d39c9b38a2a40606956f25cd7f47595e7f4ff9904c921115780c45ec485e90f3fe446befc56bc4bb486ca2f74281457ddffc1780931f5876f2ffaea03fdb79082ebc598f07969cc0bafcaf273f06617633de8ac0cf40a7e354ceccb69b9720d075d55669efaaa85fda62b7089e3aa57c832c8852142a10920cdd642834aacb041a7af735092860e9a8f00fe3407ce95f8db327e0b6eb3e1b7d5f518631c5027556191fb6f7600183cd729a19d1a1559e9b560520b471ed25a176d811d3c62369492bbd31927325cd4cb76bdf1ff9ac6739916f411b2bb1d16a629a782d8c108b87c46894f745cee40483ca9af47b9f506e518851f3d81d54dd38213aa0145fabcddf1b17bf84b61af3d62e56413eeb2f6a3ab3002a81a95dc9b09299b4a09930159f5f2cfcc9b89b04578aa0aea6c0cc6a5065e1859dfd5febc12c79eb301dafa2ee6627e14f72a23e832814a924096f387865707b5fa41d04663ef43bafcaaf14e82966c04958ac03b169ccb50e3aba2822f8d1b0fe4fea81b4024ed435fc006f7607c4033c1cee780891b2393c23e7700b694","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x18ebcb749b91d7ce895bdf0e4918426e4b417a47fe1c39a84dbd02e3b086d8e2","dataHashes":["0x01354941e62722510ef8c530586b3f4edff05009634df244e6df56f131ff1c13"],"dataParentHash":"0x01a4531284372a882e18672608435a88af99893b303a0238bbe3f8c95d44e18e","parentStateRootHash":"0x04e223e961d59de5d0cd6ecf9d78359cc9d72b4261d851557b1e974d90b71a7e","parentAggregationLastBlockTimestamp":1736794242,"lastFinalizedBlockNumber":28,"finalTimestamp":1736794254,"finalBlockNumber":31,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/32-34-bb1a9a83d812c5a46ade32842936de46f693f72c2a2f314abfb166d316bd4825-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/32-34-bb1a9a83d812c5a46ade32842936de46f693f72c2a2f314abfb166d316bd4825-getZkAggregatedProof.json new file mode 100644 index 000000000..f44d82484 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/32-34-bb1a9a83d812c5a46ade32842936de46f693f72c2a2f314abfb166d316bd4825-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xa646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831","parentAggregationFinalShnarf":"0x0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c","aggregatedProof":"0x292cffd9adba0c6c620307cc9ecc73f82b1145c7b4dda6ad9571ffabe508163b2a48791c59a6f3be9ef5b8081ac4f3d0df27b24443e74a3e7d734d12d8db756b245cf38abd47a4b10194fddc77f0be5921ed80d39eeb7f34b9d0d7adf575b1f81e8f1c6bec4b53b463e045e2bacd4f263d783c659d5fa2c228cb3cb15bdfb41725db2349b3ff2b4211ce2b3158e0c3a8380abada7d499a474f403dd3d75f99431a9c3b348808ff4a474fb9aa39b6fbbbafe85bc7b01429b9532e07ad01256ea8018b7f0f4f9c1571b86bfc925fe1de5dbb2d97f805ce0eb69079d4a7cf2dcf0401279e091d49bdf561d116f314caa6ea3af47c079cc8cc94432cfa1b3813a73005712ae6eb91f71ed735f39dbf5b60ef0058839e52bfe92b94d0871b55f32d132c11ade6f64323d152c89f0feb72bd202ad6aafe77746de1b3fe8e59e93860321f10e34ef795ec95583917a785a1e9b0eb8f97004f615bb5235955bce5a4759d2f218b537fed347bcee906eed072e2ead100f9dbd82f6cff77895a4012f021851d42cd1bd649b135ea7ef3dba5b673fe11f513f1d5e55cf514c8d4a1125f1071161aa9eeeec25a5a3d684d57b2672f3dc9584fd8ae090722831198e2555c739b20193779350f37872329e9723b795c5f1504a4430f8c1dc7179bdd0d94a59aa816ce5d9ee96ac246433e398cbc5c2338f9adce47166696aa38728c08d3dd01bc1df23063b23262c5ad07fc5ef6f23bad8b73301837aac53bee13bce935aecde3138c9af5bc32df2c09f1d24aa275f22ac44239ab4b5052044e8bcb69644b8a722233446e7242ef814a0aa1aa672f8d61459eaf6251fe8e092bf7a1c7b3105c3c24380aa842a350fb22719e0f92070e0fbafcc97845585dc5e5f83e95b5cb4c7729207b5bc399275612d938f8d17e7319de2010698a7eb286c26f91cbf105164f1edc0d2ecdb45e42803a34e09deee47af1a3754564f7e215d77ad44876029296168d43eb8c5d512aa94ca5ea8114904ef35a4c3850142994a380b7e07283d7d31190873bd4cf92a4d65bbb48171ccbf13b67aaf10eff78ab91a680fa47e348612ae9ed63d724488def59ce75d0e20a50caf8a9b646e0f95c03dfe6b98969467f0122dffaa4b62c2d3e900ba0de391571fae50ee2b1d647c0c29f3b52d3c83f6c1d77b372b1c88a8e82145aa301a82fd047fd9c9b2af83b963105cf90172c1022","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x27e6fca8713c6726033112459e10d773e7f07e04074091a34eb7a8eaf22d6591","dataHashes":["0x011531090261c2af287fb3f766eb58a8a11ec7fb958560efce58f8ec03e24e5d"],"dataParentHash":"0x01354941e62722510ef8c530586b3f4edff05009634df244e6df56f131ff1c13","parentStateRootHash":"0x072c29b2166fcbd110ef1648d38131ac98044e8f53516b2853289f6d615e74df","parentAggregationLastBlockTimestamp":1736794254,"lastFinalizedBlockNumber":31,"finalTimestamp":1736794266,"finalBlockNumber":34,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/35-37-061a9f803c029a06b7b594602ea76d6cf6d9737c25ee5215759ffca6bd3fed3c-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/35-37-061a9f803c029a06b7b594602ea76d6cf6d9737c25ee5215759ffca6bd3fed3c-getZkAggregatedProof.json new file mode 100644 index 000000000..ac12a83c4 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/35-37-061a9f803c029a06b7b594602ea76d6cf6d9737c25ee5215759ffca6bd3fed3c-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8","parentAggregationFinalShnarf":"0xa646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831","aggregatedProof":"0x2ca28db6085342c26fd36420faf5af7e76f4acf70b96594e20c746f1866dd5792c06c96302255c358686cc3588fe5521e74308d5b3f914efa4ca89994631333411dbf4c113cc8e457d6e50db476ae4217eecbe5a5d5b37b88160e9544b68f8720bbf6ce9863b10c804c6f1d142c8a9c254980b0e4a6a957435acc6d48e10f60f28cf5fb85398d402a05bc026f93f6f51d58394e91a6e0b8c45a156d2dc645bc605997c0d93bfcc0489484ac438ff61e8289a84621a578fe1e23bd848c13e9ca018a753947c0dfd887e8b31f32bcb47bd0192e111f5de1c7e5e584db0b2382f3313adb486e06b1f52fbfd3160e47d9a48deb39caeb9694d788bd141c3913b14ef1531238e239313ddb0cdc2ab4209ab8f8ce1c7a2d21c89c74e0a96a00f57863c2e8852f2aa7831dc98cafed6d3bf01595b1b7c4ea2fcd5f1b93f35117a4b25b807fc3a646c03292509f83c84b83d3c9db655c03b9e0e5a7da17efe6ca57e3a0b0a5c5cc8285480d482cb65b82974924e8185d36c205b0d72f2908367b1d6ae7824b8a6311b900b6ef84bae250687838aed4bbda3a0c74f07e4c768c57e40cbe92dce5b863f0b5f484ff6c61ee345229de68cd14b3f624ebf2b6099135b8b15a12cac27d976ddb668d023a1956942abdd38c6d01af2a88cabeefc7ff1c403cfe5021a8f3383d310a0bf62d337ad66dd335a087509104a3599c6c55289f030325812c2b281eb79c62088343d5d2356873a3e20e11597456843e716e5012ee86f1b28c71403cfb7a7b82166bcd5233e52a6141447fabb7dfb2c58241156465e36e40f780c48e21a386417f97963304a81cf40f6cc1b2a9e4a360e2fcd6339cb64cb1c5dbe820e73f284b8cd9b2360d17702b952a304cc44ecd4d1c10b4034bd40ad212193fd4a8df15462c52bcade6231d9ad9fbbd1590891c1f20248762ac6189b05b680e2b70601f851ef92aae1e728eb391311c19a0c63fcee4e01f7ee3aebb508fe09a3736d1bb3abc58405491b0c5ae9f64a76a7cd402ea84d97b3a652c0350258e4254cdb32b7913f60f03eef7816c4b9e35e818672fd81ec648092f58f3e150250fdf14d5ea7619e31081906071eabdbf55400852a11272bf9dd2f407d871ff2e8be8ee31775f9f29fa4f369767eef6ba1f5a4f90fbfa196bc12720838ac031613863116f3b71be0826fe1ce4f38e6d51123750c4513388dda54f922eb07","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x053797ffdd18091275a9f9908330cc33cbc722ea90b8930747d067d10f17e27e","dataHashes":["0x010f6596abf90a103c9558772f56e652de5ea08805763035539bf14bf3c23674"],"dataParentHash":"0x011531090261c2af287fb3f766eb58a8a11ec7fb958560efce58f8ec03e24e5d","parentStateRootHash":"0x10556468275a46e1261bd2af01c421e81af255ab49f932de2b6352de9648727c","parentAggregationLastBlockTimestamp":1736794266,"lastFinalizedBlockNumber":34,"finalTimestamp":1736794279,"finalBlockNumber":37,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/38-40-5239c241ba71475fe11f8a4dfc04addf97c874a9bc2a371bb9cf5bc245e8982c-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/38-40-5239c241ba71475fe11f8a4dfc04addf97c874a9bc2a371bb9cf5bc245e8982c-getZkAggregatedProof.json new file mode 100644 index 000000000..0829d20a0 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/38-40-5239c241ba71475fe11f8a4dfc04addf97c874a9bc2a371bb9cf5bc245e8982c-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xdec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446","parentAggregationFinalShnarf":"0x86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8","aggregatedProof":"0x012978630474a98823d9eb9f165797a0b518d793496de832df09c51778b0509b0c3ba8f4102be732222728aaa2635bd44bbc263d03e9f016faffb8f259ef65062a503a7598dc0205098f1192561aef621c7e79533fb4c24316bf63f6909b18ea098afb81a29b9f3ea20e9a5e8bff2577e2dfa4df140d93078b44ce04cf88cb85178bb1469125eb39e1bcf98d13e272af54ad38ee0665aa8ea561555487ea1b4d099e24a19b7cc9b33319404d2b3067dcc75ed8c9f03a69ddbce4d39dd82699cc07da34d0713745650b39d6d8b8e00a42e6116cff5258db1de3c8cf9f26b535740ecac7087f424bbc7019d0ea5ee84db01da7bee0c9400d571d4b965c44c604cc0aafc7577c97601feb92710c7775a45707171aa7806f0b539e4bc6c26e3e2e7715f85f2a8259d665e2eb2b43235005f131ef2d8bbb3a472e8678cf794ae1ae202d216aae6c5a671037b5ea9e176ddbfcd99b59f0758e367fe3f913b21afa6b971a404e07882eb5de48326e75f3c80c542eb85a44453d42602df8c9d4ebc7f2fa10583da9fa476a4f01bd3753033f09267b2a13ccd28f1baece9467fffd8db9692805238235658f6c563f837082b138df503e60d16de215eba48fd7d3fdf235350f2bfb9b9d2faa3c9cdcb06f93e4f2eb53f51f2824c3f763e1e42c746096099e25539f43171360f9e167b9122c82bf811601db0c94440051c2350cb873179ea017831807a53e02ae2425a93e8712e72c4113505cd8b50d10c44eee0cd73091df16ad876a29ebd477bf64757a1b046a7d559c391ddaf96a328dd7807110425a7826e4f5558284bc6a8b9dc2054132bfa18ed38851d2d66dea6fa3b73b24b64b420013dca57de8130010f05c857b6cfc397ed3ca4bb516d14a5ea373e6c563c9cb276ca6e8e572c5251c2c81d736296892e01516e76bc5e4c21a9927ae180654cd148a6e1ad2dc35b3ac924adc9e3cea6f9e16535704651522dfeaa0b702de4a7e017ae2f22541f57ef77fafd89da642c9b087707d765e81f9ef0f4af9dc3177530e1354f1abc8cb04f2a660d41ed6dea9436e16e8528d52990c067ea88f32afdb1cc9229896b3410bb102ff8032dcdd4b259c6d9da82d8c3e93de3f4b162603b1096a240cb2100f814b30517ccb185ac7a05a7016d3453609677299fc77de209e25fdf7314c6c3e04a0cd92abe0475172944eef0f192a6c51ad06964485daf9f6","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x2de8094ed9b3da7a987ee1e073ed58e77068cf8cb0e37750ad3d0e8fd433efa1","dataHashes":["0x01e5edb2951948f86cc72f924c12e14428625fdd76461f50ffb63b71b0b673f6"],"dataParentHash":"0x010f6596abf90a103c9558772f56e652de5ea08805763035539bf14bf3c23674","parentStateRootHash":"0x038f427f164b4cbd3733505c5853d245d3ae4c25dc69716762f2f7f7df68be1f","parentAggregationLastBlockTimestamp":1736794279,"lastFinalizedBlockNumber":37,"finalTimestamp":1736794291,"finalBlockNumber":40,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/4-6-ef72701818f1320dce22734cac21e65af315dd84dbb57e4ad7ecf32710e3be87-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/4-6-ef72701818f1320dce22734cac21e65af315dd84dbb57e4ad7ecf32710e3be87-getZkAggregatedProof.json new file mode 100644 index 000000000..3e3b92c47 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/4-6-ef72701818f1320dce22734cac21e65af315dd84dbb57e4ad7ecf32710e3be87-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025","parentAggregationFinalShnarf":"0xc185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977","aggregatedProof":"0x19d0580bad76cddfce2897b579eddcc0b8203edb780be7b2f8db5c6d74644705132ae2b20a43f094f626c5213c4a1a11ced30cc296f74a85d32d42096ff473bb08d718ccc85010f9b422f23c89793923d47b0265c01d1b803715d185be7ff83522f0efbec29ff46ffcb72bed8663c0224e2a64e0ccea3ea4c13f9592f2d3fb0e002a17ac7d0b55c99718fa92dae918f914162e2ea45851e9f9e88c2737cee0250ee3c732f2033ae55ef0eb48928ce1adbc6b5a45f69965bcb198b69cb1018e300c66c6b7e5d3a5478a21c6781c8216495c80f3615e4f5fc5d3e37336ef0a98e123aa96727f7d09d983e0565adae02c9b5870c9d3d8a0e91b62e401ae55b5b0781c88bae9a8c091e5fddffedf9a83127b8f39493f2b97793dddacf472599d0e0c1ef12f2934fe72313c75775290728cc6d96493c458936e4b5a07f61b46f4314a051e943f372237476bc8ac7c79b1282a3a39af51f1e4b7fc101844149f46b2c02e005fb1befe07d79fefbcf4b307ec82d229da5b090db06096dffd8fe2bb6122285dc15f3d4ee627144108463a79bff113a58c89fa5f761663c98c1fce79e3402d431c36487c89b7cb0f28b83b71e9dae7cbc88da2d62bbf41f7ea6e44551aa624dc31eadaed177546262e83f00dc26d132518d1486d4c18c4f98d888335f3a42a7c73d14308b055caaf9685b8d4190b1b6092df8bfceddf726b301df5d819290c3416108501ebb13e5ca4d505d57d70392b559930289f4e4a7eed594b51f009250664df85d2f1f56b470fa43c6371294977bd1ce3ae466fe6240f411d8c1a042f51ecdf1f41263ba6a1b2be7695778dff9cff2c286711c196132784172f8bae23237f97758f88f5d33e8cf0c683acdc98f9b964d87072f9141d6c12ae4b48f411fec567799c4cd66c3ead5c1101ba5b0245b2b4e98a2bae57eb94cda11348c3285c9ed2d2d79bc964b4f728bef44b77cd8d0641327fa02f32a9ccbd51ad0ee22759846cb21754127ce418ad002b50888faf98cec40c34bd8fd2eccbd4c2abd70dbba5e33b690e9885698392a14cd5e72441be30acab51ac44a877f17de935d4083226283fb9e2aee207b5b1a20c0cb1f1ae4a6e7925f90d28422b08dc0e7c621490a2d62405477aa6ef529974b0a17eaba14b5376ff024de2f138ce414b7efe064d2fe347808144269af789f722c595aeae47824d8745863218e00d40f9352d","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x10f7aa7664c725eee6b7ae95d93afd41a5907e7689fcef803bedfedad7df8713","dataHashes":["0x01201000a6593e1362c41814298d3cefae56c41fb2726051d0d7638e355b5b15"],"dataParentHash":"0x01f48456f10caa5029fed9b89cc5d2b3853af3a1b76f0deae6ebb5a2dd1e9ea2","parentStateRootHash":"0x12992d60a0ff80d1c2089da74125c185a3bedafb1ff68e26e0cbfcbd9055b1f6","parentAggregationLastBlockTimestamp":1736794040,"lastFinalizedBlockNumber":3,"finalTimestamp":1736794054,"finalBlockNumber":6,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/41-43-c9a80177215ac57e589cf92189846270b286b70bd3845e8ed6f19734f5e0c88c-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/41-43-c9a80177215ac57e589cf92189846270b286b70bd3845e8ed6f19734f5e0c88c-getZkAggregatedProof.json new file mode 100644 index 000000000..3bc8a653b --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/41-43-c9a80177215ac57e589cf92189846270b286b70bd3845e8ed6f19734f5e0c88c-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695","parentAggregationFinalShnarf":"0xdec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446","aggregatedProof":"0x2ec26cbe5e5ac9ca8fd8323c06aafb4f336f70460fc45cce70ff32436dd34f2e129af567eea63ba4290d0620d7f5b7775a261f631dc1877b84f7523285752e712f3e25560852a51fb322a9c2cdff1dd99c674d57439e5c96ac99aaba53eae7e208172a8e99c0f64cb916bb7b6d7e06a92be3a6924e43f30b66673a89543def30297ccd6de4bfd5db27528aab784841e0d742dd0ddeefb4c99622f255fa2aa92b2dbe36b718ffeec0a0498b4fd1dad7a4e425b0cd1fffc1286ead7fde67a78b16246af810973fc135004c256061438e856be47b709b93bc5394848e47c8e68d2c280648e0a642390afb12b0f36fe62d05ea952c6e7e8e0750fc4bfb2af12d3fae0f5cbeb6712f7fff9e4549a595b9841e58ef711e66ccb90321b2beae66feb4f51dc86d10042a1b30e7dc3cdfe3fbf0e22a44026be85a52027d4144c806c8876b14595cb7c9468391a10d3ce68ca33c41764e23d3481aa50a02cea104b7d82b5f218cd1bce8f9148e86582fec9ef799316ea04a2bde1d683646186a1efa10cb3c0b10ef46e9cc38459a3dadbd5431756a3a81095793a9e3169c8e0f75471c39610953713c58406902349b893e8cd680a3a2bfa183892930ea65066f934d31c6990572a0dfb751bc6aaa32061eb9142bed0e12226a9d7e1d0ffd986ae29a3df502045451021cfd8002e2c043418257468c3e1d3d8ff8fbdf553aa688c6feb9365902e5cd8a598ba5771f3853f2162003970c663af3251a971eaeb861fd329127aa0a46e316f196e9511adfe24457ea884ed48997dadbcabea908bbde0c9e1be95a18dfb5b8201b73f7a4373054113afe4ecda6f2d415af070b806f225f060354580755c563f70017dff15fd33f432ca55cca655dba91e6c72ddaef8ec5e6995a691d854f5d682860e4bbc9869bc3fb643af7ce5713d194677f4163169d86b71b2f1ef6c7653adec557a61bb1bacea00f9ed2171f901142f0582cddfc7a4291bd19003fcdee51c107e9c9f566ed4c64383fb3f0bc6aefd55948aa2f3a4b3fa9c86f2d5c73dceefc8ee337e7d1f6be60ed0c368f7251a9e49395e7f608b201f5273c235414acf1af6421cb08a277e2c51c85a285d2cd9e43a4ecbe5585f742658b4d2156b98441eea33d67ac76fbc1111ce2f95d9990e55f4d01e0e8a84c27ba79131fdc5e72cf9e1e7887edbdf5b77da58febb91100b085d107526828563177c0d5","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x1a7c84f1562fff23d3193e5d81f8b0968509da6bd9b6e3af4ef664f3b15b46d5","dataHashes":["0x01ab0956525f99b22c1ecaf9757afba9cc8e88b55e1e56385cb4f8bfeb986e78"],"dataParentHash":"0x01e5edb2951948f86cc72f924c12e14428625fdd76461f50ffb63b71b0b673f6","parentStateRootHash":"0x086b0a16469f68533a059d3dac85f21d2efaaff0da66110093f85b08623b2cbe","parentAggregationLastBlockTimestamp":1736794291,"lastFinalizedBlockNumber":40,"finalTimestamp":1736794303,"finalBlockNumber":43,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/44-46-78d88bad483bfe5a8f9e8fd1d3af3cb034d6248aa279b764b63279b2ba7f0f2c-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/44-46-78d88bad483bfe5a8f9e8fd1d3af3cb034d6248aa279b764b63279b2ba7f0f2c-getZkAggregatedProof.json new file mode 100644 index 000000000..58bbc15e4 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/44-46-78d88bad483bfe5a8f9e8fd1d3af3cb034d6248aa279b764b63279b2ba7f0f2c-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xe3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da","parentAggregationFinalShnarf":"0x67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695","aggregatedProof":"0x1e7f1846e16c463f98d4d25e626bc6254c71ef92704550c762a894e2c8e57c2e2fa530d1e14067cde9b64fa5515de47c88528dfe93c18574991103110580779a1a3c8470218c78d7e0a56049b83cb5be156420dc10eb81414fa69dbedec3418424a081ae820def89970f88beb1e90e2553345a3c9a0a76b8720e28602f2cee940822672b20e3c204eda01a21aae03090f3130a66f10ff01cc524b8cb2c8ced2823c1c9bf3618564e0231b649bf846ee957e8b7a938dba700c5b09c7f8a6ecc430a670dcb8793ec4cb8cd326d2eab2716e333db502b44bc658809b11760279c6512c579f7c7a544d93805726f972092f24024a96294b2dd5c670e3a87d206c43712d27249faf0c2d087feb33a555cd6e1024e0fcf0a947ea7c5190e71d01c7036150994bd5f05d34db23dc3258e1ddac410103fd0045de727cf878008a9da862c2cf5c8c7d9e3b4f43bbb933febbcd83b5791a94c03ec71bdfdf9021ae3a1fdb82dd045afcd8adb4717963499ddac256836ae1f41867f2bb409d1998f7aab38a41af061a3f68c2f3f2bd0f55ccec9cebe5d3a011c71ca37b199b35b8abe4d3a2e3021cdc723f662ffb0aab12ad24c3f8fa9896cdfc495d9bb30fdf7d1d90d4bd505defb134e3eea6975b646890f8b055c198c28a72643b81748305b60a187c86000ff03008c5ddff59d270365aa90fc8bb9ca7d19236058e5fba0f3ed121957980e9918549d2342112e5d97d5811046bfa9dbbaf05961df232f2479701291e99e25bbf8d40bdee3fae594e276b56ae846ff04e505fce0b953622c2dc3edb3915d1ba57594a5e9a6a27ff160c17e0434858106ed030c953a742271e6d40fdf0d4d1b288195e45fc83416e3a64d554309e41654caa70c305f755477c00c2e6419531513e2b7828261ff1c060801af7902bb2c1f01f3b43e5788d7be23e8fa4e708e2d3903d846ac3e4fafb41896a548234f6f97921258a5fe89c1f6a235794f02ba219f6f23be3dbfbdceb63b75a96ed48243e26dade74e45393468931217a684f9180ac99fd093d95e0b906562122a2dfd268df0f7aed59a5aab2b68199e8e86221d970011a9d5d3001a9c57a0e2f2f393a664ae4692cb58fdd63515b910ada28e0a9e46eef84918a99b8b121126c4d527ce032736c87ee8971ede96ddf08b9a571ca25dd8f12356956c42c4ee29dd3b72396f43e0cd542b9ab8d0568d2bc7e96a","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x28aa01349a5542c4ab615233d756d5f472b283718c25619ee4d16bfd1d28267c","dataHashes":["0x0104998034ee589f662c8b801b219074675af50a522d9281f23e4ff8aea8df53"],"dataParentHash":"0x01ab0956525f99b22c1ecaf9757afba9cc8e88b55e1e56385cb4f8bfeb986e78","parentStateRootHash":"0x021f2681f4ce68e3b9f77c934ec0599899cfc96c873e6a9a7450e95c5de230b0","parentAggregationLastBlockTimestamp":1736794303,"lastFinalizedBlockNumber":43,"finalTimestamp":1736794316,"finalBlockNumber":46,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/7-7-aa133bea94f49f4edbfe7488b1a7394ed2559243139ca15097356d8baedc3e65-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/7-7-aa133bea94f49f4edbfe7488b1a7394ed2559243139ca15097356d8baedc3e65-getZkAggregatedProof.json new file mode 100644 index 000000000..010fc59f6 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/7-7-aa133bea94f49f4edbfe7488b1a7394ed2559243139ca15097356d8baedc3e65-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0x7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb","parentAggregationFinalShnarf":"0x513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025","aggregatedProof":"0x11a613fe3ad986ab03b5394279e3f1cc534bcb73b30eec6294d6e2273c2318821dec07cd9696aa5f83602e6dedbc4567b633ddd8d06ea7e9cbd81a6893068169126d7b80cf6100b7a532f3b8b513c5907018d9fb8c78a8fb922db80f775cd98f18796404b4ee522dfb6dea766402233414ee07e92df210bbc49583c37d3edebf2e918835cd42c7567786380fbadb285d24b38934efd46d105e2058c2678b531b0beb69fcc6a27a3b2b78140483b99a7a023caae352978d2b95c11e69f833127c23b5f8759f2be89407a9d15418032888f5729149dad85329175b7668dfa298262cac54185ce62346327840ba35c152950f1ba02e65d1fef63a3fd251de3b2de809498d7276b2f3f6b325d3b19bed24a6f8c23311c03cd42b920d64af7d89c37c25f20ce39ce6f105b8e1acf1720c2da8d11e44259d5af4bc7ca7f67ae2d504271eb705791ab3b2c81fd3499f88e96d2bace4fac1848688c9ee13d6e29db42e2a0329f6a61d57463f8fa89a21ca8e5556fcad6d21faa5bd6ae7791ad68c19d2890712fe045387749d1ded0af89820045050f4ed834ef60a9328e3e83e2e6019ff2dfffc9dc41cc712bda9c63c3f7a159f5f188f78f8141fc63d28ace6eceb575908f97a33911e09084fcd77e43eb0915baecd686f20d9c3bf2f729c82b78ceafa17489e9f4629c8bc1884d0ceb0c9836c7177b2d3e15659c9361864a3f6ca252d1f343af1a624cdc8e8b41df9121daa5ad2ea03d2920238a1effe0e3b883c23bf2ee92490ce86c1af69178580bf348c527e1aa781b46b416d11f493178a6de2c0071a180208b4453f102821425645e6bedef9ad4d5b0e67467e88f395176a85f620090404f882095c4dd15ac14de0af0f932acb5a4a640adadfcae8dfed9c48060cca71cb579ae8c83d88d5497507f8fb45c8d3842ae70aae75d139ed7e56ab7418a78b5d2ecded47173de3b9f544d926fc82bc110eda871a3295d2cc10d2baae1a54d166dd2dc77dfc06560b8958e5fc6698b201af666f28c63283493561e4861af86de533b0f2a7c9f1a2434b8f9b37a1201d62d469dba2c146515fc6023586207013e114a2209a6ac98211d2f7c274eb101cee1030d01f0e79a2ed9b2a37081520d216cf5cf257685aefe502102ed3b1f094b682bbb1f0d88ee65c11da6dcc2b3cdcb97ad0aa0e977c9af5a63d273e631a149c9f77e1575704ab7b1db3adc7","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x282e8b4d938c5c94a2eb2ae013ef129866527de5d42dfeba21262d68fb33d9a7","dataHashes":["0x0122ac92a79da67dca1dce1ee4bdc30c4e945e02664463d0924ae3b1b9c96594"],"dataParentHash":"0x01201000a6593e1362c41814298d3cefae56c41fb2726051d0d7638e355b5b15","parentStateRootHash":"0x0f603fc5fdb46043a8a04bab525d7f4d966ee254608468da2fef80dc27f54ba2","parentAggregationLastBlockTimestamp":1736794054,"lastFinalizedBlockNumber":6,"finalTimestamp":1736794059,"finalBlockNumber":7,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/aggregation/responses/8-10-487dc52c1e22d32a1c38917b99ed120ddffdcb5effa6c5ecca536dedd6d4e2ba-getZkAggregatedProof.json b/testdata/coordinator/prover/v3/aggregation/responses/8-10-487dc52c1e22d32a1c38917b99ed120ddffdcb5effa6c5ecca536dedd6d4e2ba-getZkAggregatedProof.json new file mode 100644 index 000000000..2b5f583f7 --- /dev/null +++ b/testdata/coordinator/prover/v3/aggregation/responses/8-10-487dc52c1e22d32a1c38917b99ed120ddffdcb5effa6c5ecca536dedd6d4e2ba-getZkAggregatedProof.json @@ -0,0 +1 @@ +{"finalShnarf":"0xe6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7","parentAggregationFinalShnarf":"0x7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb","aggregatedProof":"0x185a68aa302796e41348e6933d26d44598ea5c1b7906d27e33f0724b62f60ac6043397e498ac1ef8d4d3cf79babbeef5b2449807f25949a303d3860b3d145a500cbc3af08d31021977b4074a1bb95e0b4393dee5d05ba624be48895544f15a91092857588f49829b66b4409c9779f2035762cccc89297d5d828d5bd3b6cc1c7d0e05f32d108d9287288bf7bdaa735463f6c3ae2a49c97b625bd6acaa821f9ab51d87c37a708aaa5d99b9cd80a08e059ef6b35dccef70ec7bf7d1e71f58beed6323e6f0e9f0d138a5d1d3eaae293c7f31dae2dd5538d597690e78540e9d30409d0b96cc6ea31bb22df01d6617d9bdd950d8f8cd1b99ca24ec3e15353d161fead308280f7f97e486154433e45d58cd9cc54ec13b9e8ab37492c0a22fbec85d631d10e7d1bd36af81d83b98376de046beb56d66cd420a00006f3c8cc35d5972ef0e1d8c64f54a6649fdab2eb15e0d7c506f4f07fe917134eb176a82cce25a6798bd0680cd5d462b6f9f4c255a54b2a4f6d903dd118c417c3a12baf6575bce8bb55e250fea5af78c05f51b860307c6b8188c9898ff9558b1a90073435a59c87d5bf029d35690facdc7e9da735286a8cebb3304388b1fc0d603f294545740168d332815f56bf9166646ca9501298b13e692949b256d1023b33f09e0757c20adbe82de156b3bcaa59bc245176fe7221ff03f065464c573794b12ab2a3be43141f5f45a209c3b1687f0e6d6da1f814bcbbcdc55a797ca7fd53b07a91608d654da8aee0f2dbd1e43b576a473ecbabb4f850ab53ac2b8ee8e40d998946e1edd5cb00b3a4302074c7b78206ee7abfdbb9ae8add9981bd44bcba14dfcd660921e2cdbe4242b0a7f77d2f5a93e5bda5f34c2a80fc38462fbad7ea1eb3a71fbcf9c90e4b874de2cdb0c75fd324523a73aaa6cc46ee8c95fb9a10a75617741eca1951acdf28482136f85727edc36597dc94935a38478161fe015e806ff6a9531e9c62ce2700090034bcfa77046eb8cb36c180f0860c6632a970851560fc081094635b6fe11feb31a9cf746c5f563b50c9bb70ccebafbdb3e6744e5c71e56211598d3cc2ceb70a9142bfd12d18aa1b6e38d5dac8beff40f9b07d2c4264446261592294166a8112929c1aadc708c11f790f59e44a5dfebb7ba5b1d168818e912c055af9fb8ce2a6821039e47e2671790b57e0ff83f40115c0eb404cef98bc2555e28a5cd5bac82e4","aggregatedProverVersion":"3.0.0","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x1e5331b68e9aff6e2e28103da6f0e98b78f911a05e9e7fc75fbede549e5855b9","dataHashes":["0x01c993ae52495203ab88827c3111fcf3b09c16655c392dbdaac614dc00473c32"],"dataParentHash":"0x0122ac92a79da67dca1dce1ee4bdc30c4e945e02664463d0924ae3b1b9c96594","parentStateRootHash":"0x00e974de2acac404377d2d3856a35cc1dee03cb25af603f111442cf8d8b0c700","parentAggregationLastBlockTimestamp":1736794059,"lastFinalizedBlockNumber":7,"finalTimestamp":1736794163,"finalBlockNumber":10,"l1RollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000","l1RollingHashMessageNumber":0,"l2MerkleRoots":[],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x"} diff --git a/testdata/coordinator/prover/v3/compression/responses/1-3-c185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/1-3-c185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977-getZkBlobCompressionProof.json new file mode 100644 index 000000000..45fda0a72 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/1-3-c185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01f48456f10caa5029fed9b89cc5d2b3853af3a1b76f0deae6ebb5a2dd1e9ea2","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAVqgAAQAAAmeFX6RLjQvPt0NjJkTQQPpI+DZRDi6lkY3p7uvxfJ8ygkHqs4bmr7sMhXYreijNgfyzw9D2Dl8NAC+TGHggU5gIAOgyni94CAuTF3/wcENeMQAAAj/gwIa+YgAAHGIAACxWW2IAACb+CAAntVltgAFRhAQAkARg/wEEMyfwGAYTKuwICixIw3msHKNwKkwEDACQQCKTATsBJBAKk/pLc0ujSwtjS9MLE2Mp0QMbe3OjkwsboEDS5kDT/AYA0wIkEAqTN/AYBA0tzOwZA2wMn8BgHkJz4OCG+v8FBDj3+AghxCBFhRiAADr/gMCaVGD/AgQ8R/AGAJC8hIqrAgKMhAqT+/k1wf/LcPlbU0F4mcKXs8xQQ4jLtSskKMGd9nCOgEkxIf4SCHTKFbVlthMHqAYgAA/T/CwQ9ywAhsIMIFuf4QCHromUWIMRYQGEV4BjuRdLoxBYQDWV4BjwdwPBxFhAIpXgGPVR3QfEWEAZP4GAChRhAkTV4Bj4Zb7XRRhCTNXgGP4ZqoTFGEJU/4FBT/4FAOxQYQiZV4BjzFeC9hRhCK/+AwApvclEUYQjf/gcAlvL1vM0RYQC7V/4FAChRhCBtXgGO/PnUFFGEIT1eAY8BymrEFGEIg/4HAMP4DAnRRhB8f+AwDBh5zMUYQf7/gcAamsCXQgRYQE4V4BjrUIv8BFhARL+BgAoUYQeFV4BjrqT3REUYQebV4BjuDfb6RRhB7D+CwDsUYQcpV4BjnzzlWhRgQddV4Bjohf93xRhB3D+BwGGR0UhUEWEBaVf+BQAoUYQGqv4DACve5ARRhBv1XgGOTQKHRFGEHEv4HAMP4DBVhEYQZfV4BjjeSUhxRhBnb+BwBpIkiq3EWECPVeAY2fkATOEWEB8VeAY3Q3ejQRYQHL/gYAKFGEF6FeAY30ejFURGEGHFeAY3/jNdMUYQYx/gcBG/gMA7FGEFXleAY2h6bPgFGEFlFeAY2qQa4AUYQW0/gcBsUjDu8hFhAiJX/gUAChRhBPRXgGNVfqxzFGEFKFeAY1h5RFYUYQVI/gsCdFBhBK1XgGNJHgk2FGEE1P4HAuC8v8V0RYQL+AwGY4uQMMxFhAnn+BgAoUYQQDV4BjOxLsyxRhBFlXgGM8NiFGFEhBI3+CwDsUYQPDV4BjNlaKvhRhA+P+BwFYQZaOZEWEAsVX/gUAKFGEDUVeAYxgqdQYUYQNzV4BjJIqcoxRhA5D/gcAwAf4ADj8mnFGEC4VeAYw9ok8oUYQMW/wYEUxmkACrCBdv8DB7DCBgLCBfhswAjCUSKstsIS5/4ICKdpARRX/BARTmt/4QCKdP4DANAMi/ggA0Q2EDMf4EANNNWWNgsGAgUmAAkIFSYECQIFSB/gUBB/gQA/YQMNVv4FAOkd/ggBvcWEDbP4EAb+xWW2EKDFZbAP4FAXH/+CwCGO/gHAXGELF/4GAQZ/+CwHyu/ggB8/gQB3ZWAg/gQB8YAEAVSQ/gYBxz/4LAcd7+AwOEpL/4DAT4r+BgJHv/gsCR84AD9v4JAH7T+BQLEED/4HBIQRM/gMQtYEABYEBSgGAA/4EBGH8xLv8dAK5kCpKH+DAi8EDDZGQYSmD/gYBVZfOCQUJ/tsxl9CkB7WAq7BYZzB6tKdSHzUiQlKN2FRU+o65kddwgf4GAiZn+CgTsEqP4EAydRWW2EMTf4GAqbn+AgCpwmAB/gUB1YP8IBGG38EAwQJwfwWAjd/8Bg+RVUKMtsIekfwKDRAoB/BQE0GeGlvW4a97WF9JGJWTN4qwLgXwZy/lzKZXfSX73Ldvz/AwE0Cmn8FA6wKh/wQDaCSjzwMApqn8EhGLBMqn8DgGrV/A4T4AiqowICi5/4mCJzvOEAL8FoP4LAa6/+AwrIrg1ZbYRMZ/gYC/wP4KAv9i0wNMLsHzGURxEIxkrSvto0DAM37kyjVZL57ycPQii/4HAL/0/goDzRwUmViACaYPHVMUoi2VEbXlKAxdDJuxtfALXH8f1nQV/gYGOBij+CgW4A/gcAUPf4KDGgZM/ggK9AEZ/g8Mb/gQBCa/4KDSAEX/ggAWgv4KBgeH86Cg43XpAs/ng/YNxiM8iqLE/GbneBeAXnZ+xeNJtv4HAjbb+CgPIBsX+BwuZgAJGC/gQMW/gQB5gIQg/hQFjk5CTFoRSkGQUpAgVGD+AR7/+BgzkHCf4KA4AL+BgoQHHv4LAshjzgcHKBzX+CgjRWvcPJ7IbLfbEQp2mbKt5y8LiBlyfZ9PZBrASZBUF+neBVlv+Aw/4Ha/4DEbixFVlthFWn+BgEyfP4KCJ/4HBUweR/goAUmP4IAcaf+ChEkXhP4GAsrzzgsFQFv4IAndP+CgtJDCn8MsAteu+Y87Mlugs+Vmog+HwTqVEQhU8fprP79Zj+Bg20IB/4KFGQgW/ggSpF+D+AYAfJ/4KDJsxs6Lt0m0sH0vY1zpV0dQYJbQc3+avxDMg9KFDhGA7ov4HAU1v+Cg1oRheUtYr+76icOV9PQlzPSCG1Orehi66CuzxsdLqxbYL+BwIeP/goESmv4HDOgil84KBKJf+CABW7/gsCzyv4IFG6X+DAnxg/wQEgqfwIBxzX/BQfV0ZbC5fnrl1XARW+SIESUnhhBqmRPzGAK3fwAE6HjBCq0tXn8DCQoSP/wULghJd/BAqeMAv8DAD5//BYAPp38EC8IwVfwMAfr/8FgH7d/AgQFQqy2wjIJ/AZSGz/+PgEIGCFn95Zdv/HAbnWKQDCFAyuoP/8BjfP8NizfPEADXBiwot/4ICRAFtgqGAAgmAIgREVYQoiV2EKImEsTtWW/4GAEDNXYQoz/gQAQ/gQcr/gUbxYAAgVGEKS4FgRpG/gMbeVIL+BAjhhCpVXgWBAUX8YZZZU/h0Y2YAQBGEKjJGQYS1qVlv+CCviB/gYCEp1dhCqf+BQISmgFRgAGQkhsZkJEWkFX+BwCDIV2EKyP4EApX/QcdK4XexEiUDW1QdLw4lcNsJsJ2579hwOUjUSkM99lozW/4fFe/4GLCWi/gMEK/iALrYQtB/gYD1AReAVJCDkFVgQIBRgv4DIEeBAYWQUjORf22AQAF+VqbZG7JC3vFK9dfq4er+AAfQdHXkXGeNrF1J01SYkf4KAcf4DBfQCC/g4fbYQul/gYAYwuvg4NhGlNWW/4EAKf4UAxYEWMxRhDD/+FDJAv/gUMkEFjY2Vzc0P+AzIdvbDogY2FuIG9ubHkgcmVub3VuSNl/gQyQfyByb2xlcyBmb3Igc2Vs/xEGsH/wOZTMIVGH8BjyyTBQTCNo6st/wIBhALCGLECwjgErLf8QDL7CGQF/AoKAwAENIAbCGXv8BmpT+yI2ZOfxAEY/wSaQMkMIgqwhn3/AgB0di6Iafw+AdQIDDyCkwEn8CgXbAAQcgBsCGm38CAHptSXcp/FIDx/AYwnAMIajMADEMJbtKy2KMIGyauwhqswAMP/AgAf/AYX5pzzr8/xCBHyMhIqTASQIAwUgpMCJ/A4EvAwKl/Aw6WgQJAqSEAtxMCICrCHFavFEVBQMCIMIbgK7CG4DCW9qstyCgwEAEAmsioMAAwf4EAlRGwYACE/g4OfA2EOG1f+BQlyw/ggJckFVhDg2Dg/4BRzj+BQnGQ/wQEqmBwxCMJcOKy3JqC2whxJA/wIAFyCIMIbTKy2oQ0GKMIc3q/8UgbkRIfwIBtwn8EgbcDDCjAh1l/AgLi6q9MFfxMDXwIDB/wSCPfwGC9wYowh54rsIAjH8Bhu4BB/wSCXSEDIEEHIKqi/zMr9ntBhbyAJeVwKFt+FOc6g6uO5ZBcaF6cMQ1CFvj1yDCHg0hGSEZIMJcon8ECPNCwICjBSEJIP8zbLSGA2cYE/bUvk4KWufQbldzR7O86zxf9FINs2Zz1kgwAEhRrah/BAAB/AZSwoMI4iCstwsPCQkOwAC1IKDCHsjABMI5O/wGgaMIe6x8fHx8YR8ewjpf/AgKgHwECwjsUrLccwgIqwAH+DAlsP+FA9jzwQEtq/woAM/4KCW52AAgI/+FQB6OjY3+Ay5IP7ZKRkBhLqb+A0L3+Ay9uDA4GFh1rxklBQUD2AYACBFGEQKv4A0MeRUGAfGWA/PQEWgv4DL/D2CUj1gAGAghAE+YRD+AMlkYJFQW1CRUJFQgWEQmVeAURVhEElXgFGAgmAgAf1G4/+AxfBUYTRD/iUXw/hQDqkf4HFipD+AxVcVgFR//wfAL2Qsxg63miov/AYr6owcg/0mQT84z0iPR4ycnmbcC2ogXhHhIgwJpoF0cHIW/+VWHfwGDb0SgoQwrIKDCJGOrwrAAQkgBsIjBq8KdisAKsIjAq50tMIiPMNcaQzCXUsrLbCIlEjIfwIHwsIiZfwGCiZKstyKhAxAiKsIi+q/zCgNdDizCEfjCIsEJF/wOIEwIrISQFI/wGHqwMLERHjCf8CBGzCIwKstw/8BgqK2wAH8KA+8ILCrCI06vBsIjUKstmf8Bh9AB/CoRB/AYDhCSECKgUh/AZoV/BAPF/A4A1SChAMIkZ/wIJyUr4m+n8Om438KBQMGLfwKlr/wMKbKgoKH8DBfTCJI7AAsFiqqy3/BIYR/EBPiwiT3/A4vxADAAITBMqggKsIlRK7BLqjCJS8ghfwIC8MEyqqDAAsIhWistsE0qQv8BgENorwkkoMADIqC2wTELIKsBAMIlhKOoQK2KsIlmq7BNQcgqrf8BjwUNAqUGKirAQQQCpQQqIsDBgKlIKJnIv94e4GWuCuKOQJiyKGogJEHF2jxcwEog+gOOzUDefT5ZEjIQMgBsDAAyFF/Aweh/BafTAQAqwiGcq6h/AacgA/wIc2CC3AMImpq6gYfwIEbian/AoA3/AELAAIotsIni/wooLF38QKCzC2OTKw/wKPCsjyQNP8DgBQysgB/Do8KwAH8HBlX+JgmDAWYAEXkFWAFWEUI1f+CIAwAP4CCVwEAF5BVW2EUK2Ed8FZbYRQz/gYAHO/4GAA9FiophHm/+AwBlNYR/F/gMAhWYWFhYVhIEr+FiKSIBZhFKb+BB2+Feb7/GQLsL/CI7eKWLAARP8CEgLCKXcPA7CRff8CENoCLKv8XCE7KteYg9IAAwgIv/AYIUHnn8QwIV/AgjAwAP8XKt/8GDEAq5sAH/Agwd/CwfawiuB/GQCMmkGIirCK/X8CEYdgdtJl/FZGGLqkBCCAqwixx/AhCAuZfKCf8VEvQBAMIsiwf8Ckd0ioMIsowxp/AopQAi0AKkjJKDAASMhBMIszwf8CkIUiqqEgoMIs/sIs9QkJ/AKKtklf/Ag40LSBnFQ0NDRkZ/Aw41ARP8Kjdhn/Co4GP/QrYVxep1gBPnGXdXrK4Q2FtaMiWZNy297AUOfG25cNkPDw/8Cjg4t8SspJ/wIOFcH8ED+NJ/AgplIIMhDyEBwMD/B44uLoX8PDi4uj/wOOL/wIKzB55/EwrMg/wYKoH8QJP7CL138DimTBNQP8CBRZnIv91EYBLYZdu4EWBiQPfd5J7rPjyXxeo0QLeIT53DOF1U0jRfwIJjfwMamC/iK7CL+n8DGpn8BmpciNiwqKyUj/Cxj0MEH8FmPX8Bl8AwU/8EHDowgK7CMIH8FHDowoq7CMKP8KHDow0/wMaTgw5fwKcOirCMVf8CnD2BTjax/FRw9/AxwqMXquwjF7/AacKyEiL/wQcKDG6rsIxu/wKcKKafDzX6gVdpxz8cNuPRi18mRxqQ7OetHR7cSs6rpqKsmbCFdf8CM6jABSH8EIvaKsIyTfwMLoQEGLfwGL2MIzMf0iLpAAALMH8BDzYj/wKLTMIzp/wMKLsIzv/wQLC/xWJu/wAhIwQt/Gom+rC2wjShAmbCSkqst/wWdkfwKnGwf8KpxsKLQilISP8DIcWwhiSr/xcAbfxQN4sI10mch/Cx5oLfwsSowb+Xw8QCL8/fwAjSDsF0k3Y8pIDovjwBJSgThKAYIqBTmbK3hvPAZLV/AwiEofxqB5iv8VgekBCqUkpQEH/EgHrIKqiZwlCyL/7HI+uGWzjTpUj9TOFohS6Wpya6Pbj/rJ1kPAjxQci43I/wKBdMI4FwP8DBzA0oK8B/GQcwwATBYqgGwjJLfwo6Gj/8CoPikysv8BhircxvKO6sLkyHRA5fwMAIMoQMbC2NgB/AjoawMn8DBfoF/AhSqwUyp/AyQUOWSuwg5ZfwKlHgMgNwIsKsI54/xoIisAFA/wMC9AP8ZgdX8BJqDEQKlD/wIUwQzAgQQCpQrAwQQCpQjBAfwGB24DBQc8BlPLBgfwGB9EEGDMABAirCOt6vAsBAByCgtwkMwcECgJvISYCwcADIEExL/wScg/wIf7fwQfRKjAAijCO6v8AiE3MlsPh/xChswX8FobMh/BZ/aBSH8Bgpf8Cl1H8FM2Awjzb/CgNgV/xAJqNze6EH8CvXz//A4ny0t3+KgoxC/gwTU/g4B+7P5uAfoFgAANhHyb+BEe+17Vo7/ikllgD+BADlg/gRIp0Q1yu/4qJJ5eCkFVgmIGQVWEfdIL+Bwzc/gMfDl1RgmFT+A1DSSg/4DCKf4ESCf4FSD3+PgFwxytmJAeSWAQYtzKMDFVK4jXwkyR1xRsCaIf+AChwmqZAYGD+CimP+DQdQgQv5uB1GEebWElxf4OAhMf+bgllgABbg/4DTIyHdV4SE/gRMjIORXYSDk/gdMjQAIBYCABNT+AyMOHh4X+A00MhBFdhIQT+BE0NhIRqSYCBgQJCSAgBkIEBkVD+BHa3+BVwghK1dhISv+ClwghPFdhITz+CFwI/gZPBQP4DTalX+BgHohX1dhIV/+DgHqFhYP+BAHZ7RdhIXv+BgHaR/hkB2oldhIaL+BRO9AUX8zqo/RzknhdIbyNJ/1TQUv+/EXWkP7tDOVQGdfTrsYJH+BEo+AYSHUf4FTsJFQUGEgylZbUGAAW4H+A1Doi9FeCgv4FAm/tXSEh+/4PBFqhgAIWF/gQEWIhtXYSIb/gUEWIjH+GARYiEJXYSJC/gpgfIlNXYSJT/hUEW/gYB6InZXYSJ2/g4GQYOD/gQEWIpJXYSKS/gYB2qP4ZAdrlXYSK5/ggEW579C43AwXpS3J5SMjo6thyyB52zX5aRJbH4o9mExvbC/gYBFiLs/gkEWIeFWW/4RP4WEjeP5xCsP4EBmQuvV2AA/gGBBCOXV2Ejl/4FCkiOt/g4KSL0L+FyMMDYSP6/jI45z4GCECQMV2EkDP4PDJwCAGwNhJFH+BFxoHQtBT/io5WCSd/gYHTJGZXYSRm/g4BZhISE/gQB1gldhJIL+BQ30kJj+EgOr+BGO2AYSSn/gkLRI3tWW4D+BCKT+BkjQk1PyBEjQkzP4JSNGEk5P4ESMWEk4ZCC/gRJJkP4DSL1T+ANrTJSD+BAM6nTBxf/io7nmlX+OCtFhJWWBYSb+AwMwkXCDYCBhJmH+BYK0gAWElgf4DVky9fVv4ESs/4fKyeCAYQDAYFSkIKQUv4GJXoJS/gMiT/gMiaKYP+DR9Qd6f5LwslgYQoG/hdQ3FFtgYGAAYSZwg2AC/gRU9YSZ7kGAAv4ET42f+CGroRFWEmk1dhJpNhL/4FPmpCAglKAYB8BSAfGRZgIAH+BFo+AFWEmvVf+A09iBgDaDNwGQUFtQkFAf/8fAcMsCwAECowIgwk3orsJN6fwIL3sBAAgMg/fw8GHoyLSECwAA1IKag/vH8QAMQD/AgDETq6uwk6v/GYDBMAAwk8nCfwOCRE89IMAD/BAV4A/wG7HlB2rv5gYmRmGhqbG5wcsLExsjL/CDczCsAeLMAh/AYEPvq7CT7/8CAEONMHwNwUF/AoE76q7CT+v8aAToJKSEoOSbCUGkCwmAH/wI0Hk9CrLahBirCURX8JF+cDIKX8CuOCm6OTS3M7JnRA0MrwQNjK3M7o0EDS3ObqzMzSxtLK3On8GF+cnJc8DKu7AQQUIBiQqwlFH/AsZxAmv8QPl8CLQIp/AgEX/gKCwVf4IAQeX+Bo3o1kZD+DQFr+AE2H+BwFpgCYEQ/gIAOf4WdWIEU/gMR0/gYBbgGBAg4X+AwJ4pQv4FAXIL8gNt8IIMBNWEpVIFhKQ1WW4CRUFCSUJKQUP4JIlyl6VyBgQFRg/4EMFQFhKWL+A1zJgAJEBUv4DCK4FSYACCUYA/gNlrUmEpooFgQIUBYCCHAWEp/gMQgHwH+IBB8WkZA/gN5NAf4HRzoD+BF1tggIaI/gQCp7P4FBBoU1/ggNygCCERVhKgT+BgQWIAZFQiGAfgwESYSoY/gcEZgf4DgBMq/gaH/iWAggmAFG4UBAf4DANzz+BgWggkoMBmpCZUIRiAE1l2BAgQE1l1BgYAE1lVCQk/4HXRYCDYB+E/gMBSHH+BgYuBNf4MD+CqJ/gcBMgwGRUINgIIL+BgGSh/gUBu/4IBSID+CQALgiYv+AwiAqxP4FB3og1YSrP/gUF6kdQYCCJATVhKt/+BQYqWUGBAif4DAkGBgiQE1lFBggPyBAB39/gUGok1BgoIkB/g0CPKxn+BQjNhKyWLgowBYSKX1ZbmZyYm1CWmZWYlJeUlWDAATWU/hADeK1D+FQN4o2j+DwN5gBhv+DQOH+DANoAYMCKjP4DC/Sv+BgB2JNZgUGAgiv4EBWkCKATVhK7r+CANpgigH+DgdIr1/4HAveDjYOOAWErPlZbkJhQllBggIz+A3iX+BQCT8/gYDiLAg/gkAkllCUUGCg/gkAkLCH+B5rYsLoyCjf4FAJZFQgJDUFD+BAt+VmP4HAA/4ICcGCFh/4DDtyz+Bo/+ENWEsZL+CAWgghQE1klD+Awtn+DQf8sif4HAjJWHgoj+BQW/8gMFoUJVQUFD+DAfhgh4n+BAF66/gUPUhv4OCzSzS/gTA1d6Kg4v+CwPogif4JA1ff+Bgd0tA/4JAJP4EA+kD+AkAkLRz+B57EtKYmCiv4FAJZealplQlJdQkpWTlP4FEKl/Tkh7cf8dBr6ykwEP+EAtGX+A4hhgCYMQYS2lV/4jgDr+A5rP+JgG//CQWmrAwIH/AgeEFAyuwhQMwltX/EMAgmX8EgWIB/D6bF/AKhkBsJcmq7CXJv8CAL6gwAIDIH8CiaED/AjcCwAD+D/w8nS/wGxfl38DWCf8BiMUBC/wBhEZv/Awmh/AwwpAwcEb/wGKWyECpfwILkwEEAwEF/AaBtwEEBQIrBQQJCCgv/BYHlCwKlCfwIBFQf8CI1bBAH8CI1kD/AiNZAwbBQQYCbsABAwYCwUEh/A0MYPyEl/BEK4AID/BIgH/A41gXqn8DjKrCURX8CjBX8HxubCxsbHurc6EH8Fs5oBBqLCXy8CwC/8Bi+kR/Aovo//wGsdto0ubm0tzP/AkcgQfweD1i8jCAMj/AYGuosJfqQLAUQnzBIB4AsBR/BAE7/EgRog/wUD5QLCYDyuwmA9/AoOh/EAEAAMh/hYLc4N5GIr8aFZOVJYFLDFw8z/gBrHkBhTEwwzwfO087+AGtInlc6Nyv8HBbnAmAGeB/CuM8EecECnCAwAdBhB0ewEBchHH/A+M8wgAh/A9aOADRmwgA+rLbCADf/Aq5QwALAAsFANgcHAi38DgBQzBi0CLwn8BslMjIEkLSUHIv8XwA84piyyKCaJmj+hSeUIMpL/LkVHtV/HSgw3tbIr8EjIUf8CQ5AQywDCAP38IYj4A9/wRiPyxGwE6IsIAnK/8CgBQowgJWrwDHM1EdiCjCAnyvAMfl+8cUijCA/wHfD+dvvVoowgL9/A91QQJw49CjCAQCvAMbioAxTCjCAZKvAMb9/ABG6TrwowgHB/AeA1S5a2KMICAfwFXXwBGfwQB80DCATf8B3XwMEfwHCQzyt/E82p/At2kAGr/BAKFvMIEq/wPdGAHZ/BQAsAff8CAL5YrLbCBfwNRV4CGf4OC51gBU/haCBAKD+AwY7eYQE5/gQCdlP4DAPH3/gYA9Sv4KAXQFZ/ggBdA4z+BgF1q/gsAfef4IA3QM6P4GAfYr+CgP0Bmf4IA/QSk/gaBC/haMc/gO6NAeqQT9cYNob/iB1PkP4LjHFr6kf4IjGgIl/h6MaAir+DYxoAjn+BsJOA/gOLHUYEBkGECTZGQYQeIVlv+BxDJhAl1gQT+A31ECZ2AAYQVx/gNUZYQJx/gQAT/gM9xjyg5cP4woaeCgRZgBIMBUoMWkGP+AwEKQYCQB/gkDWYACHgP4EIuUC2/4GLFVrx/gQAO71c9YACAPj3/BAXYV/A8mcBf4AhDY3+BwI1PHvKG/jICNhBaQY/4DAOpA0kGEDVZCGkCGkP4DXSgel/gsFqiP4FAkgNu/gwCSA4L+EAJL+BATYA5T+CAJQ2Wc/m/j4Ei/gMBC/gMEiYQLB/gO2q8P4EAUv+FqVthBP4EcAH8Iw3mg/h5+c/gZj2Jv4Fpc093bv4BXBRuZXcgb3duZXL+A3BV0aGUgemVybyD+B3BpkcmVzHP+Gh9n+Bthr+CayJhBKGB/gQI5UP4lDBfhRpED+JQwF/hYPiMxRhAmf+LAQP+CDgb+CAQP+A2ehlcv4HYQf4AwQT+BARH+CGfoEj/4FFz/4VkhYEW/iCYO/jcX0/hk3OASh/g85UBhr+CB+UGJYFhBeb+Cjrr+CDhwGP/4HOHEhBkr+BQCT+BziUGWv4FAD/4KOJf4wHpP4DN3GCEhv4BAI6p/gU7jgzVhBrT+BQFmSUP4DEmjVhBsT+CAHlAhPODzCkG4f4GPAoYBkVCG/gU38BvX+DDfwHB1dhBwdhBkl/gVK2H4L+ISReQgRZgPwEWgQGQg4IRgYMQFxVhB01R2EHTf4EARYFgQFKCgVKJYCCEh/4EOSQdm/gcn4IIYBGAg/gQmMYCCEgwEBUoCV/gWlekv4DAAf4LQFgea/gY8u1H+CAX/+FprX+Az1b+A19eBhP4DJJoD+AzHtS/gdVxwfvV4WBAYMBUYWCAWBgAVKCAWEH0/4EXMWBggoYBAVCYGD+ICgT+AwTQWhQEB/gOlJ/gVC9/gokKaIq13Y2VIhVbqMhpLTvNe3QKIwZJ024v0BXyLYdnkOH/gskKAAFh4VfqYGCO/UjyHc8hFp6HNJrphElK+mEurO2TWF9nHHGNkdMf4VJMBbAggU5AoAOgxTktYCAuRaw/gUiyQFFiAAQ8DgDgP4DABoM5gQFgQIGQUv4D6zpFiAAQkVluCgWCAAA2goJgAGIAAE1W/gTr0RJBQgmIAAH/+BJ89iAAVXP4E7AFiDYgAA8f4EuoFER/gPo8ZldQgFv+A+y96V2IAAB4g4NiAAEzVltQ/gW6df35kTXlCLxfAHkiUtfT1iNDMev6KGU9Qq6DLcWeOMl5j2IAAMFgAIBRYCBiABCpgzJgVGRUv4IJwhaQ/gVUS/gcAPkv4DBxpGEFv4DDO1L+AiVYYgAA7oFiAAFi/gQT/YgAA/IFiAAIA/gUKn/gYBJgIWkH+8fNdaIO4n/ZreurMgQfdVIU28a/4ASSKkMwCJGznaLlwtO/4FqD/4DUw2IAAVuDg/4E2+mD+Bdvon/gQ4E2IAEMlgJ5E5YgACl/4JSo/4GArIEWYgABzf4Ue9fyBhf5FUkMxOTY3/gUX+YWRtaW7+Ehf5l/gUX+YNAb/hBF54D+DwSlb/gkruGf4IK7ZKQkhaR/gSME/gwCdO2IAAJv/hR+ULf4SAnmltcGxlbWVudGF0aW/+BAKdu/gQWSWwb3QgYSBjb250cmFjdYJr+CAKViAAHEVluAfzYIlKBO6GjIQZnyChJLbmNyj4gdsw3Nakgo8pQXTgrvGIAAcfVv4EWCICF/ggHnhf4ECogK2kZBiAAUE/gwl+9P4IJT5iAALz/h0l/YgAC+P4Hlg5CSUJBQYgADDIaDg4diAADFlZblpX+CH15ggxViAAOKV4JRYAADYgADglf+BwIuERY7/gUAP/hKC9Hf4GxOv4FHof4FGwiB0byBub24t/gTj5wAA/giC9/gUESUIFiAAOW/gP49A5b+Awx0Dnv4JJPuBUf4DAhq9XgVGAg/4EtOID+DAHYE/gQBC/gQEUIlYW/4JDB/4DGjGIA/gfsh/gRTO/wsGJmfwWMOfwI6EsQAAg3/BajkxAAIA/wWo5/wUMhMQACHX8Cqk7EAAiLCMQAAeX/AYyGxAAIq/wGja/wKAH/wGjcKMhJKH8CA36ANgH/AYyGxAAI5/wgMiMQACRH8Di0EDA/wIASTqv/AYAIwQAB9H8EDJDAPjP8IjFTEAAmR/AYBVkfwKAVfweMWsQAAnF/BAFP6wf8Bjpv8BneTEAAf8AUl6st/wgMXQSixAACjEDCfwGqj/wKARfwGqR/wMqQfwYq4sQACof8EKuXzAoCb/AzD1/BiqqwhaFAMQACs/8FnDJswgAmrsIAIsIAC/8BmpjCACK2wgA+wgVD/C7dWZgbCBS6uwMH8QLaLAABqLP+TTGA1/Di3sAsIBMK7CASLCBcP8CUwoFHqy2/xhwhr1/HmwjBCwCwgHT/AgCuBnCstv7hr40h/IACgAnF/AoCg/Ky2/g9ct4H8ggKEX/AoFDXqy2/0c+S8v8ggUDufwKB5fist/xaX1IX8C6ryo5MLc5uDC5Mrc6KrgzuQwsjL/AZXqoOTe8PJ1/AYv3/Auq80t38B6vH8BxoLMwLY2MTCxtf8BiJzh/AYBKQOjC5M/8CF9T+y/48CuaGCEP4DTXaT+CjBCBUf4DKXvNbYQKfYQQQ/gWNrf7UxJ2hClaLMXOuE7n4pgFuJD5jtujuEXjWpxeFC11hA1v+Fi+M/gVkuYGEC62EEIP4EywAL6NmAEgYRhCNdWW/4DO0wMB5GQYQkq/gTQcAySB/gT4zIP4F+M/4D+DWAAYQQr/gQEb/4DHyyCBAf4DTWQCBUpD+BhgdhA0r+DgE9X/gMBPHT+A4LuRUGEDZ4KCYAH+BAEL+DwFn+A8rb+BAEVhA4g/gcCcA5f+DgJyk/gwCcYQRX/gUAwuf4IAMMP+BA6P+AMho/hfDx/gNS+kZJQAf4EdsIGDAwOBUpBgQFKR/gcBPQQG/goBMBLtW/gUF4G/4FACgTKVls0FWEC/gb/FYQQNINhBO7+ByUJhBEH+BCUFhBFJXYQRQg4NhBTv+KST5gQSA/h0C8/hUkyYQS4gWEFZ/4GOMGEExWEGc/4DcYJBFls2YACAN2AAgDZgAIRa9P4EPef4Dw8QTp/gM+F81v8gQ+FYQT3gWEGm/4ZScP4tJbmEFYP4TJbWEK5v4DJbGBB2b+CHA/+Fz5AGCv41PkP4kJkf4oPkGEChv4DJAf4gA2f+I9Mr+FQcz+DCdkA/iAlrYQLF/hjogO2EHP/4uBMT+Kyid/b3QgYSD+CiRT+HgTT+IAMoGLf4HKNf4V2/vyAykJhB5CRkGEKeP4WKQGEHy/4eTvwfQ/gtO/YQfh/gDKPGEH6/4PKO2EIgf4FKOmEIelf+Fq6U7/gMAb/i0KUf4uKX/4EBOlCBYQiL/gNapi4ODYQiT/gwpbYQij/g0iWv4jAiwT+AwFf+AwUaU/gRdPhYURFWEI5/4GQV/4D7GII/wcCEcqEEAycjISQHI/wGzCGv8MomwSS/wUVUfwQonYT/AzxywgrBBMISA/xoh8/wMiwhMP/Awq2EyEH/AgAlfwMiv/wahyhNb/Az/RCgMioQv8CocoTg/wYhyhOmK7CE6bCEov8eIcoUMq7CFDP8CAIv8DIcsR/BCHKFGX8EaHL/BcBcFN/8GQFwUr/wYXdQSiwhUV/ApWywhSp/DCVsMIVZ/wTAlBSp/GUCV/AGkR/BAUu2N7uWtjK7MrYQDIytjKzsLoy/wKFVMzC0tjKyfwS0A9uPf0vvLz2hgQIzpR/RTyyTeUeCphed+01kjt9UUQWRfwUh7fw+ROfxMAPf+GBP6aUCfrYjK/aiV5B+e0A70CU+NH+DJB81peQ9D0xlbScv+eM2UQRXqouCf8+Am6QKSND03/46DQ7QFRgD/HwfkD/hgQNfn9blGq2I9vTOariCcnnP/wEHiYETNz56DEYf8hBt9n+VhCqb+EwJ//HwIoX/D4G//j4EbA/hPBH/8fAg1v8Pgr/8P9Wf8Pgz/8P64H8Pg7/+PgRa3+E8If/x8COffw+Ev/4+BFFf4fCn/8fAk7f+GBGGIuMI/CWS3HhgSbfRpwhsNe8uGzP8fAhFn+fBCwoB/isKf/xMApW38Vgz/8JgT/8Vgz/8Zgb/8Vhn/8Jgb/8Vg//8Jgs//FYP//CAl5/Ai37cVViKoGdc2IYyPuN9d35259lxDQlIjUaz8hDr5JFR2irfwrAXAk5BApyBwAdBgkk0QEBcIJGMII+MIAIMAAcsII+fwGjTMIADsIIpKy2x0bx/ACI3n0CKMIAL/wMbJAA+wgBb/AcCGTsIBJKy2oMII9qy2wf+Agx95DJf4D/sv4DYOoBgBINgAGBVWvGA/gN/s/giFqwSE/gQAV8v4D58QBm/gwAXVVr0/gQAVfP4GaNASCAGRUGcSNFZ4/gMADglP+BflkgYCBgAWAfYAJj/gNIF+j+A2HMAYABC9f4GACPD+BgBD+BQBak/gkAMo/4HAF6LPgUAxof4DANqBYUFlQWlBCYABVYABUUGAAQFBBUEJQQNQRFBFUEZQR1BIUP4UcWD/+BgHY+/gUAG/hRx8PD3+BUA7O/4EUBgFgAQJgAwNgAQRgAQVgAQZgAQf+AwBYI/IDAGwlgAgFgAwpgAQtgCBBgChFgARJgARNgARQVYAH8gPeWYAEYGWAWGmABG2ABHGABHf4EAjCD+BKuH+BPTQxjX+AwBA3OP4E7noEB/gMAdgzk6/gMAZYH5QYX4BUGJPgEjUGN+ASNFUGT+AwAVnUGX+BAAaJUGb+BQAerUGf8gYAIzVBo/gcAJ71Bp/ggAKAVBq/gkALI1Br/goAMRVAbP4LADWdQbf4MADolQbv4NAD6tQb/4OAEM1QcP4PAEHvUHH+EABIBUHL+EQBMjUHP+EgBRFUHT+EwBVnUHX+EQAWiVB2/hUAXq1B3/hYAYzVB4/hcAZ71B5/hgAaAVByv4ZAGyNQe/4aAHEVQfP4bAHWdQff4cAHolQ/h0Aeq8NUH/+HgCDvgIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXkiZmpucnZ6fUP4PAAP4D8LnwB/h5W6BP4ERV8A/wAAAA==","commitment":"0xaa3634bf5a1ab3a4401cdf9461ba8d1c84a1913dec335e4e418aa51cf9e26d29b381d21a3073a89d6b11801a44e888ef","kzgProofContract":"0x97a6a81752725f5d99f018e9009f3a1e00802dc64acc586666c2c12333146b1d4fbcc030baf6f737c461a6e4a2b1a8f2","kzgProofSidecar":"0x8a8fba0fc862d02ecc0d883c51e74b1d215484e61904cedaa0c66d932c5aa07b5c6b938556a6f318645373f090ef8312","expectedX":"0x1549de5963f8c2b408a475ffa96ffc45ef0068f84b2f886fa88c1b421a2919ca","expectedY":"0x1c89bb91b772e4af1180a6b6b4d217f5305467af6729fe4e97e7a37ecd130068","snarkHash":"0x06b99868a5c7e80837668b54a265a6ae43a7877180af885453cd14180838ccb8","conflationOrder":{"startingBlockNumber":1,"upperBoundaries":[3]},"parentStateRootHash":"0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd","finalStateRootHash":"0x12992d60a0ff80d1c2089da74125c185a3bedafb1ff68e26e0cbfcbd9055b1f6","parentDataHash":"0x0000000000000000000000000000000000000000000000000000000000000000","expectedShnarf":"0xc185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977","prevShnarf":"0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x000fed46812c635ab46cd5d8ba7022612755b2f660ebfe6efe0a34b329431365c94c5d1815ba2e551296952e3bd0e9ca009e2fe1a31ad6bce23e0644d53dfa9120870a86480ea1d86472a74ff971b564e37fa3d47ff995eee73135d81266cc84010662ceca7b4939b740951e44fda074ec818aa2bac1c5bf620ab15d6993d1446bdcaa92e39a308db3350a851839f5420138eccc039c1747df5ee60c12482958d1d3dcd6964bba08229a259e813eb2b8847aa885c8f8ae690fa7bff4517bdd9f012194e6499584bedcb9588d3722ce6f009b49aa82c857cfaaab0455c949a1b4ad434daab555cc2e7ea2fdf2dfa2e4d90176edc3330c412dbabdc275cb31114a17f50ee20ceafa87e9a40c139d7879b40d01588eda1d0870f73b4af594bbc33601810748aa346dc5fd9b255c0e3a76e7847ece5f8c723e7b4271a77a94ba0441fd6c76bfe9e968dccf5209ce44e6291b00f692a4cf30a5c6095965406aeaf2fec15befc02f77757c57b2357a12830dbd7ab076333c5791d066d2eed92fcb287100271e5a429ff8627e4c14e3fcba6da41159742b80c0339fc083114da5d5e5b7b589e6c1281f60e0abcf65f2fce9975c011503bd7e78b99e1271d1364345d038a168f428defb6715ee4a9230e2a2b6d05b771a3ddbe75ff0fe3b2941b1d31fdb00609b959f0b5c935551f4b45fdf1acc122473fc974f406b9e2529241cf1aae5e68a117c8687a70c77225e2ea251b1ed002f27d5360c4df2c88c99aef43e871445e8e3b69788cff30368ec1d0e5848468661b8d98320e6458ddbfebe1192804f0197c3d24eaa3f90ffb300f03f52d303328ea4b434c4650b840a0e583362ae5067340571966d37ef642d71d87a27cfb600dcbf2caffeebff2da46c76c2b4efd47ba89b45667872b1da863106c7eb242d49138374c1b952d6ad5092199a07da40004d24bf57d3d66312dd0491e66b6f980babd362bf90e4c37537f41b5678561166d6b8a314b4ed7e075f599ef1d0f3e6014cc433cfdfcc6534f2a7ab6bae22ac05ebaeee94c6033ae6734e4ec0e2a8298183ef71f5a6ca63757771660e5c0a44000000070ef9d319e191e85c9528ea6c162a38eb2ab6eafd354e9f08eb184fbfa22bc95f0c8cb237da03b3aa90785c43f8f5c6b60db4b1708e7b1921cf09fe0e86dc313e08c09acd09655f07a871df021b50bdc9552c1c48525c4155ea4635ac6c0197700bc2c60516e7693bdc2531c31165ad5ad181ac2e6f97f94fe80b2d6a2dd25cde0e721f1f6fd3769ef41546453780ffcbce1a1bf19f2207cc2842cacbc6f6a8dc030a24f823997e7fd0a7d94172010df2840145c648453dfe9aa521be7fbf1e1f040664f432d2e5655c0c146bab5957036de9a8deebd532ac8c04bc01a1f1a4ce00c4a01f540cc69ef958a5bede01fbebd1437b8b7f8c29c1ed947db0ec11b06e4bab3bf822798e1a0df6dd70d1e6742b003227d4edad4edde93c96fbd994713e5181a32c2808193d7ac4a46172b2a2e36b2b491227abe2e1cae1ca81dc9bb619008251ca94e5b0a3f5b78215dd7826688e0157e625037b43534a58baa177ba0f0000000100b24a31e1690f8c6a076c5b14640212401cb7cff26172bd40b9f86a017e9408e3d9c2f11b95eed3206c0a105699cbc7012a6d0bdbc07d7dce3af4b5ddd9b6c83c7f54c89f9f3b2571bf6c2d62789dc92c26c91b3928f04e0649aaef5c508559","debug":{"publicInput":"0x35cd9ba8b3411696feabdee21c5da23bc46d02c76ddd9f2f92c9f8fda1c0310"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/11-13-e5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/11-13-e5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7-getZkBlobCompressionProof.json new file mode 100644 index 000000000..8e32f5217 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/11-13-e5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01f05738e04c668af5ca1887f52528ccb9eef7cc90afd73c9c23c14550021323","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYDiM/wACPjBDTmL7sjv77avwJJSLGJochT26YvajoSCrU/wAANWxdqsTmDBIVdWdNwKAHSaLeMGPFRfergXTBApyBwiy0F4B/AYAIHQSkESn8CYBOyQGB/AgDIeIzqmpUnqSrc8Jfu2Gxaseh2kYekmzLDgpKPWoZS8h4W/wwAyAn8SAMn8CAZKACdM5enlT/AABnIETILSG3IrW/BQ8HPEM3bqx6gRdefX0wM38MAZII/xIBkgP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","commitment":"0xab9bd4750ad072d0b0c28c9db6bb1bd5986d221ff14bd6c85997e7990a56cf4c550ed7cd01de02eae52509c296e2c6ef","kzgProofContract":"0x90520cf3854258ea4f13ba64a4e0d3aabd1a8d4bed9bff4877f15e457ccd9cc7e75a8dcd212a971b3b7123c008c1da8d","kzgProofSidecar":"0xa16124869146821518d622e91eff576a8146fa9df3f8de7fb17887a738d21f66fa60f5e2bab8b8bb63360ff434f99b74","expectedX":"0x12e3267a707510edfa200e89a3a24ea0a7886963b6569e896c24dbca24c9b024","expectedY":"0x68886c7a35ee00ced0cebe8c6e31af2eba1fdf9b0fbb0878fd4f12c111d08b79","snarkHash":"0x0cd0552f984176295088ff7d8fa14cb63a67ed9c0faa9d6abdeea09ccbba363b","conflationOrder":{"startingBlockNumber":11,"upperBoundaries":[13]},"parentStateRootHash":"0x06dfd5bf00ac76bece68984bced5f376d4a62abc03b56472959bf804c547d574","finalStateRootHash":"0x093fd331edcf516c7e6805250bb7b6b56131fc20921916096e4a8a71d0612167","parentDataHash":"0x01c993ae52495203ab88827c3111fcf3b09c16655c392dbdaac614dc00473c32","expectedShnarf":"0xe5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7","prevShnarf":"0xe6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x001094a84c082bac7cbc7b5dba7adef0b908dd908463bcd1e47168aa5cce2360a8a36a1c26c9a330cafe829a5e2696710068054d38ee428465537d9d86d433fe5bb5507170ed55a5a9276ead21833dfd0d9f1a8a7f46fbf7090bfbf74ea867f5014b9f3165d6388fa93a957c47588bd0f252919e1cf1a787e3a57c75dba06297e146c8b0a1a2e403e98c0ab73a3290ed0020e492acc262642aaf3f81f147e7d660a0e8c62bff7f4ab36aa13a595ba408a44ce27270f320e9e8c90e214b511c6001549de0e7c591fdd95e32167daef7bf40c3ace7c44063208ba68f7858765005f80b8d09251658ffe9839580771be3340139c2fe1aac5e9ab6695c36b9130a13024b0a6bd4673039fc96a1f735636a2a13175515a1f8b6880a10a01665e45bac003ee49c6c96ada5376c8a5fdc75aa30c76420a3eaa409cd78899e5a66015cd11039f3a84796c07127313712f1d6d11300da61950c34f79a49fe0252a531c5fd37ac8b1d929b32a2affcc3943a49ccc1396d769d151883e00154172a3af7819b0127008cedb69db746354b32bb3f1234224c24bd05d2e3e3d20ea87c33f676e62b2d40ec179323c06e9b351cbb00a0aa0068fa88123b0ea8f8f5f782168ca8095ae532c47a85e3f89e46a73c1af336fab466615b2985176a9c45e8c51877e4db0027bc9ea9828b2da3d57378ae1ae0cedf5b5c89f11987382e25e67beba73a44b80c42fb48262406f09975cac46ac0f5016acade07885dc5f183d6fe66f39620c65b49c27b95eb7465d77ba7e6b0c29b3c9d545c53a9f155af964f62be28715c0148a5fd0001b2cb40270dd79e015eab4e829e78c42dc4019bade78cd6dc0bec68c52dd01bb62d4964d68b97bb9f5a5601671368ec3b99efa547b270f6586cdc44252c46fbe300d6793de85577b9a3deaa6c27599a64d4e44bb5a0ba2c30b3f000d8f3e9e002c442ad163ecab080cf6b63b008dcdad37317d2ab51ef7e929e35549b15b34ca86bba762f034f30d314c9016143dc1b45b5edf13cfa4bcf16c19764123d12d1c22c4e60d128b2a84f52bc74b0cc2b514120103ccf59b0c6493ddb00000007025b5a8f4ffa38979c5b101fc3493ae83d1bbf4e1bf12ebc489d7094380e708e0f5832d95f958f59b8d91781ac6841122ad13c591ba1efc9bbe20f4e5d14919b0dfd2034149a2a3d3f1b8f1a8d3e1bfc8faf23ab3835d334985a39a5e62258900b0adce2b8d704fc3091c2e0cd18a838959b8890191cc946a1f33ae217d18e140206bf190f6af5e335b41fe6301843df9982d1e8164e7a24aeafcf6c45d80a7b0d937a2c2ac3930ee8a23d7129b48a8da9ae6f7ac4635cf17157fc31961473a10830957898e1fa291eb4307988d13cd089189d91b826464f9a8f87bfe45da9db015d4babd7534dcdf214f3a1aec2e248fbb2ccc9db564c6c86aa444616ccaea06b57b36bfba02fa71fde5a7b5f05eed6002878b9eaf52fcc4999494318e825d7252f92b653197bb108ab7a6a65070c7691013c2cad574d9171815e2f2851fc6d00887cffc4d048c3429f45b7c84ba3b18ca14c1d0ee3fe39418141dab71e5a540000000100a13bbcfa50fb7c66532ef12de2a214e0e8584d6505eb058d9a088fc3a59c8b9d4f8853a6d52ae70b9619f428b6e06501850b024c9b055fb89ec98343fcc6e2654459508e97a8a0451d18563ed03a93158872c6907f5f144813b2054b776876","debug":{"publicInput":"0x1138ce362611857fff908dd9230a832a2d5482887ea3dad679c95ea3a42731ae"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/14-16-8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/14-16-8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c-getZkBlobCompressionProof.json new file mode 100644 index 000000000..6e2c80966 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/14-16-8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x0117ba7a785df44964e79ee97cf056d3af4ab463f1a4f30ae273f37cd5caf211","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYEQ/brNRL/ovD4KIwEfOB/8AAYBWoZkXtJkFN9B/DB1Fh3R9kpTE5gwSFXVnTcKAHSGi3jBjxUX3q4F0wQKcg0IstBeAfwGACB0EpBEp/CYBMskBgfwIAyJHKwVYuGtyGUEMmXHQrLMtXhqe0dW0qGWDumBHrPEn5m/8MAMgP/EgDJ/AgGSmIIT6kcskJn7iZNM0AOfo2EHN+eIm5meR5WsShEnLAI7fwwBkhH8SAZI/w=","commitment":"0x98475a9c957d83b5524dfd7268be142f0e9acf1d987f87c381c3eb670cd0350390741cab7e010c6a43d9f632eec8d54e","kzgProofContract":"0xa81030a065c7ab52d321ca18c2009ce01d48b40435c2ec66d5e38ec743031648e4a963150f7b088cf2f710ff29acf219","kzgProofSidecar":"0xa547ab2520c84c2dcbdbed96f7f1029adb12a683b97c9c9dd6a3b8f1b7f37b79c721ccf44f8f8843e438418a755c3c8e","expectedX":"0x2861d2eecadab310e130d9f949469509a70f903ce709dcb9dd49fc2a7b386539","expectedY":"0x322e192bf54b7c56ec97cf3c71aada936fb7251989738ef11b3b90f5e9099e35","snarkHash":"0x0a8c6f82808aafbe9eaddf410a6097b0c19b72057f1a20fccf713b022edd7935","conflationOrder":{"startingBlockNumber":14,"upperBoundaries":[16]},"parentStateRootHash":"0x093fd331edcf516c7e6805250bb7b6b56131fc20921916096e4a8a71d0612167","finalStateRootHash":"0x026a0d5bb730f4867e5e9d696d6dcb4a028cbb918549565e9cdcb6b42f839573","parentDataHash":"0x01f05738e04c668af5ca1887f52528ccb9eef7cc90afd73c9c23c14550021323","expectedShnarf":"0x8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c","prevShnarf":"0xe5f194ad53779deb52c2455e216ca447a842026238fd8143cbb7911f7aefd9e7","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x0180db6baabb7dafd0bced27e46883af65030375cfdea8fb484949050c284674fafbd05c6b461f8348b747058e33cb2c0183c134715f4e4f2caf5b4147afde8f4b20330134f56757310d76a47d3fe2c865dbf93a33606cfa10c1678708abf0d8004504a2b490ae363789335ffe10fdfbe8cda1254594bdf1923ee602ecc18c3edfd64985fb1ecc0d8ac7e56164331dd400e5778c4dc788f359578f0975d0448b8267a3fbd0fdc991312a1e04a36f9a3604ab7be9db5939efb402fb1291c7f91000ab5e6b3a2c275784c44dc4e2cf0832ac6aa7997f67b0f0a9ba8ee032d8073d0d47e77b6475aece8ef657b2bca63f4500004d961cd77ab5cec7885dfd0bea22a5924789ddd622ea14ac9d932814091c606221ea516a5133d2e7db8b248d185b000548cf43642934e3b4961fb74fa11fc63f43c9c203bdd7ba6d98c6d0dec1e1b5d076e3d65b4a758747bdedae909bb6001bdc47d54332b575a0bf54405356a401d3dd0172b221cc18421fb6b986b982e386355cfe8b5e5ed2bf8ad77dfb53af016e3c2f2a5c24f7787fc64a0a669bbe773c4ec03ec12d94760dea0f4818d2c47e1e0837fac94b50b04ac9ebc79bdb8d00d1e71b9dc791ae630ceba3445252781d48e6d285cfedf1bec1cf41520aaec9c8e00b1fcb2d5b41dac9a43ebf743b24017a98ca6abdf5d5634181660508d7d69eb26a6d327c440b23c9d3aca6a568b5268ae17fe3ae74318e51c48f0cdf9a3f010581188e796f3d24f7e58160ebe7f9104fe6fa1974473238e437422a18e83a67719b3d1207c86f9e0f1edc59b2745e015a95f54d9a61466cfab60d391502e97c54681d17cf50cc5187e83b6e17095305cc7282efc2a9a56245495de8ddd85800c36c2ad6088c7bdca44603135ecd9f154b6723b1500314d8ad36acdd2aa1d40b81380c93adae287a1a2b445c430de7006ed89ba2f6158b8268131c4f2779452a79186690e60703e82398f3851643e287b57823a5e13fa281a76b18a75a5eb701565f92937b3e39b8b65bba434ad31dd95a4ee374c1f06beeb25e62013982c1fa5b0c87d55f6e824721030f0c0ad36000000007123b50ba658f8f23f4aaedda550f5c4beb6698de4cc155a51249865a57e626830b94fbff64ff87ac0af73afda7f5fb906e41f5d5ff6dba20d296d869b1a0626406bf05a4ddc94318dd7d41aae856e09476fa708c611013e85281a12a571ea4df10ce0782d7978779168ce57dc6f8a18f712ddb8f96c3f97bf47d88231698183a0cf5442f78e3bb9a0f6cde60ae69a4d9d488a8d68b0ca5780a2103c5e279e67b081b77269253488e8f5eb56a9773dfbd18ed0cafe7b5c5fc665246ae5f597e7002ebcf6ea433a3f2d861b1aa3501c46d6c3b9749e0004bcbce5d403af390195a01a85613ca44837ea9b8c4c196f3ae38e7da5979d4e40617e5f4ddb71848ccffe0b5f760abb381f8c877529c3ef3a5be01a110f950a20f248fa6bcb3c8714c39dfa24bcd7308d12b29217ba6d32f5c97516cfd01cc2968d66ebe9925e1727f4806d4d1aa94b09bf6db93e43bbdc9109c092cb84f88d53db4909d09e83278235100000001017d44773109ad09f95203a6397951f606de9fe6af43016748605344f41a73054046be1366ca8ac939d2f628531c8e7f0053fbc28d9f841607ca2296cfd4ca718fb92afdc4f89527917c55ba4246b6f6b9dc2929b2b3acd27a584caa0893a889","debug":{"publicInput":"0xf9c9c12d91bd06e0c96d9baa76cdf468caa8c9e545dddaa680d96674bcb9b97"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/17-19-343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/17-19-343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837-getZkBlobCompressionProof.json new file mode 100644 index 000000000..ef8ff7dfd --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/17-19-343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x011494f735f62294281086b6b718118dc25868b6df1ee20fea3a37d254c3f1c1","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYFDf9S5wKSFfeEMHYXG4FWgC/tsXIXsRUXOpC1oqkZQcm1icwYJCrqzpuFADpNFvGDB4qL71cC6YIFOQmEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZFRz+Kkl3cfRMl4fksjVhDCNng7o86Al0uqE5YDy5ueLO3+GAGQK/iQBk/gQDJWCvK4lhBjji2sAfJlEdhIAazXoqnX458dE8IjnzFlZlCv4YAyQv+JAMn/AAAAAA=","commitment":"0xac028d2fafdbd4d7465971d424956c61f9954b6872c2339c306dc33472217c709dbbcb98bf5bfe6929eeed7b52b2d1ec","kzgProofContract":"0x85c5600e3b3cadd0de0c81c1f3a2d3ac7433f496d99be8d5d8e3153ca12b6fcdfaa6a612438d26e141afc638e58c2d80","kzgProofSidecar":"0x805862fc27949b24d8f07f27c2c4bf4bec7f2fc1a787e127a729014a426459ea6181de10b89f6248aca83e69da5a9a34","expectedX":"0x47aa0554f2afdd462d20f2aca386943dacc2ea779c459fe8da72968a4521fc24","expectedY":"0x6ff357fb8e0a9a0850fe6424910a019db3704cdfc63bd66696fb792501abcb4e","snarkHash":"0x10fe048afc960f2f8f07d446e77018438414730df3bd523a75e824940347ca5e","conflationOrder":{"startingBlockNumber":17,"upperBoundaries":[19]},"parentStateRootHash":"0x026a0d5bb730f4867e5e9d696d6dcb4a028cbb918549565e9cdcb6b42f839573","finalStateRootHash":"0x0cdab0bfb220ab9c5b2199486f2e828cc1c2b350410dad11102dc3e1f333dfb8","parentDataHash":"0x0117ba7a785df44964e79ee97cf056d3af4ab463f1a4f30ae273f37cd5caf211","expectedShnarf":"0x343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837","prevShnarf":"0x8de7b2d25ebb3dd54040cc30cbe3a6333053816812bb33dca470e945eff7044c","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x006d4e2b1157fdbe7bd03f30d23b5ba82825ae4d1c562c085f35deee18f5a34a169347341c1c5a5bb5217f73a697c3100046698e96a3a603400931e239aac677e9e6e6ce94281f290f5a9b268874d9b1e254c13a382309dd57ec6b8d153aa7b1000b93cd408e98f0df2f9d8466a06a0c4ff157178afa3f1c6afff0662b23315d764620b748619b046aada4708122fd4c0020c8fab248bc403ea3c4d96e17e1c02f18e4b4cb0d06394a2470dadf8e6dbda547e7bbd6a529b91db0209d6ee4a179017e744cb0ad1b43159734026e25e42f4514ee6ba2bd14d627edc561d431193acb990e9d28186e090418aefdbb8ef6520070a8e71ef2725cbd53494ee5455f8aae950e17ed906ea7030f629f9ec844a4990825111443180f1ae17d58d86af7d100a091500f08a5d169863334ae69bb659492f134b98a9e148acfb988d54b74e34a2acb5e696678372bee22a3b4e9dabf00ccc104d9a0db4ddc2b7d21a0a401fe42b17866bb2c18038b914508206c8bdfd0ad87b4ffd3eb0482dc507bc9bac2f7001d8a02b6f4ca1c376cbea66b11b0854a11ea9129031b3c5c5a050ae1c15d498a105f12551e3c916a35b8d54b12d82e003520903ea2f20e16ed64224785f4ab185ffee3fd9c534d955714e58eaad386b2b2db18bf0c1146d383d6b859ea4b4f0143fc89037f509471eddb20c995ec9a9aa553b1ea01b2a2a5e60d5bd686def4f07d4c6bfce92a8c3c039479ee5e151c000c6adbece8f44fada8fee91a147911cb62316424cb430656317510c9e17da6f5ee720dd1bd34747e27b4727867874600a004258e8abdc04ba85d50b1df5cb9f7eeb45f4c46cecd20f3f3305c22728f7765d72532ce51d8bc37aa2acd9b57f901ad1856379036f9988d15352493d69614e57e12020b45467d279c3543dc20d11048ec14263d194ca223483a42f3e6910028249ee27c52f4c077d72196e93925b1d44f3fce3c45c7bd3b06812155db887511920c32d4a17a9a3f6b2b469369ec003d37b93ddb1c6679c00c532ed866cf9da6fad2696ff3217f8c50d262c718b511f47d757bb15d3a77b2fa8827752491000000070dcce03b494784ff0286245a45c8a08b0806ed34b2e26ea83bf798b7acf80a2605bbb29a40bcbdcfdce7a08e05460429d943f6876a90d8cd1e578cd1e4db5d2809e31e1f14845462b9a7ab9796ef01db6acdf9dcb0a582249f4dd709f1cca6370e03a25a13f976582eaebe966fbe2bf3627afee01381c75d44e02bdc4046978607de5dc5a0fc9eae4d1b7af226d404699c24a7897280e2c35d0fd98cb021c2a60248d62a385ed0bbac473bc0ad0ce0942b2c89248498c29386a70f91542d7dec07a7993d7e36b6dcce4fd2bcdd1d8cf14cadbb7aad83c8941b2504aeb959c035001a66fb3ed8217f7c73ba0bad289f760ebbc52854de155a54c449ee782af8c8ebbfc50019657b82b2a73f798db230e3013163d11b7cc2b6ac2f3a36e20fc7d33fcaf98d15a51e55035ba48011b127266e5b0673b5ca34ec2097d43a83767e5c0807129a41e2300859a8b169ddf29f6ffcec07e7e5d308054298a2c96032984e0000000100a6745cf67ba7f07c1df293cf486b461f6fdcf2fdad922edae048bece7c8bd795d9d92f45c560470bc74413147f77470187fe37a24c6d097da8ff712178e29df1b5509dee73b201d1568fa1f90d80eca9e1931d0b468e771cf0d81e96ae7dfc","debug":{"publicInput":"0xdd2d4884cb0df6c1006dfadad66c905bcbf2e4d70547ecfcfbfa1554f81d227"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/20-22-aea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/20-22-aea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7-getZkBlobCompressionProof.json new file mode 100644 index 000000000..f3f0863f2 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/20-22-aea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x0146d216177763b2ddaf338614ac3c621b193019f04145d45ea58dc381c910b1","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYFxRNrQhjU0OZ7SrG0kXjaSDQ9WKxwCaEvpw65DpQT0BE9icwYJCrqzpuFADpNFvGDB4qL71cC6YIFOQyEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZGDC9c+IOnu2hsNEuhfnnsffdFehewqeIAO4HoAivgFSFL+GAGQN/iQBk/gQDJZeIOu9cpuRH7XITNvBKOE/1ksYd8cHoyX8rJ2P9lS3vsf4YAyQ7+JAMn/AAAAAA=","commitment":"0x95f187c9f4f061fa8607ad23b6961c8a700ad010ceadc028f7266b46a43377181441e9d4d62dbfaff557bf8f51c05ff9","kzgProofContract":"0x8575f10f08e8054fcc8a2934e92a97f1d93fd6a17eff289a8a3acfb6bbc3411e145671a9025a5ba7a470d25b47dfd834","kzgProofSidecar":"0xb3d0f8e421f5cc7c069e4ed907f86452d4fd2bce4a43fa9dea106014d60a98f506d25a2b7f7bb6d380d58548f093753b","expectedX":"0x2e70e031ca54716e9f1c3887fce8717b4f3cfe20070bcc11501da6065b7eae92","expectedY":"0x4f68f7f6f1b8977467e7485135b1621e07d06b134675ac2defface30b0fdb0b1","snarkHash":"0x05a68dbec5e3908d7fd746cfc69b99af7ce645711ff822f997e33e6fd1478bae","conflationOrder":{"startingBlockNumber":20,"upperBoundaries":[22]},"parentStateRootHash":"0x0cdab0bfb220ab9c5b2199486f2e828cc1c2b350410dad11102dc3e1f333dfb8","finalStateRootHash":"0x0bab6a28cfabc29cf1e284145b39f5b37ad04ca0d85cf878943fd066b3c8fb10","parentDataHash":"0x011494f735f62294281086b6b718118dc25868b6df1ee20fea3a37d254c3f1c1","expectedShnarf":"0xaea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7","prevShnarf":"0x343fef4cdcb6d0ab0db8ea7da91820c8d21a80135608b990c0b4f40c8f48b837","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x014960f75c1ef839b5050812fd56b709649dc3f2cfa61c436ccfb402e3aa93a8f7f4e6861dae0b27342346009de6d728014ebeba43466c6fdcfb0531e726d18899b0695c07aeb45398a80734c068d07b3a27cfd156c872f0f4a2637d3afb01af0030ca4687f4e13296f4bb2012ec1ab6d6a55d8465b391de95f1034d8138c906baef5ccf825121f320472cfdea67e5d6000d534885ef7e20d5fee27061b73c4ef62e7e94242b95dfbc294df4c76d40e477ba3e2b3d42333db0a726001c1888d50175c76ad08a2c9f7c9fc9410f2b0957b3317dd4be1d89b91dac27aaaa6d84da905cc2c20b9103b82171e3ee4c7d777401418eadc3d38232fd22b2292421734f08107f0bee56383eb58e32cbb90c48c7ccab9995b128f85928923da715a8a6780055dfaaa6ac6816a4c9b059cd735ea6469c09a710e12957d84e2f905f62b974118231dbffc270722f69b4efbe6c8b36002f0e931c31cfa27e33d5776716e02db28ee5db5365ba92c0c1c8220f2384c3997376a6a04035b18bef53f6e9c2506300b2aca3389e14fd67af286a8f1b2a9c75bfb3ba505149fe70f2fccc9fdab86501aed64a5bb7d722bbbe7dcea262c7b100c8a8c0d521404922ce44eff691faa4826db70c1826b16e2ecba2f4dbd745c53451634874c29d5dbf6ffd30c7b825d9002a63e7f3ebc7401e4560531bed3d3d07a3edece400ba440d887a21a0a6e744b2fbf1bc6c6f74b9826357d15af6bdac002455654f03363fae801b32e39927db128399b80db550d1c5ebb35dc22b2a91c541cfe5e74e7b2a0bbd81a11d9be6b5003fa32d1f7528e7dba39a7547ee4b2c2fdb7d73b00fd5a638a1c7f9390ea83c69dcf4bb34ff21fe7452003878e330270183a2b4c1c6ad856bdccac0ef276a692906bac040e70a1dccad433e4716f42a4d88e52e8a935c3ccee09709ff17950d009824fd6a6492ffb336d79e045c366731474477d4ac274b7ffd188520157d5785f8c6207789002a2d539c483ade11f301858001cf2ca3945fd38798d98f2aef6bc84b92b6c0b4a208eb1eec536cc33699160d335924ce119f6d1519654252b4000000070e0ea9b34d781bdcab391b04d1acea7f1027b9c14e8e346920d0e180aa3ad4630666cc5edc269b76fe39b185f6fd1795c0ded9261409e5be0afae8614c16e1260412a81de82d1d2eb97e828eda612dee68411f92575282fe4a9851a57da382600a025792b85b23a72c5f1d0fd8c45b4e8da65c8bae1c4614dfa24f389bf2640d093f4bd73fa605b0200b0c83524db40ff4347aaa347a6f20f11402ab451d783609bd5c6503dcdf40ab177bc451048338b5c106ad8bf2b735bfa3b3ffbe899b6b0a2436a67fa969729d5bcf7ac6c66be3aa7a70f10f67e2085e752abb394e68aa0119908ef63702d3ea3dccb2473d6a04e5939e56a9c17f249dfa0fcd8d9f31750b3337450b7ec6c9abc173b8fcc3b8e90066cde9ae81f48e56c48405d60bb28116bb0792a1779cb92aed0cc68b7288bf32826027870f32b4d38713a26f098c6f11a3d4cdbf23ce57dfc694fd32327d62095a44456ab60722cb38dd09fb4185d1000000010108ab00bfe6fd906a180da81f15222934f088a7521582d7039aab4588bb02e5a92a80b70fb737ec329615fe7c39a644017290eb7650a8c76d7d9070a63121990b601dc1f2abe37c08c9fc3e598f1d9591a32b8c9ab3ad56ed56fbdcf8cfafe8","debug":{"publicInput":"0x6fa348408b4391d263da817fc22f0701399065217bf43da95b628366c4125e4"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/23-25-268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/23-25-268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b-getZkBlobCompressionProof.json new file mode 100644 index 000000000..dfd928b64 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/23-25-268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x011c205cb61ad36b464d88916e02f3979b79b042c8cab3658900d36046c4aaf1","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYGk53DA0IP2BMW8JguFxg7txOqSSQ6ky3nzdRTrUI3Y+3dicwYJCrqzpuFADpNFvGDB4qL71cC6YIFOQ+EWWgvAP4DABA6CUgiU/hMAnZIDA84EAZG0nx/VIFB9YtO4i9tt1sgnSJI9Lrt5lnKNh+X/DWq3ETr+GAGQQ/iQBk/gQDJcZgfhHuKLGLlc/pKC3rwOBXFph8L+u94GGVFPGHX+gY4P4YAyRH+JAMn/AAAAAA=","commitment":"0xb6fb447383919520b78bd861de68883f2c558095826f558c4ce79f2dacb1343c555fcd321006f8eec48f1f0e2d510ca5","kzgProofContract":"0x833ba3ad1abb1c209fd6d3bf63d9ffd66ad7f553ff294d7ee07e2c4dbf66de64d10b9bf656c7fda9c23b773ea26cf6c1","kzgProofSidecar":"0x92c4ad82a464eb8b9906eab5d383e2ba0046b76fc3cbdf08f31ec8e02dd75be05e8b91bd6dc800666f7a92e2442dda17","expectedX":"0x40e01c7c366155743e3ef4a8a6fdc5ccf2351454bdb4bfe0000756668000ead3","expectedY":"0x24e5b95a0de3c17d9be5edf15de13c6f82bccd66fe9afae8e8d5718fe9b60a19","snarkHash":"0x0f44502fa3ab1c9427775b45e393a1a917ae9fb9766dff242d425a98800f31aa","conflationOrder":{"startingBlockNumber":23,"upperBoundaries":[25]},"parentStateRootHash":"0x0bab6a28cfabc29cf1e284145b39f5b37ad04ca0d85cf878943fd066b3c8fb10","finalStateRootHash":"0x0fbfde9208962103fca09983aa7a7692edf9a9db2376cfcb92f6b4ad19bda51f","parentDataHash":"0x0146d216177763b2ddaf338614ac3c621b193019f04145d45ea58dc381c910b1","expectedShnarf":"0x268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b","prevShnarf":"0xaea706d4657966f8e30e918e1097ffa0da19513b0be56a243cabd7d3a32358c7","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x0120da112ec8a6266d08a3d19aa96e4b992b029e90e0c3cad822b46179d46ddbc8a2178480225c28fa6ca932b81b82be01917169b397689ccaa815f701faa7f9eed1518e7c1fbaa96db29822d58c714ebc3909c9bd7939861177fd90ff08dcf70011e36ec718b88628d59de6533917eb001ce356597e064c3f2388e5f2388d914b4f3f394514ff9dce56c53eb3d2c08f00f1d8bfd95010bbf2b771d36115bc25cc288e3030bb35b6c877992c43cc4e09a6f01aebe2ff54e164db2a5b3c9e7a650156627bdb62878fe4e402393ab679878ba06224ad39e4aa0802076ffa1b2d202190fa1423fc73a6c162c61b0eae97fb01a9b05d6ba6f1cfc29fff923cbf16a6360147e3bc2fdb6549a00bde8fd01e4286e138cfe18a77091cef7c280c5f2c420109c6f82c4bfe8763b32ba7c2bec2181f031ed4275a58712e1bf1ee34362e70d7171733b9afeb0eaa083b3ad7bac86100e9eec1531e5686bde08cec05dbaf2610bec2560bae34a20d171364fd60a909cb19db4bbf44a71a84dca50ece0638c9014b63629f7102a2427531659ae60e30ac8cc004b32ee3af25b09e526d416b1bb05c618de28884ffe8f1f465a9e4817a0094cf063c3f383dd12fe80ed06ec66dd867eb8b5c06629a54588002b9ea7be63a9b3b9caaa8c5669ac3078f0bbf75c5017525d9534c0e4326365f8da010e374b71e80eae78580b41b54dc0f918a11c7802c80a8bac06b2171026bee26078b4400b5789196af649f71c8b854173107c27b8318a35d87a310facb6006db6bdda9ef0ed6fbc9aa8546f9c03902784621f700f13f0e696b76d8a22a4ebd7958f3865a0ab0d22ddab067406cf7d8cf10a265495e5962bc02477b78d52b0ec8d40299014d21bd3620f9f238ec8aca2771617bb905691cb82bfaa99d9f8a43fcc41374912e3e5e721e850e26acd7ea1e878df700441d49c198730dc540b2582ee7bdb564b0c8ec285f6d85a55b87155a748b686e02e303d88cf73ac3f0611bd16cf7ee00b3d7cd7e32f5d42ce8479a329d575d62e67364505d169c5b6a33e02a59be576b51f99472a764d3a01733a85ce35d1400000007106ab930fbf3bbfa810e225d3623f1c2859477b14c063d54c3b6bdaf1182193208f35a7d6a1c5cc87d365319190371ec63ac50c50d0e48b3a724e85794def7ae127221ce90d5ef0f5a9d0616f16a315c0b75dcd1b128ee816a1cbb8a73c0b65401e16cf8dfea588fa87ee27587cd44a0238f2136adf6316b29d1d6ae93075ca700e06ea1bd0edddb17c78d0fa8a3406ae6275bc215d598b6f9b4a08716f6d2d70e6fcc2fcd2ab2ef0cb142e4a6690663acd4ce29dbfbf72a641080d4d0b43c690cb7fc6a58176d554b21dd1488591af66e08211418c7444d391019a4e51e00e7001c6715a089c69a73064fe881bc8f0df6e75d8156624697c08001d2b7a05c457bf3c0328e60f680ad94ef8679ed447c006f426113abb004e5aee4a59c90b89a1bfe503266c755a66e65933d836359a498864c0b29ee01f01c248d2a66345a2505e5c12442f7dc501ad94f8f9697b39d6946e797817daae4d496757bfe4e633a000000010061ef85d1eb9632118d9d827414bcb3d034b039327c249de8b8fb7e257851f5b73c4b717238829952f23ebcd821d548018cfbc3e72a349bde1f2df799214fe8444ef0e93db4fcd631e001644ce020a49ab5219abac8cd59a075258dbd1572aa","debug":{"publicInput":"0xfebbbeb857844875c7b336629ef346454944f69cb0a53202199cfe40c740c04"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/26-28-06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/26-28-06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d-getZkBlobCompressionProof.json new file mode 100644 index 000000000..a6f68f643 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/26-28-06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01a4531284372a882e18672608435a88af99893b303a0238bbe3f8c95d44e18e","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYHXq7IllXUFenvWrrcCtJK0weny7aW7wyHuH8IEZJVhDTdicwYJCrqzpuFADpNFvGDB4qL71cC6YIFORKEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZHmtl58hiEmxdeXn0tVHn+wWtkfyIxNpHz2mYQWw0Lg0En+GAGQT/iQBk/gQDJggOtZUOOupUjx1C8nuDCCs/lShmiah8K3NKjC9CCSe4v/4YAyRT+JAMn/AAAAAA=","commitment":"0x86d4029239ae776242220d12b43b2ddbfcedd802f2eae6bcb10a68f9a8283ff34a25175aa3e0a4e31c61ace1b8acb301","kzgProofContract":"0x97c1fe4d11f5764e3c90bb43a6cccd5c6cb1447bef047ab71678095a577c2a4182166bf843a6e87c5cedfcea662a5c5e","kzgProofSidecar":"0x85c62cc468a6cb73897e460d9c75ecea021312d77f4b5d28c061f290e32060c699af911c5e90812319214faba6fcb8cf","expectedX":"0x5126fc4b426097858bc10552dce1ebed0a959c3989591717d549daef3994f32d","expectedY":"0x6637992bdb7764635e49912b661f265afa18626144fcec1a53790fe940d23ad0","snarkHash":"0x0d06062f6c7644b100baa955d1ec4dcd1cf1bb2102b81daa4ba682eec77d5e9f","conflationOrder":{"startingBlockNumber":26,"upperBoundaries":[28]},"parentStateRootHash":"0x0fbfde9208962103fca09983aa7a7692edf9a9db2376cfcb92f6b4ad19bda51f","finalStateRootHash":"0x04e223e961d59de5d0cd6ecf9d78359cc9d72b4261d851557b1e974d90b71a7e","parentDataHash":"0x011c205cb61ad36b464d88916e02f3979b79b042c8cab3658900d36046c4aaf1","expectedShnarf":"0x06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d","prevShnarf":"0x268a263e550eb02c8196d4b9e3cc06a55d87018f2e20ed7304da5f2f3f6bbe5b","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x016db164c007ea7fb4e94a0a9bb9f949041fc93f8c894f754b80d3037ce051e2666ca19dacf44a532cd0b0d0eb7b87ba00c0aac8561ca1b2d0f6f15ee0f718703018c53871b9b217e5d5264268ed57bca114a2bc9799970e7879c9efb249885401397d67b798ab7b63dcb95e454d6cacc74cbcc3c2776d45ded2891e052cb01dc56599a592b095a5044460876d08aa72000153f8ed5358b4751a75b0a2419b444add09c1cdde82320f14da26bce3253baf2f742c72104d72e3f3800d34d3851100a2825c73d103f40a0f0115ff403ab9ae892ae7495ff3a3797822183d8c7c561795ec8c4193db59e3ac2396347968e0008949ff4c1fd96ac7ebe09998e35c20ad7f3a3d64171de621da93c8a6c50a570f50bac1cde442dfa2b668a780c1cf0400f05ab327013c0f42d0396c301b5462eea53dd1c2298f06857997b28b9c07d53799b592ec995466aafd60dc2ce51c2d00b1adfe23fa2b24aa2481c94a660ac1dc909c02ef6ea0d3809f66370737135b8a642dbd6ec3062ef706ee13f82a9e61017bb868f95bd6b6548b56dc252363feb8cec2eb15026c6018caf32872bf659ee90a463fa24d3edbd346feb0430e8c970124ebed8ef37188688b3aad62c776feea3b2c20b3d55d3ffc4973fc2cfd5968625fef9341a999d0626b0aa0f04dae4d0072a807f504c5483616fa16a6da2a4d91eebe4759e7d3c69878d825f506455dbca917f4b1392908df6a47c36715314e0088050c8b3cb886259914a25bbd1b03704c49f4b875d301d3db2a5b19f48b585bdc187dabd6bb63812f09ce58e3420a00e02507b82661f6ac159ede6a2e64f060aa446cbeb1e26eb1738beaef59dad36929b133f1baf969de5b08a36617b29e019c4757b288768d99faf027abff9abb69586b99a5c7a1db2faa92ef329bda7e4aed602c2e40158f011bc94d954ce4a701a99e8033845e3303c7209c0eb559af5747f927122acb54de7f06af8e3a1ada6617efb8513adf0d7e3c65b687b68405002f73cdb62356bee7e660cf9a7a14afacb5162f0e41d743de693fe1b628ef3a9eb7db1bd5fe2abb3fa38f860e3f6de5000000070b6aa41803ad47070066cddf1b5fd4e21c42c3d23195287ba29f84eed77a2cb612546faf91bc6c8177455779304a9aa9d1cc0d97915da7930c2914e0ed5d6f650fdc4ee07298a0e3b44dfb0f5b629ae2a1fbca6235bfe853459307f9639d679e0dab840c3aa4af25d7a35c0e41390a5275ad117a20ad71b9fc844124b5c699f10eae7c14d2ba3bc95ffd2c2cd8c5af5bc26f2562488953f440f450544086a1e906736d859571f14e9888ccb03b34328dd3b6b897b8283430bb0ebf566b0b426a125ecca84a330febaa10682d2b7046611816268427d1fd53c55f5bba95bd1234012a710574d9cc3881ae3fb121770342b55ffc0dd8bdf1b0b57b5a102a7d08c1adbd5da0b24624a30c6612f7efe1599d00b61d66f04529d275ac6fc120c06e3b1511a7e2c2ebeff391e196f291bcec9a59a05f82350ef80925e9ecf594c0dec801d0fbb96647a5cf36fad20b22e2e3e14a3cec3e869ab9c7819a1e36ceb6add9000000010000f64003b48b522beee0b1be86c409016ae0c2654e30a7ee42cb31a259265e49c106918bb603b03d8de57956a27b5601516a0c5f4103626e7ed95e895fbae69c8ec9bd7ba8104620f6b59ab23be18d1f062a26fd167f1e4859d97ecb79ad2f","debug":{"publicInput":"0xbfe32a41355f4792b20f75f039d3fe2ea12b105243ca597e95772e882059dd"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/29-31-0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/29-31-0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c-getZkBlobCompressionProof.json new file mode 100644 index 000000000..dffaf7c20 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/29-31-0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01354941e62722510ef8c530586b3f4edff05009634df244e6df56f131ff1c13","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYIYe0EUro5tDF7AfGgIC4vjC4BdXTCzUllOE8MDp0gGPiJicwYJCrqzpuFADpNFvGDB4qL71cC6YIFORWEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZIpcHZkDcwscSpG36RQ5Mirjj3qlafZFJb2KOeYgQJTmS7+GAGQW/iQBk/gQDJjllbPL/c0JfpqUKjaqkjAM764fVC/aeMCh/ix6sQDnA+/4YAyRf+JAMn/AAAAAA=","commitment":"0x914043c038399dcd9ff7040a0ce2b2ef7631eb0544911c4d77e6eda38ab53d9f500f8d7aa888254eac7ac1c7ffb81ebc","kzgProofContract":"0x9190aeceb0f6ba47f4ab823d61a0ac0cee4edbe7cd165798e962cc4674b0b28e11a4a049e6e34f20a63535d660eb4a99","kzgProofSidecar":"0x89481c3c03f6c58fd2b02be46a5954dc372c37efbf30637163a3052c8ad645b6ab5e3d0c612e433d3d92020136c71a06","expectedX":"0xc1007a373089b98c0e41071959d6ec1377c376d6a8d8a3498bcbbcd0a1db55f6","expectedY":"0x03d446b5f37abbad71c95a3e916b2ad98107dc5252323e2e56b51c48cbb3e715","snarkHash":"0x000ee937c9ffa497302444231608180adf4c843060f55f94043c0b3dece2a7ed","conflationOrder":{"startingBlockNumber":29,"upperBoundaries":[31]},"parentStateRootHash":"0x04e223e961d59de5d0cd6ecf9d78359cc9d72b4261d851557b1e974d90b71a7e","finalStateRootHash":"0x072c29b2166fcbd110ef1648d38131ac98044e8f53516b2853289f6d615e74df","parentDataHash":"0x01a4531284372a882e18672608435a88af99893b303a0238bbe3f8c95d44e18e","expectedShnarf":"0x0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c","prevShnarf":"0x06851ec1f1ba875ffd3a08fa5b2f0d88ac9426c9ccd852973abe73bd9afc921d","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x010b4cea0a68e2286a03a79a73de424bbf00077656b8c992bbe902909d44b0f6960df53e2954f4604b2eb72df507e754015b384f5cd4f084fc4a9dc2aa7832b3b305ef898e178e00d653a4545041e6890b0b517eacc5bf8bab4fa917e8b25499017c1a051d509797c83313d67c4cf03499ee6b97a50466109e81f553268628acd6ba1b82fe508bc856005b2b9eea2d4c009104852f5824df91a84e1bc9fbb397b07614ded662b95ec41a3640e525cb11df2da2e01262bed868b13e9f05b9833b00003da6d3ab7deaf956e170882fd4dd7f426b08b29f669aaf747d13151f809ea50259c01da6ea83590f986294dfc287011763177193030c0d36dc172f25ccc9fc53e4f00a20566bc616f1ff46f368ece3673b801932c8914a367e2f8a96253801340273222ac65ea4ee48c2719e4d20024be8fa8e0581ce6df1463d4becacf9e2b5d91953615138623dc41d99a3be1900a2f2555de869d63e8fffda3f666c7def0466f5997b57566be9f2d019c996ff485f54b82c0c18829146c01ed0dad3020187c2535113d03c3e548316492571a34647be6721958cb63cbcd959b9bcba9ff2204a98007ac41b56d98e1739ad888900d956b455817e003751021efff54f4e187fda16631b7ddade78b941988426a5380597c056c3d4e7a196f95ccb39e5b2014b268dd287333f4c47b43919cb97258992d63c0c34351fd06467a78de890f5aeeed6577b8c27a6232fd9467897b6a5010a1577d95b695d20a385454c719a94c5df7aeef2164d1e6d02faa9259bc237bc8717f9cef7fe68ae24c2cf847fc84500425d4b82425cbc24ae71700b8d4e24a015e752002bf6cd3c96dd289159375eb8f2f9809f19d24ea890408ddbb6d67c01a881d2979393de30b816943bd9416cc3906120d5745366be19d6fcc86a4cef630c6a449b2f612bdf040c49e559f85e014c55d7c8b9be65ea9e41b084c43a376b682608170b683c9e82ec427d80ba9523ffe375356359db25092b2d30a3189e004b67391fc1efcf0e1dc50294ba8f70205566280b651aaa5854b157a6ec58b2e7bc5a6d0a711edf275692b30926008200000007085fb982cd0fdb5aa2c6875dcb1fed8e289014765dad6ed17f55fcdefd60a8250c37f36d8490adc75ec5025dd7ac87892446f03306a2df5bf2c42f30c97e97d2112e564f48f529e7946f826c782226bb79977bfb5f2aa5f659f3e5dd8bd9c0320718d97b3e181bfeeb6af34187a6878f2bbac2160a03f2594b957fa3c49c54460edf0b2ac7ec386ac1498ecf55e4643fa448c6ea8f7a4e316381ca0f5c6a94b90eb92b6ce1e859b5ef11175e107f48ce10498f026748adcf73a3ce7c089c184401257dff39592068dcf6b8de859e8f101884123ac50ec080012b7343c66a483a01aa12edda893e432b7cac19b0bef165212647a194dad9393a75e27204b24d4194b9ced4721e2172262c99412efa6a1701abdf72dfc4b241cd029385969d4cf31f6cce4d6c9b48712900429745d72e617cfb3fc75f3d484ab810fd73c3729e1309f73a7971885e922fe9aee0d0a2b10d980c9e7a685fbc0181944188043b38000000000101404f9039ef17674e751ebec0e0e530d08c9068b4aba6460e40cd5028b4fe9bb6506a8431bcb0af0181499a37e6966f0003a8bbdd9239b74da9091ffbed895cbe5ad110dc8b8cb536c679719c4d34ae04a847c6e7fb2827b299e1a5e428489e","debug":{"publicInput":"0x218a808006e2776930739a24ab53d9900061f84d747ae84b69ff69d5b7578f0"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/32-34-a646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/32-34-a646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831-getZkBlobCompressionProof.json new file mode 100644 index 000000000..6c6736342 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/32-34-a646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x011531090261c2af287fb3f766eb58a8a11ec7fb958560efce58f8ec03e24e5d","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYJIVJQVsMsNV5WmAm74j7vZS4c5DbNz1X53q1rfxObWACxicwYJCrqzpuFADpNFvGDB4qL71cC6YIFORiEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZJZBmKWdIy+AyPdc/Y7y1+UVs2nPxYHX2wwsDtSCvq7W2X+GAGQZ/iQBk/gQDJmgVlvqJFMd08GUnpGiMAOtGf1HejZRp3WTDJnhAzVIHi/4YAyRr+JAMn/AAAAAA=","commitment":"0x93a63f3345bc67d21bad315894e368ed90e964731f7d80c63624a458d389fd74c5d1cbbecce97a977987895378f4fba1","kzgProofContract":"0x877186b16ab2050ab1882349f51eb72d806b68ff9bc133740dcebfce9101e58d3beca3f2f5a54f24a7fc86b5a2b0208c","kzgProofSidecar":"0xa715c44f2abfe59239ca6a0912d7e14e9b79e0e9de6847660ea84e37d364198c6a0d7d2bcbbdd7f81cfe0c335fe9e825","expectedX":"0x48dc636138af6a3a73783a4887c5fe24a9748338dd36996ddb21246049deff4a","expectedY":"0x433159b04ac95a514993d0c1cbb583330d744e8cbb424f3942cf9f1499a221c1","snarkHash":"0x07e86953fa53fc032cd223e331227ebe23cc887d6154a9efa6109580376d2b72","conflationOrder":{"startingBlockNumber":32,"upperBoundaries":[34]},"parentStateRootHash":"0x072c29b2166fcbd110ef1648d38131ac98044e8f53516b2853289f6d615e74df","finalStateRootHash":"0x10556468275a46e1261bd2af01c421e81af255ab49f932de2b6352de9648727c","parentDataHash":"0x01354941e62722510ef8c530586b3f4edff05009634df244e6df56f131ff1c13","expectedShnarf":"0xa646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831","prevShnarf":"0x0602578e3a61f2be5afdd3ee34c6ac99e1e36a50450c75ef9dd78e50dddd3f8c","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x00093ca416fd5edca805bf59c232a873fb42c4141da527c0678cd72d7a262b541ee0c62502dcd1066cfc27745169f852004e16b0be212e2247ff9b7514a755b29384d61b48505abd50581c7d6d904356d873d7cc5c15669731884bc5fc14903d01abb3e0cba1bae94f6b12d101c11e6e8d47be3233a494618f636eeb676535c2d0b7b1b4e70ade42dcceac4f789c4def01431a01e90b2a20b70c2a52aab7839b328922077f08efd55ad0aa81123d9f7206fabcbc6b002fb22549467b8fa8c78c00832451bb84dc3989fe8bdef2d5f3b2292a96808777625e8ae8c4b9b077f0e24fa04ebc898c5c46fa469ab648853ec8018c399463c5abbe3889fc37b56fecd5549f3a8592f0b0f5921075c59263c93e5ab1c23bb14e69206864c5fd1a4be817004aaa2c90c134eeabda1e87867b1a365b9d0dafb6e34a7702c119da7c98b894195276cc80e5d86f2a2ce6717ac31ff1012b2b39b66c806aba82e80cf05b140af00ef3f271b4d4371405277712e36a56941919c624fe9555018053b0afd66c0701273c7c4b4df7e84e132109a2e5faec30a378c3ba2009b3c02397e7a81d3a7be4451e0ac19464417a7291d93028ce9f01a94681c6c4366569dd9cd01e845fd41ccb8a1e445ded75bc8119eb3538de819847bd87cf164f2b4c6813a29cc2812a01203068cd8b25d59d6af6449529ca860801dfa99885c8dbcdce282ca6ad63a389a350ba988cde43089a291d4831a5b8019460774d4c62f6ad2251131fc0f3505fd021870cc73c9f4788c28574a059e3a661226b08cb10d1ce3434fa3992000c002d7e52b3fd13195910bc35ace9d07728207a50602a11578f89b5d9e8da45ae689e0a3f3499b76e05ebf62c6d6c66c8006643cde9efff32e8339ac7a76229c32f4bee6b9a479522ed4153b38d9293a3c13d13743527fbbcca6182e075c9139e005210d5c5fec706015e98eb37277a8e7537b1a99c1433e231f8a9a260f1ff477952a6540138ff2113f2501fa47656f1010c796eb113c58bed5ec2bc345c626ec5dc541e5ef6578691763a6aecf6ce80bd745efe4f5ba5bca99825a0c390e8c9000000070da7ba3d68e13338e0ee23afece9d5329842f07cac052cc5c1d8b76ad947a1610787417dd021a4b758de2974dff8383b8cae702215158443b7bd82313329e78e1204f099508b0495e17934ddf1025a114d778de9c983f5049e333f96e31318120ddbc8fddd8ec0c0cb31d806e292768f3969b8e6c07a7dac68e1e1b5bf616eef0424a2ade2a5e153b2d1fe897fbd44077b76907dc22c8d359781e835d74b9e7b10f2556c99a1c0caaee54325551630aff5cc0807cce97f1551fb3b8e63a91de804e01a567b8ad5e77a556c4d22322a623b69e570db962fc6c57641d3802e2967003f94d56c05840f11be273176beeca8f2df1e55998e3ec66878820d52259adc3b50f0ccbb0357d3291c2e45133ea22c0094862249385ca752c4c028495d663e07c118b5c53059205621b740e7cbabf1ca75fb9e0f729f8f124f6590dad87341080f2f25bf6e40ffd199992bf662687cca92cd28b0ae9cf5dc959fd718a6fba90000000100d551f827c8f4a0bc293490af80f0fed50fc949f52b8a1c155110d7789866021add355e1137b0b5284b4aad346888bb00bdde89038a311b7c09040080273a3241b7fce9645748e44a5015e2535ade474b3699acee2d28fbe176421dd5376674","debug":{"publicInput":"0x85026d7a9847ca73aa12735ab2c2540ae1bb1d6666f3e221577b977a33b1dd8"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/35-37-86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/35-37-86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8-getZkBlobCompressionProof.json new file mode 100644 index 000000000..ee19fd76f --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/35-37-86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x010f6596abf90a103c9558772f56e652de5ea08805763035539bf14bf3c23674","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYJ9YcwrXpuBRcO46XbW0BGeT47eVsrQpdd3IbCO7QpG5rticwYJCrqzpuFADpNFvGDB4qL71cC6YIFORuEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZKMNBYVb11MacXM6zur3qeliHCPh+oXS9Gm4uikS9XxcFb+GAGQc/iQBk/gQDJp+rn/wACRI2ghVnaZKmWL3sWQnlVsXV9q89wDRdvNtKZ4AZCT/wwBkjv8SAZI/w=","commitment":"0xa8ae865bfed6134818b5351ae988daa2c9d9d36aa80d061e31a5a405f5e91b36dd1c1c9b4c61061693d645ce72c6dab3","kzgProofContract":"0x8fc4570d6b7747e31e7b380f4cc2e602d64332373fc3b48524d9984544e88186fddbc93364cfba5224c8db4e05b610b1","kzgProofSidecar":"0xb341368ce576f037ec6cb2acf46f229810522e7d7fe3dc5573668d8c324ffbf91c73733545c5b61d125188ee373d568a","expectedX":"0x5159e662a9139ac484a7c4ee2fbaa095cd6f3271624999afa2abccf735e2d815","expectedY":"0x42ab116f821254ca906e0e4a6fd09f178dd8eddda3eba132e91b75d7e16dfe57","snarkHash":"0x10004e1bbcd2739670e91b1f566622cebc1ef7fd1333327a8e89502974a8b7fa","conflationOrder":{"startingBlockNumber":35,"upperBoundaries":[37]},"parentStateRootHash":"0x10556468275a46e1261bd2af01c421e81af255ab49f932de2b6352de9648727c","finalStateRootHash":"0x038f427f164b4cbd3733505c5853d245d3ae4c25dc69716762f2f7f7df68be1f","parentDataHash":"0x011531090261c2af287fb3f766eb58a8a11ec7fb958560efce58f8ec03e24e5d","expectedShnarf":"0x86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8","prevShnarf":"0xa646621c48d374488e214c7e02a64d431ae0712f3bc817a3d5943914f2246831","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x0138904335e4d85f4041c7b1c823fb827634bf04a223423300692e094ba1252937d2e1bc198e5045bfe2cd7316d6f06500127f80e9a42fccbda3fe3fc7257631e8ec2c94b03b2ad9b22ca66f7bbaff6b832d38857cfe4a53a517d6ff514287cf00b065f87eb3dcf1fd062f54457bd3747396dc74ebf693075fda4856bddaf0da238af834745f589c5465e9bebef48102011a665c6e00a1fef0b2a9b9d2bfff5c1ab4c403f657eac167736d834a3efe469d8ad7f07b8d58367815263589671a1a005172cb5be452871913406430a73a1a0e8ca6461975a614d3c1396592cb6451f982c25b00a894461d34bfaca887d6e100cb8e70822949e4eb24fb9b08c0ff0860daf5a479ae73f63760d39920e96244fe6362c6b46955cfa43fc483562740c700f8b0d9e36a8fd4aa589dfb72c90709c01c3c77100e663840634a9eb3d125504e562f75b2cc3e61d932df6151045701001f6a7f9717f8382a16503336eeb63a7ae7a6613d8ea80ccf4cb582ef3bd2e2c1c79f9152278542471a1ff4f190dab300ac5357af49142b13d71852f33384411e149d612f92d15e35295ec8e9bedb3ae85f1b980a70116d1b1d877409b9afd1015f54760c28368b76004fc3a2d5b3ce412a3684b392deb19a9a0b8e19b214b9c123a917c152823c8b6a6b32fc4c3cfa0033111d437cff950caced99105ce6ca82b3aef3f5ac442bd49155c4d100f13e70a57126d8eac29cbd62af4049ef3d32018df891cb1b1f6eb822b1ebc78fdb9ecde9f6cf8889aac946ead38a44383a3d46131f377d72fcc9153ef6caf6c87912009743a500bae16bf920d98d44cfb01689d764e32e7fbdd00dea33900fcc54901e7b1a020aa56e98c3b7360670ce645600fb7e9cd4940198e46289aa86f14c5c31039448afbe9d09cf7e1a8670b5d88367ce96d8b16115e1781d7cd9928ca9dc014a0f409f788107001328a82e77cd2ebc06e5b6c7c97f62d8d2df847c07b83f62c29c2bd571ea292ca9be92cc440b6900a069e97646b4500efda274c783e130eeec9a042a9097b283a401c0a1f218981ed5366891f9ff68316b165bbf2bf33c00000007086aa3037db3f53cb8555f5901c94004614946322af6d0a909921185a4859c88035c3516a6a458fa4b413fa1001db604134ad194ad3d4f3317a6ecf8b8e067320dd734a31f41edf400847b0923ec79efe15c2cf1c1c85077445a3eaf9c57eeb60e191516df1aa1eec89036179bda995decf5879196a75ede9e6217fdc9ced15c0a925f7088de2f1df04bfb828fce1ccc7dd057655d5c5816f47f591b5d7be9e60a1f0f1753a7db7cee8cc08209b016643860a17af74613a5f685b8ee773df018106d5f41bc4d495c85eb349f769e77fb312d8a40c2a665d1b64bdf00bb5b53e701a8d5a26ffd7c3cc2c018064f6083173ba5c5f1d555425fc58a9be27f4a71a7fa6cde1f178389cb8767e9b5a7beb76c004f92779d074fa7095bcbe718ad55dea75dc79d42e6595c5002890a5baabf4c69984825c4257ba8e4746f9996768ce40d3b16c8b33d40069e9ef799131b27ffa3c8751ef7e5bb3d7791edce001d1bc1000000010069b39f014cc21a0f219437bbf5fcb6a6a3654ad5d87e6b0f9d99a3d601ebdc4cec5aa57fbe08b5ba695e0db03640dd001968c26640616c9b4a1b9e2cc16978eefd22d21e0af6c564effb3204254a7743fad7972bedb9032cd223f39d629ad4","debug":{"publicInput":"0xa77a93797117f3499b782c7c31ed336484a1b73ec40ae20243dca9be28f21cf"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/38-40-dec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/38-40-dec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446-getZkBlobCompressionProof.json new file mode 100644 index 000000000..c58913620 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/38-40-dec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01e5edb2951948f86cc72f924c12e14428625fdd76461f50ffb63b71b0b673f6","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYKtOw1iNkzoyNKNUobYE5w0DtEgrVZLHBIBoAdPulQWNdpicwYJCrqzpuFADpNFvGDB4qL71cC6YIFOR6EWWgvAP4DABA6CUgiU/hMAnZIDA84EAZK8lc7T2W7v7dA24cRNIWSTb6ZHg2MSzVsX2qOkz4kFie7+GAGQf/iQBk/gQDJsxM339uKtJnGYsm9la8YJS0tKqyg6nElrlirIF1Z5b3Cv4YAySD+JAMn/AAAAAA=","commitment":"0x88ea002a6837e3e8d028cf685b099c4cf390fd030173e9c629b61cea91d34f5a728409c9398a57b83257fb4250ea3203","kzgProofContract":"0xa5ac0c37cd220bfe76c7d64ef0fb7a4a014c86d5040f865ec75e3b93c14cd8631484659858241986d745f160c0cee3a6","kzgProofSidecar":"0xa264c904fc01294c2a26ca11ce9b9d11377909d74751d6f2ab44a85a490226b07bc70f5d0e32467e07ef74a33e9b7756","expectedX":"0x91f0eb80c6e34b3ffc3485830b2570d08c4f0a00b898744ac535d216ff67f19e","expectedY":"0x043de442b97386f9a5e9b28a4186a83c499e0628c82b56da5d04b04d243187ff","snarkHash":"0x076f8610e23df1806e0268803e65ebb888bc81093c34922cee5be808250673a4","conflationOrder":{"startingBlockNumber":38,"upperBoundaries":[40]},"parentStateRootHash":"0x038f427f164b4cbd3733505c5853d245d3ae4c25dc69716762f2f7f7df68be1f","finalStateRootHash":"0x086b0a16469f68533a059d3dac85f21d2efaaff0da66110093f85b08623b2cbe","parentDataHash":"0x010f6596abf90a103c9558772f56e652de5ea08805763035539bf14bf3c23674","expectedShnarf":"0xdec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446","prevShnarf":"0x86dc4abc4be5dfa0ddf8f4b8b98783973bbcd82b5ceff8d39361fe151d4e2ee8","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x0181db222ec5f8f5e7e9e7388bc6514f1388677373817b78cc016fa57cdb2ed3c675704a13941945bc4c950a33a7ee8600d24c77d2fa9a01b6fa5fc9157144c749c7d2231781cde12674764e3da34bab52e5abd8ba20d101a484e9d3d6580efd0161494305fb5c522058ed992feb120c61d96e08a8181d423f2d5a24a446f28eb31c69c31461b822b2df68868523957a0138af78e58503cedf79217188fe5f36a491173079b059f6731459ed1e20c1dc14e73e328130c8c73fc9b38cfddf6f54000cd7a0eb93e0f2f1082c5ef8f9c43e4c98f1d3ec62a5fc32e3a2242e6895a8304a4a8782ff1b31f0dc17d68fadbb4b00c50744cc6f625c87ea2becf5863a1859d4e059099fc54c2eb6a42c844049de5e45c3f5ab3c761cdc3d39356bb83d4d0083531d8003af2afa80f811ed28daeceae989ed9eb4b35610577dce42ac9b7110f72cb35e2e356538640263bbf3b8cf008a8f39034e2e67f37513fdfe026878afcda6740aad3abdfcbc5bd9c0fcefeeece6149efc6c1d573c6eaff81e1aaa7600fd68082de2feaa76e365fca89c153da77e2116fae1a2dff647e87bc52893ced6bc758a37eb62ca1c55c25ebbe790de013deead8457faa6eb0c5a31bc70cca9e10e2eaef066dc10225503afe1fe84eb7523ba8309685a761ddf8f832e0b350f018086b73d400b6ab3c3c384bf4ce8a226e5a9e52b704e449b80e127256eb2f740fedaa9ec686d9f6977d2c0f05fb4fb00dc2106dcbb572fb1dc553682e5040cd48c58b4279726f5d7116428553a89997e2ca9e65eb8801e7578daf68710465400064128c1022c2921011a5002bb20d0a39a9121bcb99dfb22a637e72807c68ba63ec6c1018209ed82c43e6f236e2bef017809953b5acfa132ec1b0066c1edade9c9babe5db1453c993c67e3b66b6dea54d2656b8bf82d7ede01eb295bbcc0c401090ba5a886c2ffe27a67d1ee3f11dc5798a608704b704db8b02a30c16d8f5dcb08086630a134feb9fca4369f04998300679775bf94e1fb98ae3784b9dd067f9218b3f56b1c59a21300055b1c99dde880ddb3403dac1601e23b2de3287cefdf0000000701e67668c26ed179e2b94cbec1248564b3027f559d45617dc1b9d019b8b4666b0b989711d2e989b5cfee9b501f6b325e3256bdd11ff35643545ff46a6ae3e4c302d9ddab6b9c64a82bedbe9d8b574908975dbd719dbcc4eb75d81f6fe1cf768f0e46f5b614e3252311e5de6625c3928787b070a57d107c3e660ed4d36704b6c0013e7618e553ea90615ace78509648f2ef4c40abd759ae9899837b9b00ea73130d8bf532b6ea5c1adfc2d7bfcbaa59134181b59ca6c9440c640bbf31d9546d1011f293d2e06bb92de93e8578d3fa2ae857e0e1d7756f6d87f9e6a390143562200011cbba0e78b005b24929d5949d8afdfa46f891b09549297df929e07fa27caa45b83876a2bd8f17c1f1695d4bbbaea0003080723a873fc1ce3b4d857420919d29e3fbe2aa2c87a06673b29f0f55f78d03415ac91410e70db83f5d04a0ad6a49015634f3d5e9c7c88abd35115232bbd54aa63a2768f1e596d4319443cda5a23500000001016b965e01794ef681425fbb2c30008b73caa989228b0a9c7c0cb3a32c7a120e2900feb021543ce2878a30771a4533eb00a70767e519a9f0c2edfe5d362f412da10a98603e3370dc13ab090dca07c91429875669ed25950c471b9fc1918e3956","debug":{"publicInput":"0x8caf0411e624104c7f00762eb90895515cb61f1d5da57dc76ae739c0414a66a"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/4-6-513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/4-6-513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025-getZkBlobCompressionProof.json new file mode 100644 index 000000000..0ce91e43d --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/4-6-513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01201000a6593e1362c41814298d3cefae56c41fb2726051d0d7638e355b5b15","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAGW4AAQAAAWeFX7yZUf8AAj45OYnto7TPu4NjEqbjb0zrhAuIB6obQ0GIW99WbmY3NX3YZCuxW9FGbAP5Z4ensHL4aAF8jDZBApyCQAdBikxBQEBcjC5/g4Ia8GIAABH/BwQ18gKLEADB4cAcB/AYANBnMDAgLAgKUCAwgxAAAbyP8BgAvSrLcAwALAAf4MCGfHP/EwQdF/ggIaDv4UAGf8FBDUCgxAACNq3+Dghwn+FAEKCFpBQkZBQ/gDAJGIAALGCYgAAhFZb/gYATYgAAw4FiAACkVluBFGIAADP/gYC9/gMAtgVGQUGIAAOP+AwB+4Vlv/BAQ3AtsAAMBBBQgGJCrEAAIErsQAAgLEAAD+rLf8CALoCJQkFC88BgCGkrLcioKH8CgGLCLiMAxAACV/4WCH52AENhBhAA0/wgEPuNINLeAowgByrwDHHhSZiCjCAIavAMdCj9yqCjCAN3+DAh+lhAEFhAKtWWwBb/wQEQip/8DAVTCALDAgGL/goIf7AGWRkGEPYVZb/wgEP9fwIAVPX8EAFUqwAhAGwHAgMgwgEh/AYBVsqy2wgHX/AwB5RSMgwiA//BQBOMIBZsICB/wGARXbCDCn8BgA+Gwhu8rLast/wGDbyCoSH8Bg3UgCfwqDPwP8CglilAMAApMCAwABAwAEioSCgin8CgC6AosICIyDCHif8EAVbAAeEAKwAqwgJarnrAAQAfHv+CAiFaQUGAA/hUIaFmBAUWAkAf4DABSCBgwMDgUSkGBAUn+zkHv/HAcOe9/42CGERkWYCCCAYBR/hwAkgyBgxYXg1JQUFBQ/gQDG2f4DBNqv+BgNWAgwOBYACGWvBkVBQPYBgAIEUYQIWV2BAUZFQYB8ZYD89ARaC/gMMIM2CUj3+AwR6EAT5hAv4DCwWCRUFtQUICRUFCAFWECYvyAwDJ/CMN5/xwFhaQKkwAgCwgSzIMIj/BINt+rf9OglOBhP8Hgl8KtfX8EgloGifw8CWgaT/B4JaByH8VAloHA/8dglvGTRNX/NgS6CG/8PBLoI6fw8Eugjz/BoS6wglz/xUEuAltIMIjF/wUEufxEH8/xWHXUbx/AAvGffzYHXALEfw8HXAuL/DwdcC5X8HAqAMIfxUHWgwPIMIj7/wUAqH8CjKq2wDsCw/wENqiLCDeqv/AY4rAQbB4Db7/joIiwBkW/iAAg/wQEcESH+Cgjg4AIFRhBoeRkGESRlZb/lGAYYGQVVCAgGEG7ZBhEoj+BBwVhBhdWW1D+BANJgIP4VANMHW/4JA02Ag/lYDUYABgMJBQW2BI/gYGmCJz+WwSmCC7+ZAaYIlP4JBpge+/gMGmAGBQ/gMDlW/4GCjAmCP5bCjAkU/mQKMCXr+CQowIpP4FA5WD+Awcuf/gYNyCko/lwDl+v5kDcgpg/gkNyCYr+BQcug/gMKxpP4GEWAtDv5bEWArg/mQRYC0b+CRFgKcP4FCsfD+Aw5f1/gYU+DA0/lsU+C8b+ZBT4MLP4JFPgtW/ggU++v5UGEgya/goUPvr+WRT79/gMU+/wEEom/wKNyhu3/LY3KGtv8yDcobif8EjcoZ+q38CnGzABKjAAobCG+H8BjSlkrLaAkIyCiH8CEewCwhwVLSspJyUjIMImQKy3/BxIX/AZnUioaIhI1/A4BYbfwOAVwP8KAFcAbGbAAGr//j4BWJFjQ6Mv4HAH6Kl/4HAfxRt/hMB/AlSDg/4HAqrH+BACbX/hACmgvOBwMvS/hYAg/gcDr8v4DA5xU0/hAAfgFGQYCABIGAC84DHVlD+BDyIBd4BhFWWDOQGQVv4iPxmEPS4JhDyD+CA/EYQ9bgWEPQFZbglL+CD6IBkFBhD3ZgAIMBhGEPUv4CT73+BECd//x8Atd/wQA2MIfbQLCHwP8BoDrCH4P8FoA4a/wGAwacCwh9b/CCA0wh/ersIf3MIe+fwIgLsIf+z8BoCzCH4n8FICrAAQP8DgXogMwLCIA38IAXogafwKBHogIfwSAwQKj/BAIJAyH8EAJK3BwIgKsIg3K8BBAKjAMIAqTAQQP8CAIKn/AZSzCQgCpfwKCzMAAwiELBMIgdT8BgOkfAwrCIIqstyagwiE/AwrAQQwCwiCgrLcBCAP8BQFIwiFvBQjCIPX8Bk5P8FAOMFBKX8Cgsf8CgQT+yvA6Mrk3MLYpMrsyuToQIzC0tjKyf4YC7nIIBUv4FBuxECWAVg2EQwv4DKG2ERFIJhENNWW/4FBsJGQ/goG9gYEDP4DBvVJhETiBYRD8/ggHsf2NhbGxtZVRvU2VsZkRlc00cnVj/gwBx/gsBrdWAb/gkBrgIJhET/+HgGukgWERaD+CQGtleGVjdXRlQWxsIG9uIHl1bENvbnRyYf4IAcP4CwNfhYCD+CQNfsgmERq/4dA1xIQgWER1P4JA105Ie3E/x0F5wf4WCZb2AAYRJRgv4ECN5FQYRJcg/4ECQpJQgj+AwvmAghEVYRJ0V2ESc2ESF1Zb/ggKgYf4NDRxKTgmBEv4EB2/4DAGANhEqdXYRKm/gUAyYAH+CgZJhEr3+CQBryP4JAawP+Awaf+AwGvgV2ES3/4NAa/4IC3xL5gWEQub+CQ51hEwr+DQ74TGoFhEv4ADkf4KDvsD+BA74TNfOAwgCJYRLw/gMAjQmAggwGI/gYAMT2BAgwGH/gQMaYQTXGBggwGG/gYAMaWCAgwGFYRMR/gMBXdmCg/gcNBl5SUFBQ/gcMGYKD+BQGCW/gMJhiP4GARqNgIP4JAU7BgQD+CQFO9/gMBghf4GAbcpggP4HDlZaV/gkBS/g4MRgoEgzdgAIODAVL+BwHIfGWAfgwH+ChMQUEYOFYRPU/gQOARQeg4WEYRPlVlthFCeDYRP0VluEAZBQk5L+BgD3+IBHk/gkSwFGeBYRQy/g8FM/ggNNFIiBiYthFAX+AxTxhESX/gUFU/gMUgYRSk/gUFUFF7+AwIWx/goFUFL5ggP4CAQAUy2Cg/gcVUmJdQ/goFVYRTjgoX+BhCthFO/+CxDH/ggDIYRUG/gYSAFRCB/ggD+FSD+ChIBhFSmB/gYEB84KEiGBA/gQXSFUn+AxBSF/gQIT/gMQhIP4DEIRVbgYQYRT7Vlv+BwGj/CATqYwgAh/A6pKAq8AwgBB/hwJ1s/IJAH/4FVkTb+CFZH+A1EYUYQA7V4Bj/gNHzFGEARf4IFYZDYQBP/gNWGYQBNYQCK/wQE6sfxQnWAEDIMICA/wRop/8Kjdwt/gIE/L/hEVmT1BDT0RFIEZE/hgQi/ggVmADrYAmDYQCk/gQVmAPaCYQC1/h0VmARqBYQDe/gcdT88KBO5AitMB38/wAOXyy4tU6bd4y0MhSUDnT+OHtK4gDt8cccjsyRf4OCdyBMAM/4JANOY9jvJ+yNp9EWlJ74+KjhkmFBUgSZcN0BVk0GPCmN2Sv4KANP8MA5M7bVfFQMVs6/em+U3atuWfDEbop4H8CMVOE78rgwqSuuvbtpsbiN2Ri0wZvRj5nPT2VkKQqUM5lHYB/CjFTzQQKcgsAHQGmJaBKTL/h14+Mnl7gCYMAO2M9CfEMTAdAQn8BrvOB8wIyF4yVUTd/Anqh7MdFv8BKPWcfnAF4bqk57HM6YABwSvTb2n8MAMIN/EIDCD/AAAAAAAAAAAAAAAAAAAAAAA","commitment":"0xa4b33ffa5de01cadb07ec72b235ab19a3e45efb7b978ac53e084cd2ee8b29b8e347b1cc828134c4a76a4e0450cb1211b","kzgProofContract":"0x90dd7c402a931f882b203058f1241bea34a3d0c444c344a90653a9b0c266c6c4b4521b6049e210298c1fcf038c346e49","kzgProofSidecar":"0x8f5ef32ca181ed02c546034656dcee85d888f805e6b103d59122012a1376abe03ecfdd96c361d23e933b9dabed892ae3","expectedX":"0x35f257650f08ca1a59a84061cf5497818d4b7882fe4bf0841dc3a8e0cebdfdee","expectedY":"0x01b0746ec8e682a59b780b234cd18ce19d5f50766b4f134e37196ee834ddae00","snarkHash":"0x0be139d44d334d830b01c0a90afe5773c1b19a011e17d38b981326244a44b20e","conflationOrder":{"startingBlockNumber":4,"upperBoundaries":[6]},"parentStateRootHash":"0x12992d60a0ff80d1c2089da74125c185a3bedafb1ff68e26e0cbfcbd9055b1f6","finalStateRootHash":"0x0f603fc5fdb46043a8a04bab525d7f4d966ee254608468da2fef80dc27f54ba2","parentDataHash":"0x01f48456f10caa5029fed9b89cc5d2b3853af3a1b76f0deae6ebb5a2dd1e9ea2","expectedShnarf":"0x513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025","prevShnarf":"0xc185fbadf462de3a6c8517cbac3ba7402a14e939e1d77e3a515ca1c8a3f7d977","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x013fc5fd42f8b151c71ad5bbea917793119c8e2e09fc33a289e2b3f0d6909f2aa0988bc1c1fec0420175ae283aa518db00fb9367f93505cc7493ec7c48aa3a727422905c0f82d56e675498464a5f62bacc6a01095f21b12a0f76516e6ebf6d80005ae49fe2dc50a51b9124389a1470de00f64fd5646566791d54d5729b364a8e1a61e37077d6a552f75afe5f2680f86400f3bebe0cd08de00173f3575c97c3498451df5c67e13a09176c8a99fc94601addaca6317e12e4e19be5f643e7c97cef001c14d2f7b4ada58028d966ad68763234c7d098ff0b05831fbe0dd190d0ddc06cebc1014282a51793a93a3e8e0cf514007cc6537c68027bcd328835781e9056ce40c2b8018ec793a2d959f63c9b5a4b6b8e74ae354ccfbe04fad16f3e9a57f100e9729e2b6829dbc72107ef9058349012b719e3d93a5c3b4cb95f9764135ccd4efa365d31ac96497b06e6d26c3cf0b70106f3229d1926dd38f08d65a2f1cd440712cc58acda91ad8afe56288b55ccdcf1897832b2e124ccac0d7c992314796701460d816f854aef5b50019257161f715ad75b81c10accc730ee13e32e950efe38304136af93d264f8d065c4835516f60180d964c73736c5ca237153e1471a6df2edca0d72788e12c2a425727657acb0e4219d400facc9db001ae7b0d4ffa82000a931073091b32430ef1ca7557b3556475bbfaee3b660699a52014d84e1935d9f24205fb8ec494228c73faf7bd56fda0032cd2bb85e323a4f8a326cb02799e9d5a035fa4fbb0bd99dc09afcbf2fc04a6d1f1b20fb141bf2ee21837fcc91e14e0115fe9302cb97b5880048f687b369dbc6e2d513f1f2bc5a4efc9912b7fb2cdfe90e34993f3e1a612f80e8a0f8bc7cf801a8af57aa6a1323036432c785e3280e52726cef8691ac51ed7474b82bd142fd50fada15bc8dfa1d37e3630f70ac07c7001816f9f705c979fedac704638792542f3a534888586147db0fc14cc207ccf0484265a4e75891ff9f3020c93cd94e6e00a0a73417ab3fa13a6482e19b29634762afe22f9ad73da4692c70e3978d289dda73be13b6c7d12049434fce6933d2c1000000070baf3bc46ecb7f93b6af21a8dda226f893a571ca21137e2853a46f9d367f20ff08b6db98ada60e39e2790aa3e722265f76a9fe0c1feed9354b9ec701f6068e8c0b472aa936d3c1ac74315aa3ab6a84280cf0e1deab2fd54a58d730de4d7c99c0067bd7610d07406291282488b0d84f0730a3cab54f56dd6676615e66505688f6055ea5310b27a9d85a67c1b9949fb3af4df00a29505876a5f0c92ac93ef3db2709f9c707065bf99cfdd57107643f22cefd4e7a1ffd98ab690afffffc6ec0434f005a237c1730b19437bacaa353b49aa7b604c8edf4ba4ffce91b20eb5cd8a51500d298bd1c0efab923971eff2069e8007a4fd8e2572c9ffe1f998dfdc3cab48d4e30da0aa890987bf3262e391ded95a3001a006666c60b8b79db7fe36716f948a0ad6efbf6b2a872730f93788607862f805a0ea2d93b66c4dd4eeaf26d3de1e60b05f46ce37e240bcd8c9bd09a9ab9ee78858095b33d0cc9b95dddfc7776b68a000000010143f378c1e471de884daaeca16d35903364ffed01dc0e1a75e1ec6bb1d65213198cc9b1402317de30fbbb5e8aea4c0e019a4530fd01a28ae6b1a2b3be1070010748eedbf0f55c2fa5e547e9a59792c2bf7df47c65091c24ff9f064999786fa6","debug":{"publicInput":"0xafd672e17d75b7f2cd85363fd0f8aae48980939381b157b44af0e9a13919715"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/41-43-67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/41-43-67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695-getZkBlobCompressionProof.json new file mode 100644 index 000000000..b021cb64e --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/41-43-67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01ab0956525f99b22c1ecaf9757afba9cc8e88b55e1e56385cb4f8bfeb986e78","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYLey33DP+OOhd34nrN+K7h0BZt2AonPh72J6uEMd3WgS79icwYJCrqzpuFADpNFvGDB4qL71cC6YIFOSGEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZLsE89kAMenwBQ68jZTgh83WOfBgSVs14SweetowUfm4qD+GAGQi/iQBk/gQDJvy2px+cpNqeFX/xEeKjAKWbTH6vI6zwtSEmXImGiB257f4YAySP+JAMn/AAAAAA=","commitment":"0xb9d059ed007983176e704d6b9d339fcec406509b1b791d7986d7f19d323cf7ad38bcd060cd34fafef44678f022182012","kzgProofContract":"0x813564c93ac8a268eed8b2a36d01e6ba3b73f2b9804c388cdee231105b58d9c48f474b6803b7a9dcc2ce970c51b9cff4","kzgProofSidecar":"0xb2b6f7e1eb2cbfde8496d49c3e523a7fdb14d33108d7c24685a71c9ab8013f97a7784b5a61372336c01fe698289cabcb","expectedX":"0x5924ee5b7142b5737ed187b3cc52abbf26741c8cb7ae966e1f7cad22752247ec","expectedY":"0x666a9e9b0c0d562e1cc636c44dc091e0d0b9486167c74a9050148cb5098ab4ac","snarkHash":"0x037ae0babab25f9cb90125fa74a38ffa96757031a776254dcd6a8c6a73c21d9e","conflationOrder":{"startingBlockNumber":41,"upperBoundaries":[43]},"parentStateRootHash":"0x086b0a16469f68533a059d3dac85f21d2efaaff0da66110093f85b08623b2cbe","finalStateRootHash":"0x021f2681f4ce68e3b9f77c934ec0599899cfc96c873e6a9a7450e95c5de230b0","parentDataHash":"0x01e5edb2951948f86cc72f924c12e14428625fdd76461f50ffb63b71b0b673f6","expectedShnarf":"0x67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695","prevShnarf":"0xdec8e24af04a4aa184d63b3f68066b7633c2099aa042bcb37a234c5ce4210446","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x005f768c4e5446a5fa499956f3d6df68f9c8e108af232761301f233773c1eba2ea16335f278f5b534b130386a4ef5d20009ea82ca0a560a201b0d662cf316c31ace887ff81f2ca13d3f7a124b17ef81536222a6fba005176133bc9e5eb99bdbc01330a4b6208200285e3730f4465a9290411bb3260cf9388300d393c063084caa49a9c52f7bf897652bfaa69a42c2ebb011318abf31d7ffe05f423adb7e582ccac05b8223636715dde3ef67527cad923b96fb0b2c0e14e520e561b8e46b45ec40059ea108b9a6ee6c9985f4185be06645146c759b900327b99deb1e341feddeaec6c8f21b1045b016cf80ecc0ea421eb0119d7048a2260021ea71e2f04223764ddd20b0c3c385381022d3d44eb39ccfec079d85a3cf5692cc34653a92b033a7300247bcc911fbbfe57c67db3eba36c44b55f9a0ad332b55b541c320847b3c702e54bf15d24feac51b64f28421c42f89f00aa37ebadf3665d2f911760ca1bb4eb17c8f735ea03310485ab954e8647562eef4f4bca236e6268f91acf06ca4975b9008ddbcea12c5e294a5998de6aa1b3c7647506b53cbab1b5e8c10ca27aeb669be539ca8764082b2ea51267e5c3bc5f0401a196de16417157fb9a61edb2c3038ee3369c4e5de93455f61520ae21e8ab625ae6c54dccbce637a1cfd50a2306a84300c6b9294f9f3b087dcb615584e9e8d30fc6369e7ef97525b88c91879ab6cf41e97b6fbfd074081c0a6fd24b5624683100ccfb0c04214f4b980999fb6ada1aa94c2d6dc4d492265b7e932f75d4e13981f1dad4b986810278cbc71654044adbce007432d67bf8f2936489f922372cde647708f52279004752844d7f0dcb1c4f9e814b4f24fc8b90967ea44514b39a038f00e3a75d6d5188f4b41c4b554dc1426256a2a07591ffb5059692624c1e3e7ea07279ac40e114b344833982bfb530f5a500cde4fc3776b612c878e0ca7f75a6df04013081517d8b90aa9726c5f6d77ef98ed3d567259c60f6afe8b21d8f586e24002279e55c12795a103272547220043461a0f462c6eca937b2c46bd2416bc2c1f12c49891d2e5fc37cf89da5e7166a380000000707a3c1e65298abf000067abe4d14fa517dd8bef2d7a82b0528592123bd22620c0440785cd42ab55db957306cb5119186758cb6621c73094681210278ae9f197009970bc83b6a7ffee4ca94d76a91b6e410e80cce2ece91f903bbbbbca3c814f60c5e40b97886f45225e8bc659e6624eaad13bbb645b27fc971268089af53226e0a7692a95887f9de00336ce7b9366f0fd79aead5faefac43c0edd900bbe861a90439acf5d97ee256fd211e724fd60dfc7978cad8ce99e1d9feb13a1c7e7a486e06db9bc75d12fdbcb83f07748131ff57c14e5c88464cefe1e392d9e3d39a766301184393c1013fed558c22d785099ec3c206d313726afb2f3f51e7c7effa976b4c8e3c2b0e2dc6c2d298d43f466990810139b69fe8fa7d855c843e24a66894e1332d0c016725973a3e0f10b7929b2baabcd85068112d2a8e997db495d75d97490347e83aa5a763dcc300c2f8cf3b95e0b5500e24c9b1018219ee70d971b1b23e0000000101307aea552db3c5fd9b3cf833df839be6e4fb5fb1374ee0fd9cd20d1d66275f37364f64fefd956811404e38533327a900fe5e332b514fff81c5085c0fc55dc48e08ca847e81b45f5248c7d8e5837d753a6c5294667450ed7acfea55d54f89af","debug":{"publicInput":"0x127a19dcefd592a60d16a48e3a502bf3da5555d8383cd100ca90358814f0c98e"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/44-46-e3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/44-46-e3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da-getZkBlobCompressionProof.json new file mode 100644 index 000000000..7a0255b9e --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/44-46-e3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x0104998034ee589f662c8b801b219074675af50a522d9281f23e4ff8aea8df53","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYMNg7PIsb17foJWFBEnw7QiBiN6UTGpbzMv/VG4Fje61apicwYJCrqzpuFADpNFvGDB4qL71cC6YIFOSSEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZMd6fgOt0OZr/RfgK+JOFkDe7kJ0hnyVWwGSnSLDee4oHb+GAGQl/iQBk/gQDJzMqao+HgIBP6QVdTzXxZE0pAT7hENJw3YEWYVAWmtdCSv4YAySb+JAMn/AAAAAA=","commitment":"0xb65e93b0e8b4f4ab4a2433eb01f95908d1f4d34805758625fd49d13bb72a8bd96a728cb869a92dfc5af02269693b7527","kzgProofContract":"0x8e66724ec9eaa9e9775aa8877068d181437cc90bd33424b455de29f6ddb6c12574dec1a78315b497851b3c4395cc3a23","kzgProofSidecar":"0xb82ed057521fbb01dafee79644b15d77e30f46d60df713e42fa15fd203fa0e689d19aed9db0ef8e9fad063a9111d8d4f","expectedX":"0x2b5c95e024a5c8d6e9d767adfbd6e5e8afbb1ea1ab073d6dabf339a8eef4af18","expectedY":"0x267e4ae71dac6b64f616d12c0b12a5409f5ec513123778453bf6afca8305e15e","snarkHash":"0x01f556a5d2fee7beb32752174fcc462526b9b878bef030f26fa34233c78984f0","conflationOrder":{"startingBlockNumber":44,"upperBoundaries":[46]},"parentStateRootHash":"0x021f2681f4ce68e3b9f77c934ec0599899cfc96c873e6a9a7450e95c5de230b0","finalStateRootHash":"0x07a612f27fc38d0c22d8704b9bccdee3de51e2b3ec3c5ac3ce61f5e1926f21cb","parentDataHash":"0x01ab0956525f99b22c1ecaf9757afba9cc8e88b55e1e56385cb4f8bfeb986e78","expectedShnarf":"0xe3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da","prevShnarf":"0x67b48d2e3c30f21caaffe8677e9c8a84f43ae1e7ee936f0f8c03c4941cf04695","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x004070a15373a30cc508ce0453eff79deacf22c4883965b1b1738f6eac8fcd777b9e289896e37cf37541512ef1f3f23e00376a8179dddc64ba87cf5dcf05d0e06e70f76821312019554d49e9b2c0f3ac83fd8dbd9ff96d4c0e795312963023210066dc50be0ed7d9030e56ef630beda6b248deb04f1ededc0506f5777448fe784f2b78595ff652df49f03c07a088958f00f6bb273ac263efe144d7dd654609dd869ec01908afce5e5a62ba055005f3f0efe4d94478fb3f396e70f0a61c54612501785128c9a91eb5f4a6058be2a9369256c81c5914f815469c6c8a4015476c01034e8784c86da5ee9b939712e187b34500ab4420f5077a775d5e64826b2494e1fbc6b52cc312c0f90f780df4312bdf89a76e81170da65b24ad9ce9f4be1577cd01548040e80430b04edd6f9b5547eb529d05c2b905f8b6f7780cced8d807518eeca023096e7d22943b01268a941d3c8100cdcab8b5219b638e4e00c18ed408808cd3913c5cc86d49a32066724d33322093194f3beceabe01eeff29d771b86cf9009fa38a68f655de9e431c03d4edc09eb226b3d88ff435cc838cf229c0e6189220017d64c8b345a5e150e4e7878d75ab012ebabc892400c7bd01b78f868ea91cdcca4ebdd7ebdc88bf9d0ea71571b9079da6b600f15454f59e37810cbf689905004f4843155717cc623e0398a66651ab28ec41b42053605faf04a6d7bcf913c6e6efa223cc5af4c9bfcd9162c7d4a86701aa659af2b1c9dde6782e1c7fabca0a806843bcad4533a586a016f0bff8a231a55d9843f79cf882bf9ac53766fef45e0118fb4c9781fdf8085c37a8c5972ba2b8cf6330a4beebc0eeb0881faed096a552b1a52d36304d39d790c420c7819633009deb733591ac2d64d81a6996d5de3ce04274fae364f91b9021dd12785ccf8d2058fcdf2dd774cbb59742ac300cd49c003b218544132c803dfedc4f7a37e799f6bb149f294e4d81cdf477e38820b1c6d97ea3ce7bb1073b7e477f2c0476249e00c35ebc7917b47721e4f48cce1f6cdc4b10c5581da51ea89ce7a6e4e7dc6f48afea20d286ef8ecf6e55db79955e4172000000070d073de51afd794d9939e2eaa11792d702e50ba6613c2bf1e515ab4cf9549229116e735bccd2c39829cfa158b8881828bd5024ad4fb5e4d6644b9ee513ea53890f0e666a57c36929abacfb48ecd1891788a9d7e0015142c4618b1e321fd5a65005a728f4798da3122bb579ccc1ca91c364631ae90eb7e03bdcc77471f86334c10ea700b889b244c144d1e35a2133def3120f6dc03f8880fa4ebd920b9ed6e2ad115324a7ba7f0724b8290f027ce5fb5b09e36cb952a065aab24cd332c2d51e8008e9fe1e39028a19050a8d8f1956c3d9b921f5cd36b76a789ef90e560c5775120005161fb71a768e5e0665ddac9be04de4079090304d4ff3790c90184634f0385dea9d0e8c090ba24f9e3a695117a530012b7f960a7cd564dbd0c0a6fe9342ef65d1f0909249f957d90981ef29ecb87953efc0e8a3a40835d4abb036d54117b90a10ba23b1b5ca8a34ddde7ec7b2fbc3281a41db1b4b7691fb1839d03014ff88000000010043159fec81650afd6dfed546f69522ea21f247e214112cfe19d903f74b204b4670dc0138d23f32c9cb296100500f4200c9ddaff32f2cec559a6ae0db13a4bddc5226e2620e054c24f647dfe3fc19023dd96556c77b8246b62d14e292982bc8","debug":{"publicInput":"0x12760b62e87dcd4b18807a7c213d92a2d76c0c2007c76863a3c9f96dc72d608e"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/47-47-dc73dc616fccf89ba4b33ba446a9b73b5a1836142e0b1be933b7283f6f2b8061-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/47-47-dc73dc616fccf89ba4b33ba446a9b73b5a1836142e0b1be933b7283f6f2b8061-getZkBlobCompressionProof.json new file mode 100644 index 000000000..b8da579e2 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/47-47-dc73dc616fccf89ba4b33ba446a9b73b5a1836142e0b1be933b7283f6f2b8061-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01e4891ba581b2c658fd0ccd0b7084942b7e2ac4252e9d93b15bd71d41a44338","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAGUAAQAAAWeFYNBBpv8BBSJfccXONjKQMTUDl9mEm+8Tb0jqzjQe0GrCcc3yTMTmDBIVdWdNwoAdJoLeMGPFRfergXTBApyTwiy0F4B/AYAIHQSkESn8JgE7IQGAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","commitment":"0x9980568f70dc0b51ec9c64e3d9c115496e341fb8d782dc4a8c59611c7a1d005accce2d142ed4a2903af13837bb11035c","kzgProofContract":"0xb81586d096c043bdbca5da761dc0e686db316bdb45a5b134831019fe4bb6b6a00584542bd715622aabf8fa023a5a6adf","kzgProofSidecar":"0xb42478edac770629a9c3addc5cd9b9305cfc81f796789e6ac52398d219d4357ad937c6964942db8849dc5b8fefbdb0ec","expectedX":"0x51b4c44dbb7ff243628227c8597cbc6cca382a7f5c260e8d092c804d1aa7e2a3","expectedY":"0x25191ec6ae8b68aa682c11a97fb1b76473b4c686a81e6ac2b4386566cf3a847e","snarkHash":"0x06b336651388464927964c592958a9b5bb7c2ea2d1ae852b7c7c2c85379e7e48","conflationOrder":{"startingBlockNumber":47,"upperBoundaries":[47]},"parentStateRootHash":"0x07a612f27fc38d0c22d8704b9bccdee3de51e2b3ec3c5ac3ce61f5e1926f21cb","finalStateRootHash":"0x08a16016990b33c1fc814a077bf831ddb13bd07f440f3e7d8eeb7fde135a58df","parentDataHash":"0x0104998034ee589f662c8b801b219074675af50a522d9281f23e4ff8aea8df53","expectedShnarf":"0xdc73dc616fccf89ba4b33ba446a9b73b5a1836142e0b1be933b7283f6f2b8061","prevShnarf":"0xe3c210adb4a5b495db0a285094885c32b74bd6cc85bbe0e0b5a6cdf7e88387da","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x019271c206505c6736addab5cae19a152fc34708732c5e89d1db620a321ecc6e6534f23f193b9b19d0ecc2d34d7eeb970108a057bc021e84614f83be33f7b8a58f511526c70497d9b8a4709e486ad43b6847b73f60f1fb16acf6c1372a8a08a60009c8b21bcdcdfa7523f1fcc141c70993cd70eeeddab98d2d90899fe616a1ff5f0ff1ef6809027e45668a0164744116012276985fd89250507ea0612182c3f4d77932e019bced52dfd32b9dfdb792fae70e185461f2bb500b0e2c947be24623014d9f6c662546b9c3249e0b5c63768912b666781ac16f3e28ed8267f053b89868daae0e352ec068c4b7765247aa1fbb00721764422d9207c38077b149c8599be0e722e87c6d8d82c5d6b108d3945e7ad150bc861979cfbd5fe0cb72aebdb42e00261a8e08a6f801b68e94132468b40096b02ba0e29a52a2d95f4a1d05242e53d860af4dffa155f9f0d92476f5c86f2300fa3679c130783d08edce01b3a67c06a1f98e9076dedd2ee82c2e6096e22e58779f332b5214d8641e1a0e632622069b014e113d3ec0ca5bf5fc2acb022e1cc866ae1ba98ff1385932aedb597fd020cd89ac773a8c04a1c2f240cbce4be673da000b3c54b093a9804ea5f2eff3d62e604521f2f0ac34eaecfa12f81c637f1086b5cacc906809e97435519b479b54d95400f83bd803c728fb600a74ab5a1803843d70794083de3ff9d9993b541f378dd25a47c1f7cb84a5b6b0217727f2ce359f01338db9dfb27dd0b55e2093280f6e6d4adff3152201d0057ee47bef901c9b6d7260550062b1da8c7f7ecded90543fd9004d28839691ba27ab15ede4dd74dc600d788c54bd160bac035ed81ba89ad94812e96655af6df949ff1cc86ed824edc4017bc337568d138f77f6acc31c84ec83a99d985524e1a30a6624a76b82af6734f0d06186afaa5496615449c7bd6613e10020e71d85766c4ff66859f8a436157580b58c34c07e2fb507f8f9975582ba0a4055423e246027855289c59f60de6e7b011b240762096b190822ce227834c93da49739bca3448c29f9e0925cba9229a604cf1b65cdb70a30b002f95624ddb6bc0000000700ea431eb8748dbc6cac00beee748959b30eda33143daa26ddadd8c1f360b98b0fa6ac0189785e5d337d5c0783527da9d65fdd879ce51b9a2cc2e8c5ef61b26e0c58f3a9a34cf8d731f595af4cd738aff5f04e1ac93911989c2cf7078e9a1c3100eeb2f2bc7c93d43dfd2bc7f2a54466f21d52dd763952d8d23cf3649737ca4d04e84cb456972c3c0aa021ff26a97bfb4305c24dbc4c904be8a056b1d011a96c07bb930fb96b6ede94e10a34fe116d950388ed5f631e6b7e4cae21c21b68607c01f7b5ec821096a01d87c76709e83110d6e33454fdd9e32cd7c00564794c5c8b013e376bc9a91a2af0f8b8eda62e290b0aec029ab5e1d4673749ce341abe8938157d4baf2a5f0819c8b3a4dbdf94afdf017a0e57b3f1339d3c27b22871b308142ed9c7889f7b68c8b94e14d12d6b2e53f5a037df2160797e5be6107c847fae3b10aec6f9d63eb6a35517491cbd7416e9c810b46f13fef54622b07b5d6ac909010000000100c22f919dcbcebeadce04ebc4416a3617969e6571b1178c50ebc31e5cfb3116e9384715e5972665af71a25f1d461c1e008e00d4bfa11422bb6f85e5363027e8dd15fb2dc5b97bcd6ff45f9795a3f31a4c72e44a5c093e1fb9358942a88d846f","debug":{"publicInput":"0x77c1834d54f520974f8b332dc0d192f646ec9c3d1a7c0fa858317f072a79322"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/7-7-7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/7-7-7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb-getZkBlobCompressionProof.json new file mode 100644 index 000000000..320bd8809 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/7-7-7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x0122ac92a79da67dca1dce1ee4bdc30c4e945e02664463d0924ae3b1b9c96594","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAGIAAQAAAWeFX8sdfcGnMLP8G+CncyCj00SBllVLy2gCEAeYv2Xy+Sh2Ikbmr7sMhXYreijNgfyzw9D2Dl8NAC5oIFOQeADoNMS0CUmX/Drx8ZPL3AEwYAdsYehPiGJgOgIRpBpbwwP8AAAAAAAAAAAAAAAAAAAAAAAA==","commitment":"0x8839912b7ff8691e96d04e9422ec97fb935bf8928aeaf8f92a834b87345fa964ebdd5b2224e4045bf545b0bcd5aabb3c","kzgProofContract":"0x910b5a131d90b020ceb79174a0f4f130a5ef6cb31f6d7da6abff60169e5085abcf3a320f49bda75781ed7155c4297cb4","kzgProofSidecar":"0x83f1e95ca35e30ca9294af91dc459f84311103a55040f501550df8e0fd5f85f5271db168043fec9356d3cc79232af91b","expectedX":"0x4b00e9e2b96c643454cf1acc28cf685f948ddbc1fb8b1809b125cc04b6e5c946","expectedY":"0x26909f5154b9a6d019d91cae6af1bc690bb9005ea5833dc72e5b8e0a9a20ab93","snarkHash":"0x050b4aced7f075dad433db123c32b42603e77ce67b5f93b02531c6b423212531","conflationOrder":{"startingBlockNumber":7,"upperBoundaries":[7]},"parentStateRootHash":"0x0f603fc5fdb46043a8a04bab525d7f4d966ee254608468da2fef80dc27f54ba2","finalStateRootHash":"0x00e974de2acac404377d2d3856a35cc1dee03cb25af603f111442cf8d8b0c700","parentDataHash":"0x01201000a6593e1362c41814298d3cefae56c41fb2726051d0d7638e355b5b15","expectedShnarf":"0x7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb","prevShnarf":"0x513ed85de5604294e15b683fb22532c07a25531d93f402f17bb4a4c83a91b025","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x00a23af47d0a9709c1f529935d545e3e79c37859682dc1689bb55bcff024d74e493b7dcc103b5c53b0f986e658bab35000ae8a0dd3dccff134d203b1d260be50ab7d5b1f8882d6fa872d696ba3f7364e729366715fa0ce410449d82e2a1ba85f002d036b0abac7f916187a71ae8301debf66c704965fd5afd7e25718653a18ecd980abba9e9044640d6872878fc431e500f97e101480a2a21e3c2904f4ae1d48d0cdb6cbca9b9c59982fa6a169101a6de41435e4c9a3105ed7402aa3a4356db4007f16f162a2b70f80d20abeb844da1b5f0dec3a6003badfd8a710dc931b55b316e442778b6f1526720a3090b174e2ed011a7544f4a5fa98b146da07071d4c7be31440d309349c63a68d5da8cb9893ec690af6e90f511e60e5ea3afc91c48bb800ffa14f061887c3f6dfa3ab3a8a00831c5bcb3b32b096b0ad6c9a7047b138ef77c2bab962a5cf23f31339a3a9037ef300883ce9d630d884eebde44eb1aac1a5ea58e1d8054c854f79ff3ca719fddfc50aa1ae839081a3dc66be897add6c01200176358fa7bd897295a6adc274e6e659e024fd525cade3dea945eabc9462d31b899c55c58d8fbd93e33690e5b065a2bd0199368b0724a50f55ac1584e5fd30f3ca13b129f8e79b44fc322e97c277e678bdccad2a303df395785fa76618a1dc5d01662a653dcfb47e9765a3a30ff1ce73baefedb4125673898b134e0e485b004b1ccae038c831a47a6dbd3d9d24d8807200385cf8ee32d9fa9bcd9bf07b59d374a9fec1788f642ad7df331895f40b97a8652bb130a0d4abaec2765cbd62a88b6c005b17fc166a510469e1e626334db915088d0895c28c6fb529b3db12ca645165c5fe715bcaf6134a5e8685535bba6930002ea0cc9aed42d888f62a31d9c22c9a63cf38855530c53e7b72a11f1970ec350fe52e3be1a8ab6355caba5c6483524d0152ee7de90bce155a17a6b1043d306c7b9198fefa78ec63c8e938a86c8d1289cf5df20821f1693545bd5f232dadfb3d003128306a625119cbc05982fffec6182ee5b4e1eb9f0476b61375712d19e9b097dd95db9d8e61b9a4a0a85d37ea564100000007040731c20cf9e0adaccbf9b82a097c9e3e8b5d151027075e1c8b67c2fe6cf1f004631a4d68073b4a50ccd81062e105740556a238fbb77bbecee9a8b23c116c620eafccc932e22e8448a5232609b026005a377560ed61dc93ad9273e7a64254e710bd8ea5ee900a485d072beda1205e73bc21ea23b34464d9af39f1615d25ddf0097b9dc1e8675909a914ae7e2c3dd93ecf35f3492b2151f1d8196df801c97fc9037568ce2aea0c73d220245894e9385cd9f7d87fc2604562b7501b5e81b1737502842bcf1c35cdd466ebaefc969feb64de14bc0531fa22693c9f4c643093b8c80082fca0db6c0a2d263b55539df3892123ea5a6a0ed725dafdb782111efdb82beda479f78534bb647fb64c74ef688fc9007326547f3e97b86617513ab066f6f42bff1baee921157fd347948df22b33af7c0ab568102170177b5f24240b00cc36061ce55676e217ea42e737962ca8820b04e54cab18f8866474af9881c02f46b400000001005fa32579e83903a5116e13cd0d8003d3c76d03d186088021a7ab64156f29ca6bf63fe29e642f56905d10cd6d6d68d800dba923c8c2b7015064ffd8e4fdf7215c725528f6ebfb7bfa3ca8cdc6179439b6c0f028ba88dec135badccda86a0a53","debug":{"publicInput":"0x3fd011d04a20b79f8182be8fc90ca217520f3789da609c7c11064fd3c89d821"}} diff --git a/testdata/coordinator/prover/v3/compression/responses/8-10-e6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7-getZkBlobCompressionProof.json b/testdata/coordinator/prover/v3/compression/responses/8-10-e6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7-getZkBlobCompressionProof.json new file mode 100644 index 000000000..85a906051 --- /dev/null +++ b/testdata/coordinator/prover/v3/compression/responses/8-10-e6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7-getZkBlobCompressionProof.json @@ -0,0 +1 @@ +{"eip4844Enabled":true,"dataHash":"0x01c993ae52495203ab88827c3111fcf3b09c16655c392dbdaac614dc00473c32","compressedData":"P//DLcOwI2FMHAnG660DHNnI+LSRoulBjHV4RF2osVYj9wAAEAAS8AAQAAAWeFYCtie7H4OIl6mfOCG7s67wIhYeVg8ALDFACMJvvVCvxtDpicwYJCrqzpuFADpNFvGDB4qL71cC6YIFOYCEWWgvAP4DABA6CUgiU/hMAnZIDA84EAZC7IA1dYQGGjAS3wyc0PObzHDrPMsn9iU557/wAAkIY37D1bguP8MAMgD/EgDJ/AgGSZ1jf/AACah9TBhPD+q8uXzGs1eSSgdJ/m8N/vPaC9JV01Xqv/DADIBfxIAZIP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","commitment":"0xa5aa451141fe41b879aa058a20be3a9eadb902e7be4ee8eb7c5d26112e47728d3825f7cba01d64bb26a9f55dc2e0a0c3","kzgProofContract":"0xa385455eb5b14fb2fe4d7ba3d19d937a31dc31a99053496c9c93a3d97656a0fdd90eac58472a349003328bf998507b69","kzgProofSidecar":"0x90c042e73776f784b7a0e0f2469bd500eece6557f290ba30659826c85de769b7131dd85e01af310672e44e2a3d5cd759","expectedX":"0xaa7351229e2b16408a95f939adb983640536ee666204da38047aa64cb22971b0","expectedY":"0x5db2935089470a8bff08f797b4ee53249e3fb44dc7e42f991cf59b60567da524","snarkHash":"0x0cb4e1fb16c2eb266b8096b81207af2e856d76959014e7b468818eda7f51114a","conflationOrder":{"startingBlockNumber":8,"upperBoundaries":[10]},"parentStateRootHash":"0x00e974de2acac404377d2d3856a35cc1dee03cb25af603f111442cf8d8b0c700","finalStateRootHash":"0x06dfd5bf00ac76bece68984bced5f376d4a62abc03b56472959bf804c547d574","parentDataHash":"0x0122ac92a79da67dca1dce1ee4bdc30c4e945e02664463d0924ae3b1b9c96594","expectedShnarf":"0xe6a7703511076e3789cc25059b468940b2e91df262f11b95b9005f758482aed7","prevShnarf":"0x7db9a7cbfd21211ecd77d8791894eca4478be04c38002a415dce9eea9a7d39cb","proverVersion":"3.0.0","verifyingKeyShaSum":"0xc4a868954d361bf8c18d4b3699c4fa973a6b2e4543ddea0ce7970d6941f55758","decompressionProof":"0x0065f8b21dcdcbd60c44261b3bac28c7def612baa05fb88dde626ea512732e02d4168915ec34f318573cbd3a5704da320106a391a0619e36cd44fd3de0928a16f7634af98f0ef497c7a3731e853874846440ac82d7a8ee4574d3a514abc4778e016541f63a1e049c6fc858aef13088c7ecf3301229e68e28452aae82a7a611d716d4ee523bacbab5a3d0e786a75b0fb1015f6247b68a1e90e5c875b6bc8167eb7672e742deb8b8d8b920afab1ced31dff37d567f39537ba7d96aad85621e7ba60028a528ceaddd23b59ef3b1b5b52313be5d8086c8c99d1695ec84838969d7e411cfb5cf21e96ed56df3044350e3d4e701024e8898be317d12b9e5cb2ad1a3392427c95d9f01a79b14f91103eaa93924612de3cec48113d82efb41296cbbf6ed01952adff0a83b21add6fe5cac1e70e261a5e121151ed32a4e40fea7344ef7a48010a1398d7e167804067908e0a4463c00227a80a31d4a874a67abf84e10b12e2ae2ab1fc5a6bd6bf0c2da61a55af0364370fe7e4c717253894299ad8268d8ff00981208da63b489358c12ac728713a123c12c6c5df30d6991f583619a8f5a36c4887d848beaa68d6894efeef4a2a96c00ae3f3ba87100b0e8c0ce1cf46c7b0456b924f50a1e23b216a2b4223a5f36070b50996cdfa7df5a67172e6ac84a1fb900d7c809508a1522a583fc5d49e7529eb06d50c615ed017061cf02213298547c46617ba30a0a08927f6dbe567b8c48c000e0e5d48b47e17006615ab50518f1e12bb32abedc59a1ccf0122cbd4c3eafad36d384711f84b465813f0419d01c98e8017f3f954f7ab87cc748e54c641fca03137b10e50fc030d92e242404459bc4b80e32a6dd1a04e4186d699c8d021205cb005c818f78915877b39022722bfef4a1b56523d9f6a94ebb8b4a3cc5a4dd7443caf9060451e50701193945f96938b851000eb8f37b0d4b56b07c9b9416d3c5f4cc9a2c56f389d565f0d934411f75b27dcea279bd8606b868036729c515d080f900c15b357118ec7c61192962c8238aa01b635eed7b5422964c25da2c6c9a61c0ae8a802360eaf6324f94aefb4fe3c183000000070d394d5cf43825c4ae22df3bbfdfdef3b926c369a02cf4e2a0c47f23d9c93f3d0722e3870ef81055872672fce9974d7233676dda0f6b57dd78361fa848ae1ecc0e169233865012f39ca78c82e02a08dee010950dbbd99478fdc801cb32bc4eaa020f78b922746741a12cdf09d033c7ba79c011beb797dcd6799dd4d771451b6510777bd644338726a9bb25aa5f5358f93fe2fcc72cb017cd52bc222d15452b0502b74620aba1a1d52ebe407db0187b81a44791863f3e0469f56fdaa3c792b3e40af6d9e611a17c62fc6ab2ecdf6cf08e3ee77f3b6af13b12cb8995d4ad35d494015b7098609d907a2dc753d3aca3cd9233b860bed3533071a03eb80169a89988a99bae5fa03ee5f742d85065dbe3900e007d999667aa9b5d352fadef352305a8625017c76c8c34c33155ae4af96e4ce57c8d81e76975146b4f0726a9993fb9bb05cbdf763971cbd6bb0f52ea82480b0d0a6b7970f8753de83b5b34585b2a090d000000010056d1dd30270e14358caa017c55de8eff6b5c745675c7e233934d2849a3dc6aa168c3c6f1e563a5ab8809fb9743ed9a013fe90b1661ad71364a900b014f4fb57c62dadaba345043f28098342849c78b86078fdac79759a246e9361e87c1963d","debug":{"publicInput":"0x3342cb51853c46a97fe61fde0e66d7056d3dca38f81257fe90cc4ab0483349d"}}