import jsigs from 'jsonld-signatures'; const {purposes: {AssertionProofPurpose}} = jsigs; import * as Ed25519Multikey from '@digitalbazaar/ed25519-multikey'; import {DataIntegrityProof} from '@digitalbazaar/data-integrity'; import {cryptosuite as eddsaRdfc2022CryptoSuite} from '@digitalbazaar/eddsa-rdfc-2022-cryptosuite'; import fetch from 'node-fetch'; // Create an in-memory map of documents keyed by their URLs const documents = new Map(); // Define the addDocumentToLoader function function addDocumentToLoader({url, document}) { documents.set(url, { documentUrl: url, document, contextUrl: null }); } // Define the documentLoader that uses this map const documentLoader = async url => { // If the document is known, return it if (documents.has(url)) { return { contextUrl: null, documentUrl: url, document: documents.get(url).document }; } // Else, you may want to fallback to a default loader or throw an error if (url.startsWith('https://www.w3.org/2018/credentials/v1') || url.startsWith('https://w3id.org/security/suites/ed25519-2020/v1') || url.startsWith('https://w3id.org/security/data-integrity/v2') || url.startsWith('https://forge.etsi.org/rep/cim/NGSI-LD/') || url.startsWith('https://uri.etsi.org/ngsi-ld')) { return { contextUrl: null, // this is for a context via a link header document: await fetch(url).then(res => res.json()), // this is the actual document that was loaded documentUrl: url // this is the actual context URL after redirects }; } // If no match is found, throw an error throw new Error(`Document loader unable to load URL: ${url}`); } // create the JSON-LD document that should be signed let ngsilddoc = { "id": "urn:ngsi-ld:Store:002", "type": "Store", "address": { "type": "Property", "value": { "streetAddress": ["Tiger Street 4", "al"], "addressRegion": "Metropolis", "addressLocality": "Cat City", "postalCode": "42420" } }, "@context": "https://uri.etsi.org/ngsi-ld/primer/store-context.jsonld" }; // create the keypair to use when signing const controller = 'https://example.edu/issuers/565049'; const keyPair = await Ed25519Multikey.from({ '@context': 'https://w3id.org/security/multikey/v1', type: 'Multikey', controller, id: controller + '#z6MkwXG2WjeQnNxSoynSGYU8V9j3QzP3JSqhdmkHc6SaVWoT', publicKeyMultibase: 'z6MkwXG2WjeQnNxSoynSGYU8V9j3QzP3JSqhdmkHc6SaVWoT', secretKeyMultibase: 'zrv3rbPamVDGvrm7LkYPLWYJ35P9audujKKsWn3x29EUiGwwhdZQd' + '1iHhrsmZidtVALBQmhX3j9E5Fvx6Kr29DPt6LH' }); // export public key and add to document loader const publicKey = await keyPair.export({publicKey: true, includeContext: true}); addDocumentToLoader({url: publicKey.id, document: publicKey}); // create key's controller document const controllerDoc = { '@context': [ 'https://www.w3.org/ns/did/v1', 'https://w3id.org/security/multikey/v1' ], id: controller, assertionMethod: [publicKey] }; addDocumentToLoader({url: controllerDoc.id, document: controllerDoc}); // create suite const suite = new DataIntegrityProof({ signer: keyPair.signer(), cryptosuite: eddsaRdfc2022CryptoSuite }); // create signed credential const signeddoc = await jsigs.sign(ngsilddoc, { suite, purpose: new AssertionProofPurpose(), documentLoader }); console.log(JSON.stringify(signeddoc));