Zero-knowledge proof of email ownership for a privacy-preserving credential signal. No app-side issuer in the trust path, no raw email contents revealed. The trust root is the cryptographic DKIM signature your email provider already puts on every email.
A Polkadot-native zkEmail-based attestation-source prototype for Polkadot People / Individuality evaluation, designed to plug into DIM2 via a FRAME pallet and a Groth16 verifier already live on Polkadot Asset Hub mainnet.
Polkadot's People / Individuality system can use multiple credential sources. The named candidates commonly introduce either an issuer, an attestor, or a service-specific verifier in the trust path.
Server verifies the account and signs a credential. The trust path includes that issuer, so the verifier must trust KILT's attestation semantics in addition to email cryptography.
TLS attestor nodes co-witness your HTTPS session in real time. That model is strong for arbitrary web data, but it is not the native trust root for DKIM-signed email.
The trust root is the email provider's DKIM signature, a cryptographic fact that exists before zkAttest touches it. No app-side attester or issuer is added. The proof verifies on-chain.
Five steps from your inbox to a People Chain-aligned attestation. The production goal is local proving, so raw email content does not leave the user's device.
In the production flow, the dApp will trigger a relayer to send a challenge email to your address; you click a link and your browser downloads the raw .eml. For today's demo, you can drag-drop any existing DKIM-signed email from your inbox.
Why this works: major providers such as Gmail, Outlook, and Yahoo commonly sign outgoing email with a private RSA key (DKIM, RFC 6376). That signature is in the email you just received.
The production prover will run the zkEmail Circom circuit locally via WASM. The deployed CLI path already proves this circuit on Polkadot Asset Hub; the browser path is the next integration milestone. The circuit proves:
The email body, recipient, message ID, and full headers are never revealed.
The Groth16 proof is verified on Asset Hub by the deployed Verifier.sol contract (compiled to PolkaVM via Parity's resolc compiler). BN254 pairing precompiles confirm the mathematics in a single transaction.
The nullifier (a hash of the DKIM signature bytes, unique to the signed message) is stored on-chain in pallet-zkattest. Once recorded, the same proof cannot be reused.
pallet-zkattest is designed to call the People Chain personhood interface once it is finalized. The goal is a candidate People Chain attestation path without government ID, in-person ceremony, or a trusted issuer for email ownership.
Drop any .eml file to see your DKIM signature extracted and validated in the page. The demo does not upload the file.
This is the same Groth16 proving system zkAttest uses for email proofs — running here on a small demo circuit to show real ZK performance in your browser. No proving server. Inputs stay in the page.
The demo circuit proves you know two numbers a, b such that iterating
x ← x² + b 1000 times starting from a² + b
yields the public output. The full zkEmail circuit replaces this with DKIM signature verification + regex matching.
c (computed by circuit)↑ This proof is a real Groth16 proof on BN254 using the same proving stack and curve family as the deployed PolkaVM verifiers on Polkadot Asset Hub. The production email circuit has different public inputs and a separate verifier, which is already deployed and verified through the CLI path.
What's built, what's in progress, and what's next.
A snarkjs-generated Groth16 Verifier.sol compiles to valid PolkaVM bytecode via Parity's resolc 1.1.0 with zero source modifications. PVM\0 magic confirmed. Deployed and proof-verified end-to-end on Polkadot Asset Hub mainnet.
node spike/deploy-substrate.mjs against Asset Hub to populate.
pallet-dkim-registry — governance-gated on-chain key registry. 5 tests.
pallet-zkattest — attest/revoke extrinsics, nullifier storage, DIM2 integration target. 18 tests.
The zkAttest count includes 5 pallet tests, evm_abi (Solidity calldata encoder/decoder, 8 tests), and ReviveVerifier (ABI bridge to deployed verifier contract, 5 tests).
Queries DNS and archives active DKIM public keys before they rotate. Confirmed pulling live RSA keys from Gmail, Yahoo, ProtonMail, SendGrid, and others. Intended to feed governance proposals to pallet-dkim-registry.
TypeScript/ESM package (@zkattest/prover). DKIM header parsing, EML splitting, and @zk-email/helpers integration complete. The on-page demo uses a toy circuit; the real zkEmail circuit artifacts are hosted on Cloudflare R2.
ZKEMAIL_BASE_URL in web/index.html.
| Component | Trust assumption | Failure mode |
|---|---|---|
| DKIM public key | Email provider's DNS (e.g. Gmail) | Provider compromised (key rotation mitigates) |
| Key registry | Polkadot governance | Malicious governance update (OpenGov timelock) |
| ZK circuit | Upstream zkEmail circuits/helpers + open source review | Circuit bug (independent audit planned) |
| Proof verifier | BN254 pairing precompile (PolkaVM) | Precompile bug (Parity-maintained) |
Known privacy tradeoff: the current nullifier design is derived from DKIM signature bytes, which are unique per email message. The email provider could in principle correlate that nullifier to the original message. A production DIM should document or improve this construction before deployment.
zkAttest uses zkEmail's Circom circuits and TypeScript helpers, but is a different project with a different target. zkEmail is upstream DKIM proof infrastructure; zkAttest is the Polkadot-native People Chain integration prototype around that infrastructure.
| zkAttest (this project) | zkEmail (upstream) | |
|---|---|---|
| Where the proof verifies | Polkadot Asset Hub via pallet-revive (PolkaVM); later pallet-zkattest on People Chain |
Application-specific smart contracts, primarily EVM-oriented today |
| Verifier compiler | Solidity → PolkaVM via resolc 1.1.0 (Parity) |
Solidity → EVM via solc |
| Wallet integration | Polkadot.js / Talisman / SubWallet (injected web3) | MetaMask / WalletConnect |
| DKIM key trust root | On-chain pallet-dkim-registry (governance-curated) + DKIM scraper |
Application-specific key and verifier management |
| Integration target | A candidate email-ownership attestation path for Polkadot's People/Individuality stack | An ERC-721 / contract state (e.g. proof-of-twitter NFT) |
| Circuit source | @zk-email/circuits EmailVerifier (reused as-is) |
↑ same — we don't fork or reimplement |
| Reference circuit demo | People / Individuality attestation prototype for Polkadot | proof-of-twitter |
Why this matters: Polkadot's People / Individuality system could benefit from at least one privacy-preserving DIM2 (Decentralized Individuality Mechanism, tier 2) credential source. The named candidates on Polkadot today - KILT SocialKYC, eIDAS, Reclaim Protocol - include either an issuer, attestor, or service-specific verifier in the trust path. zkEmail-based credential signals exist elsewhere, notably the ZK Email Stamp on Human Passport for Ethereum, which proves Amazon/Uber receipts as a proxy for economic activity, but no equivalent Polkadot-native email-ownership path is established. zkAttest targets that gap, made possible by zkEmail's primitives plus pallet-revive's PolkaVM mainnet availability.
The button below previews the future pallet-zkattest.attest() extrinsic
shape for the future People Chain path. To submit the current toy proof on-chain now, scroll
down to the Verify the demo proof on mainnet section.
pallet-zkattest.attest() shape. Values are
placeholders unless you generated the toy proof above; the real email-proof transaction path is a grant milestone.
Submit the toy Groth16 proof you just generated to the deployed toy Verifier on Polkadot Asset Hub. Dry-run is free (off-chain runtime call); on-chain submission may incur DOT fees and produces a citable tx hash.