@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
JavaScript
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