@actuarial-ts/compliance 0.6.1 → 0.7.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.
Files changed (69) hide show
  1. package/README.md +6 -2
  2. package/dist/diagnosticArtifactStream.d.ts +30 -0
  3. package/dist/diagnosticArtifactStream.d.ts.map +1 -0
  4. package/dist/diagnosticArtifactStream.js +128 -0
  5. package/dist/diagnosticArtifactStream.js.map +1 -0
  6. package/dist/diagnosticByteSource.d.ts +10 -0
  7. package/dist/diagnosticByteSource.d.ts.map +1 -0
  8. package/dist/diagnosticByteSource.js +70 -0
  9. package/dist/diagnosticByteSource.js.map +1 -0
  10. package/dist/diagnosticByteView.d.ts +3 -0
  11. package/dist/diagnosticByteView.d.ts.map +1 -0
  12. package/dist/diagnosticByteView.js +27 -0
  13. package/dist/diagnosticByteView.js.map +1 -0
  14. package/dist/diagnosticCompactRun.d.ts +43 -0
  15. package/dist/diagnosticCompactRun.d.ts.map +1 -0
  16. package/dist/diagnosticCompactRun.js +253 -0
  17. package/dist/diagnosticCompactRun.js.map +1 -0
  18. package/dist/diagnosticReplayFrames.d.ts +10 -0
  19. package/dist/diagnosticReplayFrames.d.ts.map +1 -0
  20. package/dist/diagnosticReplayFrames.js +99 -0
  21. package/dist/diagnosticReplayFrames.js.map +1 -0
  22. package/dist/diagnosticReplayProtocol.d.ts +17 -0
  23. package/dist/diagnosticReplayProtocol.d.ts.map +1 -0
  24. package/dist/diagnosticReplayProtocol.js +98 -0
  25. package/dist/diagnosticReplayProtocol.js.map +1 -0
  26. package/dist/diagnosticReplayReader.d.ts +41 -0
  27. package/dist/diagnosticReplayReader.d.ts.map +1 -0
  28. package/dist/diagnosticReplayReader.js +346 -0
  29. package/dist/diagnosticReplayReader.js.map +1 -0
  30. package/dist/diagnosticReplayValue.d.ts +34 -0
  31. package/dist/diagnosticReplayValue.d.ts.map +1 -0
  32. package/dist/diagnosticReplayValue.js +269 -0
  33. package/dist/diagnosticReplayValue.js.map +1 -0
  34. package/dist/diagnosticReplayWriter.d.ts +25 -0
  35. package/dist/diagnosticReplayWriter.d.ts.map +1 -0
  36. package/dist/diagnosticReplayWriter.js +148 -0
  37. package/dist/diagnosticReplayWriter.js.map +1 -0
  38. package/dist/diagnosticRun.d.ts.map +1 -1
  39. package/dist/diagnosticRun.js +1 -193
  40. package/dist/diagnosticRun.js.map +1 -1
  41. package/dist/diagnosticRunEvidence.d.ts +18 -0
  42. package/dist/diagnosticRunEvidence.d.ts.map +1 -0
  43. package/dist/diagnosticRunEvidence.js +195 -0
  44. package/dist/diagnosticRunEvidence.js.map +1 -0
  45. package/dist/index.d.ts +4 -0
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +4 -0
  48. package/dist/index.js.map +1 -1
  49. package/dist/sha256Stream.d.ts +6 -0
  50. package/dist/sha256Stream.d.ts.map +1 -0
  51. package/dist/sha256Stream.js +103 -0
  52. package/dist/sha256Stream.js.map +1 -0
  53. package/dist/version.d.ts +1 -1
  54. package/dist/version.js +1 -1
  55. package/package.json +4 -4
  56. package/src/diagnosticArtifactStream.ts +148 -0
  57. package/src/diagnosticByteSource.ts +82 -0
  58. package/src/diagnosticByteView.ts +27 -0
  59. package/src/diagnosticCompactRun.ts +462 -0
  60. package/src/diagnosticReplayFrames.ts +99 -0
  61. package/src/diagnosticReplayProtocol.ts +99 -0
  62. package/src/diagnosticReplayReader.ts +428 -0
  63. package/src/diagnosticReplayValue.ts +269 -0
  64. package/src/diagnosticReplayWriter.ts +190 -0
  65. package/src/diagnosticRun.ts +7 -373
  66. package/src/diagnosticRunEvidence.ts +391 -0
  67. package/src/index.ts +10 -0
  68. package/src/sha256Stream.ts +108 -0
  69. package/src/version.ts +1 -1
@@ -0,0 +1,391 @@
1
+ import type { CompactPreparedDiagnosticData } from "@actuarial-ts/core";
2
+ import type { CompactDiagnosticReviewReceipt } from "@actuarial-ts/data";
3
+ import type {
4
+ DiagnosticArtifactDigest,
5
+ DiagnosticPreparationLineage,
6
+ } from "./diagnosticRun.js";
7
+ import { ComplianceError } from "./errors.js";
8
+
9
+ /** Shared content validation; callers separately authenticate their run owner. */
10
+ export interface DiagnosticArtifactGraphContent {
11
+ readonly prepared: Pick<
12
+ CompactPreparedDiagnosticData,
13
+ "inputAudit" | "definition"
14
+ >;
15
+ readonly review: Pick<CompactDiagnosticReviewReceipt, "evidence">;
16
+ readonly datasetArtifactId: string | null;
17
+ readonly gate: { readonly rationaleRef: string | null };
18
+ }
19
+
20
+ export const token = (value: string, path: string) => {
21
+ if (
22
+ value.length === 0 ||
23
+ /^[\t-\r ]|[\t-\r ]$/.test(value) ||
24
+ value.includes("\0")
25
+ )
26
+ throw new ComplianceError(
27
+ "BAD_DIAGNOSTIC_RUN",
28
+ `${path} must be a nonempty token`,
29
+ path,
30
+ );
31
+ for (let index = 0; index < value.length; index++) {
32
+ const unit = value.charCodeAt(index);
33
+ if (unit >= 0xd800 && unit <= 0xdbff) {
34
+ const next = value.charCodeAt(index + 1);
35
+ if (!(next >= 0xdc00 && next <= 0xdfff))
36
+ throw new ComplianceError(
37
+ "BAD_DIAGNOSTIC_RUN",
38
+ `${path} contains malformed Unicode`,
39
+ path,
40
+ );
41
+ index++;
42
+ } else if (unit >= 0xdc00 && unit <= 0xdfff)
43
+ throw new ComplianceError(
44
+ "BAD_DIAGNOSTIC_RUN",
45
+ `${path} contains malformed Unicode`,
46
+ path,
47
+ );
48
+ }
49
+ };
50
+ export function plain(value: unknown): value is Record<string, unknown> {
51
+ if (value === null || typeof value !== "object" || Array.isArray(value))
52
+ return false;
53
+ const prototype = Object.getPrototypeOf(value);
54
+ return prototype === Object.prototype || prototype === null;
55
+ }
56
+ export function exactKeys(
57
+ value: Record<string, unknown>,
58
+ allowed: readonly string[],
59
+ path: string,
60
+ ): void {
61
+ for (const key of Object.keys(value))
62
+ if (!allowed.includes(key))
63
+ throw new ComplianceError(
64
+ "BAD_DIAGNOSTIC_RUN",
65
+ `Unknown field ${key}`,
66
+ `${path}.${key}`,
67
+ );
68
+ }
69
+ export function snapshotLineage(
70
+ lineage: unknown,
71
+ ): readonly DiagnosticPreparationLineage[] {
72
+ if (!Array.isArray(lineage))
73
+ throw new ComplianceError(
74
+ "BAD_DIAGNOSTIC_RUN",
75
+ "$.preparationLineage must be an array",
76
+ "$.preparationLineage",
77
+ );
78
+ return lineage
79
+ .map((raw, index) => {
80
+ const path = `$.preparationLineage[${index}]`;
81
+ if (!plain(raw))
82
+ throw new ComplianceError(
83
+ "BAD_DIAGNOSTIC_RUN",
84
+ "Lineage edge must be a plain object",
85
+ path,
86
+ );
87
+ exactKeys(
88
+ raw,
89
+ ["outputArtifactId", "inputArtifactIds", "transformationArtifactIds"],
90
+ path,
91
+ );
92
+ if (typeof raw.outputArtifactId !== "string")
93
+ throw new ComplianceError(
94
+ "BAD_DIAGNOSTIC_RUN",
95
+ "Lineage output must be a string",
96
+ `${path}.outputArtifactId`,
97
+ );
98
+ token(raw.outputArtifactId, `${path}.outputArtifactId`);
99
+ const readIds = (value: unknown, key: string) => {
100
+ if (!Array.isArray(value))
101
+ throw new ComplianceError(
102
+ "BAD_DIAGNOSTIC_RUN",
103
+ `Lineage ${key} must be an array`,
104
+ `${path}.${key}`,
105
+ );
106
+ const result = value.map((id, inputIndex) => {
107
+ if (typeof id !== "string")
108
+ throw new ComplianceError(
109
+ "BAD_DIAGNOSTIC_RUN",
110
+ "Lineage artifact id must be a string",
111
+ `${path}.${key}[${inputIndex}]`,
112
+ );
113
+ token(id, `${path}.${key}[${inputIndex}]`);
114
+ return id;
115
+ });
116
+ if (new Set(result).size !== result.length)
117
+ throw new ComplianceError(
118
+ "BAD_DIAGNOSTIC_RUN",
119
+ `Lineage ${key} must be unique`,
120
+ `${path}.${key}`,
121
+ );
122
+ return [...result].sort();
123
+ };
124
+ const inputs = readIds(raw.inputArtifactIds, "inputArtifactIds"),
125
+ transformations = readIds(
126
+ raw.transformationArtifactIds,
127
+ "transformationArtifactIds",
128
+ );
129
+ if (inputs.length + transformations.length === 0)
130
+ throw new ComplianceError(
131
+ "BAD_DIAGNOSTIC_RUN",
132
+ "Lineage edge must have at least one upstream artifact",
133
+ path,
134
+ );
135
+ return {
136
+ outputArtifactId: raw.outputArtifactId,
137
+ inputArtifactIds: inputs,
138
+ transformationArtifactIds: transformations,
139
+ };
140
+ })
141
+ .sort((a, b) =>
142
+ a.outputArtifactId < b.outputArtifactId
143
+ ? -1
144
+ : a.outputArtifactId > b.outputArtifactId
145
+ ? 1
146
+ : 0,
147
+ );
148
+ }
149
+
150
+ export function validateArtifactGraph(
151
+ run: DiagnosticArtifactGraphContent,
152
+ inputArtifacts: readonly Pick<
153
+ DiagnosticArtifactDigest,
154
+ "id" | "scope" | "assurance"
155
+ >[],
156
+ preparationArtifacts: readonly Pick<
157
+ DiagnosticArtifactDigest,
158
+ "id" | "scope" | "assurance"
159
+ >[],
160
+ lineage: readonly DiagnosticPreparationLineage[],
161
+ ): void {
162
+ const byId = new Map<
163
+ string,
164
+ Pick<DiagnosticArtifactDigest, "id" | "scope" | "assurance">
165
+ >();
166
+ for (const [index, item] of [
167
+ ...inputArtifacts,
168
+ ...preparationArtifacts,
169
+ ].entries()) {
170
+ if (byId.has(item.id))
171
+ throw new ComplianceError(
172
+ "BAD_DIAGNOSTIC_RUN",
173
+ `Duplicate artifact ID ${item.id}`,
174
+ `$.${index < inputArtifacts.length ? "inputArtifacts" : "preparationArtifacts"}[${index < inputArtifacts.length ? index : index - inputArtifacts.length}].id`,
175
+ );
176
+ byId.set(item.id, item);
177
+ }
178
+ const referenced = new Set<string>();
179
+ const requireArtifact = (
180
+ id: string,
181
+ scope: "input" | "preparation",
182
+ path: string,
183
+ ) => {
184
+ const artifact = byId.get(id);
185
+ if (!artifact)
186
+ throw new ComplianceError(
187
+ "BAD_DIAGNOSTIC_RUN",
188
+ `Artifact reference ${id} is unresolved`,
189
+ path,
190
+ );
191
+ if (artifact.scope !== scope)
192
+ throw new ComplianceError(
193
+ "BAD_DIAGNOSTIC_RUN",
194
+ `Artifact ${id} must have ${scope} scope`,
195
+ path,
196
+ );
197
+ referenced.add(id);
198
+ };
199
+ let unsourced = false;
200
+ for (const [index, item] of run.prepared.inputAudit.entries()) {
201
+ const source = item.record.source;
202
+ if (source)
203
+ requireArtifact(
204
+ source.artifactId,
205
+ "input",
206
+ `$.completedRun.prepared.inputAudit[${index}].record.source.artifactId`,
207
+ );
208
+ else unsourced = true;
209
+ }
210
+ const evidence = run.review.evidence;
211
+ if (evidence) {
212
+ for (const [index, item] of evidence.groupingAssignments.entries()) {
213
+ if (item.source)
214
+ requireArtifact(
215
+ item.source.artifactId,
216
+ "input",
217
+ `$.completedRun.review.evidence.groupingAssignments[${index}].source.artifactId`,
218
+ );
219
+ else unsourced = true;
220
+ }
221
+ for (const [index, item] of evidence.cachedFormulas.entries()) {
222
+ if (item.source)
223
+ requireArtifact(
224
+ item.source.artifactId,
225
+ "input",
226
+ `$.completedRun.review.evidence.cachedFormulas[${index}].source.artifactId`,
227
+ );
228
+ else unsourced = true;
229
+ }
230
+ }
231
+ if (unsourced) {
232
+ if (run.datasetArtifactId === null)
233
+ throw new ComplianceError(
234
+ "BAD_DIAGNOSTIC_RUN",
235
+ "Unsourced diagnostic input requires datasetArtifactId",
236
+ "$.completedRun.datasetArtifactId",
237
+ );
238
+ const fallback = byId.get(run.datasetArtifactId);
239
+ if (
240
+ !fallback ||
241
+ fallback.scope !== "input" ||
242
+ fallback.assurance !== "sdk-computed"
243
+ )
244
+ throw new ComplianceError(
245
+ "BAD_DIAGNOSTIC_RUN",
246
+ "datasetArtifactId must resolve to SDK-computed input evidence",
247
+ "$.completedRun.datasetArtifactId",
248
+ );
249
+ referenced.add(run.datasetArtifactId);
250
+ } else if (run.datasetArtifactId !== null) {
251
+ requireArtifact(
252
+ run.datasetArtifactId,
253
+ "input",
254
+ "$.completedRun.datasetArtifactId",
255
+ );
256
+ if (byId.get(run.datasetArtifactId)!.assurance !== "sdk-computed")
257
+ throw new ComplianceError(
258
+ "BAD_DIAGNOSTIC_RUN",
259
+ "datasetArtifactId must resolve to SDK-computed input evidence",
260
+ "$.completedRun.datasetArtifactId",
261
+ );
262
+ }
263
+ for (const [
264
+ basisIndex,
265
+ basis,
266
+ ] of run.prepared.definition.definition.amountBases.entries())
267
+ for (const [componentIndex, component] of basis.components.entries())
268
+ if (
269
+ component.limitation.kind !== "unlimited" &&
270
+ component.limitation.kind !== "unknown" &&
271
+ component.limitation.derivation.kind === "external"
272
+ )
273
+ requireArtifact(
274
+ component.limitation.derivation.transformationRef,
275
+ "preparation",
276
+ `$.definition.amountBases[${basisIndex}].components[${componentIndex}].limitation.derivation.transformationRef`,
277
+ );
278
+ for (const [
279
+ ruleIndex,
280
+ rule,
281
+ ] of run.prepared.definition.definition.reviewRules.entries())
282
+ if (
283
+ rule.kind === "layer-order" &&
284
+ rule.comparability.kind === "caller-asserted"
285
+ )
286
+ requireArtifact(
287
+ rule.comparability.rationaleArtifactId,
288
+ "preparation",
289
+ `$.definition.reviewRules[${ruleIndex}].comparability.rationaleArtifactId`,
290
+ );
291
+ if (run.gate.rationaleRef !== null)
292
+ requireArtifact(
293
+ run.gate.rationaleRef,
294
+ "preparation",
295
+ "$.completedRun.gate.rationaleRef",
296
+ );
297
+ const edges = new Map<string, readonly string[]>();
298
+ for (const [index, edge] of lineage.entries()) {
299
+ const path = `$.preparationLineage[${index}]`;
300
+ if (edges.has(edge.outputArtifactId))
301
+ throw new ComplianceError(
302
+ "BAD_DIAGNOSTIC_RUN",
303
+ "An artifact may have only one producing lineage edge",
304
+ `${path}.outputArtifactId`,
305
+ );
306
+ const downstream = byId.get(edge.outputArtifactId);
307
+ if (!downstream)
308
+ throw new ComplianceError(
309
+ "BAD_DIAGNOSTIC_RUN",
310
+ `Lineage artifact ${edge.outputArtifactId} is unresolved`,
311
+ `${path}.outputArtifactId`,
312
+ );
313
+ if (downstream.scope !== "input")
314
+ throw new ComplianceError(
315
+ "BAD_DIAGNOSTIC_RUN",
316
+ "Lineage output artifact must have input scope",
317
+ `${path}.outputArtifactId`,
318
+ );
319
+ for (const [inputIndex, id] of edge.inputArtifactIds.entries()) {
320
+ if (id === edge.outputArtifactId)
321
+ throw new ComplianceError(
322
+ "BAD_DIAGNOSTIC_RUN",
323
+ "Lineage may not reference itself",
324
+ `${path}.inputArtifactIds[${inputIndex}]`,
325
+ );
326
+ const artifact = byId.get(id);
327
+ if (!artifact || artifact.scope !== "input")
328
+ throw new ComplianceError(
329
+ "BAD_DIAGNOSTIC_RUN",
330
+ `Lineage input ${id} must resolve to input evidence`,
331
+ `${path}.inputArtifactIds[${inputIndex}]`,
332
+ );
333
+ }
334
+ for (const [
335
+ transformIndex,
336
+ id,
337
+ ] of edge.transformationArtifactIds.entries()) {
338
+ const artifact = byId.get(id);
339
+ if (!artifact || artifact.scope !== "preparation")
340
+ throw new ComplianceError(
341
+ "BAD_DIAGNOSTIC_RUN",
342
+ `Lineage transformation ${id} must resolve to preparation evidence`,
343
+ `${path}.transformationArtifactIds[${transformIndex}]`,
344
+ );
345
+ }
346
+ edges.set(edge.outputArtifactId, [
347
+ ...edge.inputArtifactIds,
348
+ ...edge.transformationArtifactIds,
349
+ ]);
350
+ }
351
+ const visiting = new Set<string>(),
352
+ visited = new Set<string>();
353
+ for (const root of [...referenced]) {
354
+ const stack = [{ id: root, exit: false }];
355
+ while (stack.length > 0) {
356
+ const { id, exit } = stack.pop()!;
357
+ if (exit) {
358
+ visiting.delete(id);
359
+ visited.add(id);
360
+ continue;
361
+ }
362
+ if (visiting.has(id))
363
+ throw new ComplianceError(
364
+ "BAD_DIAGNOSTIC_RUN",
365
+ "Artifact lineage contains a cycle",
366
+ "$.preparationLineage",
367
+ );
368
+ if (visited.has(id)) continue;
369
+ visiting.add(id);
370
+ stack.push({ id, exit: true });
371
+ for (const upstream of [...(edges.get(id) ?? [])].reverse()) {
372
+ referenced.add(upstream);
373
+ stack.push({ id: upstream, exit: false });
374
+ }
375
+ }
376
+ }
377
+ for (const [index, artifact] of inputArtifacts.entries())
378
+ if (!referenced.has(artifact.id))
379
+ throw new ComplianceError(
380
+ "BAD_DIAGNOSTIC_RUN",
381
+ `Artifact ${artifact.id} is orphaned`,
382
+ `$.inputArtifacts[${index}].id`,
383
+ );
384
+ for (const [index, artifact] of preparationArtifacts.entries())
385
+ if (!referenced.has(artifact.id))
386
+ throw new ComplianceError(
387
+ "BAD_DIAGNOSTIC_RUN",
388
+ `Artifact ${artifact.id} is orphaned`,
389
+ `$.preparationArtifacts[${index}].id`,
390
+ );
391
+ }
package/src/index.ts CHANGED
@@ -5,5 +5,15 @@ export * from "./ledger.js";
5
5
  export * from "./modelCards.js";
6
6
  export * from "./disclosure.js";
7
7
  export * from "./diagnosticRun.js";
8
+ export * from "./diagnosticArtifactStream.js";
9
+ export {
10
+ createCompactDiagnosticRunIdentity,
11
+ assertVerifiedCompactDiagnosticRunProvenance,
12
+ type CompactDiagnosticArtifactEvidence,
13
+ type CreateCompactDiagnosticRunIdentityInput,
14
+ type VerifiedCompactDiagnosticRunProvenance,
15
+ } from "./diagnosticCompactRun.js";
16
+ export * from "./diagnosticReplayWriter.js";
17
+ export * from "./diagnosticReplayReader.js";
8
18
  export * from "./bundle.js";
9
19
  export * from "./ave.js";
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Private incremental SHA-256, following FIPS 180-4 sections 4.1.2, 4.2.2,
3
+ * 5.1.1, 5.3.3 and 6.2.2. No I/O, dependencies or whole-message buffering.
4
+ * https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
5
+ * This implementation is not a NIST/FIPS-validated cryptographic module.
6
+ */
7
+ const ROUND = new Uint32Array([
8
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
9
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
10
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
11
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
12
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
13
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
14
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
15
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
16
+ ]);
17
+ const rotate = (value: number, count: number) => (value >>> count) | (value << (32 - count));
18
+
19
+ /** Internal state never escapes; update consumes bytes synchronously. */
20
+ export function createSha256() {
21
+ const state = new Uint32Array([
22
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
23
+ ]);
24
+ const block = new Uint8Array(64);
25
+ const words = new Uint32Array(64);
26
+ let buffered = 0;
27
+ let byteLength = 0;
28
+ let finalized = false;
29
+
30
+ function compress() {
31
+ const view = new DataView(block.buffer);
32
+ for (let index = 0; index < 16; index++) words[index] = view.getUint32(index * 4, false);
33
+ for (let index = 16; index < 64; index++) {
34
+ const a = words[index - 15]!;
35
+ const b = words[index - 2]!;
36
+ const small0 = rotate(a, 7) ^ rotate(a, 18) ^ (a >>> 3);
37
+ const small1 = rotate(b, 17) ^ rotate(b, 19) ^ (b >>> 10);
38
+ words[index] = (words[index - 16]! + small0 + words[index - 7]! + small1) >>> 0;
39
+ }
40
+ let a = state[0]!,
41
+ b = state[1]!,
42
+ c = state[2]!,
43
+ d = state[3]!;
44
+ let e = state[4]!,
45
+ f = state[5]!,
46
+ g = state[6]!,
47
+ h = state[7]!;
48
+ for (let index = 0; index < 64; index++) {
49
+ const large1 = rotate(e, 6) ^ rotate(e, 11) ^ rotate(e, 25);
50
+ const choose = (e & f) ^ (~e & g);
51
+ const t1 = (h + large1 + choose + ROUND[index]! + words[index]!) >>> 0;
52
+ const large0 = rotate(a, 2) ^ rotate(a, 13) ^ rotate(a, 22);
53
+ const majority = (a & b) ^ (a & c) ^ (b & c);
54
+ const t2 = (large0 + majority) >>> 0;
55
+ h = g;
56
+ g = f;
57
+ f = e;
58
+ e = (d + t1) >>> 0;
59
+ d = c;
60
+ c = b;
61
+ b = a;
62
+ a = (t1 + t2) >>> 0;
63
+ }
64
+ const completed = [a, b, c, d, e, f, g, h];
65
+ for (let index = 0; index < 8; index++)
66
+ state[index] = (state[index]! + completed[index]!) >>> 0;
67
+ }
68
+
69
+ return {
70
+ update(bytes: Uint8Array): void {
71
+ if (finalized) throw new Error("SHA-256 state is finalized");
72
+ if (!Number.isSafeInteger(byteLength + bytes.byteLength))
73
+ throw new RangeError("SHA-256 byte length exceeds the safe integer range");
74
+ byteLength += bytes.byteLength;
75
+ let offset = 0;
76
+ while (offset < bytes.byteLength) {
77
+ const count = Math.min(64 - buffered, bytes.byteLength - offset);
78
+ block.set(bytes.subarray(offset, offset + count), buffered);
79
+ buffered += count;
80
+ offset += count;
81
+ if (buffered === 64) {
82
+ compress();
83
+ buffered = 0;
84
+ }
85
+ }
86
+ },
87
+ digest(): string {
88
+ if (finalized) throw new Error("SHA-256 state is finalized");
89
+ finalized = true;
90
+ block[buffered++] = 0x80;
91
+ block.fill(0, buffered);
92
+ if (buffered > 56) {
93
+ compress();
94
+ block.fill(0);
95
+ }
96
+ const view = new DataView(block.buffer);
97
+ // Split the bit length before multiplying: exact for every safe byte length.
98
+ view.setUint32(56, Math.floor(byteLength / 0x20000000), false);
99
+ view.setUint32(60, (byteLength % 0x20000000) * 8, false);
100
+ compress();
101
+ const hex = Array.from(state, (word) => word.toString(16).padStart(8, "0")).join("");
102
+ block.fill(0);
103
+ words.fill(0);
104
+ state.fill(0);
105
+ return hex;
106
+ },
107
+ };
108
+ }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const COMPLIANCE_PACKAGE_VERSION = "0.6.1";
1
+ export const COMPLIANCE_PACKAGE_VERSION = "0.7.0";