-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #27 from noir-lang/ec
Adds a stealthdrop example
- Loading branch information
Showing
22 changed files
with
8,734 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Add files here to ignore them from prettier formatting | ||
|
||
/dist | ||
/coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"arrowParens": "avoid", | ||
"singleQuote": true, | ||
"trailingComma": "all", | ||
"printWidth": 100, | ||
"proseWrap": "always" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# using hardhat default accounts, please update | ||
DEPLOYER_PRIVATE_KEY="0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e" | ||
USER1_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" | ||
CLAIMER1_PRIVATE_KEY="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" | ||
CLAIMER2_PRIVATE_KEY="0xde9be858da4a475276426320d5e9262ecfc3ba460bfac56360bfa6c4c28b4ee0" | ||
|
||
# hardhat acct #0 key, please update | ||
MUMBAI_DEPLOYER_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" | ||
MUMBAI_ALCHEMY_KEY="" | ||
# hardhat acct #0 key, please update | ||
SEPOLIA_DEPLOYER_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" | ||
SEPOLIA_ALCHEMY_KEY="" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
.env | ||
.tmp | ||
|
||
# dependencies | ||
node_modules | ||
.vitest | ||
/.pnp | ||
.pnp.js | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
.pnpm-debug.log* | ||
|
||
# local env files | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts | ||
|
||
# nargo | ||
target | ||
|
||
# hardhat | ||
cache | ||
artifacts | ||
typechain-types | ||
proofs/*.proof | ||
|
||
# other | ||
.vscode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Stealthdrop example | ||
|
||
WARNING: THIS IS UNSAFE. ECDSA signature is malleable, which means this app has a vulnerability. Check out this [twitter thread](https://twitter.com/0xPARC/status/1493704577002049537?s=20&t=X-5Bs1oWNjmbTASp2T82DA) to understand why. | ||
|
||
This example mimics the great [Stealthdrop](https://github.com/stealthdrop/stealthdrop) example, while massively reducing the complexity of the circuit, proving time, resources, and improving readability. | ||
|
||
## How to run | ||
|
||
Just clone the repo, run `yarn` and `yarn test`. It currently has two tests: a happy path and a sad path. | ||
|
||
## How does it work | ||
|
||
In the `circuits` folder you'll find a circuit, roughtly divided in four steps: | ||
|
||
- Step 1 - Recover the address: Verify ECDSA signature and recover the address. Initially I implemented this by myself, but then found the amazing `ecrecover` library by [Colin](https://github.com/colinnielsen/ecrecover-noir) already provided a module for this. In this step, we prove that the verification of the provided (private) signature was made with the private key that is elligible to claim the airdrop. We also recover the elligible address from it. | ||
- Step 2 - Prevent double-claims: We prove that the nullifier that will be stored in the contract is hash of the signature. | ||
- Step 3 - Prove elligibility: We prove that the address is part of the merkle tree of elligible accounts. | ||
- Step 4 - Allow claimer to claim the airdrop: We prove that the claimer address is the msg.sender | ||
|
||
Each step is roughly two lines of code. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[package] | ||
authors = [""] | ||
compiler_version = "0.4.1" | ||
|
||
[dependencies] | ||
ecrecover = {tag = "v0.2.1", git = "https://github.com/signorecello/ecrecover-noir.git"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
|
||
pub_key = [131,24,83,91,84,16,93,74,122,174,96,192,143,196,95,150,135,24,27,79,223,198,37,189,26,117,63,167,57,127,237,117,53,71,241,28,168,105,102,70,242,243,172,176,142,49,1,106,250,194,62,99,12,93,17,245,159,97,254,245,123,13,42,165] | ||
|
||
signature = [1,83,82,167,184,77,226,104,5,27,151,91,202,127,17,183,75,31,190,253,159,116,155,13,24,178,40,165,129,90,103,204,42,164,230,62,73,181,169,61,251,221,128,221,14,19,179,25,107,132,10,188,149,0,197,52,151,239,244,103,215,224,56,242] | ||
|
||
hashed_message = [3,57,199,96,145,58,183,241,206,140,36,34,165,163,17,210,97,254,154,79,91,223,149,18,3,210,111,56,246,219,19,104] | ||
|
||
nullifier = [142,197,227,35,35,142,255,176,38,63,247,168,33,178,55,202,46,76,167,202,130,208,59,14,151,19,144,228,58,37,10,101] | ||
|
||
merkle_path = ["0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8","0x03f943ec114f89d16dbcce5b92d643e24b34f239cb462932833b6ef4a666df10","0x10605994d9acb4d2c67befc19b650e255430faa378d010d4fdcf973f0697155e","0x25eb6b9946e31f411b7c607aa9b37cd29ca6db3ff395864bf9a30176c741bebe"] | ||
|
||
index = 0 | ||
|
||
merkle_root = "0x23bfa58e401ffe1f73d39703caa5376a8b5ee8a0673853321585208b86a451c0" | ||
|
||
claimer_pub = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" | ||
|
||
claimer_priv = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
claimer_pub = "0x00000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8" | ||
hashed_message = ["0x0000000000000000000000000000000000000000000000000000000000000003", "0x0000000000000000000000000000000000000000000000000000000000000039", "0x00000000000000000000000000000000000000000000000000000000000000c7", "0x0000000000000000000000000000000000000000000000000000000000000060", "0x0000000000000000000000000000000000000000000000000000000000000091", "0x000000000000000000000000000000000000000000000000000000000000003a", "0x00000000000000000000000000000000000000000000000000000000000000b7", "0x00000000000000000000000000000000000000000000000000000000000000f1", "0x00000000000000000000000000000000000000000000000000000000000000ce", "0x000000000000000000000000000000000000000000000000000000000000008c", "0x0000000000000000000000000000000000000000000000000000000000000024", "0x0000000000000000000000000000000000000000000000000000000000000022", "0x00000000000000000000000000000000000000000000000000000000000000a5", "0x00000000000000000000000000000000000000000000000000000000000000a3", "0x0000000000000000000000000000000000000000000000000000000000000011", "0x00000000000000000000000000000000000000000000000000000000000000d2", "0x0000000000000000000000000000000000000000000000000000000000000061", "0x00000000000000000000000000000000000000000000000000000000000000fe", "0x000000000000000000000000000000000000000000000000000000000000009a", "0x000000000000000000000000000000000000000000000000000000000000004f", "0x000000000000000000000000000000000000000000000000000000000000005b", "0x00000000000000000000000000000000000000000000000000000000000000df", "0x0000000000000000000000000000000000000000000000000000000000000095", "0x0000000000000000000000000000000000000000000000000000000000000012", "0x0000000000000000000000000000000000000000000000000000000000000003", "0x00000000000000000000000000000000000000000000000000000000000000d2", "0x000000000000000000000000000000000000000000000000000000000000006f", "0x0000000000000000000000000000000000000000000000000000000000000038", "0x00000000000000000000000000000000000000000000000000000000000000f6", "0x00000000000000000000000000000000000000000000000000000000000000db", "0x0000000000000000000000000000000000000000000000000000000000000013", "0x0000000000000000000000000000000000000000000000000000000000000068"] | ||
merkle_root = "0x23bfa58e401ffe1f73d39703caa5376a8b5ee8a0673853321585208b86a451c0" | ||
nullifier = ["0x000000000000000000000000000000000000000000000000000000000000008e", "0x00000000000000000000000000000000000000000000000000000000000000c5", "0x00000000000000000000000000000000000000000000000000000000000000e3", "0x0000000000000000000000000000000000000000000000000000000000000023", "0x0000000000000000000000000000000000000000000000000000000000000023", "0x000000000000000000000000000000000000000000000000000000000000008e", "0x00000000000000000000000000000000000000000000000000000000000000ff", "0x00000000000000000000000000000000000000000000000000000000000000b0", "0x0000000000000000000000000000000000000000000000000000000000000026", "0x000000000000000000000000000000000000000000000000000000000000003f", "0x00000000000000000000000000000000000000000000000000000000000000f7", "0x00000000000000000000000000000000000000000000000000000000000000a8", "0x0000000000000000000000000000000000000000000000000000000000000021", "0x00000000000000000000000000000000000000000000000000000000000000b2", "0x0000000000000000000000000000000000000000000000000000000000000037", "0x00000000000000000000000000000000000000000000000000000000000000ca", "0x000000000000000000000000000000000000000000000000000000000000002e", "0x000000000000000000000000000000000000000000000000000000000000004c", "0x00000000000000000000000000000000000000000000000000000000000000a7", "0x00000000000000000000000000000000000000000000000000000000000000ca", "0x0000000000000000000000000000000000000000000000000000000000000082", "0x00000000000000000000000000000000000000000000000000000000000000d0", "0x000000000000000000000000000000000000000000000000000000000000003b", "0x000000000000000000000000000000000000000000000000000000000000000e", "0x0000000000000000000000000000000000000000000000000000000000000097", "0x0000000000000000000000000000000000000000000000000000000000000013", "0x0000000000000000000000000000000000000000000000000000000000000090", "0x00000000000000000000000000000000000000000000000000000000000000e4", "0x000000000000000000000000000000000000000000000000000000000000003a", "0x0000000000000000000000000000000000000000000000000000000000000025", "0x000000000000000000000000000000000000000000000000000000000000000a", "0x0000000000000000000000000000000000000000000000000000000000000065"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
pragma solidity ^0.8.0; | ||
|
||
import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; | ||
import './plonk_vk.sol'; | ||
import 'hardhat/console.sol'; | ||
|
||
contract Airdrop is ERC20 { | ||
bytes32 public signThis; | ||
bytes32 public merkleRoot; | ||
UltraVerifier public verifier; | ||
|
||
uint256 public airdropAmount; | ||
|
||
mapping(bytes32 => bool) public nullifiers; // Keep track of claimed Merkle roots | ||
|
||
event TokensAirdropped(address indexed recipient, uint256 amount); | ||
|
||
constructor( | ||
bytes32 _merkleRoot, | ||
bytes32 _signThis, | ||
UltraVerifier _verifier, | ||
uint256 _airdropAmount | ||
) ERC20('Airdrop', 'ADRP') { | ||
merkleRoot = _merkleRoot; | ||
signThis = _signThis; | ||
verifier = _verifier; | ||
|
||
airdropAmount = _airdropAmount; | ||
_mint(address(this), airdropAmount); | ||
} | ||
|
||
function preparePublicInputs( | ||
bytes32[] memory _publicInputs, | ||
bytes32 publicInput, | ||
uint256 offset | ||
) private pure returns (bytes32[] memory) { | ||
for (uint256 i = 0; i < 32; i++) { | ||
_publicInputs[i + offset] = (publicInput >> ((31 - i) * 8)) & bytes32(uint256(0xFF)); | ||
} // TODO not cool, padding 31 bytes with 0s | ||
return _publicInputs; | ||
} | ||
|
||
function claim(bytes calldata proof, bytes32 nullifier) external { | ||
bytes32[] memory _publicInputs = new bytes32[](66); | ||
_publicInputs = preparePublicInputs(_publicInputs, signThis, 0); | ||
_publicInputs = preparePublicInputs(_publicInputs, nullifier, 32); | ||
_publicInputs[64] = merkleRoot; | ||
_publicInputs[65] = bytes32(uint256(uint160(msg.sender))); | ||
verifier.verify(proof, _publicInputs); | ||
|
||
// mint tokens | ||
_transfer(address(this), msg.sender, 1); | ||
emit TokensAirdropped(msg.sender, 1); | ||
} | ||
|
||
function getRoot() public view returns (bytes32) { | ||
return merkleRoot; | ||
} | ||
|
||
function getMessage() public view returns (bytes32) { | ||
return signThis; | ||
} | ||
} |
Oops, something went wrong.