diff --git a/src/domain/analysisProfile.ts b/src/domain/analysisProfile.ts index f6e6e00047..590186cf35 100644 --- a/src/domain/analysisProfile.ts +++ b/src/domain/analysisProfile.ts @@ -1,8 +1,6 @@ -import { createHash } from "node:crypto"; - -import canonicalize from "canonicalize"; import { z } from "zod"; +import { digestCanonicalValue } from "./canonicalDigest.js"; import { jsonObjectSchema, type JsonValue } from "./jsonValue.js"; import { digestSchema } from "./../domain/digests.js"; @@ -65,11 +63,4 @@ export const analysisProfilesEqual = ( const profileDigest = ( profile: z.infer, -): string => createHash("sha256").update(canonicalJson(profile)).digest("hex"); - -const canonicalJson = (value: JsonValue): string => { - const encoded = canonicalize(value); - if (encoded === undefined) - throw new TypeError("RFC 8785 canonicalization rejected analysis profile"); - return encoded; -}; +): string => digestCanonicalValue(profile, "Analysis profile"); diff --git a/src/domain/completionLedgerGeneration.ts b/src/domain/completionLedgerGeneration.ts index c52da3f455..7660ac99af 100644 --- a/src/domain/completionLedgerGeneration.ts +++ b/src/domain/completionLedgerGeneration.ts @@ -1,8 +1,6 @@ -import { createHash } from "node:crypto"; - -import canonicalize from "canonicalize"; import { z } from "zod"; +import { digestCanonicalValue } from "./canonicalDigest.js"; import { IDENTIFIER_PATTERN } from "./stringPatterns.js"; import { compareAsciiStrings, @@ -125,19 +123,9 @@ const completionManifestObjectSchema = z.strictObject({ }); type CompletionManifestValue = z.infer; -const canonicalJson = (value: unknown): string => { - const serialized = canonicalize(value); - if (serialized === undefined) - throw new TypeError( - "RFC 8785 canonicalization rejected completion metadata", - ); - return serialized; -}; - const computeManifestId = ( manifest: Omit, -): string => - `ecm_${createHash("sha256").update(canonicalJson(manifest)).digest("hex")}`; +): string => `ecm_${digestCanonicalValue(manifest, "Completion metadata")}`; const manifestIssues = ( manifest: CompletionManifestValue, diff --git a/src/domain/evidenceCompletionLedger.ts b/src/domain/evidenceCompletionLedger.ts index f725983a97..4037f1c9a1 100644 --- a/src/domain/evidenceCompletionLedger.ts +++ b/src/domain/evidenceCompletionLedger.ts @@ -1,8 +1,6 @@ -import { createHash } from "node:crypto"; - -import canonicalize from "canonicalize"; import { z } from "zod"; +import { digestCanonicalValue } from "./canonicalDigest.js"; import { IDENTIFIER_PATTERN } from "./stringPatterns.js"; import { prefixedDigestSchema } from "./../domain/digests.js"; import { @@ -79,21 +77,9 @@ const summarize = ( }; }; -const canonicalJson = (value: unknown): string => { - const serialized = canonicalize(value); - if (serialized === undefined) - throw new TypeError( - "RFC 8785 canonicalization rejected the completion ledger", - ); - return serialized; -}; - const computeLedgerId = ( records: readonly EvidenceCompletionRecord[], -): string => - `ecl_${createHash("sha256") - .update(canonicalJson({ records })) - .digest("hex")}`; +): string => `ecl_${digestCanonicalValue({ records }, "Completion ledger")}`; const ledgerIssues = ( ledger: EvidenceCompletionLedgerValue, diff --git a/src/domain/residualUnknown.ts b/src/domain/residualUnknown.ts index e5db1cc549..e42f77c209 100644 --- a/src/domain/residualUnknown.ts +++ b/src/domain/residualUnknown.ts @@ -1,7 +1,5 @@ -import { createHash } from "node:crypto"; - -import canonicalize from "canonicalize"; import { z } from "zod"; +import { digestCanonicalValue } from "./canonicalDigest.js"; import { compareUnicodeCodePoints, compositeKey, @@ -26,18 +24,17 @@ const stableUnknownId = ( scopeDigest: string | null, comparisonConclusionScope?: z.infer, ): string => - `unk_${createHash("sha256") - .update( - canonicalJson({ - domain: domain.trim(), - question: question.replace(/\s+/gu, " ").trim(), - scope_digest: scopeDigest, - ...(comparisonConclusionScope === undefined - ? {} - : { comparison_conclusion_scope: comparisonConclusionScope }), - }), - ) - .digest("hex")}`; + `unk_${digestCanonicalValue( + { + domain: domain.trim(), + question: question.replace(/\s+/gu, " ").trim(), + scope_digest: scopeDigest, + ...(comparisonConclusionScope === undefined + ? {} + : { comparison_conclusion_scope: comparisonConclusionScope }), + }, + "Unknown identity", + )}`; const probeSchema = z.strictObject({ operation: z.string().min(1), @@ -385,13 +382,7 @@ const computeRevisionDigest = ( const { revision_digest: _revisionDigest, ...semantic } = "revision_digest" in value ? value : { ...value, revision_digest: "" }; void _revisionDigest; - return createHash("sha256").update(canonicalJson(semantic)).digest("hex"); -}; - -const canonicalJson = (value: unknown): string => { - const serialized = canonicalize(value); - if (serialized === undefined) throw new TypeError("Unknown identity failed"); - return serialized; + return digestCanonicalValue(semantic, "Unknown identity"); }; const sortedUnique = (values: readonly string[]): string[] =>