@ziffer-io/verify 0.1.1 → 0.2.1

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.
package/README.md CHANGED
@@ -50,6 +50,14 @@ Every refusal is a thrown `Refusal` whose `clause` names the rule that fired; th
50
50
  clause, what it means and what to do is at https://ziffer.io/docs/refusals. Narrow with
51
51
  `instanceof Refusal`, record the clause, and do not retry it.
52
52
 
53
+ ## Checking an audit chain download
54
+
55
+ The console's *Download the audit chain for this window* file checks here too:
56
+ `verifyChain(fileBytes, parseAnchorKey(anchorKeyBytes))` recomputes every record's hash, checks
57
+ each anchor's signature under the audit anchor key you hold (never the copy inside the file), and
58
+ reports which records no anchor covers yet. A break throws `ChainRefusal`, whose `refusal` and
59
+ `seq` name what broke and where. Integrating the SDK, section 6, has the whole of it.
60
+
53
61
  ## Documentation
54
62
 
55
63
  - Quickstart: https://ziffer.io/docs/quickstart
package/dist/cbor.d.ts ADDED
@@ -0,0 +1,87 @@
1
+ /**
2
+ * AT-8a canonical CBOR (RFC 8949 §4.2) -- the ONE primitive this package did
3
+ * not already have, added for §8.6c and for nothing else.
4
+ *
5
+ * # Why a new module rather than a reused one
6
+ *
7
+ * `canon.ts` is the canonical JSON encoding, and it is the right preimage for
8
+ * every hash this verifier takes: the engine's `attestation_id` and AB-1 entry
9
+ * digest are `sha256:` over `acp_executor.canon` / `receipt.rs::canon`, both
10
+ * JSON, and this package reproduces those bytes. What CBOR is needed for is
11
+ * narrower and unavoidable: HM-3 says a human attester's assertion is canonical
12
+ * CBOR of `{authenticator_data, client_data_json, signature}`, and HM-1 says the
13
+ * credential's `public_key` is a COSE_Key, which is CBOR by RFC 9052. Those two
14
+ * byte strings arrive from the wire and must be DECODED; no JSON encoder can
15
+ * read them. So this is a decoder for two fixed shapes, not a general codec.
16
+ *
17
+ * The engine's twins are `crates/acp-crypto/src/cbor.rs` and
18
+ * `reference/src/acp_crypto.py`'s `_enc` / `_dec` / `decode_canonical`, and the
19
+ * rule this file takes from them verbatim is the last one:
20
+ *
21
+ * # Canonicity is proved by RE-ENCODING, not by a list of sub-rules
22
+ *
23
+ * {@link decodeCanonical} parses, re-encodes what it parsed, and refuses the
24
+ * input unless the two byte strings are identical. That single comparison
25
+ * carries every §4.2 requirement at once -- shortest-form arguments, definite
26
+ * lengths, map keys sorted by their ENCODED bytes, no duplicate keys -- and it
27
+ * cannot drift from the encoder the way a hand-written checklist of those rules
28
+ * can. The decoder still refuses the coarse violations itself (indefinite
29
+ * lengths, non-shortest arguments, reserved additional information) because a
30
+ * decoder that accepted them would have to invent a canonical form to compare
31
+ * against, and inventing one is normalising.
32
+ *
33
+ * Refused, never normalised (AT-8a): the AB-1 entry digest is taken over the
34
+ * bytes that arrived, so a second encoding of one assertion is a second digest
35
+ * for one human decision, and accepting both would put two receipt identities
36
+ * behind one approval -- the Z4 encoding split, reached through the assertion.
37
+ *
38
+ * # Floats and tags are absent on purpose
39
+ *
40
+ * Neither is encodable, so neither is decodable: a float has several
41
+ * representations of one value and no deterministic ordering story (WE-1), and
42
+ * a tag is a type this verifier has no shape for. They refuse as
43
+ * {@link CborError} rather than being skipped, because a decoder that silently
44
+ * ignores what it does not understand is a parser an attacker can steer.
45
+ */
46
+ /** The input is not canonical CBOR, or is not CBOR at all. */
47
+ export declare class CborError extends Error {
48
+ constructor(message: string);
49
+ }
50
+ /**
51
+ * What this decoder can produce. Deliberately NOT a general CBOR value type:
52
+ * a map key is an integer (COSE labels, RFC 9052 §7) or text (HM-3's three
53
+ * fields), and nothing here needs more.
54
+ */
55
+ export type Cbor = boolean | null | bigint | Uint8Array | string | Cbor[] | CborMap;
56
+ /**
57
+ * A CBOR map, kept as ordered entries rather than a JS object.
58
+ *
59
+ * An object would key everything by string and collapse the integer label `1`
60
+ * and the text key `"1"` into one entry -- two distinct CBOR values, and in
61
+ * COSE_Key the integer form is the only legal one. The order is the order the
62
+ * bytes carried, which the re-encode check has already proved canonical.
63
+ */
64
+ export interface CborMap {
65
+ readonly entries: readonly (readonly [Cbor, Cbor])[];
66
+ }
67
+ /** Whether a decoded value is a map -- the narrowing the callers need. */
68
+ export declare function cborIsMap(v: Cbor): v is CborMap;
69
+ /** A map's keys, in the (canonical) order the bytes carried. */
70
+ export declare function cborKeys(m: CborMap): Cbor[];
71
+ /** The value at an integer label, or undefined. COSE_Key's accessor. */
72
+ export declare function cborGetInt(m: CborMap, label: bigint): Cbor | undefined;
73
+ /** The value at a text key, or undefined. The assertion map's accessor. */
74
+ export declare function cborGetText(m: CborMap, key: string): Cbor | undefined;
75
+ /** A decoded value as bytes, or null if it is not a byte string. */
76
+ export declare function cborAsBytes(v: Cbor | undefined): Uint8Array | null;
77
+ /** The canonical CBOR bytes of a value. Used by {@link decodeCanonical}'s proof. */
78
+ export declare function cborEncode(value: Cbor): Uint8Array;
79
+ /**
80
+ * AT-8a: parse AND prove canonicity. Any input that is not byte-identical to
81
+ * the canonical encoding of what it decodes to is REFUSED, never normalised.
82
+ *
83
+ * The engine's `decode_canonical` in one sentence, and the same sentence is the
84
+ * whole specification of this function.
85
+ */
86
+ export declare function decodeCanonical(buf: Uint8Array): Cbor;
87
+ //# sourceMappingURL=cbor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cbor.d.ts","sourceRoot":"","sources":["../src/cbor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,8DAA8D;AAC9D,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,MAAM,MAAM,IAAI,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;AAEpF;;;;;;;GAOG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;CACtD;AAMD,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,OAAO,CAE/C;AAED,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,EAAE,CAE3C;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAGtE;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAGrE;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,GAAG,SAAS,GAAG,UAAU,GAAG,IAAI,CAElE;AAsHD,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,CAIlD;AA0FD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAQrD"}
package/dist/cbor.js ADDED
@@ -0,0 +1,326 @@
1
+ /**
2
+ * AT-8a canonical CBOR (RFC 8949 §4.2) -- the ONE primitive this package did
3
+ * not already have, added for §8.6c and for nothing else.
4
+ *
5
+ * # Why a new module rather than a reused one
6
+ *
7
+ * `canon.ts` is the canonical JSON encoding, and it is the right preimage for
8
+ * every hash this verifier takes: the engine's `attestation_id` and AB-1 entry
9
+ * digest are `sha256:` over `acp_executor.canon` / `receipt.rs::canon`, both
10
+ * JSON, and this package reproduces those bytes. What CBOR is needed for is
11
+ * narrower and unavoidable: HM-3 says a human attester's assertion is canonical
12
+ * CBOR of `{authenticator_data, client_data_json, signature}`, and HM-1 says the
13
+ * credential's `public_key` is a COSE_Key, which is CBOR by RFC 9052. Those two
14
+ * byte strings arrive from the wire and must be DECODED; no JSON encoder can
15
+ * read them. So this is a decoder for two fixed shapes, not a general codec.
16
+ *
17
+ * The engine's twins are `crates/acp-crypto/src/cbor.rs` and
18
+ * `reference/src/acp_crypto.py`'s `_enc` / `_dec` / `decode_canonical`, and the
19
+ * rule this file takes from them verbatim is the last one:
20
+ *
21
+ * # Canonicity is proved by RE-ENCODING, not by a list of sub-rules
22
+ *
23
+ * {@link decodeCanonical} parses, re-encodes what it parsed, and refuses the
24
+ * input unless the two byte strings are identical. That single comparison
25
+ * carries every §4.2 requirement at once -- shortest-form arguments, definite
26
+ * lengths, map keys sorted by their ENCODED bytes, no duplicate keys -- and it
27
+ * cannot drift from the encoder the way a hand-written checklist of those rules
28
+ * can. The decoder still refuses the coarse violations itself (indefinite
29
+ * lengths, non-shortest arguments, reserved additional information) because a
30
+ * decoder that accepted them would have to invent a canonical form to compare
31
+ * against, and inventing one is normalising.
32
+ *
33
+ * Refused, never normalised (AT-8a): the AB-1 entry digest is taken over the
34
+ * bytes that arrived, so a second encoding of one assertion is a second digest
35
+ * for one human decision, and accepting both would put two receipt identities
36
+ * behind one approval -- the Z4 encoding split, reached through the assertion.
37
+ *
38
+ * # Floats and tags are absent on purpose
39
+ *
40
+ * Neither is encodable, so neither is decodable: a float has several
41
+ * representations of one value and no deterministic ordering story (WE-1), and
42
+ * a tag is a type this verifier has no shape for. They refuse as
43
+ * {@link CborError} rather than being skipped, because a decoder that silently
44
+ * ignores what it does not understand is a parser an attacker can steer.
45
+ */
46
+ /** The input is not canonical CBOR, or is not CBOR at all. */
47
+ export class CborError extends Error {
48
+ constructor(message) {
49
+ super(message);
50
+ this.name = 'CborError';
51
+ }
52
+ }
53
+ function isCborMap(v) {
54
+ return typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof Uint8Array);
55
+ }
56
+ /** Whether a decoded value is a map -- the narrowing the callers need. */
57
+ export function cborIsMap(v) {
58
+ return isCborMap(v);
59
+ }
60
+ /** A map's keys, in the (canonical) order the bytes carried. */
61
+ export function cborKeys(m) {
62
+ return m.entries.map(([k]) => k);
63
+ }
64
+ /** The value at an integer label, or undefined. COSE_Key's accessor. */
65
+ export function cborGetInt(m, label) {
66
+ for (const [k, v] of m.entries)
67
+ if (typeof k === 'bigint' && k === label)
68
+ return v;
69
+ return undefined;
70
+ }
71
+ /** The value at a text key, or undefined. The assertion map's accessor. */
72
+ export function cborGetText(m, key) {
73
+ for (const [k, v] of m.entries)
74
+ if (typeof k === 'string' && k === key)
75
+ return v;
76
+ return undefined;
77
+ }
78
+ /** A decoded value as bytes, or null if it is not a byte string. */
79
+ export function cborAsBytes(v) {
80
+ return v instanceof Uint8Array ? v : null;
81
+ }
82
+ const MAJOR_UINT = 0;
83
+ const MAJOR_NINT = 1;
84
+ const MAJOR_BYTES = 2;
85
+ const MAJOR_TEXT = 3;
86
+ const MAJOR_ARRAY = 4;
87
+ const MAJOR_MAP = 5;
88
+ const MAJOR_SIMPLE = 7;
89
+ /**
90
+ * RFC 8949 §4.2.1: the argument MUST use the shortest form that holds it.
91
+ *
92
+ * `bigint` throughout rather than `number`, because a CBOR argument is a full
93
+ * 64-bit unsigned integer and `number` loses digits past 2^53-1 -- the same
94
+ * defect `canon.ts` refuses on the JSON side, and here it would mean re-encoding
95
+ * a length to different bytes than arrived and calling the input non-canonical
96
+ * for the decoder's own reason.
97
+ */
98
+ function encodeHead(major, value, out) {
99
+ const head = major << 5;
100
+ if (value < 24n) {
101
+ out.push(head | Number(value));
102
+ return;
103
+ }
104
+ let width;
105
+ if (value < 0x100n) {
106
+ out.push(head | 24);
107
+ width = 1;
108
+ }
109
+ else if (value < 0x10000n) {
110
+ out.push(head | 25);
111
+ width = 2;
112
+ }
113
+ else if (value < 0x100000000n) {
114
+ out.push(head | 26);
115
+ width = 4;
116
+ }
117
+ else if (value < 0x10000000000000000n) {
118
+ out.push(head | 27);
119
+ width = 8;
120
+ }
121
+ else {
122
+ throw new CborError('integer exceeds the 64-bit CBOR argument');
123
+ }
124
+ for (let i = width - 1; i >= 0; i -= 1) {
125
+ out.push(Number((value >> BigInt(i * 8)) & 0xffn));
126
+ }
127
+ }
128
+ function encodeInto(value, out) {
129
+ if (value === true) {
130
+ out.push(0xf5);
131
+ return;
132
+ }
133
+ if (value === false) {
134
+ out.push(0xf4);
135
+ return;
136
+ }
137
+ if (value === null) {
138
+ out.push(0xf6);
139
+ return;
140
+ }
141
+ if (typeof value === 'bigint') {
142
+ if (value >= 0n)
143
+ encodeHead(MAJOR_UINT, value, out);
144
+ else
145
+ encodeHead(MAJOR_NINT, -value - 1n, out);
146
+ return;
147
+ }
148
+ if (value instanceof Uint8Array) {
149
+ encodeHead(MAJOR_BYTES, BigInt(value.length), out);
150
+ for (const b of value)
151
+ out.push(b);
152
+ return;
153
+ }
154
+ if (typeof value === 'string') {
155
+ const bytes = new TextEncoder().encode(value);
156
+ encodeHead(MAJOR_TEXT, BigInt(bytes.length), out);
157
+ for (const b of bytes)
158
+ out.push(b);
159
+ return;
160
+ }
161
+ if (Array.isArray(value)) {
162
+ encodeHead(MAJOR_ARRAY, BigInt(value.length), out);
163
+ for (const item of value)
164
+ encodeInto(item, out);
165
+ return;
166
+ }
167
+ if (isCborMap(value)) {
168
+ // §4.2.1: keys sorted by their ENCODED bytes, bytewise lexicographic.
169
+ // Sorting by the decoded value would put the integer label -2 and the text
170
+ // key "x" in an order that depends on the comparison chosen rather than on
171
+ // the bytes, and the encoded order is the one the rule names.
172
+ const keyed = value.entries.map(([k, v]) => {
173
+ const kb = [];
174
+ encodeInto(k, kb);
175
+ return { kb, v };
176
+ });
177
+ keyed.sort((a, b) => compareBytes(a.kb, b.kb));
178
+ for (let i = 1; i < keyed.length; i += 1) {
179
+ const prev = keyed[i - 1];
180
+ const cur = keyed[i];
181
+ if (prev === undefined || cur === undefined)
182
+ continue; // unreachable; index in range
183
+ if (compareBytes(prev.kb, cur.kb) === 0)
184
+ throw new CborError('duplicate map key');
185
+ }
186
+ encodeHead(MAJOR_MAP, BigInt(keyed.length), out);
187
+ for (const { kb, v } of keyed) {
188
+ for (const b of kb)
189
+ out.push(b);
190
+ encodeInto(v, out);
191
+ }
192
+ return;
193
+ }
194
+ throw new CborError('value is not canonically encodable');
195
+ }
196
+ function compareBytes(a, b) {
197
+ const n = Math.min(a.length, b.length);
198
+ for (let i = 0; i < n; i += 1) {
199
+ const x = a[i];
200
+ const y = b[i];
201
+ if (x === undefined || y === undefined)
202
+ continue; // unreachable; index in range
203
+ if (x !== y)
204
+ return x - y;
205
+ }
206
+ return a.length - b.length;
207
+ }
208
+ /** The canonical CBOR bytes of a value. Used by {@link decodeCanonical}'s proof. */
209
+ export function cborEncode(value) {
210
+ const out = [];
211
+ encodeInto(value, out);
212
+ return Uint8Array.from(out);
213
+ }
214
+ function decodeAt(buf, start) {
215
+ if (start >= buf.length)
216
+ throw new CborError('truncated');
217
+ const ib = buf[start];
218
+ if (ib === undefined)
219
+ throw new CborError('truncated'); // unreachable; bound checked
220
+ const major = ib >> 5;
221
+ const ai = ib & 0x1f;
222
+ let i = start + 1;
223
+ let value;
224
+ if (ai < 24) {
225
+ value = BigInt(ai);
226
+ }
227
+ else if (ai <= 27) {
228
+ const width = 1 << (ai - 24);
229
+ if (i + width > buf.length)
230
+ throw new CborError('truncated argument');
231
+ value = 0n;
232
+ for (let k = 0; k < width; k += 1) {
233
+ const b = buf[i + k];
234
+ if (b === undefined)
235
+ throw new CborError('truncated argument'); // unreachable
236
+ value = (value << 8n) | BigInt(b);
237
+ }
238
+ i += width;
239
+ // Shortest form (§4.2.1). Refused here as well as by the re-encode proof,
240
+ // because the value that re-encodes shorter would otherwise be decoded
241
+ // first and any shape check above would run on attacker-chosen bytes.
242
+ const floor = ai === 24 ? 24n : 1n << BigInt((width / 2) * 8);
243
+ if (value < floor)
244
+ throw new CborError('non-shortest argument');
245
+ }
246
+ else if (ai === 31) {
247
+ throw new CborError('indefinite length forbidden in canonical CBOR');
248
+ }
249
+ else {
250
+ throw new CborError(`reserved additional information ${ai}`);
251
+ }
252
+ switch (major) {
253
+ case MAJOR_UINT:
254
+ return { value, next: i };
255
+ case MAJOR_NINT:
256
+ return { value: -value - 1n, next: i };
257
+ case MAJOR_BYTES:
258
+ case MAJOR_TEXT: {
259
+ const len = Number(value);
260
+ if (!Number.isSafeInteger(len) || i + len > buf.length) {
261
+ throw new CborError('truncated string');
262
+ }
263
+ const slice = buf.subarray(i, i + len);
264
+ if (major === MAJOR_BYTES)
265
+ return { value: Uint8Array.from(slice), next: i + len };
266
+ // fatal: true -- invalid UTF-8 is a refusal, not a run of U+FFFD. A
267
+ // replacement character would make two distinct byte strings decode to
268
+ // one text value, which the re-encode proof would then report as
269
+ // non-canonical for the wrong reason.
270
+ return { value: new TextDecoder('utf-8', { fatal: true }).decode(slice), next: i + len };
271
+ }
272
+ case MAJOR_ARRAY: {
273
+ const n = Number(value);
274
+ if (!Number.isSafeInteger(n) || n > buf.length - i)
275
+ throw new CborError('truncated array');
276
+ const items = [];
277
+ for (let k = 0; k < n; k += 1) {
278
+ const d = decodeAt(buf, i);
279
+ items.push(d.value);
280
+ i = d.next;
281
+ }
282
+ return { value: items, next: i };
283
+ }
284
+ case MAJOR_MAP: {
285
+ const n = Number(value);
286
+ if (!Number.isSafeInteger(n) || n > buf.length - i)
287
+ throw new CborError('truncated map');
288
+ const entries = [];
289
+ for (let k = 0; k < n; k += 1) {
290
+ const key = decodeAt(buf, i);
291
+ const val = decodeAt(buf, key.next);
292
+ entries.push([key.value, val.value]);
293
+ i = val.next;
294
+ }
295
+ return { value: { entries }, next: i };
296
+ }
297
+ case MAJOR_SIMPLE:
298
+ if (value === 20n)
299
+ return { value: false, next: i };
300
+ if (value === 21n)
301
+ return { value: true, next: i };
302
+ if (value === 22n)
303
+ return { value: null, next: i };
304
+ throw new CborError('float or unsupported simple value');
305
+ default:
306
+ throw new CborError(`unsupported major type ${major}`);
307
+ }
308
+ }
309
+ /**
310
+ * AT-8a: parse AND prove canonicity. Any input that is not byte-identical to
311
+ * the canonical encoding of what it decodes to is REFUSED, never normalised.
312
+ *
313
+ * The engine's `decode_canonical` in one sentence, and the same sentence is the
314
+ * whole specification of this function.
315
+ */
316
+ export function decodeCanonical(buf) {
317
+ const { value, next } = decodeAt(buf, 0);
318
+ if (next !== buf.length)
319
+ throw new CborError('trailing bytes');
320
+ const re = cborEncode(value);
321
+ if (re.length !== buf.length || !re.every((b, i) => b === buf[i])) {
322
+ throw new CborError('input is not the canonical encoding of its value');
323
+ }
324
+ return value;
325
+ }
326
+ //# sourceMappingURL=cbor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cbor.js","sourceRoot":"","sources":["../src/cbor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * The audit chain export verifier (ACP-428) -- the TypeScript reader of the
3
+ * file the console's "Download the audit chain for this window" link gives.
4
+ *
5
+ * The link said the file was verifiable offline and nothing a customer held
6
+ * verified it. The Python SDK's `verify_chain` and this function are that
7
+ * verifier, and they are held to ONE verdict per file by the shared corpus in
8
+ * `fixtures/chain-export/` -- the same refusal name at the same record, the
9
+ * same recomputed last hash, the same report of what the anchors cover. The
10
+ * check order below is the Python reader's, step for step, because on a file
11
+ * with two defects the order decides which one is named.
12
+ *
13
+ * # What is recomputed, and what is only reported
14
+ *
15
+ * Every `chain_hash` is RECOMPUTED -- `sha256:` over the canonical bytes of the
16
+ * record (the first record of the chain) or of `{prev, record}` (every later
17
+ * one), the audit service's own link -- and the file's value is compared,
18
+ * never used. Every `previous_hash` after the first row is compared against
19
+ * the hash just recomputed. The first row's `previous_hash`, in a file that
20
+ * starts after the beginning of the chain, is the one link this file cannot
21
+ * recompute; it is reported as `startsAfter`, and it is checked only when an
22
+ * anchor names exactly that position.
23
+ *
24
+ * # The anchor key never comes from the file
25
+ *
26
+ * Every anchor entry carries an `anchor_identity` beside it. Reading the key
27
+ * from there would accept any file whose author signed their own anchors and
28
+ * wrote their own key next to them -- the party under verification supplying
29
+ * the value it is verified with. So the key is a parameter, from a file the
30
+ * customer holds, and with no key every anchor is reported `unchecked`: never
31
+ * passed, and never dropped from the report.
32
+ *
33
+ * # Numbers: the file's TEXT is read, not only its parsed values
34
+ *
35
+ * `JSON.parse` reads `1.0` as the integer 1. The record the writer hashed said
36
+ * `1.0`, so hashing `1` would compare bytes nobody wrote and name the wrong
37
+ * defect. The parser's reviver sees each number's source text (Node 22 and
38
+ * later), and a number written with a fraction or an exponent becomes a value
39
+ * the canonical encoder refuses -- `RecordNotCanonical` inside a record,
40
+ * `ExportMalformed` in the file's own fields, exactly where the Python reader
41
+ * says so. On a runtime whose parser does not hand the reviver the source
42
+ * text, that one case would be named `ChainHashMismatch` instead; the file is
43
+ * refused either way.
44
+ */
45
+ /** The one suite an audit anchor is signed under here, and the only one an anchor key may name. */
46
+ export declare const ANCHOR_SUITE = "hybrid-ed25519-mldsa65";
47
+ /** A refusal of an export, by name, at the first record or anchor that broke. */
48
+ export declare class ChainRefusal extends Error {
49
+ /** The refusal name, identical to the Python reader's `ChainRefused.name`. */
50
+ readonly refusal: string;
51
+ readonly seq: number | null;
52
+ readonly anchor: number | null;
53
+ constructor(refusal: string, detail: string, where?: {
54
+ seq?: number;
55
+ anchor?: number;
56
+ });
57
+ }
58
+ /** An anchor key file that cannot be used, by name. A defect in the caller's own file, not a verdict. */
59
+ export declare class AnchorKeyRefusal extends Error {
60
+ readonly refusal: string;
61
+ constructor(refusal: string, detail: string);
62
+ }
63
+ /** The audit anchor identity's public halves, from the file the customer holds. */
64
+ export interface AnchorKey {
65
+ readonly alg: typeof ANCHOR_SUITE;
66
+ readonly classical: Uint8Array;
67
+ readonly pq: Uint8Array;
68
+ readonly fingerprint: string;
69
+ }
70
+ export interface AnchorResult {
71
+ readonly index: number;
72
+ readonly status: 'verified' | 'unchecked';
73
+ readonly placement: 'in_file' | 'window_floor' | 'before_file' | 'after_file' | 'no_head';
74
+ readonly headSeq: number | null;
75
+ readonly periodEnd: number;
76
+ }
77
+ export interface ChainVerified {
78
+ readonly tenant: string;
79
+ readonly firstSeq: number;
80
+ readonly lastSeq: number;
81
+ readonly records: number;
82
+ /** RECOMPUTED, never the file's. */
83
+ readonly lastChainHash: string;
84
+ readonly startsAfter: string | null;
85
+ readonly anchorsChecked: boolean;
86
+ readonly anchors: readonly AnchorResult[];
87
+ readonly anchoredThrough: number | null;
88
+ readonly unanchoredFrom: number | null;
89
+ readonly unanchoredCount: number;
90
+ }
91
+ /** The verdict as the shared corpus writes it -- snake_case, the Python reader's keys. */
92
+ export type ChainVerdict = {
93
+ readonly verdict: 'verified';
94
+ readonly tenant: string;
95
+ readonly first_seq: number;
96
+ readonly last_seq: number;
97
+ readonly records: number;
98
+ readonly last_chain_hash: string;
99
+ readonly starts_after: string | null;
100
+ readonly anchors_checked: boolean;
101
+ readonly anchors: readonly {
102
+ readonly index: number;
103
+ readonly status: string;
104
+ readonly placement: string;
105
+ readonly head_seq: number | null;
106
+ readonly period_end: number;
107
+ }[];
108
+ readonly anchored_through: number | null;
109
+ readonly unanchored_from: number | null;
110
+ readonly unanchored_count: number;
111
+ } | {
112
+ readonly verdict: 'refused';
113
+ readonly refusal: string;
114
+ readonly seq: number | null;
115
+ readonly anchor: number | null;
116
+ };
117
+ /**
118
+ * Read the audit anchor identity's public document -- `{alg, classical, pq,
119
+ * fingerprint}`, the halves in base64 -- checking every redundant field: the
120
+ * fingerprint is recomputed over both halves and compared, and a small-order
121
+ * Ed25519 half is refused, because under one a single signature verifies every
122
+ * message.
123
+ */
124
+ export declare function parseAnchorKey(file: string | Uint8Array): AnchorKey;
125
+ /**
126
+ * Verify an audit chain export, from the file's bytes or text.
127
+ *
128
+ * Throws {@link ChainRefusal} at the first break: `ExportMalformed`,
129
+ * `ExportEmpty`, `ChainSeqGap`, `RecordOutOfPlace`, `ChainLinkBroken`,
130
+ * `RecordNotCanonical`, `ChainHashMismatch`, `AnchorMalformed`,
131
+ * `AnchorSuiteNotEnrolled`, `AnchorSignatureInvalid`, `AnchorHeadMismatch`.
132
+ *
133
+ * NOT checked, on purpose, as in the Python reader: whether each record's
134
+ * fields are the set its kind of event carries, the transparency-log entry and
135
+ * timestamp stored beside each anchor, and whether the file holds EVERY record
136
+ * of its window -- a file cut short at the end verifies, and `unanchoredFrom`
137
+ * says how much of it nothing yet commits to.
138
+ */
139
+ export declare function verifyChain(file: string | Uint8Array, anchorKey?: AnchorKey): ChainVerified;
140
+ /** {@link verifyChain}'s answer, or its refusal, as one corpus-shaped object. */
141
+ export declare function chainVerdict(file: string | Uint8Array, anchorKey?: AnchorKey): ChainVerdict;
142
+ //# sourceMappingURL=chain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}