Compare commits

...

444 Commits

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

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

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

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

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

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

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

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

Former-commit-id: cf9f804651
2022-11-09 12:43:24 +01:00
cedoor
a9f8379545 refactor(groups): make attribute public and update method name
Former-commit-id: 822561a015
2022-11-09 12:29:58 +01:00
cedoor
ac3e7b42a3 chore: v2.6.1
Former-commit-id: ec5c69a795
2022-10-26 16:31:48 +02:00
cedoor
2b414f8c24 fix: set correct thegraph api urls
Former-commit-id: 29ebbe3b09
2022-10-26 16:28:26 +02:00
cedoor
1fcff83c1a style: format code with prettier
Former-commit-id: a5f1d80d84
2022-10-26 16:16:37 +02:00
cedoor
eb2d6ee62b chore: update arbitrum contract addresses
Former-commit-id: 6a60f727b8
2022-10-26 16:14:38 +02:00
cedoor
db624c24e0 style: format code with prettier
Former-commit-id: 9564ad19f0
2022-10-24 12:28:19 +02:00
cedoor
95e5ff669b chore: update goerli contract addresses
Former-commit-id: 88f44c3f49
2022-10-24 12:13:19 +02:00
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
cedoor
12982f338a chore(contracts): v2.2.0
Former-commit-id: 8dc2c85b19
2022-09-14 15:31:32 +02:00
cedoor
47c7923723 Merge pull request #133 from semaphore-protocol/feat/member-index
feat: add member index parameter to events
Former-commit-id: 2bbacbe7cd
2022-09-14 15:30:02 +02:00
cedoor
a35a505b92 docs: fix typo
Former-commit-id: bcf09a6dd2
2022-09-14 15:25:34 +02:00
cedoor
9487de51b4 fix: set correct index value
Former-commit-id: cf3e877b36
2022-09-14 15:24:52 +02:00
cedoor
65fbd732f2 feat: add member index parameter to events
Former-commit-id: 21c461aaaf
2022-09-14 14:56:48 +02:00
cedoor
e6fe600ed0 docs: replace telegram chat with discord server
Former-commit-id: 8e841a36e5
2022-09-14 10:34:10 +02:00
cedoor
28694d3413 style: reformat code with prettier
Former-commit-id: c99579768a
2022-09-13 13:46:19 +02:00
cedoor
d5d065dfb0 chore: deploy new semaphore contract on georli
Former-commit-id: c179870662
2022-09-13 13:44:03 +02:00
cedoor
cb96c7c237 Merge branch 'dev' of github.com:semaphore-protocol/semaphore into dev
Former-commit-id: d9f23f76b4
2022-09-13 13:29:25 +02:00
cedoor
cca4cf4922 chore: remove kovan network
Former-commit-id: 6880f0d7f7
2022-09-13 13:28:29 +02:00
cedoor
a97a150e98 Merge pull request #131 from semaphore-protocol/feat/add-members
Function to add multiple members

Former-commit-id: 16b571fad9
2022-09-13 12:06:35 +02:00
cedoor
5167710bb2 feat: add function to add multiple members
Former-commit-id: 0100beafc7
2022-09-13 10:56:42 +02:00
cedoor
af878df5ab Merge pull request #129 from semaphore-protocol/refactor/extensions
Refactoring of extensions contracts

Former-commit-id: 2c2c02f82b
2022-09-09 16:34:23 +02:00
cedoor
e4e895a881 chore: update lockfile
Former-commit-id: be83f13ae8
2022-09-09 16:31:05 +02:00
cedoor
95ab343fcc refactor: create solidity errors for extensions
Former-commit-id: 4debf04e1b
2022-09-09 16:23:43 +02:00
cedoor
4f36e0587c refactor: create verifier struct for extensions
Former-commit-id: dad7efb9dd
2022-09-09 15:43:09 +02:00
cedoor
f50a0765fd chore: v2.1.0
Former-commit-id: 7620927c3c
2022-09-09 15:26:22 +02:00
cedoor
7739050346 Merge pull request #128 from semaphore-protocol/feat/update-member
New function to update group members

Former-commit-id: 2d4f2deb0a
2022-09-09 13:44:04 +02:00
cedoor
07f2e14fcb style: format code with prettier
Former-commit-id: 52837e7434
2022-09-09 13:38:17 +02:00
cedoor
f7d20a4760 feat: add function to update group members
Former-commit-id: 52645ae61a
2022-09-09 13:24:30 +02:00
cedoor
65e6d7b16c Merge pull request #124 from semaphore-protocol/feat/root-expirations
Merkle tree expiries

Former-commit-id: 4a94fb19a5
2022-09-09 11:39:43 +02:00
cedoor
dfac0716a5 feat: create struct for merkle tree expiries
Former-commit-id: eeb1a04baf
2022-09-09 11:33:14 +02:00
cedoor
43850ecd3c style: format code with prettier
Former-commit-id: aa01cd1016
2022-09-09 10:16:35 +02:00
cedoor
125947d179 feat: add merkle tree root expirations
Former-commit-id: 3495e147f1
2022-09-09 10:16:35 +02:00
cedoor
4643775745 refactor: update tree variable names
Former-commit-id: c191dbe0fc
2022-09-09 10:16:35 +02:00
cedoor
dd6b7765cf chore: update semaphore libraries
Former-commit-id: c2e0f372f1
2022-09-09 10:16:35 +02:00
cedoor
b7597485ec Merge pull request #126 from semaphore-protocol/fix/merkle-tree-dep
fix: bump version of incremental merkle tree pkg
Former-commit-id: f2bb6731eb
2022-09-09 10:13:24 +02:00
cedoor
47b06b057c fix: bump version of incremental merkle tree pkg
Former-commit-id: 5cd191e2d7
2022-09-09 09:57:19 +02:00
cedoor
c06a836687 fix: update tree depth uint type
Former-commit-id: 0f0fc95832
2022-08-22 18:59:51 +02:00
cedoor
7b3acfd68f Merge pull request #119 from semaphore-protocol/chore/etherscan-verification
Etherscan verification

Former-commit-id: 361bbf2d84
2022-08-22 18:57:51 +02:00
cedoor
972cbb632b chore: verify contracts on right networks
Former-commit-id: cfd678def2
2022-08-22 18:45:37 +02:00
cedoor
b37b0e2d7a chore: add @nomiclabs/hardhat-etherscan package
Former-commit-id: adc4489e19
2022-08-22 18:44:59 +02:00
cedoor
48928db10f chore: add etherscan verification after deployments
Former-commit-id: 03b9aa4198
2022-08-22 18:15:10 +02:00
cedoor
5fdf6c6547 style: format code with prettier
Former-commit-id: 4a2fddc5a0
2022-08-18 13:45:12 +02:00
cedoor
8be15f2926 Merge pull request #118 from DevABDee/main
Little More Gas Optimization

Former-commit-id: 7390c28ea1
2022-08-18 13:35:11 +02:00
ABDul Rehman
baf7b80f64 Merge branch 'semaphore-protocol:main' into main
Former-commit-id: 3b292393de
2022-08-17 21:18:52 +05:00
ABDul Rehman
b501fd6f01 Gas Optimization
Former-commit-id: bb7470ae8a
2022-08-17 21:17:43 +05:00
cedoor
78cbd16cb6 Merge pull request #117 from DevABDee/main
Little Gas Optimization

Former-commit-id: 96608b573d
2022-08-16 20:57:27 +02:00
ABDul Rehman
94331b07b0 Gas Optimization
Former-commit-id: e2912f1c0b
2022-08-16 18:06:51 +05:00
ABDul Rehman
f9ff3b1ac2 Gas Optimization
Former-commit-id: a87ea48b7f
2022-08-14 02:14:01 +05:00
cedoor
f59588ac2f Merge pull request #116 from DevABDee/main
Fix #115, Pragma Fixed

Former-commit-id: 708d93ce08
2022-08-10 17:02:29 +02:00
ABDul Rehman
b285a19186 Pragme Fixed
Former-commit-id: 866c54ddfe
2022-08-10 18:15:18 +05:00
cedoor
5e58a2dc4a perf: replace require with new gas-efficient errors
Former-commit-id: 9da8843487
2022-07-26 00:22:37 +02:00
cedoor
b7b6e452d8 chore: update snark artifacts url
Former-commit-id: 45b8e95a45
2022-07-26 00:20:00 +02:00
cedoor
78dcfe1816 chore: update lockfile
Former-commit-id: c9e20093e0
2022-07-26 00:19:22 +02:00
cedoor
f67cafeb02 Merge pull request #113 from DevABDee/main
Gas Optimized Semaphore.sol

Former-commit-id: 92c3b59cc1
2022-07-25 23:48:59 +02:00
AB Dee
9ca5d8b8cb Gas Optimized Semaphore.sol
Former-commit-id: c425695202
2022-07-25 19:49:34 +05:00
cedoor
b80fe7d1d9 chore: update incremental-merkle-tree.sol pkg
Former-commit-id: 76e5be06b2
2022-07-04 20:01:18 +02:00
cedoor
bf2f8024e3 chore: add yarn option to update lockfile
Former-commit-id: 44b5966633
2022-06-24 17:11:23 +02:00
cedoor
ba6acccffb docs: set dark-theme semaphore icon
Former-commit-id: e48d602c0e
2022-06-23 11:44:40 +02:00
cedoor
e829885311 style: format code with prettier
Former-commit-id: aba96f84f8
2022-06-22 20:31:31 +02:00
cedoor
84e92ed975 chore: deploy contracts on arbitrum
Former-commit-id: 1357c94b59
2022-06-22 20:17:38 +02:00
cedoor
05adc1e2fe chore(contracts): v2.0.0
Former-commit-id: 24c5bce29a
2022-06-22 11:29:09 +02:00
cedoor
971b354e1c chore: update semaphore-protocol packages
Former-commit-id: a9bc12927f
2022-06-15 15:27:06 +02:00
cedoor
fa1e86c3b0 chore: update prettier ignore file
Former-commit-id: 77ef2e4883
2022-06-09 10:43:55 +02:00
cedoor
621f56a0c6 docs: add network template
Former-commit-id: f538af070b
2022-06-09 10:42:04 +02:00
cedoor
5470804e1c ci: ignore checksum checks
Former-commit-id: 31d746e8e6
2022-06-08 14:45:30 +02:00
cedoor
17e683debe ci: add yarn command to update cache
Former-commit-id: 2c0e93923b
2022-06-08 14:16:09 +02:00
cedoor
29090843aa chore: update ethereum-waffle package
Former-commit-id: b2f71bbae9
2022-06-08 14:15:52 +02:00
cedoor
d7c677bb05 chore: update dependencies
Former-commit-id: 06ef87c734
2022-06-08 14:00:20 +02:00
cedoor
16ebaa61e5 ci: remove cache option
Former-commit-id: c9fc9a7b1e
2022-06-08 13:29:37 +02:00
cedoor
52581a6d56 ci: update github workflows and add cache action
Former-commit-id: 633fab3de4
2022-06-08 13:08:24 +02:00
cedoor
43803ec21d chore: update yarn to v3
Former-commit-id: a8fb2e8e50
2022-06-08 13:07:57 +02:00
cedoor
79313cbf6c chore: update ignore files
Former-commit-id: ba11a0ab35
2022-06-08 13:07:08 +02:00
cedoor
36c3252b0c docs(readme): add label for style github workflow
Former-commit-id: 16041ca76e
2022-06-08 13:06:28 +02:00
cedoor
168215d23e docs(readme): update usage section
Former-commit-id: bd90739de0
2022-06-08 12:29:33 +02:00
cedoor
75bef955ab docs(readme): add readme for contracts npm package
Former-commit-id: 2a84024d10
2022-06-08 12:09:58 +02:00
cedoor
68a65f9645 docs(readme): remove audit warning
Former-commit-id: 58f385fa7e
2022-06-07 15:16:33 +02:00
cedoor
13b724a34f docs: replace zk-kit with semaphore.js libs
Former-commit-id: add2e545dc
2022-06-06 16:36:37 +02:00
cedoor
073ec22b34 refactor: replace zk-kit packages with semaphore.js
Former-commit-id: bfa909f7e8
2022-06-06 15:35:28 +02:00
cedoor
5d6f7b0629 style: format code with prettier
Former-commit-id: 7826f6f7b3
2022-06-06 15:35:01 +02:00
cedoor
75fc12f867 ci: add env variables
Former-commit-id: e24ca5f8f4
2022-06-06 12:07:24 +02:00
cedoor
e21ccedc15 chore: update scripts to download snark artifacts
Former-commit-id: d9c069784f
2022-06-06 12:01:24 +02:00
cedoor
68187531a5 chore: remove unused extensions
Former-commit-id: 0ae62c1f16
2022-06-06 12:00:27 +02:00
cedoor
3dba37fd06 chore: add env variable for tree depth
Former-commit-id: 496d0748a5
2022-06-06 11:59:37 +02:00
cedoor
17234ddfd2 docs: update description
Former-commit-id: ae439cac78
2022-05-31 23:24:08 +02:00
cedoor
536cf452bb ci: add command to download zk files
Former-commit-id: e064191ba7
2022-05-31 19:15:03 +02:00
cedoor
efe56e80ac chore: ignore verifiers from test coverage
Former-commit-id: 0bcba687e8
2022-05-31 19:14:49 +02:00
cedoor
f09e930857 docs: update package descriptions
Former-commit-id: abc77d0cb4
2022-05-31 19:01:21 +02:00
cedoor
2e5650a5b8 chore: v0.2.0
Former-commit-id: b591914573
2022-05-31 18:49:15 +02:00
cedoor
7c3763c012 Merge pull request #109 from semaphore-protocol/feat/new-verifiers
Feat/new verifiers

Former-commit-id: d24c516e73
2022-05-31 18:25:53 +02:00
cedoor
e67cf5d75b style: format code with prettier
Former-commit-id: 491ec8b864
2022-05-31 18:22:30 +02:00
cedoor
5a99b66f18 chore: add some env variables
Former-commit-id: f5bc809010
2022-05-31 18:20:50 +02:00
cedoor
df9286a455 docs: add install and usage sections
Former-commit-id: 280289171f
2022-05-31 18:19:55 +02:00
cedoor
f4dd5ba694 chore: add new script to deploy all contracts
Former-commit-id: 2145c141a1
2022-05-30 21:34:55 +02:00
cedoor
8c49c4ed14 docs: update contract addresses
Former-commit-id: 6083ffdb72
2022-05-30 20:17:29 +02:00
cedoor
1f805543e8 ci: add script to download zk files
Former-commit-id: 89b5644c02
2022-05-30 20:17:29 +02:00
cedoor
a674301faf test: update tests with new verifiers
Former-commit-id: 44e21911c5
2022-05-30 20:17:16 +02:00
cedoor
12e92840a4 feat: add new scripts
Former-commit-id: c70b85e36c
2022-05-30 20:17:16 +02:00
cedoor
ac7f03a695 feat: generate new verifier contracts
Former-commit-id: 9c4b9efa10
2022-05-30 20:17:16 +02:00
cedoor
20036c3739 chore: remove old zk files
Former-commit-id: 550c9edc04
2022-05-30 20:17:16 +02:00
cedoor
8826ddb47b docs: add section for issues
Former-commit-id: 6fd358f8a2
2022-05-26 21:37:21 +02:00
cedoor
c074930aad chore: add issue template for semaphore projects
Former-commit-id: 22345287f5
2022-05-26 21:32:04 +02:00
cedoor
f2a1d50603 chore: update PR template
Former-commit-id: 2664ea8cdc
2022-05-26 21:07:05 +02:00
cedoor
3dc63c83bb docs: update issues' link
Former-commit-id: 608fa4f07a
2022-05-26 20:56:27 +02:00
cedoor
0f62fe1356 chore: remove old issue templates
Former-commit-id: d232e4546b
2022-05-26 20:31:20 +02:00
cedoor
10562ca54f chore: update issue templates
Former-commit-id: 943616f091
2022-05-26 20:30:21 +02:00
cedoor
f237a44980 docs: fix language label repo link
Former-commit-id: d2fc3543d3
2022-05-24 12:41:37 +02:00
cedoor
ec99ab0759 docs: update repo links
Former-commit-id: e69ba9f384
2022-05-24 12:40:06 +02:00
cedoor
7c48005647 chore: update repo links
Former-commit-id: ee7aad1dd7
2022-05-19 11:32:04 +02:00
cedoor
3b61ceebde chore: update license holder
Former-commit-id: f86e5b4217
2022-05-19 11:31:54 +02:00
cedoor
0d43e0b4c8 chore: update contracts package name
Former-commit-id: 35735c4e87
2022-05-17 12:54:11 +02:00
cedoor
6cf990bc22 Merge pull request #100 from semaphore-protocol/feat/new-snarks-template
feat: create new snarkjs groth16 template
Former-commit-id: 7f2042312d
2022-05-17 11:40:37 +02:00
cedoor
9875778ad9 chore: move docs to semaphore-protocol org
Former-commit-id: d88e4e9146
2022-05-07 11:01:21 +02:00
cedoor
6ef014fa7c chore: v0.10.0
Former-commit-id: 6d4bb60ea9
2022-05-07 10:58:06 +02:00
cedoor
06fbe09823 feat: add zero value parameter
Former-commit-id: 339d3ac7da
2022-05-07 10:56:51 +02:00
cedoor
80d3ffb622 chore: v0.9.0
Former-commit-id: 368b5ce2f2
2022-05-04 19:36:25 +02:00
cedoor
52dbe8b14e docs: add missing word
Former-commit-id: 5bd3df387d
2022-05-04 18:38:53 +02:00
cedoor
c4207c73b0 chore: remove unused cname file
Former-commit-id: 207da78b1a
2022-05-04 18:37:52 +02:00
cedoor
45a74798c7 Merge pull request #104 from appliedzkp/feat/semaphore-contract
feat: create new semaphore deployable contract
Former-commit-id: 248d7873df
2022-05-04 18:34:55 +02:00
cedoor
5e7c3a5ae9 style: format code with prettier
Former-commit-id: b29d6c5ba6
2022-05-04 18:32:15 +02:00
cedoor
4975db4f58 docs: add section for semaphore deployed contracts
Former-commit-id: 2f50cbd13f
2022-05-04 18:31:41 +02:00
cedoor
aa96f0bbc1 feat: create new semaphore deployable contract
Former-commit-id: 87c379f5a9
2022-05-04 15:46:07 +02:00
cedoor
6e5c6fc84c docs: fix broken link
Former-commit-id: c8fc878324
2022-05-04 11:05:27 +02:00
cedoor
8c1119dba1 Merge pull request #103 from 0xorbus/3-fix-quick-setup-tutorial
3 fix quick setup tutorial

Former-commit-id: 3ce7e3b8f3
2022-05-04 10:59:14 +02:00
0xorbus
68f4bead0e docs: quick-setup.md
- fix indent.

Former-commit-id: 9aa5b656a7
2022-05-03 22:33:07 -07:00
0xorbus
bd78a71387 docs: quick-setup.md
- fix indent

Former-commit-id: c24fe8cf6c
2022-05-03 22:32:08 -07:00
0xorbus
e8f34ea272 docs: update quick-setup.md
- improve static files requirement.

Former-commit-id: 35fe024e98
2022-05-03 22:29:54 -07:00
0xorbus
2a4e92449b Update quick-setup.md
- Cleanup and organize quick-setup.md

Former-commit-id: 6e6c5aacd3
2022-05-03 22:26:55 -07:00
0xorbus
57b61614c4 docs(quick-setup): fix contract, tests, and instructions
- Update Greeters.sol to match the example repo and fix the missing variables error.
- Add chai to dependencies to install for hardhat-waffle.
- Remove unnecessary $ to prevent copying them.
- Fix text.
- Add explanation.


Former-commit-id: 6ab4526b0e
2022-05-01 19:07:20 -05:00
0xorbus
45f48799f0 wip: remove unnecessary $ terminal prompts.
Former-commit-id: 079e6eac27
2022-05-01 18:32:14 -05:00
cedoor
42c934ec1b docs: set correct etherscan link
Former-commit-id: 95f127d149
2022-04-22 17:57:03 +02:00
cedoor
35822a480e feat: integrate georli network
Former-commit-id: 84d70cb863
2022-04-22 12:14:24 +02:00
cedoor
56edbb6cd7 chore: remove unused images
Former-commit-id: 72dbe85827
2022-04-19 16:35:33 +02:00
cedoor
d0962fda19 chore: update semaphore icon
Former-commit-id: 2b5849077d
2022-04-19 11:54:46 +02:00
cedoor
d17c4a6e0c chore: v0.8.1
Former-commit-id: 6b84d41ca3
2022-04-13 12:50:48 +02:00
cedoor
4080f4af20 docs: update quick-setup contract code
Former-commit-id: 64a63cbceb
2022-04-13 12:50:16 +02:00
Omar Desogus
9e74e1a278 Merge pull request #102 from 0xorbus/docs/basic-features
Docs/basic features

Former-commit-id: 7f0568b10c
2022-04-13 12:48:58 +02:00
0xorbus
a8e0c1474c docs: fix quick setup
- improve instruction
- fix caps
- fix list indent


Former-commit-id: ab88231e92
2022-04-12 21:44:12 -05:00
cedoor
d1fcf8bfe2 chore: update wrong license
Former-commit-id: ae7e18c120
2022-04-12 17:19:17 +02:00
0xorbus
5a895f42f8 docs: Replace names with handles.
- Quick start: replace package names with handles.


Former-commit-id: 702fbd406b
2022-04-12 00:01:15 -05:00
0xorbus
8a44757417 docs: revise Quick setup
- Revise intro, Hardhat, and libraries description.


Former-commit-id: d7da4e9fa8
2022-04-11 23:53:10 -05:00
0xorbus
ad1d77b200 docs: explain base contract step
- Provide context about importing Semaphore base contract.
- Add link.


Former-commit-id: e51af6e0e1
2022-04-11 23:51:49 -05:00
0xorbus
c31b9490ed docs: revise Quick Setup
- Revise Quick Setup intro and instructions.
- Make related and advanced usage less distracting for new devs.
- Add instruction to use Node.JS LTS given Hardhat install fails with
  Node.JS current.


Former-commit-id: bea97dae22
2022-04-11 23:51:49 -05:00
cedoor
4aeeb3e1cc docs: update quick-setup section
Former-commit-id: 42e6020380
2022-04-11 19:41:38 +02:00
cedoor
23dac4c6ed chore: deploy new verifier
Former-commit-id: b7aa75194c
2022-04-11 19:28:44 +02:00
cedoor
4c4bfb568a chore: v0.8.0
Former-commit-id: 54a5801b16
2022-04-11 19:15:51 +02:00
Omar Desogus
8595e3cd0f Merge pull request #101 from 0xorbus/docs/basic-features
docs:update links and revise docs instructions
Former-commit-id: 9f19a259de
2022-04-06 18:11:16 +02:00
0xorbus
01a5b156bb docs: Update docs/README.md
- Revise intro
Former-commit-id: e48e85b58c
2022-04-06 08:38:56 -05:00
0xorbus
dd19a5e213 docs:update links and revise docs instructions
- Update links to the new domain.
- Revise install, build, and run instructions for docs contributors.


Former-commit-id: b6cf8a2b6c
2022-04-06 08:21:29 -05:00
cedoor
9e2b54ef16 feat: create new snarkjs groth16 template
Former-commit-id: 74a5653406
2022-04-04 11:57:02 +02:00
Omar Desogus
51fe424473 Merge pull request #96 from recmo/recmo/chore-cleanup-verifier
Cleanup Verifier.sol and make error handling consistent

Former-commit-id: d001dd928b
2022-04-04 11:01:44 +02:00
Remco Bloemen
5dbfaf3518 Run prettier
Former-commit-id: 2ddf0f0b2e
2022-04-03 14:54:13 -07:00
Remco Bloemen
4e18efb75c Remove redundant return value.
Former-commit-id: 3e4a493177
2022-04-02 15:05:04 -07:00
cedoor
55a89753bb chore: update package.json license
Former-commit-id: 36824964f5
2022-03-31 19:06:09 +02:00
Omar Desogus
8105d9761b Merge pull request #99 from appliedzkp/chore/new-license
Update LICENSE

Former-commit-id: e19b78e90e
2022-03-31 19:01:57 +02:00
Omar Desogus
55cef34142 Update LICENSE
Former-commit-id: cfe2d92f58
2022-03-31 18:53:35 +02:00
Remco Bloemen
bf42264033 Minor fixes
Former-commit-id: 3be4b8cf49
2022-03-24 12:07:12 -07:00
Remco Bloemen
0035a62d7a Strict input validation in Pairing library
Former-commit-id: 7ec0831817
2022-03-24 10:36:59 -07:00
Remco Bloemen
d34bded3cc Unroll loop
Former-commit-id: cfa237ec90
2022-03-23 16:05:56 -07:00
Remco Bloemen
e156cf77c2 Update tests
Former-commit-id: 39cd58d218
2022-03-23 16:04:09 -07:00
Remco Bloemen
4d662a4a0d Changelog
Former-commit-id: 6407cefc40
2022-03-23 15:58:59 -07:00
Remco Bloemen
67e907da2c Remove redundant check
Former-commit-id: a46219f35f
2022-03-23 15:57:07 -07:00
Remco Bloemen
7771f15e5a Avoid an addition
Former-commit-id: 4ced797f9b
2022-03-23 15:53:14 -07:00
Remco Bloemen
aff0c87366 Inline pairingProd4
Former-commit-id: f263f40c13
2022-03-23 15:48:58 -07:00
Remco Bloemen
77bc53d9a7 Remove unused code
Former-commit-id: d205047891
2022-03-23 15:38:58 -07:00
Remco Bloemen
2965d8decf always throw on invalid proof
Former-commit-id: fde613e9c2
2022-03-23 15:37:56 -07:00
Remco Bloemen
528ad6ef4e Remove unused code
Former-commit-id: 475165fb77
2022-03-23 15:05:31 -07:00
Remco Bloemen
bd2145dc09 Moduli constants
Former-commit-id: 66681720bb
2022-03-23 11:59:11 -07:00
Remco Bloemen
67dd25e604 Inline verify
Former-commit-id: edd06371aa
2022-03-23 11:53:37 -07:00
Remco Bloemen
25379748e6 Avoid unecessary copy
Former-commit-id: 6677c27f92
2022-03-23 11:51:45 -07:00
Remco Bloemen
9e6c0df6a2 Remove invalid() hack
Former-commit-id: f4afe22822
2022-03-23 11:49:42 -07:00
Remco Bloemen
07cbe28701 Verify returns bool
Former-commit-id: 4c5fa94650
2022-03-23 11:42:05 -07:00
cedoor
d212947d07 chore: v0.7.0
Former-commit-id: 27ae2fd99e
2022-03-17 12:11:45 +01:00
Omar Desogus
bdffdfe200 Merge pull request #95 from appliedzkp/refactor/root-history
refactor: remove root history mapping
Former-commit-id: 555b397634
2022-03-17 12:09:16 +01:00
cedoor
a8922efae1 refactor: remove root history mapping
Former-commit-id: c6667d98b8
2022-03-17 12:02:19 +01:00
Omar Desogus
4ee9913035 Merge pull request #94 from CDDelta/patch-1
docs: correct `Nullifier` technical reference inputs
Former-commit-id: 4e6be04729
2022-03-12 14:02:04 +01:00
CDDelta
04df22ed56 docs: correct Nullifier technical reference inputs
Former-commit-id: 5c6d1a6af2
2022-03-12 16:07:54 +11:00
cedoor
abc8ef3cf6 chore: v0.6.2
Former-commit-id: 3d846dafbb
2022-03-10 18:52:14 +01:00
Omar Desogus
c2a8aee15e Merge pull request #93 from vplasencia/patch-1
Just a little typo Merke -> Merkle

Former-commit-id: 6034131b0c
2022-03-10 14:31:28 +01:00
Vivian Plasencia
292ce60b81 Just a little typo Merke -> Merkle
Former-commit-id: fa6410bd0c
2022-03-09 23:32:02 -05:00
Omar Desogus
3a64ab44dd Merge pull request #92 from tomoima525/tomoima525/fix-voting-interface
Correct interface arguments in Voting Contract

Former-commit-id: 7aff72cea8
2022-03-10 00:05:42 +01:00
Omar Desogus
d597b461a7 Merge pull request #91 from appliedzkp/fix/group-id-value
Fix/group id value

Former-commit-id: aacbb11640
2022-03-10 00:01:44 +01:00
Tomoaki Imai
a7a42f8d2c Correct interface arguments in Voting Contract
Former-commit-id: bd77784a3c
2022-03-09 10:13:34 -08:00
cedoor
9f7aa7955f chore: v0.6.1
Former-commit-id: 5d8243c879
2022-03-09 18:43:34 +01:00
cedoor
2ffaf28a12 fix: add check to ensure group id is valid zk value
Former-commit-id: fd3cc6f7db
2022-03-09 18:43:06 +01:00
cedoor
bfaeb19d14 chore: update zk-kit/incremental-merkle-tree.sol pkg
Former-commit-id: 8022e4bb50
2022-03-09 18:15:29 +01:00
cedoor
aed9fa6785 docs: update quick setup section
Former-commit-id: 5186a940ff
2022-03-04 12:44:32 +01:00
Omar Desogus
ac1ad33bfd Merge pull request #89 from appliedzkp/perf/signal-type
Perf/signal type

Former-commit-id: d70ae21ed9
2022-03-04 12:37:24 +01:00
cedoor
e0e366c52a chore: v0.6.0
Former-commit-id: a9ba5c550c
2022-03-04 12:33:51 +01:00
cedoor
e6f7df17a9 perf: change signal type from string to bytes32
Former-commit-id: a48eb58eff
2022-03-04 12:32:49 +01:00
cedoor
c610ddb45a chore: v0.5.0
Former-commit-id: 119c7d1880
2022-03-01 13:05:24 +01:00
cedoor
8c7d09a5c1 refactor: rename group 'getSize' function
Former-commit-id: db262484d0
2022-03-01 13:01:33 +01:00
cedoor
8d5968a3c0 docs: update quick-setup section
Former-commit-id: 1090307adf
2022-02-28 17:23:44 +01:00
cedoor
936e0d76a6 chore: update @zk-kit/protocols pkg
Former-commit-id: 79a15cd43b
2022-02-28 17:20:45 +01:00
cedoor
b5389fed3d chore: update @zk-kit/protocols pkg
Former-commit-id: 4aced8e73e
2022-02-27 19:37:40 +01:00
cedoor
5f1ed4e08e chore: v0.4.0
Former-commit-id: e56609cc4d
2022-02-25 11:03:53 +01:00
cedoor
37bb2976b8 feat: add parameter to set tree zero value
Former-commit-id: 547f5476f2
2022-02-25 10:59:38 +01:00
cedoor
17e6330798 style: format code with prettier
Former-commit-id: 116e683313
2022-02-25 10:59:06 +01:00
cedoor
a4ecc5a125 docs: update quick setup section
Former-commit-id: f0cf3327f7
2022-02-19 15:37:48 +01:00
cedoor
9bfe26d81d chore(contracts): v0.3.0
Former-commit-id: 6f870c84b9
2022-02-19 15:19:08 +01:00
Omar Desogus
9756917fc7 Merge pull request #88 from appliedzkp/feat/external-verifiers
Feat/external verifiers

Former-commit-id: b22e51c668
2022-02-18 22:19:28 +01:00
Omar Desogus
83e29909c3 docs: add deployed verifiers
Former-commit-id: d89e213abf
2022-02-18 16:07:48 +01:00
cedoor
ae22bd7be9 chore: add kovan & arbitrum networks
Former-commit-id: 7d88065862
2022-02-18 15:45:13 +01:00
cedoor
3295483a24 feat: make verifiers external contracts
Former-commit-id: 6fee508029
2022-02-18 15:36:34 +01:00
cedoor
b21a17ea70 chore: add prettier docs to be ignored
Former-commit-id: 69964939ea
2022-02-18 15:35:41 +01:00
cedoor
d1419045e3 docs: update interep links
Former-commit-id: bd0571d366
2022-02-16 17:54:01 +01:00
cedoor
c136ba809f docs: update technical circuit section
Former-commit-id: 6d724270cc
2022-02-15 11:34:51 +01:00
Omar Desogus
bf87f4a3af Merge pull request #87 from appliedzkp/feat/binary-tree
feat: replace quin tree with binary tree
Former-commit-id: 8546570942
2022-02-14 18:45:03 +01:00
cedoor
7ddd0e0920 docs: update quick-setup section
Former-commit-id: 4d85db7d40
2022-02-14 18:37:10 +01:00
cedoor
498d14cde1 chore(semaphore-contracts): v0.2.0
Former-commit-id: a2696d3729
2022-02-14 18:31:24 +01:00
cedoor
91867d53aa chore: update @zk-kit/protocols pkg
Former-commit-id: 0f576f972a
2022-02-14 18:20:37 +01:00
cedoor
dbc9ae303d test: update new identity commitments
Former-commit-id: 59a039fe5b
2022-02-14 17:58:42 +01:00
cedoor
0c9d717fa8 feat: replace quin tree with binary tree
Former-commit-id: 3bce72febe
2022-02-14 17:44:00 +01:00
cedoor
a6256d2cdb chore: update @zk-kit/protocols pkg
Former-commit-id: 286bb4a7b1
2022-02-14 13:59:35 +01:00
cedoor
9944eb3746 chore: update @zk-kit/protocols pkg
Former-commit-id: 0aaf342470
2022-02-14 13:29:46 +01:00
cedoor
d5fd1f99a3 docs: add semaphore v1 reference
Former-commit-id: 06beb5864a
2022-02-14 13:29:08 +01:00
Omar Desogus
71dc72daa8 Merge pull request #61 from appliedzkp/version/2.0.0
version 2.0

Former-commit-id: fffab693e1
2022-02-14 12:36:32 +01:00
cedoor
7dd398ebd9 docs: update quick-setup section
Former-commit-id: 928b4094f3
2022-02-14 12:23:16 +01:00
cedoor
28990a27f3 docs: update quick-setup section
Former-commit-id: f60cf41495
2022-02-14 12:18:56 +01:00
cedoor
7993440e53 chore: update @zk-kit/protocols pkg
Former-commit-id: eb611ddc63
2022-02-14 12:15:11 +01:00
cedoor
05c26c108c docs: update technical reference sections
Former-commit-id: a2bc731c77
2022-02-14 10:50:44 +01:00
cedoor
940e6fcb75 docs: remove old content
Former-commit-id: fc0e55368e
2022-02-14 10:50:00 +01:00
cedoor
31e885a075 docs: update introduction
Former-commit-id: 3a6289402e
2022-02-13 12:34:08 +01:00
cedoor
d37deffb73 docs: init contract & zk-kit technical sections
Former-commit-id: 77859a6424
2022-02-13 12:33:56 +01:00
Omar Desogus
9285fe54e6 docs: remove install & usage sections
Former-commit-id: 5bcbe8d483
2022-02-13 11:50:36 +01:00
cedoor
7095e03162 docs: fix worng link
Former-commit-id: adf6a0f866
2022-02-12 16:06:27 +01:00
cedoor
ce09c9e4dd docs: update offchain function to create 0 value
Former-commit-id: e029c722b6
2022-02-12 15:59:55 +01:00
cedoor
17d616e0ba chore: add verification_key zk file
Former-commit-id: ef8c4a7bfe
2022-02-12 15:59:04 +01:00
cedoor
af6f040429 docs: update quick-setup section
Former-commit-id: 8605f3a5b1
2022-02-12 15:58:32 +01:00
cedoor
eeb65e4639 docs: update introduction section
Former-commit-id: f075a148e1
2022-02-12 15:58:14 +01:00
cedoor
aa544bf2c9 docs: update semaphore contracts pkg name
Former-commit-id: 4c29901ce8
2022-02-11 09:50:56 +01:00
cedoor
967e93789e chore: update contract npm pkg name
Former-commit-id: 18c42499d0
2022-02-10 13:29:35 +01:00
cedoor
ec5c6a1c23 fix: remove wrong doc links
Former-commit-id: db9a65a2c6
2022-02-10 13:28:35 +01:00
cedoor
79a6bfcbf7 docs: create docs v2 structure
Former-commit-id: 7cf4bedfe6
2022-02-10 13:21:07 +01:00
cedoor
a08c5460c3 docs: remove new files from V1 doc
Former-commit-id: bb1aebc51b
2022-02-10 12:32:15 +01:00
cedoor
1259d8e53e build: uncomment zksnark commands for verifier
Former-commit-id: 7dfc2eea8d
2022-02-10 12:24:10 +01:00
cedoor
bea3aca4a9 chore: v0.1.0
Former-commit-id: 6fef3abb10
2022-02-10 11:35:04 +01:00
cedoor
04e89d83e0 chore: update snark files
Former-commit-id: 5dab02846a
2022-02-10 11:32:27 +01:00
cedoor
83798c959e chore: update zk-kit/protocols & snarkjs pkgs
Former-commit-id: 70aa93f2d6
2022-02-10 11:22:37 +01:00
cedoor
23a9fe78bf docs: create multi-version docs
Former-commit-id: a7e1805782
2022-02-09 16:58:12 +01:00
cedoor
108160740d chore: update zk-kit ts libraries
Former-commit-id: cfb532e07c
2022-02-09 15:30:58 +01:00
cedoor
fdc66d3769 chore: update verifier sol path
Former-commit-id: 441d4f799e
2022-02-09 12:39:07 +01:00
Omar Desogus
bad1176c60 docs: create initial install & usage sections
Former-commit-id: dd7f6ade4e
2022-02-08 13:15:34 +01:00
cedoor
6d8511c35c chore: create specific npm package for contracts
Former-commit-id: cb8143d612
2022-02-08 12:11:15 +01:00
cedoor
ec48e81fe0 style: format code with prettier
Former-commit-id: 7b1e95f1e3
2022-02-08 11:54:26 +01:00
cedoor
bf7dda0666 test: add missing tests
Former-commit-id: 671db41d80
2022-02-08 11:51:47 +01:00
cedoor
ccb1d762c4 refactor: remove unnecessary requires
Former-commit-id: f5d5320945
2022-02-08 11:51:30 +01:00
cedoor
6ecf6c20af fix: set correct require condition
Former-commit-id: 18fe0ed2af
2022-02-08 11:50:48 +01:00
cedoor
e575c6025b test: add tests & update fun to create mt proofs
Former-commit-id: 3a344ff2a7
2022-02-07 18:24:20 +01:00
cedoor
1f4120f30d feat: add method to remove whistleblowers
Former-commit-id: a9c5bcc2bf
2022-02-07 18:23:50 +01:00
cedoor
ea6ff9d6a9 refactor: remove unused core modifier
Former-commit-id: a8910477b7
2022-02-07 18:22:41 +01:00
cedoor
ec7387f1c5 test: add util function to create merkle proofs
Former-commit-id: e2e4201e45
2022-02-07 18:21:58 +01:00
cedoor
04e716a917 style: format code with prettier
Former-commit-id: f0751c978a
2022-02-07 17:09:20 +01:00
cedoor
3efea8c2bf revert: remove unused contract for external nullifiers
Former-commit-id: 413191ee39
2022-02-07 17:09:02 +01:00
cedoor
a38c5b4360 test: add whistleblowing contract base tests
Former-commit-id: 29e5970799
2022-02-07 17:01:24 +01:00
cedoor
fd7342f5b3 chore: add hardhat task to deploy whistleblowing contract
Former-commit-id: 7bbea2976c
2022-02-07 17:00:58 +01:00
cedoor
7ca5de85d6 refactor: replace signal bytes type with string
Former-commit-id: f1a1ca09ff
2022-02-07 16:25:30 +01:00
cedoor
6d313e194e feat: add whistleblowing extension contract
Former-commit-id: cec6ef81b0
2022-02-07 16:24:21 +01:00
cedoor
e9ed84c868 chore: update zk-kit ts packages
Former-commit-id: 1918e8508b
2022-02-07 12:23:10 +01:00
cedoor
010726618e perf: remove unnecessary root check
Former-commit-id: 9afd500455
2022-02-07 11:26:01 +01:00
cedoor
df0c87f5e7 style: format code with prettier
Former-commit-id: 905eca9a4b
2022-02-07 11:05:56 +01:00
cedoor
55079c25a9 chore: increase reason string length
Former-commit-id: a9b92c83dd
2022-02-07 11:05:17 +01:00
cedoor
1242e73d34 chore: update verifier path
Former-commit-id: f8e9b32580
2022-02-07 11:04:45 +01:00
cedoor
1be081c10a chore: create contract folders
Former-commit-id: 7153043dce
2022-02-07 10:54:51 +01:00
Omar Desogus
4a4ef3d3bf Merge pull request #79 from appliedzkp/feat/modular-contracts
Feat/modular contracts

Former-commit-id: fc6be0f842
2022-02-04 21:55:00 +01:00
cedoor
ba02e7719f test: add tests for semaphore voting contract
Former-commit-id: d9213a2737
2022-02-04 20:26:59 +01:00
cedoor
406424c0a3 refactor: remove timestamps and add poll state
Former-commit-id: 3d01e97c88
2022-02-04 20:26:27 +01:00
cedoor
633a1a7a19 feat: add new zero value constant
Former-commit-id: f4210d6936
2022-02-04 13:02:50 +01:00
cedoor
3680cc294d chore: update some function comments
Former-commit-id: 2e14916c59
2022-02-04 12:52:49 +01:00
cedoor
6d51e94a88 refactor: udpate method names
Former-commit-id: e1189f316d
2022-02-04 12:52:30 +01:00
cedoor
9bd085195f feat: create semaphore voting interface
Former-commit-id: 3f9e35315f
2022-02-04 12:51:04 +01:00
cedoor
0826bbcfa3 chore: update deploy task contract name
Former-commit-id: 2caed5d274
2022-02-03 21:52:50 +01:00
cedoor
4c643f012b perf: replace memory signal type with calldata
Former-commit-id: 67864e2e91
2022-02-03 21:49:13 +01:00
cedoor
1a3d35662c refactor: remove underscore from parameters
Former-commit-id: c4e71f5497
2022-02-03 21:47:49 +01:00
cedoor
064aa99b3d refactor: update group id type
Former-commit-id: 9f002d2967
2022-02-03 21:37:46 +01:00
cedoor
eec2ff5c1f feat: add core function to check proof validity
Former-commit-id: fdd4cef3b1
2022-02-03 21:37:22 +01:00
cedoor
7527f159ad feat: create semaphore voting contract
Former-commit-id: 55d2ff7b1f
2022-02-03 21:35:46 +01:00
cedoor
f06a12535f feat: create abstract contract for nullifiers
Former-commit-id: 7b2b4fd0c9
2022-02-03 15:39:27 +01:00
cedoor
7ad7acfb54 refactor: update semaphore group contract
Former-commit-id: 1f510d6011
2022-02-03 15:38:39 +01:00
cedoor
76092003f7 feat: create contract for shared constants
Former-commit-id: b9f9d2fdfc
2022-02-03 15:38:11 +01:00
cedoor
817783e797 feat: create semaphore core interface
Former-commit-id: 26db39573c
2022-02-03 15:37:37 +01:00
cedoor
14a7493cc8 feat: create abstract contract for groups
Former-commit-id: d2f2357f19
2022-02-03 15:00:49 +01:00
cedoor
f15ba8fcda feat: create core semaphore contract
Former-commit-id: d0af5644d4
2022-02-03 14:59:29 +01:00
cedoor
4e04ba2413 chore: update zk-kit mt libraries
Former-commit-id: 87e12dd277
2022-02-03 10:39:35 +01:00
cedoor
5b9a4aaceb chore: update circuit scheme
Former-commit-id: d97711438d
2022-02-03 10:38:51 +01:00
cedoor
af9b07aa20 refactor: add zk-kit solidity quin tree
Former-commit-id: 827654cba2
2022-02-02 18:02:56 +01:00
cedoor
1ca9e568c4 chore: add zk-kit mt contracts
Former-commit-id: 143a6572c1
2022-02-01 19:24:17 +01:00
cedoor
c21d0b6e6b feat: modularize contracts
Former-commit-id: 431cac261b
2022-02-01 15:25:50 +01:00
cedoor
56716cb258 chore: add circuit scheme
Former-commit-id: f169951820
2022-01-31 16:51:10 +01:00
Omar Desogus
04b585021f chore: update LICENSE file
Former-commit-id: 575b25f205
2022-01-28 20:06:04 +01:00
Omar Desogus
2a44bd6c75 docs: update README file
Former-commit-id: 895a7bcee0
2022-01-28 20:04:08 +01:00
cedoor
7d54825ba1 chore: update spec name
Former-commit-id: e3fe53368e
2022-01-28 17:18:26 +01:00
cedoor
0900615ae4 chore: add cname file for doc website
Former-commit-id: d8e3666970
2022-01-28 17:02:32 +01:00
cedoor
6837dd3cbd ci: add workflow for docs deploy
Former-commit-id: 0c8c264004
2022-01-28 16:53:59 +01:00
cedoor
7888aebcd7 chore: remove docs from prettier files to ignore
Former-commit-id: 8a955e46eb
2022-01-28 16:51:10 +01:00
cedoor
a6cf53520b chore: add docusaurus folder to ignore
Former-commit-id: b62a067811
2022-01-28 16:50:46 +01:00
cedoor
0b66144c76 chore: create docusaurus project
Former-commit-id: 147af8c6f8
2022-01-28 16:50:09 +01:00
cedoor
9f931d1f19 chore: move spec on docs
Former-commit-id: bdc09eb879
2022-01-28 16:49:45 +01:00
cedoor
db8da587ab ci: remove coveralls unused conf
Former-commit-id: a929851fb4
2022-01-28 11:25:46 +01:00
cedoor
96b5e10d75 ci: separate test & coverage workflows
Former-commit-id: 9143273166
2022-01-28 11:20:39 +01:00
cedoor
e15fd3174e chore: add deploy hardhat task
Former-commit-id: 0c603218da
2022-01-27 20:02:46 +01:00
cedoor
b0bbb981a0 chore: add zk essential files
Former-commit-id: 86caaf9127
2022-01-27 18:26:06 +01:00
cedoor
d7dc8bdd60 ci: add workflow for tests and coverage
Former-commit-id: b836549a8f
2022-01-27 18:25:36 +01:00
cedoor
21b7ccabd3 chore: add gas-reporter hardhat plugin
Former-commit-id: 38bf1f58ea
2022-01-27 16:37:04 +01:00
cedoor
778d5a1574 chore: add .env files & dotenv
Former-commit-id: 2dbc09a786
2022-01-27 16:36:27 +01:00
cedoor
e7c515aabc chore: add solidity-coverage hardhat plugin
Former-commit-id: c063641384
2022-01-27 15:51:29 +01:00
cedoor
a77fcf848f chore: add typechain
Former-commit-id: f2833daee5
2022-01-27 13:34:26 +01:00
cedoor
1c91e59f71 chore: add docs for repo community standards
Former-commit-id: 222f4847c3
2022-01-27 12:41:26 +01:00
cedoor
19e54ac348 chore: rename npm script to compile contracts
Former-commit-id: f93fadea07
2022-01-27 12:40:51 +01:00
cedoor
b7b8190edc chore: set .gitignore template
Former-commit-id: ca6eac64f9
2022-01-27 12:30:12 +01:00
cedoor
ead549e9f1 chore: add solhint
Former-commit-id: ddf2d54d26
2022-01-27 12:29:39 +01:00
cedoor
55938b0eaa style: fix contract syntax with prettier
Former-commit-id: 252788f172
2022-01-27 12:06:11 +01:00
cedoor
e614cc68ac chore: fix some eslint warnings
Former-commit-id: 19b0dfe0bc
2022-01-27 11:50:54 +01:00
cedoor
3a94fb72f9 chore: add some prettier files to ignore
Former-commit-id: d27cf6158b
2022-01-27 11:50:27 +01:00
cedoor
1772e776a7 chore: add eslint
Former-commit-id: 1499f0a2d9
2022-01-27 11:50:09 +01:00
cedoor
e6a5d1f4b6 chore: remove useless exclude option
Former-commit-id: 2b074a66d8
2022-01-27 11:49:17 +01:00
cedoor
5abfed2b77 style: fix syntax with prettier
Former-commit-id: f86391ad65
2022-01-27 11:24:48 +01:00
cedoor
82c4dea962 chore: remove unused utils
Former-commit-id: 5ddd03d09f
2022-01-27 11:24:27 +01:00
cedoor
544046a392 chore: remove unused lerna conf file
Former-commit-id: 323235efe8
2022-01-27 11:22:25 +01:00
cedoor
541cd4298b chore: add prettier
Former-commit-id: c80cca3120
2022-01-27 11:21:56 +01:00
cedoor
67c6af125e chore: add commitizen packages and conf
Former-commit-id: 0a7536fbc4
2022-01-27 10:51:48 +01:00
cedoor
a11449493b chore: update solidity version
Former-commit-id: 0771ddfc37
2022-01-27 10:45:17 +01:00
cedoor
42031746fa chore: update contract license
Former-commit-id: 7202ea2903
2022-01-27 10:41:37 +01:00
cedoor
ca2d5a193c chore: update @zk-kit/protocols lib
Former-commit-id: 1eb1a17cff
2022-01-26 22:54:23 +01:00
cedoor
3602219bb6 chore: merge tests
Former-commit-id: eb3d7da447
2022-01-26 21:13:04 +01:00
Omar Desogus
710e546eee chore: set original license
Former-commit-id: ffc2c0a91a
2022-01-25 20:23:30 +01:00
cedoor
882191996c chore: add external paths
Former-commit-id: 3547d8f16f
2022-01-25 20:17:53 +01:00
cedoor
a9630e436b chore: add snarks types
Former-commit-id: 700074acf0
2022-01-25 20:17:24 +01:00
cedoor
b524655db1 chore: add paths and update npm scripts
Former-commit-id: 6b37b11459
2022-01-25 20:16:57 +01:00
cedoor
7dead05108 chore: add ts script to compile circuits
Former-commit-id: 46fbe572b7
2022-01-25 20:15:32 +01:00
cedoor
ed355829cd chore: add GPL3 licence
Former-commit-id: bc0b485ab4
2022-01-25 20:14:17 +01:00
cedoor
c37496cf00 chore: add typescript hardhat support
Former-commit-id: 917b376da3
2022-01-25 18:21:44 +01:00
cedoor
1be8ac5df5 chore: update dev dependencies
Former-commit-id: 8536aef7f2
2022-01-25 18:10:31 +01:00
Andrija
bc8362f4f0 pck update
Former-commit-id: 051484c365
2021-11-25 16:19:38 +01:00
Andrija Novakovic
e84264b24d remove unused var
Former-commit-id: d83d8a7bb9
2021-11-25 12:50:31 +01:00
Andrija Novakovic
970b19257f remove n_levels from nullifier
Former-commit-id: 2f3374c534
2021-10-28 09:55:10 +02:00
Andrija Novakovic
421b7da0ba new version of libsem protocols
Former-commit-id: 7c5b0c2436
2021-10-25 22:37:00 +02:00
Andrija Novakovic
665ab42870 version compatible with js exports
Former-commit-id: c732da9cf4
2021-10-25 19:43:53 +02:00
Andrija Novakovic
69c25d4b05 circom 2.0
Former-commit-id: bac0ce2713
2021-10-25 16:32:21 +02:00
Andrija Novakovic
37337ccff6 updated libsem
Former-commit-id: 50bdccd843
2021-10-25 13:07:38 +02:00
Andrija Novakovic
583cb2fb2a new @libsem versions
Former-commit-id: 067f479cc9
2021-10-25 12:27:52 +02:00
Andrija Novakovic
d5a3781d01 export task
Former-commit-id: 8974444df4
2021-10-24 13:10:09 +02:00
Andrija Novakovic
4d6045a01c integration test
Former-commit-id: 900d554699
2021-10-24 12:31:14 +02:00
Andrija Novakovic
acf5d7dc98 fix deployment from abi and bytecode
Former-commit-id: 5bb77575fd
2021-10-24 12:13:57 +02:00
Andrija Novakovic
358dd69753 cleanup
Former-commit-id: 15b3b8ce76
2021-10-23 22:39:38 +02:00
Andrija Novakovic
57be569adb integration tests
Former-commit-id: 30dde96a11
2021-10-23 21:14:20 +02:00
Andrija Novakovic
948685edf2 integration tests
Former-commit-id: 5e17ae9eb6
2021-10-23 18:24:24 +02:00
Andrija Novakovic
548d7bbe31 full semaphore pipeline test
Former-commit-id: 6182041c52
2021-10-23 01:42:58 +02:00
Andrija Novakovic
ceb20422b7 tests
Former-commit-id: 9cc257fa21
2021-10-23 01:11:23 +02:00
Andrija Novakovic
8e41b6cffd parametrize depth
Former-commit-id: 640f2c5e8d
2021-10-22 21:09:54 +02:00
Andrija Novakovic
a4378925ac poseidon x
Former-commit-id: 03b123313c
2021-10-21 18:10:10 +02:00
Andrija Novakovic
8f0c937023 remove unused account names
Former-commit-id: 409a42a1e3
2021-10-21 01:06:10 +02:00
Andrija Novakovic
ad6873bfb3 separate poseidon deployment
Former-commit-id: 3299d1f698
2021-10-21 01:00:48 +02:00
Andrija Novakovic
2a5ebeb6fb deployment pattern like sushi swap
Former-commit-id: dcd9690f3e
2021-10-21 00:59:38 +02:00
Andrija Novakovic
bc4b0acefd deploy scripts with hardhat-deploy module
Former-commit-id: 16b46efcab
2021-10-21 00:14:20 +02:00
Andrija Novakovic
3824857b04 test compatibility with latest lib version
Former-commit-id: a76721ee40
2021-10-20 07:59:22 +02:00
Andrija Novakovic
d945172ce9 tests with new libsem
Former-commit-id: 53dfb5855d
2021-10-20 01:37:59 +02:00
Andrija Novakovic
8f7214a921 Update package.json
Co-authored-by: Koh Wei Jie <weijiekoh@users.noreply.github.com>
Former-commit-id: 7e3a8a4318
2021-10-10 13:04:03 +02:00
Andrija Novakovic
4510809a1b Update circuits/semaphore-base.circom
Co-authored-by: Koh Wei Jie <weijiekoh@users.noreply.github.com>
Former-commit-id: a63c517772
2021-10-10 13:02:48 +02:00
Andrija Novakovic
c7ca8dc02d version 2.0
Former-commit-id: 261fdc5b44
2021-10-10 12:06:43 +02:00
Koh Wei Jie
589ade76d5 Fixed wrong link to semaphore-base.circom in docs (#37)
* fixed wrong link to semaphore-base.circom in docs

* updated the docs build script to not delete CNAME; fixed some minor errors in the tutorial

* added warning about compiling scrypt in node 12

* added warning about lerna

Former-commit-id: 1e34d21f98
2020-03-22 14:23:43 +02:00
Koh Wei Jie
36d634c47e Audit report and formal spec (#39)
* fixed wrong link to semaphore-base.circom in docs

* added audit report and spec

Former-commit-id: 7a28c614de
2020-03-22 14:20:14 +02:00
Kobi Gurkan
dabd686b1f Create CNAME
Former-commit-id: a652d654ed
2020-03-03 23:37:13 +02:00
Kobi Gurkan
5f8ad2b71b update to audited semaphore
Former-commit-id: 9702b336da
2020-03-03 23:23:23 +02:00
187 changed files with 9003 additions and 5473 deletions

View File

@@ -1,66 +0,0 @@
# Javascript Node CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2
jobs:
build:
docker:
# specify the version you desire here
- image: circleci/node:11.14.0
working_directory: ~/semaphore/semaphorejs
steps:
- checkout:
path: ~/semaphore
# restore or install npm packages
- restore_cache:
name: restore-npm-cache
keys:
- v1.10-dependencies-{{ checksum "package-lock.json" }}
- run: npm install
- save_cache:
paths:
- node_modules
key: v1.10-dependencies-{{ checksum "package-lock.json" }}
# checksum the snarks definitions
- run:
name: checksum-snarks
command: cd scripts && ./checksum_snarks.sh
# Download and cache dependencies
- restore_cache:
name: restore-snark-cache
keys:
- v1.13-dependencies-{{ checksum "build/.snark_checksum" }}
# build snarks
- run:
name: end-to-end
command: cd scripts && ./build_snarks.sh
no_output_timeout: 600m
# cache generated snark circuit and keys
- save_cache:
key: v1.13-dependencies-{{ checksum "build/.snark_checksum" }}
paths:
- build/circuit.json
- build/proving_key.bin
- build/proving_key.json
- build/verification_key.json
- build/verifier.sol
# build snarks
- run:
name: integration_tests
command: cd scripts && ./integration_tests.sh
no_output_timeout: 600m
- store_artifacts:
path: ~/semaphore/semaphorejs/build

3
.commitlintrc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": ["@commitlint/config-conventional"]
}

13
.editorconfig Normal file
View File

@@ -0,0 +1,13 @@
#root = true
[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 120
indent_size = 4
[*.md]
trim_trailing_whitespace = false

8
.env.example Normal file
View File

@@ -0,0 +1,8 @@
DEFAULT_NETWORK=hardhat
TREE_DEPTH=20
ALL_SNARK_ARTIFACTS=true
REPORT_GAS=false
BACKEND_PRIVATE_KEY=
INFURA_API_KEY=
COINMARKETCAP_API_KEY=
ETHERSCAN_API_KEY=

32
.eslintignore Normal file
View File

@@ -0,0 +1,32 @@
# dependencies
node_modules
package-lock.json
yarn.lock
.yarn
# testing
coverage
coverage.json
# hardhat
cache
# types
types
# circuits
circuits
# production
dist
build
docs
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

24
.eslintrc.json Normal file
View File

@@ -0,0 +1,24 @@
{
"root": true,
"env": {
"es6": true
},
"extends": ["airbnb-base", "airbnb-typescript/base", "plugin:jest/recommended", "plugin:jest/style", "prettier"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"project": ["./tsconfig.json", "./packages/**/tsconfig.json"]
},
"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"
}
}

18
.github/ISSUE_TEMPLATE/----network.md vendored Normal file
View File

@@ -0,0 +1,18 @@
---
name: "\U0001F578 Network"
about: Propose a new network in which to deploy Semaphore contracts
title: ''
labels: ''
assignees: ''
---
**Provide data related to the network**
* Name
* Chain id
* URL
**Why are you using this network?**
Describe the reasons why you think it is important for Semaphore to be deployed on this network.

22
.github/ISSUE_TEMPLATE/----project.md vendored Normal file
View File

@@ -0,0 +1,22 @@
---
name: " \U0001F4A0 Project"
about: If you are using Semaphore we can help you share your project
title: ''
labels: "documentation \U0001F4D6"
assignees: ''
---
**Describe your project**
A brief description of your project. In what way have you used Semaphore?
**Other info**
- Name
- Icon
**Links**
- Website
- Github
- Socials

34
.github/ISSUE_TEMPLATE/---bug.md vendored Normal file
View File

@@ -0,0 +1,34 @@
---
name: "\U0001F41E Bug"
about: Create a report to help us improve
title: ''
labels: "bug \U0001F41B"
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Technologies (please complete the following information):**
- Node.js version
- NPM version
- Solidity version
**Additional context**
Add any other context about the problem here.

20
.github/ISSUE_TEMPLATE/---feature.md vendored Normal file
View File

@@ -0,0 +1,20 @@
---
name: "\U0001F680 Feature"
about: Suggest an idea for Semaphore
title: ''
labels: 'feature :rocket:'
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

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.

24
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,24 @@
<!-- Please refer to our contributing documentation for any questions on submitting a pull request -->
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Related Issue
<!--- This project accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
## Does this introduce a breaking change?
- [ ] Yes
- [ ] No
<!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. -->
## Other information
<!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. -->

45
.github/workflows/docs.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: docs
on:
push:
branches:
- main
jobs:
gh-pages:
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: Generate doc website
run: yarn docs
- 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

90
.gitignore vendored Normal file
View File

@@ -0,0 +1,90 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# IDE
.vscode
.idea
# Testing
coverage
coverage.json
*.lcov
# Dependency directories
node_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
.DS_Store
# Output of 'npm pack'
*.tgz
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# Production
build
dist
docs/*
!docs/CNAME
!docs/index.html
# Hardhat
artifacts
cache
packages/contracts/deployed-contracts/undefined.json
packages/contracts/deployed-contracts/hardhat.json
packages/contracts/deployed-contracts/localhost.json
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v3
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# Other
snark-artifacts

3
.lintstagedrc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"**/*.{js,ts}": ["prettier --write", "eslint --fix"]
}

44
.prettierignore Normal file
View File

@@ -0,0 +1,44 @@
# dependencies
node_modules
package-lock.json
yarn.lock
.yarn
# testing
coverage
coverage.json
# hardhat
cache
packages/contracts/deployed-contracts/undefined.json
packages/contracts/deployed-contracts/hardhat.json
packages/contracts/deployed-contracts/localhost.json
# types
types
# circuits
circuits
# contracts
Verifier*.sol
# production
dist
build
docs
# github
.github/ISSUE_TEMPLATE
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# other
snark-artifacts

5
.prettierrc.json Normal file
View File

@@ -0,0 +1,5 @@
{
"semi": false,
"arrowParens": "always",
"trailingComma": "none"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
b3cadff6efb37a12712d12c2553ec703dbcaa4dd

8
.yarnrc.yml Normal file
View File

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

127
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,127 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

111
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,111 @@
# Contributing
:tada: Thank you for being interested in contributing to the Semaphore project! :tada:
Feel welcome and read the following sections in order to know how to ask questions and how to work on something.
All members of our community are expected to follow our [Code of Conduct](/CODE_OF_CONDUCT.md). Please make sure you are welcoming and friendly in all of our spaces.
We're really glad you're reading this, because we need volunteer developers to help this project come to fruition. 👏
## Issues
The best way to contribute to our projects is by opening a [new issue](https://github.com/semaphore-protocol/semaphore/issues/new/choose) or tackling one of the issues listed [here](https://github.com/semaphore-protocol/semaphore/contribute).
## Pull Requests
Pull requests are great if you want to add a feature or fix a bug. Here's a quick guide:
1. Fork the repo.
2. Run the tests. We only take pull requests with passing tests.
3. Add a test for your change. Only refactoring and documentation changes require no new tests.
4. Make sure to check out the [Style Guide](/CONTRIBUTING#style-guide) and ensure that your code complies with the rules.
5. Make the test pass.
6. Commit your changes.
7. Push to your fork and submit a pull request on our `dev` branch. Please provide us with some explanation of why you made the changes you made. For new features make sure to explain a standard use case to us.
## CI (Github Actions) Tests
We use GitHub Actions to test each PR before it is merged.
When you submit your PR (or later change that code), a CI build will automatically be kicked off. A note will be added to the PR, and will indicate the current status of the build.
## Style Guide
### Code rules
We always use ESLint and Prettier. To check that your code follows the rules, simply run the npm script `yarn lint`.
### Commits rules
For commits it is recommended to use [Conventional Commits](https://www.conventionalcommits.org).
Don't worry if it looks complicated, in our repositories, after `git add`, you can usually run the npm script `yarn commit` to make many of these steps interactive.
Each commit message consists of a **header**, a **body** and a **footer**. The **header** has a special format that includes a **type**, a **scope** and a **subject**:
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
The **header** is mandatory and the **scope** of the header must contain the name of the package you are working on.
#### Type
The type must be one of the following:
- feat: A new feature
- fix: A bug fix
- docs: Documentation only changes
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- refactor: A code change that neither fixes a bug nor adds a feature (improvements of the code structure)
- perf: A code change that improves the performance
- test: Adding missing or correcting existing tests
- build: Changes that affect the build system or external dependencies (example scopes: gulp, npm)
- ci: Changes to CI configuration files and scripts (example scopes: travis, circle)
- chore: Other changes that don't modify src or test files
- revert: Reverts a previous commit
#### Scope
The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages).
#### Subject
The subject contains a succinct description of the change:
- Use the imperative, present tense: "change" not "changed" nor "changes"
- Don't capitalize the first letter
- No dot (.) at the end
#### Body
Just as in the subject, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior.
### Branch rules
- There must be a `main` branch, used only for the releases.
- There must be a `dev` branch, used to merge all the branches under it.
- Avoid long descriptive names for long-lived branches.
- Use kebab-case (no CamelCase).
- Use grouping tokens (words) at the beginning of your branch names (in a similar way to the `type` of commit).
- Define and use short lead tokens to differentiate branches in a way that is meaningful to your workflow.
- Use slashes to separate parts of your branch names.
- Remove branch after merge if it is not important.
Examples:
```bash
git branch -b docs/readme
git branch -b test/a-feature
git branch -b feat/sidebar
git branch -b fix/b-feature
```

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

379
README.md
View File

@@ -1,168 +1,307 @@
# Semaphore
<p align="center">
<h1 align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/semaphore-protocol/website/blob/main/static/img/semaphore-icon-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="https://github.com/semaphore-protocol/website/blob/main/static/img/semaphore-icon.svg">
<img width="40" alt="Semaphore icon." src="https://github.com/semaphore-protocol/website/blob/main/static/img/semaphore-icon.svg">
</picture>
Semaphore
</h1>
</p>
[![CircleCI](https://circleci.com/gh/kobigurk/semaphore.svg?style=svg&circle-token=57fa2a6c591cd8d09ddae610313452bdd7b0fb14)](https://circleci.com/gh/kobigurk/semaphore)
<p align="center">
<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="/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%3Aproduction">
<img alt="GitHub Workflow test" src="https://img.shields.io/github/workflow/status/semaphore-protocol/semaphore/production?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>
<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>
<img alt="Repository top language" src="https://img.shields.io/github/languages/top/semaphore-protocol/semaphore?style=flat-square">
</p>
Join the [Telegram group](https://t.me/joinchat/B-PQx1U3GtAh--Z4Fwo56A) to discuss.
<div align="center">
<h4>
<a href="/CONTRIBUTING.md">
👥 Contributing
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="/CODE_OF_CONDUCT.md">
🤝 Code of conduct
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://github.com/semaphore-protocol/semaphore/contribute">
🔎 Issues
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://discord.gg/6mSdGHnstH">
🗣️ Chat &amp; Support
</a>
</h4>
</div>
## Introduction
| 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. |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
Semaphore has been introduced by [barryWhiteHat](https://github.com/barryWhiteHat) as a method of zero-knowledge signaling - a method for an approved user to broadcast an arbitrary string without exposing their identity. This repository is an implementation of an upgraded version of the concept, including the zero-knowledge circuits and the tools necessary to use it, both server-side and client-side.
The core of the Semaphore protocol is in the [circuit logic](/packages/circuits/scheme.png). However Semaphore also provides [Solidity contracts](/packages/contracts) (NPM: `@semaphore-protocol/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).
The project is implemented in plain Node.JS and uses [circom](https://github.com/iden3/circom) for the zero-knowledge proofs.
You can find Semaphore V1 on [`version/1.0.0`](https://github.com/semaphore-protocol/semaphore/tree/version/1.0.0).
## Design
Semaphore is comprised of a zkSNARK statement, a few smart contracts, a server application and a client application.
---
### Smart contracts
Implemented in [**semaphorejs/contracts**](semaphorejs/contracts).
## 📦 Packages
#### Semaphore
The Semaphore contract is the base layer of Semaphore. Other contracts can build upon this to create applications that rely on anonymous signaling. Semaphore has a tree of allowed identities, a tree of signals, a set of previously broadcast nullifiers hashes, multiple external nullifiers and a gas price refund price:
<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/subgraph">
@semaphore-protocol/subgraph
</a>
<a href="https://semaphore-protocol.github.io/semaphore/subgraph">
(docs)
</a>
</td>
<td>
<!-- NPM version -->
<a href="https://npmjs.org/package/@semaphore-protocol/subgraph">
<img src="https://img.shields.io/npm/v/@semaphore-protocol/subgraph.svg?style=flat-square" alt="NPM version" />
</a>
</td>
<td>
<!-- Downloads -->
<a href="https://npmjs.org/package/@semaphore-protocol/subgraph">
<img src="https://img.shields.io/npm/dm/@semaphore-protocol/subgraph.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>
<tbody>
* The tree of allowed identities allows a prover to show that they are an identity which is approved to signal.
* The tree of signals allows a user to verify the integrity of a list of signals.
* The nullifiers hashes set and external nullifier allows the contract to prevent double signals by the same user, within the context of each external nullifier, without exposing the specific user.
* The gas price refund price is a mechanism that supports transaction abstraction - a server can broadcast on behalf of a user to provide further anonymity, and in return they receive a refund and a small reward, with a maximum gas price for their transaction.
</table>
The contract allows administrative operations that only the owner is allowed to perform:
## 🛠 Install
* Managing identities using the **insertIdentity** and **updateIdentity** methods.
* Adding or removing an **external_nullifier**.
* Setting the broadcast permissioning - whether only the owner can broadcast.
Clone this repository:
The contract allows anyone to read the current state:
```bash
git clone https://github.com/semaphore-protocol/semaphore.git
```
* Reading the roots of the two trees.
* Reading the current parameters of **external_nullifier**.
And install the dependencies:
The contract allows anyone to attempt broadcasting a signal, given a signal, a proof and the relevant public inputs.
The contract allows anyone to fund the contract for gas refund and rewards.
```bash
cd semaphore && yarn
```
Lastly, the contract has a few events to allow a server to build a local state to serve users wishing to generate proofs:
## 📜 Usage
* **Funded** - when the contract has received some funding for refunds and rewards.
* **SignalBroadcast** - when a signal has been broadcast successfully, after verification of the proof, the public inputs and double-signaling checks.
* **LeafAdded**, **LeafUpdated** (from MerkleTreeLib) - when the trees have been updated.
Copy the `.env.example` file as `.env`:
```bash
cp .env.example .env
```
#### MerkleTreeLib
And add your environment variables.
Manages a number of append-only Merkle trees with efficient inserts and updates.
### Code quality and formatting
### zkSNARK statement
Implemented in [**semaphorejs/snark**](semaphorejs/snark).
Run [ESLint](https://eslint.org/) to analyze the code and catch bugs:
The statement assures that given public inputs:
```bash
yarn lint
```
* **signal_hash**
* **external_nullifier**
* **root**
* **nullifiers_hash**
Run [Prettier](https://prettier.io/) to check formatting rules:
and private inputs:
* **identity_pk**
* **identity_nullifier**
* **identity_trapdoor**
* **identity_path_elements**
* **identity_path_index**
* **auth_sig_r**
* **auth_sig_s**
```bash
yarn prettier
```
the following conditions hold:
Or to automatically format the code:
* The commitment of the identity structure (**identity_pk**, **identity_nullifier**, **identity_trapdoor**) exists in the identity tree with the root **root**, using the path (**identity_path_elements**, **identity_path_index**). This ensures that the user was added to the system at some point in the past.
* **nullifiers_hash** is uniquely derived from **external_nullifier**, **identity_nullifier** and **identity_path_index**. This ensures a user cannot broadcast a signal with the same **external_nullifier** more than once.
* The message (**external_nullifier**, **signal_hash**) is signed by the secret key corresponding to **identity_pk**, having the signature (**auth_sig_r**, **auth_sig_s**). This ensures that a state of the contract having a specific **external_nullifier**, ensuring no double-signaling.
```bash
yarn prettier:write
```
#### Cryptographic primitives
### Conventional commits
Semaphore uses a few cryptographic primitives provided by circomlib:
Semaphore uses [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/). A [command line utility](https://github.com/commitizen/cz-cli) to commit using the correct syntax can be used by running:
* MiMCHash for the Merkle tree, the identity commitments and the message hash in the signature.
* EdDSA for the signature.
```bash
yarn commit
```
Note: MiMCHash, and especially the specific paramteres used in the circuit, have not been heavily audited yet by the cryptography community. Additionally, the circuit and code should also receive further review before relying on it for production applications.
It will also automatically check that the modified files comply with ESLint and Prettier rules.
### Server
### Snark artifacts
Implemented in [**semaphorejs/src/server/server.js**](semaphorejs/src/server/server.js). Acts as a manager of the identities merkle tree and as an identity onboarder. The REST API allows:
Download the Semaphore snark artifacts needed to generate and verify proofs:
* An owner to submit a transaction that adds an identity to the merkle tree, provided proper authentication.
* A client to ask for a path from an identity commitment to the current root of the tree, relieving the client from the need to manage this tree by themselves.
* A client to ask a list of signals, together with their paths to the signals tree root.
* An owner to set the external nullifier.
```bash
yarn download:snark-artifacts
```
The server relies on an Ethereum node and the events in the smart contract to synchronize to the current state and handle rollbacks if they occur.
### Testing
It uses [**semaphore-merkle-tree**](https://github.com/weijiekoh/semaphore-merkle-tree) - Semaphore requires managing a growing merkle tree containing the identities allowed to signal and the signals broadcast by users. semaphore-merkle-tree manages the trees either in-memory, for browser usage or a database, making the tree scale by the disk size.
Run [Jest](https://jestjs.io/) to test the JS libraries:
### Client
```bash
yarn test:libraries
```
Implemented in [**src/client/client.js**](semaphorejs/src/client/client.js). Enables signaling a user's support of an arbitrary statemnt, given identity secrets of an identity existing in the tree. The client has 2 CLI functions:
Run [Mocha](https://mochajs.org/) to test the contracts:
* **generate_identity** - generate random identity secrets and randomness, save them to disk and print the identity commitment. The client can then send the commitment to the onboarder (using another channel), requesting they add them to the tree.
* **signal STRING** - given an arbitrary string, generates a zero-knowledge proof of the client's authorization to signal. The signalling requests the path of the identity commitment from the server, and broadcasts the transaction directly to the contract.
```bash
yarn test:contracts
```
### Web
Or test everything with:
A web interface to run the server and client APIs, generate identities and proofs directly in the browser and broadcast signals.
```bash
yarn test
```
## Running modes
### Build libraries & compile contracts
Schematically, Semaphore has the following actors:
Run [Rollup](https://www.rollupjs.org) to build all the packages:
![Semaphore architecture](docs/Semaphore.svg)
```bash
yarn build:libraries
```
There are 3 main running modes:
Compile the smart contracts with [Hardhat](https://hardhat.org/):
* One server is the owner of the Semaphore contract, other servers act as intermediate miners and clients uses them to broadcast their signals. This the lightest running mode for clients, as they rely on servers to provide them with tree paths, a list of signals and broadcast. This is the default mode that is exposed in the CLI and web clients.
* One server is the owner of the Semaphore contract and clients broadcast directly. This is still a light running mode for clients, and is less prone to server censorship, at the cost of less anonymity - as the user's Ethereum address is exposed.
* One server is the owner of the Semaphore contract and clients run a server locally. This is a heavier running mode, allowing the clients to run autonomously, reconstructing the signals and identities states locally.
```bash
yarn compile:contracts
```
## Configuration
### Documentation (JS libraries)
The server and the client look for **server-config.json** and **client-config.json**, respectively. They can also accept their configuration as environment variables:
* **server**:
* CONFIG_ENV - load configuration from environment variables rather than a file.
* CONFIG_PATH - location of the configuration file.
* LOG_LEVEL - error, info, debug or verbose.
* DB_PATH - location of the RocksDB database.
* CHAIN_ID - chain ID of the Ethereum network.
* CONTRACT_ADDRESS - the deployed Semaphore contract address.
* CREATION_HASH - the transaction hash in which the contract was created, to allow for faster initial sync.
* NODE_URL - the RPC URL of the Ehtereum node.
* SEMAPHORE_PORT - the port on which to serve the Semaphore server REST API.
* SEMAPHORE_LOGIN - the password with which clients communicating with the Semaphore server REST API must authenticate.
* FROM_ADDRESS - the address to send transactions from.
* FROM_PRIVATE_KEY - the private key of FROM_ADDRESS.
* TRANSACTION_CONFIRMATION_BLOCKS - the amount of blocks to wait until a transaction is considered confirmed. The default is 24.
* **client:**
* CONFIG_ENV - load configuration from environment variables rather than a file.
* LOG_LEVEL - error, info, debug or verbose.
* IDENTITY_PATH - location of the identity secrets file.
* CHAIN_ID - chain ID of the Ethereum network.
* CONTRACT_ADDRESS - the deployed Semaphore contract address.
* NODE_URL - the RPC URL of the Ehtereum node.
* FROM_ADDRESS - the address to send transactions from.
* FROM_PRIVATE_KEY - the private key of FROM_ADDRESS.
* TRANSACTION_CONFIRMATION_BLOCKS - the amount of blocks to wait until a transaction is considered confirmed. The default is 24.
* EXTERNAL_NULLIFIER - the external nullifier to be used with the signal. Must match the one in the contract.
* SEMAPHORE_SERVER_URL - the URL of the Semaphore REST server.
* BROADCASTER_ADDRESS - the address of the Semaphore server that will be allowed to broadcast the client's signals.
Run [TypeDoc](https://typedoc.org/) to generate a documentation website for each package:
## Running
```bash
yarn docs
```
The easiest way to try Semaphore out is to use [https://semaphore.kobi.one](https://semaphore.kobi.one) - a web interface to broadcast to a remote server and generate proofs locally. First, load the Rinkeby config using the button at the top. Then, you can generate an identity and send the commitment to @kobigurk on Telegram or open an issue in the repository. Then, you can broadcast signals, including the proof generation, directly in the browser. Lastly, you can see the signals that have been broadcast to date in the table.
* To try out Semaphore locally you can clone the repository and run the following in `semaphore/semaphorejs/`:
* **npm install && npm link**
* **cd scripts && ./compile.sh && ./do_setup.sh && ./build_verifier.sh** - compile, do a setup and build the verifier of the Semaphore circuit.
* **scripts/run_ganache.sh** - runs ganache with appropriate parameters for Semaphore testing.
* **scripts/run_all_test.sh** - runs a server and a client, generates a new random identity and broadcasts a signal.
It assumes bash, node and truffle are globally available.
Examples of run commands (roughly matching the test contract deployed on Rinkeby):
* `LOG_LEVEL=debug CHAIN_ID=4 CONTRACT_ADDRESS=0x3dE2c3f8853594440c3363f8D491449Defa0bE1F NODE_URL=https://rinkeby.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066 SEMAPHORE_PORT=3000 FROM_ADDRESS=0x1929c15f4e818abf2549510622a50c440c474223 FROM_PRIVATE_KEY=0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21 TRANSACTION_CONFIRMATION_BLOCKS=1 CREATION_HASH=0x4d6998f49f3ebb6e2bd3567c5adbf3f5ab711fbb24e618b4b53498d521f9c758 SEMAPHORE_LOGIN=test123 CONFIG_ENV=true npx semaphorejs-server`
* `LOG_LEVEL=debug TRANSACTION_CONFIRMATION_BLOCKS=1 CHAIN_ID=4 CONTRACT_ADDRESS=0x3dE2c3f8853594440c3363f8D491449Defa0bE1F NODE_URL=https://rinkeby.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066 EXTERNAL_NULLIFIER=12312 SEMAPHORE_SERVER_URL=https://semaphore-server.kobi.one BROADCASTER_ADDRESS=0x1929c15f4e818abf2549510622a50c440c474223 CONFIG_ENV=true npx semaphorejs-client signal "I vote for fork A"`
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"]
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 25 KiB

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

80
package.json Normal file
View File

@@ -0,0 +1,80 @@
{
"name": "semaphore-protocol",
"description": "A zero-knowledge protocol for anonymous signalling on Ethereum.",
"license": "MIT",
"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": {
"build:libraries": "yarn workspaces foreach 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",
"commit": "cz",
"precommit": "lint-staged",
"postinstall": "yarn download:snark-artifacts"
},
"keywords": [
"ethereum",
"semaphore",
"solidity",
"circom",
"javascript",
"typescript",
"zero-knowledge",
"zk-snarks",
"zero-knowledge-proofs",
"proof-of-membership",
"monorepo"
],
"workspaces": [
"packages/*"
],
"packageManager": "yarn@3.2.1",
"devDependencies": {
"@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",
"@rollup/plugin-typescript": "^8.3.0",
"@types/download": "^8.0.1",
"@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.9.1",
"@typescript-eslint/parser": "^5.9.1",
"babel-jest": "^27.4.6",
"commitizen": "^4.2.4",
"cz-conventional-changelog": "^3.3.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",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-jest": "^25.7.0",
"jest": "^27.4.1",
"jest-config": "^27.4.7",
"lint-staged": "^12.1.7",
"prettier": "^2.5.1",
"rimraf": "^3.0.2",
"rollup": "^2.64.0",
"ts-node": "^10.4.0",
"tslib": "^2.3.1",
"typescript": "^4.5.4"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
}

View File

@@ -0,0 +1,37 @@
<p align="center">
<h1 align="center">
Semaphore circuits
</h1>
<p align="center">Semaphore circuits to create and verify zero-knowledge proofs.</p>
</p>
<p align="center">
<a href="https://github.com/semaphore-protocol">
<img src="https://img.shields.io/badge/project-Semaphore-blue.svg?style=flat-square">
</a>
<a href="https://github.com/semaphore-protocol/semaphore/blob/main/LICENSE">
<img alt="Github license" src="https://img.shields.io/github/license/semaphore-protocol/semaphore.svg?style=flat-square">
</a>
</p>
<div align="center">
<h4>
<a href="https://github.com/semaphore-protocol/semaphore/blob/main/CONTRIBUTING.md">
👥 Contributing
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://github.com/semaphore-protocol/semaphore/blob/main/CODE_OF_CONDUCT.md">
🤝 Code of conduct
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://github.com/semaphore-protocol/semaphore/contribute">
🔎 Issues
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://discord.gg/6mSdGHnstH">
🗣️ Chat &amp; Support
</a>
</h4>
</div>
To learn more about circuits visit [semaphore.appliedzkp.org](https://semaphore.appliedzkp.org/docs/technical-reference/circuits).

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,90 @@
pragma circom 2.0.0;
include "../node_modules/circomlib/circuits/poseidon.circom";
include "./tree.circom";
template CalculateSecret() {
signal input identityNullifier;
signal input identityTrapdoor;
signal output out;
component poseidon = Poseidon(2);
poseidon.inputs[0] <== identityNullifier;
poseidon.inputs[1] <== identityTrapdoor;
out <== poseidon.out;
}
template CalculateIdentityCommitment() {
signal input secret;
signal output out;
component poseidon = Poseidon(1);
poseidon.inputs[0] <== secret;
out <== poseidon.out;
}
template CalculateNullifierHash() {
signal input externalNullifier;
signal input identityNullifier;
signal output out;
component poseidon = Poseidon(2);
poseidon.inputs[0] <== externalNullifier;
poseidon.inputs[1] <== identityNullifier;
out <== poseidon.out;
}
// nLevels must be < 32.
template Semaphore(nLevels) {
signal input identityNullifier;
signal input identityTrapdoor;
signal input treePathIndices[nLevels];
signal input treeSiblings[nLevels];
signal input signalHash;
signal input externalNullifier;
signal output root;
signal output nullifierHash;
component calculateSecret = CalculateSecret();
calculateSecret.identityNullifier <== identityNullifier;
calculateSecret.identityTrapdoor <== identityTrapdoor;
signal secret;
secret <== calculateSecret.out;
component calculateIdentityCommitment = CalculateIdentityCommitment();
calculateIdentityCommitment.secret <== secret;
component calculateNullifierHash = CalculateNullifierHash();
calculateNullifierHash.externalNullifier <== externalNullifier;
calculateNullifierHash.identityNullifier <== identityNullifier;
component inclusionProof = MerkleTreeInclusionProof(nLevels);
inclusionProof.leaf <== calculateIdentityCommitment.out;
for (var i = 0; i < nLevels; i++) {
inclusionProof.siblings[i] <== treeSiblings[i];
inclusionProof.pathIndices[i] <== treePathIndices[i];
}
root <== inclusionProof.root;
// Dummy square to prevent tampering signalHash.
signal signalHashSquared;
signalHashSquared <== signalHash * signalHash;
nullifierHash <== calculateNullifierHash.out;
}
component main {public [signalHash, externalNullifier]} = Semaphore(20);

View File

@@ -0,0 +1,40 @@
pragma circom 2.0.0;
include "../node_modules/circomlib/circuits/poseidon.circom";
include "../node_modules/circomlib/circuits/mux1.circom";
template MerkleTreeInclusionProof(nLevels) {
signal input leaf;
signal input pathIndices[nLevels];
signal input siblings[nLevels];
signal output root;
component poseidons[nLevels];
component mux[nLevels];
signal hashes[nLevels + 1];
hashes[0] <== leaf;
for (var i = 0; i < nLevels; i++) {
pathIndices[i] * (1 - pathIndices[i]) === 0;
poseidons[i] = Poseidon(2);
mux[i] = MultiMux1(2);
mux[i].c[0][0] <== hashes[i];
mux[i].c[0][1] <== siblings[i];
mux[i].c[1][0] <== siblings[i];
mux[i].c[1][1] <== hashes[i];
mux[i].s <== pathIndices[i];
poseidons[i].inputs[0] <== mux[i].out[0];
poseidons[i].inputs[1] <== mux[i].out[1];
hashes[i + 1] <== poseidons[i].out;
}
root <== hashes[nLevels];
}

View File

@@ -0,0 +1,4 @@
module.exports = {
istanbulFolder: "../../coverage/contracts",
skipFiles: ["base/Pairing.sol"]
}

View File

@@ -0,0 +1,22 @@
{
"extends": "solhint:recommended",
"plugins": ["prettier"],
"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",
"func-visibility": ["error", { "ignoreConstructors": true }],
"max-line-length": ["error", 120],
"not-rely-on-time": "off",
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
],
"reason-string": ["warn", { "maxLength": 80 }]
}
}

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

@@ -0,0 +1,120 @@
<p align="center">
<h1 align="center">
Semaphore contracts
</h1>
<p align="center">Semaphore contracts to manage groups and broadcast anonymous signals.</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/contracts">
<img alt="NPM version" src="https://img.shields.io/npm/v/@semaphore-protocol/contracts?style=flat-square" />
</a>
<a href="https://npmjs.org/package/@semaphore-protocol/contracts">
<img alt="Downloads" src="https://img.shields.io/npm/dm/@semaphore-protocol/contracts.svg?style=flat-square" />
</a>
</p>
<div align="center">
<h4>
<a href="https://github.com/semaphore-protocol/semaphore/blob/main/CONTRIBUTING.md">
👥 Contributing
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://github.com/semaphore-protocol/semaphore/blob/main/CODE_OF_CONDUCT.md">
🤝 Code of conduct
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://github.com/semaphore-protocol/semaphore/contribute">
🔎 Issues
</a>
<span>&nbsp;&nbsp;|&nbsp;&nbsp;</span>
<a href="https://discord.gg/6mSdGHnstH">
🗣️ Chat &amp; Support
</a>
</h4>
</div>
To learn more about contracts visit [semaphore.appliedzkp.org](https://semaphore.appliedzkp.org/docs/technical-reference/contracts).
---
## 🛠 Install
### npm or yarn
Install the `@semaphore-protocol/contracts` package with npm:
```bash
npm i @semaphore-protocol/contracts
```
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 a verifier contract with depth = 20:
```bash
yarn deploy:verifier --depth 20
```
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.

View File

@@ -0,0 +1,174 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "./interfaces/ISemaphore.sol";
import "./interfaces/ISemaphoreVerifier.sol";
import "./base/SemaphoreGroups.sol";
/// @title Semaphore
contract Semaphore is ISemaphore, SemaphoreGroups {
ISemaphoreVerifier public verifier;
/// @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 (groups[groupId].admin != _msgSender()) {
revert Semaphore__CallerIsNotTheGroupAdmin();
}
_;
}
/// @dev Checks if there is a verifier for the given tree depth.
/// @param merkleTreeDepth: Depth of the tree.
modifier onlySupportedMerkleTreeDepth(uint256 merkleTreeDepth) {
if (merkleTreeDepth < 16 || merkleTreeDepth > 32) {
revert Semaphore__MerkleTreeDepthIsNotSupported();
}
_;
}
/// @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);
groups[groupId].admin = admin;
groups[groupId].merkleRootDuration = 1 hours;
emit GroupAdminUpdated(groupId, address(0), admin);
}
/// @dev See {ISemaphore-createGroup}.
function createGroup(
uint256 groupId,
uint256 merkleTreeDepth,
uint256 zeroValue,
address admin,
uint256 merkleTreeRootDuration
) external override onlySupportedMerkleTreeDepth(merkleTreeDepth) {
_createGroup(groupId, merkleTreeDepth, zeroValue);
groups[groupId].admin = admin;
groups[groupId].merkleRootDuration = merkleTreeRootDuration;
emit GroupAdminUpdated(groupId, address(0), admin);
}
/// @dev See {ISemaphore-updateGroupAdmin}.
function updateGroupAdmin(uint256 groupId, address newAdmin) external override onlyGroupAdmin(groupId) {
groups[groupId].admin = newAdmin;
emit GroupAdminUpdated(groupId, _msgSender(), newAdmin);
}
/// @dev See {ISemaphore-addMember}.
function addMember(uint256 groupId, uint256 identityCommitment) external override onlyGroupAdmin(groupId) {
_addMember(groupId, identityCommitment);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
}
/// @dev See {ISemaphore-addMembers}.
function addMembers(uint256 groupId, uint256[] calldata identityCommitments)
external
override
onlyGroupAdmin(groupId)
{
for (uint8 i = 0; i < identityCommitments.length; ) {
_addMember(groupId, identityCommitments[i]);
unchecked {
++i;
}
}
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block.timestamp;
}
/// @dev See {ISemaphore-updateMember}.
function updateMember(
uint256 groupId,
uint256 identityCommitment,
uint256 newIdentityCommitment,
uint256[] calldata proofSiblings,
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}.
function removeMember(
uint256 groupId,
uint256 identityCommitment,
uint256[] calldata proofSiblings,
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,
uint256 signal,
uint256 nullifierHash,
uint256 externalNullifier,
uint256[8] calldata proof
) external override {
uint256 currentMerkleTreeRoot = getMerkleTreeRoot(groupId);
if (currentMerkleTreeRoot == 0) {
revert Semaphore__GroupDoesNotExist();
}
if (merkleTreeRoot != currentMerkleTreeRoot) {
uint256 merkleRootCreationDate = groups[groupId].merkleRootCreationDates[merkleTreeRoot];
uint256 merkleRootDuration = groups[groupId].merkleRootDuration;
if (merkleRootCreationDate == 0) {
revert Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
}
if (block.timestamp > merkleRootCreationDate + merkleRootDuration) {
revert Semaphore__MerkleTreeRootIsExpired();
}
}
if (groups[groupId].nullifierHashes[nullifierHash]) {
revert Semaphore__YouAreUsingTheSameNillifierTwice();
}
uint256 merkleTreeDepth = getMerkleTreeDepth(groupId);
verifier.verifyProof(merkleTreeRoot, nullifierHash, signal, externalNullifier, proof, merkleTreeDepth);
groups[groupId].nullifierHashes[nullifierHash] = true;
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 Semaphore__InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() public pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() public pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) public pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) {
return G1Point(0, 0);
}
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) {
revert Semaphore__InvalidProof();
}
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) public view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) {
revert Semaphore__InvalidProof();
}
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) public view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) {
revert Semaphore__InvalidProof();
}
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) {
revert Semaphore__InvalidProof();
}
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) public view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) {
revert Semaphore__InvalidProof();
}
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) {
revert Semaphore__InvalidProof();
}
}
}

View File

@@ -0,0 +1,138 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
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.
/// 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 tree data.
mapping(uint256 => IncrementalTreeData) internal merkleTree;
/// @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 (getMerkleTreeDepth(groupId) != 0) {
revert Semaphore__GroupAlreadyExists();
}
merkleTree[groupId].init(merkleTreeDepth, zeroValue);
emit GroupCreated(groupId, merkleTreeDepth, zeroValue);
}
/// @dev Adds an identity commitment to an existing group.
/// @param groupId: Id of the group.
/// @param identityCommitment: New identity commitment.
function _addMember(uint256 groupId, uint256 identityCommitment) internal virtual {
if (getMerkleTreeDepth(groupId) == 0) {
revert Semaphore__GroupDoesNotExist();
}
merkleTree[groupId].insert(identityCommitment);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = getNumberOfMerkleTreeLeaves(groupId) - 1;
emit MemberAdded(groupId, index, identityCommitment, merkleTreeRoot);
}
/// @dev Updates an identity commitment of an existing group. A proof of membership is
/// needed to check if the node to be updated is part of the tree.
/// @param groupId: Id of the group.
/// @param identityCommitment: Existing identity commitment to be updated.
/// @param newIdentityCommitment: New identity commitment.
/// @param proofSiblings: Array of the sibling nodes of the proof of membership.
/// @param proofPathIndices: Path of the proof of membership.
function _updateMember(
uint256 groupId,
uint256 identityCommitment,
uint256 newIdentityCommitment,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) internal virtual {
if (getMerkleTreeRoot(groupId) == 0) {
revert Semaphore__GroupDoesNotExist();
}
merkleTree[groupId].update(identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
emit MemberUpdated(groupId, index, identityCommitment, newIdentityCommitment, merkleTreeRoot);
}
/// @dev Removes an identity commitment from an existing group. A proof of membership is
/// needed to check if the node to be deleted is part of the tree.
/// @param groupId: Id of the group.
/// @param identityCommitment: Existing identity commitment to be removed.
/// @param proofSiblings: Array of the sibling nodes of the proof of membership.
/// @param proofPathIndices: Path of the proof of membership.
function _removeMember(
uint256 groupId,
uint256 identityCommitment,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) internal virtual {
if (getMerkleTreeRoot(groupId) == 0) {
revert Semaphore__GroupDoesNotExist();
}
merkleTree[groupId].remove(identityCommitment, proofSiblings, proofPathIndices);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
emit MemberRemoved(groupId, index, identityCommitment, merkleTreeRoot);
}
/// @dev See {ISemaphoreGroups-getMerkleTreeRoot}.
function getMerkleTreeRoot(uint256 groupId) public view virtual override returns (uint256) {
return merkleTree[groupId].root;
}
/// @dev See {ISemaphoreGroups-getMerkleTreeDepth}.
function getMerkleTreeDepth(uint256 groupId) public view virtual override returns (uint256) {
return merkleTree[groupId].depth;
}
/// @dev See {ISemaphoreGroups-getNumberOfMerkleTreeLeaves}.
function getNumberOfMerkleTreeLeaves(uint256 groupId) public view virtual override returns (uint256) {
return merkleTree[groupId].numberOfLeaves;
}
/// @dev Converts the path indices of a Merkle proof to the identity commitment index in the tree.
/// @param proofPathIndices: Path of the proof of membership.
/// @return Index of a group member.
function proofPathIndicesToMemberIndex(uint8[] calldata proofPathIndices) private pure returns (uint256) {
uint256 memberIndex = 0;
for (uint8 i = uint8(proofPathIndices.length); i > 0; ) {
if (memberIndex > 0 || proofPathIndices[i - 1] != 0) {
memberIndex *= 2;
if (proofPathIndices[i - 1] == 1) {
memberIndex += 1;
}
}
unchecked {
--i;
}
}
return memberIndex;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,114 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "../interfaces/ISemaphoreVoting.sol";
import "../interfaces/ISemaphoreVerifier.sol";
import "../base/SemaphoreGroups.sol";
/// @title Semaphore voting contract.
/// @dev The following code allows you to create polls, add voters and allow them to vote anonymously.
contract SemaphoreVoting is ISemaphoreVoting, SemaphoreGroups {
ISemaphoreVerifier public verifier;
/// @dev Gets a poll id and returns the poll data.
mapping(uint256 => Poll) internal polls;
/// @dev Gets a nullifier hash and returns true or false.
/// It is used to prevent double-voting.
mapping(uint256 => bool) internal nullifierHashes;
/// @dev Checks if the poll coordinator is the transaction sender.
/// @param pollId: Id of the poll.
modifier onlyCoordinator(uint256 pollId) {
if (polls[pollId].coordinator != _msgSender()) {
revert Semaphore__CallerIsNotThePollCoordinator();
}
_;
}
/// @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 (merkleTreeDepth < 16 || merkleTreeDepth > 32) {
revert Semaphore__MerkleTreeDepthIsNotSupported();
}
_createGroup(pollId, merkleTreeDepth, 0);
Poll memory poll;
poll.coordinator = coordinator;
polls[pollId] = poll;
emit PollCreated(pollId, coordinator);
}
/// @dev See {ISemaphoreVoting-addVoter}.
function addVoter(uint256 pollId, uint256 identityCommitment) public override onlyCoordinator(pollId) {
if (polls[pollId].state != PollState.Created) {
revert Semaphore__PollHasAlreadyBeenStarted();
}
_addMember(pollId, identityCommitment);
}
/// @dev See {ISemaphoreVoting-addVoter}.
function startPoll(uint256 pollId, uint256 encryptionKey) public override onlyCoordinator(pollId) {
if (polls[pollId].state != PollState.Created) {
revert Semaphore__PollHasAlreadyBeenStarted();
}
polls[pollId].state = PollState.Ongoing;
emit PollStarted(pollId, _msgSender(), encryptionKey);
}
/// @dev See {ISemaphoreVoting-castVote}.
function castVote(
uint256 vote,
uint256 nullifierHash,
uint256 pollId,
uint256[8] calldata proof
) public override {
Poll memory poll = polls[pollId];
if (poll.state != PollState.Ongoing) {
revert Semaphore__PollIsNotOngoing();
}
if (nullifierHashes[nullifierHash]) {
revert Semaphore__YouAreUsingTheSameNillifierTwice();
}
uint256 merkleTreeDepth = getMerkleTreeDepth(pollId);
uint256 merkleTreeRoot = getMerkleTreeRoot(pollId);
verifier.verifyProof(merkleTreeRoot, nullifierHash, vote, pollId, proof, merkleTreeDepth);
nullifierHashes[nullifierHash] = true;
emit VoteAdded(pollId, vote);
}
/// @dev See {ISemaphoreVoting-publishDecryptionKey}.
function endPoll(uint256 pollId, uint256 decryptionKey) public override onlyCoordinator(pollId) {
if (polls[pollId].state != PollState.Ongoing) {
revert Semaphore__PollIsNotOngoing();
}
polls[pollId].state = PollState.Ended;
emit PollEnded(pollId, _msgSender(), decryptionKey);
}
}

View File

@@ -0,0 +1,80 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "../interfaces/ISemaphoreWhistleblowing.sol";
import "../interfaces/ISemaphoreVerifier.sol";
import "../base/SemaphoreGroups.sol";
/// @title Semaphore whistleblowing contract.
/// @dev The following code allows you to create entities for whistleblowers (e.g. non-profit
/// organization, newspaper) and to allow them to publish news leaks anonymously.
/// Leaks can be IPFS hashes, permanent links or other kinds of reference.
contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing, SemaphoreGroups {
ISemaphoreVerifier public verifier;
/// @dev Gets an editor address and return their entity.
mapping(address => uint256) 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()]) {
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 (merkleTreeDepth < 16 || merkleTreeDepth > 32) {
revert Semaphore__MerkleTreeDepthIsNotSupported();
}
_createGroup(entityId, merkleTreeDepth, 0);
entities[editor] = entityId;
emit EntityCreated(entityId, editor);
}
/// @dev See {ISemaphoreWhistleblowing-addWhistleblower}.
function addWhistleblower(uint256 entityId, uint256 identityCommitment) public override onlyEditor(entityId) {
_addMember(entityId, identityCommitment);
}
/// @dev See {ISemaphoreWhistleblowing-removeWhistleblower}.
function removeWhistleblower(
uint256 entityId,
uint256 identityCommitment,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) public override onlyEditor(entityId) {
_removeMember(entityId, identityCommitment, proofSiblings, proofPathIndices);
}
/// @dev See {ISemaphoreWhistleblowing-publishLeak}.
function publishLeak(
uint256 leak,
uint256 nullifierHash,
uint256 entityId,
uint256[8] calldata proof
) public override {
uint256 merkleTreeDepth = getMerkleTreeDepth(entityId);
uint256 merkleTreeRoot = getMerkleTreeRoot(entityId);
verifier.verifyProof(merkleTreeRoot, nullifierHash, leak, entityId, proof, merkleTreeDepth);
emit LeakPublished(entityId, leak);
}
}

View File

@@ -0,0 +1,131 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
/// @title Semaphore interface.
/// @dev Interface of a Semaphore contract.
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 group parameters, in addition to those in the Merkle tree.
struct Group {
address admin;
uint256 merkleRootDuration;
mapping(uint256 => uint256) merkleRootCreationDates;
mapping(uint256 => bool) nullifierHashes;
}
/// @dev Emitted when an admin is assigned to a group.
/// @param groupId: Id of the group.
/// @param oldAdmin: Old admin of the group.
/// @param newAdmin: New admin of the group.
event GroupAdminUpdated(uint256 indexed groupId, address indexed oldAdmin, address indexed newAdmin);
/// @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,
uint256 merkleTreeRoot,
uint256 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.
/// @param groupId: Id of the group.
/// @param merkleTreeRoot: Root of the Merkle tree.
/// @param signal: Semaphore signal.
/// @param nullifierHash: Nullifier hash.
/// @param externalNullifier: External nullifier.
/// @param proof: Zero-knowledge proof.
function verifyProof(
uint256 groupId,
uint256 merkleTreeRoot,
uint256 signal,
uint256 nullifierHash,
uint256 externalNullifier,
uint256[8] calldata proof
) 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.
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;
/// @dev Updates the group admin.
/// @param groupId: Id of the group.
/// @param newAdmin: New admin of the group.
function updateGroupAdmin(uint256 groupId, address newAdmin) external;
/// @dev Adds a new member to an existing group.
/// @param groupId: Id of the group.
/// @param identityCommitment: New identity commitment.
function addMember(uint256 groupId, uint256 identityCommitment) external;
/// @dev Adds new members to an existing group.
/// @param groupId: Id of the group.
/// @param identityCommitments: New identity commitments.
function addMembers(uint256 groupId, uint256[] calldata identityCommitments) external;
/// @dev Updates an identity commitment of an existing group. A proof of membership is
/// needed to check if the node to be updated is part of the tree.
/// @param groupId: Id of the group.
/// @param identityCommitment: Existing identity commitment to be updated.
/// @param newIdentityCommitment: New identity commitment.
/// @param proofSiblings: Array of the sibling nodes of the proof of membership.
/// @param proofPathIndices: Path of the proof of membership.
function updateMember(
uint256 groupId,
uint256 identityCommitment,
uint256 newIdentityCommitment,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) external;
/// @dev Removes a member from an existing group. A proof of membership is
/// needed to check if the node to be removed is part of the tree.
/// @param groupId: Id of the group.
/// @param identityCommitment: Identity commitment to be removed.
/// @param proofSiblings: Array of the sibling nodes of the proof of membership.
/// @param proofPathIndices: Path of the proof of membership.
function removeMember(
uint256 groupId,
uint256 identityCommitment,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) external;
}

View File

@@ -0,0 +1,59 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
/// @title SemaphoreGroups interface.
/// @dev Interface of a SemaphoreGroups contract.
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.
/// @param merkleTreeDepth: Depth of the tree.
/// @param zeroValue: Zero value of the tree.
event GroupCreated(uint256 indexed groupId, uint256 merkleTreeDepth, uint256 zeroValue);
/// @dev Emitted when a new identity commitment is added.
/// @param groupId: Group id of the group.
/// @param index: Identity commitment index.
/// @param identityCommitment: New identity commitment.
/// @param merkleTreeRoot: New root hash of the tree.
event MemberAdded(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);
/// @dev Emitted when an identity commitment is updated.
/// @param groupId: Group id of the group.
/// @param index: Identity commitment index.
/// @param identityCommitment: Existing identity commitment to be updated.
/// @param newIdentityCommitment: New identity commitment.
/// @param merkleTreeRoot: New root hash of the tree.
event MemberUpdated(
uint256 indexed groupId,
uint256 index,
uint256 identityCommitment,
uint256 newIdentityCommitment,
uint256 merkleTreeRoot
);
/// @dev Emitted when a new identity commitment is removed.
/// @param groupId: Group id of the group.
/// @param index: Identity commitment index.
/// @param identityCommitment: Existing identity commitment to be removed.
/// @param merkleTreeRoot: New root hash of the tree.
event MemberRemoved(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);
/// @dev Returns the last root hash of a group.
/// @param groupId: Id of the group.
/// @return Root hash of the group.
function getMerkleTreeRoot(uint256 groupId) external view returns (uint256);
/// @dev Returns the depth of the tree of a group.
/// @param groupId: Id of the group.
/// @return Depth of the group tree.
function getMerkleTreeDepth(uint256 groupId) external view returns (uint256);
/// @dev Returns the number of tree leaves of a group.
/// @param groupId: Id of the group.
/// @return Number of tree leaves.
function getNumberOfMerkleTreeLeaves(uint256 groupId) external view returns (uint256);
}

View File

@@ -0,0 +1,38 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "../base/Pairing.sol";
/// @title SemaphoreVerifier interface.
/// @dev Interface of SemaphoreVerifier contract.
interface ISemaphoreVerifier {
struct VerificationKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
/// @dev Verifies that the zero-knowledge proof is valid.
/// @param merkleTreeRoot: Root of the Merkle tree.
/// @param nullifierHash: Nullifier hash.
/// @param signal: Semaphore signal.
/// @param externalNullifier: External nullifier.
/// @param proof: Zero-knowledge proof.
/// @param merkleTreeDepth: Depth of the tree.
function verifyProof(
uint256 merkleTreeRoot,
uint256 nullifierHash,
uint256 signal,
uint256 externalNullifier,
uint256[8] calldata proof,
uint256 merkleTreeDepth
) external view;
}

View File

@@ -0,0 +1,87 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
/// @title SemaphoreVoting interface.
/// @dev Interface of SemaphoreVoting contract.
interface ISemaphoreVoting {
error Semaphore__CallerIsNotThePollCoordinator();
error Semaphore__MerkleTreeDepthIsNotSupported();
error Semaphore__PollHasAlreadyBeenStarted();
error Semaphore__PollIsNotOngoing();
error Semaphore__YouAreUsingTheSameNillifierTwice();
enum PollState {
Created,
Ongoing,
Ended
}
struct Verifier {
address contractAddress;
uint256 merkleTreeDepth;
}
struct Poll {
address coordinator;
PollState state;
}
/// @dev Emitted when a new poll is created.
/// @param pollId: Id of the poll.
/// @param coordinator: Coordinator of the poll.
event PollCreated(uint256 pollId, address indexed coordinator);
/// @dev Emitted when a poll is started.
/// @param pollId: Id of the poll.
/// @param coordinator: Coordinator of the poll.
/// @param encryptionKey: Key to encrypt the poll votes.
event PollStarted(uint256 pollId, address indexed coordinator, uint256 encryptionKey);
/// @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, uint256 vote);
/// @dev Emitted when a poll is ended.
/// @param pollId: Id of the poll.
/// @param coordinator: Coordinator of the poll.
/// @param decryptionKey: Key to decrypt the poll votes.
event PollEnded(uint256 pollId, address indexed coordinator, uint256 decryptionKey);
/// @dev Creates a poll and the associated Merkle tree/group.
/// @param pollId: Id of the poll.
/// @param coordinator: Coordinator of the poll.
/// @param merkleTreeDepth: Depth of the tree.
function createPoll(
uint256 pollId,
address coordinator,
uint256 merkleTreeDepth
) external;
/// @dev Adds a voter to a poll.
/// @param pollId: Id of the poll.
/// @param identityCommitment: Identity commitment of the group member.
function addVoter(uint256 pollId, uint256 identityCommitment) external;
/// @dev Starts a pull and publishes the key to encrypt the votes.
/// @param pollId: Id of the poll.
/// @param encryptionKey: Key to encrypt poll votes.
function startPoll(uint256 pollId, uint256 encryptionKey) external;
/// @dev Casts an anonymous vote in a poll.
/// @param vote: Encrypted vote.
/// @param nullifierHash: Nullifier hash.
/// @param pollId: Id of the poll.
/// @param proof: Private zk-proof parameters.
function castVote(
uint256 vote,
uint256 nullifierHash,
uint256 pollId,
uint256[8] calldata proof
) external;
/// @dev Ends a pull and publishes the key to decrypt the votes.
/// @param pollId: Id of the poll.
/// @param decryptionKey: Key to decrypt poll votes.
function endPoll(uint256 pollId, uint256 decryptionKey) external;
}

View File

@@ -0,0 +1,63 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
/// @title SemaphoreWhistleblowing interface.
/// @dev Interface of SemaphoreWhistleblowing contract.
interface ISemaphoreWhistleblowing {
error Semaphore__CallerIsNotTheEditor();
error Semaphore__MerkleTreeDepthIsNotSupported();
struct Verifier {
address contractAddress;
uint256 merkleTreeDepth;
}
/// @dev Emitted when a new entity is created.
/// @param entityId: Id of the entity.
/// @param editor: Editor of the entity.
event EntityCreated(uint256 entityId, address indexed editor);
/// @dev Emitted when a whistleblower publish a new leak.
/// @param entityId: Id of the entity.
/// @param leak: News leak.
event LeakPublished(uint256 indexed entityId, uint256 leak);
/// @dev Creates an entity and the associated Merkle tree/group.
/// @param entityId: Id of the entity.
/// @param editor: Editor of the entity.
/// @param merkleTreeDepth: Depth of the tree.
function createEntity(
uint256 entityId,
address editor,
uint256 merkleTreeDepth
) external;
/// @dev Adds a whistleblower to an entity.
/// @param entityId: Id of the entity.
/// @param identityCommitment: Identity commitment of the group member.
function addWhistleblower(uint256 entityId, uint256 identityCommitment) external;
/// @dev Removes a whistleblower from an entity.
/// @param entityId: Id of the entity.
/// @param identityCommitment: Identity commitment of the group member.
/// @param proofSiblings: Array of the sibling nodes of the proof of membership.
/// @param proofPathIndices: Path of the proof of membership.
function removeWhistleblower(
uint256 entityId,
uint256 identityCommitment,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) external;
/// @dev Allows whistleblowers to publish leaks anonymously.
/// @param leak: News leak.
/// @param nullifierHash: Nullifier hash.
/// @param entityId: Id of the entity.
/// @param proof: Private zk-proof parameters.
function publishLeak(
uint256 leak,
uint256 nullifierHash,
uint256 entityId,
uint256[8] calldata proof
) external;
}

View File

@@ -0,0 +1,35 @@
{
"name": "@semaphore-protocol/contracts",
"version": "2.6.1",
"description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
"license": "MIT",
"files": [
"**/*.sol"
],
"keywords": [
"blockchain",
"ethereum",
"hardhat",
"smart-contracts",
"semaphore",
"identity",
"solidity",
"zero-knowledge",
"zk-snarks",
"zero-knowledge-proofs",
"circom",
"proof-of-membership"
],
"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"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"@openzeppelin/contracts": "4.7.3",
"@zk-kit/incremental-merkle-tree.sol": "1.3.1"
}
}

View File

@@ -0,0 +1,24 @@
{
"verifiers": {
"Verifier16": "0x6143ECd9Fd1A00EDe1046d456f8aab53a7D71609",
"Verifier17": "0xAc12fFFE354D6446eb50dd33E683B78FED73Fb02",
"Verifier18": "0x610aeF0F2da3CD1C8bDefe4BDB434Ee146E0C701",
"Verifier19": "0x5477725177035bbC9d70443eb921D29749D6FCb4",
"Verifier20": "0x3fB2C0988a37b76e760c44e6516aF720935f3136",
"Verifier21": "0xDc8f6B8A42836d4566256f4c6C53131DFD127DF8",
"Verifier22": "0x6962b5e706be5278eeCb01c286b50A48484632f2",
"Verifier23": "0x41e4796Bd89B4BF04013b559c93fC32E9a2BdF6B",
"Verifier24": "0xD528B1D1408ab3583af4694F92b0aFEbE33d5b60",
"Verifier25": "0x1683a27EF9c10c5286dB56412E1272cD0Ca733e7",
"Verifier26": "0x78194bB665d1E33b97eE45B1A755c15717E94C00",
"Verifier27": "0x997Dac00E6701Ef7F3518280E5a9922801126E42",
"Verifier28": "0xDd3C7f4cBA2467aE41c0F614A3c3E24bC80268c6",
"Verifier29": "0xe53eF12093933D5df5691EAbA3821bD1c1EB60Cd",
"Verifier30": "0x7FeA07c536ABBB0E7FB3c833376EE4EaDc21340e",
"Verifier31": "0xe4539a592df18936202480FBe77E47DE012F2178",
"Verifier32": "0x98c90845A7870e215cBd7265DDC653E6c07032F4"
},
"Semaphore": "0x86337c87A56117f8264bbaBA70e5a522C6E8A604",
"PoseidonT3": "0xe0c8d1e53D9Bfc9071F6564755FCFf6cC0dB61d0",
"IncrementalBinaryTree": "0x91cD2B8573629d00BeC72EA1188d446897BD3948"
}

View File

@@ -0,0 +1,24 @@
{
"verifiers": {
"Verifier16": "0xA5253ba39381Aa99c4C2C5A4D5C2deC036d06629",
"Verifier17": "0xe0418A5f8fBF051D6cbc41Ff29855Dd2a02201Ab",
"Verifier18": "0x7CdB3336d7d7c55Bce0FB1508594C54521656797",
"Verifier19": "0xbd870921d8A5398a3314C950d1fc63b8C3AB190B",
"Verifier20": "0x2a96c5696F85e3d2aa918496806B5c5a4D93E099",
"Verifier21": "0x5Ec7d851a52A2a25CEc528F42a7ACA8EcF4667Cd",
"Verifier22": "0x919d3d9c05FA7411e334deA5a763354fC7B6aA5b",
"Verifier23": "0x63917b00a6dA7865bEfdd107AfC83CC2e6BDE552",
"Verifier24": "0xd05CAd7d940114c1419098EE3cEA0776ab510E7D",
"Verifier25": "0x6D9862e6140D94E932d94c8BcE74a0BDD0ea5ACb",
"Verifier26": "0x8c29e0b77e32f704F03eeCE01c041192A5EB6c77",
"Verifier27": "0x066cC22f8CA2A8D90D7Ff77D8a10A27e629c9c4C",
"Verifier28": "0x698F9507f504E2BD238be7da56E8D9fee60C6D15",
"Verifier29": "0xbBfC2E201C3c3c6F50063c3Edb4746c6Fcb36346",
"Verifier30": "0x06bcD633988c1CE7Bd134DbE2C12119b6f3E4bD1",
"Verifier31": "0x133b69Ce47BF20C49368354914DF47519Ca6cCFE",
"Verifier32": "0xe2978F79cb4AF62e5C990EE5c7E12fb22ee22e2D"
},
"Semaphore": "0x5259d32659F1806ccAfcE593ED5a89eBAb85262f",
"PoseidonT3": "0xe0A452533853310C371b50Bd91BB9DCC8961350F",
"IncrementalBinaryTree": "0x61AE89E372492e53D941DECaaC9821649fa9B236"
}

View File

@@ -0,0 +1,70 @@
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"
import { HardhatUserConfig } from "hardhat/config"
import { NetworksUserConfig } from "hardhat/types"
import { resolve } from "path"
import "solidity-coverage"
import { config } from "./package.json"
import "./tasks/accounts"
import "./tasks/deploy-semaphore"
import "./tasks/deploy-semaphore-voting"
import "./tasks/deploy-semaphore-whistleblowing"
dotenvConfig({ path: resolve(__dirname, "../../.env") })
function getNetworks(): NetworksUserConfig {
if (!process.env.INFURA_API_KEY || !process.env.BACKEND_PRIVATE_KEY) {
return {}
}
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
},
arbitrum: {
url: "https://arb1.arbitrum.io/rpc",
chainId: 42161,
accounts
}
}
}
const hardhatConfig: HardhatUserConfig = {
solidity: config.solidity,
paths: {
sources: config.paths.contracts,
tests: config.paths.tests,
cache: config.paths.cache,
artifacts: config.paths.build.contracts
},
networks: {
hardhat: {
chainId: 1337,
allowUnlimitedContractSize: true
},
...getNetworks()
},
gasReporter: {
currency: "USD",
enabled: process.env.REPORT_GAS === "true",
coinmarketcap: process.env.COINMARKETCAP_API_KEY
},
typechain: {
outDir: config.paths.build.typechain,
target: "ethers-v5"
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY
}
}
export default hardhatConfig

View File

@@ -0,0 +1,69 @@
{
"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": {
"@nomiclabs/hardhat-ethers": "^2.0.6",
"@nomiclabs/hardhat-etherscan": "^3.1.0",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@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",
"ethereum-waffle": "^3.4.4",
"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.1"
}
}

View File

@@ -0,0 +1,33 @@
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 {}
}
}
export function saveDeployedContracts(network: string | undefined, newDeployedContracts: DeployedContracts) {
const deployedContracts = getDeployedContracts(network)
writeFileSync(
`./deployed-contracts/${network}.json`,
JSON.stringify(
{
...deployedContracts,
...newDeployedContracts
},
null,
4
)
)
}

View File

@@ -0,0 +1,29 @@
import { hardhatArguments, run } from "hardhat"
import { getDeployedContracts } from "./utils"
async function main() {
const deployedContracts = getDeployedContracts(hardhatArguments.network)
await run("verify:verify", {
address: deployedContracts.IncrementalBinaryTree
})
await run("verify:verify", {
address: deployedContracts.Semaphore
})
await run("verify:verify", {
address: deployedContracts.Pairing
})
await run("verify:verify", {
address: deployedContracts.SemaphoreVerifier
})
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})

View File

@@ -0,0 +1,217 @@
//
// 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 Verifier {
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(
<%=vk_alpha_1[0]%>,
<%=vk_alpha_1[1]%>
);
vk.beta2 = Pairing.G2Point(
[<%=vk_beta_2[0][1]%>, <%=vk_beta_2[0][0]%>],
[<%=vk_beta_2[1][1]%>, <%=vk_beta_2[1][0]%>]
);
vk.gamma2 = Pairing.G2Point(
[<%=vk_gamma_2[0][1]%>, <%=vk_gamma_2[0][0]%>],
[<%=vk_gamma_2[1][1]%>, <%=vk_gamma_2[1][0]%>]
);
vk.delta2 = Pairing.G2Point(
[<%=vk_delta_2[0][1]%>, <%=vk_delta_2[0][0]%>],
[<%=vk_delta_2[1][1]%>, <%=vk_delta_2[1][0]%>]
);
vk.IC = new Pairing.G1Point[](<%=IC.length%>);
<% for (let i=0; i<IC.length; i++) { %>
vk.IC[<%=i%>] = Pairing.G1Point(
<%=IC[i][0]%>,
<%=IC[i][1]%>
);
<% } %>
}
/// @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[<%=IC.length-1%>] 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

@@ -0,0 +1,16 @@
import { Signer } from "@ethersproject/abstract-signer"
import { task, types } from "hardhat/config"
task("accounts", "Prints the list of accounts")
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
.setAction(async ({ logs }, { ethers }) => {
const accounts: Signer[] = await ethers.getSigners()
if (logs) {
for (const account of accounts) {
console.info(await account.getAddress())
}
}
return accounts
})

View File

@@ -0,0 +1,73 @@
import { poseidon_gencontract as poseidonContract } from "circomlibjs"
import { Contract } from "ethers"
import { task, types } from "hardhat/config"
task("deploy:semaphore-voting", "Deploy a SemaphoreVoting contract")
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
.setAction(async ({ logs }, { ethers }): Promise<Contract> => {
const PairingFactory = await ethers.getContractFactory("Pairing")
const pairing = await PairingFactory.deploy()
await pairing.deployed()
if (logs) {
console.info(`Pairing library has been deployed to: ${pairing.address}`)
}
const SemaphoreVerifierFactory = await ethers.getContractFactory("SemaphoreVerifier", {
libraries: {
Pairing: pairing.address
}
})
const semaphoreVerifier = await SemaphoreVerifierFactory.deploy()
await semaphoreVerifier.deployed()
if (logs) {
console.info(`SemaphoreVerifier contract has been deployed to: ${semaphoreVerifier.address}`)
}
const poseidonABI = poseidonContract.generateABI(2)
const poseidonBytecode = poseidonContract.createCode(2)
const [signer] = await ethers.getSigners()
const PoseidonFactory = new ethers.ContractFactory(poseidonABI, poseidonBytecode, signer)
const poseidon = await PoseidonFactory.deploy()
await poseidon.deployed()
if (logs) {
console.info(`Poseidon library has been deployed to: ${poseidon.address}`)
}
const IncrementalBinaryTreeFactory = await ethers.getContractFactory("IncrementalBinaryTree", {
libraries: {
PoseidonT3: poseidon.address
}
})
const incrementalBinaryTree = await IncrementalBinaryTreeFactory.deploy()
await incrementalBinaryTree.deployed()
if (logs) {
console.info(`IncrementalBinaryTree library has been deployed to: ${incrementalBinaryTree.address}`)
}
const SemaphoreVotingFactory = await ethers.getContractFactory("SemaphoreVoting", {
libraries: {
IncrementalBinaryTree: incrementalBinaryTree.address
}
})
const semaphoreVoting = await SemaphoreVotingFactory.deploy(semaphoreVerifier.address)
await semaphoreVoting.deployed()
if (logs) {
console.info(`SemaphoreVoting contract has been deployed to: ${semaphoreVoting.address}`)
}
return semaphoreVoting
})

View File

@@ -0,0 +1,73 @@
import { poseidon_gencontract as poseidonContract } from "circomlibjs"
import { Contract } from "ethers"
import { task, types } from "hardhat/config"
task("deploy:semaphore-whistleblowing", "Deploy a SemaphoreWhistleblowing contract")
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
.setAction(async ({ logs }, { ethers }): Promise<Contract> => {
const PairingFactory = await ethers.getContractFactory("Pairing")
const pairing = await PairingFactory.deploy()
await pairing.deployed()
if (logs) {
console.info(`Pairing library has been deployed to: ${pairing.address}`)
}
const SemaphoreVerifierFactory = await ethers.getContractFactory("SemaphoreVerifier", {
libraries: {
Pairing: pairing.address
}
})
const semaphoreVerifier = await SemaphoreVerifierFactory.deploy()
await semaphoreVerifier.deployed()
if (logs) {
console.info(`SemaphoreVerifier contract has been deployed to: ${semaphoreVerifier.address}`)
}
const poseidonABI = poseidonContract.generateABI(2)
const poseidonBytecode = poseidonContract.createCode(2)
const [signer] = await ethers.getSigners()
const PoseidonFactory = new ethers.ContractFactory(poseidonABI, poseidonBytecode, signer)
const poseidon = await PoseidonFactory.deploy()
await poseidon.deployed()
if (logs) {
console.info(`Poseidon library has been deployed to: ${poseidon.address}`)
}
const IncrementalBinaryTreeFactory = await ethers.getContractFactory("IncrementalBinaryTree", {
libraries: {
PoseidonT3: poseidon.address
}
})
const incrementalBinaryTree = await IncrementalBinaryTreeFactory.deploy()
await incrementalBinaryTree.deployed()
if (logs) {
console.info(`IncrementalBinaryTree library has been deployed to: ${incrementalBinaryTree.address}`)
}
const SemaphoreWhistleblowingFactory = await ethers.getContractFactory("SemaphoreWhistleblowing", {
libraries: {
IncrementalBinaryTree: incrementalBinaryTree.address
}
})
const semaphoreWhistleblowing = await SemaphoreWhistleblowingFactory.deploy(semaphoreVerifier.address)
await semaphoreWhistleblowing.deployed()
if (logs) {
console.info(`SemaphoreWhistleblowing contract has been deployed to: ${semaphoreWhistleblowing.address}`)
}
return semaphoreWhistleblowing
})

View File

@@ -0,0 +1,118 @@
import { poseidon_gencontract as poseidonContract } from "circomlibjs"
import { Contract } from "ethers"
import { task, types } from "hardhat/config"
import { saveDeployedContracts } from "../scripts/utils"
task("deploy:semaphore", "Deploy a Semaphore contract")
.addOptionalParam<boolean>("pairing", "Pairing library address", undefined, types.string)
.addOptionalParam<boolean>("semaphoreVerifier", "SemaphoreVerifier contract address", undefined, types.string)
.addOptionalParam<boolean>("poseidon", "Poseidon library address", undefined, types.string)
.addOptionalParam<boolean>(
"incrementalBinaryTree",
"IncrementalBinaryTree library address",
undefined,
types.string
)
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
.setAction(
async (
{
logs,
pairing: pairingAddress,
semaphoreVerifier: semaphoreVerifierAddress,
poseidon: poseidonAddress,
incrementalBinaryTree: incrementalBinaryTreeAddress
},
{ ethers, hardhatArguments }
): Promise<Contract> => {
if (!semaphoreVerifierAddress) {
if (!pairingAddress) {
const PairingFactory = await ethers.getContractFactory("Pairing")
const pairing = await PairingFactory.deploy()
await pairing.deployed()
if (logs) {
console.info(`Pairing library has been deployed to: ${pairing.address}`)
}
pairingAddress = pairing.address
}
const SemaphoreVerifierFactory = await ethers.getContractFactory("SemaphoreVerifier", {
libraries: {
Pairing: pairingAddress
}
})
const semaphoreVerifier = await SemaphoreVerifierFactory.deploy()
await semaphoreVerifier.deployed()
if (logs) {
console.info(`SemaphoreVerifier contract has been deployed to: ${semaphoreVerifier.address}`)
}
semaphoreVerifierAddress = semaphoreVerifier.address
}
if (!incrementalBinaryTreeAddress) {
if (!poseidonAddress) {
const poseidonABI = poseidonContract.generateABI(2)
const poseidonBytecode = poseidonContract.createCode(2)
const [signer] = await ethers.getSigners()
const PoseidonFactory = new ethers.ContractFactory(poseidonABI, poseidonBytecode, signer)
const poseidon = await PoseidonFactory.deploy()
await poseidon.deployed()
if (logs) {
console.info(`Poseidon library has been deployed to: ${poseidon.address}`)
}
poseidonAddress = poseidon.address
}
const IncrementalBinaryTreeFactory = await ethers.getContractFactory("IncrementalBinaryTree", {
libraries: {
PoseidonT3: poseidonAddress
}
})
const incrementalBinaryTree = await IncrementalBinaryTreeFactory.deploy()
await incrementalBinaryTree.deployed()
if (logs) {
console.info(`IncrementalBinaryTree library has been deployed to: ${incrementalBinaryTree.address}`)
}
incrementalBinaryTreeAddress = incrementalBinaryTree.address
}
const SemaphoreFactory = await ethers.getContractFactory("Semaphore", {
libraries: {
IncrementalBinaryTree: incrementalBinaryTreeAddress
}
})
const semaphore = await SemaphoreFactory.deploy(semaphoreVerifierAddress)
await semaphore.deployed()
if (logs) {
console.info(`Semaphore contract has been deployed to: ${semaphore.address}`)
}
saveDeployedContracts(hardhatArguments.network, {
Pairing: pairingAddress,
SemaphoreVerifier: semaphoreVerifierAddress,
Poseidon: poseidonAddress,
IncrementalBinaryTree: incrementalBinaryTreeAddress,
Semaphore: semaphore.address
})
return semaphore
}
)

View File

@@ -0,0 +1,287 @@
/* eslint-disable @typescript-eslint/no-shadow */
/* eslint-disable jest/valid-expect */
import { Group } from "@semaphore-protocol/group"
import { Identity } from "@semaphore-protocol/identity"
import { FullProof, generateProof, packToSolidityProof, SolidityProof } from "@semaphore-protocol/proof"
import { expect } from "chai"
import { constants, Signer } from "ethers"
import { run } from "hardhat"
import { Semaphore } from "../build/typechain"
import { createIdentityCommitments } from "./utils"
describe("Semaphore", () => {
let contract: Semaphore
let signers: Signer[]
let accounts: string[]
const treeDepth = Number(process.env.TREE_DEPTH) || 20
const groupId = 1
const members = createIdentityCommitments(3)
const wasmFilePath = `../../snark-artifacts/${treeDepth}/semaphore.wasm`
const zkeyFilePath = `../../snark-artifacts/${treeDepth}/semaphore.zkey`
before(async () => {
contract = await run("deploy:semaphore", {
logs: false
})
signers = await run("accounts", { logs: false })
accounts = await Promise.all(signers.map((signer: Signer) => signer.getAddress()))
})
describe("# createGroup", () => {
it("Should not create a group if the tree depth is not supported", async () => {
const transaction = contract["createGroup(uint256,uint256,uint256,address)"](groupId, 10, 0, accounts[0])
await expect(transaction).to.be.revertedWith("Semaphore__MerkleTreeDepthIsNotSupported()")
})
it("Should create a group", async () => {
const transaction = contract
.connect(signers[1])
["createGroup(uint256,uint256,uint256,address)"](groupId, treeDepth, 0, accounts[1])
await expect(transaction).to.emit(contract, "GroupCreated").withArgs(groupId, treeDepth, 0)
await expect(transaction)
.to.emit(contract, "GroupAdminUpdated")
.withArgs(groupId, constants.AddressZero, accounts[1])
})
it("Should create a group with a custom Merkle tree root expiration", async () => {
const groupId = 2
const transaction = await contract
.connect(signers[1])
["createGroup(uint256,uint256,uint256,address,uint256)"](
groupId,
treeDepth,
0,
accounts[0],
5 // 5 seconds.
)
await contract.addMember(groupId, members[0])
await contract.addMember(groupId, members[1])
await contract.addMember(groupId, members[2])
await expect(transaction).to.emit(contract, "GroupCreated").withArgs(groupId, treeDepth, 0)
await expect(transaction)
.to.emit(contract, "GroupAdminUpdated")
.withArgs(groupId, constants.AddressZero, accounts[0])
})
})
describe("# updateGroupAdmin", () => {
it("Should not update a group admin if the caller is not the group admin", async () => {
const transaction = contract.updateGroupAdmin(groupId, accounts[0])
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotTheGroupAdmin()")
})
it("Should update the group admin", async () => {
const transaction = contract.connect(signers[1]).updateGroupAdmin(groupId, accounts[0])
await expect(transaction).to.emit(contract, "GroupAdminUpdated").withArgs(groupId, accounts[1], accounts[0])
})
})
describe("# addMember", () => {
it("Should not add a member if the caller is not the group admin", async () => {
const member = BigInt(2)
const transaction = contract.connect(signers[1]).addMember(groupId, member)
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotTheGroupAdmin()")
})
it("Should add a new member in an existing group", async () => {
const group = new Group(treeDepth)
group.addMember(members[0])
const transaction = contract.addMember(groupId, members[0])
await expect(transaction).to.emit(contract, "MemberAdded").withArgs(groupId, 0, members[0], group.root)
})
})
describe("# addMembers", () => {
it("Should add new members to an existing group", async () => {
const groupId = 3
const members = [BigInt(1), BigInt(2), BigInt(3)]
const group = new Group(treeDepth)
group.addMembers(members)
await contract["createGroup(uint256,uint256,uint256,address)"](groupId, treeDepth, 0, accounts[0])
const transaction = contract.addMembers(groupId, members)
await expect(transaction).to.emit(contract, "MemberAdded").withArgs(groupId, 2, BigInt(3), group.root)
})
})
describe("# updateMember", () => {
it("Should not update a member if the caller is not the group admin", async () => {
const member = BigInt(2)
const transaction = contract.connect(signers[1]).updateMember(groupId, member, 1, [0, 1], [0, 1])
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotTheGroupAdmin()")
})
it("Should update a member from an existing group", async () => {
const groupId = 4
const members = [BigInt(1), BigInt(2), BigInt(3)]
const group = new Group(treeDepth)
group.addMembers(members)
group.updateMember(0, BigInt(4))
await contract["createGroup(uint256,uint256,uint256,address)"](groupId, treeDepth, 0, accounts[0])
await contract.addMembers(groupId, members)
const { siblings, pathIndices, root } = group.generateMerkleProof(0)
const transaction = contract.updateMember(groupId, BigInt(1), BigInt(4), siblings, pathIndices)
await expect(transaction)
.to.emit(contract, "MemberUpdated")
.withArgs(groupId, 0, BigInt(1), BigInt(4), root)
})
})
describe("# removeMember", () => {
it("Should not remove a member if the caller is not the group admin", async () => {
const member = BigInt(2)
const transaction = contract.connect(signers[1]).removeMember(groupId, member, [0, 1], [0, 1])
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotTheGroupAdmin()")
})
it("Should remove a member from an existing group", async () => {
const groupId = 5
const members = [BigInt(1), BigInt(2), BigInt(3)]
const group = new Group(treeDepth)
group.addMembers(members)
group.removeMember(2)
await contract["createGroup(uint256,uint256,uint256,address)"](groupId, treeDepth, 0, accounts[0])
await contract.addMembers(groupId, members)
const { siblings, pathIndices, root } = group.generateMerkleProof(2)
const transaction = contract.removeMember(groupId, BigInt(3), siblings, pathIndices)
await expect(transaction).to.emit(contract, "MemberRemoved").withArgs(groupId, 2, BigInt(3), root)
})
})
describe("# verifyProof", () => {
const signal = 2
const identity = new Identity("0")
const group = new Group(treeDepth)
group.addMembers(members)
let fullProof: FullProof
let solidityProof: SolidityProof
before(async () => {
await contract.addMembers(groupId, [members[1], members[2]])
fullProof = await generateProof(identity, group, group.root, signal, {
wasmFilePath,
zkeyFilePath
})
solidityProof = packToSolidityProof(fullProof.proof)
})
it("Should not verify a proof if the group does not exist", async () => {
const transaction = contract.verifyProof(10, 1, signal, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0])
await expect(transaction).to.be.revertedWith("Semaphore__GroupDoesNotExist()")
})
it("Should not verify a proof if the Merkle tree root is not part of the group", async () => {
const transaction = contract.verifyProof(2, 1, signal, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0])
await expect(transaction).to.be.revertedWith("Semaphore__MerkleTreeRootIsNotPartOfTheGroup()")
})
it("Should throw an exception if the proof is not valid", async () => {
const transaction = contract.verifyProof(
groupId,
group.root,
signal,
fullProof.publicSignals.nullifierHash,
0,
solidityProof
)
await expect(transaction).to.be.revertedWith("Semaphore__InvalidProof()")
})
it("Should verify a proof for an onchain group correctly", async () => {
const transaction = contract.verifyProof(
groupId,
group.root,
signal,
fullProof.publicSignals.nullifierHash,
fullProof.publicSignals.merkleTreeRoot,
solidityProof
)
await expect(transaction)
.to.emit(contract, "ProofVerified")
.withArgs(
groupId,
group.root,
fullProof.publicSignals.nullifierHash,
fullProof.publicSignals.merkleTreeRoot,
signal
)
})
it("Should not verify the same proof for an onchain group twice", async () => {
const transaction = contract.verifyProof(
groupId,
group.root,
signal,
fullProof.publicSignals.nullifierHash,
fullProof.publicSignals.merkleTreeRoot,
solidityProof
)
await expect(transaction).to.be.revertedWith("Semaphore__YouAreUsingTheSameNillifierTwice()")
})
it("Should not verify a proof if the Merkle tree root is expired", async () => {
const groupId = 2
const group = new Group(treeDepth)
group.addMembers([members[0], members[1]])
const fullProof = await generateProof(identity, group, group.root, signal, {
wasmFilePath,
zkeyFilePath
})
const solidityProof = packToSolidityProof(fullProof.proof)
const transaction = contract.verifyProof(
groupId,
group.root,
signal,
fullProof.publicSignals.nullifierHash,
0,
solidityProof
)
await expect(transaction).to.be.revertedWith("Semaphore__MerkleTreeRootIsExpired()")
})
})
})

View File

@@ -0,0 +1,186 @@
/* eslint-disable jest/valid-expect */
import { Group } from "@semaphore-protocol/group"
import { Identity } from "@semaphore-protocol/identity"
import { generateProof, packToSolidityProof, PublicSignals, SolidityProof } from "@semaphore-protocol/proof"
import { expect } from "chai"
import { Signer } from "ethers"
import { ethers, run } from "hardhat"
import { SemaphoreVoting } from "../build/typechain"
describe("SemaphoreVoting", () => {
let contract: SemaphoreVoting
let accounts: Signer[]
let coordinator: string
const treeDepth = Number(process.env.TREE_DEPTH) || 20
const pollIds = [1, 2, 3]
const encryptionKey = BigInt(0)
const decryptionKey = BigInt(0)
const wasmFilePath = `../../snark-artifacts/${treeDepth}/semaphore.wasm`
const zkeyFilePath = `../../snark-artifacts/${treeDepth}/semaphore.zkey`
before(async () => {
contract = await run("deploy:semaphore-voting", {
logs: false
})
accounts = await ethers.getSigners()
coordinator = await accounts[1].getAddress()
})
describe("# createPoll", () => {
it("Should not create a poll with a wrong depth", async () => {
const transaction = contract.createPoll(pollIds[0], coordinator, 10)
await expect(transaction).to.be.revertedWith("Semaphore__MerkleTreeDepthIsNotSupported()")
})
it("Should create a poll", async () => {
const transaction = contract.createPoll(pollIds[0], coordinator, treeDepth)
await expect(transaction).to.emit(contract, "PollCreated").withArgs(pollIds[0], coordinator)
})
it("Should not create a poll if it already exists", async () => {
const transaction = contract.createPoll(pollIds[0], coordinator, treeDepth)
await expect(transaction).to.be.revertedWith("Semaphore__GroupAlreadyExists()")
})
})
describe("# startPoll", () => {
it("Should not start the poll if the caller is not the coordinator", async () => {
const transaction = contract.startPoll(pollIds[0], encryptionKey)
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotThePollCoordinator()")
})
it("Should start the poll", async () => {
const transaction = contract.connect(accounts[1]).startPoll(pollIds[0], encryptionKey)
await expect(transaction).to.emit(contract, "PollStarted").withArgs(pollIds[0], coordinator, encryptionKey)
})
it("Should not start a poll if it has already been started", async () => {
const transaction = contract.connect(accounts[1]).startPoll(pollIds[0], encryptionKey)
await expect(transaction).to.be.revertedWith("Semaphore__PollHasAlreadyBeenStarted()")
})
})
describe("# addVoter", () => {
before(async () => {
await contract.createPoll(pollIds[1], coordinator, treeDepth)
})
it("Should not add a voter if the caller is not the coordinator", async () => {
const { commitment } = new Identity()
const transaction = contract.addVoter(pollIds[0], commitment)
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotThePollCoordinator()")
})
it("Should not add a voter if the poll has already been started", async () => {
const { commitment } = new Identity()
const transaction = contract.connect(accounts[1]).addVoter(pollIds[0], commitment)
await expect(transaction).to.be.revertedWith("Semaphore__PollHasAlreadyBeenStarted()")
})
it("Should add a voter to an existing poll", async () => {
const { commitment } = new Identity("test")
const group = new Group(treeDepth)
group.addMember(commitment)
const transaction = contract.connect(accounts[1]).addVoter(pollIds[1], commitment)
await expect(transaction).to.emit(contract, "MemberAdded").withArgs(pollIds[1], 0, commitment, group.root)
})
it("Should return the correct number of poll voters", async () => {
const size = await contract.getNumberOfMerkleTreeLeaves(pollIds[1])
expect(size).to.be.eq(1)
})
})
describe("# castVote", () => {
const identity = new Identity("test")
const vote = 1
const group = new Group(treeDepth)
group.addMembers([identity.commitment, BigInt(1)])
let solidityProof: SolidityProof
let publicSignals: PublicSignals
before(async () => {
await contract.connect(accounts[1]).addVoter(pollIds[1], BigInt(1))
await contract.connect(accounts[1]).startPoll(pollIds[1], encryptionKey)
await contract.createPoll(pollIds[2], coordinator, treeDepth)
const fullProof = await generateProof(identity, group, pollIds[1], vote, {
wasmFilePath,
zkeyFilePath
})
publicSignals = fullProof.publicSignals
solidityProof = packToSolidityProof(fullProof.proof)
})
it("Should not cast a vote if the poll is not ongoing", async () => {
const transaction = contract
.connect(accounts[1])
.castVote(vote, publicSignals.nullifierHash, pollIds[2], solidityProof)
await expect(transaction).to.be.revertedWith("Semaphore__PollIsNotOngoing()")
})
it("Should not cast a vote if the proof is not valid", async () => {
const transaction = contract.connect(accounts[1]).castVote(vote, 0, pollIds[1], solidityProof)
await expect(transaction).to.be.revertedWith("Semaphore__InvalidProof()")
})
it("Should cast a vote", async () => {
const transaction = contract
.connect(accounts[1])
.castVote(vote, publicSignals.nullifierHash, pollIds[1], solidityProof)
await expect(transaction).to.emit(contract, "VoteAdded").withArgs(pollIds[1], vote)
})
it("Should not cast a vote twice", async () => {
const transaction = contract
.connect(accounts[1])
.castVote(vote, publicSignals.nullifierHash, pollIds[1], solidityProof)
await expect(transaction).to.be.revertedWith("Semaphore__YouAreUsingTheSameNillifierTwice()")
})
})
describe("# endPoll", () => {
it("Should not end the poll if the caller is not the coordinator", async () => {
const transaction = contract.endPoll(pollIds[1], decryptionKey)
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotThePollCoordinator()")
})
it("Should end the poll", async () => {
const transaction = contract.connect(accounts[1]).endPoll(pollIds[1], encryptionKey)
await expect(transaction).to.emit(contract, "PollEnded").withArgs(pollIds[1], coordinator, decryptionKey)
})
it("Should not end a poll if it has already been ended", async () => {
const transaction = contract.connect(accounts[1]).endPoll(pollIds[1], encryptionKey)
await expect(transaction).to.be.revertedWith("Semaphore__PollIsNotOngoing()")
})
})
})

View File

@@ -0,0 +1,150 @@
/* eslint-disable jest/valid-expect */
import { Group } from "@semaphore-protocol/group"
import { Identity } from "@semaphore-protocol/identity"
import { generateProof, packToSolidityProof, PublicSignals, SolidityProof } from "@semaphore-protocol/proof"
import { expect } from "chai"
import { Signer, utils } from "ethers"
import { ethers, run } from "hardhat"
import { SemaphoreWhistleblowing } from "../build/typechain"
describe("SemaphoreWhistleblowing", () => {
let contract: SemaphoreWhistleblowing
let accounts: Signer[]
let editor: string
const treeDepth = Number(process.env.TREE_DEPTH) || 20
const entityIds = [1, 2]
const wasmFilePath = `../../snark-artifacts/${treeDepth}/semaphore.wasm`
const zkeyFilePath = `../../snark-artifacts/${treeDepth}/semaphore.zkey`
before(async () => {
contract = await run("deploy:semaphore-whistleblowing", {
logs: false
})
accounts = await ethers.getSigners()
editor = await accounts[1].getAddress()
})
describe("# createEntity", () => {
it("Should not create an entity with a wrong depth", async () => {
const transaction = contract.createEntity(entityIds[0], editor, 10)
await expect(transaction).to.be.revertedWith("Semaphore__MerkleTreeDepthIsNotSupported()")
})
it("Should create an entity", async () => {
const transaction = contract.createEntity(entityIds[0], editor, treeDepth)
await expect(transaction).to.emit(contract, "EntityCreated").withArgs(entityIds[0], editor)
})
it("Should not create a entity if it already exists", async () => {
const transaction = contract.createEntity(entityIds[0], editor, treeDepth)
await expect(transaction).to.be.revertedWith("Semaphore__GroupAlreadyExists()")
})
})
describe("# addWhistleblower", () => {
it("Should not add a whistleblower if the caller is not the editor", async () => {
const { commitment } = new Identity()
const transaction = contract.addWhistleblower(entityIds[0], commitment)
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotTheEditor()")
})
it("Should add a whistleblower to an existing entity", async () => {
const { commitment } = new Identity("test")
const group = new Group(treeDepth)
group.addMember(commitment)
const transaction = contract.connect(accounts[1]).addWhistleblower(entityIds[0], commitment)
await expect(transaction).to.emit(contract, "MemberAdded").withArgs(entityIds[0], 0, commitment, group.root)
})
it("Should return the correct number of whistleblowers of an entity", async () => {
const size = await contract.getNumberOfMerkleTreeLeaves(entityIds[0])
expect(size).to.be.eq(1)
})
})
describe("# removeWhistleblower", () => {
it("Should not remove a whistleblower if the caller is not the editor", async () => {
const { commitment } = new Identity()
const group = new Group(treeDepth)
group.addMember(commitment)
const { siblings, pathIndices } = group.generateMerkleProof(0)
const transaction = contract.removeWhistleblower(entityIds[0], commitment, siblings, pathIndices)
await expect(transaction).to.be.revertedWith("Semaphore__CallerIsNotTheEditor()")
})
it("Should remove a whistleblower from an existing entity", async () => {
const { commitment } = new Identity("test")
const group = new Group(treeDepth)
group.addMember(commitment)
const { siblings, pathIndices } = group.generateMerkleProof(0)
group.removeMember(0)
const transaction = contract
.connect(accounts[1])
.removeWhistleblower(entityIds[0], commitment, siblings, pathIndices)
await expect(transaction)
.to.emit(contract, "MemberRemoved")
.withArgs(entityIds[0], 0, commitment, group.root)
})
})
describe("# publishLeak", () => {
const identity = new Identity("test")
const leak = utils.formatBytes32String("This is a leak")
const group = new Group(treeDepth)
group.addMembers([identity.commitment, BigInt(1)])
let solidityProof: SolidityProof
let publicSignals: PublicSignals
before(async () => {
await contract.createEntity(entityIds[1], editor, treeDepth)
await contract.connect(accounts[1]).addWhistleblower(entityIds[1], identity.commitment)
await contract.connect(accounts[1]).addWhistleblower(entityIds[1], BigInt(1))
const fullProof = await generateProof(identity, group, entityIds[1], leak, {
wasmFilePath,
zkeyFilePath
})
publicSignals = fullProof.publicSignals
solidityProof = packToSolidityProof(fullProof.proof)
})
it("Should not publish a leak if the proof is not valid", async () => {
const transaction = contract.connect(accounts[1]).publishLeak(leak, 0, entityIds[1], solidityProof)
await expect(transaction).to.be.revertedWith("Semaphore__InvalidProof()")
})
it("Should publish a leak", async () => {
const transaction = contract
.connect(accounts[1])
.publishLeak(leak, publicSignals.nullifierHash, entityIds[1], solidityProof)
await expect(transaction).to.emit(contract, "LeakPublished").withArgs(entityIds[1], leak)
})
})
})

View File

@@ -0,0 +1,14 @@
import { Identity } from "@semaphore-protocol/identity"
// eslint-disable-next-line import/prefer-default-export
export function createIdentityCommitments(n: number): bigint[] {
const identityCommitments: bigint[] = []
for (let i = 0; i < n; i += 1) {
const { commitment } = new Identity(i.toString())
identityCommitments.push(commitment)
}
return identityCommitments
}

View File

@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "ES2018",
"module": "CommonJS",
"outDir": "dist"
},
"include": ["scripts/**/*", "tasks/**/*", "test/**/*", "build/typechain/**/*", "types/**/*"],
"files": ["hardhat.config.ts"]
}

21
packages/group/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.

127
packages/group/README.md Normal file
View File

@@ -0,0 +1,127 @@
<p align="center">
<h1 align="center">
Semaphore group
</h1>
<p align="center">A library to create and manage Semaphore groups.</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/group">
<img alt="NPM version" src="https://img.shields.io/npm/v/@semaphore-protocol/group?style=flat-square" />
</a>
<a href="https://npmjs.org/package/@semaphore-protocol/group">
<img alt="Downloads" src="https://img.shields.io/npm/dm/@semaphore-protocol/group.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://discord.gg/6mSdGHnstH">
🗣️ Chat &amp; Support
</a>
</h4>
</div>
| This library is an abstraction of [`@zk-kit/incremental-merkle-tree`](https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/incremental-merkle-tree). The main goal is to make it easier to create offchain groups, which are also used to generate Semaphore proofs. Semaphore groups are actually incremental Merkle trees, and the group members are tree leaves. Since the Merkle tree implementation we are using is a binary tree, the maximum number of members of a group is equal to `2^treeDepth`. |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
## 🛠 Install
### npm or yarn
Install the `@semaphore-protocol/group` package with npm:
```bash
npm i @semaphore-protocol/group
```
or yarn:
```bash
yarn add @semaphore-protocol/group
```
## 📜 Usage
\# **new Group**(treeDepth = 20, zeroValue = BigInt(0)): _Group_
```typescript
import { Group } from "@semaphore-protocol/group"
// Group with max 1048576 members (20^²).
const group1 = new Group()
// Group with max 65536 members (16^²).
const group2 = new Group(16)
// Group with max 16777216 members (24^²).
const group3 = new Group(24)
```
\# **addMember**(identityCommitment: _Member_)
```typescript
import { Identity } from "@semaphore-protocol/identity"
const identity = new Identity()
const commitment = identity.generateCommitment()
group.addMember(commitment)
```
\# **addMembers**(identityCommitments: _Member\[]_)
```typescript
let identityCommitments: bigint[]
for (let i = 0; i < 10; i++) {
const identity = new Identity()
const commitment = identity.generateCommitment()
identityCommitments.push(commitment)
}
group.addMember(identityCommitments)
```
\# **removeMember**(index: _number_)
```typescript
group.removeMember(0)
```
\# **indexOf**(member: _Member_): _number_
```typescript
group.indexOf(commitment) // 0
```
\# **generateMerkleProof**(index: _number_): _MerkleProof_
```typescript
const proof = group.generateMerkleProof(0)
```

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"declarationDir": "dist/types"
},
"include": ["src"]
}

View File

@@ -0,0 +1,41 @@
{
"name": "@semaphore-protocol/group",
"version": "2.6.1",
"description": "A library to create and manage Semaphore groups.",
"license": "MIT",
"main": "dist/index.node.js",
"exports": {
"import": "./dist/index.mjs",
"require": "./dist/index.node.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/group",
"bugs": {
"url": "https://github.com/semaphore-protocol/semaphore.git/issues"
},
"scripts": {
"build:watch": "rollup -c rollup.config.ts -w --configPlugin typescript",
"build": "rimraf dist && rollup -c rollup.config.ts --configPlugin typescript",
"prepublishOnly": "yarn build",
"docs": "typedoc src/index.ts --out ../../docs/group"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"rollup-plugin-cleanup": "^3.2.1",
"rollup-plugin-typescript2": "^0.31.2",
"typedoc": "^0.22.11"
},
"dependencies": {
"@zk-kit/incremental-merkle-tree": "1.0.0",
"poseidon-lite": "^0.0.2"
}
}

View File

@@ -0,0 +1,29 @@
import typescript from "rollup-plugin-typescript2"
import * as fs from "fs"
import cleanup from "rollup-plugin-cleanup"
const pkg = JSON.parse(fs.readFileSync("./package.json", "utf-8"))
const banner = `/**
* @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.exports.require, format: "cjs", banner, exports: "auto" },
{ file: pkg.exports.import, format: "es", banner }
],
external: Object.keys(pkg.dependencies),
plugins: [
typescript({
tsconfig: "./build.tsconfig.json",
useTsconfigDeclarationDir: true
}),
cleanup({ comments: "jsdoc" })
]
}

View File

@@ -0,0 +1,95 @@
import Group from "./group"
describe("Group", () => {
describe("# Group", () => {
it("Should create a group", () => {
const group = new Group()
expect(group.root.toString()).toContain("150197")
expect(group.depth).toBe(20)
expect(group.zeroValue).toBe(BigInt(0))
expect(group.members).toHaveLength(0)
})
it("Should not create a group with a wrong tree depth", () => {
const fun = () => new Group(33)
expect(fun).toThrow("The tree depth must be between 16 and 32")
})
it("Should create a group with different parameters", () => {
const group = new Group(32, BigInt(1))
expect(group.root.toString()).toContain("640470")
expect(group.depth).toBe(32)
expect(group.zeroValue).toBe(BigInt(1))
expect(group.members).toHaveLength(0)
})
})
describe("# addMember", () => {
it("Should add a member to a group", () => {
const group = new Group()
group.addMember(BigInt(3))
expect(group.members).toHaveLength(1)
})
})
describe("# addMembers", () => {
it("Should add many members to a group", () => {
const group = new Group()
group.addMembers([BigInt(1), BigInt(3)])
expect(group.members).toHaveLength(2)
})
})
describe("# indexOf", () => {
it("Should return the index of a member in a group", () => {
const group = new Group()
group.addMembers([BigInt(1), BigInt(3)])
const index = group.indexOf(BigInt(3))
expect(index).toBe(1)
})
})
describe("# updateMember", () => {
it("Should update a member in a group", () => {
const group = new Group()
group.addMembers([BigInt(1), BigInt(3)])
group.updateMember(0, BigInt(1))
expect(group.members).toHaveLength(2)
expect(group.members[0]).toBe(BigInt(1))
})
})
describe("# removeMember", () => {
it("Should remove a member from a group", () => {
const group = new Group()
group.addMembers([BigInt(1), BigInt(3)])
group.removeMember(0)
expect(group.members).toHaveLength(2)
expect(group.members[0]).toBe(group.zeroValue)
})
})
describe("# generateMerkleProof", () => {
it("Should generate a proof of membership", () => {
const group = new Group()
group.addMembers([BigInt(1), BigInt(3)])
const proof = group.generateMerkleProof(0)
expect(proof.leaf).toBe(BigInt(1))
})
})
})

109
packages/group/src/group.ts Normal file
View File

@@ -0,0 +1,109 @@
import { IncrementalMerkleTree, MerkleProof } from "@zk-kit/incremental-merkle-tree"
import poseidon from "poseidon-lite"
import { Member } from "./types"
export default class Group {
merkleTree: IncrementalMerkleTree
/**
* Initializes the group with the tree depth and the zero value.
* @param treeDepth Tree depth.
* @param zeroValue Zero values for zeroes.
*/
constructor(treeDepth = 20, zeroValue: Member = BigInt(0)) {
if (treeDepth < 16 || treeDepth > 32) {
throw new Error("The tree depth must be between 16 and 32")
}
this.merkleTree = new IncrementalMerkleTree(poseidon, treeDepth, zeroValue, 2)
}
/**
* Returns the root hash of the tree.
* @returns Root hash.
*/
get root(): Member {
return this.merkleTree.root
}
/**
* Returns the depth of the tree.
* @returns Tree depth.
*/
get depth(): number {
return this.merkleTree.depth
}
/**
* Returns the zero value of the tree.
* @returns Tree zero value.
*/
get zeroValue(): Member {
return this.merkleTree.zeroes[0]
}
/**
* Returns the members (i.e. identity commitments) of the group.
* @returns List of members.
*/
get members(): Member[] {
return this.merkleTree.leaves
}
/**
* Returns the index of a member. If the member does not exist it returns -1.
* @param member Group member.
* @returns Index of the member.
*/
indexOf(member: Member): number {
return this.merkleTree.indexOf(member)
}
/**
* Adds a new member to the group.
* @param member New member.
*/
addMember(member: Member) {
this.merkleTree.insert(BigInt(member))
}
/**
* Adds new members to the group.
* @param members New members.
*/
addMembers(members: Member[]) {
for (const member of members) {
this.addMember(member)
}
}
/**
* Updates a member in the group.
* @param index Index of the member to be updated.
* @param member New member value.
*/
updateMember(index: number, member: Member) {
this.merkleTree.update(index, member)
}
/**
* Removes a member from the group.
* @param index Index of the member to be removed.
*/
removeMember(index: number) {
this.merkleTree.delete(index)
}
/**
* Creates a proof of membership.
* @param index Index of the proof's member.
* @returns Proof object.
*/
generateMerkleProof(index: number): MerkleProof {
const merkleProof = this.merkleTree.createProof(index)
merkleProof.siblings = merkleProof.siblings.map((s) => s[0])
return merkleProof
}
}

View File

@@ -0,0 +1,4 @@
import Group from "./group"
export { Group }
export * from "./types"

View File

@@ -0,0 +1 @@
export type Member = string | bigint

View File

@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["src", "rollup.config.ts"]
}

115
packages/hardhat/README.md Normal file
View File

@@ -0,0 +1,115 @@
<p align="center">
<h1 align="center">
Semaphore Hardhat plugin
</h1>
<p align="center">A Semaphore Hardhat plugin to deploy verifiers and Semaphore contracts.</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/hardhat">
<img alt="NPM version" src="https://img.shields.io/npm/v/@semaphore-protocol/hardhat?style=flat-square" />
</a>
<a href="https://npmjs.org/package/@semaphore-protocol/hardhat">
<img alt="Downloads" src="https://img.shields.io/npm/dm/@semaphore-protocol/hardhat.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://discord.gg/6mSdGHnstH">
🗣️ Chat &amp; Support
</a>
</h4>
</div>
| This Hardhat plugin provides two simple tasks that can be used to deploy verifiers and Semaphore contracts without any additional configuration. |
| ------------------------------------------------------------------------------------------------------------------------------------------------ |
## 🛠 Install
### npm or yarn
Install the `@semaphore-protocol/hardhat` package with npm:
```bash
npm i @semaphore-protocol/hardhat
```
or yarn:
```bash
yarn add @semaphore-protocol/hardhat
```
## 📜 Usage
Import the plugin in your `hardhat.config.ts` file:
```typescript
import "@semaphore-protocol/hardhat"
import "./tasks/deploy"
const hardhatConfig: HardhatUserConfig = {
solidity: "0.8.4"
}
export default hardhatConfig
```
And use its tasks to create your own `deploy` task and deploy your contract with a Semaphore address.
```typescript
import { task, types } from "hardhat/config"
task("deploy", "Deploy a Greeter contract")
.addOptionalParam("logs", "Print the logs", true, types.boolean)
.setAction(async ({ logs }, { ethers, run }) => {
const { address: verifierAddress } = await run("deploy:verifier", { logs, merkleTreeDepth: 20 })
const { address: semaphoreAddress } = await run("deploy:semaphore", {
logs,
verifiers: [
{
merkleTreeDepth: 20,
contractAddress: verifierAddress
}
]
})
const Greeter = await ethers.getContractFactory("Greeter")
const greeter = await Greeter.deploy(semaphoreAddress)
await greeter.deployed()
if (logs) {
console.log(`Greeter contract has been deployed to: ${greeter.address}`)
}
return greeter
})
```

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"declarationDir": "dist/types"
},
"include": ["src"]
}

View File

@@ -0,0 +1,46 @@
{
"name": "@semaphore-protocol/hardhat",
"version": "0.1.0",
"description": "A Semaphore Hardhat plugin to deploy verifiers and Semaphore contract.",
"license": "MIT",
"main": "dist/index.node.js",
"exports": {
"import": "./dist/index.mjs",
"require": "./dist/index.node.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/hardhat",
"bugs": {
"url": "https://github.com/semaphore-protocol/semaphore.git/issues"
},
"scripts": {
"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": {
"hardhat": "^2.0.0",
"rollup-plugin-cleanup": "^3.2.1",
"rollup-plugin-typescript2": "^0.31.2"
},
"peerDependencies": {
"hardhat": "^2.0.0"
},
"dependencies": {
"@nomiclabs/hardhat-ethers": "^2.1.1",
"@semaphore-protocol/contracts": "^2.5.0",
"circomlibjs": "^0.0.8",
"ethers": "^5.7.1",
"hardhat-dependency-compiler": "^1.1.3"
}
}

View File

@@ -0,0 +1,29 @@
import typescript from "rollup-plugin-typescript2"
import * as fs from "fs"
import cleanup from "rollup-plugin-cleanup"
const pkg = JSON.parse(fs.readFileSync("./package.json", "utf-8"))
const banner = `/**
* @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.exports.require, format: "cjs", banner, exports: "auto" },
{ file: pkg.exports.import, format: "es", banner }
],
external: Object.keys(pkg.dependencies),
plugins: [
typescript({
tsconfig: "./build.tsconfig.json",
useTsconfigDeclarationDir: true
}),
cleanup({ comments: "jsdoc" })
]
}

View File

@@ -0,0 +1,34 @@
import { extendConfig } from "hardhat/config"
import { HardhatConfig, HardhatUserConfig } from "hardhat/types"
import "hardhat-dependency-compiler"
import "@nomiclabs/hardhat-ethers"
import "./tasks/deploy-semaphore"
import "./tasks/deploy-verifier"
extendConfig((config: HardhatConfig, userConfig: Readonly<HardhatUserConfig>) => {
config.dependencyCompiler.paths = [
"@semaphore-protocol/contracts/verifiers/Verifier16.sol",
"@semaphore-protocol/contracts/verifiers/Verifier17.sol",
"@semaphore-protocol/contracts/verifiers/Verifier18.sol",
"@semaphore-protocol/contracts/verifiers/Verifier19.sol",
"@semaphore-protocol/contracts/verifiers/Verifier20.sol",
"@semaphore-protocol/contracts/verifiers/Verifier21.sol",
"@semaphore-protocol/contracts/verifiers/Verifier22.sol",
"@semaphore-protocol/contracts/verifiers/Verifier23.sol",
"@semaphore-protocol/contracts/verifiers/Verifier24.sol",
"@semaphore-protocol/contracts/verifiers/Verifier25.sol",
"@semaphore-protocol/contracts/verifiers/Verifier26.sol",
"@semaphore-protocol/contracts/verifiers/Verifier27.sol",
"@semaphore-protocol/contracts/verifiers/Verifier28.sol",
"@semaphore-protocol/contracts/verifiers/Verifier29.sol",
"@semaphore-protocol/contracts/verifiers/Verifier30.sol",
"@semaphore-protocol/contracts/verifiers/Verifier31.sol",
"@semaphore-protocol/contracts/verifiers/Verifier32.sol",
"@semaphore-protocol/contracts/Semaphore.sol"
]
if (userConfig.dependencyCompiler?.paths) {
config.dependencyCompiler.paths = [...config.dependencyCompiler.paths, ...userConfig.dependencyCompiler.paths]
}
})

View File

@@ -0,0 +1,51 @@
import { poseidon_gencontract as poseidonContract } from "circomlibjs"
import { Contract } from "ethers"
import { task, types } from "hardhat/config"
task("deploy:semaphore", "Deploy a Semaphore contract")
.addParam("verifiers", "Tree depths and verifier addresses", [], types.json)
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
.setAction(async ({ logs, verifiers }, { ethers }): Promise<Contract> => {
const poseidonABI = poseidonContract.generateABI(2)
const poseidonBytecode = poseidonContract.createCode(2)
const [signer] = await ethers.getSigners()
const PoseidonLibFactory = new ethers.ContractFactory(poseidonABI, poseidonBytecode, signer)
const poseidonLib = await PoseidonLibFactory.deploy()
await poseidonLib.deployed()
if (logs) {
console.info(`Poseidon library has been deployed to: ${poseidonLib.address}`)
}
const IncrementalBinaryTreeLibFactory = await ethers.getContractFactory("IncrementalBinaryTree", {
libraries: {
PoseidonT3: poseidonLib.address
}
})
const incrementalBinaryTreeLib = await IncrementalBinaryTreeLibFactory.deploy()
await incrementalBinaryTreeLib.deployed()
if (logs) {
console.info(`IncrementalBinaryTree library has been deployed to: ${incrementalBinaryTreeLib.address}`)
}
const SemaphoreContractFactory = await ethers.getContractFactory("Semaphore", {
libraries: {
IncrementalBinaryTree: incrementalBinaryTreeLib.address
}
})
const semaphoreContract = await SemaphoreContractFactory.deploy(verifiers)
await semaphoreContract.deployed()
if (logs) {
console.info(`Semaphore contract has been deployed to: ${semaphoreContract.address}`)
}
return semaphoreContract
})

View File

@@ -0,0 +1,19 @@
import { Contract } from "ethers"
import { task, types } from "hardhat/config"
task("deploy:verifier", "Deploy a Verifier contract")
.addParam<number>("merkleTreeDepth", "Merkle tree depth", undefined, types.int)
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
.setAction(async ({ merkleTreeDepth, logs }, { ethers }): Promise<Contract> => {
const VerifierContractFactory = await ethers.getContractFactory(`Verifier${merkleTreeDepth}`)
const verifierContract = await VerifierContractFactory.deploy()
await verifierContract.deployed()
if (logs) {
console.info(`Verifier${merkleTreeDepth} contract has been deployed to: ${verifierContract.address}`)
}
return verifierContract
})

View File

@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["src", "rollup.config.ts"]
}

21
packages/identity/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.

View File

@@ -0,0 +1,86 @@
<p align="center">
<h1 align="center">
Semaphore identity
</h1>
<p align="center">A library to create Semaphore identities.</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/identity">
<img alt="NPM version" src="https://img.shields.io/npm/v/@semaphore-protocol/identity?style=flat-square" />
</a>
<a href="https://npmjs.org/package/@semaphore-protocol/identity">
<img alt="Downloads" src="https://img.shields.io/npm/dm/@semaphore-protocol/identity.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://discord.gg/6mSdGHnstH">
🗣️ Chat &amp; Support
</a>
</h4>
</div>
| This library provides a class that can be used to create identities compatible with the Semaphore [circuits](https://github.com/semaphore-protocol/semaphore/tree/main/circuits). Each identity contains two secret values: _trapdoor_ and _nullifier_, and one public value: _commitment_. The Poseidon hash of the secret values is the identity secret, and its hash is the identity commitment. |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
## 🛠 Install
### npm or yarn
Install the `@semaphore-protocol/identity` package with npm:
```bash
npm i @semaphore-protocol/identity
```
or yarn:
```bash
yarn add @semaphore-protocol/identity
```
## 📜 Usage
\# **new Identity**(identityOrMessage?: _string_): _Identity_
```typescript
import { Identity } from "@semaphore-protocol/identity"
// The identity can be generated randomly.
const identity1 = new Identity()
// Deterministically from a secret message.
const identity2 = new Identity("secret-message")
// Or it can be retrieved from an existing identity.
const identity3 = new Identity(identity1.toString())
// Trapdoor, nullifier and commitment are the attributes (e.g. JS getters).
const { trapdoor, nullifier, commitment } = identity1
```

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"declarationDir": "dist/types"
},
"include": ["src"]
}

View File

@@ -0,0 +1,44 @@
{
"name": "@semaphore-protocol/identity",
"version": "2.6.1",
"description": "A library to create Semaphore identities.",
"license": "MIT",
"main": "dist/index.node.js",
"exports": {
"import": "./dist/index.mjs",
"require": "./dist/index.node.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/identity",
"bugs": {
"url": "https://github.com/semaphore-protocol/semaphore.git/issues"
},
"scripts": {
"build:watch": "rollup -c rollup.config.ts -w --configPlugin typescript",
"build": "rimraf dist && rollup -c rollup.config.ts --configPlugin typescript",
"prepublishOnly": "yarn build",
"docs": "typedoc src/index.ts --out ../../docs/identity"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"rollup-plugin-cleanup": "^3.2.1",
"rollup-plugin-typescript2": "^0.31.2",
"typedoc": "^0.22.11"
},
"dependencies": {
"@ethersproject/bignumber": "^5.5.0",
"@ethersproject/random": "^5.5.1",
"@ethersproject/sha2": "^5.6.1",
"@ethersproject/strings": "^5.6.1",
"poseidon-lite": "^0.0.2"
}
}

View File

@@ -0,0 +1,29 @@
import typescript from "rollup-plugin-typescript2"
import * as fs from "fs"
import cleanup from "rollup-plugin-cleanup"
const pkg = JSON.parse(fs.readFileSync("./package.json", "utf-8"))
const banner = `/**
* @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.exports.require, format: "cjs", banner, exports: "auto" },
{ file: pkg.exports.import, format: "es", banner }
],
external: Object.keys(pkg.dependencies),
plugins: [
typescript({
tsconfig: "./build.tsconfig.json",
useTsconfigDeclarationDir: true
}),
cleanup({ comments: "jsdoc" })
]
}

View File

@@ -0,0 +1,5 @@
export default function checkParameter(value: any, name: string, type: string) {
if (typeof value !== type) {
throw new TypeError(`Parameter '${name}' is not a ${type}`)
}
}

View File

@@ -0,0 +1,115 @@
import { BigNumber } from "@ethersproject/bignumber"
import Identity from "./identity"
describe("Identity", () => {
describe("# Identity", () => {
it("Should not create a identity if the parameter is not valid", () => {
const fun1 = () => new Identity(13 as any)
const fun2 = () => new Identity(true as any)
const fun3 = () => new Identity((() => true) as any)
expect(fun1).toThrow("Parameter 'identityOrMessage' is not a string")
expect(fun2).toThrow("Parameter 'identityOrMessage' is not a string")
expect(fun3).toThrow("Parameter 'identityOrMessage' is not a string")
})
it("Should create random identities", () => {
const identity1 = new Identity()
const identity2 = new Identity()
expect(identity1.trapdoor).not.toBe(identity2.getTrapdoor())
expect(identity1.nullifier).not.toBe(identity2.getNullifier())
expect(identity1.commitment).not.toBe(identity2.getCommitment())
})
it("Should create deterministic identities from a message", () => {
const identity1 = new Identity("message")
const identity2 = new Identity("message")
expect(identity1.trapdoor).toBe(identity2.getTrapdoor())
expect(identity1.nullifier).toBe(identity2.getNullifier())
})
it("Should create deterministic identities from number/boolean messages", () => {
const identity1 = new Identity("true")
const identity2 = new Identity("true")
const identity3 = new Identity("7")
const identity4 = new Identity("7")
expect(identity1.trapdoor).toBe(identity2.getTrapdoor())
expect(identity1.nullifier).toBe(identity2.getNullifier())
expect(identity3.trapdoor).toBe(identity4.getTrapdoor())
expect(identity3.nullifier).toBe(identity4.getNullifier())
})
it("Should not recreate an existing invalid identity", () => {
const fun = () => new Identity('[true, "01323"]')
expect(fun).toThrow("invalid BigNumber string")
})
it("Should recreate an existing identity", () => {
const identity1 = new Identity("message")
const identity2 = new Identity(identity1.toString())
expect(identity1.trapdoor).toBe(identity2.getTrapdoor())
expect(identity1.nullifier).toBe(identity2.getNullifier())
})
})
describe("# getTrapdoor", () => {
it("Should return the identity trapdoor", () => {
const identity = new Identity("message")
const trapdoor = identity.getTrapdoor()
expect(trapdoor).toBe(
BigInt("58952291509798197436757858062402199043831251943841934828591473955215726495831")
)
})
})
describe("# getNullifier", () => {
it("Should return the identity nullifier", () => {
const identity = new Identity("message")
const nullifier = identity.getNullifier()
expect(nullifier).toBe(
BigInt("44673097405870585416457571638073245190425597599743560105244308998175651589997")
)
})
})
describe("# generateCommitment", () => {
it("Should generate an identity commitment", () => {
const identity = new Identity("message")
const commitment = identity.generateCommitment()
expect(commitment).toBe(
BigInt("1720349790382552497189398984241859233944354304766757200361065203741879866188")
)
})
})
describe("# toString", () => {
it("Should return a string", () => {
const identity = new Identity("message")
const identityString = identity.toString()
expect(typeof identityString).toBe("string")
})
it("Should return a valid identity string", () => {
const identity = new Identity("message")
const [trapdoor, nullifier] = JSON.parse(identity.toString())
expect(BigNumber.from(`0x${trapdoor}`).toBigInt()).toBe(identity.getTrapdoor())
expect(BigNumber.from(`0x${nullifier}`).toBigInt()).toBe(identity.getNullifier())
})
})
})

View File

@@ -0,0 +1,108 @@
import { BigNumber } from "@ethersproject/bignumber"
import poseidon from "poseidon-lite"
import checkParameter from "./checkParameter"
import { generateCommitment, genRandomNumber, isJsonArray, sha256 } from "./utils"
export default class Identity {
private _trapdoor: bigint
private _nullifier: bigint
private _commitment: bigint
/**
* Initializes the class attributes based on the strategy passed as parameter.
* @param identityOrMessage Additional data needed to create identity for given strategy.
*/
constructor(identityOrMessage?: string) {
if (identityOrMessage === undefined) {
this._trapdoor = genRandomNumber()
this._nullifier = genRandomNumber()
this._commitment = generateCommitment(this._nullifier, this._trapdoor)
return
}
checkParameter(identityOrMessage, "identityOrMessage", "string")
if (!isJsonArray(identityOrMessage)) {
const messageHash = sha256(identityOrMessage).slice(2)
this._trapdoor = BigNumber.from(sha256(`${messageHash}identity_trapdoor`)).toBigInt()
this._nullifier = BigNumber.from(sha256(`${messageHash}identity_nullifier`)).toBigInt()
this._commitment = generateCommitment(this._nullifier, this._trapdoor)
return
}
const [trapdoor, nullifier] = JSON.parse(identityOrMessage)
this._trapdoor = BigNumber.from(`0x${trapdoor}`).toBigInt()
this._nullifier = BigNumber.from(`0x${nullifier}`).toBigInt()
this._commitment = generateCommitment(this._nullifier, this._trapdoor)
}
/**
* Returns the identity trapdoor.
* @returns The identity trapdoor.
*/
public get trapdoor(): bigint {
return this._trapdoor
}
/**
* Returns the identity trapdoor.
* @returns The identity trapdoor.
*/
public getTrapdoor(): bigint {
return this._trapdoor
}
/**
* Returns the identity nullifier.
* @returns The identity nullifier.
*/
public get nullifier(): bigint {
return this._nullifier
}
/**
* Returns the identity nullifier.
* @returns The identity nullifier.
*/
public getNullifier(): bigint {
return this._nullifier
}
/**
* Returns the identity commitment.
* @returns The identity commitment.
*/
public get commitment(): bigint {
return this._commitment
}
/**
* Returns the identity commitment.
* @returns The identity commitment.
*/
public getCommitment(): bigint {
return this._commitment
}
/**
* @deprecated since version 2.6.0
* Generates the identity commitment from trapdoor and nullifier.
* @returns identity commitment
*/
public generateCommitment(): bigint {
return poseidon([poseidon([this._nullifier, this._trapdoor])])
}
/**
* Returns a JSON string with trapdoor and nullifier. It can be used
* to export the identity and reuse it later.
* @returns The string representation of the identity.
*/
public toString(): string {
return JSON.stringify([this._trapdoor.toString(16), this._nullifier.toString(16)])
}
}

View File

@@ -0,0 +1,4 @@
import Identity from "./identity"
// eslint-disable-next-line import/prefer-default-export
export { Identity }

View File

@@ -0,0 +1,48 @@
import { BigNumber } from "@ethersproject/bignumber"
import { randomBytes } from "@ethersproject/random"
import { sha256 as _sha256 } from "@ethersproject/sha2"
import { toUtf8Bytes } from "@ethersproject/strings"
import poseidon from "poseidon-lite"
/**
* Returns an hexadecimal sha256 hash of the message passed as parameter.
* @param message The string to hash.
* @returns The hexadecimal hash of the message.
*/
export function sha256(message: string): string {
const hash = _sha256(toUtf8Bytes(message))
return hash
}
/**
* Generates a random big number.
* @param numberOfBytes The number of bytes of the number.
* @returns The generated random number.
*/
export function genRandomNumber(numberOfBytes = 31): bigint {
return BigNumber.from(randomBytes(numberOfBytes)).toBigInt()
}
/**
* Generates the identity commitment from trapdoor and nullifier.
* @param nullifier The identity nullifier.
* @param trapdoor The identity trapdoor.
* @returns identity commitment
*/
export function generateCommitment(nullifier: bigint, trapdoor: bigint): bigint {
return poseidon([poseidon([nullifier, trapdoor])])
}
/**
* Checks if a string is a JSON.
* @param jsonString The JSON string.
* @returns True or false.
*/
export function isJsonArray(jsonString: string) {
try {
return Array.isArray(JSON.parse(jsonString))
} catch (error) {
return false
}
}

View File

@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["src", "rollup.config.ts"]
}

21
packages/proof/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.

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