1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 | /**
* Wire-compat golden-vector suite.
*
* Extracted from the TypeScript implementation while it was canon (v1.2.0);
* since the CLJS port this suite runs against the committed dist/ (`npm test`)
* and is the byte-level contract the port must keep green. Two kinds of
* checks:
*
* 1. deterministic sections: every derivation is recomputed from the
* implementation and deep-compared against the committed fixture;
* 2. sealed fixtures (random IV / ephemeral key blobs, frozen at extraction
* time): the implementation must OPEN them — TS seals -> port unseals is
* the cross-implementation proof for the randomized layers.
*
* Do not regenerate the fixtures after the port; they are the contract.
*/
import { test } from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { computeAll, canonThrowCases } from "./vectors/compute.mjs";
import { canon, openEnvelope, mintRoomUrl } from "../dist/index.js";
import { utf8 } from "ardegazu-id-kit";
const fixture = async (name) => JSON.parse(await readFile(new URL(`./vectors/${name}`, import.meta.url), "utf8"));
const { ac, ch, sections } = await computeAll();
// ---- deterministic sections -------------------------------------------------
for (const name of ["canon", "envelope", "pair", "receipts", "isoweek", "mailbox", "invites", "friends", "apps-sync", "text-keys"]) {
test(`${name}.json deterministic section matches the implementation`, async () => {
const f = await fixture(`${name}.json`);
assert.deepEqual(sections[name], f.deterministic);
});
}
// ---- canon extras -----------------------------------------------------------
test("canon.json: self-contained input_json rows re-canonicalize to the committed bytes", async () => {
const f = await fixture("canon.json");
let checked = 0;
for (const c of f.deterministic.cases) {
if (c.input_json === null) continue;
assert.equal(canon(JSON.parse(c.input_json)), c.canon, c.name);
checked++;
}
assert.ok(checked >= 20, `only ${checked} self-contained rows`);
});
test("canon rejects unsupported values (throw cases)", async () => {
const f = await fixture("canon.json");
const impl = canonThrowCases();
assert.deepEqual(impl.map((c) => c.name), f.deterministic.throws.map((c) => c.name));
for (const c of impl) assert.throws(() => canon(c.make()), undefined, c.name);
});
// ---- sealed envelope --------------------------------------------------------
test("sealed envelope: the committed TS-sealed blob opens and verifies", async () => {
const f = await fixture("envelope.json");
const { ctx, outer_json, expect_inner, expired_outer_json } = f.sealed;
const opened = await openEnvelope(ac.xB, ctx, utf8(outer_json));
assert.deepEqual(opened, expect_inner);
assert.equal(await openEnvelope(ac.xB, ctx, utf8(expired_outer_json)), null, "expired envelope must not open");
});
test("sealed envelope: context binding, key binding and tamper rejection", async () => {
const f = await fixture("envelope.json");
const { ctx, outer_json } = f.sealed;
assert.equal(await openEnvelope(ac.xB, "to|v1|somewhere-else", utf8(outer_json)), null, "wrong ctx");
assert.equal(await openEnvelope(ac.xA, ctx, utf8(outer_json)), null, "wrong recipient key");
const tampered = JSON.parse(outer_json);
const ct = atob(tampered.w.ct);
tampered.w.ct = btoa(String.fromCharCode(ct.charCodeAt(0) ^ 1) + ct.slice(1));
assert.equal(await openEnvelope(ac.xB, ctx, utf8(JSON.stringify(tampered))), null, "tampered ct");
assert.equal(await openEnvelope(ac.xB, ctx, utf8("not json")), null, "garbage bytes");
assert.equal(await openEnvelope(ac.xB, ctx, utf8(JSON.stringify({ v: 2, w: tampered.w }))), null, "wrong outer version");
});
// ---- sealed pair wires ------------------------------------------------------
test("sealed pair wires: committed TS-sealed channel messages open for members only", async () => {
const f = await fixture("pair.json");
const members = [ac.idA.publicKeyB64, ac.idB.publicKeyB64];
const p = await ch.pairBA.open(f.sealed.pair_wire_from_A.wire, members);
assert.deepEqual(p, { from: ac.idA.publicKeyB64, payload: f.sealed.pair_wire_from_A.payload });
const s = await ch.self.open(f.sealed.self_wire.wire, [ac.idA.publicKeyB64]);
assert.deepEqual(s, { from: ac.idA.publicKeyB64, payload: f.sealed.self_wire.payload });
assert.equal(await ch.pairAB.open(f.sealed.pair_wire_from_A.wire, [ac.idB.publicKeyB64]), null, "sender not in member list -> tag never matches");
const tampered = JSON.parse(f.sealed.pair_wire_from_A.wire);
const ct = atob(tampered.ct);
tampered.ct = btoa(String.fromCharCode(ct.charCodeAt(0) ^ 1) + ct.slice(1));
assert.equal(await ch.pairAB.open(JSON.stringify(tampered), members), null, "tampered ct");
assert.equal(await ch.self.open(f.sealed.pair_wire_from_A.wire, members), null, "pair wire must not open on the self channel");
});
// ---- shape-only checks ------------------------------------------------------
test("mintRoomUrl mints a 43-char b64url fragment secret", async () => {
const f = await fixture("invites.json");
for (const app of f.deterministic.suite_apps) {
const url = mintRoomUrl(app.host);
assert.match(url, new RegExp(`^https://${app.host.replaceAll(".", "\\.")}/#[A-Za-z0-9_-]{43}$`));
}
assert.notEqual(mintRoomUrl("x.example"), mintRoomUrl("x.example"), "fresh randomness per mint");
});
test("receipts verify table verdicts hold when run straight off the fixture", async () => {
const f = await fixture("receipts.json");
const { verifyReceipt } = await import("../dist/index.js");
for (const row of f.deterministic.verify_table) {
const v = await verifyReceipt(row.receipt, row.opts);
assert.equal(v !== null, row.accept, row.name);
if (row.accept) assert.equal(v.hash, row.hash, `${row.name} hash`);
}
});
|