Skip to content

Instantly share code, notes, and snippets.

@critesjosh
Created May 3, 2023 14:48
Show Gist options
  • Save critesjosh/cb48dd550ba85bccb6cfa1b7d1c6859f to your computer and use it in GitHub Desktop.
Save critesjosh/cb48dd550ba85bccb6cfa1b7d1c6859f to your computer and use it in GitHub Desktop.
solidity ultraplonk verifier contract
// Verification Key Hash: 584edb3633b5589bed16edc896f2c868bc72fe184f3526d873ebd68883df01f7
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 Aztec
pragma solidity >=0.8.4;
library UltraVerificationKey {
function verificationKeyHash() internal pure returns(bytes32) {
return 0x584edb3633b5589bed16edc896f2c868bc72fe184f3526d873ebd68883df01f7;
}
function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure {
assembly {
mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000000010) // vk.circuit_size
mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000002) // vk.num_inputs
mstore(add(_vk, 0x40), 0x21082ca216cbbf4e1c6e4f4594dd508c996dfbe1174efb98b11509c6e306460b) // vk.work_root
mstore(add(_vk, 0x60), 0x2d5e098bb31e86271ccb415b196942d755b0a9c3f21dd9882fa3d63ab1000001) // vk.domain_inverse
mstore(add(_vk, 0x80), 0x24caf4ac16f549d78d1f5195a50d3b7b1824640b73d470649a505aa3df95a2e7) // vk.Q1.x
mstore(add(_vk, 0xa0), 0x0f1aedf33d5002272963dbe669f04e60f972e673af7f2a263653dd2b92c7fe08) // vk.Q1.y
mstore(add(_vk, 0xc0), 0x2213c3aa4699d551b7ea019b2444f822536f01c2cae886c12bbf93b6dd95798a) // vk.Q2.x
mstore(add(_vk, 0xe0), 0x1084e714e3fad36d0f8325146e5be6c8fd44caade34a3cf7c9044a326e95d5ec) // vk.Q2.y
mstore(add(_vk, 0x100), 0x078ad3d6a008798adec0ed30a03667ae7b8e7602315b95d4727e73d5afe4d725) // vk.Q3.x
mstore(add(_vk, 0x120), 0x193cf0f2753ddd160f732f312a2ba421a1a3dcadc7fcf50d03c890b6d3ab594e) // vk.Q3.y
mstore(add(_vk, 0x140), 0x02d6fd9e84dbe74b7531e1801405a1c292117b1a17fefe9de0bfd9edf1a84bf9) // vk.Q4.x
mstore(add(_vk, 0x160), 0x293c6ab3c06a0669af13393a82c60a459a3b2a0b768da45ac7af7f2aec40fc42) // vk.Q4.y
mstore(add(_vk, 0x180), 0x09553fb1dd8a17ef4b194224d94cb748f73794a8f4ca87e981ed21a536449c3e) // vk.Q_M.x
mstore(add(_vk, 0x1a0), 0x2065b2da0647e6320585b9a74542668a12a624e44c0cb653a6dbb82bf97c4eff) // vk.Q_M.y
mstore(add(_vk, 0x1c0), 0x040f3d5fa2c1edece8c388a8546504e4da7dc50aeb8aee7e7192bf3e2ba1c971) // vk.Q_C.x
mstore(add(_vk, 0x1e0), 0x11f46046218c8cc1c299e99b0fe0f764c67082c3251aa2d08acc23f1c1eae0ec) // vk.Q_C.y
mstore(add(_vk, 0x200), 0x1b066e2722151d9b63f4fa049e76923b7a456ec56539a4221785b4dc496aa67a) // vk.Q_ARITHMETIC.x
mstore(add(_vk, 0x220), 0x23ee360a611c1e095f6047b091750780d8f5bb047dce3f0c97b1530033dc3030) // vk.Q_ARITHMETIC.y
mstore(add(_vk, 0x240), 0x2cbce7beee3076b78dace04943d69d0d9e28aa6d00e046852781a5f20816645c) // vk.QSORT.x
mstore(add(_vk, 0x260), 0x2bc27ec2e1612ea284b08bcc55b6f2fd915d11bfedbdc0e59de09e5b28952080) // vk.QSORT.y
mstore(add(_vk, 0x280), 0x0ad34b5e8db72a5acf4427546c7294be6ed4f4d252a79059e505f9abc1bdf3ed) // vk.Q_ELLIPTIC.x
mstore(add(_vk, 0x2a0), 0x1e5b26790a26eb340217dd9ad28dbf90a049f42a3852acd45e6f521f24b4900e) // vk.Q_ELLIPTIC.y
mstore(add(_vk, 0x2c0), 0x155a0f51fec78c33ffceb7364d69d7ac27e570ae50bc180509764eb3fef94815) // vk.Q_AUX.x
mstore(add(_vk, 0x2e0), 0x1c1c4720bed44a591d97cbc72b6e44b644999713a8d3c66e9054aa5726324c76) // vk.Q_AUX.y
mstore(add(_vk, 0x300), 0x24abdf785b3fef57130c82275df9f5589a241336cb00ccd05498143e9b6abff5) // vk.SIGMA1.x
mstore(add(_vk, 0x320), 0x1545b730b4d2799ca99be9192296120d32fc038585e0d161db04a113cd8b9e90) // vk.SIGMA1.y
mstore(add(_vk, 0x340), 0x1ff7918565100d8cc2d2764b59bb00e9f6d9c28b5cab0b1851d23bc4de7b32df) // vk.SIGMA2.x
mstore(add(_vk, 0x360), 0x2bec518ca43a7fb562c6536855d1d68091e25e59a7d124811c831287ae5638a4) // vk.SIGMA2.y
mstore(add(_vk, 0x380), 0x28c74441e4a4815b5be77ba776c1af44fd74316f4087ae6495516dff5f44e722) // vk.SIGMA3.x
mstore(add(_vk, 0x3a0), 0x1b69ba4574860b595a5c476420e20cd851bfddb6852f2e8c495ed33842f169b1) // vk.SIGMA3.y
mstore(add(_vk, 0x3c0), 0x0fe847a430f50ddad34338e5c1ed0c10069634421ef71ee750494536db15b986) // vk.SIGMA4.x
mstore(add(_vk, 0x3e0), 0x04a150558ad6602228d2869dec471669ba0c2bfe5c01a08dc86c829d0754cd5e) // vk.SIGMA4.y
mstore(add(_vk, 0x400), 0x02c397073c8abce6d4140c9b961209dd783bff1a1cfc999bb29859cfb16c46fc) // vk.TABLE1.x
mstore(add(_vk, 0x420), 0x2b7bba2d1efffce0d033f596b4d030750599be670db593af86e1923fe8a1bb18) // vk.TABLE1.y
mstore(add(_vk, 0x440), 0x2c71c58b66498f903b3bbbda3d05ce8ffb571a4b3cf83533f3f71b99a04f6e6b) // vk.TABLE2.x
mstore(add(_vk, 0x460), 0x039dce37f94d1bbd97ccea32a224fe2afaefbcbd080c84dcea90b54f4e0a858f) // vk.TABLE2.y
mstore(add(_vk, 0x480), 0x27dc44977efe6b3746a290706f4f7275783c73cfe56847d848fd93b63bf32083) // vk.TABLE3.x
mstore(add(_vk, 0x4a0), 0x0a5366266dd7b71a10b356030226a2de0cbf2edc8f085b16d73652b15eced8f5) // vk.TABLE3.y
mstore(add(_vk, 0x4c0), 0x136097d79e1b0ae373255e8760c49900a7588ec4d6809c90bb451005a3de3077) // vk.TABLE4.x
mstore(add(_vk, 0x4e0), 0x13dd7515ccac4095302d204f06f0bff2595d77bdf72e4acdb0b0b43969860d98) // vk.TABLE4.y
mstore(add(_vk, 0x500), 0x16ff3501369121d410b445929239ba057fe211dad1b706e49a3b55920fac20ec) // vk.TABLE_TYPE.x
mstore(add(_vk, 0x520), 0x1e190987ebd9cf480f608b82134a00eb8007673c1ed10b834a695adf0068522a) // vk.TABLE_TYPE.y
mstore(add(_vk, 0x540), 0x0baaf073a203ba4ba0093c827bb5b3f7a55611765f111ecf80c456f631e99f29) // vk.ID1.x
mstore(add(_vk, 0x560), 0x27cd34cafd5735ec970278202765e0f1e9da3494b30b948ebce3414d078cef9e) // vk.ID1.y
mstore(add(_vk, 0x580), 0x2c55227ad8e6e40b224275d9e22541bb8e1972f0ef82d12bacab88aa2ed2dd8e) // vk.ID2.x
mstore(add(_vk, 0x5a0), 0x1231b75995c832b90687edb70e85122f30cb40a45c98b0a90ab932f62a92a7fe) // vk.ID2.y
mstore(add(_vk, 0x5c0), 0x0f11ab6fa66551be7c1214237ac466fd0d781b05a9008f0b1ab7c5c8984c1edd) // vk.ID3.x
mstore(add(_vk, 0x5e0), 0x070a442214fa3ee6c70b3b652aff3e1a72311bfa0f2e676e8d4a9a409e1ced2f) // vk.ID3.y
mstore(add(_vk, 0x600), 0x2eea648c8732596b1314fe2a4d2f05363f0c994e91cecad25835338edee2294f) // vk.ID4.x
mstore(add(_vk, 0x620), 0x0ab49886c2b94bd0bd3f6ed1dbbe2cb2671d2ae51d31c1210433c3972bb64578) // vk.ID4.y
mstore(add(_vk, 0x640), 0x00) // vk.contains_recursive_proof
mstore(add(_vk, 0x660), 0) // vk.recursive_proof_public_input_indices
mstore(add(_vk, 0x680), 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1) // vk.g2_x.X.c1
mstore(add(_vk, 0x6a0), 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0) // vk.g2_x.X.c0
mstore(add(_vk, 0x6c0), 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4) // vk.g2_x.Y.c1
mstore(add(_vk, 0x6e0), 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) // vk.g2_x.Y.c0
mstore(_omegaInverseLoc, 0x02e40daf409556c02bfc85eb303402b774954d30aeb0337eb85a71e6373428de) // vk.work_root_inverse
}
}
}
/**
* @title Ultra Plonk proof verification contract
* @dev Top level Plonk proof verification contract, which allows Plonk proof to be verified
*/
abstract contract BaseUltraVerifier {
// VERIFICATION KEY MEMORY LOCATIONS
uint256 internal constant N_LOC = 0x380;
uint256 internal constant NUM_INPUTS_LOC = 0x3a0;
uint256 internal constant OMEGA_LOC = 0x3c0;
uint256 internal constant DOMAIN_INVERSE_LOC = 0x3e0;
uint256 internal constant Q1_X_LOC = 0x400;
uint256 internal constant Q1_Y_LOC = 0x420;
uint256 internal constant Q2_X_LOC = 0x440;
uint256 internal constant Q2_Y_LOC = 0x460;
uint256 internal constant Q3_X_LOC = 0x480;
uint256 internal constant Q3_Y_LOC = 0x4a0;
uint256 internal constant Q4_X_LOC = 0x4c0;
uint256 internal constant Q4_Y_LOC = 0x4e0;
uint256 internal constant QM_X_LOC = 0x500;
uint256 internal constant QM_Y_LOC = 0x520;
uint256 internal constant QC_X_LOC = 0x540;
uint256 internal constant QC_Y_LOC = 0x560;
uint256 internal constant QARITH_X_LOC = 0x580;
uint256 internal constant QARITH_Y_LOC = 0x5a0;
uint256 internal constant QSORT_X_LOC = 0x5c0;
uint256 internal constant QSORT_Y_LOC = 0x5e0;
uint256 internal constant QELLIPTIC_X_LOC = 0x600;
uint256 internal constant QELLIPTIC_Y_LOC = 0x620;
uint256 internal constant QAUX_X_LOC = 0x640;
uint256 internal constant QAUX_Y_LOC = 0x660;
uint256 internal constant SIGMA1_X_LOC = 0x680;
uint256 internal constant SIGMA1_Y_LOC = 0x6a0;
uint256 internal constant SIGMA2_X_LOC = 0x6c0;
uint256 internal constant SIGMA2_Y_LOC = 0x6e0;
uint256 internal constant SIGMA3_X_LOC = 0x700;
uint256 internal constant SIGMA3_Y_LOC = 0x720;
uint256 internal constant SIGMA4_X_LOC = 0x740;
uint256 internal constant SIGMA4_Y_LOC = 0x760;
uint256 internal constant TABLE1_X_LOC = 0x780;
uint256 internal constant TABLE1_Y_LOC = 0x7a0;
uint256 internal constant TABLE2_X_LOC = 0x7c0;
uint256 internal constant TABLE2_Y_LOC = 0x7e0;
uint256 internal constant TABLE3_X_LOC = 0x800;
uint256 internal constant TABLE3_Y_LOC = 0x820;
uint256 internal constant TABLE4_X_LOC = 0x840;
uint256 internal constant TABLE4_Y_LOC = 0x860;
uint256 internal constant TABLE_TYPE_X_LOC = 0x880;
uint256 internal constant TABLE_TYPE_Y_LOC = 0x8a0;
uint256 internal constant ID1_X_LOC = 0x8c0;
uint256 internal constant ID1_Y_LOC = 0x8e0;
uint256 internal constant ID2_X_LOC = 0x900;
uint256 internal constant ID2_Y_LOC = 0x920;
uint256 internal constant ID3_X_LOC = 0x940;
uint256 internal constant ID3_Y_LOC = 0x960;
uint256 internal constant ID4_X_LOC = 0x980;
uint256 internal constant ID4_Y_LOC = 0x9a0;
uint256 internal constant CONTAINS_RECURSIVE_PROOF_LOC = 0x9c0;
uint256 internal constant RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC = 0x9e0;
uint256 internal constant G2X_X0_LOC = 0xa00;
uint256 internal constant G2X_X1_LOC = 0xa20;
uint256 internal constant G2X_Y0_LOC = 0xa40;
uint256 internal constant G2X_Y1_LOC = 0xa60;
// ### PROOF DATA MEMORY LOCATIONS
uint256 internal constant W1_X_LOC = 0x1200;
uint256 internal constant W1_Y_LOC = 0x1220;
uint256 internal constant W2_X_LOC = 0x1240;
uint256 internal constant W2_Y_LOC = 0x1260;
uint256 internal constant W3_X_LOC = 0x1280;
uint256 internal constant W3_Y_LOC = 0x12a0;
uint256 internal constant W4_X_LOC = 0x12c0;
uint256 internal constant W4_Y_LOC = 0x12e0;
uint256 internal constant S_X_LOC = 0x1300;
uint256 internal constant S_Y_LOC = 0x1320;
uint256 internal constant Z_X_LOC = 0x1340;
uint256 internal constant Z_Y_LOC = 0x1360;
uint256 internal constant Z_LOOKUP_X_LOC = 0x1380;
uint256 internal constant Z_LOOKUP_Y_LOC = 0x13a0;
uint256 internal constant T1_X_LOC = 0x13c0;
uint256 internal constant T1_Y_LOC = 0x13e0;
uint256 internal constant T2_X_LOC = 0x1400;
uint256 internal constant T2_Y_LOC = 0x1420;
uint256 internal constant T3_X_LOC = 0x1440;
uint256 internal constant T3_Y_LOC = 0x1460;
uint256 internal constant T4_X_LOC = 0x1480;
uint256 internal constant T4_Y_LOC = 0x14a0;
uint256 internal constant W1_EVAL_LOC = 0x1600;
uint256 internal constant W2_EVAL_LOC = 0x1620;
uint256 internal constant W3_EVAL_LOC = 0x1640;
uint256 internal constant W4_EVAL_LOC = 0x1660;
uint256 internal constant S_EVAL_LOC = 0x1680;
uint256 internal constant Z_EVAL_LOC = 0x16a0;
uint256 internal constant Z_LOOKUP_EVAL_LOC = 0x16c0;
uint256 internal constant Q1_EVAL_LOC = 0x16e0;
uint256 internal constant Q2_EVAL_LOC = 0x1700;
uint256 internal constant Q3_EVAL_LOC = 0x1720;
uint256 internal constant Q4_EVAL_LOC = 0x1740;
uint256 internal constant QM_EVAL_LOC = 0x1760;
uint256 internal constant QC_EVAL_LOC = 0x1780;
uint256 internal constant QARITH_EVAL_LOC = 0x17a0;
uint256 internal constant QSORT_EVAL_LOC = 0x17c0;
uint256 internal constant QELLIPTIC_EVAL_LOC = 0x17e0;
uint256 internal constant QAUX_EVAL_LOC = 0x1800;
uint256 internal constant TABLE1_EVAL_LOC = 0x1840;
uint256 internal constant TABLE2_EVAL_LOC = 0x1860;
uint256 internal constant TABLE3_EVAL_LOC = 0x1880;
uint256 internal constant TABLE4_EVAL_LOC = 0x18a0;
uint256 internal constant TABLE_TYPE_EVAL_LOC = 0x18c0;
uint256 internal constant ID1_EVAL_LOC = 0x18e0;
uint256 internal constant ID2_EVAL_LOC = 0x1900;
uint256 internal constant ID3_EVAL_LOC = 0x1920;
uint256 internal constant ID4_EVAL_LOC = 0x1940;
uint256 internal constant SIGMA1_EVAL_LOC = 0x1960;
uint256 internal constant SIGMA2_EVAL_LOC = 0x1980;
uint256 internal constant SIGMA3_EVAL_LOC = 0x19a0;
uint256 internal constant SIGMA4_EVAL_LOC = 0x19c0;
uint256 internal constant W1_OMEGA_EVAL_LOC = 0x19e0;
uint256 internal constant W2_OMEGA_EVAL_LOC = 0x2000;
uint256 internal constant W3_OMEGA_EVAL_LOC = 0x2020;
uint256 internal constant W4_OMEGA_EVAL_LOC = 0x2040;
uint256 internal constant S_OMEGA_EVAL_LOC = 0x2060;
uint256 internal constant Z_OMEGA_EVAL_LOC = 0x2080;
uint256 internal constant Z_LOOKUP_OMEGA_EVAL_LOC = 0x20a0;
uint256 internal constant TABLE1_OMEGA_EVAL_LOC = 0x20c0;
uint256 internal constant TABLE2_OMEGA_EVAL_LOC = 0x20e0;
uint256 internal constant TABLE3_OMEGA_EVAL_LOC = 0x2100;
uint256 internal constant TABLE4_OMEGA_EVAL_LOC = 0x2120;
uint256 internal constant PI_Z_X_LOC = 0x2300;
uint256 internal constant PI_Z_Y_LOC = 0x2320;
uint256 internal constant PI_Z_OMEGA_X_LOC = 0x2340;
uint256 internal constant PI_Z_OMEGA_Y_LOC = 0x2360;
// Used for elliptic widget. These are alias names for wire + shifted wire evaluations
uint256 internal constant X1_EVAL_LOC = W2_EVAL_LOC;
uint256 internal constant X2_EVAL_LOC = W1_OMEGA_EVAL_LOC;
uint256 internal constant X3_EVAL_LOC = W2_OMEGA_EVAL_LOC;
uint256 internal constant Y1_EVAL_LOC = W3_EVAL_LOC;
uint256 internal constant Y2_EVAL_LOC = W4_OMEGA_EVAL_LOC;
uint256 internal constant Y3_EVAL_LOC = W3_OMEGA_EVAL_LOC;
uint256 internal constant QBETA_LOC = Q3_EVAL_LOC;
uint256 internal constant QBETA_SQR_LOC = Q4_EVAL_LOC;
uint256 internal constant QSIGN_LOC = Q1_EVAL_LOC;
// ### CHALLENGES MEMORY OFFSETS
uint256 internal constant C_BETA_LOC = 0x2600;
uint256 internal constant C_GAMMA_LOC = 0x2620;
uint256 internal constant C_ALPHA_LOC = 0x2640;
uint256 internal constant C_ETA_LOC = 0x2660;
uint256 internal constant C_ETA_SQR_LOC = 0x2680;
uint256 internal constant C_ETA_CUBE_LOC = 0x26a0;
uint256 internal constant C_ZETA_LOC = 0x26c0;
uint256 internal constant C_CURRENT_LOC = 0x26e0;
uint256 internal constant C_V0_LOC = 0x2700;
uint256 internal constant C_V1_LOC = 0x2720;
uint256 internal constant C_V2_LOC = 0x2740;
uint256 internal constant C_V3_LOC = 0x2760;
uint256 internal constant C_V4_LOC = 0x2780;
uint256 internal constant C_V5_LOC = 0x27a0;
uint256 internal constant C_V6_LOC = 0x27c0;
uint256 internal constant C_V7_LOC = 0x27e0;
uint256 internal constant C_V8_LOC = 0x2800;
uint256 internal constant C_V9_LOC = 0x2820;
uint256 internal constant C_V10_LOC = 0x2840;
uint256 internal constant C_V11_LOC = 0x2860;
uint256 internal constant C_V12_LOC = 0x2880;
uint256 internal constant C_V13_LOC = 0x28a0;
uint256 internal constant C_V14_LOC = 0x28c0;
uint256 internal constant C_V15_LOC = 0x28e0;
uint256 internal constant C_V16_LOC = 0x2900;
uint256 internal constant C_V17_LOC = 0x2920;
uint256 internal constant C_V18_LOC = 0x2940;
uint256 internal constant C_V19_LOC = 0x2960;
uint256 internal constant C_V20_LOC = 0x2980;
uint256 internal constant C_V21_LOC = 0x29a0;
uint256 internal constant C_V22_LOC = 0x29c0;
uint256 internal constant C_V23_LOC = 0x29e0;
uint256 internal constant C_V24_LOC = 0x2a00;
uint256 internal constant C_V25_LOC = 0x2a20;
uint256 internal constant C_V26_LOC = 0x2a40;
uint256 internal constant C_V27_LOC = 0x2a60;
uint256 internal constant C_V28_LOC = 0x2a80;
uint256 internal constant C_V29_LOC = 0x2aa0;
uint256 internal constant C_V30_LOC = 0x2ac0;
uint256 internal constant C_U_LOC = 0x2b00;
// ### LOCAL VARIABLES MEMORY OFFSETS
uint256 internal constant DELTA_NUMERATOR_LOC = 0x3000;
uint256 internal constant DELTA_DENOMINATOR_LOC = 0x3020;
uint256 internal constant ZETA_POW_N_LOC = 0x3040;
uint256 internal constant PUBLIC_INPUT_DELTA_LOC = 0x3060;
uint256 internal constant ZERO_POLY_LOC = 0x3080;
uint256 internal constant L_START_LOC = 0x30a0;
uint256 internal constant L_END_LOC = 0x30c0;
uint256 internal constant R_ZERO_EVAL_LOC = 0x30e0;
uint256 internal constant PLOOKUP_DELTA_NUMERATOR_LOC = 0x3100;
uint256 internal constant PLOOKUP_DELTA_DENOMINATOR_LOC = 0x3120;
uint256 internal constant PLOOKUP_DELTA_LOC = 0x3140;
uint256 internal constant ACCUMULATOR_X_LOC = 0x3160;
uint256 internal constant ACCUMULATOR_Y_LOC = 0x3180;
uint256 internal constant ACCUMULATOR2_X_LOC = 0x31a0;
uint256 internal constant ACCUMULATOR2_Y_LOC = 0x31c0;
uint256 internal constant PAIRING_LHS_X_LOC = 0x31e0;
uint256 internal constant PAIRING_LHS_Y_LOC = 0x3200;
uint256 internal constant PAIRING_RHS_X_LOC = 0x3220;
uint256 internal constant PAIRING_RHS_Y_LOC = 0x3240;
// ### SUCCESS FLAG MEMORY LOCATIONS
uint256 internal constant GRAND_PRODUCT_SUCCESS_FLAG = 0x3300;
uint256 internal constant ARITHMETIC_TERM_SUCCESS_FLAG = 0x3020;
uint256 internal constant BATCH_OPENING_SUCCESS_FLAG = 0x3340;
uint256 internal constant OPENING_COMMITMENT_SUCCESS_FLAG = 0x3360;
uint256 internal constant PAIRING_PREAMBLE_SUCCESS_FLAG = 0x3380;
uint256 internal constant PAIRING_SUCCESS_FLAG = 0x33a0;
uint256 internal constant RESULT_FLAG = 0x33c0;
// misc stuff
uint256 internal constant OMEGA_INVERSE_LOC = 0x3400;
uint256 internal constant C_ALPHA_SQR_LOC = 0x3420;
uint256 internal constant C_ALPHA_CUBE_LOC = 0x3440;
uint256 internal constant C_ALPHA_QUAD_LOC = 0x3460;
uint256 internal constant C_ALPHA_BASE_LOC = 0x3480;
// ### RECURSION VARIABLE MEMORY LOCATIONS
uint256 internal constant RECURSIVE_P1_X_LOC = 0x3500;
uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3520;
uint256 internal constant RECURSIVE_P2_X_LOC = 0x3540;
uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3560;
uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3580;
// sub-identity storage
uint256 internal constant PERMUTATION_IDENTITY = 0x3600;
uint256 internal constant PLOOKUP_IDENTITY = 0x3620;
uint256 internal constant ARITHMETIC_IDENTITY = 0x3640;
uint256 internal constant SORT_IDENTITY = 0x3660;
uint256 internal constant ELLIPTIC_IDENTITY = 0x3680;
uint256 internal constant AUX_IDENTITY = 0x36a0;
uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x36c0;
uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x36e0;
uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3700;
uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3720;
uint256 internal constant AUX_MEMORY_EVALUATION = 0x3740;
uint256 internal constant QUOTIENT_EVAL_LOC = 0x3760;
uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3780;
// when hashing public inputs we use memory at NU_CHALLENGE_INPUT_LOC_A, as the hash input size is unknown at compile time
uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x37a0;
uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x37c0;
uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x37e0;
bytes4 internal constant PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR = 0xeba9f4a6;
bytes4 internal constant PUBLIC_INPUT_GE_P_SELECTOR = 0x374a972f;
bytes4 internal constant MOD_EXP_FAILURE_SELECTOR = 0xf894a7bc;
bytes4 internal constant EC_SCALAR_MUL_FAILURE_SELECTOR = 0xf755f369;
bytes4 internal constant PROOF_FAILURE_SELECTOR = 0x0711fcec;
uint256 internal constant ETA_INPUT_LENGTH = 0xc0; // W1, W2, W3 = 6 * 0x20 bytes
// We need to hash 41 field elements when generating the NU challenge
// w1, w2, w3, w4, s, z, z_lookup, q1, q2, q3, q4, qm, qc, qarith (14)
// qsort, qelliptic, qaux, sigma1, sigma2, sigma, sigma4, (7)
// table1, table2, table3, table4, tabletype, id1, id2, id3, id4, (9)
// w1_omega, w2_omega, w3_omega, w4_omega, s_omega, z_omega, z_lookup_omega, (7)
// table1_omega, table2_omega, table3_omega, table4_omega (4)
uint256 internal constant NU_INPUT_LENGTH = 0x520; // 0x520 = 41 * 0x20
// There are ELEVEN G1 group elements added into the transcript in the `beta` round, that we need to skip over
// W1, W2, W3, W4, S, Z, Z_LOOKUP, T1, T2, T3, T4
uint256 internal constant NU_CALLDATA_SKIP_LENGTH = 0x2c0; // 11 * 0x40 = 0x2c0
uint256 internal constant NEGATIVE_INVERSE_OF_2_MODULO_P =
0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;
uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68
uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14
error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual);
error PUBLIC_INPUT_INVALID_BN128_G1_POINT();
error PUBLIC_INPUT_GE_P();
error MOD_EXP_FAILURE();
error EC_SCALAR_MUL_FAILURE();
error PROOF_FAILURE();
function getVerificationKeyHash() public pure virtual returns (bytes32);
function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure virtual;
/**
* @notice Verify a Ultra Plonk proof
* @param _proof - The serialized proof
* @param _publicInputs - An array of the public inputs
* @return True if proof is valid, reverts otherwise
*/
function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) {
loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC);
uint256 requiredPublicInputCount;
assembly {
requiredPublicInputCount := mload(NUM_INPUTS_LOC)
}
if (requiredPublicInputCount != _publicInputs.length) {
revert PUBLIC_INPUT_COUNT_INVALID(requiredPublicInputCount, _publicInputs.length);
}
assembly {
let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order
let p := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // Prime field order
/**
* LOAD PROOF FROM CALLDATA
*/
{
let data_ptr := add(calldataload(0x04), 0x24)
mstore(W1_Y_LOC, mod(calldataload(data_ptr), q))
mstore(W1_X_LOC, mod(calldataload(add(data_ptr, 0x20)), q))
mstore(W2_Y_LOC, mod(calldataload(add(data_ptr, 0x40)), q))
mstore(W2_X_LOC, mod(calldataload(add(data_ptr, 0x60)), q))
mstore(W3_Y_LOC, mod(calldataload(add(data_ptr, 0x80)), q))
mstore(W3_X_LOC, mod(calldataload(add(data_ptr, 0xa0)), q))
mstore(W4_Y_LOC, mod(calldataload(add(data_ptr, 0xc0)), q))
mstore(W4_X_LOC, mod(calldataload(add(data_ptr, 0xe0)), q))
mstore(S_Y_LOC, mod(calldataload(add(data_ptr, 0x100)), q))
mstore(S_X_LOC, mod(calldataload(add(data_ptr, 0x120)), q))
mstore(Z_Y_LOC, mod(calldataload(add(data_ptr, 0x140)), q))
mstore(Z_X_LOC, mod(calldataload(add(data_ptr, 0x160)), q))
mstore(Z_LOOKUP_Y_LOC, mod(calldataload(add(data_ptr, 0x180)), q))
mstore(Z_LOOKUP_X_LOC, mod(calldataload(add(data_ptr, 0x1a0)), q))
mstore(T1_Y_LOC, mod(calldataload(add(data_ptr, 0x1c0)), q))
mstore(T1_X_LOC, mod(calldataload(add(data_ptr, 0x1e0)), q))
mstore(T2_Y_LOC, mod(calldataload(add(data_ptr, 0x200)), q))
mstore(T2_X_LOC, mod(calldataload(add(data_ptr, 0x220)), q))
mstore(T3_Y_LOC, mod(calldataload(add(data_ptr, 0x240)), q))
mstore(T3_X_LOC, mod(calldataload(add(data_ptr, 0x260)), q))
mstore(T4_Y_LOC, mod(calldataload(add(data_ptr, 0x280)), q))
mstore(T4_X_LOC, mod(calldataload(add(data_ptr, 0x2a0)), q))
mstore(W1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2c0)), p))
mstore(W2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2e0)), p))
mstore(W3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x300)), p))
mstore(W4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x320)), p))
mstore(S_EVAL_LOC, mod(calldataload(add(data_ptr, 0x340)), p))
mstore(Z_EVAL_LOC, mod(calldataload(add(data_ptr, 0x360)), p))
mstore(Z_LOOKUP_EVAL_LOC, mod(calldataload(add(data_ptr, 0x380)), p))
mstore(Q1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3a0)), p))
mstore(Q2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3c0)), p))
mstore(Q3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3e0)), p))
mstore(Q4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x400)), p))
mstore(QM_EVAL_LOC, mod(calldataload(add(data_ptr, 0x420)), p))
mstore(QC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x440)), p))
mstore(QARITH_EVAL_LOC, mod(calldataload(add(data_ptr, 0x460)), p))
mstore(QSORT_EVAL_LOC, mod(calldataload(add(data_ptr, 0x480)), p))
mstore(QELLIPTIC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4a0)), p))
mstore(QAUX_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4c0)), p))
mstore(SIGMA1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4e0)), p))
mstore(SIGMA2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x500)), p))
mstore(SIGMA3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x520)), p))
mstore(SIGMA4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x540)), p))
mstore(TABLE1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x560)), p))
mstore(TABLE2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x580)), p))
mstore(TABLE3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5a0)), p))
mstore(TABLE4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5c0)), p))
mstore(TABLE_TYPE_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5e0)), p))
mstore(ID1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x600)), p))
mstore(ID2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x620)), p))
mstore(ID3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x640)), p))
mstore(ID4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x660)), p))
mstore(W1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x680)), p))
mstore(W2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6a0)), p))
mstore(W3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6c0)), p))
mstore(W4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6e0)), p))
mstore(S_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x700)), p))
mstore(Z_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x720)), p))
mstore(Z_LOOKUP_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x740)), p))
mstore(TABLE1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x760)), p))
mstore(TABLE2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x780)), p))
mstore(TABLE3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7a0)), p))
mstore(TABLE4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7c0)), p))
mstore(PI_Z_Y_LOC, mod(calldataload(add(data_ptr, 0x7e0)), q))
mstore(PI_Z_X_LOC, mod(calldataload(add(data_ptr, 0x800)), q))
mstore(PI_Z_OMEGA_Y_LOC, mod(calldataload(add(data_ptr, 0x820)), q))
mstore(PI_Z_OMEGA_X_LOC, mod(calldataload(add(data_ptr, 0x840)), q))
}
/**
* LOAD RECURSIVE PROOF INTO MEMORY
*/
{
if mload(CONTAINS_RECURSIVE_PROOF_LOC) {
let public_inputs_ptr := add(calldataload(0x24), 0x24)
let index_counter := add(shl(5, mload(RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC)), public_inputs_ptr)
let x0 := calldataload(index_counter)
x0 := add(x0, shl(68, calldataload(add(index_counter, 0x20))))
x0 := add(x0, shl(136, calldataload(add(index_counter, 0x40))))
x0 := add(x0, shl(204, calldataload(add(index_counter, 0x60))))
let y0 := calldataload(add(index_counter, 0x80))
y0 := add(y0, shl(68, calldataload(add(index_counter, 0xa0))))
y0 := add(y0, shl(136, calldataload(add(index_counter, 0xc0))))
y0 := add(y0, shl(204, calldataload(add(index_counter, 0xe0))))
let x1 := calldataload(add(index_counter, 0x100))
x1 := add(x1, shl(68, calldataload(add(index_counter, 0x120))))
x1 := add(x1, shl(136, calldataload(add(index_counter, 0x140))))
x1 := add(x1, shl(204, calldataload(add(index_counter, 0x160))))
let y1 := calldataload(add(index_counter, 0x180))
y1 := add(y1, shl(68, calldataload(add(index_counter, 0x1a0))))
y1 := add(y1, shl(136, calldataload(add(index_counter, 0x1c0))))
y1 := add(y1, shl(204, calldataload(add(index_counter, 0x1e0))))
mstore(RECURSIVE_P1_X_LOC, x0)
mstore(RECURSIVE_P1_Y_LOC, y0)
mstore(RECURSIVE_P2_X_LOC, x1)
mstore(RECURSIVE_P2_Y_LOC, y1)
// validate these are valid bn128 G1 points
if iszero(and(and(lt(x0, q), lt(x1, q)), and(lt(y0, q), lt(y1, q)))) {
mstore(0x00, PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR)
revert(0x00, 0x04)
}
}
}
{
/**
* Generate initial challenge
*/
mstore(0x00, shl(224, mload(N_LOC)))
mstore(0x04, shl(224, mload(NUM_INPUTS_LOC)))
let challenge := keccak256(0x00, 0x08)
/**
* Generate eta challenge
*/
mstore(PUBLIC_INPUTS_HASH_LOCATION, challenge)
// The public input location is stored at 0x24, we then add 0x24 to skip selector and the length of public inputs
let public_inputs_start := add(calldataload(0x24), 0x24)
// copy the public inputs over
let public_input_size := mul(mload(NUM_INPUTS_LOC), 0x20)
calldatacopy(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_inputs_start, public_input_size)
// copy W1, W2, W3 into challenge. Each point is 0x40 bytes, so load 0xc0 = 3 * 0x40 bytes (ETA input length)
let w_start := add(calldataload(0x04), 0x24)
calldatacopy(add(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_input_size), w_start, ETA_INPUT_LENGTH)
// Challenge is the old challenge + public inputs + W1, W2, W3 (0x20 + public_input_size + 0xc0)
let challenge_bytes_size := add(0x20, add(public_input_size, ETA_INPUT_LENGTH))
challenge := keccak256(PUBLIC_INPUTS_HASH_LOCATION, challenge_bytes_size)
{
let eta := mod(challenge, p)
mstore(C_ETA_LOC, eta)
mstore(C_ETA_SQR_LOC, mulmod(eta, eta, p))
mstore(C_ETA_CUBE_LOC, mulmod(mload(C_ETA_SQR_LOC), eta, p))
}
/**
* Generate beta challenge
*/
mstore(0x00, challenge)
mstore(0x20, mload(W4_Y_LOC))
mstore(0x40, mload(W4_X_LOC))
mstore(0x60, mload(S_Y_LOC))
mstore(0x80, mload(S_X_LOC))
challenge := keccak256(0x00, 0xa0)
mstore(C_BETA_LOC, mod(challenge, p))
/**
* Generate gamma challenge
*/
mstore(0x00, challenge)
mstore8(0x20, 0x01)
challenge := keccak256(0x00, 0x21)
mstore(C_GAMMA_LOC, mod(challenge, p))
/**
* Generate alpha challenge
*/
mstore(0x00, challenge)
mstore(0x20, mload(Z_Y_LOC))
mstore(0x40, mload(Z_X_LOC))
mstore(0x60, mload(Z_LOOKUP_Y_LOC))
mstore(0x80, mload(Z_LOOKUP_X_LOC))
challenge := keccak256(0x00, 0xa0)
mstore(C_ALPHA_LOC, mod(challenge, p))
/**
* Compute and store some powers of alpha for future computations
*/
let alpha := mload(C_ALPHA_LOC)
mstore(C_ALPHA_SQR_LOC, mulmod(alpha, alpha, p))
mstore(C_ALPHA_CUBE_LOC, mulmod(mload(C_ALPHA_SQR_LOC), alpha, p))
mstore(C_ALPHA_QUAD_LOC, mulmod(mload(C_ALPHA_CUBE_LOC), alpha, p))
mstore(C_ALPHA_BASE_LOC, alpha)
/**
* Generate zeta challenge
*/
mstore(0x00, challenge)
mstore(0x20, mload(T1_Y_LOC))
mstore(0x40, mload(T1_X_LOC))
mstore(0x60, mload(T2_Y_LOC))
mstore(0x80, mload(T2_X_LOC))
mstore(0xa0, mload(T3_Y_LOC))
mstore(0xc0, mload(T3_X_LOC))
mstore(0xe0, mload(T4_Y_LOC))
mstore(0x100, mload(T4_X_LOC))
challenge := keccak256(0x00, 0x120)
mstore(C_ZETA_LOC, mod(challenge, p))
mstore(C_CURRENT_LOC, challenge)
}
/**
* EVALUATE FIELD OPERATIONS
*/
/**
* COMPUTE PUBLIC INPUT DELTA
* ΔPI = ∏ᵢ∈ℓ(wᵢ + β σ(i) + γ) / ∏ᵢ∈ℓ(wᵢ + β σ'(i) + γ)
*/
{
let beta := mload(C_BETA_LOC) // β
let gamma := mload(C_GAMMA_LOC) // γ
let work_root := mload(OMEGA_LOC) // ω
let numerator_value := 1
let denominator_value := 1
let p_clone := p // move p to the front of the stack
let valid_inputs := true
// Load the starting point of the public inputs (jump over the selector and the length of public inputs [0x24])
let public_inputs_ptr := add(calldataload(0x24), 0x24)
// endpoint_ptr = public_inputs_ptr + num_inputs * 0x20. // every public input is 0x20 bytes
let endpoint_ptr := add(public_inputs_ptr, mul(mload(NUM_INPUTS_LOC), 0x20))
// root_1 = β * 0x05
let root_1 := mulmod(beta, 0x05, p_clone) // k1.β
// root_2 = β * 0x0c
let root_2 := mulmod(beta, 0x0c, p_clone)
// @note 0x05 + 0x07 == 0x0c == external coset generator
for {} lt(public_inputs_ptr, endpoint_ptr) { public_inputs_ptr := add(public_inputs_ptr, 0x20) } {
/**
* input = public_input[i]
* valid_inputs &= input < p
* temp = input + gamma
* numerator_value *= (β.σ(i) + wᵢ + γ) // σ(i) = 0x05.ωⁱ
* denominator_value *= (β.σ'(i) + wᵢ + γ) // σ'(i) = 0x0c.ωⁱ
* root_1 *= ω
* root_2 *= ω
*/
let input := calldataload(public_inputs_ptr)
valid_inputs := and(valid_inputs, lt(input, p_clone))
let temp := addmod(input, gamma, p_clone)
numerator_value := mulmod(numerator_value, add(root_1, temp), p_clone)
denominator_value := mulmod(denominator_value, add(root_2, temp), p_clone)
root_1 := mulmod(root_1, work_root, p_clone)
root_2 := mulmod(root_2, work_root, p_clone)
}
// Revert if not all public inputs are field elements (i.e. < p)
if iszero(valid_inputs) {
mstore(0x00, PUBLIC_INPUT_GE_P_SELECTOR)
revert(0x00, 0x04)
}
mstore(DELTA_NUMERATOR_LOC, numerator_value)
mstore(DELTA_DENOMINATOR_LOC, denominator_value)
}
/**
* Compute Plookup delta factor [γ(1 + β)]^{n-k}
* k = num roots cut out of Z_H = 4
*/
{
let delta_base := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p)
let delta_numerator := delta_base
{
let exponent := mload(N_LOC)
let count := 1
for {} lt(count, exponent) { count := add(count, count) } {
delta_numerator := mulmod(delta_numerator, delta_numerator, p)
}
}
mstore(PLOOKUP_DELTA_NUMERATOR_LOC, delta_numerator)
let delta_denominator := mulmod(delta_base, delta_base, p)
delta_denominator := mulmod(delta_denominator, delta_denominator, p)
mstore(PLOOKUP_DELTA_DENOMINATOR_LOC, delta_denominator)
}
/**
* Compute lagrange poly and vanishing poly fractions
*/
{
/**
* vanishing_numerator = zeta
* ZETA_POW_N = zeta^n
* vanishing_numerator -= 1
* accumulating_root = omega_inverse
* work_root = p - accumulating_root
* domain_inverse = domain_inverse
* vanishing_denominator = zeta + work_root
* work_root *= accumulating_root
* vanishing_denominator *= (zeta + work_root)
* work_root *= accumulating_root
* vanishing_denominator *= (zeta + work_root)
* vanishing_denominator *= (zeta + (zeta + accumulating_root))
* work_root = omega
* lagrange_numerator = vanishing_numerator * domain_inverse
* l_start_denominator = zeta - 1
* accumulating_root = work_root^2
* l_end_denominator = accumulating_root^2 * work_root * zeta - 1
* Note: l_end_denominator term contains a term \omega^5 to cut out 5 roots of unity from vanishing poly
*/
let zeta := mload(C_ZETA_LOC)
// compute zeta^n, where n is a power of 2
let vanishing_numerator := zeta
{
// pow_small
let exponent := mload(N_LOC)
let count := 1
for {} lt(count, exponent) { count := add(count, count) } {
vanishing_numerator := mulmod(vanishing_numerator, vanishing_numerator, p)
}
}
mstore(ZETA_POW_N_LOC, vanishing_numerator)
vanishing_numerator := addmod(vanishing_numerator, sub(p, 1), p)
let accumulating_root := mload(OMEGA_INVERSE_LOC)
let work_root := sub(p, accumulating_root)
let domain_inverse := mload(DOMAIN_INVERSE_LOC)
let vanishing_denominator := addmod(zeta, work_root, p)
work_root := mulmod(work_root, accumulating_root, p)
vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p)
work_root := mulmod(work_root, accumulating_root, p)
vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p)
vanishing_denominator :=
mulmod(vanishing_denominator, addmod(zeta, mulmod(work_root, accumulating_root, p), p), p)
work_root := mload(OMEGA_LOC)
let lagrange_numerator := mulmod(vanishing_numerator, domain_inverse, p)
let l_start_denominator := addmod(zeta, sub(p, 1), p)
accumulating_root := mulmod(work_root, work_root, p)
let l_end_denominator :=
addmod(
mulmod(mulmod(mulmod(accumulating_root, accumulating_root, p), work_root, p), zeta, p), sub(p, 1), p
)
/**
* Compute inversions using Montgomery's batch inversion trick
*/
let accumulator := mload(DELTA_DENOMINATOR_LOC)
let t0 := accumulator
accumulator := mulmod(accumulator, vanishing_denominator, p)
let t1 := accumulator
accumulator := mulmod(accumulator, vanishing_numerator, p)
let t2 := accumulator
accumulator := mulmod(accumulator, l_start_denominator, p)
let t3 := accumulator
accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p)
let t4 := accumulator
{
mstore(0, 0x20)
mstore(0x20, 0x20)
mstore(0x40, 0x20)
mstore(0x60, mulmod(accumulator, l_end_denominator, p))
mstore(0x80, sub(p, 2))
mstore(0xa0, p)
if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) {
mstore(0x0, MOD_EXP_FAILURE_SELECTOR)
revert(0x00, 0x04)
}
accumulator := mload(0x00)
}
t4 := mulmod(accumulator, t4, p)
accumulator := mulmod(accumulator, l_end_denominator, p)
t3 := mulmod(accumulator, t3, p)
accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p)
t2 := mulmod(accumulator, t2, p)
accumulator := mulmod(accumulator, l_start_denominator, p)
t1 := mulmod(accumulator, t1, p)
accumulator := mulmod(accumulator, vanishing_numerator, p)
t0 := mulmod(accumulator, t0, p)
accumulator := mulmod(accumulator, vanishing_denominator, p)
accumulator := mulmod(mulmod(accumulator, accumulator, p), mload(DELTA_DENOMINATOR_LOC), p)
mstore(PUBLIC_INPUT_DELTA_LOC, mulmod(mload(DELTA_NUMERATOR_LOC), accumulator, p))
mstore(ZERO_POLY_LOC, mulmod(vanishing_numerator, t0, p))
mstore(ZERO_POLY_INVERSE_LOC, mulmod(vanishing_denominator, t1, p))
mstore(L_START_LOC, mulmod(lagrange_numerator, t2, p))
mstore(PLOOKUP_DELTA_LOC, mulmod(mload(PLOOKUP_DELTA_NUMERATOR_LOC), t3, p))
mstore(L_END_LOC, mulmod(lagrange_numerator, t4, p))
}
/**
* UltraPlonk Widget Ordering:
*
* 1. Permutation widget
* 2. Plookup widget
* 3. Arithmetic widget
* 4. Fixed base widget (?)
* 5. GenPermSort widget
* 6. Elliptic widget
* 7. Auxiliary widget
*/
/**
* COMPUTE PERMUTATION WIDGET EVALUATION
*/
{
let alpha := mload(C_ALPHA_LOC)
let beta := mload(C_BETA_LOC)
let gamma := mload(C_GAMMA_LOC)
/**
* t1 = (W1 + gamma + beta * ID1) * (W2 + gamma + beta * ID2)
* t2 = (W3 + gamma + beta * ID3) * (W4 + gamma + beta * ID4)
* result = alpha_base * z_eval * t1 * t2
* t1 = (W1 + gamma + beta * sigma_1_eval) * (W2 + gamma + beta * sigma_2_eval)
* t2 = (W2 + gamma + beta * sigma_3_eval) * (W3 + gamma + beta * sigma_4_eval)
* result -= (alpha_base * z_omega_eval * t1 * t2)
*/
let t1 :=
mulmod(
add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(ID1_EVAL_LOC), p)),
add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(ID2_EVAL_LOC), p)),
p
)
let t2 :=
mulmod(
add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(ID3_EVAL_LOC), p)),
add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(ID4_EVAL_LOC), p)),
p
)
let result := mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_EVAL_LOC), mulmod(t1, t2, p), p), p)
t1 :=
mulmod(
add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA1_EVAL_LOC), p)),
add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA2_EVAL_LOC), p)),
p
)
t2 :=
mulmod(
add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA3_EVAL_LOC), p)),
add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA4_EVAL_LOC), p)),
p
)
result :=
addmod(
result,
sub(p, mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_OMEGA_EVAL_LOC), mulmod(t1, t2, p), p), p)),
p
)
/**
* alpha_base *= alpha
* result += alpha_base . (L_{n-k}(ʓ) . (z(ʓ.ω) - ∆_{PI}))
* alpha_base *= alpha
* result += alpha_base . (L_1(ʓ)(Z(ʓ) - 1))
* alpha_Base *= alpha
*/
mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))
result :=
addmod(
result,
mulmod(
mload(C_ALPHA_BASE_LOC),
mulmod(
mload(L_END_LOC),
addmod(mload(Z_OMEGA_EVAL_LOC), sub(p, mload(PUBLIC_INPUT_DELTA_LOC)), p),
p
),
p
),
p
)
mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))
mstore(
PERMUTATION_IDENTITY,
addmod(
result,
mulmod(
mload(C_ALPHA_BASE_LOC),
mulmod(mload(L_START_LOC), addmod(mload(Z_EVAL_LOC), sub(p, 1), p), p),
p
),
p
)
)
mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))
}
/**
* COMPUTE PLOOKUP WIDGET EVALUATION
*/
{
/**
* Goal: f = (w1(z) + q2.w1(zω)) + η(w2(z) + qm.w2(zω)) + η²(w3(z) + qc.w_3(zω)) + q3(z).η³
* f = η.q3(z)
* f += (w3(z) + qc.w_3(zω))
* f *= η
* f += (w2(z) + qm.w2(zω))
* f *= η
* f += (w1(z) + q2.w1(zω))
*/
let f := mulmod(mload(C_ETA_LOC), mload(Q3_EVAL_LOC), p)
f :=
addmod(f, addmod(mload(W3_EVAL_LOC), mulmod(mload(QC_EVAL_LOC), mload(W3_OMEGA_EVAL_LOC), p), p), p)
f := mulmod(f, mload(C_ETA_LOC), p)
f :=
addmod(f, addmod(mload(W2_EVAL_LOC), mulmod(mload(QM_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p), p)
f := mulmod(f, mload(C_ETA_LOC), p)
f :=
addmod(f, addmod(mload(W1_EVAL_LOC), mulmod(mload(Q2_EVAL_LOC), mload(W1_OMEGA_EVAL_LOC), p), p), p)
// t(z) = table4(z).η³ + table3(z).η² + table2(z).η + table1(z)
let t :=
addmod(
addmod(
addmod(
mulmod(mload(TABLE4_EVAL_LOC), mload(C_ETA_CUBE_LOC), p),
mulmod(mload(TABLE3_EVAL_LOC), mload(C_ETA_SQR_LOC), p),
p
),
mulmod(mload(TABLE2_EVAL_LOC), mload(C_ETA_LOC), p),
p
),
mload(TABLE1_EVAL_LOC),
p
)
// t(zw) = table4(zw).η³ + table3(zw).η² + table2(zw).η + table1(zw)
let t_omega :=
addmod(
addmod(
addmod(
mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_ETA_CUBE_LOC), p),
mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_ETA_SQR_LOC), p),
p
),
mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p),
p
),
mload(TABLE1_OMEGA_EVAL_LOC),
p
)
/**
* Goal: numerator = (TABLE_TYPE_EVAL * f(z) + γ) * (t(z) + βt(zω) + γ(β + 1)) * (β + 1)
* gamma_beta_constant = γ(β + 1)
* numerator = f * TABLE_TYPE_EVAL + gamma
* temp0 = t(z) + t(zω) * β + gamma_beta_constant
* numerator *= temp0
* numerator *= (β + 1)
* temp0 = alpha * l_1
* numerator += temp0
* numerator *= z_lookup(z)
* numerator -= temp0
*/
let gamma_beta_constant := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p)
let numerator := addmod(mulmod(f, mload(TABLE_TYPE_EVAL_LOC), p), mload(C_GAMMA_LOC), p)
let temp0 := addmod(addmod(t, mulmod(t_omega, mload(C_BETA_LOC), p), p), gamma_beta_constant, p)
numerator := mulmod(numerator, temp0, p)
numerator := mulmod(numerator, addmod(mload(C_BETA_LOC), 1, p), p)
temp0 := mulmod(mload(C_ALPHA_LOC), mload(L_START_LOC), p)
numerator := addmod(numerator, temp0, p)
numerator := mulmod(numerator, mload(Z_LOOKUP_EVAL_LOC), p)
numerator := addmod(numerator, sub(p, temp0), p)
/**
* Goal: denominator = z_lookup(zω)*[s(z) + βs(zω) + γ(1 + β)] - [z_lookup(zω) - [γ(1 + β)]^{n-k}]*α²L_end(z)
* note: delta_factor = [γ(1 + β)]^{n-k}
* denominator = s(z) + βs(zω) + γ(β + 1)
* temp1 = α²L_end(z)
* denominator -= temp1
* denominator *= z_lookup(zω)
* denominator += temp1 * delta_factor
* PLOOKUP_IDENTITY = (numerator - denominator).alpha_base
* alpha_base *= alpha^3
*/
let denominator :=
addmod(
addmod(mload(S_EVAL_LOC), mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_BETA_LOC), p), p),
gamma_beta_constant,
p
)
let temp1 := mulmod(mload(C_ALPHA_SQR_LOC), mload(L_END_LOC), p)
denominator := addmod(denominator, sub(p, temp1), p)
denominator := mulmod(denominator, mload(Z_LOOKUP_OMEGA_EVAL_LOC), p)
denominator := addmod(denominator, mulmod(temp1, mload(PLOOKUP_DELTA_LOC), p), p)
mstore(PLOOKUP_IDENTITY, mulmod(addmod(numerator, sub(p, denominator), p), mload(C_ALPHA_BASE_LOC), p))
// update alpha
mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p))
}
/**
* COMPUTE ARITHMETIC WIDGET EVALUATION
*/
{
/**
* The basic arithmetic gate identity in standard plonk is as follows.
* (w_1 . w_2 . q_m) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c = 0
* However, for Ultraplonk, we extend this to support "passing" wires between rows (shown without alpha scaling below):
* q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) +
* (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0
*
* This formula results in several cases depending on q_arith:
* 1. q_arith == 0: Arithmetic gate is completely disabled
*
* 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk equation
* with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0
*
* 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is:
* (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0
* It allows defining w_4 at next index (w_4_omega) in terms of current wire values
*
* 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α allows us to split
* the equation into two:
*
* q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0
* and
* w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here)
*
* 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by (q_arith - 1).
* The equation can be split into two:
*
* (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega = 0
* and
* w_1 + w_4 - w_1_omega + q_m = 0
*
* The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values at
* the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - 3) at
* product.
*/
let w1q1 := mulmod(mload(W1_EVAL_LOC), mload(Q1_EVAL_LOC), p)
let w2q2 := mulmod(mload(W2_EVAL_LOC), mload(Q2_EVAL_LOC), p)
let w3q3 := mulmod(mload(W3_EVAL_LOC), mload(Q3_EVAL_LOC), p)
let w4q3 := mulmod(mload(W4_EVAL_LOC), mload(Q4_EVAL_LOC), p)
// @todo - Add a explicit test that hits QARITH == 3
// w1w2qm := (w_1 . w_2 . q_m . (QARITH_EVAL_LOC - 3)) / 2
let w1w2qm :=
mulmod(
mulmod(
mulmod(mulmod(mload(W1_EVAL_LOC), mload(W2_EVAL_LOC), p), mload(QM_EVAL_LOC), p),
addmod(mload(QARITH_EVAL_LOC), sub(p, 3), p),
p
),
NEGATIVE_INVERSE_OF_2_MODULO_P,
p
)
// (w_1 . w_2 . q_m . (q_arith - 3)) / -2) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c
let identity :=
addmod(
mload(QC_EVAL_LOC), addmod(w4q3, addmod(w3q3, addmod(w2q2, addmod(w1q1, w1w2qm, p), p), p), p), p
)
// if q_arith == 3 we evaluate an additional mini addition gate (on top of the regular one), where:
// w_1 + w_4 - w_1_omega + q_m = 0
// we use this gate to save an addition gate when adding or subtracting non-native field elements
// α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m)
let extra_small_addition_gate_identity :=
mulmod(
mload(C_ALPHA_LOC),
mulmod(
addmod(mload(QARITH_EVAL_LOC), sub(p, 2), p),
addmod(
mload(QM_EVAL_LOC),
addmod(
sub(p, mload(W1_OMEGA_EVAL_LOC)), addmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), p
),
p
),
p
),
p
)
// if q_arith == 2 OR q_arith == 3 we add the 4th wire of the NEXT gate into the arithmetic identity
// N.B. if q_arith > 2, this wire value will be scaled by (q_arith - 1) relative to the other gate wires!
// alpha_base * q_arith * (identity + (q_arith - 1) * (w_4_omega + extra_small_addition_gate_identity))
mstore(
ARITHMETIC_IDENTITY,
mulmod(
mload(C_ALPHA_BASE_LOC),
mulmod(
mload(QARITH_EVAL_LOC),
addmod(
identity,
mulmod(
addmod(mload(QARITH_EVAL_LOC), sub(p, 1), p),
addmod(mload(W4_OMEGA_EVAL_LOC), extra_small_addition_gate_identity, p),
p
),
p
),
p
),
p
)
)
// update alpha
mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p))
}
/**
* COMPUTE GENPERMSORT WIDGET EVALUATION
*/
{
/**
* D1 = (w2 - w1)
* D2 = (w3 - w2)
* D3 = (w4 - w3)
* D4 = (w1_omega - w4)
*
* α_a = alpha_base
* α_b = alpha_base * α
* α_c = alpha_base * α^2
* α_d = alpha_base * α^3
*
* range_accumulator = (
* D1(D1 - 1)(D1 - 2)(D1 - 3).α_a +
* D2(D2 - 1)(D2 - 2)(D2 - 3).α_b +
* D3(D3 - 1)(D3 - 2)(D3 - 3).α_c +
* D4(D4 - 1)(D4 - 2)(D4 - 3).α_d +
* ) . q_sort
*/
let minus_two := sub(p, 2)
let minus_three := sub(p, 3)
let d1 := addmod(mload(W2_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)
let d2 := addmod(mload(W3_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)
let d3 := addmod(mload(W4_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)
let d4 := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)
let range_accumulator :=
mulmod(
mulmod(
mulmod(addmod(mulmod(d1, d1, p), sub(p, d1), p), addmod(d1, minus_two, p), p),
addmod(d1, minus_three, p),
p
),
mload(C_ALPHA_BASE_LOC),
p
)
range_accumulator :=
addmod(
range_accumulator,
mulmod(
mulmod(
mulmod(addmod(mulmod(d2, d2, p), sub(p, d2), p), addmod(d2, minus_two, p), p),
addmod(d2, minus_three, p),
p
),
mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p),
p
),
p
)
range_accumulator :=
addmod(
range_accumulator,
mulmod(
mulmod(
mulmod(addmod(mulmod(d3, d3, p), sub(p, d3), p), addmod(d3, minus_two, p), p),
addmod(d3, minus_three, p),
p
),
mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p),
p
),
p
)
range_accumulator :=
addmod(
range_accumulator,
mulmod(
mulmod(
mulmod(addmod(mulmod(d4, d4, p), sub(p, d4), p), addmod(d4, minus_two, p), p),
addmod(d4, minus_three, p),
p
),
mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p),
p
),
p
)
range_accumulator := mulmod(range_accumulator, mload(QSORT_EVAL_LOC), p)
mstore(SORT_IDENTITY, range_accumulator)
// update alpha
mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p))
}
/**
* COMPUTE ELLIPTIC WIDGET EVALUATION
*/
{
/**
* endo_term = (-x_2) * x_1 * (x_3 * 2 + x_1) * q_beta
* endo_sqr_term = x_2^2
* endo_sqr_term *= (x_3 - x_1)
* endo_sqr_term *= q_beta^2
* leftovers = x_2^2
* leftovers *= x_2
* leftovers += x_1^2 * (x_3 + x_1) @follow-up Invalid comment in BB widget
* leftovers -= (y_2^2 + y_1^2)
* sign_term = y_2 * y_1
* sign_term += sign_term
* sign_term *= q_sign
*/
let endo_term :=
mulmod(
mulmod(
mulmod(sub(p, mload(X2_EVAL_LOC)), mload(X1_EVAL_LOC), p),
addmod(addmod(mload(X3_EVAL_LOC), mload(X3_EVAL_LOC), p), mload(X1_EVAL_LOC), p),
p
),
mload(QBETA_LOC),
p
)
let endo_sqr_term := mulmod(mload(X2_EVAL_LOC), mload(X2_EVAL_LOC), p)
endo_sqr_term := mulmod(endo_sqr_term, addmod(mload(X3_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p), p)
endo_sqr_term := mulmod(endo_sqr_term, mload(QBETA_SQR_LOC), p)
let leftovers := mulmod(mload(X2_EVAL_LOC), mload(X2_EVAL_LOC), p)
leftovers := mulmod(leftovers, mload(X2_EVAL_LOC), p)
leftovers :=
addmod(
leftovers,
mulmod(
mulmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p),
addmod(mload(X3_EVAL_LOC), mload(X1_EVAL_LOC), p),
p
),
p
)
leftovers :=
addmod(
leftovers,
sub(
p,
addmod(
mulmod(mload(Y2_EVAL_LOC), mload(Y2_EVAL_LOC), p),
mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p),
p
)
),
p
)
let sign_term := mulmod(mload(Y2_EVAL_LOC), mload(Y1_EVAL_LOC), p)
sign_term := addmod(sign_term, sign_term, p)
sign_term := mulmod(sign_term, mload(QSIGN_LOC), p)
/**
* x_identity = endo_term + endo_sqr_term + sign_term + leftovers
* x_identity *= alpha_base
* endo_term = (x_2 * q_beta) * (y_3 + y_1)
* sign_term = -((y2 * q_sign) * (x_1 + x_3))
* leftovers = - x1 * (y_3 + y_1) + y_1 * (x_1 - x_3)
* y_identity = (endo_term + sign_term + leftovers) * (alpha_base * α)
*/
let x_identity := addmod(addmod(endo_term, endo_sqr_term, p), addmod(sign_term, leftovers, p), p)
x_identity := mulmod(x_identity, mload(C_ALPHA_BASE_LOC), p)
endo_term :=
mulmod(
mulmod(mload(X2_EVAL_LOC), mload(QBETA_LOC), p),
addmod(mload(Y3_EVAL_LOC), mload(Y1_EVAL_LOC), p),
p
)
sign_term :=
sub(
p,
mulmod(
mulmod(mload(Y2_EVAL_LOC), mload(QSIGN_LOC), p),
addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p),
p
)
)
leftovers :=
addmod(
sub(p, mulmod(mload(X1_EVAL_LOC), addmod(mload(Y3_EVAL_LOC), mload(Y1_EVAL_LOC), p), p)),
mulmod(mload(Y1_EVAL_LOC), addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), p),
p
)
let y_identity :=
mulmod(
addmod(addmod(endo_term, sign_term, p), leftovers, p),
mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p),
p
)
// ELLIPTIC_IDENTITY = (x_identity + y_identity) * Q_ELLIPTIC_EVAL
mstore(ELLIPTIC_IDENTITY, mulmod(addmod(x_identity, y_identity, p), mload(QELLIPTIC_EVAL_LOC), p))
// update alpha
// The paper says to use ALPHA^2, we use ALPHA^4 this is a small oversight in the prover protocol
mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p))
}
/**
* COMPUTE AUXILIARY WIDGET EVALUATION
*/
{
{
/**
* Non native field arithmetic gate 2
* _ _
* / _ _ _ 14 \
* q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 |
* \_ _/
*
* limb_subproduct = w_1 . w_2_omega + w_1_omega . w_2
* non_native_field_gate_2 = w_1 * w_4 + w_4 * w_3 - w_3_omega
* non_native_field_gate_2 = non_native_field_gate_2 * limb_size
* non_native_field_gate_2 -= w_4_omega
* non_native_field_gate_2 += limb_subproduct
* non_native_field_gate_2 *= q_4
* limb_subproduct *= limb_size
* limb_subproduct += w_1_omega * w_2_omega
* non_native_field_gate_1 = (limb_subproduct + w_3 + w_4) * q_3
* non_native_field_gate_3 = (limb_subproduct + w_4 - (w_3_omega + w_4_omega)) * q_m
* non_native_field_identity = (non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3) * q_2
*/
let limb_subproduct :=
addmod(
mulmod(mload(W1_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p),
mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_EVAL_LOC), p),
p
)
let non_native_field_gate_2 :=
addmod(
addmod(
mulmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p),
mulmod(mload(W2_EVAL_LOC), mload(W3_EVAL_LOC), p),
p
),
sub(p, mload(W3_OMEGA_EVAL_LOC)),
p
)
non_native_field_gate_2 := mulmod(non_native_field_gate_2, LIMB_SIZE, p)
non_native_field_gate_2 := addmod(non_native_field_gate_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p)
non_native_field_gate_2 := addmod(non_native_field_gate_2, limb_subproduct, p)
non_native_field_gate_2 := mulmod(non_native_field_gate_2, mload(Q4_EVAL_LOC), p)
limb_subproduct := mulmod(limb_subproduct, LIMB_SIZE, p)
limb_subproduct :=
addmod(limb_subproduct, mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p)
let non_native_field_gate_1 :=
mulmod(
addmod(limb_subproduct, sub(p, addmod(mload(W3_EVAL_LOC), mload(W4_EVAL_LOC), p)), p),
mload(Q3_EVAL_LOC),
p
)
let non_native_field_gate_3 :=
mulmod(
addmod(
addmod(limb_subproduct, mload(W4_EVAL_LOC), p),
sub(p, addmod(mload(W3_OMEGA_EVAL_LOC), mload(W4_OMEGA_EVAL_LOC), p)),
p
),
mload(QM_EVAL_LOC),
p
)
let non_native_field_identity :=
mulmod(
addmod(addmod(non_native_field_gate_1, non_native_field_gate_2, p), non_native_field_gate_3, p),
mload(Q2_EVAL_LOC),
p
)
mstore(AUX_NON_NATIVE_FIELD_EVALUATION, non_native_field_identity)
}
{
/**
* limb_accumulator_1 = w_2_omega;
* limb_accumulator_1 *= SUBLIMB_SHIFT;
* limb_accumulator_1 += w_1_omega;
* limb_accumulator_1 *= SUBLIMB_SHIFT;
* limb_accumulator_1 += w_3;
* limb_accumulator_1 *= SUBLIMB_SHIFT;
* limb_accumulator_1 += w_2;
* limb_accumulator_1 *= SUBLIMB_SHIFT;
* limb_accumulator_1 += w_1;
* limb_accumulator_1 -= w_4;
* limb_accumulator_1 *= q_4;
*/
let limb_accumulator_1 := mulmod(mload(W2_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p)
limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_OMEGA_EVAL_LOC), p)
limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)
limb_accumulator_1 := addmod(limb_accumulator_1, mload(W3_EVAL_LOC), p)
limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)
limb_accumulator_1 := addmod(limb_accumulator_1, mload(W2_EVAL_LOC), p)
limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)
limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_EVAL_LOC), p)
limb_accumulator_1 := addmod(limb_accumulator_1, sub(p, mload(W4_EVAL_LOC)), p)
limb_accumulator_1 := mulmod(limb_accumulator_1, mload(Q4_EVAL_LOC), p)
/**
* limb_accumulator_2 = w_3_omega;
* limb_accumulator_2 *= SUBLIMB_SHIFT;
* limb_accumulator_2 += w_2_omega;
* limb_accumulator_2 *= SUBLIMB_SHIFT;
* limb_accumulator_2 += w_1_omega;
* limb_accumulator_2 *= SUBLIMB_SHIFT;
* limb_accumulator_2 += w_4;
* limb_accumulator_2 *= SUBLIMB_SHIFT;
* limb_accumulator_2 += w_3;
* limb_accumulator_2 -= w_4_omega;
* limb_accumulator_2 *= q_m;
*/
let limb_accumulator_2 := mulmod(mload(W3_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p)
limb_accumulator_2 := addmod(limb_accumulator_2, mload(W2_OMEGA_EVAL_LOC), p)
limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)
limb_accumulator_2 := addmod(limb_accumulator_2, mload(W1_OMEGA_EVAL_LOC), p)
limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)
limb_accumulator_2 := addmod(limb_accumulator_2, mload(W4_EVAL_LOC), p)
limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)
limb_accumulator_2 := addmod(limb_accumulator_2, mload(W3_EVAL_LOC), p)
limb_accumulator_2 := addmod(limb_accumulator_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p)
limb_accumulator_2 := mulmod(limb_accumulator_2, mload(QM_EVAL_LOC), p)
mstore(
AUX_LIMB_ACCUMULATOR_EVALUATION,
mulmod(addmod(limb_accumulator_1, limb_accumulator_2, p), mload(Q3_EVAL_LOC), p)
)
}
{
/**
* memory_record_check = w_3;
* memory_record_check *= eta;
* memory_record_check += w_2;
* memory_record_check *= eta;
* memory_record_check += w_1;
* memory_record_check *= eta;
* memory_record_check += q_c;
*
* partial_record_check = memory_record_check;
*
* memory_record_check -= w_4;
*/
let memory_record_check := mulmod(mload(W3_EVAL_LOC), mload(C_ETA_LOC), p)
memory_record_check := addmod(memory_record_check, mload(W2_EVAL_LOC), p)
memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p)
memory_record_check := addmod(memory_record_check, mload(W1_EVAL_LOC), p)
memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p)
memory_record_check := addmod(memory_record_check, mload(QC_EVAL_LOC), p)
let partial_record_check := memory_record_check
memory_record_check := addmod(memory_record_check, sub(p, mload(W4_EVAL_LOC)), p)
mstore(AUX_MEMORY_EVALUATION, memory_record_check)
// index_delta = w_1_omega - w_1
let index_delta := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)
// record_delta = w_4_omega - w_4
let record_delta := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)
// index_is_monotonically_increasing = index_delta * (index_delta - 1)
let index_is_monotonically_increasing := mulmod(index_delta, addmod(index_delta, sub(p, 1), p), p)
// adjacent_values_match_if_adjacent_indices_match = record_delta * (1 - index_delta)
let adjacent_values_match_if_adjacent_indices_match :=
mulmod(record_delta, addmod(1, sub(p, index_delta), p), p)
// AUX_ROM_CONSISTENCY_EVALUATION = ((adjacent_values_match_if_adjacent_indices_match * alpha) + index_is_monotonically_increasing) * alpha + partial_record_check
mstore(
AUX_ROM_CONSISTENCY_EVALUATION,
addmod(
mulmod(
addmod(
mulmod(adjacent_values_match_if_adjacent_indices_match, mload(C_ALPHA_LOC), p),
index_is_monotonically_increasing,
p
),
mload(C_ALPHA_LOC),
p
),
memory_record_check,
p
)
)
{
/**
* next_gate_access_type = w_3_omega;
* next_gate_access_type *= eta;
* next_gate_access_type += w_2_omega;
* next_gate_access_type *= eta;
* next_gate_access_type += w_1_omega;
* next_gate_access_type *= eta;
* next_gate_access_type = w_4_omega - next_gate_access_type;
*/
let next_gate_access_type := mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p)
next_gate_access_type := addmod(next_gate_access_type, mload(W2_OMEGA_EVAL_LOC), p)
next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p)
next_gate_access_type := addmod(next_gate_access_type, mload(W1_OMEGA_EVAL_LOC), p)
next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p)
next_gate_access_type := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, next_gate_access_type), p)
// value_delta = w_3_omega - w_3
let value_delta := addmod(mload(W3_OMEGA_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)
// adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (1 - index_delta) * value_delta * (1 - next_gate_access_type);
let adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation :=
mulmod(
addmod(1, sub(p, index_delta), p),
mulmod(value_delta, addmod(1, sub(p, next_gate_access_type), p), p),
p
)
// AUX_RAM_CONSISTENCY_EVALUATION
/**
* access_type = w_4 - partial_record_check
* access_check = access_type^2 - access_type
* next_gate_access_type_is_boolean = next_gate_access_type^2 - next_gate_access_type
* RAM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation;
* RAM_consistency_check_identity *= alpha;
* RAM_consistency_check_identity += index_is_monotonically_increasing;
* RAM_consistency_check_identity *= alpha;
* RAM_consistency_check_identity += next_gate_access_type_is_boolean;
* RAM_consistency_check_identity *= alpha;
* RAM_consistency_check_identity += access_check;
*/
let access_type := addmod(mload(W4_EVAL_LOC), sub(p, partial_record_check), p)
let access_check := mulmod(access_type, addmod(access_type, sub(p, 1), p), p)
let next_gate_access_type_is_boolean :=
mulmod(next_gate_access_type, addmod(next_gate_access_type, sub(p, 1), p), p)
let RAM_cci :=
mulmod(
adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation,
mload(C_ALPHA_LOC),
p
)
RAM_cci := addmod(RAM_cci, index_is_monotonically_increasing, p)
RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p)
RAM_cci := addmod(RAM_cci, next_gate_access_type_is_boolean, p)
RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p)
RAM_cci := addmod(RAM_cci, access_check, p)
mstore(AUX_RAM_CONSISTENCY_EVALUATION, RAM_cci)
}
{
// timestamp_delta = w_2_omega - w_2
let timestamp_delta := addmod(mload(W2_OMEGA_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)
// RAM_timestamp_check_identity = (1 - index_delta) * timestamp_delta - w_3
let RAM_timestamp_check_identity :=
addmod(
mulmod(timestamp_delta, addmod(1, sub(p, index_delta), p), p), sub(p, mload(W3_EVAL_LOC)), p
)
/**
* memory_identity = ROM_consistency_check_identity * q_2;
* memory_identity += RAM_timestamp_check_identity * q_4;
* memory_identity += memory_record_check * q_m;
* memory_identity *= q_1;
* memory_identity += (RAM_consistency_check_identity * q_arith);
*
* auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity;
* auxiliary_identity *= q_aux;
* auxiliary_identity *= alpha_base;
*/
let memory_identity := mulmod(mload(AUX_ROM_CONSISTENCY_EVALUATION), mload(Q2_EVAL_LOC), p)
memory_identity :=
addmod(memory_identity, mulmod(RAM_timestamp_check_identity, mload(Q4_EVAL_LOC), p), p)
memory_identity :=
addmod(memory_identity, mulmod(mload(AUX_MEMORY_EVALUATION), mload(QM_EVAL_LOC), p), p)
memory_identity := mulmod(memory_identity, mload(Q1_EVAL_LOC), p)
memory_identity :=
addmod(
memory_identity, mulmod(mload(AUX_RAM_CONSISTENCY_EVALUATION), mload(QARITH_EVAL_LOC), p), p
)
let auxiliary_identity := addmod(memory_identity, mload(AUX_NON_NATIVE_FIELD_EVALUATION), p)
auxiliary_identity := addmod(auxiliary_identity, mload(AUX_LIMB_ACCUMULATOR_EVALUATION), p)
auxiliary_identity := mulmod(auxiliary_identity, mload(QAUX_EVAL_LOC), p)
auxiliary_identity := mulmod(auxiliary_identity, mload(C_ALPHA_BASE_LOC), p)
mstore(AUX_IDENTITY, auxiliary_identity)
// update alpha
mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p))
}
}
}
{
/**
* quotient = ARITHMETIC_IDENTITY
* quotient += PERMUTATION_IDENTITY
* quotient += PLOOKUP_IDENTITY
* quotient += SORT_IDENTITY
* quotient += ELLIPTIC_IDENTITY
* quotient += AUX_IDENTITY
* quotient *= ZERO_POLY_INVERSE
*/
mstore(
QUOTIENT_EVAL_LOC,
mulmod(
addmod(
addmod(
addmod(
addmod(
addmod(mload(PERMUTATION_IDENTITY), mload(PLOOKUP_IDENTITY), p),
mload(ARITHMETIC_IDENTITY),
p
),
mload(SORT_IDENTITY),
p
),
mload(ELLIPTIC_IDENTITY),
p
),
mload(AUX_IDENTITY),
p
),
mload(ZERO_POLY_INVERSE_LOC),
p
)
)
}
/**
* GENERATE NU AND SEPARATOR CHALLENGES
*/
{
let current_challenge := mload(C_CURRENT_LOC)
// get a calldata pointer that points to the start of the data we want to copy
let calldata_ptr := add(calldataload(0x04), 0x24)
calldata_ptr := add(calldata_ptr, NU_CALLDATA_SKIP_LENGTH)
mstore(NU_CHALLENGE_INPUT_LOC_A, current_challenge)
mstore(NU_CHALLENGE_INPUT_LOC_B, mload(QUOTIENT_EVAL_LOC))
calldatacopy(NU_CHALLENGE_INPUT_LOC_C, calldata_ptr, NU_INPUT_LENGTH)
// hash length = (0x20 + num field elements), we include the previous challenge in the hash
let challenge := keccak256(NU_CHALLENGE_INPUT_LOC_A, add(NU_INPUT_LENGTH, 0x40))
mstore(C_V0_LOC, mod(challenge, p))
// We need THIRTY-ONE independent nu challenges!
mstore(0x00, challenge)
mstore8(0x20, 0x01)
mstore(C_V1_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x02)
mstore(C_V2_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x03)
mstore(C_V3_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x04)
mstore(C_V4_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x05)
mstore(C_V5_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x06)
mstore(C_V6_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x07)
mstore(C_V7_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x08)
mstore(C_V8_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x09)
mstore(C_V9_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x0a)
mstore(C_V10_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x0b)
mstore(C_V11_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x0c)
mstore(C_V12_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x0d)
mstore(C_V13_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x0e)
mstore(C_V14_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x0f)
mstore(C_V15_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x10)
mstore(C_V16_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x11)
mstore(C_V17_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x12)
mstore(C_V18_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x13)
mstore(C_V19_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x14)
mstore(C_V20_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x15)
mstore(C_V21_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x16)
mstore(C_V22_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x17)
mstore(C_V23_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x18)
mstore(C_V24_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x19)
mstore(C_V25_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x1a)
mstore(C_V26_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x1b)
mstore(C_V27_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x1c)
mstore(C_V28_LOC, mod(keccak256(0x00, 0x21), p))
mstore8(0x20, 0x1d)
mstore(C_V29_LOC, mod(keccak256(0x00, 0x21), p))
// @follow-up - Why are both v29 and v30 using appending 0x1d to the prior challenge and hashing, should it not change?
mstore8(0x20, 0x1d)
challenge := keccak256(0x00, 0x21)
mstore(C_V30_LOC, mod(challenge, p))
// separator
mstore(0x00, challenge)
mstore(0x20, mload(PI_Z_Y_LOC))
mstore(0x40, mload(PI_Z_X_LOC))
mstore(0x60, mload(PI_Z_OMEGA_Y_LOC))
mstore(0x80, mload(PI_Z_OMEGA_X_LOC))
mstore(C_U_LOC, mod(keccak256(0x00, 0xa0), p))
}
let success := 0
// VALIDATE T1
{
let x := mload(T1_X_LOC)
let y := mload(T1_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))
mstore(ACCUMULATOR_X_LOC, x)
mstore(add(ACCUMULATOR_X_LOC, 0x20), y)
}
// VALIDATE T2
{
let x := mload(T2_X_LOC) // 0x1400
let y := mload(T2_Y_LOC) // 0x1420
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(ZETA_POW_N_LOC))
// accumulator_2 = [T2].zeta^n
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = [T1] + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE T3
{
let x := mload(T3_X_LOC)
let y := mload(T3_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p))
// accumulator_2 = [T3].zeta^{2n}
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE T4
{
let x := mload(T4_X_LOC)
let y := mload(T4_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p), mload(ZETA_POW_N_LOC), p))
// accumulator_2 = [T4].zeta^{3n}
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE W1
{
let x := mload(W1_X_LOC)
let y := mload(W1_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V0_LOC), p))
// accumulator_2 = v0.(u + 1).[W1]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE W2
{
let x := mload(W2_X_LOC)
let y := mload(W2_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V1_LOC), p))
// accumulator_2 = v1.(u + 1).[W2]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE W3
{
let x := mload(W3_X_LOC)
let y := mload(W3_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V2_LOC), p))
// accumulator_2 = v2.(u + 1).[W3]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE W4
{
let x := mload(W4_X_LOC)
let y := mload(W4_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V3_LOC), p))
// accumulator_2 = v3.(u + 1).[W4]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE S
{
let x := mload(S_X_LOC)
let y := mload(S_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V4_LOC), p))
// accumulator_2 = v4.(u + 1).[S]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE Z
{
let x := mload(Z_X_LOC)
let y := mload(Z_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V5_LOC), p))
// accumulator_2 = v5.(u + 1).[Z]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE Z_LOOKUP
{
let x := mload(Z_LOOKUP_X_LOC)
let y := mload(Z_LOOKUP_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V6_LOC), p))
// accumulator_2 = v6.(u + 1).[Z_LOOKUP]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE Q1
{
let x := mload(Q1_X_LOC)
let y := mload(Q1_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V7_LOC))
// accumulator_2 = v7.[Q1]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE Q2
{
let x := mload(Q2_X_LOC)
let y := mload(Q2_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V8_LOC))
// accumulator_2 = v8.[Q2]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE Q3
{
let x := mload(Q3_X_LOC)
let y := mload(Q3_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V9_LOC))
// accumulator_2 = v9.[Q3]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE Q4
{
let x := mload(Q4_X_LOC)
let y := mload(Q4_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V10_LOC))
// accumulator_2 = v10.[Q4]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE QM
{
let x := mload(QM_X_LOC)
let y := mload(QM_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V11_LOC))
// accumulator_2 = v11.[Q;]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE QC
{
let x := mload(QC_X_LOC)
let y := mload(QC_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V12_LOC))
// accumulator_2 = v12.[QC]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE QARITH
{
let x := mload(QARITH_X_LOC)
let y := mload(QARITH_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V13_LOC))
// accumulator_2 = v13.[QARITH]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE QSORT
{
let x := mload(QSORT_X_LOC)
let y := mload(QSORT_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V14_LOC))
// accumulator_2 = v14.[QSORT]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE QELLIPTIC
{
let x := mload(QELLIPTIC_X_LOC)
let y := mload(QELLIPTIC_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V15_LOC))
// accumulator_2 = v15.[QELLIPTIC]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE QAUX
{
let x := mload(QAUX_X_LOC)
let y := mload(QAUX_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V16_LOC))
// accumulator_2 = v15.[Q_AUX]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE SIGMA1
{
let x := mload(SIGMA1_X_LOC)
let y := mload(SIGMA1_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V17_LOC))
// accumulator_2 = v17.[sigma1]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE SIGMA2
{
let x := mload(SIGMA2_X_LOC)
let y := mload(SIGMA2_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V18_LOC))
// accumulator_2 = v18.[sigma2]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE SIGMA3
{
let x := mload(SIGMA3_X_LOC)
let y := mload(SIGMA3_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V19_LOC))
// accumulator_2 = v19.[sigma3]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE SIGMA4
{
let x := mload(SIGMA4_X_LOC)
let y := mload(SIGMA4_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V20_LOC))
// accumulator_2 = v20.[sigma4]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE TABLE1
{
let x := mload(TABLE1_X_LOC)
let y := mload(TABLE1_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V21_LOC), p))
// accumulator_2 = u.[table1]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE TABLE2
{
let x := mload(TABLE2_X_LOC)
let y := mload(TABLE2_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V22_LOC), p))
// accumulator_2 = u.[table2]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE TABLE3
{
let x := mload(TABLE3_X_LOC)
let y := mload(TABLE3_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V23_LOC), p))
// accumulator_2 = u.[table3]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE TABLE4
{
let x := mload(TABLE4_X_LOC)
let y := mload(TABLE4_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V24_LOC), p))
// accumulator_2 = u.[table4]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE TABLE_TYPE
{
let x := mload(TABLE_TYPE_X_LOC)
let y := mload(TABLE_TYPE_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V25_LOC))
// accumulator_2 = v25.[TableType]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE ID1
{
let x := mload(ID1_X_LOC)
let y := mload(ID1_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V26_LOC))
// accumulator_2 = v26.[ID1]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE ID2
{
let x := mload(ID2_X_LOC)
let y := mload(ID2_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V27_LOC))
// accumulator_2 = v27.[ID2]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE ID3
{
let x := mload(ID3_X_LOC)
let y := mload(ID3_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V28_LOC))
// accumulator_2 = v28.[ID3]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE ID4
{
let x := mload(ID4_X_LOC)
let y := mload(ID4_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mload(C_V29_LOC))
// accumulator_2 = v29.[ID4]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
/**
* COMPUTE BATCH EVALUATION SCALAR MULTIPLIER
*/
{
/**
* batch_evaluation = v0 * (w_1_omega * u + w_1_eval)
* batch_evaluation += v1 * (w_2_omega * u + w_2_eval)
* batch_evaluation += v2 * (w_3_omega * u + w_3_eval)
* batch_evaluation += v3 * (w_4_omega * u + w_4_eval)
* batch_evaluation += v4 * (s_omega_eval * u + s_eval)
* batch_evaluation += v5 * (z_omega_eval * u + z_eval)
* batch_evaluation += v6 * (z_lookup_omega_eval * u + z_lookup_eval)
*/
let batch_evaluation :=
mulmod(
mload(C_V0_LOC),
addmod(mulmod(mload(W1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W1_EVAL_LOC), p),
p
)
batch_evaluation :=
addmod(
batch_evaluation,
mulmod(
mload(C_V1_LOC),
addmod(mulmod(mload(W2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W2_EVAL_LOC), p),
p
),
p
)
batch_evaluation :=
addmod(
batch_evaluation,
mulmod(
mload(C_V2_LOC),
addmod(mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W3_EVAL_LOC), p),
p
),
p
)
batch_evaluation :=
addmod(
batch_evaluation,
mulmod(
mload(C_V3_LOC),
addmod(mulmod(mload(W4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W4_EVAL_LOC), p),
p
),
p
)
batch_evaluation :=
addmod(
batch_evaluation,
mulmod(
mload(C_V4_LOC),
addmod(mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(S_EVAL_LOC), p),
p
),
p
)
batch_evaluation :=
addmod(
batch_evaluation,
mulmod(
mload(C_V5_LOC),
addmod(mulmod(mload(Z_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_EVAL_LOC), p),
p
),
p
)
batch_evaluation :=
addmod(
batch_evaluation,
mulmod(
mload(C_V6_LOC),
addmod(mulmod(mload(Z_LOOKUP_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_LOOKUP_EVAL_LOC), p),
p
),
p
)
/**
* batch_evaluation += v7 * Q1_EVAL
* batch_evaluation += v8 * Q2_EVAL
* batch_evaluation += v9 * Q3_EVAL
* batch_evaluation += v10 * Q4_EVAL
* batch_evaluation += v11 * QM_EVAL
* batch_evaluation += v12 * QC_EVAL
* batch_evaluation += v13 * QARITH_EVAL
* batch_evaluation += v14 * QSORT_EVAL_LOC
* batch_evaluation += v15 * QELLIPTIC_EVAL_LOC
* batch_evaluation += v16 * QAUX_EVAL_LOC
* batch_evaluation += v17 * SIGMA1_EVAL_LOC
* batch_evaluation += v18 * SIGMA2_EVAL_LOC
* batch_evaluation += v19 * SIGMA3_EVAL_LOC
* batch_evaluation += v20 * SIGMA4_EVAL_LOC
*/
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V7_LOC), mload(Q1_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V8_LOC), mload(Q2_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V9_LOC), mload(Q3_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V10_LOC), mload(Q4_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V11_LOC), mload(QM_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V12_LOC), mload(QC_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V13_LOC), mload(QARITH_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V14_LOC), mload(QSORT_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V15_LOC), mload(QELLIPTIC_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V16_LOC), mload(QAUX_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V17_LOC), mload(SIGMA1_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V18_LOC), mload(SIGMA2_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V19_LOC), mload(SIGMA3_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V20_LOC), mload(SIGMA4_EVAL_LOC), p), p)
/**
* batch_evaluation += v21 * (table1(zw) * u + table1(z))
* batch_evaluation += v22 * (table2(zw) * u + table2(z))
* batch_evaluation += v23 * (table3(zw) * u + table3(z))
* batch_evaluation += v24 * (table4(zw) * u + table4(z))
* batch_evaluation += v25 * table_type_eval
* batch_evaluation += v26 * id1_eval
* batch_evaluation += v27 * id2_eval
* batch_evaluation += v28 * id3_eval
* batch_evaluation += v29 * id4_eval
* batch_evaluation += quotient_eval
*/
batch_evaluation :=
addmod(
batch_evaluation,
mulmod(
mload(C_V21_LOC),
addmod(mulmod(mload(TABLE1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE1_EVAL_LOC), p),
p
),
p
)
batch_evaluation :=
addmod(
batch_evaluation,
mulmod(
mload(C_V22_LOC),
addmod(mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE2_EVAL_LOC), p),
p
),
p
)
batch_evaluation :=
addmod(
batch_evaluation,
mulmod(
mload(C_V23_LOC),
addmod(mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE3_EVAL_LOC), p),
p
),
p
)
batch_evaluation :=
addmod(
batch_evaluation,
mulmod(
mload(C_V24_LOC),
addmod(mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE4_EVAL_LOC), p),
p
),
p
)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V25_LOC), mload(TABLE_TYPE_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V26_LOC), mload(ID1_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V27_LOC), mload(ID2_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V28_LOC), mload(ID3_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V29_LOC), mload(ID4_EVAL_LOC), p), p)
batch_evaluation := addmod(batch_evaluation, mload(QUOTIENT_EVAL_LOC), p)
mstore(0x00, 0x01) // [1].x
mstore(0x20, 0x02) // [1].y
mstore(0x40, sub(p, batch_evaluation))
// accumulator_2 = -[1].(batch_evaluation)
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
mstore(OPENING_COMMITMENT_SUCCESS_FLAG, success)
}
/**
* PERFORM PAIRING PREAMBLE
*/
{
let u := mload(C_U_LOC)
let zeta := mload(C_ZETA_LOC)
// VALIDATE PI_Z
{
let x := mload(PI_Z_X_LOC)
let y := mload(PI_Z_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))
mstore(0x00, x)
mstore(0x20, y)
}
// compute zeta.[PI_Z] and add into accumulator
mstore(0x40, zeta)
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// accumulator = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
// VALIDATE PI_Z_OMEGA
{
let x := mload(PI_Z_OMEGA_X_LOC)
let y := mload(PI_Z_OMEGA_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
mstore(0x40, mulmod(mulmod(u, zeta, p), mload(OMEGA_LOC), p))
// accumulator_2 = u.zeta.omega.[PI_Z_OMEGA]
success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
// PAIRING_RHS = accumulator + accumulator_2
success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, PAIRING_RHS_X_LOC, 0x40))
mstore(0x00, mload(PI_Z_X_LOC))
mstore(0x20, mload(PI_Z_Y_LOC))
mstore(0x40, mload(PI_Z_OMEGA_X_LOC))
mstore(0x60, mload(PI_Z_OMEGA_Y_LOC))
mstore(0x80, u)
success := and(success, staticcall(gas(), 7, 0x40, 0x60, 0x40, 0x40))
// PAIRING_LHS = [PI_Z] + [PI_Z_OMEGA] * u
success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40))
// negate lhs y-coordinate
mstore(PAIRING_LHS_Y_LOC, sub(q, mload(PAIRING_LHS_Y_LOC)))
if mload(CONTAINS_RECURSIVE_PROOF_LOC) {
// VALIDATE RECURSIVE P1
{
let x := mload(RECURSIVE_P1_X_LOC)
let y := mload(RECURSIVE_P1_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
// compute u.u.[recursive_p1] and write into 0x60
mstore(0x40, mulmod(u, u, p))
success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x60, 0x40))
// VALIDATE RECURSIVE P2
{
let x := mload(RECURSIVE_P2_X_LOC)
let y := mload(RECURSIVE_P2_Y_LOC)
let xx := mulmod(x, x, q)
// validate on curve
success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
mstore(0x00, x)
mstore(0x20, y)
}
// compute u.u.[recursive_p2] and write into 0x00
// 0x40 still contains u*u
success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x00, 0x40))
// compute u.u.[recursiveP1] + rhs and write into rhs
mstore(0xa0, mload(PAIRING_RHS_X_LOC))
mstore(0xc0, mload(PAIRING_RHS_Y_LOC))
success := and(success, staticcall(gas(), 6, 0x60, 0x80, PAIRING_RHS_X_LOC, 0x40))
// compute u.u.[recursiveP2] + lhs and write into lhs
mstore(0x40, mload(PAIRING_LHS_X_LOC))
mstore(0x60, mload(PAIRING_LHS_Y_LOC))
success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40))
}
if iszero(success) {
mstore(0x0, EC_SCALAR_MUL_FAILURE_SELECTOR)
revert(0x00, 0x04)
}
mstore(PAIRING_PREAMBLE_SUCCESS_FLAG, success)
}
/**
* PERFORM PAIRING
*/
{
// rhs paired with [1]_2
// lhs paired with [x]_2
mstore(0x00, mload(PAIRING_RHS_X_LOC))
mstore(0x20, mload(PAIRING_RHS_Y_LOC))
mstore(0x40, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) // this is [1]_2
mstore(0x60, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed)
mstore(0x80, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b)
mstore(0xa0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)
mstore(0xc0, mload(PAIRING_LHS_X_LOC))
mstore(0xe0, mload(PAIRING_LHS_Y_LOC))
mstore(0x100, mload(G2X_X0_LOC))
mstore(0x120, mload(G2X_X1_LOC))
mstore(0x140, mload(G2X_Y0_LOC))
mstore(0x160, mload(G2X_Y1_LOC))
success := staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20)
mstore(PAIRING_SUCCESS_FLAG, success)
mstore(RESULT_FLAG, mload(0x00))
}
if iszero(
and(
and(and(mload(PAIRING_SUCCESS_FLAG), mload(RESULT_FLAG)), mload(PAIRING_PREAMBLE_SUCCESS_FLAG)),
mload(OPENING_COMMITMENT_SUCCESS_FLAG)
)
) {
mstore(0x0, PROOF_FAILURE_SELECTOR)
revert(0x00, 0x04)
}
{
mstore(0x00, 0x01)
return(0x00, 0x20) // Proof succeeded!
}
}
}
}
contract UltraVerifier is BaseUltraVerifier {
function getVerificationKeyHash() public pure override(BaseUltraVerifier) returns (bytes32) {
return UltraVerificationKey.verificationKeyHash();
}
function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BaseUltraVerifier) {
UltraVerificationKey.loadVerificationKey(vk, _omegaInverseLoc);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment