Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

foundry voting example<updated> #37

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 171 additions & 14 deletions foundry-voting/.gitignore
Original file line number Diff line number Diff line change
@@ -1,20 +1,177 @@
# Compiler files
cache/
out/
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore

# Ignores development broadcast logs
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/
# Logs

# Docs
docs/
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

circuits/target
# Caches

cache
.cache

# Diagnostic reports (https://nodejs.org/api/report.html)

report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json

# Runtime data

pids
_.pid
_.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover

lib-cov

# Coverage directory used by tools like istanbul

coverage
*.lcov

# nyc test coverage

.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)

.grunt

# Bower dependency directory (https://bower.io/)

bower_components

# node-waf configuration

.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)

build/Release

# Dependency directories

node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)

web_modules/

# TypeScript cache

*.tsbuildinfo

# Optional npm cache directory

.npm

# Optional eslint cache

.eslintcache

# Optional stylelint cache

.stylelintcache

# Microbundle cache

.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history

.node_repl_history

# Output of 'npm pack'

*.tgz

# Yarn Integrity file

.yarn-integrity

# dotenv environment variable files

# Dotenv file
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)

.parcel-cache

# Next.js build output

.next
out

# Nuxt.js build / generate output

.nuxt
dist

# Gatsby files

# Comment in the public line in if your project uses Gatsby and not Next.js

# https://nextjs.org/blog/next-9-1#public-directory-support

# public

# vuepress build output

.vuepress/dist

# vuepress v2.x temp and cache directory

.temp

# Docusaurus cache and generated files

.docusaurus

# Serverless directories

.serverless/

# FuseBox cache

.fusebox/

# DynamoDB Local files

.dynamodb/

# TernJS port file

.tern-port

# Stores VSCode versions used for testing VSCode extensions

.vscode-test

# yarn v2

.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

node_modules
crs
# IntelliJ based IDEs
.idea

circuits/contract
circuits/proofs
# Finder (MacOS) folder config
.DS_Store
3 changes: 0 additions & 3 deletions foundry-voting/.gitmodules

This file was deleted.

144 changes: 117 additions & 27 deletions foundry-voting/README.md
satyambnsal marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
# zk Voting with Foundry

[![Run Tests on PR](https://github.com/noir-lang/noir-starter/actions/workflows/foundry-voting.yml/badge.svg)](https://github.com/noir-lang/noir-starter/actions/workflows/foundry-voting.yml)
# Foundry Voting Example

This example project shows how to create a simple zk voting circuit in Noir with a corresponding Solidity contract to track eligible voters, proposals and votes.

This example was last tested with Noir version 0.28.0. You can install it with [noirup](https://noir-lang.org/docs/getting_started/installation/#installing-noirup) using

```bash
noirup -v 0.28.0
```

## Overview

This is the model used for creating the [circuit](circuits/src/main.nr) and the [zkVote contract](src/zkVote.sol) to manage private voting.
This is the model used for creating the [circuit](circuits/src/main.nr) and the [zkVote contract](contracts/zkVote.sol) to manage private voting.

1. Create a set of voters. A merkle root is stored in the zkVote Solidity contract that voters will use to verify membership against. In this example, there are 4 accounts in the set of voters. The private keys are 0, 1, 2, 3 and the secret value to create the commitment is 9.

satyambnsal marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -25,30 +17,128 @@ This is the model used for creating the [circuit](circuits/src/main.nr) and the

This gives intermediate hashes of `0x046394ae1ebbf494f2cd2c2d37171099510d099489c9accef59f90512d5f0477` (`pedersen(commitment0, commitment1)`) and `0x2a653551d87767c545a2a11b29f0581a392b4e177a87c8e3eb425c51a26a8c77` (`pedersen(commitment2, commitment3)`) and a root hash of `0x215597bacd9c7e977dfc170f320074155de974be494579d2586e5b268fa3b629`.

2. Users will input their information into the circuit and generate a proof (see example inputs in [Prover.toml](./circuits/Prover.toml) and run `nargo prove` to generate the proof.)
1. Public inputs and outputs are printed in [Verifier.toml](./circuits/Verifier.toml).
2. The proof is saved to `./proofs/foundry_voting.proof`.
3. The generated proof + the contents of Verifier.toml are sent in a transaction to the `castVote` function in the [zkVote](./src/zkVote.sol) contract. The function verifies that the sender is authorized to vote on the proposal, that they haven't already voted and tallies their vote.
1. Users will input their information into the circuit and generate a proof (see example inputs in `circuits/Prover.toml` and run `bun run circuits:ultraplonk:generate-proof` to generate the proof.)
2. The generated proof is sent in a transaction to the `castVote` function in the [zkVote](./contracts/zkVote.sol) contract. The function verifies that the sender is authorized to vote on the proposal, that they haven't already voted and tallies their vote.

## Prerequisites
This code has been tested with:

Nargo version: 1.0.0-beta.1
BB (barretenberg-cli) version: 0.66.0

you can install these following [quick start](https://noir-lang.org/docs/getting_started/quick_start) guide.

## Testing
Project uses **bun** as package manager which you can install using ```curl -fsSL https://bun.sh/install | bash```

You can run the Noir tests (also defined in main.nr) with `nargo test`. To print test output, use `nargo test --show-output`.
Make sure you have compatible versions installed before proceeding.

See the test file [here](./test/zkVote.t.sol). Run tests with `forge test`.
## Quick Start

1. Run `nargo compile` to compile the circuit.
2. Run `nargo prove` to generate the proof (with the inputs in Prover.toml).
3. Run `nargo codegen-verifier` to generate the solidity verifier contract.
4. Run `yarn test` to run the Foundry test the Solidity verifier contract at `./test/zkVote.t.sol`.

## Development
Install dependencies:
```bash
bun install
```

## Development Guide

### Interactive Build Process

If you change the circuit at `./circuits/src/main.nr` you will need to recompile (`nargo compile`) the circuit and regenerate the Solidity verifier (saved to `./circuits/contract/plonk_vk.sol`).
Run all steps interactively with status updates:
```bash
bun run build:ultraplonk
```

The merkle tree will need to be recalculated whenever there are users added to the set or if there are any changes to the voters secrets (secrets are the input to the merkle membership commitment, so changing a key changes the corresponding leaf in the merkle tree, which changes the root). See `test_valid_build_merkle_tree` for an example calculation.
This will guide you through all the steps with prompts and status updates.

Run `nargo test --show-output` in `./circuits` to print the example merkle tree.
### Manual Steps

## Contributions
#### 1. Circuit Testing

Thanks to the folks at zkCamp modifying the original example and adding tests. You can see their repo [here](https://github.com/ZKCamp/noir-voting/tree/6-security).
Run the test suite:
```bash
bun run circuits:test
```

#### 2. Circuit Execution Flow

Execute the circuit (generates witness and circuit JSON file):
```bash
bun run circuits:execute
```

#### 3. Proof Generation

Generate UltraPlonk proof:
```bash
bun run circuits:ultraplonk:generate-proof
```

Generate verification key:
```bash
bun run circuits:ultraplonk:generate-vk
```

#### 4. Contract Generation

Generate the Solidity verifier contract:
```bash
bun run circuits:contract
```

#### 5. Proof Processing

Clean and format the proof for contract verification:
```bash
bun run ultraplonk:clean-proof
```

#### 6. Contract Testing

Run Forge tests:
```bash
forge test
```

### Advanced Usage

#### Manual Circuit Commands

If you need to run circuit commands directly:

1. Navigate to circuits directory:
```bash
cd circuits
```

2. Run Noir tests with output:
```bash
nargo test --show-output
```

3. Generate Prover.toml file:
```bash
nargo check
```

4. Execute circuit (after updating Prover.toml with inputs):
```bash
nargo execute
```
This generates:
- Circuit JSON in `target/circuits.json`
- Witness file in `target/circuits.gz`

#### Manual Proof Generation

Generate proof using UltraPlonk:
```bash
bb prove -b ./target/circuits.json -w ./target/circuits.gz -o ./target/proof
```

Generate proof string manually:
**Number of character to tail is counted with formula, 32 * NUMBER_OF_PUBLIC_INPUTS + 1**
**Number of public inputs also includes return values, that's why we have 4 public input for our circuit.**
```bash
tail -c +129 ./target/proof | od -An -v -t x1 | tr -d $' \n'
```
Binary file added foundry-voting/bun.lockb
Binary file not shown.
8 changes: 4 additions & 4 deletions foundry-voting/circuits/Nargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
authors = [""]
compiler_version = ">=0.22.0"
name="foundry_voting"
type="bin"
name = "circuits"
type = "bin"
authors = ["Satyam Bansal"]

[dependencies]
trees = { git = "https://github.com/privacy-scaling-explorations/zk-kit.noir", tag = "main", directory = "packages/merkle-trees" }
4 changes: 2 additions & 2 deletions foundry-voting/circuits/Prover.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
hash_path = [
"0x1efa9d6bb4dfdf86063cc77efdec90eb9262079230f1898049efad264835b6c8",
"0x2a653551d87767c545a2a11b29f0581a392b4e177a87c8e3eb425c51a26a8c77"
"0x2a653551d87767c545a2a11b29f0581a392b4e177a87c8e3eb425c51a26a8c77",
]
index = "0"
proposalId = "0"
root = "0x215597bacd9c7e977dfc170f320074155de974be494579d2586e5b268fa3b629"
secret = "1"
vote = "1"
vote = "1"
4 changes: 0 additions & 4 deletions foundry-voting/circuits/Verifier.toml

This file was deleted.

Loading
Loading