UNPKG

mdip-agent-kit

Version:

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

46 lines (42 loc) • 3.27 kB
#!/usr/bin/env node // Second, independent-code check of the vectors using @mdip/cipher (what @mdip/keymaster and the // gatekeeper use): recomputes JCS bytes from the JSON files, compares to the committed .bin files, // and verifies each signature. Also checks the MDIP binding fields of the challenge fixture. // Usage: node vectors/verify-with-kit.js (after npm install; no network) import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import CipherNode from '@mdip/cipher/node'; const dir = path.dirname(fileURLToPath(import.meta.url)); const c = new CipherNode(); const rd = f => fs.readFileSync(path.join(dir, f), 'utf8'); const js = f => JSON.parse(rd(f)); let fail = 0; const check = (cond, msg) => { console.log(`${cond ? 'ok ' : 'FAIL'} ${msg}`); if (!cond) fail = 1; }; const unsigned = o => { const x = JSON.parse(JSON.stringify(o)); delete x.signature; return x; }; // kav-1 const signed = js('kav-1/signed.json'); const key = js('kav-1/test-key.json').publicJwk; check(c.canonicalizeJSON(unsigned(signed)) === rd('kav-1/message.bin'), 'kav-1 message.bin == JCS(signed.json minus signature)'); check(c.hashJSON(unsigned(signed)) === signed.signature.hash, 'kav-1 signature.hash == sha256(JCS)'); check(c.verifySig(signed.signature.hash, signed.signature.value, key), 'kav-1 verifySig'); check(rd('kav-1/signature.hex').trim() === signed.signature.value, 'kav-1 signature.hex == signature.value'); // mdip-challenge-1 const dids = js('mdip-challenge-1/dids.json'); const op = k => js(`mdip-challenge-1/${k}.op.json`); const keys = { [dids['verifier-agent']]: op('verifier-agent').publicJwk, [dids['responder-agent']]: op('responder-agent').publicJwk }; for (const k of ['verifier-agent', 'challenge', 'responder-agent', 'response']) { const o = op(k); check(c.canonicalizeJSON(unsigned(o)) === rd(`mdip-challenge-1/${k}.message.bin`), `${k} message.bin == JCS(op minus signature)`); check(c.hashJSON(unsigned(o)) === o.signature.hash, `${k} signature.hash`); // agent create ops are self-signed with their own publicJwk (no signer DID yet); assets by their controller const signer = o.mdip.type === 'agent' ? (k === 'verifier-agent' ? dids['verifier-agent'] : dids['responder-agent']) : o.controller; check(c.verifySig(o.signature.hash, o.signature.value, o.mdip.type === 'agent' ? o.publicJwk : keys[signer]), `${k} signed by ${signer === dids['verifier-agent'] ? 'verifier' : 'responder'} key`); } const ch = op('challenge'), re = op('response'), vr = js('mdip-challenge-1/verify-response.json'); check(ch.controller === dids['verifier-agent'], 'challenge controller == verifier DID (binds verifier)'); check(re.controller === dids['responder-agent'] && re.data.encrypted.sender === re.controller, 'response controller == encrypted.sender == responder DID'); check(Date.parse(re.mdip.validUntil) <= Date.parse(ch.mdip.validUntil), 'response validUntil <= challenge validUntil (expiry)'); check(vr.challenge === dids.challenge && vr.responder === dids['responder-agent'] && vr.match === true && !!vr.responseNonce, 'decrypted response names the challenge DID, responder, match=true, has responseNonce'); console.log(fail ? 'VECTORS FAILED' : 'ALL VECTORS OK'); process.exit(fail);