UNPKG

mdip-agent-kit

Version:

Give any AI agent its own MDIP (did:mdip) identity on the SELF (https://selfid.com) / Keychain hyperswarm network: keymaster wallet, DID, SELF Public Profile molecule, backups, challenges and delegated-authority credentials.

70 lines (67 loc) • 4.46 kB
#!/usr/bin/env node // Captures a REAL MDIP challenge -> response round trip as a fixture (vectors/mdip-challenge-1/). // Creates two clearly-named throwaway identities in temp homes (no secrets are written to the repo), // runs createChallenge / createResponse / verifyResponse through this kit, then exports the signed // create operations from the gatekeeper and writes stock-tool encodings of each signature. // Usage: MDIP_GATEKEEPER_URL=http://localhost:4224 node vectors/make-mdip-fixture.js // NOTE: like `npm test`, this publishes throwaway DIDs to the configured registry. import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import crypto from 'node:crypto'; import { fileURLToPath } from 'node:url'; import CipherNode from '@mdip/cipher/node'; import { openAgent, waitForDid } from '../src/index.js'; const out = path.join(path.dirname(fileURLToPath(import.meta.url)), 'mdip-challenge-1'); fs.rmSync(out, { recursive: true, force: true }); fs.mkdirSync(out, { recursive: true }); const cipher = new CipherNode(); const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'kav-fixture-')); const w = (f, data) => fs.writeFileSync(path.join(out, f), data); const der = hex => { const int = b => { let i = 0; while (i < b.length - 1 && b[i] === 0) i++; b = b.subarray(i); if (b[0] & 0x80) b = Buffer.concat([Buffer.from([0]), b]); return Buffer.concat([Buffer.from([0x02, b.length]), b]); }; const body = Buffer.concat([int(Buffer.from(hex.slice(0, 64), 'hex')), int(Buffer.from(hex.slice(64), 'hex'))]); return Buffer.concat([Buffer.from([0x30, body.length]), body]); }; try { const verifier = await openAgent({ home: path.join(tmp, 'v'), name: 'mdip-agent-kit-kav-verifier', create: true }); const responder = await openAgent({ home: path.join(tmp, 'r'), name: 'mdip-agent-kit-kav-responder', create: true }); const challengeDid = await verifier.createChallenge({}); // no credentials requested await waitForDid(verifier.keymaster, challengeDid); const responseDid = await responder.respondToChallenge(challengeDid); await waitForDid(verifier.keymaster, responseDid); const result = await verifier.verifyResponse(responseDid); if (!result.match) throw new Error('verifyResponse did not match'); const gk = verifier.keymaster.gatekeeper; const names = { 'verifier-agent': verifier.did, 'responder-agent': responder.did, challenge: challengeDid, response: responseDid }; const exported = await gk.exportDIDs(Object.values(names)); const ops = {}; const dids = {}; const pubs = {}; Object.keys(names).forEach((k, i) => { ops[k] = exported[i][0].operation; dids[k] = names[k]; }); for (const k of ['verifier-agent', 'responder-agent']) { pubs[names[k]] = crypto.createPublicKey({ key: { ...ops[k].publicJwk }, format: 'jwk' }).export({ type: 'spki', format: 'pem' }); w(`${k}.pub.pem`, pubs[names[k]]); } const sums = []; for (const [k, op] of Object.entries(ops)) { const copy = JSON.parse(JSON.stringify(op)); delete copy.signature; const msg = cipher.canonicalizeJSON(copy); const hash = cipher.hashMessage(msg); if (hash !== op.signature.hash) throw new Error(`${k}: hash mismatch`); // Agent create ops are self-signed (key in op.publicJwk); asset ops are signed by their controller agent. const signerKey = op.mdip.type === 'agent' ? op.publicJwk : ops[op.controller === verifier.did ? 'verifier-agent' : 'responder-agent'].publicJwk; if (!cipher.verifySig(hash, op.signature.value, signerKey)) throw new Error(`${k}: sig fails`); w(`${k}.op.json`, JSON.stringify(op, null, 2) + '\n'); w(`${k}.message.bin`, msg); w(`${k}.sig.der`, der(op.signature.value)); sums.push(`${k}.message.bin`, `${k}.sig.der`); } w('dids.json', JSON.stringify(dids, null, 2) + '\n'); // The decrypted response as seen by the verifier (contents are not secret; throwaway identities). w('verify-response.json', JSON.stringify(result, null, 2) + '\n'); w('SHA256SUMS', sums.concat(['verifier-agent.pub.pem', 'responder-agent.pub.pem']) .map(f => crypto.createHash('sha256').update(fs.readFileSync(path.join(out, f))).digest('hex') + ' ' + f).join('\n') + '\n'); console.log(JSON.stringify({ out, dids, match: result.match }, null, 2)); } finally { fs.rmSync(tmp, { recursive: true, force: true }); } process.exit(0);