Compare commits

..

289 Commits

Author SHA1 Message Date
cedoor
c1842eefc3 chore: v3.2.3
Former-commit-id: 59d2d1367c
2023-03-13 22:52:08 +00:00
Cedoor
320187ff89 Merge pull request #276 from semaphore-protocol/fix/bundle-poseidon
JS bundles with Poseidon functions

Former-commit-id: e135b1d8fa
2023-03-13 22:51:20 +00:00
cedoor
abbf1a1d30 chore: update lockfile
Former-commit-id: 982ee86208
2023-03-13 22:41:37 +00:00
cedoor
59269b067d build: bundle poseidon-lite functions with rollup
Former-commit-id: 797e62dd28
2023-03-13 22:32:23 +00:00
cedoor
21bd9fe540 ci: update auto-assign workflow name
Former-commit-id: 6a3079bf52
2023-03-13 19:35:41 +00:00
Cedoor
f60a4c02f1 Merge pull request #274 from semaphore-protocol/chore/husky
New Husky script to check commit messages' format

Former-commit-id: e00dc8eca8
2023-03-13 19:30:46 +00:00
cedoor
d012310ae1 chore: add husky script to check commit message format
re #263


Former-commit-id: 77552b0da3
2023-03-13 19:26:40 +00:00
Cedoor
f01cb91472 chore: update github token
Former-commit-id: d33d306478
2023-03-13 19:25:17 +00:00
cedoor
31e6954aff style: format code with prettier
Former-commit-id: 0137d6e759
2023-03-13 18:36:01 +00:00
Cedoor
7518d938d1 Merge pull request #273 from semaphore-protocol/chore/auto-assign-action
New Github workflow to assign PRs

Former-commit-id: f777603fba
2023-03-13 18:31:43 +00:00
Cedoor
083d8a03a4 chore: update team name
Former-commit-id: 07244fc6bc
2023-03-13 18:30:56 +00:00
Cedoor
16c9e90ae4 chore: set org devs as reviewers
Former-commit-id: b9db0663ec
2023-03-13 18:18:50 +00:00
Cedoor
1fe2745594 chore: add github workflow to auto assign PRs
Former-commit-id: 0c6df193e4
2023-03-13 16:57:52 +00:00
cedoor
18d4b740ca chore: v3.2.2
Former-commit-id: 5ea3b7e6ef
2023-03-13 11:52:02 +00:00
Cedoor
8392173370 Merge pull request #272 from semaphore-protocol/fix/data-ethers
Correct check for group existence

Former-commit-id: 46c2ad2c7a
2023-03-13 11:50:59 +00:00
cedoor
26490304e4 fix(data): set correct check for group existence
Former-commit-id: 7b938935ca
2023-03-13 11:40:23 +00:00
cedoor
1878ce2320 chore: v3.2.1
Former-commit-id: 5cc6877d15
2023-03-11 21:41:08 +00:00
cedoor
98aed04bd9 chore(contracts): include Semaphore.sol contract in npm files
Former-commit-id: d227ee1907
2023-03-11 21:40:38 +00:00
cedoor
5a0585cec2 chore: add refactor type to changelog
Former-commit-id: 4f7af880a9
2023-03-10 13:09:10 +00:00
cedoor
1a51263e5c chore: v3.2.0
Former-commit-id: 33d814fe6d
2023-03-10 11:19:52 +00:00
cedoor
4d7a976f06 chore(cli): remove unused ts paths
Former-commit-id: 915b95dfc6
2023-03-10 11:10:25 +00:00
cedoor
fe07103ff2 chore(cli-template-hardhat): add supported networks to hardhat
Former-commit-id: 0780751954
2023-03-10 11:03:17 +00:00
Cedoor
aa230345fb Merge pull request #270 from semaphore-protocol/chore/optimism-goerli
Semaphore support for Optimism Goerli network

Former-commit-id: 6344cf4954
2023-03-10 10:55:47 +00:00
Cedoor
d5c24c0f9c Merge pull request #269 from semaphore-protocol/chore/mumbai
Semaphore support for Mumbai network

Former-commit-id: e002b24f2a
2023-03-10 10:55:19 +00:00
Cedoor
c1752dcb2e Merge pull request #271 from vimwitch/poseidon-lite-upgrade
Poseidon lite upgrade

Former-commit-id: 21f2287570
2023-03-09 20:35:49 +00:00
Chance
b00ff99e5e chore: bump poseidon-lite version
Former-commit-id: 1a27d0b28b
2023-03-09 14:05:48 -06:00
cedoor
00e3c4a7f5 feat(data): add support for optimism goerli network
re #234


Former-commit-id: 3722b154bf
2023-03-09 18:21:44 +00:00
cedoor
0176a67e3a style(contracts): format code with prettier
Former-commit-id: d9f888ab70
2023-03-09 18:03:09 +00:00
cedoor
4fa9f41483 chore(contracts): deploy semaphore on optimism goerli network
re #234


Former-commit-id: 55a48a27d1
2023-03-09 18:02:16 +00:00
cedoor
64b9ef28e8 chore(contracts): update hardhat etherscan plugin
Former-commit-id: 4241be137a
2023-03-09 18:01:03 +00:00
cedoor
d7ce540f88 style(contracts): format code with prettier
Former-commit-id: 2e5e00ae55
2023-03-09 15:33:26 +00:00
cedoor
3411f55403 feat(data): add support for mumbai network
re #233


Former-commit-id: 6b498912df
2023-03-09 15:19:34 +00:00
cedoor
1bc492c39d chore(contracts): deploy semaphore on mumbai network
re #233


Former-commit-id: c98889632e
2023-03-09 14:28:35 +00:00
Cedoor
6197a03734 Merge pull request #268 from semaphore-protocol/chore/sepolia
Semaphore on Sepolia network

Former-commit-id: eceec87727
2023-03-09 11:40:03 +00:00
cedoor
6369fdfa71 style(contracts): format code with prettier
Former-commit-id: 1013516ba2
2023-03-09 11:39:51 +00:00
cedoor
48f779cd90 chore(contracts): deploy semaphore on sepolia network
re #183


Former-commit-id: a296541c6d
2023-03-09 11:28:17 +00:00
Cedoor
3ff6709a7b Merge pull request #267 from 0xdeenz/main
refactor(contracts): change Semaphore__InvalidProof to InvalidProof

Former-commit-id: 4fab94e058
2023-03-09 10:25:38 +00:00
0xdeenz
90bb4ccfa0 refactor(contracts): change Semaphore__InvalidProof to InvalidProof
Makes Pairing.sol errors more generic for greater reusability

fix #266


Former-commit-id: dc39c4ca44
2023-03-08 23:27:08 +01:00
Cedoor
5f29690641 Merge pull request #264 from semaphore-protocol/feat/data-package
New `@semaphore-protocol/data` package

Former-commit-id: 86e186cdc0
2023-03-08 21:30:33 +00:00
cedoor
2665a440fa build: add topological option to yarn workspaces cmd
Former-commit-id: b09e27477f
2023-03-08 21:18:38 +00:00
Cedoor
cf31913d27 docs: fix md syntax
Former-commit-id: 2b732f335c
2023-03-08 21:15:12 +00:00
cedoor
103a676455 docs(data): add await to usage functions
Former-commit-id: cce29363f9
2023-03-08 21:12:19 +00:00
cedoor
9aa5bc5840 fix(cli): set correct data class name
Former-commit-id: 180977841d
2023-03-08 21:11:49 +00:00
cedoor
894bc87952 docs(data): update readme file
re #256


Former-commit-id: a798acbe80
2023-03-08 20:57:32 +00:00
cedoor
cd4bd6ad91 chore(cli): sen new data package
Former-commit-id: bc165cd6e4
2023-03-08 20:32:02 +00:00
cedoor
dca7b67677 fix(data): add request header
Former-commit-id: 56e652a507
2023-03-08 20:31:40 +00:00
cedoor
60d698f6ee test(data): mock ethers tests
re #256


Former-commit-id: 9942b92f13
2023-03-07 18:24:25 +00:00
cedoor
f05e654f95 build(data): update rollup configuration
re #256


Former-commit-id: 9d27c3ac54
2023-03-06 22:14:28 +00:00
cedoor
9a4fe6ba64 chore: remove types folder from prettier ignore file
Former-commit-id: 925cc64d73
2023-03-06 17:44:44 +00:00
cedoor
c8d472a286 feat(data): create new data package
This new package allows devs to fetch on-chain data by using a Semaphore subgraph or the Ethers
library.

BREAKING CHANGE: The code of the old `@semaphore-protocol/subgraph` package has been moved to the
`@semaphore-protocol/data` package.

re #256


Former-commit-id: fc2f648acc
2023-03-06 17:43:42 +00:00
Cedoor
c9711b9007 Merge pull request #262 from vimwitch/identity-entropy
feat(identity): use sha512 to extract more entropy from message

Former-commit-id: 95e4a4e672
2023-03-05 21:07:39 +00:00
cedoor
8afcac50c2 chore(subgraph): remove subgraph package
re #256


Former-commit-id: b040c421ea
2023-03-05 20:12:46 +00:00
Chance
75c1c1373c chore: run prettier
Former-commit-id: d5d01142b1
2023-03-04 15:12:31 -06:00
Chance
2318628ca2 feat(identity): use sha512 to extract more entropy from message
Former-commit-id: ed63519423
2023-03-04 15:02:40 -06:00
Cedoor
2603600716 Merge pull request #261 from vimwitch/json-prepend-0x
feat(identity): prepend hex strings with 0x

Former-commit-id: 5a99792b68
2023-03-04 21:00:45 +00:00
Chance
3f0f1e006c feat(identity): prepend hex strings with 0x
Former-commit-id: 3c359e9a57
2023-03-04 14:47:03 -06:00
cedoor
2a4f2455d7 refactor(hardhat): update readme and set correct task name
Former-commit-id: 25e2442090
2023-03-01 19:35:57 +00:00
cedoor
0ea221d9ea Merge pull request #257 from shiyingt/feat/deploy-verifier-hardhat
add hardhat task to deploy SemaphoreVerifier.sol

Former-commit-id: 76146ed728
2023-03-01 20:20:59 +01:00
shiyingt
437674f3bc add hardhat task to deploy verifier
Former-commit-id: 934e4b2c06
2023-02-27 23:43:33 +08:00
shiyingt
4202186c0b revert all changes
Former-commit-id: b51f1d7820
2023-02-27 23:29:28 +08:00
cedoor
383e818833 docs(hardhat): update readme description
Former-commit-id: 865421a001
2023-02-23 11:54:04 +01:00
shiyingt
74014a42b5 run prettier write and eslint
Former-commit-id: 2ddbc51679
2023-02-22 22:39:10 +08:00
cedoor
e875fa4aa3 chore: update discord links
Former-commit-id: bd06422ef5
2023-02-22 13:22:46 +01:00
shiyingt
186dae79d2 fix hardhat task
Former-commit-id: 6987686426
2023-02-21 23:08:58 +08:00
shiyingt
195d545a95 fix hardhat task
Former-commit-id: 3105a0c095
2023-02-21 23:02:51 +08:00
cedoor
84245b9b1f Merge pull request #255 from semaphore-protocol/chore/bump-version
New NPM scripts to bump versions and publish NPM packages

Former-commit-id: 1bb2982f7d
2023-02-20 16:42:47 +01:00
cedoor
461e91f53b style: format code with prettier
Former-commit-id: 5c402f3ba2
2023-02-20 14:40:10 +01:00
cedoor
2893feca3c chore: add new scripts to bump versions & publish npm pkgs
re #254


Former-commit-id: 257080e478
2023-02-20 14:31:42 +01:00
cedoor
4be2973761 chore: update lockfile
re #254


Former-commit-id: 0b1519ea57
2023-02-20 12:46:15 +01:00
cedoor
01a30fd8af chore: add new workspace package
re #254


Former-commit-id: 9ef675f120
2023-02-20 12:44:36 +01:00
cedoor
a70c1b001c chore(yarn): add yarn plugin for versioning
re #254


Former-commit-id: a5df125378
2023-02-20 12:07:38 +01:00
shiyingt
30ed65d569 add hardhat task to deploy semaphore verifier only
Former-commit-id: 972790d158
2023-02-19 09:48:19 +08:00
cedoor
04a6649f2f Merge pull request #253 from semaphore-protocol/chore/release
Yarn patch to change `changelogithub` output

Former-commit-id: d2b959718c
2023-02-16 19:13:35 +01:00
cedoor
a337021d8d chore(release): create yarn patch to update changelogithub format
re #252


Former-commit-id: 739af09a5d
2023-02-16 18:41:15 +01:00
cedoor
4cd3863d03 docs(subgraph): update readme file
Former-commit-id: 6e036c0887
2023-02-15 22:00:03 +01:00
cedoor
c88639659d chore: update lockfile
Former-commit-id: 4f49736591
2023-02-15 20:57:45 +01:00
cedoor
0ca17d078b chore(semaphore): v3.1.0
Former-commit-id: 243c505d87
2023-02-15 20:47:23 +01:00
cedoor
f171506891 ci(release): add new workflow for automatic releases
Former-commit-id: a4fcb36fe0
2023-02-15 20:40:50 +01:00
cedoor
e085ecd0df test(subgraph): ignore some lines
Former-commit-id: 381c8668e4
2023-02-15 20:37:09 +01:00
cedoor
b744ee1e7b Merge pull request #250 from semaphore-protocol/refactor/cli-inquirer
Add inquirer in get-groups and get-group commands

Former-commit-id: 04ac6c2649
2023-02-15 20:18:15 +01:00
vplasencia
8d51a6689d refactor(cli): change some inquirer messages
Former-commit-id: 48ec4ba361
2023-02-15 12:29:32 -05:00
cedoor
7bec0a4e42 Merge pull request #251 from semaphore-protocol/feat/subgraph-improvements
Subgraph library improvements

Former-commit-id: 1d6f59229b
2023-02-15 18:16:11 +01:00
Saleel
71ed4d605d chore: add test for querying subgraph with filters
Former-commit-id: 11f061e586
2023-02-15 22:24:56 +05:30
Saleel
810a5358c0 chore: add tests for initalizing subgraph library with URL
Former-commit-id: 667929b09d
2023-02-15 22:05:56 +05:30
Saleel
636a9156b4 feat: add option to specify subgraph URL in subgraph library
Former-commit-id: fc4db2c8a1
2023-02-15 21:43:53 +05:30
Saleel
a679d047fa feat: add query filters to subgraph library
Former-commit-id: bc8f3495b6
2023-02-15 21:39:11 +05:30
vplasencia
6d3e685284 refactor(cli): add inquirer in get-group command
Former-commit-id: 68702bb5e4
2023-02-14 20:45:29 -05:00
vplasencia
3bfcf67b9d refactor(cli): add inquirer in get-groups command
Former-commit-id: f7fb159562
2023-02-14 16:41:00 -05:00
vplasencia
e16dbe663e refactor(cli): change project name message
Former-commit-id: 1aaaae0635
2023-02-14 16:30:14 -05:00
cedoor
0aca50ea34 Merge pull request #248 from semaphore-protocol/refactor/cli
Add node conventions and display an error for excess arguments in commands

Former-commit-id: 5604eff98d
2023-02-08 17:07:31 +01:00
vplasencia
54a6abdd2b refactor(cli): add node conventions and display an error for excess arguments in commands
Former-commit-id: 878ff0524e
2023-02-08 10:58:22 -05:00
cedoor
de32db6d2d Merge pull request #247 from semaphore-protocol/feature/cli-integrate-inquirer
Integrate Inquirer.js in create command in the CLI

Former-commit-id: 519b518c21
2023-02-08 16:32:46 +01:00
vplasencia
d43f9278e0 refactor(cli): remove projectDir variable
Former-commit-id: f7c1ca6e7e
2023-02-08 10:24:48 -05:00
vplasencia
f3d8c4ee75 feat(cli): integrate inquirer in create command
Former-commit-id: 7f63cc567e
2023-02-08 00:16:57 -05:00
cedoor
60fedc4e90 Merge pull request #244 from semaphore-protocol/feature/cli-check-latest-version
Check for latest version

Former-commit-id: dc969e0f55
2023-02-06 20:17:46 +01:00
cedoor
34d5743fa4 refactor(cli): move code to function to check latest version
re #188


Former-commit-id: fb0c016447
2023-02-06 20:06:16 +01:00
vplasencia
6810fcb5bb feat(cli): add check for latest version
Former-commit-id: ed81202bbd
2023-02-06 10:09:18 -05:00
cedoor
0bdf064614 Merge pull request #241 from semaphore-protocol/feature/group-id
Group class `id` attribute

Former-commit-id: cd3fa0c82c
2023-02-06 14:27:14 +01:00
cedoor
7c4d2c2007 feat(group): add id attribute to group class
re #240


Former-commit-id: 202fcc399c
2023-02-06 12:23:51 +01:00
cedoor
1bb57ca607 chore: update lockfile
Former-commit-id: b45c4f3510
2023-01-26 22:59:08 +01:00
cedoor
44860d70b9 chore: v3.0.0
Former-commit-id: 439a357173
2023-01-26 22:52:52 +01:00
cedoor
d286a8f1e8 Merge pull request #213 from semaphore-protocol/dev
Semaphore v3

Former-commit-id: 39a40f5f3b
2023-01-26 22:49:35 +01:00
cedoor
729ba41afd Merge pull request #236 from semaphore-protocol/vplasencia-patch-1
Change a comment

Former-commit-id: d27513d3f0
2023-01-26 11:47:04 +01:00
Vivian Plasencia
972fde32a7 Update group.ts
Former-commit-id: 5eb168c2ef
2023-01-25 21:55:17 -05:00
cedoor
c3d9e23e2a docs(contracts): update readme file
Former-commit-id: 9d12d3b050
2023-01-24 11:26:58 +01:00
cedoor
5fd7435c6d Merge pull request #232 from semaphore-protocol/refactor/proof
Proof generation/verification refactoring

Former-commit-id: f272aa26e9
2023-01-24 11:07:26 +01:00
cedoor
07888687a0 chore: update lockfile
Former-commit-id: 6b24210be1
2023-01-24 11:00:42 +01:00
cedoor
54c3a54597 chore: v3.0.0-beta.8
Former-commit-id: 8c952e9558
2023-01-24 10:38:47 +01:00
cedoor
81dba510c3 refactor(cli): update cli template tests
re #230


Former-commit-id: 5c027eef70
2023-01-24 10:37:32 +01:00
cedoor
343cdabe9c refactor(contracts): update contract tests
re #230


Former-commit-id: 1b654977b0
2023-01-23 20:29:08 +01:00
cedoor
fe6fbc1a0d refactor(proof): pack snarkjs proof
re #230


Former-commit-id: 8d68c09068
2023-01-23 20:27:56 +01:00
cedoor
f854492709 Merge pull request #231 from semaphore-protocol/feat/arbitrum-subgraph
Arbitrum subgraph

Former-commit-id: 4139c3e146
2023-01-23 17:08:48 +01:00
cedoor
30af236547 feat(subgraph): add arbitrum subgraph
re #229


Former-commit-id: 22fb9ebb87
2023-01-23 16:22:59 +01:00
cedoor
d65b4aae47 style: format code with prettier
Former-commit-id: 45d5815d95
2023-01-23 15:45:03 +01:00
cedoor
245fb2cba8 chore(contracts): deploy contracts on arbitrum
Former-commit-id: ea86ae0a3d
2023-01-23 15:41:15 +01:00
cedoor
f469ccc36a Merge pull request #228 from semaphore-protocol/refactor/bytes32-greeting
`bytes32` greeting

Former-commit-id: 5b2944105c
2023-01-19 12:12:12 +01:00
cedoor
8ee1bd9c1b Merge pull request #226 from semaphore-protocol/chore/fixed-dependencies
No version range for `snarkjs` and `poseidon-lite` dependencies

Former-commit-id: 5c03b72d37
2023-01-19 12:10:03 +01:00
cedoor
348a4327d7 refactor(cli): update greeting type to bytes32
Former-commit-id: c0ec1b5ecf
2023-01-18 20:06:48 +01:00
cedoor
faffde79f0 chore: update lockfile
re #225


Former-commit-id: 95e4a743b2
2023-01-17 15:29:05 +01:00
cedoor
89a83c7b6b chore: make snarkjs and poseidon-lite versions fixed
re #225


Former-commit-id: 59f1f624f2
2023-01-17 15:13:41 +01:00
cedoor
f36e8c1536 Merge pull request #223 from semaphore-protocol/fix/add-ts-suppress-error-comment
Fix/add ts suppress error comment

Former-commit-id: bdfc8d68a2
2023-01-11 18:34:32 +01:00
vplasencia
46ed508de8 Add TypeScript suppress error comment
Former-commit-id: 07728848f2
2023-01-11 12:12:48 -05:00
cedoor
821cdb7fd3 chore: update lockfile
Former-commit-id: 3bcec50e19
2023-01-09 17:18:17 +01:00
cedoor
dd2df7ab06 chore: v3.0.0-beta.7
Former-commit-id: ab1115c77a
2023-01-09 17:14:50 +01:00
cedoor
71fdabe65c Merge pull request #220 from semaphore-protocol/refactor/cli-init
Semaphore `create` command

Former-commit-id: a411b041b8
2023-01-09 17:03:22 +01:00
cedoor
cce6c31461 refactor(cli): replace init command with create
Former-commit-id: 72859d9b98
2023-01-09 11:05:54 +01:00
aguzmant103
f1aced7ee3 docs: adding GitPOAP link
Former-commit-id: f7e87c4442
2023-01-05 20:06:10 -06:00
cedoor
bd8b06bb7b docs(hardhat): update readme usage section
Former-commit-id: 20fa45c8f3
2023-01-05 17:44:46 +01:00
cedoor
9f692e57e8 chore: v3.0.0-beta.6
Former-commit-id: 1df18f81f7
2023-01-04 19:16:42 +01:00
cedoor
32aabf81d2 fix(subgraph): set correct goerli subgraph url
Former-commit-id: ce5c30b816
2023-01-04 19:08:52 +01:00
cedoor
a72a57ef63 style(subgraph): format code with prettier
Former-commit-id: 469e2a1310
2023-01-04 19:08:32 +01:00
cedoor
4e5b4495a3 chore: update lockfile
Former-commit-id: 1d4e7c509e
2023-01-04 18:56:23 +01:00
cedoor
578d426d1a chore(cli): v3.0.0-beta.5
Former-commit-id: 9a2db4b3bf
2023-01-04 18:52:16 +01:00
cedoor
362b025fac chore(hardhat): v3.0.0-beta.5
Former-commit-id: 23ec6dc55c
2023-01-04 18:48:54 +01:00
cedoor
84aa8d0eac chore(subgraph): v3.0.0-beta.5
Former-commit-id: ca1485bea8
2023-01-04 18:12:06 +01:00
cedoor
6592a62f25 chore(proof): v3.0.0-beta.5
Former-commit-id: e097a86875
2023-01-04 18:09:22 +01:00
cedoor
a59a2af50b chore(contracts): v3.0.0-beta.5
Former-commit-id: 268ef49ec5
2023-01-04 18:09:03 +01:00
cedoor
1e68ed1fec chore(group): v3.0.0-beta.5
Former-commit-id: 3ca1f59472
2023-01-04 18:08:14 +01:00
cedoor
2abd068cf8 chore(identity): v3.0.0-beta.5
Former-commit-id: 7f9978eb4f
2023-01-04 18:07:49 +01:00
cedoor
8b746ff2bc style(contracts): format code with prettier
Former-commit-id: ef9f927cbd
2023-01-04 13:27:15 +01:00
cedoor
23d9786e16 chore(contracts): deploy contracts on goerli
Former-commit-id: 2f14cc9fa9
2023-01-04 13:21:57 +01:00
cedoor
3b20402476 refactor(contracts): update function to verify contracts
Former-commit-id: cd65440f2c
2023-01-04 13:20:54 +01:00
cedoor
91bcc66c17 chore(cli): add arbitrum network to cli hardhat template
Former-commit-id: 3cdf7daa0f
2023-01-04 12:42:11 +01:00
cedoor
bcf9dad496 docs: update readme description
Former-commit-id: 64e47907b9
2023-01-04 11:03:33 +01:00
cedoor
29195519fb chore(cli): v0.5.0
Former-commit-id: bd30127759
2023-01-03 20:37:44 +01:00
cedoor
17efdb38af refactor(cli): add more info to init command
Former-commit-id: 3d559a6491
2023-01-03 20:36:11 +01:00
cedoor
8713e2b339 chore(cli): add files to be included in the package
re #216


Former-commit-id: 51a9d17520
2023-01-03 20:35:16 +01:00
cedoor
ef69356dca docs(proof): update readme file
Former-commit-id: 55add650f9
2022-12-23 11:08:49 +01:00
cedoor
252b866daa docs(readme): update badge & package list
Former-commit-id: d03f15c263
2022-12-23 10:58:07 +01:00
cedoor
5627f6eae7 chore: update lockfile
Former-commit-id: fead45b069
2022-12-23 10:24:07 +01:00
cedoor
45ef560324 chore(contracts): update zk-kit dependency
Former-commit-id: 9e186f3da9
2022-12-23 10:19:34 +01:00
cedoor
ee80aa172e fix(contracts): set a nullifier hashes mapping for each poll
fix #211


Former-commit-id: 681128f468
2022-12-22 18:22:45 +01:00
cedoor
c0f106edb6 Merge pull request #210 from semaphore-protocol/refactor/general
General refactoring and additional documentation to contracts

Former-commit-id: 2f1fbd8411
2022-12-22 18:20:45 +01:00
cedoor
3aea38cc9b docs(contracts): update contract comments
Former-commit-id: 4c32f4f610
2022-12-22 15:49:08 +01:00
cedoor
c6fe15cf13 refactor(contracts): remove unused contract error
Former-commit-id: 2dd0737e2c
2022-12-22 15:15:33 +01:00
cedoor
6e948d63dc refactor(contracts): make some event parameteres indexed
Former-commit-id: cd4aeab0a6
2022-12-22 13:09:02 +01:00
cedoor
c2bd4df1d9 refactor(contracts): rename merkle trees' mapping
Former-commit-id: b1ce54f0b9
2022-12-22 13:07:21 +01:00
cedoor
06e3063c3e refactor(contracts): get merkle tree depth only once
Former-commit-id: 76d8e81b65
2022-12-22 13:06:29 +01:00
cedoor
cb52b3db20 Merge pull request #197 from semaphore-protocol/fix/zero-values
Generate zeroValue based on groupId

Former-commit-id: 5726c9896a
2022-12-20 11:56:06 +01:00
cedoor
88781ea466 style(contracts): format code with prettier
Former-commit-id: 218867747b
2022-12-20 11:51:26 +01:00
cedoor
2c47ad9f28 Merge branch 'dev' into fix/zero-values
Former-commit-id: a2e31b78d3
2022-12-20 11:44:26 +01:00
cedoor
228ebd941a Merge pull request #206 from semaphore-protocol/fix/group-existence
Tree depth to check group existence

Former-commit-id: f7367b63d0
2022-12-20 11:39:27 +01:00
cedoor
71f31f0910 Merge pull request #204 from semaphore-protocol/docs/circuit-tree-depth
Update circuits' nLevels comment

Former-commit-id: a30261c373
2022-12-20 11:38:28 +01:00
cedoor
7cf8eb11a1 Merge pull request #205 from semaphore-protocol/fix/members-loop
Increase size of iterator variable

Former-commit-id: 93c7445619
2022-12-20 11:37:37 +01:00
cedoor
6bbe45fb33 Merge pull request #208 from semaphore-protocol/fix/root-duration
New function to update merkle tree duration

Former-commit-id: 81ef86757e
2022-12-20 11:36:41 +01:00
cedoor
7b4e03c7fd style(contracts): format code with prettier
Former-commit-id: dabdfc036b
2022-12-19 13:43:09 +01:00
cedoor
8e0dd30ccc fix(contracts): add function to update merkle tree duration
This bug was found by Veridise during their audit of Semaphore.

fix #200


Former-commit-id: 70d7276928
2022-12-19 13:35:01 +01:00
cedoor
0661320c2a fix(contracts): use tree depth to check group existence
This bug was found by Veridise during their audit of Semaphore.

fix #202


Former-commit-id: 6458614a76
2022-12-19 13:02:16 +01:00
cedoor
b419344297 fix(contracts): increase size of members iterator variable
This bug was found by Veridise during their audit of Semaphore.

fix #201


Former-commit-id: 1c5ccb8af5
2022-12-19 12:51:09 +01:00
cedoor
fc636b732d docs(circuits): update nLevels comment
This issue was opened by Veridise during their audit of Semaphore.

re #203


Former-commit-id: f67d803b1b
2022-12-19 12:27:08 +01:00
cedoor
5ac1cad96c Merge pull request #199 from semaphore-protocol/fix/whistleblowing-entities
Editors can be associated with multiple entities

Former-commit-id: 6b876c1606
2022-12-19 11:57:20 +01:00
cedoor
33a6a3601e fix(contracts): associate editor with many entities
This bug was found by Veridise during their audit of Semaphore.

fix #198


Former-commit-id: 2f414484ed
2022-12-17 14:32:12 +01:00
cedoor
2dc8be161c Merge pull request #195 from semaphore-protocol/chore/hardhat-chai-matchers
Migrate from hardhat-waffle to hardhat-chai-matchers

Former-commit-id: f392afbefa
2022-12-17 13:00:25 +01:00
cedoor
a9dae718d3 Merge pull request #194 from semaphore-protocol/refactor/snark-identities
New hash function to generate identity secrets

Former-commit-id: 8c51b9e707
2022-12-17 12:59:04 +01:00
cedoor
f3ca0ce3d8 fix(contracts): generate zeroValue based on groupId
This bug was found by Veridise during their audit of Semaphore.


Former-commit-id: a6d3e0719f
2022-12-16 16:23:13 +01:00
cedoor
310b1a8dcd chore(contracts): migrate to hardhat-chai-matchers
Former-commit-id: 0d3e3c8459
2022-12-16 14:46:24 +01:00
cedoor
3c3d374c54 style(identity): format code with prettier
Former-commit-id: 62c048f964
2022-12-16 13:57:21 +01:00
cedoor
c6247ace3b refactor(identity): update hash function to generate identity secrets
Former-commit-id: d46c9306e6
2022-12-16 13:50:44 +01:00
cedoor
1e9d56d3da docs(readme): update badges urls
Former-commit-id: 9ea07a8b1b
2022-12-16 12:38:45 +01:00
cedoor
a52a3bee1b chore(contracts): update incremental-merkle-tree.sol dependency
Former-commit-id: f67c5c0fe4
2022-12-16 12:36:21 +01:00
cedoor
e91bc74ab0 Merge pull request #191 from semaphore-protocol/feat/semaphore-cli
Semaphore CLI

Former-commit-id: 85af25af58
2022-12-16 11:45:03 +01:00
cedoor
2594c4e1c2 chore(cli): v0.4.0
Former-commit-id: d4b3ff5f74
2022-12-16 11:41:37 +01:00
cedoor
a199b01a50 fix(cli): add check for network option
Former-commit-id: ee27d5a056
2022-12-16 11:41:02 +01:00
cedoor
c97a0cbbb5 style: format code
Former-commit-id: 1a60f28320
2022-12-15 14:14:00 +01:00
cedoor
04fd0a3d91 chore: add files to ignore for eslint and prettier
Former-commit-id: c1d4511c77
2022-12-15 14:13:34 +01:00
cedoor
3fb849f076 build(cli): add subgraph package ts path
Former-commit-id: fb00f0cf4a
2022-12-15 14:03:57 +01:00
cedoor
b3c83bac8b chore(cli): move dependency
Former-commit-id: 53e395d0d6
2022-12-15 13:57:56 +01:00
cedoor
00c302aefc docs(cli): update readme long description
Former-commit-id: a6511d2978
2022-12-15 13:43:02 +01:00
cedoor
feee90e69d chore(cli): v.0.3.0
Former-commit-id: dc9340a70f
2022-12-15 13:38:13 +01:00
cedoor
ca87f3601d docs(cli): update usage section
Former-commit-id: 65bf4f0366
2022-12-15 13:37:07 +01:00
cedoor
a3abb810a9 refactor(cli): add more info to init command
Former-commit-id: 0e9ae15156
2022-12-15 13:35:34 +01:00
cedoor
5d19919474 docs(cli): update description and readme file
Former-commit-id: 1450d78f5c
2022-12-15 13:34:57 +01:00
cedoor
5c66f16a5b feat(cli): create init command
Former-commit-id: 4241fb97d5
2022-12-14 20:24:55 +01:00
cedoor
4b2f9e4492 feat(cli): create new cli template
Former-commit-id: 621f3ab4e6
2022-12-14 17:01:37 +01:00
cedoor
b593d1a0e9 refactor(cli): set common error syntax
Former-commit-id: ff8c73b31b
2022-12-12 15:20:27 +01:00
cedoor
d3b206ec3a refactor(cli): set error messages
Former-commit-id: d5a599c7d5
2022-12-12 14:57:16 +01:00
cedoor
adadacb218 chore(cli): v0.1.0
Former-commit-id: 8d80ba2614
2022-12-12 13:03:43 +01:00
cedoor
b7411bfcb7 feat(cli): create get-groups command
Former-commit-id: 110942071a
2022-12-12 13:02:24 +01:00
cedoor
3feeb7f9fd feat(cli): create get-group command
Former-commit-id: 190fdaff22
2022-12-09 18:34:14 +01:00
cedoor
05125c11d9 chore(cli): add cli package and basic setup
Former-commit-id: d124b48903
2022-12-08 20:45:45 +01:00
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
cedoor
6a5e9e32d3 chore: update lockfile
Former-commit-id: c9b8ab574c
2022-10-19 19:06:50 +02:00
cedoor
08d7621fc2 chore: v2.6.0
Former-commit-id: 4e0500f9ce
2022-10-19 19:05:55 +02:00
cedoor
ca3a4c1971 style: format code with prettier
Former-commit-id: b574e6a1e8
2022-10-19 18:44:04 +02:00
cedoor
dc0ceee50d chore(contracts): update incremental-merkle-tree dep version
Former-commit-id: be82cf1104
2022-10-19 17:03:44 +02:00
cedoor
6fadd3e745 docs: update contributing file
Former-commit-id: fd9a00fd58
2022-10-19 09:57:47 +02:00
cedoor
e86228102e chore(contracts): update openzeppelin dependency version
Former-commit-id: 9eebe0173a
2022-10-19 09:55:40 +02:00
cedoor
91f56941b4 docs: update identity pkg readme description
Former-commit-id: 93e042cf34
2022-10-15 17:51:12 -05:00
cedoor
22aadf2745 docs: update identity pkg readme file
Former-commit-id: 5eb18bfe5d
2022-10-15 17:47:31 -05:00
cedoor
8458a623e0 Merge pull request #142 from semaphore-protocol/feat/identity-getters
New identity class getters

Former-commit-id: bbcb065224
2022-10-13 15:13:53 -05:00
cedoor
e6a3699a56 feat: add identity class getters
Former-commit-id: 401d303b39
2022-09-30 11:46:21 +02:00
cedoor
ed74eff52a docs: remove docs link for hardhat pkg
Former-commit-id: 26e0cbcc9d
2022-09-22 13:54:57 +02:00
cedoor
a7e5b28b00 docs: add hardhat package
Former-commit-id: 92dd1db419
2022-09-22 13:49:16 +02:00
cedoor
08576e1717 Merge pull request #140 from semaphore-protocol/feat/hardhat-plugin
feat: create semaphore hardhat plugin
Former-commit-id: ab41ff13fb
2022-09-22 13:39:01 +02:00
cedoor
80376ab81e feat: create semaphore hardhat plugin
Former-commit-id: 6ceb226f5e
2022-09-21 16:16:42 +02:00
cedoor
32efdd952b style: format code with prettier
Former-commit-id: d4f85d7d04
2022-09-19 17:13:46 +02:00
cedoor
f6b79ba5d2 chore: update goerli contract addresses
Former-commit-id: b117b1ff00
2022-09-19 17:09:16 +02:00
cedoor
1a995d7087 chore: v2.5.0
Former-commit-id: 68779e90a0
2022-09-19 16:54:51 +02:00
cedoor
20fc3c58d7 Merge pull request #138 from semaphore-protocol/feat/custom-nullifier-hashes
Custom nullifier hashes

Former-commit-id: 506fa0ab7d
2022-09-19 16:49:19 +02:00
cedoor
7329ca6a48 feat: move nullifier hashes out of SemaphoreCore
Former-commit-id: f57e21c77d
2022-09-19 16:36:30 +02:00
cedoor
0c9c0c9791 style: fix eslint errors
Former-commit-id: 0a821d8214
2022-09-19 13:15:19 +02:00
cedoor
39a7e32143 style: format code with prettier
Former-commit-id: eba7d053e7
2022-09-19 13:08:25 +02:00
cedoor
87c27b9d03 chore: update lockfile
Former-commit-id: 0654895c9a
2022-09-19 13:04:54 +02:00
cedoor
4d07a1ede5 chore: update semaphore dependencies
Former-commit-id: bf4f6f75cb
2022-09-19 13:02:30 +02:00
cedoor
55fbd0f2ed chore: v2.4.0
Former-commit-id: 21ea7e80e7
2022-09-19 13:00:18 +02:00
cedoor
6dca198995 refactor: update subgraph queries
Former-commit-id: f0825d738c
2022-09-19 12:57:59 +02:00
cedoor
5f80aab430 fix: set correct contract names
Former-commit-id: 13ca6a6854
2022-09-19 12:17:53 +02:00
cedoor
c30fbb8d1c chore: update goerli contract addresses
Former-commit-id: 58c08b1e41
2022-09-19 12:12:35 +02:00
cedoor
be1014452e refactor: update scripts and tasks to deploy contracts
Former-commit-id: e960722b08
2022-09-19 12:12:22 +02:00
cedoor
0036da93b1 Merge pull request #136 from semaphore-protocol/feat/group-nullifier-hashes
Feat/group nullifier hashes

Former-commit-id: f8d3b0ad0f
2022-09-18 21:03:12 +02:00
cedoor
c984adef0e feat: add proof parameters to ProofVerified event
Former-commit-id: 85d9de669b
2022-09-18 18:16:10 +02:00
cedoor
b2d8667963 feat: hash nullifier hash with group id
Former-commit-id: 0979b5aadd
2022-09-18 18:10:14 +02:00
cedoor
466be38e42 docs: fix circuit link
Former-commit-id: d5794cca97
2022-09-18 16:50:09 +02:00
cedoor
adcb8e085d ci: fix production workflow
Former-commit-id: 011ab2b053
2022-09-18 16:19:42 +02:00
cedoor
e9a3770a39 Merge pull request #134 from semaphore-protocol/chore/monorepo
Monorepo

Former-commit-id: 47b6f6eb39
2022-09-18 16:14:03 +02:00
cedoor
d9a1387f2a docs: update workflow label url
Former-commit-id: 6ad31e445a
2022-09-18 16:01:27 +02:00
cedoor
a6710ad435 ci: remove job dependency
Former-commit-id: 3a75b81dad
2022-09-18 16:01:16 +02:00
cedoor
3d3a63a10d build: set peer dependencies
Former-commit-id: 343e259956
2022-09-18 15:54:37 +02:00
cedoor
0daf5b7dae chore: move env variables to the root folder
Former-commit-id: 9d3fc642d2
2022-09-18 15:50:16 +02:00
cedoor
ef4b3dd4b2 ci: remove jobs dependencies
Former-commit-id: 7458bcc23c
2022-09-17 19:06:50 +02:00
cedoor
0f2a13463a chore: extend contracts tsconfig
Former-commit-id: af6e11c564
2022-09-17 18:52:39 +02:00
cedoor
0a305c019d ci: add script to build libs before testing
Former-commit-id: de26e4da81
2022-09-17 18:51:59 +02:00
cedoor
de8c7f20ca chore: set workspace dependencies
Former-commit-id: f048f4ec4e
2022-09-17 18:51:40 +02:00
cedoor
23d7fdff3a fix: set default tree depth
Former-commit-id: c488b6f8ed
2022-09-17 18:20:40 +02:00
cedoor
21b9965f57 ci: fix command name
Former-commit-id: a9315fc111
2022-09-17 12:52:49 +02:00
cedoor
023c8bae64 chore: ignore docs folder with eslint
Former-commit-id: 14fe1d531f
2022-09-17 12:50:40 +02:00
cedoor
0d771eb9fa ci: compile contracts before linting
Former-commit-id: 77604a2d64
2022-09-17 12:50:00 +02:00
cedoor
62f775737d style: format code with prettier
Former-commit-id: 6a65d6c2bf
2022-09-17 12:45:04 +02:00
cedoor
12aacf24b3 chore: ignore docs folder with prettier
Former-commit-id: 93bdfd4b14
2022-09-17 12:44:54 +02:00
cedoor
b450dcec79 ci: update github workflows
Former-commit-id: 9244f42c1a
2022-09-17 12:40:29 +02:00
cedoor
e909e1db99 test: set default tree depth
Former-commit-id: 024c16bcd2
2022-09-17 12:40:14 +02:00
cedoor
92c9c9bcc8 docs: set relative repo links
Former-commit-id: c163ff1dcc
2022-09-16 16:59:36 +02:00
cedoor
5588256072 docs: update readme files
Former-commit-id: 1e630902bc
2022-09-16 16:56:35 +02:00
cedoor
8cf04ddb98 chore: create semaphore monorepo
Former-commit-id: a38dd20276
2022-09-16 16:50:30 +02:00
cedoor
ecca5a4ee9 style: format code with prettier
Former-commit-id: 5fa34109c6
2022-09-15 15:52:27 +02:00
cedoor
0a5ebe60df chore: update goerli semaphore address
Former-commit-id: 1c41b8edf5
2022-09-14 16:22:57 +02:00
189 changed files with 9462 additions and 23408 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

@@ -9,7 +9,9 @@ coverage
coverage.json
# hardhat
artifacts
cache
typechain-types
# types
types
@@ -20,6 +22,7 @@ circuits
# production
dist
build
docs
# misc
.DS_Store
@@ -29,3 +32,6 @@ build
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# packages
cli-template-*

View File

@@ -1,11 +1,24 @@
{
"root": true,
"env": {
"es6": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
"extends": ["airbnb-base", "airbnb-typescript/base", "plugin:jest/recommended", "plugin:jest/style", "prettier"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json"
"ecmaVersion": 6,
"sourceType": "module",
"project": ["./tsconfig.json", "./packages/**/tsconfig.json"]
},
"plugins": ["@typescript-eslint"]
"plugins": ["@typescript-eslint", "jest"],
"rules": {
"no-underscore-dangle": "off",
"import/no-extraneous-dependencies": "off",
"no-bitwise": "off",
"no-await-in-loop": "off",
"no-restricted-syntax": "off",
"no-console": ["warn", { "allow": ["info", "warn", "error"] }],
"@typescript-eslint/lines-between-class-members": "off",
"no-param-reassign": "off"
}
}

14
.github/ISSUE_TEMPLATE/---package.md vendored Normal file
View File

@@ -0,0 +1,14 @@
---
name: "\U0001F4E6 Package"
about: Propose a new Semaphore package
title: ''
labels: 'feature :rocket:'
assignees: ''
---
**Describe the package you'd like**
A clear and concise description of the type of package you have in mind.
**Additional context**
Add any other context about the package here.

14
.github/workflows/auto-assign.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
name: auto-assign
on:
pull_request:
types: [opened]
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: wow-actions/auto-assign@v3
with:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
reviewers: org/core-devs

View File

@@ -1,50 +0,0 @@
name: coverall
on:
push:
branches:
- main
env:
TREE_DEPTH: 20
jobs:
coverall:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v1
with:
node-version: 16.x
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- name: Restore yarn cache
uses: actions/cache@v3
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: YARN_CHECKSUM_BEHAVIOR=ignore yarn
- name: Download Snark artifacts
run: yarn download:snark-artifacts
- name: Compile contracts
run: yarn compile
- name: Test contracts with coverage
run: yarn test:coverage
- uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,13 +1,12 @@
name: style
name: docs
on:
pull_request:
push:
branches:
- main
jobs:
style:
gh-pages:
runs-on: ubuntu-latest
steps:
@@ -32,13 +31,15 @@ jobs:
${{ runner.os }}-yarn-
- name: Install dependencies
run: YARN_CHECKSUM_BEHAVIOR=ignore yarn
run: yarn
- name: Run Prettier
run: yarn prettier
- name: Generate doc website
run: yarn docs
- name: Run Eslint
run: yarn lint
- name: Compile contracts
run: yarn compile
- name: Publish on Github Pages
uses: crazy-max/ghaction-github-pages@v2.5.0
with:
build_dir: docs
jekyll: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

107
.github/workflows/production.yml vendored Normal file
View File

@@ -0,0 +1,107 @@
name: production
on:
push:
branches:
- main
env:
TREE_DEPTH: 20
ALL_SNARK_ARTIFACTS: false
jobs:
style:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v1
with:
node-version: 16.x
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- name: Restore yarn cache
uses: actions/cache@v3
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn
- name: Compile contracts
run: yarn compile:contracts
- name: Build libraries
run: yarn build:libraries
- name: Run Prettier
run: yarn prettier
- name: Run Eslint
run: yarn lint
test:
runs-on: ubuntu-latest
strategy:
matrix:
type:
- libraries
- contracts
steps:
- uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v1
with:
node-version: 16.x
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- name: Restore yarn cache
uses: actions/cache@v3
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn
- name: Build libraries
run: yarn build:libraries
- name: Test contracts and libraries
run: yarn test:${{ matrix.type }}
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: run-${{ matrix.type }}
path-to-lcov: ./coverage/${{ matrix.type }}/lcov.info
parallel: true
coverage:
runs-on: ubuntu-latest
needs: test
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel-finished: true

81
.github/workflows/pull-requests.yml vendored Normal file
View File

@@ -0,0 +1,81 @@
name: pull-requests
on:
pull_request:
env:
TREE_DEPTH: 20
ALL_SNARK_ARTIFACTS: false
jobs:
style:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v1
with:
node-version: 16.x
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- name: Restore yarn cache
uses: actions/cache@v3
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn
- name: Compile contracts
run: yarn compile:contracts
- name: Build libraries
run: yarn build:libraries
- name: Run Prettier
run: yarn prettier
- name: Run Eslint
run: yarn lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v1
with:
node-version: 16.x
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- name: Restore yarn cache
uses: actions/cache@v3
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn
- name: Build libraries
run: yarn build:libraries
- name: Test contracts and libraries
run: yarn test

View File

@@ -1,23 +1,24 @@
name: test
name: release
permissions:
contents: write
on:
pull_request:
push:
branches:
- main
env:
TREE_DEPTH: 20
tags:
- "v*"
jobs:
test:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install Node.js
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: 16.x
@@ -35,13 +36,8 @@ jobs:
${{ runner.os }}-yarn-
- name: Install dependencies
run: YARN_CHECKSUM_BEHAVIOR=ignore yarn
run: yarn
- name: Download Snark artifacts
run: yarn download:snark-artifacts
- name: Compile contracts
run: yarn compile
- name: Test contracts with coverage
run: yarn test:coverage
- run: yarn version:release
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

21
.gitignore vendored
View File

@@ -16,9 +16,14 @@ pids
*.seed
*.pid.lock
# IDE
.vscode
.idea
# Testing
coverage
coverage.json
*.lcov
# Dependency directories
node_modules/
@@ -28,6 +33,10 @@ node_modules/
# Optional npm cache directory
.npm
.DS_Store
# Output of 'npm pack'
*.tgz
# Optional eslint cache
.eslintcache
@@ -54,12 +63,17 @@ node_modules/
# Production
build
dist
deployed-contracts/undefined.json
deployed-contracts/localhost.json
docs/*
!docs/CNAME
!docs/index.html
# Hardhat
artifacts
cache
typechain-types
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
@@ -72,3 +86,6 @@ cache
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# Other
snark-artifacts

4
.husky/commit-msg Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint --edit $1

View File

@@ -9,20 +9,23 @@ coverage
coverage.json
# hardhat
artifacts
cache
# types
types
typechain-types
packages/contracts/deployed-contracts/undefined.json
packages/contracts/deployed-contracts/hardhat.json
packages/contracts/deployed-contracts/localhost.json
# circuits
circuits
# contracts
contracts/verifiers
Verifier*.sol
# production
dist
build
docs
# github
.github/ISSUE_TEMPLATE
@@ -35,3 +38,6 @@ build
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# other
snark-artifacts

View File

@@ -1,21 +0,0 @@
module.exports = {
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"
]
}

View File

@@ -1 +0,0 @@
contracts/verifiers

View File

@@ -0,0 +1,23 @@
diff --git a/dist/shared/changelogithub.821fab93.mjs b/dist/shared/changelogithub.821fab93.mjs
index 5fc2100867613c20f7827eac8715a5fc28bdc39e..97bd8dff878b81c63d2220e496904f6f3933589a 100644
--- a/dist/shared/changelogithub.821fab93.mjs
+++ b/dist/shared/changelogithub.821fab93.mjs
@@ -181,7 +181,7 @@ function formatLine(commit, options) {
function formatTitle(name, options) {
if (!options.emoji)
name = name.replace(emojisRE, "");
- return `###    ${name.trim()}`;
+ return `##    ${name.trim()}`;
}
function formatSection(commits, sectionName, options) {
if (!commits.length)
@@ -198,7 +198,8 @@ function formatSection(commits, sectionName, options) {
Object.keys(scopes).sort().forEach((scope) => {
let padding = "";
let prefix = "";
- const scopeText = `**${options.scopeMap[scope] || scope}**`;
+ const url = `https://github.com/${options.github}/tree/main/packages/${scope}`
+ const scopeText = `[**@${options.github.split("/")[0]}/${options.scopeMap[scope] || scope}**](${url})`
if (scope && useScopeGroup) {
lines.push(`- ${scopeText}:`);
padding = " ";

View File

@@ -0,0 +1 @@
87de4f440a77841135f97a187e09140c6d4e6ae2

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,11 @@
nodeLinker: node-modules
checksumBehavior: update
nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"
- path: .yarn/plugins/@yarnpkg/plugin-version.cjs
spec: "@yarnpkg/plugin-version"
yarnPath: .yarn/releases/yarn-3.2.1.cjs

View File

@@ -56,7 +56,7 @@ Each commit message consists of a **header**, a **body** and a **footer**. The *
<BLANK LINE>
<footer>
The **header** is mandatory and the **scope** of the header is optional.
The **header** is mandatory and the **scope** of the header must contain the name of the package you are working on.
#### Type

241
README.md
View File

@@ -13,18 +13,18 @@
<a href="https://github.com/semaphore-protocol" target="_blank">
<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">
<a href="/LICENSE">
<img alt="Github license" src="https://img.shields.io/github/license/semaphore-protocol/semaphore.svg?style=flat-square">
</a>
<a href="https://github.com/semaphore-protocol/semaphore/actions?query=workflow%3Atest">
<img alt="GitHub Workflow test" src="https://img.shields.io/github/workflow/status/semaphore-protocol/semaphore/test?label=test&style=flat-square&logo=github">
</a>
<a href="https://github.com/semaphore-protocol/semaphore/actions?query=workflow%3Astyle">
<img alt="GitHub Workflow style" src="https://img.shields.io/github/workflow/status/semaphore-protocol/semaphore/style?label=style&style=flat-square&logo=github">
<a href="https://github.com/semaphore-protocol/semaphore/actions?query=workflow%3Aproduction">
<img alt="GitHub Workflow test" src="https://img.shields.io/github/actions/workflow/status/semaphore-protocol/semaphore/production.yml?branch=main&label=test&style=flat-square&logo=github">
</a>
<a href="https://coveralls.io/github/semaphore-protocol/semaphore">
<img alt="Coveralls" src="https://img.shields.io/coveralls/github/semaphore-protocol/semaphore?style=flat-square&logo=coveralls">
</a>
<a href="https://deepscan.io/dashboard#view=project&tid=16502&pid=22324&bid=657461">
<img src="https://deepscan.io/api/teams/16502/projects/22324/branches/657461/badge/grade.svg" alt="DeepScan grade">
</a>
<a href="https://eslint.org/">
<img alt="Linter eslint" src="https://img.shields.io/badge/linter-eslint-8080f2?style=flat-square&logo=eslint">
</a>
@@ -32,6 +32,10 @@
<img alt="Code style prettier" src="https://img.shields.io/badge/code%20style-prettier-f8bc45?style=flat-square&logo=prettier">
</a>
<img alt="Repository top language" src="https://img.shields.io/github/languages/top/semaphore-protocol/semaphore?style=flat-square">
<a href="https://www.gitpoap.io/gh/semaphore-protocol/semaphore" target="_blank">
<img src="https://public-api.gitpoap.io/v1/repo/semaphore-protocol/semaphore/badge">
</a>
</p>
<div align="center">
@@ -48,7 +52,7 @@
🔎 Issues
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://discord.gg/6mSdGHnstH">
<a href="https://semaphore.appliedzkp.org/discord">
🗣️ Chat &amp; Support
</a>
</h4>
@@ -57,12 +61,166 @@
| Semaphore is a protocol, designed to be a simple and generic privacy layer for Ethereum DApps. Using zero knowledge, Ethereum users can prove their membership of a group and send signals such as votes or endorsements without revealing their original identity. |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
The core of the Semaphore protocol is in the [circuit logic](/circuits/scheme.png). However Semaphore also provides [Solidity contracts](/contracts) (NPM: `@semaphore-protocol/contracts`) and [JavaScript libraries](https://github.com/semaphore-protocol/semaphore.js) to make the steps for offchain proof creation and onchain verification easier. To learn more about Semaphore visit [semaphore.appliedzkp.org](https://semaphore.appliedzkp.org).
You can find Semaphore V1 on [`version/1.0.0`](https://github.com/semaphore-protocol/semaphore/tree/version/1.0.0).
The core of the Semaphore protocol is in the [circuit logic](/packages/circuits/scheme.png). However Semaphore also provides [Solidity contracts](/packages/contracts) and JavaScript libraries to make the steps for offchain proof creation and onchain verification easier. To learn more about Semaphore visit [semaphore.appliedzkp.org](https://semaphore.appliedzkp.org).
---
## 📦 Packages
<table>
<th>Package</th>
<th>Version</th>
<th>Downloads</th>
<tbody>
<tr>
<td>
<a href="/packages/contracts">
@semaphore-protocol/contracts
</a>
</td>
<td>
<!-- NPM version -->
<a href="https://npmjs.org/package/@semaphore-protocol/contracts">
<img src="https://img.shields.io/npm/v/@semaphore-protocol/contracts.svg?style=flat-square" alt="NPM version" />
</a>
</td>
<td>
<!-- Downloads -->
<a href="https://npmjs.org/package/@semaphore-protocol/contracts">
<img src="https://img.shields.io/npm/dm/@semaphore-protocol/contracts.svg?style=flat-square" alt="Downloads" />
</a>
</td>
</tr>
<tr>
<td>
<a href="/packages/identity">
@semaphore-protocol/identity
</a>
<a href="https://semaphore-protocol.github.io/semaphore/identity">
(docs)
</a>
</td>
<td>
<!-- NPM version -->
<a href="https://npmjs.org/package/@semaphore-protocol/identity">
<img src="https://img.shields.io/npm/v/@semaphore-protocol/identity.svg?style=flat-square" alt="NPM version" />
</a>
</td>
<td>
<!-- Downloads -->
<a href="https://npmjs.org/package/@semaphore-protocol/identity">
<img src="https://img.shields.io/npm/dm/@semaphore-protocol/identity.svg?style=flat-square" alt="Downloads" />
</a>
</td>
</tr>
<tr>
<td>
<a href="/packages/group">
@semaphore-protocol/group
</a>
<a href="https://semaphore-protocol.github.io/semaphore/group">
(docs)
</a>
</td>
<td>
<!-- NPM version -->
<a href="https://npmjs.org/package/@semaphore-protocol/group">
<img src="https://img.shields.io/npm/v/@semaphore-protocol/group.svg?style=flat-square" alt="NPM version" />
</a>
</td>
<td>
<!-- Downloads -->
<a href="https://npmjs.org/package/@semaphore-protocol/group">
<img src="https://img.shields.io/npm/dm/@semaphore-protocol/group.svg?style=flat-square" alt="Downloads" />
</a>
</td>
</tr>
<tr>
<td>
<a href="/packages/proof">
@semaphore-protocol/proof
</a>
<a href="https://semaphore-protocol.github.io/semaphore/proof">
(docs)
</a>
</td>
<td>
<!-- NPM version -->
<a href="https://npmjs.org/package/@semaphore-protocol/proof">
<img src="https://img.shields.io/npm/v/@semaphore-protocol/proof.svg?style=flat-square" alt="NPM version" />
</a>
</td>
<td>
<!-- Downloads -->
<a href="https://npmjs.org/package/@semaphore-protocol/proof">
<img src="https://img.shields.io/npm/dm/@semaphore-protocol/proof.svg?style=flat-square" alt="Downloads" />
</a>
</td>
</tr>
<tr>
<td>
<a href="/packages/data">
@semaphore-protocol/data
</a>
<a href="https://semaphore-protocol.github.io/semaphore/data">
(docs)
</a>
</td>
<td>
<!-- NPM version -->
<a href="https://npmjs.org/package/@semaphore-protocol/data">
<img src="https://img.shields.io/npm/v/@semaphore-protocol/data.svg?style=flat-square" alt="NPM version" />
</a>
</td>
<td>
<!-- Downloads -->
<a href="https://npmjs.org/package/@semaphore-protocol/data">
<img src="https://img.shields.io/npm/dm/@semaphore-protocol/data.svg?style=flat-square" alt="Downloads" />
</a>
</td>
</tr>
<tr>
<td>
<a href="/packages/hardhat">
@semaphore-protocol/hardhat
</a>
</td>
<td>
<!-- NPM version -->
<a href="https://npmjs.org/package/@semaphore-protocol/hardhat">
<img src="https://img.shields.io/npm/v/@semaphore-protocol/hardhat.svg?style=flat-square" alt="NPM version" />
</a>
</td>
<td>
<!-- Downloads -->
<a href="https://npmjs.org/package/@semaphore-protocol/hardhat">
<img src="https://img.shields.io/npm/dm/@semaphore-protocol/hardhat.svg?style=flat-square" alt="Downloads" />
</a>
</td>
</tr>
<tr>
<td>
<a href="/packages/cli">
@semaphore-protocol/cli
</a>
</td>
<td>
<!-- NPM version -->
<a href="https://npmjs.org/package/@semaphore-protocol/cli">
<img src="https://img.shields.io/npm/v/@semaphore-protocol/cli.svg?style=flat-square" alt="NPM version" />
</a>
</td>
<td>
<!-- Downloads -->
<a href="https://npmjs.org/package/@semaphore-protocol/cli">
<img src="https://img.shields.io/npm/dm/@semaphore-protocol/cli.svg?style=flat-square" alt="Downloads" />
</a>
</td>
</tr>
<tbody>
</table>
## 🛠 Install
Clone this repository:
@@ -71,7 +229,7 @@ Clone this repository:
git clone https://github.com/semaphore-protocol/semaphore.git
```
and install the dependencies:
And install the dependencies:
```bash
cd semaphore && yarn
@@ -85,7 +243,7 @@ Copy the `.env.example` file as `.env`:
cp .env.example .env
```
and add your environment variables.
And add your environment variables.
### Code quality and formatting
@@ -101,7 +259,7 @@ Run [Prettier](https://prettier.io/) to check formatting rules:
yarn prettier
```
or to automatically format the code:
Or to automatically format the code:
```bash
yarn prettier:write
@@ -125,59 +283,46 @@ Download the Semaphore snark artifacts needed to generate and verify proofs:
yarn download:snark-artifacts
```
### Compile contracts
Compile the smart contracts with [Hardhat](https://hardhat.org/):
```bash
yarn compile
```
### Testing
Run [Jest](https://jestjs.io/) to test the JS libraries:
```bash
yarn test:libraries
```
Run [Mocha](https://mochajs.org/) to test the contracts:
```bash
yarn test:contracts
```
Or test everything with:
```bash
yarn test
```
You can also generate a test coverage report:
### Build libraries & compile contracts
Run [Rollup](https://www.rollupjs.org) to build all the packages:
```bash
yarn test:coverage
yarn build:libraries
```
or a test gas report:
Compile the smart contracts with [Hardhat](https://hardhat.org/):
```bash
yarn test:report-gas
yarn compile:contracts
```
### Deploy contracts
### Documentation (JS libraries)
Deploy a verifier contract with depth = 20:
Run [TypeDoc](https://typedoc.org/) to generate a documentation website for each package:
```bash
yarn deploy:verifier --depth 20
yarn docs
```
Deploy the `Semaphore.sol` contract with one verifier:
```bash
yarn deploy:semaphore --verifiers '[{"merkleTreeDepth": 20, "contractAddress": "0x06bcD633988c1CE7Bd134DbE2C12119b6f3E4bD1"}]'
```
Deploy all verifiers and Semaphore contract:
```bash
yarn deploy:all
```
If you want to deploy contracts in a specific network you can set up the `DEFAULT_NETWORK` variable in your `.env` file with the name of one of our supported networks (hardhat, localhost, goerli, arbitrum). Or you can specify it as option:
```bash
yarn deploy:all --network goerli
yarn deploy:all --network localhost
```
If you want to deploy contracts on Goerli or Arbitrum, remember to provide a valid private key and an Infura API in your `.env` file.
The output will be placed on the `docs` folder.

3
babel.config.json Normal file
View File

@@ -0,0 +1,3 @@
{
"presets": [["@babel/preset-env", { "targets": { "node": "current" } }], "@babel/preset-typescript"]
}

View File

@@ -0,0 +1,7 @@
{
"types": {
"feat": { "title": "🚀 Features" },
"fix": { "title": "🐞 Bug Fixes" },
"refactor": { "title": "♻️ Refactoring" }
}
}

View File

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

View File

@@ -1,61 +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 Gets a nullifier hash and returns true or false.
/// It is used to prevent double-signaling.
mapping(uint256 => bool) internal nullifierHashes;
/// @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 {
if (nullifierHashes[nullifierHash]) {
revert Semaphore__YouAreUsingTheSameNillifierTwice();
}
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 Stores the nullifier hash to prevent double-signaling.
/// Attention! Remember to call it when you verify a proof if you
/// need to prevent double-signaling.
/// @param nullifierHash: Semaphore nullifier hash.
function _saveNullifierHash(uint256 nullifierHash) internal {
nullifierHashes[nullifierHash] = true;
}
/// @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,12 +0,0 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
/// @title SemaphoreCore interface.
/// @dev Interface of SemaphoreCore contract.
interface ISemaphoreCore {
error Semaphore__YouAreUsingTheSameNillifierTwice();
/// @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

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

@@ -1,74 +0,0 @@
[
{
"name": "Verifier16",
"address": "0x6143ECd9Fd1A00EDe1046d456f8aab53a7D71609"
},
{
"name": "Verifier17",
"address": "0xAc12fFFE354D6446eb50dd33E683B78FED73Fb02"
},
{
"name": "Verifier18",
"address": "0x610aeF0F2da3CD1C8bDefe4BDB434Ee146E0C701"
},
{
"name": "Verifier19",
"address": "0x5477725177035bbC9d70443eb921D29749D6FCb4"
},
{
"name": "Verifier20",
"address": "0x3fB2C0988a37b76e760c44e6516aF720935f3136"
},
{
"name": "Verifier21",
"address": "0xDc8f6B8A42836d4566256f4c6C53131DFD127DF8"
},
{
"name": "Verifier22",
"address": "0x6962b5e706be5278eeCb01c286b50A48484632f2"
},
{
"name": "Verifier23",
"address": "0x41e4796Bd89B4BF04013b559c93fC32E9a2BdF6B"
},
{
"name": "Verifier24",
"address": "0xD528B1D1408ab3583af4694F92b0aFEbE33d5b60"
},
{
"name": "Verifier25",
"address": "0x1683a27EF9c10c5286dB56412E1272cD0Ca733e7"
},
{
"name": "Verifier26",
"address": "0x78194bB665d1E33b97eE45B1A755c15717E94C00"
},
{
"name": "Verifier27",
"address": "0x997Dac00E6701Ef7F3518280E5a9922801126E42"
},
{
"name": "Verifier28",
"address": "0xDd3C7f4cBA2467aE41c0F614A3c3E24bC80268c6"
},
{
"name": "Verifier29",
"address": "0xe53eF12093933D5df5691EAbA3821bD1c1EB60Cd"
},
{
"name": "Verifier30",
"address": "0x7FeA07c536ABBB0E7FB3c833376EE4EaDc21340e"
},
{
"name": "Verifier31",
"address": "0xe4539a592df18936202480FBe77E47DE012F2178"
},
{
"name": "Verifier32",
"address": "0x98c90845A7870e215cBd7265DDC653E6c07032F4"
},
{
"name": "Semaphore",
"address": "0x49281E30F17A30808a6ce538f979d539747e6707"
}
]

View File

@@ -1,74 +0,0 @@
[
{
"name": "Verifier16",
"address": "0xA5253ba39381Aa99c4C2C5A4D5C2deC036d06629"
},
{
"name": "Verifier17",
"address": "0xe0418A5f8fBF051D6cbc41Ff29855Dd2a02201Ab"
},
{
"name": "Verifier18",
"address": "0x7CdB3336d7d7c55Bce0FB1508594C54521656797"
},
{
"name": "Verifier19",
"address": "0xbd870921d8A5398a3314C950d1fc63b8C3AB190B"
},
{
"name": "Verifier20",
"address": "0x2a96c5696F85e3d2aa918496806B5c5a4D93E099"
},
{
"name": "Verifier21",
"address": "0x5Ec7d851a52A2a25CEc528F42a7ACA8EcF4667Cd"
},
{
"name": "Verifier22",
"address": "0x919d3d9c05FA7411e334deA5a763354fC7B6aA5b"
},
{
"name": "Verifier23",
"address": "0x63917b00a6dA7865bEfdd107AfC83CC2e6BDE552"
},
{
"name": "Verifier24",
"address": "0xd05CAd7d940114c1419098EE3cEA0776ab510E7D"
},
{
"name": "Verifier25",
"address": "0x6D9862e6140D94E932d94c8BcE74a0BDD0ea5ACb"
},
{
"name": "Verifier26",
"address": "0x8c29e0b77e32f704F03eeCE01c041192A5EB6c77"
},
{
"name": "Verifier27",
"address": "0x066cC22f8CA2A8D90D7Ff77D8a10A27e629c9c4C"
},
{
"name": "Verifier28",
"address": "0x698F9507f504E2BD238be7da56E8D9fee60C6D15"
},
{
"name": "Verifier29",
"address": "0xbBfC2E201C3c3c6F50063c3Edb4746c6Fcb36346"
},
{
"name": "Verifier30",
"address": "0x06bcD633988c1CE7Bd134DbE2C12119b6f3E4bD1"
},
{
"name": "Verifier31",
"address": "0x133b69Ce47BF20C49368354914DF47519Ca6cCFE"
},
{
"name": "Verifier32",
"address": "0xe2978F79cb4AF62e5C990EE5c7E12fb22ee22e2D"
},
{
"name": "Semaphore",
"address": "0xd688189016277e1a6aE5228ef6894C14585A42D3"
}
]

123
docs/index.html Normal file
View File

@@ -0,0 +1,123 @@
<!DOCTYPE html>
<html style="height: 100%">
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="IE=edge" />
<title>Semaphore packages</title>
<meta
name="description"
content="A monorepo of Semaphore packages."
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
</head>
<body
style="
margin: 0;
background-color: #EAF0F4;
color: #000;
height: 100%;
font-family: 'Courier New', monospace;
display: flex;
flex-direction: column;
justify-content: space-between;
"
>
<div
style="
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex: 1;
padding: 0 20px;
text-align: center;
"
>
<div style="display: flex">
<span style="margin-right: 5px">
<img width="40" src="https://raw.githubusercontent.com/semaphore-protocol/website/main/static/img/semaphore-icon.svg">
</span>
<h1 style="margin: 0; font-size: 40px">Semaphore packages</h1>
</div>
<p style="max-width: 500px">
A monorepo of Semaphore packages.
</p>
<ul style="list-style-type: none; padding: 0; margin: 0; margin-top: 10px"></ul>
</div>
<footer
style="
display: flex;
justify-content: center;
padding: 15px 20px;
background-color: #EAF0F4;
"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
width: 900px;
"
>
<p style="margin: 0; font-size: 16px">
Copyright © 2022 Ethereum Foundation
</p>
<div>
<a
style="margin-right: 15px; text-decoration: none"
target="_blank"
href="https://github.com/semaphore-protocol/semaphore"
>
<i
class="fa fa-github"
style="font-size: 24px; color: #000"
></i>
</a>
</div>
</div>
</footer>
</body>
<script>
const url =
"https://api.github.com/repos/semaphore-protocol/semaphore/contents?ref=gh-pages"
function insertLinks(packages) {
const [element] = window.document.getElementsByTagName("ul")
let html = ""
for (const package of packages) {
html += `<li style="display: flex; align-items: center; margin-bottom: 8px">
<a style="margin-right: 15px" target="_blank" href="https://github.com/semaphore-protocol/semaphore/tree/main/packages/${package}">
<i class="fa fa-github" style="font-size: 24px; color: #000"></i>
</a>
<a style="color: #000; text-decoration: none; font-size: 16px"
onmouseover="this.style.color='#404A4E';"
onmouseout="this.style.color='#000';"
target="_blank" href="https://semaphore-protocol.github.io/semaphore/${package}">
@semaphore-protocol/${package} >
</a></li>`
}
element.innerHTML = html
}
fetch(url)
.then((response) => response.json())
.then((data) => {
const ignore = [".nojekyll", "index.html", "CNAME"]
const packages = data
.map((c) => c.name)
.filter((name) => !ignore.includes(name))
localStorage.setItem("packages", JSON.stringify(packages))
insertLinks(packages)
})
</script>
</html>

29
jest.config.ts Normal file
View File

@@ -0,0 +1,29 @@
import fs from "fs"
import type { Config } from "@jest/types"
const projects: any = fs
.readdirSync("./packages", { withFileTypes: true })
.filter((directory) => directory.isDirectory())
.map(({ name }) => ({
rootDir: `packages/${name}`,
displayName: name,
setupFiles: ["dotenv/config"],
moduleNameMapper: {
"@semaphore-protocol/(.*)": "<rootDir>/../$1/src/index.ts" // Interdependency packages.
}
}))
export default async (): Promise<Config.InitialOptions> => ({
projects,
verbose: true,
coverageDirectory: "./coverage/libraries",
collectCoverageFrom: ["<rootDir>/src/**/*.ts", "!<rootDir>/src/**/index.ts", "!<rootDir>/src/**/*.d.ts"],
coverageThreshold: {
global: {
branches: 90,
functions: 95,
lines: 95,
statements: 95
}
}
})

View File

@@ -1,104 +1,89 @@
{
"name": "semaphore",
"name": "semaphore-protocol",
"description": "A zero-knowledge protocol for anonymous signalling on Ethereum.",
"license": "MIT",
"homepage": "https://github.com/semaphore-protocol/semaphore.git#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/semaphore-protocol/semaphore.git.git"
},
"bugs": {
"url": "https://github.com/semaphore-protocol/semaphore.git/issues"
},
"repository": "git@github.com:semaphore-protocol/semaphore.git",
"homepage": "https://github.com/semaphore-protocol/semaphore",
"bugs": "https://github.com/semaphore-protocol/semaphore/issues",
"private": true,
"scripts": {
"start": "hardhat node",
"compile": "hardhat compile",
"download:snark-artifacts": "hardhat run scripts/download-snark-artifacts.ts",
"deploy:all": "hardhat run scripts/deploy-all.ts",
"deploy:verifier": "hardhat deploy:verifier",
"deploy:semaphore": "hardhat deploy:semaphore",
"deploy:semaphore-voting": "hardhat deploy:semaphore-voting",
"deploy:semaphore-whistleblowing": "hardhat deploy:semaphore-whistleblowing",
"test": "hardhat test",
"test:report-gas": "REPORT_GAS=true hardhat test",
"test:coverage": "hardhat coverage",
"typechain": "hardhat typechain",
"lint": "yarn lint:sol && yarn lint:ts",
"lint:ts": "eslint . --ext .js,.ts",
"lint:sol": "solhint 'contracts/**/*.sol'",
"build:libraries": "yarn workspaces foreach -t run build",
"compile:contracts": "yarn workspace contracts compile",
"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",
"lint": "eslint . --ext .js,.ts && yarn workspace contracts lint",
"prettier": "prettier -c .",
"prettier:write": "prettier -w .",
"docs": "yarn workspaces foreach run docs",
"version:bump": "yarn workspaces foreach --no-private version -d ${0} && yarn version apply --all && git commit -am \"chore: v${0}\" && git tag v${0}",
"version:publish": "yarn build:libraries && yarn workspaces foreach --no-private npm publish --tolerate-republish",
"version:release": "changelogithub",
"commit": "cz",
"precommit": "lint-staged"
"precommit": "lint-staged",
"postinstall": "yarn download:snark-artifacts && husky install"
},
"keywords": [
"ethereum",
"semaphore",
"solidity",
"circom",
"javascript",
"typescript",
"zero-knowledge",
"zk-snarks",
"zero-knowledge-proofs",
"proof-of-membership",
"monorepo"
],
"workspaces": [
"packages/*",
"packages/contracts/contracts"
],
"packageManager": "yarn@3.2.1",
"devDependencies": {
"@commitlint/cli": "^16.1.0",
"@babel/core": "^7.16.7",
"@babel/preset-env": "^7.16.8",
"@babel/preset-typescript": "^7.17.12",
"@commitlint/cli": "^16.0.2",
"@commitlint/config-conventional": "^16.0.0",
"@nomiclabs/hardhat-ethers": "^2.0.6",
"@nomiclabs/hardhat-etherscan": "^3.1.0",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@semaphore-protocol/group": "2.2.0",
"@semaphore-protocol/identity": "2.0.0",
"@semaphore-protocol/proof": "2.3.1",
"@typechain/ethers-v5": "^10.0.0",
"@typechain/hardhat": "^6.0.0",
"@types/chai": "^4.3.0",
"@rollup/plugin-typescript": "^8.3.0",
"@types/download": "^8.0.1",
"@types/mocha": "^9.1.0",
"@types/node": "^17.0.12",
"@types/glob": "^7.2.0",
"@types/jest": "^27.4.0",
"@types/node": "^17.0.9",
"@types/rimraf": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^5.10.1",
"@typescript-eslint/parser": "^5.10.1",
"chai": "^4.3.5",
"circomlib": "^2.0.2",
"circomlibjs": "^0.0.8",
"@typescript-eslint/eslint-plugin": "^5.9.1",
"@typescript-eslint/parser": "^5.9.1",
"babel-jest": "^27.4.6",
"changelogithub": "0.12.7",
"commitizen": "^4.2.4",
"cz-conventional-changelog": "^3.3.0",
"dotenv": "^14.3.2",
"download": "^8.0.0",
"eslint": "^8.7.0",
"dotenv": "^16.0.2",
"eslint": "^8.2.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-airbnb-typescript": "^16.1.0",
"eslint-config-prettier": "^8.3.0",
"ethereum-waffle": "^3.4.4",
"ethers": "^5.6.8",
"hardhat": "^2.9.7",
"hardhat-gas-reporter": "^1.0.8",
"js-logger": "^1.6.1",
"lint-staged": "^12.3.2",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-jest": "^25.7.0",
"husky": "^8.0.3",
"jest": "^27.4.1",
"jest-config": "^27.4.7",
"lint-staged": "^12.1.7",
"prettier": "^2.5.1",
"prettier-plugin-solidity": "^1.0.0-beta.19",
"rimraf": "^3.0.2",
"snarkjs": "^0.4.13",
"solhint": "^3.3.6",
"solhint-plugin-prettier": "^0.0.5",
"solidity-coverage": "^0.7.21",
"rollup": "^2.64.0",
"ts-node": "^10.4.0",
"typechain": "^8.0.0",
"typescript": "^4.5.5"
"tslib": "^2.3.1",
"typescript": "^4.7.0"
},
"config": {
"solidity": {
"version": "0.8.4"
},
"paths": {
"contracts": "./contracts",
"circuit": "./circuit",
"tests": "./test",
"cache": "./cache",
"snarkjs-templates": "./snarkjs-templates",
"build": {
"snark-artifacts": "./build/snark-artifacts",
"contracts": "./build/contracts",
"typechain": "./build/typechain"
}
},
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"dependencies": {
"@openzeppelin/contracts": "4.4.2",
"@zk-kit/incremental-merkle-tree.sol": "1.3.0"
"resolutions": {
"changelogithub@0.12.7": "patch:changelogithub@npm:0.12.7#.yarn/patches/changelogithub-npm-0.12.7-72f348805d.patch"
}
}

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://semaphore.appliedzkp.org/discord">
🗣️ 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

@@ -0,0 +1,7 @@
{
"name": "circuits",
"private": true,
"dependencies": {
"circomlib": "^2.0.2"
}
}

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -43,7 +43,7 @@ template CalculateNullifierHash() {
out <== poseidon.out;
}
// nLevels must be < 32.
// The current Semaphore smart contracts require nLevels <= 32 and nLevels >= 16.
template Semaphore(nLevels) {
signal input identityNullifier;
signal input identityTrapdoor;

View File

@@ -0,0 +1,4 @@
ETHEREUM_URL=
ETHEREUM_PRIVATE_KEY=
REPORT_GAS=false
COINMARKETCAP_API_KEY=

View File

@@ -0,0 +1,10 @@
node_modules
.env
coverage
coverage.json
typechain
typechain-types
# Hardhat files
cache
artifacts

View File

@@ -0,0 +1,54 @@
# Semaphore Hardhat template
This project demonstrates a basic Semaphore use case. It comes with a sample contract, a test for that contract and a sample task that deploys that contract.
## Usage
### Compile
```bash
yarn compile
```
### Testing
```bash
yarn test
```
You can also generate a test coverage report:
```bash
yarn test:coverage
```
Or a test gas report:
```bash
yarn test:report-gas
```
### Deploy
1. Copy the `.env.example` file as `.env`.
```bash
cp .env.example .env
```
2. Add your environment variables.
> **Note**
> You should at least set a valid Ethereum URL (e.g. Infura) and a private key with some ethers.
3. And deploy your contract.
```bash
yarn deploy --semaphore <semaphore-address> --group <group-id> --network goerli
```
> **Note**
> Check the Semaphore contract addresses [here](https://semaphore.appliedzkp.org/docs/deployed-contracts#semaphore).
> **Warning**
> The group id is a number!

View File

@@ -0,0 +1,42 @@
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.4;
import "@semaphore-protocol/contracts/interfaces/ISemaphore.sol";
/// @title Greeter contract.
/// @dev The following code is just a example to show how Semaphore can be used.
contract Greeter {
event NewGreeting(bytes32 greeting);
event NewUser(uint256 identityCommitment, bytes32 username);
ISemaphore public semaphore;
uint256 groupId;
mapping(uint256 => bytes32) users;
constructor(address semaphoreAddress, uint256 _groupId) {
semaphore = ISemaphore(semaphoreAddress);
groupId = _groupId;
semaphore.createGroup(groupId, 20, address(this));
}
function joinGroup(uint256 identityCommitment, bytes32 username) external {
semaphore.addMember(groupId, identityCommitment);
users[identityCommitment] = username;
emit NewUser(identityCommitment, username);
}
function greet(
bytes32 greeting,
uint256 merkleTreeRoot,
uint256 nullifierHash,
uint256[8] calldata proof
) external {
semaphore.verifyProof(groupId, merkleTreeRoot, uint256(greeting), nullifierHash, groupId, proof);
emit NewGreeting(greeting);
}
}

View File

@@ -0,0 +1,61 @@
import "@nomicfoundation/hardhat-toolbox"
import "@semaphore-protocol/hardhat"
import { config as dotenvConfig } from "dotenv"
import { HardhatUserConfig } from "hardhat/config"
import { NetworksUserConfig } from "hardhat/types"
import "./tasks/deploy"
dotenvConfig()
function getNetworks(): NetworksUserConfig {
if (process.env.ETHEREUM_URL && process.env.ETHEREUM_PRIVATE_KEY) {
const accounts = [`0x${process.env.ETHEREUM_PRIVATE_KEY}`]
return {
goerli: {
url: process.env.ETHEREUM_URL,
chainId: 5,
accounts
},
sepolia: {
url: process.env.ETHEREUM_URL,
chainId: 11155111,
accounts
},
mumbai: {
url: process.env.ETHEREUM_URL,
chainId: 80001,
accounts
},
"optimism-goerli": {
url: process.env.ETHEREUM_URL,
chainId: 420,
accounts
},
arbitrum: {
url: process.env.ETHEREUM_URL,
chainId: 42161,
accounts
}
}
}
return {}
}
const config: HardhatUserConfig = {
solidity: "0.8.4",
networks: {
hardhat: {
chainId: 1337
},
...getNetworks()
},
gasReporter: {
currency: "USD",
enabled: process.env.REPORT_GAS === "true",
coinmarketcap: process.env.COINMARKETCAP_API_KEY
}
}
export default config

View File

@@ -0,0 +1,60 @@
{
"name": "@semaphore-protocol/cli-template-hardhat",
"version": "3.2.3",
"description": "Semaphore Hardhat template.",
"license": "Unlicense",
"files": [
".gitignore",
".env.example",
"contracts/",
"tasks/",
"test/",
"hardhat.config.ts",
"tsconfig.json",
"LICENSE",
"README.md"
],
"publishConfig": {
"access": "public"
},
"scripts": {
"start": "hardhat node",
"compile": "hardhat compile",
"deploy": "hardhat deploy",
"test": "hardhat test",
"test:report-gas": "REPORT_GAS=true hardhat test",
"test:coverage": "hardhat coverage"
},
"devDependencies": {
"@ethersproject/abi": "^5.4.7",
"@ethersproject/providers": "^5.4.7",
"@nomicfoundation/hardhat-chai-matchers": "^1.0.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox": "^2.0.0",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^3.0.0",
"@semaphore-protocol/group": "3.2.3",
"@semaphore-protocol/hardhat": "3.2.3",
"@semaphore-protocol/identity": "3.2.3",
"@semaphore-protocol/proof": "3.2.3",
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.2",
"@types/chai": "^4.2.0",
"@types/download": "^8.0.1",
"@types/mocha": "^9.1.0",
"@types/node": ">=12.0.0",
"chai": "^4.2.0",
"dotenv": "^16.0.3",
"download": "^8.0.0",
"ethers": "^5.4.7",
"hardhat": "^2.11.0",
"hardhat-gas-reporter": "^1.0.8",
"solidity-coverage": "^0.8.1",
"ts-node": ">=8.0.0",
"typechain": "^8.1.0",
"typescript": ">=4.5.0"
},
"dependencies": {
"@semaphore-protocol/contracts": "3.2.3"
}
}

View File

@@ -0,0 +1,27 @@
import { task, types } from "hardhat/config"
task("deploy", "Deploy a Greeter contract")
.addOptionalParam("semaphore", "Semaphore contract address", undefined, types.string)
.addOptionalParam("group", "Group id", "42", types.string)
.addOptionalParam("logs", "Print the logs", true, types.boolean)
.setAction(async ({ logs, semaphore: semaphoreAddress, group: groupId }, { ethers, run }) => {
if (!semaphoreAddress) {
const { semaphore } = await run("deploy:semaphore", {
logs
})
semaphoreAddress = semaphore.address
}
const Greeter = await ethers.getContractFactory("Greeter")
const greeter = await Greeter.deploy(semaphoreAddress, groupId)
await greeter.deployed()
if (logs) {
console.info(`Greeter contract has been deployed to: ${greeter.address}`)
}
return greeter
})

View File

@@ -0,0 +1,72 @@
import { Group } from "@semaphore-protocol/group"
import { Identity } from "@semaphore-protocol/identity"
import { generateProof } from "@semaphore-protocol/proof"
import { expect } from "chai"
import download from "download"
import { existsSync } from "fs"
import { ethers, run } from "hardhat"
// @ts-ignore: typechain-types folder will be generated after contracts compilation
import { Greeter } from "../typechain-types"
describe("Greeter", () => {
let greeter: Greeter
const snarkArtifactsURL = "https://www.trusted-setup-pse.org/semaphore/20"
const snarkArtifactsPath = "./artifacts/snark"
const users: any[] = []
const groupId = "42"
const group = new Group(groupId)
before(async () => {
if (!existsSync(`${snarkArtifactsPath}/semaphore.wasm`)) {
await download(`${snarkArtifactsURL}/semaphore.wasm`, `${snarkArtifactsPath}`)
await download(`${snarkArtifactsURL}/semaphore.zkey`, `${snarkArtifactsPath}`)
}
greeter = await run("deploy", { logs: false, group: groupId })
users.push({
identity: new Identity(),
username: ethers.utils.formatBytes32String("anon1")
})
users.push({
identity: new Identity(),
username: ethers.utils.formatBytes32String("anon2")
})
group.addMember(users[0].identity.commitment)
group.addMember(users[1].identity.commitment)
})
describe("# joinGroup", () => {
it("Should allow users to join the group", async () => {
for (let i = 0; i < group.members.length; i += 1) {
const transaction = greeter.joinGroup(group.members[i], users[i].username)
await expect(transaction).to.emit(greeter, "NewUser").withArgs(group.members[i], users[i].username)
}
})
})
describe("# greet", () => {
it("Should allow users to greet", async () => {
const greeting = ethers.utils.formatBytes32String("Hello World")
const fullProof = await generateProof(users[1].identity, group, groupId, greeting, {
wasmFilePath: `${snarkArtifactsPath}/semaphore.wasm`,
zkeyFilePath: `${snarkArtifactsPath}/semaphore.zkey`
})
const transaction = greeter.greet(
greeting,
fullProof.merkleTreeRoot,
fullProof.nullifierHash,
fullProof.proof
)
await expect(transaction).to.emit(greeter, "NewGreeting").withArgs(greeting)
})
})
})

View File

@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
"include": ["./tasks", "./test", "./typechain-types"],
"files": ["./hardhat.config.ts"]
}

21
packages/cli/LICENSE Normal file
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.

82
packages/cli/README.md Normal file
View File

@@ -0,0 +1,82 @@
<p align="center">
<h1 align="center">
Semaphore CLI
</h1>
<p align="center">A command line tool to set up your Semaphore project and get group data.</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>
<a href="https://www.npmjs.com/package/@semaphore-protocol/cli">
<img alt="NPM version" src="https://img.shields.io/npm/v/@semaphore-protocol/cli?style=flat-square" />
</a>
<a href="https://npmjs.org/package/@semaphore-protocol/cli">
<img alt="Downloads" src="https://img.shields.io/npm/dm/@semaphore-protocol/cli.svg?style=flat-square" />
</a>
<a href="https://eslint.org/">
<img alt="Linter eslint" src="https://img.shields.io/badge/linter-eslint-8080f2?style=flat-square&logo=eslint" />
</a>
<a href="https://prettier.io/">
<img alt="Code style prettier" src="https://img.shields.io/badge/code%20style-prettier-f8bc45?style=flat-square&logo=prettier" />
</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://semaphore.appliedzkp.org/discord">
🗣️ Chat &amp; Support
</a>
</h4>
</div>
| Setting up a project, although not particularly complex, can be a lengthy process for some people. The Semaphore CLI reduces the set-up time from a few minutes to a few seconds. In addition, it can also be used to obtain on-chain group data. |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
## 🛠 Install
Install the `@semaphore-protocol/cli` package globally:
```bash
npm i -g @semaphore-protocol/cli
```
or run specific commands with `npx`:
```bash
npx @semaphore-protocol/cli create my-app
```
## 📜 Usage
```
Usage: semaphore [options] [command]
A command line tool to set up your Semaphore project and get group data.
Options:
-v, --version Show Semaphore CLI version.
-h, --help Display this help.
Commands:
create <project-directory> Create a Semaphore project with a supported template.
get-groups [options] Get the list of groups from a supported network (Goerli or Arbitrum).
get-group [options] <group-id> Get the data of a group from a supported network (Goerli or Arbitrum).
help [command] Display help for a specific command.
```

View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"baseUrl": ".",
"target": "es2020",
"module": "ESNext",
"allowSyntheticDefaultImports": true
},
"include": ["src"]
}

56
packages/cli/package.json Normal file
View File

@@ -0,0 +1,56 @@
{
"name": "@semaphore-protocol/cli",
"type": "module",
"version": "3.2.3",
"description": "A command line tool to set up your Semaphore project and get group data.",
"license": "MIT",
"bin": {
"semaphore": "dist/index.js"
},
"types": "dist/types/index.d.ts",
"files": [
"dist/",
"src/",
"LICENSE",
"README.md"
],
"repository": "https://github.com/semaphore-protocol/semaphore",
"homepage": "https://github.com/semaphore-protocol/semaphore/tree/main/packages/cli",
"bugs": {
"url": "https://github.com/semaphore-protocol/semaphore.git/issues"
},
"engines": {
"node": ">=14.16"
},
"scripts": {
"start": "ts-node --esm src/index.ts",
"build:watch": "rollup -c rollup.config.ts -w --configPlugin typescript",
"build": "rimraf dist && rollup -c rollup.config.ts --configPlugin typescript",
"prepublishOnly": "yarn build"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@types/clear": "^0.1.2",
"@types/figlet": "^1.5.5",
"@types/semver": "^7.3.13",
"rollup-plugin-cleanup": "^3.2.1",
"rollup-plugin-typescript2": "^0.31.2",
"ts-node": "^10.9.1",
"typedoc": "^0.22.11"
},
"dependencies": {
"@semaphore-protocol/data": "3.2.3",
"axios": "^1.3.2",
"boxen": "^7.0.1",
"chalk": "^5.1.2",
"commander": "^9.4.1",
"download": "^8.0.0",
"figlet": "^1.5.2",
"inquirer": "^9.1.4",
"log-symbols": "^5.1.0",
"ora": "^6.1.2",
"semver": "^7.3.8"
}
}

View File

@@ -0,0 +1,29 @@
import typescript from "rollup-plugin-typescript2"
import fs from "fs"
import cleanup from "rollup-plugin-cleanup"
const pkg = JSON.parse(fs.readFileSync("./package.json", "utf-8"))
const banner = `#!/usr/bin/env node
/**
* @module ${pkg.name}
* @version ${pkg.version}
* @file ${pkg.description}
* @copyright Ethereum Foundation 2022
* @license ${pkg.license}
* @see [Github]{@link ${pkg.homepage}}
*/
`
export default {
input: "src/index.ts",
output: [{ file: pkg.bin.semaphore, format: "es", banner }],
external: ["url", "fs", "path", ...Object.keys(pkg.dependencies)],
plugins: [
(typescript as any)({
tsconfig: "./build.tsconfig.json",
useTsconfigDeclarationDir: true
}),
cleanup({ comments: "jsdoc" })
]
}

View File

@@ -0,0 +1,48 @@
import axios from "axios"
import boxen from "boxen"
import chalk from "chalk"
import { execSync } from "child_process"
import { lt as semverLt } from "semver"
const cliRegistryURL = "https://registry.npmjs.org/-/package/@semaphore-protocol/cli/dist-tags"
/**
* Checks the registry directly via the API, if that fails, tries the slower `npm view [package] version` command.
* This is important for users in environments where direct access to npm is blocked by a firewall, and packages are
* provided exclusively via a private registry.
* @param currentVersion The current version of the CLI.
*/
export default async function checkLatestVersion(currentVersion: string) {
let latestVersion: string
try {
const { data } = await axios.get(cliRegistryURL)
latestVersion = data.latest
} catch {
try {
latestVersion = execSync("npm view @semaphore-protocol/cli version").toString().trim()
} catch {
latestVersion = null
}
}
if (latestVersion && semverLt(currentVersion, latestVersion)) {
console.info("\n")
console.info(
boxen(
chalk.white(
`Update available ${chalk.gray(currentVersion)} -> ${chalk.green(
latestVersion
)} \n\n You are currently using @semaphore-protocol/cli ${chalk.gray(
currentVersion
)} which is behind the latest release ${chalk.green(latestVersion)} \n\n Run ${chalk.cyan(
"npm install -g @semaphore-protocol/cli@latest"
)} to get the latest version`
),
{ padding: 1, borderColor: "yellow", textAlignment: "center" }
)
)
console.info("")
}
}

255
packages/cli/src/index.ts Normal file
View File

@@ -0,0 +1,255 @@
import { SemaphoreSubgraph } from "@semaphore-protocol/data"
import chalk from "chalk"
import { program } from "commander"
import download from "download"
import figlet from "figlet"
import { existsSync, readFileSync, renameSync } from "fs"
import inquirer from "inquirer"
import logSymbols from "log-symbols"
import { dirname } from "path"
import { fileURLToPath } from "url"
import checkLatestVersion from "./checkLatestVersion.js"
import Spinner from "./spinner.js"
const packagePath = `${dirname(fileURLToPath(import.meta.url))}/..`
const { description, version } = JSON.parse(readFileSync(`${packagePath}/package.json`, "utf8"))
const supportedNetworks = ["goerli", "mumbai", "optimism-goerli", "arbitrum"]
program
.name("semaphore")
.description(description)
.version(version, "-v, --version", "Show Semaphore CLI version.")
.addHelpText("before", `${figlet.textSync("Semaphore")}\n`)
.addHelpText("after", "\r")
.helpOption(undefined, "Display this help.")
.addHelpCommand("help [command]", "Display help for a specific command.")
.configureOutput({
outputError: (message) => {
console.info(`\n ${logSymbols.error}`, message)
}
})
program
.command("create")
.description("Create a Semaphore project with a supported template.")
.argument("[project-directory]", "Directory of the project.")
// .option("-t, --template <template-name>", "Supported Semaphore template.", "hardhat")
.allowExcessArguments(false)
.action(async (projectDirectory) => {
if (!projectDirectory) {
const { projectName } = await inquirer.prompt({
name: "projectName",
type: "input",
message: "What is your project name?",
default: "my-app"
})
projectDirectory = projectName
}
const currentDirectory = process.cwd()
const spinner = new Spinner(`Creating your project in ${chalk.green(`./${projectDirectory}`)}`)
const templateURL = `https://registry.npmjs.org/@semaphore-protocol/cli-template-hardhat/-/cli-template-hardhat-${version}.tgz`
if (existsSync(projectDirectory)) {
console.info(`\n ${logSymbols.error}`, `error: the '${projectDirectory}' folder already exists\n`)
return
}
spinner.start()
await checkLatestVersion(version)
await download(templateURL, currentDirectory, { extract: true })
renameSync(`${currentDirectory}/package`, `${currentDirectory}/${projectDirectory}`)
spinner.stop()
console.info(`\n ${logSymbols.success}`, `Your project is ready!\n`)
console.info(` Please, install your dependencies by running:\n`)
console.info(` ${chalk.cyan("cd")} ${projectDirectory}`)
console.info(` ${chalk.cyan("npm i")}\n`)
const { scripts } = JSON.parse(readFileSync(`${currentDirectory}/${projectDirectory}/package.json`, "utf8"))
if (scripts) {
console.info(` Available scripts:\n`)
console.info(
`${Object.keys(scripts)
.map((s) => ` ${chalk.cyan(`npm run ${s}`)}`)
.join("\n")}\n`
)
console.info(` See the README.md file to understand how to use them!\n`)
}
})
program
.command("get-groups")
.description("Get the list of groups from a supported network (goerli or arbitrum).")
.option("-n, --network <network-name>", "Supported Ethereum network.")
.allowExcessArguments(false)
.action(async ({ network }) => {
if (!network) {
const { selectedNetwork } = await inquirer.prompt({
name: "selectedNetwork",
type: "list",
message: "Select one of our supported networks:",
default: supportedNetworks[0],
choices: supportedNetworks
})
network = selectedNetwork
}
if (!supportedNetworks.includes(network)) {
console.info(`\n ${logSymbols.error}`, `error: the network '${network}' is not supported\n`)
return
}
const subgraph = new SemaphoreSubgraph(network)
const spinner = new Spinner("Fetching groups")
spinner.start()
try {
const groupIds = await subgraph.getGroupIds()
spinner.stop()
if (groupIds.length === 0) {
console.info(`\n ${logSymbols.info}`, "info: there are no groups in this network\n")
return
}
const content = `\n${groupIds.map((id: any) => ` - ${id}`).join("\n")}`
console.info(`${content}\n`)
} catch (error) {
spinner.stop()
console.info(`\n ${logSymbols.error}`, "error: unexpected error with the Semaphore subgraph")
}
})
program
.command("get-group")
.description("Get the data of a group from a supported network (Goerli or Arbitrum).")
.argument("[group-id]", "Identifier of the group.")
.option("-n, --network <network-name>", "Supported Ethereum network.")
.option("-m, --members", "Show group members.")
.option("-s, --signals", "Show group signals.")
.allowExcessArguments(false)
.action(async (groupId, { network, members, signals }) => {
if (!network) {
const { selectedNetwork } = await inquirer.prompt({
name: "selectedNetwork",
type: "list",
message: "Select one of our supported networks:",
default: supportedNetworks[0],
choices: supportedNetworks
})
network = selectedNetwork
}
if (!groupId) {
const subgraphGroups = new SemaphoreSubgraph(network)
const spinnerGroups = new Spinner("Fetching groups")
spinnerGroups.start()
try {
const groups = await subgraphGroups.getGroups()
spinnerGroups.stop()
if (groups.length === 0) {
console.info(`\n ${logSymbols.info}`, "info: there are no groups in this network\n")
return
}
const groupIds = groups.map(({ id }: any) => id)
const { selectedGroupId } = await inquirer.prompt({
name: "selectedGroupId",
type: "list",
message: "Select one of the following existing group ids:",
choices: groupIds
})
groupId = selectedGroupId
} catch (error) {
spinnerGroups.stop()
console.info(`\n ${logSymbols.error}`, "error: unexpected error with the Semaphore subgraph")
return
}
}
if (!members && !signals) {
const { showMembers } = await inquirer.prompt({
name: "showMembers",
type: "confirm",
message: "Do you want to show members?",
default: false
})
members = showMembers
const { showSignals } = await inquirer.prompt({
name: "showSignals",
type: "confirm",
message: "Do you want to show signals?",
default: false
})
signals = showSignals
}
if (!supportedNetworks.includes(network)) {
console.info(`\n ${logSymbols.error}`, `error: the network '${network}' is not supported\n`)
return
}
const subgraph = new SemaphoreSubgraph(network)
const spinner = new Spinner(`Fetching group ${groupId}`)
spinner.start()
try {
const group = await subgraph.getGroup(groupId, { members, verifiedProofs: signals })
spinner.stop()
if (!group) {
console.info(`\n ${logSymbols.error}`, "error: the group does not exist\n")
return
}
let content = ` ${chalk.bold("Id")}: ${group.id}\n`
content += ` ${chalk.bold("Admin")}: ${group.admin}\n`
content += ` ${chalk.bold("Merkle tree")}:\n`
content += ` Root: ${group.merkleTree.root}\n`
content += ` Depth: ${group.merkleTree.depth}\n`
content += ` Zero value: ${group.merkleTree.zeroValue}\n`
content += ` Number of leaves: ${group.merkleTree.numberOfLeaves}`
if (members) {
content += `\n\n ${chalk.bold("Members")}: \n${group.members
.map((member: string, i: number) => ` ${i}. ${member}`)
.join("\n")}`
}
if (signals) {
content += `\n\n ${chalk.bold("Signals")}: \n${group.verifiedProofs
.map(({ signal }: any) => ` - ${signal}`)
.join("\n")}`
}
console.info(`\n${content}\n`)
} catch (error) {
spinner.stop()
console.info(`\n ${logSymbols.error}`, "error: unexpected error with the Semaphore subgraph")
}
})
program.parse(process.argv)

View File

@@ -0,0 +1,25 @@
import ora, { Ora } from "ora"
export default class Spinner {
private text: string
private ora: Ora
constructor(text: string) {
this.text = text
}
start() {
console.info("")
this.ora = ora({
text: this.text,
indent: 1
}).start()
}
stop() {
this.ora.stop()
process.stdout.moveCursor(0, -1)
}
}

View File

@@ -0,0 +1,10 @@
{
"compilerOptions": {
"baseUrl": ".",
"target": "es2020",
"module": "ESNext",
"moduleResolution": "Node16",
"allowSyntheticDefaultImports": true
},
"include": ["src", "rollup.config.ts"]
}

View File

@@ -0,0 +1,4 @@
module.exports = {
istanbulFolder: "../../coverage/contracts",
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

@@ -0,0 +1 @@
contracts/base/Pairing.sol

View File

@@ -0,0 +1 @@
contracts/README.md

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

@@ -7,7 +7,7 @@
<p align="center">
<a href="https://github.com/semaphore-protocol">
<img src="https://img.shields.io/badge/project-semaphore-blue.svg?style=flat-square">
<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">
@@ -34,7 +34,7 @@
🔎 Issues
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://discord.gg/6mSdGHnstH">
<a href="https://semaphore.appliedzkp.org/discord">
🗣️ Chat &amp; Support
</a>
</h4>
@@ -59,3 +59,62 @@ or yarn:
```bash
yarn add @semaphore-protocol/contracts
```
## 📜 Usage
### Compile contracts
Compile the smart contracts with [Hardhat](https://hardhat.org/):
```bash
yarn compile
```
### Testing
Run [Mocha](https://mochajs.org/) to test the contracts:
```bash
yarn test
```
You can also generate a test coverage report:
```bash
yarn test:coverage
```
Or a test gas report:
```bash
yarn test:report-gas
```
### Deploy contracts
Deploy the `Semaphore.sol` contract without any parameter:
```bash
yarn deploy:semaphore
```
or deploy it by providing the addresses of the contracts/libraries on which it depends:
```bash
yarn deploy:semaphore --semaphoreVerifier <address>
```
> **Note**
> Run `yarn deploy:semaphore --help` to see the complete list.
If you want to deploy your contract in a specific network you can set up the `DEFAULT_NETWORK` variable in your `.env` file with the name of one of our supported networks (hardhat, localhost, goerli, arbitrum). Or you can specify it as an option:
```bash
yarn deploy:semaphore --network goerli
yarn deploy:semaphore --network sepolia
yarn deploy:semaphore --network mumbai
yarn deploy:semaphore --network optimism-goerli
yarn deploy:semaphore --network arbitrum
```
If you want to deploy contracts on Goerli or Arbitrum, remember to provide a valid private key and an Infura API in your `.env` file.

View File

@@ -2,25 +2,26 @@
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;
/// @dev This contract uses the Semaphore base contracts to provide a complete service
/// to allow admins to create and manage groups and their members to generate Semaphore proofs
/// and verify them. Group admins can add, update or remove group members, and can be
/// an Ethereum account or a smart contract. This contract also assigns each new Merkle tree
/// generated with a new root a duration (or an expiry) within which the proofs generated with that root
/// can be validated.
contract Semaphore is ISemaphore, SemaphoreGroups {
ISemaphoreVerifier public verifier;
/// @dev Gets a group id and returns the group admin address.
mapping(uint256 => address) public groupAdmins;
/// @dev Gets a group id and returns data to check if a Merkle root is expired.
mapping(uint256 => MerkleTreeExpiry) public merkleTreeExpiries;
/// @dev Gets a group id and returns the group parameters.
mapping(uint256 => Group) public groups;
/// @dev Checks if the group admin is the transaction sender.
/// @param groupId: Id of the group.
modifier onlyGroupAdmin(uint256 groupId) {
if (groupAdmins[groupId] != _msgSender()) {
if (groups[groupId].admin != _msgSender()) {
revert Semaphore__CallerIsNotTheGroupAdmin();
}
_;
@@ -29,35 +30,28 @@ 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}.
function createGroup(
uint256 groupId,
uint256 merkleTreeDepth,
uint256 zeroValue,
address admin
) external override onlySupportedMerkleTreeDepth(merkleTreeDepth) {
_createGroup(groupId, merkleTreeDepth, zeroValue);
_createGroup(groupId, merkleTreeDepth);
groupAdmins[groupId] = admin;
merkleTreeExpiries[groupId].rootDuration = 1 hours;
groups[groupId].admin = admin;
groups[groupId].merkleTreeDuration = 1 hours;
emit GroupAdminUpdated(groupId, address(0), admin);
}
@@ -66,32 +60,44 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
function createGroup(
uint256 groupId,
uint256 merkleTreeDepth,
uint256 zeroValue,
address admin,
uint256 merkleTreeRootDuration
uint256 merkleTreeDuration
) external override onlySupportedMerkleTreeDepth(merkleTreeDepth) {
_createGroup(groupId, merkleTreeDepth, zeroValue);
_createGroup(groupId, merkleTreeDepth);
groupAdmins[groupId] = admin;
merkleTreeExpiries[groupId].rootDuration = merkleTreeRootDuration;
groups[groupId].admin = admin;
groups[groupId].merkleTreeDuration = merkleTreeDuration;
emit GroupAdminUpdated(groupId, address(0), admin);
}
/// @dev See {ISemaphore-updateGroupAdmin}.
function updateGroupAdmin(uint256 groupId, address newAdmin) external override onlyGroupAdmin(groupId) {
groupAdmins[groupId] = newAdmin;
groups[groupId].admin = newAdmin;
emit GroupAdminUpdated(groupId, _msgSender(), newAdmin);
}
/// @dev See {ISemaphore-updateGroupMerkleTreeDuration}.
function updateGroupMerkleTreeDuration(uint256 groupId, uint256 newMerkleTreeDuration)
external
override
onlyGroupAdmin(groupId)
{
uint256 oldMerkleTreeDuration = groups[groupId].merkleTreeDuration;
groups[groupId].merkleTreeDuration = newMerkleTreeDuration;
emit GroupMerkleTreeDurationUpdated(groupId, oldMerkleTreeDuration, newMerkleTreeDuration);
}
/// @dev See {ISemaphore-addMember}.
function addMember(uint256 groupId, uint256 identityCommitment) external override onlyGroupAdmin(groupId) {
_addMember(groupId, identityCommitment);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
merkleTreeExpiries[groupId].rootCreationDates[merkleTreeRoot] = block.timestamp;
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
}
/// @dev See {ISemaphore-addMembers}.
@@ -100,7 +106,7 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
override
onlyGroupAdmin(groupId)
{
for (uint8 i = 0; i < identityCommitments.length; ) {
for (uint256 i = 0; i < identityCommitments.length; ) {
_addMember(groupId, identityCommitments[i]);
unchecked {
@@ -110,7 +116,7 @@ contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
merkleTreeExpiries[groupId].rootCreationDates[merkleTreeRoot] = block.timestamp;
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
}
/// @dev See {ISemaphore-updateMember}.
@@ -122,6 +128,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}.
@@ -132,44 +142,52 @@ 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
) external override {
uint256 currentMerkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 merkleTreeDepth = getMerkleTreeDepth(groupId);
if (currentMerkleTreeRoot == 0) {
if (merkleTreeDepth == 0) {
revert Semaphore__GroupDoesNotExist();
}
if (merkleTreeRoot != currentMerkleTreeRoot) {
uint256 rootCreationDate = merkleTreeExpiries[groupId].rootCreationDates[merkleTreeRoot];
uint256 rootDuration = merkleTreeExpiries[groupId].rootDuration;
uint256 currentMerkleTreeRoot = getMerkleTreeRoot(groupId);
if (rootCreationDate == 0) {
// A proof could have used an old Merkle tree root.
// https://github.com/semaphore-protocol/semaphore/issues/98
if (merkleTreeRoot != currentMerkleTreeRoot) {
uint256 merkleRootCreationDate = groups[groupId].merkleRootCreationDates[merkleTreeRoot];
uint256 merkleTreeDuration = groups[groupId].merkleTreeDuration;
if (merkleRootCreationDate == 0) {
revert Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
}
if (block.timestamp > rootCreationDate + rootDuration) {
if (block.timestamp > merkleRootCreationDate + merkleTreeDuration) {
revert Semaphore__MerkleTreeRootIsExpired();
}
}
uint256 merkleTreeDepth = getMerkleTreeDepth(groupId);
if (groups[groupId].nullifierHashes[nullifierHash]) {
revert Semaphore__YouAreUsingTheSameNillifierTwice();
}
IVerifier verifier = verifiers[merkleTreeDepth];
verifier.verifyProof(merkleTreeRoot, nullifierHash, signal, externalNullifier, proof, merkleTreeDepth);
_verifyProof(signal, merkleTreeRoot, nullifierHash, externalNullifier, proof, verifier);
groups[groupId].nullifierHashes[nullifierHash] = true;
_saveNullifierHash(nullifierHash);
emit ProofVerified(groupId, signal);
emit ProofVerified(groupId, merkleTreeRoot, nullifierHash, externalNullifier, signal);
}
}

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

View File

@@ -1,38 +1,33 @@
//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";
/// @title Semaphore groups contract.
/// @dev The following code allows you to create groups, add and remove members.
/// @dev This contract allows you to create groups, add, remove and update members.
/// You can use getters to obtain informations about groups (root, depth, number of leaves).
abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
using IncrementalBinaryTree for IncrementalTreeData;
/// @dev Gets a group id and returns the group/tree data.
mapping(uint256 => IncrementalTreeData) internal groups;
/// @dev Gets a group id and returns the tree data.
mapping(uint256 => IncrementalTreeData) internal merkleTrees;
/// @dev Creates a new group by initializing the associated tree.
/// @param groupId: Id of the group.
/// @param merkleTreeDepth: Depth of the tree.
/// @param zeroValue: Zero value of the tree.
function _createGroup(
uint256 groupId,
uint256 merkleTreeDepth,
uint256 zeroValue
) internal virtual {
if (groupId >= SNARK_SCALAR_FIELD) {
revert Semaphore__GroupIdIsNotLessThanSnarkScalarField();
}
function _createGroup(uint256 groupId, uint256 merkleTreeDepth) internal virtual {
if (getMerkleTreeDepth(groupId) != 0) {
revert Semaphore__GroupAlreadyExists();
}
groups[groupId].init(merkleTreeDepth, zeroValue);
// The zeroValue is an implicit member of the group, or an implicit leaf of the Merkle tree.
// Although there is a remote possibility that the preimage of
// the hash may be calculated, using this value we aim to minimize the risk.
uint256 zeroValue = uint256(keccak256(abi.encodePacked(groupId))) >> 8;
merkleTrees[groupId].init(merkleTreeDepth, zeroValue);
emit GroupCreated(groupId, merkleTreeDepth, zeroValue);
}
@@ -45,7 +40,7 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
revert Semaphore__GroupDoesNotExist();
}
groups[groupId].insert(identityCommitment);
merkleTrees[groupId].insert(identityCommitment);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = getNumberOfMerkleTreeLeaves(groupId) - 1;
@@ -67,11 +62,11 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) internal virtual {
if (getMerkleTreeRoot(groupId) == 0) {
if (getMerkleTreeDepth(groupId) == 0) {
revert Semaphore__GroupDoesNotExist();
}
groups[groupId].update(identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
merkleTrees[groupId].update(identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
@@ -91,11 +86,11 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) internal virtual {
if (getMerkleTreeRoot(groupId) == 0) {
if (getMerkleTreeDepth(groupId) == 0) {
revert Semaphore__GroupDoesNotExist();
}
groups[groupId].remove(identityCommitment, proofSiblings, proofPathIndices);
merkleTrees[groupId].remove(identityCommitment, proofSiblings, proofPathIndices);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
@@ -105,17 +100,17 @@ abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
/// @dev See {ISemaphoreGroups-getMerkleTreeRoot}.
function getMerkleTreeRoot(uint256 groupId) public view virtual override returns (uint256) {
return groups[groupId].root;
return merkleTrees[groupId].root;
}
/// @dev See {ISemaphoreGroups-getMerkleTreeDepth}.
function getMerkleTreeDepth(uint256 groupId) public view virtual override returns (uint256) {
return groups[groupId].depth;
return merkleTrees[groupId].depth;
}
/// @dev See {ISemaphoreGroups-getNumberOfMerkleTreeLeaves}.
function getNumberOfMerkleTreeLeaves(uint256 groupId) public view virtual override returns (uint256) {
return groups[groupId].numberOfLeaves;
return merkleTrees[groupId].numberOfLeaves;
}
/// @dev Converts the path indices of a Merkle proof to the identity commitment index in the tree.

File diff suppressed because one or more lines are too long

View File

@@ -2,30 +2,18 @@
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.
/// @notice It allows users to vote anonymously in a poll.
/// @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;
/// @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) {
@@ -36,23 +24,25 @@ 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();
}
_createGroup(pollId, merkleTreeDepth, 0);
_createGroup(pollId, merkleTreeDepth);
Poll memory poll;
poll.coordinator = coordinator;
polls[pollId] = poll;
polls[pollId].coordinator = coordinator;
emit PollCreated(pollId, coordinator);
}
@@ -79,26 +69,25 @@ 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) {
Poll memory poll = polls[pollId];
if (poll.state != PollState.Ongoing) {
) public override {
if (polls[pollId].state != PollState.Ongoing) {
revert Semaphore__PollIsNotOngoing();
}
if (polls[pollId].nullifierHashes[nullifierHash]) {
revert Semaphore__YouAreUsingTheSameNillifierTwice();
}
uint256 merkleTreeDepth = getMerkleTreeDepth(pollId);
uint256 merkleTreeRoot = getMerkleTreeRoot(pollId);
IVerifier verifier = verifiers[merkleTreeDepth];
verifier.verifyProof(merkleTreeRoot, nullifierHash, vote, pollId, proof, merkleTreeDepth);
_verifyProof(vote, merkleTreeRoot, nullifierHash, pollId, proof, verifier);
// Prevent double-voting (nullifierHash = hash(pollId + identityNullifier)).
_saveNullifierHash(nullifierHash);
polls[pollId].nullifierHashes[nullifierHash] = true;
emit VoteAdded(pollId, vote);
}

View File

@@ -2,55 +2,49 @@
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.
/// @notice It allows users to leak information anonymously .
/// @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;
/// organization, newspaper) and allow them to leak anonymously.
/// Leaks can be IPFS hashes, permanent links or other kinds of references.
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 Gets an entity id and return its editor address.
mapping(uint256 => address) private entities;
/// @dev Checks if the editor is the transaction sender.
/// @param entityId: Id of the entity.
modifier onlyEditor(uint256 entityId) {
if (entityId != entities[_msgSender()]) {
if (entities[entityId] != _msgSender()) {
revert Semaphore__CallerIsNotTheEditor();
}
_;
}
/// @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();
}
_createGroup(entityId, merkleTreeDepth, 0);
_createGroup(entityId, merkleTreeDepth);
entities[editor] = entityId;
entities[entityId] = editor;
emit EntityCreated(entityId, editor);
}
@@ -72,17 +66,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

@@ -1,24 +1,20 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
/// @title Semaphore interface.
/// @dev Interface of a Semaphore contract.
/// @title Semaphore contract interface.
interface ISemaphore {
error Semaphore__CallerIsNotTheGroupAdmin();
error Semaphore__MerkleTreeDepthIsNotSupported();
error Semaphore__MerkleTreeRootIsExpired();
error Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
error Semaphore__YouAreUsingTheSameNillifierTwice();
struct Verifier {
address contractAddress;
uint256 merkleTreeDepth;
}
/// It defines all the parameters needed to check whether a
/// zero-knowledge proof generated with a certain Merkle tree is still valid.
struct MerkleTreeExpiry {
uint256 rootDuration;
mapping(uint256 => uint256) rootCreationDates;
/// It defines all the group parameters, in addition to those in the Merkle tree.
struct Group {
address admin;
uint256 merkleTreeDuration;
mapping(uint256 => uint256) merkleRootCreationDates;
mapping(uint256 => bool) nullifierHashes;
}
/// @dev Emitted when an admin is assigned to a group.
@@ -27,10 +23,29 @@ interface ISemaphore {
/// @param newAdmin: New admin of the group.
event GroupAdminUpdated(uint256 indexed groupId, address indexed oldAdmin, address indexed newAdmin);
/// @dev Emitted when the Merkle tree duration of a group is updated.
/// @param groupId: Id of the group.
/// @param oldMerkleTreeDuration: Old Merkle tree duration of the group.
/// @param newMerkleTreeDuration: New Merkle tree duration of the group.
event GroupMerkleTreeDurationUpdated(
uint256 indexed groupId,
uint256 oldMerkleTreeDuration,
uint256 newMerkleTreeDuration
);
/// @dev Emitted when a Semaphore proof is verified.
/// @param groupId: Id of the group.
/// @param merkleTreeRoot: Root of the Merkle tree.
/// @param externalNullifier: External nullifier.
/// @param nullifierHash: Nullifier hash.
/// @param signal: Semaphore signal.
event ProofVerified(uint256 indexed groupId, bytes32 signal);
event ProofVerified(
uint256 indexed groupId,
uint256 indexed merkleTreeRoot,
uint256 indexed externalNullifier,
uint256 nullifierHash,
uint256 signal
);
/// @dev Saves the nullifier hash to avoid double signaling and emits an event
/// if the zero-knowledge proof is valid.
@@ -43,7 +58,7 @@ interface ISemaphore {
function verifyProof(
uint256 groupId,
uint256 merkleTreeRoot,
bytes32 signal,
uint256 signal,
uint256 nullifierHash,
uint256 externalNullifier,
uint256[8] calldata proof
@@ -52,25 +67,21 @@ interface ISemaphore {
/// @dev Creates a new group. Only the admin will be able to add or remove members.
/// @param groupId: Id of the group.
/// @param depth: Depth of the tree.
/// @param zeroValue: Zero value of the tree.
/// @param admin: Admin of the group.
function createGroup(
uint256 groupId,
uint256 depth,
uint256 zeroValue,
address admin
) external;
/// @dev Creates a new group. Only the admin will be able to add or remove members.
/// @param groupId: Id of the group.
/// @param depth: Depth of the tree.
/// @param zeroValue: Zero value of the tree.
/// @param admin: Admin of the group.
/// @param merkleTreeRootDuration: Time before the validity of a root expires.
function createGroup(
uint256 groupId,
uint256 depth,
uint256 zeroValue,
address admin,
uint256 merkleTreeRootDuration
) external;
@@ -80,6 +91,11 @@ interface ISemaphore {
/// @param newAdmin: New admin of the group.
function updateGroupAdmin(uint256 groupId, address newAdmin) external;
/// @dev Updates the group Merkle tree duration.
/// @param groupId: Id of the group.
/// @param newMerkleTreeDuration: New Merkle tree duration.
function updateGroupMerkleTreeDuration(uint256 groupId, uint256 newMerkleTreeDuration) external;
/// @dev Adds a new member to an existing group.
/// @param groupId: Id of the group.
/// @param identityCommitment: New identity commitment.

View File

@@ -1,12 +1,10 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
/// @title SemaphoreGroups interface.
/// @dev Interface of a SemaphoreGroups contract.
/// @title SemaphoreGroups contract interface.
interface ISemaphoreGroups {
error Semaphore__GroupDoesNotExist();
error Semaphore__GroupAlreadyExists();
error Semaphore__GroupIdIsNotLessThanSnarkScalarField();
/// @dev Emitted when a new group is created.
/// @param groupId: Id of the group.

View File

@@ -0,0 +1,37 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "../base/Pairing.sol";
/// @title SemaphoreVerifier contract interface.
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 whether a Semaphore 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

@@ -1,13 +1,13 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
/// @title SemaphoreVoting interface.
/// @dev Interface of SemaphoreVoting contract.
/// @title SemaphoreVoting contract interface.
interface ISemaphoreVoting {
error Semaphore__CallerIsNotThePollCoordinator();
error Semaphore__MerkleTreeDepthIsNotSupported();
error Semaphore__PollHasAlreadyBeenStarted();
error Semaphore__PollIsNotOngoing();
error Semaphore__YouAreUsingTheSameNillifierTwice();
enum PollState {
Created,
@@ -23,6 +23,7 @@ interface ISemaphoreVoting {
struct Poll {
address coordinator;
PollState state;
mapping(uint256 => bool) nullifierHashes;
}
/// @dev Emitted when a new poll is created.
@@ -39,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.
@@ -73,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

@@ -1,8 +1,7 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
/// @title SemaphoreWhistleblowing interface.
/// @dev Interface of SemaphoreWhistleblowing contract.
/// @title SemaphoreWhistleblowing contract interface.
interface ISemaphoreWhistleblowing {
error Semaphore__CallerIsNotTheEditor();
error Semaphore__MerkleTreeDepthIsNotSupported();
@@ -20,7 +19,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 +54,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,9 +1,10 @@
{
"name": "@semaphore-protocol/contracts",
"version": "2.2.0",
"version": "3.2.3",
"description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
"license": "MIT",
"files": [
"Semaphore.sol",
"**/*.sol"
],
"keywords": [
@@ -20,11 +21,8 @@
"circom",
"proof-of-membership"
],
"homepage": "https://github.com/semaphore-protocol/semaphore.git#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/semaphore-protocol/semaphore.git.git"
},
"repository": "https://github.com/semaphore-protocol/semaphore",
"homepage": "https://github.com/semaphore-protocol/semaphore/tree/main/packages/contracts",
"bugs": {
"url": "https://github.com/semaphore-protocol/semaphore.git/issues"
},
@@ -32,7 +30,7 @@
"access": "public"
},
"dependencies": {
"@openzeppelin/contracts": "4.4.2",
"@zk-kit/incremental-merkle-tree.sol": "1.3.0"
"@openzeppelin/contracts": "4.7.3",
"@zk-kit/incremental-merkle-tree.sol": "1.3.3"
}
}

View File

@@ -0,0 +1,7 @@
{
"Pairing": "0xE3a4C2FE9f025405cA6F60f6E960B4558604A74C",
"SemaphoreVerifier": "0xCAbeED6cB96a287000aBd834b0B79c05e6Ea4d07",
"Poseidon": "0xe0c8d1e53D9Bfc9071F6564755FCFf6cC0dB61d0",
"IncrementalBinaryTree": "0xcDF8efE6334c68aF283C83f2F14648da51fcfFb0",
"Semaphore": "0x72dca3c971136bf47BACF16A141f0fcfAC925aeC"
}

View File

@@ -0,0 +1,8 @@
{
"Semaphore": "0x89490c95eD199D980Cdb4FF8Bac9977EDb41A7E7",
"PoseidonT3": "0xe0A452533853310C371b50Bd91BB9DCC8961350F",
"IncrementalBinaryTree": "0x9Ed9f58CA9212Ddf0377C8C4Cd089748F9337820",
"Pairing": "0xE9c41c912CF750D79Cf304a196d4Bc8Dfd626C86",
"SemaphoreVerifier": "0x66e772B0B8Ee1c24E4b6aC99A3A82C77f431792E",
"Poseidon": "0xe0A452533853310C371b50Bd91BB9DCC8961350F"
}

View File

@@ -0,0 +1,7 @@
{
"Pairing": "0x3d3df6CFc6BFf68d9693e097F32bF4a9903E77a5",
"SemaphoreVerifier": "0x5f4edC58142f4395D1D536e793137A0252dA5a49",
"Poseidon": "0x181B7f34538cE3BceC68597d4A212aB3f7881648",
"IncrementalBinaryTree": "0x220fBdB6F996827b1Cf12f0C181E8d5e6de3a36F",
"Semaphore": "0xF864ABa335073e01234c9a88888BfFfa965650bD"
}

View File

@@ -0,0 +1,7 @@
{
"Pairing": "0xEFD83f827FA5B0496359D817c6CD8a5AA5D2aCe5",
"SemaphoreVerifier": "0x3d3df6CFc6BFf68d9693e097F32bF4a9903E77a5",
"Poseidon": "0x5f4edC58142f4395D1D536e793137A0252dA5a49",
"IncrementalBinaryTree": "0x181B7f34538cE3BceC68597d4A212aB3f7881648",
"Semaphore": "0x220fBdB6F996827b1Cf12f0C181E8d5e6de3a36F"
}

View File

@@ -0,0 +1,7 @@
{
"Pairing": "0xEFD83f827FA5B0496359D817c6CD8a5AA5D2aCe5",
"SemaphoreVerifier": "0x3d3df6CFc6BFf68d9693e097F32bF4a9903E77a5",
"Poseidon": "0x5f4edC58142f4395D1D536e793137A0252dA5a49",
"IncrementalBinaryTree": "0x181B7f34538cE3BceC68597d4A212aB3f7881648",
"Semaphore": "0x220fBdB6F996827b1Cf12f0C181E8d5e6de3a36F"
}

View File

@@ -1,6 +1,6 @@
import "@nomicfoundation/hardhat-chai-matchers"
import "@nomiclabs/hardhat-ethers"
import "@nomiclabs/hardhat-etherscan"
import "@nomiclabs/hardhat-waffle"
import "@typechain/hardhat"
import { config as dotenvConfig } from "dotenv"
import "hardhat-gas-reporter"
@@ -13,26 +13,42 @@ 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") })
dotenvConfig({ path: resolve(__dirname, "../../.env") })
function getNetworks(): NetworksUserConfig | undefined {
if (process.env.INFURA_API_KEY && process.env.BACKEND_PRIVATE_KEY) {
const infuraApiKey = process.env.INFURA_API_KEY
const accounts = [`0x${process.env.BACKEND_PRIVATE_KEY}`]
function getNetworks(): NetworksUserConfig {
if (!process.env.INFURA_API_KEY || !process.env.BACKEND_PRIVATE_KEY) {
return {}
}
return {
goerli: {
url: `https://goerli.infura.io/v3/${infuraApiKey}`,
chainId: 5,
accounts
},
arbitrum: {
url: "https://arb1.arbitrum.io/rpc",
chainId: 42161,
accounts
}
const infuraApiKey = process.env.INFURA_API_KEY
const accounts = [`0x${process.env.BACKEND_PRIVATE_KEY}`]
return {
goerli: {
url: `https://goerli.infura.io/v3/${infuraApiKey}`,
chainId: 5,
accounts
},
sepolia: {
url: `https://sepolia.infura.io/v3/${infuraApiKey}`,
chainId: 11155111,
accounts
},
mumbai: {
url: `https://polygon-mumbai.infura.io/v3/${infuraApiKey}`,
chainId: 80001,
accounts
},
"optimism-goerli": {
url: `https://optimism-goerli.infura.io/v3/${infuraApiKey}`,
chainId: 420,
accounts
},
arbitrum: {
url: `https://arbitrum-mainnet.infura.io/v3/${infuraApiKey}`,
chainId: 42161,
accounts
}
}
}

View File

@@ -0,0 +1,68 @@
{
"name": "contracts",
"private": true,
"scripts": {
"start": "hardhat node",
"compile": "hardhat compile",
"deploy:semaphore": "hardhat deploy:semaphore",
"deploy:semaphore-voting": "hardhat deploy:semaphore-voting",
"deploy:semaphore-whistleblowing": "hardhat deploy:semaphore-whistleblowing",
"verify:contracts": "hardhat run scripts/verify-contracts.ts",
"test": "hardhat test",
"test:report-gas": "REPORT_GAS=true hardhat test",
"test:coverage": "hardhat coverage",
"typechain": "hardhat typechain",
"lint": "solhint 'contracts/**/*.sol'"
},
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^1.0.5",
"@nomiclabs/hardhat-ethers": "^2.0.6",
"@nomiclabs/hardhat-etherscan": "^3.1.7",
"@semaphore-protocol/group": "workspace:packages/group",
"@semaphore-protocol/identity": "workspace:packages/identity",
"@semaphore-protocol/proof": "workspace:packages/proof",
"@typechain/ethers-v5": "^10.0.0",
"@typechain/hardhat": "^6.0.0",
"@types/chai": "^4.3.0",
"@types/download": "^8.0.1",
"@types/mocha": "^9.1.0",
"@types/node": "^17.0.12",
"@types/rimraf": "^3.0.2",
"chai": "^4.3.5",
"circomlib": "^2.0.2",
"circomlibjs": "^0.0.8",
"download": "^8.0.0",
"ethers": "^5.6.8",
"hardhat": "^2.9.7",
"hardhat-gas-reporter": "^1.0.8",
"js-logger": "^1.6.1",
"prettier-plugin-solidity": "^1.0.0-beta.19",
"rimraf": "^3.0.2",
"snarkjs": "^0.4.13",
"solhint": "^3.3.6",
"solhint-plugin-prettier": "^0.0.5",
"solidity-coverage": "^0.7.21",
"ts-node": "^10.4.0",
"typechain": "^8.0.0"
},
"config": {
"solidity": {
"version": "0.8.4"
},
"paths": {
"contracts": "./contracts",
"circuit": "./circuit",
"tests": "./test",
"cache": "./cache",
"snarkjs-templates": "./snarkjs-templates",
"build": {
"contracts": "./build/contracts",
"typechain": "./build/typechain"
}
}
},
"dependencies": {
"@openzeppelin/contracts": "4.7.3",
"@zk-kit/incremental-merkle-tree.sol": "1.3.3"
}
}

View File

@@ -0,0 +1,21 @@
import { readFileSync, writeFileSync } from "fs"
type DeployedContracts = {
Pairing: string
SemaphoreVerifier: string
Poseidon: string
IncrementalBinaryTree: string
Semaphore: string
}
export function getDeployedContracts(network: string | undefined): DeployedContracts | null {
try {
return JSON.parse(readFileSync(`./deployed-contracts/${network}.json`, "utf8"))
} catch (error) {
return null
}
}
export function saveDeployedContracts(network: string | undefined, deployedContracts: DeployedContracts) {
writeFileSync(`./deployed-contracts/${network}.json`, JSON.stringify(deployedContracts, null, 4))
}

View File

@@ -0,0 +1,31 @@
import { hardhatArguments, run } from "hardhat"
import { getDeployedContracts } from "./utils"
async function verify(address: string, constructorArguments?: any[]): Promise<void> {
try {
await run("verify:verify", {
address,
constructorArguments
})
} catch (error) {
console.error(error)
}
}
async function main() {
const deployedContracts = getDeployedContracts(hardhatArguments.network)
if (deployedContracts) {
await verify(deployedContracts.IncrementalBinaryTree)
await verify(deployedContracts.Pairing)
await verify(deployedContracts.SemaphoreVerifier)
await verify(deployedContracts.Semaphore, [deployedContracts.SemaphoreVerifier])
}
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})

Some files were not shown because too many files have changed in this diff Show More