Kotlin: X3DH, and the account KDF beneath it
The Android engine had primitives and no protocol: no handshake, no ratchet, no session. It could verify a safety number and could not start a conversation. X3DH is the first half of fixing that. The four agreements are mixed in the order the spec fixes, and DH4 is omitted rather than zero-filled when the one-time prekey pool is drained. Both are choices that produce 32 plausible bytes when wrong — the failure lands at the far end as a message that will not decrypt, pointing nowhere near here, so the tests check that the two sides AGREE rather than that either looks right. Keys are JCA objects rather than raw bytes throughout, because Conscrypt will not build an XDH key from raw bytes and wants a DER spec. Passing raw bytes would work on this JVM and throw on the first tap on a phone, which this engine has already been bitten by once. Also here: AccountKdf, so Android can derive an account key and an address. Checked against the vectors pinned from the enclave client — including the non-ASCII and empty-passphrase cases, where a CharArray API and a UTF-8 wire format quietly disagree. ⚠️ Still missing before an Android app can send a message: the Double Ratchet, a session layer, a wire client, and the app itself. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b7021e9a73
commit
c893d412d2
@@ -86,22 +86,10 @@ class AccountKdfTest {
|
||||
assertEquals(32, account.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `the account seed produces the address the other engines publish`() {
|
||||
// Ties the two halves together: the KDF above and the encoder in FNID.
|
||||
// A seed that derives correctly but encodes differently would still
|
||||
// give this account a different name on every client.
|
||||
val seed = ByteArray(32) { 0x2a }
|
||||
val ai = JSONObject(
|
||||
File(
|
||||
listOfNotNull(
|
||||
System.getenv("FLAMENET_VECTORS"),
|
||||
"../../engine/test/vectors/protocol-v1.json",
|
||||
"../../../flamenet-e2e/test/vectors/protocol-v1.json",
|
||||
).first { File(it).exists() },
|
||||
).readText(),
|
||||
).getJSONObject("accountIdentity")
|
||||
|
||||
assertEquals(ai.getString("address"), FNID.address(seed))
|
||||
}
|
||||
// The tie between this KDF and FNID.encode — that a correctly derived seed
|
||||
// also produces the same ADDRESS on every client — belongs here too, and
|
||||
// cannot be written yet: the Kotlin FNID lives on the multi-homing branch
|
||||
// and is not on main. Add it when that lands, because a seed that derives
|
||||
// correctly and encodes differently still gives one account a different
|
||||
// name on every platform.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user