Polkadot-native DKIM/ZK Email attestations for People Chain evaluation.
zkAttest lets a user prove possession of a DKIM-signed email with a zero-knowledge proof, then verify that proof through Polkadot infrastructure. The project builds on upstream ZK Email circuits and adds the Polkadot-specific integration layer: PolkaVM verification, FRAME pallets, a governance-managed DKIM registry, Polkadot wallet UX, and a People Chain / DIM integration path.
Links:
- Demo site: https://msmrez.github.io/zkattest/
- Repository: https://github.com/msmrez/zkattest
zkAttest is a prototype credential source for Polkadot People / Project Individuality evaluation. It explores a DIM2-compatible email-ownership signal whose cryptographic trust path runs through:
- the email provider's DKIM signature,
- an on-chain DKIM key registry,
- a Groth16 verifier compiled for PolkaVM / pallet-revive,
- a FRAME pallet that handles proof verification, nullifiers, and attestation flow.
The current system demonstrates the core technical path:
.emlparsing and DKIM metadata extraction in the browser demo,- toy Groth16 browser proving and wallet-signed Asset Hub submission,
- a real zkEmail-derived circuit path through CLI / Node,
- proof verification against a deployed Asset Hub verifier,
- prototype FRAME pallets for DKIM registry and zkAttest logic.
zkAttest should first be evaluated as a supplemental DIM2-compatible credential source for Polkadot People / Individuality, not as a standalone proof-of-personhood mechanism.
zkAttest is not positioned as a standalone unique-humanity system.
Email ownership is an attestation signal. It does not, by itself, establish that one account maps to one unique human. The intended first role is a supplemental DIM2-compatible credential signal for Polkadot People / Individuality evaluation, alongside stronger personhood mechanisms and policy decisions.
| Component | State |
|---|---|
| Real zkEmail-derived Groth16 verifier on PolkaVM | Deployed and proof-verified on Polkadot Asset Hub mainnet |
pallet-dkim-registry |
Prototype complete, 5 source tests |
pallet-zkattest |
Prototype complete, 18 source tests: 5 pallet tests, 8 evm_abi tests, 5 ReviveVerifier tests |
| DKIM key scraper | Prototype that pulls real keys from Gmail, Outlook, Yahoo, ProtonMail, SendGrid |
| Prover SDK | TypeScript wrapper around @zk-email/helpers and snarkjs |
| Browser proof generation | Live toy-circuit Groth16 demo; real zkEmail-derived proof currently runs through CLI / Node |
| Browser on-chain submission | Wallet-signed revive.call to the deployed toy verifier |
| People Chain integration | Target path; production interface integration is grant work |
Proof-critical package versions used in this repo:
| Package | Version |
|---|---|
@zk-email/helpers |
6.4.2 |
@zk-email/circuits |
6.3.4 |
snarkjs |
0.7.6 |
Live mainnet artifacts for the current prototype:
Real zkEmail-derived circuit:
- Circuit:
real-circuit/zkattest_email.circom - Constraint count: approximately 315k
- Public inputs: 3
- Verifier contract:
0xca1a3ad129e204d9af942a30f7f09282d20e28bf - Deploy tx:
0x271f59aa8c7670809efb8f76c594628cc0eeb8bc9f68f796ca8eff8a8fbf1edc - Verify tx:
0x82bdae3a8530797f890d41d279daccc087d3a4e7e35ecaf2b99275cad4f71acc - Recorded gas:
refTimeabout3.93e9,proofSizeabout19.6 KiB
Toy circuit used by the browser demo:
- Circuit:
web/circuit/circuit.circom - Verifier contract:
0x4fa8678fb0188b29e49254759fb876eecdede468 - Verify tx:
0xe3e11b8a2b386e2aa77dd8168d7aac7200bb83529f44ad1d92e2922e061f76a8 - Recorded gas:
refTimeabout1.77e9,proofSizeabout15.0 KiB
See artifacts/MANIFEST.md for checksums and artifact mapping.
The web demo has two separate purposes:
- It parses
.emlfiles locally and extracts DKIM metadata. - It runs a real Groth16 proof in the browser using a small toy circuit, then submits that proof to a toy verifier on Asset Hub.
The production email circuit is separate. The real zkEmail-derived circuit has been built and proof-verified through the CLI / Asset Hub path. Integrating full real-email proving into the browser is future work.
People Chain pallet integration is also future work. The current pallet is a prototype integration target, not a production People Chain deployment.
- Demo site: https://msmrez.github.io/zkattest/
- Repository: https://github.com/msmrez/zkattest
The demo page is intentionally explicit about status: browser proving is a toy circuit, while the real zkEmail-derived proof path is currently CLI / Node plus Asset Hub verification.
pallets/
dkim-registry/ On-chain registry of trusted (domain, selector) to DKIM pubkey
zkattest/ Proof verification, nullifier, and People Chain integration target
prover/ TypeScript prover helpers
scraper/ DKIM key scraper prototype
real-circuit/ Real zkEmail-derived circuit build recipe and verifier artifacts
spike/ Asset Hub deploy, proof generation, and verifier scripts
web/ Static GitHub Pages demo
artifacts/MANIFEST.md Checksums and artifact mapping
docs/REPRODUCIBILITY.md Reviewer reproduction paths
docs/TRUST_MODEL.md Trust assumptions and privacy notes
HOSTING.md Cloudflare R2 upload notes
See docs/REPRODUCIBILITY.md for the full reviewer checklist. Proof-critical dependency versions are pinned in the package files and summarized in the current status table above.
Generate and locally verify a real zkEmail-derived Groth16 proof:
cd spike
npm install
curl -L https://pub-a34a2db2f64d4ca1b7914c0cfe6652fc.r2.dev/email_ownership/circuit_final.zkey -o circuit_final.zkey
node gen-proof.mjsExpected signal:
node gen-proof.mjsprintsLocal verify: OK.
cd web
python3 -m http.server 8000Open http://localhost:8000, drop a DKIM-signed .eml file, generate the toy
Groth16 proof, and optionally connect a Polkadot wallet for the toy Asset Hub
verification flow.
Dry-run the real proof against the deployed Asset Hub verifier:
cd spike
DRYRUN_ONLY=1 CONTRACT=0xca1a3ad129e204d9af942a30f7f09282d20e28bf node verify-substrate.mjsExpected signal:
verify-substrate.mjsprintsverifyProof returned: true.
These are scope boundaries for the current prototype:
- Email ownership is a credential signal, not complete proof of unique humanity.
- The browser demo uses a toy Groth16 circuit; the full zkEmail-derived browser prover is grant work.
- The real circuit currently uses minimal parameters and synthetic test inputs.
- The
pallet-zkattestPeople Chain path is prototype-level until the target People interface is finalized and integrated. - DKIM key rotation, registry governance, nullifier privacy, and replay prevention require production policy decisions.
See docs/KNOWN_LIMITATIONS.md for the full list and docs/TRUST_MODEL.md for the detailed trust model.
The current design relies on:
- DKIM provider DNS keys being available and correctly represented in the registry,
- governance-managed activation, expiry, and revocation of DKIM keys,
- upstream ZK Email circuit correctness,
- Groth16 trusted setup and artifact integrity,
- PolkaVM / BN254 precompile correctness,
- nullifier construction that prevents replay while preserving the intended privacy properties.
Completed:
- Groth16 verifier compiled to PolkaVM via
resolc 1.1.0. - Real zkEmail-derived proof verified on Polkadot Asset Hub mainnet.
- FRAME prototype pallets with 23 source tests.
- Browser demo with DKIM parsing, toy Groth16 proof generation, and toy Asset Hub verifier submission.
- DKIM scraper prototype with real key pulls.
- Cloudflare R2 hosting for real-circuit
.wasm,.zkey, and vkey artifacts.
Next:
- Reproducible build/devcontainer path.
- Production-oriented real email circuit parameters.
- Real zkEmail browser or hybrid prover path.
-
pallet-zkattestintegration against the production People interface. - DIM2 attestation-source RFC / pre-proposal.
- Independent review of circuit, verifier, pallet, and registry assumptions.
Apache-2.0. See LICENSE.