Skip to content

Commit dc2cda2

Browse files
authored
Merge pull request #65 from moven0831/docs/rsa-verifier-circuits
docs(wallet-unit-poc): add RSA verifier circuits reference
2 parents fa16eb4 + d714837 commit dc2cda2

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

wallet-unit-poc/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ cd ecdsa-spartan2
110110
cargo run --release -- benchmark
111111
```
112112

113+
### RSA Verifier Circuits (Reference)
114+
115+
For RS256 (RSA-based) JWT verification, standalone RSA-2048 and RSA-4096 verifier circuits are available as a PoC on the [`feat/rsa-verifier-circuit`](https://github.com/moven0831/zkID/tree/feat/rsa-verifier-circuit) branch. See [RSA_REFERENCE.md](./RSA_REFERENCE.md) for circuit specification, build commands, and benchmarks.
116+
113117
### Mobile Benchmarks
114118

115119
For the reproduction of mobile benchmarks, please check the [OpenAC mobile app directory](/wallet-unit-poc/mobile/)

wallet-unit-poc/RSA_REFERENCE.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# RSA Verifier Circuits — Reference
2+
3+
Standalone RSA-2048 and RSA-4096 signature verification circuits for RS256 JWT verification. This is a **proof-of-concept** on the [`feat/rsa-verifier-circuit`](https://github.com/moven0831/zkID/tree/feat/rsa-verifier-circuit) branch, supplementary to the primary ES256 (JWT + Show) construction.
4+
5+
> **Note:** The main zkID pipeline uses ES256 with shared witness commitments and reblinding for unlinkability. These RSA circuits are independent — no shared witness, no reblinding — and are provided as a reference for teams using RS256 instead of ES256.
6+
7+
## Overview
8+
9+
The RSA verifier circuit performs standalone RSA signature verification in three steps:
10+
11+
1. **SHA-256** — hash the padded message using `@zk-email/circuits`
12+
2. **Bits2Limbs** — convert the 256-bit big-endian hash to little-endian `n`-bit RSA limbs
13+
3. **RSAVerifier65537** — verify PKCS#1 v1.5 RSA-SHA256 signature against the hash
14+
15+
Unlike the main JWT/Show pipeline, these circuits operate independently with no shared witness commitments (`comm_w_shared`) and no reblinding support.
16+
17+
## Circuit Specification
18+
19+
### `RSAVerify(maxByteLength, n, k)`
20+
21+
| Parameter | Description |
22+
|-----------|-------------|
23+
| `maxByteLength` | Max SHA-256 padded message length in bytes (must be multiple of 64) |
24+
| `n` | Bits per RSA limb (recommended: 121) |
25+
| `k` | Number of RSA limbs (17 for RSA-2048, 34 for RSA-4096) |
26+
27+
**Inputs:**
28+
29+
| Signal | Type | Description |
30+
|--------|------|-------------|
31+
| `message[maxByteLength]` | private | SHA-256 padded message bytes |
32+
| `messageLength` | private | Actual message length |
33+
| `signature[k]` | private | RSA signature as `k` limbs |
34+
| `modulus[k]` | **public** | RSA public modulus as `k` limbs |
35+
36+
### Helper: `Bits2Limbs(n, k, totalBits)`
37+
38+
Converts big-endian SHA-256 output bits to little-endian `n`-bit limbs for the RSA verifier. Maps LSB-first limb bit positions to big-endian SHA output indices.
39+
40+
### Concrete Instantiations
41+
42+
| Circuit | Template | File |
43+
|---------|----------|------|
44+
| RSA-2048 | `RSAVerify(64, 121, 17)` | `circuits/main/rsa_verify_2048.circom` |
45+
| RSA-4096 | `RSAVerify(64, 121, 34)` | `circuits/main/rsa_verify_4096.circom` |
46+
47+
## Build & Run Commands
48+
49+
### Circom Compilation
50+
51+
From `wallet-unit-poc/circom/`:
52+
53+
```sh
54+
yarn # install deps (includes @zk-email/circuits)
55+
yarn generate:rsa # generate test inputs (RSA key pair + signature)
56+
yarn compile:rsa2048 # compile RSA-2048 circuit
57+
yarn compile:rsa4096 # compile RSA-4096 circuit
58+
```
59+
60+
### Rust CLI (Spartan2)
61+
62+
From `wallet-unit-poc/ecdsa-spartan2/`:
63+
64+
```sh
65+
# RSA circuits require the rsa-circuits feature flag
66+
cargo run --release --features rsa-circuits -- rsa2048 setup --input ../circom/inputs/rsa_verify_2048/default.json
67+
cargo run --release --features rsa-circuits -- rsa2048 prove --input ../circom/inputs/rsa_verify_2048/default.json
68+
cargo run --release --features rsa-circuits -- rsa2048 verify
69+
70+
cargo run --release --features rsa-circuits -- rsa4096 setup --input ../circom/inputs/rsa_verify_4096/default.json
71+
cargo run --release --features rsa-circuits -- rsa4096 prove --input ../circom/inputs/rsa_verify_4096/default.json
72+
cargo run --release --features rsa-circuits -- rsa4096 verify
73+
74+
# Full benchmark for a single circuit
75+
cargo run --release --features rsa-circuits -- rsa2048 benchmark --input ../circom/inputs/rsa_verify_2048/default.json
76+
cargo run --release --features rsa-circuits -- rsa4096 benchmark --input ../circom/inputs/rsa_verify_4096/default.json
77+
```
78+
79+
### Feature Flags
80+
81+
```toml
82+
[features]
83+
default = ["jwt-circuit", "show-circuit"]
84+
jwt-circuit = []
85+
show-circuit = []
86+
rsa-circuits = [] # opt-in, not built by default
87+
```
88+
89+
**Reblind is not supported** for RSA circuits — the `shared()` and `precommitted()` trait methods return empty vectors.
90+
91+
## Benchmarks
92+
93+
**Test Device:** MacBook Pro, M4, 14-core GPU, 24GB RAM
94+
95+
### Circuit Characteristics
96+
97+
| Metric | RSA-2048 | RSA-4096 |
98+
|--------|----------|----------|
99+
| Wires | 215,439 | 405,962 |
100+
| Constraints | 216,400 | 407,824 |
101+
| Private Inputs | 82 | 99 |
102+
| Public Inputs | 17 | 34 |
103+
104+
### Timing
105+
106+
| Operation | RSA-2048 | RSA-4096 |
107+
|-----------|----------|----------|
108+
| Setup | 713 ms | 2,042 ms |
109+
| Prove | 345 ms | 767 ms |
110+
| Verify | 33 ms | 68 ms |
111+
112+
### Artifact Sizes
113+
114+
| Artifact | RSA-2048 | RSA-4096 |
115+
|----------|----------|----------|
116+
| Proving Key | 65.92 MB | 174.91 MB |
117+
| Verifying Key | 65.92 MB | 174.91 MB |
118+
| Proof | 50.61 KB | 59.87 KB |
119+
| Witness | 8.01 MB | 16.02 MB |
120+
121+
Source: [ZK-based-Human-Verification #14](https://github.com/zkmopro/ZK-based-Human-Verification/issues/14#issuecomment-3883009179)
122+
123+
## Key Files on Branch
124+
125+
All files are on the [`feat/rsa-verifier-circuit`](https://github.com/moven0831/zkID/tree/feat/rsa-verifier-circuit) branch.
126+
127+
| File | Description |
128+
|------|-------------|
129+
| `circom/circuits/rsa_verify.circom` | `RSAVerify` and `Bits2Limbs` circuit templates |
130+
| `circom/circuits/main/rsa_verify_2048.circom` | RSA-2048 instantiation (`k=17`) |
131+
| `circom/circuits/main/rsa_verify_4096.circom` | RSA-4096 instantiation (`k=34`) |
132+
| `circom/inputs/rsa_verify_2048/default.json` | Test inputs for RSA-2048 |
133+
| `circom/inputs/rsa_verify_4096/default.json` | Test inputs for RSA-4096 |
134+
| `circom/src/generate_rsa_inputs.ts` | Input generator (RSA key pair + PKCS#1 v1.5 signature) |
135+
| `ecdsa-spartan2/src/circuits/rsa_verify_circuit.rs` | Rust `SpartanCircuit<E>` implementation |
136+
| `ecdsa-spartan2/Cargo.toml` | Feature flags (`rsa-circuits`) |
137+
| `ecdsa-spartan2/src/main.rs` | CLI commands for `rsa2048` / `rsa4096` |

0 commit comments

Comments
 (0)