Skip to content

Commit

Permalink
Merge pull request #27 from noir-lang/ec
Browse files Browse the repository at this point in the history
Adds a stealthdrop example
  • Loading branch information
signorecello authored Jun 12, 2023
2 parents eab157d + e00171c commit 1dc4e00
Show file tree
Hide file tree
Showing 22 changed files with 8,734 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .prettierignore
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
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"arrowParens": "avoid",
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"proseWrap": "always"
}
12 changes: 12 additions & 0 deletions stealthdrop/.env.example
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=""
52 changes: 52 additions & 0 deletions stealthdrop/.gitignore
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
20 changes: 20 additions & 0 deletions stealthdrop/README.md
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.
6 changes: 6 additions & 0 deletions stealthdrop/circuits/Nargo.toml
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"}
19 changes: 19 additions & 0 deletions stealthdrop/circuits/Prover.toml
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"

4 changes: 4 additions & 0 deletions stealthdrop/circuits/Verifier.toml
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"]
63 changes: 63 additions & 0 deletions stealthdrop/circuits/contract/Airdrop.sol
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;
}
}
Loading

0 comments on commit 1dc4e00

Please sign in to comment.