Skip to content

Commit 1f102d8

Browse files
committed
test: reduce chain length for ci
remove workflow Update README.md Update README.md docs and refactor readme Update README.md Update README.md readme readme refactor docs, tests, error handling, type alias docs readme Update README.md Update README.md add testing workflow workflow workflow update Update README.md test: layer count docs workflows and readme workflow names Update README.md workflow badges add benches Update README.md Update README.md update TODO circuit telemetry and benches clippy doctest workflow telemetry Update README.md add RAM bench Update README.md circuit diagram Update README.md docs docs function names and docs
1 parent bd05d26 commit 1f102d8

File tree

10 files changed

+731
-160
lines changed

10 files changed

+731
-160
lines changed

.github/workflows/rust_test.yaml

Lines changed: 0 additions & 28 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Test Keccak Hash
2+
3+
on:
4+
push:
5+
branches:
6+
- feat/keccak
7+
pull_request:
8+
branches:
9+
- feat/keccak
10+
11+
jobs:
12+
build_and_test:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v3
16+
- uses: actions-rs/toolchain@v1
17+
with:
18+
toolchain: nightly
19+
profile: minimal
20+
override: true
21+
components: rustfmt, clippy
22+
- uses: actions-rs/cargo@v1
23+
with:
24+
command: test
25+
args: --release
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Test Poseidon Hash
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
build_and_test:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v3
16+
- uses: actions-rs/toolchain@v1
17+
with:
18+
toolchain: nightly
19+
profile: minimal
20+
override: true
21+
components: rustfmt, clippy
22+
- uses: actions-rs/cargo@v1
23+
with:
24+
command: test
25+
args: --release

.vscode/settings.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"git.openRepositoryInParentFolders": "never",
3+
"git.confirmSync": false,
4+
"editor.formatOnSave": true,
5+
"workbench.startupEditor": "none",
6+
"extensions.ignoreRecommendations": true,
7+
"rust-analyzer.rustfmt.overrideCommand": [
8+
"rustfmt",
9+
"+nightly"
10+
],
11+
"rust-analyzer.server.path": null,
12+
"explorer.confirmDelete": false
13+
}

Cargo.lock

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ log = "0.4.20"
1919
sha3 = "0.10.6"
2020
structopt = { version = "0.3.26", default-features = false }
2121
env_logger = "0.11.5"
22+
thiserror = "1.0.63"
23+
criterion = "0.3"
2224

2325
[dev-dependencies]
2426
debug_print = { version = "1.0.0" }
@@ -32,4 +34,9 @@ plonky2 = { git = "https://github.com/drcapybara/plonky2", branch = "upstream" }
3234
plonky2_crypto = { git = "https://github.com/Lagrange-Labs/plonky2-crypto", branch = "patch-plonky2" }
3335

3436
[profile.dev]
35-
opt-level = 3
37+
opt-level = 3
38+
39+
[[bench]]
40+
name = "hash_chain_bench"
41+
path = "benches/hash_chain_benches.rs"
42+
harness = false

README.md

Lines changed: 150 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,108 @@
11
# Cyclic Hash Computation with Plonky2
22

3-
Have you ever been sitting behind your desk one evening and thought to yourself, "Gee whiz, I sure wish I could cryptographically prove in quantum-resistant zero knowledge that I computed a gigantic chain of hashes correctly"? Well _good news_ because this repo will fill that burning hole in your heart with a plonky2-based implementation of a recursive computation chain that proves a series of hashes a la IVC style and outputs a compressed proof of constant size, arguing the integrity of a potentially unlimited size computation.
3+
Have you ever thought to yourself, "Gee, I sure wish I could cryptographically prove in quantum-resistant zero knowledge that I computed a gigantic chain of hashes correctly"? Well _good news_ because this repo will fill that burning hole in your heart with a plonky2-based implementation of a prover/verifier pair for a recursive computation chain that argues the computational integrity of a series of hashes a la IVC style and outputs a compressed proof of constant size. The recursive nature of this circuit gives desireable scaling characteristics, and this work presents and effort to better understand the unique design challenges presented when working with low-level circuitry.
4+
5+
## Quick start:
6+
7+
You can download the repo and run the main branch with:
8+
```bash
9+
cargo test
10+
```
11+
12+
Which is run in release mode by default. This repo requires the nightly toolchain. If you are seeing errors related to:
13+
14+
```bash
15+
6 | #![feature(specialization)]
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
18+
error[E0554]: `#![feature]` may not be used on the stable release channel
19+
|
20+
7 | #![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_avx512))]
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
22+
23+
error[E0554]: `#![feature]` may not be used on the stable release channel
24+
|
25+
7 | #![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_avx512))]
26+
| ^^^^^^^^^^^^^^^^^^
27+
```
28+
29+
Then please double check your toolchain. Otherwise, this repo should work out of the box.
30+
31+
You can also run:
32+
33+
```bash
34+
RUSTFLAGS="-Ctarget-cpu=native" cargo run --release --example circuit_telemetry -- -vv --steps 20
35+
```
36+
37+
To quickly benchmark prover and verifer performance, as well as examine details about the chain over a given number of steps:
38+
39+
```text
40+
[2024-08-23T08:01:38Z INFO hash_chain] Number of gates in circuit: 112960
41+
[2024-08-23T08:01:46Z INFO hash_chain] Total Proof length: 133440 bytes
42+
[2024-08-23T08:01:46Z INFO circuit_telemetry] Proof time: 9.733192095s
43+
[2024-08-23T08:01:46Z INFO circuit_telemetry] Verification time: 4.142599ms
44+
[2024-08-23T08:01:46Z INFO circuit_telemetry] Circuit depth: 20
45+
```
46+
## Supported Hashes:
47+
48+
The following hashes are available in the recursive chain:
49+
50+
| Hasher | Validation |
51+
|----------|----------|
52+
| Poseidon Hash | [![Test Poseidon Hash](https://github.com/drcapybara/hash-chain/actions/workflows/test_poseidon_hash_chain.yml/badge.svg?branch=main)](https://github.com/drcapybara/hash-chain/actions/workflows/test_poseidon_hash_chain.yml) |
53+
| Keccak | [![Test Keccak Hash](https://github.com/drcapybara/hash-chain/actions/workflows/test_keccak_hash_chain.yml/badge.svg?branch=feat%2Fkeccak)](https://github.com/drcapybara/hash-chain/actions/workflows/test_keccak_hash_chain.yml) |
54+
55+
The keccak chain fails to build successfully at current, work is ongoing to fix this eventually.
456

557
# Strategy
658

759
Our approach is to insert the following gates into the circuit with the requisite connections. It is not enough to create a circuit that simply connects each hash output the next input, the prover must argue the hash computation _and_ verify the preceeding hash in a single step, taking into account the recursive structure of the chain:
860

61+
```text
62+
+--------------------------------+ +-------------------------+ +------------------------------+
63+
| 1. initialize_circuit_builder | | 2. setup_hashes | | 3. common_data_for_recursion |
64+
| Set up the circuit builder |──▶| Configure initial |──▶| Set up data for recursion |
65+
| and configuration. | | and current hash | | and verifier data inputs. |
66+
+--------------------------------+ | targets and register | +------------------------------+
67+
| | them as public inputs. | |
68+
| +-------------------------+ |
69+
│ │
70+
│ +--------------------+ │
71+
└──────────▶| 4. setup_condition | │
72+
| Set condition for | │
73+
| recursion base. | │
74+
+--------------------+ │
75+
│ ▼
76+
│ +--------------------------------------+
77+
└──────────▶| 5. setup_recursive_layers |
78+
| Configure recursive layers |
79+
| and integrate proof. |
80+
+--------------------------------------+
81+
│ ▲
82+
│ │
83+
│ │
84+
▼ │
85+
+-----------------------------+ │
86+
| 6. process_recursive_layer |──┘
87+
| Handle recursion, verify, |
88+
| and loop through steps. |
89+
+-----------------------------+
90+
91+
92+
+-------------------------+
93+
| 7. compile_and_process |
94+
| Finalize circuit and |
95+
| handle processing. |
96+
+-------------------------+
997
```
10-
+------------------+ +------------------+ +-----------------+
11-
| Initial Hash | | Current Hash | | Verifier Data |
12-
| Target Gate |──▶| Input Target |──▶| Target Gate |
13-
+------------------+ | (Updateable) | +-----------------+
14-
│ +------------------+ │
15-
│ │ ▲ │
16-
│ │ │ │
17-
│ │ └───────┐ │
18-
│ │ │ │
19-
│ +-----------+ │ │
20-
└───────────▶| Condition | │ │
21-
| Check Gate| │ │
22-
+-----------+ │ │
23-
│ │ │
24-
│ +------------------------+
25-
└───┤ Recursive Proof |
26-
| Integration & Loop |
27-
+------------------------+
28-
│ ▲
29-
│ │
30-
│ │
31-
│ │
32-
+---------------+ │
33-
| Step Counter |───┘
34-
| & Loop Check |
35-
+---------------+
36-
37-
38-
+---------------+
39-
| Finalize Hash |
40-
| & Verification|
41-
+---------------+
42-
```
98+
You can also view a rough sketch of a circuit diagram of the entire setup:
99+
![](https://github.com/user-attachments/assets/0d7e9a9a-a1c3-4b5e-95fd-1dbe812d1076)
100+
43101

44102
### Initial Setup
45103
- **Counter Initialization**: A counter gate is initialized to track the depth of recursion.
46104
- **Hash Initialization**: A virtual hash target gate is inserted and registered as a public input, marking the starting point of the hash chain.
47-
- **Keccak Hash Gate**: An updateable hash gate is added to enable hash updates as the recursion progresses.
105+
- **Hash Gate**: An updateable hash gate is added to enable hash updates as the recursion progresses.
48106

49107
### Recursive Hashing
50108
- **Verifier Data Setup**: Circuit common data is prepared, including configuration and partial witnesses required for recursion.
@@ -72,24 +130,69 @@ use plonky2::{
72130
},
73131
};
74132

75-
// setup the parameters for the circuit
76133
const D: usize = 2;
77-
type C = PoseidonGoldilocksConfig; // this is the hasher for FRI, not for the circuit
134+
type C = PoseidonGoldilocksConfig; // A config with poseidon as the hasher for FRI
78135
type F = <C as GenericConfig<D>>::F;
79136

80-
let config = CircuitConfig::standard_recursion_config(); // Non-ZK standard recursion config
81-
let mut hash_chain_circuit = CircuitBuilder::<F, D>::new(config.clone());
137+
// a non-ZK config, commitments and proof may reveal input data
138+
let config = CircuitConfig::standard_recursion_config();
139+
let mut circuit = CircuitBuilder::<F, D>::new(config.clone());
140+
141+
// Prove
142+
let (proof, circuit_data) =
143+
<CircuitBuilder<GoldilocksField, D> as HashChain<GoldilocksField, D, C>>::build_hash_chain_circuit(
144+
&mut circuit,
145+
2, // number of steps in the hash chain
146+
)
147+
.unwrap();
82148

83-
<CircuitBuilder<GoldilocksField, 2> as HashChain<GoldilocksField, 2, C>>::hash_chain(
84-
&mut hash_chain_circuit,
85-
10, // compute a hash chain of size 10
86-
)
87-
.unwrap();
149+
// Verify
150+
let verification_result =
151+
<CircuitBuilder<GoldilocksField, D> as HashChain<GoldilocksField, D, C>>::verify(proof, circuit_data);
152+
assert!(verification_result.is_ok());
88153
```
89154

90-
We observe a total uncomressed proof size of 133440 bytes, regardless of number of steps in the chain.
155+
We observe a total uncompressed proof size of 133440 bytes, regardless of number of steps in the chain. We find this is very nice because this number stays the same no matter how many hashes we compute. In theory, recursively verifiable proofs of this nature can compress extremely large computations into a very small space. Think fully-succinct blockchains, in which light clients can verify the entire state of the chain trustlessly by verifying a small and simple proof in trivial amounts of time.
156+
157+
## Benches
158+
159+
This crate uses criterion for formal benchmarks. Bench prover and verifier performance with:
160+
161+
```bash
162+
cargo bench
163+
```
164+
Here are some prelimnary performance metrics observed thus far:
165+
166+
| Circuit depth (steps) | Prover Runtime (s) | Verifier Runtime (ms)| System RAM Used (mb)|
167+
|-----------------------|--------------------|----------------------|---------------------|
168+
| 2 | 3.3680 s | 3.1013 ms | 375.692 |
169+
| 4 | 4.2126 s | 3.1220 ms | 381.536 |
170+
| 8 | 5.7366 s | 3.0812 ms | 392.716 |
171+
| 16 | 8.8146 s | 3.1098 ms | 405.516 |
172+
| 32 | 14.957 s | 3.0865 ms | 417.704 |
173+
| 64 | 27.294 s | 3.1625 ms | 436.424 |
174+
175+
176+
## Acknowledgments
177+
178+
This project makes use of the following open-source libraries:
179+
180+
Recursive STARK Wiring framework:
181+
- **[plonky2](https://github.com/drcapybara/plonky2)** by Polygon Labs
182+
183+
184+
Hash Circuits:
185+
- **[plonky2_crypto](https://github.com/JumpCrypto/plonky2-crypto)** by Jump Crypto
186+
187+
## Readings
188+
- [Plonky2 whitepaper](https://github.com/0xPolygonZero/plonky2/blob/main/plonky2/plonky2.pdf)
189+
190+
- The always excellent [Anatomy of a STARK](https://aszepieniec.github.io/stark-anatomy/):
191+
91192

92-
TODO
193+
## TODO
194+
- [x] add benches
195+
- [x] better error handling with thiserr
93196
- [ ] Compress the proof at the end
94197
- [ ] support keccak
95-
- [ ] add benches
198+
- [ ] add richer circuit telemetry

0 commit comments

Comments
 (0)