zimakri / tree / src/did.js ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
// did:key for an Ed25519 public key (multicodec 0xed01, multibase base58btc, prefix z). Pure, no network.
import { generateKeyPairSync, createPublicKey } from 'node:crypto';

const B58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
export function base58btc(bytes) {
  let n = 0n;
  for (const b of bytes) n = (n << 8n) | BigInt(b);
  let out = '';
  while (n > 0n) { out = B58[Number(n % 58n)] + out; n /= 58n; }
  for (const b of bytes) { if (b !== 0) break; out = '1' + out; }
  return out;
}
export function base58decode(s) {
  let n = 0n;
  for (const c of s) { const i = B58.indexOf(c); if (i < 0) throw new Error('not base58'); n = n * 58n + BigInt(i); }
  const bytes = [];
  while (n > 0n) { bytes.unshift(Number(n & 0xffn)); n >>= 8n; }
  for (const c of s) { if (c !== '1') break; bytes.unshift(0); }
  return Uint8Array.from(bytes);
}
/** Raw 32 byte Ed25519 public key from a KeyObject. */
export function rawPublicKey(publicKey) {
  const der = publicKey.export({ format: 'der', type: 'spki' });
  return new Uint8Array(der.subarray(der.length - 32));
}
export function didKeyFromPublic(raw) {
  if (raw.length !== 32) throw new Error('an Ed25519 public key is 32 bytes');
  return `did:key:z${base58btc(Uint8Array.from([0xed, 0x01, ...raw]))}`;
}
export function publicFromDidKey(did) {
  const m = /^did:key:z([1-9A-HJ-NP-Za-km-z]+)$/.exec(did);
  if (!m) throw new Error('not a did:key');
  const b = base58decode(m[1]);
  if (b[0] !== 0xed || b[1] !== 0x01 || b.length !== 34) throw new Error('not an Ed25519 did:key');
  return b.subarray(2);
}
/** A fresh identity made on this machine. The private key stays a KeyObject; the caller decides where it is stored. */
export function newIdentity() {
  const { publicKey, privateKey } = generateKeyPairSync('ed25519');
  const raw = rawPublicKey(publicKey);
  return { did: didKeyFromPublic(raw), publicKey, privateKey };
}
export { createPublicKey };

agentgate-source: code mirror on Cloudflare Pages. All repos