Copy // File: contracts/Pairing.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
library Pairing {
struct G1Point {
uint X;
uint Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint[2] X;
uint[2] Y;
}
/// @return the generator of G1
function P1() pure internal returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() pure internal returns (G2Point memory) {
// Original code point
return G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
}
// @return the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) pure internal returns (G1Point memory r) {
// The prime q in the base field F_q for G1
uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
if (p.X == 0 && p.Y == 0)
return G1Point(0, 0);
return G1Point(p.X, q - (p.Y % q));
}
// @return the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) public returns (G1Point memory result) {
uint[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
assembly {
let success := call(gas(), 0x06, 0, input, 0x80, result, 0x40)
switch success
case 0 { invalid() }
}
}
// @return the product of a point on G1 and a scalar, i.e.
// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint scalar) public returns (G1Point memory result) {
uint[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = scalar;
assembly {
let success := call(gas(), 0x07, 0, input, 0x60, result, 0x40)
switch success
case 0 { invalid() }
}
}
// @return the result of computing the pairing check
// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
// For example pairing([P1(), P1().negate()], [P2(), P2()]) should
// return true.
function pairing(G1Point[] memory p1, G2Point[] memory p2) public returns (bool) {
require(p1.length == p2.length);
uint elements = p1.length;
uint inputSize = elements * 6;
uint[] memory input = new uint[](inputSize);
for (uint i = 0; i < elements; i++)
{
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint[1] memory out;
bool success;
assembly {
//let memPtr := mload(0x40)
success := call(gas(), 0x08, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
switch success
case 0 {
invalid()
}
}
require(success);
return out[0] != 0;
}
/// Convenience method for a pairing check for two pairs.
function pairingProd2(
G1Point memory a1, G2Point memory a2,
G1Point memory b1, G2Point memory b2
) public returns (bool) {
G1Point[] memory p1 = new G1Point[](2);
G2Point[] memory p2 = new G2Point[](2);
p1[0] = a1;
p1[1] = b1;
p2[0] = a2;
p2[1] = b2;
return pairing(p1, p2);
}
/// Convenience method for a pairing check for three pairs.
function pairingProd3(
G1Point memory a1, G2Point memory a2,
G1Point memory b1, G2Point memory b2,
G1Point memory c1, G2Point memory c2
) public returns (bool) {
G1Point[] memory p1 = new G1Point[](3);
G2Point[] memory p2 = new G2Point[](3);
p1[0] = a1;
p1[1] = b1;
p1[2] = c1;
p2[0] = a2;
p2[1] = b2;
p2[2] = c2;
return pairing(p1, p2);
}
/// Convenience method for a pairing check for four pairs.
function pairingProd4(
G1Point memory a1, G2Point memory a2,
G1Point memory b1, G2Point memory b2,
G1Point memory c1, G2Point memory c2,
G1Point memory d1, G2Point memory d2
) public returns (bool) {
G1Point[] memory p1 = new G1Point[](4);
G2Point[] memory p2 = new G2Point[](4);
p1[0] = a1;
p1[1] = b1;
p1[2] = c1;
p1[3] = d1;
p2[0] = a2;
p2[1] = b2;
p2[2] = c2;
p2[3] = d2;
return pairing(p1, p2);
}
}
// File: contracts/BnPairingCheck.sol
pragma solidity ^0.8.10;
contract BnPairingCheck {
using Pairing for *;
bool public result = false;
struct VerifyingKey {
Pairing.G2Point A;
Pairing.G1Point B;
Pairing.G2Point C;
Pairing.G2Point gamma;
Pairing.G1Point gammaBeta1;
Pairing.G2Point gammaBeta2;
Pairing.G2Point Z;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G1Point A_p;
Pairing.G2Point B;
Pairing.G1Point B_p;
Pairing.G1Point C;
Pairing.G1Point C_p;
Pairing.G1Point K;
Pairing.G1Point H;
}
function verifyingKey() pure internal returns (VerifyingKey memory vk) {
vk.A = Pairing.G2Point([16610027721320090851672124826930543804510863425028512395206306928317475535804,8936789845922544559097602524648054597031330865008407381460968729887808214434], [2278578217592196498969542612994107970434638305320265550173445225942027074854,18336449124045676471393750622290479431334440531824730522288602977607157240650]);
vk.B = Pairing.G1Point(1984924168632842141759455341627143753024960974027438898638858975972756407564,10991053238332375915565380359166789463201591761740938272761726473772838859618);
vk.C = Pairing.G2Point([10660728934017853141365044466918475010597411890641229655657848436103395876116,3996391662237560225890291735380647896924014963474714424016445511172825791389], [5221331779058503178196633838312686055158887166644266661901185854029433298779,12183448649224206996148652487149426507910593413372228701177454061805688094675]);
vk.gamma = Pairing.G2Point([19004037734259218065220057650211328986997252342301116788268586579684875932598,18093848281567039857436784662151682189745312020865996311429156694186522940309], [5377856403552463400841775516298918127240964967532295209455188775179474313786,2889539749595311565918940419300442407947814810042015422814827877135693568505]);
vk.gammaBeta1 = Pairing.G1Point(7796626316580434743798382369107477206221192049125686546210621144964120983689,7934884528679805498299923633957794379202307702360555586276991024938091670488);
vk.gammaBeta2 = Pairing.G2Point([4487005664450616024577102016311266690760571702764152553013463219021170678312,372268767343205135890641734006927513939290443891671725490699149337509414363], [8727588333078631340262914721329976700431073842680933627593659695896604918915,5027865297535949490479385388683367202474878200260477572501220964101178956894]);
vk.Z = Pairing.G2Point([10162018577464408960423216104240658562943290569546240862381635704410977689235,15750847760428609853592351550031388692358090666989687368017823231947603993362], [13703537493621251480372183323146309058645469102580923196624726955632303691613,10133848043702140632001179191067180047829615626613968726429425860753144960369]);
vk.IC = new Pairing.G1Point[](2);
vk.IC[0] = Pairing.G1Point(10205875104072397627386129936295372804967786394340262122517620344193853862704,3108802252545217304319096845192350237223097046684036942919565176050064079266);
vk.IC[1] = Pairing.G1Point(19450223878547003131641146404062695786601341609154957657760980302351711435043,2090278837353290546550331589621169669090493301065290400727820127066575899332);
}
function verify(uint[] memory input, Proof memory proof) public returns (uint ret) {
VerifyingKey memory vk = verifyingKey();
require(input.length + 1 == vk.IC.length);
// Compute the linear combination vk_x
Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
for (uint i = 0; i < input.length; i++)
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));
vk_x = Pairing.addition(vk_x, vk.IC[0]);
if (!Pairing.pairingProd2(proof.A, vk.A, Pairing.negate(proof.A_p), Pairing.P2())) return 1;
if (!Pairing.pairingProd2(vk.B, proof.B, Pairing.negate(proof.B_p), Pairing.P2())) return 2;
if (!Pairing.pairingProd2(proof.C, vk.C, Pairing.negate(proof.C_p), Pairing.P2())) return 3;
if (!Pairing.pairingProd3(
proof.K, vk.gamma,
Pairing.negate(Pairing.addition(vk_x, Pairing.addition(proof.A, proof.C))), vk.gammaBeta2,
Pairing.negate(vk.gammaBeta1), proof.B
)) return 4;
if (!Pairing.pairingProd3(
Pairing.addition(vk_x, proof.A), proof.B,
Pairing.negate(proof.H), vk.Z,
Pairing.negate(proof.C), Pairing.P2()
)) return 5;
return 0;
}
function verifyProof(
uint[2] memory a,
uint[2] memory a_p,
uint[2][2] memory b,
uint[2] memory b_p,
uint[2] memory c,
uint[2] memory c_p,
uint[2] memory h,
uint[2] memory k,
uint[1] memory input
) public returns (bool r) {
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.A_p = Pairing.G1Point(a_p[0], a_p[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.B_p = Pairing.G1Point(b_p[0], b_p[1]);
proof.C = Pairing.G1Point(c[0], c[1]);
proof.C_p = Pairing.G1Point(c_p[0], c_p[1]);
proof.H = Pairing.G1Point(h[0], h[1]);
proof.K = Pairing.G1Point(k[0], k[1]);
uint[] memory inputValues = new uint[](input.length);
for(uint i = 0; i < input.length; i++){
inputValues[i] = input[i];
}
if (verify(inputValues, proof) == 0) {
return true;
} else {
return false;
}
}
function test0() public returns(bool) {
result = verifyProof(
/* a */ [uint(0), uint(0)],
/* ap */ [uint(0), uint(0)],
/* b */ [[uint(0), uint(0)],
[uint(0), uint(0)]],
/* bp */[uint(0), uint(0)],
/* c */ [uint(0), uint(0)],
/* cp */ [uint(0), uint(0)],
/* h */[uint(0), uint(0)],
/* k*/[uint(0), uint(0)],
[uint(0)]
);
return result;
}
function test1() public returns(bool) {
result = verifyProof(
/* a */ [2718095278949549179404065840476808091497056756728594798546953443174968085826, 6822245515525308836376340038348001955735763358906191705690804179787195477339],
/* ap */ [7962916779937813326271929941948123357638224433531051619920345691927094697341, 21602782423350364400160182139945359886597092844703295668648735242500045407956],
/* b */ [[8709267585010911413120517213461511437508385177818224549274052467927652980944, 19632384762601388343074878513416079515099688438290666177847273314001684795253],
[17954051800382421030408553656518095452830038658837501416087917013452810023812, 9313407443169062170332246002789350394219940180217974180983075689645346151558]],
/* bp */[9635209788867086759474994015521126137037843808855500775255711247474353341942, 10532357498625738653781203652235407445504418461844494535410725185262967725536],
/* c */ [2979082982449319418800994115689753411721779945253248515532569378637518482124, 3143567336181932302511851756760472718883118738818983203961850684965916083031],
/* cp */ [11182798853760866712100529614936626355599675889193406642506513786597302995359, 21503918186037221985951496509528138040813374125019591054416463010791565738112],
/* h */[4633883772453921040686106381946310074681701049370649431093501227658192420448, 21021275022297515067274628176614711148054587207810962211311080345928349346190],
/* k*/[20481961466655736077506474649847772957810447411263729097818993207697766925974, 18134245132528824771900871678480123127745757902738189746990901944851179135138],
[6301007345864501926049365915105502481566397466935164158686624182392111092001]
);
return result;
}
function test2() public returns(bool) {
result = verifyProof(
/* a */ [16483647994083632042653019342376493617507292244409483767011999030917568268646, 14894910552958451837608824090793975141071530720863443570081513964969682749237],
/* ap */ [7069277083124752480589269138496991668756747028035402285843178020131615294350, 9769833532751559998465267694651537664145336267300309123767160432711724831666],
/* b */ [
[10396820912983820590012141974278057713805439603448882846227355198709322789238, 4215149779965623264519391521256199140559499990271137375702176633421893610383],
[7168677908279967661582166035120849421362854198112972513633076412090253938046, 7939490528358177281807348800807384862458498738673302498496997520510790421465]
],
/* bp */[7292093587831110061576671664967603794360646367363057619801314532700018122737, 10723124365185779888153587187015081260999880730039480846573969372689234107375],
/* c */ [20110710583089424502944360852129601455489734470597967975354770536748481794282, 3145757061004047107401063345908323315455945293305604627001670605409827213671],
/* cp */ [6105559872747339441542380675491167877666447243500071222034839405367679925851, 17725653028994652750960303183103332283186984823200422907924350712276575028588],
/* h */[10049851113757098751686276929149014031557853631351627054447767136629148270384, 17909597939692457233922845451343003254610968728013606609824460021235534590306],
/* k*/[5996023988124922181895500924586855924244464998893492209549740999859637471335, 18044112761446177853237991684844833615435851238016207034759388984418696008767],
[uint(33)]
);
return result;
}
}