Skip to content

Commit 4ed5b71

Browse files
authored
Merge pull request #1 from bloxbean/feat/poseidon_bls12-381
Add BLS12-381 Poseidon, Jubjub-in-circuit support
2 parents 2cc021a + fc96ac5 commit 4ed5b71

45 files changed

Lines changed: 7134 additions & 82 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,4 @@ Thumbs.db
7878

7979
### Development planning (not part of the source) ###
8080
plan.md
81+
/.playwright-mcp/
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# ADR-0014: W3C Verifiable Credential Support in Circuit Lib
2+
3+
## Status
4+
Proposed
5+
6+
## Date
7+
2026-04-02
8+
9+
## Context
10+
11+
The identity-kyc demo (`zeroj-usecases/identity-kyc`) demonstrates privacy-preserving KYC on Cardano — users prove eligibility (age, country) without revealing personal data. However, it uses **Poseidon-signed credentials** (a shared-secret scheme), which has two limitations:
12+
13+
1. **No standard interoperability** — Poseidon-signed credentials are ZeroJ-specific. They can't be issued or verified by W3C VC tooling, DID wallets, or Atala PRISM.
14+
2. **Weak security model** — the issuer and holder share the same secret (`credentialSecret`). The issuer can impersonate the holder, and the secret must be transmitted securely.
15+
16+
To support W3C Verifiable Credentials and DID-based identity, the ZK circuit library needs three new capabilities that enable **asymmetric credential signatures** verifiable inside a ZK proof.
17+
18+
### Current state of zeroj-circuit-lib
19+
20+
| Primitive | Status | Notes |
21+
|-----------|--------|-------|
22+
| Poseidon hash | Available | Used for credential hashing today |
23+
| Merkle proof verification | Available | Used for country whitelist |
24+
| Range comparisons | Available | Used for age >= minAge |
25+
| **BabyJubJub curve** | **Removed** | Was in circuit-lib, removed during security audit (missing subgroup checks) |
26+
| **EdDSA signature verification** | **Removed** | Depended on BabyJubJub, removed with it (signature malleability issues) |
27+
| **BBS+ signature verification** | **Not implemented** | Requires pairing math inside circuit |
28+
29+
The BabyJubJub and EdDSA implementations were removed after a security audit identified:
30+
- BabyJubJub: missing cofactor-clearing / subgroup checks — points from the larger curve group could bypass verification
31+
- EdDSA: signature malleability — multiple valid signatures for the same message (S + L is also valid where L is the subgroup order)
32+
- Both: zero test coverage for edge cases
33+
34+
### Why these matter for Cardano
35+
36+
Cardano's identity ecosystem is moving toward DID and W3C VCs:
37+
- **Atala PRISM** uses W3C Verifiable Credentials with DID:prism identifiers
38+
- **CIP-0030 / CIP-0045** wallet standards support credential presentation
39+
- **EU eIDAS 2.0** mandates interoperable digital identity — W3C VC is the baseline format
40+
41+
Without in-circuit signature verification, ZeroJ can only prove statements about credentials signed with symmetric (Poseidon) schemes, limiting adoption to single-issuer, closed systems.
42+
43+
## Decision
44+
45+
### Add three capabilities to zeroj-circuit-lib, in priority order:
46+
47+
### 1. BabyJubJub curve (re-add with hardening)
48+
49+
Re-implement the BabyJubJub twisted Edwards curve with proper security:
50+
51+
```java
52+
public class SignalBabyJubJub {
53+
// Point addition on BabyJubJub (twisted Edwards: ax^2 + y^2 = 1 + dx^2y^2)
54+
// a = 168700, d = 168696 (matching circomlib)
55+
static Signal[] add(SignalBuilder c, Signal[] p1, Signal[] p2);
56+
57+
// Scalar multiplication via double-and-add (constant-time ladder)
58+
static Signal[] scalarMul(SignalBuilder c, Signal scalar, Signal[] basePoint, int nBits);
59+
60+
// Subgroup check: verify point is in the prime-order subgroup
61+
// Multiplies by cofactor (8) and checks result is not identity
62+
static void assertInSubgroup(SignalBuilder c, Signal[] point);
63+
}
64+
```
65+
66+
**Security fixes:**
67+
- Cofactor clearing: `assertInSubgroup()` ensures points are in the prime-order subgroup (order `l`), not the larger curve group (order `8l`)
68+
- All public inputs that are curve points must pass subgroup check before use in arithmetic
69+
- Test vectors from circomlib/iden3 for edge cases (identity, generator, cofactor multiples)
70+
71+
**Constraints:** ~500 per scalar multiplication (256 doublings + ~128 additions for 256-bit scalar)
72+
73+
### 2. EdDSA signature verification in-circuit
74+
75+
Verify EdDSA (EdDSA-BabyJubJub, compatible with circomlib/iden3) signatures inside a ZK proof:
76+
77+
```java
78+
public class SignalEdDSA {
79+
/**
80+
* Verify an EdDSA signature (R, S) on message M under public key A.
81+
*
82+
* Checks: [S]B == R + [H(R, A, M)]A
83+
* where B is the generator and H is Poseidon (matching circomlib).
84+
*/
85+
static Signal verify(SignalBuilder c,
86+
Signal[] pubKeyA, // [Ax, Ay]
87+
Signal[] sigR, // [Rx, Ry]
88+
Signal sigS, // scalar S
89+
Signal message); // message hash
90+
}
91+
```
92+
93+
**Security fixes:**
94+
- Strict S range check: `S < l` (subgroup order) — prevents signature malleability where `S + l` is also valid
95+
- R point subgroup check via `assertInSubgroup()`
96+
- Public key subgroup check via `assertInSubgroup()`
97+
- Use Poseidon for H(R, A, M) — matching circomlib's `EdDSAPoseidonVerifier`
98+
99+
**Constraints:** ~3,000 (2 scalar multiplications + 1 point addition + Poseidon hash + range check)
100+
101+
### 3. BBS+ selective disclosure (future)
102+
103+
BBS+ signatures allow a holder to selectively disclose individual claims from a credential without revealing others. This is the gold standard for W3C VC privacy.
104+
105+
```java
106+
public class SignalBBS {
107+
/**
108+
* Verify a BBS+ signature on a set of messages, with selective disclosure.
109+
*
110+
* Only disclosed messages are public inputs. Hidden messages are private.
111+
* The verifier learns: "a trusted issuer signed these claims, and the
112+
* disclosed claims have these values" — without learning the hidden claims.
113+
*/
114+
static Signal verify(SignalBuilder c,
115+
Signal[] disclosedMessages, // public
116+
Signal[] hiddenMessages, // private
117+
Signal[] signature, // private
118+
Signal[] issuerPublicKey); // public
119+
}
120+
```
121+
122+
**Complexity:** Requires BLS12-381 pairing operations inside the circuit (~10,000+ constraints). This is the most complex primitive and should be implemented after EdDSA is stable.
123+
124+
**Note:** BBS+ is still evolving as a standard (IETF draft). Implementation should track the latest spec.
125+
126+
## Consequences
127+
128+
### Positive
129+
130+
1. **W3C VC compatibility** — credentials issued by any W3C VC compliant issuer (Atala PRISM, Spruce, etc.) can be verified inside ZeroJ ZK proofs
131+
2. **Multi-issuer ecosystems** — asymmetric signatures mean the issuer can't impersonate the holder
132+
3. **Atala PRISM integration** — enables ZK proofs over PRISM-issued credentials on Cardano
133+
4. **EU eIDAS readiness** — Cardano DApps can accept European Digital Identity Wallet credentials
134+
5. **Selective disclosure (BBS+)** — holders reveal only the claims needed, not the entire credential
135+
6. **Ecosystem alignment** — matches what other ZK projects (circomlib, Polygon ID, Iden3) provide
136+
137+
### Negative
138+
139+
1. **Circuit size increase** — EdDSA verification adds ~3,000 constraints vs ~660 for Poseidon-signed, increasing proof generation time by ~3x
140+
2. **BabyJubJub is not Cardano-native** — Cardano's Plutus V3 has BLS12-381 builtins, not BabyJubJub. EdDSA signature verification happens inside the ZK circuit (off-chain), not via on-chain builtins
141+
3. **Implementation complexity** — elliptic curve arithmetic in R1CS is error-prone; incomplete addition formulas, special-case handling for identity/doubling
142+
4. **BBS+ is speculative** — the IETF standard is not finalized; implementation may need to change
143+
144+
## Risks
145+
146+
| Risk | Severity | Mitigation |
147+
|------|----------|------------|
148+
| BabyJubJub subgroup check bypass | **Critical** | Mandatory cofactor clearing; test with all 8 coset representatives; differential testing against circomlib |
149+
| EdDSA signature malleability | **Critical** | Strict S < l range check (bit decomposition); test with S, S+l, S+2l; compare against circomlib EdDSAPoseidonVerifier |
150+
| Incomplete addition formula edge cases | High | Use complete twisted Edwards addition formula (no exceptions for doubling/identity); exhaustive test with identity, generator, -generator, cofactor points |
151+
| BBS+ spec changes | Medium | Implement behind feature flag; track IETF draft; plan for breaking changes |
152+
| Performance regression for simple use cases | Low | Poseidon-signed credentials remain available as a lightweight option; circuit choice is per-application |
153+
154+
## Implementation Order
155+
156+
1. **Phase 1: BabyJubJub** — re-add with subgroup checks, 100% test coverage, differential testing against circomlib
157+
2. **Phase 2: EdDSA** — signature verification circuit, malleability fix, test against circomlib EdDSAPoseidonVerifier
158+
3. **Phase 3: Identity KYC demo upgrade** — switch from Poseidon-signed to EdDSA-signed credentials
159+
4. **Phase 4: BBS+** — selective disclosure (when IETF spec stabilizes)
160+
161+
## References
162+
163+
- [W3C Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/)
164+
- [W3C Decentralized Identifiers (DIDs)](https://www.w3.org/TR/did-core/)
165+
- [BabyJubJub — iden3 specification](https://iden3-docs.readthedocs.io/en/latest/iden3_repos/research/publications/zkproof-standards-workshop-2/baby-jubjub/baby-jubjub.html)
166+
- [circomlib EdDSAPoseidonVerifier](https://github.com/iden3/circomlib/blob/master/circuits/eddsa.circom)
167+
- [BBS+ Signatures — IETF Draft](https://www.ietf.org/archive/id/draft-irtf-cfrg-bbs-signatures-07.html)
168+
- [Atala PRISM — Cardano Identity](https://atalaprism.io/)
169+
- [EU eIDAS 2.0 — European Digital Identity](https://digital-strategy.ec.europa.eu/en/policies/eidas-regulation)
170+
- ZeroJ security audit findings (BabyJubJub/EdDSA removal rationale)
171+
- `zeroj-usecases/identity-kyc` — current Poseidon-signed credential demo
172+
- `docs/usecases/identity-and-credentials.md` — full design doc with 3 credential approaches

0 commit comments

Comments
 (0)