{"version":3,"file":"EddsaJcs2022Cryptosuite.mjs","names":[],"sources":["../../../../../src/modules/w3c-di/cryptosuites/eddsa-jcs-2022/EddsaJcs2022Cryptosuite.ts"],"sourcesContent":["import { canonicalizeEx } from 'json-canonicalize'\n\nimport type { AgentContext } from '../../../../agent/context'\nimport { Hasher } from '../../../../crypto'\nimport { asArray, MultiBaseEncoder, TypedArrayEncoder } from '../../../../utils'\nimport { isObject } from '../../../../utils/object'\nimport { KeyManagementApi } from '../../../kms'\nimport { isXsdDateTimeStamp } from '../../proof-processing/iso8601Datetime'\nimport { publicJwkFromVerificationMethodId, publicKeyIdFromVerificationMethodId } from '../../proof-processing/keyUtils'\nimport { omitUndefinedFields } from '../../proof-processing/normalization'\nimport { W3cDataIntegrityProcessingError, W3cDataIntegrityProcessingErrorCode } from '../../W3cDataIntegrityError'\nimport type {\n  W3cDataIntegrityCryptosuiteProof,\n  W3cDataIntegrityCryptosuiteProofOptions,\n  W3cDataIntegrityUnsecuredDocument,\n} from '../../W3cDataIntegrityProof'\nimport type {\n  W3cDataIntegrityCryptosuite,\n  W3cDataIntegrityProofVerificationInput,\n  W3cDataIntegrityProofVerificationResult,\n} from '../types'\n\nexport class EddsaJcs2022Cryptosuite implements W3cDataIntegrityCryptosuite {\n  public readonly cryptosuite = 'eddsa-jcs-2022'\n  private keyManagementApi: KeyManagementApi\n  private agentContext: AgentContext\n\n  public constructor(agentContext: AgentContext) {\n    this.agentContext = agentContext\n    this.keyManagementApi = agentContext.dependencyManager.resolve(KeyManagementApi)\n  }\n\n  private canonicalizeJcsStrict(value: unknown) {\n    const normalized = omitUndefinedFields(value)\n    assertJcsInput(normalized)\n    return canonicalizeEx(normalized, {\n      allowCircular: false,\n      filterUndefined: true,\n      undefinedInArrayToNull: false,\n    })\n  }\n\n  /*\n   * Spec: VC DI EdDSA v1.0 §§3.3.1\n   * https://www.w3.org/TR/vc-di-eddsa/#create-proof-eddsa-jcs-2022\n   */\n  public async createProof(\n    unsecuredDocument: W3cDataIntegrityUnsecuredDocument,\n    options: W3cDataIntegrityCryptosuiteProofOptions\n  ): Promise<W3cDataIntegrityCryptosuiteProof> {\n    // Boundary contract: callers must pass DataIntegrityProof + eddsa-jcs-2022 options.\n    // W3cDataIntegrityProofService is the normal enforcement gate, but this guard protects\n    // direct callers as well and keeps failures close to cryptosuite entry points.\n    this.assertProofTypeAndCryptosuite(options, W3cDataIntegrityProcessingErrorCode.ProofGenerationError, 'createProof')\n\n    const proof: W3cDataIntegrityCryptosuiteProofOptions = { ...options } // 1\n\n    if ('@context' in unsecuredDocument) {\n      proof['@context'] = unsecuredDocument['@context']\n    } // 2\n\n    const proofConfig = this.proofConfiguration(proof) // 3\n    const transformedDocument = this.transformation(unsecuredDocument, options) // 4\n    const hashData = this.hashing(transformedDocument, proofConfig) // 5\n    const proofBytes = await this.proofSerialization(hashData, options) // 6\n    const proofValue = MultiBaseEncoder.encode(proofBytes, 'base58btc') // 7\n\n    return {\n      ...proof,\n      proofValue,\n    } // 8\n  }\n\n  /*\n   * Spec: VC DI EdDSA v1.0 §§3.3.2\n   * https://www.w3.org/TR/vc-di-eddsa/#verify-proof-eddsa-jcs-2022\n   */\n  public async verifyProof(\n    input: W3cDataIntegrityProofVerificationInput\n  ): Promise<W3cDataIntegrityProofVerificationResult> {\n    const { unsecuredDocument: securedDocument, proof } = input\n    const unsecuredDocument: W3cDataIntegrityUnsecuredDocument = { ...securedDocument } // 1\n    const { proofValue, ...proofOptions } = proof // 2\n\n    // Boundary contract: when verifyProof is called directly, validate proof suite\n    // identity before running cryptographic verification.\n    this.assertProofTypeAndCryptosuite(\n      proofOptions,\n      W3cDataIntegrityProcessingErrorCode.ProofVerificationError,\n      'verifyProof'\n    )\n\n    const proofBytes = MultiBaseEncoder.decode(proofValue).data // 3\n\n    if ('@context' in proofOptions) {\n      // 4\n      const proofContext = asArray(proofOptions['@context'])\n      const documentContext = asArray(unsecuredDocument['@context'])\n\n      const hasMatchingContext =\n        documentContext.length >= proofContext.length &&\n        proofContext.every((value, index) => documentContext[index] === value) // 4.1\n\n      if (!hasMatchingContext) {\n        return {\n          verified: false,\n          verifiedDocument: null,\n        } // 4.1\n      }\n\n      unsecuredDocument['@context'] = proofOptions['@context'] // 4.2\n    }\n\n    const transformedDocument = this.transformation(unsecuredDocument, proofOptions) // 5\n    const proofConfig = this.proofConfiguration(proofOptions) // 6\n    const hashData = this.hashing(transformedDocument, proofConfig) // 7\n    const verified = await this.proofVerification(hashData, proofBytes, proofOptions) // 8\n\n    return {\n      verified,\n      verifiedDocument: verified ? unsecuredDocument : null,\n    } // 9\n  }\n\n  /*\n   * Spec: VC DI EdDSA v1.0 §§3.3.3\n   * https://www.w3.org/TR/vc-di-eddsa/#transformation-eddsa-jcs-2022\n   */\n  public transformation(\n    unsecuredDocument: W3cDataIntegrityUnsecuredDocument,\n    proofOptions: W3cDataIntegrityCryptosuiteProofOptions\n  ) {\n    if (proofOptions.type !== 'DataIntegrityProof' || proofOptions.cryptosuite !== 'eddsa-jcs-2022') {\n      const err = `Proof type must be 'DataIntegrityProof' AND cryptosuite must be 'eddsa-jcs-2022'`\n      throw new W3cDataIntegrityProcessingError(W3cDataIntegrityProcessingErrorCode.ProofTransformationError, err)\n    } // 1\n\n    const canonicalDocument = this.canonicalizeJcsStrict(unsecuredDocument) // 2\n    return canonicalDocument // 3\n  }\n\n  /*\n   * Spec: VC DI EdDSA v1.0 §§3.3.4\n   * https://www.w3.org/TR/vc-di-eddsa/#hashing-eddsa-jcs-2022\n   */\n  public hashing(transformedDocument: string, canonicalProofConfig: string) {\n    const transformedDocumentHash = Hasher.hash(TypedArrayEncoder.fromUtf8String(transformedDocument), 'sha-256') // 1\n    const proofConfigHash = Hasher.hash(TypedArrayEncoder.fromUtf8String(canonicalProofConfig), 'sha-256') // 2\n    const hashData = new Uint8Array(64) // 3 create empty 64-byte array\n    hashData.set(proofConfigHash, 0) // 3 append proofConfigHash from 0-31\n    hashData.set(transformedDocumentHash, 32) // 3 append transformedDocumentHash from 32-63\n    return hashData // 4\n  }\n\n  /*\n   * Spec: VC DI EdDSA v1.0 §§3.3.5\n   * https://www.w3.org/TR/vc-di-eddsa/#proof-configuration-eddsa-jcs-2022\n   */\n  public proofConfiguration(proofOptions: W3cDataIntegrityCryptosuiteProofOptions) {\n    const proofConfig = { ...proofOptions } // 1\n\n    if (proofConfig.type !== 'DataIntegrityProof' || proofConfig.cryptosuite !== 'eddsa-jcs-2022') {\n      const err = `Proof type must be 'DataIntegrityProof' AND cryptosuite must be 'eddsa-jcs-2022'`\n      throw new W3cDataIntegrityProcessingError(W3cDataIntegrityProcessingErrorCode.ProofGenerationError, err)\n    }\n\n    if (typeof proofConfig.created === 'string' && !isXsdDateTimeStamp(proofConfig.created)) {\n      const err = `Proof created must be a valid dateTimeStamp. Received '${proofConfig.created}'`\n      throw new W3cDataIntegrityProcessingError(W3cDataIntegrityProcessingErrorCode.ProofGenerationError, err)\n    }\n\n    const canonicalProofConfig = this.canonicalizeJcsStrict(proofConfig) // 4\n    return canonicalProofConfig // 5\n  }\n\n  /*\n   * Spec: VC DI EdDSA v1.0 §§3.3.6\n   * https://www.w3.org/TR/vc-di-eddsa/#proof-serialization-eddsa-jcs-2022\n   */\n  public async proofSerialization(hashData: Uint8Array, options: W3cDataIntegrityCryptosuiteProofOptions) {\n    // Caller (W3cDataIntegrityProofService) is responsible for required-member and suite-shape validation before invocation.\n    // This method intentionally focuses on §3.3.6 signing semantics only.\n\n    const verificationMethod = options.verificationMethod\n    const keyId = await publicKeyIdFromVerificationMethodId(this.agentContext, verificationMethod) // 1\n    const signResult = await this.keyManagementApi.sign({\n      keyId,\n      algorithm: 'EdDSA',\n      data: hashData,\n    })\n    const proofBytes = signResult.signature // 2\n    if (proofBytes.length !== 64) {\n      const err = `EdDSA signature must be exactly 64 bytes, got ${proofBytes.length}`\n      throw new W3cDataIntegrityProcessingError(W3cDataIntegrityProcessingErrorCode.ProofGenerationError, err)\n    } // 2\n    return proofBytes // 3\n  }\n\n  /*\n   * Spec: VC DI EdDSA v1.0 §§3.3.7\n   * https://www.w3.org/TR/vc-di-eddsa/#proof-verification-eddsa-jcs-2022\n   */\n  public async proofVerification(\n    hashData: Uint8Array,\n    proofBytes: Uint8Array,\n    options: W3cDataIntegrityCryptosuiteProofOptions\n  ) {\n    const verificationMethod = options.verificationMethod\n    const publicKeyBytes = await publicJwkFromVerificationMethodId(this.agentContext, verificationMethod) // 1\n    const verificationResult = await this.keyManagementApi.verify({\n      key: { publicJwk: publicKeyBytes.toJson() },\n      algorithm: 'EdDSA',\n      signature: proofBytes,\n      data: hashData,\n    }) // 2\n    return verificationResult.verified // 3\n  }\n\n  private assertProofTypeAndCryptosuite(\n    options: Partial<W3cDataIntegrityCryptosuiteProofOptions>,\n    errorCode: W3cDataIntegrityProcessingErrorCode,\n    caller: 'createProof' | 'verifyProof'\n  ) {\n    if (options.type !== 'DataIntegrityProof' || options.cryptosuite !== 'eddsa-jcs-2022') {\n      const err = `Proof type must be 'DataIntegrityProof' AND cryptosuite must be 'eddsa-jcs-2022'`\n      throw new W3cDataIntegrityProcessingError(errorCode, err)\n    }\n  }\n}\n\nfunction assertJcsInput(value: unknown, path = '$', seen = new WeakSet<object>()) {\n  if (value === undefined || typeof value === 'function' || typeof value === 'symbol' || typeof value === 'bigint') {\n    const err = `JCS canonicalization input contains unsupported value at ${path}`\n    throw new W3cDataIntegrityProcessingError(W3cDataIntegrityProcessingErrorCode.ProofTransformationError, err)\n  }\n\n  if (typeof value === 'number' && !Number.isFinite(value)) {\n    const err = `JCS canonicalization input contains non-finite number at ${path}`\n    throw new W3cDataIntegrityProcessingError(W3cDataIntegrityProcessingErrorCode.ProofTransformationError, err)\n  }\n\n  if (Array.isArray(value)) {\n    for (let i = 0; i < value.length; i++) {\n      assertJcsInput(value[i], `${path}[${i}]`, seen)\n    }\n    return\n  }\n\n  if (isObject(value)) {\n    const objectValue = value as object\n    if (seen.has(objectValue)) {\n      const err = `JCS canonicalization input contains circular reference at ${path}`\n      throw new W3cDataIntegrityProcessingError(W3cDataIntegrityProcessingErrorCode.ProofTransformationError, err)\n    }\n\n    seen.add(objectValue)\n\n    for (const [key, nestedValue] of Object.entries(value as Record<string, unknown>)) {\n      assertJcsInput(nestedValue, `${path}.${key}`, seen)\n    }\n  }\n}\n"],"mappings":"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"}