Skip to main content

Post-quantum cryptography

New polls encrypt answers with X-Wing hybrid key encapsulation, and published results are signed with ML-DSA-65. Here is what uses which algorithm.

  • Security reviewers
  • 3 min read
  • Updated Oct 14, 2026
  • Reviewed by Security
Note

Heads up

Why PQC (harvest now, decrypt later): ciphertext saved today could fall to a future quantum computer. Every new poll uses hybrid classical + post-quantum key encapsulation; pair this page with Encryption model overview for the full stack.

We use post-quantum hybrid cryptography so answers archived today stay hard to open later. Anonymity doesn't depend on the algorithm choice: nothing we store links an answer to its author, whatever cipher sealed it.

#What uses which algorithm

UseAlgorithm
Sealing answers on new pollsX-Wing (X25519 + ML-KEM-768), then AES-256-GCM
Wrapping folder keys for each personX-Wing
Signing published results documents and shared slicesML-DSA-65
Polls created before the post-quantum upgradeRSA-OAEP 2048 (unchanged)
One-vote ballots on personal invitesRSA-2048 blind signatures

Answers themselves aren't signed. A signature goes on the aggregate document an admin publishes, so a reader can check the numbers weren't changed afterwards. See Verifying a published results document.

Personal invites use a separate, classical primitive on purpose: a blind RSA signature is what lets us sign a ballot without seeing it, so we can enforce one vote per invite without being able to match the answer to the invite. There's no standard post-quantum blind signature yet. A future quantum attacker could forge ballot signatures for a poll, but that's a question of vote counting after the fact, not of reading answers.

Good to know

What this buys you

Hybrid encapsulation combines X25519 with ML-KEM-768, so an attacker has to break both to open an answer.

#How an answer is sealed

  1. Publish the poll's public key. The poll's X-Wing public key is served with its questions.
  2. Encapsulate with X-Wing. The respondent's browser runs the hybrid key encapsulation against that key.
  3. Derive and seal. HKDF-SHA-256 derives an AES-256-GCM key, and the answers are sealed under it.
  4. Store ciphertext. We store a versioned blob that opens only with the poll's private key.
hybrid-encapsulate.tsILLUSTRATIVE
const { ciphertext: kem, sharedSecret } = xwingEncapsulate(pollPublicKey);
const aesKey = hkdfSha256(sharedSecret, randomSalt, "response-v2");
const sealed = aesGcmEncrypt(aesKey, randomIv, payload);
// stored as { version: 2, salt, xwingCiphertext: kem, iv, ciphertext: sealed }

#Browser constraints

Library@noble/post-quantum, open-source, pure TypeScript
RuntimeNo WebAssembly for the post-quantum code
StorageKey material in IndexedDB

The library is open-source and auditable. It hasn't had an independent third-party audit, so treat it as you would any young implementation of new standards.

#Upgrades and versioning

The post-quantum upgrade happens per admin account, not per poll or workspace. The first time an account signs in after the upgrade, its browser creates an X-Wing collaboration key and re-wraps the folder keys and poll keys it holds, then tells us the account has moved to the new version. Polls created before that keep their original RSA-OAEP keypair, so their answers stay readable; every poll created afterwards gets an X-Wing keypair.

Each stored answer carries a version field, so the admin's browser knows which algorithm opens it.

Note

Next

Return to Encryption model overview for the product-level story, or Zero-knowledge architecture for confidentiality mapped to behaviour.