Compare commits

...

34 Commits

Author SHA1 Message Date
cedoor
3188d3dbff Merge pull request #180 from semaphore-protocol/refactor/group-id
No SNARK restrictions for Group IDs

Former-commit-id: 27320f1723
2022-11-28 15:52:49 +01:00
cedoor
04f57db7f0 refactor(contracts): remove snark field check for group id values
Former-commit-id: c15145da2c
2022-11-28 15:31:04 +01:00
cedoor
066f38c471 chore: add license to contracts package
Former-commit-id: 0f24c01ff1
2022-11-23 13:04:38 +01:00
cedoor
37e8784471 docs(circuits): add readme file
Former-commit-id: 9cd0144734
2022-11-23 13:03:46 +01:00
cedoor
889cf1890a Merge pull request #173 from semaphore-protocol/chore/poseidon-lite
New Poseidon library

Former-commit-id: 8081766843
2022-11-23 12:00:17 +01:00
cedoor
1a4a7f36e0 chore: replace circomlibjs with poseidon-lite
Former-commit-id: df6ce176cb
2022-11-23 11:32:48 +01:00
cedoor
3d6c24a51b Merge pull request #170 from semaphore-protocol/refactor/normalize-signals
New hash function to normalize signal & external nullifier

Former-commit-id: 23fb94fd65
2022-11-22 15:25:07 +01:00
cedoor
781922436e refactor: create hash function to normalize snark signals
Former-commit-id: 7f872bcd92
2022-11-22 15:12:29 +01:00
cedoor
277a790e36 Merge pull request #168 from semaphore-protocol/refactor/hardcode-verification-keys
Hardcoded snark verification keys

Former-commit-id: 901531b062
2022-11-21 13:32:46 +01:00
cedoor
d880925604 refactor(proof): move zk verification keys to the code
Former-commit-id: 26d1c5153e
2022-11-21 13:16:56 +01:00
cedoor
5466178f40 Merge pull request #167 from semaphore-protocol/fix/merkle-root-creation-dates
Merkle roots for any tree update

Former-commit-id: 583311fc03
2022-11-20 19:58:22 +01:00
cedoor
6cc4dc07bb Merge pull request #166 from semaphore-protocol/refactor/semaphore-verifier
One Verifier to rule them all

Former-commit-id: 7061785fa0
2022-11-20 19:54:53 +01:00
cedoor
98a35c0a37 fix(contracts): save merkle roots after updates or removal of members
Former-commit-id: be4165afa5
2022-11-18 20:04:39 +01:00
cedoor
bfeb24791d chore(contracts): fix lint warnings
Former-commit-id: 22c7ec8bb3
2022-11-18 19:28:49 +01:00
cedoor
37e2614ac7 style: format code with prettier
Former-commit-id: 6f73de2daf
2022-11-18 17:42:02 +01:00
cedoor
84bb9c89a4 chore: add folder to ignore
Former-commit-id: 975aba3d7a
2022-11-18 17:41:38 +01:00
cedoor
a4aaf7f7ec fix: download snark artifacts in the right folder
Former-commit-id: ecd586a757
2022-11-18 16:36:13 +01:00
cedoor
b92a6e1c7a refactor(proof): update snark artifacts path
Former-commit-id: ec7f605551
2022-11-18 16:35:32 +01:00
cedoor
3afae28e06 refactor: remove unused solidity interface
Former-commit-id: 4f964c9d7f
2022-11-18 16:35:02 +01:00
cedoor
63cddf3da2 chore: add contracts files to ignore
Former-commit-id: eecc8fe97f
2022-11-18 16:34:38 +01:00
cedoor
499ec1cbeb refactor(contracts): replace old verifiers with a single semaphore verifier
Former-commit-id: 56ecb4a2a7
2022-11-18 16:33:58 +01:00
cedoor
fb1ffee89d ci: replace snark-artifacts folder for each download
Former-commit-id: 92d70e1050
2022-11-18 16:18:50 +01:00
cedoor
f7bc7900e0 ci: add env variables to workflows
Former-commit-id: 2ec07b4b99
2022-11-18 16:13:51 +01:00
cedoor
bc14210bc7 chore: add env var to download all snark artifacts
Former-commit-id: 8f269ecafc
2022-11-18 16:13:25 +01:00
cedoor
aabad94a81 Merge pull request #164 from semaphore-protocol/refactor/extension-contracts
Remove modifiers from proof verification functions

Former-commit-id: ba149545f2
2022-11-09 15:34:23 +01:00
cedoor
eeac211c01 refactor(contracts): remove modifier from proof verification functions
Former-commit-id: 99a358ca12
2022-11-09 15:13:12 +01:00
cedoor
6e0236e9bc Merge pull request #163 from semaphore-protocol/refactor/merkle-tree-attributes
Public `merkleTree` attribute and new method name

Former-commit-id: cf9f804651
2022-11-09 12:43:24 +01:00
cedoor
a9f8379545 refactor(groups): make attribute public and update method name
Former-commit-id: 822561a015
2022-11-09 12:29:58 +01:00
cedoor
ac3e7b42a3 chore: v2.6.1
Former-commit-id: ec5c69a795
2022-10-26 16:31:48 +02:00
cedoor
2b414f8c24 fix: set correct thegraph api urls
Former-commit-id: 29ebbe3b09
2022-10-26 16:28:26 +02:00
cedoor
1fcff83c1a style: format code with prettier
Former-commit-id: a5f1d80d84
2022-10-26 16:16:37 +02:00
cedoor
eb2d6ee62b chore: update arbitrum contract addresses
Former-commit-id: 6a60f727b8
2022-10-26 16:14:38 +02:00
cedoor
db624c24e0 style: format code with prettier
Former-commit-id: 9564ad19f0
2022-10-24 12:28:19 +02:00
cedoor
95e5ff669b chore: update goerli contract addresses
Former-commit-id: 88f44c3f49
2022-10-24 12:13:19 +02:00
81 changed files with 1573 additions and 4646 deletions

View File

@@ -1,5 +1,6 @@
DEFAULT_NETWORK=hardhat
TREE_DEPTH=20
ALL_SNARK_ARTIFACTS=true
REPORT_GAS=false
BACKEND_PRIVATE_KEY=
INFURA_API_KEY=

View File

@@ -5,6 +5,10 @@ on:
branches:
- main
env:
TREE_DEPTH: 20
ALL_SNARK_ARTIFACTS: false
jobs:
style:
runs-on: ubuntu-latest

View File

@@ -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
View File

@@ -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

View File

@@ -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

View File

@@ -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",

View 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>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://github.com/semaphore-protocol/semaphore/blob/main/CODE_OF_CONDUCT.md">
🤝 Code of conduct
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://github.com/semaphore-protocol/semaphore/contribute">
🔎 Issues
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://discord.gg/6mSdGHnstH">
🗣️ Chat &amp; Support
</a>
</h4>
</div>
To learn more about circuits visit [semaphore.appliedzkp.org](https://semaphore.appliedzkp.org/docs/technical-reference/circuits).

View File

@@ -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"]
}

View File

@@ -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",

View File

@@ -1 +1 @@
contracts/verifiers
contracts/base/Pairing.sol

View 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.

View File

@@ -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;

View 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();
}
}
}

View File

@@ -1,4 +0,0 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;

View File

@@ -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;
}
}

View File

@@ -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();
}

File diff suppressed because one or more lines are too long

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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": [

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -18,7 +18,7 @@
"Verifier31": "0xe4539a592df18936202480FBe77E47DE012F2178",
"Verifier32": "0x98c90845A7870e215cBd7265DDC653E6c07032F4"
},
"Semaphore": "0x49281E30F17A30808a6ce538f979d539747e6707",
"Semaphore": "0x86337c87A56117f8264bbaBA70e5a522C6E8A604",
"PoseidonT3": "0xe0c8d1e53D9Bfc9071F6564755FCFf6cC0dB61d0",
"IncrementalBinaryTree": "0x9fCea5E9aF68D5B0c55A1003b49284d70BffC1A9"
"IncrementalBinaryTree": "0x91cD2B8573629d00BeC72EA1188d446897BD3948"
}

View File

@@ -18,7 +18,7 @@
"Verifier31": "0x133b69Ce47BF20C49368354914DF47519Ca6cCFE",
"Verifier32": "0xe2978F79cb4AF62e5C990EE5c7E12fb22ee22e2D"
},
"Semaphore": "0xE585f0Db9aB24dC912404DFfb9b28fb8BF211fA6",
"PoseidonT3": "0x8Bf7E5236957D1224b6e4F41E04730439cb802F7",
"IncrementalBinaryTree": "0xD6729903227dFf493Bf23Bf889dC73b853655abe"
"Semaphore": "0x5259d32659F1806ccAfcE593ED5a89eBAb85262f",
"PoseidonT3": "0xe0A452533853310C371b50Bd91BB9DCC8961350F",
"IncrementalBinaryTree": "0x61AE89E372492e53D941DECaaC9821649fa9B236"
}

View File

@@ -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") })

View File

@@ -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",

View File

@@ -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)
})

View File

@@ -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
)
)
}

View File

@@ -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()

View File

@@ -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
})

View File

@@ -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
})

View File

@@ -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
})
)

View File

@@ -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
})

View File

@@ -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
)

View File

@@ -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()")
})

View File

@@ -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)
})
})
})

View File

@@ -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)
```

View File

@@ -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"
}
}

View File

@@ -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))
})

View File

@@ -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])

View File

@@ -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"
}
}

View File

@@ -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"

View File

@@ -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.

View File

@@ -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_

View File

@@ -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"
}
}

View File

@@ -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()
]
}

View File

@@ -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)])
}

View File

@@ -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]

View File

@@ -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)
}

View 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)
}

View File

@@ -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)
})
})
})

View File

@@ -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"

View File

@@ -19,7 +19,7 @@ export type FullProof = {
}
export type PublicSignals = {
merkleRoot: BigNumberish
merkleTreeRoot: BigNumberish
nullifierHash: BigNumberish
signalHash: BigNumberish
externalNullifier: BigNumberish

View 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"
]
]
]
}

View File

@@ -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

View File

@@ -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",

View File

@@ -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`)
}

View File

@@ -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}`)
}
}

View File

@@ -1 +1 @@
8276b0b79cbaeb8dc05901c868cfb7500ea1dc1f
d5e764e1df1ee8a4de266237c73e44074450106d