UNPKG

@credo-ts/core

Version:

<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1

144 lines (143 loc) • 7.43 kB
import { asArray } from "../../../../utils/array.mjs"; import { TypedArrayEncoder } from "../../../../utils/TypedArrayEncoder.mjs"; import { Hasher } from "../../../../crypto/hashes/Hasher.mjs"; import { MultiBaseEncoder } from "../../../../utils/MultiBaseEncoder.mjs"; import "../../../../utils/index.mjs"; import { KeyManagementApi } from "../../../kms/KeyManagementApi.mjs"; import "../../../kms/index.mjs"; import "../../../../crypto/index.mjs"; import { isObject } from "../../../../utils/object.mjs"; import { isXsdDateTimeStamp } from "../../proof-processing/iso8601Datetime.mjs"; import { publicJwkFromVerificationMethodId, publicKeyIdFromVerificationMethodId } from "../../proof-processing/keyUtils.mjs"; import { omitUndefinedFields } from "../../proof-processing/normalization.mjs"; import { W3cDataIntegrityProcessingError } from "../../W3cDataIntegrityError.mjs"; import { canonicalizeEx } from "json-canonicalize"; //#region src/modules/w3c-di/cryptosuites/eddsa-jcs-2022/EddsaJcs2022Cryptosuite.ts var EddsaJcs2022Cryptosuite = class { constructor(agentContext) { this.cryptosuite = "eddsa-jcs-2022"; this.agentContext = agentContext; this.keyManagementApi = agentContext.dependencyManager.resolve(KeyManagementApi); } canonicalizeJcsStrict(value) { const normalized = omitUndefinedFields(value); assertJcsInput(normalized); return canonicalizeEx(normalized, { allowCircular: false, filterUndefined: true, undefinedInArrayToNull: false }); } async createProof(unsecuredDocument, options) { this.assertProofTypeAndCryptosuite(options, "https://w3id.org/security#PROOF_GENERATION_ERROR", "createProof"); const proof = { ...options }; if ("@context" in unsecuredDocument) proof["@context"] = unsecuredDocument["@context"]; const proofConfig = this.proofConfiguration(proof); const transformedDocument = this.transformation(unsecuredDocument, options); const hashData = this.hashing(transformedDocument, proofConfig); const proofBytes = await this.proofSerialization(hashData, options); const proofValue = MultiBaseEncoder.encode(proofBytes, "base58btc"); return { ...proof, proofValue }; } async verifyProof(input) { const { unsecuredDocument: securedDocument, proof } = input; const unsecuredDocument = { ...securedDocument }; const { proofValue, ...proofOptions } = proof; this.assertProofTypeAndCryptosuite(proofOptions, "https://w3id.org/security#PROOF_VERIFICATION_ERROR", "verifyProof"); const proofBytes = MultiBaseEncoder.decode(proofValue).data; if ("@context" in proofOptions) { const proofContext = asArray(proofOptions["@context"]); const documentContext = asArray(unsecuredDocument["@context"]); if (!(documentContext.length >= proofContext.length && proofContext.every((value, index) => documentContext[index] === value))) return { verified: false, verifiedDocument: null }; unsecuredDocument["@context"] = proofOptions["@context"]; } const transformedDocument = this.transformation(unsecuredDocument, proofOptions); const proofConfig = this.proofConfiguration(proofOptions); const hashData = this.hashing(transformedDocument, proofConfig); const verified = await this.proofVerification(hashData, proofBytes, proofOptions); return { verified, verifiedDocument: verified ? unsecuredDocument : null }; } transformation(unsecuredDocument, proofOptions) { if (proofOptions.type !== "DataIntegrityProof" || proofOptions.cryptosuite !== "eddsa-jcs-2022") throw new W3cDataIntegrityProcessingError("https://w3id.org/security#PROOF_TRANSFORMATION_ERROR", `Proof type must be 'DataIntegrityProof' AND cryptosuite must be 'eddsa-jcs-2022'`); return this.canonicalizeJcsStrict(unsecuredDocument); } hashing(transformedDocument, canonicalProofConfig) { const transformedDocumentHash = Hasher.hash(TypedArrayEncoder.fromUtf8String(transformedDocument), "sha-256"); const proofConfigHash = Hasher.hash(TypedArrayEncoder.fromUtf8String(canonicalProofConfig), "sha-256"); const hashData = /* @__PURE__ */ new Uint8Array(64); hashData.set(proofConfigHash, 0); hashData.set(transformedDocumentHash, 32); return hashData; } proofConfiguration(proofOptions) { const proofConfig = { ...proofOptions }; if (proofConfig.type !== "DataIntegrityProof" || proofConfig.cryptosuite !== "eddsa-jcs-2022") throw new W3cDataIntegrityProcessingError("https://w3id.org/security#PROOF_GENERATION_ERROR", `Proof type must be 'DataIntegrityProof' AND cryptosuite must be 'eddsa-jcs-2022'`); if (typeof proofConfig.created === "string" && !isXsdDateTimeStamp(proofConfig.created)) { const err = `Proof created must be a valid dateTimeStamp. Received '${proofConfig.created}'`; throw new W3cDataIntegrityProcessingError("https://w3id.org/security#PROOF_GENERATION_ERROR", err); } return this.canonicalizeJcsStrict(proofConfig); } async proofSerialization(hashData, options) { const verificationMethod = options.verificationMethod; const keyId = await publicKeyIdFromVerificationMethodId(this.agentContext, verificationMethod); const proofBytes = (await this.keyManagementApi.sign({ keyId, algorithm: "EdDSA", data: hashData })).signature; if (proofBytes.length !== 64) { const err = `EdDSA signature must be exactly 64 bytes, got ${proofBytes.length}`; throw new W3cDataIntegrityProcessingError("https://w3id.org/security#PROOF_GENERATION_ERROR", err); } return proofBytes; } async proofVerification(hashData, proofBytes, options) { const verificationMethod = options.verificationMethod; const publicKeyBytes = await publicJwkFromVerificationMethodId(this.agentContext, verificationMethod); return (await this.keyManagementApi.verify({ key: { publicJwk: publicKeyBytes.toJson() }, algorithm: "EdDSA", signature: proofBytes, data: hashData })).verified; } assertProofTypeAndCryptosuite(options, errorCode, caller) { if (options.type !== "DataIntegrityProof" || options.cryptosuite !== "eddsa-jcs-2022") throw new W3cDataIntegrityProcessingError(errorCode, `Proof type must be 'DataIntegrityProof' AND cryptosuite must be 'eddsa-jcs-2022'`); } }; function assertJcsInput(value, path = "$", seen = /* @__PURE__ */ new WeakSet()) { if (value === void 0 || typeof value === "function" || typeof value === "symbol" || typeof value === "bigint") { const err = `JCS canonicalization input contains unsupported value at ${path}`; throw new W3cDataIntegrityProcessingError("https://w3id.org/security#PROOF_TRANSFORMATION_ERROR", err); } if (typeof value === "number" && !Number.isFinite(value)) { const err = `JCS canonicalization input contains non-finite number at ${path}`; throw new W3cDataIntegrityProcessingError("https://w3id.org/security#PROOF_TRANSFORMATION_ERROR", err); } if (Array.isArray(value)) { for (let i = 0; i < value.length; i++) assertJcsInput(value[i], `${path}[${i}]`, seen); return; } if (isObject(value)) { const objectValue = value; if (seen.has(objectValue)) { const err = `JCS canonicalization input contains circular reference at ${path}`; throw new W3cDataIntegrityProcessingError("https://w3id.org/security#PROOF_TRANSFORMATION_ERROR", err); } seen.add(objectValue); for (const [key, nestedValue] of Object.entries(value)) assertJcsInput(nestedValue, `${path}.${key}`, seen); } } //#endregion export { EddsaJcs2022Cryptosuite }; //# sourceMappingURL=EddsaJcs2022Cryptosuite.mjs.map