Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x60806040 | 7941040 | 82 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xF39f6481...9643c7F80 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
L1VerifierFflonk
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.24; import {IVerifierV2} from "../chain-interfaces/IVerifierV2.sol"; /// @title Fflonk Verifier Implementation /// @author Matter Labs /// @notice FFT inspired version of PlonK to optimize on-chain gas cost /// @dev For better understanding of the protocol follow the below papers: /// * Fflonk Paper: https://eprint.iacr.org/2021/1167 /// @custom:security-contact [email protected] contract L1VerifierFflonk is IVerifierV2 { // ================Constants================ uint32 internal constant DST_0 = 0; uint32 internal constant DST_1 = 1; uint32 internal constant DST_CHALLENGE = 2; uint256 internal constant FR_MASK = 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; uint256 internal constant Q_MOD = 21888242871839275222246405745257275088696311157297823662689037894645226208583; uint256 internal constant R_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; uint256 internal constant BN254_B_COEFF = 3; // ================Verification Key================ uint256 internal constant VK_NUM_INPUTS = 1; // [C0]1 = qL(X^8)+ X*qR(X^8)+ X^2*qO(X^8)+ X^3*qM(X^8)+ X^4*qC(X^8)+ X^5*Sσ1(X^8)+ X^6*Sσ2(X^8)+ X^7*Sσ3(X^8) uint256 internal constant VK_C0_G1_X = 0x146c490b673b3679fa6143548cd90ecb2da85895a04494fef50391aa6897e105; uint256 internal constant VK_C0_G1_Y = 0x25e7bb363dab113de8490e742512a29a1094fa5ee2084570d4de714e795428fd; // k1 = 5, k2 = 7 uint256 internal constant VK_NON_RESIDUES_0 = 0x05; uint256 internal constant VK_NON_RESIDUES_1 = 0x07; // G2 Elements = [1]_2, [s]_2 uint256 internal constant VK_G2_ELEMENT_0_X1 = 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2; uint256 internal constant VK_G2_ELEMENT_0_X2 = 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed; uint256 internal constant VK_G2_ELEMENT_0_Y1 = 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b; uint256 internal constant VK_G2_ELEMENT_0_Y2 = 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa; uint256 internal constant VK_G2_ELEMENT_1_X1 = 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1; uint256 internal constant VK_G2_ELEMENT_1_X2 = 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0; uint256 internal constant VK_G2_ELEMENT_1_Y1 = 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4; uint256 internal constant VK_G2_ELEMENT_1_Y2 = 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55; // Memory slots from 0x000 to 0x200 are reserved for intermediate computations and call to precompiles. // ================Transcript================ // ================Constants================ uint256 internal constant ONE = 1; uint256 internal constant DOMAIN_SIZE = 8388608; uint256 internal constant OMEGA = 0x1283ba6f4b7b1a76ba2008fe823128bea4adb9269cbfd7c41c223be65bc60863; // ========================================= uint256 internal constant TRANSCRIPT_BEGIN_SLOT = 0x200; uint256 internal constant TRANSCRIPT_DST_BYTE_SLOT = 0x203; uint256 internal constant TRANSCRIPT_STATE_0_SLOT = 0x204; uint256 internal constant TRANSCRIPT_STATE_1_SLOT = 0x224; uint256 internal constant TRANSCRIPT_CHALLENGE_SLOT = 0x244; // ================PartialVerifierState================ // copy-permutation challenges uint256 internal constant PVS_BETA = 0x264 + 0x00; uint256 internal constant PVS_GAMMA = 0x264 + 0x20; // evaluation challenges uint256 internal constant PVS_R = 0x264 + 0x40; uint256 internal constant PVS_Z = 0x264 + 0x60; uint256 internal constant PVS_Z_OMEGA = 0x264 + 0x80; // aggregation challenge uint256 internal constant PVS_ALPHA_0 = 0x264 + 0xa0; uint256 internal constant PVS_ALPHA_1 = 0x264 + 0xc0; // final evaluation challenge uint256 internal constant PVS_Y = 0x264 + 0xe0; // convenience uint256 internal constant PVS_VANISHING_AT_Z = 0x264 + 0x100; uint256 internal constant PVS_VANISHING_AT_Z_INV = 0x264 + 0x120; uint256 internal constant PVS_L_0_AT_Z = 0x264 + 0x140; uint256 internal constant MAIN_GATE_QUOTIENT_AT_Z = 0x264 + 0x160; uint256 internal constant COPY_PERM_FIRST_QUOTIENT_AT_Z = 0x264 + 0x180; uint256 internal constant COPY_PERM_SECOND_QUOTIENT_AT_Z = 0x264 + 0x1a0; // ================Opening State================ // h0, h1, h2, h2_shifted uint256 internal constant OPS_OPENING_POINTS = 0x264 + 0x1c0 + 0x00; // 4 slots uint256 internal constant OPS_Y_POWS = 0x264 + 0x1c0 + 0x80; // 9 SLOTS // ================Pairing State================ uint256 internal constant PS_VANISHING_AT_Y = 0x264 + 0x1c0 + 0x1a0; uint256 internal constant PS_INV_ZTS0_AT_Y = 0x264 + 0x1c0 + 0x1c0; uint256 internal constant PS_SET_DIFFERENCES_AT_Y = 0x264 + 0x1c0 + 0x1e0; // 3 slots uint256 internal constant PS_MINUS_Z = 0x264 + 0x1c0 + 0x240; // 2 slots uint256 internal constant PS_R_EVALS = 0x264 + 0x1c0 + 0x280; // 3 slots // ================In Memory(from Proof)================ uint256 internal constant MEM_PROOF_PUBLIC_INPUT_SLOT = 0x264 + 0x1c0 + 0x2e0; uint256 internal constant MEM_PROOF_COMMITMENT_0_G1_X = 0x264 + 0x1c0 + 0x2e0 + 0x20; uint256 internal constant MEM_PROOF_COMMITMENT_0_G1_Y = 0x264 + 0x1c0 + 0x2e0 + 0x40; uint256 internal constant MEM_PROOF_COMMITMENT_1_G1_X = 0x264 + 0x1c0 + 0x2e0 + 0x60; uint256 internal constant MEM_PROOF_COMMITMENT_1_G1_Y = 0x264 + 0x1c0 + 0x2e0 + 0x80; uint256 internal constant MEM_PROOF_COMMITMENT_2_G1_X = 0x264 + 0x1c0 + 0x2e0 + 0xa0; uint256 internal constant MEM_PROOF_COMMITMENT_2_G1_Y = 0x264 + 0x1c0 + 0x2e0 + 0xc0; uint256 internal constant MEM_PROOF_COMMITMENT_3_G1_X = 0x264 + 0x1c0 + 0x2e0 + 0xe0; uint256 internal constant MEM_PROOF_COMMITMENT_3_G1_Y = 0x264 + 0x1c0 + 0x2e0 + 0x100; uint256 internal constant MEM_PROOF_EVALUATIONS = 0x264 + 0x1c0 + 0x2e0 + 0x120; // 15 slots uint256 internal constant MEM_PROOF_MONTGOMERY_LAGRANGE_BASIS_INVERSE = 0x264 + 0x1c0 + 0x2e0 + 0x120 + 0x1e0; // 1 slots uint256 internal constant MEM_LAGRANGE_BASIS_DENOMS = 0x264 + 0x1c0 + 0x2e0 + 0x120 + 0x200; //18 slots uint256 internal constant MEM_LAGRANGE_BASIS_DENOM_PRODUCTS = 0x264 + 0x1c0 + 0x2e0 + 0x120 + 0x440; // 18 slots uint256 internal constant MEM_PROOF_LAGRANGE_BASIS_EVALS = 0x264 + 0x1c0 + 0x2e0 + 0x120 + 0x680; // 18 Slots // ================Constants================ uint256 internal constant PROOF_PUBLIC_INPUTS_LENGTH = 1; uint256 internal constant PROOF_LENGTH = 24; uint256 internal constant PROOF_EVALUATIONS_LENGTH = 15; uint256 internal constant TOTAL_LAGRANGE_BASIS_INVERSES_LENGTH = 18; /// @inheritdoc IVerifierV2 function verificationKeyHash() external pure returns (bytes32 vkHash) { return keccak256( // solhint-disable-next-line func-named-parameters abi.encodePacked( VK_NUM_INPUTS, VK_C0_G1_X, VK_C0_G1_Y, VK_NON_RESIDUES_0, VK_NON_RESIDUES_1, VK_G2_ELEMENT_0_X1, VK_G2_ELEMENT_0_X2, VK_G2_ELEMENT_0_Y1, VK_G2_ELEMENT_0_Y2, VK_G2_ELEMENT_1_X1, VK_G2_ELEMENT_1_X2, VK_G2_ELEMENT_1_Y1, VK_G2_ELEMENT_1_Y2 ) ); } /// @inheritdoc IVerifierV2 function verify( uint256[] calldata, // _publicInputs uint256[] calldata // _proof ) external view virtual returns (bool) { // Beginning of the big inline assembly block that makes all the verification work. // Note: We use the custom memory layout, so the return value should be returned from the assembly, not // Solidity code. assembly { // load public inputs and proof from the calldata load_inputs() initialize_transcript() // identities at verifier's point compute_main_gate_quotient() compute_copy_permutation_quotients() // openings initialize_opening_state() // final pairing let result := check_openings() mstore(0, result) return(0, 0x20) function load_inputs() { // 1. Load public inputs let publicInputOffset := calldataload(0x04) let publicInputLengthInWords := calldataload(add(publicInputOffset, 0x04)) // We expect only one public input if iszero(eq(publicInputLengthInWords, PROOF_PUBLIC_INPUTS_LENGTH)) { revertWithMessage(32, "public input length is incorrect") } mstore(MEM_PROOF_PUBLIC_INPUT_SLOT, mod(calldataload(add(publicInputOffset, 0x24)), R_MOD)) // 2. Load proof let proofLengthOffset := calldataload(0x24) let proofLengthInWords := calldataload(add(proofLengthOffset, 0x04)) if iszero(eq(proofLengthInWords, PROOF_LENGTH)) { revertWithMessage(25, "proof length is incorrect") } let proofOffset := add(proofLengthOffset, 0x24) // Note: We don't accept the point-at-infinity as a valid input for the commitments considering the security risks involved, // as it may aid in proof manipulation and final pairing computation. { let x := mod(calldataload(proofOffset), Q_MOD) let y := mod(calldataload(add(proofOffset, 0x20)), Q_MOD) let xx := mulmod(x, x, Q_MOD) if iszero(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD))) { revertWithMessage(28, "commitment 0 is not on curve") } mstore(MEM_PROOF_COMMITMENT_0_G1_Y, y) mstore(MEM_PROOF_COMMITMENT_0_G1_X, x) } { let x := mod(calldataload(add(proofOffset, 0x40)), Q_MOD) let y := mod(calldataload(add(proofOffset, 0x60)), Q_MOD) let xx := mulmod(x, x, Q_MOD) if iszero(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD))) { revertWithMessage(28, "commitment 1 is not on curve") } mstore(MEM_PROOF_COMMITMENT_1_G1_Y, y) mstore(MEM_PROOF_COMMITMENT_1_G1_X, x) } { let x := mod(calldataload(add(proofOffset, 0x80)), Q_MOD) let y := mod(calldataload(add(proofOffset, 0xa0)), Q_MOD) let xx := mulmod(x, x, Q_MOD) if iszero(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD))) { revertWithMessage(28, "commitment 2 is not on curve") } mstore(MEM_PROOF_COMMITMENT_2_G1_Y, y) mstore(MEM_PROOF_COMMITMENT_2_G1_X, x) } { let x := mod(calldataload(add(proofOffset, 0xc0)), Q_MOD) let y := mod(calldataload(add(proofOffset, 0xe0)), Q_MOD) let xx := mulmod(x, x, Q_MOD) if iszero(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD))) { revertWithMessage(28, "commitment 3 is not on curve") } mstore(MEM_PROOF_COMMITMENT_3_G1_Y, y) mstore(MEM_PROOF_COMMITMENT_3_G1_X, x) } proofOffset := add(proofOffset, 0x100) for { let i := 0 } lt(i, PROOF_EVALUATIONS_LENGTH) { i := add(i, 1) } { let eval := mod(calldataload(add(proofOffset, mul(i, 0x20))), R_MOD) let slot := add(MEM_PROOF_EVALUATIONS, mul(i, 0x20)) mstore(slot, eval) } proofOffset := add(proofOffset, mul(PROOF_EVALUATIONS_LENGTH, 0x20)) mstore(MEM_PROOF_MONTGOMERY_LAGRANGE_BASIS_INVERSE, mod(calldataload(proofOffset), R_MOD)) } /** * @dev Commits data in the transcript then gets the challenges * @notice that at this point, the transcript only has public inputs * But luckily prover doesn't need any randomness in the first round * so that prover has no control over the values because quotients are * separated(there is no quotient aggregation neither in this round nor all rounds) * * w = 0x1283ba6f4b7b1a76ba2008fe823128bea4adb9269cbfd7c41c223be65bc60863 */ function initialize_transcript() { if iszero(lt(DOMAIN_SIZE, R_MOD)) { revertWithMessage(26, "Domain size >= R_MOD [ITS]") } if iszero(lt(OMEGA, R_MOD)) { revertWithMessage(20, "Omega >= R_MOD [ITS]") } for { let i := 0 } lt(i, VK_NUM_INPUTS) { i := add(i, 1) } { update_transcript(mload(add(MEM_PROOF_PUBLIC_INPUT_SLOT, mul(i, 0x20)))) } // commit first round commitment: preprocessed polynomials update_transcript(VK_C0_G1_X) update_transcript(VK_C0_G1_Y) // commit second round commitment: witnesses and gate identities update_transcript(mload(MEM_PROOF_COMMITMENT_0_G1_X)) update_transcript(mload(MEM_PROOF_COMMITMENT_0_G1_Y)) // copy-permutation challenges mstore(PVS_BETA, get_challenge(0)) mstore(PVS_GAMMA, get_challenge(1)) // commit third round commitment: copy-perm update_transcript(mload(MEM_PROOF_COMMITMENT_1_G1_X)) update_transcript(mload(MEM_PROOF_COMMITMENT_1_G1_Y)) // get evaluation challenge // all system polynomials will be evaluated at z // then combined polynomials will be opened at h_i = r^power_i // then it becomes e.g C_i(X) = f_0(x^2) + x*f(x^2) in case of two polynomials mstore(PVS_R, get_challenge(2)) // commit all evaluations for { let i := 0 } lt(i, PROOF_EVALUATIONS_LENGTH) { i := add(i, 1) } { update_transcript(mload(add(MEM_PROOF_EVALUATIONS, mul(i, 0x20)))) } // get aggregation challenge mstore(PVS_ALPHA_0, get_challenge(3)) mstore(PVS_ALPHA_1, mulmod(mload(PVS_ALPHA_0), mload(PVS_ALPHA_0), R_MOD)) // commit w(X) update_transcript(mload(MEM_PROOF_COMMITMENT_2_G1_X)) update_transcript(mload(MEM_PROOF_COMMITMENT_2_G1_Y)) // opening challenge mstore(PVS_Y, get_challenge(4)) mstore(PVS_Z, modexp(mload(PVS_R), 24)) // grand product of copy-permutation needs to be opened at shifted position mstore(PVS_Z_OMEGA, mulmod(mload(PVS_Z), OMEGA, R_MOD)) // Z_h(z) = X^N - 1 mstore(PVS_VANISHING_AT_Z, addmod(modexp(mload(PVS_Z), DOMAIN_SIZE), sub(R_MOD, ONE), R_MOD)) // L0(z) = 1/(N*(X-1)) * (X^N - 1) mstore( PVS_L_0_AT_Z, modexp(mulmod(addmod(mload(PVS_Z), sub(R_MOD, ONE), R_MOD), DOMAIN_SIZE, R_MOD), sub(R_MOD, 2)) ) mstore(PVS_L_0_AT_Z, mulmod(mload(PVS_L_0_AT_Z), mload(PVS_VANISHING_AT_Z), R_MOD)) mstore(PVS_VANISHING_AT_Z_INV, modexp(mload(PVS_VANISHING_AT_Z), sub(R_MOD, 2))) } /** * @dev Computes main gate quotient T0(ζ) * T0(ζ) = (qm(ζ)*a(ζ)*b(ζ) + qa(ζ)*a(ζ) + qb(ζ)*b(ζ) + qc(ζ)*c(ζ) + qconst(ζ) + PI*L0(ζ)) * ZH(ζ)^-1 */ function compute_main_gate_quotient() { // q_const let rhs := mload(add(MEM_PROOF_EVALUATIONS, mul(4, 0x20))) rhs := addmod(rhs, mulmod(mload(PVS_L_0_AT_Z), mload(MEM_PROOF_PUBLIC_INPUT_SLOT), R_MOD), R_MOD) for { let i := 0 } lt(i, 3) { i := add(i, 1) } { rhs := addmod( rhs, mulmod( mload(add(MEM_PROOF_EVALUATIONS, mul(i, 0x20))), mload(add(MEM_PROOF_EVALUATIONS, mul(add(8, i), 0x20))), R_MOD ), R_MOD ) } // q_m*A*B rhs := mulmod( addmod( rhs, mulmod( mulmod( mload(add(MEM_PROOF_EVALUATIONS, mul(3, 0x20))), mload(add(MEM_PROOF_EVALUATIONS, mul(8, 0x20))), R_MOD ), mload(add(MEM_PROOF_EVALUATIONS, mul(9, 0x20))), R_MOD ), R_MOD ), mload(PVS_VANISHING_AT_Z_INV), R_MOD ) mstore(MAIN_GATE_QUOTIENT_AT_Z, rhs) } /** * @dev Computes copy permutation quotients T1(ζ) & T2(ζ) * T1(ζ) = ((z(ζ) * (a(ζ)+β*ζ+γ) * (b(ζ)+k1*β*ζ+γ) * (c(ζ)+k2*β*ζ+γ)) * −(z(ζω) * (a(ζ)+β*sσ1(ζ)+γ) * (b(ζ)+β*sσ2(ζ)+γ) * (c(ζ)+β*sσ3(ζ)+γ)) * ZH(ζ)^-1 * T2(ζ) = (z(ζ)−1)*L0(ζ)*ZH(ζ)^-1 */ function compute_copy_permutation_quotients() { let tmp let tmp2 // (c(ζ)+k2*β*ζ+γ) let rhs := addmod( addmod( mulmod(mulmod(mload(PVS_BETA), mload(PVS_Z), R_MOD), VK_NON_RESIDUES_1, R_MOD), mload(PVS_GAMMA), R_MOD ), mload(add(MEM_PROOF_EVALUATIONS, mul(add(8, 2), 0x20))), R_MOD ) // (b(ζ)+k1*β*ζ+γ) tmp := addmod( addmod( mulmod(mulmod(mload(PVS_BETA), mload(PVS_Z), R_MOD), VK_NON_RESIDUES_0, R_MOD), mload(PVS_GAMMA), R_MOD ), mload(add(MEM_PROOF_EVALUATIONS, mul(add(8, 1), 0x20))), R_MOD ) // (b(ζ)+k1*β*ζ+γ) * (c(ζ)+k2*β*ζ+γ) rhs := mulmod(rhs, tmp, R_MOD) // (z(ζ) * (a(ζ)+β*ζ+γ) * (b(ζ)+k1*β*ζ+γ) * (c(ζ)+k2*β*ζ+γ) rhs := mulmod( mulmod( rhs, addmod( addmod(mulmod(mload(PVS_BETA), mload(PVS_Z), R_MOD), mload(PVS_GAMMA), R_MOD), mload(add(MEM_PROOF_EVALUATIONS, mul(8, 0x20))), R_MOD ), R_MOD ), mload(add(MEM_PROOF_EVALUATIONS, mul(11, 0x20))), R_MOD ) // (z(ζω) * (b(ζ)+β*sσ2(ζ)+γ) * (c(ζ)+β*sσ3(ζ)+γ)) tmp2 := mulmod( mulmod( addmod( addmod( mulmod(mload(PVS_BETA), mload(add(MEM_PROOF_EVALUATIONS, mul(add(5, 2), 0x20))), R_MOD), mload(PVS_GAMMA), R_MOD ), mload(add(MEM_PROOF_EVALUATIONS, mul(add(8, 2), 0x20))), R_MOD ), mload(add(MEM_PROOF_EVALUATIONS, mul(12, 0x20))), R_MOD ), addmod( addmod( mulmod(mload(PVS_BETA), mload(add(MEM_PROOF_EVALUATIONS, mul(add(5, 1), 0x20))), R_MOD), mload(PVS_GAMMA), R_MOD ), mload(add(MEM_PROOF_EVALUATIONS, mul(add(8, 1), 0x20))), R_MOD ), R_MOD ) // (a(ζ)+β*sσ1(ζ)+γ) tmp := addmod( addmod( mulmod(mload(PVS_BETA), mload(add(MEM_PROOF_EVALUATIONS, mul(5, 0x20))), R_MOD), mload(PVS_GAMMA), R_MOD ), mload(add(MEM_PROOF_EVALUATIONS, mul(8, 0x20))), R_MOD ) // z(ζω) * (a(ζ)+β*sσ1(ζ)+γ) * (b(ζ)+β*sσ2(ζ)+γ) * (c(ζ)+β*sσ3(ζ)+γ) tmp2 := mulmod(tmp2, tmp, R_MOD) // −(z(ζω) * (a(ζ)+β*sσ1(ζ)+γ) * (b(ζ)+β*sσ2(ζ)+γ) * (c(ζ)+β*sσ3(ζ)+γ)) tmp2 := sub(R_MOD, tmp2) // ((z(ζ) * (a(ζ)+β*ζ+γ) * (b(ζ)+k1*β*ζ+γ) * (c(ζ)+k2*β*ζ+γ)) − (z(ζω) * (a(ζ)+β*sσ1(ζ)+γ) * (b(ζ)+β*sσ2(ζ)+γ) * (c(ζ)+β*sσ3(ζ)+γ)) * ZH(ζ)^-1 rhs := mulmod(addmod(rhs, tmp2, R_MOD), mload(PVS_VANISHING_AT_Z_INV), R_MOD) mstore(COPY_PERM_FIRST_QUOTIENT_AT_Z, rhs) // (z(ζ)−1)*L0(ζ)*ZH(ζ)^-1 rhs := mulmod( mulmod( addmod(mload(add(MEM_PROOF_EVALUATIONS, mul(11, 0x20))), sub(R_MOD, 1), R_MOD), mload(PVS_L_0_AT_Z), R_MOD ), mload(PVS_VANISHING_AT_Z_INV), R_MOD ) mstore(COPY_PERM_SECOND_QUOTIENT_AT_Z, rhs) } /** * @dev Computes partial lagrange basis evaluations Li(y)_numerator {i = [start..(start+num_polys))} using montgomery lagrange basis inverses sent with proof. * Li(y)_numerator = (w_i * (y^{num_polys} - h^{num_polys})) * Li(y)_denominator = (num_polys * h^{num_polys-1} * (y - (h * w_i))) * Li(y) = Li(y)_numerator / Li(y)_denominator = (w_i * (y^{num_polys} - h^{num_polys})) / (num_polys * h^{num_polys-1} * (y - (h * w_i))) * * Also calculates the products of the denominators of the lagrange basis evaluations: * Li(y)_denominators_product = Li(y)_previous_denominators_product * (∏(Li(y)_denominator {i = [start..(start+num_polys))})) */ function precompute_partial_lagrange_basis_evaluations(start, num_polys, y, omega, h, product) -> interim_product { if gt(add(start, num_polys), TOTAL_LAGRANGE_BASIS_INVERSES_LENGTH) { revertWithMessage(31, "Precompute Eval. Error [PLBEI1]") } let tmp := h let loop_length := sub(num_polys, 2) // h^{num_polys-1} for { let i := 0 } lt(i, loop_length) { i := add(i, 1) } { tmp := mulmod(tmp, h, R_MOD) } // num_polys * h^{num_polys-1} let constant_part := mulmod(num_polys, tmp, R_MOD) // y^{num_polys} let y_pow := mload(add(OPS_Y_POWS, mul(num_polys, 0x20))) // h^{num_polys} let num_at_y := mulmod(tmp, h, R_MOD) // -h^{num_polys} num_at_y := sub(R_MOD, num_at_y) // (y^{num_polys} - h^{num_polys}) num_at_y := addmod(num_at_y, y_pow, R_MOD) let current_omega := 1 for { let i := 0 } lt(i, num_polys) { i := add(i, 1) } { // h*w_i tmp := mulmod(current_omega, h, R_MOD) // -h*w_i tmp := sub(R_MOD, tmp) // y-(h*w_i) tmp := addmod(tmp, y, R_MOD) // (num_polys * h^{num_polys-1} * (y - (h * w_i))) tmp := mulmod(tmp, constant_part, R_MOD) mstore(add(MEM_LAGRANGE_BASIS_DENOMS, mul(add(start, i), 0x20)), tmp) product := mulmod(product, tmp, R_MOD) mstore(add(MEM_LAGRANGE_BASIS_DENOM_PRODUCTS, mul(add(start, i), 0x20)), product) // Li(y) = (W_i * (y^{num_polys} - h^{num_polys})) mstore( add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(start, i), 0x20)), mulmod(num_at_y, current_omega, R_MOD) ) // w_i {i = i+1} current_omega := mulmod(current_omega, omega, R_MOD) } interim_product := product } /** * @dev Computes partial lagrange basis evaluations Li(y)_numerator = {i = [start..(start+num_polys))} & Li(y)_numerator {i = [(start+num_polys)..(start+(2*num_polys)))} using montgomery lagrange basis inverses sent with proof. * For Li(y)_numerator{i = [start..(start+num_polys))}: * Li(y)_numerator = w_i * (y^{2*num_polys} + (h^{num_polys} * h_s^{num_polys}) - (y^{num_polys} * (h^{num_polys} + h_s^{num_polys}))) * Li(y)_denominator = (num_polys * (h^{(2*num_polys)-1}-(h^{num_polys-1} * h_s^{num_polys})) * (y-(h*w_i))) * Li(y) = Li(y)_numerator / Li(y)_denominator = (w_i * (y^{2*num_polys} + (h^{num_polys} * h_s^{num_polys}) - (y^{num_polys} * (h^{num_polys} + h_s^{num_polys})))) / (num_polys * (h^{(2*num_polys)-1}-(h^{num_polys-1} * h_s^{num_polys})) * (y-(h*w_i))) * * For Li(y)_numerator{i = [(start+num_polys)..(start+(2*num_polys)))} * Li(y)_numerator = w_i * (y^{2*num_polys} + (h^{num_polys} * h_s^{num_polys}) - (y^{num_polys} * (h^{num_polys} + h_s^{num_polys}))) * Li(y)_denominator = (num_polys * (h_s^{(2*num_polys)-1}-(h_s^{num_polys-1} * h^{num_polys})) * (y-(h_s*w_i))) * Li(y) = Li(y)_numerator / Li(y)_denominator = (w_i * (y^{2*num_polys} + (h^{num_polys} * h_s^{num_polys}) - (y^{num_polys} * (h^{num_polys} + h_s^{num_polys}))) ) / (num_polys * (h_s^{(2*num_polys)-1}-(h_s^{num_polys-1} * h^{num_polys})) * (y-(h_s*w_i))) * * Also calculates the products of the denominators of the lagrange basis evaluations: * Li(y)_denominators_product = Li(y)_previous_denominators_product * (∏(Li(y)_denominator {i = [start..(start+num_polys))})) * (∏(Li(y)_denominator {i = [(start+num_polys)..(start+(2*num_polys)))})) */ function precompute_partial_lagrange_basis_evaluations_for_union_set( start, num_polys, y, omega, h, h_shifted, product ) -> final_product { if gt(add(start, mul(2, num_polys)), TOTAL_LAGRANGE_BASIS_INVERSES_LENGTH) { revertWithMessage(32, "Precompute Eval. Error [PLBEIU1]") } let h_pows_0 := h let h_pows_1 := h_shifted let loop_length := sub(num_polys, 2) // h^{num_polys-1} & h_s^{num_polys-1} for { let i := 0 } lt(i, loop_length) { i := add(i, 1) } { h_pows_0 := mulmod(h_pows_0, h, R_MOD) h_pows_1 := mulmod(h_pows_1, h_shifted, R_MOD) } let constant_parts_0 := h_pows_0 let constant_parts_1 := h_pows_1 // h^{num_polys} h_pows_0 := mulmod(h_pows_0, h, R_MOD) // h_s^{num_polys} h_pows_1 := mulmod(h_pows_1, h_shifted, R_MOD) // h^{num_polys-1} * h_s^{num_polys} constant_parts_0 := mulmod(constant_parts_0, h_pows_1, R_MOD) // -h^{num_polys-1} * h_s^{num_polys} constant_parts_0 := sub(R_MOD, constant_parts_0) // h_s^{num_polys-1} * h^{num_polys} constant_parts_1 := mulmod(constant_parts_1, h_pows_0, R_MOD) // -h_s^{num_polys-1} * h^{num_polys} constant_parts_1 := sub(R_MOD, constant_parts_1) // y^{num_polys} let t_2 := mload(add(OPS_Y_POWS, mul(num_polys, 0x20))) // h^{num_polys} * h_s^{num_polys} let t_1 := mulmod(h_pows_0, h_pows_1, R_MOD) // h^{num_polys} + h_s^{num_polys} let t_0 := addmod(h_pows_0, h_pows_1, R_MOD) // y^{num_polys} * (h^{num_polys} + h_s^{num_polys}) t_0 := mulmod(t_0, t_2, R_MOD) // - (y^{num_polys} * (h^{num_polys} + h_s^{num_polys})) t_0 := sub(R_MOD, t_0) // h^{num_polys} * h_s^{num_polys} - (y^{num_polys} * (h^{num_polys} + h_s^{num_polys})) t_1 := addmod(t_1, t_0, R_MOD) // y^{2*num_polys} t_2 := mulmod(t_2, t_2, R_MOD) // y^{2*num_polys} + (h^{num_polys} * h_s^{num_polys}) - (y^{num_polys} * (h^{num_polys} + h_s^{num_polys})) t_1 := addmod(t_1, t_2, R_MOD) loop_length := sub(num_polys, 1) // h^{(2*num_polys)-1} & h_s^{(2*num_polys)-1} for { let i := 0 } lt(i, loop_length) { i := add(i, 1) } { h_pows_0 := mulmod(h_pows_0, h, R_MOD) h_pows_1 := mulmod(h_pows_1, h_shifted, R_MOD) } // h^{(2*num_polys)-1}-(h^{num_polys-1} * h_s^{num_polys}) constant_parts_0 := addmod(constant_parts_0, h_pows_0, R_MOD) // num_polys * (h^{(2*num_polys)-1}-(h^{num_polys-1} * h_s^{num_polys})) constant_parts_0 := mulmod(constant_parts_0, num_polys, R_MOD) // h_s^{(2*num_polys)-1}-(h_s^{num_polys-1} * h^{num_polys}) constant_parts_1 := addmod(constant_parts_1, h_pows_1, R_MOD) // num_polys * (h_s^{(2*num_polys)-1}-(h_s^{num_polys-1} * h^{num_polys})) constant_parts_1 := mulmod(constant_parts_1, num_polys, R_MOD) let current_omega := 1 let interim_product := product for { let i := 0 } lt(i, num_polys) { i := add(i, 1) } { t_0 := mulmod(current_omega, h, R_MOD) t_0 := sub(R_MOD, t_0) t_0 := addmod(t_0, y, R_MOD) // (num_polys * (h^{(2*num_polys)-1}-(h^{num_polys-1} * h_s^{num_polys})) * (y-(h*w_i))) t_0 := mulmod(t_0, constant_parts_0, R_MOD) mstore(add(MEM_LAGRANGE_BASIS_DENOMS, mul(add(start, i), 0x20)), t_0) interim_product := mulmod(interim_product, t_0, R_MOD) mstore(add(MEM_LAGRANGE_BASIS_DENOM_PRODUCTS, mul(add(start, i), 0x20)), interim_product) // w_i * (y^{2*num_polys} + (h^{num_polys} * h_s^{num_polys}) - (y^{num_polys} * (h^{num_polys} + h_s^{num_polys}))) mstore( add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(start, i), 0x20)), mulmod(t_1, current_omega, R_MOD) ) // w_i {i = i+1} current_omega := mulmod(current_omega, omega, R_MOD) } current_omega := 1 for { let i := 0 } lt(i, num_polys) { i := add(i, 1) } { t_0 := mulmod(current_omega, h_shifted, R_MOD) t_0 := sub(R_MOD, t_0) t_0 := addmod(t_0, y, R_MOD) // (num_polys * (h_s^{(2*num_polys)-1}-(h_s^{num_polys-1} * h^{num_polys})) * (y-(h_s*w_i))) t_0 := mulmod(t_0, constant_parts_1, R_MOD) mstore(add(MEM_LAGRANGE_BASIS_DENOMS, mul(add(add(start, num_polys), i), 0x20)), t_0) interim_product := mulmod(interim_product, t_0, R_MOD) mstore( add(MEM_LAGRANGE_BASIS_DENOM_PRODUCTS, mul(add(add(start, num_polys), i), 0x20)), interim_product ) // w_i * (y^{2*num_polys} + (h^{num_polys} * h_s^{num_polys}) - (y^{num_polys} * (h^{num_polys} + h_s^{num_polys}))) mstore( add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(add(start, num_polys), i), 0x20)), mulmod(t_1, current_omega, R_MOD) ) // w_i {i = i+1} current_omega := mulmod(current_omega, omega, R_MOD) } final_product := interim_product } /** * @dev Computes lagrange basis evaluations using montgomery lagrange basis inverses sent with proof. * @notice Check individual functions for more details */ function precompute_all_lagrange_basis_evaluations_from_inverses() { let y := mload(PVS_Y) // w8 = 0x2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e80 // w4 = 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636 // w3 = 0x0000000000000000b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd let product_0_7 := precompute_partial_lagrange_basis_evaluations( 0, 8, y, 0x2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e80, mload(add(OPS_OPENING_POINTS, mul(0, 0x20))), 1 ) let product_0_11 := precompute_partial_lagrange_basis_evaluations( 8, 4, y, 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636, mload(add(OPS_OPENING_POINTS, mul(1, 0x20))), product_0_7 ) let product_0_17 := precompute_partial_lagrange_basis_evaluations_for_union_set( add(8, 4), 3, y, 0x0000000000000000b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd, mload(add(OPS_OPENING_POINTS, mul(2, 0x20))), mload(add(OPS_OPENING_POINTS, mul(3, 0x20))), product_0_11 ) let montgomery_inverse := mload(MEM_PROOF_MONTGOMERY_LAGRANGE_BASIS_INVERSE) if iszero(eq(mulmod(product_0_17, montgomery_inverse, R_MOD), 1)) { revertWithMessage(30, "Precompute Eval. Error [PALBE]") } let temp := montgomery_inverse let loop_length := sub(TOTAL_LAGRANGE_BASIS_INVERSES_LENGTH, 1) for { let i := loop_length } gt(i, 0) { i := sub(i, 1) } { mstore( add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(i, 0x20)), mulmod( mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(i, 0x20))), mulmod(mload(add(MEM_LAGRANGE_BASIS_DENOM_PRODUCTS, mul(sub(i, 1), 0x20))), temp, R_MOD), R_MOD ) ) temp := mulmod(temp, mload(add(MEM_LAGRANGE_BASIS_DENOMS, mul(i, 0x20))), R_MOD) } mstore( add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(0, 0x20)), mulmod(mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(0, 0x20))), temp, R_MOD) ) } /** * @dev Computes opening points h0, h1, h2, h3 */ function compute_opening_points() { // h = r^{power/num_polys} let pvs_r := mload(PVS_R) let r_2 := mulmod(pvs_r, pvs_r, R_MOD) let r_3 := mulmod(r_2, pvs_r, R_MOD) let r_6 := mulmod(r_3, r_3, R_MOD) let r_8 := mulmod(r_6, r_2, R_MOD) // h0 = pvs_r^3 mstore(add(OPS_OPENING_POINTS, mul(0, 0x20)), r_3) // h1 = pvs_r^6 mstore(add(OPS_OPENING_POINTS, mul(1, 0x20)), r_6) // h2 = pvs_r^8 mstore(add(OPS_OPENING_POINTS, mul(2, 0x20)), r_8) // h3 (only round 2 needs opening at shifted point) mstore( add(OPS_OPENING_POINTS, mul(3, 0x20)), mulmod(r_8, 0x0925f0bd364638ec3084b45fc27895f8f3f6f079096600fe946c8e9db9a47124, R_MOD) ) } /** * @dev Initializes opening state OPS_Y_POWS[i] = y^i * @notice only 9 powers are computed since the rest stay unused. */ function initialize_opening_state() { compute_opening_points() let acc := 1 for { let i := 0 } lt(i, 9) { i := add(i, 1) } { mstore(add(OPS_Y_POWS, mul(i, 0x20)), acc) acc := mulmod(acc, mload(PVS_Y), R_MOD) } precompute_all_lagrange_basis_evaluations_from_inverses() } /** * @dev Computes r polynomial evaluations utilizing horner method * (r*w)^{i}:{1, w*r, (w*r)^2, .. , (w*r)^{k-1}} * horner: c0 + c1*(rw) + c2*(rw)^2 + c3*(rw)^3 -> (c0 + (rw)*(c1 + (rw)*(c2 + c3*(rw)))) */ function evaluate_r_polys_at_point_unrolled( main_gate_quotient_at_z, copy_perm_first_quotient_at_z, copy_perm_second_quotient_at_z ) { let omega_h let c // setup round // r // w8^1 = 0x2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e80 // w8^2 = 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636 // w8^3 = 0x1d59376149b959ccbd157ac850893a6f07c2d99b3852513ab8d01be8e846a566 // w8^4 = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000 // w8^5 = 0x0530d09118705106cbb4a786ead16926d5d174e181a26686af5448492e42a181 // w8^6 = 0x0000000000000000b3c4d79d41a91758cb49c3517c4604a520cff123608fc9cb // w8^7 = 0x130b17119778465cfb3acaee30f81dee20710ead41671f568b11d9ab07b95a9b omega_h := mload(add(OPS_OPENING_POINTS, mul(0, 0x20))) c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(7, 0x20))), omega_h, R_MOD) for { let i := 1 } lt(i, 7) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(7, i), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(MEM_PROOF_EVALUATIONS), R_MOD) mstore( PS_R_EVALS, addmod( mload(PS_R_EVALS), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(0, 0x20))), R_MOD), R_MOD ) ) omega_h := mulmod( 0x2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e80, mload(add(OPS_OPENING_POINTS, mul(0, 0x20))), R_MOD ) c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(7, 0x20))), omega_h, R_MOD) for { let i := 1 } lt(i, 7) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(7, i), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(MEM_PROOF_EVALUATIONS), R_MOD) mstore( PS_R_EVALS, addmod( mload(PS_R_EVALS), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(1, 0x20))), R_MOD), R_MOD ) ) omega_h := mulmod( 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636, mload(add(OPS_OPENING_POINTS, mul(0, 0x20))), R_MOD ) c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(7, 0x20))), omega_h, R_MOD) for { let i := 1 } lt(i, 7) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(7, i), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(MEM_PROOF_EVALUATIONS), R_MOD) mstore( PS_R_EVALS, addmod( mload(PS_R_EVALS), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(2, 0x20))), R_MOD), R_MOD ) ) omega_h := mulmod( 0x1d59376149b959ccbd157ac850893a6f07c2d99b3852513ab8d01be8e846a566, mload(add(OPS_OPENING_POINTS, mul(0, 0x20))), R_MOD ) c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(7, 0x20))), omega_h, R_MOD) for { let i := 1 } lt(i, 7) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(7, i), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(MEM_PROOF_EVALUATIONS), R_MOD) mstore( PS_R_EVALS, addmod( mload(PS_R_EVALS), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(3, 0x20))), R_MOD), R_MOD ) ) omega_h := mulmod( 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000, mload(add(OPS_OPENING_POINTS, mul(0, 0x20))), R_MOD ) c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(7, 0x20))), omega_h, R_MOD) for { let i := 1 } lt(i, 7) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(7, i), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(MEM_PROOF_EVALUATIONS), R_MOD) mstore( PS_R_EVALS, addmod( mload(PS_R_EVALS), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(4, 0x20))), R_MOD), R_MOD ) ) omega_h := mulmod( 0x0530d09118705106cbb4a786ead16926d5d174e181a26686af5448492e42a181, mload(add(OPS_OPENING_POINTS, mul(0, 0x20))), R_MOD ) c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(7, 0x20))), omega_h, R_MOD) for { let i := 1 } lt(i, 7) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(7, i), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(MEM_PROOF_EVALUATIONS), R_MOD) mstore( PS_R_EVALS, addmod( mload(PS_R_EVALS), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(5, 0x20))), R_MOD), R_MOD ) ) omega_h := mulmod( 0x0000000000000000b3c4d79d41a91758cb49c3517c4604a520cff123608fc9cb, mload(add(OPS_OPENING_POINTS, mul(0, 0x20))), R_MOD ) c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(7, 0x20))), omega_h, R_MOD) for { let i := 1 } lt(i, 7) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(7, i), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(MEM_PROOF_EVALUATIONS), R_MOD) mstore( PS_R_EVALS, addmod( mload(PS_R_EVALS), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(6, 0x20))), R_MOD), R_MOD ) ) omega_h := mulmod( 0x130b17119778465cfb3acaee30f81dee20710ead41671f568b11d9ab07b95a9b, mload(add(OPS_OPENING_POINTS, mul(0, 0x20))), R_MOD ) c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(7, 0x20))), omega_h, R_MOD) for { let i := 1 } lt(i, 7) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(7, i), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(MEM_PROOF_EVALUATIONS), R_MOD) mstore( PS_R_EVALS, addmod( mload(PS_R_EVALS), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(7, 0x20))), R_MOD), R_MOD ) ) // first round // r // w4^1 = 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636 // w4^2 = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000 // w4^3 = 0x0000000000000000b3c4d79d41a91758cb49c3517c4604a520cff123608fc9cb omega_h := mload(add(OPS_OPENING_POINTS, mul(1, 0x20))) c := mulmod(main_gate_quotient_at_z, omega_h, R_MOD) for { let i := 1 } lt(i, 3) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(sub(add(8, 4), i), 1), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(sub(add(8, 4), 3), 1), 0x20))), R_MOD) mstore( add(PS_R_EVALS, mul(1, 0x20)), addmod( mload(add(PS_R_EVALS, mul(1, 0x20))), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(8, 0), 0x20))), R_MOD), R_MOD ) ) omega_h := mulmod( 0x30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f703636, mload(add(OPS_OPENING_POINTS, mul(1, 0x20))), R_MOD ) c := mulmod(main_gate_quotient_at_z, omega_h, R_MOD) for { let i := 1 } lt(i, 3) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(sub(add(8, 4), i), 1), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(sub(add(8, 4), 3), 1), 0x20))), R_MOD) mstore( add(PS_R_EVALS, mul(1, 0x20)), addmod( mload(add(PS_R_EVALS, mul(1, 0x20))), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(8, 1), 0x20))), R_MOD), R_MOD ) ) omega_h := mulmod( 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000, mload(add(OPS_OPENING_POINTS, mul(1, 0x20))), R_MOD ) c := mulmod(main_gate_quotient_at_z, omega_h, R_MOD) for { let i := 1 } lt(i, 3) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(sub(add(8, 4), i), 1), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(sub(add(8, 4), 3), 1), 0x20))), R_MOD) mstore( add(PS_R_EVALS, mul(1, 0x20)), addmod( mload(add(PS_R_EVALS, mul(1, 0x20))), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(8, 2), 0x20))), R_MOD), R_MOD ) ) omega_h := mulmod( 0x0000000000000000b3c4d79d41a91758cb49c3517c4604a520cff123608fc9cb, mload(add(OPS_OPENING_POINTS, mul(1, 0x20))), R_MOD ) c := mulmod(main_gate_quotient_at_z, omega_h, R_MOD) for { let i := 1 } lt(i, 3) { i := add(i, 1) } { c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(sub(add(8, 4), i), 1), 0x20))), R_MOD), omega_h, R_MOD ) } c := addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(sub(sub(add(8, 4), 3), 1), 0x20))), R_MOD) mstore( add(PS_R_EVALS, mul(1, 0x20)), addmod( mload(add(PS_R_EVALS, mul(1, 0x20))), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(8, 3), 0x20))), R_MOD), R_MOD ) ) // second round // c2 // r omega_h := mload(add(OPS_OPENING_POINTS, mul(2, 0x20))) let omega_h_shifted := mload(add(OPS_OPENING_POINTS, mul(3, 0x20))) c := mulmod(copy_perm_second_quotient_at_z, omega_h, R_MOD) c := mulmod(addmod(c, copy_perm_first_quotient_at_z, R_MOD), omega_h, R_MOD) c := addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(11, 0x20))), R_MOD) mstore( add(PS_R_EVALS, mul(2, 0x20)), addmod( mload(add(PS_R_EVALS, mul(2, 0x20))), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(add(8, 4), 0), 0x20))), R_MOD), R_MOD ) ) // c2 shifted c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(add(12, 2), 0x20))), omega_h_shifted, R_MOD) c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(add(12, 1), 0x20))), R_MOD), omega_h_shifted, R_MOD ) c := addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(12, 0x20))), R_MOD) mstore( add(PS_R_EVALS, mul(2, 0x20)), addmod( mload(add(PS_R_EVALS, mul(2, 0x20))), mulmod( c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(add(add(8, 4), 3), 0), 0x20))), R_MOD ), R_MOD ) ) // c2 omega_h := mulmod( 0x0000000000000000b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd, mload(add(OPS_OPENING_POINTS, mul(2, 0x20))), R_MOD ) omega_h_shifted := mulmod( 0x0000000000000000b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd, mload(add(OPS_OPENING_POINTS, mul(3, 0x20))), R_MOD ) c := mulmod(copy_perm_second_quotient_at_z, omega_h, R_MOD) c := mulmod(addmod(c, copy_perm_first_quotient_at_z, R_MOD), omega_h, R_MOD) c := addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(11, 0x20))), R_MOD) mstore( add(PS_R_EVALS, mul(2, 0x20)), addmod( mload(add(PS_R_EVALS, mul(2, 0x20))), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(add(8, 4), 1), 0x20))), R_MOD), R_MOD ) ) // c2 shifted c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(add(12, 2), 0x20))), omega_h_shifted, R_MOD) c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(add(12, 1), 0x20))), R_MOD), omega_h_shifted, R_MOD ) c := addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(12, 0x20))), R_MOD) mstore( add(PS_R_EVALS, mul(2, 0x20)), addmod( mload(add(PS_R_EVALS, mul(2, 0x20))), mulmod( c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(add(add(8, 4), 3), 1), 0x20))), R_MOD ), R_MOD ) ) // c2 omega_h := mulmod( 0x30644e72e131a029048b6e193fd84104cc37a73fec2bc5e9b8ca0b2d36636f23, mload(add(OPS_OPENING_POINTS, mul(2, 0x20))), R_MOD ) omega_h_shifted := mulmod( 0x30644e72e131a029048b6e193fd84104cc37a73fec2bc5e9b8ca0b2d36636f23, mload(add(OPS_OPENING_POINTS, mul(3, 0x20))), R_MOD ) c := mulmod(copy_perm_second_quotient_at_z, omega_h, R_MOD) c := mulmod(addmod(c, copy_perm_first_quotient_at_z, R_MOD), omega_h, R_MOD) c := addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(11, 0x20))), R_MOD) mstore( add(PS_R_EVALS, mul(2, 0x20)), addmod( mload(add(PS_R_EVALS, mul(2, 0x20))), mulmod(c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(add(8, 4), 2), 0x20))), R_MOD), R_MOD ) ) // c2 shifted c := mulmod(mload(add(MEM_PROOF_EVALUATIONS, mul(add(12, 2), 0x20))), omega_h_shifted, R_MOD) c := mulmod( addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(add(12, 1), 0x20))), R_MOD), omega_h_shifted, R_MOD ) c := addmod(c, mload(add(MEM_PROOF_EVALUATIONS, mul(12, 0x20))), R_MOD) mstore( add(PS_R_EVALS, mul(2, 0x20)), addmod( mload(add(PS_R_EVALS, mul(2, 0x20))), mulmod( c, mload(add(MEM_PROOF_LAGRANGE_BASIS_EVALS, mul(add(add(add(8, 4), 3), 2), 0x20))), R_MOD ), R_MOD ) ) } /** * @dev Computes the openings and returns the result of pairing computation */ function check_openings() -> out { // f(X) = (Z_{T\S0}(y) * (C0(X) - r0(y))) + (alpha*(Z_{T\S1}(y)*(C1(X) - r1(y)))) + (alpha^{2}*(Z_{T\S2}(y)*(C2(X) - r2(y)))) // Note that, in our case set differences(Z_T\{S_i}) are: // - Z_{T\S0}(y): (y^{k1}-ζ)*(y^{k2}-ζ)*(y^{k2}-(ζ*w)) // - Z_{T\S1}(y): (y^{k0}-ζ)*(y^{k2}-ζ)*(y^{k2}-(ζ*w)) // - Z_{T\S2}(y): (y^{k0}-ζ)*(y^{k1}-ζ) where // k0=8, k1=4, and k2=3 are number of the polynomials for setup, first and second round respectively let tmp evaluate_r_polys_at_point_unrolled( mload(MAIN_GATE_QUOTIENT_AT_Z), mload(COPY_PERM_FIRST_QUOTIENT_AT_Z), mload(COPY_PERM_SECOND_QUOTIENT_AT_Z) ) // -ζ mstore(add(PS_MINUS_Z, mul(0, 0x20)), sub(R_MOD, mload(PVS_Z))) // -(ζ*w) mstore(add(PS_MINUS_Z, mul(1, 0x20)), sub(R_MOD, mload(PVS_Z_OMEGA))) // Z_{T\S0}(y) mstore( add(PS_SET_DIFFERENCES_AT_Y, mul(0, 0x20)), addmod(mload(add(OPS_Y_POWS, mul(3, 0x20))), mload(add(PS_MINUS_Z, mul(1, 0x20))), R_MOD) ) tmp := addmod(mload(add(OPS_Y_POWS, mul(3, 0x20))), mload(add(PS_MINUS_Z, mul(0, 0x20))), R_MOD) mstore( add(PS_SET_DIFFERENCES_AT_Y, mul(0, 0x20)), mulmod(mload(add(PS_SET_DIFFERENCES_AT_Y, mul(0, 0x20))), tmp, R_MOD) ) tmp := addmod(mload(add(OPS_Y_POWS, mul(4, 0x20))), mload(add(PS_MINUS_Z, mul(0, 0x20))), R_MOD) mstore( add(PS_SET_DIFFERENCES_AT_Y, mul(0, 0x20)), mulmod(mload(add(PS_SET_DIFFERENCES_AT_Y, mul(0, 0x20))), tmp, R_MOD) ) mstore(PS_VANISHING_AT_Y, mload(add(PS_SET_DIFFERENCES_AT_Y, mul(0, 0x20)))) mstore(PS_INV_ZTS0_AT_Y, modexp(mload(add(PS_SET_DIFFERENCES_AT_Y, mul(0, 0x20))), sub(R_MOD, 2))) // Z_{T\S1}(y) mstore( add(PS_SET_DIFFERENCES_AT_Y, mul(1, 0x20)), addmod(mload(add(OPS_Y_POWS, mul(3, 0x20))), mload(add(PS_MINUS_Z, mul(1, 0x20))), R_MOD) ) tmp := addmod(mload(add(OPS_Y_POWS, mul(3, 0x20))), mload(add(PS_MINUS_Z, mul(0, 0x20))), R_MOD) mstore( add(PS_SET_DIFFERENCES_AT_Y, mul(1, 0x20)), mulmod(mload(add(PS_SET_DIFFERENCES_AT_Y, mul(1, 0x20))), tmp, R_MOD) ) tmp := addmod(mload(add(OPS_Y_POWS, mul(8, 0x20))), mload(add(PS_MINUS_Z, mul(0, 0x20))), R_MOD) mstore( add(PS_SET_DIFFERENCES_AT_Y, mul(1, 0x20)), mulmod(mload(add(PS_SET_DIFFERENCES_AT_Y, mul(1, 0x20))), tmp, R_MOD) ) mstore(PS_VANISHING_AT_Y, mulmod(mload(PS_VANISHING_AT_Y), tmp, R_MOD)) // // Z_{T\S2}(y) mstore( add(PS_SET_DIFFERENCES_AT_Y, mul(2, 0x20)), addmod(mload(add(OPS_Y_POWS, mul(4, 0x20))), mload(add(PS_MINUS_Z, mul(0, 0x20))), R_MOD) ) tmp := addmod(mload(add(OPS_Y_POWS, mul(8, 0x20))), mload(add(PS_MINUS_Z, mul(0, 0x20))), R_MOD) mstore( add(PS_SET_DIFFERENCES_AT_Y, mul(2, 0x20)), mulmod(mload(add(PS_SET_DIFFERENCES_AT_Y, mul(2, 0x20))), tmp, R_MOD) ) // W(X) = f(X) / Z_T(y) where Z_T(y) = (y^{k0}-ζ)*(y^{k1}-ζ)*(y^{k2}-ζ)*(y^{k2}-(ζ*w)) // we need to check that // f(X) - W(X) * Z_T(y) = 0 // W'(X) = L(X) / (Z_{T\S0}(y)*(X-y)) // L(X)/Z_{T\S0}(y) = (C0(X) - r0(y)) + (alpha*(Z_{T\S1}(y)/Z_{T\S0}(y))*(C1(X) - r1(y))) + (alpha^{2}*(Z_{T\S2}(y)/Z_{T\S0}(y))*(C2(X) - r2(y))) - ((Z_T(y)/Z_{T\S0}(y))*W(X)) // the identity check is reduced into following // L(X) - W'(X)*Z_{T\S0}(y)(X-y) == 0 // verifier has commitments to the C_i(X) polynomials // verifier also recomputed r_i(y) // group constant and commitment parts // first prepare L(X)/Z_{T\S0}(y) // C(X) = C0(X) + ((alpha*Z_{T\S1}(y)/Z_{T\S0}(y))*C1(X)) + ((alpha^2*Z_{T\S2}(y)/Z_{T\S0}(y))*C2(X)) // r(y) = r0(y) + ((alpha*Z_{T\S1}(y)/Z_{T\S0}(y))*r1(y)) + ((alpha^2*Z_{T\S2}(y)/Z_{T\S0}(y))*r2(y)) // now construct // L(X)/Z_{T\S0}(y) = C(X) - r(y) - ((Z_T(y)/Z_{T\S0}(y))*W(X)) // now check following identity // C(X) - r(y) - ((Z_t(y)/Z_{T\S0}(y))*W(X)) - (W'(X)*(X-y)) = 0 // [C(X)] - [r(y)*G1] - (Z_T(y)/Z_{T\S0}(y))*[W] - [(X-y)*W'] = 0 // [C(X)] - [r(y)*G1] - (Z_T(y)/Z_{T\S0}(y))*[W] - [X*W'] + [y*W]' = 0 // [C(X)] - [r(y)*G1] - (Z_T(y)/Z_{T\S0}(y))*[W] + [y*W'] - [X*W'] = 0 // points with X will be multiplied in the exponent via pairing // so final pairing would ne // e([C(X)] - [r(y)*G1] - [Z_T(y)/(Z_{T\S0}(y)*W)] + [y*W'], G2)*e(-W', X*G2) = 1 // C0 let ps_aggregated_commitment_g1_x := VK_C0_G1_X let ps_aggregated_commitment_g1_y := VK_C0_G1_Y // ((alpha^{2}*Z_{T\S2}(y))/Z_{T\S0}(y)) let aggregated_r_at_y := mulmod( mload(add(PS_SET_DIFFERENCES_AT_Y, mul(2, 0x20))), mload(PS_INV_ZTS0_AT_Y), R_MOD ) aggregated_r_at_y := mulmod(aggregated_r_at_y, mload(PVS_ALPHA_1), R_MOD) // ((alpha^{2}*Z_{T\S2}(y))/Z_{T\S0}(y))*C2 let tp_g1_x, tp_g1_y := point_mul( mload(MEM_PROOF_COMMITMENT_1_G1_X), mload(MEM_PROOF_COMMITMENT_1_G1_Y), aggregated_r_at_y ) // c0 + (((alpha^{2}*Z_{T\S2}(y))/Z_{T\S0}(y))*C2) ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y := point_add( ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y, tp_g1_x, tp_g1_y ) // ((alpha^{2}*Z_{T\S2}(y))/Z_{T\S0}(y))*r2 aggregated_r_at_y := mulmod(aggregated_r_at_y, mload(add(PS_R_EVALS, mul(2, 0x20))), R_MOD) // (alpha*Z_{T\S1}(y)/Z_{T\S0}(y)) tmp := mulmod(mload(add(PS_SET_DIFFERENCES_AT_Y, mul(1, 0x20))), mload(PS_INV_ZTS0_AT_Y), R_MOD) tmp := mulmod(tmp, mload(PVS_ALPHA_0), R_MOD) // (alpha*Z_{T\S1}(y)/Z_{T\S0}(y))*C1 tp_g1_x, tp_g1_y := point_mul( mload(MEM_PROOF_COMMITMENT_0_G1_X), mload(MEM_PROOF_COMMITMENT_0_G1_Y), tmp ) // c0 + ((alpha*Z_{T\S1}(y)/Z_{T\S0}(y))*C1) + (((alpha^{2}*Z_{T\S2}(y))/Z_{T\S0}(y))*C2) ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y := point_add( ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y, tp_g1_x, tp_g1_y ) // (alpha*Z_{T\S1}(y)/Z_{T\S0}(y))*r1 tmp := mulmod(tmp, mload(add(PS_R_EVALS, mul(1, 0x20))), R_MOD) // ((alpha*Z_{T\S1}(y)/Z_{T\S0}(y))*r1) + ((alpha^{2}*Z_{T\S2}(y)/Z_{T\S0}(y))*r2) aggregated_r_at_y := addmod(aggregated_r_at_y, tmp, R_MOD) // r0 + (alpha*Z_{T\S1}(y)/Z_{T\S0}(y))*r1 + ((alpha^{2}*Z_{T\S2}(y)/Z_{T\S0}(y))*r2) aggregated_r_at_y := addmod(aggregated_r_at_y, mload(PS_R_EVALS), R_MOD) tp_g1_x, tp_g1_y := point_mul(1, 2, aggregated_r_at_y) ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y := point_sub( ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y, tp_g1_x, tp_g1_y ) // - ((Z_T(y)/Z_{T\S0}(y))*W(X)) mstore(PS_VANISHING_AT_Y, mulmod(mload(PS_VANISHING_AT_Y), mload(PS_INV_ZTS0_AT_Y), R_MOD)) tp_g1_x, tp_g1_y := point_mul( mload(MEM_PROOF_COMMITMENT_2_G1_X), mload(MEM_PROOF_COMMITMENT_2_G1_Y), mload(PS_VANISHING_AT_Y) ) ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y := point_sub( ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y, tp_g1_x, tp_g1_y ) // L(X)/Z_{T\S0}(y) is aggregated // Now check W'(X) = L(X) / (Z_{T\S0}(y)*(x-y)) // L(X)/Z_{T\S0}(y) + (y*W'(X)) - (x*W'(X)) = 0 tp_g1_x, tp_g1_y := point_mul( mload(MEM_PROOF_COMMITMENT_3_G1_X), mload(MEM_PROOF_COMMITMENT_3_G1_Y), mload(PVS_Y) ) ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y := point_add( ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y, tp_g1_x, tp_g1_y ) let is_zero_commitment if iszero(mload(MEM_PROOF_COMMITMENT_3_G1_Y)) { if gt(mload(MEM_PROOF_COMMITMENT_3_G1_X), 0) { revertWithMessage(21, "non zero x value [CO]") } is_zero_commitment := 1 } out := pairing_check(ps_aggregated_commitment_g1_x, ps_aggregated_commitment_g1_y, is_zero_commitment) } /** * @dev Generates the rolling hash using `val` and updates the transcript. * The computation is done as follows: * new_state_0 = keccak256(uint32(0) || old_state_0 || old_state_1 || value) * new_state_1 = keccak256(uint32(1) || old_state_0 || old_state_1 || value) * * @notice The computation assumes that the memory slots 0x200 - 0x202 are clean and doesn't explicitly clean them */ function update_transcript(value) { mstore8(TRANSCRIPT_DST_BYTE_SLOT, 0x00) mstore(TRANSCRIPT_CHALLENGE_SLOT, value) let newState0 := keccak256(TRANSCRIPT_BEGIN_SLOT, 0x64) mstore8(TRANSCRIPT_DST_BYTE_SLOT, 0x01) let newState1 := keccak256(TRANSCRIPT_BEGIN_SLOT, 0x64) mstore(TRANSCRIPT_STATE_1_SLOT, newState1) mstore(TRANSCRIPT_STATE_0_SLOT, newState0) } /** * @dev Generates a new challenge with (uint32(2) || state_0 || state_1 || uint32(challenge_counter)) * The challenge_counter is incremented after every challenge */ function get_challenge(challenge_counter) -> challenge { mstore8(TRANSCRIPT_DST_BYTE_SLOT, 0x02) mstore(TRANSCRIPT_CHALLENGE_SLOT, shl(224, challenge_counter)) challenge := and(keccak256(TRANSCRIPT_BEGIN_SLOT, 0x48), FR_MASK) } /** * @dev Performs scalar multiplication: point * scalar -> t * @notice Stores values starting from the initial free memory pointer i.e., 0x80. * The free memory pointer is not updated as it stays unused throughout the code execution. */ function point_mul(p_x, p_y, s) -> t_x, t_y { mstore(0x80, p_x) mstore(0xa0, p_y) mstore(0xc0, s) let success := staticcall(gas(), 7, 0x80, 0x60, 0x80, 0x40) if iszero(success) { revertWithMessage(27, "point multiplication failed") } t_x := mload(0x80) t_y := mload(add(0x80, 0x20)) } /** * @dev Performs point addition: point 1 + point 2 -> t * @notice Stores values starting from the initial free memory pointer i.e., 0x80. * The free memory pointer is not updated as it stays unused throughout the code execution. */ function point_add(p1_x, p1_y, p2_x, p2_y) -> t_x, t_y { mstore(0x80, p1_x) mstore(0xa0, p1_y) mstore(0xc0, p2_x) mstore(0xe0, p2_y) let success := staticcall(gas(), 6, 0x80, 0x80, 0x80, 0x40) if iszero(success) { revertWithMessage(21, "point addition failed") } t_x := mload(0x80) t_y := mload(add(0x80, 0x20)) } /** * @dev Performs point subtraction: point 1 + point 2 -> t * @notice Stores values starting from the initial free memory pointer i.e., 0x80. * The free memory pointer is not updated as it stays unused throughout the code execution. * @notice We don't consider the highly unlikely case where p2 can be a point-at-infinity and the function would revert. */ function point_sub(p1_x, p1_y, p2_x, p2_y) -> t_x, t_y { mstore(0x80, p1_x) mstore(0xa0, p1_y) mstore(0xc0, p2_x) mstore(0xe0, sub(Q_MOD, p2_y)) let success := staticcall(gas(), 6, 0x80, 0x80, 0x80, 0x40) if iszero(success) { revertWithMessage(24, "point subtraction failed") } t_x := mload(0x80) t_y := mload(add(0x80, 0x20)) } /** * @dev Calculates EC Pairing result following the EIP-197: https://eips.ethereum.org/EIPS/eip-197 * Performs point negation before pairing calculation, if the flag `is_zero_commitment` is true * * @notice Stores values starting from the initial free memory pointer i.e., 0x80. * The free memory pointer is not updated as it stays unused throughout the code execution. * While code reformatting consider not to overwrite the first constant-defined memory location, which is currently * TRANSCRIPT_BEGIN_SLOT = 0x200 */ function pairing_check(p1_x, p1_y, is_zero_commitment) -> res { mstore(0x80, p1_x) mstore(0xa0, p1_y) mstore(0xc0, VK_G2_ELEMENT_0_X1) mstore(0xe0, VK_G2_ELEMENT_0_X2) mstore(0x100, VK_G2_ELEMENT_0_Y1) mstore(0x120, VK_G2_ELEMENT_0_Y2) mstore(0x140, mload(MEM_PROOF_COMMITMENT_3_G1_X)) mstore(0x160, mload(MEM_PROOF_COMMITMENT_3_G1_Y)) if iszero(is_zero_commitment) { mstore(0x160, sub(Q_MOD, mload(MEM_PROOF_COMMITMENT_3_G1_Y))) } mstore(0x180, VK_G2_ELEMENT_1_X1) mstore(0x1a0, VK_G2_ELEMENT_1_X2) mstore(0x1c0, VK_G2_ELEMENT_1_Y1) mstore(0x1e0, VK_G2_ELEMENT_1_Y2) let success := staticcall(gas(), 8, 0x80, mul(12, 0x20), 0x80, 0x20) if iszero(success) { revertWithMessage(20, "pairing check failed") } res := mload(0x80) } /** * @dev Reverts with the desired custom error string. * @notice Stores values starting from the initial free memory pointer i.e., 0x80. * The free memory pointer is not updated as it stays unused throughout the code execution. */ function revertWithMessage(len, reason) { // "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) mstore(0x80, 0x08c379a000000000000000000000000000000000000000000000000000000000) // Data offset mstore(0x84, 0x0000000000000000000000000000000000000000000000000000000000000020) // Length of revert string mstore(0xa4, len) // Revert reason mstore(0xc4, reason) // Revert revert(0x80, 0x64) } /** * @dev Performs modular exponentiation using the formula (value ^ power) mod R_MOD. * @notice Stores values starting from the 0x00 memory slot. * The free memory pointer is not updated as it stays unused throughout the code execution. */ function modexp(value, power) -> res { mstore(0x00, 0x20) mstore(0x20, 0x20) mstore(0x40, 0x20) mstore(0x60, value) mstore(0x80, power) mstore(0xa0, R_MOD) if iszero(staticcall(gas(), 5, 0, 0xc0, 0x00, 0x20)) { revertWithMessage(24, "modexp precompile failed") } res := mload(0x00) } } } }
// SPDX-License-Identifier: MIT // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.21; /// @title The interface of the Verifier contract, responsible for the zero knowledge proof verification. /// @author Matter Labs /// @custom:security-contact [email protected] interface IVerifierV2 { /// @dev Verifies a zk-SNARK proof. /// @return A boolean value indicating whether the zk-SNARK proof is valid. /// Note: The function may revert execution instead of returning false in some cases. function verify(uint256[] calldata _publicInputs, uint256[] calldata _proof) external view returns (bool); /// @notice Calculates a keccak256 hash of the runtime loaded verification keys. /// @return vkHash The keccak256 hash of the loaded verification keys. function verificationKeyHash() external view returns (bytes32); }
{ "remappings": [ "@ensdomains/=node_modules/@ensdomains/", "ds-test/=lib/forge-std/lib/ds-test/src/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "forge-std/=lib/forge-std/src/", "hardhat/=node_modules/hardhat/", "murky/=lib/murky/src/", "foundry-test/=test/foundry/", "l2-contracts/=../l2-contracts/contracts/", "@openzeppelin/contracts-v4/=lib/openzeppelin-contracts-v4/contracts/", "@openzeppelin/contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/contracts/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable-v4/lib/erc4626-tests/", "openzeppelin-contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/", "openzeppelin-contracts-v4/=lib/openzeppelin-contracts-v4/", "openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": {} }
Contract ABI
API[{"inputs":[],"name":"verificationKeyHash","outputs":[{"internalType":"bytes32","name":"vkHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"name":"verify","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
0x608060405234801561000f575f80fd5b506127218061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80639e8945d214610038578063b864f5a91461020c575b5f80fd5b6101f960408051600160208201527f146c490b673b3679fa6143548cd90ecb2da85895a04494fef50391aa6897e105918101919091527f25e7bb363dab113de8490e742512a29a1094fa5ee2084570d4de714e795428fd606082015260056080820152600760a08201527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260c08201527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60e08201527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6101008201527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101208201527f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c16101408201527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b06101608201527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe46101808201527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101a08201525f906101c00160405160208183030381529060405280519060200120905090565b6040519081526020015b60405180910390f35b61021f61021a366004612644565b61022f565b6040519015158152602001610203565b5f610238610268565b6102406105f0565b610248610844565b6102506108d6565b6102586111ce565b610260611e98565b805f5260205ff35b6004356004810135600181146102a3576102a37f7075626c696320696e707574206c656e67746820697320696e636f72726563746020612576565b505f805160206126cc8339815191526024918201350661070452356004810135601881146102f6576102f67f70726f6f66206c656e67746820697320696e636f7272656374000000000000006019612576565b506024810190505f805160206126ac8339815191528135065f805160206126ac8339815191526020830135065f805160206126ac8339815191528283095f805160206126ac83398151915260035f805160206126ac833981519152838609085f805160206126ac83398151915283840914610396576103967f636f6d6d69746d656e742030206973206e6f74206f6e20637572766500000000601c612576565b508061074452508061072452505f805160206126ac8339815191526040820135065f805160206126ac8339815191526060830135065f805160206126ac8339815191528283095f805160206126ac83398151915260035f805160206126ac833981519152838609085f805160206126ac8339815191528384091461043f5761043f7f636f6d6d69746d656e742031206973206e6f74206f6e20637572766500000000601c612576565b508061078452508061076452505f805160206126ac8339815191526080820135065f805160206126ac83398151915260a0830135065f805160206126ac8339815191528283095f805160206126ac83398151915260035f805160206126ac833981519152838609085f805160206126ac833981519152838409146104e8576104e87f636f6d6d69746d656e742032206973206e6f74206f6e20637572766500000000601c612576565b50806107c45250806107a452505f805160206126ac83398151915260c0820135065f805160206126ac83398151915260e0830135065f805160206126ac8339815191528283095f805160206126ac83398151915260035f805160206126ac833981519152838609085f805160206126ac83398151915283840914610591576105917f636f6d6d69746d656e742033206973206e6f74206f6e20637572766500000000601c612576565b50610804526107e452610100015f5b600f8110156105d2575f805160206126cc833981519152602082028381013591909106610824909101526001016105a0565b505f805160206126cc8339815191526101e0919091013506610a0452565b5f5b60018110156106145761060c602082026107040151612293565b6001016105f2565b5061063e7f146c490b673b3679fa6143548cd90ecb2da85895a04494fef50391aa6897e105612293565b6106677f25e7bb363dab113de8490e742512a29a1094fa5ee2084570d4de714e795428fd612293565b61067361072451612293565b61067f61074451612293565b6106885f6122b8565b6102645261069660016122b8565b610284526106a661076451612293565b6106b261078451612293565b6106bc60026122b8565b6102a4525f5b600f8110156106e4576106dc602082026108240151612293565b6001016106c2565b506106ef60036122b8565b610304525f805160206126cc8339815191526103045161030451096103245261071a6107a451612293565b6107266107c451612293565b61073060046122b8565b6103445261074260186102a451612594565b6102c4525f805160206126cc8339815191527f1283ba6f4b7b1a76ba2008fe823128bea4adb9269cbfd7c41c223be65bc608636102c451096102e4525f805160206126cc83398151915260015f805160206126cc833981519152036107ad628000006102c451612594565b086103645261080260025f805160206126cc833981519152035f805160206126cc833981519152628000005f805160206126cc83398151915260015f805160206126cc833981519152036102c4510809612594565b6103a4525f805160206126cc833981519152610364516103a451096103a45261083e60025f805160206126cc8339815191520361036451612594565b61038452565b6108a451610704516103a4515f805160206126cc83398151915291829109820890505f5b60038110156108a2575f805160206126cc833981519152806020836008010261082401516020840261082401510983089150600101610868565b50610384516109445161092451610884515f805160206126cc83398151915293928492839283919009098408096103c45250565b5f805f805160206126cc833981519152602060026008010261082401515f805160206126cc833981519152610284515f805160206126cc83398151915260075f805160206126cc8339815191526102c45161026451090908085f805160206126cc833981519152602060016008010261082401515f805160206126cc833981519152610284515f805160206126cc83398151915260055f805160206126cc8339815191526102c451610264510909080892505f805160206126cc83398151915283820990505f805160206126cc8339815191526020600b0261082401515f805160206126cc83398151915280602060080261082401515f805160206126cc833981519152610284515f805160206126cc8339815191526102c4516102645109080884090961094451610284516108e451610264519394505f805160206126cc83398151915293849392849290918391900908086109a451610964516102845161090451610264515f805160206126cc8339815191529493859390928492839190090808090961092451610284516108c451610264519395505f805160206126cc83398151915293849291839109080892505f805160206126cc833981519152838309610384515f805160206126cc833981519152918203935081848408099050806103e4525f805160206126cc833981519152610384515f805160206126cc8339815191526103a4515f805160206126cc83398151915260015f805160206126cc833981519152036020600b02610824015108090961040452505050565b5f60128383011115610b4b57610b4b7f507265636f6d70757465204576616c2e204572726f72205b504c424549315d00601f612576565b85600284035f5b81811015610b75575f805160206126cc8339815191528984099250600101610b52565b50505f805160206126cc833981519152818509602085026104a401515f805160206126cc8339815191528984095f805160206126cc833981519152908103908282089050600191505f5b87811015610c65575f805160206126cc8339815191528b84095f805160206126cc833981519152908103955089860894505f805160206126cc833981519152848609945084602082890102610a2401525f805160206126cc833981519152858d099b508b602082890102610c6401525f805160206126cc833981519152838309602082890102610ea401525f805160206126cc8339815191528a84099250600101610bbf565b50999a9950505050505050505050565b5f60128360020283011115610caf57610caf7f507265636f6d70757465204576616c2e204572726f72205b504c42454955315d6020612576565b8587600285035f5b81811015610ced575f805160206126cc8339815191528a850993505f805160206126cc8339815191528b84099250600101610cb7565b5082825f805160206126cc8339815191528b860994505f805160206126cc8339815191528c850993505f805160206126cc8339815191528483095f805160206126cc83398151915290810392508582096104a460208a0201515f805160206126cc8339815191529182039250908587095f805160206126cc8339815191528688085f805160206126cc8339815191528382095f805160206126cc833981519152908103915081830891505f805160206126cc83398151915283840992505f805160206126cc833981519152838308915060018b0395505f92505b85831015610e00575f805160206126cc8339815191528e890997505f805160206126cc8339815191528f88099650600183019250610dc7565b5f805160206126cc83398151915288860894505f805160206126cc8339815191528b860994505f805160206126cc83398151915287850893505f805160206126cc8339815191528b85099350600197508f96505f95505b8a861015610f00575f805160206126cc8339815191528e89095f805160206126cc83398151915290810391508c820890505f805160206126cc8339815191528582099050806020878c0102610a2401525f805160206126cc8339815191528188099650866020878c0102610c6401525f805160206126cc8339815191528883096020878c0102610ea401525f805160206126cc8339815191528d89099750600186019550610e57565b600197505f95505b8a861015610fb7575f805160206126cc8339815191528f89095f805160206126cc83398151915290810391508c820890505f805160206126cc8339815191528482099050806020878d8d010102610a2401525f805160206126cc8339815191528188099650866020878d8d010102610c6401525f805160206126cc8339815191528883096020878d8d010102610ea401525f805160206126cc8339815191528d89099750600186019550610f08565b50949e9d5050505050505050505050505050565b6103445161042451611004906001907f2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e808460085f610b14565b610444516110399082907f30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f7036368560046008610b14565b610484516104645191925061106e9183919077b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd866003600c610c75565b915050610a045160015f805160206126cc833981519152828409146110b8576110b87f507265636f6d70757465204576616c2e204572726f72205b50414c42455d0000601e612576565b90506011805b8015611117575f805160206126cc833981519152808460206001850302610c6401510960208302610ea401510960208202610ea401525f805160206126cc83398151915260208202610a240151840992505f19016110be565b5050610ea4515f805160206126cc83398151915290829009610ea45250565b6102a4515f805160206126cc8339815191528182095f805160206126cc83398151915282820991505f805160206126cc8339815191528283095f805160206126cc8339815191528282096104248490526104449190915261046481905290505f805160206126cc8339815191527f0925f0bd364638ec3084b45fc27895f8f3f6f079096600fe946c8e9db9a471248209610484525050565b6111d6611136565b60015f5b600981101561120b5781602082026104a401525f805160206126cc83398151915261034451830991506001016111da565b5050611215610fcb565b565b61042451610904515f905f805160206126cc83398151915290839009905060015b6007811015611277575f805160206126cc833981519152835f805160206126cc8339815191526020846007030261082401518508099150600101611238565b505f805160206126cc833981519152610824518208610ea4519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e8009610904519092505f805160206126cc83398151915290839009905060015b6007811015611341575f805160206126cc833981519152835f805160206126cc8339815191526020846007030261082401518508099150600101611302565b505f805160206126cc833981519152610824518208610ec4519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f70363609610904519092505f805160206126cc83398151915290839009905060015b600781101561140b575f805160206126cc833981519152835f805160206126cc83398151915260208460070302610824015185080991506001016113cc565b505f805160206126cc833981519152610824518208610ee4519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f1d59376149b959ccbd157ac850893a6f07c2d99b3852513ab8d01be8e846a56609610904519092505f805160206126cc83398151915290839009905060015b60078110156114d5575f805160206126cc833981519152835f805160206126cc8339815191526020846007030261082401518508099150600101611496565b505f805160206126cc833981519152610824518208610f04519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000009610904519092505f805160206126cc83398151915290839009905060015b600781101561159f575f805160206126cc833981519152835f805160206126cc8339815191526020846007030261082401518508099150600101611560565b505f805160206126cc833981519152610824518208610f24519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f0530d09118705106cbb4a786ead16926d5d174e181a26686af5448492e42a18109610904519092505f805160206126cc83398151915290839009905060015b6007811015611669575f805160206126cc833981519152835f805160206126cc833981519152602084600703026108240151850809915060010161162a565b505f805160206126cc833981519152610824518208610f44519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc8339815191529077b3c4d79d41a91758cb49c3517c4604a520cff123608fc9cb09610904519092505f805160206126cc83398151915290839009905060015b600781101561172b575f805160206126cc833981519152835f805160206126cc83398151915260208460070302610824015185080991506001016116ec565b505f805160206126cc833981519152610824518208610f64519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f130b17119778465cfb3acaee30f81dee20710ead41671f568b11d9ab07b95a9b09610904519092505f805160206126cc83398151915290839009905060015b60078110156117f5575f805160206126cc833981519152835f805160206126cc83398151915260208460070302610824015185080991506001016117b6565b505f805160206126cc833981519152610824518208610f84519091505f805160206126cc83398151915290819083096106a451086106a4526104445191505f805160206126cc833981519152828409905060015b600381101561188e575f805160206126cc833981519152835f805160206126cc8339815191526020600185600460080103030261082401518508099150600101611849565b50610924515f805160206126cc833981519152908208610fa4519091505f805160206126cc83398151915290819083096106c451086106c452610444515f805160206126cc833981519152907f30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f7036360991505f805160206126cc833981519152828409905060015b6003811015611959575f805160206126cc833981519152835f805160206126cc8339815191526020600185600460080103030261082401518508099150600101611914565b50610924515f805160206126cc833981519152908208610fc4519091505f805160206126cc83398151915290819083096106c451086106c452610444515f805160206126cc833981519152907f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000000991505f805160206126cc833981519152828409905060015b6003811015611a24575f805160206126cc833981519152835f805160206126cc83398151915260206001856004600801030302610824015185080991506001016119df565b50610924515f805160206126cc833981519152908208610fe4519091505f805160206126cc83398151915290819083096106c451086106c452610444515f805160206126cc8339815191529077b3c4d79d41a91758cb49c3517c4604a520cff123608fc9cb0991505f805160206126cc833981519152828409905060015b6003811015611ae7575f805160206126cc833981519152835f805160206126cc8339815191526020600185600460080103030261082401518508099150600101611aa2565b50610924515f805160206126cc833981519152908208611004519091505f805160206126cc83398151915290819083096106c451086106c45261046451610484519092505f805160206126cc83398151915283870991505f805160206126cc833981519152835f805160206126cc83398151915287850809610984519092505f805160206126cc833981519152908308611024519092505f805160206126cc83398151915290819084096106e451086106e4526109e4515f805160206126cc833981519152908290096109c4519092505f805160206126cc83398151915290829082908508096109a4519092505f805160206126cc833981519152908308611084519092505f805160206126cc83398151915290819084096106e451086106e452610464515f805160206126cc8339815191529077b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd09610484519093505f805160206126cc8339815191529077b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd0990505f805160206126cc83398151915283870991505f805160206126cc833981519152835f805160206126cc83398151915287850809610984519092505f805160206126cc833981519152908308611044519092505f805160206126cc83398151915290819084096106e451086106e4526109e4515f805160206126cc833981519152908290096109c4519092505f805160206126cc83398151915290829082908508096109a4519092505f805160206126cc8339815191529083086110a4519092505f805160206126cc83398151915290819084096106e451086106e452610464515f805160206126cc833981519152907f30644e72e131a029048b6e193fd84104cc37a73fec2bc5e9b8ca0b2d36636f2309610484519093505f805160206126cc833981519152907f30644e72e131a029048b6e193fd84104cc37a73fec2bc5e9b8ca0b2d36636f230990505f805160206126cc83398151915283870991505f805160206126cc833981519152835f805160206126cc83398151915287850809610984519092505f805160206126cc833981519152908308611064519092505f805160206126cc83398151915290819084096106e451086106e4526109e4515f805160206126cc833981519152908290096109c4519092505f805160206126cc83398151915290829082908508096109a4519092505f805160206126cc833981519152915082086110c4519091505f805160206126cc83398151915290819083096106e451086106e4525050505050565b5f80611eae610404516103e4516103c451611217565b6102c4515f805160206126cc833981519152908103610664526102e451810361068481905261050451086106045261066451610504515f805160206126cc833981519152919008610604519091505f805160206126cc833981519152908290096106045261066451610524515f805160206126cc833981519152919008610604519091505f805160206126cc833981519152908290096106048190526105c4819052611f7b907f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff90612594565b6105e45261068451610504515f805160206126cc8339815191529190086106245261066451610504515f805160206126cc833981519152919008610624519091505f805160206126cc8339815191529082900961062452610664516105a4515f805160206126cc833981519152919008610624519091505f805160206126cc83398151915290829009610624526105c4515f805160206126cc833981519152908290096105c45261066451610524515f805160206126cc83398151915291900861064452610664516105a4515f805160206126cc833981519152919008610644519091505f805160206126cc833981519152908290096106448190526105e4517f146c490b673b3679fa6143548cd90ecb2da85895a04494fef50391aa6897e105917f25e7bb363dab113de8490e742512a29a1094fa5ee2084570d4de714e795428fd915f805160206126cc83398151915291095f805160206126cc83398151915261032451820990506120f68161078451610764516122d7565b61210281838688612333565b6106e45191965094505f805160206126cc8339815191529084096105e451610624519194505f805160206126cc833981519152910995505f805160206126cc83398151915261030451870995506121608661074451610724516122d7565b9150915061217081838688612333565b6106c45191965094505f805160206126cc83398151915290870995505f805160206126cc83398151915286840892505f805160206126cc8339815191526106a451840892506121c283600260016122d7565b915091506121d28183868861237c565b945094505f805160206126cc8339815191526105e4516105c451096105c4526122056105c4516107c4516107a4516122d7565b915091506122158183868861237c565b9450945061222d61034451610804516107e4516122d7565b9150915061223d81838688612333565b945094505050505f925061080451612280576107e4511561227b5761227b746e6f6e207a65726f20782076616c7565205b434f5d60581b6015612576565b600192505b61228b8382846123dc565b935050505090565b5f61020353610244526064610200206001610203536064610200206102245261020452565b60026102035360e01b610244526048610200206001600160fd1b031690565b80608052508060a052508060c052505f80604060806060608060075afa80612324576123247f706f696e74206d756c7469706c69636174696f6e206661696c65640000000000601b612576565b505060805160a0519092909150565b80608052508060a052508060c052508060e052505f806040608080608060065afa8061232457612324741c1bda5b9d081859191a5d1a5bdb8819985a5b1959605a1b6015612576565b80608052508060a052508060c05250805f805160206126ac8339815191520360e052505f806040608080608060065afa80612324576123247f706f696e74207375627472616374696f6e206661696c656400000000000000006018612576565b60805260a0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260c0527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60e0527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610100527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa610120526107e4516101405261080451610160525f816124a257610804515f805160206126ac83398151915203610160525b7f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1610180527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b06101a0527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe46101c0527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101e052602060806020600c02608060085afa8061256c5761256c731c185a5c9a5b99c818da1958dac819985a5b195960621b6014612576565b5050608051919050565b62461bcd60e51b60805260206084528060a452508060c45260646080fd5b60205f52602080526020604052806060525080608052505f805160206126cc83398151915260a0525f60205f60c05f60055afa6125f6576125f67f6d6f6465787020707265636f6d70696c65206661696c656400000000000000006018612576565b505f5190565b5f8083601f84011261260c575f80fd5b50813567ffffffffffffffff811115612623575f80fd5b6020830191508360208260051b850101111561263d575f80fd5b9250929050565b5f805f8060408587031215612657575f80fd5b843567ffffffffffffffff8082111561266e575f80fd5b61267a888389016125fc565b90965094506020870135915080821115612692575f80fd5b5061269f878288016125fc565b9598949750955050505056fe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4730644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a264697066735822122071f4c9af55f861ad7b48e65f0a0a1906b4a29e35485603136998d5415fd8eb6864736f6c63430008180033
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c80639e8945d214610038578063b864f5a91461020c575b5f80fd5b6101f960408051600160208201527f146c490b673b3679fa6143548cd90ecb2da85895a04494fef50391aa6897e105918101919091527f25e7bb363dab113de8490e742512a29a1094fa5ee2084570d4de714e795428fd606082015260056080820152600760a08201527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260c08201527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60e08201527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6101008201527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101208201527f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c16101408201527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b06101608201527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe46101808201527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101a08201525f906101c00160405160208183030381529060405280519060200120905090565b6040519081526020015b60405180910390f35b61021f61021a366004612644565b61022f565b6040519015158152602001610203565b5f610238610268565b6102406105f0565b610248610844565b6102506108d6565b6102586111ce565b610260611e98565b805f5260205ff35b6004356004810135600181146102a3576102a37f7075626c696320696e707574206c656e67746820697320696e636f72726563746020612576565b505f805160206126cc8339815191526024918201350661070452356004810135601881146102f6576102f67f70726f6f66206c656e67746820697320696e636f7272656374000000000000006019612576565b506024810190505f805160206126ac8339815191528135065f805160206126ac8339815191526020830135065f805160206126ac8339815191528283095f805160206126ac83398151915260035f805160206126ac833981519152838609085f805160206126ac83398151915283840914610396576103967f636f6d6d69746d656e742030206973206e6f74206f6e20637572766500000000601c612576565b508061074452508061072452505f805160206126ac8339815191526040820135065f805160206126ac8339815191526060830135065f805160206126ac8339815191528283095f805160206126ac83398151915260035f805160206126ac833981519152838609085f805160206126ac8339815191528384091461043f5761043f7f636f6d6d69746d656e742031206973206e6f74206f6e20637572766500000000601c612576565b508061078452508061076452505f805160206126ac8339815191526080820135065f805160206126ac83398151915260a0830135065f805160206126ac8339815191528283095f805160206126ac83398151915260035f805160206126ac833981519152838609085f805160206126ac833981519152838409146104e8576104e87f636f6d6d69746d656e742032206973206e6f74206f6e20637572766500000000601c612576565b50806107c45250806107a452505f805160206126ac83398151915260c0820135065f805160206126ac83398151915260e0830135065f805160206126ac8339815191528283095f805160206126ac83398151915260035f805160206126ac833981519152838609085f805160206126ac83398151915283840914610591576105917f636f6d6d69746d656e742033206973206e6f74206f6e20637572766500000000601c612576565b50610804526107e452610100015f5b600f8110156105d2575f805160206126cc833981519152602082028381013591909106610824909101526001016105a0565b505f805160206126cc8339815191526101e0919091013506610a0452565b5f5b60018110156106145761060c602082026107040151612293565b6001016105f2565b5061063e7f146c490b673b3679fa6143548cd90ecb2da85895a04494fef50391aa6897e105612293565b6106677f25e7bb363dab113de8490e742512a29a1094fa5ee2084570d4de714e795428fd612293565b61067361072451612293565b61067f61074451612293565b6106885f6122b8565b6102645261069660016122b8565b610284526106a661076451612293565b6106b261078451612293565b6106bc60026122b8565b6102a4525f5b600f8110156106e4576106dc602082026108240151612293565b6001016106c2565b506106ef60036122b8565b610304525f805160206126cc8339815191526103045161030451096103245261071a6107a451612293565b6107266107c451612293565b61073060046122b8565b6103445261074260186102a451612594565b6102c4525f805160206126cc8339815191527f1283ba6f4b7b1a76ba2008fe823128bea4adb9269cbfd7c41c223be65bc608636102c451096102e4525f805160206126cc83398151915260015f805160206126cc833981519152036107ad628000006102c451612594565b086103645261080260025f805160206126cc833981519152035f805160206126cc833981519152628000005f805160206126cc83398151915260015f805160206126cc833981519152036102c4510809612594565b6103a4525f805160206126cc833981519152610364516103a451096103a45261083e60025f805160206126cc8339815191520361036451612594565b61038452565b6108a451610704516103a4515f805160206126cc83398151915291829109820890505f5b60038110156108a2575f805160206126cc833981519152806020836008010261082401516020840261082401510983089150600101610868565b50610384516109445161092451610884515f805160206126cc83398151915293928492839283919009098408096103c45250565b5f805f805160206126cc833981519152602060026008010261082401515f805160206126cc833981519152610284515f805160206126cc83398151915260075f805160206126cc8339815191526102c45161026451090908085f805160206126cc833981519152602060016008010261082401515f805160206126cc833981519152610284515f805160206126cc83398151915260055f805160206126cc8339815191526102c451610264510909080892505f805160206126cc83398151915283820990505f805160206126cc8339815191526020600b0261082401515f805160206126cc83398151915280602060080261082401515f805160206126cc833981519152610284515f805160206126cc8339815191526102c4516102645109080884090961094451610284516108e451610264519394505f805160206126cc83398151915293849392849290918391900908086109a451610964516102845161090451610264515f805160206126cc8339815191529493859390928492839190090808090961092451610284516108c451610264519395505f805160206126cc83398151915293849291839109080892505f805160206126cc833981519152838309610384515f805160206126cc833981519152918203935081848408099050806103e4525f805160206126cc833981519152610384515f805160206126cc8339815191526103a4515f805160206126cc83398151915260015f805160206126cc833981519152036020600b02610824015108090961040452505050565b5f60128383011115610b4b57610b4b7f507265636f6d70757465204576616c2e204572726f72205b504c424549315d00601f612576565b85600284035f5b81811015610b75575f805160206126cc8339815191528984099250600101610b52565b50505f805160206126cc833981519152818509602085026104a401515f805160206126cc8339815191528984095f805160206126cc833981519152908103908282089050600191505f5b87811015610c65575f805160206126cc8339815191528b84095f805160206126cc833981519152908103955089860894505f805160206126cc833981519152848609945084602082890102610a2401525f805160206126cc833981519152858d099b508b602082890102610c6401525f805160206126cc833981519152838309602082890102610ea401525f805160206126cc8339815191528a84099250600101610bbf565b50999a9950505050505050505050565b5f60128360020283011115610caf57610caf7f507265636f6d70757465204576616c2e204572726f72205b504c42454955315d6020612576565b8587600285035f5b81811015610ced575f805160206126cc8339815191528a850993505f805160206126cc8339815191528b84099250600101610cb7565b5082825f805160206126cc8339815191528b860994505f805160206126cc8339815191528c850993505f805160206126cc8339815191528483095f805160206126cc83398151915290810392508582096104a460208a0201515f805160206126cc8339815191529182039250908587095f805160206126cc8339815191528688085f805160206126cc8339815191528382095f805160206126cc833981519152908103915081830891505f805160206126cc83398151915283840992505f805160206126cc833981519152838308915060018b0395505f92505b85831015610e00575f805160206126cc8339815191528e890997505f805160206126cc8339815191528f88099650600183019250610dc7565b5f805160206126cc83398151915288860894505f805160206126cc8339815191528b860994505f805160206126cc83398151915287850893505f805160206126cc8339815191528b85099350600197508f96505f95505b8a861015610f00575f805160206126cc8339815191528e89095f805160206126cc83398151915290810391508c820890505f805160206126cc8339815191528582099050806020878c0102610a2401525f805160206126cc8339815191528188099650866020878c0102610c6401525f805160206126cc8339815191528883096020878c0102610ea401525f805160206126cc8339815191528d89099750600186019550610e57565b600197505f95505b8a861015610fb7575f805160206126cc8339815191528f89095f805160206126cc83398151915290810391508c820890505f805160206126cc8339815191528482099050806020878d8d010102610a2401525f805160206126cc8339815191528188099650866020878d8d010102610c6401525f805160206126cc8339815191528883096020878d8d010102610ea401525f805160206126cc8339815191528d89099750600186019550610f08565b50949e9d5050505050505050505050505050565b6103445161042451611004906001907f2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e808460085f610b14565b610444516110399082907f30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f7036368560046008610b14565b610484516104645191925061106e9183919077b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd866003600c610c75565b915050610a045160015f805160206126cc833981519152828409146110b8576110b87f507265636f6d70757465204576616c2e204572726f72205b50414c42455d0000601e612576565b90506011805b8015611117575f805160206126cc833981519152808460206001850302610c6401510960208302610ea401510960208202610ea401525f805160206126cc83398151915260208202610a240151840992505f19016110be565b5050610ea4515f805160206126cc83398151915290829009610ea45250565b6102a4515f805160206126cc8339815191528182095f805160206126cc83398151915282820991505f805160206126cc8339815191528283095f805160206126cc8339815191528282096104248490526104449190915261046481905290505f805160206126cc8339815191527f0925f0bd364638ec3084b45fc27895f8f3f6f079096600fe946c8e9db9a471248209610484525050565b6111d6611136565b60015f5b600981101561120b5781602082026104a401525f805160206126cc83398151915261034451830991506001016111da565b5050611215610fcb565b565b61042451610904515f905f805160206126cc83398151915290839009905060015b6007811015611277575f805160206126cc833981519152835f805160206126cc8339815191526020846007030261082401518508099150600101611238565b505f805160206126cc833981519152610824518208610ea4519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e8009610904519092505f805160206126cc83398151915290839009905060015b6007811015611341575f805160206126cc833981519152835f805160206126cc8339815191526020846007030261082401518508099150600101611302565b505f805160206126cc833981519152610824518208610ec4519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f70363609610904519092505f805160206126cc83398151915290839009905060015b600781101561140b575f805160206126cc833981519152835f805160206126cc83398151915260208460070302610824015185080991506001016113cc565b505f805160206126cc833981519152610824518208610ee4519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f1d59376149b959ccbd157ac850893a6f07c2d99b3852513ab8d01be8e846a56609610904519092505f805160206126cc83398151915290839009905060015b60078110156114d5575f805160206126cc833981519152835f805160206126cc8339815191526020846007030261082401518508099150600101611496565b505f805160206126cc833981519152610824518208610f04519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000009610904519092505f805160206126cc83398151915290839009905060015b600781101561159f575f805160206126cc833981519152835f805160206126cc8339815191526020846007030261082401518508099150600101611560565b505f805160206126cc833981519152610824518208610f24519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f0530d09118705106cbb4a786ead16926d5d174e181a26686af5448492e42a18109610904519092505f805160206126cc83398151915290839009905060015b6007811015611669575f805160206126cc833981519152835f805160206126cc833981519152602084600703026108240151850809915060010161162a565b505f805160206126cc833981519152610824518208610f44519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc8339815191529077b3c4d79d41a91758cb49c3517c4604a520cff123608fc9cb09610904519092505f805160206126cc83398151915290839009905060015b600781101561172b575f805160206126cc833981519152835f805160206126cc83398151915260208460070302610824015185080991506001016116ec565b505f805160206126cc833981519152610824518208610f64519091505f805160206126cc83398151915290819083096106a451086106a452610424515f805160206126cc833981519152907f130b17119778465cfb3acaee30f81dee20710ead41671f568b11d9ab07b95a9b09610904519092505f805160206126cc83398151915290839009905060015b60078110156117f5575f805160206126cc833981519152835f805160206126cc83398151915260208460070302610824015185080991506001016117b6565b505f805160206126cc833981519152610824518208610f84519091505f805160206126cc83398151915290819083096106a451086106a4526104445191505f805160206126cc833981519152828409905060015b600381101561188e575f805160206126cc833981519152835f805160206126cc8339815191526020600185600460080103030261082401518508099150600101611849565b50610924515f805160206126cc833981519152908208610fa4519091505f805160206126cc83398151915290819083096106c451086106c452610444515f805160206126cc833981519152907f30644e72e131a029048b6e193fd841045cea24f6fd736bec231204708f7036360991505f805160206126cc833981519152828409905060015b6003811015611959575f805160206126cc833981519152835f805160206126cc8339815191526020600185600460080103030261082401518508099150600101611914565b50610924515f805160206126cc833981519152908208610fc4519091505f805160206126cc83398151915290819083096106c451086106c452610444515f805160206126cc833981519152907f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000000991505f805160206126cc833981519152828409905060015b6003811015611a24575f805160206126cc833981519152835f805160206126cc83398151915260206001856004600801030302610824015185080991506001016119df565b50610924515f805160206126cc833981519152908208610fe4519091505f805160206126cc83398151915290819083096106c451086106c452610444515f805160206126cc8339815191529077b3c4d79d41a91758cb49c3517c4604a520cff123608fc9cb0991505f805160206126cc833981519152828409905060015b6003811015611ae7575f805160206126cc833981519152835f805160206126cc8339815191526020600185600460080103030261082401518508099150600101611aa2565b50610924515f805160206126cc833981519152908208611004519091505f805160206126cc83398151915290819083096106c451086106c45261046451610484519092505f805160206126cc83398151915283870991505f805160206126cc833981519152835f805160206126cc83398151915287850809610984519092505f805160206126cc833981519152908308611024519092505f805160206126cc83398151915290819084096106e451086106e4526109e4515f805160206126cc833981519152908290096109c4519092505f805160206126cc83398151915290829082908508096109a4519092505f805160206126cc833981519152908308611084519092505f805160206126cc83398151915290819084096106e451086106e452610464515f805160206126cc8339815191529077b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd09610484519093505f805160206126cc8339815191529077b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd0990505f805160206126cc83398151915283870991505f805160206126cc833981519152835f805160206126cc83398151915287850809610984519092505f805160206126cc833981519152908308611044519092505f805160206126cc83398151915290819084096106e451086106e4526109e4515f805160206126cc833981519152908290096109c4519092505f805160206126cc83398151915290829082908508096109a4519092505f805160206126cc8339815191529083086110a4519092505f805160206126cc83398151915290819084096106e451086106e452610464515f805160206126cc833981519152907f30644e72e131a029048b6e193fd84104cc37a73fec2bc5e9b8ca0b2d36636f2309610484519093505f805160206126cc833981519152907f30644e72e131a029048b6e193fd84104cc37a73fec2bc5e9b8ca0b2d36636f230990505f805160206126cc83398151915283870991505f805160206126cc833981519152835f805160206126cc83398151915287850809610984519092505f805160206126cc833981519152908308611064519092505f805160206126cc83398151915290819084096106e451086106e4526109e4515f805160206126cc833981519152908290096109c4519092505f805160206126cc83398151915290829082908508096109a4519092505f805160206126cc833981519152915082086110c4519091505f805160206126cc83398151915290819083096106e451086106e4525050505050565b5f80611eae610404516103e4516103c451611217565b6102c4515f805160206126cc833981519152908103610664526102e451810361068481905261050451086106045261066451610504515f805160206126cc833981519152919008610604519091505f805160206126cc833981519152908290096106045261066451610524515f805160206126cc833981519152919008610604519091505f805160206126cc833981519152908290096106048190526105c4819052611f7b907f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff90612594565b6105e45261068451610504515f805160206126cc8339815191529190086106245261066451610504515f805160206126cc833981519152919008610624519091505f805160206126cc8339815191529082900961062452610664516105a4515f805160206126cc833981519152919008610624519091505f805160206126cc83398151915290829009610624526105c4515f805160206126cc833981519152908290096105c45261066451610524515f805160206126cc83398151915291900861064452610664516105a4515f805160206126cc833981519152919008610644519091505f805160206126cc833981519152908290096106448190526105e4517f146c490b673b3679fa6143548cd90ecb2da85895a04494fef50391aa6897e105917f25e7bb363dab113de8490e742512a29a1094fa5ee2084570d4de714e795428fd915f805160206126cc83398151915291095f805160206126cc83398151915261032451820990506120f68161078451610764516122d7565b61210281838688612333565b6106e45191965094505f805160206126cc8339815191529084096105e451610624519194505f805160206126cc833981519152910995505f805160206126cc83398151915261030451870995506121608661074451610724516122d7565b9150915061217081838688612333565b6106c45191965094505f805160206126cc83398151915290870995505f805160206126cc83398151915286840892505f805160206126cc8339815191526106a451840892506121c283600260016122d7565b915091506121d28183868861237c565b945094505f805160206126cc8339815191526105e4516105c451096105c4526122056105c4516107c4516107a4516122d7565b915091506122158183868861237c565b9450945061222d61034451610804516107e4516122d7565b9150915061223d81838688612333565b945094505050505f925061080451612280576107e4511561227b5761227b746e6f6e207a65726f20782076616c7565205b434f5d60581b6015612576565b600192505b61228b8382846123dc565b935050505090565b5f61020353610244526064610200206001610203536064610200206102245261020452565b60026102035360e01b610244526048610200206001600160fd1b031690565b80608052508060a052508060c052505f80604060806060608060075afa80612324576123247f706f696e74206d756c7469706c69636174696f6e206661696c65640000000000601b612576565b505060805160a0519092909150565b80608052508060a052508060c052508060e052505f806040608080608060065afa8061232457612324741c1bda5b9d081859191a5d1a5bdb8819985a5b1959605a1b6015612576565b80608052508060a052508060c05250805f805160206126ac8339815191520360e052505f806040608080608060065afa80612324576123247f706f696e74207375627472616374696f6e206661696c656400000000000000006018612576565b60805260a0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c260c0527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed60e0527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610100527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa610120526107e4516101405261080451610160525f816124a257610804515f805160206126ac83398151915203610160525b7f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1610180527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b06101a0527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe46101c0527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101e052602060806020600c02608060085afa8061256c5761256c731c185a5c9a5b99c818da1958dac819985a5b195960621b6014612576565b5050608051919050565b62461bcd60e51b60805260206084528060a452508060c45260646080fd5b60205f52602080526020604052806060525080608052505f805160206126cc83398151915260a0525f60205f60c05f60055afa6125f6576125f67f6d6f6465787020707265636f6d70696c65206661696c656400000000000000006018612576565b505f5190565b5f8083601f84011261260c575f80fd5b50813567ffffffffffffffff811115612623575f80fd5b6020830191508360208260051b850101111561263d575f80fd5b9250929050565b5f805f8060408587031215612657575f80fd5b843567ffffffffffffffff8082111561266e575f80fd5b61267a888389016125fc565b90965094506020870135915080821115612692575f80fd5b5061269f878288016125fc565b9598949750955050505056fe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4730644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a264697066735822122071f4c9af55f861ad7b48e65f0a0a1906b4a29e35485603136998d5415fd8eb6864736f6c63430008180033
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.