From 6da9eb30cf3682dfefe3a50c0d1aeb8e81c65bf4 Mon Sep 17 00:00:00 2001 From: krlosMata Date: Tue, 10 Sep 2024 16:02:28 +0200 Subject: [PATCH] set verifiers forkID & add README in updateRollup tool --- contracts/verifiers/FflonkVerifier.sol | 1760 ++++++++++---- contracts/verifiers/FflonkVerifier_12.sol | 2158 +++++++++++++++++ .../previousVerifiers/FflonkVerifier_10.sol | 2158 +++++++++++++++++ .../previousVerifiers/FflonkVerifier_11.sol | 2158 +++++++++++++++++ .../v2/create_rollup_parameters.json.example | 2 +- tools/addRollupType/.gitignore | 3 +- tools/addRollupType/addRollupType.ts | 20 +- tools/deployVerifier/deployVerifier.ts | 2 +- .../deploy_verifier_parameters.example | 1 + tools/updateRollup/.gitignore | 2 + tools/updateRollup/README.md | 61 + tools/updateRollup/updateRollup.ts | 110 +- tools/updateRollup/updateRollupTimelock.ts | 184 ++ 13 files changed, 8096 insertions(+), 523 deletions(-) create mode 100644 contracts/verifiers/FflonkVerifier_12.sol create mode 100644 contracts/verifiers/previousVerifiers/FflonkVerifier_10.sol create mode 100644 contracts/verifiers/previousVerifiers/FflonkVerifier_11.sol create mode 100644 tools/updateRollup/.gitignore create mode 100644 tools/updateRollup/README.md create mode 100644 tools/updateRollup/updateRollupTimelock.ts diff --git a/contracts/verifiers/FflonkVerifier.sol b/contracts/verifiers/FflonkVerifier.sol index 5e69dc102..74e9d79ae 100644 --- a/contracts/verifiers/FflonkVerifier.sol +++ b/contracts/verifiers/FflonkVerifier.sol @@ -21,91 +21,117 @@ pragma solidity >=0.7.0 <0.9.0; contract FflonkVerifier { - uint32 constant n = 16777216; // Domain size + uint32 constant n = 16777216; // Domain size // Verification Key data - uint256 constant k1 = 2; // Plonk k1 multiplicative factor to force distinct cosets of H - uint256 constant k2 = 3; // Plonk k2 multiplicative factor to force distinct cosets of H + uint256 constant k1 = 2; // Plonk k1 multiplicative factor to force distinct cosets of H + uint256 constant k2 = 3; // Plonk k2 multiplicative factor to force distinct cosets of H // OMEGAS // Omega, Omega^{1/3} - uint256 constant w1 = 5709868443893258075976348696661355716898495876243883251619397131511003808859; - uint256 constant wr = 18200100796661656210024324131237448517259556535315737226009542456080026430510; + uint256 constant w1 = + 5709868443893258075976348696661355716898495876243883251619397131511003808859; + uint256 constant wr = + 18200100796661656210024324131237448517259556535315737226009542456080026430510; // Omega_3, Omega_3^2 - uint256 constant w3 = 21888242871839275217838484774961031246154997185409878258781734729429964517155; - uint256 constant w3_2 = 4407920970296243842393367215006156084916469457145843978461; + uint256 constant w3 = + 21888242871839275217838484774961031246154997185409878258781734729429964517155; + uint256 constant w3_2 = + 4407920970296243842393367215006156084916469457145843978461; // Omega_4, Omega_4^2, Omega_4^3 - uint256 constant w4 = 21888242871839275217838484774961031246007050428528088939761107053157389710902; - uint256 constant w4_2 = 21888242871839275222246405745257275088548364400416034343698204186575808495616; - uint256 constant w4_3 = 4407920970296243842541313971887945403937097133418418784715; + uint256 constant w4 = + 21888242871839275217838484774961031246007050428528088939761107053157389710902; + uint256 constant w4_2 = + 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 constant w4_3 = + 4407920970296243842541313971887945403937097133418418784715; // Omega_8, Omega_8^2, Omega_8^3, Omega_8^4, Omega_8^5, Omega_8^6, Omega_8^7 - uint256 constant w8_1 = 19540430494807482326159819597004422086093766032135589407132600596362845576832; - uint256 constant w8_2 = 21888242871839275217838484774961031246007050428528088939761107053157389710902; - uint256 constant w8_3 = 13274704216607947843011480449124596415239537050559949017414504948711435969894; - uint256 constant w8_4 = 21888242871839275222246405745257275088548364400416034343698204186575808495616; - uint256 constant w8_5 = 2347812377031792896086586148252853002454598368280444936565603590212962918785; - uint256 constant w8_6 = 4407920970296243842541313971887945403937097133418418784715; - uint256 constant w8_7 = 8613538655231327379234925296132678673308827349856085326283699237864372525723; + uint256 constant w8_1 = + 19540430494807482326159819597004422086093766032135589407132600596362845576832; + uint256 constant w8_2 = + 21888242871839275217838484774961031246007050428528088939761107053157389710902; + uint256 constant w8_3 = + 13274704216607947843011480449124596415239537050559949017414504948711435969894; + uint256 constant w8_4 = + 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 constant w8_5 = + 2347812377031792896086586148252853002454598368280444936565603590212962918785; + uint256 constant w8_6 = + 4407920970296243842541313971887945403937097133418418784715; + uint256 constant w8_7 = + 8613538655231327379234925296132678673308827349856085326283699237864372525723; // Verifier preprocessed input C_0(x)·[1]_1 - uint256 constant C0x = 14108481345212921148996352149587402371241828412155926312706521103747833870705; - uint256 constant C0y = 5431364720504262011685673568202437040741271312846880378221091213893853645141; + uint256 constant C0x = + 19531210301294568511992648735135291982401633864004026433715722115099857739632; + uint256 constant C0y = + 16913517370715546973488219367119174715262034757907912789481968159710930517904; // Verifier preprocessed input x·[1]_2 - uint256 constant X2x1 = 21831381940315734285607113342023901060522397560371972897001948545212302161822; - uint256 constant X2x2 = 17231025384763736816414546592865244497437017442647097510447326538965263639101; - uint256 constant X2y1 = 2388026358213174446665280700919698872609886601280537296205114254867301080648; - uint256 constant X2y2 = 11507326595632554467052522095592665270651932854513688777769618397986436103170; + uint256 constant X2x1 = + 21831381940315734285607113342023901060522397560371972897001948545212302161822; + uint256 constant X2x2 = + 17231025384763736816414546592865244497437017442647097510447326538965263639101; + uint256 constant X2y1 = + 2388026358213174446665280700919698872609886601280537296205114254867301080648; + uint256 constant X2y2 = + 11507326595632554467052522095592665270651932854513688777769618397986436103170; // Scalar field size - uint256 constant q = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + uint256 constant q = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Base field size - uint256 constant qf = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + uint256 constant qf = + 21888242871839275222246405745257275088696311157297823662689037894645226208583; // [1]_1 - uint256 constant G1x = 1; - uint256 constant G1y = 2; + uint256 constant G1x = 1; + uint256 constant G1y = 2; // [1]_2 - uint256 constant G2x1 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; - uint256 constant G2x2 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; - uint256 constant G2y1 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; - uint256 constant G2y2 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; + uint256 constant G2x1 = + 10857046999023057135944570762232829481370756359578518086990519993285655852781; + uint256 constant G2x2 = + 11559732032986387107991004021392285783925812861821192530917403151452391805634; + uint256 constant G2y1 = + 8495653923123431417604973247489272438418190587263600148770280649306958101930; + uint256 constant G2y2 = + 4082367875863433681332203403145435568316851327593401208105741076214120093531; // Proof calldata // Byte offset of every parameter of the calldata // Polynomial commitments - uint16 constant pC1 = 4 + 0; // [C1]_1 - uint16 constant pC2 = 4 + 32*2; // [C2]_1 - uint16 constant pW1 = 4 + 32*4; // [W]_1 - uint16 constant pW2 = 4 + 32*6; // [W']_1 + uint16 constant pC1 = 4 + 0; // [C1]_1 + uint16 constant pC2 = 4 + 32 * 2; // [C2]_1 + uint16 constant pW1 = 4 + 32 * 4; // [W]_1 + uint16 constant pW2 = 4 + 32 * 6; // [W']_1 // Opening evaluations - uint16 constant pEval_ql = 4 + 32*8; // q_L(xi) - uint16 constant pEval_qr = 4 + 32*9; // q_R(xi) - uint16 constant pEval_qm = 4 + 32*10; // q_M(xi) - uint16 constant pEval_qo = 4 + 32*11; // q_O(xi) - uint16 constant pEval_qc = 4 + 32*12; // q_C(xi) - uint16 constant pEval_s1 = 4 + 32*13; // S_{sigma_1}(xi) - uint16 constant pEval_s2 = 4 + 32*14; // S_{sigma_2}(xi) - uint16 constant pEval_s3 = 4 + 32*15; // S_{sigma_3}(xi) - uint16 constant pEval_a = 4 + 32*16; // a(xi) - uint16 constant pEval_b = 4 + 32*17; // b(xi) - uint16 constant pEval_c = 4 + 32*18; // c(xi) - uint16 constant pEval_z = 4 + 32*19; // z(xi) - uint16 constant pEval_zw = 4 + 32*20; // z_omega(xi) - uint16 constant pEval_t1w = 4 + 32*21; // T_1(xi omega) - uint16 constant pEval_t2w = 4 + 32*22; // T_2(xi omega) - uint16 constant pEval_inv = 4 + 32*23; // inv(batch) sent by the prover to avoid any inverse calculation to save gas, - // we check the correctness of the inv(batch) by computing batch - // and checking inv(batch) * batch == 1 + uint16 constant pEval_ql = 4 + 32 * 8; // q_L(xi) + uint16 constant pEval_qr = 4 + 32 * 9; // q_R(xi) + uint16 constant pEval_qm = 4 + 32 * 10; // q_M(xi) + uint16 constant pEval_qo = 4 + 32 * 11; // q_O(xi) + uint16 constant pEval_qc = 4 + 32 * 12; // q_C(xi) + uint16 constant pEval_s1 = 4 + 32 * 13; // S_{sigma_1}(xi) + uint16 constant pEval_s2 = 4 + 32 * 14; // S_{sigma_2}(xi) + uint16 constant pEval_s3 = 4 + 32 * 15; // S_{sigma_3}(xi) + uint16 constant pEval_a = 4 + 32 * 16; // a(xi) + uint16 constant pEval_b = 4 + 32 * 17; // b(xi) + uint16 constant pEval_c = 4 + 32 * 18; // c(xi) + uint16 constant pEval_z = 4 + 32 * 19; // z(xi) + uint16 constant pEval_zw = 4 + 32 * 20; // z_omega(xi) + uint16 constant pEval_t1w = 4 + 32 * 21; // T_1(xi omega) + uint16 constant pEval_t2w = 4 + 32 * 22; // T_2(xi omega) + uint16 constant pEval_inv = 4 + 32 * 23; // inv(batch) sent by the prover to avoid any inverse calculation to save gas, + // we check the correctness of the inv(batch) by computing batch + // and checking inv(batch) * batch == 1 // Memory data // Challenges - uint16 constant pAlpha = 0; // alpha challenge - uint16 constant pBeta = 32; // beta challenge - uint16 constant pGamma = 64; // gamma challenge - uint16 constant pY = 96; // y challenge - uint16 constant pXiSeed = 128; // xi seed, from this value we compute xi = xiSeed^24 + uint16 constant pAlpha = 0; // alpha challenge + uint16 constant pBeta = 32; // beta challenge + uint16 constant pGamma = 64; // gamma challenge + uint16 constant pY = 96; // y challenge + uint16 constant pXiSeed = 128; // xi seed, from this value we compute xi = xiSeed^24 uint16 constant pXiSeed2 = 160; // (xi seed)^2 - uint16 constant pXi = 192; // xi challenge + uint16 constant pXi = 192; // xi challenge // Roots // S_0 = roots_8(xi) = { h_0, h_0w_8, h_0w_8^2, h_0w_8^3, h_0w_8^4, h_0w_8^5, h_0w_8^6, h_0w_8^7 } @@ -134,40 +160,40 @@ contract FflonkVerifier { uint16 constant pH3w3_1 = 736; uint16 constant pH3w3_2 = 768; - uint16 constant pPi = 800; // PI(xi) - uint16 constant pR0 = 832; // r0(y) - uint16 constant pR1 = 864; // r1(y) - uint16 constant pR2 = 896; // r2(y) + uint16 constant pPi = 800; // PI(xi) + uint16 constant pR0 = 832; // r0(y) + uint16 constant pR1 = 864; // r1(y) + uint16 constant pR2 = 896; // r2(y) - uint16 constant pF = 928; // [F]_1, 64 bytes - uint16 constant pE = 992; // [E]_1, 64 bytes - uint16 constant pJ = 1056; // [J]_1, 64 bytes + uint16 constant pF = 928; // [F]_1, 64 bytes + uint16 constant pE = 992; // [E]_1, 64 bytes + uint16 constant pJ = 1056; // [J]_1, 64 bytes - uint16 constant pZh = 1184; // Z_H(xi) + uint16 constant pZh = 1184; // Z_H(xi) // From this point we write all the variables that must be computed using the Montgomery batch inversion - uint16 constant pZhInv = 1216; // 1/Z_H(xi) - uint16 constant pDenH1 = 1248; // 1/( (y-h_1w_4) (y-h_1w_4^2) (y-h_1w_4^3) (y-h_1w_4^4) ) - uint16 constant pDenH2 = 1280; // 1/( (y-h_2w_3) (y-h_2w_3^2) (y-h_2w_3^3) (y-h_3w_3) (y-h_3w_3^2) (y-h_3w_3^3) ) + uint16 constant pZhInv = 1216; // 1/Z_H(xi) + uint16 constant pDenH1 = 1248; // 1/( (y-h_1w_4) (y-h_1w_4^2) (y-h_1w_4^3) (y-h_1w_4^4) ) + uint16 constant pDenH2 = 1280; // 1/( (y-h_2w_3) (y-h_2w_3^2) (y-h_2w_3^3) (y-h_3w_3) (y-h_3w_3^2) (y-h_3w_3^3) ) uint16 constant pLiS0Inv = 1312; // Reserve 8 * 32 bytes to compute r_0(X) uint16 constant pLiS1Inv = 1568; // Reserve 4 * 32 bytes to compute r_1(X) uint16 constant pLiS2Inv = 1696; // Reserve 6 * 32 bytes to compute r_2(X) // Lagrange evaluations - + uint16 constant pEval_l1 = 1888; - - + uint16 constant lastMem = 1920; - - function verifyProof(bytes32[24] calldata proof, uint256[1] calldata pubSignals) public view returns (bool) { + function verifyProof( + bytes32[24] calldata proof, + uint256[1] calldata pubSignals + ) public view returns (bool) { assembly { // Computes the inverse of an array of values // See https://vitalik.ca/general/2018/07/21/starks_part_3.html in section where explain fields operations // To save the inverse to be computed on chain the prover sends the inverse as an evaluation in commits.eval_inv function inverseArray(pMem) { - - let pAux := mload(0x40) // Point to the next free position - let acc := mload(add(pMem,pZhInv)) // Read the first element + let pAux := mload(0x40) // Point to the next free position + let acc := mload(add(pMem, pZhInv)) // Read the first element mstore(pAux, acc) pAux := add(pAux, 32) @@ -254,13 +280,12 @@ contract FflonkVerifier { acc := mulmod(acc, mload(add(pMem, pEval_l1)), q) mstore(pAux, acc) - let inv := calldataload(pEval_inv) // Before using the inverse sent by the prover the verifier checks inv(batch) * batch === 1 if iszero(eq(1, mulmod(acc, inv, q))) { mstore(0, 0) - return(0,0x20) + return(0, 0x20) } acc := inv @@ -373,8 +398,8 @@ contract FflonkVerifier { mstore(0, 0) return(0, 0x20) } - } - + } + // Validate all the evaluations sent by the prover ∈ F function checkInput() { // Check proof commitments fullfill bn128 curve equation Y^2 = X^3 + 3 @@ -405,18 +430,22 @@ contract FflonkVerifier { function computeChallenges(pMem, pPublic) { // Compute challenge.beta & challenge.gamma - mstore(add(pMem, 1920 ), C0x) - mstore(add(pMem, 1952 ), C0y) + mstore(add(pMem, 1920), C0x) + mstore(add(pMem, 1952), C0y) mstore(add(pMem, 1984), calldataload(pPublic)) - - - mstore(add(pMem, 2016 ), calldataload(pC1)) - mstore(add(pMem, 2048 ), calldataload(add(pC1, 32))) + mstore(add(pMem, 2016), calldataload(pC1)) + mstore(add(pMem, 2048), calldataload(add(pC1, 32))) - mstore(add(pMem, pBeta), mod(keccak256(add(pMem, lastMem), 160), q)) - mstore(add(pMem, pGamma), mod(keccak256(add(pMem, pBeta), 32), q)) + mstore( + add(pMem, pBeta), + mod(keccak256(add(pMem, lastMem), 160), q) + ) + mstore( + add(pMem, pGamma), + mod(keccak256(add(pMem, pBeta), 32), q) + ) // Get xiSeed & xiSeed2 mstore(add(pMem, lastMem), mload(add(pMem, pGamma))) @@ -428,99 +457,175 @@ contract FflonkVerifier { mstore(add(pMem, pXiSeed2), mulmod(xiSeed, xiSeed, q)) // Compute roots.S0.h0w8 - mstore(add(pMem, pH0w8_0), mulmod(mload(add(pMem, pXiSeed2)), mload(add(pMem, pXiSeed)), q)) - mstore(add(pMem, pH0w8_1), mulmod(mload(add(pMem, pH0w8_0)), w8_1, q)) - mstore(add(pMem, pH0w8_2), mulmod(mload(add(pMem, pH0w8_0)), w8_2, q)) - mstore(add(pMem, pH0w8_3), mulmod(mload(add(pMem, pH0w8_0)), w8_3, q)) - mstore(add(pMem, pH0w8_4), mulmod(mload(add(pMem, pH0w8_0)), w8_4, q)) - mstore(add(pMem, pH0w8_5), mulmod(mload(add(pMem, pH0w8_0)), w8_5, q)) - mstore(add(pMem, pH0w8_6), mulmod(mload(add(pMem, pH0w8_0)), w8_6, q)) - mstore(add(pMem, pH0w8_7), mulmod(mload(add(pMem, pH0w8_0)), w8_7, q)) + mstore( + add(pMem, pH0w8_0), + mulmod( + mload(add(pMem, pXiSeed2)), + mload(add(pMem, pXiSeed)), + q + ) + ) + mstore( + add(pMem, pH0w8_1), + mulmod(mload(add(pMem, pH0w8_0)), w8_1, q) + ) + mstore( + add(pMem, pH0w8_2), + mulmod(mload(add(pMem, pH0w8_0)), w8_2, q) + ) + mstore( + add(pMem, pH0w8_3), + mulmod(mload(add(pMem, pH0w8_0)), w8_3, q) + ) + mstore( + add(pMem, pH0w8_4), + mulmod(mload(add(pMem, pH0w8_0)), w8_4, q) + ) + mstore( + add(pMem, pH0w8_5), + mulmod(mload(add(pMem, pH0w8_0)), w8_5, q) + ) + mstore( + add(pMem, pH0w8_6), + mulmod(mload(add(pMem, pH0w8_0)), w8_6, q) + ) + mstore( + add(pMem, pH0w8_7), + mulmod(mload(add(pMem, pH0w8_0)), w8_7, q) + ) // Compute roots.S1.h1w4 - mstore(add(pMem, pH1w4_0), mulmod(mload(add(pMem, pH0w8_0)), mload(add(pMem, pH0w8_0)), q)) - mstore(add(pMem, pH1w4_1), mulmod(mload(add(pMem, pH1w4_0)), w4, q)) - mstore(add(pMem, pH1w4_2), mulmod(mload(add(pMem, pH1w4_0)), w4_2, q)) - mstore(add(pMem, pH1w4_3), mulmod(mload(add(pMem, pH1w4_0)), w4_3, q)) + mstore( + add(pMem, pH1w4_0), + mulmod( + mload(add(pMem, pH0w8_0)), + mload(add(pMem, pH0w8_0)), + q + ) + ) + mstore( + add(pMem, pH1w4_1), + mulmod(mload(add(pMem, pH1w4_0)), w4, q) + ) + mstore( + add(pMem, pH1w4_2), + mulmod(mload(add(pMem, pH1w4_0)), w4_2, q) + ) + mstore( + add(pMem, pH1w4_3), + mulmod(mload(add(pMem, pH1w4_0)), w4_3, q) + ) // Compute roots.S2.h2w3 - mstore(add(pMem, pH2w3_0), mulmod(mload(add(pMem, pH1w4_0)), mload(add(pMem, pXiSeed2)), q)) - mstore(add(pMem, pH2w3_1), mulmod(mload(add(pMem, pH2w3_0)), w3, q)) - mstore(add(pMem, pH2w3_2), mulmod(mload(add(pMem, pH2w3_0)), w3_2, q)) + mstore( + add(pMem, pH2w3_0), + mulmod( + mload(add(pMem, pH1w4_0)), + mload(add(pMem, pXiSeed2)), + q + ) + ) + mstore( + add(pMem, pH2w3_1), + mulmod(mload(add(pMem, pH2w3_0)), w3, q) + ) + mstore( + add(pMem, pH2w3_2), + mulmod(mload(add(pMem, pH2w3_0)), w3_2, q) + ) // Compute roots.S2.h2w3 - mstore(add(pMem, pH3w3_0), mulmod(mload(add(pMem, pH2w3_0)), wr, q)) - mstore(add(pMem, pH3w3_1), mulmod(mload(add(pMem, pH3w3_0)), w3, q)) - mstore(add(pMem, pH3w3_2), mulmod(mload(add(pMem, pH3w3_0)), w3_2, q)) - - let xin := mulmod(mulmod(mload(add(pMem, pH2w3_0)), mload(add(pMem, pH2w3_0)), q), mload(add(pMem, pH2w3_0)), q) + mstore( + add(pMem, pH3w3_0), + mulmod(mload(add(pMem, pH2w3_0)), wr, q) + ) + mstore( + add(pMem, pH3w3_1), + mulmod(mload(add(pMem, pH3w3_0)), w3, q) + ) + mstore( + add(pMem, pH3w3_2), + mulmod(mload(add(pMem, pH3w3_0)), w3_2, q) + ) + + let xin := mulmod( + mulmod( + mload(add(pMem, pH2w3_0)), + mload(add(pMem, pH2w3_0)), + q + ), + mload(add(pMem, pH2w3_0)), + q + ) mstore(add(pMem, pXi), xin) // Compute xi^n - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - xin:= mulmod(xin, xin, q) - - - xin:= mod(add(sub(xin, 1), q), q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mod(add(sub(xin, 1), q), q) mstore(add(pMem, pZh), xin) - mstore(add(pMem, pZhInv), xin) // We will invert later together with lagrange pols + mstore(add(pMem, pZhInv), xin) // We will invert later together with lagrange pols // Compute challenge.alpha mstore(add(pMem, lastMem), xiSeed) calldatacopy(add(pMem, 1952), pEval_ql, 480) - mstore(add(pMem, pAlpha), mod(keccak256(add(pMem, lastMem), 512), q)) + mstore( + add(pMem, pAlpha), + mod(keccak256(add(pMem, lastMem), 512), q) + ) // Compute challenge.y mstore(add(pMem, lastMem), mload(add(pMem, pAlpha))) - mstore(add(pMem, 1952 ), calldataload(pW1)) - mstore(add(pMem, 1984 ), calldataload(add(pW1, 32))) + mstore(add(pMem, 1952), calldataload(pW1)) + mstore(add(pMem, 1984), calldataload(add(pW1, 32))) mstore(add(pMem, pY), mod(keccak256(add(pMem, lastMem), 96), q)) } @@ -534,49 +639,120 @@ contract FflonkVerifier { den1 := mulmod(den1, root0, q) den1 := mulmod(den1, root0, q) den1 := mulmod(den1, root0, q) - - den1 := mulmod(8, den1, q) - - let den2 := mload(add(pMem, add(pH0w8_0, mul(mod(mul(7, 0), 8), 32)))) - let den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(0, 32))))), q), q) - - mstore(add(pMem, add(pLiS0Inv, 0)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH0w8_0, mul(mod(mul(7, 1), 8), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(1, 32))))), q), q) - - mstore(add(pMem, add(pLiS0Inv, 32)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH0w8_0, mul(mod(mul(7, 2), 8), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(2, 32))))), q), q) - - mstore(add(pMem, add(pLiS0Inv, 64)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH0w8_0, mul(mod(mul(7, 3), 8), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(3, 32))))), q), q) - - mstore(add(pMem, add(pLiS0Inv, 96)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH0w8_0, mul(mod(mul(7, 4), 8), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(4, 32))))), q), q) - - mstore(add(pMem, add(pLiS0Inv, 128)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH0w8_0, mul(mod(mul(7, 5), 8), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(5, 32))))), q), q) - - mstore(add(pMem, add(pLiS0Inv, 160)), mulmod(den1, mulmod(den2, den3, q), q)) - den2 := mload(add(pMem, add(pH0w8_0, mul(mod(mul(7, 6), 8), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(6, 32))))), q), q) - - mstore(add(pMem, add(pLiS0Inv, 192)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH0w8_0, mul(mod(mul(7, 7), 8), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(7, 32))))), q), q) + den1 := mulmod(8, den1, q) - mstore(add(pMem, add(pLiS0Inv, 224)), mulmod(den1, mulmod(den2, den3, q), q)) - + let den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 0), 8), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 1), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 2), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 3), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(3, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 4), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(4, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 128)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 5), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(5, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 160)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 6), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(6, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 192)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 7), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(7, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 224)), + mulmod(den1, mulmod(den2, den3, q), q) + ) } function computeLiS1(pMem) { @@ -585,67 +761,172 @@ contract FflonkVerifier { let den1 := 1 den1 := mulmod(den1, root0, q) den1 := mulmod(den1, root0, q) - - den1 := mulmod(4, den1, q) - - let den2 := mload(add(pMem, add(pH1w4_0, mul(mod(mul(3, 0), 4), 32)))) - let den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(0, 32))))), q), q) - - mstore(add(pMem, add(pLiS1Inv, 0)), mulmod(den1, mulmod(den2, den3, q), q)) - den2 := mload(add(pMem, add(pH1w4_0, mul(mod(mul(3, 1), 4), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(1, 32))))), q), q) - - mstore(add(pMem, add(pLiS1Inv, 32)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH1w4_0, mul(mod(mul(3, 2), 4), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(2, 32))))), q), q) - - mstore(add(pMem, add(pLiS1Inv, 64)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH1w4_0, mul(mod(mul(3, 3), 4), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(3, 32))))), q), q) + den1 := mulmod(4, den1, q) - mstore(add(pMem, add(pLiS1Inv, 96)), mulmod(den1, mulmod(den2, den3, q), q)) + let den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 0), 4), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 1), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 2), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 3), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(3, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) } function computeLiS2(pMem) { - let y := mload(add(pMem, pY)) - let den1 := mulmod(mulmod(3,mload(add(pMem, pH2w3_0)),q), addmod(mload(add(pMem, pXi)) ,mod(sub(q, mulmod(mload(add(pMem, pXi)), w1 ,q)), q), q), q) - - let den2 := mload(add(pMem, add(pH2w3_0, mul(mod(mul(2, 0), 3), 32)))) - let den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(0, 32))))), q), q) - - mstore(add(pMem, add(pLiS2Inv, 0)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH2w3_0, mul(mod(mul(2, 1), 3), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(1, 32))))), q), q) - - mstore(add(pMem, add(pLiS2Inv, 32)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH2w3_0, mul(mod(mul(2, 2), 3), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(2, 32))))), q), q) - - mstore(add(pMem, add(pLiS2Inv, 64)), mulmod(den1, mulmod(den2, den3, q), q)) - - den1 := mulmod(mulmod(3,mload(add(pMem, pH3w3_0)),q), addmod(mulmod(mload(add(pMem, pXi)), w1 ,q),mod(sub(q, mload(add(pMem, pXi))), q), q), q) - - den2 := mload(add(pMem, add(pH3w3_0, mul(mod(mul(2, 0), 3), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(0, 32))))), q), q) - - mstore(add(pMem, add(pLiS2Inv, 96)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH3w3_0, mul(mod(mul(2, 1), 3), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(1, 32))))), q), q) - - mstore(add(pMem, add(pLiS2Inv, 128)), mulmod(den1, mulmod(den2, den3, q), q)) - - den2 := mload(add(pMem, add(pH3w3_0, mul(mod(mul(2, 2), 3), 32)))) - den3 := addmod(y, mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(2, 32))))), q), q) - - mstore(add(pMem, add(pLiS2Inv, 160)), mulmod(den1, mulmod(den2, den3, q), q)) + let den1 := mulmod( + mulmod(3, mload(add(pMem, pH2w3_0)), q), + addmod( + mload(add(pMem, pXi)), + mod(sub(q, mulmod(mload(add(pMem, pXi)), w1, q)), q), + q + ), + q + ) + + let den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 0), 3), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 1), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 2), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den1 := mulmod( + mulmod(3, mload(add(pMem, pH3w3_0)), q), + addmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mod(sub(q, mload(add(pMem, pXi))), q), + q + ), + q + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 0), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 1), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 128)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 2), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 160)), + mulmod(den1, mulmod(den2, den3, q), q) + ) } // Prepare all the denominators that must be inverted, placed them in consecutive memory addresses @@ -657,23 +938,55 @@ contract FflonkVerifier { // used in steps 10 and 11 of the verifier let y := mload(add(pMem, pY)) let w := addmod(y, mod(sub(q, mload(add(pMem, pH1w4_0))), q), q) - w := mulmod(w, addmod(y, mod(sub(q, mload(add(pMem, pH1w4_1))), q), q), q) - w := mulmod(w, addmod(y, mod(sub(q, mload(add(pMem, pH1w4_2))), q), q), q) - w := mulmod(w, addmod(y, mod(sub(q, mload(add(pMem, pH1w4_3))), q), q), q) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_2))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_3))), q), q), + q + ) mstore(add(pMem, pDenH1), w) // 1/((y - h2) (y - h2w3) (y - h2w3_2) (y - h3) (y - h3w3) (y - h3w3_2)) w := addmod(y, mod(sub(q, mload(add(pMem, pH2w3_0))), q), q) - w := mulmod(w, addmod(y, mod(sub(q, mload(add(pMem, pH2w3_1))), q), q), q) - w := mulmod(w, addmod(y, mod(sub(q, mload(add(pMem, pH2w3_2))), q), q), q) - w := mulmod(w, addmod(y, mod(sub(q, mload(add(pMem, pH3w3_0))), q), q), q) - w := mulmod(w, addmod(y, mod(sub(q, mload(add(pMem, pH3w3_1))), q), q), q) - w := mulmod(w, addmod(y, mod(sub(q, mload(add(pMem, pH3w3_2))), q), q), q) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH2w3_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH2w3_2))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_0))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_2))), q), q), + q + ) mstore(add(pMem, pDenH2), w) // Denominator needed in the verifier when computing L_i^{S0}(X) computeLiS0(pMem) - + // Denominator needed in the verifier when computing L_i^{S1}(X) computeLiS1(pMem) @@ -683,27 +996,45 @@ contract FflonkVerifier { // L_i where i from 1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) w := 1 let xi := mload(add(pMem, pXi)) - - mstore(add(pMem, pEval_l1), mulmod(n, mod(add(sub(xi, w), q), q), q)) - + + mstore( + add(pMem, pEval_l1), + mulmod(n, mod(add(sub(xi, w), q), q), q) + ) // Execute Montgomery batched inversions of the previous prepared values - inverseArray(pMem) } + inverseArray(pMem) + } // Compute Lagrange polynomial evaluation L_i(xi) function computeLagrange(pMem) { let zh := mload(add(pMem, pZh)) let w := 1 - - mstore(add(pMem, pEval_l1 ), mulmod(mload(add(pMem, pEval_l1 )), zh, q)) - + + mstore( + add(pMem, pEval_l1), + mulmod(mload(add(pMem, pEval_l1)), zh, q) + ) } // Compute public input polynomial evaluation PI(xi) function computePi(pMem, pPub) { let pi := 0 - pi := mod(add(sub(pi, mulmod(mload(add(pMem, pEval_l1)), calldataload(pPub), q)), q), q) - + pi := mod( + add( + sub( + pi, + mulmod( + mload(add(pMem, pEval_l1)), + calldataload(pPub), + q + ) + ), + q + ), + q + ) + mstore(add(pMem, pPi), pi) } @@ -729,166 +1060,446 @@ contract FflonkVerifier { let h0w80 let c0Value let h0w8i - + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 h0w80 := mload(add(pMem, pH0w8_0)) - c0Value := addmod(calldataload(pEval_ql), mulmod(calldataload(pEval_qr), h0w80, q), q) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) h0w8i := mulmod(h0w80, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qo), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qm), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qc), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s1), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s2), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s3), h0w8i, q), q) - - res := addmod(res, mulmod(c0Value, mulmod(num, mload(add(pMem, add(pLiS0Inv, 0))), q), q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 0))), q), + q + ), + q + ) - // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 h0w80 := mload(add(pMem, pH0w8_1)) - c0Value := addmod(calldataload(pEval_ql), mulmod(calldataload(pEval_qr), h0w80, q), q) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) h0w8i := mulmod(h0w80, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qo), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qm), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qc), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s1), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s2), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s3), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 32))), q), + q + ), + q + ) - res := addmod(res, mulmod(c0Value, mulmod(num, mload(add(pMem, add(pLiS0Inv, 32))), q), q), q) - - // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 h0w80 := mload(add(pMem, pH0w8_2)) - c0Value := addmod(calldataload(pEval_ql), mulmod(calldataload(pEval_qr), h0w80, q), q) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) h0w8i := mulmod(h0w80, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qo), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qm), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qc), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s1), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s2), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s3), h0w8i, q), q) - - res := addmod(res, mulmod(c0Value, mulmod(num, mload(add(pMem, add(pLiS0Inv, 64))), q), q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 64))), q), + q + ), + q + ) - // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 h0w80 := mload(add(pMem, pH0w8_3)) - c0Value := addmod(calldataload(pEval_ql), mulmod(calldataload(pEval_qr), h0w80, q), q) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) h0w8i := mulmod(h0w80, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qo), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qm), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qc), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s1), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s2), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s3), h0w8i, q), q) - - res := addmod(res, mulmod(c0Value, mulmod(num, mload(add(pMem, add(pLiS0Inv, 96))), q), q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 96))), q), + q + ), + q + ) - // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 h0w80 := mload(add(pMem, pH0w8_4)) - c0Value := addmod(calldataload(pEval_ql), mulmod(calldataload(pEval_qr), h0w80, q), q) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) h0w8i := mulmod(h0w80, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qo), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qm), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qc), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s1), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s2), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s3), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 128))), q), + q + ), + q + ) - res := addmod(res, mulmod(c0Value, mulmod(num, mload(add(pMem, add(pLiS0Inv, 128))), q), q), q) - - // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 h0w80 := mload(add(pMem, pH0w8_5)) - c0Value := addmod(calldataload(pEval_ql), mulmod(calldataload(pEval_qr), h0w80, q), q) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) h0w8i := mulmod(h0w80, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qo), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qm), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qc), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s1), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s2), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s3), h0w8i, q), q) - - res := addmod(res, mulmod(c0Value, mulmod(num, mload(add(pMem, add(pLiS0Inv, 160))), q), q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 160))), q), + q + ), + q + ) - // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 h0w80 := mload(add(pMem, pH0w8_6)) - c0Value := addmod(calldataload(pEval_ql), mulmod(calldataload(pEval_qr), h0w80, q), q) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) h0w8i := mulmod(h0w80, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qo), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qm), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qc), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s1), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s2), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s3), h0w8i, q), q) - - res := addmod(res, mulmod(c0Value, mulmod(num, mload(add(pMem, add(pLiS0Inv, 192))), q), q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 192))), q), + q + ), + q + ) - // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 h0w80 := mload(add(pMem, pH0w8_7)) - c0Value := addmod(calldataload(pEval_ql), mulmod(calldataload(pEval_qr), h0w80, q), q) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) h0w8i := mulmod(h0w80, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qo), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qm), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_qc), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s1), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s2), h0w8i, q), q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) h0w8i := mulmod(h0w8i, h0w80, q) - c0Value := addmod(c0Value, mulmod(calldataload(pEval_s3), h0w8i, q), q) - - res := addmod(res, mulmod(c0Value, mulmod(num, mload(add(pMem, add(pLiS0Inv, 224))), q), q), q) - + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 224))), q), + q + ), + q + ) mstore(add(pMem, pR0), res) } @@ -913,10 +1524,14 @@ contract FflonkVerifier { let evalC := calldataload(pEval_c) t0 := mulmod(calldataload(pEval_ql), evalA, q) - t0 := addmod(t0, mulmod(calldataload(pEval_qr), evalB, q) ,q) - t0 := addmod(t0, mulmod(calldataload(pEval_qm), mulmod(evalA, evalB, q), q) ,q) - t0 := addmod(t0, mulmod(calldataload(pEval_qo), evalC, q) ,q) - t0 := addmod(t0, calldataload(pEval_qc) ,q) + t0 := addmod(t0, mulmod(calldataload(pEval_qr), evalB, q), q) + t0 := addmod( + t0, + mulmod(calldataload(pEval_qm), mulmod(evalA, evalB, q), q), + q + ) + t0 := addmod(t0, mulmod(calldataload(pEval_qo), evalC, q), q) + t0 := addmod(t0, calldataload(pEval_qc), q) t0 := addmod(t0, mload(add(pMem, pPi)), q) t0 := mulmod(t0, mload(add(pMem, pZhInv)), q) @@ -930,9 +1545,25 @@ contract FflonkVerifier { c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) square := mulmod(h1w4, h1w4, q) c1Value := addmod(c1Value, mulmod(square, evalC, q), q) - c1Value := addmod(c1Value, mulmod(mulmod(square, h1w4, q), t0, q), q) - - res := addmod(res, mulmod(c1Value, mulmod(num, mload(add(pMem, add(pLiS1Inv, mul(0, 32)))), q), q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(0, 32)))), + q + ), + q + ), + q + ) c1Value := evalA h1w4 := mload(add(pMem, pH1w4_1)) @@ -940,9 +1571,25 @@ contract FflonkVerifier { c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) square := mulmod(h1w4, h1w4, q) c1Value := addmod(c1Value, mulmod(square, evalC, q), q) - c1Value := addmod(c1Value, mulmod(mulmod(square, h1w4, q), t0, q), q) - - res := addmod(res, mulmod(c1Value, mulmod(num, mload(add(pMem, add(pLiS1Inv, mul(1, 32)))), q), q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(1, 32)))), + q + ), + q + ), + q + ) c1Value := evalA h1w4 := mload(add(pMem, pH1w4_2)) @@ -950,9 +1597,25 @@ contract FflonkVerifier { c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) square := mulmod(h1w4, h1w4, q) c1Value := addmod(c1Value, mulmod(square, evalC, q), q) - c1Value := addmod(c1Value, mulmod(mulmod(square, h1w4, q), t0, q), q) - - res := addmod(res, mulmod(c1Value, mulmod(num, mload(add(pMem, add(pLiS1Inv, mul(2, 32)))), q), q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(2, 32)))), + q + ), + q + ), + q + ) c1Value := evalA h1w4 := mload(add(pMem, pH1w4_3)) @@ -960,10 +1623,25 @@ contract FflonkVerifier { c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) square := mulmod(h1w4, h1w4, q) c1Value := addmod(c1Value, mulmod(square, evalC, q), q) - c1Value := addmod(c1Value, mulmod(mulmod(square, h1w4, q), t0, q), q) - - res := addmod(res, mulmod(c1Value, mulmod(num, mload(add(pMem, add(pLiS1Inv, mul(3, 32)))), q), q), q) - + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(3, 32)))), + q + ), + q + ), + q + ) mstore(add(pMem, pR1), res) } @@ -986,79 +1664,245 @@ contract FflonkVerifier { num2 := mulmod(y, num2, q) num2 := mulmod(y, num2, q) num2 := mulmod(y, num2, q) - num2 := mulmod(num2, addmod(mulmod(mload(add(pMem, pXi)), w1 ,q), mload(add(pMem, pXi)), q), q) + num2 := mulmod( + num2, + addmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mload(add(pMem, pXi)), + q + ), + q + ) num := addmod(num, mod(sub(q, num2), q), q) - num2 := mulmod(mulmod(mload(add(pMem, pXi)), w1 ,q), mload(add(pMem, pXi)), q) + num2 := mulmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mload(add(pMem, pXi)), + q + ) num := addmod(num, num2, q) let t1 let t2 - let betaXi := mulmod(mload(add(pMem, pBeta)), mload(add(pMem, pXi)), q) + let betaXi := mulmod( + mload(add(pMem, pBeta)), + mload(add(pMem, pXi)), + q + ) let gamma := mload(add(pMem, pGamma)) - t2 := addmod(calldataload( pEval_a), addmod(betaXi, gamma, q) ,q) - t2 := mulmod(t2, - addmod(calldataload( pEval_b), - addmod(mulmod(betaXi, k1, q), gamma, q) ,q), q) - t2 := mulmod(t2, - addmod(calldataload( pEval_c), - addmod(mulmod(betaXi, k2, q), gamma, q) ,q), q) + t2 := addmod(calldataload(pEval_a), addmod(betaXi, gamma, q), q) + t2 := mulmod( + t2, + addmod( + calldataload(pEval_b), + addmod(mulmod(betaXi, k1, q), gamma, q), + q + ), + q + ) + t2 := mulmod( + t2, + addmod( + calldataload(pEval_c), + addmod(mulmod(betaXi, k2, q), gamma, q), + q + ), + q + ) t2 := mulmod(t2, calldataload(pEval_z), q) //Let's use t1 as a temporal variable to save one local - t1 := addmod(calldataload(pEval_a), addmod(mulmod(mload(add(pMem, pBeta)), calldataload(pEval_s1), q), gamma, q) ,q) - t1 := mulmod(t1, - addmod(calldataload(pEval_b), addmod(mulmod(mload(add(pMem, pBeta)), calldataload(pEval_s2), q), gamma, q) ,q), q) - t1 := mulmod(t1, - addmod(calldataload(pEval_c), addmod(mulmod(mload(add(pMem, pBeta)), calldataload(pEval_s3), q), gamma, q) ,q), q) + t1 := addmod( + calldataload(pEval_a), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s1), + q + ), + gamma, + q + ), + q + ) + t1 := mulmod( + t1, + addmod( + calldataload(pEval_b), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s2), + q + ), + gamma, + q + ), + q + ), + q + ) + t1 := mulmod( + t1, + addmod( + calldataload(pEval_c), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s3), + q + ), + gamma, + q + ), + q + ), + q + ) t1 := mulmod(t1, calldataload(pEval_zw), q) - t2:= addmod(t2, mod(sub(q, t1), q), q) + t2 := addmod(t2, mod(sub(q, t1), q), q) t2 := mulmod(t2, mload(add(pMem, pZhInv)), q) // Compute T1(xi) t1 := sub(calldataload(pEval_z), 1) - t1 := mulmod(t1, mload(add(pMem, pEval_l1)) ,q) - t1 := mulmod(t1, mload(add(pMem, pZhInv)) ,q) + t1 := mulmod(t1, mload(add(pMem, pEval_l1)), q) + t1 := mulmod(t1, mload(add(pMem, pZhInv)), q) // Let's use local variable gamma to save the result - gamma:=0 - + gamma := 0 + let hw - let c2Value + let c2Value hw := mload(add(pMem, pH2w3_0)) c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) - gamma := addmod(gamma, mulmod(c2Value, mulmod(num, mload(add(pMem, add(pLiS2Inv, mul(0, 32)))), q), q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(0, 32)))), + q + ), + q + ), + q + ) hw := mload(add(pMem, pH2w3_1)) c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) - gamma := addmod(gamma, mulmod(c2Value, mulmod(num, mload(add(pMem, add(pLiS2Inv, mul(1, 32)))), q), q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(1, 32)))), + q + ), + q + ), + q + ) hw := mload(add(pMem, pH2w3_2)) c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) - gamma := addmod(gamma, mulmod(c2Value, mulmod(num, mload(add(pMem, add(pLiS2Inv, mul(2, 32)))), q), q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(2, 32)))), + q + ), + q + ), + q + ) hw := mload(add(pMem, pH3w3_0)) - c2Value := addmod(calldataload(pEval_zw), mulmod(hw, calldataload(pEval_t1w), q), q) - c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), q) - gamma := addmod(gamma, mulmod(c2Value, mulmod(num, mload(add(pMem, add(pLiS2Inv, mul(3, 32)))), q), q), q) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(3, 32)))), + q + ), + q + ), + q + ) hw := mload(add(pMem, pH3w3_1)) - c2Value := addmod(calldataload(pEval_zw), mulmod(hw, calldataload(pEval_t1w), q), q) - c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), q) - gamma := addmod(gamma, mulmod(c2Value, mulmod(num, mload(add(pMem, add(pLiS2Inv, mul(4, 32)))), q), q), q) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(4, 32)))), + q + ), + q + ), + q + ) hw := mload(add(pMem, pH3w3_2)) - c2Value := addmod(calldataload(pEval_zw), mulmod(hw, calldataload(pEval_t1w), q), q) - c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), q) - gamma := addmod(gamma, mulmod(c2Value, mulmod(num, mload(add(pMem, add(pLiS2Inv, mul(5, 32)))), q), q), q) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(5, 32)))), + q + ), + q + ), + q + ) mstore(add(pMem, pR2), gamma) } @@ -1134,18 +1978,62 @@ contract FflonkVerifier { function computeFEJ(pMem) { // Prepare shared numerator between F, E and J to reuse it let y := mload(add(pMem, pY)) - let numerator := addmod(y, mod(sub(q, mload(add(pMem, pH0w8_0))), q), q) - numerator := mulmod(numerator, addmod(y, mod(sub(q, mload(add(pMem, pH0w8_1))), q), q), q) - numerator := mulmod(numerator, addmod(y, mod(sub(q, mload(add(pMem, pH0w8_2))), q), q), q) - numerator := mulmod(numerator, addmod(y, mod(sub(q, mload(add(pMem, pH0w8_3))), q), q), q) - numerator := mulmod(numerator, addmod(y, mod(sub(q, mload(add(pMem, pH0w8_4))), q), q), q) - numerator := mulmod(numerator, addmod(y, mod(sub(q, mload(add(pMem, pH0w8_5))), q), q), q) - numerator := mulmod(numerator, addmod(y, mod(sub(q, mload(add(pMem, pH0w8_6))), q), q), q) - numerator := mulmod(numerator, addmod(y, mod(sub(q, mload(add(pMem, pH0w8_7))), q), q), q) + let numerator := addmod( + y, + mod(sub(q, mload(add(pMem, pH0w8_0))), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_1))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_2))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_3))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_4))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_5))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_6))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_7))), q), q), + q + ) // Prepare shared quotient between F and E to reuse it - let quotient1 := mulmod(mload(add(pMem, pAlpha)), mulmod(numerator, mload(add(pMem, pDenH1)), q), q) - let quotient2 := mulmod(mulmod(mload(add(pMem, pAlpha)), mload(add(pMem, pAlpha)), q), mulmod(numerator, mload(add(pMem, pDenH2)), q), q) + let quotient1 := mulmod( + mload(add(pMem, pAlpha)), + mulmod(numerator, mload(add(pMem, pDenH1)), q), + q + ) + let quotient2 := mulmod( + mulmod( + mload(add(pMem, pAlpha)), + mload(add(pMem, pAlpha)), + q + ), + mulmod(numerator, mload(add(pMem, pDenH2)), q), + q + ) // Compute full batched polynomial commitment [F]_1 mstore(add(pMem, pF), C0x) @@ -1154,7 +2042,20 @@ contract FflonkVerifier { g1_mulAcc(add(pMem, pF), pC2, quotient2) // Compute group-encoded batch evaluation [E]_1 - g1_mulAccC(add(pMem, pE), G1x, G1y, addmod(mload(add(pMem, pR0)), addmod(mulmod(quotient1, mload(add(pMem, pR1)),q), mulmod(quotient2, mload(add(pMem, pR2)),q), q), q)) + g1_mulAccC( + add(pMem, pE), + G1x, + G1y, + addmod( + mload(add(pMem, pR0)), + addmod( + mulmod(quotient1, mload(add(pMem, pR1)), q), + mulmod(quotient2, mload(add(pMem, pR2)), q), + q + ), + q + ) + ) // Compute the full difference [J]_1 g1_mulAcc(add(pMem, pJ), pW1, numerator) @@ -1166,9 +2067,15 @@ contract FflonkVerifier { // First pairing value // Compute -E - mstore(add(add(pMem, pE), 32), mod(sub(qf, mload(add(add(pMem, pE), 32))), qf)) + mstore( + add(add(pMem, pE), 32), + mod(sub(qf, mload(add(add(pMem, pE), 32))), qf) + ) // Compute -J - mstore(add(add(pMem, pJ), 32), mod(sub(qf, mload(add(add(pMem, pJ), 32))), qf)) + mstore( + add(add(pMem, pJ), 32), + mod(sub(qf, mload(add(add(pMem, pJ), 32))), qf) + ) // F = F - E - J + y·W2 g1_acc(add(pMem, pF), add(pMem, pE)) g1_acc(add(pMem, pF), add(pMem, pJ)) @@ -1196,7 +2103,14 @@ contract FflonkVerifier { mstore(add(mIn, 320), X2y2) mstore(add(mIn, 352), X2y1) - let success := staticcall(sub(gas(), 2000), 8, mIn, 384, mIn, 0x20) + let success := staticcall( + sub(gas(), 2000), + 8, + mIn, + 384, + mIn, + 0x20 + ) isOk := and(success, mload(mIn)) } diff --git a/contracts/verifiers/FflonkVerifier_12.sol b/contracts/verifiers/FflonkVerifier_12.sol new file mode 100644 index 000000000..a167dff23 --- /dev/null +++ b/contracts/verifiers/FflonkVerifier_12.sol @@ -0,0 +1,2158 @@ +// SPDX-License-Identifier: GPL-3.0 +/* + Copyright 2021 0KIMS association. + + This file is generated with [snarkJS](https://github.com/iden3/snarkjs). + + snarkJS is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + snarkJS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with snarkJS. If not, see . +*/ + +pragma solidity >=0.7.0 <0.9.0; + +contract FflonkVerifier_12 { + uint32 constant n = 16777216; // Domain size + + // Verification Key data + uint256 constant k1 = 2; // Plonk k1 multiplicative factor to force distinct cosets of H + uint256 constant k2 = 3; // Plonk k2 multiplicative factor to force distinct cosets of H + + // OMEGAS + // Omega, Omega^{1/3} + uint256 constant w1 = + 5709868443893258075976348696661355716898495876243883251619397131511003808859; + uint256 constant wr = + 18200100796661656210024324131237448517259556535315737226009542456080026430510; + // Omega_3, Omega_3^2 + uint256 constant w3 = + 21888242871839275217838484774961031246154997185409878258781734729429964517155; + uint256 constant w3_2 = + 4407920970296243842393367215006156084916469457145843978461; + // Omega_4, Omega_4^2, Omega_4^3 + uint256 constant w4 = + 21888242871839275217838484774961031246007050428528088939761107053157389710902; + uint256 constant w4_2 = + 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 constant w4_3 = + 4407920970296243842541313971887945403937097133418418784715; + // Omega_8, Omega_8^2, Omega_8^3, Omega_8^4, Omega_8^5, Omega_8^6, Omega_8^7 + uint256 constant w8_1 = + 19540430494807482326159819597004422086093766032135589407132600596362845576832; + uint256 constant w8_2 = + 21888242871839275217838484774961031246007050428528088939761107053157389710902; + uint256 constant w8_3 = + 13274704216607947843011480449124596415239537050559949017414504948711435969894; + uint256 constant w8_4 = + 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 constant w8_5 = + 2347812377031792896086586148252853002454598368280444936565603590212962918785; + uint256 constant w8_6 = + 4407920970296243842541313971887945403937097133418418784715; + uint256 constant w8_7 = + 8613538655231327379234925296132678673308827349856085326283699237864372525723; + + // Verifier preprocessed input C_0(x)·[1]_1 + uint256 constant C0x = + 14108481345212921148996352149587402371241828412155926312706521103747833870705; + uint256 constant C0y = + 5431364720504262011685673568202437040741271312846880378221091213893853645141; + + // Verifier preprocessed input x·[1]_2 + uint256 constant X2x1 = + 21831381940315734285607113342023901060522397560371972897001948545212302161822; + uint256 constant X2x2 = + 17231025384763736816414546592865244497437017442647097510447326538965263639101; + uint256 constant X2y1 = + 2388026358213174446665280700919698872609886601280537296205114254867301080648; + uint256 constant X2y2 = + 11507326595632554467052522095592665270651932854513688777769618397986436103170; + + // Scalar field size + uint256 constant q = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + // Base field size + uint256 constant qf = + 21888242871839275222246405745257275088696311157297823662689037894645226208583; + // [1]_1 + uint256 constant G1x = 1; + uint256 constant G1y = 2; + // [1]_2 + uint256 constant G2x1 = + 10857046999023057135944570762232829481370756359578518086990519993285655852781; + uint256 constant G2x2 = + 11559732032986387107991004021392285783925812861821192530917403151452391805634; + uint256 constant G2y1 = + 8495653923123431417604973247489272438418190587263600148770280649306958101930; + uint256 constant G2y2 = + 4082367875863433681332203403145435568316851327593401208105741076214120093531; + + // Proof calldata + // Byte offset of every parameter of the calldata + // Polynomial commitments + uint16 constant pC1 = 4 + 0; // [C1]_1 + uint16 constant pC2 = 4 + 32 * 2; // [C2]_1 + uint16 constant pW1 = 4 + 32 * 4; // [W]_1 + uint16 constant pW2 = 4 + 32 * 6; // [W']_1 + // Opening evaluations + uint16 constant pEval_ql = 4 + 32 * 8; // q_L(xi) + uint16 constant pEval_qr = 4 + 32 * 9; // q_R(xi) + uint16 constant pEval_qm = 4 + 32 * 10; // q_M(xi) + uint16 constant pEval_qo = 4 + 32 * 11; // q_O(xi) + uint16 constant pEval_qc = 4 + 32 * 12; // q_C(xi) + uint16 constant pEval_s1 = 4 + 32 * 13; // S_{sigma_1}(xi) + uint16 constant pEval_s2 = 4 + 32 * 14; // S_{sigma_2}(xi) + uint16 constant pEval_s3 = 4 + 32 * 15; // S_{sigma_3}(xi) + uint16 constant pEval_a = 4 + 32 * 16; // a(xi) + uint16 constant pEval_b = 4 + 32 * 17; // b(xi) + uint16 constant pEval_c = 4 + 32 * 18; // c(xi) + uint16 constant pEval_z = 4 + 32 * 19; // z(xi) + uint16 constant pEval_zw = 4 + 32 * 20; // z_omega(xi) + uint16 constant pEval_t1w = 4 + 32 * 21; // T_1(xi omega) + uint16 constant pEval_t2w = 4 + 32 * 22; // T_2(xi omega) + uint16 constant pEval_inv = 4 + 32 * 23; // inv(batch) sent by the prover to avoid any inverse calculation to save gas, + // we check the correctness of the inv(batch) by computing batch + // and checking inv(batch) * batch == 1 + + // Memory data + // Challenges + uint16 constant pAlpha = 0; // alpha challenge + uint16 constant pBeta = 32; // beta challenge + uint16 constant pGamma = 64; // gamma challenge + uint16 constant pY = 96; // y challenge + uint16 constant pXiSeed = 128; // xi seed, from this value we compute xi = xiSeed^24 + uint16 constant pXiSeed2 = 160; // (xi seed)^2 + uint16 constant pXi = 192; // xi challenge + + // Roots + // S_0 = roots_8(xi) = { h_0, h_0w_8, h_0w_8^2, h_0w_8^3, h_0w_8^4, h_0w_8^5, h_0w_8^6, h_0w_8^7 } + uint16 constant pH0w8_0 = 224; + uint16 constant pH0w8_1 = 256; + uint16 constant pH0w8_2 = 288; + uint16 constant pH0w8_3 = 320; + uint16 constant pH0w8_4 = 352; + uint16 constant pH0w8_5 = 384; + uint16 constant pH0w8_6 = 416; + uint16 constant pH0w8_7 = 448; + + // S_1 = roots_4(xi) = { h_1, h_1w_4, h_1w_4^2, h_1w_4^3 } + uint16 constant pH1w4_0 = 480; + uint16 constant pH1w4_1 = 512; + uint16 constant pH1w4_2 = 544; + uint16 constant pH1w4_3 = 576; + + // S_2 = roots_3(xi) U roots_3(xi omega) + // roots_3(xi) = { h_2, h_2w_3, h_2w_3^2 } + uint16 constant pH2w3_0 = 608; + uint16 constant pH2w3_1 = 640; + uint16 constant pH2w3_2 = 672; + // roots_3(xi omega) = { h_3, h_3w_3, h_3w_3^2 } + uint16 constant pH3w3_0 = 704; + uint16 constant pH3w3_1 = 736; + uint16 constant pH3w3_2 = 768; + + uint16 constant pPi = 800; // PI(xi) + uint16 constant pR0 = 832; // r0(y) + uint16 constant pR1 = 864; // r1(y) + uint16 constant pR2 = 896; // r2(y) + + uint16 constant pF = 928; // [F]_1, 64 bytes + uint16 constant pE = 992; // [E]_1, 64 bytes + uint16 constant pJ = 1056; // [J]_1, 64 bytes + + uint16 constant pZh = 1184; // Z_H(xi) + // From this point we write all the variables that must be computed using the Montgomery batch inversion + uint16 constant pZhInv = 1216; // 1/Z_H(xi) + uint16 constant pDenH1 = 1248; // 1/( (y-h_1w_4) (y-h_1w_4^2) (y-h_1w_4^3) (y-h_1w_4^4) ) + uint16 constant pDenH2 = 1280; // 1/( (y-h_2w_3) (y-h_2w_3^2) (y-h_2w_3^3) (y-h_3w_3) (y-h_3w_3^2) (y-h_3w_3^3) ) + uint16 constant pLiS0Inv = 1312; // Reserve 8 * 32 bytes to compute r_0(X) + uint16 constant pLiS1Inv = 1568; // Reserve 4 * 32 bytes to compute r_1(X) + uint16 constant pLiS2Inv = 1696; // Reserve 6 * 32 bytes to compute r_2(X) + // Lagrange evaluations + + uint16 constant pEval_l1 = 1888; + + uint16 constant lastMem = 1920; + + function verifyProof( + bytes32[24] calldata proof, + uint256[1] calldata pubSignals + ) public view returns (bool) { + assembly { + // Computes the inverse of an array of values + // See https://vitalik.ca/general/2018/07/21/starks_part_3.html in section where explain fields operations + // To save the inverse to be computed on chain the prover sends the inverse as an evaluation in commits.eval_inv + function inverseArray(pMem) { + let pAux := mload(0x40) // Point to the next free position + let acc := mload(add(pMem, pZhInv)) // Read the first element + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pDenH1)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pDenH2)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pLiS0Inv)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 32))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 64))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 96))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 128))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 160))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 192))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 224))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pLiS1Inv)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 32))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 64))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 96))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pLiS2Inv)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 32))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 64))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 96))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 128))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 160))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pEval_l1)), q) + mstore(pAux, acc) + + let inv := calldataload(pEval_inv) + + // Before using the inverse sent by the prover the verifier checks inv(batch) * batch === 1 + if iszero(eq(1, mulmod(acc, inv, q))) { + mstore(0, 0) + return(0, 0x20) + } + + acc := inv + + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pEval_l1)), q) + mstore(add(pMem, pEval_l1), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 160))), q) + mstore(add(pMem, add(pLiS2Inv, 160)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 128))), q) + mstore(add(pMem, add(pLiS2Inv, 128)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 96))), q) + mstore(add(pMem, add(pLiS2Inv, 96)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 64))), q) + mstore(add(pMem, add(pLiS2Inv, 64)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 32))), q) + mstore(add(pMem, add(pLiS2Inv, 32)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pLiS2Inv)), q) + mstore(add(pMem, pLiS2Inv), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 96))), q) + mstore(add(pMem, add(pLiS1Inv, 96)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 64))), q) + mstore(add(pMem, add(pLiS1Inv, 64)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 32))), q) + mstore(add(pMem, add(pLiS1Inv, 32)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pLiS1Inv)), q) + mstore(add(pMem, pLiS1Inv), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 224))), q) + mstore(add(pMem, add(pLiS0Inv, 224)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 192))), q) + mstore(add(pMem, add(pLiS0Inv, 192)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 160))), q) + mstore(add(pMem, add(pLiS0Inv, 160)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 128))), q) + mstore(add(pMem, add(pLiS0Inv, 128)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 96))), q) + mstore(add(pMem, add(pLiS0Inv, 96)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 64))), q) + mstore(add(pMem, add(pLiS0Inv, 64)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 32))), q) + mstore(add(pMem, add(pLiS0Inv, 32)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pLiS0Inv)), q) + mstore(add(pMem, pLiS0Inv), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pDenH2)), q) + mstore(add(pMem, pDenH2), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pDenH1)), q) + mstore(add(pMem, pDenH1), inv) + + mstore(add(pMem, pZhInv), acc) + } + + function checkField(v) { + if iszero(lt(v, q)) { + mstore(0, 0) + return(0, 0x20) + } + } + + function checkPointBelongsToBN128Curve(p) { + let x := calldataload(p) + let y := calldataload(add(p, 32)) + + // Check that the point is on the curve + // y^2 = x^3 + 3 + let x3_3 := addmod(mulmod(x, mulmod(x, x, qf), qf), 3, qf) + let y2 := mulmod(y, y, qf) + + if iszero(eq(x3_3, y2)) { + mstore(0, 0) + return(0, 0x20) + } + } + + // Validate all the evaluations sent by the prover ∈ F + function checkInput() { + // Check proof commitments fullfill bn128 curve equation Y^2 = X^3 + 3 + checkPointBelongsToBN128Curve(pC1) + checkPointBelongsToBN128Curve(pC2) + checkPointBelongsToBN128Curve(pW1) + checkPointBelongsToBN128Curve(pW2) + + checkField(calldataload(pEval_ql)) + checkField(calldataload(pEval_qr)) + checkField(calldataload(pEval_qm)) + checkField(calldataload(pEval_qo)) + checkField(calldataload(pEval_qc)) + checkField(calldataload(pEval_s1)) + checkField(calldataload(pEval_s2)) + checkField(calldataload(pEval_s3)) + checkField(calldataload(pEval_a)) + checkField(calldataload(pEval_b)) + checkField(calldataload(pEval_c)) + checkField(calldataload(pEval_z)) + checkField(calldataload(pEval_zw)) + checkField(calldataload(pEval_t1w)) + checkField(calldataload(pEval_t2w)) + checkField(calldataload(pEval_inv)) + + // Points are checked in the point operations precompiled smart contracts + } + + function computeChallenges(pMem, pPublic) { + // Compute challenge.beta & challenge.gamma + mstore(add(pMem, 1920), C0x) + mstore(add(pMem, 1952), C0y) + + mstore(add(pMem, 1984), calldataload(pPublic)) + + mstore(add(pMem, 2016), calldataload(pC1)) + mstore(add(pMem, 2048), calldataload(add(pC1, 32))) + + mstore( + add(pMem, pBeta), + mod(keccak256(add(pMem, lastMem), 160), q) + ) + mstore( + add(pMem, pGamma), + mod(keccak256(add(pMem, pBeta), 32), q) + ) + + // Get xiSeed & xiSeed2 + mstore(add(pMem, lastMem), mload(add(pMem, pGamma))) + mstore(add(pMem, 1952), calldataload(pC2)) + mstore(add(pMem, 1984), calldataload(add(pC2, 32))) + let xiSeed := mod(keccak256(add(pMem, lastMem), 96), q) + + mstore(add(pMem, pXiSeed), xiSeed) + mstore(add(pMem, pXiSeed2), mulmod(xiSeed, xiSeed, q)) + + // Compute roots.S0.h0w8 + mstore( + add(pMem, pH0w8_0), + mulmod( + mload(add(pMem, pXiSeed2)), + mload(add(pMem, pXiSeed)), + q + ) + ) + mstore( + add(pMem, pH0w8_1), + mulmod(mload(add(pMem, pH0w8_0)), w8_1, q) + ) + mstore( + add(pMem, pH0w8_2), + mulmod(mload(add(pMem, pH0w8_0)), w8_2, q) + ) + mstore( + add(pMem, pH0w8_3), + mulmod(mload(add(pMem, pH0w8_0)), w8_3, q) + ) + mstore( + add(pMem, pH0w8_4), + mulmod(mload(add(pMem, pH0w8_0)), w8_4, q) + ) + mstore( + add(pMem, pH0w8_5), + mulmod(mload(add(pMem, pH0w8_0)), w8_5, q) + ) + mstore( + add(pMem, pH0w8_6), + mulmod(mload(add(pMem, pH0w8_0)), w8_6, q) + ) + mstore( + add(pMem, pH0w8_7), + mulmod(mload(add(pMem, pH0w8_0)), w8_7, q) + ) + + // Compute roots.S1.h1w4 + mstore( + add(pMem, pH1w4_0), + mulmod( + mload(add(pMem, pH0w8_0)), + mload(add(pMem, pH0w8_0)), + q + ) + ) + mstore( + add(pMem, pH1w4_1), + mulmod(mload(add(pMem, pH1w4_0)), w4, q) + ) + mstore( + add(pMem, pH1w4_2), + mulmod(mload(add(pMem, pH1w4_0)), w4_2, q) + ) + mstore( + add(pMem, pH1w4_3), + mulmod(mload(add(pMem, pH1w4_0)), w4_3, q) + ) + + // Compute roots.S2.h2w3 + mstore( + add(pMem, pH2w3_0), + mulmod( + mload(add(pMem, pH1w4_0)), + mload(add(pMem, pXiSeed2)), + q + ) + ) + mstore( + add(pMem, pH2w3_1), + mulmod(mload(add(pMem, pH2w3_0)), w3, q) + ) + mstore( + add(pMem, pH2w3_2), + mulmod(mload(add(pMem, pH2w3_0)), w3_2, q) + ) + + // Compute roots.S2.h2w3 + mstore( + add(pMem, pH3w3_0), + mulmod(mload(add(pMem, pH2w3_0)), wr, q) + ) + mstore( + add(pMem, pH3w3_1), + mulmod(mload(add(pMem, pH3w3_0)), w3, q) + ) + mstore( + add(pMem, pH3w3_2), + mulmod(mload(add(pMem, pH3w3_0)), w3_2, q) + ) + + let xin := mulmod( + mulmod( + mload(add(pMem, pH2w3_0)), + mload(add(pMem, pH2w3_0)), + q + ), + mload(add(pMem, pH2w3_0)), + q + ) + mstore(add(pMem, pXi), xin) + + // Compute xi^n + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mod(add(sub(xin, 1), q), q) + mstore(add(pMem, pZh), xin) + mstore(add(pMem, pZhInv), xin) // We will invert later together with lagrange pols + + // Compute challenge.alpha + mstore(add(pMem, lastMem), xiSeed) + + calldatacopy(add(pMem, 1952), pEval_ql, 480) + mstore( + add(pMem, pAlpha), + mod(keccak256(add(pMem, lastMem), 512), q) + ) + + // Compute challenge.y + mstore(add(pMem, lastMem), mload(add(pMem, pAlpha))) + mstore(add(pMem, 1952), calldataload(pW1)) + mstore(add(pMem, 1984), calldataload(add(pW1, 32))) + mstore(add(pMem, pY), mod(keccak256(add(pMem, lastMem), 96), q)) + } + + function computeLiS0(pMem) { + let root0 := mload(add(pMem, pH0w8_0)) + let y := mload(add(pMem, pY)) + let den1 := 1 + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + + den1 := mulmod(8, den1, q) + + let den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 0), 8), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 1), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 2), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 3), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(3, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 4), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(4, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 128)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 5), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(5, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 160)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 6), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(6, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 192)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 7), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(7, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 224)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + } + + function computeLiS1(pMem) { + let root0 := mload(add(pMem, pH1w4_0)) + let y := mload(add(pMem, pY)) + let den1 := 1 + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + + den1 := mulmod(4, den1, q) + + let den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 0), 4), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 1), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 2), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 3), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(3, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + } + + function computeLiS2(pMem) { + let y := mload(add(pMem, pY)) + + let den1 := mulmod( + mulmod(3, mload(add(pMem, pH2w3_0)), q), + addmod( + mload(add(pMem, pXi)), + mod(sub(q, mulmod(mload(add(pMem, pXi)), w1, q)), q), + q + ), + q + ) + + let den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 0), 3), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 1), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 2), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den1 := mulmod( + mulmod(3, mload(add(pMem, pH3w3_0)), q), + addmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mod(sub(q, mload(add(pMem, pXi))), q), + q + ), + q + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 0), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 1), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 128)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 2), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 160)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + } + + // Prepare all the denominators that must be inverted, placed them in consecutive memory addresses + function computeInversions(pMem) { + // 1/ZH(xi) used in steps 8 and 9 of the verifier to multiply by 1/Z_H(xi) + // Value computed during computeChallenges function and stores in pMem+pZhInv + + // 1/((y - h1) (y - h1w4) (y - h1w4_2) (y - h1w4_3)) + // used in steps 10 and 11 of the verifier + let y := mload(add(pMem, pY)) + let w := addmod(y, mod(sub(q, mload(add(pMem, pH1w4_0))), q), q) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_2))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_3))), q), q), + q + ) + mstore(add(pMem, pDenH1), w) + + // 1/((y - h2) (y - h2w3) (y - h2w3_2) (y - h3) (y - h3w3) (y - h3w3_2)) + w := addmod(y, mod(sub(q, mload(add(pMem, pH2w3_0))), q), q) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH2w3_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH2w3_2))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_0))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_2))), q), q), + q + ) + mstore(add(pMem, pDenH2), w) + + // Denominator needed in the verifier when computing L_i^{S0}(X) + computeLiS0(pMem) + + // Denominator needed in the verifier when computing L_i^{S1}(X) + computeLiS1(pMem) + + // Denominator needed in the verifier when computing L_i^{S2}(X) + computeLiS2(pMem) + + // L_i where i from 1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) + w := 1 + let xi := mload(add(pMem, pXi)) + + mstore( + add(pMem, pEval_l1), + mulmod(n, mod(add(sub(xi, w), q), q), q) + ) + + // Execute Montgomery batched inversions of the previous prepared values + inverseArray(pMem) + } + + // Compute Lagrange polynomial evaluation L_i(xi) + function computeLagrange(pMem) { + let zh := mload(add(pMem, pZh)) + let w := 1 + + mstore( + add(pMem, pEval_l1), + mulmod(mload(add(pMem, pEval_l1)), zh, q) + ) + } + + // Compute public input polynomial evaluation PI(xi) + function computePi(pMem, pPub) { + let pi := 0 + pi := mod( + add( + sub( + pi, + mulmod( + mload(add(pMem, pEval_l1)), + calldataload(pPub), + q + ) + ), + q + ), + q + ) + + mstore(add(pMem, pPi), pi) + } + + // Compute r0(y) by interpolating the polynomial r0(X) using 8 points (x,y) + // where x = {h9, h0w8, h0w8^2, h0w8^3, h0w8^4, h0w8^5, h0w8^6, h0w8^7} + // and y = {C0(h0), C0(h0w8), C0(h0w8^2), C0(h0w8^3), C0(h0w8^4), C0(h0w8^5), C0(h0w8^6), C0(h0w8^7)} + // and computing C0(xi) + function computeR0(pMem) { + let num := 1 + let y := mload(add(pMem, pY)) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + + num := addmod(num, mod(sub(q, mload(add(pMem, pXi))), q), q) + + let res + let h0w80 + let c0Value + let h0w8i + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_0)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 0))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_1)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 32))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_2)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 64))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_3)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 96))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_4)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 128))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_5)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 160))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_6)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 192))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_7)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 224))), q), + q + ), + q + ) + + mstore(add(pMem, pR0), res) + } + + // Compute r1(y) by interpolating the polynomial r1(X) using 4 points (x,y) + // where x = {h1, h1w4, h1w4^2, h1w4^3} + // and y = {C1(h1), C1(h1w4), C1(h1w4^2), C1(h1w4^3)} + // and computing T0(xi) + function computeR1(pMem) { + let num := 1 + let y := mload(add(pMem, pY)) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + + num := addmod(num, mod(sub(q, mload(add(pMem, pXi))), q), q) + + let t0 + let evalA := calldataload(pEval_a) + let evalB := calldataload(pEval_b) + let evalC := calldataload(pEval_c) + + t0 := mulmod(calldataload(pEval_ql), evalA, q) + t0 := addmod(t0, mulmod(calldataload(pEval_qr), evalB, q), q) + t0 := addmod( + t0, + mulmod(calldataload(pEval_qm), mulmod(evalA, evalB, q), q), + q + ) + t0 := addmod(t0, mulmod(calldataload(pEval_qo), evalC, q), q) + t0 := addmod(t0, calldataload(pEval_qc), q) + t0 := addmod(t0, mload(add(pMem, pPi)), q) + t0 := mulmod(t0, mload(add(pMem, pZhInv)), q) + + let res + let c1Value + let h1w4 + let square + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_0)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(0, 32)))), + q + ), + q + ), + q + ) + + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_1)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(1, 32)))), + q + ), + q + ), + q + ) + + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_2)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(2, 32)))), + q + ), + q + ), + q + ) + + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_3)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(3, 32)))), + q + ), + q + ), + q + ) + + mstore(add(pMem, pR1), res) + } + + // Compute r2(y) by interpolating the polynomial r2(X) using 6 points (x,y) + // where x = {[h2, h2w3, h2w3^2], [h3, h3w3, h3w3^2]} + // and y = {[C2(h2), C2(h2w3), C2(h2w3^2)], [C2(h3), C2(h3w3), C2(h3w3^2)]} + // and computing T1(xi) and T2(xi) + function computeR2(pMem) { + let y := mload(add(pMem, pY)) + let num := 1 + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + + let num2 := 1 + num2 := mulmod(y, num2, q) + num2 := mulmod(y, num2, q) + num2 := mulmod(y, num2, q) + num2 := mulmod( + num2, + addmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mload(add(pMem, pXi)), + q + ), + q + ) + + num := addmod(num, mod(sub(q, num2), q), q) + + num2 := mulmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mload(add(pMem, pXi)), + q + ) + + num := addmod(num, num2, q) + + let t1 + let t2 + let betaXi := mulmod( + mload(add(pMem, pBeta)), + mload(add(pMem, pXi)), + q + ) + let gamma := mload(add(pMem, pGamma)) + + t2 := addmod(calldataload(pEval_a), addmod(betaXi, gamma, q), q) + t2 := mulmod( + t2, + addmod( + calldataload(pEval_b), + addmod(mulmod(betaXi, k1, q), gamma, q), + q + ), + q + ) + t2 := mulmod( + t2, + addmod( + calldataload(pEval_c), + addmod(mulmod(betaXi, k2, q), gamma, q), + q + ), + q + ) + t2 := mulmod(t2, calldataload(pEval_z), q) + + //Let's use t1 as a temporal variable to save one local + t1 := addmod( + calldataload(pEval_a), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s1), + q + ), + gamma, + q + ), + q + ) + t1 := mulmod( + t1, + addmod( + calldataload(pEval_b), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s2), + q + ), + gamma, + q + ), + q + ), + q + ) + t1 := mulmod( + t1, + addmod( + calldataload(pEval_c), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s3), + q + ), + gamma, + q + ), + q + ), + q + ) + t1 := mulmod(t1, calldataload(pEval_zw), q) + + t2 := addmod(t2, mod(sub(q, t1), q), q) + t2 := mulmod(t2, mload(add(pMem, pZhInv)), q) + + // Compute T1(xi) + t1 := sub(calldataload(pEval_z), 1) + t1 := mulmod(t1, mload(add(pMem, pEval_l1)), q) + t1 := mulmod(t1, mload(add(pMem, pZhInv)), q) + + // Let's use local variable gamma to save the result + gamma := 0 + + let hw + let c2Value + + hw := mload(add(pMem, pH2w3_0)) + c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) + c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(0, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH2w3_1)) + c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) + c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(1, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH2w3_2)) + c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) + c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(2, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH3w3_0)) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(3, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH3w3_1)) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(4, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH3w3_2)) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(5, 32)))), + q + ), + q + ), + q + ) + + mstore(add(pMem, pR2), gamma) + } + + // G1 function to accumulate a G1 value to an address + function g1_acc(pR, pP) { + let mIn := mload(0x40) + mstore(mIn, mload(pR)) + mstore(add(mIn, 32), mload(add(pR, 32))) + mstore(add(mIn, 64), mload(pP)) + mstore(add(mIn, 96), mload(add(pP, 32))) + + let success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value to value in an address + function g1_mulAcc(pR, pP, s) { + let success + let mIn := mload(0x40) + mstore(mIn, calldataload(pP)) + mstore(add(mIn, 32), calldataload(add(pP, 32))) + mstore(add(mIn, 64), s) + + success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + + mstore(add(mIn, 64), mload(pR)) + mstore(add(mIn, 96), mload(add(pR, 32))) + + success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value(x,y) to value in an address + function g1_mulAccC(pR, x, y, s) { + let success + let mIn := mload(0x40) + mstore(mIn, x) + mstore(add(mIn, 32), y) + mstore(add(mIn, 64), s) + + success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + + mstore(add(mIn, 64), mload(pR)) + mstore(add(mIn, 96), mload(add(pR, 32))) + + success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + function computeFEJ(pMem) { + // Prepare shared numerator between F, E and J to reuse it + let y := mload(add(pMem, pY)) + let numerator := addmod( + y, + mod(sub(q, mload(add(pMem, pH0w8_0))), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_1))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_2))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_3))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_4))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_5))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_6))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_7))), q), q), + q + ) + + // Prepare shared quotient between F and E to reuse it + let quotient1 := mulmod( + mload(add(pMem, pAlpha)), + mulmod(numerator, mload(add(pMem, pDenH1)), q), + q + ) + let quotient2 := mulmod( + mulmod( + mload(add(pMem, pAlpha)), + mload(add(pMem, pAlpha)), + q + ), + mulmod(numerator, mload(add(pMem, pDenH2)), q), + q + ) + + // Compute full batched polynomial commitment [F]_1 + mstore(add(pMem, pF), C0x) + mstore(add(pMem, add(pF, 32)), C0y) + g1_mulAcc(add(pMem, pF), pC1, quotient1) + g1_mulAcc(add(pMem, pF), pC2, quotient2) + + // Compute group-encoded batch evaluation [E]_1 + g1_mulAccC( + add(pMem, pE), + G1x, + G1y, + addmod( + mload(add(pMem, pR0)), + addmod( + mulmod(quotient1, mload(add(pMem, pR1)), q), + mulmod(quotient2, mload(add(pMem, pR2)), q), + q + ), + q + ) + ) + + // Compute the full difference [J]_1 + g1_mulAcc(add(pMem, pJ), pW1, numerator) + } + + // Validate all evaluations with a pairing checking that e([F]_1 - [E]_1 - [J]_1 + y[W2]_1, [1]_2) == e([W']_1, [x]_2) + function checkPairing(pMem) -> isOk { + let mIn := mload(0x40) + + // First pairing value + // Compute -E + mstore( + add(add(pMem, pE), 32), + mod(sub(qf, mload(add(add(pMem, pE), 32))), qf) + ) + // Compute -J + mstore( + add(add(pMem, pJ), 32), + mod(sub(qf, mload(add(add(pMem, pJ), 32))), qf) + ) + // F = F - E - J + y·W2 + g1_acc(add(pMem, pF), add(pMem, pE)) + g1_acc(add(pMem, pF), add(pMem, pJ)) + g1_mulAcc(add(pMem, pF), pW2, mload(add(pMem, pY))) + + mstore(mIn, mload(add(pMem, pF))) + mstore(add(mIn, 32), mload(add(add(pMem, pF), 32))) + + // Second pairing value + mstore(add(mIn, 64), G2x2) + mstore(add(mIn, 96), G2x1) + mstore(add(mIn, 128), G2y2) + mstore(add(mIn, 160), G2y1) + + // Third pairing value + // Compute -W2 + mstore(add(mIn, 192), calldataload(pW2)) + let s := calldataload(add(pW2, 32)) + s := mod(sub(qf, s), qf) + mstore(add(mIn, 224), s) + + // Fourth pairing value + mstore(add(mIn, 256), X2x2) + mstore(add(mIn, 288), X2x1) + mstore(add(mIn, 320), X2y2) + mstore(add(mIn, 352), X2y1) + + let success := staticcall( + sub(gas(), 2000), + 8, + mIn, + 384, + mIn, + 0x20 + ) + + isOk := and(success, mload(mIn)) + } + + let pMem := mload(0x40) + mstore(0x40, add(pMem, lastMem)) + + // Validate that all evaluations ∈ F + checkInput() + + // Compute the challenges: beta, gamma, xi, alpha and y ∈ F, h1w4/h2w3/h3w3 roots, xiN and zh(xi) + computeChallenges(pMem, pubSignals) + + // To divide prime fields the Extended Euclidean Algorithm for computing modular inverses is needed. + // The Montgomery batch inversion algorithm allow us to compute n inverses reducing to a single one inversion. + // More info: https://vitalik.ca/general/2018/07/21/starks_part_3.html + // To avoid this single inverse computation on-chain, it has been computed in proving time and send it to the verifier. + // Therefore, the verifier: + // 1) Prepare all the denominators to inverse + // 2) Check the inverse sent by the prover it is what it should be + // 3) Compute the others inverses using the Montgomery Batched Algorithm using the inverse sent to avoid the inversion operation it does. + computeInversions(pMem) + + // Compute Lagrange polynomial evaluations Li(xi) + computeLagrange(pMem) + + // Compute public input polynomial evaluation PI(xi) = \sum_i^l -public_input_i·L_i(xi) + computePi(pMem, pubSignals) + + // Computes r1(y) and r2(y) + computeR0(pMem) + computeR1(pMem) + computeR2(pMem) + + // Compute full batched polynomial commitment [F]_1, group-encoded batch evaluation [E]_1 and the full difference [J]_1 + computeFEJ(pMem) + + // Validate all evaluations + let isValid := checkPairing(pMem) + + mstore(0, isValid) + return(0, 0x20) + } + } +} diff --git a/contracts/verifiers/previousVerifiers/FflonkVerifier_10.sol b/contracts/verifiers/previousVerifiers/FflonkVerifier_10.sol new file mode 100644 index 000000000..682c0e9ec --- /dev/null +++ b/contracts/verifiers/previousVerifiers/FflonkVerifier_10.sol @@ -0,0 +1,2158 @@ +// SPDX-License-Identifier: GPL-3.0 +/* + Copyright 2021 0KIMS association. + + This file is generated with [snarkJS](https://github.com/iden3/snarkjs). + + snarkJS is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + snarkJS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with snarkJS. If not, see . +*/ + +pragma solidity >=0.7.0 <0.9.0; + +contract FflonkVerifier_10 { + uint32 constant n = 16777216; // Domain size + + // Verification Key data + uint256 constant k1 = 2; // Plonk k1 multiplicative factor to force distinct cosets of H + uint256 constant k2 = 3; // Plonk k2 multiplicative factor to force distinct cosets of H + + // OMEGAS + // Omega, Omega^{1/3} + uint256 constant w1 = + 5709868443893258075976348696661355716898495876243883251619397131511003808859; + uint256 constant wr = + 18200100796661656210024324131237448517259556535315737226009542456080026430510; + // Omega_3, Omega_3^2 + uint256 constant w3 = + 21888242871839275217838484774961031246154997185409878258781734729429964517155; + uint256 constant w3_2 = + 4407920970296243842393367215006156084916469457145843978461; + // Omega_4, Omega_4^2, Omega_4^3 + uint256 constant w4 = + 21888242871839275217838484774961031246007050428528088939761107053157389710902; + uint256 constant w4_2 = + 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 constant w4_3 = + 4407920970296243842541313971887945403937097133418418784715; + // Omega_8, Omega_8^2, Omega_8^3, Omega_8^4, Omega_8^5, Omega_8^6, Omega_8^7 + uint256 constant w8_1 = + 19540430494807482326159819597004422086093766032135589407132600596362845576832; + uint256 constant w8_2 = + 21888242871839275217838484774961031246007050428528088939761107053157389710902; + uint256 constant w8_3 = + 13274704216607947843011480449124596415239537050559949017414504948711435969894; + uint256 constant w8_4 = + 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 constant w8_5 = + 2347812377031792896086586148252853002454598368280444936565603590212962918785; + uint256 constant w8_6 = + 4407920970296243842541313971887945403937097133418418784715; + uint256 constant w8_7 = + 8613538655231327379234925296132678673308827349856085326283699237864372525723; + + // Verifier preprocessed input C_0(x)·[1]_1 + uint256 constant C0x = + 11210367295020917257703235313889457022168952188583021305208665558514331769248; + uint256 constant C0y = + 17059301660817115093380673187280876999008701101209472326054844504600568092098; + + // Verifier preprocessed input x·[1]_2 + uint256 constant X2x1 = + 21831381940315734285607113342023901060522397560371972897001948545212302161822; + uint256 constant X2x2 = + 17231025384763736816414546592865244497437017442647097510447326538965263639101; + uint256 constant X2y1 = + 2388026358213174446665280700919698872609886601280537296205114254867301080648; + uint256 constant X2y2 = + 11507326595632554467052522095592665270651932854513688777769618397986436103170; + + // Scalar field size + uint256 constant q = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + // Base field size + uint256 constant qf = + 21888242871839275222246405745257275088696311157297823662689037894645226208583; + // [1]_1 + uint256 constant G1x = 1; + uint256 constant G1y = 2; + // [1]_2 + uint256 constant G2x1 = + 10857046999023057135944570762232829481370756359578518086990519993285655852781; + uint256 constant G2x2 = + 11559732032986387107991004021392285783925812861821192530917403151452391805634; + uint256 constant G2y1 = + 8495653923123431417604973247489272438418190587263600148770280649306958101930; + uint256 constant G2y2 = + 4082367875863433681332203403145435568316851327593401208105741076214120093531; + + // Proof calldata + // Byte offset of every parameter of the calldata + // Polynomial commitments + uint16 constant pC1 = 4 + 0; // [C1]_1 + uint16 constant pC2 = 4 + 32 * 2; // [C2]_1 + uint16 constant pW1 = 4 + 32 * 4; // [W]_1 + uint16 constant pW2 = 4 + 32 * 6; // [W']_1 + // Opening evaluations + uint16 constant pEval_ql = 4 + 32 * 8; // q_L(xi) + uint16 constant pEval_qr = 4 + 32 * 9; // q_R(xi) + uint16 constant pEval_qm = 4 + 32 * 10; // q_M(xi) + uint16 constant pEval_qo = 4 + 32 * 11; // q_O(xi) + uint16 constant pEval_qc = 4 + 32 * 12; // q_C(xi) + uint16 constant pEval_s1 = 4 + 32 * 13; // S_{sigma_1}(xi) + uint16 constant pEval_s2 = 4 + 32 * 14; // S_{sigma_2}(xi) + uint16 constant pEval_s3 = 4 + 32 * 15; // S_{sigma_3}(xi) + uint16 constant pEval_a = 4 + 32 * 16; // a(xi) + uint16 constant pEval_b = 4 + 32 * 17; // b(xi) + uint16 constant pEval_c = 4 + 32 * 18; // c(xi) + uint16 constant pEval_z = 4 + 32 * 19; // z(xi) + uint16 constant pEval_zw = 4 + 32 * 20; // z_omega(xi) + uint16 constant pEval_t1w = 4 + 32 * 21; // T_1(xi omega) + uint16 constant pEval_t2w = 4 + 32 * 22; // T_2(xi omega) + uint16 constant pEval_inv = 4 + 32 * 23; // inv(batch) sent by the prover to avoid any inverse calculation to save gas, + // we check the correctness of the inv(batch) by computing batch + // and checking inv(batch) * batch == 1 + + // Memory data + // Challenges + uint16 constant pAlpha = 0; // alpha challenge + uint16 constant pBeta = 32; // beta challenge + uint16 constant pGamma = 64; // gamma challenge + uint16 constant pY = 96; // y challenge + uint16 constant pXiSeed = 128; // xi seed, from this value we compute xi = xiSeed^24 + uint16 constant pXiSeed2 = 160; // (xi seed)^2 + uint16 constant pXi = 192; // xi challenge + + // Roots + // S_0 = roots_8(xi) = { h_0, h_0w_8, h_0w_8^2, h_0w_8^3, h_0w_8^4, h_0w_8^5, h_0w_8^6, h_0w_8^7 } + uint16 constant pH0w8_0 = 224; + uint16 constant pH0w8_1 = 256; + uint16 constant pH0w8_2 = 288; + uint16 constant pH0w8_3 = 320; + uint16 constant pH0w8_4 = 352; + uint16 constant pH0w8_5 = 384; + uint16 constant pH0w8_6 = 416; + uint16 constant pH0w8_7 = 448; + + // S_1 = roots_4(xi) = { h_1, h_1w_4, h_1w_4^2, h_1w_4^3 } + uint16 constant pH1w4_0 = 480; + uint16 constant pH1w4_1 = 512; + uint16 constant pH1w4_2 = 544; + uint16 constant pH1w4_3 = 576; + + // S_2 = roots_3(xi) U roots_3(xi omega) + // roots_3(xi) = { h_2, h_2w_3, h_2w_3^2 } + uint16 constant pH2w3_0 = 608; + uint16 constant pH2w3_1 = 640; + uint16 constant pH2w3_2 = 672; + // roots_3(xi omega) = { h_3, h_3w_3, h_3w_3^2 } + uint16 constant pH3w3_0 = 704; + uint16 constant pH3w3_1 = 736; + uint16 constant pH3w3_2 = 768; + + uint16 constant pPi = 800; // PI(xi) + uint16 constant pR0 = 832; // r0(y) + uint16 constant pR1 = 864; // r1(y) + uint16 constant pR2 = 896; // r2(y) + + uint16 constant pF = 928; // [F]_1, 64 bytes + uint16 constant pE = 992; // [E]_1, 64 bytes + uint16 constant pJ = 1056; // [J]_1, 64 bytes + + uint16 constant pZh = 1184; // Z_H(xi) + // From this point we write all the variables that must be computed using the Montgomery batch inversion + uint16 constant pZhInv = 1216; // 1/Z_H(xi) + uint16 constant pDenH1 = 1248; // 1/( (y-h_1w_4) (y-h_1w_4^2) (y-h_1w_4^3) (y-h_1w_4^4) ) + uint16 constant pDenH2 = 1280; // 1/( (y-h_2w_3) (y-h_2w_3^2) (y-h_2w_3^3) (y-h_3w_3) (y-h_3w_3^2) (y-h_3w_3^3) ) + uint16 constant pLiS0Inv = 1312; // Reserve 8 * 32 bytes to compute r_0(X) + uint16 constant pLiS1Inv = 1568; // Reserve 4 * 32 bytes to compute r_1(X) + uint16 constant pLiS2Inv = 1696; // Reserve 6 * 32 bytes to compute r_2(X) + // Lagrange evaluations + + uint16 constant pEval_l1 = 1888; + + uint16 constant lastMem = 1920; + + function verifyProof( + bytes32[24] calldata proof, + uint256[1] calldata pubSignals + ) public view returns (bool) { + assembly { + // Computes the inverse of an array of values + // See https://vitalik.ca/general/2018/07/21/starks_part_3.html in section where explain fields operations + // To save the inverse to be computed on chain the prover sends the inverse as an evaluation in commits.eval_inv + function inverseArray(pMem) { + let pAux := mload(0x40) // Point to the next free position + let acc := mload(add(pMem, pZhInv)) // Read the first element + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pDenH1)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pDenH2)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pLiS0Inv)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 32))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 64))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 96))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 128))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 160))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 192))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 224))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pLiS1Inv)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 32))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 64))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 96))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pLiS2Inv)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 32))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 64))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 96))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 128))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 160))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pEval_l1)), q) + mstore(pAux, acc) + + let inv := calldataload(pEval_inv) + + // Before using the inverse sent by the prover the verifier checks inv(batch) * batch === 1 + if iszero(eq(1, mulmod(acc, inv, q))) { + mstore(0, 0) + return(0, 0x20) + } + + acc := inv + + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pEval_l1)), q) + mstore(add(pMem, pEval_l1), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 160))), q) + mstore(add(pMem, add(pLiS2Inv, 160)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 128))), q) + mstore(add(pMem, add(pLiS2Inv, 128)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 96))), q) + mstore(add(pMem, add(pLiS2Inv, 96)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 64))), q) + mstore(add(pMem, add(pLiS2Inv, 64)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 32))), q) + mstore(add(pMem, add(pLiS2Inv, 32)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pLiS2Inv)), q) + mstore(add(pMem, pLiS2Inv), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 96))), q) + mstore(add(pMem, add(pLiS1Inv, 96)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 64))), q) + mstore(add(pMem, add(pLiS1Inv, 64)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 32))), q) + mstore(add(pMem, add(pLiS1Inv, 32)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pLiS1Inv)), q) + mstore(add(pMem, pLiS1Inv), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 224))), q) + mstore(add(pMem, add(pLiS0Inv, 224)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 192))), q) + mstore(add(pMem, add(pLiS0Inv, 192)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 160))), q) + mstore(add(pMem, add(pLiS0Inv, 160)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 128))), q) + mstore(add(pMem, add(pLiS0Inv, 128)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 96))), q) + mstore(add(pMem, add(pLiS0Inv, 96)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 64))), q) + mstore(add(pMem, add(pLiS0Inv, 64)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 32))), q) + mstore(add(pMem, add(pLiS0Inv, 32)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pLiS0Inv)), q) + mstore(add(pMem, pLiS0Inv), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pDenH2)), q) + mstore(add(pMem, pDenH2), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pDenH1)), q) + mstore(add(pMem, pDenH1), inv) + + mstore(add(pMem, pZhInv), acc) + } + + function checkField(v) { + if iszero(lt(v, q)) { + mstore(0, 0) + return(0, 0x20) + } + } + + function checkPointBelongsToBN128Curve(p) { + let x := calldataload(p) + let y := calldataload(add(p, 32)) + + // Check that the point is on the curve + // y^2 = x^3 + 3 + let x3_3 := addmod(mulmod(x, mulmod(x, x, qf), qf), 3, qf) + let y2 := mulmod(y, y, qf) + + if iszero(eq(x3_3, y2)) { + mstore(0, 0) + return(0, 0x20) + } + } + + // Validate all the evaluations sent by the prover ∈ F + function checkInput() { + // Check proof commitments fullfill bn128 curve equation Y^2 = X^3 + 3 + checkPointBelongsToBN128Curve(pC1) + checkPointBelongsToBN128Curve(pC2) + checkPointBelongsToBN128Curve(pW1) + checkPointBelongsToBN128Curve(pW2) + + checkField(calldataload(pEval_ql)) + checkField(calldataload(pEval_qr)) + checkField(calldataload(pEval_qm)) + checkField(calldataload(pEval_qo)) + checkField(calldataload(pEval_qc)) + checkField(calldataload(pEval_s1)) + checkField(calldataload(pEval_s2)) + checkField(calldataload(pEval_s3)) + checkField(calldataload(pEval_a)) + checkField(calldataload(pEval_b)) + checkField(calldataload(pEval_c)) + checkField(calldataload(pEval_z)) + checkField(calldataload(pEval_zw)) + checkField(calldataload(pEval_t1w)) + checkField(calldataload(pEval_t2w)) + checkField(calldataload(pEval_inv)) + + // Points are checked in the point operations precompiled smart contracts + } + + function computeChallenges(pMem, pPublic) { + // Compute challenge.beta & challenge.gamma + mstore(add(pMem, 1920), C0x) + mstore(add(pMem, 1952), C0y) + + mstore(add(pMem, 1984), calldataload(pPublic)) + + mstore(add(pMem, 2016), calldataload(pC1)) + mstore(add(pMem, 2048), calldataload(add(pC1, 32))) + + mstore( + add(pMem, pBeta), + mod(keccak256(add(pMem, lastMem), 160), q) + ) + mstore( + add(pMem, pGamma), + mod(keccak256(add(pMem, pBeta), 32), q) + ) + + // Get xiSeed & xiSeed2 + mstore(add(pMem, lastMem), mload(add(pMem, pGamma))) + mstore(add(pMem, 1952), calldataload(pC2)) + mstore(add(pMem, 1984), calldataload(add(pC2, 32))) + let xiSeed := mod(keccak256(add(pMem, lastMem), 96), q) + + mstore(add(pMem, pXiSeed), xiSeed) + mstore(add(pMem, pXiSeed2), mulmod(xiSeed, xiSeed, q)) + + // Compute roots.S0.h0w8 + mstore( + add(pMem, pH0w8_0), + mulmod( + mload(add(pMem, pXiSeed2)), + mload(add(pMem, pXiSeed)), + q + ) + ) + mstore( + add(pMem, pH0w8_1), + mulmod(mload(add(pMem, pH0w8_0)), w8_1, q) + ) + mstore( + add(pMem, pH0w8_2), + mulmod(mload(add(pMem, pH0w8_0)), w8_2, q) + ) + mstore( + add(pMem, pH0w8_3), + mulmod(mload(add(pMem, pH0w8_0)), w8_3, q) + ) + mstore( + add(pMem, pH0w8_4), + mulmod(mload(add(pMem, pH0w8_0)), w8_4, q) + ) + mstore( + add(pMem, pH0w8_5), + mulmod(mload(add(pMem, pH0w8_0)), w8_5, q) + ) + mstore( + add(pMem, pH0w8_6), + mulmod(mload(add(pMem, pH0w8_0)), w8_6, q) + ) + mstore( + add(pMem, pH0w8_7), + mulmod(mload(add(pMem, pH0w8_0)), w8_7, q) + ) + + // Compute roots.S1.h1w4 + mstore( + add(pMem, pH1w4_0), + mulmod( + mload(add(pMem, pH0w8_0)), + mload(add(pMem, pH0w8_0)), + q + ) + ) + mstore( + add(pMem, pH1w4_1), + mulmod(mload(add(pMem, pH1w4_0)), w4, q) + ) + mstore( + add(pMem, pH1w4_2), + mulmod(mload(add(pMem, pH1w4_0)), w4_2, q) + ) + mstore( + add(pMem, pH1w4_3), + mulmod(mload(add(pMem, pH1w4_0)), w4_3, q) + ) + + // Compute roots.S2.h2w3 + mstore( + add(pMem, pH2w3_0), + mulmod( + mload(add(pMem, pH1w4_0)), + mload(add(pMem, pXiSeed2)), + q + ) + ) + mstore( + add(pMem, pH2w3_1), + mulmod(mload(add(pMem, pH2w3_0)), w3, q) + ) + mstore( + add(pMem, pH2w3_2), + mulmod(mload(add(pMem, pH2w3_0)), w3_2, q) + ) + + // Compute roots.S2.h2w3 + mstore( + add(pMem, pH3w3_0), + mulmod(mload(add(pMem, pH2w3_0)), wr, q) + ) + mstore( + add(pMem, pH3w3_1), + mulmod(mload(add(pMem, pH3w3_0)), w3, q) + ) + mstore( + add(pMem, pH3w3_2), + mulmod(mload(add(pMem, pH3w3_0)), w3_2, q) + ) + + let xin := mulmod( + mulmod( + mload(add(pMem, pH2w3_0)), + mload(add(pMem, pH2w3_0)), + q + ), + mload(add(pMem, pH2w3_0)), + q + ) + mstore(add(pMem, pXi), xin) + + // Compute xi^n + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mod(add(sub(xin, 1), q), q) + mstore(add(pMem, pZh), xin) + mstore(add(pMem, pZhInv), xin) // We will invert later together with lagrange pols + + // Compute challenge.alpha + mstore(add(pMem, lastMem), xiSeed) + + calldatacopy(add(pMem, 1952), pEval_ql, 480) + mstore( + add(pMem, pAlpha), + mod(keccak256(add(pMem, lastMem), 512), q) + ) + + // Compute challenge.y + mstore(add(pMem, lastMem), mload(add(pMem, pAlpha))) + mstore(add(pMem, 1952), calldataload(pW1)) + mstore(add(pMem, 1984), calldataload(add(pW1, 32))) + mstore(add(pMem, pY), mod(keccak256(add(pMem, lastMem), 96), q)) + } + + function computeLiS0(pMem) { + let root0 := mload(add(pMem, pH0w8_0)) + let y := mload(add(pMem, pY)) + let den1 := 1 + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + + den1 := mulmod(8, den1, q) + + let den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 0), 8), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 1), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 2), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 3), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(3, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 4), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(4, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 128)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 5), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(5, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 160)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 6), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(6, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 192)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 7), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(7, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 224)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + } + + function computeLiS1(pMem) { + let root0 := mload(add(pMem, pH1w4_0)) + let y := mload(add(pMem, pY)) + let den1 := 1 + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + + den1 := mulmod(4, den1, q) + + let den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 0), 4), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 1), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 2), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 3), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(3, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + } + + function computeLiS2(pMem) { + let y := mload(add(pMem, pY)) + + let den1 := mulmod( + mulmod(3, mload(add(pMem, pH2w3_0)), q), + addmod( + mload(add(pMem, pXi)), + mod(sub(q, mulmod(mload(add(pMem, pXi)), w1, q)), q), + q + ), + q + ) + + let den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 0), 3), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 1), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 2), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den1 := mulmod( + mulmod(3, mload(add(pMem, pH3w3_0)), q), + addmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mod(sub(q, mload(add(pMem, pXi))), q), + q + ), + q + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 0), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 1), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 128)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 2), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 160)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + } + + // Prepare all the denominators that must be inverted, placed them in consecutive memory addresses + function computeInversions(pMem) { + // 1/ZH(xi) used in steps 8 and 9 of the verifier to multiply by 1/Z_H(xi) + // Value computed during computeChallenges function and stores in pMem+pZhInv + + // 1/((y - h1) (y - h1w4) (y - h1w4_2) (y - h1w4_3)) + // used in steps 10 and 11 of the verifier + let y := mload(add(pMem, pY)) + let w := addmod(y, mod(sub(q, mload(add(pMem, pH1w4_0))), q), q) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_2))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_3))), q), q), + q + ) + mstore(add(pMem, pDenH1), w) + + // 1/((y - h2) (y - h2w3) (y - h2w3_2) (y - h3) (y - h3w3) (y - h3w3_2)) + w := addmod(y, mod(sub(q, mload(add(pMem, pH2w3_0))), q), q) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH2w3_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH2w3_2))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_0))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_2))), q), q), + q + ) + mstore(add(pMem, pDenH2), w) + + // Denominator needed in the verifier when computing L_i^{S0}(X) + computeLiS0(pMem) + + // Denominator needed in the verifier when computing L_i^{S1}(X) + computeLiS1(pMem) + + // Denominator needed in the verifier when computing L_i^{S2}(X) + computeLiS2(pMem) + + // L_i where i from 1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) + w := 1 + let xi := mload(add(pMem, pXi)) + + mstore( + add(pMem, pEval_l1), + mulmod(n, mod(add(sub(xi, w), q), q), q) + ) + + // Execute Montgomery batched inversions of the previous prepared values + inverseArray(pMem) + } + + // Compute Lagrange polynomial evaluation L_i(xi) + function computeLagrange(pMem) { + let zh := mload(add(pMem, pZh)) + let w := 1 + + mstore( + add(pMem, pEval_l1), + mulmod(mload(add(pMem, pEval_l1)), zh, q) + ) + } + + // Compute public input polynomial evaluation PI(xi) + function computePi(pMem, pPub) { + let pi := 0 + pi := mod( + add( + sub( + pi, + mulmod( + mload(add(pMem, pEval_l1)), + calldataload(pPub), + q + ) + ), + q + ), + q + ) + + mstore(add(pMem, pPi), pi) + } + + // Compute r0(y) by interpolating the polynomial r0(X) using 8 points (x,y) + // where x = {h9, h0w8, h0w8^2, h0w8^3, h0w8^4, h0w8^5, h0w8^6, h0w8^7} + // and y = {C0(h0), C0(h0w8), C0(h0w8^2), C0(h0w8^3), C0(h0w8^4), C0(h0w8^5), C0(h0w8^6), C0(h0w8^7)} + // and computing C0(xi) + function computeR0(pMem) { + let num := 1 + let y := mload(add(pMem, pY)) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + + num := addmod(num, mod(sub(q, mload(add(pMem, pXi))), q), q) + + let res + let h0w80 + let c0Value + let h0w8i + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_0)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 0))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_1)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 32))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_2)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 64))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_3)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 96))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_4)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 128))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_5)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 160))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_6)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 192))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_7)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 224))), q), + q + ), + q + ) + + mstore(add(pMem, pR0), res) + } + + // Compute r1(y) by interpolating the polynomial r1(X) using 4 points (x,y) + // where x = {h1, h1w4, h1w4^2, h1w4^3} + // and y = {C1(h1), C1(h1w4), C1(h1w4^2), C1(h1w4^3)} + // and computing T0(xi) + function computeR1(pMem) { + let num := 1 + let y := mload(add(pMem, pY)) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + + num := addmod(num, mod(sub(q, mload(add(pMem, pXi))), q), q) + + let t0 + let evalA := calldataload(pEval_a) + let evalB := calldataload(pEval_b) + let evalC := calldataload(pEval_c) + + t0 := mulmod(calldataload(pEval_ql), evalA, q) + t0 := addmod(t0, mulmod(calldataload(pEval_qr), evalB, q), q) + t0 := addmod( + t0, + mulmod(calldataload(pEval_qm), mulmod(evalA, evalB, q), q), + q + ) + t0 := addmod(t0, mulmod(calldataload(pEval_qo), evalC, q), q) + t0 := addmod(t0, calldataload(pEval_qc), q) + t0 := addmod(t0, mload(add(pMem, pPi)), q) + t0 := mulmod(t0, mload(add(pMem, pZhInv)), q) + + let res + let c1Value + let h1w4 + let square + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_0)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(0, 32)))), + q + ), + q + ), + q + ) + + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_1)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(1, 32)))), + q + ), + q + ), + q + ) + + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_2)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(2, 32)))), + q + ), + q + ), + q + ) + + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_3)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(3, 32)))), + q + ), + q + ), + q + ) + + mstore(add(pMem, pR1), res) + } + + // Compute r2(y) by interpolating the polynomial r2(X) using 6 points (x,y) + // where x = {[h2, h2w3, h2w3^2], [h3, h3w3, h3w3^2]} + // and y = {[C2(h2), C2(h2w3), C2(h2w3^2)], [C2(h3), C2(h3w3), C2(h3w3^2)]} + // and computing T1(xi) and T2(xi) + function computeR2(pMem) { + let y := mload(add(pMem, pY)) + let num := 1 + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + + let num2 := 1 + num2 := mulmod(y, num2, q) + num2 := mulmod(y, num2, q) + num2 := mulmod(y, num2, q) + num2 := mulmod( + num2, + addmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mload(add(pMem, pXi)), + q + ), + q + ) + + num := addmod(num, mod(sub(q, num2), q), q) + + num2 := mulmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mload(add(pMem, pXi)), + q + ) + + num := addmod(num, num2, q) + + let t1 + let t2 + let betaXi := mulmod( + mload(add(pMem, pBeta)), + mload(add(pMem, pXi)), + q + ) + let gamma := mload(add(pMem, pGamma)) + + t2 := addmod(calldataload(pEval_a), addmod(betaXi, gamma, q), q) + t2 := mulmod( + t2, + addmod( + calldataload(pEval_b), + addmod(mulmod(betaXi, k1, q), gamma, q), + q + ), + q + ) + t2 := mulmod( + t2, + addmod( + calldataload(pEval_c), + addmod(mulmod(betaXi, k2, q), gamma, q), + q + ), + q + ) + t2 := mulmod(t2, calldataload(pEval_z), q) + + //Let's use t1 as a temporal variable to save one local + t1 := addmod( + calldataload(pEval_a), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s1), + q + ), + gamma, + q + ), + q + ) + t1 := mulmod( + t1, + addmod( + calldataload(pEval_b), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s2), + q + ), + gamma, + q + ), + q + ), + q + ) + t1 := mulmod( + t1, + addmod( + calldataload(pEval_c), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s3), + q + ), + gamma, + q + ), + q + ), + q + ) + t1 := mulmod(t1, calldataload(pEval_zw), q) + + t2 := addmod(t2, mod(sub(q, t1), q), q) + t2 := mulmod(t2, mload(add(pMem, pZhInv)), q) + + // Compute T1(xi) + t1 := sub(calldataload(pEval_z), 1) + t1 := mulmod(t1, mload(add(pMem, pEval_l1)), q) + t1 := mulmod(t1, mload(add(pMem, pZhInv)), q) + + // Let's use local variable gamma to save the result + gamma := 0 + + let hw + let c2Value + + hw := mload(add(pMem, pH2w3_0)) + c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) + c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(0, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH2w3_1)) + c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) + c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(1, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH2w3_2)) + c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) + c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(2, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH3w3_0)) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(3, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH3w3_1)) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(4, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH3w3_2)) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(5, 32)))), + q + ), + q + ), + q + ) + + mstore(add(pMem, pR2), gamma) + } + + // G1 function to accumulate a G1 value to an address + function g1_acc(pR, pP) { + let mIn := mload(0x40) + mstore(mIn, mload(pR)) + mstore(add(mIn, 32), mload(add(pR, 32))) + mstore(add(mIn, 64), mload(pP)) + mstore(add(mIn, 96), mload(add(pP, 32))) + + let success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value to value in an address + function g1_mulAcc(pR, pP, s) { + let success + let mIn := mload(0x40) + mstore(mIn, calldataload(pP)) + mstore(add(mIn, 32), calldataload(add(pP, 32))) + mstore(add(mIn, 64), s) + + success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + + mstore(add(mIn, 64), mload(pR)) + mstore(add(mIn, 96), mload(add(pR, 32))) + + success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value(x,y) to value in an address + function g1_mulAccC(pR, x, y, s) { + let success + let mIn := mload(0x40) + mstore(mIn, x) + mstore(add(mIn, 32), y) + mstore(add(mIn, 64), s) + + success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + + mstore(add(mIn, 64), mload(pR)) + mstore(add(mIn, 96), mload(add(pR, 32))) + + success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + function computeFEJ(pMem) { + // Prepare shared numerator between F, E and J to reuse it + let y := mload(add(pMem, pY)) + let numerator := addmod( + y, + mod(sub(q, mload(add(pMem, pH0w8_0))), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_1))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_2))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_3))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_4))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_5))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_6))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_7))), q), q), + q + ) + + // Prepare shared quotient between F and E to reuse it + let quotient1 := mulmod( + mload(add(pMem, pAlpha)), + mulmod(numerator, mload(add(pMem, pDenH1)), q), + q + ) + let quotient2 := mulmod( + mulmod( + mload(add(pMem, pAlpha)), + mload(add(pMem, pAlpha)), + q + ), + mulmod(numerator, mload(add(pMem, pDenH2)), q), + q + ) + + // Compute full batched polynomial commitment [F]_1 + mstore(add(pMem, pF), C0x) + mstore(add(pMem, add(pF, 32)), C0y) + g1_mulAcc(add(pMem, pF), pC1, quotient1) + g1_mulAcc(add(pMem, pF), pC2, quotient2) + + // Compute group-encoded batch evaluation [E]_1 + g1_mulAccC( + add(pMem, pE), + G1x, + G1y, + addmod( + mload(add(pMem, pR0)), + addmod( + mulmod(quotient1, mload(add(pMem, pR1)), q), + mulmod(quotient2, mload(add(pMem, pR2)), q), + q + ), + q + ) + ) + + // Compute the full difference [J]_1 + g1_mulAcc(add(pMem, pJ), pW1, numerator) + } + + // Validate all evaluations with a pairing checking that e([F]_1 - [E]_1 - [J]_1 + y[W2]_1, [1]_2) == e([W']_1, [x]_2) + function checkPairing(pMem) -> isOk { + let mIn := mload(0x40) + + // First pairing value + // Compute -E + mstore( + add(add(pMem, pE), 32), + mod(sub(qf, mload(add(add(pMem, pE), 32))), qf) + ) + // Compute -J + mstore( + add(add(pMem, pJ), 32), + mod(sub(qf, mload(add(add(pMem, pJ), 32))), qf) + ) + // F = F - E - J + y·W2 + g1_acc(add(pMem, pF), add(pMem, pE)) + g1_acc(add(pMem, pF), add(pMem, pJ)) + g1_mulAcc(add(pMem, pF), pW2, mload(add(pMem, pY))) + + mstore(mIn, mload(add(pMem, pF))) + mstore(add(mIn, 32), mload(add(add(pMem, pF), 32))) + + // Second pairing value + mstore(add(mIn, 64), G2x2) + mstore(add(mIn, 96), G2x1) + mstore(add(mIn, 128), G2y2) + mstore(add(mIn, 160), G2y1) + + // Third pairing value + // Compute -W2 + mstore(add(mIn, 192), calldataload(pW2)) + let s := calldataload(add(pW2, 32)) + s := mod(sub(qf, s), qf) + mstore(add(mIn, 224), s) + + // Fourth pairing value + mstore(add(mIn, 256), X2x2) + mstore(add(mIn, 288), X2x1) + mstore(add(mIn, 320), X2y2) + mstore(add(mIn, 352), X2y1) + + let success := staticcall( + sub(gas(), 2000), + 8, + mIn, + 384, + mIn, + 0x20 + ) + + isOk := and(success, mload(mIn)) + } + + let pMem := mload(0x40) + mstore(0x40, add(pMem, lastMem)) + + // Validate that all evaluations ∈ F + checkInput() + + // Compute the challenges: beta, gamma, xi, alpha and y ∈ F, h1w4/h2w3/h3w3 roots, xiN and zh(xi) + computeChallenges(pMem, pubSignals) + + // To divide prime fields the Extended Euclidean Algorithm for computing modular inverses is needed. + // The Montgomery batch inversion algorithm allow us to compute n inverses reducing to a single one inversion. + // More info: https://vitalik.ca/general/2018/07/21/starks_part_3.html + // To avoid this single inverse computation on-chain, it has been computed in proving time and send it to the verifier. + // Therefore, the verifier: + // 1) Prepare all the denominators to inverse + // 2) Check the inverse sent by the prover it is what it should be + // 3) Compute the others inverses using the Montgomery Batched Algorithm using the inverse sent to avoid the inversion operation it does. + computeInversions(pMem) + + // Compute Lagrange polynomial evaluations Li(xi) + computeLagrange(pMem) + + // Compute public input polynomial evaluation PI(xi) = \sum_i^l -public_input_i·L_i(xi) + computePi(pMem, pubSignals) + + // Computes r1(y) and r2(y) + computeR0(pMem) + computeR1(pMem) + computeR2(pMem) + + // Compute full batched polynomial commitment [F]_1, group-encoded batch evaluation [E]_1 and the full difference [J]_1 + computeFEJ(pMem) + + // Validate all evaluations + let isValid := checkPairing(pMem) + + mstore(0, isValid) + return(0, 0x20) + } + } +} diff --git a/contracts/verifiers/previousVerifiers/FflonkVerifier_11.sol b/contracts/verifiers/previousVerifiers/FflonkVerifier_11.sol new file mode 100644 index 000000000..d38c93f18 --- /dev/null +++ b/contracts/verifiers/previousVerifiers/FflonkVerifier_11.sol @@ -0,0 +1,2158 @@ +// SPDX-License-Identifier: GPL-3.0 +/* + Copyright 2021 0KIMS association. + + This file is generated with [snarkJS](https://github.com/iden3/snarkjs). + + snarkJS is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + snarkJS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with snarkJS. If not, see . +*/ + +pragma solidity >=0.7.0 <0.9.0; + +contract FflonkVerifier_11 { + uint32 constant n = 16777216; // Domain size + + // Verification Key data + uint256 constant k1 = 2; // Plonk k1 multiplicative factor to force distinct cosets of H + uint256 constant k2 = 3; // Plonk k2 multiplicative factor to force distinct cosets of H + + // OMEGAS + // Omega, Omega^{1/3} + uint256 constant w1 = + 5709868443893258075976348696661355716898495876243883251619397131511003808859; + uint256 constant wr = + 18200100796661656210024324131237448517259556535315737226009542456080026430510; + // Omega_3, Omega_3^2 + uint256 constant w3 = + 21888242871839275217838484774961031246154997185409878258781734729429964517155; + uint256 constant w3_2 = + 4407920970296243842393367215006156084916469457145843978461; + // Omega_4, Omega_4^2, Omega_4^3 + uint256 constant w4 = + 21888242871839275217838484774961031246007050428528088939761107053157389710902; + uint256 constant w4_2 = + 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 constant w4_3 = + 4407920970296243842541313971887945403937097133418418784715; + // Omega_8, Omega_8^2, Omega_8^3, Omega_8^4, Omega_8^5, Omega_8^6, Omega_8^7 + uint256 constant w8_1 = + 19540430494807482326159819597004422086093766032135589407132600596362845576832; + uint256 constant w8_2 = + 21888242871839275217838484774961031246007050428528088939761107053157389710902; + uint256 constant w8_3 = + 13274704216607947843011480449124596415239537050559949017414504948711435969894; + uint256 constant w8_4 = + 21888242871839275222246405745257275088548364400416034343698204186575808495616; + uint256 constant w8_5 = + 2347812377031792896086586148252853002454598368280444936565603590212962918785; + uint256 constant w8_6 = + 4407920970296243842541313971887945403937097133418418784715; + uint256 constant w8_7 = + 8613538655231327379234925296132678673308827349856085326283699237864372525723; + + // Verifier preprocessed input C_0(x)·[1]_1 + uint256 constant C0x = + 5025437015266224703663153706990323429998172899911094409768560315505934222779; + uint256 constant C0y = + 16237221832599777269427415426993243095357146403844115525422788241385670511064; + + // Verifier preprocessed input x·[1]_2 + uint256 constant X2x1 = + 21831381940315734285607113342023901060522397560371972897001948545212302161822; + uint256 constant X2x2 = + 17231025384763736816414546592865244497437017442647097510447326538965263639101; + uint256 constant X2y1 = + 2388026358213174446665280700919698872609886601280537296205114254867301080648; + uint256 constant X2y2 = + 11507326595632554467052522095592665270651932854513688777769618397986436103170; + + // Scalar field size + uint256 constant q = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + // Base field size + uint256 constant qf = + 21888242871839275222246405745257275088696311157297823662689037894645226208583; + // [1]_1 + uint256 constant G1x = 1; + uint256 constant G1y = 2; + // [1]_2 + uint256 constant G2x1 = + 10857046999023057135944570762232829481370756359578518086990519993285655852781; + uint256 constant G2x2 = + 11559732032986387107991004021392285783925812861821192530917403151452391805634; + uint256 constant G2y1 = + 8495653923123431417604973247489272438418190587263600148770280649306958101930; + uint256 constant G2y2 = + 4082367875863433681332203403145435568316851327593401208105741076214120093531; + + // Proof calldata + // Byte offset of every parameter of the calldata + // Polynomial commitments + uint16 constant pC1 = 4 + 0; // [C1]_1 + uint16 constant pC2 = 4 + 32 * 2; // [C2]_1 + uint16 constant pW1 = 4 + 32 * 4; // [W]_1 + uint16 constant pW2 = 4 + 32 * 6; // [W']_1 + // Opening evaluations + uint16 constant pEval_ql = 4 + 32 * 8; // q_L(xi) + uint16 constant pEval_qr = 4 + 32 * 9; // q_R(xi) + uint16 constant pEval_qm = 4 + 32 * 10; // q_M(xi) + uint16 constant pEval_qo = 4 + 32 * 11; // q_O(xi) + uint16 constant pEval_qc = 4 + 32 * 12; // q_C(xi) + uint16 constant pEval_s1 = 4 + 32 * 13; // S_{sigma_1}(xi) + uint16 constant pEval_s2 = 4 + 32 * 14; // S_{sigma_2}(xi) + uint16 constant pEval_s3 = 4 + 32 * 15; // S_{sigma_3}(xi) + uint16 constant pEval_a = 4 + 32 * 16; // a(xi) + uint16 constant pEval_b = 4 + 32 * 17; // b(xi) + uint16 constant pEval_c = 4 + 32 * 18; // c(xi) + uint16 constant pEval_z = 4 + 32 * 19; // z(xi) + uint16 constant pEval_zw = 4 + 32 * 20; // z_omega(xi) + uint16 constant pEval_t1w = 4 + 32 * 21; // T_1(xi omega) + uint16 constant pEval_t2w = 4 + 32 * 22; // T_2(xi omega) + uint16 constant pEval_inv = 4 + 32 * 23; // inv(batch) sent by the prover to avoid any inverse calculation to save gas, + // we check the correctness of the inv(batch) by computing batch + // and checking inv(batch) * batch == 1 + + // Memory data + // Challenges + uint16 constant pAlpha = 0; // alpha challenge + uint16 constant pBeta = 32; // beta challenge + uint16 constant pGamma = 64; // gamma challenge + uint16 constant pY = 96; // y challenge + uint16 constant pXiSeed = 128; // xi seed, from this value we compute xi = xiSeed^24 + uint16 constant pXiSeed2 = 160; // (xi seed)^2 + uint16 constant pXi = 192; // xi challenge + + // Roots + // S_0 = roots_8(xi) = { h_0, h_0w_8, h_0w_8^2, h_0w_8^3, h_0w_8^4, h_0w_8^5, h_0w_8^6, h_0w_8^7 } + uint16 constant pH0w8_0 = 224; + uint16 constant pH0w8_1 = 256; + uint16 constant pH0w8_2 = 288; + uint16 constant pH0w8_3 = 320; + uint16 constant pH0w8_4 = 352; + uint16 constant pH0w8_5 = 384; + uint16 constant pH0w8_6 = 416; + uint16 constant pH0w8_7 = 448; + + // S_1 = roots_4(xi) = { h_1, h_1w_4, h_1w_4^2, h_1w_4^3 } + uint16 constant pH1w4_0 = 480; + uint16 constant pH1w4_1 = 512; + uint16 constant pH1w4_2 = 544; + uint16 constant pH1w4_3 = 576; + + // S_2 = roots_3(xi) U roots_3(xi omega) + // roots_3(xi) = { h_2, h_2w_3, h_2w_3^2 } + uint16 constant pH2w3_0 = 608; + uint16 constant pH2w3_1 = 640; + uint16 constant pH2w3_2 = 672; + // roots_3(xi omega) = { h_3, h_3w_3, h_3w_3^2 } + uint16 constant pH3w3_0 = 704; + uint16 constant pH3w3_1 = 736; + uint16 constant pH3w3_2 = 768; + + uint16 constant pPi = 800; // PI(xi) + uint16 constant pR0 = 832; // r0(y) + uint16 constant pR1 = 864; // r1(y) + uint16 constant pR2 = 896; // r2(y) + + uint16 constant pF = 928; // [F]_1, 64 bytes + uint16 constant pE = 992; // [E]_1, 64 bytes + uint16 constant pJ = 1056; // [J]_1, 64 bytes + + uint16 constant pZh = 1184; // Z_H(xi) + // From this point we write all the variables that must be computed using the Montgomery batch inversion + uint16 constant pZhInv = 1216; // 1/Z_H(xi) + uint16 constant pDenH1 = 1248; // 1/( (y-h_1w_4) (y-h_1w_4^2) (y-h_1w_4^3) (y-h_1w_4^4) ) + uint16 constant pDenH2 = 1280; // 1/( (y-h_2w_3) (y-h_2w_3^2) (y-h_2w_3^3) (y-h_3w_3) (y-h_3w_3^2) (y-h_3w_3^3) ) + uint16 constant pLiS0Inv = 1312; // Reserve 8 * 32 bytes to compute r_0(X) + uint16 constant pLiS1Inv = 1568; // Reserve 4 * 32 bytes to compute r_1(X) + uint16 constant pLiS2Inv = 1696; // Reserve 6 * 32 bytes to compute r_2(X) + // Lagrange evaluations + + uint16 constant pEval_l1 = 1888; + + uint16 constant lastMem = 1920; + + function verifyProof( + bytes32[24] calldata proof, + uint256[1] calldata pubSignals + ) public view returns (bool) { + assembly { + // Computes the inverse of an array of values + // See https://vitalik.ca/general/2018/07/21/starks_part_3.html in section where explain fields operations + // To save the inverse to be computed on chain the prover sends the inverse as an evaluation in commits.eval_inv + function inverseArray(pMem) { + let pAux := mload(0x40) // Point to the next free position + let acc := mload(add(pMem, pZhInv)) // Read the first element + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pDenH1)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pDenH2)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pLiS0Inv)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 32))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 64))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 96))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 128))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 160))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 192))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 224))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pLiS1Inv)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 32))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 64))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 96))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pLiS2Inv)), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 32))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 64))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 96))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 128))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 160))), q) + mstore(pAux, acc) + + pAux := add(pAux, 32) + acc := mulmod(acc, mload(add(pMem, pEval_l1)), q) + mstore(pAux, acc) + + let inv := calldataload(pEval_inv) + + // Before using the inverse sent by the prover the verifier checks inv(batch) * batch === 1 + if iszero(eq(1, mulmod(acc, inv, q))) { + mstore(0, 0) + return(0, 0x20) + } + + acc := inv + + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pEval_l1)), q) + mstore(add(pMem, pEval_l1), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 160))), q) + mstore(add(pMem, add(pLiS2Inv, 160)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 128))), q) + mstore(add(pMem, add(pLiS2Inv, 128)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 96))), q) + mstore(add(pMem, add(pLiS2Inv, 96)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 64))), q) + mstore(add(pMem, add(pLiS2Inv, 64)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS2Inv, 32))), q) + mstore(add(pMem, add(pLiS2Inv, 32)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pLiS2Inv)), q) + mstore(add(pMem, pLiS2Inv), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 96))), q) + mstore(add(pMem, add(pLiS1Inv, 96)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 64))), q) + mstore(add(pMem, add(pLiS1Inv, 64)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS1Inv, 32))), q) + mstore(add(pMem, add(pLiS1Inv, 32)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pLiS1Inv)), q) + mstore(add(pMem, pLiS1Inv), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 224))), q) + mstore(add(pMem, add(pLiS0Inv, 224)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 192))), q) + mstore(add(pMem, add(pLiS0Inv, 192)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 160))), q) + mstore(add(pMem, add(pLiS0Inv, 160)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 128))), q) + mstore(add(pMem, add(pLiS0Inv, 128)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 96))), q) + mstore(add(pMem, add(pLiS0Inv, 96)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 64))), q) + mstore(add(pMem, add(pLiS0Inv, 64)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, add(pLiS0Inv, 32))), q) + mstore(add(pMem, add(pLiS0Inv, 32)), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pLiS0Inv)), q) + mstore(add(pMem, pLiS0Inv), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pDenH2)), q) + mstore(add(pMem, pDenH2), inv) + pAux := sub(pAux, 32) + inv := mulmod(acc, mload(pAux), q) + acc := mulmod(acc, mload(add(pMem, pDenH1)), q) + mstore(add(pMem, pDenH1), inv) + + mstore(add(pMem, pZhInv), acc) + } + + function checkField(v) { + if iszero(lt(v, q)) { + mstore(0, 0) + return(0, 0x20) + } + } + + function checkPointBelongsToBN128Curve(p) { + let x := calldataload(p) + let y := calldataload(add(p, 32)) + + // Check that the point is on the curve + // y^2 = x^3 + 3 + let x3_3 := addmod(mulmod(x, mulmod(x, x, qf), qf), 3, qf) + let y2 := mulmod(y, y, qf) + + if iszero(eq(x3_3, y2)) { + mstore(0, 0) + return(0, 0x20) + } + } + + // Validate all the evaluations sent by the prover ∈ F + function checkInput() { + // Check proof commitments fullfill bn128 curve equation Y^2 = X^3 + 3 + checkPointBelongsToBN128Curve(pC1) + checkPointBelongsToBN128Curve(pC2) + checkPointBelongsToBN128Curve(pW1) + checkPointBelongsToBN128Curve(pW2) + + checkField(calldataload(pEval_ql)) + checkField(calldataload(pEval_qr)) + checkField(calldataload(pEval_qm)) + checkField(calldataload(pEval_qo)) + checkField(calldataload(pEval_qc)) + checkField(calldataload(pEval_s1)) + checkField(calldataload(pEval_s2)) + checkField(calldataload(pEval_s3)) + checkField(calldataload(pEval_a)) + checkField(calldataload(pEval_b)) + checkField(calldataload(pEval_c)) + checkField(calldataload(pEval_z)) + checkField(calldataload(pEval_zw)) + checkField(calldataload(pEval_t1w)) + checkField(calldataload(pEval_t2w)) + checkField(calldataload(pEval_inv)) + + // Points are checked in the point operations precompiled smart contracts + } + + function computeChallenges(pMem, pPublic) { + // Compute challenge.beta & challenge.gamma + mstore(add(pMem, 1920), C0x) + mstore(add(pMem, 1952), C0y) + + mstore(add(pMem, 1984), calldataload(pPublic)) + + mstore(add(pMem, 2016), calldataload(pC1)) + mstore(add(pMem, 2048), calldataload(add(pC1, 32))) + + mstore( + add(pMem, pBeta), + mod(keccak256(add(pMem, lastMem), 160), q) + ) + mstore( + add(pMem, pGamma), + mod(keccak256(add(pMem, pBeta), 32), q) + ) + + // Get xiSeed & xiSeed2 + mstore(add(pMem, lastMem), mload(add(pMem, pGamma))) + mstore(add(pMem, 1952), calldataload(pC2)) + mstore(add(pMem, 1984), calldataload(add(pC2, 32))) + let xiSeed := mod(keccak256(add(pMem, lastMem), 96), q) + + mstore(add(pMem, pXiSeed), xiSeed) + mstore(add(pMem, pXiSeed2), mulmod(xiSeed, xiSeed, q)) + + // Compute roots.S0.h0w8 + mstore( + add(pMem, pH0w8_0), + mulmod( + mload(add(pMem, pXiSeed2)), + mload(add(pMem, pXiSeed)), + q + ) + ) + mstore( + add(pMem, pH0w8_1), + mulmod(mload(add(pMem, pH0w8_0)), w8_1, q) + ) + mstore( + add(pMem, pH0w8_2), + mulmod(mload(add(pMem, pH0w8_0)), w8_2, q) + ) + mstore( + add(pMem, pH0w8_3), + mulmod(mload(add(pMem, pH0w8_0)), w8_3, q) + ) + mstore( + add(pMem, pH0w8_4), + mulmod(mload(add(pMem, pH0w8_0)), w8_4, q) + ) + mstore( + add(pMem, pH0w8_5), + mulmod(mload(add(pMem, pH0w8_0)), w8_5, q) + ) + mstore( + add(pMem, pH0w8_6), + mulmod(mload(add(pMem, pH0w8_0)), w8_6, q) + ) + mstore( + add(pMem, pH0w8_7), + mulmod(mload(add(pMem, pH0w8_0)), w8_7, q) + ) + + // Compute roots.S1.h1w4 + mstore( + add(pMem, pH1w4_0), + mulmod( + mload(add(pMem, pH0w8_0)), + mload(add(pMem, pH0w8_0)), + q + ) + ) + mstore( + add(pMem, pH1w4_1), + mulmod(mload(add(pMem, pH1w4_0)), w4, q) + ) + mstore( + add(pMem, pH1w4_2), + mulmod(mload(add(pMem, pH1w4_0)), w4_2, q) + ) + mstore( + add(pMem, pH1w4_3), + mulmod(mload(add(pMem, pH1w4_0)), w4_3, q) + ) + + // Compute roots.S2.h2w3 + mstore( + add(pMem, pH2w3_0), + mulmod( + mload(add(pMem, pH1w4_0)), + mload(add(pMem, pXiSeed2)), + q + ) + ) + mstore( + add(pMem, pH2w3_1), + mulmod(mload(add(pMem, pH2w3_0)), w3, q) + ) + mstore( + add(pMem, pH2w3_2), + mulmod(mload(add(pMem, pH2w3_0)), w3_2, q) + ) + + // Compute roots.S2.h2w3 + mstore( + add(pMem, pH3w3_0), + mulmod(mload(add(pMem, pH2w3_0)), wr, q) + ) + mstore( + add(pMem, pH3w3_1), + mulmod(mload(add(pMem, pH3w3_0)), w3, q) + ) + mstore( + add(pMem, pH3w3_2), + mulmod(mload(add(pMem, pH3w3_0)), w3_2, q) + ) + + let xin := mulmod( + mulmod( + mload(add(pMem, pH2w3_0)), + mload(add(pMem, pH2w3_0)), + q + ), + mload(add(pMem, pH2w3_0)), + q + ) + mstore(add(pMem, pXi), xin) + + // Compute xi^n + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mulmod(xin, xin, q) + + xin := mod(add(sub(xin, 1), q), q) + mstore(add(pMem, pZh), xin) + mstore(add(pMem, pZhInv), xin) // We will invert later together with lagrange pols + + // Compute challenge.alpha + mstore(add(pMem, lastMem), xiSeed) + + calldatacopy(add(pMem, 1952), pEval_ql, 480) + mstore( + add(pMem, pAlpha), + mod(keccak256(add(pMem, lastMem), 512), q) + ) + + // Compute challenge.y + mstore(add(pMem, lastMem), mload(add(pMem, pAlpha))) + mstore(add(pMem, 1952), calldataload(pW1)) + mstore(add(pMem, 1984), calldataload(add(pW1, 32))) + mstore(add(pMem, pY), mod(keccak256(add(pMem, lastMem), 96), q)) + } + + function computeLiS0(pMem) { + let root0 := mload(add(pMem, pH0w8_0)) + let y := mload(add(pMem, pY)) + let den1 := 1 + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + + den1 := mulmod(8, den1, q) + + let den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 0), 8), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 1), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 2), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 3), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(3, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 4), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(4, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 128)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 5), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(5, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 160)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 6), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(6, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 192)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH0w8_0, mul(mod(mul(7, 7), 8), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH0w8_0, mul(7, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS0Inv, 224)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + } + + function computeLiS1(pMem) { + let root0 := mload(add(pMem, pH1w4_0)) + let y := mload(add(pMem, pY)) + let den1 := 1 + den1 := mulmod(den1, root0, q) + den1 := mulmod(den1, root0, q) + + den1 := mulmod(4, den1, q) + + let den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 0), 4), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 1), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 2), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH1w4_0, mul(mod(mul(3, 3), 4), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH1w4_0, mul(3, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS1Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + } + + function computeLiS2(pMem) { + let y := mload(add(pMem, pY)) + + let den1 := mulmod( + mulmod(3, mload(add(pMem, pH2w3_0)), q), + addmod( + mload(add(pMem, pXi)), + mod(sub(q, mulmod(mload(add(pMem, pXi)), w1, q)), q), + q + ), + q + ) + + let den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 0), 3), 32))) + ) + let den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 0)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 1), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 32)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH2w3_0, mul(mod(mul(2, 2), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH2w3_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 64)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den1 := mulmod( + mulmod(3, mload(add(pMem, pH3w3_0)), q), + addmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mod(sub(q, mload(add(pMem, pXi))), q), + q + ), + q + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 0), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(0, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 96)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 1), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(1, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 128)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + + den2 := mload( + add(pMem, add(pH3w3_0, mul(mod(mul(2, 2), 3), 32))) + ) + den3 := addmod( + y, + mod(sub(q, mload(add(pMem, add(pH3w3_0, mul(2, 32))))), q), + q + ) + + mstore( + add(pMem, add(pLiS2Inv, 160)), + mulmod(den1, mulmod(den2, den3, q), q) + ) + } + + // Prepare all the denominators that must be inverted, placed them in consecutive memory addresses + function computeInversions(pMem) { + // 1/ZH(xi) used in steps 8 and 9 of the verifier to multiply by 1/Z_H(xi) + // Value computed during computeChallenges function and stores in pMem+pZhInv + + // 1/((y - h1) (y - h1w4) (y - h1w4_2) (y - h1w4_3)) + // used in steps 10 and 11 of the verifier + let y := mload(add(pMem, pY)) + let w := addmod(y, mod(sub(q, mload(add(pMem, pH1w4_0))), q), q) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_2))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH1w4_3))), q), q), + q + ) + mstore(add(pMem, pDenH1), w) + + // 1/((y - h2) (y - h2w3) (y - h2w3_2) (y - h3) (y - h3w3) (y - h3w3_2)) + w := addmod(y, mod(sub(q, mload(add(pMem, pH2w3_0))), q), q) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH2w3_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH2w3_2))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_0))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_1))), q), q), + q + ) + w := mulmod( + w, + addmod(y, mod(sub(q, mload(add(pMem, pH3w3_2))), q), q), + q + ) + mstore(add(pMem, pDenH2), w) + + // Denominator needed in the verifier when computing L_i^{S0}(X) + computeLiS0(pMem) + + // Denominator needed in the verifier when computing L_i^{S1}(X) + computeLiS1(pMem) + + // Denominator needed in the verifier when computing L_i^{S2}(X) + computeLiS2(pMem) + + // L_i where i from 1 to num public inputs, needed in step 6 and 7 of the verifier to compute L_1(xi) and PI(xi) + w := 1 + let xi := mload(add(pMem, pXi)) + + mstore( + add(pMem, pEval_l1), + mulmod(n, mod(add(sub(xi, w), q), q), q) + ) + + // Execute Montgomery batched inversions of the previous prepared values + inverseArray(pMem) + } + + // Compute Lagrange polynomial evaluation L_i(xi) + function computeLagrange(pMem) { + let zh := mload(add(pMem, pZh)) + let w := 1 + + mstore( + add(pMem, pEval_l1), + mulmod(mload(add(pMem, pEval_l1)), zh, q) + ) + } + + // Compute public input polynomial evaluation PI(xi) + function computePi(pMem, pPub) { + let pi := 0 + pi := mod( + add( + sub( + pi, + mulmod( + mload(add(pMem, pEval_l1)), + calldataload(pPub), + q + ) + ), + q + ), + q + ) + + mstore(add(pMem, pPi), pi) + } + + // Compute r0(y) by interpolating the polynomial r0(X) using 8 points (x,y) + // where x = {h9, h0w8, h0w8^2, h0w8^3, h0w8^4, h0w8^5, h0w8^6, h0w8^7} + // and y = {C0(h0), C0(h0w8), C0(h0w8^2), C0(h0w8^3), C0(h0w8^4), C0(h0w8^5), C0(h0w8^6), C0(h0w8^7)} + // and computing C0(xi) + function computeR0(pMem) { + let num := 1 + let y := mload(add(pMem, pY)) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + + num := addmod(num, mod(sub(q, mload(add(pMem, pXi))), q), q) + + let res + let h0w80 + let c0Value + let h0w8i + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_0)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 0))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_1)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 32))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_2)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 64))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_3)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 96))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_4)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 128))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_5)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 160))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_6)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 192))), q), + q + ), + q + ) + + // Compute c0Value = ql + (h0w8i) qr + (h0w8i)^2 qo + (h0w8i)^3 qm + (h0w8i)^4 qc + + // + (h0w8i)^5 S1 + (h0w8i)^6 S2 + (h0w8i)^7 S3 + h0w80 := mload(add(pMem, pH0w8_7)) + c0Value := addmod( + calldataload(pEval_ql), + mulmod(calldataload(pEval_qr), h0w80, q), + q + ) + h0w8i := mulmod(h0w80, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qo), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qm), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_qc), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s1), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s2), h0w8i, q), + q + ) + h0w8i := mulmod(h0w8i, h0w80, q) + c0Value := addmod( + c0Value, + mulmod(calldataload(pEval_s3), h0w8i, q), + q + ) + + res := addmod( + res, + mulmod( + c0Value, + mulmod(num, mload(add(pMem, add(pLiS0Inv, 224))), q), + q + ), + q + ) + + mstore(add(pMem, pR0), res) + } + + // Compute r1(y) by interpolating the polynomial r1(X) using 4 points (x,y) + // where x = {h1, h1w4, h1w4^2, h1w4^3} + // and y = {C1(h1), C1(h1w4), C1(h1w4^2), C1(h1w4^3)} + // and computing T0(xi) + function computeR1(pMem) { + let num := 1 + let y := mload(add(pMem, pY)) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + num := mulmod(num, y, q) + + num := addmod(num, mod(sub(q, mload(add(pMem, pXi))), q), q) + + let t0 + let evalA := calldataload(pEval_a) + let evalB := calldataload(pEval_b) + let evalC := calldataload(pEval_c) + + t0 := mulmod(calldataload(pEval_ql), evalA, q) + t0 := addmod(t0, mulmod(calldataload(pEval_qr), evalB, q), q) + t0 := addmod( + t0, + mulmod(calldataload(pEval_qm), mulmod(evalA, evalB, q), q), + q + ) + t0 := addmod(t0, mulmod(calldataload(pEval_qo), evalC, q), q) + t0 := addmod(t0, calldataload(pEval_qc), q) + t0 := addmod(t0, mload(add(pMem, pPi)), q) + t0 := mulmod(t0, mload(add(pMem, pZhInv)), q) + + let res + let c1Value + let h1w4 + let square + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_0)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(0, 32)))), + q + ), + q + ), + q + ) + + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_1)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(1, 32)))), + q + ), + q + ), + q + ) + + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_2)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(2, 32)))), + q + ), + q + ), + q + ) + + c1Value := evalA + h1w4 := mload(add(pMem, pH1w4_3)) + + c1Value := addmod(c1Value, mulmod(h1w4, evalB, q), q) + square := mulmod(h1w4, h1w4, q) + c1Value := addmod(c1Value, mulmod(square, evalC, q), q) + c1Value := addmod( + c1Value, + mulmod(mulmod(square, h1w4, q), t0, q), + q + ) + + res := addmod( + res, + mulmod( + c1Value, + mulmod( + num, + mload(add(pMem, add(pLiS1Inv, mul(3, 32)))), + q + ), + q + ), + q + ) + + mstore(add(pMem, pR1), res) + } + + // Compute r2(y) by interpolating the polynomial r2(X) using 6 points (x,y) + // where x = {[h2, h2w3, h2w3^2], [h3, h3w3, h3w3^2]} + // and y = {[C2(h2), C2(h2w3), C2(h2w3^2)], [C2(h3), C2(h3w3), C2(h3w3^2)]} + // and computing T1(xi) and T2(xi) + function computeR2(pMem) { + let y := mload(add(pMem, pY)) + let num := 1 + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + num := mulmod(y, num, q) + + let num2 := 1 + num2 := mulmod(y, num2, q) + num2 := mulmod(y, num2, q) + num2 := mulmod(y, num2, q) + num2 := mulmod( + num2, + addmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mload(add(pMem, pXi)), + q + ), + q + ) + + num := addmod(num, mod(sub(q, num2), q), q) + + num2 := mulmod( + mulmod(mload(add(pMem, pXi)), w1, q), + mload(add(pMem, pXi)), + q + ) + + num := addmod(num, num2, q) + + let t1 + let t2 + let betaXi := mulmod( + mload(add(pMem, pBeta)), + mload(add(pMem, pXi)), + q + ) + let gamma := mload(add(pMem, pGamma)) + + t2 := addmod(calldataload(pEval_a), addmod(betaXi, gamma, q), q) + t2 := mulmod( + t2, + addmod( + calldataload(pEval_b), + addmod(mulmod(betaXi, k1, q), gamma, q), + q + ), + q + ) + t2 := mulmod( + t2, + addmod( + calldataload(pEval_c), + addmod(mulmod(betaXi, k2, q), gamma, q), + q + ), + q + ) + t2 := mulmod(t2, calldataload(pEval_z), q) + + //Let's use t1 as a temporal variable to save one local + t1 := addmod( + calldataload(pEval_a), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s1), + q + ), + gamma, + q + ), + q + ) + t1 := mulmod( + t1, + addmod( + calldataload(pEval_b), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s2), + q + ), + gamma, + q + ), + q + ), + q + ) + t1 := mulmod( + t1, + addmod( + calldataload(pEval_c), + addmod( + mulmod( + mload(add(pMem, pBeta)), + calldataload(pEval_s3), + q + ), + gamma, + q + ), + q + ), + q + ) + t1 := mulmod(t1, calldataload(pEval_zw), q) + + t2 := addmod(t2, mod(sub(q, t1), q), q) + t2 := mulmod(t2, mload(add(pMem, pZhInv)), q) + + // Compute T1(xi) + t1 := sub(calldataload(pEval_z), 1) + t1 := mulmod(t1, mload(add(pMem, pEval_l1)), q) + t1 := mulmod(t1, mload(add(pMem, pZhInv)), q) + + // Let's use local variable gamma to save the result + gamma := 0 + + let hw + let c2Value + + hw := mload(add(pMem, pH2w3_0)) + c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) + c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(0, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH2w3_1)) + c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) + c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(1, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH2w3_2)) + c2Value := addmod(calldataload(pEval_z), mulmod(hw, t1, q), q) + c2Value := addmod(c2Value, mulmod(mulmod(hw, hw, q), t2, q), q) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(2, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH3w3_0)) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(3, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH3w3_1)) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(4, 32)))), + q + ), + q + ), + q + ) + + hw := mload(add(pMem, pH3w3_2)) + c2Value := addmod( + calldataload(pEval_zw), + mulmod(hw, calldataload(pEval_t1w), q), + q + ) + c2Value := addmod( + c2Value, + mulmod(mulmod(hw, hw, q), calldataload(pEval_t2w), q), + q + ) + gamma := addmod( + gamma, + mulmod( + c2Value, + mulmod( + num, + mload(add(pMem, add(pLiS2Inv, mul(5, 32)))), + q + ), + q + ), + q + ) + + mstore(add(pMem, pR2), gamma) + } + + // G1 function to accumulate a G1 value to an address + function g1_acc(pR, pP) { + let mIn := mload(0x40) + mstore(mIn, mload(pR)) + mstore(add(mIn, 32), mload(add(pR, 32))) + mstore(add(mIn, 64), mload(pP)) + mstore(add(mIn, 96), mload(add(pP, 32))) + + let success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value to value in an address + function g1_mulAcc(pR, pP, s) { + let success + let mIn := mload(0x40) + mstore(mIn, calldataload(pP)) + mstore(add(mIn, 32), calldataload(add(pP, 32))) + mstore(add(mIn, 64), s) + + success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + + mstore(add(mIn, 64), mload(pR)) + mstore(add(mIn, 96), mload(add(pR, 32))) + + success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value(x,y) to value in an address + function g1_mulAccC(pR, x, y, s) { + let success + let mIn := mload(0x40) + mstore(mIn, x) + mstore(add(mIn, 32), y) + mstore(add(mIn, 64), s) + + success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + + mstore(add(mIn, 64), mload(pR)) + mstore(add(mIn, 96), mload(add(pR, 32))) + + success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + function computeFEJ(pMem) { + // Prepare shared numerator between F, E and J to reuse it + let y := mload(add(pMem, pY)) + let numerator := addmod( + y, + mod(sub(q, mload(add(pMem, pH0w8_0))), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_1))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_2))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_3))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_4))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_5))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_6))), q), q), + q + ) + numerator := mulmod( + numerator, + addmod(y, mod(sub(q, mload(add(pMem, pH0w8_7))), q), q), + q + ) + + // Prepare shared quotient between F and E to reuse it + let quotient1 := mulmod( + mload(add(pMem, pAlpha)), + mulmod(numerator, mload(add(pMem, pDenH1)), q), + q + ) + let quotient2 := mulmod( + mulmod( + mload(add(pMem, pAlpha)), + mload(add(pMem, pAlpha)), + q + ), + mulmod(numerator, mload(add(pMem, pDenH2)), q), + q + ) + + // Compute full batched polynomial commitment [F]_1 + mstore(add(pMem, pF), C0x) + mstore(add(pMem, add(pF, 32)), C0y) + g1_mulAcc(add(pMem, pF), pC1, quotient1) + g1_mulAcc(add(pMem, pF), pC2, quotient2) + + // Compute group-encoded batch evaluation [E]_1 + g1_mulAccC( + add(pMem, pE), + G1x, + G1y, + addmod( + mload(add(pMem, pR0)), + addmod( + mulmod(quotient1, mload(add(pMem, pR1)), q), + mulmod(quotient2, mload(add(pMem, pR2)), q), + q + ), + q + ) + ) + + // Compute the full difference [J]_1 + g1_mulAcc(add(pMem, pJ), pW1, numerator) + } + + // Validate all evaluations with a pairing checking that e([F]_1 - [E]_1 - [J]_1 + y[W2]_1, [1]_2) == e([W']_1, [x]_2) + function checkPairing(pMem) -> isOk { + let mIn := mload(0x40) + + // First pairing value + // Compute -E + mstore( + add(add(pMem, pE), 32), + mod(sub(qf, mload(add(add(pMem, pE), 32))), qf) + ) + // Compute -J + mstore( + add(add(pMem, pJ), 32), + mod(sub(qf, mload(add(add(pMem, pJ), 32))), qf) + ) + // F = F - E - J + y·W2 + g1_acc(add(pMem, pF), add(pMem, pE)) + g1_acc(add(pMem, pF), add(pMem, pJ)) + g1_mulAcc(add(pMem, pF), pW2, mload(add(pMem, pY))) + + mstore(mIn, mload(add(pMem, pF))) + mstore(add(mIn, 32), mload(add(add(pMem, pF), 32))) + + // Second pairing value + mstore(add(mIn, 64), G2x2) + mstore(add(mIn, 96), G2x1) + mstore(add(mIn, 128), G2y2) + mstore(add(mIn, 160), G2y1) + + // Third pairing value + // Compute -W2 + mstore(add(mIn, 192), calldataload(pW2)) + let s := calldataload(add(pW2, 32)) + s := mod(sub(qf, s), qf) + mstore(add(mIn, 224), s) + + // Fourth pairing value + mstore(add(mIn, 256), X2x2) + mstore(add(mIn, 288), X2x1) + mstore(add(mIn, 320), X2y2) + mstore(add(mIn, 352), X2y1) + + let success := staticcall( + sub(gas(), 2000), + 8, + mIn, + 384, + mIn, + 0x20 + ) + + isOk := and(success, mload(mIn)) + } + + let pMem := mload(0x40) + mstore(0x40, add(pMem, lastMem)) + + // Validate that all evaluations ∈ F + checkInput() + + // Compute the challenges: beta, gamma, xi, alpha and y ∈ F, h1w4/h2w3/h3w3 roots, xiN and zh(xi) + computeChallenges(pMem, pubSignals) + + // To divide prime fields the Extended Euclidean Algorithm for computing modular inverses is needed. + // The Montgomery batch inversion algorithm allow us to compute n inverses reducing to a single one inversion. + // More info: https://vitalik.ca/general/2018/07/21/starks_part_3.html + // To avoid this single inverse computation on-chain, it has been computed in proving time and send it to the verifier. + // Therefore, the verifier: + // 1) Prepare all the denominators to inverse + // 2) Check the inverse sent by the prover it is what it should be + // 3) Compute the others inverses using the Montgomery Batched Algorithm using the inverse sent to avoid the inversion operation it does. + computeInversions(pMem) + + // Compute Lagrange polynomial evaluations Li(xi) + computeLagrange(pMem) + + // Compute public input polynomial evaluation PI(xi) = \sum_i^l -public_input_i·L_i(xi) + computePi(pMem, pubSignals) + + // Computes r1(y) and r2(y) + computeR0(pMem) + computeR1(pMem) + computeR2(pMem) + + // Compute full batched polynomial commitment [F]_1, group-encoded batch evaluation [E]_1 and the full difference [J]_1 + computeFEJ(pMem) + + // Validate all evaluations + let isValid := checkPairing(pMem) + + mstore(0, isValid) + return(0, 0x20) + } + } +} diff --git a/deployment/v2/create_rollup_parameters.json.example b/deployment/v2/create_rollup_parameters.json.example index 1693f4f87..57ddf47f9 100644 --- a/deployment/v2/create_rollup_parameters.json.example +++ b/deployment/v2/create_rollup_parameters.json.example @@ -6,7 +6,7 @@ "trustedSequencer":"0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", "chainID": 1001, "adminZkEVM":"0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", - "forkID": 11, + "forkID": 12, "consensusContract": "PolygonZkEVMEtrog", "gasTokenAddress":"", "deployerPvtKey": "", diff --git a/tools/addRollupType/.gitignore b/tools/addRollupType/.gitignore index a3f141a85..a7ca529c6 100644 --- a/tools/addRollupType/.gitignore +++ b/tools/addRollupType/.gitignore @@ -1,2 +1,3 @@ -add_rollup_type_output.json +add_rollup_type_output-*.json +add_rollup_type.json genesis.json \ No newline at end of file diff --git a/tools/addRollupType/addRollupType.ts b/tools/addRollupType/addRollupType.ts index 422b36a6f..abd52b434 100644 --- a/tools/addRollupType/addRollupType.ts +++ b/tools/addRollupType/addRollupType.ts @@ -31,7 +31,7 @@ async function main() { "polygonRollupManagerAddress", "verifierAddress", "rollupCompatibilityID", - "genesisRoot" + "genesisRoot", ]; for (const parameterName of mandatoryDeploymentParameters) { @@ -47,7 +47,7 @@ async function main() { consensusContract, polygonRollupManagerAddress, verifierAddress, - genesisRoot + genesisRoot, } = addRollupParameters; const supportedConensus = ["PolygonZkEVMEtrog", "PolygonValidiumEtrog"]; @@ -117,21 +117,19 @@ async function main() { // Sanity checks genesisRoot if (genesisRoot !== genesis.root) { - throw new Error( - `Genesis root in the 'add_rollup_type.json' does not match the root in the 'genesis.json'` - ); + throw new Error(`Genesis root in the 'add_rollup_type.json' does not match the root in the 'genesis.json'`); } // get bridge address in genesis file - let genesisBridgeAddress = ethers.constants.AddresZero; + let genesisBridgeAddress = ethers.ZeroAddress; for (let i = 0; i < genesis.genesis.lenght; i++) { - if (genesis.genesis[i].contractName === 'PolygonZkEVMBridge proxy') { + if (genesis.genesis[i].contractName === "PolygonZkEVMBridge proxy") { genesisBridgeAddress = genesis.genesis[i].address; break; } } - if (polygonZkEVMBridgeAddress.toLowerCase() !== genesisBridgeAddress ) { + if (polygonZkEVMBridgeAddress.toLowerCase() !== genesisBridgeAddress.toLowerCase()) { throw new Error( `'PolygonZkEVMBridge proxy' root in the 'genesis.json' does not match 'bridgeAddress' in the 'PolygonRollupManager'` ); @@ -155,7 +153,10 @@ async function main() { // Create consensus implementation if needed let polygonConsensusContractAddress; - if (typeof addRollupParameters.polygonconsensusContract !== 'undefined' && ethers.isAddress(addRollupParameters.polygonconsensusContract)) { + if ( + typeof addRollupParameters.polygonconsensusContract !== "undefined" && + ethers.isAddress(addRollupParameters.polygonconsensusContract) + ) { polygonConsensusContractAddress = addRollupParameters.polygonconsensusContract; } else { const PolygonconsensusFactory = (await ethers.getContractFactory(consensusContract, deployer)) as any; @@ -210,7 +211,6 @@ async function main() { outputJson.rollupTypeID = newRollupTypeID; // add time to output path - const dateStr = new Date().toISOString(); fs.writeFileSync(pathOutputJson, JSON.stringify(outputJson, null, 1)); } diff --git a/tools/deployVerifier/deployVerifier.ts b/tools/deployVerifier/deployVerifier.ts index 2c0d37d37..89a1eecbb 100644 --- a/tools/deployVerifier/deployVerifier.ts +++ b/tools/deployVerifier/deployVerifier.ts @@ -61,7 +61,7 @@ async function main() { /* * Deployment Verifier */ - const verifierName = `FflonkVerifier`; + const verifierName = `FflonkVerifier_${deployParameters.forkID}`; let verifierContract; if (deployParameters.realVerifier === true) { const VerifierRollup = await ethers.getContractFactory(verifierName, deployer); diff --git a/tools/deployVerifier/deploy_verifier_parameters.example b/tools/deployVerifier/deploy_verifier_parameters.example index 82d313e24..a15b9852b 100644 --- a/tools/deployVerifier/deploy_verifier_parameters.example +++ b/tools/deployVerifier/deploy_verifier_parameters.example @@ -1,5 +1,6 @@ { "realVerifier": true, + "forkID": 12, "deployerPvtKey": "", "maxFeePerGas":"", "maxPriorityFeePerGas":"", diff --git a/tools/updateRollup/.gitignore b/tools/updateRollup/.gitignore new file mode 100644 index 000000000..f9604b070 --- /dev/null +++ b/tools/updateRollup/.gitignore @@ -0,0 +1,2 @@ +updateRollupOutput-*.json +updateRollup.json \ No newline at end of file diff --git a/tools/updateRollup/README.md b/tools/updateRollup/README.md new file mode 100644 index 000000000..13193ff25 --- /dev/null +++ b/tools/updateRollup/README.md @@ -0,0 +1,61 @@ +# Update rollup +Script to deploy call `updateRollup` function in the `PolygonRollupManager.sol` smart contract + +## Install +``` +npm i +``` + +## Setup +- Config file + - `rollupAddress`: rollup address of the rollup that is going to be updated + - `newRollupTypeID`: select which is the `rollupTypeID` to upgrade + - `upgradeData`: data necessary to perform the upgrade (default to `0x`) + - `polygonRollupManagerAddress`: `PolygonRollupManager.sol` SC address + - `timelockDelay (optional)`: at least it should be the minimum delay of the timelock smart contract + - `deployerPvtKey`: private key deployer + - First option will load `deployerPvtKey`. Otherwise, `process.env.MNEMONIC` will be loaded from the `.env` file + - `maxFeePerGas`: set custom gas + - `maxPriorityFeePerGas`: set custom gas + - `multiplierGas`: set custom gas +- A network should be selected when running the script + - examples: `-- sepolia` or `--mainnet` + - This uses variables set in `hardhat.config.ts` + - Which uses some environment variables that should be set in `.env` +> All paths are from root repository + +## Usage +> All commands are done from root repository. + +### Call 'addNewRollupType' from an EOA +- Copy configuration file: +``` +cp ./tools/updateRollup/updateRollup.json.example ./tools/updateRollup/updateRollup.json +``` + +- Set your parameters +- Run tool: +- Standrad transaction: +``` +npx hardhat run ./tools/updateRollup/updateRollup.ts --network sepolia +``` + +### Generate 'updateRollup' data to the Timelock SC + +- Copy configuration file: +``` +cp ./tools/updateRollup/updateRollup.json.example ./tools/updateRollup/updateRollup.json +``` + +- Set your parameters +- Run tool: +``` +npx hardhat run ./tools/updateRollup/updateRollupTimelock.ts --network sepolia +``` +- Output: + - scheduleData + - executeData +> send data to the timelock contract address: +> - use your favourite browser extension +> - send tx to timelock address with hex data as `scheduleData` +> - wait `timelockDelay` and then send `executeData` to timelock address diff --git a/tools/updateRollup/updateRollup.ts b/tools/updateRollup/updateRollup.ts index efb7746be..a4fb86381 100644 --- a/tools/updateRollup/updateRollup.ts +++ b/tools/updateRollup/updateRollup.ts @@ -6,11 +6,13 @@ import fs = require("fs"); import * as dotenv from "dotenv"; dotenv.config({path: path.resolve(__dirname, "../../.env")}); -import {ethers} from "hardhat"; +import {ethers, network} from "hardhat"; const addRollupParameters = require("./updateRollup.json"); -const pathOutputJson = path.join(__dirname, "./updateRollupOutput.json"); +const dateStr = new Date().toISOString(); +const pathOutputJson = path.join(__dirname, `./updateRollupOutput-${dateStr}.json`); +import {PolygonRollupManager} from "../../typechain-types"; import "../../deployment/helpers/utils"; async function main() { @@ -25,7 +27,6 @@ async function main() { "newRollupTypeID", "upgradeData", "polygonRollupManagerAddress", - "timelockDelay", ]; for (const parameterName of mandatoryDeploymentParameters) { @@ -34,10 +35,7 @@ async function main() { } } - const {rollupAddress, newRollupTypeID, upgradeData, polygonRollupManagerAddress, timelockDelay} = - addRollupParameters; - - const salt = addRollupParameters.timelockSalt || ethers.ZeroHash; + const {rollupAddress, newRollupTypeID, upgradeData, polygonRollupManagerAddress} = addRollupParameters; // Load provider let currentProvider = ethers.provider; @@ -87,75 +85,30 @@ async function main() { console.log("Using with: ", deployer.address); - // load timelock - const timelockContractFactory = await ethers.getContractFactory("PolygonZkEVMTimelock", deployer); - // Load Rollup manager const PolgonRollupManagerFactory = await ethers.getContractFactory("PolygonRollupManager", deployer); + const rollupManagerContract = PolgonRollupManagerFactory.attach( + polygonRollupManagerAddress + ) as PolygonRollupManager; - const operation = genOperation( - polygonRollupManagerAddress, - 0, // value - PolgonRollupManagerFactory.interface.encodeFunctionData("updateRollup", [ - rollupAddress, - newRollupTypeID, - upgradeData, - ]), - ethers.ZeroHash, // predecesoor - salt // salt - ); - - // Schedule operation - const scheduleData = timelockContractFactory.interface.encodeFunctionData("schedule", [ - operation.target, - operation.value, - operation.data, - operation.predecessor, - operation.salt, - timelockDelay, - ]); - // Execute operation - const executeData = timelockContractFactory.interface.encodeFunctionData("execute", [ - operation.target, - operation.value, - operation.data, - operation.predecessor, - operation.salt, - ]); - - console.log({scheduleData}); - console.log({executeData}); - - outputJson.scheduleData = scheduleData; - outputJson.executeData = executeData; - - // Decode the scheduleData for better readibility - const timelockTx = timelockContractFactory.interface.parseTransaction({data: scheduleData}); - const paramsArray = timelockTx?.fragment.inputs; - const objectDecoded = {}; - - for (let i = 0; i < paramsArray?.length; i++) { - const currentParam = paramsArray[i]; - - objectDecoded[currentParam.name] = timelockTx?.args[i]; - - if (currentParam.name == "data") { - const decodedRollupManagerData = PolgonRollupManagerFactory.interface.parseTransaction({ - data: timelockTx?.args[i], - }); - const objectDecodedData = {}; - const paramsArrayData = decodedRollupManagerData?.fragment.inputs; - - for (let j = 0; j < paramsArrayData?.length; j++) { - const currentParam = paramsArrayData[j]; - objectDecodedData[currentParam.name] = decodedRollupManagerData?.args[j]; - } - objectDecoded["decodedData"] = objectDecodedData; - } + // Check role + const UPDATE_ROLLUP_ROLE = ethers.id("UPDATE_ROLLUP_ROLE"); + + if ((await rollupManagerContract.hasRole(UPDATE_ROLLUP_ROLE, deployer.address)) == false) { + // log that address ha sno role + throw new Error(`Address ${deployer.address} does not have the UPDATE_ROLLUP_ROLE role`); } - outputJson.decodedScheduleData = objectDecoded; + // Add a new rollup type with timelock + console.log(await (await rollupManagerContract.updateRollup(rollupAddress, newRollupTypeID, upgradeData)).wait()); + + outputJson.networkName = network.name; + outputJson.polygonRollupManagerAddress = polygonRollupManagerAddress; + outputJson.rollupAddress = rollupAddress; + outputJson.newRollupTypeID = newRollupTypeID; + outputJson.upgradeData = upgradeData; + // add time to output path fs.writeFileSync(pathOutputJson, JSON.stringify(outputJson, null, 1)); } @@ -163,20 +116,3 @@ main().catch((e) => { console.error(e); process.exit(1); }); - -// OZ test functions -function genOperation(target: any, value: any, data: any, predecessor: any, salt: any) { - const abiEncoded = ethers.AbiCoder.defaultAbiCoder().encode( - ["address", "uint256", "bytes", "uint256", "bytes32"], - [target, value, data, predecessor, salt] - ); - const id = ethers.keccak256(abiEncoded); - return { - id, - target, - value, - data, - predecessor, - salt, - }; -} diff --git a/tools/updateRollup/updateRollupTimelock.ts b/tools/updateRollup/updateRollupTimelock.ts new file mode 100644 index 000000000..e0f1eb301 --- /dev/null +++ b/tools/updateRollup/updateRollupTimelock.ts @@ -0,0 +1,184 @@ +/* eslint-disable no-await-in-loop, no-use-before-define, no-lonely-if */ +/* eslint-disable no-console, no-inner-declarations, no-undef, import/no-unresolved */ +import {expect} from "chai"; +import path = require("path"); +import fs = require("fs"); + +import * as dotenv from "dotenv"; +dotenv.config({path: path.resolve(__dirname, "../../.env")}); +import {ethers, network} from "hardhat"; + +const addRollupParameters = require("./updateRollup.json"); + +const dateStr = new Date().toISOString(); +const pathOutputJson = path.join(__dirname, `./updateRollupOutput-${dateStr}.json`); +import "../../deployment/helpers/utils"; + +async function main() { + const outputJson = {} as any; + + /* + * Check deploy parameters + * Check that every necessary parameter is fullfilled + */ + const mandatoryDeploymentParameters = [ + "rollupAddress", + "newRollupTypeID", + "upgradeData", + "polygonRollupManagerAddress", + "timelockDelay", + ]; + + for (const parameterName of mandatoryDeploymentParameters) { + if (addRollupParameters[parameterName] === undefined || addRollupParameters[parameterName] === "") { + throw new Error(`Missing parameter: ${parameterName}`); + } + } + + const {rollupAddress, newRollupTypeID, upgradeData, polygonRollupManagerAddress, timelockDelay} = + addRollupParameters; + + const salt = addRollupParameters.timelockSalt || ethers.ZeroHash; + + // Load provider + let currentProvider = ethers.provider; + if (addRollupParameters.multiplierGas || addRollupParameters.maxFeePerGas) { + if (process.env.HARDHAT_NETWORK !== "hardhat") { + currentProvider = ethers.getDefaultProvider( + `https://${process.env.HARDHAT_NETWORK}.infura.io/v3/${process.env.INFURA_PROJECT_ID}` + ) as any; + if (addRollupParameters.maxPriorityFeePerGas && addRollupParameters.maxFeePerGas) { + console.log( + `Hardcoded gas used: MaxPriority${addRollupParameters.maxPriorityFeePerGas} gwei, MaxFee${addRollupParameters.maxFeePerGas} gwei` + ); + const FEE_DATA = new ethers.FeeData( + null, + ethers.parseUnits(addRollupParameters.maxFeePerGas, "gwei"), + ethers.parseUnits(addRollupParameters.maxPriorityFeePerGas, "gwei") + ); + + currentProvider.getFeeData = async () => FEE_DATA; + } else { + console.log("Multiplier gas used: ", addRollupParameters.multiplierGas); + async function overrideFeeData() { + const feedata = await ethers.provider.getFeeData(); + return new ethers.FeeData( + null, + ((feedata.maxFeePerGas as bigint) * BigInt(addRollupParameters.multiplierGas)) / 1000n, + ((feedata.maxPriorityFeePerGas as bigint) * BigInt(addRollupParameters.multiplierGas)) / 1000n + ); + } + currentProvider.getFeeData = overrideFeeData; + } + } + } + + // Load deployer + let deployer; + if (addRollupParameters.deployerPvtKey) { + deployer = new ethers.Wallet(addRollupParameters.deployerPvtKey, currentProvider); + } else if (process.env.MNEMONIC) { + deployer = ethers.HDNodeWallet.fromMnemonic( + ethers.Mnemonic.fromPhrase(process.env.MNEMONIC), + "m/44'/60'/0'/0/0" + ).connect(currentProvider); + } else { + [deployer] = await ethers.getSigners(); + } + + console.log("Using with: ", deployer.address); + + // load timelock + const timelockContractFactory = await ethers.getContractFactory("PolygonZkEVMTimelock", deployer); + + // Load Rollup manager + const PolgonRollupManagerFactory = await ethers.getContractFactory("PolygonRollupManager", deployer); + + const operation = genOperation( + polygonRollupManagerAddress, + 0, // value + PolgonRollupManagerFactory.interface.encodeFunctionData("updateRollup", [ + rollupAddress, + newRollupTypeID, + upgradeData, + ]), + ethers.ZeroHash, // predecesoor + salt // salt + ); + + // Schedule operation + const scheduleData = timelockContractFactory.interface.encodeFunctionData("schedule", [ + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + timelockDelay, + ]); + // Execute operation + const executeData = timelockContractFactory.interface.encodeFunctionData("execute", [ + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + ]); + + console.log({scheduleData}); + console.log({executeData}); + + outputJson.networkName = network.name; + outputJson.scheduleData = scheduleData; + outputJson.executeData = executeData; + + // Decode the scheduleData for better readibility + const timelockTx = timelockContractFactory.interface.parseTransaction({data: scheduleData}); + const paramsArray = timelockTx?.fragment.inputs; + const objectDecoded = {}; + + for (let i = 0; i < paramsArray?.length; i++) { + const currentParam = paramsArray[i]; + + objectDecoded[currentParam.name] = timelockTx?.args[i]; + + if (currentParam.name == "data") { + const decodedRollupManagerData = PolgonRollupManagerFactory.interface.parseTransaction({ + data: timelockTx?.args[i], + }); + const objectDecodedData = {}; + const paramsArrayData = decodedRollupManagerData?.fragment.inputs; + + for (let j = 0; j < paramsArrayData?.length; j++) { + const currentParam = paramsArrayData[j]; + objectDecodedData[currentParam.name] = decodedRollupManagerData?.args[j]; + } + objectDecoded["decodedData"] = objectDecodedData; + } + } + + outputJson.decodedScheduleData = objectDecoded; + + fs.writeFileSync(pathOutputJson, JSON.stringify(outputJson, null, 1)); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); + +// OZ test functions +function genOperation(target: any, value: any, data: any, predecessor: any, salt: any) { + const abiEncoded = ethers.AbiCoder.defaultAbiCoder().encode( + ["address", "uint256", "bytes", "uint256", "bytes32"], + [target, value, data, predecessor, salt] + ); + const id = ethers.keccak256(abiEncoded); + return { + id, + target, + value, + data, + predecessor, + salt, + }; +}