Sacha Saint-Leger cd1d6d3e36 | 4 years ago | |
---|---|---|
.github/workflows | 4 years ago | |
circuits | 4 years ago | |
contracts | 4 years ago | |
dist | 4 years ago | |
migrations | 4 years ago | |
src | 4 years ago | |
test | 4 years ago | |
.gitattributes | 4 years ago | |
.gitignore | 4 years ago | |
LICENSE | 4 years ago | |
README.md | 4 years ago | |
compile-circuits.sh | 4 years ago | |
miksi-logo00-small.png | 4 years ago | |
package-lock.json | 4 years ago | |
package.json | 4 years ago | |
test-compile-circuits.sh | 4 years ago | |
truffle-config.js | 4 years ago | |
tsconfig.json | 4 years ago | |
tslint.json | 4 years ago |
From Esperanto, miksi (miks·i): to mingle, to blend, to mix, to shuffle
Ethereum mixer where all the computation & constructions are done offchain and then proved inside a zkSNARK to the smart-contract (both to deposit and withdraw).
The client builds a MerkleTree, carries out the required computation, and then generates a zk-proof proving that the offchain computation has been done correctly (no leaf deletion, and only one correctly formatted leaf addition).
This approach requires only ~325.000 gas
to deposit (compared to ~1M gas
for an onchain computation approach) , and ~308.000 gas
to withdraw.
These gas savings come from the fact that we don't need to carry out the MerkleTree computations onchain. Instead, we prove the correctness of these offchain computations inside the snark proof, and verify this proof onchain. It's much cheaper to verify the proof than to carry out the necessary computations onchain.
Warning: This repository is in a very early stage. The current version works, but is not finished. There are some improvements in the works.
The WebApp to use miksi-core can be found at https://github.com/arnaucube/miksi-app
npm run test-circuits
npm run test-sc
./compile-circuits.sh
Note: Both the spec and the code are works in progress. There are some pending improvements in the works, and some diagrams are needed to better explain things.
All computations and constructions are done offchain and then proved inside a zkSNARK to the smart-contract
From the depositer's perspective, the interface facilitates the following flow:
Generate a random secret
& nullifier
Compute the commitment
, which is the Poseidon hash: commitment = H(coinCode, amount, secret, nullifier)
, where:
coinCode
: code that specifies which currency is being used (0
==ETH)amount
: the amount to be depositedsecret
: random, privatenullifier
: randomFetch all the commitments from the smart-contract
Build the MerkleTree with the fetched commitments
Add the newly computed commitment
to the MerkleTree
Generate a zkSNARK proof, which proves:
secret
& nullifier
for the commitment
contained in the leaf you've just added to the MerkleTreeRootOld
(the current one in the Smart Contract) to RootNew
has been done following the rules (no leaf deletion, and only one correctly formatted leaf addition, etc.)Send ETH to the smart-contract deposit
call, together with the zkProof data
Once these steps have been carried out, the smart-contract verifies the zkProof of the deposit, and if everything checks out ok, stores the commitment and the new root.
The deposit circuit can be found here.
As before, all computations and constructions are done offchain and then proved inside a zkSNARK to the Smart Contract
From the withdrawer's perspective, the interface facilitates the following flow:
Fetch all the commitments from the smart-contract
Build the MerkleTree with the fetched commitments
Generate the siblings (merkle proof) for the commitment
whose secret
& nullifier
you know
Generate a zkSNARK proof, which proves:
- you know a secret
for a nullifier
you reveal, whose commitment
is in a MerkleTree with root
matching the one stored in the smart-contract
If the zkProof verification passes, and the nullifier has not already been used, the smart-contract sends the ETH to the specified address.
The withdraw circuit can be found here.
Miksi is made possible thanks to circom, circomlib, wasmsnark, and the ideas developed in the Zexe paper.