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.

60 lines (53 loc) • 3.8 kB
#!/usr/bin/env node // Regenerates vectors/kav-1/* (known-answer vector 1) using the SAME @mdip/cipher calls that // @mdip/keymaster addSignature()/verifySignature() use: sha256(JCS(obj)) -> secp256k1 ECDSA // (RFC 6979, low-S, compact r||s hex). Output is deterministic; re-running must produce no diff. // Usage: node vectors/generate.js (needs the kit's npm deps; verifying needs only openssl) import fs from 'node:fs'; import path from 'node:path'; import crypto from 'node:crypto'; import { fileURLToPath } from 'node:url'; import CipherNode from '@mdip/cipher/node'; const dir = path.join(path.dirname(fileURLToPath(import.meta.url)), 'kav-1'); fs.mkdirSync(dir, { recursive: true }); const cipher = new CipherNode(); const w = (f, data) => fs.writeFileSync(path.join(dir, f), data); // PUBLIC TEST KEY. Derived from a published label so anyone can re-derive it. Never use it for anything real. const LABEL = 'mdip-agent-kit kav-1 PUBLIC TEST KEY - never use for anything real'; const d = crypto.createHash('sha256').update(LABEL, 'utf8').digest(); const { publicJwk, privateJwk } = cipher.generateJwk(new Uint8Array(d)); // Example payload (application data, NOT the MDIP challenge wire format; see README). const payload = { kit: 'mdip-agent-kit', vector: 'kav-1', message: 'Known-answer vector for MDIP signed JSON. Non-empty on purpose.', nonce: '6b61762d312d6e6f6e63652d30303031', verifier: 'did:example:kav-1-verifier', validUntil: '2026-12-31T23:59:59.000Z', }; const canonical = cipher.canonicalizeJSON(payload); const hash = cipher.hashJSON(payload); const value = cipher.signHash(hash, privateJwk); if (!cipher.verifySig(hash, value, publicJwk)) throw new Error('self-check failed'); // Same shape as keymaster.addSignature() / `mdip-agent sign` output. Signer is a placeholder, not resolvable. const signed = { ...payload, signature: { signer: 'did:example:kav-1-signer', signed: '2026-10-26T00:00:00.000Z', hash, value } }; // Stock-tool encodings: SPKI PEM public key and DER ECDSA signature. const pub = crypto.createPublicKey({ key: { ...publicJwk }, format: 'jwk' }); const r = Buffer.from(value.slice(0, 64), 'hex'), s = Buffer.from(value.slice(64), '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(r), int(s)]); const der = Buffer.concat([Buffer.from([0x30, body.length]), body]); if (!crypto.verify('sha256', Buffer.from(canonical, 'utf8'), { key: pub, dsaEncoding: 'der' }, der)) throw new Error('node DER check failed'); w('test-key.json', JSON.stringify({ WARNING: 'PUBLIC TEST KEY - private part is published on purpose; never use it', label: LABEL, privateKeyHex: d.toString('hex'), publicJwk, privateJwk }, null, 2) + '\n'); w('pub.pem', pub.export({ type: 'spki', format: 'pem' })); w('payload.json', JSON.stringify(payload, null, 2) + '\n'); w('message.bin', canonical); // exact signed-over bytes: JCS(payload), UTF-8, no trailing newline w('message.sha256', hash + '\n'); w('signature.hex', value + '\n'); // what MDIP stores in signature.value (64-byte compact r||s) w('signature.der', der); w('signed.json', JSON.stringify(signed, null, 2) + '\n'); w('message-tampered.bin', canonical.replace('Non-empty', 'Non-emptY')); // negative case: must FAIL const sums = ['message.bin', 'message-tampered.bin', 'signature.der', 'pub.pem', 'signed.json'] .map(f => crypto.createHash('sha256').update(fs.readFileSync(path.join(dir, f))).digest('hex') + ' ' + f).join('\n') + '\n'; w('SHA256SUMS', sums); console.log(JSON.stringify({ dir, bytes: Buffer.byteLength(canonical), hash, value }, null, 2));