Compare commits

...

316 Commits

Author SHA1 Message Date
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
Kobi Gurkan
f4734cf9ce fix: invalidates snark cache
Former-commit-id: f97636be08
2019-09-28 19:29:20 +03:00
Koh Wei Jie
12d54003c5 Support for multiple external nullifiers (#31)
* added support for multiple external nullifiers

* support for removing an external nullifier

* removed rocksdb from the tests to avoid the lock error

* updated readme about multiple external nullifiers


Former-commit-id: 13cf56616f
2019-09-28 19:08:45 +03:00
Kobi Gurkan
cfa98a9833 fix: fake_zero must be constrained to zero
Former-commit-id: fbd2f0cefa
2019-09-27 11:54:52 +03:00
Kobi Gurkan
01921268fb fix: uses latest circomlib to fix mimcsponge bug
Former-commit-id: 2933bce0e4
2019-09-17 09:15:53 +03:00
Kobi Gurkan
93448311f5 fix: makes fake_zero a private input
Former-commit-id: 3aed03c65d
2019-09-16 22:54:17 +03:00
Kobi Gurkan
6ed742771a fix: moves fake_zero*root to correct place
Former-commit-id: cc3f08d1a0
2019-09-16 10:43:13 +03:00
Kobi Gurkan
86e22c8cb9 fix: uses fake_zero differently in sig_verifier
Former-commit-id: a76c72a777
2019-09-16 09:17:20 +03:00
Kobi Gurkan
dd435e0bf9 adds fake_zero to prevent unconstrained variables
Former-commit-id: 370992cc2e
2019-09-16 09:05:11 +03:00
Kobi Gurkan
6d26f0d39e uses <-- in one place in blake2s
Former-commit-id: 2cedb25dfa
2019-09-15 22:41:12 +03:00
Kobi Gurkan
c01132b535 makes blake2s use <==
Former-commit-id: 6ffdd09d78
2019-09-15 22:22:47 +03:00
Kobi Gurkan
f94e88c1af fix: updates snark cache
Former-commit-id: 9327523436
2019-09-15 20:31:21 +03:00
Kobi Gurkan
0af2ccc8c9 feat: updates circom version
Former-commit-id: 352a28c8a0
2019-09-15 20:19:31 +03:00
Kobi Gurkan
99922c3a76 fix: removes broadcaster_address from readme
Former-commit-id: 9c9ef5dbe2
2019-08-25 22:48:59 +03:00
138 changed files with 24592 additions and 5224 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.10-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.10-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

7
.env.example Normal file
View File

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

31
.eslintignore Normal file
View File

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

11
.eslintrc.json Normal file
View File

@@ -0,0 +1,11 @@
{
"env": {
"es6": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json"
},
"plugins": ["@typescript-eslint"]
}

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.

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

50
.github/workflows/coverall.yml vendored Normal file
View File

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

44
.github/workflows/style.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: style
on:
pull_request:
push:
branches:
- main
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_CHECKSUM_BEHAVIOR=ignore yarn
- name: Run Prettier
run: yarn prettier
- name: Run Eslint
run: yarn lint
- name: Compile contracts
run: yarn compile

47
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,47 @@
name: test
on:
pull_request:
push:
branches:
- main
env:
TREE_DEPTH: 20
jobs:
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_CHECKSUM_BEHAVIOR=ignore yarn
- name: Download Snark artifacts
run: yarn download:snark-artifacts
- name: Compile contracts
run: yarn compile
- name: Test contracts with coverage
run: yarn test:coverage

74
.gitignore vendored Normal file
View File

@@ -0,0 +1,74 @@
# 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
# Testing
coverage
coverage.json
# Dependency directories
node_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# 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
deployed-contracts/undefined.json
deployed-contracts/localhost.json
# Hardhat
artifacts
cache
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v3
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

3
.lintstagedrc.json Normal file
View File

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

37
.prettierignore Normal file
View File

@@ -0,0 +1,37 @@
# dependencies
node_modules
package-lock.json
yarn.lock
.yarn
# testing
coverage
coverage.json
# hardhat
cache
# types
types
# circuits
circuits
# contracts
contracts/verifiers
# production
dist
build
# github
.github/ISSUE_TEMPLATE
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

5
.prettierrc.json Normal file
View File

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

21
.solcover.js Normal file
View File

@@ -0,0 +1,21 @@
module.exports = {
skipFiles: [
"verifiers/Verifier16.sol",
"verifiers/Verifier17.sol",
"verifiers/Verifier18.sol",
"verifiers/Verifier19.sol",
"verifiers/Verifier20.sol",
"verifiers/Verifier21.sol",
"verifiers/Verifier22.sol",
"verifiers/Verifier23.sol",
"verifiers/Verifier24.sol",
"verifiers/Verifier25.sol",
"verifiers/Verifier26.sol",
"verifiers/Verifier27.sol",
"verifiers/Verifier28.sol",
"verifiers/Verifier29.sol",
"verifiers/Verifier30.sol",
"verifiers/Verifier31.sol",
"verifiers/Verifier32.sol"
]
}

21
.solhint.json Normal file
View File

@@ -0,0 +1,21 @@
{
"extends": "solhint:recommended",
"plugins": ["prettier"],
"rules": {
"code-complexity": ["error", 7],
"compiler-version": ["error", ">=0.8.0"],
"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 }]
}
}

1
.solhintignore Normal file
View File

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

View File

@@ -0,0 +1 @@
b3cadff6efb37a12712d12c2553ec703dbcaa4dd

3
.yarnrc.yml Normal file
View File

@@ -0,0 +1,3 @@
nodeLinker: node-modules
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 is optional.
#### 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.

250
README.md
View File

@@ -1,169 +1,179 @@
# Semaphore
<p align="center">
<h1 align="center">
<img width="40" src="https://github.com/semaphore-protocol/website/blob/main/static/img/semaphore-icon.svg">
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="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://github.com/semaphore-protocol/semaphore/actions?query=workflow%3Atest">
<img alt="GitHub Workflow test" src="https://img.shields.io/github/workflow/status/semaphore-protocol/semaphore/test?label=test&style=flat-square&logo=github">
</a>
<a href="https://github.com/semaphore-protocol/semaphore/actions?query=workflow%3Astyle">
<img alt="GitHub Workflow style" src="https://img.shields.io/github/workflow/status/semaphore-protocol/semaphore/style?label=style&style=flat-square&logo=github">
</a>
<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://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://t.me/joinchat/B-PQx1U3GtAh--Z4Fwo56A">
🗣️ 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](/circuits/scheme.png). However Semaphore also provides [Solidity contracts](/contracts) (NPM: `@semaphore-protocol/contracts`) and [JavaScript libraries](https://github.com/semaphore-protocol/semaphore.js) to make the steps for offchain proof creation and onchain verification easier. To learn more about Semaphore visit [semaphore.appliedzkp.org](https://semaphore.appliedzkp.org).
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).
## 🛠 Install
#### 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, an external nullifier and a gas price refund price:
Clone this repository:
* 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, 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.
```bash
git clone https://github.com/semaphore-protocol/semaphore.git
```
The contract allows administrative operations that only the owner is allowed to perform:
and install the dependencies:
* Managing identities using the **insertIdentity** and **updateIdentity** methods.
* Setting the **external_nullifier**.
* Setting the broadcast permissioning - whether only the owner can broadcast.
```bash
cd semaphore && yarn
```
The contract allows anyone to read the current state:
## 📜 Usage
* Reading the roots of the two trees.
* Reading the current parameters of **external_nullifier**.
Copy the `.env.example` file as `.env`:
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
cp .env.example .env
```
Lastly, the contract has a few events to allow a server to build a local state to serve users wishing to generate proofs:
and add your environment variables.
* **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.
### Code quality and formatting
Run [ESLint](https://eslint.org/) to analyze the code and catch bugs:
#### MerkleTreeLib
```bash
yarn lint
```
Manages a number of append-only Merkle trees with efficient inserts and updates.
Run [Prettier](https://prettier.io/) to check formatting rules:
### zkSNARK statement
Implemented in [**semaphorejs/snark**](semaphorejs/snark).
```bash
yarn prettier
```
The statement assures that given public inputs:
or to automatically format the code:
* **signal_hash**
* **external_nullifier**
* **broadcaster_address**
* **root**
* **nullifiers_hash**
```bash
yarn prettier:write
```
and private inputs:
* **identity_pk**
* **identity_nullifier**
* **identity_trapdoor**
* **identity_path_elements**
* **identity_path_index**
* **auth_sig_r**
* **auth_sig_s**
### Conventional commits
the following conditions hold:
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:
* 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**, **broadcaster_address**) is signed by the secret key corresponding to **identity_pk**, having the signature (**auth_sig_r**, **auth_sig_s**). This ensures that the user approves the signal broadcast by a specific **broadcaster_address**, preventing front-running attacks, and a specific state of the contract having a specific **external_nullifier**, ensuring no double-signaling.
```bash
yarn commit
```
#### Cryptographic primitives
It will also automatically check that the modified files comply with ESLint and Prettier rules.
Semaphore uses a few cryptographic primitives provided by circomlib:
### Snark artifacts
* MiMCHash for the Merkle tree, the identity commitments and the message hash in the signature.
* EdDSA for the signature.
Download the Semaphore snark artifacts needed to generate and verify proofs:
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.
```bash
yarn download:snark-artifacts
```
### Server
### Compile contracts
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:
Compile the smart contracts with [Hardhat](https://hardhat.org/):
* 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 compile
```
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 [Mocha](https://mochajs.org/) to test the contracts:
### Client
```bash
yarn test
```
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:
You can also generate a test coverage report:
* **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:coverage
```
### Web
or a test gas report:
A web interface to run the server and client APIs, generate identities and proofs directly in the browser and broadcast signals.
```bash
yarn test:report-gas
```
## Running modes
### Deploy contracts
Schematically, Semaphore has the following actors:
Deploy a verifier contract with depth = 20:
![Semaphore architecture](docs/Semaphore.svg)
```bash
yarn deploy:verifier --depth 20
```
There are 3 main running modes:
Deploy the `Semaphore.sol` contract with one verifier:
* 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 deploy:semaphore --verifiers '[{"merkleTreeDepth": 20, "contractAddress": "0x06bcD633988c1CE7Bd134DbE2C12119b6f3E4bD1"}]'
```
## Configuration
Deploy all verifiers and Semaphore contract:
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.
```bash
yarn deploy:all
```
## Running
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, kovan, arbitrum). Or you can specify it as option:
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.
```bash
yarn deploy:all --network kovan
yarn deploy:all --network localhost
```
* 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"`
If you want to deploy contracts on Goerli, Kovan or Arbitrum, remember to provide a valid private key and an Infura API in your `.env` file.

BIN
circuits/scheme.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

90
circuits/semaphore.circom Normal file
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);

40
circuits/tree.circom Normal file
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];
}

61
contracts/README.md Normal file
View File

@@ -0,0 +1,61 @@
<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://t.me/joinchat/B-PQx1U3GtAh--Z4Fwo56A">
🗣️ 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
```

96
contracts/Semaphore.sol Normal file
View File

@@ -0,0 +1,96 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./interfaces/ISemaphore.sol";
import "./interfaces/IVerifier.sol";
import "./base/SemaphoreCore.sol";
import "./base/SemaphoreGroups.sol";
/// @title Semaphore
contract Semaphore is ISemaphore, SemaphoreCore, SemaphoreGroups {
/// @dev Gets a tree depth and returns its verifier address.
mapping(uint8 => IVerifier) public verifiers;
/// @dev Gets a group id and returns the group admin address.
mapping(uint256 => address) public groupAdmins;
/// @dev Checks if the group admin is the transaction sender.
/// @param groupId: Id of the group.
modifier onlyGroupAdmin(uint256 groupId) {
require(groupAdmins[groupId] == _msgSender(), "Semaphore: caller is not the group admin");
_;
}
/// @dev Checks if there is a verifier for the given tree depth.
/// @param depth: Depth of the tree.
modifier onlySupportedDepth(uint8 depth) {
require(address(verifiers[depth]) != address(0), "Semaphore: tree depth is not supported");
_;
}
/// @dev Initializes the Semaphore verifiers used to verify the user's ZK proofs.
/// @param _verifiers: List of Semaphore verifiers (address and related Merkle tree depth).
constructor(Verifier[] memory _verifiers) {
for (uint8 i = 0; i < _verifiers.length; i++) {
verifiers[_verifiers[i].merkleTreeDepth] = IVerifier(_verifiers[i].contractAddress);
}
}
/// @dev See {ISemaphore-createGroup}.
function createGroup(
uint256 groupId,
uint8 depth,
uint256 zeroValue,
address admin
) external override onlySupportedDepth(depth) {
_createGroup(groupId, depth, zeroValue);
groupAdmins[groupId] = admin;
emit GroupAdminUpdated(groupId, address(0), admin);
}
/// @dev See {ISemaphore-updateGroupAdmin}.
function updateGroupAdmin(uint256 groupId, address newAdmin) external override onlyGroupAdmin(groupId) {
groupAdmins[groupId] = newAdmin;
emit GroupAdminUpdated(groupId, _msgSender(), newAdmin);
}
/// @dev See {ISemaphore-addMember}.
function addMember(uint256 groupId, uint256 identityCommitment) external override onlyGroupAdmin(groupId) {
_addMember(groupId, identityCommitment);
}
/// @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);
}
/// @dev See {ISemaphore-verifyProof}.
function verifyProof(
uint256 groupId,
bytes32 signal,
uint256 nullifierHash,
uint256 externalNullifier,
uint256[8] calldata proof
) external override {
uint256 root = getRoot(groupId);
uint8 depth = getDepth(groupId);
require(depth != 0, "Semaphore: group does not exist");
IVerifier verifier = verifiers[depth];
_verifyProof(signal, root, nullifierHash, externalNullifier, proof, verifier);
_saveNullifierHash(nullifierHash);
emit ProofVerified(groupId, signal);
}
}

View File

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

View File

@@ -0,0 +1,59 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../interfaces/ISemaphoreCore.sol";
import "../interfaces/IVerifier.sol";
/// @title Semaphore core contract.
/// @notice Minimal code to allow users to signal their endorsement of an arbitrary string.
/// @dev The following code verifies that the proof is correct and saves the hash of the
/// nullifier to prevent double-signaling. External nullifier and Merkle trees (i.e. groups) must be
/// managed externally.
contract SemaphoreCore is ISemaphoreCore {
/// @dev Gets a nullifier hash and returns true or false.
/// It is used to prevent double-signaling.
mapping(uint256 => bool) internal nullifierHashes;
/// @dev Asserts that no nullifier already exists and if the zero-knowledge proof is valid.
/// Otherwise it reverts.
/// @param signal: Semaphore signal.
/// @param root: Root of the Merkle tree.
/// @param nullifierHash: Nullifier hash.
/// @param externalNullifier: External nullifier.
/// @param proof: Zero-knowledge proof.
/// @param verifier: Verifier address.
function _verifyProof(
bytes32 signal,
uint256 root,
uint256 nullifierHash,
uint256 externalNullifier,
uint256[8] calldata proof,
IVerifier verifier
) internal view {
require(!nullifierHashes[nullifierHash], "SemaphoreCore: you cannot use the same nullifier twice");
uint256 signalHash = _hashSignal(signal);
verifier.verifyProof(
[proof[0], proof[1]],
[[proof[2], proof[3]], [proof[4], proof[5]]],
[proof[6], proof[7]],
[root, nullifierHash, signalHash, externalNullifier]
);
}
/// @dev Stores the nullifier hash to prevent double-signaling.
/// Attention! Remember to call it when you verify a proof if you
/// need to prevent double-signaling.
/// @param nullifierHash: Semaphore nullifier hash.
function _saveNullifierHash(uint256 nullifierHash) internal {
nullifierHashes[nullifierHash] = true;
}
/// @dev Creates a keccak256 hash of the signal.
/// @param signal: Semaphore signal.
/// @return Hash of the signal.
function _hashSignal(bytes32 signal) private pure returns (uint256) {
return uint256(keccak256(abi.encodePacked(signal))) >> 8;
}
}

View File

@@ -0,0 +1,83 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {SNARK_SCALAR_FIELD} from "./SemaphoreConstants.sol";
import "../interfaces/ISemaphoreGroups.sol";
import "@zk-kit/incremental-merkle-tree.sol/contracts/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 group/tree data.
mapping(uint256 => IncrementalTreeData) internal groups;
/// @dev Creates a new group by initializing the associated tree.
/// @param groupId: Id of the group.
/// @param depth: Depth of the tree.
/// @param zeroValue: Zero value of the tree.
function _createGroup(
uint256 groupId,
uint8 depth,
uint256 zeroValue
) internal virtual {
require(groupId < SNARK_SCALAR_FIELD, "SemaphoreGroups: group id must be < SNARK_SCALAR_FIELD");
require(getDepth(groupId) == 0, "SemaphoreGroups: group already exists");
groups[groupId].init(depth, zeroValue);
emit GroupCreated(groupId, depth, 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 {
require(getDepth(groupId) != 0, "SemaphoreGroups: group does not exist");
groups[groupId].insert(identityCommitment);
uint256 root = getRoot(groupId);
emit MemberAdded(groupId, identityCommitment, root);
}
/// @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 deleted.
/// @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 {
require(getDepth(groupId) != 0, "SemaphoreGroups: group does not exist");
groups[groupId].remove(identityCommitment, proofSiblings, proofPathIndices);
uint256 root = getRoot(groupId);
emit MemberRemoved(groupId, identityCommitment, root);
}
/// @dev See {ISemaphoreGroups-getRoot}.
function getRoot(uint256 groupId) public view virtual override returns (uint256) {
return groups[groupId].root;
}
/// @dev See {ISemaphoreGroups-getDepth}.
function getDepth(uint256 groupId) public view virtual override returns (uint8) {
return groups[groupId].depth;
}
/// @dev See {ISemaphoreGroups-getNumberOfLeaves}.
function getNumberOfLeaves(uint256 groupId) public view virtual override returns (uint256) {
return groups[groupId].numberOfLeaves;
}
}

View File

@@ -0,0 +1,107 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../interfaces/ISemaphoreVoting.sol";
import "../base/SemaphoreCore.sol";
import "../base/SemaphoreGroups.sol";
/// @title Semaphore voting contract.
/// @dev The following code allows you to create polls, add voters and allow them to vote anonymously.
contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
/// @dev Gets a tree depth and returns its verifier address.
mapping(uint8 => IVerifier) internal verifiers;
/// @dev Gets a poll id and returns the poll data.
mapping(uint256 => Poll) internal polls;
/// @dev Since there can be multiple verifier contracts (each associated with a certain tree depth),
/// it is necessary to pass the addresses of the previously deployed contracts with the associated
/// tree depth. Depending on the depth chosen when creating the poll, a certain verifier will be
/// used to verify that the proof is correct.
/// @param depths: Three depths used in verifiers.
/// @param verifierAddresses: Verifier addresses.
constructor(uint8[] memory depths, address[] memory verifierAddresses) {
require(
depths.length == verifierAddresses.length,
"SemaphoreVoting: parameters lists does not have the same length"
);
for (uint8 i = 0; i < depths.length; i++) {
verifiers[depths[i]] = IVerifier(verifierAddresses[i]);
}
}
/// @dev Checks if the poll coordinator is the transaction sender.
/// @param pollId: Id of the poll.
modifier onlyCoordinator(uint256 pollId) {
require(polls[pollId].coordinator == _msgSender(), "SemaphoreVoting: caller is not the poll coordinator");
_;
}
/// @dev See {ISemaphoreVoting-createPoll}.
function createPoll(
uint256 pollId,
address coordinator,
uint8 depth
) public override {
require(address(verifiers[depth]) != address(0), "SemaphoreVoting: depth value is not supported");
_createGroup(pollId, depth, 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) {
require(polls[pollId].state == PollState.Created, "SemaphoreVoting: voters can only be added before voting");
_addMember(pollId, identityCommitment);
}
/// @dev See {ISemaphoreVoting-addVoter}.
function startPoll(uint256 pollId, uint256 encryptionKey) public override onlyCoordinator(pollId) {
require(polls[pollId].state == PollState.Created, "SemaphoreVoting: poll has already been started");
polls[pollId].state = PollState.Ongoing;
emit PollStarted(pollId, _msgSender(), encryptionKey);
}
/// @dev See {ISemaphoreVoting-castVote}.
function castVote(
bytes32 vote,
uint256 nullifierHash,
uint256 pollId,
uint256[8] calldata proof
) public override onlyCoordinator(pollId) {
Poll memory poll = polls[pollId];
require(poll.state == PollState.Ongoing, "SemaphoreVoting: vote can only be cast in an ongoing poll");
uint8 depth = getDepth(pollId);
uint256 root = getRoot(pollId);
IVerifier verifier = verifiers[depth];
_verifyProof(vote, root, nullifierHash, pollId, proof, verifier);
// Prevent double-voting (nullifierHash = hash(pollId + identityNullifier)).
_saveNullifierHash(nullifierHash);
emit VoteAdded(pollId, vote);
}
/// @dev See {ISemaphoreVoting-publishDecryptionKey}.
function endPoll(uint256 pollId, uint256 decryptionKey) public override onlyCoordinator(pollId) {
require(polls[pollId].state == PollState.Ongoing, "SemaphoreVoting: poll is not ongoing");
polls[pollId].state = PollState.Ended;
emit PollEnded(pollId, _msgSender(), decryptionKey);
}
}

View File

@@ -0,0 +1,88 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../interfaces/ISemaphoreWhistleblowing.sol";
import "../base/SemaphoreCore.sol";
import "../base/SemaphoreGroups.sol";
/// @title Semaphore whistleblowing contract.
/// @dev The following code allows you to create entities for whistleblowers (e.g. non-profit
/// organization, newspaper) and to allow them to publish news leaks anonymously.
/// Leaks can be IPFS hashes, permanent links or other kinds of reference.
contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing, SemaphoreCore, SemaphoreGroups {
/// @dev Gets a tree depth and returns its verifier address.
mapping(uint8 => IVerifier) internal verifiers;
/// @dev Gets an editor address and return their entity.
mapping(address => uint256) private entities;
/// @dev Since there can be multiple verifier contracts (each associated with a certain tree depth),
/// it is necessary to pass the addresses of the previously deployed contracts with the associated
/// tree depth. Depending on the depth chosen when creating the entity, a certain verifier will be
/// used to verify that the proof is correct.
/// @param depths: Three depths used in verifiers.
/// @param verifierAddresses: Verifier addresses.
constructor(uint8[] memory depths, address[] memory verifierAddresses) {
require(
depths.length == verifierAddresses.length,
"SemaphoreWhistleblowing: parameters lists does not have the same length"
);
for (uint8 i = 0; i < depths.length; i++) {
verifiers[depths[i]] = IVerifier(verifierAddresses[i]);
}
}
/// @dev Checks if the editor is the transaction sender.
/// @param entityId: Id of the entity.
modifier onlyEditor(uint256 entityId) {
require(entityId == entities[_msgSender()], "SemaphoreWhistleblowing: caller is not the editor");
_;
}
/// @dev See {ISemaphoreWhistleblowing-createEntity}.
function createEntity(
uint256 entityId,
address editor,
uint8 depth
) public override {
require(address(verifiers[depth]) != address(0), "SemaphoreWhistleblowing: depth value is not supported");
_createGroup(entityId, depth, 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(
bytes32 leak,
uint256 nullifierHash,
uint256 entityId,
uint256[8] calldata proof
) public override onlyEditor(entityId) {
uint8 depth = getDepth(entityId);
uint256 root = getRoot(entityId);
IVerifier verifier = verifiers[depth];
_verifyProof(leak, root, nullifierHash, entityId, proof, verifier);
emit LeakPublished(entityId, leak);
}
}

View File

@@ -0,0 +1,72 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @title Semaphore interface.
/// @dev Interface of a Semaphore contract.
interface ISemaphore {
struct Verifier {
address contractAddress;
uint8 merkleTreeDepth;
}
/// @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 signal: Semaphore signal.
event ProofVerified(uint256 indexed groupId, bytes32 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 signal: Semaphore signal.
/// @param nullifierHash: Nullifier hash.
/// @param externalNullifier: External nullifier.
/// @param proof: Zero-knowledge proof.
function verifyProof(
uint256 groupId,
bytes32 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,
uint8 depth,
uint256 zeroValue,
address admin
) 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 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 deleted.
/// @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,10 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @title SemaphoreCore interface.
/// @dev Interface of SemaphoreCore contract.
interface ISemaphoreCore {
/// @notice Emitted when a proof is verified correctly and a new nullifier hash is added.
/// @param nullifierHash: Hash of external and identity nullifiers.
event NullifierHashAdded(uint256 nullifierHash);
}

View File

@@ -0,0 +1,39 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @title SemaphoreGroups interface.
/// @dev Interface of a SemaphoreGroups contract.
interface ISemaphoreGroups {
/// @dev Emitted when a new group is created.
/// @param groupId: Id of the group.
/// @param depth: Depth of the tree.
/// @param zeroValue: Zero value of the tree.
event GroupCreated(uint256 indexed groupId, uint8 depth, uint256 zeroValue);
/// @dev Emitted when a new identity commitment is added.
/// @param groupId: Group id of the group.
/// @param identityCommitment: New identity commitment.
/// @param root: New root hash of the tree.
event MemberAdded(uint256 indexed groupId, uint256 identityCommitment, uint256 root);
/// @dev Emitted when a new identity commitment is removed.
/// @param groupId: Group id of the group.
/// @param identityCommitment: New identity commitment.
/// @param root: New root hash of the tree.
event MemberRemoved(uint256 indexed groupId, uint256 identityCommitment, uint256 root);
/// @dev Returns the last root hash of a group.
/// @param groupId: Id of the group.
/// @return Root hash of the group.
function getRoot(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 getDepth(uint256 groupId) external view returns (uint8);
/// @dev Returns the number of tree leaves of a group.
/// @param groupId: Id of the group.
/// @return Number of tree leaves.
function getNumberOfLeaves(uint256 groupId) external view returns (uint256);
}

View File

@@ -0,0 +1,14 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @title SemaphoreNullifiers interface.
/// @dev Interface of SemaphoreNullifiers contract.
interface ISemaphoreNullifiers {
/// @dev Emitted when a external nullifier is added.
/// @param externalNullifier: External Semaphore nullifier.
event ExternalNullifierAdded(uint256 externalNullifier);
/// @dev Emitted when a external nullifier is removed.
/// @param externalNullifier: External Semaphore nullifier.
event ExternalNullifierRemoved(uint256 externalNullifier);
}

View File

@@ -0,0 +1,76 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @title SemaphoreVoting interface.
/// @dev Interface of SemaphoreVoting contract.
interface ISemaphoreVoting {
enum PollState {
Created,
Ongoing,
Ended
}
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, bytes32 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 depth: Depth of the tree.
function createPoll(
uint256 pollId,
address coordinator,
uint8 depth
) 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(
bytes32 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,55 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @title SemaphoreWhistleblowing interface.
/// @dev Interface of SemaphoreWhistleblowing contract.
interface ISemaphoreWhistleblowing {
/// @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, bytes32 leak);
/// @dev Creates an entity and the associated Merkle tree/group.
/// @param entityId: Id of the entity.
/// @param editor: Editor of the entity.
/// @param depth: Depth of the tree.
function createEntity(
uint256 entityId,
address editor,
uint8 depth
) 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(
bytes32 leak,
uint256 nullifierHash,
uint256 entityId,
uint256[8] calldata proof
) external;
}

View File

@@ -0,0 +1,13 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @title Verifier interface.
/// @dev Interface of Verifier contract.
interface IVerifier {
function verifyProof(
uint256[2] memory a,
uint256[2][2] memory b,
uint256[2] memory c,
uint256[4] memory input
) external view;
}

38
contracts/package.json Normal file
View File

@@ -0,0 +1,38 @@
{
"name": "@semaphore-protocol/contracts",
"version": "2.0.0",
"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"
],
"homepage": "https://github.com/semaphore-protocol/semaphore.git#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/semaphore-protocol/semaphore.git.git"
},
"bugs": {
"url": "https://github.com/semaphore-protocol/semaphore.git/issues"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"@openzeppelin/contracts": "^4.4.2",
"@zk-kit/incremental-merkle-tree.sol": "^0.3.1"
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier16 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[13406811599156507528361773763681356312643537981039994686313383243831956396116, 16243966861079634958125511652590761846958471358623040426599000904006426210032],
[11781596534582143578120404722739278517564025497573071755253972265891888117374, 15688083679237922164673518758181461582601853873216319711156397437601833996222]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
1964404930528116823793003656764176108669615750422202377358993070935069307720,
2137714996673694828207437580381836490878070731768805974506391024595988817424
);
vk.IC[1] = Pairing.G1Point(
19568893707760843340848992184233194433177372925415116053368211122719346671126,
11639469568629189918046964192305250472192697612201524135560178632824282818614
);
vk.IC[2] = Pairing.G1Point(
5317268879687484957437879782519918549127939892210247573193613900261494313825,
528174394975085006443543773707702838726735933116136102590448357278717993744
);
vk.IC[3] = Pairing.G1Point(
14865918005176722116473730206622066845866539143554731094374354951675249722731,
3197770568483953664363740385883457803041685902965668289308665954510373380344
);
vk.IC[4] = Pairing.G1Point(
6863358721495494421022713667808247652425178970453300712435830652679038918987,
15025816433373311798308762709072064417001390853103872064614174594927359131281
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier17 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[15629200772768268814959330350023920183087521275477047626405113853190187031523, 13589689305661231568162336263197960570915890299814486885851912452076929115480],
[11464919285924930973853174493551975632739604254498590354200272115844983493029, 16004221700357242255845535848024178544616388017965468694776181247983831995562]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
17789438292552571310739605737896030466581277887660997531707911256058650850910,
4112657509505371631825493224748310061184972897405589115208158208294581472016
);
vk.IC[1] = Pairing.G1Point(
3322052920119834475842380240689494113984887785733316517680891208549118967155,
381029395779795399840019487059126246243641886087320875571067736504031557148
);
vk.IC[2] = Pairing.G1Point(
8777645223617381095463415690983421308854368583891690388850387317049320450400,
11923582117369144413749726090967341613266070909169947059497952692052020331958
);
vk.IC[3] = Pairing.G1Point(
15493263571528401950994933073246603557158047091963487223668240334879173885581,
6315532173951617115856055775098532808695228294437279844344466163873167020700
);
vk.IC[4] = Pairing.G1Point(
3481637421055377106140197938175958155334313900824697193932986771017625492245,
20088416136090515091300914661950097694450984520235647990572441134215240947932
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier18 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[9218320951536642499143228327011901814587826948504871816273184688188019956292, 19717684456458906358368865507225121991585492363133107109865920739019288468011],
[16717590750910963405756115910371408378114896008824240863060392362901176601412, 18221695645112467945186983098720611586049108689347006136423489099202471884089]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
4691595252082380256698158158199364410440273386659834000993210659508747323919,
9205801980459323513061837717352821162780471027241700646145937351740096374660
);
vk.IC[1] = Pairing.G1Point(
16150531426263112884093068164597994126623437929929609532055221646496813246000,
20245743178241899668170758952526381872637304119026868520579207157118516761827
);
vk.IC[2] = Pairing.G1Point(
6063536446992770713985314309889717594240410784717230886576072989709763902848,
18258781411255795973918859665416013869184055573057512603788635470145328981347
);
vk.IC[3] = Pairing.G1Point(
10109932964756104512054045207253535333686585863745296080906925765480296575285,
4174640428253153601540284363759502713687021920150940723252842152556151210349
);
vk.IC[4] = Pairing.G1Point(
18049428534741480832385046397049175120355008065781483226058177421025493210952,
591730261265040164434889324846001338201068482543108348317417391345612814922
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier19 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[3995128789564535587814512245259203300137618476815456454931286633947953135662, 15953239752392927777442331623182226063776310198012173504208557434319753428770],
[20957319343912866335583737646657534123362052690050674068142580221965936605075, 2523786679709693946058523307330825034772478122295850507521258983130425334580]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
9877211178693075145402462781884120278654771727348087433632224794894486095150,
19972682062587174829535281061580296764150591339640180868104711395548066529340
);
vk.IC[1] = Pairing.G1Point(
6324578424031095537345184040149690238371517387586958921377481904541316423724,
15513931720576048544404512239839508014664224085062729779520992909505663748296
);
vk.IC[2] = Pairing.G1Point(
11371337652479737143800707796204655130812036287859296372695832558127430723628,
11757275188600040111649009832378343123994225623498773406233261322165903848967
);
vk.IC[3] = Pairing.G1Point(
13282496583564708104981015168203451877588903263486398132954741568835583461335,
1746144324840370907926720490289700342734912534857331743685374514401176014195
);
vk.IC[4] = Pairing.G1Point(
7993952462467372951144011615584426050192046712674662254138390197508963352374,
5156942148925224345709309361345680948125600198010285179548841917923439945819
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier20 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[18976133691706015337908381757202123182841901611067930614519324084182946094218, 1382518990777992893805140303684642328066746531257780279226677247567004248173],
[6627710380771660558660627878547223719795356903257079198333641681330388499309, 21806956747910197517744499423107239699428979652113081469385876768212706694581]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
19918517214839406678907482305035208173510172567546071380302965459737278553528,
7151186077716310064777520690144511885696297127165278362082219441732663131220
);
vk.IC[1] = Pairing.G1Point(
690581125971423619528508316402701520070153774868732534279095503611995849608,
21271996888576045810415843612869789314680408477068973024786458305950370465558
);
vk.IC[2] = Pairing.G1Point(
16461282535702132833442937829027913110152135149151199860671943445720775371319,
2814052162479976678403678512565563275428791320557060777323643795017729081887
);
vk.IC[3] = Pairing.G1Point(
4319780315499060392574138782191013129592543766464046592208884866569377437627,
13920930439395002698339449999482247728129484070642079851312682993555105218086
);
vk.IC[4] = Pairing.G1Point(
3554830803181375418665292545416227334138838284686406179598687755626325482686,
5951609174746846070367113593675211691311013364421437923470787371738135276998
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier21 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[3811592683283527904145155808200366192489850711742363953668998371801696238057, 9032545080831535702239063467087720597970266046938395860207839433937324718536],
[16308433125974933290258540904373317426123214107276055539769464205982500660715, 12429982191499850873612518410809641163252887523090441166572590809691267943605]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
9494885690931955877467315318223108618392113101843890678090902614660136056680,
11783514256715757384821021009301806722951917744219075907912683963173706887379
);
vk.IC[1] = Pairing.G1Point(
7562082660623781416745328104576133910743071878837764423695105915778139873834,
17954307004260053757579194018551114133664721761483240877658498973152950708099
);
vk.IC[2] = Pairing.G1Point(
19338184851116432029108109461622579541195083625346674255186169347975445785058,
38361206266360048012365562393026952048730052530888439195454086987795985927
);
vk.IC[3] = Pairing.G1Point(
21178537742782571863590222710872928190886000600239072595684369348717288330049,
9786438258541172244884631831247223050494423968411444302812755467521949734320
);
vk.IC[4] = Pairing.G1Point(
11330504221972341797183339350494223413034293674225690456356444509688810101433,
1490009915387901405464437253469086864085891770312035292355706249426866485365
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier22 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[9485639152672984144988597737758037391807993615552051606205480347442429414340, 17626503110323089701269363177710295379967225765713250625279671011873619640598],
[12391874700409435648975069978280047983726144854114915177376036190441913967689, 18953587685067712486092665232725058638563458484886448540567142557894080640927]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
21791720972262589799021600767292883644106575897307484548888696814333235336885,
11092962469758788187888592619035811117815082357439060720677582048880121542623
);
vk.IC[1] = Pairing.G1Point(
9418924955930663972575130074928583215922927562059194231976193350658171304436,
16113558481826020406162261319744796072664750077095575593106901121115073101408
);
vk.IC[2] = Pairing.G1Point(
20054934960262983176880675919444457578562219675808407582143519621873973120773,
14877415271301547911435683263206245199959943680225555496786470669330176961657
);
vk.IC[3] = Pairing.G1Point(
4215199263810110748751715719957184804379752373072771007598572158043965517488,
5225943468606602818132879686778547605180105897615251160509064537462109826521
);
vk.IC[4] = Pairing.G1Point(
6250242626034734280813142093008675407723196706248829741247204621913994561803,
1472231555266678689888727724824566171966416459791722465278225775922487343641
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier23 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[9830856103389248449121962275587399130605902703453384856543071762984116567573, 11408965575174993375815840422438995549652812400401163392501956884932167624437],
[11814906841949499037550820576929552248172160643991870665022770052632331265834, 19969543376625663966419118899515353499678204573709836615846115182224340858492]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
3047486363455933831148688762823238723024952519326207356549121929667745957778,
20241836359289449005887237560564358543646542598344362915541027571505243817211
);
vk.IC[1] = Pairing.G1Point(
5965631918800530319167124148627450454569264331058008407732200168631989208657,
20463557477532480934514091877628554948892025887087712764683631108388998871350
);
vk.IC[2] = Pairing.G1Point(
16605042322692983282732511249912403956057999815658038166796858627082222971215,
12219061498275616585164456833410962809536084885494309093787669879221959361956
);
vk.IC[3] = Pairing.G1Point(
1548998572074037722622224303222294716243074837074272552644853986075252666508,
10393312002885367652301897874262367916506364670364584602554176742602334134772
);
vk.IC[4] = Pairing.G1Point(
16180907689593358346406392015123900260925622357393826746385511046141256905390,
12267326749885120640972074479210537480053065569337817484467225562817467244765
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier24 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[15035335306919942325459417688135340085377315274625768597233474641923619728582, 10090041889587324002759549286390619541526396451963494627957072069124011137562],
[21342049717074059749518233491526445388158772701642182532370641230478027030319, 10507786999799841055999967456762679569286329319056926475375760604262707147294]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
19590996174696909242575628014943555633938195923520472786993379268302478708283,
2673753072556442230312995111304911178679525806396134504594492458566941824354
);
vk.IC[1] = Pairing.G1Point(
13411253172375451489380472831999887223592471057462692619008484995624281735092,
17181767455563581254432161119660408482332423481128600038352147258951772423229
);
vk.IC[2] = Pairing.G1Point(
19138864631164378176055647711995352935065134904103255748190268290992108588628,
14282526277736365863821375748687709839392307698935143595732632710176778519757
);
vk.IC[3] = Pairing.G1Point(
20183773658676161990469276414858234178608794783112866811307579993999118293429,
5223464433544489066271184294750886227362580875255044558831927430970236355539
);
vk.IC[4] = Pairing.G1Point(
12333466991139269670298178539679773509487545471126920233507132846828588847444,
3787586478923104354547687861486563468235879611952775292288436085429794222238
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier25 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[15718373132479769904443326381037437528372212185108294117696143473979328398658, 43456740675249348549891878341522275183186932745162972528932808393415299552],
[11236864934894600819960883124570686936554376109344998527334431594565774237827, 4289247401578837038775845192875793775418122783738936298355403103074020081838]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
18580370382199518848261939652153768394883698461842792002922164533882262019935,
20516185953882700254387267244708111605796661864845495645678049276372075842359
);
vk.IC[1] = Pairing.G1Point(
20041291712709610738573661974551517833120775539593003477018637287434210072702,
6326630253906616820412999166182553773360987412889775567442543181359104720511
);
vk.IC[2] = Pairing.G1Point(
13268971611130152315428629919012388924225656285593904211561391821918930327614,
9247437189452353488017802041158840512956111558640958728149597697508914590433
);
vk.IC[3] = Pairing.G1Point(
6267384495557139339708615182113725421733376438932580472141549274050146739549,
1832264154031452148715318442722960696977572389206897240030908464579133134237
);
vk.IC[4] = Pairing.G1Point(
16650684165487873559901140599157559153018449083939294496255590830891994564285,
14140282729498011406186082176268025578697081678243955538935501306868500498994
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier26 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[1723458149089715907994189658689343304709709060535625667210252753337752162173, 4023016874169005249382064394379671330447496454371261692205411970999350949293],
[7651670126664625790835334090273463062538865895183205964669372719235003083565, 17710652158212212080502343565075513548898593397103675832636832371532093744857]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
4247947150009812467217672970806328247513830308400387953244764907353849211641,
14500381439127180474801393438175928191199696177607750163263715436006533630877
);
vk.IC[1] = Pairing.G1Point(
21213779524495874664157797605662894019112036728653622806607467354233012380232,
1429370857470083395421401524518861545167550347090873730934256398864585069083
);
vk.IC[2] = Pairing.G1Point(
12465277751642747637430517396067173985821959773399832969105187923427872239200,
4377704428607835904642653580543541241155601291484645500691968624389522190030
);
vk.IC[3] = Pairing.G1Point(
11283027832501128633761619552392013253304972822086786857121687098087331014745,
21463394238922953607096052056881931791797740737164052798044623278557203313720
);
vk.IC[4] = Pairing.G1Point(
19687293493101130967741578773742597470558958652351513582962108464055656171331,
4445165696525061401582979300506082669540223774145877762689724631935313716632
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier27 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[745924679191739894055143748466112994378439645681039136007774787076115375124, 13132169670125192016391258838554965176628317453468870968867717287446623320643],
[2126777833939378028304266129616145667925849332481755567268747182629795296580, 20909608709868730010029182074820840312550443752829480953667886902663547957991]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
3388767735894417381503201756905214431625081913405504580464345986403824999889,
21014112837214011009096825602791072748195337199912773858499588477762724153070
);
vk.IC[1] = Pairing.G1Point(
10521317016331497094903116740581271122844131442882845700567581775404872949272,
13201921794561774338466680421903602920184688290946713194187958007088351657367
);
vk.IC[2] = Pairing.G1Point(
16170260722059932609965743383032703380650557609693540121262881902248073364496,
6004983491336500911294872035126141746032033211872472427212274143945425740617
);
vk.IC[3] = Pairing.G1Point(
10275615677574391293596971122111363003313434841806630200532546038183081960924,
5955568702561336410725734958627459212680756023420452791680213386065159525989
);
vk.IC[4] = Pairing.G1Point(
19059081014385850734732058652137664919364805650872154944590269874395511868415,
19202365837673729366500417038229950532560250566916189579621883380623278182155
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier28 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[4553625243522856553165922942982108474187282402890756796515747778282922584601, 16835654219229187428071649241190746119082269636345872682107941472241044260584],
[3272293478534046729728233267765357195255129499603632413158978822084188871854, 873742823867191038535544062852920538566418819521732785500614249239215175476]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
7856986171681248404396064225772749784181602218562773063185003409958949630985,
11707218736744382138692483591389641607570557654489363179025201039696228471230
);
vk.IC[1] = Pairing.G1Point(
2902255937308264958973169948617099471543255757887963647238093192858290079050,
4092153880227661899721872164083575597602963673456107552146583620177664115673
);
vk.IC[2] = Pairing.G1Point(
18380478859138320895837407377103009470968863533040661874531861881638854174636,
14502773952184441371657781525836310753176308880224816843041318743809785835984
);
vk.IC[3] = Pairing.G1Point(
2781117248053224106149213822307598926495461873135153638774638501111353469325,
3500056595279027698683405880585654897391289317486204483344715855049598477604
);
vk.IC[4] = Pairing.G1Point(
8880120765926282932795149634761705738498809569874317407549203808931092257005,
19080036326648068547894941015038877788526324720587349784852594495705578761000
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier29 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[7252337675475138150830402909353772156046809729627064992143762325769537840623, 7601443214415704135008588588192028557655441716696726549510699770097979655628],
[436607343827794507835462908831699962173244647704538949914686722631806931932, 18500126298578278987997086114400065402270866280547473913420536595663876273004]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
18427701611614193839908361166447988195308352665132182219164437649866377475111,
5299493942596042045861137432338955179078182570752746487573709678936617478454
);
vk.IC[1] = Pairing.G1Point(
4188155714164125069834512529839479682516489319499446390214266838952761728656,
2720966082507704094346897998659841489771837229143573083003847010258396944787
);
vk.IC[2] = Pairing.G1Point(
13256461570028177373135283778770729308216900804505379897951455548375840027026,
10722074030307391322177899534114921764931623271723882054692012663305322382747
);
vk.IC[3] = Pairing.G1Point(
9824147497244652955949696442395586567974424828238608972020527958186701134273,
15755269950882650791869946186461432242513999576056199368058858215068920022191
);
vk.IC[4] = Pairing.G1Point(
21172488506061181949536573476893375313339715931330476837156243346077173297265,
13892434487977776248366965108031841947713544939953824768291380177301871559945
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier30 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[10202326166286888893675634318107715186834588694714750762952081034135561546271, 15028154694713144242204861571552635520290993855826554325002991692907421516918],
[18486039841380105976272577521609866666900576498507352937328726490052296469859, 12766289885372833812620582632847872978085960777075662988932200910695848591357]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
1452272927738590248356371174422184656932731110936062990115610832462181634644,
3608050114233210789542189629343107890943266759827387991788718454179833288695
);
vk.IC[1] = Pairing.G1Point(
14798240452388909327945424685903532333765637883272751382037716636327236955001,
10773894897711848209682368488916121016695006898681985691467605219098835500201
);
vk.IC[2] = Pairing.G1Point(
17204267933132009093604099819536245144503489322639121825381131096467570698650,
7704298975420304156332734115679983371345754866278811368869074990486717531131
);
vk.IC[3] = Pairing.G1Point(
8060465662017324080560848316478407038163145149983639907596180500095598669247,
20475082166427284188002500222093571716651248980245637602667562336751029856573
);
vk.IC[4] = Pairing.G1Point(
7457566682692308112726332096733260585025339741083447785327706250123165087868,
11904519443874922292602150685069370036383697877657723976244907400392778002614
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier31 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[14930624777162656776068112402283260602512252179767747308433194885322661150422, 13682963731073238132274278610660469286329368216526659590944079211949686450402],
[18705481657148807016785305378773304476425591636333098330324049960258682574070, 21315724107376627085778492378001676935454590984229146391746301404292016287653]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
12628427235010608529869146871556870477182704310235373946877240509680742038961,
15093298104438768585559335868663959710321348106117735180051519837845319121254
);
vk.IC[1] = Pairing.G1Point(
6593907467779318957599440584793099005109789224774644007604434924706249001015,
18549596630007199540674697114946251030815675677713256327810772799104711621483
);
vk.IC[2] = Pairing.G1Point(
6271101737045248834759003849256661059806617144229427987717476992610974162336,
355748132218964841305454070022507122319085542484477110563322753565651576458
);
vk.IC[3] = Pairing.G1Point(
2116139772133141967317791473319540620104888687412078412336248003979594158546,
4004400204967325849492155713520296687406035356901102254880522534085890616486
);
vk.IC[4] = Pairing.G1Point(
4206647028595764233995379982714022410660284578620723510907006350595207905228,
19380634286337609988098517090003334645113675227742745065381519159322795845003
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

@@ -0,0 +1,237 @@
//
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
// fixed linter warnings
// added requiere error messages
//
// 2021 Remco Bloemen
// cleaned up code
// added InvalidProve() error
// always revert with InvalidProof() on invalid proof
// make Pairing strict
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
// The prime q in the base field F_q for G1
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
// The prime moludus of the scalar field of G1.
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/// @return the generator of G1
function P1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
/// @return the generator of G2
function P2() internal pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) return G1Point(0, 0);
// Validate input or revert
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) revert InvalidProof();
// We know p.Y > 0 and p.Y < BASE_MODULUS.
return G1Point(p.X, BASE_MODULUS - p.Y);
}
/// @return r the sum of two points of G1
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
// By EIP-196 all input is validated to be less than the BASE_MODULUS and form points
// on the curve.
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// @return r the product of a point on G1 and a scalar, i.e.
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
// By EIP-196 the values p.X and p.Y are verified to less than the BASE_MODULUS and
// form a valid point on the curve. But the scalar is not verified, so we do that explicitelly.
if (s >= SCALAR_MODULUS) revert InvalidProof();
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) revert InvalidProof();
}
/// Asserts the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should succeed
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) internal view {
// By EIP-197 all input is verified to be less than the BASE_MODULUS and form elements in their
// respective groups of the right order.
if (p1.length != p2.length) revert InvalidProof();
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) revert InvalidProof();
}
}
contract Verifier32 {
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
);
vk.beta2 = Pairing.G2Point(
[4252822878758300859123897981450591353533073413197771768651442665752259397132, 6375614351688725206403948262868962793625744043794305715222011528459656738731],
[21847035105528745403288232691147584728191162732299865338377159692350059136679, 10505242626370262277552901082094356697409835680220590971873171140371331206856]
);
vk.gamma2 = Pairing.G2Point(
[11559732032986387107991004021392285783925812861821192530917403151452391805634, 10857046999023057135944570762232829481370756359578518086990519993285655852781],
[4082367875863433681332203403145435568316851327593401208105741076214120093531, 8495653923123431417604973247489272438418190587263600148770280649306958101930]
);
vk.delta2 = Pairing.G2Point(
[12315240965742683516581565369496371929586281338862761742109651525191835544242, 18994803742708336446369128568423705404354655742604689352630273180469431952708],
[18019403342409608922812569436317484250134945386869657285229378095251425778096, 12707009780301102830224094192984906206920666691015255692741008594808694787917]
);
vk.IC = new Pairing.G1Point[](5);
vk.IC[0] = Pairing.G1Point(
2592407181901686208061988776764501828311271519595797153264758207470081204331,
11847594161160074962679125411562687287595382335410213641115001866587988494499
);
vk.IC[1] = Pairing.G1Point(
3346927026869562921166545684451290646273836362895645367665514203662899621366,
15758185693543979820528128025093553492246135914029575732836221618882836493143
);
vk.IC[2] = Pairing.G1Point(
20528686657810499188368147206002308531447185877994439397529705707372170337045,
18025396678079701612906003769476076600196287001844168390936182972248852818155
);
vk.IC[3] = Pairing.G1Point(
9799815250059685769827017947834627563597884023490186073806184882963949644596,
4998495094322372762314630336611134866447406022687118703953312157819349892603
);
vk.IC[4] = Pairing.G1Point(
16176535527670849161173306151058200762642157343823553073439957507563856439772,
21877331533292960470552563236986670222564955589137303622102707801351340670855
);
}
/// @dev Verifies a Semaphore proof. Reverts with InvalidProof if the proof is invalid.
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) public view {
// If the values are not in the correct range, the Pairing contract will revert.
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x of inputs times IC
if (input.length + 1 != vk.IC.length) revert Pairing.InvalidProof();
Pairing.G1Point memory vk_x = vk.IC[0];
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[1], input[0]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[2], input[1]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[3], input[2]));
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[4], input[3]));
// Check pairing
Pairing.G1Point[] memory p1 = new Pairing.G1Point[](4);
Pairing.G2Point[] memory p2 = new Pairing.G2Point[](4);
p1[0] = Pairing.negate(proof.A);
p2[0] = proof.B;
p1[1] = vk.alfa1;
p2[1] = vk.beta2;
p1[2] = vk_x;
p2[2] = vk.gamma2;
p1[3] = proof.C;
p2[3] = vk.delta2;
Pairing.pairingCheck(p1, p2);
}
}

View File

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

View File

@@ -0,0 +1,74 @@
[
{
"name": "Verifier16",
"address": "0x0C9DF9a417871b531684302f4062180E6A479431"
},
{
"name": "Verifier17",
"address": "0xa3739cFc24dd66deF7674393B0c7EcD3fe1DD90c"
},
{
"name": "Verifier18",
"address": "0xF9149c3AA6711c0f579b0cFB505D09A1226BbB02"
},
{
"name": "Verifier19",
"address": "0x863bB7875429B9774C4c771567778E2dc4991140"
},
{
"name": "Verifier20",
"address": "0xA701c1c97C1d42593D2b567f08c1859BBA7D6441"
},
{
"name": "Verifier21",
"address": "0x915d0A168894053362E64dCf04A731E2b4eE0276"
},
{
"name": "Verifier22",
"address": "0x22F2369A0d50fEb07F810d2B5411D2c58D371eB0"
},
{
"name": "Verifier23",
"address": "0x7D46E0612861Ff15FDF4fC16eF4BE0f37796E656"
},
{
"name": "Verifier24",
"address": "0xd3339E5Ff07bC961f3F7B641F5D3Bf690C2D14BF"
},
{
"name": "Verifier25",
"address": "0xc340cc18f682E4320217e8198d2e65B1C70BfDff"
},
{
"name": "Verifier26",
"address": "0x90FA0d9Ec6EFe94410bF06efeaa4Ec0F1dba0D67"
},
{
"name": "Verifier27",
"address": "0xd688189016277e1a6aE5228ef6894C14585A42D3"
},
{
"name": "Verifier28",
"address": "0x11EA2F1Bf24d46da9bb88B13e7d2Cb9FaCDb6B01"
},
{
"name": "Verifier29",
"address": "0x4784656EbE7AcF393154487A575b11e1c0E0dd47"
},
{
"name": "Verifier30",
"address": "0x590CB053A5F429719E6858CeeC56e6bedD4e9cfA"
},
{
"name": "Verifier31",
"address": "0x9E4D3a0B22B13d142711d7Eb69786f91c51E9ba6"
},
{
"name": "Verifier32",
"address": "0xa66F7B0Ce8662C1BfD7Ea97B7Dd8F4A7436A3cCd"
},
{
"name": "Semaphore",
"address": "0x9e4080e133384d2D09b593C003DCaF3c5a0C53A6"
}
]

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 25 KiB

70
hardhat.config.ts Normal file
View File

@@ -0,0 +1,70 @@
import "@nomiclabs/hardhat-ethers"
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"
import "./tasks/deploy-verifier"
dotenvConfig({ path: resolve(__dirname, "./.env") })
function getNetworks(): NetworksUserConfig | undefined {
if (process.env.INFURA_API_KEY && process.env.BACKEND_PRIVATE_KEY) {
const infuraApiKey = process.env.INFURA_API_KEY
const accounts = [`0x${process.env.BACKEND_PRIVATE_KEY}`]
return {
goerli: {
url: `https://goerli.infura.io/v3/${infuraApiKey}`,
chainId: 5,
accounts
},
kovan: {
url: `https://kovan.infura.io/v3/${infuraApiKey}`,
chainId: 42,
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"
}
}
export default hardhatConfig

104
package.json Normal file
View File

@@ -0,0 +1,104 @@
{
"name": "semaphore",
"version": "2.0.0",
"description": "A zero-knowledge protocol for anonymous signalling on Ethereum.",
"license": "MIT",
"homepage": "https://github.com/semaphore-protocol/semaphore.git#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/semaphore-protocol/semaphore.git.git"
},
"bugs": {
"url": "https://github.com/semaphore-protocol/semaphore.git/issues"
},
"private": true,
"scripts": {
"start": "hardhat node",
"compile": "hardhat compile",
"download:snark-artifacts": "hardhat run scripts/download-snark-artifacts.ts",
"deploy:all": "hardhat run scripts/deploy-all.ts",
"deploy:verifier": "hardhat deploy:verifier",
"deploy:semaphore": "hardhat deploy:semaphore",
"deploy:semaphore-voting": "hardhat deploy:semaphore-voting",
"deploy:semaphore-whistleblowing": "hardhat deploy:semaphore-whistleblowing",
"test": "hardhat test",
"test:report-gas": "REPORT_GAS=true hardhat test",
"test:coverage": "hardhat coverage",
"typechain": "hardhat typechain",
"lint": "yarn lint:sol && yarn lint:ts",
"lint:ts": "eslint . --ext .js,.ts",
"lint:sol": "solhint 'contracts/**/*.sol'",
"prettier": "prettier -c .",
"prettier:write": "prettier -w .",
"commit": "cz",
"precommit": "lint-staged"
},
"packageManager": "yarn@3.2.1",
"devDependencies": {
"@commitlint/cli": "^16.1.0",
"@commitlint/config-conventional": "^16.0.0",
"@nomiclabs/hardhat-ethers": "^2.0.6",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@semaphore-protocol/group": "0.1.2",
"@semaphore-protocol/identity": "0.2.2",
"@semaphore-protocol/proof": "0.3.3",
"@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",
"@typescript-eslint/eslint-plugin": "^5.10.1",
"@typescript-eslint/parser": "^5.10.1",
"chai": "^4.3.5",
"circomlib": "^2.0.2",
"circomlibjs": "^0.0.8",
"commitizen": "^4.2.4",
"cz-conventional-changelog": "^3.3.0",
"dotenv": "^14.3.2",
"download": "^8.0.0",
"eslint": "^8.7.0",
"eslint-config-prettier": "^8.3.0",
"ethereum-waffle": "^3.4.4",
"ethers": "^5.6.8",
"hardhat": "^2.9.7",
"hardhat-gas-reporter": "^1.0.8",
"js-logger": "^1.6.1",
"lint-staged": "^12.3.2",
"prettier": "^2.5.1",
"prettier-plugin-solidity": "^1.0.0-beta.19",
"rimraf": "^3.0.2",
"snarkjs": "^0.4.13",
"solhint": "^3.3.6",
"solhint-plugin-prettier": "^0.0.5",
"solidity-coverage": "^0.7.21",
"ts-node": "^10.4.0",
"typechain": "^8.0.0",
"typescript": "^4.5.5"
},
"config": {
"solidity": {
"version": "0.8.4"
},
"paths": {
"contracts": "./contracts",
"circuit": "./circuit",
"tests": "./test",
"cache": "./cache",
"snarkjs-templates": "./snarkjs-templates",
"build": {
"snark-artifacts": "./build/snark-artifacts",
"contracts": "./build/contracts",
"typechain": "./build/typechain"
}
},
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"dependencies": {
"@openzeppelin/contracts": "^4.4.2",
"@zk-kit/incremental-merkle-tree.sol": "^0.3.1"
}
}

38
scripts/deploy-all.ts Normal file
View File

@@ -0,0 +1,38 @@
import fs from "fs"
import { run, hardhatArguments } from "hardhat"
async function main() {
const deployedContracts: { name: string; address: string }[] = []
// Deploy verifiers.
for (let treeDepth = 16; treeDepth <= 32; treeDepth++) {
const { address } = await run("deploy:verifier", { depth: treeDepth })
deployedContracts.push({
name: `Verifier${treeDepth}`,
address
})
}
// Deploy Semaphore.
const { address } = await run("deploy:semaphore", {
verifiers: deployedContracts.map((c) => ({ merkleTreeDepth: c.name.substring(8), contractAddress: c.address }))
})
deployedContracts.push({
name: `Semaphore`,
address
})
fs.writeFileSync(
`./deployed-contracts/${hardhatArguments.network}.json`,
JSON.stringify(deployedContracts, null, 4)
)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})

View File

@@ -0,0 +1,24 @@
import download from "download"
import fs from "fs"
import { config } from "../package.json"
async function main() {
const snarkArtifactsPath = config.paths.build["snark-artifacts"]
const url = `http://www.trusted-setup-pse.org/semaphore/${process.env.TREE_DEPTH}`
if (!fs.existsSync(snarkArtifactsPath)) {
fs.mkdirSync(snarkArtifactsPath, { recursive: true })
}
if (!fs.existsSync(`${snarkArtifactsPath}/semaphore.zkey`)) {
await download(`${url}/semaphore.wasm`, snarkArtifactsPath)
await download(`${url}/semaphore.zkey`, snarkArtifactsPath)
}
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})

View File

@@ -1,78 +0,0 @@
blake2sdef.json
build/.snark_checksum
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
build
src/web/dist
src/web/semaphore.js
src/web/Semaphore.json
src/web/circuit.json
src/web/groth16_wasm.js
src/web/proving_key.json
src/web/proving_key.bin
src/web/verification_key.json
src/web/websnark.js
scripts/semaphore_identity.json
scripts/semaphore_server.db
scripts/witness.json

View File

@@ -1,40 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
pragma solidity ^0.5.0;
contract HashTester {
constructor() public {
}
event DebugHash(bytes32 normal, uint256 converted, bytes32 normal_shifted, uint256 converted_shifted);
event DebugRollingHash(uint256 prev_rolling_hash, uint256 signal_hash, uint256 rolling_hash, bytes encoded);
uint256 rolling_hash = 1238129381923;
function Test(bytes memory signal) public {
uint256 signal_hash = uint256(sha256(signal)) >> 8;
emit DebugHash(sha256(signal), uint256(sha256(signal)), sha256(signal) >> 8, signal_hash);
bytes memory encoded = abi.encodePacked(rolling_hash, signal_hash);
uint256 new_rolling_hash = uint256(sha256(encoded));
emit DebugRollingHash(rolling_hash, signal_hash, new_rolling_hash, encoded);
}
}

View File

@@ -1,120 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
pragma solidity ^0.5.0;
library MiMC {
function MiMCSponge(uint256 in_xL, uint256 in_xR, uint256 in_k) pure public returns (uint256 xL, uint256 xR);
}
contract MerkleTree {
uint8 levels;
uint256 public root = 0;
uint256[] public filled_subtrees;
uint256[] public zeros;
uint32 public next_index = 0;
event LeafAdded(uint256 leaf, uint32 leaf_index);
event LeafUpdated(uint256 leaf, uint32 leaf_index);
constructor(uint8 tree_levels, uint256 zero_value) public {
levels = tree_levels;
zeros.push(zero_value);
filled_subtrees.push(zeros[0]);
for (uint8 i = 1; i < levels; i++) {
zeros.push(HashLeftRight(zeros[i-1], zeros[i-1]));
filled_subtrees.push(zeros[i]);
}
root = HashLeftRight(zeros[levels - 1], zeros[levels - 1]);
}
function HashLeftRight(uint256 left, uint256 right) public pure returns (uint256 mimc_hash) {
uint256 k = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 R = 0;
uint256 C = 0;
R = addmod(R, left, k);
(R, C) = MiMC.MiMCSponge(R, C, 0);
R = addmod(R, right, k);
(R, C) = MiMC.MiMCSponge(R, C, 0);
mimc_hash = R;
}
function insert(uint256 leaf) internal {
uint32 leaf_index = next_index;
uint32 current_index = next_index;
next_index += 1;
uint256 current_level_hash = leaf;
uint256 left;
uint256 right;
for (uint8 i = 0; i < levels; i++) {
if (current_index % 2 == 0) {
left = current_level_hash;
right = zeros[i];
filled_subtrees[i] = current_level_hash;
} else {
left = filled_subtrees[i];
right = current_level_hash;
}
current_level_hash = HashLeftRight(left, right);
current_index /= 2;
}
root = current_level_hash;
emit LeafAdded(leaf, leaf_index);
}
function update(uint256 leaf, uint32 leaf_index, uint256[] memory path) internal {
uint32 current_index = leaf_index;
uint256 current_level_hash = leaf;
uint256 left;
uint256 right;
for (uint8 i = 0; i < levels; i++) {
if (current_index % 2 == 0) {
left = current_level_hash;
right = path[i];
} else {
left = path[i];
right = current_level_hash;
}
current_level_hash = HashLeftRight(left, right);
current_index /= 2;
}
emit LeafUpdated(leaf, leaf_index);
}
}

View File

@@ -1,157 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
pragma solidity ^0.5.0;
library MiMC {
function MiMCSponge(uint256 in_xL, uint256 in_xR, uint256 in_k) pure public returns (uint256 xL, uint256 xR);
}
contract MultipleMerkleTree {
uint8[] levels;
uint256[] internal tree_roots;
uint256[][] filled_subtrees;
uint256[][] zeros;
uint32[] next_index;
uint256[][] internal tree_leaves;
event LeafAdded(uint8 tree_index, uint256 leaf, uint32 leaf_index);
event LeafUpdated(uint8 tree_index, uint256 leaf, uint32 leaf_index);
function init_tree(uint8 tree_levels, uint256 zero_value) public returns (uint8 tree_index) {
levels.push(tree_levels);
uint256[] memory current_zeros = new uint256[](tree_levels);
current_zeros[0] = zero_value;
uint256[] memory current_filled_subtrees = new uint256[](tree_levels);
current_filled_subtrees[0] = current_zeros[0];
for (uint8 i = 1; i < tree_levels; i++) {
current_zeros[i] = HashLeftRight(current_zeros[i-1], current_zeros[i-1]);
current_filled_subtrees[i] = current_zeros[i];
}
zeros.push(current_zeros);
filled_subtrees.push(current_filled_subtrees);
tree_roots.push(HashLeftRight(current_zeros[tree_levels - 1], current_zeros[tree_levels - 1]));
next_index.push(0);
tree_leaves.push(new uint256[](0));
return uint8(tree_roots.length) - 1;
}
function HashLeftRight(uint256 left, uint256 right) public pure returns (uint256 mimc_hash) {
uint256 k = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 R = 0;
uint256 C = 0;
R = addmod(R, left, k);
(R, C) = MiMC.MiMCSponge(R, C, 0);
R = addmod(R, right, k);
(R, C) = MiMC.MiMCSponge(R, C, 0);
mimc_hash = R;
}
function insert(uint8 tree_index, uint256 leaf) internal {
uint32 leaf_index = next_index[tree_index];
uint32 current_index = next_index[tree_index];
next_index[tree_index] += 1;
uint256 current_level_hash = leaf;
uint256 left;
uint256 right;
for (uint8 i = 0; i < levels[tree_index]; i++) {
if (current_index % 2 == 0) {
left = current_level_hash;
right = zeros[tree_index][i];
filled_subtrees[tree_index][i] = current_level_hash;
} else {
left = filled_subtrees[tree_index][i];
right = current_level_hash;
}
current_level_hash = HashLeftRight(left, right);
current_index /= 2;
}
tree_roots[tree_index] = current_level_hash;
tree_leaves[tree_index].push(leaf);
emit LeafAdded(tree_index, leaf, leaf_index);
}
function update(uint8 tree_index, uint256 old_leaf, uint256 leaf, uint32 leaf_index, uint256[] memory old_path, uint256[] memory path) internal {
uint32 current_index = leaf_index;
uint256 current_level_hash = old_leaf;
uint256 left;
uint256 right;
for (uint8 i = 0; i < levels[tree_index]; i++) {
if (current_index % 2 == 0) {
left = current_level_hash;
right = old_path[i];
} else {
left = old_path[i];
right = current_level_hash;
}
current_level_hash = HashLeftRight(left, right);
current_index /= 2;
}
require(tree_roots[tree_index] == current_level_hash, "MultipleMerkleTree: tree root / current level hash mismatch");
current_index = leaf_index;
current_level_hash = leaf;
for (uint8 i = 0; i < levels[tree_index]; i++) {
if (current_index % 2 == 0) {
left = current_level_hash;
right = path[i];
} else {
left = path[i];
right = current_level_hash;
}
current_level_hash = HashLeftRight(left, right);
current_index /= 2;
}
tree_roots[tree_index] = current_level_hash;
tree_leaves[tree_index][leaf_index] = leaf;
emit LeafUpdated(tree_index, leaf, leaf_index);
}
}

View File

@@ -1,32 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
pragma solidity ^0.5.0;
import "./MerkleTree.sol";
contract MerkleTreeTester is MerkleTree {
constructor() MerkleTree(2, 4) public {
}
function insert_test(uint256 leaf) public {
insert(leaf);
}
}

View File

@@ -1,43 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
pragma solidity >=0.4.21 <0.6.0;
contract Migrations {
address public owner;
uint public last_completed_migration;
constructor() public {
owner = msg.sender;
}
modifier restricted() {
if (msg.sender == owner) _;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}

View File

@@ -1,75 +0,0 @@
pragma solidity ^0.5.0;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be aplied to your functions to restrict their use to
* the owner.
*/
contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Returns true if the caller is the current owner.
*/
function isOwner() public view returns (bool) {
return msg.sender == _owner;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* > Note: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}

View File

@@ -1,236 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
pragma solidity ^0.5.0;
import "./verifier.sol";
import "./MerkleTreeLib.sol";
import "./Ownable.sol";
contract Semaphore is Verifier, MultipleMerkleTree, Ownable {
// The external_nullifier helps to prevent double-signalling by the same
// user.
uint256 public external_nullifier;
uint8 public id_tree_index;
// Whether broadcastSignal() can only be called by the owner of this
// contract. This is the case as a safe default.
bool public is_broadcast_permissioned = true;
// Whether the contract has already seen a particular Merkle tree root
mapping (uint256 => bool) root_history;
uint8 current_root_index = 0;
// Whether the contract has already seen a particular nullifier hash
mapping (uint => bool) nullifier_hash_history;
// All signals broadcasted
mapping (uint => bytes) public signals;
// The higest index of the `signals` mapping
uint public current_signal_index = 0;
event SignalBroadcast(bytes signal, uint256 nullifiers_hash, uint256 external_nullifier);
/*
* If broadcastSignal is permissioned, check if msg.sender is the contract owner
*/
modifier onlyOwnerIfPermissioned() {
require(!is_broadcast_permissioned || isOwner(), "Semaphore: broadcast permission denied");
_;
}
constructor(uint8 tree_levels, uint256 zero_value, uint256 external_nullifier_in) Ownable() public {
external_nullifier = external_nullifier_in;
id_tree_index = init_tree(tree_levels, zero_value);
}
/*
* Register a new user.
* @param identity_commitment The user's identity commitment, which is the
* hash of their public key and their identity
* nullifier (a random 31-byte value)
*/
function insertIdentity(uint256 identity_commitment) public onlyOwner {
insert(id_tree_index, identity_commitment);
root_history[tree_roots[id_tree_index]] = true;
}
/*
* Change a user's identity commitment.
* @param old_leaf The user's original identity commitment
* @param leaf The user's new identity commitment
* @param leaf_index The index of the original identity commitment in the tree
* @param old_path The Merkle path to the original identity commitment
* @param path The Merkle path to the new identity commitment
*/
function updateIdentity(
uint256 old_leaf,
uint256 leaf,
uint32 leaf_index,
uint256[] memory old_path,
uint256[] memory path
) public onlyOwner {
update(id_tree_index, old_leaf, leaf, leaf_index, old_path, path);
root_history[tree_roots[id_tree_index]] = true;
}
/*
* @param n The nulllifier hash to check
* @return True if the nullifier hash has previously been stored in the
* contract
*/
function hasNullifier(uint n) public view returns (bool) {
return nullifier_hash_history[n];
}
/*
* @param The Merkle root to check
* @return True if the root has previously been stored in the
* contract
*/
function isInRootHistory(uint n) public view returns (bool) {
return root_history[n];
}
/*
* A convenience view function which helps operators to easily verify all
* inputs to broadcastSignal() using a single contract call. This helps
* them to save gas by detecting invalid inputs before they invoke
* broadcastSignal(). Note that this function does the same checks as
* `isValidSignalAndProof` but returns a bool instead of using require()
* statements.
*/
function preBroadcastCheck (
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input,
uint256 signal_hash
) public view returns (bool) {
return hasNullifier(input[1]) == false &&
signal_hash == input[2] &&
external_nullifier == input[3] &&
isInRootHistory(input[0]) &&
verifyProof(a, b, c, input);
}
/*
* A modifier which ensures that the signal and proof are valid.
* @param signal The signal to broadcast
* @param a The corresponding `a` parameter to verifier.sol's verifyProof()
* @param b The corresponding `b` parameter to verifier.sol's verifyProof()
* @param c The corresponding `c` parameter to verifier.sol's verifyProof()
* @param input The public inputs to the zk-SNARK
*/
modifier isValidSignalAndProof (
bytes memory signal,
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input
) {
// Hash the signal
uint256 signal_hash = uint256(keccak256(signal)) >> 8;
require(hasNullifier(input[1]) == false, "Semaphore: nullifier already seen");
require(signal_hash == input[2], "Semaphore: signal hash mismatch");
require(external_nullifier == input[3], "Semaphore: external nullifier mismatch");
require(isInRootHistory(input[0]), "Semaphore: root not seen");
require(verifyProof(a, b, c, input), "Semaphore: invalid proof");
_;
}
/*
* Broadcast the signal.
* @param signal The signal to broadcast
* @param a The corresponding `a` parameter to verifier.sol's verifyProof()
* @param b The corresponding `b` parameter to verifier.sol's verifyProof()
* @param c The corresponding `c` parameter to verifier.sol's verifyProof()
* @param input The public inputs to the zk-SNARK
*/
function broadcastSignal(
bytes memory signal,
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input // (root, nullifiers_hash, signal_hash, external_nullifier)
) public
onlyOwnerIfPermissioned
isValidSignalAndProof(signal, a, b, c, input)
{
uint nullifiers_hash = input[1];
signals[current_signal_index++] = signal;
nullifier_hash_history[nullifiers_hash] = true;
emit SignalBroadcast(signal, nullifiers_hash, external_nullifier);
}
/*
* @param tree_index The tree in question
* @return The Merkle root
*/
function root(uint8 tree_index) public view returns (uint256) {
return tree_roots[tree_index];
}
/*
* @param tree_index The tree in question
* @return The leaves of the tree
*/
function leaves(uint8 tree_index) public view returns (uint256[] memory) {
return tree_leaves[tree_index];
}
/*
* @param tree_index The tree in question
* @param leaf_index The index of the leaf to fetch
* @return The leaf at leaf_index of the tree with index tree_index
*/
function leaf(uint8 tree_index, uint256 leaf_index) public view returns (uint256) {
return tree_leaves[tree_index][leaf_index];
}
/*
* @return The index of the identity tree in MultipleMerkleTree
*/
function getIdTreeIndex() public view returns (uint8) {
return id_tree_index;
}
/*
* Sets a new external nullifier for the contract. Only the owner can do this.
* @param new_external_nullifier The new external nullifier to set
*/
function setExternalNullifier(uint256 new_external_nullifier) public onlyOwner {
external_nullifier = new_external_nullifier;
}
/*
* Sets the `is_broadcast_permissioned` storage variable, which determines
* whether broadcastSignal can or cannot be called by only the contract
* owner.
*/
function setPermissioning(bool _newPermission) public onlyOwner {
is_broadcast_permissioned = _newPermission;
}
}

View File

@@ -1 +0,0 @@
../build/verifier.sol

View File

@@ -1,27 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
const Migrations = artifacts.require("Migrations");
module.exports = (deployer) => {
return deployer.then( async () => {
await deployer.deploy(Migrations);
});
};

View File

@@ -1,44 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
const path = require('path');
const mimcGenContract = require('circomlib/src/mimcsponge_gencontract.js');
const Artifactor = require('truffle-artifactor');
const SEED = 'mimcsponge';
module.exports = function(deployer) {
return deployer.then( async () => {
const contractsDir = path.join(__dirname, '..', 'build/contracts');
let artifactor = new Artifactor(contractsDir);
let mimcContractName = 'MiMC';
await artifactor.save({
contractName: mimcContractName,
abi: mimcGenContract.abi,
unlinked_binary: mimcGenContract.createCode(SEED, 220),
})
.then(async () => {
const MiMC = artifacts.require(mimcContractName);
await deployer.deploy(MiMC);
});
});
};

View File

@@ -1,29 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
const MiMC = artifacts.require('MiMC');
const MerkleTree = artifacts.require('MerkleTree');
module.exports = function(deployer) {
return deployer.then( async () => {
await deployer.link(MiMC, MerkleTree);
await deployer.deploy(MerkleTree, 2, 4);
});
};

View File

@@ -1,32 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
const MiMC = artifacts.require('MiMC');
const Semaphore = artifacts.require('Semaphore');
const snarkjs = require('snarkjs');
const bigInt = snarkjs.bigInt;
module.exports = function(deployer) {
return deployer.then( async () => {
await deployer.link(MiMC, Semaphore);
await deployer.deploy(Semaphore, 20, 0, 12312);
});
};

View File

@@ -1,29 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
const MiMC = artifacts.require('MiMC');
const MerkleTree = artifacts.require('MerkleTreeTester');
module.exports = function(deployer) {
return deployer.then( async () => {
await deployer.link(MiMC, MerkleTree);
await deployer.deploy(MerkleTree);
});
};

View File

@@ -1,27 +0,0 @@
/*
* semaphorejs - Zero-knowledge signaling on Ethereum
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of semaphorejs.
*
* semaphorejs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* semaphorejs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
*/
const HashTester = artifacts.require('HashTester');
module.exports = function(deployer) {
return deployer.then( async () => {
await deployer.deploy(HashTester);
});
};

View File

@@ -1 +0,0 @@
f009e2cd6f4f37fcf6b6e060415ec6d65182b03a

View File

@@ -1,53 +0,0 @@
{
"name": "zkp-semaphorejs",
"version": "0.3.3",
"description": "Zero-knowledge signaling on Ethereum",
"main": "index.js",
"scripts": {
"test": "truffle test --network=local",
"migrate": "truffle migrate --network=local",
"npm-update-git-deps": "npm-update-git-deps"
},
"bin": {
"semaphorejs-server": "./src/server/server.js",
"semaphorejs-client": "./src/client/client.js"
},
"author": "Kobi Gurkan",
"license": "GPL-3.0",
"repository": {
"type": "git",
"url": "https://github.com/kobigurk/semaphore.git"
},
"dependencies": {
"blakejs": "^1.1.0",
"circom": "0.0.30",
"circomlib": "0.0.13",
"cors": "^2.8.5",
"del": "^4.1.0",
"ethers": "^4.0.33",
"file-saver": "^2.0.1",
"ganache-cli": "^6.4.1",
"ganache-core": "^2.5.3",
"html-webpack-plugin": "^3.2.0",
"level-rocksdb": "^3.0.1",
"mocha": "^6.0.2",
"node-fetch": "^2.3.0",
"require-nocache": "^1.0.0",
"semaphore-merkle-tree": "1.0.6",
"snarkjs": "0.1.17",
"truffle": "^5.0.10",
"truffle-artifactor": "^4.0.10",
"truffle-contract": "^4.0.11",
"truffle-hdwallet-provider": "^1.0.0-web3one.5",
"truffle-privatekey-provider": "^1.1.0",
"web3": "^1.0.0-beta.51",
"webpack": "^4.30.0",
"websnark": "0.0.5",
"winston": "^3.2.1"
},
"devDependencies": {
"npm-update-git-deps": "^1.2.4",
"null-loader": "^0.1.1",
"webpack-cli": "^3.3.0"
}
}

View File

@@ -1,26 +0,0 @@
#!/bin/bash -xe
#
# semaphorejs - Zero-knowledge signaling on Ethereum
# Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
#
# This file is part of semaphorejs.
#
# semaphorejs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# semaphorejs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
#
echo "Working directory: `pwd`"
./compile.sh
./do_setup.sh
./convert_to_wasm.sh
./build_verifier.sh

View File

@@ -1,27 +0,0 @@
#!/bin/bash -ex
#
# semaphorejs - Zero-knowledge signaling on Ethereum
# Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
#
# This file is part of semaphorejs.
#
# semaphorejs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# semaphorejs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
#
mkdir -p ../build
cd ../build
if [ ! -f ../build/verifier.sol ]; then
npx snarkjs generateverifier --vk ../build/verification_key.json -v ../build/verifier.sol
fi

View File

@@ -1,7 +0,0 @@
#!/bin/bash -ex
cd ..
mkdir -p build
find snark -type f -exec md5sum {} \; | sort -k 2 | md5sum > ./build/.snark_checksum
echo './build/.snark_checksum:'
cat ./build/.snark_checksum

View File

@@ -1,28 +0,0 @@
#!/bin/bash -ex
#
# semaphorejs - Zero-knowledge signaling on Ethereum
# Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
#
# This file is part of semaphorejs.
#
# semaphorejs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# semaphorejs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
#
mkdir -p ../build
cd ../build
if [ ! -f ./circuit.json ]; then
export NODE_OPTIONS=--max-old-space-size=4096
npx circom ../snark/semaphore.circom
fi

View File

@@ -1,25 +0,0 @@
#!/bin/bash -xe
#
# semaphorejs - Zero-knowledge signaling on Ethereum
# Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
#
# This file is part of semaphorejs.
#
# semaphorejs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# semaphorejs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
#
if [ ! -f ../build/proving_key.bin ]; then
export NODE_OPTIONS=--max-old-space-size=4096
node ../node_modules/websnark/tools/buildpkey.js -i ../build/proving_key.json -o ../build/proving_key.bin
fi

View File

@@ -1,28 +0,0 @@
#!/bin/bash -ex
#
# semaphorejs - Zero-knowledge signaling on Ethereum
# Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
#
# This file is part of semaphorejs.
#
# semaphorejs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# semaphorejs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
#
mkdir -p ../build
cd ../build
if [ ! -f ./proving_key.json ]; then
export NODE_OPTIONS=--max-old-space-size=4096
npx snarkjs setup --protocol groth
fi

View File

@@ -1,28 +0,0 @@
#!/bin/bash -xe
#
# semaphorejs - Zero-knowledge signaling on Ethereum
# Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
#
# This file is part of semaphorejs.
#
# semaphorejs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# semaphorejs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
#
echo "Working directory: `pwd`"
npx mocha --recursive ../test/circuits
../node_modules/.bin/ganache-cli -p 7545 -l 8800000 -i 5777 --account='0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21,100000000000000000000000000' --account='0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd22,10000000000000000000000000' -q &
../node_modules/.bin/truffle migrate --reset --network=local
../node_modules/.bin/truffle test ../test/contracts/* --network=local

View File

@@ -1,72 +0,0 @@
#!/bin/bash -xe
#
# semaphorejs - Zero-knowledge signaling on Ethereum
# Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
#
# This file is part of semaphorejs.
#
# semaphorejs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# semaphorejs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
#
rm -rf semaphore_server.db
export CHAIN_ID=5777
export NODE_URL=http://localhost:7545
export SERVER_NODE_URL=http://localhost:7545
export DEPLOY_TO=local
export SLEEP_TIME=10
if [ "$1" == "goerli" ]; then
CHAIN_ID=5
NODE_URL=https://goerli.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066
SERVER_NODE_URL=https://goerli.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066
DEPLOY_TO=goerli
SLEEP_TIME=20
fi
if [ "$1" == "ropsten" ]; then
CHAIN_ID=3
NODE_URL=https://ropsten.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066
SERVER_NODE_URL=https://ropsten.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066
DEPLOY_TO=ropsten
SLEEP_TIME=20
fi
if [ "$1" == "rinkeby" ]; then
CHAIN_ID=4
NODE_URL=https://rinkeby.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066
SERVER_NODE_URL=https://rinkeby.infura.io/v3/f4a3ad81db3f4750bd201955c8d20066
DEPLOY_TO=rinkeby
SLEEP_TIME=20
fi
LOG_LEVEL=$2 || "verbose"
if [ "$3" == "true" ]; then
truffle migrate --network ${DEPLOY_TO} -f 2 --to 2
truffle migrate --network ${DEPLOY_TO} -f 4 --to 4
fi
ADDRESS=`cat ../build/contracts/Semaphore.json | jq ".networks.\"${CHAIN_ID}\".address" | sed 's/"//g'`
CREATION_HASH=`cat ../build/contracts/Semaphore.json | jq ".networks.\"${CHAIN_ID}\".transactionHash" | sed 's/"//g'`
CHAIN_ID=${CHAIN_ID} CONTRACT_ADDRESS=$ADDRESS FROM_ADDRESS=0x1929c15f4e818abf2549510622a50c440c474223 FROM_PRIVATE_KEY=0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21 NODE_URL=${NODE_URL} EXTERNAL_NULLIFIER=12312 SEMAPHORE_SERVER_URL=http://localhost:3000 CONFIG_ENV=true BASE_DIR=../.. npx semaphorejs-client generate_identity
echo done
IDENTITY_COMMITMENT=`cat ./semaphore_identity.json | jq '.identity_commitment' | sed 's/"//g'`
echo ${IDENTITY_COMMITMENT}
tmux \
new-session "source ~/.bashrc; export CONFIG_ENV=true LOG_LEVEL=${LOG_LEVEL} CHAIN_ID=${CHAIN_ID} CONTRACT_ADDRESS=$ADDRESS NODE_URL=${SERVER_NODE_URL} SEMAPHORE_PORT=3000 FROM_ADDRESS=0x1929c15f4e818abf2549510622a50c440c474223 FROM_PRIVATE_KEY=0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21 TRANSACTION_CONFIRMATION_BLOCKS=1 CREATION_HASH=${CREATION_HASH}; npx semaphorejs-server disable_permissioning; npx semaphorejs-server; bash -i" \; \
split-window -h -t 0 "source ~/.bashrc; sleep ${SLEEP_TIME}; LOG_LEVEL=${LOG_LEVEL} curl http://localhost:3000/add_identity -X POST -d'{\"leaf\": \"${IDENTITY_COMMITMENT}\"}' -H 'Content-Type: application/json'; bash -i" \; \
split-window -t 0 "source ~/.bashrc; sleep ${SLEEP_TIME}; ./wait_for_element.sh ${IDENTITY_COMMITMENT}; LOG_LEVEL=${LOG_LEVEL} TRANSACTION_CONFIRMATION_BLOCKS=1 CHAIN_ID=${CHAIN_ID} CONTRACT_ADDRESS=$ADDRESS FROM_ADDRESS=0x1929c15f4e818abf2549510622a50c440c474223 FROM_PRIVATE_KEY=0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21 NODE_URL=${NODE_URL} EXTERNAL_NULLIFIER=12312 SEMAPHORE_SERVER_URL=http://localhost:3000 BROADCASTER_ADDRESS=0x1929c15f4e818abf2549510622a50c440c474223 CONFIG_ENV=true BASE_DIR=`pwd`/.. npx semaphorejs-client signal `shuf -i 1-100000000 -n 1`; bash -i"

View File

@@ -1,21 +0,0 @@
#
# semaphorejs - Zero-knowledge signaling on Ethereum
# Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
#
# This file is part of semaphorejs.
#
# semaphorejs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# semaphorejs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
#
../node_modules/.bin/ganache-cli -p 7545 -l 8800000 -i 5777 --account='0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21,100000000000000000000000000' --account='0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd22,10000000000000000000000000' -b 1 -q

View File

@@ -1,31 +0,0 @@
#!/bin/bash -xe
#
# semaphorejs - Zero-knowledge signaling on Ethereum
# Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
#
# This file is part of semaphorejs.
#
# semaphorejs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# semaphorejs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
#
while true; do
code=`curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/element_index/$1`
if [ $code -eq 200 ]; then
echo "found commitment, continuing"
break
else
echo "didn't find commitment, waiting"
sleep 1
fi
done

View File

@@ -1,384 +0,0 @@
// based on https://github.com/zcash/librustzcash/blob/master/sapling-crypto/src/circuit/blake2s.rs
include "uint32.circom";
include "../../node_modules/circomlib/circuits/bitify.circom";
include "../../node_modules/circomlib/circuits/sha256/rotate.circom";
template MixingG(a, b, c, d) {
signal input in_v[16][32];
signal input x[32];
signal input y[32];
signal output out_v[16][32];
component v_a_add = Uint32Add(3);
for (var i = 0; i < 32; i++) {
v_a_add.nums_bits[0][i] <== in_v[a][i];
v_a_add.nums_bits[1][i] <== in_v[b][i];
v_a_add.nums_bits[2][i] <== x[i];
}
component v_d_a_xor = Uint32Xor();
for (var i = 0; i < 32; i++) {
v_d_a_xor.a_bits[i] <== in_v[d][i];
v_d_a_xor.b_bits[i] <== v_a_add.out_bits[i];
}
component v_d_a_rot = RotR(32, 16);
for (var i = 0; i < 32; i++) {
v_d_a_rot.in[i] <== v_d_a_xor.out_bits[i];
}
component v_c_add = Uint32Add(2);
for (var i = 0; i < 32; i++) {
v_c_add.nums_bits[0][i] <== in_v[c][i];
v_c_add.nums_bits[1][i] <== v_d_a_rot.out[i];
}
component v_b_c_xor = Uint32Xor();
for (var i = 0; i < 32; i++) {
v_b_c_xor.a_bits[i] <== in_v[b][i];
v_b_c_xor.b_bits[i] <== v_c_add.out_bits[i];
}
component v_b_c_rot = RotR(32, 12);
for (var i = 0; i < 32; i++) {
v_b_c_rot.in[i] <== v_b_c_xor.out_bits[i];
}
component v_a_add_2 = Uint32Add(3);
for (var i = 0; i < 32; i++) {
v_a_add_2.nums_bits[0][i] <== v_a_add.out_bits[i];
v_a_add_2.nums_bits[1][i] <== v_b_c_rot.out[i];
v_a_add_2.nums_bits[2][i] <== y[i];
}
component v_d_a_xor_2 = Uint32Xor();
for (var i = 0; i < 32; i++) {
v_d_a_xor_2.a_bits[i] <== v_d_a_rot.out[i];
v_d_a_xor_2.b_bits[i] <== v_a_add_2.out_bits[i];
}
component v_d_a_rot_2 = RotR(32, 8);
for (var i = 0; i < 32; i++) {
v_d_a_rot_2.in[i] <== v_d_a_xor_2.out_bits[i];
}
component v_c_add_2 = Uint32Add(2);
for (var i = 0; i < 32; i++) {
v_c_add_2.nums_bits[0][i] <== v_c_add.out_bits[i];
v_c_add_2.nums_bits[1][i] <== v_d_a_rot_2.out[i];
}
component v_b_c_xor_2 = Uint32Xor();
for (var i = 0; i < 32; i++) {
v_b_c_xor_2.a_bits[i] <== v_b_c_rot.out[i];
v_b_c_xor_2.b_bits[i] <== v_c_add_2.out_bits[i];
}
component v_b_c_rot_2 = RotR(32, 7);
for (var i = 0; i < 32; i++) {
v_b_c_rot_2.in[i] <== v_b_c_xor_2.out_bits[i];
}
for (var i = 0; i < 16; i++) {
for (var j = 0; j < 32; j++) {
if (i == a) {
out_v[i][j] <== v_a_add_2.out_bits[j];
} else if (i == b) {
out_v[i][j] <== v_b_c_rot_2.out[j];
} else if (i == c) {
out_v[i][j] <== v_c_add_2.out_bits[j];
} else if (i == d) {
out_v[i][j] <== v_d_a_rot_2.out[j];
} else {
out_v[i][j] <== in_v[i][j];
}
}
}
}
template Blake2sCompression(t, f) {
signal input in_h[8][32];
signal input in_m[16][32];
signal output out_h[8][32];
var v_consts = [
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
];
signal v_h[16][32];
for (var i = 0; i < 16; i++) {
if (i < 8) {
for (var j = 0; j < 32; j++) {
v_h[i][j] <== in_h[i][j];
}
} else {
for (var j = 0; j < 32; j++) {
v_h[i][j] <== (v_consts[i - 8] >> j) & 1;
}
}
}
signal v_pass_1[16][32];
component v_12_xor = Uint32Xor();
component v_13_xor = Uint32Xor();
component v_14_xor = Uint32Xor();
for (var i = 0; i < 16; i++) {
if (i == 12) {
for (var j = 0; j < 32; j++) {
v_12_xor.a_bits[j] <== v_h[i][j];
v_12_xor.b_bits[j] <== (t >> j) & 1;
}
for (var j = 0; j < 32; j++) {
v_pass_1[i][j] <== v_12_xor.out_bits[j];
}
} else if (i == 13) {
for (var j = 0; j < 32; j++) {
v_13_xor.a_bits[j] <== v_h[i][j];
v_13_xor.b_bits[j] <== (t >> (32 + j)) & 1;
}
for (var j = 0; j < 32; j++) {
v_pass_1[i][j] <== v_13_xor.out_bits[j];
}
} else if ((i == 14)) {
if (f == 1) {
for (var j = 0; j < 32; j++) {
v_14_xor.a_bits[j] <== v_h[i][j];
v_14_xor.b_bits[j] <== 1;
}
for (var j = 0; j < 32; j++) {
v_pass_1[i][j] <== v_14_xor.out_bits[j];
}
} else {
for (var j = 0; j < 32; j++) {
v_14_xor.a_bits[j] <== v_h[i][j];
v_14_xor.b_bits[j] <== 0;
}
for (var j = 0; j < 32; j++) {
v_pass_1[i][j] <== v_h[i][j];
}
}
} else {
for (var j = 0; j < 32; j++) {
v_pass_1[i][j] <== v_h[i][j];
}
}
}
var sigma = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
[7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
[9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
[2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]
];
component mixing_g[10][8];
var s;
for (var i = 0; i < 10; i++) {
s = sigma[i];
mixing_g[i][0] = MixingG(0, 4, 8, 12);
for (var j = 0; j < 16; j++) {
for (var k = 0; k < 32; k++) {
if (i == 0) {
mixing_g[i][0].in_v[j][k] <== v_pass_1[j][k];
} else {
mixing_g[i][0].in_v[j][k] <== mixing_g[i - 1][7].out_v[j][k];
}
}
}
for (var k = 0; k < 32; k++) {
mixing_g[i][0].x[k] <== in_m[s[0]][k];
mixing_g[i][0].y[k] <== in_m[s[1]][k];
}
mixing_g[i][1] = MixingG(1, 5, 9, 13);
for (var k = 0; k < 32; k++) {
for (var j = 0; j < 16; j++) {
mixing_g[i][1].in_v[j][k] <== mixing_g[i][0].out_v[j][k];
}
mixing_g[i][1].x[k] <== in_m[s[2]][k];
mixing_g[i][1].y[k] <== in_m[s[3]][k];
}
mixing_g[i][2] = MixingG(2, 6, 10, 14);
for (var k = 0; k < 32; k++) {
for (var j = 0; j < 16; j++) {
mixing_g[i][2].in_v[j][k] <== mixing_g[i][1].out_v[j][k];
}
mixing_g[i][2].x[k] <== in_m[s[4]][k];
mixing_g[i][2].y[k] <== in_m[s[5]][k];
}
mixing_g[i][3] = MixingG(3, 7, 11, 15);
for (var k = 0; k < 32; k++) {
for (var j = 0; j < 16; j++) {
mixing_g[i][3].in_v[j][k] <== mixing_g[i][2].out_v[j][k];
}
mixing_g[i][3].x[k] <== in_m[s[6]][k];
mixing_g[i][3].y[k] <== in_m[s[7]][k];
}
mixing_g[i][4] = MixingG(0, 5, 10, 15);
for (var k = 0; k < 32; k++) {
for (var j = 0; j < 16; j++) {
mixing_g[i][4].in_v[j][k] <== mixing_g[i][3].out_v[j][k];
}
mixing_g[i][4].x[k] <== in_m[s[8]][k];
mixing_g[i][4].y[k] <== in_m[s[9]][k];
}
mixing_g[i][5] = MixingG(1, 6, 11, 12);
for (var k = 0; k < 32; k++) {
for (var j = 0; j < 16; j++) {
mixing_g[i][5].in_v[j][k] <== mixing_g[i][4].out_v[j][k];
}
mixing_g[i][5].x[k] <== in_m[s[10]][k];
mixing_g[i][5].y[k] <== in_m[s[11]][k];
}
mixing_g[i][6] = MixingG(2, 7, 8, 13);
for (var k = 0; k < 32; k++) {
for (var j = 0; j < 16; j++) {
mixing_g[i][6].in_v[j][k] <== mixing_g[i][5].out_v[j][k];
}
mixing_g[i][6].x[k] <== in_m[s[12]][k];
mixing_g[i][6].y[k] <== in_m[s[13]][k];
}
mixing_g[i][7] = MixingG(3, 4, 9, 14);
for (var k = 0; k < 32; k++) {
for (var j = 0; j < 16; j++) {
mixing_g[i][7].in_v[j][k] <== mixing_g[i][6].out_v[j][k];
}
mixing_g[i][7].x[k] <== in_m[s[14]][k];
mixing_g[i][7].y[k] <== in_m[s[15]][k];
}
}
component h_xor_1[8];
component h_xor_2[8];
for (var i = 0; i < 8; i++) {
h_xor_1[i] = Uint32Xor();
h_xor_2[i] = Uint32Xor();
for (var j = 0; j < 32; j++) {
h_xor_1[i].a_bits[j] <== in_h[i][j];
h_xor_1[i].b_bits[j] <== mixing_g[9][7].out_v[i][j];
}
for (var j = 0; j < 32; j++) {
h_xor_2[i].a_bits[j] <== h_xor_1[i].out_bits[j];
h_xor_2[i].b_bits[j] <== mixing_g[9][7].out_v[i + 8][j];
}
for (var j = 0; j < 32; j++) {
out_h[i][j] <== h_xor_2[i].out_bits[j];
}
}
}
template Blake2s(n_bits, personalization) {
signal input in_bits[n_bits];
signal output out[256];
signal h[8][32];
component h_from_bits[8];
component h6_xor;
component h7_xor;
var h_consts = [
0x6A09E667 ^ 0x01010000 ^ 32,
0xBB67AE85,
0x3C6EF372,
0xA54FF53A,
0x510E527F,
0x9B05688C,
0x1F83D9AB,
0x5BE0CD19
];
for (var i = 0; i < 8; i++) {
h_from_bits[i] = Num2Bits(32);
h_from_bits[i].in <== h_consts[i];
if (i == 6) {
h6_xor = Uint32Xor();
for (var j = 0; j < 32; j++) {
h6_xor.a_bits[j] <== h_from_bits[i].out[j];
h6_xor.b_bits[j] <== (personalization >> j) & 1;
}
for (var j = 0; j < 32; j++) {
h[i][j] <== h6_xor.out_bits[j];
}
} else if (i == 7) {
h7_xor = Uint32Xor();
for (var j = 0; j < 32; j++) {
h7_xor.a_bits[j] <== h_from_bits[i].out[j];
h7_xor.b_bits[j] <== (personalization >> (32 + j)) & 1;
}
for (var j = 0; j < 32; j++) {
h[i][j] <== h7_xor.out_bits[j];
}
} else {
for (var j = 0; j < 32; j++) {
h[i][j] <== h_from_bits[i].out[j];
}
}
}
var n_rounded;
if ( (n_bits % 512) == 0) {
n_rounded = n_bits;
} else {
n_rounded = n_bits + (512 - (n_bits % 512));
}
var num_blocks = n_rounded / 512;
if (num_blocks == 0) {
num_blocks = 1;
}
component compressions[num_blocks];
var current_bit = 0;
for (var i = 0; i < num_blocks; i++) {
if (i < (num_blocks - 1)) {
compressions[i] = Blake2sCompression((i + 1)*64, 0);
} else {
compressions[i] = Blake2sCompression((n_bits - (n_bits % 512))/8, 1);
}
for (var j = 0; j < 32; j++) {
for (var k = 0; k < 8; k++) {
if (i == 0) {
compressions[i].in_h[k][j] <== h[k][j];
} else {
compressions[i].in_h[k][j] <== compressions[i - 1].out_h[k][j];
}
}
for (var l = 0; l < 16; l++) {
current_bit = 512*i + 32*l + j;
if (current_bit < n_bits) {
compressions[i].in_m[l][j] <== in_bits[current_bit];
} else {
compressions[i].in_m[l][j] <== 0;
}
}
}
if (i == (num_blocks - 1)) {
for (var j = 0; j < 8; j++) {
for (var k = 0; k < 4; k++) {
for (var l = 0; l < 8; l++) {
out[32*j + 8*k + l] <== compressions[num_blocks - 1].out_h[8 - 1 - j][(4 - 1 - k)*8 + l];
}
}
}
}
}
}

View File

@@ -1,62 +0,0 @@
// based on https://github.com/zcash/librustzcash/blob/master/sapling-crypto/src/circuit/uint32.rs
include "../../node_modules/circomlib/circuits/bitify.circom";
template Uint32Add(n) {
signal input nums_bits[n][32];
signal output out_bits[32];
var result_num_bits = 32 + n - 1;
signal result_bits[result_num_bits];
signal nums_vals[n];
signal result_val[n];
var coeff;
var num_lc;
var lc = 0;
for (var i = 0; i < n; i++) {
num_lc = 0;
coeff = 1;
for (var j = 0; j < 32; j++) {
lc += nums_bits[i][j]*coeff;
num_lc += nums_bits[i][j]*coeff;
coeff *= 2;
}
nums_vals[i] <-- num_lc;
if (i == 0) {
result_val[i] <-- nums_vals[i];
} else {
result_val[i] <-- result_val[i-1] + nums_vals[i];
}
}
var result_lc = 0;
coeff = 1;
for (var i = 0; i < result_num_bits; i++) {
result_bits[i] <-- (result_val[n-1] >> i) & 1;
result_bits[i] * (result_bits[i] - 1) === 0;
result_lc += result_bits[i]*coeff;
coeff *= 2;
}
result_lc === lc;
for (var i = 0; i < 32; i++) {
out_bits[i] <== result_bits[i];
}
}
template Uint32Xor() {
signal input a_bits[32];
signal input b_bits[32];
signal output out_bits[32];
for (var i = 0; i < 32; i++) {
out_bits[i] <== a_bits[i] + b_bits[i] - 2*a_bits[i]*b_bits[i];
}
}

View File

@@ -1,178 +0,0 @@
include "../node_modules/circomlib/circuits/pedersen.circom";
include "../node_modules/circomlib/circuits/mimcsponge.circom";
include "../node_modules/circomlib/circuits/bitify.circom";
include "../node_modules/circomlib/circuits/eddsamimcsponge.circom";
include "./blake2s/blake2s.circom";
template HashLeftRight(n_rounds) {
signal input left;
signal input right;
signal output hash;
component hasher = MiMCSponge(2, n_rounds, 1);
left ==> hasher.ins[0];
right ==> hasher.ins[1];
hasher.k <== 0;
hash <== hasher.outs[0];
}
template Selector() {
signal input input_elem;
signal input path_elem;
signal input path_index;
signal output left;
signal output right;
signal left_selector_1;
signal left_selector_2;
signal right_selector_1;
signal right_selector_2;
path_index * (1-path_index) === 0
left_selector_1 <== (1 - path_index)*input_elem;
left_selector_2 <== (path_index)*path_elem;
right_selector_1 <== (path_index)*input_elem;
right_selector_2 <== (1 - path_index)*path_elem;
left <== left_selector_1 + left_selector_2;
right <== right_selector_1 + right_selector_2;
}
template Semaphore(jubjub_field_size, n_levels, n_rounds) {
// BEGIN signals
signal input signal_hash;
signal input external_nullifier;
// mimc vector commitment
signal private input identity_pk[2];
signal private input identity_nullifier;
signal private input identity_trapdoor;
signal private input identity_path_elements[n_levels];
signal private input identity_path_index[n_levels];
// signature on (external nullifier, signal_hash) with identity_pk
signal private input auth_sig_r[2];
signal private input auth_sig_s;
// get a prime subgroup element derived from identity_pk
component dbl1 = BabyDbl();
dbl1.x <== identity_pk[0];
dbl1.y <== identity_pk[1];
component dbl2 = BabyDbl();
dbl2.x <== dbl1.xout;
dbl2.y <== dbl1.yout;
component dbl3 = BabyDbl();
dbl3.x <== dbl2.xout;
dbl3.y <== dbl2.yout;
// mimc hash
signal output root;
signal output nullifiers_hash;
// END signals
component identity_nullifier_bits = Num2Bits(248);
identity_nullifier_bits.in <== identity_nullifier;
component identity_trapdoor_bits = Num2Bits(248);
identity_trapdoor_bits.in <== identity_trapdoor;
component identity_pk_0_bits = Num2Bits_strict();
identity_pk_0_bits.in <== dbl3.xout;
component identity_commitment = Pedersen(3*256);
// BEGIN identity commitment
for (var i = 0; i < 256; i++) {
if (i < 254) {
identity_commitment.in[i] <== identity_pk_0_bits.out[i];
} else {
identity_commitment.in[i] <== 0;
}
if (i < 248) {
identity_commitment.in[i + 256] <== identity_nullifier_bits.out[i];
identity_commitment.in[i + 2*256] <== identity_trapdoor_bits.out[i];
} else {
identity_commitment.in[i + 256] <== 0;
identity_commitment.in[i + 2*256] <== 0;
}
}
// END identity commitment
// BEGIN tree
component selectors[n_levels];
component hashers[n_levels];
for (var i = 0; i < n_levels; i++) {
selectors[i] = Selector();
hashers[i] = HashLeftRight(n_rounds);
identity_path_index[i] ==> selectors[i].path_index;
identity_path_elements[i] ==> selectors[i].path_elem;
selectors[i].left ==> hashers[i].left;
selectors[i].right ==> hashers[i].right;
}
identity_commitment.out[0] ==> selectors[0].input_elem;
for (var i = 1; i < n_levels; i++) {
hashers[i-1].hash ==> selectors[i].input_elem;
}
root <== hashers[n_levels - 1].hash;
// END tree
// BEGIN nullifiers
component external_nullifier_bits = Num2Bits(232);
external_nullifier_bits.in <== external_nullifier;
component nullifiers_hasher = Blake2s(512, 0);
for (var i = 0; i < 248; i++) {
nullifiers_hasher.in_bits[i] <== identity_nullifier_bits.out[i];
}
for (var i = 0; i < 232; i++) {
nullifiers_hasher.in_bits[248 + i] <== external_nullifier_bits.out[i];
}
for (var i = 0; i < n_levels; i++) {
nullifiers_hasher.in_bits[248 + 232 + i] <== identity_path_index[i];
}
for (var i = (248 + 232 + n_levels); i < 512; i++) {
nullifiers_hasher.in_bits[i] <== 0;
}
component nullifiers_hash_num = Bits2Num(253);
for (var i = 0; i < 253; i++) {
nullifiers_hash_num.in[i] <== nullifiers_hasher.out[i];
}
nullifiers_hash <== nullifiers_hash_num.out;
// END nullifiers
// BEGIN verify sig
component msg_hasher = MiMCSponge(2, n_rounds, 1);
msg_hasher.ins[0] <== external_nullifier;
msg_hasher.ins[1] <== signal_hash;
msg_hasher.k <== 0;
component sig_verifier = EdDSAMiMCSpongeVerifier();
1 ==> sig_verifier.enabled;
identity_pk[0] ==> sig_verifier.Ax;
identity_pk[1] ==> sig_verifier.Ay;
auth_sig_r[0] ==> sig_verifier.R8x;
auth_sig_r[1] ==> sig_verifier.R8y;
auth_sig_s ==> sig_verifier.S;
msg_hasher.outs[0] ==> sig_verifier.M;
// END verify sig
}

View File

@@ -1,3 +0,0 @@
include "./semaphore-base.circom";
component main = Semaphore(251, 20, 220);

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