UNPKG

@tangle-js/ld-proofs

Version:

Linked Data Proofs on the Tangle. Powered by IOTA Identity & IOTA Streams

163 lines 12.7 kB
/* eslint-disable jsdoc/require-jsdoc */ // eslint-disable-next-line unicorn/prefer-node-protocol import bs58 from "bs58"; import * as crypto from "crypto"; import jsonld from "jsonld"; import LdProofError from "./errors/ldProofError.mjs"; import LdProofErrorNames from "./errors/ldProofErrorNames.mjs"; import { JsonCanonicalization } from "./helpers/jsonCanonicalization.mjs"; import JsonHelper from "./helpers/jsonHelper.mjs"; import { customLdContextLoader } from "./helpers/jsonLdHelper.mjs"; import ValidationHelper from "./helpers/validationHelper.mjs"; import { LdContextURL } from "./models/ldContextURL.mjs"; import { SignatureTypes } from "./models/signatureTypes.mjs"; import DidService from "./services/didService.mjs"; import SigningService from "./services/signingService.mjs"; /** * It allows to sign and verify messages using a Verification Method provided by a DID. * * It generates and verifies EdDSA (Ed25519) signatures. * */ export class IotaSigner { constructor(did, didDocument) { this._did = did; this._didDocument = didDocument; } get did() { return this._did; } /** * Creates a new signer associating it with a particular decentralized identity. * * @param did The DID that has the verification methods of the signer. * @param node The node. * @returns The newly created signer. */ static async create(did, node) { if (node && !ValidationHelper.url(node)) { throw new LdProofError(LdProofErrorNames.INVALID_NODE, "Node is not a URL"); } if (!ValidationHelper.did(did)) { throw new LdProofError(LdProofErrorNames.INVALID_DID, "Invalid DID"); } const didDoc = await DidService.resolve(node, did); return new IotaSigner(did, didDoc); } /** * Signs a string message using the Ed25519 signature algorithm. * * @param message The message. * @param options The signing options. * @returns The signature details including its value encoded in Base58. */ async sign(message, options) { let secret = options.secret; if (typeof options.secret === "string") { secret = bs58.decode(options.secret); } const request = { didDocument: this._didDocument, type: SignatureTypes.ED25519_2018, method: options.verificationMethod, secret: secret, message }; const result = await SigningService.sign(request); return result; } /** * Signs a JSON(-LD) document. * * @param doc The JSON(-LD) document as an object or as a string. * @param options The parameters to use to generate the signature. * @returns The JSON document including its corresponding Linked Data Signature. */ async signJson(doc, options) { if (options.signatureType === SignatureTypes.JCS_ED25519_2020) { return this.doSignJson(doc, options); } if (options.signatureType === SignatureTypes.ED25519_2018) { return this.doSignJsonLd(doc, options); } // Otherwise exception is thrown throw new LdProofError(LdProofErrorNames.NOT_SUPPORTED_SIGNATURE, `Only '${SignatureTypes.JCS_ED25519_2020}' and '${SignatureTypes.ED25519_2018}' are supported`); } /** * Signs a JSON document. * * @param doc The JSON document as an object or as a string. * @param options The parameters to use to generate the signature. * @returns The JSON document including its corresponding Linked Data Signature. */ async doSignJson(doc, options) { const docToBeSigned = JsonHelper.getDocument(doc); if (options.signatureType !== SignatureTypes.JCS_ED25519_2020) { throw new LdProofError(LdProofErrorNames.NOT_SUPPORTED_SIGNATURE, "Only the 'JcsEd25519Signature2020' is supported"); } const proof = { type: SignatureTypes.JCS_ED25519_2020, verificationMethod: `${this._didDocument.id()}#${options.verificationMethod}`, proofPurpose: "dataVerification", created: new Date().toISOString() }; // The canonicalization has to be performed over the whole object excluding the proof value docToBeSigned.proof = proof; // JSON Canonicalization Scheme const canonized = JsonCanonicalization.calculate(docToBeSigned); // We use SHA256 to calculate the digest as mandated by https://identity.foundation/JcsEd25519Signature2020/ const digest = crypto.createHash("sha256").update(canonized) .digest(); const signature = await this.sign(digest, options); // Finally restore the original object delete docToBeSigned.proof; return { proofValue: signature.signatureValue, ...proof }; } /** * Signs a JSON-LD document. * * @param doc The JSON-LD document as an object or as a string. * @param options The parameters to use to generate the signature. * @returns The Linked Data Signature represented as a Linked Data Proof. */ async doSignJsonLd(doc, options) { const docToBeSigned = JsonHelper.getJsonLdDocument(doc); if (options.signatureType !== SignatureTypes.ED25519_2018) { throw new LdProofError(LdProofErrorNames.NOT_SUPPORTED_SIGNATURE, "Only the 'Ed25519Signature2018' is supported"); } const canonizeOptions = { algorithm: "URDNA2015", format: "application/n-quads", documentLoader: customLdContextLoader }; // RDF canonization algorithm over the document const canonized = await jsonld.canonize(docToBeSigned, canonizeOptions); const docHash = crypto // eslint-disable-next-line @typescript-eslint/no-unsafe-argument .createHash("sha512").update(canonized) .digest(); const proofOptionsLd = { "@context": LdContextURL.W3C_SECURITY, verificationMethod: `${this._didDocument.id()}#${options.verificationMethod}`, created: new Date().toISOString() }; const proofOptionsCanonized = await jsonld.canonize(proofOptionsLd, canonizeOptions); const proofOptionsHash = crypto // eslint-disable-next-line @typescript-eslint/no-unsafe-argument .createHash("sha512").update(proofOptionsCanonized) .digest(); const finalHash = Buffer.concat([docHash, proofOptionsHash]); const signature = await this.sign(finalHash, options); return { type: SignatureTypes.ED25519_2018, verificationMethod: proofOptionsLd.verificationMethod, proofValue: signature.signatureValue, proofPurpose: "dataVerification", created: proofOptionsLd.created }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW90YVNpZ25lci5tanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW90YVNpZ25lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx3Q0FBd0M7QUFHeEMsd0RBQXdEO0FBQ3hELE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUN4QixPQUFPLEtBQUssTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUNqQyxPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxZQUFZLE1BQU0sdUJBQXVCLENBQUM7QUFDakQsT0FBTyxpQkFBaUIsTUFBTSw0QkFBNEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN0RSxPQUFPLFVBQVUsTUFBTSxzQkFBc0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMvRCxPQUFPLGdCQUFnQixNQUFNLDRCQUE0QixDQUFDO0FBTTFELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDekQsT0FBTyxVQUFVLE1BQU0sdUJBQXVCLENBQUM7QUFDL0MsT0FBTyxjQUFjLE1BQU0sMkJBQTJCLENBQUM7QUFHdkQ7Ozs7O0dBS0c7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUtuQixZQUFvQixHQUFXLEVBQUUsV0FBd0I7UUFDckQsSUFBSSxDQUFDLElBQUksR0FBRyxHQUFHLENBQUM7UUFDaEIsSUFBSSxDQUFDLFlBQVksR0FBRyxXQUFXLENBQUM7SUFDcEMsQ0FBQztJQUVELElBQVcsR0FBRztRQUNWLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQztJQUNyQixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ksTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBVyxFQUFFLElBQWE7UUFDakQsSUFBSSxJQUFJLElB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