@motebit/crypto 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,562 @@
1
+ /**
2
+ * Deletion certificate — sign + verify for the three retention shapes.
3
+ *
4
+ * Permissive floor (Apache-2.0). Zero monorepo dependencies — types
5
+ * mirror `@motebit/protocol`'s discriminated union; primitives route
6
+ * through `@motebit/crypto/suite-dispatch`.
7
+ *
8
+ * Three arms in one union (`@motebit/protocol :: DeletionCertificate`):
9
+ *
10
+ * - `mutable_pruning` and `consolidation_flush` — multi-signature
11
+ * certs (subject / operator / delegate / guardian, at-least-one
12
+ * required by the reason-table). Each present signature covers the
13
+ * same canonical bytes: `canonicalJson(cert minus all *_signature
14
+ * fields)`. Pattern matches identity-v1 §3.8.1 dual-signature
15
+ * succession (one canonical payload, multiple verifiable signers).
16
+ *
17
+ * - `append_only_horizon` — single-issuer signature plus witness
18
+ * signatures. Both the issuer and every witness sign the same
19
+ * `canonicalJson(cert minus signature)`. Witness array is part of
20
+ * the signed body — a forged witness fails verification.
21
+ *
22
+ * Verification dispatches by `kind`. Reason × signer × mode table
23
+ * (decision 5) gates which signer compositions are admissible. Each
24
+ * admissible signature is then cryptographically verified through
25
+ * `verifyBySuite`.
26
+ */
27
+ import { canonicalJson, hexToBytes, fromBase64Url, toBase64Url, bytesToHex } from "./signing.js";
28
+ import { signBySuite, verifyBySuite } from "./suite-dispatch.js";
29
+ // ── Constants ────────────────────────────────────────────────────────
30
+ /** The cryptosuite every deletion certificate signs under today. */
31
+ export const DELETION_CERTIFICATE_SUITE = "motebit-jcs-ed25519-b64-v1";
32
+ /**
33
+ * Filing window for `WitnessOmissionDispute` (retention phase 4b-3).
34
+ * A dispute MUST be filed within 24h of the cert's `issued_at`;
35
+ * `verifyWitnessOmissionDispute` rejects beyond this window. Mirrors
36
+ * the 24h cadence of `spec/dispute-v1.md` §7.5 (filing / withdrawal /
37
+ * appeal windows).
38
+ */
39
+ export const WITNESS_OMISSION_DISPUTE_WINDOW_MS = 24 * 60 * 60 * 1000;
40
+ /**
41
+ * Canonical empty-tree merkle root — hex-encoded SHA-256 of zero
42
+ * bytes. The verifier in `verifyHorizonCert` rejects horizon certs
43
+ * whose `federation_graph_anchor.leaf_count = 0` carries a
44
+ * `merkle_root` other than this value, so a malicious issuer cannot
45
+ * mint a self-witnessed cert with arbitrary anchor bytes. Mirrors
46
+ * `EMPTY_FEDERATION_GRAPH_ANCHOR.merkle_root` in `@motebit/protocol`.
47
+ */
48
+ const EMPTY_FEDERATION_GRAPH_ANCHOR_ROOT = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
49
+ const REASON_TABLE = Object.freeze({
50
+ user_request: {
51
+ required: "subject",
52
+ optional: ["operator"],
53
+ forbidden: [],
54
+ modes: ["sovereign", "mediated", "enterprise"],
55
+ },
56
+ retention_enforcement: {
57
+ required: "operator",
58
+ optional: ["subject"],
59
+ forbidden: [],
60
+ modes: ["mediated", "enterprise"],
61
+ },
62
+ retention_enforcement_post_classification: {
63
+ required: "operator",
64
+ optional: ["subject"],
65
+ forbidden: [],
66
+ modes: ["mediated", "enterprise"],
67
+ },
68
+ operator_request: {
69
+ required: "operator",
70
+ optional: [],
71
+ forbidden: ["subject"],
72
+ modes: ["mediated", "enterprise"],
73
+ },
74
+ delegated_request: {
75
+ required: "delegate",
76
+ optional: ["operator"],
77
+ forbidden: [],
78
+ modes: ["mediated", "enterprise"],
79
+ },
80
+ self_enforcement: {
81
+ required: "subject",
82
+ optional: [],
83
+ forbidden: ["operator"],
84
+ // Admitted in every mode: the subject's runtime can drive its own
85
+ // retention policy whether or not an operator exists. The
86
+ // distinction from `retention_enforcement` is who signs — subject
87
+ // for self_enforcement, operator for retention_enforcement.
88
+ modes: ["sovereign", "mediated", "enterprise"],
89
+ },
90
+ guardian_request: {
91
+ required: "guardian",
92
+ optional: ["operator"],
93
+ forbidden: [],
94
+ modes: ["enterprise"],
95
+ },
96
+ });
97
+ // ── Signing helpers ──────────────────────────────────────────────────
98
+ /**
99
+ * Compute the canonical signing bytes for a `mutable_pruning` or
100
+ * `consolidation_flush` cert. Strips every `*_signature` field so all
101
+ * present signers sign identical bytes — matches identity-v1 §3.8.1's
102
+ * dual-signature canonical payload.
103
+ */
104
+ export function canonicalizeMultiSignatureCert(cert) {
105
+ const { subject_signature, operator_signature, delegate_signature, guardian_signature, ...body } = cert;
106
+ // touch all extracted fields so unused-locals lint doesn't fail
107
+ void subject_signature;
108
+ void operator_signature;
109
+ void delegate_signature;
110
+ void guardian_signature;
111
+ return new TextEncoder().encode(canonicalJson(body));
112
+ }
113
+ /**
114
+ * Compute the canonical signing bytes for an `append_only_horizon`
115
+ * cert's ISSUER signature. Strips only `signature`. The issuer commits
116
+ * to the full body — including every witness's signature in
117
+ * `witnessed_by` — so a forged witness fails verification at the
118
+ * issuer signature step (the body the issuer signed no longer matches
119
+ * the post-tampering body).
120
+ */
121
+ export function canonicalizeHorizonCert(cert) {
122
+ const { signature, ...body } = cert;
123
+ void signature;
124
+ return new TextEncoder().encode(canonicalJson(body));
125
+ }
126
+ /**
127
+ * Compute the canonical signing bytes for a WITNESS signature on an
128
+ * `append_only_horizon` cert. Strips both `signature` and
129
+ * `witnessed_by` so witnesses can co-sign asynchronously without
130
+ * needing to know each other's signatures.
131
+ *
132
+ * Witness's identity is bound to the signature via the public key
133
+ * used at verification (resolved from `witnessed_by[i].motebit_id`).
134
+ * The cert body's other fields (subject, store_id, horizon_ts,
135
+ * issued_at, federation_graph_anchor) make two distinct horizon
136
+ * advances produce distinct signing bytes, so a witness signature
137
+ * cannot be relayed to a different cert.
138
+ *
139
+ * The issuer's separate signature commits to the assembled witness
140
+ * array — that's the binding that makes a forged or substituted
141
+ * witness detectable.
142
+ */
143
+ export function canonicalizeHorizonCertForWitness(cert) {
144
+ const { signature, witnessed_by, ...body } = cert;
145
+ void signature;
146
+ void witnessed_by;
147
+ return new TextEncoder().encode(canonicalJson(body));
148
+ }
149
+ /**
150
+ * Sign a `mutable_pruning` or `consolidation_flush` cert as the
151
+ * subject (motebit identity key). Adds the `subject_signature` block.
152
+ *
153
+ * Callers compose: sign as subject → optionally sign as operator → emit.
154
+ * Each signing step appends a signature block; the canonical bytes are
155
+ * recomputed from the body each time, so signatures are commutative
156
+ * (any signing order produces identical bytes for every signer).
157
+ */
158
+ export async function signCertAsSubject(cert, motebitId, privateKey) {
159
+ const bytes = canonicalizeMultiSignatureCert(cert);
160
+ const sig = await signBySuite(DELETION_CERTIFICATE_SUITE, bytes, privateKey);
161
+ return {
162
+ ...cert,
163
+ subject_signature: {
164
+ motebit_id: motebitId,
165
+ suite: DELETION_CERTIFICATE_SUITE,
166
+ signature: toBase64Url(sig),
167
+ },
168
+ };
169
+ }
170
+ /** Sign a multi-signature cert as the operator. */
171
+ export async function signCertAsOperator(cert, operatorId, privateKey) {
172
+ const bytes = canonicalizeMultiSignatureCert(cert);
173
+ const sig = await signBySuite(DELETION_CERTIFICATE_SUITE, bytes, privateKey);
174
+ return {
175
+ ...cert,
176
+ operator_signature: {
177
+ operator_id: operatorId,
178
+ suite: DELETION_CERTIFICATE_SUITE,
179
+ signature: toBase64Url(sig),
180
+ },
181
+ };
182
+ }
183
+ /** Sign a multi-signature cert as a delegate (multi-hop authorization). */
184
+ export async function signCertAsDelegate(cert, delegateMotebitId, delegationReceiptId, privateKey) {
185
+ const bytes = canonicalizeMultiSignatureCert(cert);
186
+ const sig = await signBySuite(DELETION_CERTIFICATE_SUITE, bytes, privateKey);
187
+ return {
188
+ ...cert,
189
+ delegate_signature: {
190
+ motebit_id: delegateMotebitId,
191
+ delegation_receipt_id: delegationReceiptId,
192
+ suite: DELETION_CERTIFICATE_SUITE,
193
+ signature: toBase64Url(sig),
194
+ },
195
+ };
196
+ }
197
+ /** Sign a multi-signature cert as the guardian (enterprise custody). */
198
+ export async function signCertAsGuardian(cert, guardianPublicKey, privateKey) {
199
+ const bytes = canonicalizeMultiSignatureCert(cert);
200
+ const sig = await signBySuite(DELETION_CERTIFICATE_SUITE, bytes, privateKey);
201
+ return {
202
+ ...cert,
203
+ guardian_signature: {
204
+ guardian_public_key: bytesToHex(guardianPublicKey),
205
+ suite: DELETION_CERTIFICATE_SUITE,
206
+ signature: toBase64Url(sig),
207
+ },
208
+ };
209
+ }
210
+ /**
211
+ * Sign an `append_only_horizon` cert as the issuer. The issuer is the
212
+ * subject named by the discriminator — motebit identity key for
213
+ * per-motebit horizons, operator key for operator-wide horizons.
214
+ */
215
+ export async function signHorizonCertAsIssuer(cert, privateKey) {
216
+ const withSuite = { ...cert, suite: DELETION_CERTIFICATE_SUITE, signature: "" };
217
+ const bytes = canonicalizeHorizonCert(withSuite);
218
+ const sig = await signBySuite(DELETION_CERTIFICATE_SUITE, bytes, privateKey);
219
+ return { ...withSuite, signature: toBase64Url(sig) };
220
+ }
221
+ /**
222
+ * Add a witness signature to an `append_only_horizon` cert. Witness
223
+ * signs the same canonical body as the issuer; the witness array is
224
+ * part of the signed body, so once the issuer has signed, the witness
225
+ * additions are appended without re-signing the issuer side.
226
+ *
227
+ * Note: the issuer's signature is over the body INCLUDING the
228
+ * witness array as it stood when the issuer signed. Witnesses added
229
+ * after issuer-signing invalidate the issuer signature. Production
230
+ * flow: build the witness array first → issuer signs last. This
231
+ * function is here for tests and offline witness aggregation.
232
+ */
233
+ export async function signHorizonWitness(cert, witnessMotebitId, privateKey, inclusionProof) {
234
+ const bytes = canonicalizeHorizonCertForWitness(cert);
235
+ const sig = await signBySuite(DELETION_CERTIFICATE_SUITE, bytes, privateKey);
236
+ const witness = {
237
+ motebit_id: witnessMotebitId,
238
+ signature: toBase64Url(sig),
239
+ ...(inclusionProof !== undefined ? { inclusion_proof: inclusionProof } : {}),
240
+ };
241
+ return witness;
242
+ }
243
+ // ── Witness solicitation request body — issuer + peer-side primitives (4b-3) ──
244
+ //
245
+ // `HorizonWitnessRequestBody` is the cert body witnesses canonicalize
246
+ // and sign. By construction it equals the `append_only_horizon` cert
247
+ // minus `witnessed_by[]` and minus top-level `signature` — the same
248
+ // projection `canonicalizeHorizonCertForWitness` produces. These three
249
+ // helpers wrap that projection so call sites never re-derive the
250
+ // canonical bytes by hand (rule: services consume primitives, never
251
+ // inline `canonicalJson`).
252
+ //
253
+ // Both the issuer's `WitnessSolicitationRequest.issuer_signature` and
254
+ // each peer's `WitnessSolicitationResponse.signature` are over THE
255
+ // SAME bytes — `canonicalJson(cert_body)` under
256
+ // `motebit-jcs-ed25519-b64-v1`. The peer's verify-issuer + sign-as-
257
+ // witness paths share canonical-bytes derivation by design (session-3
258
+ // sub-decision: issuer-signature payload IS witness-signature payload).
259
+ /**
260
+ * Compute the canonical signing bytes for a `HorizonWitnessRequestBody`.
261
+ * Byte-equal to `canonicalizeHorizonCertForWitness` over the
262
+ * corresponding full cert (since the function strips
263
+ * `witnessed_by[]` + `signature`); exposed as a separate helper so
264
+ * call sites pass the wire-shaped request body directly without
265
+ * synthesizing a full cert.
266
+ */
267
+ export function canonicalizeHorizonWitnessRequestBody(body) {
268
+ return canonicalizeHorizonCertForWitness({
269
+ ...body,
270
+ witnessed_by: [],
271
+ signature: "",
272
+ });
273
+ }
274
+ /**
275
+ * Sign a `HorizonWitnessRequestBody` — produces a base64url-encoded
276
+ * Ed25519 signature over the canonical bytes. Used by BOTH:
277
+ *
278
+ * - the issuer, for `WitnessSolicitationRequest.issuer_signature`
279
+ * (attests authenticity of the solicitation request before any
280
+ * peer signs as witness),
281
+ * - each peer witness, for `WitnessSolicitationResponse.signature`
282
+ * (the per-witness signature copied verbatim into
283
+ * `cert.witnessed_by[].signature`).
284
+ *
285
+ * Both roles sign byte-equal canonical bytes by design (session-3
286
+ * sub-decision: issuer-signature payload IS witness-signature payload).
287
+ * The peer's verify-issuer + sign-as-witness paths share canonical-bytes
288
+ * derivation through this primitive — drift-impossible.
289
+ */
290
+ export async function signHorizonWitnessRequestBody(body, privateKey) {
291
+ const bytes = canonicalizeHorizonWitnessRequestBody(body);
292
+ const sig = await signBySuite(DELETION_CERTIFICATE_SUITE, bytes, privateKey);
293
+ return toBase64Url(sig);
294
+ }
295
+ /**
296
+ * Verify the issuer's `issuer_signature` on a
297
+ * `WitnessSolicitationRequest`. Peer-side fail-closed gate before the
298
+ * peer signs as a witness over the same bytes. Returns `false` on any
299
+ * malformed signature, suite mismatch, or hash failure — never throws.
300
+ */
301
+ export async function verifyHorizonWitnessRequestSignature(body, signatureBase64Url, issuerPublicKey) {
302
+ let sigBytes;
303
+ try {
304
+ sigBytes = fromBase64Url(signatureBase64Url);
305
+ }
306
+ catch {
307
+ return false;
308
+ }
309
+ if (sigBytes.length === 0)
310
+ return false;
311
+ const bytes = canonicalizeHorizonWitnessRequestBody(body);
312
+ return verifyBySuite(DELETION_CERTIFICATE_SUITE, bytes, sigBytes, issuerPublicKey);
313
+ }
314
+ // ── Verifier ─────────────────────────────────────────────────────────
315
+ /**
316
+ * Verify a deletion certificate. Single entry point — dispatches by
317
+ * `kind` to the per-arm verifier. Fail-closed throughout: any
318
+ * verification step that errors or returns false → `valid: false`.
319
+ *
320
+ * The verifier checks, in order:
321
+ * 1. Reason × signer × mode table is satisfied (decision 5).
322
+ * 2. Each present signature is cryptographically valid against the
323
+ * cert's canonical signing bytes.
324
+ * 3. (Horizon arm only) the issuer signature and each witness
325
+ * signature verify.
326
+ * 4. (Optional, when `validateGuardianBinding` supplied) the
327
+ * embedded guardian public key matches the subject motebit's
328
+ * declared guardian.
329
+ */
330
+ export async function verifyDeletionCertificate(cert, ctx) {
331
+ switch (cert.kind) {
332
+ case "mutable_pruning":
333
+ case "consolidation_flush":
334
+ return verifyMultiSignatureCert(cert, ctx);
335
+ case "append_only_horizon":
336
+ return verifyHorizonCert(cert, ctx);
337
+ }
338
+ }
339
+ async function verifyMultiSignatureCert(cert, ctx) {
340
+ const errors = [];
341
+ const rule = REASON_TABLE[cert.reason];
342
+ if (rule === undefined) {
343
+ return failResult(`unknown reason: ${cert.reason}`);
344
+ }
345
+ // Mode check (only when caller declared a mode).
346
+ if (ctx.deploymentMode !== undefined && !rule.modes.includes(ctx.deploymentMode)) {
347
+ errors.push(`reason "${cert.reason}" not admitted in deployment mode "${ctx.deploymentMode}"`);
348
+ }
349
+ // Presence check — required signer must be present, forbidden must be absent.
350
+ const present = {
351
+ subject: cert.subject_signature !== undefined,
352
+ operator: cert.operator_signature !== undefined,
353
+ delegate: cert.delegate_signature !== undefined,
354
+ guardian: cert.guardian_signature !== undefined,
355
+ };
356
+ if (!present[rule.required]) {
357
+ errors.push(`reason "${cert.reason}" requires ${rule.required}_signature, not present`);
358
+ }
359
+ for (const f of rule.forbidden) {
360
+ if (present[f]) {
361
+ errors.push(`reason "${cert.reason}" forbids ${f}_signature, present`);
362
+ }
363
+ }
364
+ // Signature verification — verify every present signature against canonical bytes.
365
+ const bytes = canonicalizeMultiSignatureCert(cert);
366
+ let subjectValid = null;
367
+ if (cert.subject_signature !== undefined) {
368
+ subjectValid = await verifyOneSignature(bytes, cert.subject_signature.signature, cert.subject_signature.suite, await ctx.resolveMotebitPublicKey(cert.subject_signature.motebit_id));
369
+ if (!subjectValid)
370
+ errors.push("subject_signature invalid");
371
+ }
372
+ let operatorValid = null;
373
+ if (cert.operator_signature !== undefined) {
374
+ operatorValid = await verifyOneSignature(bytes, cert.operator_signature.signature, cert.operator_signature.suite, await ctx.resolveOperatorPublicKey(cert.operator_signature.operator_id));
375
+ if (!operatorValid)
376
+ errors.push("operator_signature invalid");
377
+ }
378
+ let delegateValid = null;
379
+ if (cert.delegate_signature !== undefined) {
380
+ delegateValid = await verifyOneSignature(bytes, cert.delegate_signature.signature, cert.delegate_signature.suite, await ctx.resolveMotebitPublicKey(cert.delegate_signature.motebit_id));
381
+ if (!delegateValid)
382
+ errors.push("delegate_signature invalid");
383
+ }
384
+ let guardianValid = null;
385
+ if (cert.guardian_signature !== undefined) {
386
+ let guardianKey;
387
+ try {
388
+ guardianKey = hexToBytes(cert.guardian_signature.guardian_public_key);
389
+ }
390
+ catch {
391
+ guardianKey = null;
392
+ errors.push("guardian_public_key not valid hex");
393
+ }
394
+ if (ctx.validateGuardianBinding !== undefined) {
395
+ const subjectMotebitId = cert.subject_signature !== undefined
396
+ ? cert.subject_signature.motebit_id
397
+ : undefined;
398
+ const ok = await ctx.validateGuardianBinding(subjectMotebitId, cert.guardian_signature.guardian_public_key);
399
+ if (!ok)
400
+ errors.push("guardian_public_key not bound to subject motebit");
401
+ }
402
+ guardianValid = await verifyOneSignature(bytes, cert.guardian_signature.signature, cert.guardian_signature.suite, guardianKey);
403
+ if (!guardianValid)
404
+ errors.push("guardian_signature invalid");
405
+ }
406
+ return {
407
+ valid: errors.length === 0,
408
+ errors,
409
+ steps: {
410
+ reason_table_satisfied: errors.length === 0,
411
+ subject_signature_valid: subjectValid,
412
+ operator_signature_valid: operatorValid,
413
+ delegate_signature_valid: delegateValid,
414
+ guardian_signature_valid: guardianValid,
415
+ horizon_issuer_signature_valid: null,
416
+ horizon_witnesses_valid_count: null,
417
+ horizon_witnesses_present_count: null,
418
+ },
419
+ };
420
+ }
421
+ async function verifyHorizonCert(cert, ctx) {
422
+ const errors = [];
423
+ // Empty-tree anchor sanity check — when `leaf_count = 0`, the only
424
+ // admissible `merkle_root` is the empty-tree value. Otherwise an
425
+ // issuer could mint a self-witnessed cert with arbitrary anchor
426
+ // bytes and dodge inclusion-proof scrutiny in WitnessOmissionDispute.
427
+ const anchor = cert.federation_graph_anchor;
428
+ if (anchor !== undefined) {
429
+ if (anchor.leaf_count === 0 && anchor.merkle_root !== EMPTY_FEDERATION_GRAPH_ANCHOR_ROOT) {
430
+ errors.push("federation_graph_anchor.leaf_count=0 requires the empty-tree merkle_root");
431
+ }
432
+ if (anchor.leaf_count < 0 || !Number.isInteger(anchor.leaf_count)) {
433
+ errors.push("federation_graph_anchor.leaf_count must be a non-negative integer");
434
+ }
435
+ }
436
+ const issuerBytes = canonicalizeHorizonCert(cert);
437
+ const witnessBytes = canonicalizeHorizonCertForWitness(cert);
438
+ // Issuer key resolution depends on subject discriminator.
439
+ const issuerKey = cert.subject.kind === "motebit"
440
+ ? await ctx.resolveMotebitPublicKey(cert.subject.motebit_id)
441
+ : await ctx.resolveOperatorPublicKey(cert.subject.operator_id);
442
+ const issuerValid = await verifyOneSignature(issuerBytes, cert.signature, cert.suite, issuerKey);
443
+ if (!issuerValid)
444
+ errors.push("horizon issuer signature invalid");
445
+ // Witness verification — witnesses sign the body without `witnessed_by`,
446
+ // so each witness signature can be co-signed asynchronously. The
447
+ // issuer's separate signature commits to the assembled witness array
448
+ // (a forged witness fails issuer-signature verification above).
449
+ let witnessesValid = 0;
450
+ for (const w of cert.witnessed_by) {
451
+ const key = await ctx.resolveMotebitPublicKey(w.motebit_id);
452
+ const ok = await verifyOneSignature(witnessBytes, w.signature, cert.suite, key);
453
+ if (ok)
454
+ witnessesValid++;
455
+ else
456
+ errors.push(`witness ${w.motebit_id} signature invalid`);
457
+ }
458
+ return {
459
+ valid: errors.length === 0,
460
+ errors,
461
+ steps: {
462
+ reason_table_satisfied: true,
463
+ subject_signature_valid: null,
464
+ operator_signature_valid: null,
465
+ delegate_signature_valid: null,
466
+ guardian_signature_valid: null,
467
+ horizon_issuer_signature_valid: issuerValid,
468
+ horizon_witnesses_valid_count: witnessesValid,
469
+ horizon_witnesses_present_count: cert.witnessed_by.length,
470
+ },
471
+ };
472
+ }
473
+ async function verifyOneSignature(canonicalBytes, signatureBase64Url, suite, publicKey) {
474
+ if (publicKey === null)
475
+ return false;
476
+ let sigBytes;
477
+ try {
478
+ sigBytes = fromBase64Url(signatureBase64Url);
479
+ }
480
+ catch {
481
+ return false;
482
+ }
483
+ return verifyBySuite(suite, canonicalBytes, sigBytes, publicKey);
484
+ }
485
+ function failResult(message) {
486
+ return {
487
+ valid: false,
488
+ errors: [message],
489
+ steps: {
490
+ reason_table_satisfied: false,
491
+ subject_signature_valid: null,
492
+ operator_signature_valid: null,
493
+ delegate_signature_valid: null,
494
+ guardian_signature_valid: null,
495
+ horizon_issuer_signature_valid: null,
496
+ horizon_witnesses_valid_count: null,
497
+ horizon_witnesses_present_count: null,
498
+ },
499
+ };
500
+ }
501
+ /**
502
+ * Verify a retention manifest published at
503
+ * `/.well-known/motebit-retention.json`. The manifest's signature
504
+ * covers `canonicalJson(manifest minus signature)`, signed by the
505
+ * operator's identity key under `motebit-jcs-ed25519-hex-v1` —
506
+ * sibling to the operator-transparency manifest's signing flow.
507
+ *
508
+ * Browser-side re-verifier per docs/doctrine/retention-policy.md
509
+ * §"Self-attesting transparency". Composes existing primitives —
510
+ * `canonicalJson` from signing.ts, `verifyBySuite` from
511
+ * suite-dispatch.ts. Same shape as the `verifySkillBundle`
512
+ * (87e2f174) browser primitive.
513
+ *
514
+ * The verifier accepts the operator's public key directly — callers
515
+ * resolve it from the operator-transparency manifest at
516
+ * `/.well-known/motebit-transparency.json` (its `relay_public_key`
517
+ * field), so a single manifest fetch + verify pair gives users a
518
+ * full retention claim audit.
519
+ */
520
+ export async function verifyRetentionManifest(manifest, operatorPublicKey) {
521
+ const errors = [];
522
+ if (manifest.spec !== "motebit/retention-manifest@1") {
523
+ errors.push(`unexpected spec: ${String(manifest.spec)}`);
524
+ }
525
+ if (manifest.suite !== "motebit-jcs-ed25519-hex-v1") {
526
+ errors.push(`unexpected suite: ${manifest.suite}`);
527
+ }
528
+ if (errors.length > 0) {
529
+ return { valid: false, errors, manifest: null };
530
+ }
531
+ const { signature, ...body } = manifest;
532
+ const canonical = canonicalJson(body);
533
+ const canonicalBytes = new TextEncoder().encode(canonical);
534
+ let signatureBytes;
535
+ try {
536
+ // hex-encoded signature per `motebit-jcs-ed25519-hex-v1`
537
+ if (signature.length !== 128 || !/^[0-9a-f]+$/i.test(signature)) {
538
+ errors.push("signature is not 128-char hex");
539
+ return { valid: false, errors, manifest: null };
540
+ }
541
+ const out = new Uint8Array(64);
542
+ for (let i = 0; i < 64; i++) {
543
+ out[i] = parseInt(signature.slice(i * 2, i * 2 + 2), 16);
544
+ }
545
+ signatureBytes = out;
546
+ /* c8 ignore start -- defensive catch; the parseInt-based hex decode above doesn't throw on invalid input (parseInt returns NaN), so this catch is unreachable today. Keep for forward-compat: if a future hex-decode primitive (e.g. native Uint8Array.fromHex) throws, this branch ensures fail-closed verification rather than silently passing garbage bytes through to verifyBySuite. */
547
+ }
548
+ catch {
549
+ errors.push("signature decode failed");
550
+ return { valid: false, errors, manifest: null };
551
+ }
552
+ /* c8 ignore stop */
553
+ const ok = await verifyBySuite("motebit-jcs-ed25519-hex-v1", canonicalBytes, signatureBytes, operatorPublicKey);
554
+ if (!ok) {
555
+ errors.push("manifest signature does not verify against operator_public_key");
556
+ return { valid: false, errors, manifest: null };
557
+ }
558
+ return { valid: true, errors: [], manifest };
559
+ }
560
+ // Re-export to satisfy unused-import lint when MotebitId only appears in JSDoc.
561
+ void null;
562
+ //# sourceMappingURL=deletion-certificate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deletion-certificate.js","sourceRoot":"","sources":["../src/deletion-certificate.ts"],"names":[],"mappings":"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"}