mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-09 20:27:58 -05:00
1351 lines
58 KiB
Solidity
1351 lines
58 KiB
Solidity
// SPDX-License-Identifier: Apache-2.0
|
||
|
||
// Copyright 2023 Consensys Software Inc.
|
||
//
|
||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
// you may not use this file except in compliance with the License.
|
||
// You may obtain a copy of the License at
|
||
//
|
||
// http://www.apache.org/licenses/LICENSE-2.0
|
||
//
|
||
// Unless required by applicable law or agreed to in writing, software
|
||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
// See the License for the specific language governing permissions and
|
||
// limitations under the License.
|
||
|
||
// Code generated by gnark DO NOT EDIT
|
||
|
||
pragma solidity 0.8.28;
|
||
|
||
contract PlonkVerifierMainnetFull {
|
||
uint256 private constant R_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||
uint256 private constant R_MOD_MINUS_ONE =
|
||
21888242871839275222246405745257275088548364400416034343698204186575808495616;
|
||
uint256 private constant P_MOD = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||
|
||
uint256 private constant G2_SRS_0_X_0 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
|
||
uint256 private constant G2_SRS_0_X_1 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
|
||
uint256 private constant G2_SRS_0_Y_0 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
|
||
uint256 private constant G2_SRS_0_Y_1 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
|
||
|
||
uint256 private constant G2_SRS_1_X_0 = 15805639136721018565402881920352193254830339253282065586954346329754995870280;
|
||
uint256 private constant G2_SRS_1_X_1 = 19089565590083334368588890253123139704298730990782503769911324779715431555531;
|
||
uint256 private constant G2_SRS_1_Y_0 = 9779648407879205346559610309258181044130619080926897934572699915909528404984;
|
||
uint256 private constant G2_SRS_1_Y_1 = 6779728121489434657638426458390319301070371227460768374343986326751507916979;
|
||
|
||
uint256 private constant G1_SRS_X = 14312776538779914388377568895031746459131577658076416373430523308756343304251;
|
||
uint256 private constant G1_SRS_Y = 11763105256161367503191792604679297387056316997144156930871823008787082098465;
|
||
|
||
// ----------------------- vk ---------------------
|
||
uint256 private constant VK_NB_PUBLIC_INPUTS = 1;
|
||
uint256 private constant VK_DOMAIN_SIZE = 33554432;
|
||
uint256 private constant VK_INV_DOMAIN_SIZE =
|
||
21888242219518804655518433051623070663413851959604507555939307129453691614729;
|
||
uint256 private constant VK_OMEGA = 19200870435978225707111062059747084165650991997241425080699860725083300967194;
|
||
uint256 private constant VK_QL_COM_X = 16763721632302187064245116535318993406793422693670709276397395043117985043396;
|
||
uint256 private constant VK_QL_COM_Y = 21704519434294991344748680408475309717320132372621249588391334885901175870089;
|
||
uint256 private constant VK_QR_COM_X = 4659174267124804103032945565127374540672993228651562455767923366230378925207;
|
||
uint256 private constant VK_QR_COM_Y = 10075466426568401715266713487428009727978964696508926491453956484207585528204;
|
||
uint256 private constant VK_QM_COM_X = 5553410513240938543232634851474389708189012141911611575921923499176928976035;
|
||
uint256 private constant VK_QM_COM_Y = 21267989559503205894532435033155162591528358593663117280327683708498106399392;
|
||
uint256 private constant VK_QO_COM_X = 13140407506194185536762256003490074009791461766528862809770970563406607579309;
|
||
uint256 private constant VK_QO_COM_Y = 11663278532712784593989622026161493805298382402342305264603337558265085421392;
|
||
uint256 private constant VK_QK_COM_X = 21544117489243114508976994357104276445865936964460835218289822182809574259347;
|
||
uint256 private constant VK_QK_COM_Y = 16099525972751353512827910298795837779966478757167964357688560266722970909995;
|
||
|
||
uint256 private constant VK_S1_COM_X = 17908311428460199492590388039829063852878010071334545129594028234377672983820;
|
||
uint256 private constant VK_S1_COM_Y = 10103954308412520729697582995254223647125533280505646768640456923233032025547;
|
||
|
||
uint256 private constant VK_S2_COM_X = 12866105337297597904597049017273016292761285097880812243024788656739840139515;
|
||
uint256 private constant VK_S2_COM_Y = 20599250613846035633202356428996750914987720427398215234715506893022862458023;
|
||
|
||
uint256 private constant VK_S3_COM_X = 13307442681122525480630104759544119339845938219103784786642372773456371926253;
|
||
uint256 private constant VK_S3_COM_Y = 50594248840254746757473639804224481189760085670009668062319144215804614333;
|
||
|
||
uint256 private constant VK_COSET_SHIFT = 5;
|
||
|
||
uint256 private constant VK_QCP_0_X = 5422475623920098124263885207962814853820529823128844521562879788393274458288;
|
||
uint256 private constant VK_QCP_0_Y = 8659836707667766389541194141097455574165699707943735466972591014628520691103;
|
||
|
||
uint256 private constant VK_INDEX_COMMIT_API_0 = 9131137;
|
||
uint256 private constant VK_NB_CUSTOM_GATES = 1;
|
||
|
||
// ------------------------------------------------
|
||
|
||
// size of the proof without call custom gate
|
||
uint256 private constant FIXED_PROOF_SIZE = 0x300;
|
||
|
||
// offset proof
|
||
|
||
uint256 private constant PROOF_L_COM_X = 0x0;
|
||
uint256 private constant PROOF_L_COM_Y = 0x20;
|
||
uint256 private constant PROOF_R_COM_X = 0x40;
|
||
uint256 private constant PROOF_R_COM_Y = 0x60;
|
||
uint256 private constant PROOF_O_COM_X = 0x80;
|
||
uint256 private constant PROOF_O_COM_Y = 0xa0;
|
||
|
||
// h = h_0 + x^{n+2}h_1 + x^{2(n+2)}h_2
|
||
uint256 private constant PROOF_H_0_COM_X = 0xc0;
|
||
uint256 private constant PROOF_H_0_COM_Y = 0xe0;
|
||
uint256 private constant PROOF_H_1_COM_X = 0x100;
|
||
uint256 private constant PROOF_H_1_COM_Y = 0x120;
|
||
uint256 private constant PROOF_H_2_COM_X = 0x140;
|
||
uint256 private constant PROOF_H_2_COM_Y = 0x160;
|
||
|
||
// "evaluations of wire polynomials at zeta
|
||
uint256 private constant PROOF_L_AT_ZETA = 0x180;
|
||
uint256 private constant PROOF_R_AT_ZETA = 0x1a0;
|
||
uint256 private constant PROOF_O_AT_ZETA = 0x1c0;
|
||
|
||
// S1(zeta),S2(zeta)
|
||
uint256 private constant PROOF_S1_AT_ZETA = 0x1e0; // Sσ1(zeta)
|
||
uint256 private constant PROOF_S2_AT_ZETA = 0x200; // Sσ2(zeta)
|
||
|
||
// [Z]
|
||
uint256 private constant PROOF_GRAND_PRODUCT_COMMITMENT_X = 0x220;
|
||
uint256 private constant PROOF_GRAND_PRODUCT_COMMITMENT_Y = 0x240;
|
||
|
||
uint256 private constant PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA = 0x260; // z(w*zeta)
|
||
|
||
// Folded proof for the opening of linearised poly, l, r, o, s_1, s_2, qcp
|
||
uint256 private constant PROOF_BATCH_OPENING_AT_ZETA_X = 0x280;
|
||
uint256 private constant PROOF_BATCH_OPENING_AT_ZETA_Y = 0x2a0;
|
||
|
||
uint256 private constant PROOF_OPENING_AT_ZETA_OMEGA_X = 0x2c0;
|
||
uint256 private constant PROOF_OPENING_AT_ZETA_OMEGA_Y = 0x2e0;
|
||
|
||
uint256 private constant PROOF_OPENING_QCP_AT_ZETA = 0x300;
|
||
uint256 private constant PROOF_BSB_COMMITMENTS = 0x320;
|
||
|
||
// -------- offset state
|
||
|
||
// challenges to check the claimed quotient
|
||
|
||
uint256 private constant STATE_ALPHA = 0x0;
|
||
uint256 private constant STATE_BETA = 0x20;
|
||
uint256 private constant STATE_GAMMA = 0x40;
|
||
uint256 private constant STATE_ZETA = 0x60;
|
||
uint256 private constant STATE_ALPHA_SQUARE_LAGRANGE_0 = 0x80;
|
||
uint256 private constant STATE_FOLDED_H_X = 0xa0;
|
||
uint256 private constant STATE_FOLDED_H_Y = 0xc0;
|
||
uint256 private constant STATE_LINEARISED_POLYNOMIAL_X = 0xe0;
|
||
uint256 private constant STATE_LINEARISED_POLYNOMIAL_Y = 0x100;
|
||
uint256 private constant STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA = 0x120;
|
||
uint256 private constant STATE_FOLDED_CLAIMED_VALUES = 0x140; // Folded proof for the opening of H, linearised poly, l, r, o, s_1, s_2, qcp
|
||
uint256 private constant STATE_FOLDED_DIGESTS_X = 0x160; // linearised poly, l, r, o, s_1, s_2, qcp
|
||
uint256 private constant STATE_FOLDED_DIGESTS_Y = 0x180;
|
||
uint256 private constant STATE_PI = 0x1a0;
|
||
uint256 private constant STATE_ZETA_POWER_N_MINUS_ONE = 0x1c0;
|
||
uint256 private constant STATE_GAMMA_KZG = 0x1e0;
|
||
uint256 private constant STATE_SUCCESS = 0x200;
|
||
uint256 private constant STATE_CHECK_VAR = 0x220; // /!\ this slot is used for debugging only
|
||
uint256 private constant STATE_LAST_MEM = 0x240;
|
||
|
||
// -------- utils (for Fiat Shamir)
|
||
uint256 private constant FS_ALPHA = 0x616C706861; // "alpha"
|
||
uint256 private constant FS_BETA = 0x62657461; // "beta"
|
||
uint256 private constant FS_GAMMA = 0x67616d6d61; // "gamma"
|
||
uint256 private constant FS_ZETA = 0x7a657461; // "zeta"
|
||
uint256 private constant FS_GAMMA_KZG = 0x67616d6d61; // "gamma"
|
||
|
||
// -------- errors
|
||
uint256 private constant ERROR_STRING_ID = 0x08c379a000000000000000000000000000000000000000000000000000000000; // selector for function Error(string)
|
||
|
||
// -------- utils (for hash_fr)
|
||
uint256 private constant HASH_FR_BB = 340282366920938463463374607431768211456; // 2**128
|
||
uint256 private constant HASH_FR_ZERO_UINT256 = 0;
|
||
uint8 private constant HASH_FR_LEN_IN_BYTES = 48;
|
||
uint8 private constant HASH_FR_SIZE_DOMAIN = 11;
|
||
uint8 private constant HASH_FR_ONE = 1;
|
||
uint8 private constant HASH_FR_TWO = 2;
|
||
|
||
// -------- precompiles
|
||
uint8 private constant SHA2 = 0x2;
|
||
uint8 private constant MOD_EXP = 0x5;
|
||
uint8 private constant EC_ADD = 0x6;
|
||
uint8 private constant EC_MUL = 0x7;
|
||
uint8 private constant EC_PAIR = 0x8;
|
||
|
||
/// Verify a Plonk proof.
|
||
/// Reverts if the proof or the public inputs are malformed.
|
||
/// @param proof serialised plonk proof (using gnark's MarshalSolidity)
|
||
/// @param public_inputs (must be reduced)
|
||
/// @return success true if the proof passes false otherwise
|
||
function Verify(bytes calldata proof, uint256[] calldata public_inputs) public view returns (bool success) {
|
||
assembly {
|
||
let mem := mload(0x40)
|
||
let freeMem := add(mem, STATE_LAST_MEM)
|
||
|
||
// sanity checks
|
||
check_number_of_public_inputs(public_inputs.length)
|
||
check_inputs_size(public_inputs.length, public_inputs.offset)
|
||
check_proof_size(proof.length)
|
||
check_proof_openings_size(proof.offset)
|
||
|
||
// compute the challenges
|
||
let prev_challenge_non_reduced
|
||
prev_challenge_non_reduced := derive_gamma(proof.offset, public_inputs.length, public_inputs.offset)
|
||
prev_challenge_non_reduced := derive_beta(prev_challenge_non_reduced)
|
||
prev_challenge_non_reduced := derive_alpha(proof.offset, prev_challenge_non_reduced)
|
||
derive_zeta(proof.offset, prev_challenge_non_reduced)
|
||
|
||
// evaluation of Z=Xⁿ-1 at ζ, we save this value
|
||
let zeta := mload(add(mem, STATE_ZETA))
|
||
let zeta_power_n_minus_one := addmod(pow(zeta, VK_DOMAIN_SIZE, freeMem), sub(R_MOD, 1), R_MOD)
|
||
mstore(add(mem, STATE_ZETA_POWER_N_MINUS_ONE), zeta_power_n_minus_one)
|
||
|
||
// public inputs contribution
|
||
let l_pi := sum_pi_wo_api_commit(public_inputs.offset, public_inputs.length, freeMem)
|
||
let l_pi_commit := sum_pi_commit(proof.offset, public_inputs.length, freeMem)
|
||
l_pi := addmod(l_pi_commit, l_pi, R_MOD)
|
||
mstore(add(mem, STATE_PI), l_pi)
|
||
|
||
compute_alpha_square_lagrange_0()
|
||
compute_opening_linearised_polynomial(proof.offset)
|
||
fold_h(proof.offset)
|
||
compute_commitment_linearised_polynomial(proof.offset)
|
||
compute_gamma_kzg(proof.offset)
|
||
fold_state(proof.offset)
|
||
batch_verify_multi_points(proof.offset)
|
||
|
||
success := mload(add(mem, STATE_SUCCESS))
|
||
|
||
// Beginning errors -------------------------------------------------
|
||
|
||
function error_nb_public_inputs() {
|
||
let ptError := mload(0x40)
|
||
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
|
||
mstore(add(ptError, 0x4), 0x20)
|
||
mstore(add(ptError, 0x24), 0x1d)
|
||
mstore(add(ptError, 0x44), "wrong number of public inputs")
|
||
revert(ptError, 0x64)
|
||
}
|
||
|
||
/// Called when an exponentiation mod r fails
|
||
function error_mod_exp() {
|
||
let ptError := mload(0x40)
|
||
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
|
||
mstore(add(ptError, 0x4), 0x20)
|
||
mstore(add(ptError, 0x24), 0xc)
|
||
mstore(add(ptError, 0x44), "error mod exp")
|
||
revert(ptError, 0x64)
|
||
}
|
||
|
||
/// Called when an operation on Bn254 fails
|
||
/// @dev for instance when calling EcMul on a point not on Bn254.
|
||
function error_ec_op() {
|
||
let ptError := mload(0x40)
|
||
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
|
||
mstore(add(ptError, 0x4), 0x20)
|
||
mstore(add(ptError, 0x24), 0x12)
|
||
mstore(add(ptError, 0x44), "error ec operation")
|
||
revert(ptError, 0x64)
|
||
}
|
||
|
||
/// Called when one of the public inputs is not reduced.
|
||
function error_inputs_size() {
|
||
let ptError := mload(0x40)
|
||
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
|
||
mstore(add(ptError, 0x4), 0x20)
|
||
mstore(add(ptError, 0x24), 0x18)
|
||
mstore(add(ptError, 0x44), "inputs are bigger than r")
|
||
revert(ptError, 0x64)
|
||
}
|
||
|
||
/// Called when the size proof is not as expected
|
||
/// @dev to avoid overflow attack for instance
|
||
function error_proof_size() {
|
||
let ptError := mload(0x40)
|
||
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
|
||
mstore(add(ptError, 0x4), 0x20)
|
||
mstore(add(ptError, 0x24), 0x10)
|
||
mstore(add(ptError, 0x44), "wrong proof size")
|
||
revert(ptError, 0x64)
|
||
}
|
||
|
||
/// Called when one the openings is bigger than r
|
||
/// The openings are the claimed evalutions of a polynomial
|
||
/// in a Kzg proof.
|
||
function error_proof_openings_size() {
|
||
let ptError := mload(0x40)
|
||
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
|
||
mstore(add(ptError, 0x4), 0x20)
|
||
mstore(add(ptError, 0x24), 0x16)
|
||
mstore(add(ptError, 0x44), "openings bigger than r")
|
||
revert(ptError, 0x64)
|
||
}
|
||
|
||
function error_pairing() {
|
||
let ptError := mload(0x40)
|
||
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
|
||
mstore(add(ptError, 0x4), 0x20)
|
||
mstore(add(ptError, 0x24), 0xd)
|
||
mstore(add(ptError, 0x44), "error pairing")
|
||
revert(ptError, 0x64)
|
||
}
|
||
|
||
function error_verify() {
|
||
let ptError := mload(0x40)
|
||
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
|
||
mstore(add(ptError, 0x4), 0x20)
|
||
mstore(add(ptError, 0x24), 0xc)
|
||
mstore(add(ptError, 0x44), "error verify")
|
||
revert(ptError, 0x64)
|
||
}
|
||
|
||
function error_random_generation() {
|
||
let ptError := mload(0x40)
|
||
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
|
||
mstore(add(ptError, 0x4), 0x20)
|
||
mstore(add(ptError, 0x24), 0x14)
|
||
mstore(add(ptError, 0x44), "error random gen kzg")
|
||
revert(ptError, 0x64)
|
||
}
|
||
// end errors -------------------------------------------------
|
||
|
||
// Beginning checks -------------------------------------------------
|
||
|
||
/// @param s actual number of public inputs
|
||
function check_number_of_public_inputs(s) {
|
||
if iszero(eq(s, VK_NB_PUBLIC_INPUTS)) {
|
||
error_nb_public_inputs()
|
||
}
|
||
}
|
||
|
||
/// Checks that the public inputs are < R_MOD.
|
||
/// @param s number of public inputs
|
||
/// @param p pointer to the public inputs array
|
||
function check_inputs_size(s, p) {
|
||
for {
|
||
let i
|
||
} lt(i, s) {
|
||
i := add(i, 1)
|
||
} {
|
||
if gt(calldataload(p), R_MOD_MINUS_ONE) {
|
||
error_inputs_size()
|
||
}
|
||
p := add(p, 0x20)
|
||
}
|
||
}
|
||
|
||
/// Checks if the proof is of the correct size
|
||
/// @param actual_proof_size size of the proof (not the expected size)
|
||
function check_proof_size(actual_proof_size) {
|
||
let expected_proof_size := add(FIXED_PROOF_SIZE, mul(VK_NB_CUSTOM_GATES, 0x60))
|
||
if iszero(eq(actual_proof_size, expected_proof_size)) {
|
||
error_proof_size()
|
||
}
|
||
}
|
||
|
||
/// Checks if the multiple openings of the polynomials are < R_MOD.
|
||
/// @param aproof pointer to the beginning of the proof
|
||
/// @dev the 'a' prepending proof is to have a local name
|
||
function check_proof_openings_size(aproof) {
|
||
// PROOF_L_AT_ZETA
|
||
let p := add(aproof, PROOF_L_AT_ZETA)
|
||
if gt(calldataload(p), R_MOD_MINUS_ONE) {
|
||
error_proof_openings_size()
|
||
}
|
||
|
||
// PROOF_R_AT_ZETA
|
||
p := add(aproof, PROOF_R_AT_ZETA)
|
||
if gt(calldataload(p), R_MOD_MINUS_ONE) {
|
||
error_proof_openings_size()
|
||
}
|
||
|
||
// PROOF_O_AT_ZETA
|
||
p := add(aproof, PROOF_O_AT_ZETA)
|
||
if gt(calldataload(p), R_MOD_MINUS_ONE) {
|
||
error_proof_openings_size()
|
||
}
|
||
|
||
// PROOF_S1_AT_ZETA
|
||
p := add(aproof, PROOF_S1_AT_ZETA)
|
||
if gt(calldataload(p), R_MOD_MINUS_ONE) {
|
||
error_proof_openings_size()
|
||
}
|
||
|
||
// PROOF_S2_AT_ZETA
|
||
p := add(aproof, PROOF_S2_AT_ZETA)
|
||
if gt(calldataload(p), R_MOD_MINUS_ONE) {
|
||
error_proof_openings_size()
|
||
}
|
||
|
||
// PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA
|
||
p := add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA)
|
||
if gt(calldataload(p), R_MOD_MINUS_ONE) {
|
||
error_proof_openings_size()
|
||
}
|
||
|
||
// PROOF_OPENING_QCP_AT_ZETA
|
||
|
||
p := add(aproof, PROOF_OPENING_QCP_AT_ZETA)
|
||
for {
|
||
let i := 0
|
||
} lt(i, VK_NB_CUSTOM_GATES) {
|
||
i := add(i, 1)
|
||
} {
|
||
if gt(calldataload(p), R_MOD_MINUS_ONE) {
|
||
error_proof_openings_size()
|
||
}
|
||
p := add(p, 0x20)
|
||
}
|
||
}
|
||
// end checks -------------------------------------------------
|
||
|
||
// Beginning challenges -------------------------------------------------
|
||
|
||
/// Derive gamma as Sha256(<transcript>)
|
||
/// @param aproof pointer to the proof
|
||
/// @param nb_pi number of public inputs
|
||
/// @param pi pointer to the array of public inputs
|
||
/// @return the challenge gamma, not reduced
|
||
/// @notice The transcript is the concatenation (in this order) of:
|
||
/// * the word "gamma" in ascii, equal to [0x67,0x61,0x6d, 0x6d, 0x61] and encoded as a uint256.
|
||
/// * the commitments to the permutation polynomials S1, S2, S3, where we concatenate the coordinates of those points
|
||
/// * the commitments of Ql, Qr, Qm, Qo, Qk
|
||
/// * the public inputs
|
||
/// * the commitments of the wires related to the custom gates (commitments_wires_commit_api)
|
||
/// * commitments to L, R, O (proof_<l,r,o>_com_<x,y>)
|
||
/// The data described above is written starting at mPtr. "gamma" lies on 5 bytes,
|
||
/// and is encoded as a uint256 number n. In basis b = 256, the number looks like this
|
||
/// [0 0 0 .. 0x67 0x61 0x6d, 0x6d, 0x61]. The first non zero entry is at position 27=0x1b
|
||
/// Gamma reduced (the actual challenge) is stored at add(state, state_gamma)
|
||
function derive_gamma(aproof, nb_pi, pi) -> gamma_not_reduced {
|
||
let state := mload(0x40)
|
||
let mPtr := add(state, STATE_LAST_MEM)
|
||
|
||
mstore(mPtr, FS_GAMMA) // "gamma"
|
||
|
||
mstore(add(mPtr, 0x20), VK_S1_COM_X)
|
||
mstore(add(mPtr, 0x40), VK_S1_COM_Y)
|
||
mstore(add(mPtr, 0x60), VK_S2_COM_X)
|
||
mstore(add(mPtr, 0x80), VK_S2_COM_Y)
|
||
mstore(add(mPtr, 0xa0), VK_S3_COM_X)
|
||
mstore(add(mPtr, 0xc0), VK_S3_COM_Y)
|
||
mstore(add(mPtr, 0xe0), VK_QL_COM_X)
|
||
mstore(add(mPtr, 0x100), VK_QL_COM_Y)
|
||
mstore(add(mPtr, 0x120), VK_QR_COM_X)
|
||
mstore(add(mPtr, 0x140), VK_QR_COM_Y)
|
||
mstore(add(mPtr, 0x160), VK_QM_COM_X)
|
||
mstore(add(mPtr, 0x180), VK_QM_COM_Y)
|
||
mstore(add(mPtr, 0x1a0), VK_QO_COM_X)
|
||
mstore(add(mPtr, 0x1c0), VK_QO_COM_Y)
|
||
mstore(add(mPtr, 0x1e0), VK_QK_COM_X)
|
||
mstore(add(mPtr, 0x200), VK_QK_COM_Y)
|
||
|
||
mstore(add(mPtr, 0x220), VK_QCP_0_X)
|
||
mstore(add(mPtr, 0x240), VK_QCP_0_Y)
|
||
|
||
// public inputs
|
||
let _mPtr := add(mPtr, 0x260)
|
||
let size_pi_in_bytes := mul(nb_pi, 0x20)
|
||
calldatacopy(_mPtr, pi, size_pi_in_bytes)
|
||
_mPtr := add(_mPtr, size_pi_in_bytes)
|
||
|
||
// commitments to l, r, o
|
||
let size_commitments_lro_in_bytes := 0xc0
|
||
calldatacopy(_mPtr, aproof, size_commitments_lro_in_bytes)
|
||
_mPtr := add(_mPtr, size_commitments_lro_in_bytes)
|
||
|
||
// total size is :
|
||
// sizegamma(=0x5) + 11*64(=0x2c0)
|
||
// + nb_public_inputs*0x20
|
||
// + nb_custom gates*0x40
|
||
let size := add(0x2c5, size_pi_in_bytes)
|
||
|
||
size := add(size, mul(VK_NB_CUSTOM_GATES, 0x40))
|
||
let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1b), size, mPtr, 0x20) //0x1b -> 000.."gamma"
|
||
if iszero(l_success) {
|
||
error_verify()
|
||
}
|
||
gamma_not_reduced := mload(mPtr)
|
||
mstore(add(state, STATE_GAMMA), mod(gamma_not_reduced, R_MOD))
|
||
}
|
||
|
||
/// derive beta as Sha256<transcript>
|
||
/// @param gamma_not_reduced the previous challenge (gamma) not reduced
|
||
/// @return beta_not_reduced the next challenge, beta, not reduced
|
||
/// @notice the transcript consists of the previous challenge only.
|
||
/// The reduced version of beta is stored at add(state, state_beta)
|
||
function derive_beta(gamma_not_reduced) -> beta_not_reduced {
|
||
let state := mload(0x40)
|
||
let mPtr := add(mload(0x40), STATE_LAST_MEM)
|
||
|
||
// beta
|
||
mstore(mPtr, FS_BETA) // "beta"
|
||
mstore(add(mPtr, 0x20), gamma_not_reduced)
|
||
let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1c), 0x24, mPtr, 0x20) //0x1b -> 000.."gamma"
|
||
if iszero(l_success) {
|
||
error_verify()
|
||
}
|
||
beta_not_reduced := mload(mPtr)
|
||
mstore(add(state, STATE_BETA), mod(beta_not_reduced, R_MOD))
|
||
}
|
||
|
||
/// derive alpha as sha256<transcript>
|
||
/// @param aproof pointer to the proof object
|
||
/// @param beta_not_reduced the previous challenge (beta) not reduced
|
||
/// @return alpha_not_reduced the next challenge, alpha, not reduced
|
||
/// @notice the transcript consists of the previous challenge (beta)
|
||
/// not reduced, the commitments to the wires associated to the QCP_i,
|
||
/// and the commitment to the grand product polynomial
|
||
function derive_alpha(aproof, beta_not_reduced) -> alpha_not_reduced {
|
||
let state := mload(0x40)
|
||
let mPtr := add(mload(0x40), STATE_LAST_MEM)
|
||
let full_size := 0x65 // size("alpha") + 0x20 (previous challenge)
|
||
|
||
// alpha
|
||
mstore(mPtr, FS_ALPHA) // "alpha"
|
||
let _mPtr := add(mPtr, 0x20)
|
||
mstore(_mPtr, beta_not_reduced)
|
||
_mPtr := add(_mPtr, 0x20)
|
||
|
||
// Bsb22Commitments
|
||
let proof_bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS)
|
||
let size_bsb_commitments := mul(0x40, VK_NB_CUSTOM_GATES)
|
||
calldatacopy(_mPtr, proof_bsb_commitments, size_bsb_commitments)
|
||
_mPtr := add(_mPtr, size_bsb_commitments)
|
||
full_size := add(full_size, size_bsb_commitments)
|
||
|
||
// [Z], the commitment to the grand product polynomial
|
||
calldatacopy(_mPtr, add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X), 0x40)
|
||
let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1b), full_size, mPtr, 0x20)
|
||
if iszero(l_success) {
|
||
error_verify()
|
||
}
|
||
|
||
alpha_not_reduced := mload(mPtr)
|
||
mstore(add(state, STATE_ALPHA), mod(alpha_not_reduced, R_MOD))
|
||
}
|
||
|
||
/// derive zeta as sha256<transcript>
|
||
/// @param aproof pointer to the proof object
|
||
/// @param alpha_not_reduced the previous challenge (alpha) not reduced
|
||
/// The transcript consists of the previous challenge and the commitment to
|
||
/// the quotient polynomial h.
|
||
function derive_zeta(aproof, alpha_not_reduced) {
|
||
let state := mload(0x40)
|
||
let mPtr := add(mload(0x40), STATE_LAST_MEM)
|
||
|
||
// zeta
|
||
mstore(mPtr, FS_ZETA) // "zeta"
|
||
mstore(add(mPtr, 0x20), alpha_not_reduced)
|
||
calldatacopy(add(mPtr, 0x40), add(aproof, PROOF_H_0_COM_X), 0xc0)
|
||
let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1c), 0xe4, mPtr, 0x20)
|
||
if iszero(l_success) {
|
||
error_verify()
|
||
}
|
||
let zeta_not_reduced := mload(mPtr)
|
||
mstore(add(state, STATE_ZETA), mod(zeta_not_reduced, R_MOD))
|
||
}
|
||
// END challenges -------------------------------------------------
|
||
|
||
// BEGINNING compute_pi -------------------------------------------------
|
||
|
||
/// sum_pi_wo_api_commit computes the public inputs contributions,
|
||
/// except for the public inputs coming from the custom gate
|
||
/// @param ins pointer to the public inputs
|
||
/// @param n number of public inputs
|
||
/// @param mPtr free memory
|
||
/// @return pi_wo_commit public inputs contribution (except the public inputs coming from the custom gate)
|
||
function sum_pi_wo_api_commit(ins, n, mPtr) -> pi_wo_commit {
|
||
let state := mload(0x40)
|
||
let z := mload(add(state, STATE_ZETA))
|
||
let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE))
|
||
|
||
let li := mPtr
|
||
batch_compute_lagranges_at_z(z, zpnmo, n, li)
|
||
|
||
let tmp := 0
|
||
for {
|
||
let i := 0
|
||
} lt(i, n) {
|
||
i := add(i, 1)
|
||
} {
|
||
tmp := mulmod(mload(li), calldataload(ins), R_MOD)
|
||
pi_wo_commit := addmod(pi_wo_commit, tmp, R_MOD)
|
||
li := add(li, 0x20)
|
||
ins := add(ins, 0x20)
|
||
}
|
||
}
|
||
|
||
/// batch_compute_lagranges_at_z computes [L_0(z), .., L_{n-1}(z)]
|
||
/// @param z point at which the Lagranges are evaluated
|
||
/// @param zpnmo ζⁿ-1
|
||
/// @param n_pub number of public inputs (number of Lagranges to compute)
|
||
/// @param mPtr pointer to which the results are stored
|
||
function batch_compute_lagranges_at_z(z, zpnmo, n_pub, mPtr) {
|
||
let zn := mulmod(zpnmo, VK_INV_DOMAIN_SIZE, R_MOD) // 1/n * (ζⁿ - 1)
|
||
|
||
let _w := 1
|
||
let _mPtr := mPtr
|
||
for {
|
||
let i := 0
|
||
} lt(i, n_pub) {
|
||
i := add(i, 1)
|
||
} {
|
||
mstore(_mPtr, addmod(z, sub(R_MOD, _w), R_MOD))
|
||
_w := mulmod(_w, VK_OMEGA, R_MOD)
|
||
_mPtr := add(_mPtr, 0x20)
|
||
}
|
||
batch_invert(mPtr, n_pub, _mPtr)
|
||
_mPtr := mPtr
|
||
_w := 1
|
||
for {
|
||
let i := 0
|
||
} lt(i, n_pub) {
|
||
i := add(i, 1)
|
||
} {
|
||
mstore(_mPtr, mulmod(mulmod(mload(_mPtr), zn, R_MOD), _w, R_MOD))
|
||
_mPtr := add(_mPtr, 0x20)
|
||
_w := mulmod(_w, VK_OMEGA, R_MOD)
|
||
}
|
||
}
|
||
|
||
/// @notice Montgomery trick for batch inversion mod R_MOD
|
||
/// @param ins pointer to the data to batch invert
|
||
/// @param number of elements to batch invert
|
||
/// @param mPtr free memory
|
||
function batch_invert(ins, nb_ins, mPtr) {
|
||
mstore(mPtr, 1)
|
||
let offset := 0
|
||
for {
|
||
let i := 0
|
||
} lt(i, nb_ins) {
|
||
i := add(i, 1)
|
||
} {
|
||
let prev := mload(add(mPtr, offset))
|
||
let cur := mload(add(ins, offset))
|
||
cur := mulmod(prev, cur, R_MOD)
|
||
offset := add(offset, 0x20)
|
||
mstore(add(mPtr, offset), cur)
|
||
}
|
||
ins := add(ins, sub(offset, 0x20))
|
||
mPtr := add(mPtr, offset)
|
||
let inv := pow(mload(mPtr), sub(R_MOD, 2), add(mPtr, 0x20))
|
||
for {
|
||
let i := 0
|
||
} lt(i, nb_ins) {
|
||
i := add(i, 1)
|
||
} {
|
||
mPtr := sub(mPtr, 0x20)
|
||
let tmp := mload(ins)
|
||
let cur := mulmod(inv, mload(mPtr), R_MOD)
|
||
mstore(ins, cur)
|
||
inv := mulmod(inv, tmp, R_MOD)
|
||
ins := sub(ins, 0x20)
|
||
}
|
||
}
|
||
|
||
/// Public inputs (the ones coming from the custom gate) contribution
|
||
/// @param aproof pointer to the proof
|
||
/// @param nb_public_inputs number of public inputs
|
||
/// @param mPtr pointer to free memory
|
||
/// @return pi_commit custom gate public inputs contribution
|
||
function sum_pi_commit(aproof, nb_public_inputs, mPtr) -> pi_commit {
|
||
let state := mload(0x40)
|
||
let z := mload(add(state, STATE_ZETA))
|
||
let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE))
|
||
|
||
let p := add(aproof, PROOF_BSB_COMMITMENTS)
|
||
|
||
let h_fr, ith_lagrange
|
||
|
||
h_fr := hash_fr(calldataload(p), calldataload(add(p, 0x20)), mPtr)
|
||
ith_lagrange := compute_ith_lagrange_at_z(z, zpnmo, add(nb_public_inputs, VK_INDEX_COMMIT_API_0), mPtr)
|
||
pi_commit := addmod(pi_commit, mulmod(h_fr, ith_lagrange, R_MOD), R_MOD)
|
||
}
|
||
|
||
/// Computes L_i(zeta) = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) where:
|
||
/// @param z zeta
|
||
/// @param zpmno ζⁿ-1
|
||
/// @param i i-th lagrange
|
||
/// @param mPtr free memory
|
||
/// @return res = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ)
|
||
function compute_ith_lagrange_at_z(z, zpnmo, i, mPtr) -> res {
|
||
let w := pow(VK_OMEGA, i, mPtr) // w**i
|
||
i := addmod(z, sub(R_MOD, w), R_MOD) // z-w**i
|
||
w := mulmod(w, VK_INV_DOMAIN_SIZE, R_MOD) // w**i/n
|
||
i := pow(i, sub(R_MOD, 2), mPtr) // (z-w**i)**-1
|
||
w := mulmod(w, i, R_MOD) // w**i/n*(z-w)**-1
|
||
res := mulmod(w, zpnmo, R_MOD)
|
||
}
|
||
|
||
/// @dev https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2
|
||
/// @param x x coordinate of a point on Bn254(𝔽_p)
|
||
/// @param y y coordinate of a point on Bn254(𝔽_p)
|
||
/// @param mPtr free memory
|
||
/// @return res an element mod R_MOD
|
||
function hash_fr(x, y, mPtr) -> res {
|
||
// [0x00, .. , 0x00 || x, y, || 0, 48, 0, dst, HASH_FR_SIZE_DOMAIN]
|
||
// <- 64 bytes -> <-64b -> <- 1 bytes each ->
|
||
|
||
// [0x00, .., 0x00] 64 bytes of zero
|
||
mstore(mPtr, HASH_FR_ZERO_UINT256)
|
||
mstore(add(mPtr, 0x20), HASH_FR_ZERO_UINT256)
|
||
|
||
// msg = x || y , both on 32 bytes
|
||
mstore(add(mPtr, 0x40), x)
|
||
mstore(add(mPtr, 0x60), y)
|
||
|
||
// 0 || 48 || 0 all on 1 byte
|
||
mstore8(add(mPtr, 0x80), 0)
|
||
mstore8(add(mPtr, 0x81), HASH_FR_LEN_IN_BYTES)
|
||
mstore8(add(mPtr, 0x82), 0)
|
||
|
||
// "BSB22-Plonk" = [42, 53, 42, 32, 32, 2d, 50, 6c, 6f, 6e, 6b,]
|
||
mstore8(add(mPtr, 0x83), 0x42)
|
||
mstore8(add(mPtr, 0x84), 0x53)
|
||
mstore8(add(mPtr, 0x85), 0x42)
|
||
mstore8(add(mPtr, 0x86), 0x32)
|
||
mstore8(add(mPtr, 0x87), 0x32)
|
||
mstore8(add(mPtr, 0x88), 0x2d)
|
||
mstore8(add(mPtr, 0x89), 0x50)
|
||
mstore8(add(mPtr, 0x8a), 0x6c)
|
||
mstore8(add(mPtr, 0x8b), 0x6f)
|
||
mstore8(add(mPtr, 0x8c), 0x6e)
|
||
mstore8(add(mPtr, 0x8d), 0x6b)
|
||
|
||
// size domain
|
||
mstore8(add(mPtr, 0x8e), HASH_FR_SIZE_DOMAIN)
|
||
|
||
let l_success := staticcall(gas(), SHA2, mPtr, 0x8f, mPtr, 0x20)
|
||
if iszero(l_success) {
|
||
error_verify()
|
||
}
|
||
|
||
let b0 := mload(mPtr)
|
||
|
||
// [b0 || one || dst || HASH_FR_SIZE_DOMAIN]
|
||
// <-64bytes -> <- 1 byte each ->
|
||
mstore8(add(mPtr, 0x20), HASH_FR_ONE) // 1
|
||
|
||
mstore8(add(mPtr, 0x21), 0x42) // dst
|
||
mstore8(add(mPtr, 0x22), 0x53)
|
||
mstore8(add(mPtr, 0x23), 0x42)
|
||
mstore8(add(mPtr, 0x24), 0x32)
|
||
mstore8(add(mPtr, 0x25), 0x32)
|
||
mstore8(add(mPtr, 0x26), 0x2d)
|
||
mstore8(add(mPtr, 0x27), 0x50)
|
||
mstore8(add(mPtr, 0x28), 0x6c)
|
||
mstore8(add(mPtr, 0x29), 0x6f)
|
||
mstore8(add(mPtr, 0x2a), 0x6e)
|
||
mstore8(add(mPtr, 0x2b), 0x6b)
|
||
|
||
mstore8(add(mPtr, 0x2c), HASH_FR_SIZE_DOMAIN) // size domain
|
||
l_success := staticcall(gas(), SHA2, mPtr, 0x2d, mPtr, 0x20)
|
||
if iszero(l_success) {
|
||
error_verify()
|
||
}
|
||
|
||
// b1 is located at mPtr. We store b2 at add(mPtr, 0x20)
|
||
|
||
// [b0^b1 || two || dst || HASH_FR_SIZE_DOMAIN]
|
||
// <-64bytes -> <- 1 byte each ->
|
||
mstore(add(mPtr, 0x20), xor(mload(mPtr), b0))
|
||
mstore8(add(mPtr, 0x40), HASH_FR_TWO)
|
||
|
||
mstore8(add(mPtr, 0x41), 0x42) // dst
|
||
mstore8(add(mPtr, 0x42), 0x53)
|
||
mstore8(add(mPtr, 0x43), 0x42)
|
||
mstore8(add(mPtr, 0x44), 0x32)
|
||
mstore8(add(mPtr, 0x45), 0x32)
|
||
mstore8(add(mPtr, 0x46), 0x2d)
|
||
mstore8(add(mPtr, 0x47), 0x50)
|
||
mstore8(add(mPtr, 0x48), 0x6c)
|
||
mstore8(add(mPtr, 0x49), 0x6f)
|
||
mstore8(add(mPtr, 0x4a), 0x6e)
|
||
mstore8(add(mPtr, 0x4b), 0x6b)
|
||
|
||
mstore8(add(mPtr, 0x4c), HASH_FR_SIZE_DOMAIN) // size domain
|
||
|
||
let offset := add(mPtr, 0x20)
|
||
l_success := staticcall(gas(), SHA2, offset, 0x2d, offset, 0x20)
|
||
if iszero(l_success) {
|
||
error_verify()
|
||
}
|
||
|
||
// at this point we have mPtr = [ b1 || b2] where b1 is on 32byes and b2 in 16bytes.
|
||
// we interpret it as a big integer mod r in big endian (similar to regular decimal notation)
|
||
// the result is then 2**(8*16)*mPtr[:32] + mPtr[32:48]
|
||
res := mulmod(mload(mPtr), HASH_FR_BB, R_MOD) // <- res = 2**128 * mPtr[:32]
|
||
let b1 := shr(128, mload(add(mPtr, 0x20))) // b1 <- [0, 0, .., 0 || b2[:16] ]
|
||
res := addmod(res, b1, R_MOD)
|
||
}
|
||
|
||
// END compute_pi -------------------------------------------------
|
||
|
||
/// @notice compute α² * 1/n * (ζ{n}-1)/(ζ - 1) where
|
||
/// * α = challenge derived in derive_gamma_beta_alpha_zeta
|
||
/// * n = vk_domain_size
|
||
/// * ω = vk_omega (generator of the multiplicative cyclic group of order n in (ℤ/rℤ)*)
|
||
/// * ζ = zeta (challenge derived with Fiat Shamir)
|
||
function compute_alpha_square_lagrange_0() {
|
||
let state := mload(0x40)
|
||
let mPtr := add(mload(0x40), STATE_LAST_MEM)
|
||
|
||
let res := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE))
|
||
let den := addmod(mload(add(state, STATE_ZETA)), sub(R_MOD, 1), R_MOD)
|
||
den := pow(den, sub(R_MOD, 2), mPtr)
|
||
den := mulmod(den, VK_INV_DOMAIN_SIZE, R_MOD)
|
||
res := mulmod(den, res, R_MOD)
|
||
|
||
let l_alpha := mload(add(state, STATE_ALPHA))
|
||
res := mulmod(res, l_alpha, R_MOD)
|
||
res := mulmod(res, l_alpha, R_MOD)
|
||
mstore(add(state, STATE_ALPHA_SQUARE_LAGRANGE_0), res)
|
||
}
|
||
|
||
/// @notice follows alg. p.13 of https://eprint.iacr.org/2019/953.pdf
|
||
/// with t₁ = t₂ = 1, and the proofs are ([digest] + [quotient] +purported evaluation):
|
||
/// * [state_folded_state_digests], [proof_batch_opening_at_zeta_x], state_folded_evals
|
||
/// * [proof_grand_product_commitment], [proof_opening_at_zeta_omega_x], [proof_grand_product_at_zeta_omega]
|
||
/// @param aproof pointer to the proof
|
||
function batch_verify_multi_points(aproof) {
|
||
let state := mload(0x40)
|
||
let mPtr := add(state, STATE_LAST_MEM)
|
||
|
||
// derive a random number. As there is no random generator, we
|
||
// do an FS like challenge derivation, depending on both digests and
|
||
// ζ to ensure that the prover cannot control the random number.
|
||
// Note: adding the other point ζω is not needed, as ω is known beforehand.
|
||
mstore(mPtr, mload(add(state, STATE_FOLDED_DIGESTS_X)))
|
||
mstore(add(mPtr, 0x20), mload(add(state, STATE_FOLDED_DIGESTS_Y)))
|
||
mstore(add(mPtr, 0x40), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X)))
|
||
mstore(add(mPtr, 0x60), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_Y)))
|
||
mstore(add(mPtr, 0x80), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X)))
|
||
mstore(add(mPtr, 0xa0), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_Y)))
|
||
mstore(add(mPtr, 0xc0), calldataload(add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X)))
|
||
mstore(add(mPtr, 0xe0), calldataload(add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_Y)))
|
||
mstore(add(mPtr, 0x100), mload(add(state, STATE_ZETA)))
|
||
mstore(add(mPtr, 0x120), mload(add(state, STATE_GAMMA_KZG)))
|
||
let random := staticcall(gas(), SHA2, mPtr, 0x140, mPtr, 0x20)
|
||
if iszero(random) {
|
||
error_random_generation()
|
||
}
|
||
random := mod(mload(mPtr), R_MOD) // use the same variable as we are one variable away from getting stack-too-deep error...
|
||
|
||
let folded_quotients := mPtr
|
||
mPtr := add(folded_quotients, 0x40)
|
||
mstore(folded_quotients, calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X)))
|
||
mstore(add(folded_quotients, 0x20), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_Y)))
|
||
point_acc_mul_calldata(folded_quotients, add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X), random, mPtr)
|
||
|
||
let folded_digests := add(state, STATE_FOLDED_DIGESTS_X)
|
||
point_acc_mul_calldata(folded_digests, add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X), random, mPtr)
|
||
|
||
let folded_evals := add(state, STATE_FOLDED_CLAIMED_VALUES)
|
||
fr_acc_mul_calldata(folded_evals, add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA), random)
|
||
|
||
let folded_evals_commit := mPtr
|
||
mPtr := add(folded_evals_commit, 0x40)
|
||
mstore(folded_evals_commit, G1_SRS_X)
|
||
mstore(add(folded_evals_commit, 0x20), G1_SRS_Y)
|
||
mstore(add(folded_evals_commit, 0x40), mload(folded_evals))
|
||
let check_staticcall := staticcall(gas(), 7, folded_evals_commit, 0x60, folded_evals_commit, 0x40)
|
||
if iszero(check_staticcall) {
|
||
error_verify()
|
||
}
|
||
|
||
let folded_evals_commit_y := add(folded_evals_commit, 0x20)
|
||
mstore(folded_evals_commit_y, sub(P_MOD, mload(folded_evals_commit_y)))
|
||
point_add(folded_digests, folded_digests, folded_evals_commit, mPtr)
|
||
|
||
let folded_points_quotients := mPtr
|
||
mPtr := add(mPtr, 0x40)
|
||
point_mul_calldata(
|
||
folded_points_quotients,
|
||
add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X),
|
||
mload(add(state, STATE_ZETA)),
|
||
mPtr
|
||
)
|
||
let zeta_omega := mulmod(mload(add(state, STATE_ZETA)), VK_OMEGA, R_MOD)
|
||
random := mulmod(random, zeta_omega, R_MOD)
|
||
point_acc_mul_calldata(folded_points_quotients, add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X), random, mPtr)
|
||
|
||
point_add(folded_digests, folded_digests, folded_points_quotients, mPtr)
|
||
|
||
let folded_quotients_y := add(folded_quotients, 0x20)
|
||
mstore(folded_quotients_y, sub(P_MOD, mload(folded_quotients_y)))
|
||
|
||
mstore(mPtr, mload(folded_digests))
|
||
|
||
mstore(add(mPtr, 0x20), mload(add(folded_digests, 0x20)))
|
||
mstore(add(mPtr, 0x40), G2_SRS_0_X_0) // the 4 lines are the canonical G2 point on BN254
|
||
mstore(add(mPtr, 0x60), G2_SRS_0_X_1)
|
||
mstore(add(mPtr, 0x80), G2_SRS_0_Y_0)
|
||
mstore(add(mPtr, 0xa0), G2_SRS_0_Y_1)
|
||
mstore(add(mPtr, 0xc0), mload(folded_quotients))
|
||
mstore(add(mPtr, 0xe0), mload(add(folded_quotients, 0x20)))
|
||
mstore(add(mPtr, 0x100), G2_SRS_1_X_0)
|
||
mstore(add(mPtr, 0x120), G2_SRS_1_X_1)
|
||
mstore(add(mPtr, 0x140), G2_SRS_1_Y_0)
|
||
mstore(add(mPtr, 0x160), G2_SRS_1_Y_1)
|
||
check_pairing_kzg(mPtr)
|
||
}
|
||
|
||
/// @notice check_pairing_kzg checks the result of the final pairing product of the batched
|
||
/// kzg verification. The purpose of this function is to avoid exhausting the stack
|
||
/// in the function batch_verify_multi_points.
|
||
/// @param mPtr pointer storing the tuple of pairs
|
||
function check_pairing_kzg(mPtr) {
|
||
let state := mload(0x40)
|
||
|
||
let l_success := staticcall(gas(), 8, mPtr, 0x180, 0x00, 0x20)
|
||
if iszero(l_success) {
|
||
error_pairing()
|
||
}
|
||
let res_pairing := mload(0x00)
|
||
mstore(add(state, STATE_SUCCESS), res_pairing)
|
||
}
|
||
|
||
/// @notice Fold the opening proofs at ζ:
|
||
/// * at state+state_folded_digest we store: [Linearised_polynomial]+γ[L] + γ²[R] + γ³[O] + γ⁴[S₁] +γ⁵[S₂] + ∑ᵢγ⁵⁺ⁱ[Pi_{i}]
|
||
/// * at state+state_folded_claimed_values we store: Linearised_polynomial(ζ)+γL(ζ) + γ²R(ζ)+ γ³O(ζ) + γ⁴S₁(ζ) +γ⁵S₂(ζ) + ∑ᵢγ⁵⁺ⁱPi_{i}(ζ)
|
||
/// @param aproof pointer to the proof
|
||
/// acc_gamma stores the γⁱ
|
||
function fold_state(aproof) {
|
||
let state := mload(0x40)
|
||
let mPtr := add(mload(0x40), STATE_LAST_MEM)
|
||
let mPtr20 := add(mPtr, 0x20)
|
||
let mPtr40 := add(mPtr, 0x40)
|
||
|
||
let l_gamma_kzg := mload(add(state, STATE_GAMMA_KZG))
|
||
let acc_gamma := l_gamma_kzg
|
||
let state_folded_digests := add(state, STATE_FOLDED_DIGESTS_X)
|
||
|
||
mstore(state_folded_digests, mload(add(state, STATE_LINEARISED_POLYNOMIAL_X)))
|
||
mstore(add(state, STATE_FOLDED_DIGESTS_Y), mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y)))
|
||
mstore(add(state, STATE_FOLDED_CLAIMED_VALUES), mload(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA)))
|
||
|
||
point_acc_mul_calldata(state_folded_digests, add(aproof, PROOF_L_COM_X), acc_gamma, mPtr)
|
||
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_L_AT_ZETA), acc_gamma)
|
||
|
||
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
|
||
point_acc_mul_calldata(state_folded_digests, add(aproof, PROOF_R_COM_X), acc_gamma, mPtr)
|
||
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_R_AT_ZETA), acc_gamma)
|
||
|
||
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
|
||
point_acc_mul_calldata(state_folded_digests, add(aproof, PROOF_O_COM_X), acc_gamma, mPtr)
|
||
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_O_AT_ZETA), acc_gamma)
|
||
|
||
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
|
||
mstore(mPtr, VK_S1_COM_X)
|
||
mstore(mPtr20, VK_S1_COM_Y)
|
||
point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40)
|
||
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_S1_AT_ZETA), acc_gamma)
|
||
|
||
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
|
||
mstore(mPtr, VK_S2_COM_X)
|
||
mstore(mPtr20, VK_S2_COM_Y)
|
||
point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40)
|
||
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_S2_AT_ZETA), acc_gamma)
|
||
let poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA)
|
||
|
||
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
|
||
mstore(mPtr, VK_QCP_0_X)
|
||
mstore(mPtr20, VK_QCP_0_Y)
|
||
point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40)
|
||
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), poqaz, acc_gamma)
|
||
poqaz := add(poqaz, 0x20)
|
||
}
|
||
|
||
/// @notice generate the challenge (using Fiat Shamir) to fold the opening proofs
|
||
/// at ζ.
|
||
/// The process for deriving γ is the same as in derive_gamma but this time the inputs are
|
||
/// in this order (the [] means it's a commitment):
|
||
/// * ζ
|
||
/// * [Linearised polynomial]
|
||
/// * [L], [R], [O]
|
||
/// * [S₁] [S₂]
|
||
/// * [Pi_{i}] (wires associated to custom gates)
|
||
/// Then there are the purported evaluations of the previous committed polynomials:
|
||
/// * Linearised_polynomial(ζ)
|
||
/// * L(ζ), R(ζ), O(ζ), S₁(ζ), S₂(ζ)
|
||
/// * Pi_{i}(ζ)
|
||
/// * Z(ζω)
|
||
/// @param aproof pointer to the proof
|
||
function compute_gamma_kzg(aproof) {
|
||
let state := mload(0x40)
|
||
let mPtr := add(mload(0x40), STATE_LAST_MEM)
|
||
mstore(mPtr, FS_GAMMA_KZG) // "gamma"
|
||
mstore(add(mPtr, 0x20), mload(add(state, STATE_ZETA)))
|
||
mstore(add(mPtr, 0x40), mload(add(state, STATE_LINEARISED_POLYNOMIAL_X)))
|
||
mstore(add(mPtr, 0x60), mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y)))
|
||
calldatacopy(add(mPtr, 0x80), add(aproof, PROOF_L_COM_X), 0xc0)
|
||
mstore(add(mPtr, 0x140), VK_S1_COM_X)
|
||
mstore(add(mPtr, 0x160), VK_S1_COM_Y)
|
||
mstore(add(mPtr, 0x180), VK_S2_COM_X)
|
||
mstore(add(mPtr, 0x1a0), VK_S2_COM_Y)
|
||
|
||
let offset := 0x1c0
|
||
|
||
mstore(add(mPtr, offset), VK_QCP_0_X)
|
||
mstore(add(mPtr, add(offset, 0x20)), VK_QCP_0_Y)
|
||
offset := add(offset, 0x40)
|
||
mstore(add(mPtr, offset), mload(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA)))
|
||
mstore(add(mPtr, add(offset, 0x20)), calldataload(add(aproof, PROOF_L_AT_ZETA)))
|
||
mstore(add(mPtr, add(offset, 0x40)), calldataload(add(aproof, PROOF_R_AT_ZETA)))
|
||
mstore(add(mPtr, add(offset, 0x60)), calldataload(add(aproof, PROOF_O_AT_ZETA)))
|
||
mstore(add(mPtr, add(offset, 0x80)), calldataload(add(aproof, PROOF_S1_AT_ZETA)))
|
||
mstore(add(mPtr, add(offset, 0xa0)), calldataload(add(aproof, PROOF_S2_AT_ZETA)))
|
||
|
||
let _mPtr := add(mPtr, add(offset, 0xc0))
|
||
|
||
let _poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA)
|
||
calldatacopy(_mPtr, _poqaz, mul(VK_NB_CUSTOM_GATES, 0x20))
|
||
_mPtr := add(_mPtr, mul(VK_NB_CUSTOM_GATES, 0x20))
|
||
|
||
mstore(_mPtr, calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA)))
|
||
|
||
let start_input := 0x1b // 00.."gamma"
|
||
let size_input := add(0x14, mul(VK_NB_CUSTOM_GATES, 3)) // number of 32bytes elmts = 0x14 (zeta+3*6 for the digests+openings) + 3*VK_NB_CUSTOM_GATES (for the commitments of the selectors) + 1 (opening of Z at ζω)
|
||
size_input := add(0x5, mul(size_input, 0x20)) // size in bytes: 15*32 bytes + 5 bytes for gamma
|
||
let check_staticcall := staticcall(
|
||
gas(),
|
||
SHA2,
|
||
add(mPtr, start_input),
|
||
size_input,
|
||
add(state, STATE_GAMMA_KZG),
|
||
0x20
|
||
)
|
||
if iszero(check_staticcall) {
|
||
error_verify()
|
||
}
|
||
mstore(add(state, STATE_GAMMA_KZG), mod(mload(add(state, STATE_GAMMA_KZG)), R_MOD))
|
||
}
|
||
|
||
function compute_commitment_linearised_polynomial_ec(aproof, s1, s2) {
|
||
let state := mload(0x40)
|
||
let mPtr := add(mload(0x40), STATE_LAST_MEM)
|
||
|
||
mstore(mPtr, VK_QL_COM_X)
|
||
mstore(add(mPtr, 0x20), VK_QL_COM_Y)
|
||
point_mul(
|
||
add(state, STATE_LINEARISED_POLYNOMIAL_X),
|
||
mPtr,
|
||
calldataload(add(aproof, PROOF_L_AT_ZETA)),
|
||
add(mPtr, 0x40)
|
||
)
|
||
|
||
mstore(mPtr, VK_QR_COM_X)
|
||
mstore(add(mPtr, 0x20), VK_QR_COM_Y)
|
||
point_acc_mul(
|
||
add(state, STATE_LINEARISED_POLYNOMIAL_X),
|
||
mPtr,
|
||
calldataload(add(aproof, PROOF_R_AT_ZETA)),
|
||
add(mPtr, 0x40)
|
||
)
|
||
|
||
let rl := mulmod(calldataload(add(aproof, PROOF_L_AT_ZETA)), calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD)
|
||
mstore(mPtr, VK_QM_COM_X)
|
||
mstore(add(mPtr, 0x20), VK_QM_COM_Y)
|
||
point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, rl, add(mPtr, 0x40))
|
||
|
||
mstore(mPtr, VK_QO_COM_X)
|
||
mstore(add(mPtr, 0x20), VK_QO_COM_Y)
|
||
point_acc_mul(
|
||
add(state, STATE_LINEARISED_POLYNOMIAL_X),
|
||
mPtr,
|
||
calldataload(add(aproof, PROOF_O_AT_ZETA)),
|
||
add(mPtr, 0x40)
|
||
)
|
||
|
||
mstore(mPtr, VK_QK_COM_X)
|
||
mstore(add(mPtr, 0x20), VK_QK_COM_Y)
|
||
point_add(
|
||
add(state, STATE_LINEARISED_POLYNOMIAL_X),
|
||
add(state, STATE_LINEARISED_POLYNOMIAL_X),
|
||
mPtr,
|
||
add(mPtr, 0x40)
|
||
)
|
||
|
||
let qcp_opening_at_zeta := add(aproof, PROOF_OPENING_QCP_AT_ZETA)
|
||
let bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS)
|
||
for {
|
||
let i := 0
|
||
} lt(i, VK_NB_CUSTOM_GATES) {
|
||
i := add(i, 1)
|
||
} {
|
||
mstore(mPtr, calldataload(bsb_commitments))
|
||
mstore(add(mPtr, 0x20), calldataload(add(bsb_commitments, 0x20)))
|
||
point_acc_mul(
|
||
add(state, STATE_LINEARISED_POLYNOMIAL_X),
|
||
mPtr,
|
||
calldataload(qcp_opening_at_zeta),
|
||
add(mPtr, 0x40)
|
||
)
|
||
qcp_opening_at_zeta := add(qcp_opening_at_zeta, 0x20)
|
||
bsb_commitments := add(bsb_commitments, 0x40)
|
||
}
|
||
|
||
mstore(mPtr, VK_S3_COM_X)
|
||
mstore(add(mPtr, 0x20), VK_S3_COM_Y)
|
||
point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, s1, add(mPtr, 0x40))
|
||
|
||
mstore(mPtr, calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X)))
|
||
mstore(add(mPtr, 0x20), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_Y)))
|
||
point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, s2, add(mPtr, 0x40))
|
||
|
||
point_add(
|
||
add(state, STATE_LINEARISED_POLYNOMIAL_X),
|
||
add(state, STATE_LINEARISED_POLYNOMIAL_X),
|
||
add(state, STATE_FOLDED_H_X),
|
||
mPtr
|
||
)
|
||
}
|
||
|
||
/// @notice Compute the commitment to the linearized polynomial equal to
|
||
/// L(ζ)[Qₗ]+r(ζ)[Qᵣ]+R(ζ)L(ζ)[Qₘ]+O(ζ)[Qₒ]+[Qₖ]+Σᵢqc'ᵢ(ζ)[BsbCommitmentᵢ] +
|
||
/// α*( Z(μζ)(L(ζ)+β*S₁(ζ)+γ)*(R(ζ)+β*S₂(ζ)+γ)[S₃]-[Z](L(ζ)+β*id_{1}(ζ)+γ)*(R(ζ)+β*id_{2}(ζ)+γ)*(O(ζ)+β*id_{3}(ζ)+γ) ) +
|
||
/// α²*L₁(ζ)[Z] - Z_{H}(ζ)*(([H₀] + ζᵐ⁺²*[H₁] + ζ²⁽ᵐ⁺²⁾*[H₂])
|
||
/// where
|
||
/// * id_1 = id, id_2 = vk_coset_shift*id, id_3 = vk_coset_shift^{2}*id
|
||
/// * the [] means that it's a commitment (i.e. a point on Bn254(F_p))
|
||
/// * Z_{H}(ζ) = ζ^n-1
|
||
/// @param aproof pointer to the proof
|
||
function compute_commitment_linearised_polynomial(aproof) {
|
||
let state := mload(0x40)
|
||
let l_beta := mload(add(state, STATE_BETA))
|
||
let l_gamma := mload(add(state, STATE_GAMMA))
|
||
let l_zeta := mload(add(state, STATE_ZETA))
|
||
let l_alpha := mload(add(state, STATE_ALPHA))
|
||
|
||
let u := mulmod(calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA)), l_beta, R_MOD)
|
||
let v := mulmod(l_beta, calldataload(add(aproof, PROOF_S1_AT_ZETA)), R_MOD)
|
||
v := addmod(v, calldataload(add(aproof, PROOF_L_AT_ZETA)), R_MOD)
|
||
v := addmod(v, l_gamma, R_MOD)
|
||
|
||
let w := mulmod(l_beta, calldataload(add(aproof, PROOF_S2_AT_ZETA)), R_MOD)
|
||
w := addmod(w, calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD)
|
||
w := addmod(w, l_gamma, R_MOD)
|
||
|
||
let s1 := mulmod(u, v, R_MOD)
|
||
s1 := mulmod(s1, w, R_MOD)
|
||
s1 := mulmod(s1, l_alpha, R_MOD)
|
||
|
||
let coset_square := mulmod(VK_COSET_SHIFT, VK_COSET_SHIFT, R_MOD)
|
||
let betazeta := mulmod(l_beta, l_zeta, R_MOD)
|
||
u := addmod(betazeta, calldataload(add(aproof, PROOF_L_AT_ZETA)), R_MOD)
|
||
u := addmod(u, l_gamma, R_MOD)
|
||
|
||
v := mulmod(betazeta, VK_COSET_SHIFT, R_MOD)
|
||
v := addmod(v, calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD)
|
||
v := addmod(v, l_gamma, R_MOD)
|
||
|
||
w := mulmod(betazeta, coset_square, R_MOD)
|
||
w := addmod(w, calldataload(add(aproof, PROOF_O_AT_ZETA)), R_MOD)
|
||
w := addmod(w, l_gamma, R_MOD)
|
||
|
||
let s2 := mulmod(u, v, R_MOD)
|
||
s2 := mulmod(s2, w, R_MOD)
|
||
s2 := sub(R_MOD, s2)
|
||
s2 := mulmod(s2, l_alpha, R_MOD)
|
||
s2 := addmod(s2, mload(add(state, STATE_ALPHA_SQUARE_LAGRANGE_0)), R_MOD)
|
||
|
||
// at this stage:
|
||
// * s₁ = α*Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*β
|
||
// * s₂ = -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ)
|
||
|
||
compute_commitment_linearised_polynomial_ec(aproof, s1, s2)
|
||
}
|
||
|
||
/// @notice compute -z_h(ζ)*([H₁] + ζⁿ⁺²[H₂] + ζ²⁽ⁿ⁺²⁾[H₃]) and store the result at
|
||
/// state + state_folded_h
|
||
/// @param aproof pointer to the proof
|
||
function fold_h(aproof) {
|
||
let state := mload(0x40)
|
||
let n_plus_two := add(VK_DOMAIN_SIZE, 2)
|
||
let mPtr := add(mload(0x40), STATE_LAST_MEM)
|
||
let zeta_power_n_plus_two := pow(mload(add(state, STATE_ZETA)), n_plus_two, mPtr)
|
||
point_mul_calldata(add(state, STATE_FOLDED_H_X), add(aproof, PROOF_H_2_COM_X), zeta_power_n_plus_two, mPtr)
|
||
point_add_calldata(
|
||
add(state, STATE_FOLDED_H_X),
|
||
add(state, STATE_FOLDED_H_X),
|
||
add(aproof, PROOF_H_1_COM_X),
|
||
mPtr
|
||
)
|
||
point_mul(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), zeta_power_n_plus_two, mPtr)
|
||
point_add_calldata(
|
||
add(state, STATE_FOLDED_H_X),
|
||
add(state, STATE_FOLDED_H_X),
|
||
add(aproof, PROOF_H_0_COM_X),
|
||
mPtr
|
||
)
|
||
point_mul(
|
||
add(state, STATE_FOLDED_H_X),
|
||
add(state, STATE_FOLDED_H_X),
|
||
mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)),
|
||
mPtr
|
||
)
|
||
let folded_h_y := mload(add(state, STATE_FOLDED_H_Y))
|
||
folded_h_y := sub(P_MOD, folded_h_y)
|
||
mstore(add(state, STATE_FOLDED_H_Y), folded_h_y)
|
||
}
|
||
|
||
/// @notice check that the opening of the linearised polynomial at zeta is equal to
|
||
/// - [ PI(ζ) - α²*L₁(ζ) + α(l(ζ)+β*s1(ζ)+γ)(r(ζ)+β*s2(ζ)+γ)(o(ζ)+γ)*z(ωζ) ]
|
||
/// @param aproof pointer to the proof
|
||
function compute_opening_linearised_polynomial(aproof) {
|
||
let state := mload(0x40)
|
||
|
||
// (l(ζ)+β*s1(ζ)+γ)
|
||
let s1
|
||
s1 := mulmod(calldataload(add(aproof, PROOF_S1_AT_ZETA)), mload(add(state, STATE_BETA)), R_MOD)
|
||
s1 := addmod(s1, mload(add(state, STATE_GAMMA)), R_MOD)
|
||
s1 := addmod(s1, calldataload(add(aproof, PROOF_L_AT_ZETA)), R_MOD)
|
||
|
||
// (r(ζ)+β*s2(ζ)+γ)
|
||
let s2
|
||
s2 := mulmod(calldataload(add(aproof, PROOF_S2_AT_ZETA)), mload(add(state, STATE_BETA)), R_MOD)
|
||
s2 := addmod(s2, mload(add(state, STATE_GAMMA)), R_MOD)
|
||
s2 := addmod(s2, calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD)
|
||
|
||
// (o(ζ)+γ)
|
||
let o
|
||
o := addmod(calldataload(add(aproof, PROOF_O_AT_ZETA)), mload(add(state, STATE_GAMMA)), R_MOD)
|
||
|
||
// α*Z(μζ)*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*(o(ζ)+γ)
|
||
s1 := mulmod(s1, s2, R_MOD)
|
||
s1 := mulmod(s1, o, R_MOD)
|
||
s1 := mulmod(s1, mload(add(state, STATE_ALPHA)), R_MOD)
|
||
s1 := mulmod(s1, calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA)), R_MOD)
|
||
|
||
// PI(ζ) - α²*L₁(ζ) + α(l(ζ)+β*s1(ζ)+γ)(r(ζ)+β*s2(ζ)+γ)(o(ζ)+γ)*z(ωζ)
|
||
s1 := addmod(s1, mload(add(state, STATE_PI)), R_MOD)
|
||
s2 := mload(add(state, STATE_ALPHA_SQUARE_LAGRANGE_0))
|
||
s2 := sub(R_MOD, s2)
|
||
s1 := addmod(s1, s2, R_MOD)
|
||
s1 := sub(R_MOD, s1)
|
||
|
||
mstore(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA), s1)
|
||
}
|
||
|
||
// BEGINNING utils math functions -------------------------------------------------
|
||
|
||
/// @param dst pointer storing the result
|
||
/// @param p pointer to the first point
|
||
/// @param q pointer to the second point
|
||
/// @param mPtr pointer to free memory
|
||
function point_add(dst, p, q, mPtr) {
|
||
mstore(mPtr, mload(p))
|
||
mstore(add(mPtr, 0x20), mload(add(p, 0x20)))
|
||
mstore(add(mPtr, 0x40), mload(q))
|
||
mstore(add(mPtr, 0x60), mload(add(q, 0x20)))
|
||
let l_success := staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40)
|
||
if iszero(l_success) {
|
||
error_ec_op()
|
||
}
|
||
}
|
||
|
||
/// @param dst pointer storing the result
|
||
/// @param p pointer to the first point (calldata)
|
||
/// @param q pointer to the second point (calladata)
|
||
/// @param mPtr pointer to free memory
|
||
function point_add_calldata(dst, p, q, mPtr) {
|
||
mstore(mPtr, mload(p))
|
||
mstore(add(mPtr, 0x20), mload(add(p, 0x20)))
|
||
mstore(add(mPtr, 0x40), calldataload(q))
|
||
mstore(add(mPtr, 0x60), calldataload(add(q, 0x20)))
|
||
let l_success := staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40)
|
||
if iszero(l_success) {
|
||
error_ec_op()
|
||
}
|
||
}
|
||
|
||
/// @parma dst pointer storing the result
|
||
/// @param src pointer to a point on Bn254(𝔽_p)
|
||
/// @param s scalar
|
||
/// @param mPtr free memory
|
||
function point_mul(dst, src, s, mPtr) {
|
||
mstore(mPtr, mload(src))
|
||
mstore(add(mPtr, 0x20), mload(add(src, 0x20)))
|
||
mstore(add(mPtr, 0x40), s)
|
||
let l_success := staticcall(gas(), EC_MUL, mPtr, 0x60, dst, 0x40)
|
||
if iszero(l_success) {
|
||
error_ec_op()
|
||
}
|
||
}
|
||
|
||
/// @parma dst pointer storing the result
|
||
/// @param src pointer to a point on Bn254(𝔽_p) on calldata
|
||
/// @param s scalar
|
||
/// @param mPtr free memory
|
||
function point_mul_calldata(dst, src, s, mPtr) {
|
||
mstore(mPtr, calldataload(src))
|
||
mstore(add(mPtr, 0x20), calldataload(add(src, 0x20)))
|
||
mstore(add(mPtr, 0x40), s)
|
||
let l_success := staticcall(gas(), EC_MUL, mPtr, 0x60, dst, 0x40)
|
||
if iszero(l_success) {
|
||
error_ec_op()
|
||
}
|
||
}
|
||
|
||
/// @notice dst <- dst + [s]src (Elliptic curve)
|
||
/// @param dst pointer accumulator point storing the result
|
||
/// @param src pointer to the point to multiply and add
|
||
/// @param s scalar
|
||
/// @param mPtr free memory
|
||
function point_acc_mul(dst, src, s, mPtr) {
|
||
mstore(mPtr, mload(src))
|
||
mstore(add(mPtr, 0x20), mload(add(src, 0x20)))
|
||
mstore(add(mPtr, 0x40), s)
|
||
let l_success := staticcall(gas(), 7, mPtr, 0x60, mPtr, 0x40)
|
||
mstore(add(mPtr, 0x40), mload(dst))
|
||
mstore(add(mPtr, 0x60), mload(add(dst, 0x20)))
|
||
l_success := and(l_success, staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40))
|
||
if iszero(l_success) {
|
||
error_ec_op()
|
||
}
|
||
}
|
||
|
||
/// @notice dst <- dst + [s]src (Elliptic curve)
|
||
/// @param dst pointer accumulator point storing the result
|
||
/// @param src pointer to the point to multiply and add (on calldata)
|
||
/// @param s scalar
|
||
/// @mPtr free memory
|
||
function point_acc_mul_calldata(dst, src, s, mPtr) {
|
||
mstore(mPtr, calldataload(src))
|
||
mstore(add(mPtr, 0x20), calldataload(add(src, 0x20)))
|
||
mstore(add(mPtr, 0x40), s)
|
||
let l_success := staticcall(gas(), 7, mPtr, 0x60, mPtr, 0x40)
|
||
mstore(add(mPtr, 0x40), mload(dst))
|
||
mstore(add(mPtr, 0x60), mload(add(dst, 0x20)))
|
||
l_success := and(l_success, staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40))
|
||
if iszero(l_success) {
|
||
error_ec_op()
|
||
}
|
||
}
|
||
|
||
/// @notice dst <- dst + src*s (Fr) dst,src are addresses, s is a value
|
||
/// @param dst pointer storing the result
|
||
/// @param src pointer to the scalar to multiply and add (on calldata)
|
||
/// @param s scalar
|
||
function fr_acc_mul_calldata(dst, src, s) {
|
||
let tmp := mulmod(calldataload(src), s, R_MOD)
|
||
mstore(dst, addmod(mload(dst), tmp, R_MOD))
|
||
}
|
||
|
||
/// @param x element to exponentiate
|
||
/// @param e exponent
|
||
/// @param mPtr free memory
|
||
/// @return res x ** e mod r
|
||
function pow(x, e, mPtr) -> res {
|
||
mstore(mPtr, 0x20)
|
||
mstore(add(mPtr, 0x20), 0x20)
|
||
mstore(add(mPtr, 0x40), 0x20)
|
||
mstore(add(mPtr, 0x60), x)
|
||
mstore(add(mPtr, 0x80), e)
|
||
mstore(add(mPtr, 0xa0), R_MOD)
|
||
let check_staticcall := staticcall(gas(), MOD_EXP, mPtr, 0xc0, mPtr, 0x20)
|
||
if eq(check_staticcall, 0) {
|
||
error_mod_exp()
|
||
}
|
||
res := mload(mPtr)
|
||
}
|
||
}
|
||
}
|
||
}
|