2c1e7f972dd9

fix: PCH-02-002 Noise XX message 1 empty-payload mixHash — wire change, ships with Android v2.3.0 (v4.0.0)

time
2026-06-12 20:40 UTC · 4 months ago
machine
koh2
agent
gpt-5
session
pch-02 integration
parent
fc06218b9f63
3 files src/shared/noise-blake2s-kat.test.ts+2 −2src/shared/noise-js.ts+5 −3src/shared/noise-xx.ts+6 −0
src/shared/noise-blake2s-kat.test.ts+2 −2
@@ -101,9 +101,9 @@101101 102102     // Both directions agree (consistency) ...103103     expect(hex(a.handshakeHash)).toBe(hex(b.handshakeHash));104-    // ... and equal the pinned BLAKE2s vector (a SHA-256 revert changes this).104+    // ... and equal the pinned BLAKE2s + canonical msg1-empty-hash vector.105105     expect(hex(a.handshakeHash)).toBe(106-      "11c8bf7fcefad1f00ff8573c7bca66891626d053addae6d2b78b2f195a9ffd8a",106+      "505b6dcb59838e5d163f4fd4897cfff87c20ecca23aa993b416206aba25ee71c",107107     );108108 109109     // Transport keys are also BLAKE2s-derived; a frame must still round-trip.

view file

src/shared/noise-js.ts+5 −3
@@ -9,9 +9,11 @@99  * vectors only (a regression guard against accidental changes on the JS side).1010  *1111  * PCH-01-002: this implementation derives `h` and HKDF over BLAKE2s to match the12- * named pattern. A stock `snow` stack would interoperate; the Android port must13- * mirror the same hash choices. Any change to the hash, HKDF, or transcript here14- * is a BREAKING wire change and requires a coordinated Android release.12+ * named pattern. PCH-02-002 brought the XX hand-port back to the canonical13+ * empty-payload msg1 transcript too, so a stock Noise stack should interoperate.14+ * The Android port must mirror these hash choices and transcript steps. Any15+ * change to the hash, HKDF, or transcript here is a BREAKING wire change and16+ * requires a coordinated Android release.1517  */1618 1719 import { generateKeyPair, sharedKey } from "@stablelib/x25519";

view file

src/shared/noise-xx.ts+6 −0
@@ -93,6 +93,10 @@9393   // --- Message 1: -> e ---9494   const e = generateKeyPair();9595   h = mixHash(h, e.publicKey);96+  // PCH-02-002: canonical Noise still runs EncryptAndHash(empty) for msg1.97+  // No bytes are added to the wire; the transcript hash moves in lockstep with98+  // peach-android.99+  h = mixHash(h, new Uint8Array(0));96100   await send(e.publicKey);97101 98102   // --- Message 2: <- e, ee, s, es ---@@ -191,6 +195,8 @@191195   if (msg1.length < 32) throw new Error("Noise XX: msg1 too short");192196   const remoteEphemeral = msg1.slice(0, 32);193197   h = mixHash(h, remoteEphemeral);198+  // PCH-02-002: mirror the initiator's empty-payload MixHash for msg1.199+  h = mixHash(h, new Uint8Array(0));194200 195201   // --- Message 2: -> e, ee, s, es ---196202   const e = generateKeyPair();

view file