2024-01-18 06:52:00 +00:00
|
|
|
// Copyright 2017 Christian Reitwiessner
|
2024-01-18 09:29:10 +00:00
|
|
|
// Copyright 2019 OKIMS
|
|
|
|
// Copyright 2024 Codex
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
// SOFTWARE.
|
2024-01-18 07:56:15 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2024-01-23 09:24:02 +00:00
|
|
|
pragma solidity 0.8.23;
|
2024-01-23 12:18:33 +00:00
|
|
|
import "./Groth16.sol";
|
2024-01-23 12:30:11 +00:00
|
|
|
|
2024-01-30 11:08:40 +00:00
|
|
|
contract Groth16Verifier {
|
2024-01-30 11:15:37 +00:00
|
|
|
uint private constant _P =
|
2024-01-23 12:30:11 +00:00
|
|
|
21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
2024-01-30 11:15:37 +00:00
|
|
|
uint256 private constant _Q =
|
2024-01-30 11:14:34 +00:00
|
|
|
21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
|
|
|
|
|
|
|
VerifyingKey private _verifyingKey;
|
|
|
|
|
|
|
|
struct VerifyingKey {
|
|
|
|
G1Point alpha1;
|
|
|
|
G2Point beta2;
|
|
|
|
G2Point gamma2;
|
|
|
|
G2Point delta2;
|
|
|
|
G1Point[] ic;
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor(VerifyingKey memory key) {
|
|
|
|
_verifyingKey.alpha1 = key.alpha1;
|
|
|
|
_verifyingKey.beta2 = key.beta2;
|
|
|
|
_verifyingKey.gamma2 = key.gamma2;
|
|
|
|
_verifyingKey.delta2 = key.delta2;
|
|
|
|
for (uint i = 0; i < key.ic.length; i++) {
|
|
|
|
_verifyingKey.ic.push(key.ic[i]);
|
|
|
|
}
|
|
|
|
}
|
2024-01-23 12:30:11 +00:00
|
|
|
|
2024-01-23 09:41:50 +00:00
|
|
|
/// The negation of p, i.e. p.addition(p.negate()) should be zero.
|
|
|
|
function negate(G1Point memory p) internal pure returns (G1Point memory) {
|
2024-01-30 11:15:37 +00:00
|
|
|
return G1Point(p.x, (_P - p.y) % _P);
|
2024-01-23 09:41:50 +00:00
|
|
|
}
|
2024-01-23 12:30:11 +00:00
|
|
|
|
2024-01-23 09:41:50 +00:00
|
|
|
/// The sum of two points of G1
|
2024-01-30 08:35:44 +00:00
|
|
|
function add(
|
2024-01-23 12:30:11 +00:00
|
|
|
G1Point memory p1,
|
|
|
|
G1Point memory p2
|
2024-01-30 08:47:44 +00:00
|
|
|
) internal view returns (bool success, G1Point memory sum) {
|
2024-01-23 09:41:50 +00:00
|
|
|
uint[4] memory input;
|
2024-01-23 11:34:43 +00:00
|
|
|
input[0] = p1.x;
|
|
|
|
input[1] = p1.y;
|
|
|
|
input[2] = p2.x;
|
|
|
|
input[3] = p2.y;
|
2024-01-23 12:05:27 +00:00
|
|
|
// solhint-disable-next-line no-inline-assembly
|
2024-01-23 09:41:50 +00:00
|
|
|
assembly {
|
2024-01-30 08:34:56 +00:00
|
|
|
success := staticcall(sub(gas(), 2000), 6, input, 128, sum, 64)
|
2024-01-18 06:52:00 +00:00
|
|
|
}
|
2024-01-23 09:41:50 +00:00
|
|
|
}
|
2024-01-23 12:30:11 +00:00
|
|
|
|
2024-01-23 09:41:50 +00:00
|
|
|
/// The product of a point on G1 and a scalar, i.e.
|
2024-01-23 12:05:27 +00:00
|
|
|
/// p == p.scalarMul(1) and p.addition(p) == p.scalarMul(2) for all points p.
|
2024-01-30 08:35:44 +00:00
|
|
|
function multiply(
|
2024-01-23 12:30:11 +00:00
|
|
|
G1Point memory p,
|
|
|
|
uint s
|
2024-01-30 08:47:44 +00:00
|
|
|
) internal view returns (bool success, G1Point memory product) {
|
2024-01-23 09:41:50 +00:00
|
|
|
uint[3] memory input;
|
2024-01-23 11:34:43 +00:00
|
|
|
input[0] = p.x;
|
|
|
|
input[1] = p.y;
|
2024-01-23 09:41:50 +00:00
|
|
|
input[2] = s;
|
2024-01-23 12:05:27 +00:00
|
|
|
// solhint-disable-next-line no-inline-assembly
|
2024-01-23 09:41:50 +00:00
|
|
|
assembly {
|
2024-01-30 08:34:56 +00:00
|
|
|
success := staticcall(sub(gas(), 2000), 7, input, 96, product, 64)
|
2024-01-18 06:52:00 +00:00
|
|
|
}
|
2024-01-23 09:41:50 +00:00
|
|
|
}
|
2024-01-23 12:30:11 +00:00
|
|
|
|
2024-01-30 11:05:22 +00:00
|
|
|
function checkPairing(
|
|
|
|
G1Point memory a1,
|
|
|
|
G2Point memory a2,
|
|
|
|
G1Point memory b1,
|
|
|
|
G2Point memory b2,
|
|
|
|
G1Point memory c1,
|
|
|
|
G2Point memory c2,
|
|
|
|
G1Point memory d1,
|
|
|
|
G2Point memory d2
|
2024-01-30 09:24:59 +00:00
|
|
|
) internal view returns (bool success, uint outcome) {
|
2024-01-30 11:05:22 +00:00
|
|
|
uint[24] memory input; // 4 pairs of G1 and G2 points
|
2024-01-30 09:24:59 +00:00
|
|
|
uint[1] memory output;
|
2024-01-30 11:05:22 +00:00
|
|
|
|
|
|
|
input[0] = a1.x;
|
|
|
|
input[1] = a1.y;
|
|
|
|
input[2] = a2.x.imag;
|
|
|
|
input[3] = a2.x.real;
|
|
|
|
input[4] = a2.y.imag;
|
|
|
|
input[5] = a2.y.real;
|
|
|
|
|
|
|
|
input[6] = b1.x;
|
|
|
|
input[7] = b1.y;
|
|
|
|
input[8] = b2.x.imag;
|
|
|
|
input[9] = b2.x.real;
|
|
|
|
input[10] = b2.y.imag;
|
|
|
|
input[11] = b2.y.real;
|
|
|
|
|
|
|
|
input[12] = c1.x;
|
|
|
|
input[13] = c1.y;
|
|
|
|
input[14] = c2.x.imag;
|
|
|
|
input[15] = c2.x.real;
|
|
|
|
input[16] = c2.y.imag;
|
|
|
|
input[17] = c2.y.real;
|
|
|
|
|
|
|
|
input[18] = d1.x;
|
|
|
|
input[19] = d1.y;
|
|
|
|
input[20] = d2.x.imag;
|
|
|
|
input[21] = d2.x.real;
|
|
|
|
input[22] = d2.y.imag;
|
|
|
|
input[23] = d2.y.real;
|
|
|
|
|
2024-01-23 12:05:27 +00:00
|
|
|
// solhint-disable-next-line no-inline-assembly
|
2024-01-23 09:41:50 +00:00
|
|
|
assembly {
|
2024-01-23 12:30:11 +00:00
|
|
|
success := staticcall(
|
|
|
|
sub(gas(), 2000),
|
|
|
|
8,
|
2024-01-30 11:05:22 +00:00
|
|
|
input,
|
|
|
|
768, // 24 uints, 32 bytes each
|
2024-01-30 09:24:59 +00:00
|
|
|
output,
|
2024-01-30 08:34:56 +00:00
|
|
|
32
|
2024-01-23 12:30:11 +00:00
|
|
|
)
|
2024-01-18 06:52:00 +00:00
|
|
|
}
|
2024-01-30 09:24:59 +00:00
|
|
|
return (success, output[0]);
|
2024-01-23 09:41:50 +00:00
|
|
|
}
|
2024-01-23 12:30:11 +00:00
|
|
|
|
|
|
|
function verify(
|
|
|
|
Groth16Proof calldata proof,
|
|
|
|
uint[] memory input
|
2024-01-30 08:47:44 +00:00
|
|
|
) public view returns (bool success) {
|
2024-01-23 12:30:11 +00:00
|
|
|
require(input.length + 1 == _verifyingKey.ic.length, "verifier-bad-input");
|
2024-01-23 12:05:27 +00:00
|
|
|
// Compute the linear combination vkX
|
2024-01-23 12:18:33 +00:00
|
|
|
G1Point memory vkX = G1Point(0, 0);
|
2024-01-23 09:41:50 +00:00
|
|
|
for (uint i = 0; i < input.length; i++) {
|
2024-01-23 12:30:11 +00:00
|
|
|
require(
|
2024-01-30 11:15:37 +00:00
|
|
|
input[i] < _Q,
|
2024-01-23 12:30:11 +00:00
|
|
|
"verifier-gte-snark-scalar-field"
|
|
|
|
);
|
2024-01-30 08:47:44 +00:00
|
|
|
G1Point memory product;
|
2024-01-30 11:08:40 +00:00
|
|
|
(success, product) = multiply(_verifyingKey.ic[i + 1], input[i]);
|
2024-01-30 10:17:04 +00:00
|
|
|
if (!success) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-01-30 11:08:40 +00:00
|
|
|
(success, vkX) = add(vkX, product);
|
2024-01-30 10:17:04 +00:00
|
|
|
if (!success) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-01-18 06:52:00 +00:00
|
|
|
}
|
2024-01-30 11:08:40 +00:00
|
|
|
(success, vkX) = add(vkX, _verifyingKey.ic[0]);
|
2024-01-30 10:17:04 +00:00
|
|
|
if (!success) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-01-30 09:24:59 +00:00
|
|
|
uint outcome;
|
2024-01-30 11:14:34 +00:00
|
|
|
(success, outcome) = checkPairing(
|
|
|
|
negate(proof.a),
|
|
|
|
proof.b,
|
|
|
|
_verifyingKey.alpha1,
|
|
|
|
_verifyingKey.beta2,
|
|
|
|
vkX,
|
|
|
|
_verifyingKey.gamma2,
|
|
|
|
proof.c,
|
|
|
|
_verifyingKey.delta2
|
|
|
|
);
|
2024-01-30 10:17:04 +00:00
|
|
|
if (!success) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-01-30 09:24:59 +00:00
|
|
|
return outcome == 1;
|
2024-01-23 09:41:50 +00:00
|
|
|
}
|
2024-01-18 06:52:00 +00:00
|
|
|
}
|