PARITY: post-quantum is shipped on both clients #90

Merged
paulhitt merged 1 commits from docs/parity-pq-is-shipped into main 2026-09-05 00:30:07 +00:00
+28 -10
View File
@@ -45,17 +45,35 @@ everything above the protocol.
| Device identity + prekey rotation | ✅ | ✅ | retired prekeys retained past the relay window |
| Vault (encryption at rest) | ✅ | ✅ | Android Keystore, AES-GCM, record name bound into the AAD |
| ML-KEM-768 (PQ agreement) | ⚠️ | ⚪ | see below |
| ML-DSA-65 (PQ identity) | ⚠️ | ⚪ | see below |
| ML-KEM-768 (PQ agreement) | ✅ | ✅ | cross-engine verified — see below |
| ML-DSA-65 (PQ identity) | ✅ | ✅ | see below |
⚠️ **The post-quantum gap is not what it looks like.** iOS has `PQKEM.swift` and
`PQSign.swift`, and they are inert: CryptoKit exposes ML-KEM only on iOS 26 and
the app targets iOS 16, so no shipped iOS build does post-quantum anything.
Android has no platform ML-KEM at any API level. So the two clients are
*currently equal in effect* and the honest parity target is v1/v2 negotiation
that degrades cleanly — which the Android engine already does, and the interop
harness asserts. Closing this properly is a separate decision (implement, or
take a vetted library) and it should be made once, for both clients.
🔴 **These two rows said ⚪ and ⚠️, and both were wrong — understating, which
is the same direction relay#45 warns about and the same one that had the
comparison page scoring a competitor unfairly.** The note that used to sit here
said iOS's PQ files were inert because CryptoKit exposes ML-KEM only on iOS 26
while the app targeted 16, that Android had no ML-KEM at any API level, and so
"neither client does post-quantum anything today". None of that is true now, and
the middle claim was never quite the point.
- **Android** uses BouncyCastle's `MLKEMExtractor` / `MLKEMGenerator` — FIPS 203,
a real implementation shipped in the engine. There is no *platform* ML-KEM on
Android at any API level, which is what the old note was reaching for, and it
is why the engine carries its own rather than a reason it has none.
- **iOS** uses CryptoKit's `MLKEM768`, and it is **unconditional**:
`project.yml` sets the deployment target to 26.0, so the runtime gate that
made those files inert is gone. `PQKEM.swift` says so at the top.
⚠️ Corrected by a run, not by reading the source. The cross-engine harness
(`test/interop-swift-kotlin.mjs`) establishes it end to end: *"Android picks v3
for an iPhone peer"*, *"the first Android envelope carries a PQ ratchet step"*,
*"the iPhone agrees the session is v3"*, and *"a v3 session survives being
archived and restored mid-conversation"* — with the same four in the other
direction.
⚠️ The honest limit, which has not changed: post-quantum protection counts only
once **both** ends have it, so today that means two Android phones, or an
Android phone and an iPhone running a build that has not shipped yet.
---