aere-contracts/contracts/zkverify/AereHalo2CubicVerifier.sol
Aere Network a13a649b77
Some checks are pending
contracts-ci / Install (lockfile) → compile → full test suite (push) Waiting to run
contracts-ci / PQC known-answer tests (NIST vectors) (push) Waiting to run
contracts-ci / Coverage (scoped, with artifacts) (push) Waiting to run
Initial public release
Aere Network public source. Everything here can be checked against the live
chain (chain id 2800, https://rpc.aere.network).

Scope note, stated up front rather than buried: consensus on chain 2800 is
classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at
the signature, precompile, account and transport layers. Nothing here makes the
consensus post-quantum, and no document in it should be read as claiming so.
2026-07-20 01:02:37 +03:00

805 lines
38 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract AereHalo2CubicVerifier {
uint256 internal constant PROOF_LEN_CPTR = 0x44;
uint256 internal constant PROOF_CPTR = 0x64;
uint256 internal constant NUM_INSTANCE_CPTR = 0x04e4;
uint256 internal constant INSTANCE_CPTR = 0x0504;
uint256 internal constant FIRST_QUOTIENT_X_CPTR = 0x01a4;
uint256 internal constant LAST_QUOTIENT_X_CPTR = 0x0264;
uint256 internal constant VK_MPTR = 0x0320;
uint256 internal constant VK_DIGEST_MPTR = 0x0320;
uint256 internal constant NUM_INSTANCES_MPTR = 0x0340;
uint256 internal constant K_MPTR = 0x0360;
uint256 internal constant N_INV_MPTR = 0x0380;
uint256 internal constant OMEGA_MPTR = 0x03a0;
uint256 internal constant OMEGA_INV_MPTR = 0x03c0;
uint256 internal constant OMEGA_INV_TO_L_MPTR = 0x03e0;
uint256 internal constant HAS_ACCUMULATOR_MPTR = 0x0400;
uint256 internal constant ACC_OFFSET_MPTR = 0x0420;
uint256 internal constant NUM_ACC_LIMBS_MPTR = 0x0440;
uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = 0x0460;
uint256 internal constant G1_X_MPTR = 0x0480;
uint256 internal constant G1_Y_MPTR = 0x04a0;
uint256 internal constant G2_X_1_MPTR = 0x04c0;
uint256 internal constant G2_X_2_MPTR = 0x04e0;
uint256 internal constant G2_Y_1_MPTR = 0x0500;
uint256 internal constant G2_Y_2_MPTR = 0x0520;
uint256 internal constant NEG_S_G2_X_1_MPTR = 0x0540;
uint256 internal constant NEG_S_G2_X_2_MPTR = 0x0560;
uint256 internal constant NEG_S_G2_Y_1_MPTR = 0x0580;
uint256 internal constant NEG_S_G2_Y_2_MPTR = 0x05a0;
uint256 internal constant CHALLENGE_MPTR = 0x07c0;
uint256 internal constant THETA_MPTR = 0x07c0;
uint256 internal constant BETA_MPTR = 0x07e0;
uint256 internal constant GAMMA_MPTR = 0x0800;
uint256 internal constant Y_MPTR = 0x0820;
uint256 internal constant X_MPTR = 0x0840;
uint256 internal constant ZETA_MPTR = 0x0860;
uint256 internal constant NU_MPTR = 0x0880;
uint256 internal constant MU_MPTR = 0x08a0;
uint256 internal constant ACC_LHS_X_MPTR = 0x08c0;
uint256 internal constant ACC_LHS_Y_MPTR = 0x08e0;
uint256 internal constant ACC_RHS_X_MPTR = 0x0900;
uint256 internal constant ACC_RHS_Y_MPTR = 0x0920;
uint256 internal constant X_N_MPTR = 0x0940;
uint256 internal constant X_N_MINUS_1_INV_MPTR = 0x0960;
uint256 internal constant L_LAST_MPTR = 0x0980;
uint256 internal constant L_BLIND_MPTR = 0x09a0;
uint256 internal constant L_0_MPTR = 0x09c0;
uint256 internal constant INSTANCE_EVAL_MPTR = 0x09e0;
uint256 internal constant QUOTIENT_EVAL_MPTR = 0x0a00;
uint256 internal constant QUOTIENT_X_MPTR = 0x0a20;
uint256 internal constant QUOTIENT_Y_MPTR = 0x0a40;
uint256 internal constant G1_SCALAR_MPTR = 0x0a60;
uint256 internal constant PAIRING_LHS_X_MPTR = 0x0a80;
uint256 internal constant PAIRING_LHS_Y_MPTR = 0x0aa0;
uint256 internal constant PAIRING_RHS_X_MPTR = 0x0ac0;
uint256 internal constant PAIRING_RHS_Y_MPTR = 0x0ae0;
function verifyProof(
bytes calldata proof,
uint256[] calldata instances
) public view returns (bool) {
assembly {
// Read EC point (x, y) at (proof_cptr, proof_cptr + 0x20),
// and check if the point is on affine plane,
// and store them in (hash_mptr, hash_mptr + 0x20).
// Return updated (success, proof_cptr, hash_mptr).
function read_ec_point(success, proof_cptr, hash_mptr, q) -> ret0, ret1, ret2 {
let x := calldataload(proof_cptr)
let y := calldataload(add(proof_cptr, 0x20))
ret0 := and(success, lt(x, q))
ret0 := and(ret0, lt(y, q))
ret0 := and(ret0, eq(mulmod(y, y, q), addmod(mulmod(x, mulmod(x, x, q), q), 3, q)))
mstore(hash_mptr, x)
mstore(add(hash_mptr, 0x20), y)
ret1 := add(proof_cptr, 0x40)
ret2 := add(hash_mptr, 0x40)
}
// Squeeze challenge by keccak256(memory[0..hash_mptr]),
// and store hash mod r as challenge in challenge_mptr,
// and push back hash in 0x00 as the first input for next squeeze.
// Return updated (challenge_mptr, hash_mptr).
function squeeze_challenge(challenge_mptr, hash_mptr, r) -> ret0, ret1 {
let hash := keccak256(0x00, hash_mptr)
mstore(challenge_mptr, mod(hash, r))
mstore(0x00, hash)
ret0 := add(challenge_mptr, 0x20)
ret1 := 0x20
}
// Squeeze challenge without absorbing new input from calldata,
// by putting an extra 0x01 in memory[0x20] and squeeze by keccak256(memory[0..21]),
// and store hash mod r as challenge in challenge_mptr,
// and push back hash in 0x00 as the first input for next squeeze.
// Return updated (challenge_mptr).
function squeeze_challenge_cont(challenge_mptr, r) -> ret {
mstore8(0x20, 0x01)
let hash := keccak256(0x00, 0x21)
mstore(challenge_mptr, mod(hash, r))
mstore(0x00, hash)
ret := add(challenge_mptr, 0x20)
}
// Batch invert values in memory[mptr_start..mptr_end] in place.
// Return updated (success).
function batch_invert(success, mptr_start, mptr_end, r) -> ret {
let gp_mptr := mptr_end
let gp := mload(mptr_start)
let mptr := add(mptr_start, 0x20)
for
{}
lt(mptr, sub(mptr_end, 0x20))
{}
{
gp := mulmod(gp, mload(mptr), r)
mstore(gp_mptr, gp)
mptr := add(mptr, 0x20)
gp_mptr := add(gp_mptr, 0x20)
}
gp := mulmod(gp, mload(mptr), r)
mstore(gp_mptr, 0x20)
mstore(add(gp_mptr, 0x20), 0x20)
mstore(add(gp_mptr, 0x40), 0x20)
mstore(add(gp_mptr, 0x60), gp)
mstore(add(gp_mptr, 0x80), sub(r, 2))
mstore(add(gp_mptr, 0xa0), r)
ret := and(success, staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20))
let all_inv := mload(gp_mptr)
let first_mptr := mptr_start
let second_mptr := add(first_mptr, 0x20)
gp_mptr := sub(gp_mptr, 0x20)
for
{}
lt(second_mptr, mptr)
{}
{
let inv := mulmod(all_inv, mload(gp_mptr), r)
all_inv := mulmod(all_inv, mload(mptr), r)
mstore(mptr, inv)
mptr := sub(mptr, 0x20)
gp_mptr := sub(gp_mptr, 0x20)
}
let inv_first := mulmod(all_inv, mload(second_mptr), r)
let inv_second := mulmod(all_inv, mload(first_mptr), r)
mstore(first_mptr, inv_first)
mstore(second_mptr, inv_second)
}
// Add (x, y) into point at (0x00, 0x20).
// Return updated (success).
function ec_add_acc(success, x, y) -> ret {
mstore(0x40, x)
mstore(0x60, y)
ret := and(success, staticcall(gas(), 0x06, 0x00, 0x80, 0x00, 0x40))
}
// Scale point at (0x00, 0x20) by scalar.
function ec_mul_acc(success, scalar) -> ret {
mstore(0x40, scalar)
ret := and(success, staticcall(gas(), 0x07, 0x00, 0x60, 0x00, 0x40))
}
// Add (x, y) into point at (0x80, 0xa0).
// Return updated (success).
function ec_add_tmp(success, x, y) -> ret {
mstore(0xc0, x)
mstore(0xe0, y)
ret := and(success, staticcall(gas(), 0x06, 0x80, 0x80, 0x80, 0x40))
}
// Scale point at (0x80, 0xa0) by scalar.
// Return updated (success).
function ec_mul_tmp(success, scalar) -> ret {
mstore(0xc0, scalar)
ret := and(success, staticcall(gas(), 0x07, 0x80, 0x60, 0x80, 0x40))
}
// Perform pairing check.
// Return updated (success).
function ec_pairing(success, lhs_x, lhs_y, rhs_x, rhs_y) -> ret {
mstore(0x00, lhs_x)
mstore(0x20, lhs_y)
mstore(0x40, mload(G2_X_1_MPTR))
mstore(0x60, mload(G2_X_2_MPTR))
mstore(0x80, mload(G2_Y_1_MPTR))
mstore(0xa0, mload(G2_Y_2_MPTR))
mstore(0xc0, rhs_x)
mstore(0xe0, rhs_y)
mstore(0x100, mload(NEG_S_G2_X_1_MPTR))
mstore(0x120, mload(NEG_S_G2_X_2_MPTR))
mstore(0x140, mload(NEG_S_G2_Y_1_MPTR))
mstore(0x160, mload(NEG_S_G2_Y_2_MPTR))
ret := and(success, staticcall(gas(), 0x08, 0x00, 0x180, 0x00, 0x20))
ret := and(ret, mload(0x00))
}
// Modulus
let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // BN254 base field
let r := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // BN254 scalar field
// Initialize success as true
let success := true
{
// Load vk_digest and num_instances of vk into memory
mstore(0x0320, 0x11b8d7714d2fe38e4b8de74dfa5b27118ded5acb94e51d86774485048eaab68b) // vk_digest
mstore(0x0340, 0x0000000000000000000000000000000000000000000000000000000000000001) // num_instances
// Check valid length of proof
success := and(success, eq(0x0480, calldataload(PROOF_LEN_CPTR)))
// Check valid length of instances
let num_instances := mload(NUM_INSTANCES_MPTR)
success := and(success, eq(num_instances, calldataload(NUM_INSTANCE_CPTR)))
// Absorb vk diegst
mstore(0x00, mload(VK_DIGEST_MPTR))
// Read instances and witness commitments and generate challenges
let hash_mptr := 0x20
let instance_cptr := INSTANCE_CPTR
for
{ let instance_cptr_end := add(instance_cptr, mul(0x20, num_instances)) }
lt(instance_cptr, instance_cptr_end)
{}
{
let instance := calldataload(instance_cptr)
success := and(success, lt(instance, r))
mstore(hash_mptr, instance)
instance_cptr := add(instance_cptr, 0x20)
hash_mptr := add(hash_mptr, 0x20)
}
let proof_cptr := PROOF_CPTR
let challenge_mptr := CHALLENGE_MPTR
// Phase 1
for
{ let proof_cptr_end := add(proof_cptr, 0xc0) }
lt(proof_cptr, proof_cptr_end)
{}
{
success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q)
}
challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r)
challenge_mptr := squeeze_challenge_cont(challenge_mptr, r)
challenge_mptr := squeeze_challenge_cont(challenge_mptr, r)
// Phase 2
for
{ let proof_cptr_end := add(proof_cptr, 0x80) }
lt(proof_cptr, proof_cptr_end)
{}
{
success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q)
}
challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r)
// Phase 3
for
{ let proof_cptr_end := add(proof_cptr, 0x0100) }
lt(proof_cptr, proof_cptr_end)
{}
{
success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q)
}
challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r)
// Read evaluations
for
{ let proof_cptr_end := add(proof_cptr, 0x01c0) }
lt(proof_cptr, proof_cptr_end)
{}
{
let eval := calldataload(proof_cptr)
success := and(success, lt(eval, r))
mstore(hash_mptr, eval)
proof_cptr := add(proof_cptr, 0x20)
hash_mptr := add(hash_mptr, 0x20)
}
// Read batch opening proof and generate challenges
challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // zeta
challenge_mptr := squeeze_challenge_cont(challenge_mptr, r) // nu
success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) // W
challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // mu
success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) // W'
// Load full vk into memory
mstore(0x0320, 0x11b8d7714d2fe38e4b8de74dfa5b27118ded5acb94e51d86774485048eaab68b) // vk_digest
mstore(0x0340, 0x0000000000000000000000000000000000000000000000000000000000000001) // num_instances
mstore(0x0360, 0x000000000000000000000000000000000000000000000000000000000000000a) // k
mstore(0x0380, 0x3058355f447953c1ade231a513e0f80710e9db4e679b02351f90fd168b040001) // n_inv
mstore(0x03a0, 0x2ad9021ed07c42ab19f77c5cf2cbd2deb135ea330f1b1573bd08d99309c4bb7d) // omega
mstore(0x03c0, 0x0ae3c95fc03c0a5f2de8a8f46c03ccdfdfed2bb98c9e4ae0b10b15eda4e3b1e3) // omega_inv
mstore(0x03e0, 0x15f79db9c39181bc3e31c83f9291da76eedf1b23c410add7e9098464aaa4fb26) // omega_inv_to_l
mstore(0x0400, 0x0000000000000000000000000000000000000000000000000000000000000000) // has_accumulator
mstore(0x0420, 0x0000000000000000000000000000000000000000000000000000000000000000) // acc_offset
mstore(0x0440, 0x0000000000000000000000000000000000000000000000000000000000000000) // num_acc_limbs
mstore(0x0460, 0x0000000000000000000000000000000000000000000000000000000000000000) // num_acc_limb_bits
mstore(0x0480, 0x0000000000000000000000000000000000000000000000000000000000000001) // g1_x
mstore(0x04a0, 0x0000000000000000000000000000000000000000000000000000000000000002) // g1_y
mstore(0x04c0, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) // g2_x_1
mstore(0x04e0, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) // g2_x_2
mstore(0x0500, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) // g2_y_1
mstore(0x0520, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) // g2_y_2
mstore(0x0540, 0x12c0e8d2fae98104fcd44c7e31e3b66f61e404949cb079aeef10b75c665db892) // neg_s_g2_x_1
mstore(0x0560, 0x179c7e86619a91461751256c782b6200c9bb6e70beb8c90d206b956b92235e28) // neg_s_g2_x_2
mstore(0x0580, 0x0a0c9027cee6bb59d2f3459a8c5fd59a02b32f5a012a8221b7cffcb4d676f56f) // neg_s_g2_y_1
mstore(0x05a0, 0x2f5f9ab0af884ceb2222b6d3826751366d38486be711f7e9929fbc0777fac256) // neg_s_g2_y_2
mstore(0x05c0, 0x018ae5cff801e7035bab74d7c7c8837ee34dc88354ec6a6ec3e4ea94ffc5b31e) // fixed_comms[0].x
mstore(0x05e0, 0x1b881cd510a49b060b48d563340cee9a406b636114a29ca72a43a1fd7b833566) // fixed_comms[0].y
mstore(0x0600, 0x2796320633288d633427b3b200db8f34a146ce05ac2b9c55223da5c7a0dbbf79) // fixed_comms[1].x
mstore(0x0620, 0x2c94fd3f66b10ba737247338c1688eda12db66e66a64d596b0c0e6190ac88357) // fixed_comms[1].y
mstore(0x0640, 0x2533b1eae2d4f10a32ba520bf9716c0961824891a9c3b87e766d64a5bffb1e40) // fixed_comms[2].x
mstore(0x0660, 0x1120d5179bd78c44ed4b286ec5f5a46bffd06a6396611982fcc2b2a05b0c138c) // fixed_comms[2].y
mstore(0x0680, 0x08b4c37280e855fd45ae292c16a0c5be2ec2e9203652b3de358175108ce68bb8) // fixed_comms[3].x
mstore(0x06a0, 0x17bec8b8d337980c5a7611eab611fd353ac2d3b69c935d6e25827722e7e65ce2) // fixed_comms[3].y
mstore(0x06c0, 0x2a275f0773f0047bdede17e8fb0359fc96826efc6dcc1bd3d52632bb53bcad6d) // fixed_comms[4].x
mstore(0x06e0, 0x1065e5809bbfbbb9ca99e1b56daab043cf2bc3310385bb46a8202ddaf42291d5) // fixed_comms[4].y
mstore(0x0700, 0x2c30689dfa71d55014d238f1280183844517e99d4bbee5824c8d49b76b5304b1) // permutation_comms[0].x
mstore(0x0720, 0x1d52e508e8605ef882357a21ea8b6bb2f42a84eae6de1c28ae0d2921346df6b5) // permutation_comms[0].y
mstore(0x0740, 0x1a62f5081b33e431fb050a901291ee7bec2005e2a2cff727f46dc2e22bf14128) // permutation_comms[1].x
mstore(0x0760, 0x0211cac7165924093fdfbb20e793dcea288181ba24d854c3dcc838a52d607a86) // permutation_comms[1].y
mstore(0x0780, 0x2691f98a2c52172f0ccf930d12afbe07ad981c7d1817d819071cf25da892ae5b) // permutation_comms[2].x
mstore(0x07a0, 0x1fdce525572200d2cb5e8dd7170bc339c98b992971ec3255e2e87f2670be6157) // permutation_comms[2].y
// Read accumulator from instances
if mload(HAS_ACCUMULATOR_MPTR) {
let num_limbs := mload(NUM_ACC_LIMBS_MPTR)
let num_limb_bits := mload(NUM_ACC_LIMB_BITS_MPTR)
let cptr := add(INSTANCE_CPTR, mul(mload(ACC_OFFSET_MPTR), 0x20))
let lhs_y_off := mul(num_limbs, 0x20)
let rhs_x_off := mul(lhs_y_off, 2)
let rhs_y_off := mul(lhs_y_off, 3)
let lhs_x := calldataload(cptr)
let lhs_y := calldataload(add(cptr, lhs_y_off))
let rhs_x := calldataload(add(cptr, rhs_x_off))
let rhs_y := calldataload(add(cptr, rhs_y_off))
for
{
let cptr_end := add(cptr, mul(0x20, num_limbs))
let shift := num_limb_bits
}
lt(cptr, cptr_end)
{}
{
cptr := add(cptr, 0x20)
lhs_x := add(lhs_x, shl(shift, calldataload(cptr)))
lhs_y := add(lhs_y, shl(shift, calldataload(add(cptr, lhs_y_off))))
rhs_x := add(rhs_x, shl(shift, calldataload(add(cptr, rhs_x_off))))
rhs_y := add(rhs_y, shl(shift, calldataload(add(cptr, rhs_y_off))))
shift := add(shift, num_limb_bits)
}
success := and(success, and(lt(lhs_x, q), lt(lhs_y, q)))
success := and(success, eq(mulmod(lhs_y, lhs_y, q), addmod(mulmod(lhs_x, mulmod(lhs_x, lhs_x, q), q), 3, q)))
success := and(success, and(lt(rhs_x, q), lt(rhs_y, q)))
success := and(success, eq(mulmod(rhs_y, rhs_y, q), addmod(mulmod(rhs_x, mulmod(rhs_x, rhs_x, q), q), 3, q)))
mstore(ACC_LHS_X_MPTR, lhs_x)
mstore(ACC_LHS_Y_MPTR, lhs_y)
mstore(ACC_RHS_X_MPTR, rhs_x)
mstore(ACC_RHS_Y_MPTR, rhs_y)
}
pop(q)
}
// Revert earlier if anything from calldata is invalid
if iszero(success) {
revert(0, 0)
}
// Compute lagrange evaluations and instance evaluation
{
let k := mload(K_MPTR)
let x := mload(X_MPTR)
let x_n := x
for
{ let idx := 0 }
lt(idx, k)
{ idx := add(idx, 1) }
{
x_n := mulmod(x_n, x_n, r)
}
let omega := mload(OMEGA_MPTR)
let mptr := X_N_MPTR
let mptr_end := add(mptr, mul(0x20, add(mload(NUM_INSTANCES_MPTR), 6)))
if iszero(mload(NUM_INSTANCES_MPTR)) {
mptr_end := add(mptr_end, 0x20)
}
for
{ let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) }
lt(mptr, mptr_end)
{ mptr := add(mptr, 0x20) }
{
mstore(mptr, addmod(x, sub(r, pow_of_omega), r))
pow_of_omega := mulmod(pow_of_omega, omega, r)
}
let x_n_minus_1 := addmod(x_n, sub(r, 1), r)
mstore(mptr_end, x_n_minus_1)
success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), r)
mptr := X_N_MPTR
let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r)
for
{ let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) }
lt(mptr, mptr_end)
{ mptr := add(mptr, 0x20) }
{
mstore(mptr, mulmod(l_i_common, mulmod(mload(mptr), pow_of_omega, r), r))
pow_of_omega := mulmod(pow_of_omega, omega, r)
}
let l_blind := mload(add(X_N_MPTR, 0x20))
let l_i_cptr := add(X_N_MPTR, 0x40)
for
{ let l_i_cptr_end := add(X_N_MPTR, 0xc0) }
lt(l_i_cptr, l_i_cptr_end)
{ l_i_cptr := add(l_i_cptr, 0x20) }
{
l_blind := addmod(l_blind, mload(l_i_cptr), r)
}
let instance_eval := 0
for
{
let instance_cptr := INSTANCE_CPTR
let instance_cptr_end := add(instance_cptr, mul(0x20, mload(NUM_INSTANCES_MPTR)))
}
lt(instance_cptr, instance_cptr_end)
{
instance_cptr := add(instance_cptr, 0x20)
l_i_cptr := add(l_i_cptr, 0x20)
}
{
instance_eval := addmod(instance_eval, mulmod(mload(l_i_cptr), calldataload(instance_cptr), r), r)
}
let x_n_minus_1_inv := mload(mptr_end)
let l_last := mload(X_N_MPTR)
let l_0 := mload(add(X_N_MPTR, 0xc0))
mstore(X_N_MPTR, x_n)
mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv)
mstore(L_LAST_MPTR, l_last)
mstore(L_BLIND_MPTR, l_blind)
mstore(L_0_MPTR, l_0)
mstore(INSTANCE_EVAL_MPTR, instance_eval)
}
// Compute quotient evavluation
{
let quotient_eval_numer
let delta := 4131629893567559867359510883348571134090853742863529169391034518566172092834
let y := mload(Y_MPTR)
{
let f_0 := calldataload(0x0304)
let a_0 := calldataload(0x02a4)
let var0 := mulmod(f_0, a_0, r)
let f_1 := calldataload(0x0324)
let a_1 := calldataload(0x02c4)
let var1 := mulmod(f_1, a_1, r)
let var2 := addmod(var0, var1, r)
let f_2 := calldataload(0x0344)
let a_2 := calldataload(0x02e4)
let var3 := mulmod(f_2, a_2, r)
let var4 := addmod(var2, var3, r)
let f_3 := calldataload(0x0364)
let var5 := mulmod(f_3, a_0, r)
let var6 := mulmod(var5, a_1, r)
let var7 := addmod(var4, var6, r)
let f_4 := calldataload(0x0384)
let var8 := addmod(var7, f_4, r)
let i_eval := mload(INSTANCE_EVAL_MPTR)
let var9 := addmod(var8, i_eval, r)
quotient_eval_numer := var9
}
{
let l_0 := mload(L_0_MPTR)
let eval := addmod(l_0, sub(r, mulmod(l_0, calldataload(0x0424), r)), r)
quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r)
}
{
let perm_z_last := calldataload(0x0424)
let eval := mulmod(mload(L_LAST_MPTR), addmod(mulmod(perm_z_last, perm_z_last, r), sub(r, perm_z_last), r), r)
quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r)
}
{
let gamma := mload(GAMMA_MPTR)
let beta := mload(BETA_MPTR)
let lhs := calldataload(0x0444)
let rhs := calldataload(0x0424)
lhs := mulmod(lhs, addmod(addmod(calldataload(0x02a4), mulmod(beta, calldataload(0x03c4), r), r), gamma, r), r)
lhs := mulmod(lhs, addmod(addmod(calldataload(0x02c4), mulmod(beta, calldataload(0x03e4), r), r), gamma, r), r)
lhs := mulmod(lhs, addmod(addmod(calldataload(0x02e4), mulmod(beta, calldataload(0x0404), r), r), gamma, r), r)
mstore(0x00, mulmod(beta, mload(X_MPTR), r))
rhs := mulmod(rhs, addmod(addmod(calldataload(0x02a4), mload(0x00), r), gamma, r), r)
mstore(0x00, mulmod(mload(0x00), delta, r))
rhs := mulmod(rhs, addmod(addmod(calldataload(0x02c4), mload(0x00), r), gamma, r), r)
mstore(0x00, mulmod(mload(0x00), delta, r))
rhs := mulmod(rhs, addmod(addmod(calldataload(0x02e4), mload(0x00), r), gamma, r), r)
let left_sub_right := addmod(lhs, sub(r, rhs), r)
let eval := addmod(left_sub_right, sub(r, mulmod(left_sub_right, addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r), r)), r)
quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), eval, r)
}
pop(y)
pop(delta)
let quotient_eval := mulmod(quotient_eval_numer, mload(X_N_MINUS_1_INV_MPTR), r)
mstore(QUOTIENT_EVAL_MPTR, quotient_eval)
}
// Compute quotient commitment
{
mstore(0x00, calldataload(LAST_QUOTIENT_X_CPTR))
mstore(0x20, calldataload(add(LAST_QUOTIENT_X_CPTR, 0x20)))
let x_n := mload(X_N_MPTR)
for
{
let cptr := sub(LAST_QUOTIENT_X_CPTR, 0x40)
let cptr_end := sub(FIRST_QUOTIENT_X_CPTR, 0x40)
}
lt(cptr_end, cptr)
{}
{
success := ec_mul_acc(success, x_n)
success := ec_add_acc(success, calldataload(cptr), calldataload(add(cptr, 0x20)))
cptr := sub(cptr, 0x40)
}
mstore(QUOTIENT_X_MPTR, mload(0x00))
mstore(QUOTIENT_Y_MPTR, mload(0x20))
}
// Compute pairing lhs and rhs
{
{
let x := mload(X_MPTR)
let omega := mload(OMEGA_MPTR)
let omega_inv := mload(OMEGA_INV_MPTR)
let x_pow_of_omega := mulmod(x, omega, r)
mstore(0x01e0, x_pow_of_omega)
mstore(0x01c0, x)
x_pow_of_omega := mulmod(x, omega_inv, r)
}
{
let mu := mload(MU_MPTR)
for
{
let mptr := 0x0200
let mptr_end := 0x0240
let point_mptr := 0x01c0
}
lt(mptr, mptr_end)
{
mptr := add(mptr, 0x20)
point_mptr := add(point_mptr, 0x20)
}
{
mstore(mptr, addmod(mu, sub(r, mload(point_mptr)), r))
}
let s
s := mload(0x0200)
mstore(0x0240, s)
let diff
diff := mload(0x0220)
mstore(0x0260, diff)
mstore(0x00, diff)
diff := 1
mstore(0x0280, diff)
}
{
let point_0 := mload(0x01c0)
let coeff
coeff := 1
coeff := mulmod(coeff, mload(0x0200), r)
mstore(0x20, coeff)
}
{
let point_0 := mload(0x01c0)
let point_1 := mload(0x01e0)
let coeff
coeff := addmod(point_0, sub(r, point_1), r)
coeff := mulmod(coeff, mload(0x0200), r)
mstore(0x40, coeff)
coeff := addmod(point_1, sub(r, point_0), r)
coeff := mulmod(coeff, mload(0x0220), r)
mstore(0x60, coeff)
}
{
success := batch_invert(success, 0, 0x80, r)
let diff_0_inv := mload(0x00)
mstore(0x0260, diff_0_inv)
for
{
let mptr := 0x0280
let mptr_end := 0x02a0
}
lt(mptr, mptr_end)
{ mptr := add(mptr, 0x20) }
{
mstore(mptr, mulmod(mload(mptr), diff_0_inv, r))
}
}
{
let coeff := mload(0x20)
let zeta := mload(ZETA_MPTR)
let r_eval
r_eval := mulmod(coeff, calldataload(0x03a4), r)
r_eval := mulmod(r_eval, zeta, r)
r_eval := addmod(r_eval, mulmod(coeff, mload(QUOTIENT_EVAL_MPTR), r), r)
for
{
let cptr := 0x0404
let cptr_end := 0x03a4
}
lt(cptr_end, cptr)
{ cptr := sub(cptr, 0x20) }
{
r_eval := addmod(mulmod(r_eval, zeta, r), mulmod(coeff, calldataload(cptr), r), r)
}
for
{
let cptr := 0x0384
let cptr_end := 0x0284
}
lt(cptr_end, cptr)
{ cptr := sub(cptr, 0x20) }
{
r_eval := addmod(mulmod(r_eval, zeta, r), mulmod(coeff, calldataload(cptr), r), r)
}
mstore(0x02a0, r_eval)
}
{
let zeta := mload(ZETA_MPTR)
let r_eval
r_eval := addmod(r_eval, mulmod(mload(0x40), calldataload(0x0424), r), r)
r_eval := addmod(r_eval, mulmod(mload(0x60), calldataload(0x0444), r), r)
r_eval := mulmod(r_eval, mload(0x0280), r)
mstore(0x02c0, r_eval)
}
{
let sum := mload(0x20)
mstore(0x02e0, sum)
}
{
let sum := mload(0x40)
sum := addmod(sum, mload(0x60), r)
mstore(0x0300, sum)
}
{
for
{
let mptr := 0x00
let mptr_end := 0x40
let sum_mptr := 0x02e0
}
lt(mptr, mptr_end)
{
mptr := add(mptr, 0x20)
sum_mptr := add(sum_mptr, 0x20)
}
{
mstore(mptr, mload(sum_mptr))
}
success := batch_invert(success, 0, 0x40, r)
let r_eval := mulmod(mload(0x20), mload(0x02c0), r)
for
{
let sum_inv_mptr := 0x00
let sum_inv_mptr_end := 0x40
let r_eval_mptr := 0x02a0
}
lt(sum_inv_mptr, sum_inv_mptr_end)
{
sum_inv_mptr := sub(sum_inv_mptr, 0x20)
r_eval_mptr := sub(r_eval_mptr, 0x20)
}
{
r_eval := mulmod(r_eval, mload(NU_MPTR), r)
r_eval := addmod(r_eval, mulmod(mload(sum_inv_mptr), mload(r_eval_mptr), r), r)
}
mstore(G1_SCALAR_MPTR, sub(r, r_eval))
}
{
let zeta := mload(ZETA_MPTR)
let nu := mload(NU_MPTR)
mstore(0x00, calldataload(0x0164))
mstore(0x20, calldataload(0x0184))
success := ec_mul_acc(success, zeta)
success := ec_add_acc(success, mload(QUOTIENT_X_MPTR), mload(QUOTIENT_Y_MPTR))
for
{
let ptr := 0x0780
let ptr_end := 0x0580
}
lt(ptr_end, ptr)
{ ptr := sub(ptr, 0x40) }
{
success := ec_mul_acc(success, zeta)
success := ec_add_acc(success, mload(ptr), mload(add(ptr, 0x20)))
}
for
{
let ptr := 0xe4
let ptr_end := 0x24
}
lt(ptr_end, ptr)
{ ptr := sub(ptr, 0x40) }
{
success := ec_mul_acc(success, zeta)
success := ec_add_acc(success, calldataload(ptr), calldataload(add(ptr, 0x20)))
}
mstore(0x80, calldataload(0x0124))
mstore(0xa0, calldataload(0x0144))
success := ec_mul_tmp(success, mulmod(nu, mload(0x0280), r))
success := ec_add_acc(success, mload(0x80), mload(0xa0))
mstore(0x80, mload(G1_X_MPTR))
mstore(0xa0, mload(G1_Y_MPTR))
success := ec_mul_tmp(success, mload(G1_SCALAR_MPTR))
success := ec_add_acc(success, mload(0x80), mload(0xa0))
mstore(0x80, calldataload(0x0464))
mstore(0xa0, calldataload(0x0484))
success := ec_mul_tmp(success, sub(r, mload(0x0240)))
success := ec_add_acc(success, mload(0x80), mload(0xa0))
mstore(0x80, calldataload(0x04a4))
mstore(0xa0, calldataload(0x04c4))
success := ec_mul_tmp(success, mload(MU_MPTR))
success := ec_add_acc(success, mload(0x80), mload(0xa0))
mstore(PAIRING_LHS_X_MPTR, mload(0x00))
mstore(PAIRING_LHS_Y_MPTR, mload(0x20))
mstore(PAIRING_RHS_X_MPTR, calldataload(0x04a4))
mstore(PAIRING_RHS_Y_MPTR, calldataload(0x04c4))
}
}
// Random linear combine with accumulator
if mload(HAS_ACCUMULATOR_MPTR) {
mstore(0x00, mload(ACC_LHS_X_MPTR))
mstore(0x20, mload(ACC_LHS_Y_MPTR))
mstore(0x40, mload(ACC_RHS_X_MPTR))
mstore(0x60, mload(ACC_RHS_Y_MPTR))
mstore(0x80, mload(PAIRING_LHS_X_MPTR))
mstore(0xa0, mload(PAIRING_LHS_Y_MPTR))
mstore(0xc0, mload(PAIRING_RHS_X_MPTR))
mstore(0xe0, mload(PAIRING_RHS_Y_MPTR))
let challenge := mod(keccak256(0x00, 0x100), r)
// [pairing_lhs] += challenge * [acc_lhs]
success := ec_mul_acc(success, challenge)
success := ec_add_acc(success, mload(PAIRING_LHS_X_MPTR), mload(PAIRING_LHS_Y_MPTR))
mstore(PAIRING_LHS_X_MPTR, mload(0x00))
mstore(PAIRING_LHS_Y_MPTR, mload(0x20))
// [pairing_rhs] += challenge * [acc_rhs]
mstore(0x00, mload(ACC_RHS_X_MPTR))
mstore(0x20, mload(ACC_RHS_Y_MPTR))
success := ec_mul_acc(success, challenge)
success := ec_add_acc(success, mload(PAIRING_RHS_X_MPTR), mload(PAIRING_RHS_Y_MPTR))
mstore(PAIRING_RHS_X_MPTR, mload(0x00))
mstore(PAIRING_RHS_Y_MPTR, mload(0x20))
}
// Perform pairing
success := ec_pairing(
success,
mload(PAIRING_LHS_X_MPTR),
mload(PAIRING_LHS_Y_MPTR),
mload(PAIRING_RHS_X_MPTR),
mload(PAIRING_RHS_Y_MPTR)
)
// Revert if anything fails
if iszero(success) {
revert(0x00, 0x00)
}
// Return 1 as result if everything succeeds
mstore(0x00, 1)
return(0x00, 0x20)
}
}
}