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.
805 lines
38 KiB
Solidity
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)
|
|
}
|
|
}
|
|
} |