Android does not exist, and the first thing it needs is not a screen. It needs the protocol implemented a third time — which is only worth anything if the third implementation is checked against the spec and the published vectors rather than against a reading of our own Swift. So `android/engine` is a plain Kotlin/JVM library with no Android in it: no SDK, no emulator, no device, and therefore gateable in CI on Linux like everything else. It reads engine/test/vectors/protocol-v1.json from its one location rather than carrying a copy, because a vector transcribed into the test that checks it is a vector that agrees with itself. Covered so far: safety numbers (§7) and key transparency verification (§19) — RFC 6962 leaf and node hashing, the unbalanced split, and bottom-up audit paths. Nine tests, all green against the same file the JavaScript and Swift engines answer to. The §19 tests are the ones worth having. A top-down reading of a bottom-up audit path yields the correct root for every left-spine index, so it passes any suite that only checks index 0 — the vectors pin a right-descending index, and the tests assert both that the published path verifies and that the same path reversed does not. android/README.md lists what is missing — X25519, X3DH, the ratchet, sealed sender, both post-quantum halves, the relay client, the app — as a table rather than as an omission. Android stays honestly marked "not started" on the site until that list is shorter. Bytecode targets 17 without demanding a JDK 17 be installed: a jvmToolchain(17) fails on any newer JDK, which is a poor trade for a library with no JDK 17-specific behaviour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
60 lines
2.6 KiB
Markdown
60 lines
2.6 KiB
Markdown
# Flamenet Messenger — Android
|
|
|
|
Nothing here is an app yet. This is the engine, and it is deliberately first.
|
|
|
|
An Android client needs the protocol implemented a third time. That third
|
|
implementation is the one that finds the places where the specification says
|
|
less than the two existing engines quietly agreed on — but only if it is
|
|
written against the spec and the published vectors rather than against a
|
|
reading of our own Swift and JavaScript. So the engine comes first, it is a
|
|
plain Kotlin/JVM library with no Android in it at all, and it is held to
|
|
`engine/test/vectors/protocol-v1.json` — the same file the other two engines
|
|
are checked against, read from that one location rather than copied here.
|
|
|
|
```
|
|
./gradlew :engine:test
|
|
```
|
|
|
|
No Android SDK, no emulator, no device. It runs anywhere a JVM does, which is
|
|
also what lets it run in CI on Linux.
|
|
|
|
## What the engine covers today
|
|
|
|
| Area | Spec | State |
|
|
|---|---|---|
|
|
| Safety numbers | §7 | **Done** — fingerprints and conversation ordering match the published vectors |
|
|
| Key transparency verification | §19 | **Done** — RFC 6962 leaf/node hashing, unbalanced split, bottom-up audit paths |
|
|
| Byte helpers | — | Unsigned comparison, constant-time equality |
|
|
|
|
## What it does not cover
|
|
|
|
Listed rather than left to be discovered, because a table of green ticks with
|
|
the hard parts quietly missing is worse than no table:
|
|
|
|
| Area | Spec | State |
|
|
|---|---|---|
|
|
| X25519 / Ed25519 | §3 | Not started — needs a provider that works on both JVM and Android |
|
|
| X3DH key agreement | §4 | Not started |
|
|
| Double Ratchet | §6 | Not started |
|
|
| Sealed sender | §12 | Not started |
|
|
| ML-KEM-768 hybrid | §11 | Not started |
|
|
| ML-DSA-65 identities | §20 | Not started |
|
|
| Relay client | §8 | Not started |
|
|
| The app itself | — | Not started |
|
|
|
|
Until those exist, Android is honestly marked "not started" on the website, and
|
|
a conversation gets the protocol's guarantees only when both ends are iOS.
|
|
|
|
## Why the vectors matter more than the code
|
|
|
|
Two implementations that agree may both be wrong in the same way, especially
|
|
when one was written while reading the other. The audit-path ordering in §19 is
|
|
the worked example: a top-down reading of a bottom-up path produces the correct
|
|
root for every left-spine index, so it passes any test that only checks index
|
|
0. The vector file pins a right-descending index for that reason, and the
|
|
Kotlin tests assert both that the published path verifies and that the same
|
|
path reversed does not.
|
|
|
|
If this engine ever disagrees with the file, the interesting question is which
|
|
of the three is wrong — not this one by default.
|