mirror of
https://github.com/zkemail/zk-email-verify.git
synced 2026-01-09 21:48:14 -05:00
Merge branch 'refactor_upstream' into fe-refactor
This commit is contained in:
@@ -8,9 +8,13 @@ jobs:
|
|||||||
- image: ghcr.io/foundry-rs/foundry:latest
|
- image: ghcr.io/foundry-rs/foundry:latest
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: install foundry packages
|
||||||
|
command: forge install openzeppelin/openzeppelin-contracts foundry-rs/forge-std openzeppelin/openzeppelin-contracts-upgradeable dapphub/ds-test --no-git
|
||||||
|
working_directory: src/contracts
|
||||||
- run:
|
- run:
|
||||||
name: run foundry tests
|
name: run foundry tests
|
||||||
command: forge test --via-ir
|
command: forge test --fork-url https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}
|
||||||
working_directory: src/contracts
|
working_directory: src/contracts
|
||||||
|
|
||||||
run_unit_and_e2e_tests:
|
run_unit_and_e2e_tests:
|
||||||
@@ -47,7 +51,7 @@ jobs:
|
|||||||
- store_test_results:
|
- store_test_results:
|
||||||
path: reports/
|
path: reports/
|
||||||
workflows:
|
workflows:
|
||||||
build_test:
|
build_test:
|
||||||
jobs:
|
jobs:
|
||||||
- run_unit_and_e2e_tests
|
- run_unit_and_e2e_tests
|
||||||
- run_forge_tests
|
- run_forge_tests
|
||||||
|
|||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -6,7 +6,8 @@ dist
|
|||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
/node_modules
|
/node_modules
|
||||||
**/node_modules
|
/e2e-lambdatest/node_modules/
|
||||||
|
/e2e-lambdatest/.yarn/
|
||||||
/.pnp
|
/.pnp
|
||||||
.pnp.js
|
.pnp.js
|
||||||
|
|
||||||
@@ -53,10 +54,13 @@ circuits/email/
|
|||||||
cache/
|
cache/
|
||||||
test.log
|
test.log
|
||||||
src/contracts/out/
|
src/contracts/out/
|
||||||
|
src/contracts/lib/
|
||||||
|
src/contracts/broadcast
|
||||||
.next
|
.next
|
||||||
|
node_modules.nosync
|
||||||
*Wallet*
|
*Wallet*
|
||||||
*wallet*
|
*wallet*
|
||||||
node_modules.nosync
|
circuits/regexes/subject_regex*
|
||||||
|
|
||||||
# Files that never should be committed, but can be obtained by asking Aayush or generating them yourself
|
# Files that never should be committed, but can be obtained by asking Aayush or generating them yourself
|
||||||
*.eml
|
*.eml
|
||||||
|
|||||||
8
.gitmodules
vendored
8
.gitmodules
vendored
@@ -1,6 +1,14 @@
|
|||||||
[submodule "src/contracts/lib/openzeppelin-contracts"]
|
[submodule "src/contracts/lib/openzeppelin-contracts"]
|
||||||
path = src/contracts/lib/openzeppelin-contracts
|
path = src/contracts/lib/openzeppelin-contracts
|
||||||
url = https://github.com/openzeppelin/openzeppelin-contracts
|
url = https://github.com/openzeppelin/openzeppelin-contracts
|
||||||
|
branch = v4.8.1
|
||||||
[submodule "src/contracts/lib/forge-std"]
|
[submodule "src/contracts/lib/forge-std"]
|
||||||
path = src/contracts/lib/forge-std
|
path = src/contracts/lib/forge-std
|
||||||
url = https://github.com/foundry-rs/forge-std
|
url = https://github.com/foundry-rs/forge-std
|
||||||
|
[submodule "src/contracts/lib/openzeppelin-contracts-upgradeable"]
|
||||||
|
path = src/contracts/lib/openzeppelin-contracts-upgradeable
|
||||||
|
url = https://github.com/openzeppelin/openzeppelin-contracts-upgradeable
|
||||||
|
branch = v4.9.0
|
||||||
|
[submodule "src/contracts/lib/ds-test"]
|
||||||
|
path = src/contracts/lib/ds-test
|
||||||
|
url = https://github.com/dapphub/ds-test
|
||||||
|
|||||||
101
README.md
101
README.md
@@ -14,13 +14,13 @@ The documentation for the app is located at https://zkemail.xyz/docs (WIP). Made
|
|||||||
|
|
||||||
To run the frontend with existing circuits (there is no backend or server), enable Node 16 (with nvm) and run:
|
To run the frontend with existing circuits (there is no backend or server), enable Node 16 (with nvm) and run:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
yarn start
|
yarn start
|
||||||
```
|
```
|
||||||
|
|
||||||
If the frontend shows an error on fullProve line, run this and rerun
|
If the frontend shows an error on fullProve line, run this and rerun
|
||||||
|
|
||||||
```
|
```bash
|
||||||
yarn add snarkjs@https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e
|
yarn add snarkjs@https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -44,6 +44,8 @@ circuits/ # groth16 zk circuits
|
|||||||
input_email_domain.json # Standard input for from/to mit.edu domain matching, for use with circuit without body checks
|
input_email_domain.json # Standard input for from/to mit.edu domain matching, for use with circuit without body checks
|
||||||
input_email_packed.json # Same as above but has useless packed input -- is private so irrelevant, this file could be deleted.
|
input_email_packed.json # Same as above but has useless packed input -- is private so irrelevant, this file could be deleted.
|
||||||
main/ # Legacy RSA code
|
main/ # Legacy RSA code
|
||||||
|
regexes/ # Generated regexes
|
||||||
|
helpers/ # Common helper circom circuits imported in email circuits
|
||||||
scripts/ # Run snarkjs ceremony to generate zkey with yarn compile
|
scripts/ # Run snarkjs ceremony to generate zkey with yarn compile
|
||||||
dizkus-scripts/
|
dizkus-scripts/
|
||||||
*.sh # Scripts to compile the chunked keys on a remote server
|
*.sh # Scripts to compile the chunked keys on a remote server
|
||||||
@@ -72,12 +74,12 @@ public/ # Should contain vkey/wasm, but we end up fetching those from AWS server
|
|||||||
|
|
||||||
### Regex to Circom
|
### Regex to Circom
|
||||||
|
|
||||||
First, generate a regex. Go to our [min_dfa fork](https://mindfa.onrender.com/min_dfa) of cyberzhg's toolbox and insert your regex on the top line. We've forked [min-dfa into a UI here](https://mindfa.onrender.com/min_dfa) to create a UI that converts existing regexes with [] support, as well as escapes \_, and the character classes a-z, A-Z, and 0-9. It also shows the DFA states very clearly so you can choose accept states easily. This should make converting regexes into DFA form way cleaner.
|
See regex_to_circom/README.md for usage instructions.
|
||||||
|
|
||||||
Modify either `let raw_regex = ` (that supports actual regex strings like `[A-Za-z0-9]` [but no other character ranges]) or modify `let regex = ` (that does not support brackets or character ranges and supports only the limited syntax in https://cyberzhg.github.io/toolbox/min_dfa) in regex_to_circom/regex_to_dfa.js and then run `python3 gen.py`.
|
|
||||||
|
|
||||||
### Email Circuit Build Steps
|
### Email Circuit Build Steps
|
||||||
|
|
||||||
|
#### Build
|
||||||
|
|
||||||
Install rust/circom2 via the following steps, according to: https://docs.circom.io/getting-started/installation/
|
Install rust/circom2 via the following steps, according to: https://docs.circom.io/getting-started/installation/
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -96,7 +98,7 @@ cargo install --path circom
|
|||||||
|
|
||||||
Inside `zk-email-verify` folder, do
|
Inside `zk-email-verify` folder, do
|
||||||
|
|
||||||
```
|
```bash
|
||||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash # If don't have npm
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash # If don't have npm
|
||||||
. ~/.nvm/nvm.sh # If don't have npm
|
. ~/.nvm/nvm.sh # If don't have npm
|
||||||
nvm install 16 # If don't have node 16
|
nvm install 16 # If don't have node 16
|
||||||
@@ -119,6 +121,8 @@ mv powersOfTau28_hez_final_21.ptau circuits/powersOfTau28_hez_final_21.ptau
|
|||||||
<!-- Previously snarkjs@git+https://github.com/vb7401/snarkjs.git#fae4fe381bdad2da13eee71010dfe477fc694ac1 -->
|
<!-- Previously snarkjs@git+https://github.com/vb7401/snarkjs.git#fae4fe381bdad2da13eee71010dfe477fc694ac1 -->
|
||||||
<!-- Now -> yarn add https://github.com/vb7401/snarkjs/commits/chunk_zkey_gen -->
|
<!-- Now -> yarn add https://github.com/vb7401/snarkjs/commits/chunk_zkey_gen -->
|
||||||
|
|
||||||
|
#### Zkey Creation
|
||||||
|
|
||||||
Put the email into ...\*.eml. Edit the constant filename at the top of generate_input.ts to import that file, then use the output of running that file as the input file (you may need to rename it). You'll need this for both zkey and verifier generation.
|
Put the email into ...\*.eml. Edit the constant filename at the top of generate_input.ts to import that file, then use the output of running that file as the input file (you may need to rename it). You'll need this for both zkey and verifier generation.
|
||||||
|
|
||||||
To create a chunked zkey for in-browser proving, run the following on a high CPU computer:
|
To create a chunked zkey for in-browser proving, run the following on a high CPU computer:
|
||||||
@@ -129,15 +133,17 @@ cd dizkus-scripts/
|
|||||||
cp entropy.env.example entropy.env
|
cp entropy.env.example entropy.env
|
||||||
```
|
```
|
||||||
|
|
||||||
Not put random characters into the values for entropy1 and entropy2, and hexadecimal characters into the beacon. These scripts will compile and test your zkey for you.
|
Fill out the env via random characters into the values for entropy1 and entropy2, and hexadecimal characters into the beacon. These scripts will compile and test your zkey for you, and generate a normal zkey with for an on chain verifier or server side prover, with the same entropy as the chunked one. If you only want the chunked one, use ./3_gen_chunk_zkey.sh in place of the generation.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./1_compile.sh && ./2_gen_wtns.sh && ./3_gen_both_zkeys.sh && ./4_gen_vkey.sh && ./5_gen_proof.sh
|
||||||
```
|
```
|
||||||
./1_compile.sh && ./2_gen_wtns.sh && ./3_gen_chunk_zkey.sh && ./4_gen_vkey.sh && ./5_gen_proof.sh
|
|
||||||
```
|
#### Server-side Prover: Rapidsnark Setup (Optional)
|
||||||
|
|
||||||
If you want to run a fast server side prover, install rapidsnark and test proofgen:
|
If you want to run a fast server side prover, install rapidsnark and test proofgen:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
cd ../../
|
cd ../../
|
||||||
git clone https://github.com/iden3/rapidsnark
|
git clone https://github.com/iden3/rapidsnark
|
||||||
cd rapidsnark
|
cd rapidsnark
|
||||||
@@ -149,7 +155,7 @@ npx task createFieldSources
|
|||||||
|
|
||||||
You're supposed to run `npx task buildPistache` next, but that errored, so I had to manually build the pistache lib first:
|
You're supposed to run `npx task buildPistache` next, but that errored, so I had to manually build the pistache lib first:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
cd depends/pistache
|
cd depends/pistache
|
||||||
sudo apt-get install meson ninja-build
|
sudo apt-get install meson ninja-build
|
||||||
meson setup build --buildtype=release
|
meson setup build --buildtype=release
|
||||||
@@ -161,22 +167,28 @@ cd ../..
|
|||||||
|
|
||||||
Then, from rapidsnark/ I could run
|
Then, from rapidsnark/ I could run
|
||||||
|
|
||||||
```
|
```bash
|
||||||
npx task buildProverServer
|
npx task buildProverServer
|
||||||
```
|
```
|
||||||
|
|
||||||
And from zk-email-verify, convert your proof params to a rapidsnark friendly version:
|
And from zk-email-verify, convert your proof params to a rapidsnark friendly version, generating the C-based witness generator and rapidsnark prover. To target to the AWS autoprover, go to the Makefile and manually replace the `CFLAGS=-std=c++11 -O3 -I.` line with (targeted to g4dn.xlarge and g5.xlarge, tuned to g5.xlarge):
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
```bash
|
||||||
cd ../zk-email-verify/dizkus-scripts
|
cd ../zk-email-verify/dizkus-scripts
|
||||||
./6_gen_proof_rapidsnark.sh
|
./6_gen_proof_rapidsnark.sh
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To compile a non-chunked zkey for server-side use only,
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn compile-all
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Uploading to AWS
|
||||||
|
|
||||||
To upload zkeys to an s3 box on AWS, change bucket_name in upload_to_s3.py and run:
|
To upload zkeys to an s3 box on AWS, change bucket_name in upload_to_s3.py and run:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
sudo apt install awscli # Ubuntu
|
sudo apt install awscli # Ubuntu
|
||||||
brew install awscli # Mac
|
brew install awscli # Mac
|
||||||
|
|
||||||
@@ -188,30 +200,24 @@ yarn add snarkjs@https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a73463
|
|||||||
|
|
||||||
If you want to upload different files, you can parameterize the script as well:
|
If you want to upload different files, you can parameterize the script as well:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
python3 dizkus-scripts/upload_to_s3.py --dirs ~/zk-email-verify/build/email/email_js/ --bucket_name zkemail-zkey-chunks --prefix email.wasm
|
python3 dizkus-scripts/upload_to_s3.py --dirs ~/zk-email-verify/build/email/email_js/ --bucket_name zkemail-zkey-chunks --prefix email.wasm
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that there's no .zkeya file, only .zkeyb ... .zkeyk. The script will automatically zip into .tar.gz files and load into s3 bucket.
|
Note that there's no .zkeya file, only .zkeyb ... .zkeyk. The script will automatically zip into .tar.gz files and load into s3 bucket.
|
||||||
|
|
||||||
We use a fork of [zkp.ts](https://github.com/personaelabs/heyanon/blob/main/lib/zkp.ts) to load these keys into localforage. In the browser, to read off of localforage, you have to use this fork when running the frontend locally/in prod:
|
#### Recompile Frontend (Important!)
|
||||||
|
|
||||||
```
|
We use a fork of [zkp.ts](https://github.com/personaelabs/heyanon/blob/main/lib/zkp.ts) to load these keys into localforage. In the browser, to read off of localforage, you have to use this fork when running the frontend locally/in prod. THIS IS VERY IMPORTANT -- WRONG SNARKJS FORKS CAUSE THE MOST ERRORS.
|
||||||
|
|
||||||
|
```bash
|
||||||
yarn install snarkjs@git+https://github.com/vb7401/snarkjs.git#53e86631b5e409e5bd30300611b495ca469503bc
|
yarn install snarkjs@git+https://github.com/vb7401/snarkjs.git#53e86631b5e409e5bd30300611b495ca469503bc
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Manually copy paste the modulus in the resulting generated file into solidity verified mailserver keys.
|
Manually copy paste the modulus in the resulting generated file into solidity verified mailserver keys.
|
||||||
|
|
||||||
Change s3 address in the frontend to your bucket.
|
Change s3 address in the frontend to your bucket.
|
||||||
|
|
||||||
To do a non-chunked zkey for non-browser running,
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn compile-all
|
|
||||||
```
|
|
||||||
|
|
||||||
### Really Large Circuits
|
### Really Large Circuits
|
||||||
|
|
||||||
If your circuit ends up being > 20M constraints, you will need to follow [these guidelines](https://hackmd.io/V-7Aal05Tiy-ozmzTGBYPA?view#Compilation-and-proving) to compile it.
|
If your circuit ends up being > 20M constraints, you will need to follow [these guidelines](https://hackmd.io/V-7Aal05Tiy-ozmzTGBYPA?view#Compilation-and-proving) to compile it.
|
||||||
@@ -243,16 +249,20 @@ and you can swap `email` for `sha` or `rsa` or any other circuit name that match
|
|||||||
|
|
||||||
and when the circuit doesn't change,
|
and when the circuit doesn't change,
|
||||||
|
|
||||||
```
|
```bash
|
||||||
yarn compile email true skip-r1cswasm
|
yarn compile email true skip-r1cswasm
|
||||||
```
|
```
|
||||||
|
|
||||||
and when the zkey also doesn't change,
|
and when the zkey also doesn't change,
|
||||||
|
|
||||||
```
|
```bash
|
||||||
yarn compile email true skip-r1cswasm skip-zkey
|
yarn compile email true skip-r1cswasm skip-zkey
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Contract Deployment
|
||||||
|
|
||||||
|
Follow the instructions in `src/contracts/README.md`.
|
||||||
|
|
||||||
### Production
|
### Production
|
||||||
|
|
||||||
For production, make sure to set a beacon in .env.
|
For production, make sure to set a beacon in .env.
|
||||||
@@ -263,39 +273,20 @@ Note that this leaks the number of characters in the username of someone who sen
|
|||||||
|
|
||||||
To constraint count, do
|
To constraint count, do
|
||||||
|
|
||||||
```
|
```bash
|
||||||
cd circuits
|
cd circuits
|
||||||
node --max-old-space-size=614400 ./../node_modules/.bin/snarkjs r1cs info email.r1cs
|
node --max-old-space-size=614400 ./../node_modules/.bin/snarkjs r1cs info email.r1cs
|
||||||
```
|
```
|
||||||
|
|
||||||
To test solidity,
|
To test solidity,
|
||||||
|
|
||||||
```
|
```bash
|
||||||
cp node_modules/forge-std src/contracts/lib/forge-std
|
cp node_modules/forge-std src/contracts/lib/forge-std
|
||||||
cd src/contracts
|
cd src/contracts
|
||||||
forge test
|
forge test
|
||||||
```
|
```
|
||||||
|
|
||||||
To deploy contract to forked mainnet, do:
|
To deploy contracts, look at src/contracts/README.md.
|
||||||
|
|
||||||
```
|
|
||||||
anvil --fork-url https://eth-mainnet.alchemyapi.io/v2/***REMOVED*** --port 8547 # Run in tmux
|
|
||||||
export ETH_RPC_URL=http://localhost:8547
|
|
||||||
|
|
||||||
# Public anvil sk
|
|
||||||
export SK=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
|
|
||||||
forge create --rpc-url $ETH_RPC_URL StringUtils --private-key $SK --via-ir --force
|
|
||||||
forge create --rpc-url $ETH_RPC_URL NFTSVG --private-key $SK --via-ir --force
|
|
||||||
|
|
||||||
# Edit the Cargo.toml to have the two deployment addresses, then call this
|
|
||||||
forge create --rpc-url $ETH_RPC_URL VerifiedTwitterEmail --private-key $SK --via-ir --force
|
|
||||||
```
|
|
||||||
|
|
||||||
For just the contracts, can do
|
|
||||||
|
|
||||||
```
|
|
||||||
forge create --rpc-url $ETH_RPC_URL src/contracts/src/emailVerifier.sol:Verifier --private-key $SK
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance
|
## Performance
|
||||||
|
|
||||||
@@ -327,7 +318,7 @@ Short term ways to improve the performance would be to replace the regex checks
|
|||||||
|
|
||||||
Looking more long term, we are actively using Halo2 and Nova to speed up the most expensive operations of regex and SHA. As hash functions and regex DFA traversal are repeated operations, they are a great fit for Nova's folding methods to compress repeated computation into a constant sized folded instance. But to actually use Nova to fold expensive operations outside of Halo2/Groth16, we need to verify the folded instance is valid inside the circuit for zero-knowledge and to link it to the rest of the computation. We also are attempting to use the lookup feature of Halo2 to precompute the entire table of possible regex state transitions, and just looking up that all of the transitions made are valid ones in the table instead of expensively checking each state! This idea is due to Sora Suegami, explained in more detail here: https://hackmd.io/@SoraSuegami/Hy9dWgT8i.
|
Looking more long term, we are actively using Halo2 and Nova to speed up the most expensive operations of regex and SHA. As hash functions and regex DFA traversal are repeated operations, they are a great fit for Nova's folding methods to compress repeated computation into a constant sized folded instance. But to actually use Nova to fold expensive operations outside of Halo2/Groth16, we need to verify the folded instance is valid inside the circuit for zero-knowledge and to link it to the rest of the computation. We also are attempting to use the lookup feature of Halo2 to precompute the entire table of possible regex state transitions, and just looking up that all of the transitions made are valid ones in the table instead of expensively checking each state! This idea is due to Sora Suegami, explained in more detail here: https://hackmd.io/@SoraSuegami/Hy9dWgT8i.
|
||||||
|
|
||||||
The current set of remaining tasks and potential final states is documented in the following DAG, please reach out if any of the projects seem interesting!
|
The current set `of remaining tasks and potential final states is documented in the following DAG, please reach out if any of the projects seem interesting!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -343,11 +334,11 @@ The full email header and body check circuit, with 7-byte packing and final publ
|
|||||||
|
|
||||||
In the browser, on a 2019 Intel Mac on Chrome, proving uses 7.3/8 cores. zk-gen takes 384 s, groth16 prove takes 375 s, and witness calculation takes 9 s.
|
In the browser, on a 2019 Intel Mac on Chrome, proving uses 7.3/8 cores. zk-gen takes 384 s, groth16 prove takes 375 s, and witness calculation takes 9 s.
|
||||||
|
|
||||||
For baremetal, proof generation time on 16 CPUs took 97 seconds. Generating zkey 0 took 17 minutes. zkey 1 and zkey 2 each took 5 minutes. r1cs + wasm generation took 5 minutes. Witness generation took 16 seconds. cpp generation of witness gen file (from script 6) took 210 minutes -- we do not run this pathway anymore.
|
For baremetal, proof generation time on 16 CPUs took 97 seconds. Generating zkey 0 took 17 minutes. zkey 1 and zkey 2 each took 5 minutes. r1cs + wasm generation took 5 minutes. Witness generation took 16 seconds. cpp generation of witness gen file (from script 6) took 210 minutes -- this is only useful for server side proving.
|
||||||
|
|
||||||
### Scrubbing Sensitive Files
|
### Scrubbing Sensitive Files
|
||||||
|
|
||||||
```
|
```bash
|
||||||
brew install git-filter-repo
|
brew install git-filter-repo
|
||||||
git filter-repo --replace-text <(echo "0x000000000000000000000000000000000000000000000000000000000abcdef")
|
git filter-repo --replace-text <(echo "0x000000000000000000000000000000000000000000000000000000000abcdef")
|
||||||
git filter-repo --path mit_msg.eml --invert-paths
|
git filter-repo --path mit_msg.eml --invert-paths
|
||||||
@@ -401,7 +392,7 @@ Use https://sha256algorithm.com/ as an explainer! It's a great visualization of
|
|||||||
|
|
||||||
### I'm having trouble with regex or base64 understanding. How do I understand that better?
|
### I'm having trouble with regex or base64 understanding. How do I understand that better?
|
||||||
|
|
||||||
Use https://cyberzhg.github.io/toolbox/ to experiement with conversions to/from base64 and to/from DFAs and NFAs.
|
Use https://cyberzhg.github.io/toolbox/ to experiment with conversions to/from base64 and to/from DFAs and NFAs.
|
||||||
|
|
||||||
### What are the differences between generating proofs (snarkjs.groth16.fullprove) on the client vs. on a server?
|
### What are the differences between generating proofs (snarkjs.groth16.fullprove) on the client vs. on a server?
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
// pragma circom 2.1.5;
|
|
||||||
|
|
||||||
// signal output reveal[num_bytes];
|
|
||||||
// for (var i = 0; i < num_bytes; i++) {
|
|
||||||
// reveal[i] <== in[i] * (states[i+1][18] + states[i+1][14]);
|
|
||||||
// }
|
|
||||||
@@ -2,6 +2,7 @@ pragma circom 2.1.5;
|
|||||||
|
|
||||||
include "../../node_modules/circomlib/circuits/bitify.circom";
|
include "../../node_modules/circomlib/circuits/bitify.circom";
|
||||||
include "../../node_modules/circomlib/circuits/comparators.circom";
|
include "../../node_modules/circomlib/circuits/comparators.circom";
|
||||||
|
include "../../node_modules/circomlib/circuits/mimcsponge.circom";
|
||||||
include "./fp.circom";
|
include "./fp.circom";
|
||||||
|
|
||||||
// returns ceil(log2(a+1))
|
// returns ceil(log2(a+1))
|
||||||
@@ -175,3 +176,28 @@ template Bytes2Packed(n){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// salt_is_message_id_from, custom_anon_from_hashed_salt = MakeAnonEmailSalt(max_email_from_len, max_message_id_len)(email_from, custom_message_id_from, shifted_message_id)
|
||||||
|
template MakeAnonEmailSalt(email_len, blinder_len) {
|
||||||
|
signal input email[email_len];
|
||||||
|
signal input custom_message_id[blinder_len]; // previous message id, used to source past account
|
||||||
|
signal input original_message_id[blinder_len]; // previous message id, used to source past account
|
||||||
|
signal intermediate_is_message_id_from[blinder_len + 1];
|
||||||
|
signal isEq[blinder_len];
|
||||||
|
signal output blinder_matches;
|
||||||
|
signal output anon_salt;
|
||||||
|
|
||||||
|
component hasher = MiMCSponge(email_len + blinder_len, 220, 1);
|
||||||
|
hasher.k <== 123;
|
||||||
|
for (var i = 0; i < email_len; i++) {
|
||||||
|
hasher.ins[i] <== email[i];
|
||||||
|
}
|
||||||
|
intermediate_is_message_id_from[0] <== 1;
|
||||||
|
for (var i = 0; i < blinder_len; i++) {
|
||||||
|
hasher.ins[i + email_len] <== custom_message_id[i];
|
||||||
|
isEq[i] <== IsEqual()([custom_message_id[i], original_message_id[i]]);
|
||||||
|
intermediate_is_message_id_from[i + 1] <== isEq[i] * intermediate_is_message_id_from[i];
|
||||||
|
}
|
||||||
|
blinder_matches <== intermediate_is_message_id_from[blinder_len];
|
||||||
|
anon_salt <== hasher.outs[0];
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ template FromRegex (msg_bytes) {
|
|||||||
component multi_or[10][num_bytes];
|
component multi_or[10][num_bytes];
|
||||||
signal states[num_bytes+1][16];
|
signal states[num_bytes+1][16];
|
||||||
|
|
||||||
for (var i = 0; i < num_bytes; i++) {
|
for (var i = 0; i < num_bytes+1; i++) {
|
||||||
states[i][0] <== 1;
|
states[i][0] <== 1;
|
||||||
}
|
}
|
||||||
for (var i = 1; i < 16; i++) {
|
for (var i = 1; i < 16; i++) {
|
||||||
@@ -164,7 +164,7 @@ template FromRegex (msg_bytes) {
|
|||||||
states[i+1][2] <== and[8][i].out;
|
states[i+1][2] <== and[8][i].out;
|
||||||
eq[15][i] = IsEqual();
|
eq[15][i] = IsEqual();
|
||||||
eq[15][i].in[0] <== in[i];
|
eq[15][i].in[0] <== in[i];
|
||||||
eq[15][i].in[1] <== 94;
|
eq[15][i].in[1] <== 128;
|
||||||
and[9][i] = AND();
|
and[9][i] = AND();
|
||||||
and[9][i].a <== states[i][0];
|
and[9][i].a <== states[i][0];
|
||||||
and[9][i].b <== eq[15][i].out;
|
and[9][i].b <== eq[15][i].out;
|
||||||
|
|||||||
291
circuits/regexes/message_id_regex.circom
Normal file
291
circuits/regexes/message_id_regex.circom
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
pragma circom 2.1.5;
|
||||||
|
|
||||||
|
include "./regex_helpers.circom";
|
||||||
|
|
||||||
|
template MessageIDRegex (msg_bytes) {
|
||||||
|
signal input msg[msg_bytes];
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
var num_bytes = msg_bytes+1;
|
||||||
|
signal in[num_bytes];
|
||||||
|
in[0] <== 128; // \x80 (sentinel for first character in string)
|
||||||
|
for (var i = 0; i < msg_bytes; i++) {
|
||||||
|
in[i+1] <== msg[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
component eq[30][num_bytes];
|
||||||
|
component lt[12][num_bytes];
|
||||||
|
component and[26][num_bytes];
|
||||||
|
component multi_or[4][num_bytes];
|
||||||
|
signal states[num_bytes+1][19];
|
||||||
|
|
||||||
|
for (var i = 0; i < num_bytes+1; i++) {
|
||||||
|
states[i][0] <== 1;
|
||||||
|
}
|
||||||
|
for (var i = 1; i < 19; i++) {
|
||||||
|
states[0][i] <== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < num_bytes; i++) {
|
||||||
|
lt[0][i] = LessThan(8);
|
||||||
|
lt[0][i].in[0] <== 64;
|
||||||
|
lt[0][i].in[1] <== in[i];
|
||||||
|
lt[1][i] = LessThan(8);
|
||||||
|
lt[1][i].in[0] <== in[i];
|
||||||
|
lt[1][i].in[1] <== 91;
|
||||||
|
and[0][i] = AND();
|
||||||
|
and[0][i].a <== lt[0][i].out;
|
||||||
|
and[0][i].b <== lt[1][i].out;
|
||||||
|
lt[2][i] = LessThan(8);
|
||||||
|
lt[2][i].in[0] <== 96;
|
||||||
|
lt[2][i].in[1] <== in[i];
|
||||||
|
lt[3][i] = LessThan(8);
|
||||||
|
lt[3][i].in[0] <== in[i];
|
||||||
|
lt[3][i].in[1] <== 123;
|
||||||
|
and[1][i] = AND();
|
||||||
|
and[1][i].a <== lt[2][i].out;
|
||||||
|
and[1][i].b <== lt[3][i].out;
|
||||||
|
lt[4][i] = LessThan(8);
|
||||||
|
lt[4][i].in[0] <== 47;
|
||||||
|
lt[4][i].in[1] <== in[i];
|
||||||
|
lt[5][i] = LessThan(8);
|
||||||
|
lt[5][i].in[0] <== in[i];
|
||||||
|
lt[5][i].in[1] <== 58;
|
||||||
|
and[2][i] = AND();
|
||||||
|
and[2][i].a <== lt[4][i].out;
|
||||||
|
and[2][i].b <== lt[5][i].out;
|
||||||
|
eq[0][i] = IsEqual();
|
||||||
|
eq[0][i].in[0] <== in[i];
|
||||||
|
eq[0][i].in[1] <== 95;
|
||||||
|
eq[1][i] = IsEqual();
|
||||||
|
eq[1][i].in[0] <== in[i];
|
||||||
|
eq[1][i].in[1] <== 46;
|
||||||
|
eq[2][i] = IsEqual();
|
||||||
|
eq[2][i].in[0] <== in[i];
|
||||||
|
eq[2][i].in[1] <== 43;
|
||||||
|
eq[3][i] = IsEqual();
|
||||||
|
eq[3][i].in[0] <== in[i];
|
||||||
|
eq[3][i].in[1] <== 61;
|
||||||
|
eq[4][i] = IsEqual();
|
||||||
|
eq[4][i].in[0] <== in[i];
|
||||||
|
eq[4][i].in[1] <== 64;
|
||||||
|
eq[5][i] = IsEqual();
|
||||||
|
eq[5][i].in[0] <== in[i];
|
||||||
|
eq[5][i].in[1] <== 45;
|
||||||
|
and[3][i] = AND();
|
||||||
|
and[3][i].a <== states[i][1];
|
||||||
|
multi_or[0][i] = MultiOR(9);
|
||||||
|
multi_or[0][i].in[0] <== and[0][i].out;
|
||||||
|
multi_or[0][i].in[1] <== and[1][i].out;
|
||||||
|
multi_or[0][i].in[2] <== and[2][i].out;
|
||||||
|
multi_or[0][i].in[3] <== eq[0][i].out;
|
||||||
|
multi_or[0][i].in[4] <== eq[1][i].out;
|
||||||
|
multi_or[0][i].in[5] <== eq[2][i].out;
|
||||||
|
multi_or[0][i].in[6] <== eq[3][i].out;
|
||||||
|
multi_or[0][i].in[7] <== eq[4][i].out;
|
||||||
|
multi_or[0][i].in[8] <== eq[5][i].out;
|
||||||
|
and[3][i].b <== multi_or[0][i].out;
|
||||||
|
lt[6][i] = LessThan(8);
|
||||||
|
lt[6][i].in[0] <== 64;
|
||||||
|
lt[6][i].in[1] <== in[i];
|
||||||
|
lt[7][i] = LessThan(8);
|
||||||
|
lt[7][i].in[0] <== in[i];
|
||||||
|
lt[7][i].in[1] <== 91;
|
||||||
|
and[4][i] = AND();
|
||||||
|
and[4][i].a <== lt[6][i].out;
|
||||||
|
and[4][i].b <== lt[7][i].out;
|
||||||
|
lt[8][i] = LessThan(8);
|
||||||
|
lt[8][i].in[0] <== 96;
|
||||||
|
lt[8][i].in[1] <== in[i];
|
||||||
|
lt[9][i] = LessThan(8);
|
||||||
|
lt[9][i].in[0] <== in[i];
|
||||||
|
lt[9][i].in[1] <== 123;
|
||||||
|
and[5][i] = AND();
|
||||||
|
and[5][i].a <== lt[8][i].out;
|
||||||
|
and[5][i].b <== lt[9][i].out;
|
||||||
|
lt[10][i] = LessThan(8);
|
||||||
|
lt[10][i].in[0] <== 47;
|
||||||
|
lt[10][i].in[1] <== in[i];
|
||||||
|
lt[11][i] = LessThan(8);
|
||||||
|
lt[11][i].in[0] <== in[i];
|
||||||
|
lt[11][i].in[1] <== 58;
|
||||||
|
and[6][i] = AND();
|
||||||
|
and[6][i].a <== lt[10][i].out;
|
||||||
|
and[6][i].b <== lt[11][i].out;
|
||||||
|
eq[6][i] = IsEqual();
|
||||||
|
eq[6][i].in[0] <== in[i];
|
||||||
|
eq[6][i].in[1] <== 95;
|
||||||
|
eq[7][i] = IsEqual();
|
||||||
|
eq[7][i].in[0] <== in[i];
|
||||||
|
eq[7][i].in[1] <== 46;
|
||||||
|
eq[8][i] = IsEqual();
|
||||||
|
eq[8][i].in[0] <== in[i];
|
||||||
|
eq[8][i].in[1] <== 43;
|
||||||
|
eq[9][i] = IsEqual();
|
||||||
|
eq[9][i].in[0] <== in[i];
|
||||||
|
eq[9][i].in[1] <== 61;
|
||||||
|
eq[10][i] = IsEqual();
|
||||||
|
eq[10][i].in[0] <== in[i];
|
||||||
|
eq[10][i].in[1] <== 64;
|
||||||
|
eq[11][i] = IsEqual();
|
||||||
|
eq[11][i].in[0] <== in[i];
|
||||||
|
eq[11][i].in[1] <== 45;
|
||||||
|
and[7][i] = AND();
|
||||||
|
and[7][i].a <== states[i][18];
|
||||||
|
multi_or[1][i] = MultiOR(9);
|
||||||
|
multi_or[1][i].in[0] <== and[4][i].out;
|
||||||
|
multi_or[1][i].in[1] <== and[5][i].out;
|
||||||
|
multi_or[1][i].in[2] <== and[6][i].out;
|
||||||
|
multi_or[1][i].in[3] <== eq[6][i].out;
|
||||||
|
multi_or[1][i].in[4] <== eq[7][i].out;
|
||||||
|
multi_or[1][i].in[5] <== eq[8][i].out;
|
||||||
|
multi_or[1][i].in[6] <== eq[9][i].out;
|
||||||
|
multi_or[1][i].in[7] <== eq[10][i].out;
|
||||||
|
multi_or[1][i].in[8] <== eq[11][i].out;
|
||||||
|
and[7][i].b <== multi_or[1][i].out;
|
||||||
|
multi_or[2][i] = MultiOR(2);
|
||||||
|
multi_or[2][i].in[0] <== and[3][i].out;
|
||||||
|
multi_or[2][i].in[1] <== and[7][i].out;
|
||||||
|
states[i+1][1] <== multi_or[2][i].out;
|
||||||
|
eq[12][i] = IsEqual();
|
||||||
|
eq[12][i].in[0] <== in[i];
|
||||||
|
eq[12][i].in[1] <== 13;
|
||||||
|
and[8][i] = AND();
|
||||||
|
and[8][i].a <== states[i][0];
|
||||||
|
and[8][i].b <== eq[12][i].out;
|
||||||
|
states[i+1][2] <== and[8][i].out;
|
||||||
|
eq[13][i] = IsEqual();
|
||||||
|
eq[13][i].in[0] <== in[i];
|
||||||
|
eq[13][i].in[1] <== 128;
|
||||||
|
and[9][i] = AND();
|
||||||
|
and[9][i].a <== states[i][0];
|
||||||
|
and[9][i].b <== eq[13][i].out;
|
||||||
|
eq[14][i] = IsEqual();
|
||||||
|
eq[14][i].in[0] <== in[i];
|
||||||
|
eq[14][i].in[1] <== 10;
|
||||||
|
and[10][i] = AND();
|
||||||
|
and[10][i].a <== states[i][2];
|
||||||
|
and[10][i].b <== eq[14][i].out;
|
||||||
|
multi_or[3][i] = MultiOR(2);
|
||||||
|
multi_or[3][i].in[0] <== and[9][i].out;
|
||||||
|
multi_or[3][i].in[1] <== and[10][i].out;
|
||||||
|
states[i+1][3] <== multi_or[3][i].out;
|
||||||
|
eq[15][i] = IsEqual();
|
||||||
|
eq[15][i].in[0] <== in[i];
|
||||||
|
eq[15][i].in[1] <== 62;
|
||||||
|
and[11][i] = AND();
|
||||||
|
and[11][i].a <== states[i][1];
|
||||||
|
and[11][i].b <== eq[15][i].out;
|
||||||
|
states[i+1][4] <== and[11][i].out;
|
||||||
|
eq[16][i] = IsEqual();
|
||||||
|
eq[16][i].in[0] <== in[i];
|
||||||
|
eq[16][i].in[1] <== 109;
|
||||||
|
and[12][i] = AND();
|
||||||
|
and[12][i].a <== states[i][3];
|
||||||
|
and[12][i].b <== eq[16][i].out;
|
||||||
|
states[i+1][5] <== and[12][i].out;
|
||||||
|
eq[17][i] = IsEqual();
|
||||||
|
eq[17][i].in[0] <== in[i];
|
||||||
|
eq[17][i].in[1] <== 13;
|
||||||
|
and[13][i] = AND();
|
||||||
|
and[13][i].a <== states[i][4];
|
||||||
|
and[13][i].b <== eq[17][i].out;
|
||||||
|
states[i+1][6] <== and[13][i].out;
|
||||||
|
eq[18][i] = IsEqual();
|
||||||
|
eq[18][i].in[0] <== in[i];
|
||||||
|
eq[18][i].in[1] <== 10;
|
||||||
|
and[14][i] = AND();
|
||||||
|
and[14][i].a <== states[i][6];
|
||||||
|
and[14][i].b <== eq[18][i].out;
|
||||||
|
states[i+1][7] <== and[14][i].out;
|
||||||
|
eq[19][i] = IsEqual();
|
||||||
|
eq[19][i].in[0] <== in[i];
|
||||||
|
eq[19][i].in[1] <== 101;
|
||||||
|
and[15][i] = AND();
|
||||||
|
and[15][i].a <== states[i][5];
|
||||||
|
and[15][i].b <== eq[19][i].out;
|
||||||
|
states[i+1][8] <== and[15][i].out;
|
||||||
|
eq[20][i] = IsEqual();
|
||||||
|
eq[20][i].in[0] <== in[i];
|
||||||
|
eq[20][i].in[1] <== 115;
|
||||||
|
and[16][i] = AND();
|
||||||
|
and[16][i].a <== states[i][8];
|
||||||
|
and[16][i].b <== eq[20][i].out;
|
||||||
|
states[i+1][9] <== and[16][i].out;
|
||||||
|
eq[21][i] = IsEqual();
|
||||||
|
eq[21][i].in[0] <== in[i];
|
||||||
|
eq[21][i].in[1] <== 115;
|
||||||
|
and[17][i] = AND();
|
||||||
|
and[17][i].a <== states[i][9];
|
||||||
|
and[17][i].b <== eq[21][i].out;
|
||||||
|
states[i+1][10] <== and[17][i].out;
|
||||||
|
eq[22][i] = IsEqual();
|
||||||
|
eq[22][i].in[0] <== in[i];
|
||||||
|
eq[22][i].in[1] <== 97;
|
||||||
|
and[18][i] = AND();
|
||||||
|
and[18][i].a <== states[i][10];
|
||||||
|
and[18][i].b <== eq[22][i].out;
|
||||||
|
states[i+1][11] <== and[18][i].out;
|
||||||
|
eq[23][i] = IsEqual();
|
||||||
|
eq[23][i].in[0] <== in[i];
|
||||||
|
eq[23][i].in[1] <== 103;
|
||||||
|
and[19][i] = AND();
|
||||||
|
and[19][i].a <== states[i][11];
|
||||||
|
and[19][i].b <== eq[23][i].out;
|
||||||
|
states[i+1][12] <== and[19][i].out;
|
||||||
|
eq[24][i] = IsEqual();
|
||||||
|
eq[24][i].in[0] <== in[i];
|
||||||
|
eq[24][i].in[1] <== 101;
|
||||||
|
and[20][i] = AND();
|
||||||
|
and[20][i].a <== states[i][12];
|
||||||
|
and[20][i].b <== eq[24][i].out;
|
||||||
|
states[i+1][13] <== and[20][i].out;
|
||||||
|
eq[25][i] = IsEqual();
|
||||||
|
eq[25][i].in[0] <== in[i];
|
||||||
|
eq[25][i].in[1] <== 45;
|
||||||
|
and[21][i] = AND();
|
||||||
|
and[21][i].a <== states[i][13];
|
||||||
|
and[21][i].b <== eq[25][i].out;
|
||||||
|
states[i+1][14] <== and[21][i].out;
|
||||||
|
eq[26][i] = IsEqual();
|
||||||
|
eq[26][i].in[0] <== in[i];
|
||||||
|
eq[26][i].in[1] <== 105;
|
||||||
|
and[22][i] = AND();
|
||||||
|
and[22][i].a <== states[i][14];
|
||||||
|
and[22][i].b <== eq[26][i].out;
|
||||||
|
states[i+1][15] <== and[22][i].out;
|
||||||
|
eq[27][i] = IsEqual();
|
||||||
|
eq[27][i].in[0] <== in[i];
|
||||||
|
eq[27][i].in[1] <== 100;
|
||||||
|
and[23][i] = AND();
|
||||||
|
and[23][i].a <== states[i][15];
|
||||||
|
and[23][i].b <== eq[27][i].out;
|
||||||
|
states[i+1][16] <== and[23][i].out;
|
||||||
|
eq[28][i] = IsEqual();
|
||||||
|
eq[28][i].in[0] <== in[i];
|
||||||
|
eq[28][i].in[1] <== 58;
|
||||||
|
and[24][i] = AND();
|
||||||
|
and[24][i].a <== states[i][16];
|
||||||
|
and[24][i].b <== eq[28][i].out;
|
||||||
|
states[i+1][17] <== and[24][i].out;
|
||||||
|
eq[29][i] = IsEqual();
|
||||||
|
eq[29][i].in[0] <== in[i];
|
||||||
|
eq[29][i].in[1] <== 60;
|
||||||
|
and[25][i] = AND();
|
||||||
|
and[25][i].a <== states[i][17];
|
||||||
|
and[25][i].b <== eq[29][i].out;
|
||||||
|
states[i+1][18] <== and[25][i].out;
|
||||||
|
}
|
||||||
|
|
||||||
|
signal final_state_sum[num_bytes+1];
|
||||||
|
final_state_sum[0] <== states[0][7];
|
||||||
|
for (var i = 1; i <= num_bytes; i++) {
|
||||||
|
final_state_sum[i] <== final_state_sum[i-1] + states[i][7];
|
||||||
|
}
|
||||||
|
out <== final_state_sum[num_bytes];
|
||||||
|
|
||||||
|
signal output reveal[msg_bytes];
|
||||||
|
for (var i = 0; i < msg_bytes; i++) {
|
||||||
|
reveal[i] <== in[i+1] * (states[i+2][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
1331
circuits/regexes/subject_regex_operation.circom
Normal file
1331
circuits/regexes/subject_regex_operation.circom
Normal file
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ template WalletSubjectRegex (msg_bytes) {
|
|||||||
component multi_or[21][num_bytes];
|
component multi_or[21][num_bytes];
|
||||||
signal states[num_bytes+1][50];
|
signal states[num_bytes+1][50];
|
||||||
|
|
||||||
for (var i = 0; i < num_bytes; i++) {
|
for (var i = 0; i < num_bytes+1; i++) {
|
||||||
states[i][0] <== 1;
|
states[i][0] <== 1;
|
||||||
}
|
}
|
||||||
for (var i = 1; i < 50; i++) {
|
for (var i = 1; i < 50; i++) {
|
||||||
@@ -10,8 +10,6 @@ include "./regexes/from_regex.circom";
|
|||||||
include "./regexes/tofrom_domain_regex.circom";
|
include "./regexes/tofrom_domain_regex.circom";
|
||||||
include "./regexes/body_hash_regex.circom";
|
include "./regexes/body_hash_regex.circom";
|
||||||
include "./regexes/twitter_reset_regex.circom";
|
include "./regexes/twitter_reset_regex.circom";
|
||||||
include "./regexes/subject_regex.circom";
|
|
||||||
|
|
||||||
|
|
||||||
// Here, n and k are the biginteger parameters for RSA
|
// Here, n and k are the biginteger parameters for RSA
|
||||||
// This is because the number is chunked into k pack_size of n bits each
|
// This is because the number is chunked into k pack_size of n bits each
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
source circuit.env
|
source circuit.env
|
||||||
|
|
||||||
echo "****MAKE CPP FILE FOR WITNESS GENERATION****"
|
# echo "****MAKE CPP FILE FOR WITNESS GENERATION****"
|
||||||
start=$(date +%s)
|
# start=$(date +%s)
|
||||||
set -x
|
# set -x
|
||||||
make -C "$BUILD_DIR"/"$CIRCUIT_NAME"_cpp/
|
# make -C "$BUILD_DIR"/"$CIRCUIT_NAME"_cpp/
|
||||||
{ set +x; } 2>/dev/null
|
# { set +x; } 2>/dev/null
|
||||||
end=$(date +%s)
|
# end=$(date +%s)
|
||||||
echo "DONE ($((end - start))s)"
|
# echo "DONE ($((end - start))s)"
|
||||||
echo
|
# echo
|
||||||
|
|
||||||
# echo "****GENERATING WITNESS FOR SAMPLE INPUT****"
|
# echo "****GENERATING WITNESS FOR SAMPLE INPUT****"
|
||||||
# start=`date +%s`
|
# start=`date +%s`
|
||||||
|
|||||||
6
e2e-lambdatest/babel.config.js
Normal file
6
e2e-lambdatest/babel.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
['@babel/preset-env', {targets: {node: 'current'}}],
|
||||||
|
'@babel/preset-typescript',
|
||||||
|
],
|
||||||
|
};
|
||||||
102
e2e-lambdatest/e2e-dl-zkp.test.ts
Normal file
102
e2e-lambdatest/e2e-dl-zkp.test.ts
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import puppeteer, { Page } from "puppeteer";
|
||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
const pageUrl = "https://dev.zkemail.xyz/";
|
||||||
|
|
||||||
|
const testEthAddress = "0x00000000000000000000";
|
||||||
|
const testEmailFilePath = path.join(__dirname, "..", "src", "__fixtures__/email/zktestemail.test-eml");
|
||||||
|
const testEmailText = fs.readFileSync(testEmailFilePath, "utf8");
|
||||||
|
|
||||||
|
// puppeteer test helpers
|
||||||
|
const emailInputSelector = "textarea[aria-label='Full Email with Headers']";
|
||||||
|
const ethInputSelector = "input[placeholder='Ethereum Address']";
|
||||||
|
const proofTextareaSelector = "textarea[aria-label='Proof Output']";
|
||||||
|
|
||||||
|
const downloadTimeout = 10000000;
|
||||||
|
const proofTimeout = 10000000;
|
||||||
|
|
||||||
|
const setTextAreaValue = async (page: Page, selector: string, value: string) => {
|
||||||
|
// This is a workaround for the fact that page.keyboard.type() is too slow.
|
||||||
|
return await page.$eval(selector, async (element: any, value: string) => {
|
||||||
|
function setNativeValue(element: any, value: string) {
|
||||||
|
// @ts-ignore
|
||||||
|
const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
|
||||||
|
const prototype = Object.getPrototypeOf(element);
|
||||||
|
// @ts-ignore
|
||||||
|
const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;
|
||||||
|
|
||||||
|
if (valueSetter && valueSetter !== prototypeValueSetter) {
|
||||||
|
// @ts-ignore
|
||||||
|
prototypeValueSetter.call(element, value);
|
||||||
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
|
valueSetter.call(element, value);
|
||||||
|
}
|
||||||
|
element.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
}
|
||||||
|
setNativeValue(element, value);
|
||||||
|
}, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const gotToPageAndEnterInputs = async (page: Page, emailInputSelector: string, ethInputSelector: string, testEmailText: string, testEthAddress: string) => {
|
||||||
|
await page.goto(pageUrl);
|
||||||
|
await page.waitForSelector(emailInputSelector);
|
||||||
|
// 'page.keyboard.type()' takes too long. Use workaround.
|
||||||
|
// await page.focus(emailInputSelector);
|
||||||
|
// await page.keyboard.type(testEmailText);
|
||||||
|
await setTextAreaValue(page, emailInputSelector, testEmailText);
|
||||||
|
await page.waitForSelector(ethInputSelector);
|
||||||
|
await page.focus(ethInputSelector);
|
||||||
|
await page.keyboard.type(testEthAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("App.js", () => {
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await gotToPageAndEnterInputs(page, emailInputSelector, ethInputSelector, testEmailText, testEthAddress);
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
it("should start download and run zkproof after entering inputs and click", async () => {
|
||||||
|
await page.waitForSelector("[data-testid='status-not-started']");
|
||||||
|
console.log("starting e2e test...this will take up to 10 minutes and consume bandwidth and cpu time")
|
||||||
|
const proveButtonSelector = "button[data-testid='prove-button']";
|
||||||
|
await page.click(proveButtonSelector);
|
||||||
|
// starting download
|
||||||
|
console.log("starting download...this will take up to 10 minutes and consume bandwidth");
|
||||||
|
const proveButtonIsDisabled = await page.$eval(proveButtonSelector, button => (button as HTMLButtonElement).disabled);
|
||||||
|
expect(proveButtonIsDisabled).toBe(true);
|
||||||
|
|
||||||
|
let status;
|
||||||
|
await page.waitForSelector("[data-testid='status-downloading-proof-files']");
|
||||||
|
status = await page.$eval("[data-testid='status-downloading-proof-files']", e => e.attributes['data-testid'].value);
|
||||||
|
expect(status).toBe("status-downloading-proof-files");
|
||||||
|
|
||||||
|
await page.waitForSelector("[data-testid='status-generating-proof']", {timeout: downloadTimeout});
|
||||||
|
console.log("finished download...starting proof");
|
||||||
|
console.log("starting proof...this will take up to 10 minutes and consume cpu time");
|
||||||
|
status = await page.$eval("[data-testid='status-generating-proof']", e => e.attributes['data-testid'].value);
|
||||||
|
expect(status).toBe("status-generating-proof");
|
||||||
|
|
||||||
|
await page.waitForSelector("[data-testid='status-done']", {timeout: proofTimeout});
|
||||||
|
status = await page.$eval("[data-testid='status-done']", e => e.attributes['data-testid'].value);
|
||||||
|
expect(status).toBe("status-done");
|
||||||
|
|
||||||
|
// check proof
|
||||||
|
const proofValue = await page.$eval(proofTextareaSelector, e => (e as HTMLInputElement).value);
|
||||||
|
const proofObj = JSON.parse(proofValue);
|
||||||
|
expect(proofObj["pi_a"]).toBeTruthy();
|
||||||
|
expect(proofObj["pi_b"]).toBeTruthy();
|
||||||
|
expect(proofObj["pi_c"]).toBeTruthy();
|
||||||
|
expect(proofObj["protocol"]).toBe("groth16");
|
||||||
|
expect(proofObj["curve"]).toBe("bn128");
|
||||||
|
|
||||||
|
// report times
|
||||||
|
const downloadTime = await page.$eval("[data-testid='download-time']", e => e.textContent);
|
||||||
|
const proofTime = await page.$eval("[data-testid='proof-time']", e => e.textContent);
|
||||||
|
console.log("Completed download and proof");
|
||||||
|
console.log("download in ms took", downloadTime);
|
||||||
|
console.log("proof in ms took", proofTime);
|
||||||
|
}, proofTimeout + downloadTimeout + 30000);
|
||||||
|
|
||||||
|
});
|
||||||
80
e2e-lambdatest/e2e-ui-lambda.test.ts
Normal file
80
e2e-lambdatest/e2e-ui-lambda.test.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import puppeteer, { Page } from "puppeteer";
|
||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
const pageUrl = "https://dev.zkemail.xyz/";
|
||||||
|
|
||||||
|
const testEthAddress = "0x00000000000000000000";
|
||||||
|
const testEmailFilePath = path.join(__dirname, "..", "src", "__fixtures__/email/zktestemail.test-eml");
|
||||||
|
const testEmailText = fs.readFileSync(testEmailFilePath, "utf8");
|
||||||
|
// const testProofFile = "/__fixtures__/proofs/zktestemail.test-proof.json"
|
||||||
|
// const testProofText = fs.readFileSync(__dirname + testProofFile, "utf8");
|
||||||
|
|
||||||
|
// puppeteer test helpers
|
||||||
|
const emailInputSelector = "textarea[aria-label='Full Email with Headers']";
|
||||||
|
const ethInputSelector = "input[placeholder='Ethereum Address']";
|
||||||
|
// const proofTextareaSelector = "textarea[aria-label='Proof Output']";
|
||||||
|
|
||||||
|
// const downloadTimeout = 10000000;
|
||||||
|
// const proofTimeout = 10000000;
|
||||||
|
|
||||||
|
const setTextAreaValue = async (page: Page, selector: string, value: string) => {
|
||||||
|
// This is a workaround for the fact that page.keyboard.type() is too slow.
|
||||||
|
return await page.$eval(selector, async (element: any, value: string) => {
|
||||||
|
function setNativeValue(element: any, value: string) {
|
||||||
|
// @ts-ignore
|
||||||
|
const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
|
||||||
|
const prototype = Object.getPrototypeOf(element);
|
||||||
|
// @ts-ignore
|
||||||
|
const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;
|
||||||
|
|
||||||
|
if (valueSetter && valueSetter !== prototypeValueSetter) {
|
||||||
|
// @ts-ignore
|
||||||
|
prototypeValueSetter.call(element, value);
|
||||||
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
|
valueSetter.call(element, value);
|
||||||
|
}
|
||||||
|
element.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
}
|
||||||
|
setNativeValue(element, value);
|
||||||
|
}, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const gotToPageAndEnterInputs = async (page: Page, emailInputSelector: string, ethInputSelector: string, testEmailText: string, testEthAddress: string) => {
|
||||||
|
await page.goto(pageUrl);
|
||||||
|
await page.waitForSelector(emailInputSelector);
|
||||||
|
// 'page.keyboard.type()' takes too long. Use workaround.
|
||||||
|
// await page.focus(emailInputSelector);
|
||||||
|
// await page.keyboard.type(testEmailText);
|
||||||
|
await setTextAreaValue(page, emailInputSelector, testEmailText);
|
||||||
|
await page.waitForSelector(ethInputSelector);
|
||||||
|
await page.focus(ethInputSelector);
|
||||||
|
await page.keyboard.type(testEthAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("App.js", () => {
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await gotToPageAndEnterInputs(page, emailInputSelector, ethInputSelector, testEmailText, testEthAddress);
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
it("should allow email and eth addr to be entered into inputs", async () => {
|
||||||
|
await page.waitForSelector("[data-testid='status-not-started']");
|
||||||
|
const emailValue = await page.$eval(emailInputSelector, e => (e as HTMLInputElement).value);
|
||||||
|
expect(emailValue).toBe(testEmailText);
|
||||||
|
const ethValue = await page.$eval(ethInputSelector, e => (e as HTMLInputElement).value);
|
||||||
|
expect(ethValue).toBe(testEthAddress);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should start with an enabled prove button and status should be 'not-started'", async () => {
|
||||||
|
await page.waitForSelector("[data-testid='status-not-started']");
|
||||||
|
const proveButtonSelector = "button[data-testid='prove-button']";
|
||||||
|
const proveButtonIsDisabled = await page.$eval(proveButtonSelector, button => (button as HTMLButtonElement).disabled);
|
||||||
|
expect(proveButtonIsDisabled).toBe(false);
|
||||||
|
|
||||||
|
const status = await page.$eval("[data-testid='status-not-started']", e => e.attributes['data-testid'].value);
|
||||||
|
expect(status).toBe("status-not-started");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
35
e2e-lambdatest/jest-puppeteer.config.js
Normal file
35
e2e-lambdatest/jest-puppeteer.config.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
const caps_chrome = {
|
||||||
|
browserName : 'Chrome',
|
||||||
|
browserVersion : 'latest',
|
||||||
|
'LT:Options' : {
|
||||||
|
platform : 'Windows 10',
|
||||||
|
build : 'ZK Email Puppeteer-Jest',
|
||||||
|
name : 'ZK Email Puppeteer-jest test on Chrome',
|
||||||
|
resolution : '1366x768',
|
||||||
|
user : process.env.LT_USERNAME,
|
||||||
|
accessKey : process.env.LT_ACCESS_KEY,
|
||||||
|
network : true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const caps_edge = {
|
||||||
|
browserName : 'MicrosoftEdge',
|
||||||
|
browserVersion : 'latest',
|
||||||
|
'LT:Options' : {
|
||||||
|
platform : 'Windows 10',
|
||||||
|
build : 'Sample Puppeteer-Jest',
|
||||||
|
name : 'Puppeteer-jest test on Edge',
|
||||||
|
resolution : '1366x768',
|
||||||
|
user : process.env.LT_USERNAME,
|
||||||
|
accessKey : process.env.LT_ACCESS_KEY,
|
||||||
|
network : true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
connect : {
|
||||||
|
browserWSEndpoint : `wss://cdp.lambdatest.com/puppeteer?capabilities=${encodeURIComponent(
|
||||||
|
JSON.stringify(caps_chrome)
|
||||||
|
)}`
|
||||||
|
}
|
||||||
|
};
|
||||||
9
e2e-lambdatest/jest.config.ts
Normal file
9
e2e-lambdatest/jest.config.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import type {Config} from 'jest';
|
||||||
|
|
||||||
|
|
||||||
|
export default async (): Promise<Config> => {
|
||||||
|
return {
|
||||||
|
verbose: true,
|
||||||
|
preset: "jest-puppeteer"
|
||||||
|
};
|
||||||
|
};
|
||||||
17
e2e-lambdatest/package.json
Normal file
17
e2e-lambdatest/package.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "zk-email-verify-e2e-lambdatest",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Tests for ZK Email on LambdaTest",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "jest"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/preset-typescript": "^7.21.0",
|
||||||
|
"@jest/globals": "^29.4.3",
|
||||||
|
"jest": "^29.4.3",
|
||||||
|
"jest-puppeteer": "^7.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
4104
e2e-lambdatest/yarn.lock
Normal file
4104
e2e-lambdatest/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
403
emls/zktestemail_twitter.eml
Normal file
403
emls/zktestemail_twitter.eml
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
Delivered-To: zkemailverify@gmail.com
|
||||||
|
Received: by 2002:abe:244f:0:b0:351:8511:f81d with SMTP id k76csp1565968vlk;
|
||||||
|
Sat, 11 Feb 2023 09:22:14 -0800 (PST)
|
||||||
|
X-Google-Smtp-Source: AK7set/Y3OsAAeTIiMSNbcB9uLcnu/XZVkr0lwa3Lhc02UYddJqHwBqjTSDEn8LEcuk5B2ooL7iz
|
||||||
|
X-Received: by 2002:a05:690c:b99:b0:52e:9f98:3afb with SMTP id ck25-20020a05690c0b9900b0052e9f983afbmr7390402ywb.8.1676136134009;
|
||||||
|
Sat, 11 Feb 2023 09:22:14 -0800 (PST)
|
||||||
|
ARC-Seal: i=1; a=rsa-sha256; t=1676136133; cv=none;
|
||||||
|
d=google.com; s=arc-20160816;
|
||||||
|
b=XizR8dC+HfpBsj5NgSZvKF6bGWkJfnE5N8tcK+jWhnn4aC1T8qXM/aPjeKXbasjxVw
|
||||||
|
EwD0BSIvm28FQ+no5vP1F+/jLaCMB5YvCQBQwadWrzFmhZnYHZ5j/sHeYeAxitbvwzuq
|
||||||
|
W8soAUmi4jkytC+tbQkHl7FIjAZ8yLgcMnzKWvNYD5VhfSMfr0q0ZJthzX5AjyP47zjk
|
||||||
|
Noliyk67gPd3ZEeR66wHDVIUaZb9AhExIPfPyg/uO3Qi3vlgoDVYdNYEwY763XK8sMtk
|
||||||
|
PfZJ9AyarJiBzEUGXMMmaqM3wdxcvAUV8d8EF4HaIU4U1Q0UatOomAGOo1H+JADR0fH/
|
||||||
|
ZX5Q==
|
||||||
|
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
|
||||||
|
h=feedback-id:message-id:mime-version:subject:to:from:date
|
||||||
|
:dkim-signature;
|
||||||
|
bh=luw1SBOWXFuYP/jkF1TjW99cBB9mxovOyljNia105q8=;
|
||||||
|
b=Yw8cjT3S7XHSO4MoOvbKTK/zg5wCWRH91dUpNvyHyQGohemvn6oBL4on6IOZ6wRseC
|
||||||
|
SJkH6T7facdD6VOFyzdHkGOPTXKPMP90HveULVk7f+57u4aTPpxnRtG6DZlWOqnh/GZl
|
||||||
|
gvaoWDYrge43sbFMbYd3goNfGuDHOZJbOit+g+GReQ6XBOY2oI7UgYuDtrYR/NB0MBJW
|
||||||
|
Ed2mr4E3XxX3N+i5fZle4OjfK3xPN+N8huFNaS9x4bOxs8jb+XjRV2vMhadhpmLDRlxN
|
||||||
|
7iVAWYGz7sa9DOPGKQxh+1cGmlgUJiyeOshHwzK7kKjSFUANfB1qlqZKd7kAc6KYPQ0R
|
||||||
|
zDcg==
|
||||||
|
ARC-Authentication-Results: i=1; mx.google.com;
|
||||||
|
dkim=pass header.i=@twitter.com header.s=dkim-201406 header.b=Mf8VchLe;
|
||||||
|
spf=pass (google.com: domain of n0399d118e2-e108b1a8a8ec4d32-zkemailverify===gmail.com@bounce.twitter.com designates 199.16.156.166 as permitted sender) smtp.mailfrom="n0399d118e2-e108b1a8a8ec4d32-zkemailverify===gmail.com@bounce.twitter.com";
|
||||||
|
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=twitter.com
|
||||||
|
Return-Path: <n0399d118e2-e108b1a8a8ec4d32-zkemailverify===gmail.com@bounce.twitter.com>
|
||||||
|
Received: from spring-chicken-ba.twitter.com (spring-chicken-ba.twitter.com. [199.16.156.166])
|
||||||
|
by mx.google.com with ESMTPS id f184-20020a816ac1000000b0050a5b687438si2536384ywc.362.2023.02.11.09.22.13
|
||||||
|
for <zkemailverify@gmail.com>
|
||||||
|
(version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
|
||||||
|
Sat, 11 Feb 2023 09:22:13 -0800 (PST)
|
||||||
|
Received-SPF: pass (google.com: domain of n0399d118e2-e108b1a8a8ec4d32-zkemailverify===gmail.com@bounce.twitter.com designates 199.16.156.166 as permitted sender) client-ip=199.16.156.166;
|
||||||
|
Authentication-Results: mx.google.com;
|
||||||
|
dkim=pass header.i=@twitter.com header.s=dkim-201406 header.b=Mf8VchLe;
|
||||||
|
spf=pass (google.com: domain of n0399d118e2-e108b1a8a8ec4d32-zkemailverify===gmail.com@bounce.twitter.com designates 199.16.156.166 as permitted sender) smtp.mailfrom="n0399d118e2-e108b1a8a8ec4d32-zkemailverify===gmail.com@bounce.twitter.com";
|
||||||
|
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=twitter.com
|
||||||
|
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=twitter.com;
|
||||||
|
s=dkim-201406; t=1676136133;
|
||||||
|
bh=luw1SBOWXFuYP/jkF1TjW99cBB9mxovOyljNia105q8=;
|
||||||
|
h=Date:From:To:Subject:MIME-Version:Content-Type:Message-ID;
|
||||||
|
b=Mf8VchLeAPEOR6FSuqtVMIW0Zut2I+Apy+kLYu93HIzNKlJR2obsh/wirFuTo0qje
|
||||||
|
KQWpAlyaOGrtWiw7q7Kx7BEZ4wXuKmenccAdNUvS0AedwVeIIgemQHh5ebgw51b1hD
|
||||||
|
mlZw66c8Q7ffC4cPvGzKM1TYdFt5yNaSSWYLWIoFvQiLL7ePodeYgdT0IMp4kjRl97
|
||||||
|
sXbdEInGVPYI1g1KkzjhORYI9eBKkZVT4YA/BZZ0WF3fSC1DkF1TecUotNZaDVjB0i
|
||||||
|
1QxDKumXbQxzmrJ8Z/8jFZ/kaCPKpMSg8RXYzpvaPe635vblMOMPtpIYvRy93vlGxf
|
||||||
|
ltxUwAkCsug8Q==
|
||||||
|
X-MSFBL: JEendVXqQSf0QfW2bVHGwxqI6nksIAh1iV1Le82G8P0=|eyJnIjoiQnVsayIsImI
|
||||||
|
iOiJhdGxhLWJzZy0yOS1zcjEtQnVsay4xODYiLCJyIjoiemtlbWFpbHZlcmlmeUB
|
||||||
|
nbWFpbC5jb20iLCJ1IjoiemtlbWFpbHZlcmlmeUBnbWFpbC5jb21AaWlkIyNlMTA
|
||||||
|
4YjFhOGE4ZWM0ZDMyODMwNjdiNTVhMDA5MTJiOUB1c2IjIzI0QDI5NkAxNjI0NDU
|
||||||
|
3Nzc1ODk0OTg2NzU0QDBAMjRmODhjZTY1YmE4ZWMyNjI2YWZkNjQxZGFkMTY5YzI
|
||||||
|
yNjJiZjE4NSJ9
|
||||||
|
Date: Sat, 11 Feb 2023 17:22:13 +0000
|
||||||
|
From: Twitter <info@twitter.com>
|
||||||
|
To: zk_practice <zkemailverify@gmail.com>
|
||||||
|
Subject: Password reset request
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: multipart/alternative;
|
||||||
|
boundary="----=_Part_327915209_1341522477.1676136133617"
|
||||||
|
X-Twitter-CID: ibis2-password_reset_pin_based_email
|
||||||
|
Message-ID: <1D.E4.03737.5CEC7E36@twitter.com>
|
||||||
|
Feedback-ID: atla.c5bbd1c7e491b5023ff4b22a03711997:Twitter
|
||||||
|
|
||||||
|
------=_Part_327915209_1341522477.1676136133617
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
Twitter
|
||||||
|
|
||||||
|
Reset your password?
|
||||||
|
|
||||||
|
If you requested a password reset for zktestemail, use the confirmation code below to complete the process. If you didn't make this request, ignore this email.
|
||||||
|
|
||||||
|
> akfrmhya
|
||||||
|
|
||||||
|
|
||||||
|
Getting a lot of password reset emails?
|
||||||
|
You can change your account settings to require personal information to reset your password.
|
||||||
|
|
||||||
|
account settings
|
||||||
|
> https://twitter.com/settings/security
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
Help
|
||||||
|
> https://support.twitter.com/articles/14663
|
||||||
|
|
||||||
|
Not my account
|
||||||
|
> https://twitter.com/account/not_my_account/1624457775894986754/8D785-ED35A-167613?ut=1&cn=cGFzc3dvcmRfcmVzZXRfcGluX2Jhc2VkX2VtYWls
|
||||||
|
|
||||||
|
Email security tips
|
||||||
|
> https://support.twitter.com/articles/204820-fake-twitter-emails
|
||||||
|
|
||||||
|
Twitter, Inc. 1355 Market Street, Suite 900 San Francisco, CA 94103
|
||||||
|
|
||||||
|
------=_Part_327915209_1341522477.1676136133617
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: quoted-printable
|
||||||
|
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www=
|
||||||
|
.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" />
|
||||||
|
<meta name=3D"viewport" content=3D"width=3Ddevice-width, minimum-scale=3D1.=
|
||||||
|
0, maximum-scale=3D1.0, user-scalable=3D0" />
|
||||||
|
<meta name=3D"apple-mobile-web-app-capable" content=3D"yes" />
|
||||||
|
<style type=3D"text/css">
|
||||||
|
@media only screen and (max-width: 320px) {
|
||||||
|
table[class=3D"edu-module"]{
|
||||||
|
border-radius: 0px !important;
|
||||||
|
-webkit-border-radius: 0px !important;
|
||||||
|
-moz-border-radius: 0px !important;
|
||||||
|
}
|
||||||
|
td[class=3D"edu-collapse"]{
|
||||||
|
width: 0px !important;
|
||||||
|
}
|
||||||
|
td[class=3D"mobile-height"]{
|
||||||
|
height: 30px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 420px) {
|
||||||
|
td[class=3D"spacer"]{
|
||||||
|
font-size:4px !important;
|
||||||
|
}
|
||||||
|
span[class=3D"address"] a {
|
||||||
|
line-height:18px !important;
|
||||||
|
}
|
||||||
|
a[class=3D"cut"]{
|
||||||
|
display:none !important;
|
||||||
|
}
|
||||||
|
td[class=3D"margins"]{
|
||||||
|
width:18px !important;
|
||||||
|
}
|
||||||
|
td[class=3D"edu-margins"]{
|
||||||
|
width:18px !important;
|
||||||
|
}
|
||||||
|
td[class=3D"logo_space"]{
|
||||||
|
height:12px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 480px) {
|
||||||
|
table[class=3D"collapse"]{
|
||||||
|
width:100% !important;
|
||||||
|
}
|
||||||
|
table[class=3D"edu-module"]{
|
||||||
|
width:100% !important;
|
||||||
|
}
|
||||||
|
div[class=3D"collapse"]{
|
||||||
|
width:100% !important;
|
||||||
|
}
|
||||||
|
td[class=3D"logo_space"]{
|
||||||
|
height: 24px !important;
|
||||||
|
}
|
||||||
|
span[class=3D"address"]{
|
||||||
|
display:block !important;
|
||||||
|
width:240px !important;
|
||||||
|
}
|
||||||
|
td[class=3D"cut"]{
|
||||||
|
display:none !important;
|
||||||
|
}
|
||||||
|
td[class=3D"logo"] img {
|
||||||
|
width:24px !important;
|
||||||
|
}
|
||||||
|
span[class=3D"address"] a {
|
||||||
|
line-height:18px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body bgcolor=3D"#F5F8FA" style=3D"margin:0;padding:0;-webkit-text-size-adj=
|
||||||
|
ust:100%;-ms-text-size-adjust:100%;">
|
||||||
|
<table cellpadding=3D"0" cellspacing=3D"0" border=3D"0" width=3D"100%" bgco=
|
||||||
|
lor=3D"#F5F8FA" style=3D"background-color:#F5F8FA;padding:0;margin:0;line-h=
|
||||||
|
eight:1px;font-size:1px;" class=3D"body_wrapper">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:=
|
||||||
|
1px;">
|
||||||
|
<table class=3D"collapse" id=3D"header" align=3D"center" width=3D"448" styl=
|
||||||
|
e=3D"width: 448px;padding:0;margin:0;line-height:1px;font-size:1px;" bgcolo=
|
||||||
|
r=3D"#ffffff" cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style=3D"min-width: 448px;padding:0;margin:0;line-height:1px;font-size:=
|
||||||
|
1px;" class=3D"cut"> <img src=3D"https://ea.twimg.com/email/self_serve/medi=
|
||||||
|
a/spacer-1402696023930.png" style=3D"min-width: 448px;height:1px;margin:0;p=
|
||||||
|
adding:0;display:block;-ms-interpolation-mode:bicubic;border:none;outline:n=
|
||||||
|
one;" /> </td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:=
|
||||||
|
1px;">
|
||||||
|
<!--/////////////////// header ///////////////////////////-->
|
||||||
|
<table class=3D"collapse" id=3D"header" align=3D"center" width=3D"448" styl=
|
||||||
|
e=3D"width:448px;background-color:#ffffff;padding:0;margin:0;line-height:1p=
|
||||||
|
x;font-size:1px;" bgcolor=3D"#ffffff" cellpadding=3D"0" cellspacing=3D"0" b=
|
||||||
|
order=3D"0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td colspan=3D"4" height=3D"24" style=3D"height:24px;padding:0;margin:0;lin=
|
||||||
|
e-height:1px;font-size:1px;" class=3D"logo_space"> </td>
|
||||||
|
</tr>
|
||||||
|
<tr align=3D"right">
|
||||||
|
<td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1=
|
||||||
|
px;font-size:1px;"></td>
|
||||||
|
<td align=3D"right" style=3D"padding:0;margin:0;line-height:1px;font-size:1=
|
||||||
|
px;"> <a href=3D"#" target=3D"blank" style=3D"text-decoration:none;border-s=
|
||||||
|
tyle:none;border:0;padding:0;margin:0;"> <img width=3D"32" align=3D"right" =
|
||||||
|
src=3D"https://ea.twimg.com/email/self_serve/media/Twitter_logo_180-1468901=
|
||||||
|
451975.png" style=3D"width:32px;margin:0;padding:0;display:block;-ms-interp=
|
||||||
|
olation-mode:bicubic;border:none;outline:none;" /> </a> </td>
|
||||||
|
<td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1=
|
||||||
|
px;font-size:1px;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan=3D"3" height=3D"24" style=3D"height:24px;padding:0;margin:0;lin=
|
||||||
|
e-height:1px;font-size:1px;" class=3D"logo_space"> <img width=3D"1" height=
|
||||||
|
=3D"1" style=3D"display: block;margin:0;padding:0;display:block;-ms-interpo=
|
||||||
|
lation-mode:bicubic;border:none;outline:none;" src=3D"https://twitter.com/s=
|
||||||
|
cribe/ibis?t=3D1&cn=3DcGFzc3dvcmRfcmVzZXRfcGluX2Jhc2VkX2VtYWls&iid=
|
||||||
|
=3De108b1a8a8ec4d3283067b55a00912b9&uid=3D1624457775894986754&nid=
|
||||||
|
=3D296+20" /> </td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<!--/////////////////// end header///////////////////////////-->
|
||||||
|
<!--/////////////////// body ///////////////////////////-->
|
||||||
|
<table class=3D"collapse" id=3D"header" align=3D"center" width=3D"448" styl=
|
||||||
|
e=3D"width:448px;background-color:#ffffff;padding:0;margin:0;line-height:1p=
|
||||||
|
x;font-size:1px;" bgcolor=3D"#ffffff" cellpadding=3D"0" cellspacing=3D"0" b=
|
||||||
|
order=3D"0">
|
||||||
|
<tbody>
|
||||||
|
<tr align=3D"left;">
|
||||||
|
<td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1=
|
||||||
|
px;font-size:1px;"></td>
|
||||||
|
<td align=3D"left;" style=3D"padding:0;margin:0;line-height:1px;font-size:1=
|
||||||
|
px;">
|
||||||
|
<table class=3D"collapse" cellpadding=3D"0" cellspacing=3D"0" border=3D"0" =
|
||||||
|
style=3D"padding:0;margin:0;line-height:1px;font-size:1px;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left;" class=3D"h2" style=3D"padding:0;margin:0;line-height:1p=
|
||||||
|
x;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helvetica, A=
|
||||||
|
rial, sans-serif;font-size:24px;line-height:32px;font-weight:bold;color:#29=
|
||||||
|
2F33;text-align:left;text-decoration:none;-webkit-font-smoothing:antialiase=
|
||||||
|
d;"> Reset your password? </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td height=3D"12" style=3D"padding:0;margin:0;line-height:1px;font-size:1px=
|
||||||
|
;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left;" class=3D"body-text" style=3D"padding:0;margin:0;line-he=
|
||||||
|
ight:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helve=
|
||||||
|
tica, Arial, sans-serif;font-size:16px;line-height:20px;font-weight:400;col=
|
||||||
|
or:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:anti=
|
||||||
|
aliased;"> If you requested a password reset for @zktestemail, use the conf=
|
||||||
|
irmation code below to complete the process. If you didn't make this reques=
|
||||||
|
t, ignore this email. </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td height=3D"24" style=3D"padding:0;margin:0;line-height:1px;font-size:1px=
|
||||||
|
;"></td>
|
||||||
|
</tr>
|
||||||
|
<!--*********** password reset pin ************-->
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left;" class=3D"support" style=3D"padding:0;margin:0;line-heig=
|
||||||
|
ht:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helveti=
|
||||||
|
ca, Arial, sans-serif;font-size:14px;line-height:16px;font-weight:400;color=
|
||||||
|
:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:antial=
|
||||||
|
iased;"> <strong>akfrmhya</strong> </td>
|
||||||
|
</tr>
|
||||||
|
<!--*********** end password reset pin ************-->
|
||||||
|
<tr>
|
||||||
|
<td height=3D"36" style=3D"height:36px;padding:0;margin:0;line-height:1px;f=
|
||||||
|
ont-size:1px;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left;" class=3D"body-text" style=3D"padding:0;margin:0;line-he=
|
||||||
|
ight:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helve=
|
||||||
|
tica, Arial, sans-serif;font-size:16px;line-height:20px;font-weight:400;col=
|
||||||
|
or:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:anti=
|
||||||
|
aliased;"> <strong>Getting a lot of password reset emails?</strong> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td height=3D"12" style=3D"padding:0;margin:0;line-height:1px;font-size:1px=
|
||||||
|
;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"left;" class=3D"body-text" style=3D"padding:0;margin:0;line-he=
|
||||||
|
ight:1px;font-size:1px;font-family:'HelveticaNeue', 'Helvetica Neue', Helve=
|
||||||
|
tica, Arial, sans-serif;font-size:16px;line-height:20px;font-weight:400;col=
|
||||||
|
or:#292F33;text-align:left;text-decoration:none;-webkit-font-smoothing:anti=
|
||||||
|
aliased;"> You can change your <a href=3D"https://twitter.com/i/redirect?ur=
|
||||||
|
l=3Dhttps%3A%2F%2Ftwitter.com%2Fsettings%2Fsecurity&t=3D1&cn=3DcGFz=
|
||||||
|
c3dvcmRfcmVzZXRfcGluX2Jhc2VkX2VtYWls&sig=3D4f2138a21ba47b29174181b08569=
|
||||||
|
71ac67b6f7f0&iid=3De108b1a8a8ec4d3283067b55a00912b9&uid=3D162445777=
|
||||||
|
5894986754&nid=3D296+3" style=3D"text-decoration:none;border-style:none=
|
||||||
|
;border:0;padding:0;margin:0;border:none;text-decoration:none;font-weight:4=
|
||||||
|
00;color:#1DA1F2;">account settings</a> to require personal information to =
|
||||||
|
reset your password. </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td height=3D"36" style=3D"padding:0;margin:0;line-height:1px;font-size:1px=
|
||||||
|
;"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table> </td>
|
||||||
|
<td width=3D"24" class=3D"margin" style=3D"padding:0;margin:0;line-height:1=
|
||||||
|
px;font-size:1px;"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<!--/////////////////// end body///////////////////////////-->
|
||||||
|
<!--///////////////////// footer /////////////////////-->
|
||||||
|
<table class=3D"collapse" id=3D"footer" align=3D"center" width=3D"448" styl=
|
||||||
|
e=3D"width:448px; background-color:#ffffff;padding:0;margin:0;line-height:1=
|
||||||
|
px;font-size:1px;" cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td height=3D"36" style=3D"height:36px;padding:0;margin:0;line-height:1px;f=
|
||||||
|
ont-size:1px;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:=
|
||||||
|
1px;"> <span class=3D"small-copy" style=3D"font-family:'HelveticaNeue', 'He=
|
||||||
|
lvetica Neue', Helvetica, Arial, sans-serif;font-size:12px;line-height:16px=
|
||||||
|
;font-weight:400;color:#8899A6;text-align:left;text-decoration:none;-webkit=
|
||||||
|
-font-smoothing:antialiased;"> <a href=3D"https://support.twitter.com/artic=
|
||||||
|
les/14663" class=3D"small-copy" style=3D"text-decoration:none;border-style:=
|
||||||
|
none;border:0;padding:0;margin:0;font-family:'HelveticaNeue', 'Helvetica Ne=
|
||||||
|
ue', Helvetica, Arial, sans-serif;font-size:12px;line-height:16px;font-weig=
|
||||||
|
ht:400;color:#8899A6;text-align:left;text-decoration:none;-webkit-font-smoo=
|
||||||
|
thing:antialiased;font-family:'HelveticaNeue', 'Helvetica Neue', Helvetica,=
|
||||||
|
Arial, sans-serif;font-size:12px;line-height:16px;font-weight:600;color:#1=
|
||||||
|
DA1F2;text-align:left;text-decoration:none;-webkit-font-smoothing:antialias=
|
||||||
|
ed;">Help</a> | <a href=3D"https://twitter.com/account/not_my_a=
|
||||||
|
ccount/1624457775894986754/8D785-ED35A-167613?ut=3D1&cn=3DcGFzc3dvcmRfc=
|
||||||
|
mVzZXRfcGluX2Jhc2VkX2VtYWls" class=3D"small-copy" style=3D"text-decoration:=
|
||||||
|
none;border-style:none;border:0;padding:0;margin:0;font-family:'HelveticaNe=
|
||||||
|
ue', 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:12px;line-hei=
|
||||||
|
ght:16px;font-weight:400;color:#8899A6;text-align:left;text-decoration:none=
|
||||||
|
;-webkit-font-smoothing:antialiased;font-family:'HelveticaNeue', 'Helvetica=
|
||||||
|
Neue', Helvetica, Arial, sans-serif;font-size:12px;line-height:16px;font-w=
|
||||||
|
eight:600;color:#1DA1F2;text-align:left;text-decoration:none;-webkit-font-s=
|
||||||
|
moothing:antialiased;">Not my account</a> | <a href=3D"https://=
|
||||||
|
twitter.com/i/redirect?url=3Dhttps%3A%2F%2Fsupport.twitter.com%2Farticles%2=
|
||||||
|
F204820-fake-twitter-emails&t=3D1&cn=3DcGFzc3dvcmRfcmVzZXRfcGluX2Jh=
|
||||||
|
c2VkX2VtYWls&sig=3D53906e913dd2fe024d96561261d0eed884844e3e&iid=3De=
|
||||||
|
108b1a8a8ec4d3283067b55a00912b9&uid=3D1624457775894986754&nid=3D296=
|
||||||
|
+6" class=3D"small-copy" style=3D"text-decoration:none;border-style:none;bo=
|
||||||
|
rder:0;padding:0;margin:0;font-family:'HelveticaNeue', 'Helvetica Neue', He=
|
||||||
|
lvetica, Arial, sans-serif;font-size:12px;line-height:16px;font-weight:400;=
|
||||||
|
color:#8899A6;text-align:left;text-decoration:none;-webkit-font-smoothing:a=
|
||||||
|
ntialiased;font-family:'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial,=
|
||||||
|
sans-serif;font-size:12px;line-height:16px;font-weight:600;color:#1DA1F2;t=
|
||||||
|
ext-align:left;text-decoration:none;-webkit-font-smoothing:antialiased;">Em=
|
||||||
|
ail security tips</a> </span> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td height=3D"12" style=3D"height:12px;line-height:1px;font-size:1px;paddin=
|
||||||
|
g:0;margin:0;line-height:1px;font-size:1px;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:=
|
||||||
|
1px;"> <span class=3D"small-copy" style=3D"font-family:'HelveticaNeue', 'He=
|
||||||
|
lvetica Neue', Helvetica, Arial, sans-serif;font-size:12px;line-height:16px=
|
||||||
|
;font-weight:400;color:#8899A6;text-align:left;text-decoration:none;-webkit=
|
||||||
|
-font-smoothing:antialiased;"> This email was meant for @zktestemail </span=
|
||||||
|
> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td height=3D"6" style=3D"height:6px;line-height:1px;font-size:1px;padding:=
|
||||||
|
0;margin:0;line-height:1px;font-size:1px;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align=3D"center" style=3D"padding:0;margin:0;line-height:1px;font-size:=
|
||||||
|
1px;"> <span class=3D"address"> <a href=3D"#" style=3D"text-decoration:none=
|
||||||
|
;border-style:none;border:0;padding:0;margin:0;font-family:'HelveticaNeue',=
|
||||||
|
'Helvetica Neue', Helvetica, Arial, sans-serif;-webkit-font-smoothing:anti=
|
||||||
|
aliased;color:#8899A6;font-size:12px;padding:0px;margin:0px;font-weight:nor=
|
||||||
|
mal;line-height:12px;cursor:default;">Twitter, Inc. 1355 Market Street, Sui=
|
||||||
|
te 900 San Francisco, CA 94103</a> </span> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td height=3D"72" style=3D"height:72px;padding:0;margin:0;line-height:1px;f=
|
||||||
|
ont-size:1px;"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<!--///////////////////// end footer /////////////////////--> </td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
------=_Part_327915209_1341522477.1676136133617--
|
||||||
19
package.json
19
package.json
@@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "double-blind",
|
"name": "zk-email",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@openzeppelin/contracts": "^4.8.3",
|
|
||||||
"@rainbow-me/rainbowkit": "^0.8.0",
|
"@rainbow-me/rainbowkit": "^0.8.0",
|
||||||
"@testing-library/jest-dom": "^5.16.3",
|
"@testing-library/jest-dom": "^5.16.3",
|
||||||
"@testing-library/react": "^12.1.4",
|
"@testing-library/react": "^12.1.4",
|
||||||
@@ -17,6 +16,8 @@
|
|||||||
"atob": "^2.1.2",
|
"atob": "^2.1.2",
|
||||||
"base64-sol": "^1.1.0",
|
"base64-sol": "^1.1.0",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
|
"chai": "^4.3.7",
|
||||||
|
"circom_tester": "^0.0.19",
|
||||||
"circomlibjs": "^0.1.2",
|
"circomlibjs": "^0.1.2",
|
||||||
"cryo": "^0.0.6",
|
"cryo": "^0.0.6",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
"libmime": "^5.1.0",
|
"libmime": "^5.1.0",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
"mocha": "^10.2.0",
|
||||||
"next": "^12.3.1",
|
"next": "^12.3.1",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
"pako": "^2.1.0",
|
"pako": "^2.1.0",
|
||||||
@@ -42,7 +44,7 @@
|
|||||||
"react-use": "^17.3.2",
|
"react-use": "^17.3.2",
|
||||||
"readline": "^1.3.0",
|
"readline": "^1.3.0",
|
||||||
"serve": "^14.0.1",
|
"serve": "^14.0.1",
|
||||||
"snarkjs": "https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e",
|
"snarkjs": "latest",
|
||||||
"sshpk": "^1.17.0",
|
"sshpk": "^1.17.0",
|
||||||
"styled-components": "^5.3.5",
|
"styled-components": "^5.3.5",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
@@ -64,10 +66,11 @@
|
|||||||
"serve": "vite preview",
|
"serve": "vite preview",
|
||||||
"test": "jest --runInBand --testPathIgnorePatterns='e2e' --reporters=default --reporters=jest-junit",
|
"test": "jest --runInBand --testPathIgnorePatterns='e2e' --reporters=default --reporters=jest-junit",
|
||||||
"start-e2e-test-server": "serve -s dist -p 3000",
|
"start-e2e-test-server": "serve -s dist -p 3000",
|
||||||
"test:e2e-ui": "CI=true jest ./e2e-ui*.test.*",
|
"test:e2e-ui": "CI=true jest ./src/e2e-ui*.test.*",
|
||||||
"test:e2e-zkp": "CI=true jest ./e2e-dl-zkp.test.ts",
|
"test:e2e-zkp": "CI=true jest ./src/e2e-dl-zkp.test.ts",
|
||||||
|
"jest": "jest",
|
||||||
"compile": "node circuits/scripts/compile.js",
|
"compile": "node circuits/scripts/compile.js",
|
||||||
"gen-input": "npx tsx ./scripts/generate_input.ts",
|
"gen-input": "npx tsx ./src/scripts/generate_input.ts",
|
||||||
"compile-all": "yarn gen-input && yarn compile email true",
|
"compile-all": "yarn gen-input && yarn compile email true",
|
||||||
"prepare": "husky install"
|
"prepare": "husky install"
|
||||||
},
|
},
|
||||||
@@ -97,8 +100,10 @@
|
|||||||
"@babel/preset-typescript": "^7.21.5",
|
"@babel/preset-typescript": "^7.21.5",
|
||||||
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
||||||
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
|
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
|
||||||
|
"@openzeppelin/contracts": "^4.9.0",
|
||||||
"@types/atob": "^2.1.2",
|
"@types/atob": "^2.1.2",
|
||||||
"@types/jest": "^29.4.0",
|
"@types/jest": "^29.5.1",
|
||||||
|
"@types/mocha": "^10.0.1",
|
||||||
"@types/node": "^18.0.6",
|
"@types/node": "^18.0.6",
|
||||||
"@types/node-forge": "^1.3.2",
|
"@types/node-forge": "^1.3.2",
|
||||||
"@types/tar-stream": "^2.2.2",
|
"@types/tar-stream": "^2.2.2",
|
||||||
|
|||||||
@@ -1,14 +1,24 @@
|
|||||||
# ZK Regex
|
# ZK Regex
|
||||||
|
|
||||||
This code generates a circom regex file with Python and JS, but doesn't support all regex syntax.
|
This code generates a circom regex file with Python and JS, but doesn't support all regex syntax. You have to edit the test_regex function in regex_to_dfa.js to change what is generated.
|
||||||
|
|
||||||
Note that there is a full JS version of this code with tests at https://github.com/zk-email-verify/zk-regex/ , which also now supports some additional character classes. Once it reaches parity, we expect to update this repo to use that library instead.
|
Note that there is a buggy JS version of this code with tests and a command line tool at https://github.com/zk-email-verify/zk-regex/, which also now supports some additional character classes. Once it reaches parity, we expect to update this repo to use that library instead of gen.py.
|
||||||
|
|
||||||
Edit the regex on the top of lexical.js to change which regex is generated, then run `python3 gen.py`.
|
Edit the regex on the top of lexical.js to change which regex is generated, then run `python3 gen.py`.
|
||||||
|
|
||||||
## Halo2
|
## Circom Instructions
|
||||||
|
|
||||||
You can use the compiled halo2_regex_lookup.txt file as input to the https://github.com/zk-email-verify/halo2-regex/ library, which will generate a regex circuit in halo2 instead. That circuit is much more efficient than this one for large inputs.
|
First, generate a regex. Go to our [min_dfa fork](zkregex.com/min_dfa) of cyberzhg's toolbox and insert your regex on the top line. We've forked [min-dfa into a UI here](zkregex.com/min_dfa) to create a UI that converts existing regexes with [] support, as well as escapes \_, and the character classes a-z, A-Z, and 0-9. It also shows the DFA states very clearly so you can choose accept states easily. This should make converting regexes into DFA form way cleaner.
|
||||||
|
|
||||||
|
In the function `test_regex()` in `regex_to_dfa.js`, modify either `let raw_regex = ` (that supports some regex strings like `[A-Za-z0-9]` [but no other character ranges]) or modify `let regex = regexToMinDFASpec(<raw regex>)` (that does not support generic brackets or character ranges, only the limited syntax in https://zkregex.com/min_dfa) in `regex_to_circom/regex_to_dfa.js`. The top line of min_dfa tool corresponds to the "raw_regex", and the second line corresponds to the expanded "regex".
|
||||||
|
|
||||||
|
Then run `npx tsx regex_to_dfa.js` to make sure that it compiles and `tsx` is installed, and then remove all `console.log` statements except for the last line, and finally run `python3 gen.py`.
|
||||||
|
|
||||||
|
This will output a circom body. Wrap it the same way for instance circuits/regexes/from_regex.circom is written. Note that states in the zkregex [min_dfa visualizer](zkregex.com/min_dfa) are now 0 indexed (previous to Apr 2023 you had to subtract 1 from the indexes that showed up to match the circom, now it is the same).
|
||||||
|
|
||||||
|
Note that if your regex uses `^` at the start to mean sentinel starting character, you have to edit the resulting regex.circom file to manually change `94` (ascii code of ^) to `128` (manually inserted sentinel character meaning start, you'll see it defined as the 0th character of the string).
|
||||||
|
|
||||||
|
We will soon have a website [WIP](https://frontend-zk-regex.vercel.app/) that automatically does this. If you'd like to make this process simpler, cleaner, and less hacky, we'd recommend making a PR here or to the zk-regex library (which is a bit out of date regex-string wise and match group-wise).
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
@@ -16,9 +26,15 @@ states[i+1][j] means that there was a character at msg[i] which led to the trans
|
|||||||
|
|
||||||
This means that reveal for index i should be looking at state of index i+1.
|
This means that reveal for index i should be looking at state of index i+1.
|
||||||
|
|
||||||
|
Note that ^ has to be manually replaced with \x80 in the circom regex.
|
||||||
|
|
||||||
|
## Halo2
|
||||||
|
|
||||||
|
You can use the compiled halo2_regex_lookup.txt file as input to the https://github.com/zk-email-verify/halo2-regex/ library, which will generate a regex circuit in halo2 instead. That circuit is more efficient than this one for large inputs for use for fast clientside proofs that require privacy.
|
||||||
|
|
||||||
## Some regexes
|
## Some regexes
|
||||||
|
|
||||||
There are more in the regex section of the top level readme. Here are som examples however, for instance for from/subject/to order-free extraction:
|
There are more in the regex section of the top level zk-email-verify README. Here are some examples however, for instance for from/subject/to order-free extraction:
|
||||||
|
|
||||||
raw regex: ((\\n|\x80|^)(((from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?|(subject:[a-zA-Z 0-9]+)?|((to):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?)(\\r))+
|
raw regex: ((\\n|\x80|^)(((from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?|(subject:[a-zA-Z 0-9]+)?|((to):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?)(\\r))+
|
||||||
min-dfa version: (((\n|^)(((from):([A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9| |_|.|"|@|-]+<)?[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.|-]+@[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.]+>)?|(subject:[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z| |0|1|2|3|4|5|6|7|8|9]+)?|((to):([A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9| |_|.|"|@|-]+<)?[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.|-]+@[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.]+>)?)(\r))+)
|
min-dfa version: (((\n|^)(((from):([A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9| |_|.|"|@|-]+<)?[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.|-]+@[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.]+>)?|(subject:[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z| |0|1|2|3|4|5|6|7|8|9]+)?|((to):([A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9| |_|.|"|@|-]+<)?[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.|-]+@[a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|_|.]+>)?)(\r))+)
|
||||||
|
|||||||
@@ -139,8 +139,10 @@ function parseRegex(text) {
|
|||||||
let new_text = [];
|
let new_text = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < text.length) {
|
while (i < text.length) {
|
||||||
if (text[i] == "\\") {
|
if (text[i] === "\\") {
|
||||||
new_text.push([text[i + 1]]);
|
const escapeMap = { n: "\n", r: "\r", t: "\t", v: "\v", f: "\f", "^": String.fromCharCode(128) };
|
||||||
|
const char = text[i + 1];
|
||||||
|
new_text.push([escapeMap[char] || char]);
|
||||||
i += 2;
|
i += 2;
|
||||||
} else {
|
} else {
|
||||||
new_text.push(text[i]);
|
new_text.push(text[i]);
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
/*jslint browser: true*/
|
/*jslint browser: true*/
|
||||||
/*global require, exports*/
|
/*global require, exports*/
|
||||||
import { assert } from "console";
|
|
||||||
import { STRING_PRESELECTOR } from "../src/helpers/constants.ts";
|
import { STRING_PRESELECTOR } from "../src/helpers/constants.ts";
|
||||||
import { minDfa, nfaToDfa, regexToNfa } from "./lexical";
|
import { minDfa, nfaToDfa, regexToNfa } from "./lexical";
|
||||||
|
|
||||||
/** This section sets the 'regex' variable to the regex you want to use.
|
/** This section defines helper regex components -- to edit the regex used, edit the return
|
||||||
|
* of the test_regex function.
|
||||||
* All of the relevant regexes are in the main repo README.
|
* All of the relevant regexes are in the main repo README.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Helper components
|
||||||
const a2z = "a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z";
|
const a2z = "a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z";
|
||||||
const A2Z = "A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z";
|
const A2Z = "A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z";
|
||||||
const r0to9 = "0|1|2|3|4|5|6|7|8|9";
|
const r0to9 = "0|1|2|3|4|5|6|7|8|9";
|
||||||
@@ -23,18 +24,78 @@ const email_chars = `${alphanum}|_|.|-`;
|
|||||||
const base_64 = `(${alphanum}|\\+|/|=)`;
|
const base_64 = `(${alphanum}|\\+|/|=)`;
|
||||||
const word_char = `(${alphanum}|_)`;
|
const word_char = `(${alphanum}|_)`;
|
||||||
|
|
||||||
// let to_from_regex_old = '(\r\n|\x80)(to|from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>?\r\n';
|
|
||||||
// let regex = `\r\ndkim-signature:(${key_chars}=${catch_all_without_semicolon}+; )+bh=${base_64}+; `;
|
|
||||||
// let order_invariant_regex_raw = `((\\n|\x80|^)(((from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?|(subject:[a-zA-Z 0-9]+)?|((to):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?|(dkim-signature:((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|/|:|<|=|>|\\?|@|[|\\\\|]|^|_|`|{|\\||}|~| |\t|\n|\r|\x0B|\f)+; ))?)(\\r))+` // Uses a-z syntax instead of | for each char
|
|
||||||
|
|
||||||
const a2z_nosep = "abcdefghijklmnopqrstuvwxyz";
|
const a2z_nosep = "abcdefghijklmnopqrstuvwxyz";
|
||||||
const A2Z_nosep = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
const A2Z_nosep = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
const a2f_nosep = "abcdef";
|
||||||
|
const A2F_nosep = "ABCDEF";
|
||||||
const r0to9_nosep = "0123456789";
|
const r0to9_nosep = "0123456789";
|
||||||
|
|
||||||
// Note that in order to specify this string in regex, we must use \\ to escape \'s i.e. in the \r\n
|
// TODO: Note that this is replicated code in lexical.js as well
|
||||||
let order_invariant_header_regex_raw = `(((\\n|^)(((from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?|(subject:[a-zA-Z 0-9]+)?|((to):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?)(\\r))+)\\n`;
|
// Note that ^ has to be manually replaced with \x80 in the regex
|
||||||
let sig_regex = `\r\ndkim-signature:(${key_chars}=${catch_all_without_semicolon}+; )+bh=${base_64}+; `;
|
const escapeMap = { n: "\n", r: "\r", t: "\t", v: "\v", f: "\f" };
|
||||||
|
let whitespace = Object.values(escapeMap);
|
||||||
|
const slash_s = whitespace.join("|");
|
||||||
|
|
||||||
|
// The test_regex function whose return needs to be edited
|
||||||
|
// Note that in order to specify some strings in regex, we must use \\ to escape \'s.
|
||||||
|
// For instance, matching the literal + is represented as \\+.
|
||||||
|
// However, matching the literal \r (ascii 60) character is still \r
|
||||||
|
// Matching \ then an r as two characters would be \\r in the js string literal
|
||||||
|
function test_regex() {
|
||||||
|
// let to_from_regex_old = '(\r\n|\x80)(to|from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>?\r\n';
|
||||||
|
// let regex = `\r\ndkim-signature:(${key_chars}=${catch_all_without_semicolon}+; )+bh=${base_64}+; `;
|
||||||
|
// let order_invariant_regex_raw = `((\\n|\x80|^)(((from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?|(subject:[a-zA-Z 0-9]+)?|((to):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?|(dkim-signature:((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|/|:|<|=|>|\\?|@|[|\\\\|]|^|_|`|{|\\||}|~| |\t|\n|\r|\x0B|\f)+; ))?)(\\r))+` // Uses a-z syntax instead of | for each char
|
||||||
|
let email_address_regex = `([a-zA-Z0-9._%\\+-=]+@[a-zA-Z0-9.-]+)`;
|
||||||
|
|
||||||
|
// ------- HEADER/SIGNATURE REGEX --------
|
||||||
|
let order_invariant_header_regex_raw = `(((\\n|^)(((from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?|(subject:[a-zA-Z 0-9]+)?|((to):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?)(\\r))+)\\n`;
|
||||||
|
let sig_regex = `\r\ndkim-signature:(${key_chars}=${catch_all_without_semicolon}+; )+bh=${base_64}+; `;
|
||||||
|
|
||||||
|
// let full_header_regex = order_invariant_header_regex_raw + sig_regex;
|
||||||
|
// let raw_regex = order_invariant_header_regex_raw;
|
||||||
|
// let regex = regexToMinDFASpec(raw_regex) + sig_regex;
|
||||||
|
// console.log(format_regex_printable(sig_regex));
|
||||||
|
|
||||||
|
// -------- SUBJECT REGEXES --------
|
||||||
|
// This raw subject line (with \\ replaced with \) can be put into regexr.com to test new match strings and sanity check that it works
|
||||||
|
// TODO: Other valid chars in email addresses: #$%!^/&*, outlined at https://ladedu.com/valid-characters-for-email-addresses-the-complete-list/ and in the RFC
|
||||||
|
|
||||||
|
// -- SEND SPECIFIC REGEXES --
|
||||||
|
// let send_specific_raw_subject_regex = `((\r\n)|^)subject:[Ss]end (\$)?[0-9]+(.[0-9]+)? [a-zA-Z]+ to (${email_address_regex}|0x[0-9a-fA_F]+)\r\n`;
|
||||||
|
// let raw_subject_regex = `((\r\n)|^)subject:[a-zA-Z]+ (\\$)?[0-9]+(.[0-9]+)? [a-zA-Z]+ to (([a-zA-Z0-9._%\\+-=]+@[a-zA-Z0-9.-]+)|0x[0-9]+)\r\n`;
|
||||||
|
// Input: ((\\r\\n)|^)subject:[Ss]end (\$)?[0-9]+(.[0-9]+)? [a-zA-Z]+ to (([a-zA-Z0-9._%\+-=]+@[a-zA-Z0-9.-]+)|0x[0-9]+)\\r\\n
|
||||||
|
// This can be pasted into the first line of https://zkregex.com/min_dfa (after replacing \\ -> \)
|
||||||
|
// ((\\r\\n)|\^)subject:[Ss]end (\$)?[0-9]+(\.[0-9])? (ETH|DAI|USDC|eth|usdc|dai) to (([a-zA-Z0-9\._%\+-]+@[a-zA-Z0-9\.-]+.[a-zA-Z0-9]+)|0x[0-9]+)\\r\\n
|
||||||
|
// console.log(raw_subject_regex);
|
||||||
|
|
||||||
|
// -- GENERIC SUBJECT COMMANDS --
|
||||||
|
let raw_subject_regex = `((\r\n)|^)subject:[a-zA-Z]+ (\\$)?[0-9]+(.[0-9]+)? [a-zA-Z]+ to (${email_address_regex}|0x[0-9a-fA_F]+)\r\n`;
|
||||||
|
|
||||||
|
// -------- OTHER FIELD REGEXES --------
|
||||||
|
let raw_from_regex = `(\r\n|^)from:([A-Za-z0-9 _.,"@-]+)<[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+>\r\n`;
|
||||||
|
// let message_id_regex = `(\r\n|^)message-id:<[=@.\\+_-a-zA-Z0-9]+>\r\n`;
|
||||||
|
|
||||||
|
// -------- TWITTER BODY REGEX ---------
|
||||||
|
// let regex = STRING_PRESELECTOR + `${word_char}+`;
|
||||||
|
|
||||||
|
// ---------- DEPRECATAED REGEXES ----------
|
||||||
|
// let order_invariant_header_regex_raw = `(((\\n|^)(((from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?|(subject:[a-zA-Z 0-9]+)?|((to):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?)(\\r))+)`;
|
||||||
|
// let order_invariant_full_regex_raw = `(dkim-signature:((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|/|:|<|=|>|\\?|@|[|\\\\|]|^|_|\`|{|\\||}|~| |\t|\n|\r|\x0B|\f)+; ))?)(\\r))+` // Uses a-z syntax instead of | for each char
|
||||||
|
// let old_regex = '(\r\n|\x80)(to|from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>?\r\n';
|
||||||
|
// let regex = `(\n|^)(to|from):((${email_chars}|"|@| )+<)?(${email_chars})+@(${email_chars})+>?\r`;
|
||||||
|
// let regex = `(\r\n|^)(to|from):((${email_chars}|"|@| )+<)?(${email_chars})+@(${email_chars})+>?\r\n`;
|
||||||
|
// 'dkim-signature:((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|/|:|<|=|>|\\?|@|[|\\\\|]|^|_|`|{|\\||}|~| |\t|\n|\r|\x0B|\f)+; )+bh=(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\+|/|=)+; '
|
||||||
|
// let regex = 'hello(0|1|2|3|4|5|6|7|8|9)+world';
|
||||||
|
|
||||||
|
// --------- FINAL CONVERSION ---------
|
||||||
|
// console.log(format_regex_printable(raw_subject_regex));
|
||||||
|
let regex = regexToMinDFASpec(raw_subject_regex);
|
||||||
|
// console.log(format_regex_printable(regex));
|
||||||
|
|
||||||
|
return regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escapes and prints regexes (might be buggy)
|
||||||
function format_regex_printable(s) {
|
function format_regex_printable(s) {
|
||||||
const escaped_string_json = JSON.stringify(s);
|
const escaped_string_json = JSON.stringify(s);
|
||||||
const escaped_string = escaped_string_json.slice(1, escaped_string_json.length - 1);
|
const escaped_string = escaped_string_json.slice(1, escaped_string_json.length - 1);
|
||||||
@@ -53,10 +114,22 @@ function format_regex_printable(s) {
|
|||||||
// let fixed = escaped.replaceAll("\\(", "(").replaceAll("\\)", ")").replaceAll("\\+", "+").replaceAll("\\*", "*").replaceAll("\\?", "?");
|
// let fixed = escaped.replaceAll("\\(", "(").replaceAll("\\)", ")").replaceAll("\\+", "+").replaceAll("\\*", "*").replaceAll("\\?", "?");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that this is not complete and very case specific i.e. can only handle a-z and not a-c.
|
// Note that this is not complete and very case specific i.e. can only handle a-z and a-f, and not a-c.
|
||||||
|
// This function expands [] sections to convert values for https://zkregex.com/min_dfa
|
||||||
|
// The input is a regex with [] and special characters (i.e. the first line of min_dfa tool)
|
||||||
|
// The output is expanded regexes without any special characters
|
||||||
function regexToMinDFASpec(str) {
|
function regexToMinDFASpec(str) {
|
||||||
// Replace all A-Z with A2Z etc
|
// Replace all A-Z with A2Z etc
|
||||||
let combined_nosep = str.replaceAll("A-Z", A2Z_nosep).replaceAll("a-z", a2z_nosep).replaceAll("0-9", r0to9_nosep);
|
// TODO: Upstream this to min_dfa
|
||||||
|
let combined_nosep = str
|
||||||
|
.replaceAll("A-Z", A2Z_nosep)
|
||||||
|
.replaceAll("a-z", a2z_nosep)
|
||||||
|
.replaceAll("A-F", A2F_nosep)
|
||||||
|
.replaceAll("a-f", a2f_nosep)
|
||||||
|
.replaceAll("0-9", r0to9_nosep)
|
||||||
|
.replaceAll("\\w", A2Z_nosep + r0to9_nosep + a2z_nosep + "_")
|
||||||
|
.replaceAll("\\d", r0to9_nosep)
|
||||||
|
.replaceAll("\\s", slash_s);
|
||||||
// .replaceAll("\\w", A2Z_nosep + r0to9_nosep + a2z_nosep); // I think that there's also an underscore here
|
// .replaceAll("\\w", A2Z_nosep + r0to9_nosep + a2z_nosep); // I think that there's also an underscore here
|
||||||
|
|
||||||
function addPipeInsideBrackets(str) {
|
function addPipeInsideBrackets(str) {
|
||||||
@@ -99,6 +172,7 @@ function regexToMinDFASpec(str) {
|
|||||||
function checkIfBracketsHavePipes(str) {
|
function checkIfBracketsHavePipes(str) {
|
||||||
let result = true;
|
let result = true;
|
||||||
let insideBrackets = false;
|
let insideBrackets = false;
|
||||||
|
let insideParens = 0;
|
||||||
let indexAt = 0;
|
let indexAt = 0;
|
||||||
for (let i = 0; i < str.length; i++) {
|
for (let i = 0; i < str.length; i++) {
|
||||||
if (indexAt >= str.length) break;
|
if (indexAt >= str.length) break;
|
||||||
@@ -109,6 +183,11 @@ function regexToMinDFASpec(str) {
|
|||||||
} else if (str[indexAt] === "]") {
|
} else if (str[indexAt] === "]") {
|
||||||
insideBrackets = false;
|
insideBrackets = false;
|
||||||
}
|
}
|
||||||
|
if (str[indexAt] === "(") {
|
||||||
|
insideParens++;
|
||||||
|
} else if (str[indexAt] === ")") {
|
||||||
|
insideParens--;
|
||||||
|
}
|
||||||
if (insideBrackets) {
|
if (insideBrackets) {
|
||||||
if (str[indexAt] === "|") {
|
if (str[indexAt] === "|") {
|
||||||
indexAt++;
|
indexAt++;
|
||||||
@@ -117,6 +196,9 @@ function regexToMinDFASpec(str) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!insideParens && str[indexAt] === "|") {
|
||||||
|
console.log("Error: | outside of parens!");
|
||||||
|
}
|
||||||
if (str[indexAt] === "\\") {
|
if (str[indexAt] === "\\") {
|
||||||
indexAt++;
|
indexAt++;
|
||||||
}
|
}
|
||||||
@@ -129,7 +211,9 @@ function regexToMinDFASpec(str) {
|
|||||||
if (!checkIfBracketsHavePipes(combined_nosep)) {
|
if (!checkIfBracketsHavePipes(combined_nosep)) {
|
||||||
// console.log("Adding pipes within brackets between everything!");
|
// console.log("Adding pipes within brackets between everything!");
|
||||||
combined = addPipeInsideBrackets(combined_nosep);
|
combined = addPipeInsideBrackets(combined_nosep);
|
||||||
assert(checkIfBracketsHavePipes(combined), "Did not add brackets correctly!");
|
if (!checkIfBracketsHavePipes(combined)) {
|
||||||
|
console.log("Did not add brackets correctly!");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
combined = combined_nosep;
|
combined = combined_nosep;
|
||||||
}
|
}
|
||||||
@@ -137,79 +221,6 @@ function regexToMinDFASpec(str) {
|
|||||||
return combined;
|
return combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// let full_header_regex = order_invariant_header_regex_raw + sig_regex;
|
|
||||||
// let raw_regex = order_invariant_header_regex_raw;
|
|
||||||
// let regex = regexToMinDFASpec(raw_regex) + sig_regex;
|
|
||||||
// console.log(format_regex_printable(sig_regex));
|
|
||||||
|
|
||||||
// This raw subject line (with \\ replaced with \) can be put into regexr.com to test new match strings and sanity check that it works
|
|
||||||
let email_address_regex = `([a-zA-Z0-9\\._%\\+-]+@[a-zA-Z0-9\\.-]+.[a-zA-Z0-9]+)`;
|
|
||||||
let raw_subject_regex = `((\r\n)|\^)subject:[Ss]end (\\$)?[0-9]+(\\.[0-9])? (ETH|DAI|USDC|eth|usdc|dai) to (${email_address_regex}|0x[0-9]+)\r\n`;
|
|
||||||
let raw_from_regex = `(\r\n|^)from:([A-Za-z0-9 _.,"@-]+)<[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+>\r\n`;
|
|
||||||
// This can be pasted into the first line of zkregex.com/min_dfa
|
|
||||||
// ((\\r\\n)|\^)subject:[Ss]end (\$)?[0-9]+(\.[0-9])? (ETH|DAI|USDC|eth|usdc|dai) to (([a-zA-Z0-9\._%\+-]+@[a-zA-Z0-9\.-]+.[a-zA-Z0-9]+)|0x[0-9]+)\\r\\n
|
|
||||||
// console.log(raw_subject_regex);
|
|
||||||
let regex = regexToMinDFASpec(raw_from_regex);
|
|
||||||
// This can be pasted into the second line of zkregex.com/min_dfa
|
|
||||||
// console.log(format_regex_printable(regex));
|
|
||||||
// TODO" change \^ into \0x80
|
|
||||||
|
|
||||||
/*
|
|
||||||
One indexed! Need to subtract 1 from the DFA state!
|
|
||||||
// Transition states--
|
|
||||||
// Amount:
|
|
||||||
53 2
|
|
||||||
54 2
|
|
||||||
2 2
|
|
||||||
2 4
|
|
||||||
4 11
|
|
||||||
// Currency:
|
|
||||||
3 5
|
|
||||||
5 13
|
|
||||||
13 19
|
|
||||||
3 6
|
|
||||||
6 14
|
|
||||||
14 19
|
|
||||||
3 7
|
|
||||||
7 15
|
|
||||||
15 20
|
|
||||||
20 19
|
|
||||||
3 8
|
|
||||||
8 16
|
|
||||||
16 19
|
|
||||||
3 9
|
|
||||||
9 17
|
|
||||||
17 19
|
|
||||||
3 10
|
|
||||||
10 18
|
|
||||||
18 21
|
|
||||||
21 19
|
|
||||||
// Dest states only
|
|
||||||
// Recipient:
|
|
||||||
28
|
|
||||||
34
|
|
||||||
38
|
|
||||||
39
|
|
||||||
26
|
|
||||||
32
|
|
||||||
35
|
|
||||||
40
|
|
||||||
44
|
|
||||||
*/
|
|
||||||
// console.log(raw_regex, "\n", regex);
|
|
||||||
// let order_invariant_header_regex_raw = `(((\\n|^)(((from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?|(subject:[a-zA-Z 0-9]+)?|((to):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>)?)(\\r))+)`;
|
|
||||||
// let order_invariant_full_regex_raw = `(dkim-signature:((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|/|:|<|=|>|\\?|@|[|\\\\|]|^|_|\`|{|\\||}|~| |\t|\n|\r|\x0B|\f)+; ))?)(\\r))+` // Uses a-z syntax instead of | for each char
|
|
||||||
// let old_regex = '(\r\n|\x80)(to|from):([A-Za-z0-9 _."@-]+<)?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.]+>?\r\n';
|
|
||||||
// let regex = `(\n|^)(to|from):((${email_chars}|"|@| )+<)?(${email_chars})+@(${email_chars})+>?\r`;
|
|
||||||
// let regex = `(\r\n|^)(to|from):((${email_chars}|"|@| )+<)?(${email_chars})+@(${email_chars})+>?\r\n`;
|
|
||||||
// let regex = `\r\ndkim-signature:(${key_chars}=${catch_all_without_semicolon}+; )+bh=${base_64}+; `;
|
|
||||||
// console.log(regex);
|
|
||||||
// 'dkim-signature:((a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)=(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|!|"|#|$|%|&|\'|\\(|\\)|\\*|\\+|,|-|.|/|:|<|=|>|\\?|@|[|\\\\|]|^|_|`|{|\\||}|~| |\t|\n|\r|\x0B|\f)+; )+bh=(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9|\\+|/|=)+; '
|
|
||||||
// let regex = STRING_PRESELECTOR + `${word_char}+`;
|
|
||||||
// let regex = 'hello(0|1|2|3|4|5|6|7|8|9)+world';
|
|
||||||
// console.log(regex);
|
|
||||||
// console.log(Buffer.from(regex).toString('base64'));
|
|
||||||
|
|
||||||
function toNature(col) {
|
function toNature(col) {
|
||||||
var i,
|
var i,
|
||||||
j,
|
j,
|
||||||
@@ -225,47 +236,58 @@ function toNature(col) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
let nfa = regexToNfa(regex);
|
function printGraphForRegex(regex) {
|
||||||
let dfa = minDfa(nfaToDfa(nfa));
|
let nfa = regexToNfa(regex);
|
||||||
|
let dfa = minDfa(nfaToDfa(nfa));
|
||||||
|
|
||||||
var i,
|
var i,
|
||||||
j,
|
j,
|
||||||
states = {},
|
states = {},
|
||||||
nodes = [],
|
nodes = [],
|
||||||
stack = [dfa],
|
stack = [dfa],
|
||||||
symbols = [],
|
symbols = [],
|
||||||
top;
|
top;
|
||||||
|
|
||||||
while (stack.length > 0) {
|
while (stack.length > 0) {
|
||||||
top = stack.pop();
|
top = stack.pop();
|
||||||
if (!states.hasOwnProperty(top.id)) {
|
if (!states.hasOwnProperty(top.id)) {
|
||||||
states[top.id] = top;
|
states[top.id] = top;
|
||||||
top.nature = toNature(top.id);
|
top.nature = toNature(top.id);
|
||||||
nodes.push(top);
|
nodes.push(top);
|
||||||
for (i = 0; i < top.edges.length; i += 1) {
|
for (i = 0; i < top.edges.length; i += 1) {
|
||||||
if (top.edges[i][0] !== "ϵ" && symbols.indexOf(top.edges[i][0]) < 0) {
|
if (top.edges[i][0] !== "ϵ" && symbols.indexOf(top.edges[i][0]) < 0) {
|
||||||
symbols.push(top.edges[i][0]);
|
symbols.push(top.edges[i][0]);
|
||||||
|
}
|
||||||
|
stack.push(top.edges[i][1]);
|
||||||
}
|
}
|
||||||
stack.push(top.edges[i][1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
nodes.sort(function (a, b) {
|
||||||
nodes.sort(function (a, b) {
|
return a.nature - b.nature;
|
||||||
return a.nature - b.nature;
|
});
|
||||||
});
|
symbols.sort();
|
||||||
symbols.sort();
|
|
||||||
|
|
||||||
let graph = [];
|
let graph = [];
|
||||||
for (let i = 0; i < nodes.length; i += 1) {
|
for (let i = 0; i < nodes.length; i += 1) {
|
||||||
let curr = {};
|
let curr = {};
|
||||||
curr.type = nodes[i].type;
|
curr.type = nodes[i].type;
|
||||||
curr.edges = {};
|
curr.edges = {};
|
||||||
for (let j = 0; j < symbols.length; j += 1) {
|
for (let j = 0; j < symbols.length; j += 1) {
|
||||||
if (nodes[i].trans.hasOwnProperty(symbols[j])) {
|
if (nodes[i].trans.hasOwnProperty(symbols[j])) {
|
||||||
curr.edges[symbols[j]] = nodes[i].trans[symbols[j]].nature - 1;
|
curr.edges[symbols[j]] = nodes[i].trans[symbols[j]].nature - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
graph[nodes[i].nature - 1] = curr;
|
||||||
}
|
}
|
||||||
graph[nodes[i].nature - 1] = curr;
|
|
||||||
|
console.log(JSON.stringify(graph));
|
||||||
|
return JSON.stringify(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(JSON.stringify(graph));
|
let regex = test_regex();
|
||||||
|
printGraphForRegex(regex);
|
||||||
|
|
||||||
|
if (typeof require === "function") {
|
||||||
|
exports.regexToMinDFASpec = regexToMinDFASpec;
|
||||||
|
exports.toNature = toNature;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
ALCHEMY_GOERLI_KEY=
|
ALCHEMY_GOERLI_KEY=
|
||||||
|
INFURA_KEY=
|
||||||
ETHERSCAN_API_KEY=
|
ETHERSCAN_API_KEY=
|
||||||
PRIVATE_KEY=
|
PRIVATE_KEY=
|
||||||
|
|
||||||
|
# Prod
|
||||||
|
# RPC_URL=https://eth-goerli.g.alchemy.com/v2/$ALCHEMY_GOERLI_KEY
|
||||||
|
RPC_URL=https://goerli.infura.io/v3/$INFURA_KEY
|
||||||
|
|
||||||
|
# Dev
|
||||||
|
# RPC_URL=http://localhost:8548
|
||||||
|
|||||||
@@ -11,41 +11,64 @@ To setup,
|
|||||||
```
|
```
|
||||||
curl -L https://foundry.paradigm.xyz | bash && source ~/.bashrc && foundryup
|
curl -L https://foundry.paradigm.xyz | bash && source ~/.bashrc && foundryup
|
||||||
forge install foundry-rs/forge-std
|
forge install foundry-rs/forge-std
|
||||||
cp node_modules/forge-std src/contracts/lib/forge-std
|
cp -r node_modules/@openzeppelin src/contracts/lib/@openzeppelin
|
||||||
cd src/contracts
|
cd src/contracts
|
||||||
|
|
||||||
|
forge install
|
||||||
|
forge install dapphub/ds-test --no-commit --no-git
|
||||||
```
|
```
|
||||||
|
|
||||||
To test,
|
To test your own contracts, copy TestTwitter.t.sol into a new test file, and make sure you can compile your proof fine. You can run a specific test with `forge test --match test_name`. Then make sure the whole suite passes and isn't above the size limit:
|
||||||
|
|
||||||
```
|
```
|
||||||
forge test
|
forge test --fork-url https://eth-goerli.g.alchemy.com/v2/$ALCHEMY_GOERLI_KEY
|
||||||
forge build --sizes # Make sure these are all below 24kB
|
forge build --sizes # Make sure these are all below 24kB
|
||||||
```
|
```
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
Goerli Address of Deployment: 0xA555F9E05402F8240AC99A0d045081E19C0eB9B3
|
Goerli Address of Anon Deployment: 0x5c5c7e908ed9904ac9e4f53c8195f95720b9f5c9
|
||||||
|
Goerli Address of Old Non-Anon Deployment: 0x026343f978d9f5600bf2e05992eb3fff06e4ea80
|
||||||
|
|
||||||
To deploy contract to local forked mainnet or prod, edit Deploy.s.sol to point to your contracts. You should also edit the `.env` file from cloning ` .env.example` to include your own private key.
|
To deploy contract to local forked mainnet or prod, edit Deploy.s.sol to point to your contracts. In `src/contracts`, you should also edit the `.env` file from cloning `.env.example` to include your own private key.
|
||||||
|
|
||||||
```
|
Run local chain in tmux window 1:
|
||||||
# Set terminal to the folder with this README
|
```bash
|
||||||
cd src/contracts
|
tmux
|
||||||
|
|
||||||
# Run local chain in tmux window 1
|
# Run local chain in tmux window 1
|
||||||
export ALCHEMY_GOERLI_KEY=...
|
anvil --fork-url https://eth-goerli.g.alchemy.com/v2/$ALCHEMY_GOERLI_KEY --port 8548
|
||||||
anvil --fork-url https://eth-goerli.g.alchemy.com/v2/$ALCHEMY_GOERLI_KEY --port 8548 # Run in tmux
|
```
|
||||||
|
|
||||||
|
Then deploy the contract to forked goerli:
|
||||||
|
```bash
|
||||||
|
# Set terminal to the folder with this README
|
||||||
|
cd src/contracts
|
||||||
|
source .env
|
||||||
|
export MAIN_CONTRACT_NAME=VerifiedTwitterEmail
|
||||||
|
export RPC_URL="http://127.0.0.1:8548"
|
||||||
|
|
||||||
# Export to abi for relayers
|
# Export to abi for relayers
|
||||||
forge inspect src/TwitterEmailHandler.sol:$MAIN_CONTRACT_NAME abi --via-ir >> contract.abi
|
forge inspect src/TwitterEmailHandler.sol:$MAIN_CONTRACT_NAME abi >> contract.abi
|
||||||
source .env
|
|
||||||
|
|
||||||
# First, test deploy without actually broadcasting it
|
# First, test deploy without actually broadcasting it
|
||||||
forge script script/Deploy.s.sol:Deploy --via-ir -vvvv --rpc-url $RPC_URL
|
forge script script/Deploy.s.sol:Deploy -vvvv --rpc-url $RPC_URL
|
||||||
|
|
||||||
# Then, actually deploy
|
# Then, actually deploy
|
||||||
forge script script/Deploy.s.sol:Deploy --via-ir -vvvv --rpc-url $RPC_URL --broadcast
|
forge script script/Deploy.s.sol:Deploy -vvvv --rpc-url $RPC_URL --broadcast --slow
|
||||||
|
|
||||||
# Verify the contract with the raw one via Etherscan
|
# Verify the contract with the raw one via Etherscan
|
||||||
forge verify-contract $EMAIL_ADDR $MAIN_CONTRACT_NAME --watch --etherscan-api-key $GOERLI_ETHERSCAN_API_KEY
|
forge verify-contract $EMAIL_ADDR $MAIN_CONTRACT_NAME --watch --etherscan-api-key $GOERLI_ETHERSCAN_API_KEY
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### What if I get an error about request failed and not all the contracts deploy?
|
||||||
|
|
||||||
|
Maybe fullnode is on [old geth](https://github.com/ethereum/go-ethereum/issues/26890) endpoint, like Alchemy is. Switch to infura or add `--slow` to deploy script:
|
||||||
|
|
||||||
|
```
|
||||||
|
forge script script/Deploy.s.sol:Deploy -vvvv --rpc-url $RPC_URL --broadcast --slow
|
||||||
|
```
|
||||||
|
|
||||||
|
### Versions
|
||||||
|
|
||||||
|
10a840db7305d9cdcd1fa56aee88ec77db86a562 is the last stable wallet version before breaking changes to add on-chain anonymity.
|
||||||
|
|||||||
@@ -2,5 +2,4 @@
|
|||||||
src = 'src'
|
src = 'src'
|
||||||
out = 'out'
|
out = 'out'
|
||||||
libs = ['lib'] # See more config options https://github.com/foundry-rs/foundry/tree/master/config
|
libs = ['lib'] # See more config options https://github.com/foundry-rs/foundry/tree/master/config
|
||||||
remappings = ['ds-test=lib/ds-test/', 'forge-std/=lib/forge-std/']
|
|
||||||
viaIR = true
|
viaIR = true
|
||||||
|
|||||||
@@ -1,656 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// This program 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.
|
|
||||||
|
|
||||||
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
pragma solidity >=0.5.0;
|
|
||||||
|
|
||||||
contract DSTest {
|
|
||||||
event log(string);
|
|
||||||
event logs(bytes);
|
|
||||||
|
|
||||||
event log_address(address);
|
|
||||||
event log_bytes32(bytes32);
|
|
||||||
event log_int(int256);
|
|
||||||
event log_uint(uint256);
|
|
||||||
event log_bytes(bytes);
|
|
||||||
event log_string(string);
|
|
||||||
|
|
||||||
event log_named_address(string key, address val);
|
|
||||||
event log_named_bytes32(string key, bytes32 val);
|
|
||||||
event log_named_decimal_int(string key, int256 val, uint256 decimals);
|
|
||||||
event log_named_decimal_uint(string key, uint256 val, uint256 decimals);
|
|
||||||
event log_named_int(string key, int256 val);
|
|
||||||
event log_named_uint(string key, uint256 val);
|
|
||||||
event log_named_bytes(string key, bytes val);
|
|
||||||
event log_named_string(string key, string val);
|
|
||||||
|
|
||||||
bool public IS_TEST = true;
|
|
||||||
bool private _failed;
|
|
||||||
|
|
||||||
address constant HEVM_ADDRESS = address(bytes20(uint160(uint256(keccak256("hevm cheat code")))));
|
|
||||||
|
|
||||||
modifier mayRevert() {
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
modifier testopts(string memory) {
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
|
|
||||||
function failed() public returns (bool) {
|
|
||||||
if (_failed) {
|
|
||||||
return _failed;
|
|
||||||
} else {
|
|
||||||
bool globalFailed = false;
|
|
||||||
if (hasHEVMContext()) {
|
|
||||||
(, bytes memory retdata) = HEVM_ADDRESS.call(abi.encodePacked(bytes4(keccak256("load(address,bytes32)")), abi.encode(HEVM_ADDRESS, bytes32("failed"))));
|
|
||||||
globalFailed = abi.decode(retdata, (bool));
|
|
||||||
}
|
|
||||||
return globalFailed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fail() internal {
|
|
||||||
if (hasHEVMContext()) {
|
|
||||||
(bool status, ) = HEVM_ADDRESS.call(
|
|
||||||
abi.encodePacked(bytes4(keccak256("store(address,bytes32,bytes32)")), abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01))))
|
|
||||||
);
|
|
||||||
status; // Silence compiler warnings
|
|
||||||
}
|
|
||||||
_failed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasHEVMContext() internal view returns (bool) {
|
|
||||||
uint256 hevmCodeSize = 0;
|
|
||||||
assembly {
|
|
||||||
hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)
|
|
||||||
}
|
|
||||||
return hevmCodeSize > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
modifier logs_gas() {
|
|
||||||
uint256 startGas = gasleft();
|
|
||||||
_;
|
|
||||||
uint256 endGas = gasleft();
|
|
||||||
emit log_named_uint("gas", startGas - endGas);
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertTrue(bool condition) internal {
|
|
||||||
if (!condition) {
|
|
||||||
emit log("Error: Assertion Failed");
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertTrue(bool condition, string memory err) internal {
|
|
||||||
if (!condition) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertTrue(condition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq(address a, address b) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log("Error: a == b not satisfied [address]");
|
|
||||||
emit log_named_address(" Expected", b);
|
|
||||||
emit log_named_address(" Actual", a);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq(
|
|
||||||
address a,
|
|
||||||
address b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertEq(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq(bytes32 a, bytes32 b) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log("Error: a == b not satisfied [bytes32]");
|
|
||||||
emit log_named_bytes32(" Expected", b);
|
|
||||||
emit log_named_bytes32(" Actual", a);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq(
|
|
||||||
bytes32 a,
|
|
||||||
bytes32 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertEq(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq32(bytes32 a, bytes32 b) internal {
|
|
||||||
assertEq(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq32(
|
|
||||||
bytes32 a,
|
|
||||||
bytes32 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
assertEq(a, b, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq(int256 a, int256 b) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log("Error: a == b not satisfied [int]");
|
|
||||||
emit log_named_int(" Expected", b);
|
|
||||||
emit log_named_int(" Actual", a);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertEq(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq(uint256 a, uint256 b) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log("Error: a == b not satisfied [uint]");
|
|
||||||
emit log_named_uint(" Expected", b);
|
|
||||||
emit log_named_uint(" Actual", a);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertEq(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEqDecimal(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
uint256 decimals
|
|
||||||
) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log("Error: a == b not satisfied [decimal int]");
|
|
||||||
emit log_named_decimal_int(" Expected", b, decimals);
|
|
||||||
emit log_named_decimal_int(" Actual", a, decimals);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEqDecimal(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
uint256 decimals,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertEqDecimal(a, b, decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEqDecimal(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
uint256 decimals
|
|
||||||
) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log("Error: a == b not satisfied [decimal uint]");
|
|
||||||
emit log_named_decimal_uint(" Expected", b, decimals);
|
|
||||||
emit log_named_decimal_uint(" Actual", a, decimals);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEqDecimal(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
uint256 decimals,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a != b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertEqDecimal(a, b, decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGt(uint256 a, uint256 b) internal {
|
|
||||||
if (a <= b) {
|
|
||||||
emit log("Error: a > b not satisfied [uint]");
|
|
||||||
emit log_named_uint(" Value a", a);
|
|
||||||
emit log_named_uint(" Value b", b);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGt(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a <= b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertGt(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGt(int256 a, int256 b) internal {
|
|
||||||
if (a <= b) {
|
|
||||||
emit log("Error: a > b not satisfied [int]");
|
|
||||||
emit log_named_int(" Value a", a);
|
|
||||||
emit log_named_int(" Value b", b);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGt(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a <= b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertGt(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGtDecimal(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
uint256 decimals
|
|
||||||
) internal {
|
|
||||||
if (a <= b) {
|
|
||||||
emit log("Error: a > b not satisfied [decimal int]");
|
|
||||||
emit log_named_decimal_int(" Value a", a, decimals);
|
|
||||||
emit log_named_decimal_int(" Value b", b, decimals);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGtDecimal(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
uint256 decimals,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a <= b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertGtDecimal(a, b, decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGtDecimal(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
uint256 decimals
|
|
||||||
) internal {
|
|
||||||
if (a <= b) {
|
|
||||||
emit log("Error: a > b not satisfied [decimal uint]");
|
|
||||||
emit log_named_decimal_uint(" Value a", a, decimals);
|
|
||||||
emit log_named_decimal_uint(" Value b", b, decimals);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGtDecimal(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
uint256 decimals,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a <= b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertGtDecimal(a, b, decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGe(uint256 a, uint256 b) internal {
|
|
||||||
if (a < b) {
|
|
||||||
emit log("Error: a >= b not satisfied [uint]");
|
|
||||||
emit log_named_uint(" Value a", a);
|
|
||||||
emit log_named_uint(" Value b", b);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGe(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a < b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertGe(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGe(int256 a, int256 b) internal {
|
|
||||||
if (a < b) {
|
|
||||||
emit log("Error: a >= b not satisfied [int]");
|
|
||||||
emit log_named_int(" Value a", a);
|
|
||||||
emit log_named_int(" Value b", b);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGe(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a < b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertGe(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGeDecimal(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
uint256 decimals
|
|
||||||
) internal {
|
|
||||||
if (a < b) {
|
|
||||||
emit log("Error: a >= b not satisfied [decimal int]");
|
|
||||||
emit log_named_decimal_int(" Value a", a, decimals);
|
|
||||||
emit log_named_decimal_int(" Value b", b, decimals);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGeDecimal(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
uint256 decimals,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a < b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertGeDecimal(a, b, decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGeDecimal(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
uint256 decimals
|
|
||||||
) internal {
|
|
||||||
if (a < b) {
|
|
||||||
emit log("Error: a >= b not satisfied [decimal uint]");
|
|
||||||
emit log_named_decimal_uint(" Value a", a, decimals);
|
|
||||||
emit log_named_decimal_uint(" Value b", b, decimals);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertGeDecimal(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
uint256 decimals,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a < b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertGeDecimal(a, b, decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLt(uint256 a, uint256 b) internal {
|
|
||||||
if (a >= b) {
|
|
||||||
emit log("Error: a < b not satisfied [uint]");
|
|
||||||
emit log_named_uint(" Value a", a);
|
|
||||||
emit log_named_uint(" Value b", b);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLt(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a >= b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertLt(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLt(int256 a, int256 b) internal {
|
|
||||||
if (a >= b) {
|
|
||||||
emit log("Error: a < b not satisfied [int]");
|
|
||||||
emit log_named_int(" Value a", a);
|
|
||||||
emit log_named_int(" Value b", b);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLt(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a >= b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertLt(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLtDecimal(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
uint256 decimals
|
|
||||||
) internal {
|
|
||||||
if (a >= b) {
|
|
||||||
emit log("Error: a < b not satisfied [decimal int]");
|
|
||||||
emit log_named_decimal_int(" Value a", a, decimals);
|
|
||||||
emit log_named_decimal_int(" Value b", b, decimals);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLtDecimal(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
uint256 decimals,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a >= b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertLtDecimal(a, b, decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLtDecimal(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
uint256 decimals
|
|
||||||
) internal {
|
|
||||||
if (a >= b) {
|
|
||||||
emit log("Error: a < b not satisfied [decimal uint]");
|
|
||||||
emit log_named_decimal_uint(" Value a", a, decimals);
|
|
||||||
emit log_named_decimal_uint(" Value b", b, decimals);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLtDecimal(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
uint256 decimals,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a >= b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertLtDecimal(a, b, decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLe(uint256 a, uint256 b) internal {
|
|
||||||
if (a > b) {
|
|
||||||
emit log("Error: a <= b not satisfied [uint]");
|
|
||||||
emit log_named_uint(" Value a", a);
|
|
||||||
emit log_named_uint(" Value b", b);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLe(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a > b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertLe(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLe(int256 a, int256 b) internal {
|
|
||||||
if (a > b) {
|
|
||||||
emit log("Error: a <= b not satisfied [int]");
|
|
||||||
emit log_named_int(" Value a", a);
|
|
||||||
emit log_named_int(" Value b", b);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLe(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a > b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertLe(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLeDecimal(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
uint256 decimals
|
|
||||||
) internal {
|
|
||||||
if (a > b) {
|
|
||||||
emit log("Error: a <= b not satisfied [decimal int]");
|
|
||||||
emit log_named_decimal_int(" Value a", a, decimals);
|
|
||||||
emit log_named_decimal_int(" Value b", b, decimals);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLeDecimal(
|
|
||||||
int256 a,
|
|
||||||
int256 b,
|
|
||||||
uint256 decimals,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a > b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertLeDecimal(a, b, decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLeDecimal(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
uint256 decimals
|
|
||||||
) internal {
|
|
||||||
if (a > b) {
|
|
||||||
emit log("Error: a <= b not satisfied [decimal uint]");
|
|
||||||
emit log_named_decimal_uint(" Value a", a, decimals);
|
|
||||||
emit log_named_decimal_uint(" Value b", b, decimals);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertLeDecimal(
|
|
||||||
uint256 a,
|
|
||||||
uint256 b,
|
|
||||||
uint256 decimals,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (a > b) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertGeDecimal(a, b, decimals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq(string memory a, string memory b) internal {
|
|
||||||
if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) {
|
|
||||||
emit log("Error: a == b not satisfied [string]");
|
|
||||||
emit log_named_string(" Expected", b);
|
|
||||||
emit log_named_string(" Actual", a);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq(
|
|
||||||
string memory a,
|
|
||||||
string memory b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertEq(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) {
|
|
||||||
ok = true;
|
|
||||||
if (a.length == b.length) {
|
|
||||||
for (uint256 i = 0; i < a.length; i++) {
|
|
||||||
if (a[i] != b[i]) {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq0(bytes memory a, bytes memory b) internal {
|
|
||||||
if (!checkEq0(a, b)) {
|
|
||||||
emit log("Error: a == b not satisfied [bytes]");
|
|
||||||
emit log_named_bytes(" Expected", b);
|
|
||||||
emit log_named_bytes(" Actual", a);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertEq0(
|
|
||||||
bytes memory a,
|
|
||||||
bytes memory b,
|
|
||||||
string memory err
|
|
||||||
) internal {
|
|
||||||
if (!checkEq0(a, b)) {
|
|
||||||
emit log_named_string("Error", err);
|
|
||||||
assertEq0(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Submodule src/contracts/lib/forge-std deleted from 066ff16c5c
Submodule src/contracts/lib/openzeppelin-contracts deleted from c404862cba
@@ -2,3 +2,4 @@
|
|||||||
@openzepplin/contracts/=lib/openzeppelin-contracts/contracts/
|
@openzepplin/contracts/=lib/openzeppelin-contracts/contracts/
|
||||||
@openzepplin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
|
@openzepplin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
|
||||||
forge-std/=lib/forge-std/src/
|
forge-std/=lib/forge-std/src/
|
||||||
|
ds-test=lib/ds-test/src/
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
import "forge-std/Test.sol";
|
|
||||||
import "forge-std/console.sol";
|
|
||||||
import "forge-std/Script.sol";
|
|
||||||
import "../src/TwitterEmailHandler.sol";
|
|
||||||
import "../src/StringUtils.sol";
|
|
||||||
import "../src/Groth16VerifierTwitter.sol";
|
|
||||||
|
|
||||||
contract Deploy is Script, Test {
|
|
||||||
function getPrivateKey() internal returns (uint256) {
|
|
||||||
try vm.envUint("PRIVATE_KEY") returns (uint256 privateKey) {
|
|
||||||
return privateKey;
|
|
||||||
} catch {
|
|
||||||
// This is the anvil default exposed secret key
|
|
||||||
return 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function run() public {
|
|
||||||
uint256 sk = getPrivateKey();
|
|
||||||
vm.startBroadcast(sk);
|
|
||||||
Verifier proofVerifier = new Verifier();
|
|
||||||
MailServer mailServer = new MailServer();
|
|
||||||
VerifiedTwitterEmail testVerifier = new VerifiedTwitterEmail(proofVerifier, mailServer);
|
|
||||||
vm.stopBroadcast();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
27
src/contracts/script/DeployTwitter.s.sol
Normal file
27
src/contracts/script/DeployTwitter.s.sol
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "forge-std/Test.sol";
|
||||||
|
import "forge-std/console.sol";
|
||||||
|
import "forge-std/Script.sol";
|
||||||
|
import "../src/TwitterEmailHandler.sol";
|
||||||
|
import "../src/Groth16VerifierTwitter.sol";
|
||||||
|
|
||||||
|
contract Deploy is Script, Test {
|
||||||
|
function getPrivateKey() internal returns (uint256) {
|
||||||
|
try vm.envUint("PRIVATE_KEY") returns (uint256 privateKey) {
|
||||||
|
return privateKey;
|
||||||
|
} catch {
|
||||||
|
// This is the anvil default exposed secret key
|
||||||
|
return 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function run() public {
|
||||||
|
uint256 sk = getPrivateKey();
|
||||||
|
vm.startBroadcast(sk);
|
||||||
|
Verifier proofVerifier = new Verifier();
|
||||||
|
MailServer mailServer = new MailServer();
|
||||||
|
VerifiedTwitterEmail testVerifier = new VerifiedTwitterEmail(proofVerifier, mailServer);
|
||||||
|
vm.stopBroadcast();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
pragma solidity ^0.8.0;
|
|
||||||
|
|
||||||
import "forge-std/console.sol";
|
|
||||||
|
|
||||||
contract MailServer {
|
|
||||||
uint16 constant rsa_modulus_chunks_len = 17;
|
|
||||||
mapping(string => uint256[rsa_modulus_chunks_len]) verifiedMailserverKeys;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
// Do dig TXT outgoing._domainkey.twitter.com to verify these.
|
|
||||||
// This is the base 2^121 representation of that key.
|
|
||||||
// Circom bigint: represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k)
|
|
||||||
initMailserverKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
function initMailserverKeys() internal {
|
|
||||||
// TODO: Create a type that takes in a raw RSA key, the bit count,
|
|
||||||
// and whether or not its base64 encoded, and converts it to either 8 or 16 signals
|
|
||||||
verifiedMailserverKeys["gmail.com"][0] = 1886180949733815343726466520516992271;
|
|
||||||
verifiedMailserverKeys["gmail.com"][1] = 1551366393280668736485689616947198994;
|
|
||||||
verifiedMailserverKeys["gmail.com"][2] = 1279057759087427731263511728885611780;
|
|
||||||
verifiedMailserverKeys["gmail.com"][3] = 1711061746895435768547617398484429347;
|
|
||||||
verifiedMailserverKeys["gmail.com"][4] = 2329140368326888129406637741054282011;
|
|
||||||
verifiedMailserverKeys["gmail.com"][5] = 2094858442222190249786465516374057361;
|
|
||||||
verifiedMailserverKeys["gmail.com"][6] = 2584558507302599829894674874442909655;
|
|
||||||
verifiedMailserverKeys["gmail.com"][7] = 1521552483858643935889582214011445675;
|
|
||||||
verifiedMailserverKeys["gmail.com"][8] = 176847449040377757035522930003764000;
|
|
||||||
verifiedMailserverKeys["gmail.com"][9] = 632921959964166974634188077062540145;
|
|
||||||
verifiedMailserverKeys["gmail.com"][10] = 2172441457165086627497230906075093832;
|
|
||||||
verifiedMailserverKeys["gmail.com"][11] = 248112436365636977369105357296082574;
|
|
||||||
verifiedMailserverKeys["gmail.com"][12] = 1408592841800630696650784801114783401;
|
|
||||||
verifiedMailserverKeys["gmail.com"][13] = 364610811473321782531041012695979858;
|
|
||||||
verifiedMailserverKeys["gmail.com"][14] = 342338521965453258686441392321054163;
|
|
||||||
verifiedMailserverKeys["gmail.com"][15] = 2269703683857229911110544415296249295;
|
|
||||||
verifiedMailserverKeys["gmail.com"][16] = 3643644972862751728748413716653892;
|
|
||||||
|
|
||||||
verifiedMailserverKeys["hotmail.com"][0] = 128339925410438117770406273090474249;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][1] = 2158906895782814996316644028571725310;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][2] = 2278019331164769360372919938620729773;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][3] = 1305319804455735154587383372570664109;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][4] = 2358345194772578919713586294428642696;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][5] = 1333692900109074470874155333266985021;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][6] = 2252956899717870524129098594286063236;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][7] = 1963190090223950324858653797870319519;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][8] = 2099240641399560863760865662500577339;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][9] = 1591320380606901546957315803395187883;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][10] = 1943831890994545117064894677442719428;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][11] = 2243327453964709681573059557263184139;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][12] = 1078181067739519006314708889181549671;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][13] = 2209638307239559037039565345615684964;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][14] = 1936371786309180968911326337008120155;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][15] = 2611115500285740051274748743252547506;
|
|
||||||
verifiedMailserverKeys["hotmail.com"][16] = 3841983033048617585564391738126779;
|
|
||||||
|
|
||||||
verifiedMailserverKeys["ethereum.org"][0] = 119886678941863893035426121053426453;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][1] = 1819786846289142128062035525540154587;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][2] = 18664768675154515296388092785538021;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][3] = 2452916380017370778812419704280324749;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][4] = 147541693845229442834461965414634823;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][5] = 714676313158744653841521918164405002;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][6] = 1495951612535183023869749054624579068;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][7] = 974892773071523448175479681445882254;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][8] = 53117264910028079;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][9] = 0;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][10] = 0;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][11] = 0;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][12] = 0;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][13] = 0;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][14] = 0;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][15] = 0;
|
|
||||||
verifiedMailserverKeys["ethereum.org"][16] = 0;
|
|
||||||
|
|
||||||
verifiedMailserverKeys["twitter.com"][0] = 1634582323953821262989958727173988295;
|
|
||||||
verifiedMailserverKeys["twitter.com"][1] = 1938094444722442142315201757874145583;
|
|
||||||
verifiedMailserverKeys["twitter.com"][2] = 375300260153333632727697921604599470;
|
|
||||||
verifiedMailserverKeys["twitter.com"][3] = 1369658125109277828425429339149824874;
|
|
||||||
verifiedMailserverKeys["twitter.com"][4] = 1589384595547333389911397650751436647;
|
|
||||||
verifiedMailserverKeys["twitter.com"][5] = 1428144289938431173655248321840778928;
|
|
||||||
verifiedMailserverKeys["twitter.com"][6] = 1919508490085653366961918211405731923;
|
|
||||||
verifiedMailserverKeys["twitter.com"][7] = 2358009612379481320362782200045159837;
|
|
||||||
verifiedMailserverKeys["twitter.com"][8] = 518833500408858308962881361452944175;
|
|
||||||
verifiedMailserverKeys["twitter.com"][9] = 1163210548821508924802510293967109414;
|
|
||||||
verifiedMailserverKeys["twitter.com"][10] = 1361351910698751746280135795885107181;
|
|
||||||
verifiedMailserverKeys["twitter.com"][11] = 1445969488612593115566934629427756345;
|
|
||||||
verifiedMailserverKeys["twitter.com"][12] = 2457340995040159831545380614838948388;
|
|
||||||
verifiedMailserverKeys["twitter.com"][13] = 2612807374136932899648418365680887439;
|
|
||||||
verifiedMailserverKeys["twitter.com"][14] = 16021263889082005631675788949457422;
|
|
||||||
verifiedMailserverKeys["twitter.com"][15] = 299744519975649772895460843780023483;
|
|
||||||
verifiedMailserverKeys["twitter.com"][16] = 3933359104846508935112096715593287;
|
|
||||||
|
|
||||||
verifiedMailserverKeys["skiff.com"][0] = 2637270478154147701703365710201556843;
|
|
||||||
verifiedMailserverKeys["skiff.com"][1] = 2082690054369201099288110516791254232;
|
|
||||||
verifiedMailserverKeys["skiff.com"][2] = 1108253255381437937379143813840625818;
|
|
||||||
verifiedMailserverKeys["skiff.com"][3] = 1535554154331979875086566323552212673;
|
|
||||||
verifiedMailserverKeys["skiff.com"][4] = 273019276149049264013012583938735085;
|
|
||||||
verifiedMailserverKeys["skiff.com"][5] = 741436192387359949728618527229215889;
|
|
||||||
verifiedMailserverKeys["skiff.com"][6] = 1851608307869135205473270393049341043;
|
|
||||||
verifiedMailserverKeys["skiff.com"][7] = 1428718881138594152975742734455140338;
|
|
||||||
verifiedMailserverKeys["skiff.com"][8] = 778850382237088374273157869416671135;
|
|
||||||
verifiedMailserverKeys["skiff.com"][9] = 549599381370898291203601849666570597;
|
|
||||||
verifiedMailserverKeys["skiff.com"][10] = 221161044322752364431317167498442512;
|
|
||||||
verifiedMailserverKeys["skiff.com"][11] = 2041801755941244198449288035460748224;
|
|
||||||
verifiedMailserverKeys["skiff.com"][12] = 1083114189020989870026920716001138899;
|
|
||||||
verifiedMailserverKeys["skiff.com"][13] = 1380362773644527202561949550864154963;
|
|
||||||
verifiedMailserverKeys["skiff.com"][14] = 1366599807917971505788646146248798329;
|
|
||||||
verifiedMailserverKeys["skiff.com"][15] = 391565989352979266796804441125988853;
|
|
||||||
verifiedMailserverKeys["skiff.com"][16] = 3704766395208948862861103932863036;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _stringEq(string memory a, string memory b) internal pure returns (bool) {
|
|
||||||
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
function isVerified(string memory domain, uint256 index, uint256 val) public view returns (bool) {
|
|
||||||
// allow external queries on mapping
|
|
||||||
uint256 val1 = verifiedMailserverKeys[domain][index];
|
|
||||||
uint256 val2 = val;
|
|
||||||
if (val1 != val2) {
|
|
||||||
console.log(val1, val2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return verifiedMailserverKeys[domain][index] == val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
|
||||||
pragma solidity >=0.7.6;
|
|
||||||
|
|
||||||
// https://github.com/nalinbhardwaj/ethdosnumber/blob/main/ethdos-contracts/src/HexStrings.sol
|
|
||||||
library StringUtils {
|
|
||||||
bytes16 internal constant ALPHABET = "0123456789abcdef";
|
|
||||||
|
|
||||||
/// @notice Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
|
|
||||||
/// @dev Credit to Open Zeppelin under MIT license https://github.com/OpenZeppelin/openzeppelin-contracts/blob/243adff49ce1700e0ecb99fe522fb16cff1d1ddc/contracts/utils/Strings.sol#L55
|
|
||||||
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
|
|
||||||
bytes memory buffer = new bytes(2 * length + 2);
|
|
||||||
buffer[0] = "0";
|
|
||||||
buffer[1] = "x";
|
|
||||||
for (uint256 i = 2 * length + 1; i > 1; --i) {
|
|
||||||
buffer[i] = ALPHABET[value & 0xf];
|
|
||||||
value >>= 4;
|
|
||||||
}
|
|
||||||
require(value == 0, "Strings: hex length insufficient");
|
|
||||||
return string(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory) {
|
|
||||||
bytes memory buffer = new bytes(2 * length);
|
|
||||||
for (uint256 i = buffer.length; i > 0; i--) {
|
|
||||||
buffer[i - 1] = ALPHABET[value & 0xf];
|
|
||||||
value >>= 4;
|
|
||||||
}
|
|
||||||
return string(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toString(uint256 value) internal pure returns (string memory) {
|
|
||||||
return toString(abi.encodePacked(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
function toString(bytes32 value) internal pure returns (string memory) {
|
|
||||||
return toString(abi.encodePacked(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
function toString(address account) internal pure returns (string memory) {
|
|
||||||
return toString(abi.encodePacked(account));
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringEq(string memory a, string memory b) internal pure returns (bool) {
|
|
||||||
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
function toString(bytes memory data) internal pure returns (string memory) {
|
|
||||||
bytes memory alphabet = "0123456789abcdef";
|
|
||||||
|
|
||||||
bytes memory str = new bytes(2 + data.length * 2);
|
|
||||||
str[0] = "0";
|
|
||||||
str[1] = "x";
|
|
||||||
for (uint256 i = 0; i < data.length; i++) {
|
|
||||||
str[2 + i * 2] = alphabet[uint256(uint8(data[i] >> 4))];
|
|
||||||
str[3 + i * 2] = alphabet[uint256(uint8(data[i] & 0x0f))];
|
|
||||||
}
|
|
||||||
return string(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unpacks uint256s into bytes and then extracts the non-zero characters
|
|
||||||
// Only extracts contiguous non-zero characters and ensures theres only 1 such state
|
|
||||||
// Note that unpackedLen may be more than packedBytes.length * 8 since there may be 0s
|
|
||||||
// TODO: Remove console.logs and define this as a pure function instead of a view
|
|
||||||
function convertPackedBytesToBytes(uint256[] memory packedBytes, uint256 maxBytes, uint256 packSize) internal pure returns (string memory extractedString) {
|
|
||||||
uint8 state = 0;
|
|
||||||
// bytes: 0 0 0 0 y u s h _ g 0 0 0
|
|
||||||
// state: 0 0 0 0 1 1 1 1 1 1 2 2 2
|
|
||||||
bytes memory nonzeroBytesArray = new bytes(packedBytes.length * 7);
|
|
||||||
uint256 nonzeroBytesArrayIndex = 0;
|
|
||||||
for (uint16 i = 0; i < packedBytes.length; i++) {
|
|
||||||
uint256 packedByte = packedBytes[i];
|
|
||||||
uint8[] memory unpackedBytes = new uint8[](packSize);
|
|
||||||
for (uint256 j = 0; j < packSize; j++) {
|
|
||||||
unpackedBytes[j] = uint8(packedByte >> (j * 8));
|
|
||||||
}
|
|
||||||
for (uint256 j = 0; j < packSize; j++) {
|
|
||||||
uint256 unpackedByte = unpackedBytes[j]; //unpackedBytes[j];
|
|
||||||
// console.log(i, j, state, unpackedByte);
|
|
||||||
if (unpackedByte != 0) {
|
|
||||||
nonzeroBytesArray[nonzeroBytesArrayIndex] = bytes1(uint8(unpackedByte));
|
|
||||||
nonzeroBytesArrayIndex++;
|
|
||||||
if (state % 2 == 0) {
|
|
||||||
state += 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (state % 2 == 1) {
|
|
||||||
state += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
packedByte = packedByte >> 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string memory returnValue = string(nonzeroBytesArray);
|
|
||||||
require(state >= 1, "Invalid final state of packed bytes in email");
|
|
||||||
// console.log("Characters in username: ", nonzeroBytesArrayIndex);
|
|
||||||
require(nonzeroBytesArrayIndex <= maxBytes, "Packed bytes more than allowed max length!");
|
|
||||||
return returnValue;
|
|
||||||
// Have to end at the end of the email -- state cannot be 1 since there should be an email footer
|
|
||||||
}
|
|
||||||
|
|
||||||
function bytes32ToString(bytes32 input) internal pure returns (string memory) {
|
|
||||||
uint256 i;
|
|
||||||
for (i = 0; i < 32 && input[i] != 0; i++) {}
|
|
||||||
bytes memory resultBytes = new bytes(i);
|
|
||||||
for (i = 0; i < 32 && input[i] != 0; i++) {
|
|
||||||
resultBytes[i] = input[i];
|
|
||||||
}
|
|
||||||
return string(resultBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sliceArray is used to slice an array of uint256s from start-end into a new array of uint256s
|
|
||||||
function sliceArray(uint256[] memory input, uint256 start, uint256 end) internal pure returns (uint256[] memory) {
|
|
||||||
require(start <= end && end <= input.length, "Invalid slice indices");
|
|
||||||
uint256[] memory result = new uint256[](end - start);
|
|
||||||
for (uint256 i = start; i < end; i++) {
|
|
||||||
result[i - start] = input[i];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// stringToUint is used to convert a string like "45" to a uint256 4
|
|
||||||
function stringToUint(string memory s) internal pure returns (uint256) {
|
|
||||||
bytes memory b = bytes(s);
|
|
||||||
uint256 result = 0;
|
|
||||||
for (uint256 i = 0; i < b.length; i++) {
|
|
||||||
if (b[i] >= 0x30 && b[i] <= 0x39) {
|
|
||||||
result = result * 10 + (uint256(uint8(b[i])) - 48);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Currently truncates decimals
|
|
||||||
if (b[i] == 0x2E) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDomainFromEmail is used to extract the domain from an email i.e. the part after the @
|
|
||||||
function getDomainFromEmail(string memory fromEmail) internal pure returns (string memory) {
|
|
||||||
bytes memory emailBytes = bytes(fromEmail);
|
|
||||||
uint256 atIndex;
|
|
||||||
for (uint256 i = 0; i < emailBytes.length; i++) {
|
|
||||||
if (emailBytes[i] == "@") {
|
|
||||||
atIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes memory domainBytes = new bytes(emailBytes.length - atIndex - 1);
|
|
||||||
for (uint256 j = 0; j < domainBytes.length; j++) {
|
|
||||||
domainBytes[j] = emailBytes[atIndex + 1 + j];
|
|
||||||
}
|
|
||||||
return bytes32ToString(bytes32(bytes(domainBytes)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,95 +5,101 @@ import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
|
|||||||
import "@openzeppelin/contracts/utils/Strings.sol";
|
import "@openzeppelin/contracts/utils/Strings.sol";
|
||||||
import "@openzeppelin/contracts/utils/Counters.sol";
|
import "@openzeppelin/contracts/utils/Counters.sol";
|
||||||
import "forge-std/console.sol";
|
import "forge-std/console.sol";
|
||||||
import "./StringUtils.sol";
|
import "./utils/StringUtils.sol";
|
||||||
import "./NFTSVG.sol";
|
import "./utils/NFTSVG.sol";
|
||||||
import { Verifier } from "./Groth16VerifierTwitter.sol";
|
import {Verifier} from "./Groth16VerifierTwitter.sol";
|
||||||
import "./MailServer.sol";
|
import "./utils/MailServer.sol";
|
||||||
|
|
||||||
contract VerifiedTwitterEmail is ERC721Enumerable, Verifier {
|
contract VerifiedTwitterEmail is ERC721Enumerable {
|
||||||
using Counters for Counters.Counter;
|
using Counters for Counters.Counter;
|
||||||
using StringUtils for *;
|
using StringUtils for *;
|
||||||
using NFTSVG for *;
|
using NFTSVG for *;
|
||||||
|
|
||||||
Counters.Counter private tokenCounter;
|
Counters.Counter private tokenCounter;
|
||||||
|
|
||||||
uint16 public constant msg_len = 21; // header + body
|
uint16 public constant msg_len = 21; // header + body
|
||||||
uint16 public constant bytesInPackedBytes = 7; // 7 bytes in a packed item returned from circom
|
uint16 public constant bytesInPackedBytes = 7; // 7 bytes in a packed item returned from circom
|
||||||
uint256 public constant body_len = 3;
|
uint256 public constant body_len = 3;
|
||||||
uint256 public constant rsa_modulus_chunks_len = 17;
|
uint256 public constant rsa_modulus_chunks_len = 17;
|
||||||
uint256 public constant header_len = msg_len - body_len;
|
uint256 public constant header_len = msg_len - body_len;
|
||||||
uint256 public constant addressIndexInSignals = msg_len - 1;
|
uint256 public constant addressIndexInSignals = msg_len - 1;
|
||||||
|
|
||||||
mapping(string => uint256[rsa_modulus_chunks_len]) public verifiedMailserverKeys;
|
mapping(string => uint256[rsa_modulus_chunks_len]) public verifiedMailserverKeys;
|
||||||
mapping(uint256 => string) public tokenIDToName;
|
mapping(uint256 => string) public tokenIDToName;
|
||||||
string constant domain = "twitter.com";
|
string constant domain = "twitter.com";
|
||||||
MailServer mailServer;
|
MailServer mailServer;
|
||||||
Verifier public immutable verifier;
|
Verifier public immutable verifier;
|
||||||
|
|
||||||
constructor(Verifier v, MailServer m) ERC721("VerifiedEmail", "VerifiedEmail") {
|
constructor(Verifier v, MailServer m) ERC721("VerifiedEmail", "VerifiedEmail") {
|
||||||
verifier = v;
|
verifier = v;
|
||||||
mailServer = m;
|
mailServer = m;
|
||||||
require(rsa_modulus_chunks_len + body_len + 1 == msg_len, "Variable counts are wrong!");
|
require(rsa_modulus_chunks_len + body_len + 1 == msg_len, "Variable counts are wrong!");
|
||||||
}
|
|
||||||
|
|
||||||
function tokenDesc(uint256 tokenId) public view returns (string memory) {
|
|
||||||
string memory twitter_username = tokenIDToName[tokenId];
|
|
||||||
address address_owner = ownerOf(tokenId);
|
|
||||||
string memory result = string(abi.encodePacked("Twitter username", twitter_username, "is owned by", StringUtils.toString(address_owner)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tokenURI(uint256 tokenId) public view override returns (string memory) {
|
|
||||||
string memory username = tokenIDToName[tokenId];
|
|
||||||
address owner = ownerOf(tokenId);
|
|
||||||
return NFTSVG.constructAndReturnSVG(username, tokenId, owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _domainCheck(uint256[] memory headerSignals) public pure returns (bool) {
|
|
||||||
string memory senderBytes = StringUtils.convertPackedBytesToBytes(headerSignals, 18, bytesInPackedBytes);
|
|
||||||
string[2] memory domainStrings = ["verify@twitter.com", "info@twitter.com"];
|
|
||||||
return StringUtils.stringEq(senderBytes, domainStrings[0]) || StringUtils.stringEq(senderBytes, domainStrings[1]);
|
|
||||||
// Usage: require(_domainCheck(senderBytes, domainStrings), "Invalid domain");
|
|
||||||
}
|
|
||||||
|
|
||||||
function mint(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[msg_len] memory signals) public {
|
|
||||||
// TODO no invalid signal check yet, which is fine since the zk proof does it
|
|
||||||
// Checks: Verify proof and check signals
|
|
||||||
// require(signals[0] == 1337, "invalid signals");
|
|
||||||
|
|
||||||
// 3 public signals are the masked packed message bytes, 17 are the modulus.
|
|
||||||
uint256[] memory bodySignals = new uint256[](body_len);
|
|
||||||
uint256[] memory rsaModulusSignals = new uint256[](header_len);
|
|
||||||
for (uint256 i = 0; i < body_len; i++) {
|
|
||||||
bodySignals[i] = signals[i];
|
|
||||||
}
|
|
||||||
for (uint256 i = body_len; i < msg_len - 1; i++) {
|
|
||||||
rsaModulusSignals[i - body_len] = signals[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check eth address committed to in proof matches msg.sender, to avoid replayability
|
function tokenDesc(uint256 tokenId) public view returns (string memory) {
|
||||||
require(address(uint160(signals[addressIndexInSignals])) == msg.sender, "Invalid address");
|
string memory twitter_username = tokenIDToName[tokenId];
|
||||||
|
address address_owner = ownerOf(tokenId);
|
||||||
// Check from/to email domains are correct [in this case, only from domain is checked]
|
string memory result = string(
|
||||||
// Right now, we just check that any email was received from anyone at Twitter, which is good enough for now
|
abi.encodePacked("Twitter username", twitter_username, "is owned by", StringUtils.toString(address_owner))
|
||||||
// We will upload the version with these domain checks soon!
|
);
|
||||||
// require(_domainCheck(headerSignals), "Invalid domain");
|
return result;
|
||||||
|
|
||||||
// Verify that the public key for RSA matches the hardcoded one
|
|
||||||
for (uint256 i = body_len; i < msg_len - 1; i++) {
|
|
||||||
require(mailServer.isVerified(domain, i - body_len, signals[i]), "Invalid: RSA modulus not matched");
|
|
||||||
}
|
}
|
||||||
require(verifyProof(a, b, c, signals), "Invalid Proof"); // checks effects iteractions, this should come first
|
|
||||||
|
|
||||||
// Effects: Mint token
|
function tokenURI(uint256 tokenId) public view override returns (string memory) {
|
||||||
uint256 tokenId = tokenCounter.current() + 1;
|
string memory username = tokenIDToName[tokenId];
|
||||||
string memory messageBytes = StringUtils.convertPackedBytesToBytes(bodySignals, bytesInPackedBytes * body_len, bytesInPackedBytes);
|
address owner = ownerOf(tokenId);
|
||||||
tokenIDToName[tokenId] = messageBytes;
|
return NFTSVG.constructAndReturnSVG(username, tokenId, owner);
|
||||||
_mint(msg.sender, tokenId);
|
}
|
||||||
tokenCounter.increment();
|
|
||||||
}
|
|
||||||
|
|
||||||
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal {
|
function _domainCheck(uint256[] memory headerSignals) public pure returns (bool) {
|
||||||
require(from == address(0), "Cannot transfer - VerifiedEmail is soulbound");
|
string memory senderBytes = StringUtils.convertPackedBytesToString(headerSignals, 18, bytesInPackedBytes);
|
||||||
}
|
string[2] memory domainStrings = ["verify@twitter.com", "info@twitter.com"];
|
||||||
|
return
|
||||||
|
StringUtils.stringEq(senderBytes, domainStrings[0]) || StringUtils.stringEq(senderBytes, domainStrings[1]);
|
||||||
|
// Usage: require(_domainCheck(senderBytes, domainStrings), "Invalid domain");
|
||||||
|
}
|
||||||
|
|
||||||
|
function mint(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[msg_len] memory signals)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
// TODO no invalid signal check yet, which is fine since the zk proof does it
|
||||||
|
// Checks: Verify proof and check signals
|
||||||
|
// require(signals[0] == 1337, "invalid signals");
|
||||||
|
|
||||||
|
// 3 public signals are the masked packed message bytes, 17 are the modulus.
|
||||||
|
uint256[] memory bodySignals = new uint256[](body_len);
|
||||||
|
uint256[] memory rsaModulusSignals = new uint256[](header_len);
|
||||||
|
for (uint256 i = 0; i < body_len; i++) {
|
||||||
|
bodySignals[i] = signals[i];
|
||||||
|
}
|
||||||
|
for (uint256 i = body_len; i < msg_len - 1; i++) {
|
||||||
|
rsaModulusSignals[i - body_len] = signals[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check eth address committed to in proof matches msg.sender, to avoid replayability
|
||||||
|
require(address(uint160(signals[addressIndexInSignals])) == msg.sender, "Invalid address");
|
||||||
|
|
||||||
|
// Check from/to email domains are correct [in this case, only from domain is checked]
|
||||||
|
// Right now, we just check that any email was received from anyone at Twitter, which is good enough for now
|
||||||
|
// We will upload the version with these domain checks soon!
|
||||||
|
// require(_domainCheck(headerSignals), "Invalid domain");
|
||||||
|
|
||||||
|
// Verify that the public key for RSA matches the hardcoded one
|
||||||
|
for (uint256 i = body_len; i < msg_len - 1; i++) {
|
||||||
|
require(mailServer.isVerified(domain, i - body_len, signals[i]), "Invalid: RSA modulus not matched");
|
||||||
|
}
|
||||||
|
require(verifier.verifyProof(a, b, c, signals), "Invalid Proof"); // checks effects iteractions, this should come first
|
||||||
|
|
||||||
|
// Effects: Mint token
|
||||||
|
uint256 tokenId = tokenCounter.current() + 1;
|
||||||
|
string memory messageBytes =
|
||||||
|
StringUtils.convertPackedBytesToString(bodySignals, bytesInPackedBytes * body_len, bytesInPackedBytes);
|
||||||
|
tokenIDToName[tokenId] = messageBytes;
|
||||||
|
_mint(msg.sender, tokenId);
|
||||||
|
tokenCounter.increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal {
|
||||||
|
require(from == address(0), "Cannot transfer - VerifiedEmail is soulbound");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.8.0;
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
import "forge-std/Test.sol";
|
import "forge-std/Test.sol";
|
||||||
import "../../script/Deploy.s.sol";
|
import "../../script/DeployTwitter.s.sol";
|
||||||
|
|
||||||
contract TestDeploy is Test {
|
contract TestDeploy is Test {
|
||||||
Deploy deploy;
|
Deploy deploy;
|
||||||
|
|||||||
@@ -6,165 +6,187 @@ import "../TwitterEmailHandler.sol";
|
|||||||
import "../Groth16VerifierTwitter.sol";
|
import "../Groth16VerifierTwitter.sol";
|
||||||
|
|
||||||
contract TwitterUtilsTest is Test {
|
contract TwitterUtilsTest is Test {
|
||||||
using StringUtils for *;
|
using StringUtils for *;
|
||||||
|
|
||||||
address constant VM_ADDR = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; // Hardcoded address of the VM from foundry
|
address constant VM_ADDR = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; // Hardcoded address of the VM from foundry
|
||||||
|
|
||||||
Verifier proofVerifier;
|
Verifier proofVerifier;
|
||||||
MailServer mailServer;
|
MailServer mailServer;
|
||||||
VerifiedTwitterEmail testVerifier;
|
VerifiedTwitterEmail testVerifier;
|
||||||
|
|
||||||
uint16 public constant packSize = 7;
|
uint16 public constant packSize = 7;
|
||||||
|
|
||||||
function setUp() public {
|
function setUp() public {
|
||||||
proofVerifier = new Verifier();
|
proofVerifier = new Verifier();
|
||||||
mailServer = new MailServer();
|
mailServer = new MailServer();
|
||||||
testVerifier = new VerifiedTwitterEmail(proofVerifier, mailServer);
|
testVerifier = new VerifiedTwitterEmail(proofVerifier, mailServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// function testMint() public {
|
// function testMint() public {
|
||||||
// testVerifier.mint
|
// testVerifier.mint
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Should pass (note that there are extra 0 bytes, which are filtered out but should be noted in audits)
|
// Should pass (note that there are extra 0 bytes, which are filtered out but should be noted in audits)
|
||||||
function testUnpack1() public {
|
function testUnpack1() public {
|
||||||
uint256[] memory packedBytes = new uint256[](3);
|
uint256[] memory packedBytes = new uint256[](3);
|
||||||
packedBytes[0] = 29096824819513600;
|
packedBytes[0] = 29096824819513600;
|
||||||
packedBytes[1] = 0;
|
packedBytes[1] = 0;
|
||||||
packedBytes[2] = 0;
|
packedBytes[2] = 0;
|
||||||
|
|
||||||
// This is 0x797573685f670000000000000000000000000000000000000000000000000000
|
// This is 0x797573685f670000000000000000000000000000000000000000000000000000
|
||||||
// packSize = 7
|
// packSize = 7
|
||||||
string memory byteList = StringUtils.convertPackedBytesToBytes(packedBytes, 15, packSize);
|
string memory byteList = StringUtils.convertPackedBytesToString(packedBytes, 15, packSize);
|
||||||
// This is 0x797573685f67, since strings are internally arbitrary length arrays
|
// This is 0x797573685f67, since strings are internally arbitrary length arrays
|
||||||
string memory intended_value = "yush_g";
|
string memory intended_value = "yush_g";
|
||||||
|
|
||||||
// We need to cast both to bytes32, which works since usernames can be at most 15, alphanumeric + '_' characters
|
// We need to cast both to bytes32, which works since usernames can be at most 15, alphanumeric + '_' characters
|
||||||
// Note that this may not generalize to non-ascii characters.
|
// Note that this may not generalize to non-ascii characters.
|
||||||
// Weird characters are allowed in email addresses, see https://en.wikipedia.org/wiki/Email_address#Local-part
|
// Weird characters are allowed in email addresses, see https://en.wikipedia.org/wiki/Email_address#Local-part
|
||||||
// See https://stackoverflow.com/a/2049510/3977093 -- you can even have international characters with RFC 6532
|
// See https://stackoverflow.com/a/2049510/3977093 -- you can even have international characters with RFC 6532
|
||||||
// Our regex should just disallow most of these emails, but they may end up taking more than two bytes
|
// Our regex should just disallow most of these emails, but they may end up taking more than two bytes
|
||||||
// ASCII should fit in 2 bytes but emails may not be ASCII
|
// ASCII should fit in 2 bytes but emails may not be ASCII
|
||||||
assertEq(bytes32(bytes(byteList)), bytes32(bytes(intended_value)));
|
assertEq(bytes32(bytes(byteList)), bytes32(bytes(intended_value)));
|
||||||
console.logString(byteList);
|
console.logString(byteList);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testUnpack2() public {
|
function testUnpack2() public {
|
||||||
uint256[] memory packedBytes = new uint256[](3);
|
uint256[] memory packedBytes = new uint256[](3);
|
||||||
packedBytes[0] = 28557011619965818;
|
packedBytes[0] = 28557011619965818;
|
||||||
packedBytes[1] = 1818845549;
|
packedBytes[1] = 1818845549;
|
||||||
packedBytes[2] = 0;
|
packedBytes[2] = 0;
|
||||||
string memory byteList = StringUtils.convertPackedBytesToBytes(packedBytes, 15, packSize);
|
string memory byteList = StringUtils.convertPackedBytesToString(packedBytes, 15, packSize);
|
||||||
string memory intended_value = "zktestemail";
|
string memory intended_value = "zktestemail";
|
||||||
assertEq(bytes32(bytes(byteList)), bytes32(bytes(intended_value)));
|
assertEq(bytes32(bytes(byteList)), bytes32(bytes(intended_value)));
|
||||||
console.logString(byteList);
|
console.logString(byteList);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should pass (note that there are extra 0 bytes, which are filtered out but should be noted in audits)
|
// Should pass (note that there are extra 0 bytes, which are filtered out but should be noted in audits)
|
||||||
function testVerifyTestEmail() public {
|
function testVerifyTestEmail() public {
|
||||||
uint256[21] memory publicSignals;
|
uint256[21] memory publicSignals;
|
||||||
publicSignals[0] = 28557011619965818;
|
publicSignals[0] = 28557011619965818;
|
||||||
publicSignals[1] = 1818845549;
|
publicSignals[1] = 1818845549;
|
||||||
publicSignals[2] = 0;
|
publicSignals[2] = 0;
|
||||||
publicSignals[3] = 1634582323953821262989958727173988295;
|
publicSignals[3] = 1634582323953821262989958727173988295;
|
||||||
publicSignals[4] = 1938094444722442142315201757874145583;
|
publicSignals[4] = 1938094444722442142315201757874145583;
|
||||||
publicSignals[5] = 375300260153333632727697921604599470;
|
publicSignals[5] = 375300260153333632727697921604599470;
|
||||||
publicSignals[6] = 1369658125109277828425429339149824874;
|
publicSignals[6] = 1369658125109277828425429339149824874;
|
||||||
publicSignals[7] = 1589384595547333389911397650751436647;
|
publicSignals[7] = 1589384595547333389911397650751436647;
|
||||||
publicSignals[8] = 1428144289938431173655248321840778928;
|
publicSignals[8] = 1428144289938431173655248321840778928;
|
||||||
publicSignals[9] = 1919508490085653366961918211405731923;
|
publicSignals[9] = 1919508490085653366961918211405731923;
|
||||||
publicSignals[10] = 2358009612379481320362782200045159837;
|
publicSignals[10] = 2358009612379481320362782200045159837;
|
||||||
publicSignals[11] = 518833500408858308962881361452944175;
|
publicSignals[11] = 518833500408858308962881361452944175;
|
||||||
publicSignals[12] = 1163210548821508924802510293967109414;
|
publicSignals[12] = 1163210548821508924802510293967109414;
|
||||||
publicSignals[13] = 1361351910698751746280135795885107181;
|
publicSignals[13] = 1361351910698751746280135795885107181;
|
||||||
publicSignals[14] = 1445969488612593115566934629427756345;
|
publicSignals[14] = 1445969488612593115566934629427756345;
|
||||||
publicSignals[15] = 2457340995040159831545380614838948388;
|
publicSignals[15] = 2457340995040159831545380614838948388;
|
||||||
publicSignals[16] = 2612807374136932899648418365680887439;
|
publicSignals[16] = 2612807374136932899648418365680887439;
|
||||||
publicSignals[17] = 16021263889082005631675788949457422;
|
publicSignals[17] = 16021263889082005631675788949457422;
|
||||||
publicSignals[18] = 299744519975649772895460843780023483;
|
publicSignals[18] = 299744519975649772895460843780023483;
|
||||||
publicSignals[19] = 3933359104846508935112096715593287;
|
publicSignals[19] = 3933359104846508935112096715593287;
|
||||||
publicSignals[20] = 1;
|
publicSignals[20] = 1;
|
||||||
|
|
||||||
uint256[2] memory proof_a = [
|
uint256[2] memory proof_a = [
|
||||||
19927878014774420599335762081097643265718718256586894795640382494403322204498,
|
19927878014774420599335762081097643265718718256586894795640382494403322204498,
|
||||||
14891682495744632566900850738763676245933032364192093662622519454269163038775
|
14891682495744632566900850738763676245933032364192093662622519454269163038775
|
||||||
];
|
];
|
||||||
// Note: you need to swap the order of the two elements in each subarray
|
// Note: you need to swap the order of the two elements in each subarray
|
||||||
uint256[2][2] memory proof_b = [
|
uint256[2][2] memory proof_b = [
|
||||||
[14339187615496075499805495539746225674931332745294633353238109947200788411047, 5073539291744271938197991858884932464126239394557616491779032788471213143054],
|
[
|
||||||
[14306493036235766258625927887837901586089699893867499630969317589097278736626, 6852189668501753411744690866678572576357476484128490006857314905430126107219]
|
14339187615496075499805495539746225674931332745294633353238109947200788411047,
|
||||||
];
|
5073539291744271938197991858884932464126239394557616491779032788471213143054
|
||||||
uint256[2] memory proof_c = [
|
],
|
||||||
410487323277858030399204852640011945213610339130647561627952237033421360197,
|
[
|
||||||
6281805762334485380296289707165572755690746355667398246912272308643846746573
|
14306493036235766258625927887837901586089699893867499630969317589097278736626,
|
||||||
];
|
6852189668501753411744690866678572576357476484128490006857314905430126107219
|
||||||
|
]
|
||||||
|
];
|
||||||
|
uint256[2] memory proof_c = [
|
||||||
|
410487323277858030399204852640011945213610339130647561627952237033421360197,
|
||||||
|
6281805762334485380296289707165572755690746355667398246912272308643846746573
|
||||||
|
];
|
||||||
|
|
||||||
// Test proof verification
|
// Test proof verification
|
||||||
bool verified = proofVerifier.verifyProof(proof_a, proof_b, proof_c, publicSignals);
|
bool verified = proofVerifier.verifyProof(proof_a, proof_b, proof_c, publicSignals);
|
||||||
assertEq(verified, true);
|
assertEq(verified, true);
|
||||||
|
|
||||||
// Test mint after spoofing msg.sender
|
// Test mint after spoofing msg.sender
|
||||||
Vm vm = Vm(VM_ADDR);
|
Vm vm = Vm(VM_ADDR);
|
||||||
vm.startPrank(0x0000000000000000000000000000000000000001);
|
vm.startPrank(0x0000000000000000000000000000000000000001);
|
||||||
testVerifier.mint(proof_a, proof_b, proof_c, publicSignals);
|
testVerifier.mint(proof_a, proof_b, proof_c, publicSignals);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should pass (note that there are extra 0 bytes, which are filtered out but should be noted in audits)
|
// Should pass (note that there are extra 0 bytes, which are filtered out but should be noted in audits)
|
||||||
function testVerifyYushEmail() public {
|
function testVerifyYushEmail() public {
|
||||||
uint256[21] memory publicSignals;
|
uint256[21] memory publicSignals;
|
||||||
publicSignals[0] = 113659471951225;
|
publicSignals[0] = 113659471951225;
|
||||||
publicSignals[1] = 0;
|
publicSignals[1] = 0;
|
||||||
publicSignals[2] = 0;
|
publicSignals[2] = 0;
|
||||||
publicSignals[3] = 1634582323953821262989958727173988295;
|
publicSignals[3] = 1634582323953821262989958727173988295;
|
||||||
publicSignals[4] = 1938094444722442142315201757874145583;
|
publicSignals[4] = 1938094444722442142315201757874145583;
|
||||||
publicSignals[5] = 375300260153333632727697921604599470;
|
publicSignals[5] = 375300260153333632727697921604599470;
|
||||||
publicSignals[6] = 1369658125109277828425429339149824874;
|
publicSignals[6] = 1369658125109277828425429339149824874;
|
||||||
publicSignals[7] = 1589384595547333389911397650751436647;
|
publicSignals[7] = 1589384595547333389911397650751436647;
|
||||||
publicSignals[8] = 1428144289938431173655248321840778928;
|
publicSignals[8] = 1428144289938431173655248321840778928;
|
||||||
publicSignals[9] = 1919508490085653366961918211405731923;
|
publicSignals[9] = 1919508490085653366961918211405731923;
|
||||||
publicSignals[10] = 2358009612379481320362782200045159837;
|
publicSignals[10] = 2358009612379481320362782200045159837;
|
||||||
publicSignals[11] = 518833500408858308962881361452944175;
|
publicSignals[11] = 518833500408858308962881361452944175;
|
||||||
publicSignals[12] = 1163210548821508924802510293967109414;
|
publicSignals[12] = 1163210548821508924802510293967109414;
|
||||||
publicSignals[13] = 1361351910698751746280135795885107181;
|
publicSignals[13] = 1361351910698751746280135795885107181;
|
||||||
publicSignals[14] = 1445969488612593115566934629427756345;
|
publicSignals[14] = 1445969488612593115566934629427756345;
|
||||||
publicSignals[15] = 2457340995040159831545380614838948388;
|
publicSignals[15] = 2457340995040159831545380614838948388;
|
||||||
publicSignals[16] = 2612807374136932899648418365680887439;
|
publicSignals[16] = 2612807374136932899648418365680887439;
|
||||||
publicSignals[17] = 16021263889082005631675788949457422;
|
publicSignals[17] = 16021263889082005631675788949457422;
|
||||||
publicSignals[18] = 299744519975649772895460843780023483;
|
publicSignals[18] = 299744519975649772895460843780023483;
|
||||||
publicSignals[19] = 3933359104846508935112096715593287;
|
publicSignals[19] = 3933359104846508935112096715593287;
|
||||||
publicSignals[20] = 556307310756571904145052207427031380052712977221;
|
publicSignals[20] = 556307310756571904145052207427031380052712977221;
|
||||||
|
|
||||||
// TODO switch order
|
// TODO switch order
|
||||||
uint256[2] memory proof_a = [
|
uint256[2] memory proof_a = [
|
||||||
9363006867611269678582925935753021647889027030446896413835957187406043727690,
|
9363006867611269678582925935753021647889027030446896413835957187406043727690,
|
||||||
21630169556253404895678159104497446719574525736987888783761908716313881927992
|
21630169556253404895678159104497446719574525736987888783761908716313881927992
|
||||||
];
|
];
|
||||||
// Note: you need to swap the order of the two elements in each subarray
|
// Note: you need to swap the order of the two elements in each subarray
|
||||||
uint256[2][2] memory proof_b = [
|
uint256[2][2] memory proof_b = [
|
||||||
[16566593201830840943252718762249962483142131594763397873538075518277702645082, 18567659038303546225106951504886253604470228016916658528973206870511276829533],
|
[
|
||||||
[2266080565824575322432873090363833504418041632970946239667340737263413898232, 2242723441612422425510136818011613824051492998493014918147869951941405078798]
|
16566593201830840943252718762249962483142131594763397873538075518277702645082,
|
||||||
];
|
18567659038303546225106951504886253604470228016916658528973206870511276829533
|
||||||
uint256[2] memory proof_c = [
|
],
|
||||||
12224501323997049527817799755022184802988108888333268634200461535503052305125,
|
[
|
||||||
3177656185967472916322211236519001250723481802804621893491948147849123768548
|
2266080565824575322432873090363833504418041632970946239667340737263413898232,
|
||||||
];
|
2242723441612422425510136818011613824051492998493014918147869951941405078798
|
||||||
// Test proof verification
|
]
|
||||||
bool verified = proofVerifier.verifyProof(proof_a, proof_b, proof_c, publicSignals);
|
];
|
||||||
assertEq(verified, true);
|
uint256[2] memory proof_c = [
|
||||||
|
12224501323997049527817799755022184802988108888333268634200461535503052305125,
|
||||||
|
3177656185967472916322211236519001250723481802804621893491948147849123768548
|
||||||
|
];
|
||||||
|
// Test proof verification
|
||||||
|
bool verified = proofVerifier.verifyProof(proof_a, proof_b, proof_c, publicSignals);
|
||||||
|
assertEq(verified, true);
|
||||||
|
|
||||||
// Test mint after spoofing msg.sender
|
// Test mint after spoofing msg.sender
|
||||||
Vm vm = Vm(VM_ADDR);
|
Vm vm = Vm(VM_ADDR);
|
||||||
vm.startPrank(0x6171aeBcC9e9B9E1D90EC9C2E124982932297345);
|
vm.startPrank(0x6171aeBcC9e9B9E1D90EC9C2E124982932297345);
|
||||||
testVerifier.mint(proof_a, proof_b, proof_c, publicSignals);
|
testVerifier.mint(proof_a, proof_b, proof_c, publicSignals);
|
||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
}
|
}
|
||||||
|
|
||||||
function testSVG() public {
|
function testSVG() public {
|
||||||
testVerifyYushEmail();
|
testVerifyYushEmail();
|
||||||
testVerifyTestEmail();
|
testVerifyTestEmail();
|
||||||
string memory svgValue = testVerifier.tokenURI(1);
|
string memory svgValue = testVerifier.tokenURI(1);
|
||||||
console.log(svgValue);
|
console.log(svgValue);
|
||||||
assert(bytes(svgValue).length > 0);
|
assert(bytes(svgValue).length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testChainID() public view {
|
||||||
|
uint256 chainId;
|
||||||
|
assembly {
|
||||||
|
chainId := chainid()
|
||||||
|
}
|
||||||
|
console.log(chainId);
|
||||||
|
// Local chain, xdai, goerli, mainnet
|
||||||
|
assert(chainId == 31337 || chainId == 100 || chainId == 5 || chainId == 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
129
src/contracts/src/utils/MailServer.sol
Normal file
129
src/contracts/src/utils/MailServer.sol
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "forge-std/console.sol";
|
||||||
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||||
|
|
||||||
|
contract MailServer is Ownable {
|
||||||
|
uint16 constant rsa_modulus_chunks_len = 17;
|
||||||
|
mapping(string => uint256[rsa_modulus_chunks_len]) verifiedMailserverKeys;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// Do dig TXT outgoing._domainkey.twitter.com to verify these.
|
||||||
|
// This is the base 2^121 representation of that key.
|
||||||
|
// Circom bigint: represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k)
|
||||||
|
initMailserverKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initMailserverKeys() internal {
|
||||||
|
// TODO: Create a type that takes in a raw RSA key, the bit count,
|
||||||
|
// and whether or not its base64 encoded, and converts it to either 8 or 16 signals
|
||||||
|
verifiedMailserverKeys["gmail.com"][0] = 1886180949733815343726466520516992271;
|
||||||
|
verifiedMailserverKeys["gmail.com"][1] = 1551366393280668736485689616947198994;
|
||||||
|
verifiedMailserverKeys["gmail.com"][2] = 1279057759087427731263511728885611780;
|
||||||
|
verifiedMailserverKeys["gmail.com"][3] = 1711061746895435768547617398484429347;
|
||||||
|
verifiedMailserverKeys["gmail.com"][4] = 2329140368326888129406637741054282011;
|
||||||
|
verifiedMailserverKeys["gmail.com"][5] = 2094858442222190249786465516374057361;
|
||||||
|
verifiedMailserverKeys["gmail.com"][6] = 2584558507302599829894674874442909655;
|
||||||
|
verifiedMailserverKeys["gmail.com"][7] = 1521552483858643935889582214011445675;
|
||||||
|
verifiedMailserverKeys["gmail.com"][8] = 176847449040377757035522930003764000;
|
||||||
|
verifiedMailserverKeys["gmail.com"][9] = 632921959964166974634188077062540145;
|
||||||
|
verifiedMailserverKeys["gmail.com"][10] = 2172441457165086627497230906075093832;
|
||||||
|
verifiedMailserverKeys["gmail.com"][11] = 248112436365636977369105357296082574;
|
||||||
|
verifiedMailserverKeys["gmail.com"][12] = 1408592841800630696650784801114783401;
|
||||||
|
verifiedMailserverKeys["gmail.com"][13] = 364610811473321782531041012695979858;
|
||||||
|
verifiedMailserverKeys["gmail.com"][14] = 342338521965453258686441392321054163;
|
||||||
|
verifiedMailserverKeys["gmail.com"][15] = 2269703683857229911110544415296249295;
|
||||||
|
verifiedMailserverKeys["gmail.com"][16] = 3643644972862751728748413716653892;
|
||||||
|
|
||||||
|
verifiedMailserverKeys["hotmail.com"][0] = 128339925410438117770406273090474249;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][1] = 2158906895782814996316644028571725310;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][2] = 2278019331164769360372919938620729773;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][3] = 1305319804455735154587383372570664109;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][4] = 2358345194772578919713586294428642696;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][5] = 1333692900109074470874155333266985021;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][6] = 2252956899717870524129098594286063236;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][7] = 1963190090223950324858653797870319519;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][8] = 2099240641399560863760865662500577339;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][9] = 1591320380606901546957315803395187883;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][10] = 1943831890994545117064894677442719428;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][11] = 2243327453964709681573059557263184139;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][12] = 1078181067739519006314708889181549671;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][13] = 2209638307239559037039565345615684964;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][14] = 1936371786309180968911326337008120155;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][15] = 2611115500285740051274748743252547506;
|
||||||
|
verifiedMailserverKeys["hotmail.com"][16] = 3841983033048617585564391738126779;
|
||||||
|
|
||||||
|
verifiedMailserverKeys["ethereum.org"][0] = 119886678941863893035426121053426453;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][1] = 1819786846289142128062035525540154587;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][2] = 18664768675154515296388092785538021;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][3] = 2452916380017370778812419704280324749;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][4] = 147541693845229442834461965414634823;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][5] = 714676313158744653841521918164405002;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][6] = 1495951612535183023869749054624579068;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][7] = 974892773071523448175479681445882254;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][8] = 53117264910028079;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][9] = 0;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][10] = 0;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][11] = 0;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][12] = 0;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][13] = 0;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][14] = 0;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][15] = 0;
|
||||||
|
verifiedMailserverKeys["ethereum.org"][16] = 0;
|
||||||
|
|
||||||
|
verifiedMailserverKeys["twitter.com"][0] = 1634582323953821262989958727173988295;
|
||||||
|
verifiedMailserverKeys["twitter.com"][1] = 1938094444722442142315201757874145583;
|
||||||
|
verifiedMailserverKeys["twitter.com"][2] = 375300260153333632727697921604599470;
|
||||||
|
verifiedMailserverKeys["twitter.com"][3] = 1369658125109277828425429339149824874;
|
||||||
|
verifiedMailserverKeys["twitter.com"][4] = 1589384595547333389911397650751436647;
|
||||||
|
verifiedMailserverKeys["twitter.com"][5] = 1428144289938431173655248321840778928;
|
||||||
|
verifiedMailserverKeys["twitter.com"][6] = 1919508490085653366961918211405731923;
|
||||||
|
verifiedMailserverKeys["twitter.com"][7] = 2358009612379481320362782200045159837;
|
||||||
|
verifiedMailserverKeys["twitter.com"][8] = 518833500408858308962881361452944175;
|
||||||
|
verifiedMailserverKeys["twitter.com"][9] = 1163210548821508924802510293967109414;
|
||||||
|
verifiedMailserverKeys["twitter.com"][10] = 1361351910698751746280135795885107181;
|
||||||
|
verifiedMailserverKeys["twitter.com"][11] = 1445969488612593115566934629427756345;
|
||||||
|
verifiedMailserverKeys["twitter.com"][12] = 2457340995040159831545380614838948388;
|
||||||
|
verifiedMailserverKeys["twitter.com"][13] = 2612807374136932899648418365680887439;
|
||||||
|
verifiedMailserverKeys["twitter.com"][14] = 16021263889082005631675788949457422;
|
||||||
|
verifiedMailserverKeys["twitter.com"][15] = 299744519975649772895460843780023483;
|
||||||
|
verifiedMailserverKeys["twitter.com"][16] = 3933359104846508935112096715593287;
|
||||||
|
|
||||||
|
verifiedMailserverKeys["skiff.com"][0] = 2637270478154147701703365710201556843;
|
||||||
|
verifiedMailserverKeys["skiff.com"][1] = 2082690054369201099288110516791254232;
|
||||||
|
verifiedMailserverKeys["skiff.com"][2] = 1108253255381437937379143813840625818;
|
||||||
|
verifiedMailserverKeys["skiff.com"][3] = 1535554154331979875086566323552212673;
|
||||||
|
verifiedMailserverKeys["skiff.com"][4] = 273019276149049264013012583938735085;
|
||||||
|
verifiedMailserverKeys["skiff.com"][5] = 741436192387359949728618527229215889;
|
||||||
|
verifiedMailserverKeys["skiff.com"][6] = 1851608307869135205473270393049341043;
|
||||||
|
verifiedMailserverKeys["skiff.com"][7] = 1428718881138594152975742734455140338;
|
||||||
|
verifiedMailserverKeys["skiff.com"][8] = 778850382237088374273157869416671135;
|
||||||
|
verifiedMailserverKeys["skiff.com"][9] = 549599381370898291203601849666570597;
|
||||||
|
verifiedMailserverKeys["skiff.com"][10] = 221161044322752364431317167498442512;
|
||||||
|
verifiedMailserverKeys["skiff.com"][11] = 2041801755941244198449288035460748224;
|
||||||
|
verifiedMailserverKeys["skiff.com"][12] = 1083114189020989870026920716001138899;
|
||||||
|
verifiedMailserverKeys["skiff.com"][13] = 1380362773644527202561949550864154963;
|
||||||
|
verifiedMailserverKeys["skiff.com"][14] = 1366599807917971505788646146248798329;
|
||||||
|
verifiedMailserverKeys["skiff.com"][15] = 391565989352979266796804441125988853;
|
||||||
|
verifiedMailserverKeys["skiff.com"][16] = 3704766395208948862861103932863036;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _stringEq(string memory a, string memory b) internal pure returns (bool) {
|
||||||
|
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isVerified(string memory domain, uint256 index, uint256 val) public view returns (bool) {
|
||||||
|
// Allow external queries on mapping
|
||||||
|
if (verifiedMailserverKeys[domain][index] != val) {
|
||||||
|
console.log(verifiedMailserverKeys[domain][index], val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return verifiedMailserverKeys[domain][index] == val;
|
||||||
|
}
|
||||||
|
|
||||||
|
function editMailserverKey(string memory domain, uint256 index, uint256 val) public onlyOwner {
|
||||||
|
verifiedMailserverKeys[domain][index] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add DNSSEC verification to add a key as well
|
||||||
|
}
|
||||||
260
src/contracts/src/utils/StringUtils.sol
Normal file
260
src/contracts/src/utils/StringUtils.sol
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.7.6;
|
||||||
|
|
||||||
|
// https://github.com/nalinbhardwaj/ethdosnumber/blob/main/ethdos-contracts/src/HexStrings.sol
|
||||||
|
library StringUtils {
|
||||||
|
bytes16 internal constant ALPHABET = "0123456789abcdef";
|
||||||
|
|
||||||
|
/// @notice Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
|
||||||
|
/// @dev Credit to Open Zeppelin under MIT license https://github.com/OpenZeppelin/openzeppelin-contracts/blob/243adff49ce1700e0ecb99fe522fb16cff1d1ddc/contracts/utils/Strings.sol#L55
|
||||||
|
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
|
||||||
|
bytes memory buffer = new bytes(2 * length + 2);
|
||||||
|
buffer[0] = "0";
|
||||||
|
buffer[1] = "x";
|
||||||
|
for (uint256 i = 2 * length + 1; i > 1; --i) {
|
||||||
|
buffer[i] = ALPHABET[value & 0xf];
|
||||||
|
value >>= 4;
|
||||||
|
}
|
||||||
|
require(value == 0, "Strings: hex length insufficient");
|
||||||
|
return string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory) {
|
||||||
|
bytes memory buffer = new bytes(2 * length);
|
||||||
|
for (uint256 i = buffer.length; i > 0; i--) {
|
||||||
|
buffer[i - 1] = ALPHABET[value & 0xf];
|
||||||
|
value >>= 4;
|
||||||
|
}
|
||||||
|
return string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toString(uint256 value) internal pure returns (string memory) {
|
||||||
|
return toString(abi.encodePacked(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function toString(bytes32 value) internal pure returns (string memory) {
|
||||||
|
return toString(abi.encodePacked(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function toString(address account) internal pure returns (string memory) {
|
||||||
|
return toString(abi.encodePacked(account));
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringEq(string memory a, string memory b) internal pure returns (bool) {
|
||||||
|
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
function toString(bytes memory data) internal pure returns (string memory) {
|
||||||
|
bytes memory alphabet = "0123456789abcdef";
|
||||||
|
|
||||||
|
bytes memory str = new bytes(2 + data.length * 2);
|
||||||
|
str[0] = "0";
|
||||||
|
str[1] = "x";
|
||||||
|
for (uint256 i = 0; i < data.length; i++) {
|
||||||
|
str[2 + i * 2] = alphabet[uint256(uint8(data[i] >> 4))];
|
||||||
|
str[3 + i * 2] = alphabet[uint256(uint8(data[i] & 0x0f))];
|
||||||
|
}
|
||||||
|
return string(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertPackedByteToString(uint256 packedByte, uint256 maxBytes, uint256 packSize)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (string memory extractedString)
|
||||||
|
{
|
||||||
|
uint256[] memory packedBytes = new uint256[](1);
|
||||||
|
packedBytes[0] = packedByte;
|
||||||
|
return convertPackedBytesToString(packedBytes, maxBytes, packSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unpacks uint256s into bytes and then extracts the non-zero characters
|
||||||
|
// Only extracts contiguous non-zero characters and ensures theres only 1 such state
|
||||||
|
// Note that unpackedLen may be more than packedBytes.length * 8 since there may be 0s
|
||||||
|
// TODO: Remove console.logs and define this as a pure function instead of a view
|
||||||
|
function convertPackedBytesToString(uint256[] memory packedBytes, uint256 maxBytes, uint256 packSize)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (string memory extractedString)
|
||||||
|
{
|
||||||
|
uint8 state = 0;
|
||||||
|
// bytes: 0 0 0 0 y u s h _ g 0 0 0
|
||||||
|
// state: 0 0 0 0 1 1 1 1 1 1 2 2 2
|
||||||
|
bytes memory nonzeroBytesArray = new bytes(packedBytes.length * 7);
|
||||||
|
uint256 nonzeroBytesArrayIndex = 0;
|
||||||
|
for (uint16 i = 0; i < packedBytes.length; i++) {
|
||||||
|
uint256 packedByte = packedBytes[i];
|
||||||
|
uint8[] memory unpackedBytes = new uint8[](packSize);
|
||||||
|
for (uint256 j = 0; j < packSize; j++) {
|
||||||
|
unpackedBytes[j] = uint8(packedByte >> (j * 8));
|
||||||
|
}
|
||||||
|
for (uint256 j = 0; j < packSize; j++) {
|
||||||
|
uint256 unpackedByte = unpackedBytes[j]; //unpackedBytes[j];
|
||||||
|
// console.log(i, j, state, unpackedByte);
|
||||||
|
if (unpackedByte != 0) {
|
||||||
|
nonzeroBytesArray[nonzeroBytesArrayIndex] = bytes1(uint8(unpackedByte));
|
||||||
|
nonzeroBytesArrayIndex++;
|
||||||
|
if (state % 2 == 0) {
|
||||||
|
state += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (state % 2 == 1) {
|
||||||
|
state += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
packedByte = packedByte >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require(state >= 1, "Invalid final state of packed bytes in email, or value is 0!");
|
||||||
|
require(nonzeroBytesArrayIndex <= maxBytes, "Packed bytes more than allowed max length!");
|
||||||
|
string memory returnValue = removeTrailingZeros(string(nonzeroBytesArray));
|
||||||
|
return returnValue;
|
||||||
|
// Have to end at the end of the email -- state cannot be 1 since there should be an email footer
|
||||||
|
}
|
||||||
|
|
||||||
|
function bytes32ToString(bytes32 input) internal pure returns (string memory) {
|
||||||
|
uint256 i;
|
||||||
|
for (i = 0; i < 32 && input[i] != 0; i++) {}
|
||||||
|
bytes memory resultBytes = new bytes(i);
|
||||||
|
for (i = 0; i < 32 && input[i] != 0; i++) {
|
||||||
|
resultBytes[i] = input[i];
|
||||||
|
}
|
||||||
|
return string(resultBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sliceArray is used to slice an array of uint256s from start-end into a new array of uint256s
|
||||||
|
function sliceArray(uint256[] memory input, uint256 start, uint256 end) internal pure returns (uint256[] memory) {
|
||||||
|
require(start <= end && end <= input.length, "Invalid slice indices");
|
||||||
|
uint256[] memory result = new uint256[](end - start);
|
||||||
|
for (uint256 i = start; i < end; i++) {
|
||||||
|
result[i - start] = input[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stringToUint is used to convert a string like "45" to a uint256 4
|
||||||
|
function stringToUint(string memory s) internal pure returns (uint256) {
|
||||||
|
bytes memory b = bytes(s);
|
||||||
|
uint256 result = 0;
|
||||||
|
for (uint256 i = 0; i < b.length; i++) {
|
||||||
|
if (b[i] >= 0x30 && b[i] <= 0x39) {
|
||||||
|
result = result * 10 + (uint256(uint8(b[i])) - 48);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Currently truncates decimals
|
||||||
|
if (b[i] == 0x2E) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getDomainFromEmail is used to extract the domain from an email i.e. the part after the @
|
||||||
|
function getDomainFromEmail(string memory fromEmail) internal pure returns (string memory) {
|
||||||
|
bytes memory emailBytes = bytes(fromEmail);
|
||||||
|
uint256 atIndex;
|
||||||
|
for (uint256 i = 0; i < emailBytes.length; i++) {
|
||||||
|
if (emailBytes[i] == "@") {
|
||||||
|
atIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes memory domainBytes = new bytes(emailBytes.length - atIndex - 1);
|
||||||
|
for (uint256 j = 0; j < domainBytes.length; j++) {
|
||||||
|
domainBytes[j] = emailBytes[atIndex + 1 + j];
|
||||||
|
}
|
||||||
|
return bytes32ToString(bytes32(bytes(domainBytes)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeTrailingZeros(string memory input) public pure returns (string memory) {
|
||||||
|
bytes memory inputBytes = bytes(input);
|
||||||
|
uint256 endIndex = inputBytes.length;
|
||||||
|
|
||||||
|
for (uint256 i = 0; i < inputBytes.length; i++) {
|
||||||
|
if (inputBytes[i] == 0) {
|
||||||
|
endIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes memory resultBytes = new bytes(endIndex);
|
||||||
|
for (uint256 i = 0; i < endIndex; i++) {
|
||||||
|
resultBytes[i] = inputBytes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(resultBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upper/lower string utils from https://github.com/willitscale/solidity-util/blob/master/lib/Strings.sol
|
||||||
|
/**
|
||||||
|
* Upper
|
||||||
|
*
|
||||||
|
* Converts all the values of a string to their corresponding upper case
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @param _base When being used for a data type this is the extended object
|
||||||
|
* otherwise this is the string base to convert to upper case
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function upper(string memory _base) public pure returns (string memory) {
|
||||||
|
bytes memory _baseBytes = bytes(_base);
|
||||||
|
for (uint256 i = 0; i < _baseBytes.length; i++) {
|
||||||
|
_baseBytes[i] = _upper(_baseBytes[i]);
|
||||||
|
}
|
||||||
|
return string(_baseBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lower
|
||||||
|
*
|
||||||
|
* Converts all the values of a string to their corresponding lower case
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @param _base When being used for a data type this is the extended object
|
||||||
|
* otherwise this is the string base to convert to lower case
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function lower(string memory _base) public pure returns (string memory) {
|
||||||
|
bytes memory _baseBytes = bytes(_base);
|
||||||
|
for (uint256 i = 0; i < _baseBytes.length; i++) {
|
||||||
|
_baseBytes[i] = _lower(_baseBytes[i]);
|
||||||
|
}
|
||||||
|
return string(_baseBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upper
|
||||||
|
*
|
||||||
|
* Convert an alphabetic character to upper case and return the original
|
||||||
|
* value when not alphabetic
|
||||||
|
*
|
||||||
|
* @param _b1 The byte to be converted to upper case
|
||||||
|
* @return bytes1 The converted value if the passed value was alphabetic
|
||||||
|
* and in a lower case otherwise returns the original value
|
||||||
|
*/
|
||||||
|
function _upper(bytes1 _b1) private pure returns (bytes1) {
|
||||||
|
if (_b1 >= 0x61 && _b1 <= 0x7A) {
|
||||||
|
return bytes1(uint8(_b1) - 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lower
|
||||||
|
*
|
||||||
|
* Convert an alphabetic character to lower case and return the original
|
||||||
|
* value when not alphabetic
|
||||||
|
*
|
||||||
|
* @param _b1 The byte to be converted to lower case
|
||||||
|
* @return bytes1 The converted value if the passed value was alphabetic
|
||||||
|
* and in a upper case otherwise returns the original value
|
||||||
|
*/
|
||||||
|
function _lower(bytes1 _b1) private pure returns (bytes1) {
|
||||||
|
if (_b1 >= 0x41 && _b1 <= 0x5A) {
|
||||||
|
return bytes1(uint8(_b1) + 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _b1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,10 +4,11 @@ export function bytesToString(bytes: Uint8Array): string {
|
|||||||
return new TextDecoder().decode(bytes);
|
return new TextDecoder().decode(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stringToUint8Array
|
||||||
export function stringToBytes(str: string) {
|
export function stringToBytes(str: string) {
|
||||||
const encodedText = new TextEncoder().encode(str);
|
const encodedText = new TextEncoder().encode(str);
|
||||||
const toReturn = Uint8Array.from(str, (x) => x.charCodeAt(0));
|
const toReturn = Uint8Array.from(str, (x) => x.charCodeAt(0));
|
||||||
const buf = Buffer.from(str, "utf8");
|
// const buf = Buffer.from(str, "utf8");
|
||||||
return toReturn;
|
return toReturn;
|
||||||
// TODO: Check encoding mismatch if the proof doesnt work
|
// TODO: Check encoding mismatch if the proof doesnt work
|
||||||
// Note that our custom encoding function maps (239, 191, 189) -> (253)
|
// Note that our custom encoding function maps (239, 191, 189) -> (253)
|
||||||
|
|||||||
@@ -1,11 +1,3 @@
|
|||||||
// the numeric form of the payload1 passed into the primitive
|
|
||||||
// corresponds to the openssh signature produced by the following command:
|
|
||||||
// echo "E PLURIBUS UNUM; DO NOT SHARE" | ssh-keygen -Y sign -n double-blind.xyz -f ~/.ssh/id_rsa | pbcopy
|
|
||||||
export const MAGIC_DOUBLE_BLIND_BASE_MESSAGE =
|
|
||||||
14447023197094784173331616578829287000074783130802912942914027114823662617007553911501158244718575362051758829289159984830457466395841150324770159971462582912755545324694933673046215187947905307019469n;
|
|
||||||
// Length in bits
|
|
||||||
export const MAGIC_DOUBLE_BLIND_BASE_MESSAGE_LEN = 672;
|
|
||||||
|
|
||||||
export const CIRCOM_FIELD_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
export const CIRCOM_FIELD_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
||||||
export const MAX_HEADER_PADDED_BYTES = 1024; // NOTE: this must be the same as the first arg in the email in main args circom
|
export const MAX_HEADER_PADDED_BYTES = 1024; // NOTE: this must be the same as the first arg in the email in main args circom
|
||||||
export const MAX_BODY_PADDED_BYTES = 1536; // NOTE: this must be the same as the arg to sha the remainder number of bytes in the email in main args circom
|
export const MAX_BODY_PADDED_BYTES = 1536; // NOTE: this must be the same as the arg to sha the remainder number of bytes in the email in main args circom
|
||||||
|
|||||||
9
src/scripts/convert_pem.py
Normal file
9
src/scripts/convert_pem.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from Crypto.PublicKey import RSA
|
||||||
|
from Crypto.Util.number import long_to_bytes
|
||||||
|
|
||||||
|
n = 93230141572400662170783753550307761264955081869460053639895434883348985555848023394186640556096911451485975596801521695255694734630678338219590345941037464687540511026989400486063960033279502094209058208866021776512104192812763971526144421706090065402405684981981627715733224518387601434649205998732618652003
|
||||||
|
e = 65537
|
||||||
|
|
||||||
|
key = RSA.construct((n, e))
|
||||||
|
with open("rsa_pub_key.der", "wb") as f:
|
||||||
|
f.write(key.exportKey("DER"))
|
||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
Uint8ArrayToCharArray,
|
Uint8ArrayToCharArray,
|
||||||
assert,
|
assert,
|
||||||
mergeUInt8Arrays,
|
mergeUInt8Arrays,
|
||||||
|
int8toBytes,
|
||||||
int64toBytes,
|
int64toBytes,
|
||||||
} from "../helpers/binaryFormat";
|
} from "../helpers/binaryFormat";
|
||||||
import { CIRCOM_FIELD_MODULUS, MAX_HEADER_PADDED_BYTES, MAX_BODY_PADDED_BYTES, STRING_PRESELECTOR } from "../helpers/constants";
|
import { CIRCOM_FIELD_MODULUS, MAX_HEADER_PADDED_BYTES, MAX_BODY_PADDED_BYTES, STRING_PRESELECTOR } from "../helpers/constants";
|
||||||
@@ -24,7 +25,7 @@ async function getArgs() {
|
|||||||
const emailFileArg = args.find((arg) => arg.startsWith("--email_file="));
|
const emailFileArg = args.find((arg) => arg.startsWith("--email_file="));
|
||||||
const nonceArg = args.find((arg) => arg.startsWith("--nonce="));
|
const nonceArg = args.find((arg) => arg.startsWith("--nonce="));
|
||||||
|
|
||||||
const email_file = emailFileArg ? emailFileArg.split("=")[1] : "test_sendgrid.eml";
|
const email_file = emailFileArg ? emailFileArg.split("=")[1] : "emls/zktestemail_twitter.eml";
|
||||||
const nonce = nonceArg ? nonceArg.split("=")[1] : null;
|
const nonce = nonceArg ? nonceArg.split("=")[1] : null;
|
||||||
|
|
||||||
return { email_file, nonce };
|
return { email_file, nonce };
|
||||||
@@ -47,17 +48,25 @@ export interface ICircuitInputs {
|
|||||||
address_plus_one?: string;
|
address_plus_one?: string;
|
||||||
twitter_username_idx?: string;
|
twitter_username_idx?: string;
|
||||||
email_from_idx?: string;
|
email_from_idx?: string;
|
||||||
|
|
||||||
|
// subject commands only
|
||||||
|
command_idx?: string;
|
||||||
|
message_id_idx?: string;
|
||||||
amount_idx?: string;
|
amount_idx?: string;
|
||||||
currency_idx?: string;
|
currency_idx?: string;
|
||||||
recipient_idx?: string;
|
recipient_idx?: string;
|
||||||
|
custom_message_id_from?: string[];
|
||||||
|
custom_message_id_recipient?: string[];
|
||||||
|
nullifier?: string;
|
||||||
|
relayer?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CircuitType {
|
enum CircuitType {
|
||||||
RSA = "rsa",
|
RSA = "rsa",
|
||||||
SHA = "sha",
|
SHA = "sha",
|
||||||
TEST = "test",
|
TEST = "test",
|
||||||
EMAIL = "email",
|
EMAIL_TWITTER = "email_twitter",
|
||||||
SUBJECTPARSER = "subjectparser",
|
EMAIL_SUBJECT = "email_subject",
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findSelector(a: Uint8Array, selector: number[]): Promise<number> {
|
async function findSelector(a: Uint8Array, selector: number[]): Promise<number> {
|
||||||
@@ -77,6 +86,24 @@ async function findSelector(a: Uint8Array, selector: number[]): Promise<number>
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the part of str that appears after substr
|
||||||
|
function trimStrByStr(str: string, substr: string) {
|
||||||
|
const index = str.indexOf(substr);
|
||||||
|
if (index === -1) return str;
|
||||||
|
return str.slice(index + substr.length, str.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function strToCharArrayStr(str: string) {
|
||||||
|
return str.split("").map((char) => char.charCodeAt(0).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// padWithZero(bodyRemaining, MAX_BODY_PADDED_BYTES)
|
||||||
|
function padWithZero(arr: Uint8Array, length: number) {
|
||||||
|
while (arr.length < length) {
|
||||||
|
arr = mergeUInt8Arrays(arr, int8toBytes(0));
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
export async function getCircuitInputs(
|
export async function getCircuitInputs(
|
||||||
rsa_signature: BigInt,
|
rsa_signature: BigInt,
|
||||||
rsa_modulus: BigInt,
|
rsa_modulus: BigInt,
|
||||||
@@ -130,9 +157,7 @@ export async function getCircuitInputs(
|
|||||||
const bodyRemainingLen = bodyPaddedLen - precomputeText.length;
|
const bodyRemainingLen = bodyPaddedLen - precomputeText.length;
|
||||||
assert(bodyRemainingLen < MAX_BODY_PADDED_BYTES, "Invalid slice");
|
assert(bodyRemainingLen < MAX_BODY_PADDED_BYTES, "Invalid slice");
|
||||||
assert(bodyRemaining.length % 64 === 0, "Not going to be padded correctly with int64s");
|
assert(bodyRemaining.length % 64 === 0, "Not going to be padded correctly with int64s");
|
||||||
while (bodyRemaining.length < MAX_BODY_PADDED_BYTES) {
|
bodyRemaining = padWithZero(bodyRemaining, MAX_BODY_PADDED_BYTES);
|
||||||
bodyRemaining = mergeUInt8Arrays(bodyRemaining, int64toBytes(0));
|
|
||||||
}
|
|
||||||
assert(bodyRemaining.length === MAX_BODY_PADDED_BYTES, "Invalid slice");
|
assert(bodyRemaining.length === MAX_BODY_PADDED_BYTES, "Invalid slice");
|
||||||
const bodyShaPrecompute = await partialSha(precomputeText, shaCutoffIndex);
|
const bodyShaPrecompute = await partialSha(precomputeText, shaCutoffIndex);
|
||||||
|
|
||||||
@@ -150,26 +175,16 @@ export async function getCircuitInputs(
|
|||||||
const body_hash_idx = bufferToString(message).indexOf(body_hash).toString();
|
const body_hash_idx = bufferToString(message).indexOf(body_hash).toString();
|
||||||
|
|
||||||
const address = bytesToBigInt(fromHex(eth_address)).toString();
|
const address = bytesToBigInt(fromHex(eth_address)).toString();
|
||||||
|
const nullifier = signature[0];
|
||||||
|
// bytesToBigInt(fromHex()).toString();
|
||||||
const address_plus_one = (bytesToBigInt(fromHex(eth_address)) + 1n).toString();
|
const address_plus_one = (bytesToBigInt(fromHex(eth_address)) + 1n).toString();
|
||||||
|
|
||||||
const USERNAME_SELECTOR = Buffer.from(STRING_PRESELECTOR);
|
const USERNAME_SELECTOR = Buffer.from(STRING_PRESELECTOR);
|
||||||
|
|
||||||
function trimStrByStr(str: string, substr: string) {
|
|
||||||
const index = str.indexOf(substr);
|
|
||||||
if (index === -1) {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
return str.slice(index + substr.length, str.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
let raw_header = Buffer.from(prehash_message_string).toString();
|
let raw_header = Buffer.from(prehash_message_string).toString();
|
||||||
const email_from_idx = raw_header.length - trimStrByStr(trimStrByStr(raw_header, "from:"), "<").length;
|
const email_from_idx = raw_header.length - trimStrByStr(trimStrByStr(raw_header, "from:"), "<").length;
|
||||||
let email_subject = trimStrByStr(raw_header, "subject:");
|
let email_subject = trimStrByStr(raw_header, "\r\nsubject:");
|
||||||
const amount_idx = raw_header.length - trimStrByStr(email_subject, "end ").length;
|
//in javascript, give me a function that extracts the first word in a string, everything before the first space
|
||||||
const currency_idx = raw_header.length - trimStrByStr(trimStrByStr(email_subject, "end "), " ").length;
|
|
||||||
const recipient_idx = raw_header.length - trimStrByStr(email_subject, "to ").length;
|
|
||||||
const twitter_username_idx = (Buffer.from(bodyRemaining).indexOf(USERNAME_SELECTOR) + USERNAME_SELECTOR.length).toString();
|
|
||||||
console.log("Indexes into header string are: ", email_from_idx, amount_idx, currency_idx, recipient_idx, twitter_username_idx);
|
|
||||||
|
|
||||||
if (circuit === CircuitType.RSA) {
|
if (circuit === CircuitType.RSA) {
|
||||||
circuitInputs = {
|
circuitInputs = {
|
||||||
@@ -177,7 +192,10 @@ export async function getCircuitInputs(
|
|||||||
signature,
|
signature,
|
||||||
base_message,
|
base_message,
|
||||||
};
|
};
|
||||||
} else if (circuit === CircuitType.EMAIL) {
|
} else if (circuit === CircuitType.EMAIL_TWITTER) {
|
||||||
|
const twitter_username_idx = (Buffer.from(bodyRemaining).indexOf(USERNAME_SELECTOR) + USERNAME_SELECTOR.length).toString();
|
||||||
|
console.log("Indexes into header string are: ", email_from_idx, twitter_username_idx);
|
||||||
|
|
||||||
circuitInputs = {
|
circuitInputs = {
|
||||||
in_padded,
|
in_padded,
|
||||||
modulus,
|
modulus,
|
||||||
@@ -192,19 +210,39 @@ export async function getCircuitInputs(
|
|||||||
body_hash_idx,
|
body_hash_idx,
|
||||||
// email_from_idx,
|
// email_from_idx,
|
||||||
};
|
};
|
||||||
} else if (circuit === CircuitType.SUBJECTPARSER) {
|
} else if (circuit === CircuitType.EMAIL_SUBJECT) {
|
||||||
|
// First word after "subject:" (usually send/Send)
|
||||||
|
const command = email_subject.split(" ")[0];
|
||||||
|
const command_idx = raw_header.length - email_subject.length;
|
||||||
|
// Index of first word after command
|
||||||
|
const amount_idx = raw_header.length - trimStrByStr(email_subject, command).length;
|
||||||
|
// Index of second word after command
|
||||||
|
const currency_idx = raw_header.length - trimStrByStr(trimStrByStr(email_subject, command), " ").length;
|
||||||
|
// Index of first word after subject and "to"
|
||||||
|
const recipient_idx = raw_header.length - trimStrByStr(email_subject, " to ").length;
|
||||||
|
// Used to get the private message-id
|
||||||
|
const message_id_idx = raw_header.length - trimStrByStr(raw_header, "\r\nmessage-id:<").length;
|
||||||
|
const message_id = raw_header.slice(message_id_idx).split(">\r\n")[0];
|
||||||
|
const MAX_MESSAGE_ID_LEN = 128;
|
||||||
|
const message_id_array = await Uint8ArrayToCharArray(padWithZero(stringToBytes(message_id), MAX_MESSAGE_ID_LEN));
|
||||||
|
console.log("Indexes into header string are: ", email_from_idx, amount_idx, currency_idx, recipient_idx);
|
||||||
|
|
||||||
circuitInputs = {
|
circuitInputs = {
|
||||||
in_padded,
|
in_padded,
|
||||||
modulus,
|
modulus,
|
||||||
signature,
|
signature,
|
||||||
in_len_padded_bytes,
|
in_len_padded_bytes,
|
||||||
address,
|
address: address,
|
||||||
address_plus_one,
|
nullifier: nullifier,
|
||||||
body_hash_idx,
|
body_hash_idx,
|
||||||
email_from_idx: email_from_idx.toString(),
|
email_from_idx: email_from_idx.toString(),
|
||||||
|
command_idx: command_idx.toString(),
|
||||||
|
message_id_idx: message_id_idx.toString(),
|
||||||
amount_idx: amount_idx.toString(),
|
amount_idx: amount_idx.toString(),
|
||||||
currency_idx: currency_idx.toString(),
|
currency_idx: currency_idx.toString(),
|
||||||
recipient_idx: recipient_idx.toString(),
|
recipient_idx: recipient_idx.toString(),
|
||||||
|
custom_message_id_from: message_id_array,
|
||||||
|
custom_message_id_recipient: message_id_array,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
assert(circuit === CircuitType.SHA, "Invalid circuit type");
|
assert(circuit === CircuitType.SHA, "Invalid circuit type");
|
||||||
@@ -231,6 +269,8 @@ export async function generate_inputs(raw_email: Buffer | string, eth_address: s
|
|||||||
|
|
||||||
console.log("DKIM verification starting");
|
console.log("DKIM verification starting");
|
||||||
result = await dkimVerify(email);
|
result = await dkimVerify(email);
|
||||||
|
console.log("From:", result.headerFrom);
|
||||||
|
console.log("Results:", result.results[0]);
|
||||||
if (!result.results[0]) {
|
if (!result.results[0]) {
|
||||||
throw new Error(`No result found on dkim output ${result}`);
|
throw new Error(`No result found on dkim output ${result}`);
|
||||||
} else {
|
} else {
|
||||||
@@ -245,7 +285,7 @@ export async function generate_inputs(raw_email: Buffer | string, eth_address: s
|
|||||||
const _ = result.results[0].publicKey.toString();
|
const _ = result.results[0].publicKey.toString();
|
||||||
console.log("DKIM verification successful");
|
console.log("DKIM verification successful");
|
||||||
// try {
|
// try {
|
||||||
// // TODO: Condiiton code on if there is an internet connection, run this code
|
// // TODO: Condition code on if there is an internet connection, run this code
|
||||||
// var frozen = Cryo.stringify(result);
|
// var frozen = Cryo.stringify(result);
|
||||||
// fs.writeFileSync(`./email_cache_2.json`, frozen, { flag: "w" });
|
// fs.writeFileSync(`./email_cache_2.json`, frozen, { flag: "w" });
|
||||||
// } catch (e) {
|
// } catch (e) {
|
||||||
@@ -257,7 +297,7 @@ export async function generate_inputs(raw_email: Buffer | string, eth_address: s
|
|||||||
let message = result.results[0].status.signature_header;
|
let message = result.results[0].status.signature_header;
|
||||||
let body = result.results[0].body;
|
let body = result.results[0].body;
|
||||||
let body_hash = result.results[0].bodyHash;
|
let body_hash = result.results[0].bodyHash;
|
||||||
let circuitType = CircuitType.EMAIL;
|
let circuitType = CircuitType.EMAIL_SUBJECT;
|
||||||
|
|
||||||
let pubkey = result.results[0].publicKey;
|
let pubkey = result.results[0].publicKey;
|
||||||
const pubKeyData = pki.publicKeyFromPem(pubkey.toString());
|
const pubKeyData = pki.publicKeyFromPem(pubkey.toString());
|
||||||
@@ -267,22 +307,6 @@ export async function generate_inputs(raw_email: Buffer | string, eth_address: s
|
|||||||
return fin_result.circuitInputs;
|
return fin_result.circuitInputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only called when the whole function is called from the command line, to read inputs
|
|
||||||
async function do_generate(writeToFile: boolean = true) {
|
|
||||||
const { email_file, nonce } = await getArgs();
|
|
||||||
const email = fs.readFileSync(email_file.trim());
|
|
||||||
console.log(email);
|
|
||||||
const gen_inputs = await generate_inputs(email, "0x0000000000000000000000000000000000000000", nonce);
|
|
||||||
console.log(JSON.stringify(gen_inputs));
|
|
||||||
if (writeToFile) {
|
|
||||||
const file_dir = email_file.substring(email_file.lastIndexOf("/") + 1);
|
|
||||||
const filename = nonce ? `${file_dir}/input_${nonce}.json` : "./circuits/inputs/input.json";
|
|
||||||
console.log(`Writing to default file ${filename}`);
|
|
||||||
fs.writeFileSync(filename, JSON.stringify(gen_inputs), { flag: "w" });
|
|
||||||
}
|
|
||||||
return gen_inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sometimes, newline encodings re-encode \r\n as just \n, so re-insert the \r so that the email hashes correctly
|
// Sometimes, newline encodings re-encode \r\n as just \n, so re-insert the \r so that the email hashes correctly
|
||||||
export async function insert13Before10(a: Uint8Array): Promise<Uint8Array> {
|
export async function insert13Before10(a: Uint8Array): Promise<Uint8Array> {
|
||||||
let ret = new Uint8Array(a.length + 1000);
|
let ret = new Uint8Array(a.length + 1000);
|
||||||
@@ -299,7 +323,24 @@ export async function insert13Before10(a: Uint8Array): Promise<Uint8Array> {
|
|||||||
return ret.slice(0, j);
|
return ret.slice(0, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only called when the whole function is called from the command line, to read inputs
|
||||||
|
// Will generate a test proof with the empty Ethereum address, that cannot be proven by anybody else
|
||||||
|
async function test_generate(writeToFile: boolean = true) {
|
||||||
|
const { email_file, nonce } = await getArgs();
|
||||||
|
const email = fs.readFileSync(email_file.trim());
|
||||||
|
console.log(email);
|
||||||
|
const gen_inputs = await generate_inputs(email, "0x0000000000000000000000000000000000000000", nonce);
|
||||||
|
console.log(JSON.stringify(gen_inputs));
|
||||||
|
if (writeToFile) {
|
||||||
|
const file_dir = email_file.substring(0, email_file.lastIndexOf("/") + 1);
|
||||||
|
const filename = nonce ? `${file_dir}/input_${nonce}.json` : "./circuits/inputs/input.json";
|
||||||
|
console.log(`Writing to default file ${filename}`);
|
||||||
|
fs.writeFileSync(filename, JSON.stringify(gen_inputs), { flag: "w" });
|
||||||
|
}
|
||||||
|
return gen_inputs;
|
||||||
|
}
|
||||||
|
|
||||||
// If file called directly with `npx tsx generate_inputs.ts`
|
// If file called directly with `npx tsx generate_inputs.ts`
|
||||||
if (typeof require !== "undefined" && require.main === module) {
|
if (typeof require !== "undefined" && require.main === module) {
|
||||||
do_generate(true);
|
test_generate(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "ESNext",
|
"target": "es2020",
|
||||||
"target": "ESNext",
|
"module": "esnext",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"types": ["vite/client"],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
@@ -16,8 +15,10 @@
|
|||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"typeRoots": ["./node_modules/@types", "./types"]
|
"typeRoots": ["./node_modules/@types", "./types"],
|
||||||
|
"types": ["node", "jest"],
|
||||||
|
"incremental": true
|
||||||
},
|
},
|
||||||
"include": [".", "../src/contracts"],
|
"include": ["src", "circuits/scripts/"],
|
||||||
"exclude": ["./dist"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
637
yarn.lock
637
yarn.lock
@@ -2755,7 +2755,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@openzeppelin/contracts@npm:^4.8.3":
|
"@openzeppelin/contracts@npm:^4.9.0":
|
||||||
version: 4.9.1
|
version: 4.9.1
|
||||||
resolution: "@openzeppelin/contracts@npm:4.9.1"
|
resolution: "@openzeppelin/contracts@npm:4.9.1"
|
||||||
checksum: 9bb3cc6aecd6c56d5ece10d9820d43e6e9c460395b75cc4af9b4e776f1a9e56c9906bc03538b0707e617dc31f1abdfffcbeedfecc8884358d864198ed73f59c1
|
checksum: 9bb3cc6aecd6c56d5ece10d9820d43e6e9c460395b75cc4af9b4e776f1a9e56c9906bc03538b0707e617dc31f1abdfffcbeedfecc8884358d864198ed73f59c1
|
||||||
@@ -3333,7 +3333,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/jest@npm:*, @types/jest@npm:^29.4.0":
|
"@types/jest@npm:*, @types/jest@npm:^29.5.1":
|
||||||
version: 29.5.2
|
version: 29.5.2
|
||||||
resolution: "@types/jest@npm:29.5.2"
|
resolution: "@types/jest@npm:29.5.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3391,6 +3391,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/mocha@npm:^10.0.1":
|
||||||
|
version: 10.0.1
|
||||||
|
resolution: "@types/mocha@npm:10.0.1"
|
||||||
|
checksum: 224ea9fce7b1734ccdb9aa99a622d902a538ce1847bca7fd22c5fb38adcf3ed536f50f48f587085db988a4bb3c2eb68f4b98e1cd6a38bc5547bd3bbbedc54495
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/ms@npm:*":
|
"@types/ms@npm:*":
|
||||||
version: 0.7.31
|
version: 0.7.31
|
||||||
resolution: "@types/ms@npm:0.7.31"
|
resolution: "@types/ms@npm:0.7.31"
|
||||||
@@ -4227,6 +4234,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"ansi-colors@npm:4.1.1":
|
||||||
|
version: 4.1.1
|
||||||
|
resolution: "ansi-colors@npm:4.1.1"
|
||||||
|
checksum: 138d04a51076cb085da0a7e2d000c5c0bb09f6e772ed5c65c53cb118d37f6c5f1637506d7155fb5f330f0abcf6f12fa2e489ac3f8cdab9da393bf1bb4f9a32b0
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ansi-escapes@npm:^4.2.1":
|
"ansi-escapes@npm:^4.2.1":
|
||||||
version: 4.3.2
|
version: 4.3.2
|
||||||
resolution: "ansi-escapes@npm:4.3.2"
|
resolution: "ansi-escapes@npm:4.3.2"
|
||||||
@@ -4449,6 +4463,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"assertion-error@npm:^1.1.0":
|
||||||
|
version: 1.1.0
|
||||||
|
resolution: "assertion-error@npm:1.1.0"
|
||||||
|
checksum: fd9429d3a3d4fd61782eb3962ae76b6d08aa7383123fca0596020013b3ebd6647891a85b05ce821c47d1471ed1271f00b0545cf6a4326cf2fc91efcc3b0fbecf
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ast-module-types@npm:^2.7.1":
|
"ast-module-types@npm:^2.7.1":
|
||||||
version: 2.7.1
|
version: 2.7.1
|
||||||
resolution: "ast-module-types@npm:2.7.1"
|
resolution: "ast-module-types@npm:2.7.1"
|
||||||
@@ -4959,6 +4980,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"browser-stdout@npm:1.3.1":
|
||||||
|
version: 1.3.1
|
||||||
|
resolution: "browser-stdout@npm:1.3.1"
|
||||||
|
checksum: b717b19b25952dd6af483e368f9bcd6b14b87740c3d226c2977a65e84666ffd67000bddea7d911f111a9b6ddc822b234de42d52ab6507bce4119a4cc003ef7b3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"browserify-aes@npm:^1.0.0, browserify-aes@npm:^1.0.4, browserify-aes@npm:^1.2.0":
|
"browserify-aes@npm:^1.0.0, browserify-aes@npm:^1.0.4, browserify-aes@npm:^1.2.0":
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
resolution: "browserify-aes@npm:1.2.0"
|
resolution: "browserify-aes@npm:1.2.0"
|
||||||
@@ -5282,7 +5310,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"camelcase@npm:^6.2.0":
|
"camelcase@npm:^6.0.0, camelcase@npm:^6.2.0":
|
||||||
version: 6.3.0
|
version: 6.3.0
|
||||||
resolution: "camelcase@npm:6.3.0"
|
resolution: "camelcase@npm:6.3.0"
|
||||||
checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d
|
checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d
|
||||||
@@ -5317,6 +5345,21 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"chai@npm:^4.3.6, chai@npm:^4.3.7":
|
||||||
|
version: 4.3.7
|
||||||
|
resolution: "chai@npm:4.3.7"
|
||||||
|
dependencies:
|
||||||
|
assertion-error: ^1.1.0
|
||||||
|
check-error: ^1.0.2
|
||||||
|
deep-eql: ^4.1.2
|
||||||
|
get-func-name: ^2.0.0
|
||||||
|
loupe: ^2.3.1
|
||||||
|
pathval: ^1.1.1
|
||||||
|
type-detect: ^4.0.5
|
||||||
|
checksum: 0bba7d267848015246a66995f044ce3f0ebc35e530da3cbdf171db744e14cbe301ab913a8d07caf7952b430257ccbb1a4a983c570a7c5748dc537897e5131f7c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"chalk-template@npm:0.4.0":
|
"chalk-template@npm:0.4.0":
|
||||||
version: 0.4.0
|
version: 0.4.0
|
||||||
resolution: "chalk-template@npm:0.4.0"
|
resolution: "chalk-template@npm:0.4.0"
|
||||||
@@ -5395,6 +5438,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"check-error@npm:^1.0.2":
|
||||||
|
version: 1.0.2
|
||||||
|
resolution: "check-error@npm:1.0.2"
|
||||||
|
checksum: d9d106504404b8addd1ee3f63f8c0eaa7cd962a1a28eb9c519b1c4a1dc7098be38007fc0060f045ee00f075fbb7a2a4f42abcf61d68323677e11ab98dc16042e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"check-types@npm:^11.1.1":
|
"check-types@npm:^11.1.1":
|
||||||
version: 11.2.2
|
version: 11.2.2
|
||||||
resolution: "check-types@npm:11.2.2"
|
resolution: "check-types@npm:11.2.2"
|
||||||
@@ -5431,7 +5481,14 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"chokidar@npm:^3.4.2, chokidar@npm:^3.5.1, chokidar@npm:^3.5.2":
|
"child_process@npm:^1.0.2":
|
||||||
|
version: 1.0.2
|
||||||
|
resolution: "child_process@npm:1.0.2"
|
||||||
|
checksum: bd814d82bc8c6e85ed6fb157878978121cd03b5296c09f6135fa3d081fd9a6a617a6d509c50397711df713af403331241a9c0397a7fad30672051485e156c2a1
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"chokidar@npm:3.5.3, chokidar@npm:^3.4.2, chokidar@npm:^3.5.1, chokidar@npm:^3.5.2":
|
||||||
version: 3.5.3
|
version: 3.5.3
|
||||||
resolution: "chokidar@npm:3.5.3"
|
resolution: "chokidar@npm:3.5.3"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5499,6 +5556,33 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"circom_runtime@npm:0.1.22":
|
||||||
|
version: 0.1.22
|
||||||
|
resolution: "circom_runtime@npm:0.1.22"
|
||||||
|
dependencies:
|
||||||
|
ffjavascript: 0.2.57
|
||||||
|
bin:
|
||||||
|
calcwit: calcwit.js
|
||||||
|
checksum: bf7b2e9f74cd7704ebc45ce686d4df49e58ed09114070a98beaab90e5ff7784d1943468ea3315bd4db638e6a76cda24e8b610aa2cd50be56adb4391e20469366
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"circom_tester@npm:^0.0.19":
|
||||||
|
version: 0.0.19
|
||||||
|
resolution: "circom_tester@npm:0.0.19"
|
||||||
|
dependencies:
|
||||||
|
chai: ^4.3.6
|
||||||
|
child_process: ^1.0.2
|
||||||
|
ffjavascript: ^0.2.56
|
||||||
|
fnv-plus: ^1.3.1
|
||||||
|
r1csfile: ^0.0.41
|
||||||
|
snarkjs: 0.5.0
|
||||||
|
tmp-promise: ^3.0.3
|
||||||
|
util: ^0.12.4
|
||||||
|
checksum: 703d7317493ddafb33462b5b0caf9b8a95bde938429e030d024fa7ac41ccb45a9ddbe8ebb93f91138dbee94bb2e0d504570c0aca070802d79ee532ba1ae5db0e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"circomlibjs@npm:^0.1.2":
|
"circomlibjs@npm:^0.1.2":
|
||||||
version: 0.1.7
|
version: 0.1.7
|
||||||
resolution: "circomlibjs@npm:0.1.7"
|
resolution: "circomlibjs@npm:0.1.7"
|
||||||
@@ -5595,6 +5679,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"cliui@npm:^7.0.2":
|
||||||
|
version: 7.0.4
|
||||||
|
resolution: "cliui@npm:7.0.4"
|
||||||
|
dependencies:
|
||||||
|
string-width: ^4.2.0
|
||||||
|
strip-ansi: ^6.0.0
|
||||||
|
wrap-ansi: ^7.0.0
|
||||||
|
checksum: ce2e8f578a4813806788ac399b9e866297740eecd4ad1823c27fd344d78b22c5f8597d548adbcc46f0573e43e21e751f39446c5a5e804a12aace402b7a315d7f
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"cliui@npm:^8.0.1":
|
"cliui@npm:^8.0.1":
|
||||||
version: 8.0.1
|
version: 8.0.1
|
||||||
resolution: "cliui@npm:8.0.1"
|
resolution: "cliui@npm:8.0.1"
|
||||||
@@ -6189,6 +6284,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"decamelize@npm:^4.0.0":
|
||||||
|
version: 4.0.0
|
||||||
|
resolution: "decamelize@npm:4.0.0"
|
||||||
|
checksum: b7d09b82652c39eead4d6678bb578e3bebd848add894b76d0f6b395bc45b2d692fb88d977e7cfb93c4ed6c119b05a1347cef261174916c2e75c0a8ca57da1809
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"decimal.js@npm:^10.4.2":
|
"decimal.js@npm:^10.4.2":
|
||||||
version: 10.4.3
|
version: 10.4.3
|
||||||
resolution: "decimal.js@npm:10.4.3"
|
resolution: "decimal.js@npm:10.4.3"
|
||||||
@@ -6219,6 +6321,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"deep-eql@npm:^4.1.2":
|
||||||
|
version: 4.1.3
|
||||||
|
resolution: "deep-eql@npm:4.1.3"
|
||||||
|
dependencies:
|
||||||
|
type-detect: ^4.0.0
|
||||||
|
checksum: 7f6d30cb41c713973dc07eaadded848b2ab0b835e518a88b91bea72f34e08c4c71d167a722a6f302d3a6108f05afd8e6d7650689a84d5d29ec7fe6220420397f
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"deep-equal@npm:^2.0.5":
|
"deep-equal@npm:^2.0.5":
|
||||||
version: 2.2.1
|
version: 2.2.1
|
||||||
resolution: "deep-equal@npm:2.2.1"
|
resolution: "deep-equal@npm:2.2.1"
|
||||||
@@ -6581,6 +6692,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"diff@npm:5.0.0":
|
||||||
|
version: 5.0.0
|
||||||
|
resolution: "diff@npm:5.0.0"
|
||||||
|
checksum: f19fe29284b633afdb2725c2a8bb7d25761ea54d321d8e67987ac851c5294be4afeab532bd84531e02583a3fe7f4014aa314a3eda84f5590e7a9e6b371ef3b46
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"diff@npm:^4.0.1":
|
"diff@npm:^4.0.1":
|
||||||
version: 4.0.2
|
version: 4.0.2
|
||||||
resolution: "diff@npm:4.0.2"
|
resolution: "diff@npm:4.0.2"
|
||||||
@@ -6685,95 +6803,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"double-blind@workspace:.":
|
|
||||||
version: 0.0.0-use.local
|
|
||||||
resolution: "double-blind@workspace:."
|
|
||||||
dependencies:
|
|
||||||
"@babel/preset-env": ^7.22.2
|
|
||||||
"@babel/preset-react": ^7.22.0
|
|
||||||
"@babel/preset-typescript": ^7.21.5
|
|
||||||
"@esbuild-plugins/node-globals-polyfill": ^0.2.3
|
|
||||||
"@esbuild-plugins/node-modules-polyfill": ^0.2.2
|
|
||||||
"@openzeppelin/contracts": ^4.8.3
|
|
||||||
"@rainbow-me/rainbowkit": ^0.8.0
|
|
||||||
"@testing-library/jest-dom": ^5.16.3
|
|
||||||
"@testing-library/react": ^12.1.4
|
|
||||||
"@testing-library/user-event": ^13.5.0
|
|
||||||
"@types/atob": ^2.1.2
|
|
||||||
"@types/jest": ^29.4.0
|
|
||||||
"@types/lodash": ^4.14.181
|
|
||||||
"@types/node": ^18.0.6
|
|
||||||
"@types/node-forge": ^1.3.2
|
|
||||||
"@types/pako": ^2.0.0
|
|
||||||
"@types/styled-components": ^5.1.24
|
|
||||||
"@types/tar-stream": ^2.2.2
|
|
||||||
"@types/yargs": ^17.0.24
|
|
||||||
"@vitejs/plugin-react": ^4.0.0
|
|
||||||
addressparser: ^1.0.1
|
|
||||||
atob: ^2.1.2
|
|
||||||
babel-preset-jest: ^29.5.0
|
|
||||||
base64-sol: ^1.1.0
|
|
||||||
browserify-fs: ^1.0.0
|
|
||||||
browserstack-local: ^1.5.1
|
|
||||||
browserstack-node-sdk: ^1.6.1
|
|
||||||
buffer: ^6.0.3
|
|
||||||
circomlibjs: ^0.1.2
|
|
||||||
cryo: ^0.0.6
|
|
||||||
crypto-browserify: ^3.12.0
|
|
||||||
ethereumjs-abi: ^0.6.8
|
|
||||||
ethers: ^5.7.1
|
|
||||||
forge-std: ^1.1.2
|
|
||||||
husky: ^8.0.3
|
|
||||||
jest: ^29.5.0
|
|
||||||
jest-environment-jsdom: ^29.5.0
|
|
||||||
jest-fetch-mock: ^3.0.3
|
|
||||||
jest-junit: ^15.0.0
|
|
||||||
jsdom-worker: ^0.3.0
|
|
||||||
libmime: ^5.1.0
|
|
||||||
localforage: ^1.10.0
|
|
||||||
lodash: ^4.17.21
|
|
||||||
madge: ^6.0.0
|
|
||||||
msw: ^1.0.1
|
|
||||||
next: ^12.3.1
|
|
||||||
node-forge: ^1.3.1
|
|
||||||
nodemon: ^2.0.19
|
|
||||||
pako: ^2.1.0
|
|
||||||
prettier: ^2.7.1
|
|
||||||
prettier-plugin-solidity: ^1.0.0-beta.24
|
|
||||||
process: ^0.11.10
|
|
||||||
puppeteer: 18.1
|
|
||||||
react: ^17.0.2
|
|
||||||
react-dom: ^17.0.2
|
|
||||||
react-dropzone: ^12.0.4
|
|
||||||
react-error-overlay: 6.0.9
|
|
||||||
react-json-view: ^1.21.3
|
|
||||||
react-router: ^6.2.2
|
|
||||||
react-router-dom: ^6.2.2
|
|
||||||
react-use: ^17.3.2
|
|
||||||
readline: ^1.3.0
|
|
||||||
rollup-plugin-node-polyfills: ^0.2.1
|
|
||||||
selenium-webdriver: ^4.8.1
|
|
||||||
serve: ^14.0.1
|
|
||||||
snarkjs: "https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e"
|
|
||||||
sshpk: ^1.17.0
|
|
||||||
styled-components: ^5.3.5
|
|
||||||
ts-node: ^10.9.1
|
|
||||||
ts-node-dev: ^2.0.0
|
|
||||||
typescript: ^4.8.3
|
|
||||||
update-browserslist-db: latest
|
|
||||||
util: ^0.12.5
|
|
||||||
vite: ^4.3.3
|
|
||||||
vite-plugin-commonjs: ^0.7.1
|
|
||||||
vite-plugin-ngmi-polyfill: ^0.0.2
|
|
||||||
vite-plugin-node-polyfills: ^0.8.2
|
|
||||||
vite-plugin-svgr: ^2.4.0
|
|
||||||
vite-tsconfig-paths: ^4.2.0
|
|
||||||
wagmi: ^0.6.8
|
|
||||||
web-vitals: ^2.1.4
|
|
||||||
yargs: ^17.7.1
|
|
||||||
languageName: unknown
|
|
||||||
linkType: soft
|
|
||||||
|
|
||||||
"duplexer3@npm:^0.1.4":
|
"duplexer3@npm:^0.1.4":
|
||||||
version: 0.1.5
|
version: 0.1.5
|
||||||
resolution: "duplexer3@npm:0.1.5"
|
resolution: "duplexer3@npm:0.1.5"
|
||||||
@@ -7128,6 +7157,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"escape-string-regexp@npm:4.0.0, escape-string-regexp@npm:^4.0.0":
|
||||||
|
version: 4.0.0
|
||||||
|
resolution: "escape-string-regexp@npm:4.0.0"
|
||||||
|
checksum: 98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"escape-string-regexp@npm:^1.0.5":
|
"escape-string-regexp@npm:^1.0.5":
|
||||||
version: 1.0.5
|
version: 1.0.5
|
||||||
resolution: "escape-string-regexp@npm:1.0.5"
|
resolution: "escape-string-regexp@npm:1.0.5"
|
||||||
@@ -7142,13 +7178,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"escape-string-regexp@npm:^4.0.0":
|
|
||||||
version: 4.0.0
|
|
||||||
resolution: "escape-string-regexp@npm:4.0.0"
|
|
||||||
checksum: 98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"escodegen@npm:^2.0.0":
|
"escodegen@npm:^2.0.0":
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
resolution: "escodegen@npm:2.0.0"
|
resolution: "escodegen@npm:2.0.0"
|
||||||
@@ -7663,7 +7692,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"ffjavascript@npm:^0.2.45, ffjavascript@npm:^0.2.48":
|
"ffjavascript@npm:0.2.57":
|
||||||
|
version: 0.2.57
|
||||||
|
resolution: "ffjavascript@npm:0.2.57"
|
||||||
|
dependencies:
|
||||||
|
wasmbuilder: 0.0.16
|
||||||
|
wasmcurves: 0.2.0
|
||||||
|
web-worker: ^1.2.0
|
||||||
|
checksum: 8f3e87b3e2739c607dfc2ef8cb36d92202da57b1323987cca09ade378c584a946b9d784607ee5e2193a2de6200afdc254c19f72f79145aa55d9a8688f83f6708
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"ffjavascript@npm:0.2.59, ffjavascript@npm:^0.2.45, ffjavascript@npm:^0.2.48, ffjavascript@npm:^0.2.56":
|
||||||
version: 0.2.59
|
version: 0.2.59
|
||||||
resolution: "ffjavascript@npm:0.2.59"
|
resolution: "ffjavascript@npm:0.2.59"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -7740,6 +7780,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"find-up@npm:5.0.0, find-up@npm:^5.0.0":
|
||||||
|
version: 5.0.0
|
||||||
|
resolution: "find-up@npm:5.0.0"
|
||||||
|
dependencies:
|
||||||
|
locate-path: ^6.0.0
|
||||||
|
path-exists: ^4.0.0
|
||||||
|
checksum: 07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"find-up@npm:^3.0.0":
|
"find-up@npm:^3.0.0":
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
resolution: "find-up@npm:3.0.0"
|
resolution: "find-up@npm:3.0.0"
|
||||||
@@ -7759,13 +7809,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"find-up@npm:^5.0.0":
|
"flat@npm:^5.0.2":
|
||||||
version: 5.0.0
|
version: 5.0.2
|
||||||
resolution: "find-up@npm:5.0.0"
|
resolution: "flat@npm:5.0.2"
|
||||||
dependencies:
|
bin:
|
||||||
locate-path: ^6.0.0
|
flat: cli.js
|
||||||
path-exists: ^4.0.0
|
checksum: 12a1536ac746db74881316a181499a78ef953632ddd28050b7a3a43c62ef5462e3357c8c29d76072bb635f147f7a9a1f0c02efef6b4be28f8db62ceb3d5c7f5d
|
||||||
checksum: 07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095
|
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -7795,6 +7844,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"fnv-plus@npm:^1.3.1":
|
||||||
|
version: 1.3.1
|
||||||
|
resolution: "fnv-plus@npm:1.3.1"
|
||||||
|
checksum: 4d3de8026d538ffab13dfa38ac0662b045b2ad0f920efa54f1ca65f59ad1a49b4d62482c5fcdc9cce0a18d9852df1db97c618937089d85678ce03f2e76b07e8b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"follow-redirects@npm:^1.14.0":
|
"follow-redirects@npm:^1.14.0":
|
||||||
version: 1.15.2
|
version: 1.15.2
|
||||||
resolution: "follow-redirects@npm:1.15.2"
|
resolution: "follow-redirects@npm:1.15.2"
|
||||||
@@ -7979,6 +8035,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"get-func-name@npm:^2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "get-func-name@npm:2.0.0"
|
||||||
|
checksum: 8d82e69f3e7fab9e27c547945dfe5cc0c57fc0adf08ce135dddb01081d75684a03e7a0487466f478872b341d52ac763ae49e660d01ab83741f74932085f693c3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0":
|
"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0":
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
resolution: "get-intrinsic@npm:1.2.1"
|
resolution: "get-intrinsic@npm:1.2.1"
|
||||||
@@ -8078,6 +8141,20 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"glob@npm:7.2.0":
|
||||||
|
version: 7.2.0
|
||||||
|
resolution: "glob@npm:7.2.0"
|
||||||
|
dependencies:
|
||||||
|
fs.realpath: ^1.0.0
|
||||||
|
inflight: ^1.0.4
|
||||||
|
inherits: 2
|
||||||
|
minimatch: ^3.0.4
|
||||||
|
once: ^1.3.0
|
||||||
|
path-is-absolute: ^1.0.0
|
||||||
|
checksum: 78a8ea942331f08ed2e055cb5b9e40fe6f46f579d7fd3d694f3412fe5db23223d29b7fee1575440202e9a7ff9a72ab106a39fee39934c7bedafe5e5f8ae20134
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"glob@npm:^7.0.5, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6":
|
"glob@npm:^7.0.5, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6":
|
||||||
version: 7.2.3
|
version: 7.2.3
|
||||||
resolution: "glob@npm:7.2.3"
|
resolution: "glob@npm:7.2.3"
|
||||||
@@ -8309,6 +8386,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"he@npm:1.2.0":
|
||||||
|
version: 1.2.0
|
||||||
|
resolution: "he@npm:1.2.0"
|
||||||
|
bin:
|
||||||
|
he: bin/he
|
||||||
|
checksum: 3d4d6babccccd79c5c5a3f929a68af33360d6445587d628087f39a965079d84f18ce9c3d3f917ee1e3978916fc833bb8b29377c3b403f919426f91bc6965e7a7
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"headers-polyfill@npm:^3.1.0, headers-polyfill@npm:^3.1.2":
|
"headers-polyfill@npm:^3.1.0, headers-polyfill@npm:^3.1.2":
|
||||||
version: 3.1.2
|
version: 3.1.2
|
||||||
resolution: "headers-polyfill@npm:3.1.2"
|
resolution: "headers-polyfill@npm:3.1.2"
|
||||||
@@ -8917,6 +9003,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"is-plain-obj@npm:^2.1.0":
|
||||||
|
version: 2.1.0
|
||||||
|
resolution: "is-plain-obj@npm:2.1.0"
|
||||||
|
checksum: cec9100678b0a9fe0248a81743041ed990c2d4c99f893d935545cfbc42876cbe86d207f3b895700c690ad2fa520e568c44afc1605044b535a7820c1d40e38daa
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"is-port-reachable@npm:4.0.0":
|
"is-port-reachable@npm:4.0.0":
|
||||||
version: 4.0.0
|
version: 4.0.0
|
||||||
resolution: "is-port-reachable@npm:4.0.0"
|
resolution: "is-port-reachable@npm:4.0.0"
|
||||||
@@ -9754,6 +9847,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"js-yaml@npm:4.1.0, js-yaml@npm:^4.1.0":
|
||||||
|
version: 4.1.0
|
||||||
|
resolution: "js-yaml@npm:4.1.0"
|
||||||
|
dependencies:
|
||||||
|
argparse: ^2.0.1
|
||||||
|
bin:
|
||||||
|
js-yaml: bin/js-yaml.js
|
||||||
|
checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"js-yaml@npm:^3.13.1":
|
"js-yaml@npm:^3.13.1":
|
||||||
version: 3.14.1
|
version: 3.14.1
|
||||||
resolution: "js-yaml@npm:3.14.1"
|
resolution: "js-yaml@npm:3.14.1"
|
||||||
@@ -9766,17 +9870,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"js-yaml@npm:^4.1.0":
|
|
||||||
version: 4.1.0
|
|
||||||
resolution: "js-yaml@npm:4.1.0"
|
|
||||||
dependencies:
|
|
||||||
argparse: ^2.0.1
|
|
||||||
bin:
|
|
||||||
js-yaml: bin/js-yaml.js
|
|
||||||
checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"jsbn@npm:~0.1.0":
|
"jsbn@npm:~0.1.0":
|
||||||
version: 0.1.1
|
version: 0.1.1
|
||||||
resolution: "jsbn@npm:0.1.1"
|
resolution: "jsbn@npm:0.1.1"
|
||||||
@@ -10250,7 +10343,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"log-symbols@npm:^4.1.0":
|
"log-symbols@npm:4.1.0, log-symbols@npm:^4.1.0":
|
||||||
version: 4.1.0
|
version: 4.1.0
|
||||||
resolution: "log-symbols@npm:4.1.0"
|
resolution: "log-symbols@npm:4.1.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -10292,6 +10385,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"loupe@npm:^2.3.1":
|
||||||
|
version: 2.3.6
|
||||||
|
resolution: "loupe@npm:2.3.6"
|
||||||
|
dependencies:
|
||||||
|
get-func-name: ^2.0.0
|
||||||
|
checksum: cc83f1b124a1df7384601d72d8d1f5fe95fd7a8185469fec48bb2e4027e45243949e7a013e8d91051a138451ff0552310c32aa9786e60b6a30d1e801bdc2163f
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"lowercase-keys@npm:^1.0.0, lowercase-keys@npm:^1.0.1":
|
"lowercase-keys@npm:^1.0.0, lowercase-keys@npm:^1.0.1":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "lowercase-keys@npm:1.0.1"
|
resolution: "lowercase-keys@npm:1.0.1"
|
||||||
@@ -10597,6 +10699,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"minimatch@npm:5.0.1":
|
||||||
|
version: 5.0.1
|
||||||
|
resolution: "minimatch@npm:5.0.1"
|
||||||
|
dependencies:
|
||||||
|
brace-expansion: ^2.0.1
|
||||||
|
checksum: b34b98463da4754bc526b244d680c69d4d6089451ebe512edaf6dd9eeed0279399cfa3edb19233513b8f830bf4bfcad911dddcdf125e75074100d52f724774f0
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"minimatch@npm:^5.0.1":
|
"minimatch@npm:^5.0.1":
|
||||||
version: 5.1.6
|
version: 5.1.6
|
||||||
resolution: "minimatch@npm:5.1.6"
|
resolution: "minimatch@npm:5.1.6"
|
||||||
@@ -10725,6 +10836,38 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"mocha@npm:^10.2.0":
|
||||||
|
version: 10.2.0
|
||||||
|
resolution: "mocha@npm:10.2.0"
|
||||||
|
dependencies:
|
||||||
|
ansi-colors: 4.1.1
|
||||||
|
browser-stdout: 1.3.1
|
||||||
|
chokidar: 3.5.3
|
||||||
|
debug: 4.3.4
|
||||||
|
diff: 5.0.0
|
||||||
|
escape-string-regexp: 4.0.0
|
||||||
|
find-up: 5.0.0
|
||||||
|
glob: 7.2.0
|
||||||
|
he: 1.2.0
|
||||||
|
js-yaml: 4.1.0
|
||||||
|
log-symbols: 4.1.0
|
||||||
|
minimatch: 5.0.1
|
||||||
|
ms: 2.1.3
|
||||||
|
nanoid: 3.3.3
|
||||||
|
serialize-javascript: 6.0.0
|
||||||
|
strip-json-comments: 3.1.1
|
||||||
|
supports-color: 8.1.1
|
||||||
|
workerpool: 6.2.1
|
||||||
|
yargs: 16.2.0
|
||||||
|
yargs-parser: 20.2.4
|
||||||
|
yargs-unparser: 2.0.0
|
||||||
|
bin:
|
||||||
|
_mocha: bin/_mocha
|
||||||
|
mocha: bin/mocha.js
|
||||||
|
checksum: 406c45eab122ffd6ea2003c2f108b2bc35ba036225eee78e0c784b6fa2c7f34e2b13f1dbacef55a4fdf523255d76e4f22d1b5aacda2394bd11666febec17c719
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"module-definition@npm:^3.3.1":
|
"module-definition@npm:^3.3.1":
|
||||||
version: 3.4.0
|
version: 3.4.0
|
||||||
resolution: "module-definition@npm:3.4.0"
|
resolution: "module-definition@npm:3.4.0"
|
||||||
@@ -10785,7 +10928,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"ms@npm:^2.0.0, ms@npm:^2.1.1":
|
"ms@npm:2.1.3, ms@npm:^2.0.0, ms@npm:^2.1.1":
|
||||||
version: 2.1.3
|
version: 2.1.3
|
||||||
resolution: "ms@npm:2.1.3"
|
resolution: "ms@npm:2.1.3"
|
||||||
checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d
|
checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d
|
||||||
@@ -10859,6 +11002,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"nanoid@npm:3.3.3":
|
||||||
|
version: 3.3.3
|
||||||
|
resolution: "nanoid@npm:3.3.3"
|
||||||
|
bin:
|
||||||
|
nanoid: bin/nanoid.cjs
|
||||||
|
checksum: ada019402a07464a694553c61d2dca8a4353645a7d92f2830f0d487fedff403678a0bee5323a46522752b2eab95a0bc3da98b6cccaa7c0c55cd9975130e6d6f0
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"nanoid@npm:^3.3.4, nanoid@npm:^3.3.6":
|
"nanoid@npm:^3.3.4, nanoid@npm:^3.3.6":
|
||||||
version: 3.3.6
|
version: 3.3.6
|
||||||
resolution: "nanoid@npm:3.3.6"
|
resolution: "nanoid@npm:3.3.6"
|
||||||
@@ -11587,6 +11739,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"pathval@npm:^1.1.1":
|
||||||
|
version: 1.1.1
|
||||||
|
resolution: "pathval@npm:1.1.1"
|
||||||
|
checksum: 090e3147716647fb7fb5b4b8c8e5b55e5d0a6086d085b6cd23f3d3c01fcf0ff56fd3cc22f2f4a033bd2e46ed55d61ed8379e123b42afe7d531a2a5fc8bb556d6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"pause-stream@npm:0.0.11":
|
"pause-stream@npm:0.0.11":
|
||||||
version: 0.0.11
|
version: 0.0.11
|
||||||
resolution: "pause-stream@npm:0.0.11"
|
resolution: "pause-stream@npm:0.0.11"
|
||||||
@@ -12177,7 +12336,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"r1csfile@npm:0.0.41":
|
"r1csfile@npm:0.0.41, r1csfile@npm:^0.0.41":
|
||||||
version: 0.0.41
|
version: 0.0.41
|
||||||
resolution: "r1csfile@npm:0.0.41"
|
resolution: "r1csfile@npm:0.0.41"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -12189,6 +12348,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"r1csfile@npm:0.0.45":
|
||||||
|
version: 0.0.45
|
||||||
|
resolution: "r1csfile@npm:0.0.45"
|
||||||
|
dependencies:
|
||||||
|
"@iden3/bigarray": 0.0.2
|
||||||
|
"@iden3/binfileutils": 0.0.11
|
||||||
|
fastfile: 0.0.20
|
||||||
|
ffjavascript: 0.2.57
|
||||||
|
checksum: ae2d7ab3f2c37640aea2b4f45753d1f2258f5d904a51d7aaff67c32a931c3e90d22d257e8f10752044fa36b3ac31516f60e503f858913a625015b9b05575ba47
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.1.0":
|
"randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.1.0":
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
resolution: "randombytes@npm:2.1.0"
|
resolution: "randombytes@npm:2.1.0"
|
||||||
@@ -13135,6 +13306,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"serialize-javascript@npm:6.0.0":
|
||||||
|
version: 6.0.0
|
||||||
|
resolution: "serialize-javascript@npm:6.0.0"
|
||||||
|
dependencies:
|
||||||
|
randombytes: ^2.1.0
|
||||||
|
checksum: 56f90b562a1bdc92e55afb3e657c6397c01a902c588c0fe3d4c490efdcc97dcd2a3074ba12df9e94630f33a5ce5b76a74784a7041294628a6f4306e0ec84bf93
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"serve-handler@npm:6.1.5":
|
"serve-handler@npm:6.1.5":
|
||||||
version: 6.1.5
|
version: 6.1.5
|
||||||
resolution: "serve-handler@npm:6.1.5"
|
resolution: "serve-handler@npm:6.1.5"
|
||||||
@@ -13292,9 +13472,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"snarkjs@https://github.com/sampritipanda/snarkjs.git#fef81fc51d17a734637555c6edbd585ecda02d9e":
|
"snarkjs@npm:0.5.0":
|
||||||
version: 0.5.0
|
version: 0.5.0
|
||||||
resolution: "snarkjs@https://github.com/sampritipanda/snarkjs.git#commit=fef81fc51d17a734637555c6edbd585ecda02d9e"
|
resolution: "snarkjs@npm:0.5.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@iden3/binfileutils": 0.0.11
|
"@iden3/binfileutils": 0.0.11
|
||||||
bfj: ^7.0.2
|
bfj: ^7.0.2
|
||||||
@@ -13304,12 +13484,31 @@ __metadata:
|
|||||||
fastfile: 0.0.20
|
fastfile: 0.0.20
|
||||||
ffjavascript: 0.2.56
|
ffjavascript: 0.2.56
|
||||||
js-sha3: ^0.8.0
|
js-sha3: ^0.8.0
|
||||||
localforage: ^1.10.0
|
|
||||||
logplease: ^1.2.15
|
logplease: ^1.2.15
|
||||||
r1csfile: 0.0.41
|
r1csfile: 0.0.41
|
||||||
bin:
|
bin:
|
||||||
snarkjs: build/cli.cjs
|
snarkjs: build/cli.cjs
|
||||||
checksum: f2050f0135d50d459ea0edddf3e394e833a2d28c6648e5889b2f896814865e5c60606e978a8a106bd5bfe7e27501c315f249db5b71895d5e7e6e9a87bfcd55ab
|
checksum: f0233103548bcd0f75b2ff8998ba02437e5131486d126c4a6a31355cd3558c7ce4311e21d5f24ea9ca198d0556e91e63e2ec6aef8da44014c16b29b6a7086ca2
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"snarkjs@npm:latest":
|
||||||
|
version: 0.7.0
|
||||||
|
resolution: "snarkjs@npm:0.7.0"
|
||||||
|
dependencies:
|
||||||
|
"@iden3/binfileutils": 0.0.11
|
||||||
|
bfj: ^7.0.2
|
||||||
|
blake2b-wasm: ^2.4.0
|
||||||
|
circom_runtime: 0.1.22
|
||||||
|
ejs: ^3.1.6
|
||||||
|
fastfile: 0.0.20
|
||||||
|
ffjavascript: 0.2.59
|
||||||
|
js-sha3: ^0.8.0
|
||||||
|
logplease: ^1.2.15
|
||||||
|
r1csfile: 0.0.45
|
||||||
|
bin:
|
||||||
|
snarkjs: build/cli.cjs
|
||||||
|
checksum: 8382c765c9b2fb3fac71807cd58352d0f497793b8eb18843a6ca7d7d6d4c8afbb97becd0e02211c51c0561e97646660a4c3edaed8200d1d182845879156f76b6
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -13719,6 +13918,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"strip-json-comments@npm:3.1.1, strip-json-comments@npm:^3.1.1":
|
||||||
|
version: 3.1.1
|
||||||
|
resolution: "strip-json-comments@npm:3.1.1"
|
||||||
|
checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"strip-json-comments@npm:^2.0.0, strip-json-comments@npm:~2.0.1":
|
"strip-json-comments@npm:^2.0.0, strip-json-comments@npm:~2.0.1":
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
resolution: "strip-json-comments@npm:2.0.1"
|
resolution: "strip-json-comments@npm:2.0.1"
|
||||||
@@ -13726,13 +13932,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"strip-json-comments@npm:^3.1.1":
|
|
||||||
version: 3.1.1
|
|
||||||
resolution: "strip-json-comments@npm:3.1.1"
|
|
||||||
checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"styled-components@npm:^5.3.5":
|
"styled-components@npm:^5.3.5":
|
||||||
version: 5.3.11
|
version: 5.3.11
|
||||||
resolution: "styled-components@npm:5.3.11"
|
resolution: "styled-components@npm:5.3.11"
|
||||||
@@ -13802,6 +14001,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"supports-color@npm:8.1.1, supports-color@npm:^8.0.0":
|
||||||
|
version: 8.1.1
|
||||||
|
resolution: "supports-color@npm:8.1.1"
|
||||||
|
dependencies:
|
||||||
|
has-flag: ^4.0.0
|
||||||
|
checksum: c052193a7e43c6cdc741eb7f378df605636e01ad434badf7324f17fb60c69a880d8d8fcdcb562cf94c2350e57b937d7425ab5b8326c67c2adc48f7c87c1db406
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"supports-color@npm:^5.3.0, supports-color@npm:^5.5.0":
|
"supports-color@npm:^5.3.0, supports-color@npm:^5.5.0":
|
||||||
version: 5.5.0
|
version: 5.5.0
|
||||||
resolution: "supports-color@npm:5.5.0"
|
resolution: "supports-color@npm:5.5.0"
|
||||||
@@ -13820,15 +14028,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"supports-color@npm:^8.0.0":
|
|
||||||
version: 8.1.1
|
|
||||||
resolution: "supports-color@npm:8.1.1"
|
|
||||||
dependencies:
|
|
||||||
has-flag: ^4.0.0
|
|
||||||
checksum: c052193a7e43c6cdc741eb7f378df605636e01ad434badf7324f17fb60c69a880d8d8fcdcb562cf94c2350e57b937d7425ab5b8326c67c2adc48f7c87c1db406
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"supports-preserve-symlinks-flag@npm:^1.0.0":
|
"supports-preserve-symlinks-flag@npm:^1.0.0":
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
resolution: "supports-preserve-symlinks-flag@npm:1.0.0"
|
resolution: "supports-preserve-symlinks-flag@npm:1.0.0"
|
||||||
@@ -13953,6 +14152,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"tmp-promise@npm:^3.0.3":
|
||||||
|
version: 3.0.3
|
||||||
|
resolution: "tmp-promise@npm:3.0.3"
|
||||||
|
dependencies:
|
||||||
|
tmp: ^0.2.0
|
||||||
|
checksum: f854f5307dcee6455927ec3da9398f139897faf715c5c6dcee6d9471ae85136983ea06662eba2edf2533bdcb0fca66d16648e79e14381e30c7fb20be9c1aa62c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"tmp@npm:^0.0.33":
|
"tmp@npm:^0.0.33":
|
||||||
version: 0.0.33
|
version: 0.0.33
|
||||||
resolution: "tmp@npm:0.0.33"
|
resolution: "tmp@npm:0.0.33"
|
||||||
@@ -13962,7 +14170,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"tmp@npm:^0.2.1":
|
"tmp@npm:^0.2.0, tmp@npm:^0.2.1":
|
||||||
version: 0.2.1
|
version: 0.2.1
|
||||||
resolution: "tmp@npm:0.2.1"
|
resolution: "tmp@npm:0.2.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -14254,7 +14462,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"type-detect@npm:4.0.8":
|
"type-detect@npm:4.0.8, type-detect@npm:^4.0.0, type-detect@npm:^4.0.5":
|
||||||
version: 4.0.8
|
version: 4.0.8
|
||||||
resolution: "type-detect@npm:4.0.8"
|
resolution: "type-detect@npm:4.0.8"
|
||||||
checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15
|
checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15
|
||||||
@@ -15085,6 +15293,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"workerpool@npm:6.2.1":
|
||||||
|
version: 6.2.1
|
||||||
|
resolution: "workerpool@npm:6.2.1"
|
||||||
|
checksum: c2c6eebbc5225f10f758d599a5c016fa04798bcc44e4c1dffb34050cd361d7be2e97891aa44419e7afe647b1f767b1dc0b85a5e046c409d890163f655028b09d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"wrap-ansi@npm:^5.1.0":
|
"wrap-ansi@npm:^5.1.0":
|
||||||
version: 5.1.0
|
version: 5.1.0
|
||||||
resolution: "wrap-ansi@npm:5.1.0"
|
resolution: "wrap-ansi@npm:5.1.0"
|
||||||
@@ -15336,6 +15551,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"yargs-parser@npm:20.2.4":
|
||||||
|
version: 20.2.4
|
||||||
|
resolution: "yargs-parser@npm:20.2.4"
|
||||||
|
checksum: d251998a374b2743a20271c2fd752b9fbef24eb881d53a3b99a7caa5e8227fcafd9abf1f345ac5de46435821be25ec12189a11030c12ee6481fef6863ed8b924
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"yargs-parser@npm:^13.1.2":
|
"yargs-parser@npm:^13.1.2":
|
||||||
version: 13.1.2
|
version: 13.1.2
|
||||||
resolution: "yargs-parser@npm:13.1.2"
|
resolution: "yargs-parser@npm:13.1.2"
|
||||||
@@ -15356,6 +15578,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"yargs-parser@npm:^20.2.2":
|
||||||
|
version: 20.2.9
|
||||||
|
resolution: "yargs-parser@npm:20.2.9"
|
||||||
|
checksum: 8bb69015f2b0ff9e17b2c8e6bfe224ab463dd00ca211eece72a4cd8a906224d2703fb8a326d36fdd0e68701e201b2a60ed7cf81ce0fd9b3799f9fe7745977ae3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"yargs-parser@npm:^21.1.1":
|
"yargs-parser@npm:^21.1.1":
|
||||||
version: 21.1.1
|
version: 21.1.1
|
||||||
resolution: "yargs-parser@npm:21.1.1"
|
resolution: "yargs-parser@npm:21.1.1"
|
||||||
@@ -15363,6 +15592,33 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"yargs-unparser@npm:2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "yargs-unparser@npm:2.0.0"
|
||||||
|
dependencies:
|
||||||
|
camelcase: ^6.0.0
|
||||||
|
decamelize: ^4.0.0
|
||||||
|
flat: ^5.0.2
|
||||||
|
is-plain-obj: ^2.1.0
|
||||||
|
checksum: 68f9a542c6927c3768c2f16c28f71b19008710abd6b8f8efbac6dcce26bbb68ab6503bed1d5994bdbc2df9a5c87c161110c1dfe04c6a3fe5c6ad1b0e15d9a8a3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"yargs@npm:16.2.0":
|
||||||
|
version: 16.2.0
|
||||||
|
resolution: "yargs@npm:16.2.0"
|
||||||
|
dependencies:
|
||||||
|
cliui: ^7.0.2
|
||||||
|
escalade: ^3.1.1
|
||||||
|
get-caller-file: ^2.0.5
|
||||||
|
require-directory: ^2.1.1
|
||||||
|
string-width: ^4.2.0
|
||||||
|
y18n: ^5.0.5
|
||||||
|
yargs-parser: ^20.2.2
|
||||||
|
checksum: b14afbb51e3251a204d81937c86a7e9d4bdbf9a2bcee38226c900d00f522969ab675703bee2a6f99f8e20103f608382936034e64d921b74df82b63c07c5e8f59
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"yargs@npm:^13.2.4":
|
"yargs@npm:^13.2.4":
|
||||||
version: 13.3.2
|
version: 13.3.2
|
||||||
resolution: "yargs@npm:13.3.2"
|
resolution: "yargs@npm:13.3.2"
|
||||||
@@ -15439,6 +15695,99 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"zk-email@workspace:.":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "zk-email@workspace:."
|
||||||
|
dependencies:
|
||||||
|
"@babel/preset-env": ^7.22.2
|
||||||
|
"@babel/preset-react": ^7.22.0
|
||||||
|
"@babel/preset-typescript": ^7.21.5
|
||||||
|
"@esbuild-plugins/node-globals-polyfill": ^0.2.3
|
||||||
|
"@esbuild-plugins/node-modules-polyfill": ^0.2.2
|
||||||
|
"@openzeppelin/contracts": ^4.9.0
|
||||||
|
"@rainbow-me/rainbowkit": ^0.8.0
|
||||||
|
"@testing-library/jest-dom": ^5.16.3
|
||||||
|
"@testing-library/react": ^12.1.4
|
||||||
|
"@testing-library/user-event": ^13.5.0
|
||||||
|
"@types/atob": ^2.1.2
|
||||||
|
"@types/jest": ^29.5.1
|
||||||
|
"@types/lodash": ^4.14.181
|
||||||
|
"@types/mocha": ^10.0.1
|
||||||
|
"@types/node": ^18.0.6
|
||||||
|
"@types/node-forge": ^1.3.2
|
||||||
|
"@types/pako": ^2.0.0
|
||||||
|
"@types/styled-components": ^5.1.24
|
||||||
|
"@types/tar-stream": ^2.2.2
|
||||||
|
"@types/yargs": ^17.0.24
|
||||||
|
"@vitejs/plugin-react": ^4.0.0
|
||||||
|
addressparser: ^1.0.1
|
||||||
|
atob: ^2.1.2
|
||||||
|
babel-preset-jest: ^29.5.0
|
||||||
|
base64-sol: ^1.1.0
|
||||||
|
browserify-fs: ^1.0.0
|
||||||
|
browserstack-local: ^1.5.1
|
||||||
|
browserstack-node-sdk: ^1.6.1
|
||||||
|
buffer: ^6.0.3
|
||||||
|
chai: ^4.3.7
|
||||||
|
circom_tester: ^0.0.19
|
||||||
|
circomlibjs: ^0.1.2
|
||||||
|
cryo: ^0.0.6
|
||||||
|
crypto-browserify: ^3.12.0
|
||||||
|
ethereumjs-abi: ^0.6.8
|
||||||
|
ethers: ^5.7.1
|
||||||
|
forge-std: ^1.1.2
|
||||||
|
husky: ^8.0.3
|
||||||
|
jest: ^29.5.0
|
||||||
|
jest-environment-jsdom: ^29.5.0
|
||||||
|
jest-fetch-mock: ^3.0.3
|
||||||
|
jest-junit: ^15.0.0
|
||||||
|
jsdom-worker: ^0.3.0
|
||||||
|
libmime: ^5.1.0
|
||||||
|
localforage: ^1.10.0
|
||||||
|
lodash: ^4.17.21
|
||||||
|
madge: ^6.0.0
|
||||||
|
mocha: ^10.2.0
|
||||||
|
msw: ^1.0.1
|
||||||
|
next: ^12.3.1
|
||||||
|
node-forge: ^1.3.1
|
||||||
|
nodemon: ^2.0.19
|
||||||
|
pako: ^2.1.0
|
||||||
|
prettier: ^2.7.1
|
||||||
|
prettier-plugin-solidity: ^1.0.0-beta.24
|
||||||
|
process: ^0.11.10
|
||||||
|
puppeteer: 18.1
|
||||||
|
react: ^17.0.2
|
||||||
|
react-dom: ^17.0.2
|
||||||
|
react-dropzone: ^12.0.4
|
||||||
|
react-error-overlay: 6.0.9
|
||||||
|
react-json-view: ^1.21.3
|
||||||
|
react-router: ^6.2.2
|
||||||
|
react-router-dom: ^6.2.2
|
||||||
|
react-use: ^17.3.2
|
||||||
|
readline: ^1.3.0
|
||||||
|
rollup-plugin-node-polyfills: ^0.2.1
|
||||||
|
selenium-webdriver: ^4.8.1
|
||||||
|
serve: ^14.0.1
|
||||||
|
snarkjs: latest
|
||||||
|
sshpk: ^1.17.0
|
||||||
|
styled-components: ^5.3.5
|
||||||
|
ts-node: ^10.9.1
|
||||||
|
ts-node-dev: ^2.0.0
|
||||||
|
typescript: ^4.8.3
|
||||||
|
update-browserslist-db: latest
|
||||||
|
util: ^0.12.5
|
||||||
|
vite: ^4.3.3
|
||||||
|
vite-plugin-commonjs: ^0.7.1
|
||||||
|
vite-plugin-ngmi-polyfill: ^0.0.2
|
||||||
|
vite-plugin-node-polyfills: ^0.8.2
|
||||||
|
vite-plugin-svgr: ^2.4.0
|
||||||
|
vite-tsconfig-paths: ^4.2.0
|
||||||
|
wagmi: ^0.6.8
|
||||||
|
web-vitals: ^2.1.4
|
||||||
|
yargs: ^17.7.1
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"zustand@npm:^4.0.0":
|
"zustand@npm:^4.0.0":
|
||||||
version: 4.3.8
|
version: 4.3.8
|
||||||
resolution: "zustand@npm:4.3.8"
|
resolution: "zustand@npm:4.3.8"
|
||||||
|
|||||||
Reference in New Issue
Block a user