mirror of
https://github.com/semaphore-protocol/semaphore.git
synced 2026-01-11 07:38:14 -05:00
Compare commits
34 Commits
v2.6.0
...
v3.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3188d3dbff | ||
|
|
04f57db7f0 | ||
|
|
066f38c471 | ||
|
|
37e8784471 | ||
|
|
889cf1890a | ||
|
|
1a4a7f36e0 | ||
|
|
3d6c24a51b | ||
|
|
781922436e | ||
|
|
277a790e36 | ||
|
|
d880925604 | ||
|
|
5466178f40 | ||
|
|
6cc4dc07bb | ||
|
|
98a35c0a37 | ||
|
|
bfeb24791d | ||
|
|
37e2614ac7 | ||
|
|
84bb9c89a4 | ||
|
|
a4aaf7f7ec | ||
|
|
b92a6e1c7a | ||
|
|
3afae28e06 | ||
|
|
63cddf3da2 | ||
|
|
499ec1cbeb | ||
|
|
fb1ffee89d | ||
|
|
f7bc7900e0 | ||
|
|
bc14210bc7 | ||
|
|
aabad94a81 | ||
|
|
eeac211c01 | ||
|
|
6e0236e9bc | ||
|
|
a9f8379545 | ||
|
|
ac3e7b42a3 | ||
|
|
2b414f8c24 | ||
|
|
1fcff83c1a | ||
|
|
eb2d6ee62b | ||
|
|
db624c24e0 | ||
|
|
95e5ff669b |
@@ -1,5 +1,6 @@
|
||||
DEFAULT_NETWORK=hardhat
|
||||
TREE_DEPTH=20
|
||||
ALL_SNARK_ARTIFACTS=true
|
||||
REPORT_GAS=false
|
||||
BACKEND_PRIVATE_KEY=
|
||||
INFURA_API_KEY=
|
||||
|
||||
4
.github/workflows/production.yml
vendored
4
.github/workflows/production.yml
vendored
@@ -5,6 +5,10 @@ on:
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
TREE_DEPTH: 20
|
||||
ALL_SNARK_ARTIFACTS: false
|
||||
|
||||
jobs:
|
||||
style:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
4
.github/workflows/pull-requests.yml
vendored
4
.github/workflows/pull-requests.yml
vendored
@@ -3,6 +3,10 @@ name: pull-requests
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
TREE_DEPTH: 20
|
||||
ALL_SNARK_ARTIFACTS: false
|
||||
|
||||
jobs:
|
||||
style:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -70,6 +70,9 @@ docs/*
|
||||
# Hardhat
|
||||
artifacts
|
||||
cache
|
||||
packages/contracts/deployed-contracts/undefined.json
|
||||
packages/contracts/deployed-contracts/hardhat.json
|
||||
packages/contracts/deployed-contracts/localhost.json
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
@@ -10,6 +10,9 @@ coverage.json
|
||||
|
||||
# hardhat
|
||||
cache
|
||||
packages/contracts/deployed-contracts/undefined.json
|
||||
packages/contracts/deployed-contracts/hardhat.json
|
||||
packages/contracts/deployed-contracts/localhost.json
|
||||
|
||||
# types
|
||||
types
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"scripts": {
|
||||
"build:libraries": "yarn workspaces foreach run build",
|
||||
"compile:contracts": "yarn workspace contracts compile",
|
||||
"download:snark-artifacts": "ts-node scripts/download-snark-artifacts.ts",
|
||||
"download:snark-artifacts": "rimraf snark-artifacts && ts-node scripts/download-snark-artifacts.ts",
|
||||
"test": "yarn test:libraries && yarn test:contracts",
|
||||
"test:libraries": "jest --coverage",
|
||||
"test:contracts": "yarn workspace contracts test:coverage",
|
||||
@@ -53,7 +53,6 @@
|
||||
"@typescript-eslint/eslint-plugin": "^5.9.1",
|
||||
"@typescript-eslint/parser": "^5.9.1",
|
||||
"babel-jest": "^27.4.6",
|
||||
"circomlibjs": "^0.0.8",
|
||||
"commitizen": "^4.2.4",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"dotenv": "^16.0.2",
|
||||
|
||||
37
packages/circuits/README.md
Normal file
37
packages/circuits/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
<p align="center">
|
||||
<h1 align="center">
|
||||
Semaphore circuits
|
||||
</h1>
|
||||
<p align="center">Semaphore circuits to create and verify zero-knowledge proofs.</p>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/semaphore-protocol">
|
||||
<img src="https://img.shields.io/badge/project-Semaphore-blue.svg?style=flat-square">
|
||||
</a>
|
||||
<a href="https://github.com/semaphore-protocol/semaphore/blob/main/LICENSE">
|
||||
<img alt="Github license" src="https://img.shields.io/github/license/semaphore-protocol/semaphore.svg?style=flat-square">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
<h4>
|
||||
<a href="https://github.com/semaphore-protocol/semaphore/blob/main/CONTRIBUTING.md">
|
||||
👥 Contributing
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://github.com/semaphore-protocol/semaphore/blob/main/CODE_OF_CONDUCT.md">
|
||||
🤝 Code of conduct
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://github.com/semaphore-protocol/semaphore/contribute">
|
||||
🔎 Issues
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://discord.gg/6mSdGHnstH">
|
||||
🗣️ Chat & Support
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
To learn more about circuits visit [semaphore.appliedzkp.org](https://semaphore.appliedzkp.org/docs/technical-reference/circuits).
|
||||
@@ -1,22 +1,4 @@
|
||||
module.exports = {
|
||||
istanbulFolder: "../../coverage/contracts",
|
||||
skipFiles: [
|
||||
"verifiers/Verifier16.sol",
|
||||
"verifiers/Verifier17.sol",
|
||||
"verifiers/Verifier18.sol",
|
||||
"verifiers/Verifier19.sol",
|
||||
"verifiers/Verifier20.sol",
|
||||
"verifiers/Verifier21.sol",
|
||||
"verifiers/Verifier22.sol",
|
||||
"verifiers/Verifier23.sol",
|
||||
"verifiers/Verifier24.sol",
|
||||
"verifiers/Verifier25.sol",
|
||||
"verifiers/Verifier26.sol",
|
||||
"verifiers/Verifier27.sol",
|
||||
"verifiers/Verifier28.sol",
|
||||
"verifiers/Verifier29.sol",
|
||||
"verifiers/Verifier30.sol",
|
||||
"verifiers/Verifier31.sol",
|
||||
"verifiers/Verifier32.sol"
|
||||
]
|
||||
skipFiles: ["base/Pairing.sol"]
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"rules": {
|
||||
"code-complexity": ["error", 7],
|
||||
"compiler-version": ["error", ">=0.8.0"],
|
||||
"var-name-mixedcase": "off",
|
||||
"const-name-snakecase": "off",
|
||||
"no-empty-blocks": "off",
|
||||
"constructor-syntax": "error",
|
||||
|
||||
@@ -1 +1 @@
|
||||
contracts/verifiers
|
||||
contracts/base/Pairing.sol
|
||||
|
||||
21
packages/contracts/contracts/LICENSE
Normal file
21
packages/contracts/contracts/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Ethereum Foundation
|
||||
|
||||
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.
|
||||
@@ -2,14 +2,12 @@
|
||||
pragma solidity 0.8.4;
|
||||
|
||||
import "./interfaces/ISemaphore.sol";
|
||||
import "./interfaces/IVerifier.sol";
|
||||
import "./base/SemaphoreCore.sol";
|
||||
import "./interfaces/ISemaphoreVerifier.sol";
|
||||
import "./base/SemaphoreGroups.sol";
|
||||
|
||||
/// @title Semaphore
|
||||
contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
|
||||
/// @dev Gets a tree depth and returns its verifier address.
|
||||
mapping(uint256 => IVerifier) public verifiers;
|
||||
contract Semaphore is ISemaphore, SemaphoreGroups {
|
||||
ISemaphoreVerifier public verifier;
|
||||
|
||||
/// @dev Gets a group id and returns the group parameters.
|
||||
mapping(uint256 => Group) public groups;
|
||||
@@ -26,22 +24,16 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
|
||||
/// @dev Checks if there is a verifier for the given tree depth.
|
||||
/// @param merkleTreeDepth: Depth of the tree.
|
||||
modifier onlySupportedMerkleTreeDepth(uint256 merkleTreeDepth) {
|
||||
if (address(verifiers[merkleTreeDepth]) == address(0)) {
|
||||
if (merkleTreeDepth < 16 || merkleTreeDepth > 32) {
|
||||
revert Semaphore__MerkleTreeDepthIsNotSupported();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
/// @dev Initializes the Semaphore verifiers used to verify the user's ZK proofs.
|
||||
/// @param _verifiers: List of Semaphore verifiers (address and related Merkle tree depth).
|
||||
constructor(Verifier[] memory _verifiers) {
|
||||
for (uint8 i = 0; i < _verifiers.length; ) {
|
||||
verifiers[_verifiers[i].merkleTreeDepth] = IVerifier(_verifiers[i].contractAddress);
|
||||
|
||||
unchecked {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
/// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
|
||||
/// @param _verifier: Semaphore verifier address.
|
||||
constructor(ISemaphoreVerifier _verifier) {
|
||||
verifier = _verifier;
|
||||
}
|
||||
|
||||
/// @dev See {ISemaphore-createGroup}.
|
||||
@@ -119,6 +111,10 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
|
||||
uint8[] calldata proofPathIndices
|
||||
) external override onlyGroupAdmin(groupId) {
|
||||
_updateMember(groupId, identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
|
||||
|
||||
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
||||
|
||||
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
||||
}
|
||||
|
||||
/// @dev See {ISemaphore-removeMember}.
|
||||
@@ -129,13 +125,17 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
|
||||
uint8[] calldata proofPathIndices
|
||||
) external override onlyGroupAdmin(groupId) {
|
||||
_removeMember(groupId, identityCommitment, proofSiblings, proofPathIndices);
|
||||
|
||||
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
|
||||
|
||||
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
|
||||
}
|
||||
|
||||
/// @dev See {ISemaphore-verifyProof}.
|
||||
function verifyProof(
|
||||
uint256 groupId,
|
||||
uint256 merkleTreeRoot,
|
||||
bytes32 signal,
|
||||
uint256 signal,
|
||||
uint256 nullifierHash,
|
||||
uint256 externalNullifier,
|
||||
uint256[8] calldata proof
|
||||
@@ -165,9 +165,7 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
|
||||
|
||||
uint256 merkleTreeDepth = getMerkleTreeDepth(groupId);
|
||||
|
||||
IVerifier verifier = verifiers[merkleTreeDepth];
|
||||
|
||||
_verifyProof(signal, merkleTreeRoot, nullifierHash, externalNullifier, proof, verifier);
|
||||
verifier.verifyProof(merkleTreeRoot, nullifierHash, signal, externalNullifier, proof, merkleTreeDepth);
|
||||
|
||||
groups[groupId].nullifierHashes[nullifierHash] = true;
|
||||
|
||||
|
||||
151
packages/contracts/contracts/base/Pairing.sol
Normal file
151
packages/contracts/contracts/base/Pairing.sol
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// The following Pairing library is a modified version adapted to Semaphore.
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error Semaphore__InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() public pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() public pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) public pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) {
|
||||
return G1Point(0, 0);
|
||||
}
|
||||
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) {
|
||||
revert Semaphore__InvalidProof();
|
||||
}
|
||||
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) public view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
|
||||
bool success;
|
||||
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
revert Semaphore__InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) public view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) {
|
||||
revert Semaphore__InvalidProof();
|
||||
}
|
||||
|
||||
uint256[3] memory input;
|
||||
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
|
||||
bool success;
|
||||
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
revert Semaphore__InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) public view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) {
|
||||
revert Semaphore__InvalidProof();
|
||||
}
|
||||
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
|
||||
for (uint256 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];
|
||||
}
|
||||
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
|
||||
if (!success || out[0] != 1) {
|
||||
revert Semaphore__InvalidProof();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
//SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.4;
|
||||
|
||||
uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
@@ -1,45 +0,0 @@
|
||||
//SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.4;
|
||||
|
||||
import "../interfaces/ISemaphoreCore.sol";
|
||||
import "../interfaces/IVerifier.sol";
|
||||
|
||||
/// @title Semaphore core contract.
|
||||
/// @notice Minimal code to allow users to signal their endorsement of an arbitrary string.
|
||||
/// @dev The following code verifies that the proof is correct and saves the hash of the
|
||||
/// nullifier to prevent double-signaling. External nullifier and Merkle trees (i.e. groups) must be
|
||||
/// managed externally.
|
||||
contract SemaphoreCore is ISemaphoreCore {
|
||||
/// @dev Asserts that no nullifier already exists and if the zero-knowledge proof is valid.
|
||||
/// Otherwise it reverts.
|
||||
/// @param signal: Semaphore signal.
|
||||
/// @param root: Root of the Merkle tree.
|
||||
/// @param nullifierHash: Nullifier hash.
|
||||
/// @param externalNullifier: External nullifier.
|
||||
/// @param proof: Zero-knowledge proof.
|
||||
/// @param verifier: Verifier address.
|
||||
function _verifyProof(
|
||||
bytes32 signal,
|
||||
uint256 root,
|
||||
uint256 nullifierHash,
|
||||
uint256 externalNullifier,
|
||||
uint256[8] calldata proof,
|
||||
IVerifier verifier
|
||||
) internal view {
|
||||
uint256 signalHash = _hashSignal(signal);
|
||||
|
||||
verifier.verifyProof(
|
||||
[proof[0], proof[1]],
|
||||
[[proof[2], proof[3]], [proof[4], proof[5]]],
|
||||
[proof[6], proof[7]],
|
||||
[root, nullifierHash, signalHash, externalNullifier]
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Creates a keccak256 hash of the signal.
|
||||
/// @param signal: Semaphore signal.
|
||||
/// @return Hash of the signal.
|
||||
function _hashSignal(bytes32 signal) private pure returns (uint256) {
|
||||
return uint256(keccak256(abi.encodePacked(signal))) >> 8;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
//SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.4;
|
||||
|
||||
import {SNARK_SCALAR_FIELD} from "./SemaphoreConstants.sol";
|
||||
import "../interfaces/ISemaphoreGroups.sol";
|
||||
import "@zk-kit/incremental-merkle-tree.sol/IncrementalBinaryTree.sol";
|
||||
import "@openzeppelin/contracts/utils/Context.sol";
|
||||
@@ -24,10 +23,6 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
|
||||
uint256 merkleTreeDepth,
|
||||
uint256 zeroValue
|
||||
) internal virtual {
|
||||
if (groupId >= SNARK_SCALAR_FIELD) {
|
||||
revert Semaphore__GroupIdIsNotLessThanSnarkScalarField();
|
||||
}
|
||||
|
||||
if (getMerkleTreeDepth(groupId) != 0) {
|
||||
revert Semaphore__GroupAlreadyExists();
|
||||
}
|
||||
|
||||
113
packages/contracts/contracts/base/SemaphoreVerifier.sol
Normal file
113
packages/contracts/contracts/base/SemaphoreVerifier.sol
Normal file
File diff suppressed because one or more lines are too long
@@ -2,14 +2,13 @@
|
||||
pragma solidity 0.8.4;
|
||||
|
||||
import "../interfaces/ISemaphoreVoting.sol";
|
||||
import "../base/SemaphoreCore.sol";
|
||||
import "../interfaces/ISemaphoreVerifier.sol";
|
||||
import "../base/SemaphoreGroups.sol";
|
||||
|
||||
/// @title Semaphore voting contract.
|
||||
/// @dev The following code allows you to create polls, add voters and allow them to vote anonymously.
|
||||
contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
|
||||
/// @dev Gets a tree depth and returns its verifier address.
|
||||
mapping(uint256 => IVerifier) internal verifiers;
|
||||
contract SemaphoreVoting is ISemaphoreVoting, SemaphoreGroups {
|
||||
ISemaphoreVerifier public verifier;
|
||||
|
||||
/// @dev Gets a poll id and returns the poll data.
|
||||
mapping(uint256 => Poll) internal polls;
|
||||
@@ -18,18 +17,6 @@ contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
|
||||
/// It is used to prevent double-voting.
|
||||
mapping(uint256 => bool) internal nullifierHashes;
|
||||
|
||||
/// @dev Initializes the Semaphore verifiers used to verify the user's ZK proofs.
|
||||
/// @param _verifiers: List of Semaphore verifiers (address and related Merkle tree depth).
|
||||
constructor(Verifier[] memory _verifiers) {
|
||||
for (uint8 i = 0; i < _verifiers.length; ) {
|
||||
verifiers[_verifiers[i].merkleTreeDepth] = IVerifier(_verifiers[i].contractAddress);
|
||||
|
||||
unchecked {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Checks if the poll coordinator is the transaction sender.
|
||||
/// @param pollId: Id of the poll.
|
||||
modifier onlyCoordinator(uint256 pollId) {
|
||||
@@ -40,13 +27,19 @@ contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
|
||||
_;
|
||||
}
|
||||
|
||||
/// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
|
||||
/// @param _verifier: Semaphore verifier address.
|
||||
constructor(ISemaphoreVerifier _verifier) {
|
||||
verifier = _verifier;
|
||||
}
|
||||
|
||||
/// @dev See {ISemaphoreVoting-createPoll}.
|
||||
function createPoll(
|
||||
uint256 pollId,
|
||||
address coordinator,
|
||||
uint256 merkleTreeDepth
|
||||
) public override {
|
||||
if (address(verifiers[merkleTreeDepth]) == address(0)) {
|
||||
if (merkleTreeDepth < 16 || merkleTreeDepth > 32) {
|
||||
revert Semaphore__MerkleTreeDepthIsNotSupported();
|
||||
}
|
||||
|
||||
@@ -83,11 +76,11 @@ contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
|
||||
|
||||
/// @dev See {ISemaphoreVoting-castVote}.
|
||||
function castVote(
|
||||
bytes32 vote,
|
||||
uint256 vote,
|
||||
uint256 nullifierHash,
|
||||
uint256 pollId,
|
||||
uint256[8] calldata proof
|
||||
) public override onlyCoordinator(pollId) {
|
||||
) public override {
|
||||
Poll memory poll = polls[pollId];
|
||||
|
||||
if (poll.state != PollState.Ongoing) {
|
||||
@@ -101,9 +94,7 @@ contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
|
||||
uint256 merkleTreeDepth = getMerkleTreeDepth(pollId);
|
||||
uint256 merkleTreeRoot = getMerkleTreeRoot(pollId);
|
||||
|
||||
IVerifier verifier = verifiers[merkleTreeDepth];
|
||||
|
||||
_verifyProof(vote, merkleTreeRoot, nullifierHash, pollId, proof, verifier);
|
||||
verifier.verifyProof(merkleTreeRoot, nullifierHash, vote, pollId, proof, merkleTreeDepth);
|
||||
|
||||
nullifierHashes[nullifierHash] = true;
|
||||
|
||||
|
||||
@@ -2,32 +2,19 @@
|
||||
pragma solidity 0.8.4;
|
||||
|
||||
import "../interfaces/ISemaphoreWhistleblowing.sol";
|
||||
import "../base/SemaphoreCore.sol";
|
||||
import "../interfaces/ISemaphoreVerifier.sol";
|
||||
import "../base/SemaphoreGroups.sol";
|
||||
|
||||
/// @title Semaphore whistleblowing contract.
|
||||
/// @dev The following code allows you to create entities for whistleblowers (e.g. non-profit
|
||||
/// organization, newspaper) and to allow them to publish news leaks anonymously.
|
||||
/// Leaks can be IPFS hashes, permanent links or other kinds of reference.
|
||||
contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing, SemaphoreCore, SemaphoreGroups {
|
||||
/// @dev Gets a tree depth and returns its verifier address.
|
||||
mapping(uint256 => IVerifier) internal verifiers;
|
||||
contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing, SemaphoreGroups {
|
||||
ISemaphoreVerifier public verifier;
|
||||
|
||||
/// @dev Gets an editor address and return their entity.
|
||||
mapping(address => uint256) private entities;
|
||||
|
||||
/// @dev Initializes the Semaphore verifiers used to verify the user's ZK proofs.
|
||||
/// @param _verifiers: List of Semaphore verifiers (address and related Merkle tree depth).
|
||||
constructor(Verifier[] memory _verifiers) {
|
||||
for (uint8 i = 0; i < _verifiers.length; ) {
|
||||
verifiers[_verifiers[i].merkleTreeDepth] = IVerifier(_verifiers[i].contractAddress);
|
||||
|
||||
unchecked {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Checks if the editor is the transaction sender.
|
||||
/// @param entityId: Id of the entity.
|
||||
modifier onlyEditor(uint256 entityId) {
|
||||
@@ -38,13 +25,19 @@ contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing, SemaphoreCore, Sem
|
||||
_;
|
||||
}
|
||||
|
||||
/// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
|
||||
/// @param _verifier: Semaphore verifier address.
|
||||
constructor(ISemaphoreVerifier _verifier) {
|
||||
verifier = _verifier;
|
||||
}
|
||||
|
||||
/// @dev See {ISemaphoreWhistleblowing-createEntity}.
|
||||
function createEntity(
|
||||
uint256 entityId,
|
||||
address editor,
|
||||
uint256 merkleTreeDepth
|
||||
) public override {
|
||||
if (address(verifiers[merkleTreeDepth]) == address(0)) {
|
||||
if (merkleTreeDepth < 16 || merkleTreeDepth > 32) {
|
||||
revert Semaphore__MerkleTreeDepthIsNotSupported();
|
||||
}
|
||||
|
||||
@@ -72,17 +65,15 @@ contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing, SemaphoreCore, Sem
|
||||
|
||||
/// @dev See {ISemaphoreWhistleblowing-publishLeak}.
|
||||
function publishLeak(
|
||||
bytes32 leak,
|
||||
uint256 leak,
|
||||
uint256 nullifierHash,
|
||||
uint256 entityId,
|
||||
uint256[8] calldata proof
|
||||
) public override onlyEditor(entityId) {
|
||||
) public override {
|
||||
uint256 merkleTreeDepth = getMerkleTreeDepth(entityId);
|
||||
uint256 merkleTreeRoot = getMerkleTreeRoot(entityId);
|
||||
|
||||
IVerifier verifier = verifiers[merkleTreeDepth];
|
||||
|
||||
_verifyProof(leak, merkleTreeRoot, nullifierHash, entityId, proof, verifier);
|
||||
verifier.verifyProof(merkleTreeRoot, nullifierHash, leak, entityId, proof, merkleTreeDepth);
|
||||
|
||||
emit LeakPublished(entityId, leak);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ interface ISemaphore {
|
||||
uint256 merkleTreeRoot,
|
||||
uint256 externalNullifier,
|
||||
uint256 nullifierHash,
|
||||
bytes32 signal
|
||||
uint256 signal
|
||||
);
|
||||
|
||||
/// @dev Saves the nullifier hash to avoid double signaling and emits an event
|
||||
@@ -54,7 +54,7 @@ interface ISemaphore {
|
||||
function verifyProof(
|
||||
uint256 groupId,
|
||||
uint256 merkleTreeRoot,
|
||||
bytes32 signal,
|
||||
uint256 signal,
|
||||
uint256 nullifierHash,
|
||||
uint256 externalNullifier,
|
||||
uint256[8] calldata proof
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
//SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.4;
|
||||
|
||||
/// @title SemaphoreCore interface.
|
||||
/// @dev Interface of SemaphoreCore contract.
|
||||
interface ISemaphoreCore {
|
||||
/// @notice Emitted when a proof is verified correctly and a new nullifier hash is added.
|
||||
/// @param nullifierHash: Hash of external and identity nullifiers.
|
||||
event NullifierHashAdded(uint256 nullifierHash);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
//SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.4;
|
||||
|
||||
/// @title SemaphoreNullifiers interface.
|
||||
/// @dev Interface of SemaphoreNullifiers contract.
|
||||
interface ISemaphoreNullifiers {
|
||||
/// @dev Emitted when a external nullifier is added.
|
||||
/// @param externalNullifier: External Semaphore nullifier.
|
||||
event ExternalNullifierAdded(uint256 externalNullifier);
|
||||
|
||||
/// @dev Emitted when a external nullifier is removed.
|
||||
/// @param externalNullifier: External Semaphore nullifier.
|
||||
event ExternalNullifierRemoved(uint256 externalNullifier);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.4;
|
||||
|
||||
import "../base/Pairing.sol";
|
||||
|
||||
/// @title SemaphoreVerifier interface.
|
||||
/// @dev Interface of SemaphoreVerifier contract.
|
||||
interface ISemaphoreVerifier {
|
||||
struct VerificationKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
/// @dev Verifies that the zero-knowledge proof is valid.
|
||||
/// @param merkleTreeRoot: Root of the Merkle tree.
|
||||
/// @param nullifierHash: Nullifier hash.
|
||||
/// @param signal: Semaphore signal.
|
||||
/// @param externalNullifier: External nullifier.
|
||||
/// @param proof: Zero-knowledge proof.
|
||||
/// @param merkleTreeDepth: Depth of the tree.
|
||||
function verifyProof(
|
||||
uint256 merkleTreeRoot,
|
||||
uint256 nullifierHash,
|
||||
uint256 signal,
|
||||
uint256 externalNullifier,
|
||||
uint256[8] calldata proof,
|
||||
uint256 merkleTreeDepth
|
||||
) external view;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ interface ISemaphoreVoting {
|
||||
/// @dev Emitted when a user votes on a poll.
|
||||
/// @param pollId: Id of the poll.
|
||||
/// @param vote: User encrypted vote.
|
||||
event VoteAdded(uint256 indexed pollId, bytes32 vote);
|
||||
event VoteAdded(uint256 indexed pollId, uint256 vote);
|
||||
|
||||
/// @dev Emitted when a poll is ended.
|
||||
/// @param pollId: Id of the poll.
|
||||
@@ -74,7 +74,7 @@ interface ISemaphoreVoting {
|
||||
/// @param pollId: Id of the poll.
|
||||
/// @param proof: Private zk-proof parameters.
|
||||
function castVote(
|
||||
bytes32 vote,
|
||||
uint256 vote,
|
||||
uint256 nullifierHash,
|
||||
uint256 pollId,
|
||||
uint256[8] calldata proof
|
||||
|
||||
@@ -20,7 +20,7 @@ interface ISemaphoreWhistleblowing {
|
||||
/// @dev Emitted when a whistleblower publish a new leak.
|
||||
/// @param entityId: Id of the entity.
|
||||
/// @param leak: News leak.
|
||||
event LeakPublished(uint256 indexed entityId, bytes32 leak);
|
||||
event LeakPublished(uint256 indexed entityId, uint256 leak);
|
||||
|
||||
/// @dev Creates an entity and the associated Merkle tree/group.
|
||||
/// @param entityId: Id of the entity.
|
||||
@@ -55,7 +55,7 @@ interface ISemaphoreWhistleblowing {
|
||||
/// @param entityId: Id of the entity.
|
||||
/// @param proof: Private zk-proof parameters.
|
||||
function publishLeak(
|
||||
bytes32 leak,
|
||||
uint256 leak,
|
||||
uint256 nullifierHash,
|
||||
uint256 entityId,
|
||||
uint256[8] calldata proof
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
//SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.4;
|
||||
|
||||
/// @title Verifier interface.
|
||||
/// @dev Interface of Verifier contract.
|
||||
interface IVerifier {
|
||||
function verifyProof(
|
||||
uint256[2] memory a,
|
||||
uint256[2][2] memory b,
|
||||
uint256[2] memory c,
|
||||
uint256[4] memory input
|
||||
) external view;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@semaphore-protocol/contracts",
|
||||
"version": "2.6.0",
|
||||
"version": "2.6.1",
|
||||
"description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier16 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[13406811599156507528361773763681356312643537981039994686313383243831956396116, 16243966861079634958125511652590761846958471358623040426599000904006426210032],
|
||||
[11781596534582143578120404722739278517564025497573071755253972265891888117374, 15688083679237922164673518758181461582601853873216319711156397437601833996222]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
1964404930528116823793003656764176108669615750422202377358993070935069307720,
|
||||
2137714996673694828207437580381836490878070731768805974506391024595988817424
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
19568893707760843340848992184233194433177372925415116053368211122719346671126,
|
||||
11639469568629189918046964192305250472192697612201524135560178632824282818614
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
5317268879687484957437879782519918549127939892210247573193613900261494313825,
|
||||
528174394975085006443543773707702838726735933116136102590448357278717993744
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
14865918005176722116473730206622066845866539143554731094374354951675249722731,
|
||||
3197770568483953664363740385883457803041685902965668289308665954510373380344
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
6863358721495494421022713667808247652425178970453300712435830652679038918987,
|
||||
15025816433373311798308762709072064417001390853103872064614174594927359131281
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier17 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[15629200772768268814959330350023920183087521275477047626405113853190187031523, 13589689305661231568162336263197960570915890299814486885851912452076929115480],
|
||||
[11464919285924930973853174493551975632739604254498590354200272115844983493029, 16004221700357242255845535848024178544616388017965468694776181247983831995562]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
17789438292552571310739605737896030466581277887660997531707911256058650850910,
|
||||
4112657509505371631825493224748310061184972897405589115208158208294581472016
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
3322052920119834475842380240689494113984887785733316517680891208549118967155,
|
||||
381029395779795399840019487059126246243641886087320875571067736504031557148
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
8777645223617381095463415690983421308854368583891690388850387317049320450400,
|
||||
11923582117369144413749726090967341613266070909169947059497952692052020331958
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
15493263571528401950994933073246603557158047091963487223668240334879173885581,
|
||||
6315532173951617115856055775098532808695228294437279844344466163873167020700
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
3481637421055377106140197938175958155334313900824697193932986771017625492245,
|
||||
20088416136090515091300914661950097694450984520235647990572441134215240947932
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier18 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[9218320951536642499143228327011901814587826948504871816273184688188019956292, 19717684456458906358368865507225121991585492363133107109865920739019288468011],
|
||||
[16717590750910963405756115910371408378114896008824240863060392362901176601412, 18221695645112467945186983098720611586049108689347006136423489099202471884089]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
4691595252082380256698158158199364410440273386659834000993210659508747323919,
|
||||
9205801980459323513061837717352821162780471027241700646145937351740096374660
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
16150531426263112884093068164597994126623437929929609532055221646496813246000,
|
||||
20245743178241899668170758952526381872637304119026868520579207157118516761827
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
6063536446992770713985314309889717594240410784717230886576072989709763902848,
|
||||
18258781411255795973918859665416013869184055573057512603788635470145328981347
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
10109932964756104512054045207253535333686585863745296080906925765480296575285,
|
||||
4174640428253153601540284363759502713687021920150940723252842152556151210349
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
18049428534741480832385046397049175120355008065781483226058177421025493210952,
|
||||
591730261265040164434889324846001338201068482543108348317417391345612814922
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier19 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[3995128789564535587814512245259203300137618476815456454931286633947953135662, 15953239752392927777442331623182226063776310198012173504208557434319753428770],
|
||||
[20957319343912866335583737646657534123362052690050674068142580221965936605075, 2523786679709693946058523307330825034772478122295850507521258983130425334580]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
9877211178693075145402462781884120278654771727348087433632224794894486095150,
|
||||
19972682062587174829535281061580296764150591339640180868104711395548066529340
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
6324578424031095537345184040149690238371517387586958921377481904541316423724,
|
||||
15513931720576048544404512239839508014664224085062729779520992909505663748296
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
11371337652479737143800707796204655130812036287859296372695832558127430723628,
|
||||
11757275188600040111649009832378343123994225623498773406233261322165903848967
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
13282496583564708104981015168203451877588903263486398132954741568835583461335,
|
||||
1746144324840370907926720490289700342734912534857331743685374514401176014195
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
7993952462467372951144011615584426050192046712674662254138390197508963352374,
|
||||
5156942148925224345709309361345680948125600198010285179548841917923439945819
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier20 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[18976133691706015337908381757202123182841901611067930614519324084182946094218, 1382518990777992893805140303684642328066746531257780279226677247567004248173],
|
||||
[6627710380771660558660627878547223719795356903257079198333641681330388499309, 21806956747910197517744499423107239699428979652113081469385876768212706694581]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
19918517214839406678907482305035208173510172567546071380302965459737278553528,
|
||||
7151186077716310064777520690144511885696297127165278362082219441732663131220
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
690581125971423619528508316402701520070153774868732534279095503611995849608,
|
||||
21271996888576045810415843612869789314680408477068973024786458305950370465558
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
16461282535702132833442937829027913110152135149151199860671943445720775371319,
|
||||
2814052162479976678403678512565563275428791320557060777323643795017729081887
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
4319780315499060392574138782191013129592543766464046592208884866569377437627,
|
||||
13920930439395002698339449999482247728129484070642079851312682993555105218086
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
3554830803181375418665292545416227334138838284686406179598687755626325482686,
|
||||
5951609174746846070367113593675211691311013364421437923470787371738135276998
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier21 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[3811592683283527904145155808200366192489850711742363953668998371801696238057, 9032545080831535702239063467087720597970266046938395860207839433937324718536],
|
||||
[16308433125974933290258540904373317426123214107276055539769464205982500660715, 12429982191499850873612518410809641163252887523090441166572590809691267943605]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
9494885690931955877467315318223108618392113101843890678090902614660136056680,
|
||||
11783514256715757384821021009301806722951917744219075907912683963173706887379
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
7562082660623781416745328104576133910743071878837764423695105915778139873834,
|
||||
17954307004260053757579194018551114133664721761483240877658498973152950708099
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
19338184851116432029108109461622579541195083625346674255186169347975445785058,
|
||||
38361206266360048012365562393026952048730052530888439195454086987795985927
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
21178537742782571863590222710872928190886000600239072595684369348717288330049,
|
||||
9786438258541172244884631831247223050494423968411444302812755467521949734320
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
11330504221972341797183339350494223413034293674225690456356444509688810101433,
|
||||
1490009915387901405464437253469086864085891770312035292355706249426866485365
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier22 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[9485639152672984144988597737758037391807993615552051606205480347442429414340, 17626503110323089701269363177710295379967225765713250625279671011873619640598],
|
||||
[12391874700409435648975069978280047983726144854114915177376036190441913967689, 18953587685067712486092665232725058638563458484886448540567142557894080640927]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
21791720972262589799021600767292883644106575897307484548888696814333235336885,
|
||||
11092962469758788187888592619035811117815082357439060720677582048880121542623
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
9418924955930663972575130074928583215922927562059194231976193350658171304436,
|
||||
16113558481826020406162261319744796072664750077095575593106901121115073101408
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
20054934960262983176880675919444457578562219675808407582143519621873973120773,
|
||||
14877415271301547911435683263206245199959943680225555496786470669330176961657
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
4215199263810110748751715719957184804379752373072771007598572158043965517488,
|
||||
5225943468606602818132879686778547605180105897615251160509064537462109826521
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
6250242626034734280813142093008675407723196706248829741247204621913994561803,
|
||||
1472231555266678689888727724824566171966416459791722465278225775922487343641
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier23 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[9830856103389248449121962275587399130605902703453384856543071762984116567573, 11408965575174993375815840422438995549652812400401163392501956884932167624437],
|
||||
[11814906841949499037550820576929552248172160643991870665022770052632331265834, 19969543376625663966419118899515353499678204573709836615846115182224340858492]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
3047486363455933831148688762823238723024952519326207356549121929667745957778,
|
||||
20241836359289449005887237560564358543646542598344362915541027571505243817211
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
5965631918800530319167124148627450454569264331058008407732200168631989208657,
|
||||
20463557477532480934514091877628554948892025887087712764683631108388998871350
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
16605042322692983282732511249912403956057999815658038166796858627082222971215,
|
||||
12219061498275616585164456833410962809536084885494309093787669879221959361956
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
1548998572074037722622224303222294716243074837074272552644853986075252666508,
|
||||
10393312002885367652301897874262367916506364670364584602554176742602334134772
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
16180907689593358346406392015123900260925622357393826746385511046141256905390,
|
||||
12267326749885120640972074479210537480053065569337817484467225562817467244765
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier24 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[15035335306919942325459417688135340085377315274625768597233474641923619728582, 10090041889587324002759549286390619541526396451963494627957072069124011137562],
|
||||
[21342049717074059749518233491526445388158772701642182532370641230478027030319, 10507786999799841055999967456762679569286329319056926475375760604262707147294]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
19590996174696909242575628014943555633938195923520472786993379268302478708283,
|
||||
2673753072556442230312995111304911178679525806396134504594492458566941824354
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
13411253172375451489380472831999887223592471057462692619008484995624281735092,
|
||||
17181767455563581254432161119660408482332423481128600038352147258951772423229
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
19138864631164378176055647711995352935065134904103255748190268290992108588628,
|
||||
14282526277736365863821375748687709839392307698935143595732632710176778519757
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
20183773658676161990469276414858234178608794783112866811307579993999118293429,
|
||||
5223464433544489066271184294750886227362580875255044558831927430970236355539
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
12333466991139269670298178539679773509487545471126920233507132846828588847444,
|
||||
3787586478923104354547687861486563468235879611952775292288436085429794222238
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier25 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[15718373132479769904443326381037437528372212185108294117696143473979328398658, 43456740675249348549891878341522275183186932745162972528932808393415299552],
|
||||
[11236864934894600819960883124570686936554376109344998527334431594565774237827, 4289247401578837038775845192875793775418122783738936298355403103074020081838]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
18580370382199518848261939652153768394883698461842792002922164533882262019935,
|
||||
20516185953882700254387267244708111605796661864845495645678049276372075842359
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
20041291712709610738573661974551517833120775539593003477018637287434210072702,
|
||||
6326630253906616820412999166182553773360987412889775567442543181359104720511
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
13268971611130152315428629919012388924225656285593904211561391821918930327614,
|
||||
9247437189452353488017802041158840512956111558640958728149597697508914590433
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
6267384495557139339708615182113725421733376438932580472141549274050146739549,
|
||||
1832264154031452148715318442722960696977572389206897240030908464579133134237
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
16650684165487873559901140599157559153018449083939294496255590830891994564285,
|
||||
14140282729498011406186082176268025578697081678243955538935501306868500498994
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier26 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[1723458149089715907994189658689343304709709060535625667210252753337752162173, 4023016874169005249382064394379671330447496454371261692205411970999350949293],
|
||||
[7651670126664625790835334090273463062538865895183205964669372719235003083565, 17710652158212212080502343565075513548898593397103675832636832371532093744857]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
4247947150009812467217672970806328247513830308400387953244764907353849211641,
|
||||
14500381439127180474801393438175928191199696177607750163263715436006533630877
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
21213779524495874664157797605662894019112036728653622806607467354233012380232,
|
||||
1429370857470083395421401524518861545167550347090873730934256398864585069083
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
12465277751642747637430517396067173985821959773399832969105187923427872239200,
|
||||
4377704428607835904642653580543541241155601291484645500691968624389522190030
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
11283027832501128633761619552392013253304972822086786857121687098087331014745,
|
||||
21463394238922953607096052056881931791797740737164052798044623278557203313720
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
19687293493101130967741578773742597470558958652351513582962108464055656171331,
|
||||
4445165696525061401582979300506082669540223774145877762689724631935313716632
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier27 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[745924679191739894055143748466112994378439645681039136007774787076115375124, 13132169670125192016391258838554965176628317453468870968867717287446623320643],
|
||||
[2126777833939378028304266129616145667925849332481755567268747182629795296580, 20909608709868730010029182074820840312550443752829480953667886902663547957991]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
3388767735894417381503201756905214431625081913405504580464345986403824999889,
|
||||
21014112837214011009096825602791072748195337199912773858499588477762724153070
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
10521317016331497094903116740581271122844131442882845700567581775404872949272,
|
||||
13201921794561774338466680421903602920184688290946713194187958007088351657367
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
16170260722059932609965743383032703380650557609693540121262881902248073364496,
|
||||
6004983491336500911294872035126141746032033211872472427212274143945425740617
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
10275615677574391293596971122111363003313434841806630200532546038183081960924,
|
||||
5955568702561336410725734958627459212680756023420452791680213386065159525989
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
19059081014385850734732058652137664919364805650872154944590269874395511868415,
|
||||
19202365837673729366500417038229950532560250566916189579621883380623278182155
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier28 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[4553625243522856553165922942982108474187282402890756796515747778282922584601, 16835654219229187428071649241190746119082269636345872682107941472241044260584],
|
||||
[3272293478534046729728233267765357195255129499603632413158978822084188871854, 873742823867191038535544062852920538566418819521732785500614249239215175476]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
7856986171681248404396064225772749784181602218562773063185003409958949630985,
|
||||
11707218736744382138692483591389641607570557654489363179025201039696228471230
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
2902255937308264958973169948617099471543255757887963647238093192858290079050,
|
||||
4092153880227661899721872164083575597602963673456107552146583620177664115673
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
18380478859138320895837407377103009470968863533040661874531861881638854174636,
|
||||
14502773952184441371657781525836310753176308880224816843041318743809785835984
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
2781117248053224106149213822307598926495461873135153638774638501111353469325,
|
||||
3500056595279027698683405880585654897391289317486204483344715855049598477604
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
8880120765926282932795149634761705738498809569874317407549203808931092257005,
|
||||
19080036326648068547894941015038877788526324720587349784852594495705578761000
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier29 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[7252337675475138150830402909353772156046809729627064992143762325769537840623, 7601443214415704135008588588192028557655441716696726549510699770097979655628],
|
||||
[436607343827794507835462908831699962173244647704538949914686722631806931932, 18500126298578278987997086114400065402270866280547473913420536595663876273004]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
18427701611614193839908361166447988195308352665132182219164437649866377475111,
|
||||
5299493942596042045861137432338955179078182570752746487573709678936617478454
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
4188155714164125069834512529839479682516489319499446390214266838952761728656,
|
||||
2720966082507704094346897998659841489771837229143573083003847010258396944787
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
13256461570028177373135283778770729308216900804505379897951455548375840027026,
|
||||
10722074030307391322177899534114921764931623271723882054692012663305322382747
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
9824147497244652955949696442395586567974424828238608972020527958186701134273,
|
||||
15755269950882650791869946186461432242513999576056199368058858215068920022191
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
21172488506061181949536573476893375313339715931330476837156243346077173297265,
|
||||
13892434487977776248366965108031841947713544939953824768291380177301871559945
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier30 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[10202326166286888893675634318107715186834588694714750762952081034135561546271, 15028154694713144242204861571552635520290993855826554325002991692907421516918],
|
||||
[18486039841380105976272577521609866666900576498507352937328726490052296469859, 12766289885372833812620582632847872978085960777075662988932200910695848591357]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
1452272927738590248356371174422184656932731110936062990115610832462181634644,
|
||||
3608050114233210789542189629343107890943266759827387991788718454179833288695
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
14798240452388909327945424685903532333765637883272751382037716636327236955001,
|
||||
10773894897711848209682368488916121016695006898681985691467605219098835500201
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
17204267933132009093604099819536245144503489322639121825381131096467570698650,
|
||||
7704298975420304156332734115679983371345754866278811368869074990486717531131
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
8060465662017324080560848316478407038163145149983639907596180500095598669247,
|
||||
20475082166427284188002500222093571716651248980245637602667562336751029856573
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
7457566682692308112726332096733260585025339741083447785327706250123165087868,
|
||||
11904519443874922292602150685069370036383697877657723976244907400392778002614
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier31 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[14930624777162656776068112402283260602512252179767747308433194885322661150422, 13682963731073238132274278610660469286329368216526659590944079211949686450402],
|
||||
[18705481657148807016785305378773304476425591636333098330324049960258682574070, 21315724107376627085778492378001676935454590984229146391746301404292016287653]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
12628427235010608529869146871556870477182704310235373946877240509680742038961,
|
||||
15093298104438768585559335868663959710321348106117735180051519837845319121254
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
6593907467779318957599440584793099005109789224774644007604434924706249001015,
|
||||
18549596630007199540674697114946251030815675677713256327810772799104711621483
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
6271101737045248834759003849256661059806617144229427987717476992610974162336,
|
||||
355748132218964841305454070022507122319085542484477110563322753565651576458
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
2116139772133141967317791473319540620104888687412078412336248003979594158546,
|
||||
4004400204967325849492155713520296687406035356901102254880522534085890616486
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
4206647028595764233995379982714022410660284578620723510907006350595207905228,
|
||||
19380634286337609988098517090003334645113675227742745065381519159322795845003
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
//
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// 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.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
// 2021 Remco Bloemen
|
||||
// cleaned up code
|
||||
// added InvalidProve() error
|
||||
// always revert with InvalidProof() on invalid proof
|
||||
// make Pairing strict
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
library Pairing {
|
||||
error InvalidProof();
|
||||
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// The prime moludus of the scalar field of G1.
|
||||
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
|
||||
/// @return the generator of G1
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
|
||||
/// @return the generator of G2
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
return
|
||||
G2Point(
|
||||
[
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634,
|
||||
10857046999023057135944570762232829481370756359578518086990519993285655852781
|
||||
],
|
||||
[
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531,
|
||||
8495653923123431417604973247489272438418190587263600148770280649306958101930
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
|
||||
// Validate input or revert
|
||||
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
|
||||
// We know p.Y > 0 and p.Y < BASE_MODULUS.
|
||||
return G1Point(p.X, BASE_MODULUS - p.Y);
|
||||
}
|
||||
|
||||
/// @return r the sum of two points of G1
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
|
||||
// on the curve.
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// @return r 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, uint256 s) internal view returns (G1Point memory r) {
|
||||
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
|
||||
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
|
||||
if (s >= SCALAR_MODULUS) revert InvalidProof();
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
}
|
||||
if (!success) revert InvalidProof();
|
||||
}
|
||||
|
||||
/// Asserts the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
|
||||
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
|
||||
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
|
||||
// respective groups of the right order.
|
||||
if (p1.length != p2.length) revert InvalidProof();
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 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];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
}
|
||||
if (!success || out[0] != 1) revert InvalidProof();
|
||||
}
|
||||
}
|
||||
|
||||
contract Verifier32 {
|
||||
using Pairing for *;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20491192805390485299153009773594534940189261866228447918068658471970481763042,
|
||||
9383485363053290200918347156157836566562967994039712273449902621266178545958
|
||||
);
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
|
||||
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
|
||||
);
|
||||
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
|
||||
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
|
||||
);
|
||||
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[12315240965742683516581565369496371929586281338862761742109651525191835544242, 18994803742708336446369128568423705404354655742604689352630273180469431952708],
|
||||
[18019403342409608922812569436317484250134945386869657285229378095251425778096, 12707009780301102830224094192984906206920666691015255692741008594808694787917]
|
||||
);
|
||||
|
||||
vk.IC = new Pairing.G1Point[](5);
|
||||
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
2592407181901686208061988776764501828311271519595797153264758207470081204331,
|
||||
11847594161160074962679125411562687287595382335410213641115001866587988494499
|
||||
);
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
3346927026869562921166545684451290646273836362895645367665514203662899621366,
|
||||
15758185693543979820528128025093553492246135914029575732836221618882836493143
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
20528686657810499188368147206002308531447185877994439397529705707372170337045,
|
||||
18025396678079701612906003769476076600196287001844168390936182972248852818155
|
||||
);
|
||||
|
||||
vk.IC[3] = Pairing.G1Point(
|
||||
9799815250059685769827017947834627563597884023490186073806184882963949644596,
|
||||
4998495094322372762314630336611134866447406022687118703953312157819349892603
|
||||
);
|
||||
|
||||
vk.IC[4] = Pairing.G1Point(
|
||||
16176535527670849161173306151058200762642157343823553073439957507563856439772,
|
||||
21877331533292960470552563236986670222564955589137303622102707801351340670855
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
|
||||
function verifyProof(
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input
|
||||
) public view {
|
||||
// If the values are not in the correct range, the Pairing contract will revert.
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
|
||||
// Compute the linear combination vk_x of inputs times IC
|
||||
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
|
||||
Pairing.G1Point memory vk_x = vk.IC[0];
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
|
||||
|
||||
// Check pairing
|
||||
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
|
||||
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
|
||||
p1[0] = Pairing.negate(proof.A);
|
||||
p2[0] = proof.B;
|
||||
p1[1] = vk.alfa1;
|
||||
p2[1] = vk.beta2;
|
||||
p1[2] = vk_x;
|
||||
p2[2] = vk.gamma2;
|
||||
p1[3] = proof.C;
|
||||
p2[3] = vk.delta2;
|
||||
Pairing.pairingCheck(p1, p2);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
"Verifier31": "0xe4539a592df18936202480FBe77E47DE012F2178",
|
||||
"Verifier32": "0x98c90845A7870e215cBd7265DDC653E6c07032F4"
|
||||
},
|
||||
"Semaphore": "0x49281E30F17A30808a6ce538f979d539747e6707",
|
||||
"Semaphore": "0x86337c87A56117f8264bbaBA70e5a522C6E8A604",
|
||||
"PoseidonT3": "0xe0c8d1e53D9Bfc9071F6564755FCFf6cC0dB61d0",
|
||||
"IncrementalBinaryTree": "0x9fCea5E9aF68D5B0c55A1003b49284d70BffC1A9"
|
||||
"IncrementalBinaryTree": "0x91cD2B8573629d00BeC72EA1188d446897BD3948"
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"Verifier31": "0x133b69Ce47BF20C49368354914DF47519Ca6cCFE",
|
||||
"Verifier32": "0xe2978F79cb4AF62e5C990EE5c7E12fb22ee22e2D"
|
||||
},
|
||||
"Semaphore": "0xE585f0Db9aB24dC912404DFfb9b28fb8BF211fA6",
|
||||
"PoseidonT3": "0x8Bf7E5236957D1224b6e4F41E04730439cb802F7",
|
||||
"IncrementalBinaryTree": "0xD6729903227dFf493Bf23Bf889dC73b853655abe"
|
||||
"Semaphore": "0x5259d32659F1806ccAfcE593ED5a89eBAb85262f",
|
||||
"PoseidonT3": "0xe0A452533853310C371b50Bd91BB9DCC8961350F",
|
||||
"IncrementalBinaryTree": "0x61AE89E372492e53D941DECaaC9821649fa9B236"
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import "./tasks/accounts"
|
||||
import "./tasks/deploy-semaphore"
|
||||
import "./tasks/deploy-semaphore-voting"
|
||||
import "./tasks/deploy-semaphore-whistleblowing"
|
||||
import "./tasks/deploy-verifier"
|
||||
|
||||
dotenvConfig({ path: resolve(__dirname, "../../.env") })
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
"scripts": {
|
||||
"start": "hardhat node",
|
||||
"compile": "hardhat compile",
|
||||
"deploy:verifier": "hardhat deploy:verifier",
|
||||
"deploy:verifiers": "hardhat run scripts/deploy-verifiers.ts",
|
||||
"deploy:semaphore": "hardhat deploy:semaphore",
|
||||
"deploy:semaphore-voting": "hardhat deploy:semaphore-voting",
|
||||
"deploy:semaphore-whistleblowing": "hardhat deploy:semaphore-whistleblowing",
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { hardhatArguments, run } from "hardhat"
|
||||
import { saveDeployedContracts } from "./utils"
|
||||
|
||||
async function main() {
|
||||
const verifiers: Record<string, string> = {}
|
||||
|
||||
// Deploy verifiers.
|
||||
for (let treeDepth = 16; treeDepth <= 32; treeDepth += 1) {
|
||||
const { address } = await run("deploy:verifier", { depth: treeDepth })
|
||||
|
||||
verifiers[`Verifier${treeDepth}`] = address
|
||||
}
|
||||
|
||||
saveDeployedContracts(hardhatArguments.network, { verifiers })
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -1,34 +1,33 @@
|
||||
import { readFileSync, writeFileSync } from "fs"
|
||||
|
||||
export function saveDeployedContracts(network: string | undefined, deployedContracts: any) {
|
||||
if (network !== "goerli" && network !== "arbitrum") {
|
||||
return
|
||||
}
|
||||
|
||||
writeFileSync(`./deployed-contracts/${network}.json`, JSON.stringify(deployedContracts, null, 4))
|
||||
type DeployedContracts = {
|
||||
Pairing?: string
|
||||
SemaphoreVerifier?: string
|
||||
Poseidon?: string
|
||||
IncrementalBinaryTree?: string
|
||||
Semaphore?: string
|
||||
}
|
||||
|
||||
export function getDeployedContracts(network: string | undefined): any {
|
||||
if (network !== "goerli" && network !== "arbitrum") {
|
||||
return null
|
||||
export function getDeployedContracts(network: string | undefined): DeployedContracts | null {
|
||||
try {
|
||||
return JSON.parse(readFileSync(`./deployed-contracts/${network}.json`, "utf8"))
|
||||
} catch (error) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return JSON.parse(readFileSync(`./deployed-contracts/${network}.json`, "utf8"))
|
||||
}
|
||||
|
||||
export function verifiersToSolidityArgument(deployedContracts: any): any {
|
||||
const verifiers = []
|
||||
export function saveDeployedContracts(network: string | undefined, newDeployedContracts: DeployedContracts) {
|
||||
const deployedContracts = getDeployedContracts(network)
|
||||
|
||||
if (deployedContracts && deployedContracts.verifiers) {
|
||||
for (const verifier in deployedContracts.verifiers) {
|
||||
if (Object.prototype.hasOwnProperty.call(deployedContracts.verifiers, verifier)) {
|
||||
verifiers.push({
|
||||
merkleTreeDepth: verifier.substring(8),
|
||||
contractAddress: deployedContracts.verifiers[verifier]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return verifiers
|
||||
writeFileSync(
|
||||
`./deployed-contracts/${network}.json`,
|
||||
JSON.stringify(
|
||||
{
|
||||
...deployedContracts,
|
||||
...newDeployedContracts
|
||||
},
|
||||
null,
|
||||
4
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
import { hardhatArguments, run } from "hardhat"
|
||||
import { getDeployedContracts, verifiersToSolidityArgument } from "./utils"
|
||||
import { getDeployedContracts } from "./utils"
|
||||
|
||||
async function main() {
|
||||
const deployedContracts = getDeployedContracts(hardhatArguments.network)
|
||||
|
||||
if (deployedContracts) {
|
||||
await run("verify:verify", {
|
||||
address: deployedContracts.Semaphore,
|
||||
constructorArguments: [verifiersToSolidityArgument(deployedContracts)]
|
||||
})
|
||||
await run("verify:verify", {
|
||||
address: deployedContracts.IncrementalBinaryTree
|
||||
})
|
||||
|
||||
await run("verify:verify", {
|
||||
address: deployedContracts.IncrementalBinaryTree
|
||||
})
|
||||
}
|
||||
await run("verify:verify", {
|
||||
address: deployedContracts.Semaphore
|
||||
})
|
||||
|
||||
await run("verify:verify", {
|
||||
address: deployedContracts.Pairing
|
||||
})
|
||||
|
||||
await run("verify:verify", {
|
||||
address: deployedContracts.SemaphoreVerifier
|
||||
})
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
@@ -4,48 +4,70 @@ import { task, types } from "hardhat/config"
|
||||
|
||||
task("deploy:semaphore-voting", "Deploy a SemaphoreVoting contract")
|
||||
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
|
||||
.addParam("verifiers", "Tree depths and verifier addresses", undefined, types.json)
|
||||
.setAction(async ({ logs, verifiers }, { ethers }): Promise<Contract> => {
|
||||
.setAction(async ({ logs }, { ethers }): Promise<Contract> => {
|
||||
const PairingFactory = await ethers.getContractFactory("Pairing")
|
||||
const pairing = await PairingFactory.deploy()
|
||||
|
||||
await pairing.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`Pairing library has been deployed to: ${pairing.address}`)
|
||||
}
|
||||
|
||||
const SemaphoreVerifierFactory = await ethers.getContractFactory("SemaphoreVerifier", {
|
||||
libraries: {
|
||||
Pairing: pairing.address
|
||||
}
|
||||
})
|
||||
|
||||
const semaphoreVerifier = await SemaphoreVerifierFactory.deploy()
|
||||
|
||||
await semaphoreVerifier.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`SemaphoreVerifier contract has been deployed to: ${semaphoreVerifier.address}`)
|
||||
}
|
||||
|
||||
const poseidonABI = poseidonContract.generateABI(2)
|
||||
const poseidonBytecode = poseidonContract.createCode(2)
|
||||
|
||||
const [signer] = await ethers.getSigners()
|
||||
|
||||
const PoseidonLibFactory = new ethers.ContractFactory(poseidonABI, poseidonBytecode, signer)
|
||||
const poseidonLib = await PoseidonLibFactory.deploy()
|
||||
const PoseidonFactory = new ethers.ContractFactory(poseidonABI, poseidonBytecode, signer)
|
||||
const poseidon = await PoseidonFactory.deploy()
|
||||
|
||||
await poseidonLib.deployed()
|
||||
await poseidon.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`Poseidon library has been deployed to: ${poseidonLib.address}`)
|
||||
console.info(`Poseidon library has been deployed to: ${poseidon.address}`)
|
||||
}
|
||||
|
||||
const IncrementalBinaryTreeLibFactory = await ethers.getContractFactory("IncrementalBinaryTree", {
|
||||
const IncrementalBinaryTreeFactory = await ethers.getContractFactory("IncrementalBinaryTree", {
|
||||
libraries: {
|
||||
PoseidonT3: poseidonLib.address
|
||||
PoseidonT3: poseidon.address
|
||||
}
|
||||
})
|
||||
const incrementalBinaryTreeLib = await IncrementalBinaryTreeLibFactory.deploy()
|
||||
const incrementalBinaryTree = await IncrementalBinaryTreeFactory.deploy()
|
||||
|
||||
await incrementalBinaryTreeLib.deployed()
|
||||
await incrementalBinaryTree.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`IncrementalBinaryTree library has been deployed to: ${incrementalBinaryTreeLib.address}`)
|
||||
console.info(`IncrementalBinaryTree library has been deployed to: ${incrementalBinaryTree.address}`)
|
||||
}
|
||||
|
||||
const ContractFactory = await ethers.getContractFactory("SemaphoreVoting", {
|
||||
const SemaphoreVotingFactory = await ethers.getContractFactory("SemaphoreVoting", {
|
||||
libraries: {
|
||||
IncrementalBinaryTree: incrementalBinaryTreeLib.address
|
||||
IncrementalBinaryTree: incrementalBinaryTree.address
|
||||
}
|
||||
})
|
||||
|
||||
const contract = await ContractFactory.deploy(verifiers)
|
||||
const semaphoreVoting = await SemaphoreVotingFactory.deploy(semaphoreVerifier.address)
|
||||
|
||||
await contract.deployed()
|
||||
await semaphoreVoting.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`SemaphoreVoting contract has been deployed to: ${contract.address}`)
|
||||
console.info(`SemaphoreVoting contract has been deployed to: ${semaphoreVoting.address}`)
|
||||
}
|
||||
|
||||
return contract
|
||||
return semaphoreVoting
|
||||
})
|
||||
|
||||
@@ -4,48 +4,70 @@ import { task, types } from "hardhat/config"
|
||||
|
||||
task("deploy:semaphore-whistleblowing", "Deploy a SemaphoreWhistleblowing contract")
|
||||
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
|
||||
.addParam("verifiers", "Verifier contract address", undefined, types.json)
|
||||
.setAction(async ({ logs, verifiers }, { ethers }): Promise<Contract> => {
|
||||
.setAction(async ({ logs }, { ethers }): Promise<Contract> => {
|
||||
const PairingFactory = await ethers.getContractFactory("Pairing")
|
||||
const pairing = await PairingFactory.deploy()
|
||||
|
||||
await pairing.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`Pairing library has been deployed to: ${pairing.address}`)
|
||||
}
|
||||
|
||||
const SemaphoreVerifierFactory = await ethers.getContractFactory("SemaphoreVerifier", {
|
||||
libraries: {
|
||||
Pairing: pairing.address
|
||||
}
|
||||
})
|
||||
|
||||
const semaphoreVerifier = await SemaphoreVerifierFactory.deploy()
|
||||
|
||||
await semaphoreVerifier.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`SemaphoreVerifier contract has been deployed to: ${semaphoreVerifier.address}`)
|
||||
}
|
||||
|
||||
const poseidonABI = poseidonContract.generateABI(2)
|
||||
const poseidonBytecode = poseidonContract.createCode(2)
|
||||
|
||||
const [signer] = await ethers.getSigners()
|
||||
|
||||
const PoseidonLibFactory = new ethers.ContractFactory(poseidonABI, poseidonBytecode, signer)
|
||||
const poseidonLib = await PoseidonLibFactory.deploy()
|
||||
const PoseidonFactory = new ethers.ContractFactory(poseidonABI, poseidonBytecode, signer)
|
||||
const poseidon = await PoseidonFactory.deploy()
|
||||
|
||||
await poseidonLib.deployed()
|
||||
await poseidon.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`Poseidon library has been deployed to: ${poseidonLib.address}`)
|
||||
console.info(`Poseidon library has been deployed to: ${poseidon.address}`)
|
||||
}
|
||||
|
||||
const IncrementalBinaryTreeLibFactory = await ethers.getContractFactory("IncrementalBinaryTree", {
|
||||
const IncrementalBinaryTreeFactory = await ethers.getContractFactory("IncrementalBinaryTree", {
|
||||
libraries: {
|
||||
PoseidonT3: poseidonLib.address
|
||||
PoseidonT3: poseidon.address
|
||||
}
|
||||
})
|
||||
const incrementalBinaryTreeLib = await IncrementalBinaryTreeLibFactory.deploy()
|
||||
const incrementalBinaryTree = await IncrementalBinaryTreeFactory.deploy()
|
||||
|
||||
await incrementalBinaryTreeLib.deployed()
|
||||
await incrementalBinaryTree.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`IncrementalBinaryTree library has been deployed to: ${incrementalBinaryTreeLib.address}`)
|
||||
console.info(`IncrementalBinaryTree library has been deployed to: ${incrementalBinaryTree.address}`)
|
||||
}
|
||||
|
||||
const ContractFactory = await ethers.getContractFactory("SemaphoreWhistleblowing", {
|
||||
const SemaphoreWhistleblowingFactory = await ethers.getContractFactory("SemaphoreWhistleblowing", {
|
||||
libraries: {
|
||||
IncrementalBinaryTree: incrementalBinaryTreeLib.address
|
||||
IncrementalBinaryTree: incrementalBinaryTree.address
|
||||
}
|
||||
})
|
||||
|
||||
const contract = await ContractFactory.deploy(verifiers)
|
||||
const semaphoreWhistleblowing = await SemaphoreWhistleblowingFactory.deploy(semaphoreVerifier.address)
|
||||
|
||||
await contract.deployed()
|
||||
await semaphoreWhistleblowing.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`SemaphoreWhistleblowing contract has been deployed to: ${contract.address}`)
|
||||
console.info(`SemaphoreWhistleblowing contract has been deployed to: ${semaphoreWhistleblowing.address}`)
|
||||
}
|
||||
|
||||
return contract
|
||||
return semaphoreWhistleblowing
|
||||
})
|
||||
|
||||
@@ -1,67 +1,118 @@
|
||||
import { poseidon_gencontract as poseidonContract } from "circomlibjs"
|
||||
import { Contract } from "ethers"
|
||||
import { task, types } from "hardhat/config"
|
||||
import { getDeployedContracts, saveDeployedContracts, verifiersToSolidityArgument } from "../scripts/utils"
|
||||
import { saveDeployedContracts } from "../scripts/utils"
|
||||
|
||||
task("deploy:semaphore", "Deploy a Semaphore contract")
|
||||
.addOptionalParam<boolean>("pairing", "Pairing library address", undefined, types.string)
|
||||
.addOptionalParam<boolean>("semaphoreVerifier", "SemaphoreVerifier contract address", undefined, types.string)
|
||||
.addOptionalParam<boolean>("poseidon", "Poseidon library address", undefined, types.string)
|
||||
.addOptionalParam<boolean>(
|
||||
"incrementalBinaryTree",
|
||||
"IncrementalBinaryTree library address",
|
||||
undefined,
|
||||
types.string
|
||||
)
|
||||
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
|
||||
.addOptionalParam("verifiers", "Tree depths and verifier addresses", [], types.json)
|
||||
.setAction(async ({ logs, verifiers }, { ethers, hardhatArguments }): Promise<Contract> => {
|
||||
let deployedContracts: any
|
||||
.setAction(
|
||||
async (
|
||||
{
|
||||
logs,
|
||||
pairing: pairingAddress,
|
||||
semaphoreVerifier: semaphoreVerifierAddress,
|
||||
poseidon: poseidonAddress,
|
||||
incrementalBinaryTree: incrementalBinaryTreeAddress
|
||||
},
|
||||
{ ethers, hardhatArguments }
|
||||
): Promise<Contract> => {
|
||||
if (!semaphoreVerifierAddress) {
|
||||
if (!pairingAddress) {
|
||||
const PairingFactory = await ethers.getContractFactory("Pairing")
|
||||
const pairing = await PairingFactory.deploy()
|
||||
|
||||
if (verifiers.length === 0) {
|
||||
deployedContracts = getDeployedContracts(hardhatArguments.network)
|
||||
verifiers = verifiersToSolidityArgument(deployedContracts)
|
||||
}
|
||||
await pairing.deployed()
|
||||
|
||||
const poseidonABI = poseidonContract.generateABI(2)
|
||||
const poseidonBytecode = poseidonContract.createCode(2)
|
||||
if (logs) {
|
||||
console.info(`Pairing library has been deployed to: ${pairing.address}`)
|
||||
}
|
||||
|
||||
const [signer] = await ethers.getSigners()
|
||||
pairingAddress = pairing.address
|
||||
}
|
||||
|
||||
const PoseidonLibFactory = new ethers.ContractFactory(poseidonABI, poseidonBytecode, signer)
|
||||
const poseidonLib = await PoseidonLibFactory.deploy()
|
||||
const SemaphoreVerifierFactory = await ethers.getContractFactory("SemaphoreVerifier", {
|
||||
libraries: {
|
||||
Pairing: pairingAddress
|
||||
}
|
||||
})
|
||||
|
||||
await poseidonLib.deployed()
|
||||
const semaphoreVerifier = await SemaphoreVerifierFactory.deploy()
|
||||
|
||||
if (logs) {
|
||||
console.info(`Poseidon library has been deployed to: ${poseidonLib.address}`)
|
||||
}
|
||||
await semaphoreVerifier.deployed()
|
||||
|
||||
const IncrementalBinaryTreeLibFactory = await ethers.getContractFactory("IncrementalBinaryTree", {
|
||||
libraries: {
|
||||
PoseidonT3: poseidonLib.address
|
||||
if (logs) {
|
||||
console.info(`SemaphoreVerifier contract has been deployed to: ${semaphoreVerifier.address}`)
|
||||
}
|
||||
|
||||
semaphoreVerifierAddress = semaphoreVerifier.address
|
||||
}
|
||||
})
|
||||
const incrementalBinaryTreeLib = await IncrementalBinaryTreeLibFactory.deploy()
|
||||
|
||||
await incrementalBinaryTreeLib.deployed()
|
||||
if (!incrementalBinaryTreeAddress) {
|
||||
if (!poseidonAddress) {
|
||||
const poseidonABI = poseidonContract.generateABI(2)
|
||||
const poseidonBytecode = poseidonContract.createCode(2)
|
||||
|
||||
if (logs) {
|
||||
console.info(`IncrementalBinaryTree library has been deployed to: ${incrementalBinaryTreeLib.address}`)
|
||||
}
|
||||
const [signer] = await ethers.getSigners()
|
||||
|
||||
const ContractFactory = await ethers.getContractFactory("Semaphore", {
|
||||
libraries: {
|
||||
IncrementalBinaryTree: incrementalBinaryTreeLib.address
|
||||
const PoseidonFactory = new ethers.ContractFactory(poseidonABI, poseidonBytecode, signer)
|
||||
const poseidon = await PoseidonFactory.deploy()
|
||||
|
||||
await poseidon.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`Poseidon library has been deployed to: ${poseidon.address}`)
|
||||
}
|
||||
|
||||
poseidonAddress = poseidon.address
|
||||
}
|
||||
|
||||
const IncrementalBinaryTreeFactory = await ethers.getContractFactory("IncrementalBinaryTree", {
|
||||
libraries: {
|
||||
PoseidonT3: poseidonAddress
|
||||
}
|
||||
})
|
||||
const incrementalBinaryTree = await IncrementalBinaryTreeFactory.deploy()
|
||||
|
||||
await incrementalBinaryTree.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`IncrementalBinaryTree library has been deployed to: ${incrementalBinaryTree.address}`)
|
||||
}
|
||||
|
||||
incrementalBinaryTreeAddress = incrementalBinaryTree.address
|
||||
}
|
||||
})
|
||||
|
||||
const contract = await ContractFactory.deploy(verifiers)
|
||||
const SemaphoreFactory = await ethers.getContractFactory("Semaphore", {
|
||||
libraries: {
|
||||
IncrementalBinaryTree: incrementalBinaryTreeAddress
|
||||
}
|
||||
})
|
||||
|
||||
await contract.deployed()
|
||||
const semaphore = await SemaphoreFactory.deploy(semaphoreVerifierAddress)
|
||||
|
||||
if (logs) {
|
||||
console.info(`Semaphore contract has been deployed to: ${contract.address}`)
|
||||
await semaphore.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`Semaphore contract has been deployed to: ${semaphore.address}`)
|
||||
}
|
||||
|
||||
saveDeployedContracts(hardhatArguments.network, {
|
||||
Pairing: pairingAddress,
|
||||
SemaphoreVerifier: semaphoreVerifierAddress,
|
||||
Poseidon: poseidonAddress,
|
||||
IncrementalBinaryTree: incrementalBinaryTreeAddress,
|
||||
Semaphore: semaphore.address
|
||||
})
|
||||
|
||||
return semaphore
|
||||
}
|
||||
|
||||
if (deployedContracts) {
|
||||
deployedContracts.PoseidonT3 = poseidonLib.address
|
||||
deployedContracts.IncrementalBinaryTree = incrementalBinaryTreeLib.address
|
||||
deployedContracts.Semaphore = contract.address
|
||||
|
||||
saveDeployedContracts(hardhatArguments.network, deployedContracts)
|
||||
}
|
||||
|
||||
return contract
|
||||
})
|
||||
)
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Contract } from "ethers"
|
||||
import { task, types } from "hardhat/config"
|
||||
|
||||
task("deploy:verifier", "Deploy a Verifier contract")
|
||||
.addOptionalParam<number>("depth", "Tree depth", Number(process.env.TREE_DEPTH) || 20, types.int)
|
||||
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
|
||||
.setAction(async ({ depth, logs }, { ethers }): Promise<Contract> => {
|
||||
const ContractFactory = await ethers.getContractFactory(`Verifier${depth}`)
|
||||
|
||||
const contract = await ContractFactory.deploy()
|
||||
|
||||
await contract.deployed()
|
||||
|
||||
if (logs) {
|
||||
console.info(`Verifier${depth} contract has been deployed to: ${contract.address}`)
|
||||
}
|
||||
|
||||
return contract
|
||||
})
|
||||
@@ -4,7 +4,7 @@ import { Group } from "@semaphore-protocol/group"
|
||||
import { Identity } from "@semaphore-protocol/identity"
|
||||
import { FullProof, generateProof, packToSolidityProof, SolidityProof } from "@semaphore-protocol/proof"
|
||||
import { expect } from "chai"
|
||||
import { constants, Signer, utils } from "ethers"
|
||||
import { constants, Signer } from "ethers"
|
||||
import { run } from "hardhat"
|
||||
import { Semaphore } from "../build/typechain"
|
||||
import { createIdentityCommitments } from "./utils"
|
||||
@@ -18,14 +18,12 @@ describe("Semaphore", () => {
|
||||
const groupId = 1
|
||||
const members = createIdentityCommitments(3)
|
||||
|
||||
const wasmFilePath = `../../snark-artifacts/semaphore.wasm`
|
||||
const zkeyFilePath = `../../snark-artifacts/semaphore.zkey`
|
||||
const wasmFilePath = `../../snark-artifacts/${treeDepth}/semaphore.wasm`
|
||||
const zkeyFilePath = `../../snark-artifacts/${treeDepth}/semaphore.zkey`
|
||||
|
||||
before(async () => {
|
||||
const { address: verifierAddress } = await run("deploy:verifier", { logs: false, depth: treeDepth })
|
||||
contract = await run("deploy:semaphore", {
|
||||
logs: false,
|
||||
verifiers: [{ merkleTreeDepth: treeDepth, contractAddress: verifierAddress }]
|
||||
logs: false
|
||||
})
|
||||
|
||||
signers = await run("accounts", { logs: false })
|
||||
@@ -96,16 +94,13 @@ describe("Semaphore", () => {
|
||||
})
|
||||
|
||||
it("Should add a new member in an existing group", async () => {
|
||||
const group = new Group(treeDepth)
|
||||
|
||||
group.addMember(members[0])
|
||||
|
||||
const transaction = contract.addMember(groupId, members[0])
|
||||
|
||||
await expect(transaction)
|
||||
.to.emit(contract, "MemberAdded")
|
||||
.withArgs(
|
||||
groupId,
|
||||
0,
|
||||
members[0],
|
||||
"18951329906296061785889394467312334959162736293275411745101070722914184798221"
|
||||
)
|
||||
await expect(transaction).to.emit(contract, "MemberAdded").withArgs(groupId, 0, members[0], group.root)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -146,7 +141,7 @@ describe("Semaphore", () => {
|
||||
await contract["createGroup(uint256,uint256,uint256,address)"](groupId, treeDepth, 0, accounts[0])
|
||||
await contract.addMembers(groupId, members)
|
||||
|
||||
const { siblings, pathIndices, root } = group.generateProofOfMembership(0)
|
||||
const { siblings, pathIndices, root } = group.generateMerkleProof(0)
|
||||
|
||||
const transaction = contract.updateMember(groupId, BigInt(1), BigInt(4), siblings, pathIndices)
|
||||
|
||||
@@ -177,7 +172,7 @@ describe("Semaphore", () => {
|
||||
await contract["createGroup(uint256,uint256,uint256,address)"](groupId, treeDepth, 0, accounts[0])
|
||||
await contract.addMembers(groupId, members)
|
||||
|
||||
const { siblings, pathIndices, root } = group.generateProofOfMembership(2)
|
||||
const { siblings, pathIndices, root } = group.generateMerkleProof(2)
|
||||
|
||||
const transaction = contract.removeMember(groupId, BigInt(3), siblings, pathIndices)
|
||||
|
||||
@@ -186,7 +181,7 @@ describe("Semaphore", () => {
|
||||
})
|
||||
|
||||
describe("# verifyProof", () => {
|
||||
const signal = utils.formatBytes32String("Hello world")
|
||||
const signal = 2
|
||||
const identity = new Identity("0")
|
||||
|
||||
const group = new Group(treeDepth)
|
||||
@@ -228,7 +223,7 @@ describe("Semaphore", () => {
|
||||
solidityProof
|
||||
)
|
||||
|
||||
await expect(transaction).to.be.revertedWith("InvalidProof()")
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__InvalidProof()")
|
||||
})
|
||||
|
||||
it("Should verify a proof for an onchain group correctly", async () => {
|
||||
@@ -237,7 +232,7 @@ describe("Semaphore", () => {
|
||||
group.root,
|
||||
signal,
|
||||
fullProof.publicSignals.nullifierHash,
|
||||
fullProof.publicSignals.merkleRoot,
|
||||
fullProof.publicSignals.merkleTreeRoot,
|
||||
solidityProof
|
||||
)
|
||||
|
||||
@@ -247,7 +242,7 @@ describe("Semaphore", () => {
|
||||
groupId,
|
||||
group.root,
|
||||
fullProof.publicSignals.nullifierHash,
|
||||
fullProof.publicSignals.externalNullifier,
|
||||
fullProof.publicSignals.merkleTreeRoot,
|
||||
signal
|
||||
)
|
||||
})
|
||||
@@ -258,7 +253,7 @@ describe("Semaphore", () => {
|
||||
group.root,
|
||||
signal,
|
||||
fullProof.publicSignals.nullifierHash,
|
||||
fullProof.publicSignals.merkleRoot,
|
||||
fullProof.publicSignals.merkleTreeRoot,
|
||||
solidityProof
|
||||
)
|
||||
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
/* eslint-disable jest/valid-expect */
|
||||
import { Group } from "@semaphore-protocol/group"
|
||||
import { Identity } from "@semaphore-protocol/identity"
|
||||
import {
|
||||
generateNullifierHash,
|
||||
generateProof,
|
||||
packToSolidityProof,
|
||||
PublicSignals,
|
||||
SolidityProof
|
||||
} from "@semaphore-protocol/proof"
|
||||
import { generateProof, packToSolidityProof, PublicSignals, SolidityProof } from "@semaphore-protocol/proof"
|
||||
import { expect } from "chai"
|
||||
import { Signer, utils } from "ethers"
|
||||
import { Signer } from "ethers"
|
||||
import { ethers, run } from "hardhat"
|
||||
import { SemaphoreVoting } from "../build/typechain"
|
||||
|
||||
@@ -19,18 +13,16 @@ describe("SemaphoreVoting", () => {
|
||||
let coordinator: string
|
||||
|
||||
const treeDepth = Number(process.env.TREE_DEPTH) || 20
|
||||
const pollIds = [BigInt(1), BigInt(2), BigInt(3)]
|
||||
const pollIds = [1, 2, 3]
|
||||
const encryptionKey = BigInt(0)
|
||||
const decryptionKey = BigInt(0)
|
||||
|
||||
const wasmFilePath = `../../snark-artifacts/semaphore.wasm`
|
||||
const zkeyFilePath = `../../snark-artifacts/semaphore.zkey`
|
||||
const wasmFilePath = `../../snark-artifacts/${treeDepth}/semaphore.wasm`
|
||||
const zkeyFilePath = `../../snark-artifacts/${treeDepth}/semaphore.zkey`
|
||||
|
||||
before(async () => {
|
||||
const { address: verifierAddress } = await run("deploy:verifier", { logs: false, depth: treeDepth })
|
||||
contract = await run("deploy:semaphore-voting", {
|
||||
logs: false,
|
||||
verifiers: [{ merkleTreeDepth: treeDepth, contractAddress: verifierAddress }]
|
||||
logs: false
|
||||
})
|
||||
|
||||
accounts = await ethers.getSigners()
|
||||
@@ -44,16 +36,6 @@ describe("SemaphoreVoting", () => {
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__MerkleTreeDepthIsNotSupported()")
|
||||
})
|
||||
|
||||
it("Should not create a poll greater than the snark scalar field", async () => {
|
||||
const transaction = contract.createPoll(
|
||||
BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495618"),
|
||||
coordinator,
|
||||
treeDepth
|
||||
)
|
||||
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__GroupIdIsNotLessThanSnarkScalarField()")
|
||||
})
|
||||
|
||||
it("Should create a poll", async () => {
|
||||
const transaction = contract.createPoll(pollIds[0], coordinator, treeDepth)
|
||||
|
||||
@@ -110,17 +92,13 @@ describe("SemaphoreVoting", () => {
|
||||
|
||||
it("Should add a voter to an existing poll", async () => {
|
||||
const { commitment } = new Identity("test")
|
||||
const group = new Group(treeDepth)
|
||||
|
||||
group.addMember(commitment)
|
||||
|
||||
const transaction = contract.connect(accounts[1]).addVoter(pollIds[1], commitment)
|
||||
|
||||
await expect(transaction)
|
||||
.to.emit(contract, "MemberAdded")
|
||||
.withArgs(
|
||||
pollIds[1],
|
||||
0,
|
||||
commitment,
|
||||
"14787813191318312920980352979830075893203307366494541177071234930769373297362"
|
||||
)
|
||||
await expect(transaction).to.emit(contract, "MemberAdded").withArgs(pollIds[1], 0, commitment, group.root)
|
||||
})
|
||||
|
||||
it("Should return the correct number of poll voters", async () => {
|
||||
@@ -132,8 +110,7 @@ describe("SemaphoreVoting", () => {
|
||||
|
||||
describe("# castVote", () => {
|
||||
const identity = new Identity("test")
|
||||
const vote = "1"
|
||||
const bytes32Vote = utils.formatBytes32String(vote)
|
||||
const vote = 1
|
||||
|
||||
const group = new Group(treeDepth)
|
||||
|
||||
@@ -156,42 +133,32 @@ describe("SemaphoreVoting", () => {
|
||||
solidityProof = packToSolidityProof(fullProof.proof)
|
||||
})
|
||||
|
||||
it("Should not cast a vote if the caller is not the coordinator", async () => {
|
||||
const transaction = contract.castVote(bytes32Vote, publicSignals.nullifierHash, pollIds[0], solidityProof)
|
||||
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotThePollCoordinator()")
|
||||
})
|
||||
|
||||
it("Should not cast a vote if the poll is not ongoing", async () => {
|
||||
const transaction = contract
|
||||
.connect(accounts[1])
|
||||
.castVote(bytes32Vote, publicSignals.nullifierHash, pollIds[2], solidityProof)
|
||||
.castVote(vote, publicSignals.nullifierHash, pollIds[2], solidityProof)
|
||||
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__PollIsNotOngoing()")
|
||||
})
|
||||
|
||||
it("Should not cast a vote if the proof is not valid", async () => {
|
||||
const nullifierHash = generateNullifierHash(pollIds[0], identity.getNullifier())
|
||||
const transaction = contract.connect(accounts[1]).castVote(vote, 0, pollIds[1], solidityProof)
|
||||
|
||||
const transaction = contract
|
||||
.connect(accounts[1])
|
||||
.castVote(bytes32Vote, nullifierHash, pollIds[1], solidityProof)
|
||||
|
||||
await expect(transaction).to.be.revertedWith("InvalidProof()")
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__InvalidProof()")
|
||||
})
|
||||
|
||||
it("Should cast a vote", async () => {
|
||||
const transaction = contract
|
||||
.connect(accounts[1])
|
||||
.castVote(bytes32Vote, publicSignals.nullifierHash, pollIds[1], solidityProof)
|
||||
.castVote(vote, publicSignals.nullifierHash, pollIds[1], solidityProof)
|
||||
|
||||
await expect(transaction).to.emit(contract, "VoteAdded").withArgs(pollIds[1], bytes32Vote)
|
||||
await expect(transaction).to.emit(contract, "VoteAdded").withArgs(pollIds[1], vote)
|
||||
})
|
||||
|
||||
it("Should not cast a vote twice", async () => {
|
||||
const transaction = contract
|
||||
.connect(accounts[1])
|
||||
.castVote(bytes32Vote, publicSignals.nullifierHash, pollIds[1], solidityProof)
|
||||
.castVote(vote, publicSignals.nullifierHash, pollIds[1], solidityProof)
|
||||
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__YouAreUsingTheSameNillifierTwice()")
|
||||
})
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
/* eslint-disable jest/valid-expect */
|
||||
import { Group } from "@semaphore-protocol/group"
|
||||
import { Identity } from "@semaphore-protocol/identity"
|
||||
import {
|
||||
generateNullifierHash,
|
||||
generateProof,
|
||||
packToSolidityProof,
|
||||
PublicSignals,
|
||||
SolidityProof
|
||||
} from "@semaphore-protocol/proof"
|
||||
import { generateProof, packToSolidityProof, PublicSignals, SolidityProof } from "@semaphore-protocol/proof"
|
||||
import { expect } from "chai"
|
||||
import { Signer, utils } from "ethers"
|
||||
import { ethers, run } from "hardhat"
|
||||
@@ -19,16 +13,14 @@ describe("SemaphoreWhistleblowing", () => {
|
||||
let editor: string
|
||||
|
||||
const treeDepth = Number(process.env.TREE_DEPTH) || 20
|
||||
const entityIds = [BigInt(1), BigInt(2)]
|
||||
const entityIds = [1, 2]
|
||||
|
||||
const wasmFilePath = `../../snark-artifacts/semaphore.wasm`
|
||||
const zkeyFilePath = `../../snark-artifacts/semaphore.zkey`
|
||||
const wasmFilePath = `../../snark-artifacts/${treeDepth}/semaphore.wasm`
|
||||
const zkeyFilePath = `../../snark-artifacts/${treeDepth}/semaphore.zkey`
|
||||
|
||||
before(async () => {
|
||||
const { address: verifierAddress } = await run("deploy:verifier", { logs: false, depth: treeDepth })
|
||||
contract = await run("deploy:semaphore-whistleblowing", {
|
||||
logs: false,
|
||||
verifiers: [{ merkleTreeDepth: treeDepth, contractAddress: verifierAddress }]
|
||||
logs: false
|
||||
})
|
||||
|
||||
accounts = await ethers.getSigners()
|
||||
@@ -42,16 +34,6 @@ describe("SemaphoreWhistleblowing", () => {
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__MerkleTreeDepthIsNotSupported()")
|
||||
})
|
||||
|
||||
it("Should not create an entity greater than the snark scalar field", async () => {
|
||||
const transaction = contract.createEntity(
|
||||
BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495618"),
|
||||
editor,
|
||||
treeDepth
|
||||
)
|
||||
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__GroupIdIsNotLessThanSnarkScalarField()")
|
||||
})
|
||||
|
||||
it("Should create an entity", async () => {
|
||||
const transaction = contract.createEntity(entityIds[0], editor, treeDepth)
|
||||
|
||||
@@ -76,17 +58,13 @@ describe("SemaphoreWhistleblowing", () => {
|
||||
|
||||
it("Should add a whistleblower to an existing entity", async () => {
|
||||
const { commitment } = new Identity("test")
|
||||
const group = new Group(treeDepth)
|
||||
|
||||
group.addMember(commitment)
|
||||
|
||||
const transaction = contract.connect(accounts[1]).addWhistleblower(entityIds[0], commitment)
|
||||
|
||||
await expect(transaction)
|
||||
.to.emit(contract, "MemberAdded")
|
||||
.withArgs(
|
||||
entityIds[0],
|
||||
0,
|
||||
commitment,
|
||||
"14787813191318312920980352979830075893203307366494541177071234930769373297362"
|
||||
)
|
||||
await expect(transaction).to.emit(contract, "MemberAdded").withArgs(entityIds[0], 0, commitment, group.root)
|
||||
})
|
||||
|
||||
it("Should return the correct number of whistleblowers of an entity", async () => {
|
||||
@@ -103,7 +81,7 @@ describe("SemaphoreWhistleblowing", () => {
|
||||
|
||||
group.addMember(commitment)
|
||||
|
||||
const { siblings, pathIndices } = group.generateProofOfMembership(0)
|
||||
const { siblings, pathIndices } = group.generateMerkleProof(0)
|
||||
|
||||
const transaction = contract.removeWhistleblower(entityIds[0], commitment, siblings, pathIndices)
|
||||
|
||||
@@ -116,7 +94,9 @@ describe("SemaphoreWhistleblowing", () => {
|
||||
|
||||
group.addMember(commitment)
|
||||
|
||||
const { siblings, pathIndices } = group.generateProofOfMembership(0)
|
||||
const { siblings, pathIndices } = group.generateMerkleProof(0)
|
||||
|
||||
group.removeMember(0)
|
||||
|
||||
const transaction = contract
|
||||
.connect(accounts[1])
|
||||
@@ -124,19 +104,13 @@ describe("SemaphoreWhistleblowing", () => {
|
||||
|
||||
await expect(transaction)
|
||||
.to.emit(contract, "MemberRemoved")
|
||||
.withArgs(
|
||||
entityIds[0],
|
||||
0,
|
||||
commitment,
|
||||
"15019797232609675441998260052101280400536945603062888308240081994073687793470"
|
||||
)
|
||||
.withArgs(entityIds[0], 0, commitment, group.root)
|
||||
})
|
||||
})
|
||||
|
||||
describe("# publishLeak", () => {
|
||||
const identity = new Identity("test")
|
||||
const leak = "leak"
|
||||
const bytes32Leak = utils.formatBytes32String(leak)
|
||||
const leak = utils.formatBytes32String("This is a leak")
|
||||
|
||||
const group = new Group(treeDepth)
|
||||
|
||||
@@ -159,33 +133,18 @@ describe("SemaphoreWhistleblowing", () => {
|
||||
solidityProof = packToSolidityProof(fullProof.proof)
|
||||
})
|
||||
|
||||
it("Should not publish a leak if the caller is not the editor", async () => {
|
||||
const transaction = contract.publishLeak(
|
||||
bytes32Leak,
|
||||
publicSignals.nullifierHash,
|
||||
entityIds[0],
|
||||
solidityProof
|
||||
)
|
||||
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotTheEditor()")
|
||||
})
|
||||
|
||||
it("Should not publish a leak if the proof is not valid", async () => {
|
||||
const nullifierHash = generateNullifierHash(entityIds[0], identity.getNullifier())
|
||||
const transaction = contract.connect(accounts[1]).publishLeak(leak, 0, entityIds[1], solidityProof)
|
||||
|
||||
const transaction = contract
|
||||
.connect(accounts[1])
|
||||
.publishLeak(bytes32Leak, nullifierHash, entityIds[1], solidityProof)
|
||||
|
||||
await expect(transaction).to.be.revertedWith("InvalidProof()")
|
||||
await expect(transaction).to.be.revertedWith("Semaphore__InvalidProof()")
|
||||
})
|
||||
|
||||
it("Should publish a leak", async () => {
|
||||
const transaction = contract
|
||||
.connect(accounts[1])
|
||||
.publishLeak(bytes32Leak, publicSignals.nullifierHash, entityIds[1], solidityProof)
|
||||
.publishLeak(leak, publicSignals.nullifierHash, entityIds[1], solidityProof)
|
||||
|
||||
await expect(transaction).to.emit(contract, "LeakPublished").withArgs(entityIds[1], bytes32Leak)
|
||||
await expect(transaction).to.emit(contract, "LeakPublished").withArgs(entityIds[1], leak)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -120,8 +120,8 @@ group.removeMember(0)
|
||||
group.indexOf(commitment) // 0
|
||||
```
|
||||
|
||||
\# **generateProofOfMembership**(index: _number_): _MerkleProof_
|
||||
\# **generateMerkleProof**(index: _number_): _MerkleProof_
|
||||
|
||||
```typescript
|
||||
const proof = group.generateProofOfMembership(0)
|
||||
const proof = group.generateMerkleProof(0)
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@semaphore-protocol/group",
|
||||
"version": "2.6.0",
|
||||
"version": "2.6.1",
|
||||
"description": "A library to create and manage Semaphore groups.",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.node.js",
|
||||
@@ -36,6 +36,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@zk-kit/incremental-merkle-tree": "1.0.0",
|
||||
"circomlibjs": "0.0.8"
|
||||
"poseidon-lite": "^0.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,12 +82,12 @@ describe("Group", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("# generateProofOfMembership", () => {
|
||||
describe("# generateMerkleProof", () => {
|
||||
it("Should generate a proof of membership", () => {
|
||||
const group = new Group()
|
||||
group.addMembers([BigInt(1), BigInt(3)])
|
||||
|
||||
const proof = group.generateProofOfMembership(0)
|
||||
const proof = group.generateMerkleProof(0)
|
||||
|
||||
expect(proof.leaf).toBe(BigInt(1))
|
||||
})
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { IncrementalMerkleTree, MerkleProof } from "@zk-kit/incremental-merkle-tree"
|
||||
import { poseidon } from "circomlibjs"
|
||||
import poseidon from "poseidon-lite"
|
||||
import { Member } from "./types"
|
||||
|
||||
export default class Group {
|
||||
private _merkleTree: IncrementalMerkleTree
|
||||
merkleTree: IncrementalMerkleTree
|
||||
|
||||
/**
|
||||
* Initializes the group with the tree depth and the zero value.
|
||||
@@ -15,7 +15,7 @@ export default class Group {
|
||||
throw new Error("The tree depth must be between 16 and 32")
|
||||
}
|
||||
|
||||
this._merkleTree = new IncrementalMerkleTree(poseidon, treeDepth, zeroValue, 2)
|
||||
this.merkleTree = new IncrementalMerkleTree(poseidon, treeDepth, zeroValue, 2)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -23,7 +23,7 @@ export default class Group {
|
||||
* @returns Root hash.
|
||||
*/
|
||||
get root(): Member {
|
||||
return this._merkleTree.root
|
||||
return this.merkleTree.root
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,7 +31,7 @@ export default class Group {
|
||||
* @returns Tree depth.
|
||||
*/
|
||||
get depth(): number {
|
||||
return this._merkleTree.depth
|
||||
return this.merkleTree.depth
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ export default class Group {
|
||||
* @returns Tree zero value.
|
||||
*/
|
||||
get zeroValue(): Member {
|
||||
return this._merkleTree.zeroes[0]
|
||||
return this.merkleTree.zeroes[0]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ export default class Group {
|
||||
* @returns List of members.
|
||||
*/
|
||||
get members(): Member[] {
|
||||
return this._merkleTree.leaves
|
||||
return this.merkleTree.leaves
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,34 +56,34 @@ export default class Group {
|
||||
* @returns Index of the member.
|
||||
*/
|
||||
indexOf(member: Member): number {
|
||||
return this._merkleTree.indexOf(member)
|
||||
return this.merkleTree.indexOf(member)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new member to the group.
|
||||
* @param identityCommitment New member.
|
||||
* @param member New member.
|
||||
*/
|
||||
addMember(identityCommitment: Member) {
|
||||
this._merkleTree.insert(BigInt(identityCommitment))
|
||||
addMember(member: Member) {
|
||||
this.merkleTree.insert(BigInt(member))
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new members to the group.
|
||||
* @param identityCommitments New members.
|
||||
* @param members New members.
|
||||
*/
|
||||
addMembers(identityCommitments: Member[]) {
|
||||
for (const identityCommitment of identityCommitments) {
|
||||
this.addMember(identityCommitment)
|
||||
addMembers(members: Member[]) {
|
||||
for (const member of members) {
|
||||
this.addMember(member)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a member in the group.
|
||||
* @param index Index of the member to be updated.
|
||||
* @param identityCommitment New member value.
|
||||
* @param member New member value.
|
||||
*/
|
||||
updateMember(index: number, identityCommitment: Member) {
|
||||
this._merkleTree.update(index, identityCommitment)
|
||||
updateMember(index: number, member: Member) {
|
||||
this.merkleTree.update(index, member)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,7 +91,7 @@ export default class Group {
|
||||
* @param index Index of the member to be removed.
|
||||
*/
|
||||
removeMember(index: number) {
|
||||
this._merkleTree.delete(index)
|
||||
this.merkleTree.delete(index)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,8 +99,8 @@ export default class Group {
|
||||
* @param index Index of the proof's member.
|
||||
* @returns Proof object.
|
||||
*/
|
||||
generateProofOfMembership(index: number): MerkleProof {
|
||||
const merkleProof = this._merkleTree.createProof(index)
|
||||
generateMerkleProof(index: number): MerkleProof {
|
||||
const merkleProof = this.merkleTree.createProof(index)
|
||||
|
||||
merkleProof.siblings = merkleProof.siblings.map((s) => s[0])
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@semaphore-protocol/identity",
|
||||
"version": "2.6.0",
|
||||
"version": "2.6.1",
|
||||
"description": "A library to create Semaphore identities.",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.node.js",
|
||||
@@ -39,6 +39,6 @@
|
||||
"@ethersproject/random": "^5.5.1",
|
||||
"@ethersproject/sha2": "^5.6.1",
|
||||
"@ethersproject/strings": "^5.6.1",
|
||||
"circomlibjs": "0.0.8"
|
||||
"poseidon-lite": "^0.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BigNumber } from "@ethersproject/bignumber"
|
||||
import { poseidon } from "circomlibjs"
|
||||
import poseidon from "poseidon-lite"
|
||||
import checkParameter from "./checkParameter"
|
||||
import { generateCommitment, genRandomNumber, isJsonArray, sha256 } from "./utils"
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { BigNumber } from "@ethersproject/bignumber"
|
||||
import { randomBytes } from "@ethersproject/random"
|
||||
import { sha256 as _sha256 } from "@ethersproject/sha2"
|
||||
import { toUtf8Bytes } from "@ethersproject/strings"
|
||||
import { poseidon } from "circomlibjs"
|
||||
import poseidon from "poseidon-lite"
|
||||
|
||||
/**
|
||||
* Returns an hexadecimal sha256 hash of the message passed as parameter.
|
||||
|
||||
@@ -67,7 +67,7 @@ yarn add @semaphore-protocol/identity @semaphore-protocol/group @semaphore-proto
|
||||
|
||||
## 📜 Usage
|
||||
|
||||
\# **generateProof**(identity: _Identity_, group: _Group_, externalNullifier: _BigNumberish_, signal: _string_, snarkArtifacts?: _SnarkArtifacts_): Promise\<_SemaphoreFullProof_>
|
||||
\# **generateProof**(identity: _Identity_, group: _Group_ | _MerkleProof_, externalNullifier: _BigNumberish_, signal: _string_, snarkArtifacts?: _SnarkArtifacts_): Promise\<_SemaphoreFullProof_>
|
||||
|
||||
```typescript
|
||||
import { Identity } from "@semaphore-protocol/identity"
|
||||
@@ -81,23 +81,21 @@ const signal = "Hello world"
|
||||
|
||||
group.addMembers([...identityCommitments, identity.generateCommitment()])
|
||||
|
||||
const fullProof = await generateProof(identity, merkleProof, externalNullifier, signal, {
|
||||
const fullProof = await generateProof(identity, group, externalNullifier, signal, {
|
||||
zkeyFilePath: "./semaphore.zkey",
|
||||
wasmFilePath: "./semaphore.wasm"
|
||||
})
|
||||
|
||||
// You can also use the default zkey/wasm files (only for browsers!).
|
||||
// const fullProof = await generateProof(identity, merkleProof, externalNullifier, signal)
|
||||
// You can also use the default zkey/wasm files (it only works from browsers!).
|
||||
// const fullProof = await generateProof(identity, group, externalNullifier, signal)
|
||||
```
|
||||
|
||||
\# **verifyProof**(verificationKey: _any_, fullProof: _FullProof_): Promise\<_boolean_>
|
||||
\# **verifyProof**(fullProof: _FullProof_, treeDepth: _number_): Promise\<_boolean_>
|
||||
|
||||
```typescript
|
||||
import { verifyProof } from "@semaphore-protocol/proof"
|
||||
|
||||
const verificationKey = JSON.parse(fs.readFileSync("/semaphore.json", "utf-8"))
|
||||
|
||||
await verifyProof(verificationKey, fullProof)
|
||||
await verifyProof(fullProof, 20)
|
||||
```
|
||||
|
||||
\# **packToSolidityProof**(proof: _Proof_): _SolidityProof_
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@semaphore-protocol/proof",
|
||||
"version": "2.6.0",
|
||||
"version": "2.6.1",
|
||||
"description": "A library to generate and verify Semaphore proofs.",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.node.js",
|
||||
@@ -30,21 +30,22 @@
|
||||
"access": "public"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-json": "^5.0.1",
|
||||
"ffjavascript": "^0.2.54",
|
||||
"rollup-plugin-cleanup": "^3.2.1",
|
||||
"rollup-plugin-typescript2": "^0.31.2",
|
||||
"typedoc": "^0.22.11"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@semaphore-protocol/group": "2.6.0",
|
||||
"@semaphore-protocol/identity": "2.6.0"
|
||||
"@semaphore-protocol/group": "2.6.1",
|
||||
"@semaphore-protocol/identity": "2.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ethersproject/bignumber": "^5.5.0",
|
||||
"@ethersproject/bytes": "^5.7.0",
|
||||
"@ethersproject/solidity": "^5.5.0",
|
||||
"@ethersproject/keccak256": "^5.7.0",
|
||||
"@ethersproject/strings": "^5.5.0",
|
||||
"@zk-kit/incremental-merkle-tree": "0.4.3",
|
||||
"circomlibjs": "0.0.8",
|
||||
"snarkjs": "^0.4.13"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import typescript from "rollup-plugin-typescript2"
|
||||
import * as fs from "fs"
|
||||
import cleanup from "rollup-plugin-cleanup"
|
||||
import json from "@rollup/plugin-json"
|
||||
|
||||
const pkg = JSON.parse(fs.readFileSync("./package.json", "utf-8"))
|
||||
const banner = `/**
|
||||
@@ -24,6 +25,7 @@ export default {
|
||||
tsconfig: "./build.tsconfig.json",
|
||||
useTsconfigDeclarationDir: true
|
||||
}),
|
||||
cleanup({ comments: "jsdoc" })
|
||||
cleanup({ comments: "jsdoc" }),
|
||||
json()
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { poseidon } from "circomlibjs"
|
||||
import { BigNumberish } from "./types"
|
||||
|
||||
/**
|
||||
* Generates a nullifier by hashing the external and the identity nullifiers.
|
||||
* @param externalNullifier The external nullifier.
|
||||
* @param identityNullifier The identity nullifier.
|
||||
* @returns The nullifier hash.
|
||||
*/
|
||||
export default function generateNullifierHash(
|
||||
externalNullifier: BigNumberish,
|
||||
identityNullifier: BigNumberish
|
||||
): bigint {
|
||||
return poseidon([BigInt(externalNullifier), BigInt(identityNullifier)])
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
import { BytesLike, Hexable } from "@ethersproject/bytes"
|
||||
import { Group } from "@semaphore-protocol/group"
|
||||
import type { Identity } from "@semaphore-protocol/identity"
|
||||
import { MerkleProof } from "@zk-kit/incremental-merkle-tree"
|
||||
import { groth16 } from "snarkjs"
|
||||
import generateSignalHash from "./generateSignalHash"
|
||||
import { BigNumberish, FullProof, SnarkArtifacts } from "./types"
|
||||
import hash from "./hash"
|
||||
import { FullProof, SnarkArtifacts } from "./types"
|
||||
|
||||
export default async function generateProof(
|
||||
{ trapdoor, nullifier, commitment }: Identity,
|
||||
groupOrMerkleProof: Group | MerkleProof,
|
||||
externalNullifier: BigNumberish,
|
||||
signal: string,
|
||||
externalNullifier: BytesLike | Hexable | number | bigint,
|
||||
signal: BytesLike | Hexable | number | bigint,
|
||||
snarkArtifacts?: SnarkArtifacts
|
||||
): Promise<FullProof> {
|
||||
let merkleProof: MerkleProof
|
||||
@@ -21,7 +22,7 @@ export default async function generateProof(
|
||||
throw new Error("The identity is not part of the group")
|
||||
}
|
||||
|
||||
merkleProof = groupOrMerkleProof.generateProofOfMembership(index)
|
||||
merkleProof = groupOrMerkleProof.generateMerkleProof(index)
|
||||
} else {
|
||||
merkleProof = groupOrMerkleProof
|
||||
}
|
||||
@@ -39,8 +40,8 @@ export default async function generateProof(
|
||||
identityNullifier: nullifier,
|
||||
treePathIndices: merkleProof.pathIndices,
|
||||
treeSiblings: merkleProof.siblings,
|
||||
externalNullifier,
|
||||
signalHash: generateSignalHash(signal)
|
||||
externalNullifier: hash(externalNullifier),
|
||||
signalHash: hash(signal)
|
||||
},
|
||||
snarkArtifacts.wasmFilePath,
|
||||
snarkArtifacts.zkeyFilePath
|
||||
@@ -49,7 +50,7 @@ export default async function generateProof(
|
||||
return {
|
||||
proof,
|
||||
publicSignals: {
|
||||
merkleRoot: publicSignals[0],
|
||||
merkleTreeRoot: publicSignals[0],
|
||||
nullifierHash: publicSignals[1],
|
||||
signalHash: publicSignals[2],
|
||||
externalNullifier: publicSignals[3]
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { isHexString } from "@ethersproject/bytes"
|
||||
import { keccak256 } from "@ethersproject/solidity"
|
||||
import { formatBytes32String } from "@ethersproject/strings"
|
||||
|
||||
/**
|
||||
* Hashes a signal string with Keccak256.
|
||||
* @param signal The Semaphore signal.
|
||||
* @returns The signal hash.
|
||||
*/
|
||||
export default function genSignalHash(signal: string): bigint {
|
||||
if (!isHexString(signal, 32)) {
|
||||
signal = formatBytes32String(signal)
|
||||
}
|
||||
|
||||
return BigInt(keccak256(["bytes32"], [signal])) >> BigInt(8)
|
||||
}
|
||||
15
packages/proof/src/hash.ts
Normal file
15
packages/proof/src/hash.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { BigNumber } from "@ethersproject/bignumber"
|
||||
import { BytesLike, Hexable, zeroPad } from "@ethersproject/bytes"
|
||||
import { keccak256 } from "@ethersproject/keccak256"
|
||||
|
||||
/**
|
||||
* Creates a keccak256 hash of a message compatible with the SNARK scalar modulus.
|
||||
* @param message The message to be hashed.
|
||||
* @returns The message digest.
|
||||
*/
|
||||
export default function hash(message: BytesLike | Hexable | number | bigint): bigint {
|
||||
message = BigNumber.from(message).toTwos(256).toHexString()
|
||||
message = zeroPad(message, 32)
|
||||
|
||||
return BigInt(keccak256(message)) >> BigInt(8)
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
import { formatBytes32String } from "@ethersproject/strings"
|
||||
import { Group } from "@semaphore-protocol/group"
|
||||
import { Identity } from "@semaphore-protocol/identity"
|
||||
import { getCurveFromName } from "ffjavascript"
|
||||
import fs from "fs"
|
||||
import generateNullifierHash from "./generateNullifierHash"
|
||||
import generateProof from "./generateProof"
|
||||
import generateSignalHash from "./generateSignalHash"
|
||||
import hash from "./hash"
|
||||
import packToSolidityProof from "./packToSolidityProof"
|
||||
import { FullProof } from "./types"
|
||||
import verifyProof from "./verifyProof"
|
||||
@@ -13,12 +10,11 @@ import verifyProof from "./verifyProof"
|
||||
describe("Proof", () => {
|
||||
const treeDepth = Number(process.env.TREE_DEPTH) || 20
|
||||
|
||||
const externalNullifier = "1"
|
||||
const signal = "0x111"
|
||||
const externalNullifier = 1
|
||||
const signal = 2
|
||||
|
||||
const wasmFilePath = `./snark-artifacts/semaphore.wasm`
|
||||
const zkeyFilePath = `./snark-artifacts/semaphore.zkey`
|
||||
const verificationKeyPath = `./snark-artifacts/semaphore.json`
|
||||
const wasmFilePath = `./snark-artifacts/${treeDepth}/semaphore.wasm`
|
||||
const zkeyFilePath = `./snark-artifacts/${treeDepth}/semaphore.zkey`
|
||||
|
||||
const identity = new Identity()
|
||||
|
||||
@@ -69,45 +65,79 @@ describe("Proof", () => {
|
||||
})
|
||||
|
||||
expect(typeof fullProof).toBe("object")
|
||||
expect(fullProof.publicSignals.externalNullifier).toBe(externalNullifier)
|
||||
expect(fullProof.publicSignals.merkleRoot).toBe(group.root.toString())
|
||||
expect(fullProof.publicSignals.merkleTreeRoot).toBe(group.root.toString())
|
||||
}, 20000)
|
||||
|
||||
it("Should generate a Semaphore proof passing a Merkle proof as parametr", async () => {
|
||||
it("Should generate a Semaphore proof passing a Merkle proof as parameter", async () => {
|
||||
const group = new Group(treeDepth)
|
||||
|
||||
group.addMembers([BigInt(1), BigInt(2), identity.commitment])
|
||||
|
||||
fullProof = await generateProof(identity, group.generateProofOfMembership(2), externalNullifier, signal, {
|
||||
fullProof = await generateProof(identity, group.generateMerkleProof(2), externalNullifier, signal, {
|
||||
wasmFilePath,
|
||||
zkeyFilePath
|
||||
})
|
||||
|
||||
expect(typeof fullProof).toBe("object")
|
||||
expect(fullProof.publicSignals.externalNullifier).toBe(externalNullifier)
|
||||
expect(fullProof.publicSignals.merkleRoot).toBe(group.root.toString())
|
||||
expect(fullProof.publicSignals.merkleTreeRoot).toBe(group.root.toString())
|
||||
}, 20000)
|
||||
})
|
||||
|
||||
describe("# generateSignalHash", () => {
|
||||
it("Should generate a valid signal hash", async () => {
|
||||
const signalHash = generateSignalHash(signal)
|
||||
describe("# verifyProof", () => {
|
||||
it("Should not verify a proof if the tree depth is wrong", () => {
|
||||
const fun = () => verifyProof(fullProof, 3)
|
||||
|
||||
expect(signalHash.toString()).toBe(fullProof.publicSignals.signalHash)
|
||||
expect(fun).toThrow("The tree depth must be a number between 16 and 32")
|
||||
})
|
||||
|
||||
it("Should generate a valid signal hash by passing a valid hex string", async () => {
|
||||
const signalHash = generateSignalHash(formatBytes32String(signal))
|
||||
it("Should verify a Semaphore proof", async () => {
|
||||
const response = await verifyProof(fullProof, treeDepth)
|
||||
|
||||
expect(signalHash.toString()).toBe(fullProof.publicSignals.signalHash)
|
||||
expect(response).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("# generateNullifierHash", () => {
|
||||
it("Should generate a valid nullifier hash", async () => {
|
||||
const nullifierHash = generateNullifierHash(externalNullifier, identity.getNullifier())
|
||||
describe("# hash", () => {
|
||||
it("Should hash the signal value correctly", async () => {
|
||||
const signalHash = hash(signal)
|
||||
|
||||
expect(nullifierHash.toString()).toBe(fullProof.publicSignals.nullifierHash)
|
||||
expect(signalHash.toString()).toBe(fullProof.publicSignals.signalHash)
|
||||
})
|
||||
|
||||
it("Should hash the external nullifier value correctly", async () => {
|
||||
const externalNullifierHash = hash(externalNullifier)
|
||||
|
||||
expect(externalNullifierHash.toString()).toBe(fullProof.publicSignals.externalNullifier)
|
||||
})
|
||||
|
||||
it("Should hash a number", async () => {
|
||||
expect(hash(2).toString()).toBe(
|
||||
"113682330006535319932160121224458771213356533826860247409332700812532759386"
|
||||
)
|
||||
})
|
||||
|
||||
it("Should hash a big number", async () => {
|
||||
expect(hash(BigInt(2)).toString()).toBe(
|
||||
"113682330006535319932160121224458771213356533826860247409332700812532759386"
|
||||
)
|
||||
})
|
||||
|
||||
it("Should hash an hex number", async () => {
|
||||
expect(hash("0x2").toString()).toBe(
|
||||
"113682330006535319932160121224458771213356533826860247409332700812532759386"
|
||||
)
|
||||
})
|
||||
|
||||
it("Should hash an string number", async () => {
|
||||
expect(hash("2").toString()).toBe(
|
||||
"113682330006535319932160121224458771213356533826860247409332700812532759386"
|
||||
)
|
||||
})
|
||||
|
||||
it("Should hash an array", async () => {
|
||||
expect(hash([2]).toString()).toBe(
|
||||
"113682330006535319932160121224458771213356533826860247409332700812532759386"
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -118,14 +148,4 @@ describe("Proof", () => {
|
||||
expect(solidityProof).toHaveLength(8)
|
||||
})
|
||||
})
|
||||
|
||||
describe("# verifyProof", () => {
|
||||
it("Should generate and verify a Semaphore proof", async () => {
|
||||
const verificationKey = JSON.parse(fs.readFileSync(verificationKeyPath, "utf-8"))
|
||||
|
||||
const response = await verifyProof(verificationKey, fullProof)
|
||||
|
||||
expect(response).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import generateNullifierHash from "./generateNullifierHash"
|
||||
import generateProof from "./generateProof"
|
||||
import verifyProof from "./verifyProof"
|
||||
import generateSignalHash from "./generateSignalHash"
|
||||
import packToSolidityProof from "./packToSolidityProof"
|
||||
|
||||
export { generateNullifierHash, generateProof, verifyProof, generateSignalHash, packToSolidityProof }
|
||||
export { generateProof, verifyProof, packToSolidityProof }
|
||||
export * from "./types"
|
||||
|
||||
@@ -19,7 +19,7 @@ export type FullProof = {
|
||||
}
|
||||
|
||||
export type PublicSignals = {
|
||||
merkleRoot: BigNumberish
|
||||
merkleTreeRoot: BigNumberish
|
||||
nullifierHash: BigNumberish
|
||||
signalHash: BigNumberish
|
||||
externalNullifier: BigNumberish
|
||||
|
||||
712
packages/proof/src/verificationKeys.json
Normal file
712
packages/proof/src/verificationKeys.json
Normal file
@@ -0,0 +1,712 @@
|
||||
{
|
||||
"protocol": "groth16",
|
||||
"curve": "bn128",
|
||||
"nPublic": 4,
|
||||
"vk_alpha_1": [
|
||||
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
|
||||
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
|
||||
"1"
|
||||
],
|
||||
"vk_beta_2": [
|
||||
[
|
||||
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
|
||||
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
|
||||
],
|
||||
[
|
||||
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
|
||||
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
"vk_gamma_2": [
|
||||
[
|
||||
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
||||
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
||||
],
|
||||
[
|
||||
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
||||
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
"vk_delta_2": [
|
||||
[
|
||||
[
|
||||
"16243966861079634958125511652590761846958471358623040426599000904006426210032",
|
||||
"13406811599156507528361773763681356312643537981039994686313383243831956396116"
|
||||
],
|
||||
[
|
||||
"15688083679237922164673518758181461582601853873216319711156397437601833996222",
|
||||
"11781596534582143578120404722739278517564025497573071755253972265891888117374"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"13589689305661231568162336263197960570915890299814486885851912452076929115480",
|
||||
"15629200772768268814959330350023920183087521275477047626405113853190187031523"
|
||||
],
|
||||
[
|
||||
"16004221700357242255845535848024178544616388017965468694776181247983831995562",
|
||||
"11464919285924930973853174493551975632739604254498590354200272115844983493029"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"19717684456458906358368865507225121991585492363133107109865920739019288468011",
|
||||
"9218320951536642499143228327011901814587826948504871816273184688188019956292"
|
||||
],
|
||||
[
|
||||
"18221695645112467945186983098720611586049108689347006136423489099202471884089",
|
||||
"16717590750910963405756115910371408378114896008824240863060392362901176601412"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"15953239752392927777442331623182226063776310198012173504208557434319753428770",
|
||||
"3995128789564535587814512245259203300137618476815456454931286633947953135662"
|
||||
],
|
||||
[
|
||||
"2523786679709693946058523307330825034772478122295850507521258983130425334580",
|
||||
"20957319343912866335583737646657534123362052690050674068142580221965936605075"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"1382518990777992893805140303684642328066746531257780279226677247567004248173",
|
||||
"18976133691706015337908381757202123182841901611067930614519324084182946094218"
|
||||
],
|
||||
[
|
||||
"21806956747910197517744499423107239699428979652113081469385876768212706694581",
|
||||
"6627710380771660558660627878547223719795356903257079198333641681330388499309"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"9032545080831535702239063467087720597970266046938395860207839433937324718536",
|
||||
"3811592683283527904145155808200366192489850711742363953668998371801696238057"
|
||||
],
|
||||
[
|
||||
"12429982191499850873612518410809641163252887523090441166572590809691267943605",
|
||||
"16308433125974933290258540904373317426123214107276055539769464205982500660715"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"17626503110323089701269363177710295379967225765713250625279671011873619640598",
|
||||
"9485639152672984144988597737758037391807993615552051606205480347442429414340"
|
||||
],
|
||||
[
|
||||
"18953587685067712486092665232725058638563458484886448540567142557894080640927",
|
||||
"12391874700409435648975069978280047983726144854114915177376036190441913967689"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"11408965575174993375815840422438995549652812400401163392501956884932167624437",
|
||||
"9830856103389248449121962275587399130605902703453384856543071762984116567573"
|
||||
],
|
||||
[
|
||||
"19969543376625663966419118899515353499678204573709836615846115182224340858492",
|
||||
"11814906841949499037550820576929552248172160643991870665022770052632331265834"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"10090041889587324002759549286390619541526396451963494627957072069124011137562",
|
||||
"15035335306919942325459417688135340085377315274625768597233474641923619728582"
|
||||
],
|
||||
[
|
||||
"10507786999799841055999967456762679569286329319056926475375760604262707147294",
|
||||
"21342049717074059749518233491526445388158772701642182532370641230478027030319"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"43456740675249348549891878341522275183186932745162972528932808393415299552",
|
||||
"15718373132479769904443326381037437528372212185108294117696143473979328398658"
|
||||
],
|
||||
[
|
||||
"4289247401578837038775845192875793775418122783738936298355403103074020081838",
|
||||
"11236864934894600819960883124570686936554376109344998527334431594565774237827"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"4023016874169005249382064394379671330447496454371261692205411970999350949293",
|
||||
"1723458149089715907994189658689343304709709060535625667210252753337752162173"
|
||||
],
|
||||
[
|
||||
"17710652158212212080502343565075513548898593397103675832636832371532093744857",
|
||||
"7651670126664625790835334090273463062538865895183205964669372719235003083565"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"13132169670125192016391258838554965176628317453468870968867717287446623320643",
|
||||
"745924679191739894055143748466112994378439645681039136007774787076115375124"
|
||||
],
|
||||
[
|
||||
"20909608709868730010029182074820840312550443752829480953667886902663547957991",
|
||||
"2126777833939378028304266129616145667925849332481755567268747182629795296580"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"16835654219229187428071649241190746119082269636345872682107941472241044260584",
|
||||
"4553625243522856553165922942982108474187282402890756796515747778282922584601"
|
||||
],
|
||||
[
|
||||
"873742823867191038535544062852920538566418819521732785500614249239215175476",
|
||||
"3272293478534046729728233267765357195255129499603632413158978822084188871854"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"7601443214415704135008588588192028557655441716696726549510699770097979655628",
|
||||
"7252337675475138150830402909353772156046809729627064992143762325769537840623"
|
||||
],
|
||||
[
|
||||
"18500126298578278987997086114400065402270866280547473913420536595663876273004",
|
||||
"436607343827794507835462908831699962173244647704538949914686722631806931932"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"15028154694713144242204861571552635520290993855826554325002991692907421516918",
|
||||
"10202326166286888893675634318107715186834588694714750762952081034135561546271"
|
||||
],
|
||||
[
|
||||
"12766289885372833812620582632847872978085960777075662988932200910695848591357",
|
||||
"18486039841380105976272577521609866666900576498507352937328726490052296469859"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"13682963731073238132274278610660469286329368216526659590944079211949686450402",
|
||||
"14930624777162656776068112402283260602512252179767747308433194885322661150422"
|
||||
],
|
||||
[
|
||||
"21315724107376627085778492378001676935454590984229146391746301404292016287653",
|
||||
"18705481657148807016785305378773304476425591636333098330324049960258682574070"
|
||||
],
|
||||
["1", "0"]
|
||||
],
|
||||
[
|
||||
[
|
||||
"18994803742708336446369128568423705404354655742604689352630273180469431952708",
|
||||
"12315240965742683516581565369496371929586281338862761742109651525191835544242"
|
||||
],
|
||||
[
|
||||
"12707009780301102830224094192984906206920666691015255692741008594808694787917",
|
||||
"18019403342409608922812569436317484250134945386869657285229378095251425778096"
|
||||
],
|
||||
["1", "0"]
|
||||
]
|
||||
],
|
||||
"vk_alphabeta_12": [
|
||||
[
|
||||
[
|
||||
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
|
||||
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
|
||||
],
|
||||
[
|
||||
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
|
||||
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
|
||||
],
|
||||
[
|
||||
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
|
||||
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
|
||||
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
|
||||
],
|
||||
[
|
||||
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
|
||||
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
|
||||
],
|
||||
[
|
||||
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
|
||||
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
|
||||
]
|
||||
]
|
||||
],
|
||||
"IC": [
|
||||
[
|
||||
[
|
||||
"1964404930528116823793003656764176108669615750422202377358993070935069307720",
|
||||
"2137714996673694828207437580381836490878070731768805974506391024595988817424",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19568893707760843340848992184233194433177372925415116053368211122719346671126",
|
||||
"11639469568629189918046964192305250472192697612201524135560178632824282818614",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"5317268879687484957437879782519918549127939892210247573193613900261494313825",
|
||||
"528174394975085006443543773707702838726735933116136102590448357278717993744",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"14865918005176722116473730206622066845866539143554731094374354951675249722731",
|
||||
"3197770568483953664363740385883457803041685902965668289308665954510373380344",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6863358721495494421022713667808247652425178970453300712435830652679038918987",
|
||||
"15025816433373311798308762709072064417001390853103872064614174594927359131281",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"17789438292552571310739605737896030466581277887660997531707911256058650850910",
|
||||
"4112657509505371631825493224748310061184972897405589115208158208294581472016",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3322052920119834475842380240689494113984887785733316517680891208549118967155",
|
||||
"381029395779795399840019487059126246243641886087320875571067736504031557148",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8777645223617381095463415690983421308854368583891690388850387317049320450400",
|
||||
"11923582117369144413749726090967341613266070909169947059497952692052020331958",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15493263571528401950994933073246603557158047091963487223668240334879173885581",
|
||||
"6315532173951617115856055775098532808695228294437279844344466163873167020700",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3481637421055377106140197938175958155334313900824697193932986771017625492245",
|
||||
"20088416136090515091300914661950097694450984520235647990572441134215240947932",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"4691595252082380256698158158199364410440273386659834000993210659508747323919",
|
||||
"9205801980459323513061837717352821162780471027241700646145937351740096374660",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16150531426263112884093068164597994126623437929929609532055221646496813246000",
|
||||
"20245743178241899668170758952526381872637304119026868520579207157118516761827",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6063536446992770713985314309889717594240410784717230886576072989709763902848",
|
||||
"18258781411255795973918859665416013869184055573057512603788635470145328981347",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"10109932964756104512054045207253535333686585863745296080906925765480296575285",
|
||||
"4174640428253153601540284363759502713687021920150940723252842152556151210349",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"18049428534741480832385046397049175120355008065781483226058177421025493210952",
|
||||
"591730261265040164434889324846001338201068482543108348317417391345612814922",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"9877211178693075145402462781884120278654771727348087433632224794894486095150",
|
||||
"19972682062587174829535281061580296764150591339640180868104711395548066529340",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6324578424031095537345184040149690238371517387586958921377481904541316423724",
|
||||
"15513931720576048544404512239839508014664224085062729779520992909505663748296",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11371337652479737143800707796204655130812036287859296372695832558127430723628",
|
||||
"11757275188600040111649009832378343123994225623498773406233261322165903848967",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"13282496583564708104981015168203451877588903263486398132954741568835583461335",
|
||||
"1746144324840370907926720490289700342734912534857331743685374514401176014195",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"7993952462467372951144011615584426050192046712674662254138390197508963352374",
|
||||
"5156942148925224345709309361345680948125600198010285179548841917923439945819",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"19918517214839406678907482305035208173510172567546071380302965459737278553528",
|
||||
"7151186077716310064777520690144511885696297127165278362082219441732663131220",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"690581125971423619528508316402701520070153774868732534279095503611995849608",
|
||||
"21271996888576045810415843612869789314680408477068973024786458305950370465558",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16461282535702132833442937829027913110152135149151199860671943445720775371319",
|
||||
"2814052162479976678403678512565563275428791320557060777323643795017729081887",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"4319780315499060392574138782191013129592543766464046592208884866569377437627",
|
||||
"13920930439395002698339449999482247728129484070642079851312682993555105218086",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3554830803181375418665292545416227334138838284686406179598687755626325482686",
|
||||
"5951609174746846070367113593675211691311013364421437923470787371738135276998",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"9494885690931955877467315318223108618392113101843890678090902614660136056680",
|
||||
"11783514256715757384821021009301806722951917744219075907912683963173706887379",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"7562082660623781416745328104576133910743071878837764423695105915778139873834",
|
||||
"17954307004260053757579194018551114133664721761483240877658498973152950708099",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19338184851116432029108109461622579541195083625346674255186169347975445785058",
|
||||
"38361206266360048012365562393026952048730052530888439195454086987795985927",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"21178537742782571863590222710872928190886000600239072595684369348717288330049",
|
||||
"9786438258541172244884631831247223050494423968411444302812755467521949734320",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11330504221972341797183339350494223413034293674225690456356444509688810101433",
|
||||
"1490009915387901405464437253469086864085891770312035292355706249426866485365",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"21791720972262589799021600767292883644106575897307484548888696814333235336885",
|
||||
"11092962469758788187888592619035811117815082357439060720677582048880121542623",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"9418924955930663972575130074928583215922927562059194231976193350658171304436",
|
||||
"16113558481826020406162261319744796072664750077095575593106901121115073101408",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"20054934960262983176880675919444457578562219675808407582143519621873973120773",
|
||||
"14877415271301547911435683263206245199959943680225555496786470669330176961657",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"4215199263810110748751715719957184804379752373072771007598572158043965517488",
|
||||
"5225943468606602818132879686778547605180105897615251160509064537462109826521",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6250242626034734280813142093008675407723196706248829741247204621913994561803",
|
||||
"1472231555266678689888727724824566171966416459791722465278225775922487343641",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"3047486363455933831148688762823238723024952519326207356549121929667745957778",
|
||||
"20241836359289449005887237560564358543646542598344362915541027571505243817211",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"5965631918800530319167124148627450454569264331058008407732200168631989208657",
|
||||
"20463557477532480934514091877628554948892025887087712764683631108388998871350",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16605042322692983282732511249912403956057999815658038166796858627082222971215",
|
||||
"12219061498275616585164456833410962809536084885494309093787669879221959361956",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1548998572074037722622224303222294716243074837074272552644853986075252666508",
|
||||
"10393312002885367652301897874262367916506364670364584602554176742602334134772",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16180907689593358346406392015123900260925622357393826746385511046141256905390",
|
||||
"12267326749885120640972074479210537480053065569337817484467225562817467244765",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"19590996174696909242575628014943555633938195923520472786993379268302478708283",
|
||||
"2673753072556442230312995111304911178679525806396134504594492458566941824354",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"13411253172375451489380472831999887223592471057462692619008484995624281735092",
|
||||
"17181767455563581254432161119660408482332423481128600038352147258951772423229",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19138864631164378176055647711995352935065134904103255748190268290992108588628",
|
||||
"14282526277736365863821375748687709839392307698935143595732632710176778519757",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"20183773658676161990469276414858234178608794783112866811307579993999118293429",
|
||||
"5223464433544489066271184294750886227362580875255044558831927430970236355539",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"12333466991139269670298178539679773509487545471126920233507132846828588847444",
|
||||
"3787586478923104354547687861486563468235879611952775292288436085429794222238",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"18580370382199518848261939652153768394883698461842792002922164533882262019935",
|
||||
"20516185953882700254387267244708111605796661864845495645678049276372075842359",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"20041291712709610738573661974551517833120775539593003477018637287434210072702",
|
||||
"6326630253906616820412999166182553773360987412889775567442543181359104720511",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"13268971611130152315428629919012388924225656285593904211561391821918930327614",
|
||||
"9247437189452353488017802041158840512956111558640958728149597697508914590433",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6267384495557139339708615182113725421733376438932580472141549274050146739549",
|
||||
"1832264154031452148715318442722960696977572389206897240030908464579133134237",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16650684165487873559901140599157559153018449083939294496255590830891994564285",
|
||||
"14140282729498011406186082176268025578697081678243955538935501306868500498994",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"4247947150009812467217672970806328247513830308400387953244764907353849211641",
|
||||
"14500381439127180474801393438175928191199696177607750163263715436006533630877",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"21213779524495874664157797605662894019112036728653622806607467354233012380232",
|
||||
"1429370857470083395421401524518861545167550347090873730934256398864585069083",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"12465277751642747637430517396067173985821959773399832969105187923427872239200",
|
||||
"4377704428607835904642653580543541241155601291484645500691968624389522190030",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11283027832501128633761619552392013253304972822086786857121687098087331014745",
|
||||
"21463394238922953607096052056881931791797740737164052798044623278557203313720",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19687293493101130967741578773742597470558958652351513582962108464055656171331",
|
||||
"4445165696525061401582979300506082669540223774145877762689724631935313716632",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"3388767735894417381503201756905214431625081913405504580464345986403824999889",
|
||||
"21014112837214011009096825602791072748195337199912773858499588477762724153070",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"10521317016331497094903116740581271122844131442882845700567581775404872949272",
|
||||
"13201921794561774338466680421903602920184688290946713194187958007088351657367",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16170260722059932609965743383032703380650557609693540121262881902248073364496",
|
||||
"6004983491336500911294872035126141746032033211872472427212274143945425740617",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"10275615677574391293596971122111363003313434841806630200532546038183081960924",
|
||||
"5955568702561336410725734958627459212680756023420452791680213386065159525989",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19059081014385850734732058652137664919364805650872154944590269874395511868415",
|
||||
"19202365837673729366500417038229950532560250566916189579621883380623278182155",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"7856986171681248404396064225772749784181602218562773063185003409958949630985",
|
||||
"11707218736744382138692483591389641607570557654489363179025201039696228471230",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2902255937308264958973169948617099471543255757887963647238093192858290079050",
|
||||
"4092153880227661899721872164083575597602963673456107552146583620177664115673",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"18380478859138320895837407377103009470968863533040661874531861881638854174636",
|
||||
"14502773952184441371657781525836310753176308880224816843041318743809785835984",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2781117248053224106149213822307598926495461873135153638774638501111353469325",
|
||||
"3500056595279027698683405880585654897391289317486204483344715855049598477604",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8880120765926282932795149634761705738498809569874317407549203808931092257005",
|
||||
"19080036326648068547894941015038877788526324720587349784852594495705578761000",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"18427701611614193839908361166447988195308352665132182219164437649866377475111",
|
||||
"5299493942596042045861137432338955179078182570752746487573709678936617478454",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"4188155714164125069834512529839479682516489319499446390214266838952761728656",
|
||||
"2720966082507704094346897998659841489771837229143573083003847010258396944787",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"13256461570028177373135283778770729308216900804505379897951455548375840027026",
|
||||
"10722074030307391322177899534114921764931623271723882054692012663305322382747",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"9824147497244652955949696442395586567974424828238608972020527958186701134273",
|
||||
"15755269950882650791869946186461432242513999576056199368058858215068920022191",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"21172488506061181949536573476893375313339715931330476837156243346077173297265",
|
||||
"13892434487977776248366965108031841947713544939953824768291380177301871559945",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"1452272927738590248356371174422184656932731110936062990115610832462181634644",
|
||||
"3608050114233210789542189629343107890943266759827387991788718454179833288695",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"14798240452388909327945424685903532333765637883272751382037716636327236955001",
|
||||
"10773894897711848209682368488916121016695006898681985691467605219098835500201",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"17204267933132009093604099819536245144503489322639121825381131096467570698650",
|
||||
"7704298975420304156332734115679983371345754866278811368869074990486717531131",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8060465662017324080560848316478407038163145149983639907596180500095598669247",
|
||||
"20475082166427284188002500222093571716651248980245637602667562336751029856573",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"7457566682692308112726332096733260585025339741083447785327706250123165087868",
|
||||
"11904519443874922292602150685069370036383697877657723976244907400392778002614",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"12628427235010608529869146871556870477182704310235373946877240509680742038961",
|
||||
"15093298104438768585559335868663959710321348106117735180051519837845319121254",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6593907467779318957599440584793099005109789224774644007604434924706249001015",
|
||||
"18549596630007199540674697114946251030815675677713256327810772799104711621483",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6271101737045248834759003849256661059806617144229427987717476992610974162336",
|
||||
"355748132218964841305454070022507122319085542484477110563322753565651576458",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2116139772133141967317791473319540620104888687412078412336248003979594158546",
|
||||
"4004400204967325849492155713520296687406035356901102254880522534085890616486",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"4206647028595764233995379982714022410660284578620723510907006350595207905228",
|
||||
"19380634286337609988098517090003334645113675227742745065381519159322795845003",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"2592407181901686208061988776764501828311271519595797153264758207470081204331",
|
||||
"11847594161160074962679125411562687287595382335410213641115001866587988494499",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3346927026869562921166545684451290646273836362895645367665514203662899621366",
|
||||
"15758185693543979820528128025093553492246135914029575732836221618882836493143",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"20528686657810499188368147206002308531447185877994439397529705707372170337045",
|
||||
"18025396678079701612906003769476076600196287001844168390936182972248852818155",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"9799815250059685769827017947834627563597884023490186073806184882963949644596",
|
||||
"4998495094322372762314630336611134866447406022687118703953312157819349892603",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16176535527670849161173306151058200762642157343823553073439957507563856439772",
|
||||
"21877331533292960470552563236986670222564955589137303622102707801351340670855",
|
||||
"1"
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -1,17 +1,28 @@
|
||||
import { groth16 } from "snarkjs"
|
||||
import { FullProof } from "./types"
|
||||
import verificationKeys from "./verificationKeys.json"
|
||||
|
||||
/**
|
||||
* Verifies a SnarkJS proof.
|
||||
* @param verificationKey The zero-knowledge verification key.
|
||||
* @param fullProof The SnarkJS full proof.
|
||||
* @param treeDepth The Merkle tree depth.
|
||||
* @returns True if the proof is valid, false otherwise.
|
||||
*/
|
||||
export default function verifyProof(verificationKey: any, { proof, publicSignals }: FullProof): Promise<boolean> {
|
||||
export default function verifyProof({ proof, publicSignals }: FullProof, treeDepth: number): Promise<boolean> {
|
||||
if (treeDepth < 16 || treeDepth > 32) {
|
||||
throw new TypeError("The tree depth must be a number between 16 and 32")
|
||||
}
|
||||
|
||||
const verificationKey = {
|
||||
...verificationKeys,
|
||||
vk_delta_2: verificationKeys.vk_delta_2[treeDepth - 16],
|
||||
IC: verificationKeys.IC[treeDepth - 16]
|
||||
}
|
||||
|
||||
return groth16.verify(
|
||||
verificationKey,
|
||||
[
|
||||
publicSignals.merkleRoot,
|
||||
publicSignals.merkleTreeRoot,
|
||||
publicSignals.nullifierHash,
|
||||
publicSignals.signalHash,
|
||||
publicSignals.externalNullifier
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@semaphore-protocol/subgraph",
|
||||
"version": "2.6.0",
|
||||
"version": "2.6.1",
|
||||
"description": "A library to query Semaphore contracts.",
|
||||
"license": "MIT",
|
||||
"iife": "dist/index.js",
|
||||
|
||||
@@ -8,8 +8,9 @@ import { Network } from "./types"
|
||||
export default function getURL(network: Network): string {
|
||||
switch (network) {
|
||||
case "goerli":
|
||||
return `https://api.thegraph.com/subgraphs/name/semaphore-protocol/goerli-5259d3`
|
||||
case "arbitrum":
|
||||
return `https://api.thegraph.com/subgraphs/name/semaphore-protocol/${network}`
|
||||
return `https://api.thegraph.com/subgraphs/name/semaphore-protocol/arbitrum-86337c`
|
||||
default:
|
||||
throw new TypeError(`Network '${network}' is not supported`)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import dotenv from "dotenv"
|
||||
import download from "download"
|
||||
import fs from "fs"
|
||||
|
||||
dotenv.config()
|
||||
|
||||
async function main() {
|
||||
const snarkArtifactsPath = "./snark-artifacts"
|
||||
const url = `https://www.trusted-setup-pse.org/semaphore/${process.env.TREE_DEPTH || 20}`
|
||||
|
||||
if (!fs.existsSync(snarkArtifactsPath)) {
|
||||
fs.mkdirSync(snarkArtifactsPath, { recursive: true })
|
||||
}
|
||||
if (process.env.ALL_SNARK_ARTIFACTS === "true") {
|
||||
const url = `https://www.trusted-setup-pse.org/semaphore/semaphore.zip`
|
||||
|
||||
if (!fs.existsSync(`${snarkArtifactsPath}/semaphore.zkey`)) {
|
||||
await download(`${url}/semaphore.wasm`, snarkArtifactsPath)
|
||||
await download(`${url}/semaphore.zkey`, snarkArtifactsPath)
|
||||
await download(`${url}/semaphore.json`, snarkArtifactsPath)
|
||||
await download(url, snarkArtifactsPath, {
|
||||
extract: true
|
||||
})
|
||||
} else {
|
||||
const treeDepth = process.env.TREE_DEPTH || 20
|
||||
const url = `https://www.trusted-setup-pse.org/semaphore/${treeDepth}`
|
||||
|
||||
await download(`${url}/semaphore.wasm`, `${snarkArtifactsPath}/${treeDepth}`)
|
||||
await download(`${url}/semaphore.zkey`, `${snarkArtifactsPath}/${treeDepth}`)
|
||||
await download(`${url}/semaphore.json`, `${snarkArtifactsPath}/${treeDepth}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
8276b0b79cbaeb8dc05901c868cfb7500ea1dc1f
|
||||
d5e764e1df1ee8a4de266237c73e44074450106d
|
||||
Reference in New Issue
Block a user