@toon-protocol/townhouse 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/wallet/rsa-from-seed.ts"],"sourcesContent":["/**\n * rsa-from-seed — CVE-free replacement for human-crypto-keys RSA derivation.\n *\n * Produces byte-for-byte identical RSA-4096 keys as\n * `human-crypto-keys.getKeyPairFromSeed(seed, {id:'rsa', modulusLength:4096},\n * {privateKeyFormat:'pkcs1-pem'})`.\n *\n * Algorithm (preserved exactly to maintain golden test vectors):\n * 1. HMAC-DRBG(SHA-256, entropy=seed, nonce=[], pers=[])\n * Re-implemented with @noble/hashes (already a workspace dep).\n * Byte-for-byte identical to hmac-drbg@1.0.1 used by human-crypto-keys.\n * 2. node-forge 1.3.3 (CVE-free) PRIMEINC prime search driven by (1).\n * Identical to node-forge 0.8.5 because jsbn.js and the PRIMEINC loop\n * are unchanged between versions (verified by diff).\n * 3. Export private key as PKCS#1 PEM string.\n *\n * Why not Node.js crypto.generateKeyPair?\n * It uses OpenSSL's system CSPRNG and cannot be seeded deterministically.\n *\n * Performance: same as before (~5–30s for RSA-4096 on a 2024 desktop).\n * The on-disk ar-cache.ts already amortises this cost after first derivation.\n */\n\nimport { hmac } from '@noble/hashes/hmac';\nimport { sha256 } from '@noble/hashes/sha256';\n\n// ── HMAC-DRBG (SP 800-90A, SHA-256 variant) ─────────────────────────────────\n//\n// Replicates hmac-drbg@1.0.1 with one key behavioural detail:\n// generate(n) in hmac-drbg discards leftover bytes and calls _update()\n// AFTER each call (not per 32-byte V-block). Our getBytesSync() mirrors\n// that exact behaviour: generate fresh V-chain on every call, discard\n// surplus, then do a 2-step _update (no seed data ⇒ only K/V steps 1+2).\n\nfunction hmacSha256(key: Uint8Array, ...parts: Uint8Array[]): Uint8Array {\n const h = hmac.create(sha256, key);\n for (const p of parts) h.update(p);\n return h.digest();\n}\n\nconst BYTE_00 = new Uint8Array([0x00]);\nconst BYTE_01 = new Uint8Array([0x01]);\n\n/**\n * Create a HMAC-DRBG PRNG that returns forge-compatible \"binary strings\"\n * (Latin-1 encoded byte strings used internally by node-forge).\n *\n * @param seedBytes 32-byte BIP-32 sub-seed (raw entropy; hex-decoding step\n * from human-crypto-keys is a no-op and not replicated).\n * @param rawEncode `forge.util.binary.raw.encode` — converts Uint8Array to\n * forge's internal binary string format.\n */\nfunction makeHmacDrbgPrng(\n seedBytes: Uint8Array,\n rawEncode: (bytes: Uint8Array) => string\n): { getBytesSync: (n: number) => string } {\n // Initialise K and V per SP 800-90A §10.1.2.3\n let K = new Uint8Array(32).fill(0x00);\n let V = new Uint8Array(32).fill(0x01);\n\n // _update(seed) — seeding phase (seed data present → full 4-step update)\n K = hmacSha256(K, V, BYTE_00, seedBytes);\n V = hmacSha256(K, V);\n K = hmacSha256(K, V, BYTE_01, seedBytes);\n V = hmacSha256(K, V);\n\n return {\n getBytesSync(size: number): string {\n // Generate V-chain until we have enough bytes (same as hmac-drbg's\n // `while (temp.length < len) { V = HMAC(K, V); temp.concat(V); }`).\n // Surplus bytes beyond `size` are discarded on purpose — matches the\n // original `temp.slice(0, len)` behaviour that ensures determinism.\n const chunks: Uint8Array[] = [];\n let total = 0;\n while (total < size) {\n V = hmacSha256(K, V);\n chunks.push(V);\n total += V.length;\n }\n // Flatten and slice\n const flat = new Uint8Array(total);\n let offset = 0;\n for (const c of chunks) {\n flat.set(c, offset);\n offset += c.length;\n }\n const out = flat.slice(0, size);\n\n // _update(undefined) — post-generate state update (2-step only,\n // since there is no additional data; mirrors the `if(!seed) return`\n // branch in hmac-drbg._update).\n K = hmacSha256(K, V, BYTE_00);\n V = hmacSha256(K, V);\n\n return rawEncode(out);\n },\n };\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\n/**\n * Derive a deterministic RSA-4096 PKCS#1 PEM private key from a 32-byte seed.\n *\n * Identical output to:\n * `human-crypto-keys.getKeyPairFromSeed(seed, {id:'rsa', modulusLength:4096},\n * {privateKeyFormat:'pkcs1-pem'}).privateKey`\n *\n * @param seed 32-byte BIP-32 sub-seed. Zeroed by caller after this returns.\n * @returns PKCS#1 PEM-encoded RSA-4096 private key string.\n */\nexport async function rsaPrivateKeyPemFromSeed(\n seed: Uint8Array\n): Promise<string> {\n // Lazy-import node-forge so callers that never touch Arweave don't pay the\n // module-load cost. node-forge is a CJS module; dynamic import wraps it.\n const forge = (await import('node-forge')).default;\n\n const prng = makeHmacDrbgPrng(seed, (bytes) =>\n forge.util.binary.raw.encode(bytes)\n );\n\n // Promisify the callback-based generateKeyPair\n const { privateKey } = await new Promise<{\n privateKey: forge.pki.rsa.PrivateKey;\n publicKey: forge.pki.rsa.PublicKey;\n }>((resolve, reject) => {\n forge.pki.rsa.generateKeyPair(\n 4096,\n 65537,\n { prng, algorithm: 'PRIMEINC' },\n (err, kp) => (err ? reject(err) : resolve(kp))\n );\n });\n\n return forge.pki.privateKeyToPem(privateKey);\n}\n"],"mappings":";;;;AAuBA,SAAS,YAAY;AACrB,SAAS,cAAc;AAUvB,SAAS,WAAW,QAAoB,OAAiC;AACvE,QAAM,IAAI,KAAK,OAAO,QAAQ,GAAG;AACjC,aAAW,KAAK,MAAO,GAAE,OAAO,CAAC;AACjC,SAAO,EAAE,OAAO;AAClB;AAEA,IAAM,UAAU,IAAI,WAAW,CAAC,CAAI,CAAC;AACrC,IAAM,UAAU,IAAI,WAAW,CAAC,CAAI,CAAC;AAWrC,SAAS,iBACP,WACA,WACyC;AAEzC,MAAI,IAAI,IAAI,WAAW,EAAE,EAAE,KAAK,CAAI;AACpC,MAAI,IAAI,IAAI,WAAW,EAAE,EAAE,KAAK,CAAI;AAGpC,MAAI,WAAW,GAAG,GAAG,SAAS,SAAS;AACvC,MAAI,WAAW,GAAG,CAAC;AACnB,MAAI,WAAW,GAAG,GAAG,SAAS,SAAS;AACvC,MAAI,WAAW,GAAG,CAAC;AAEnB,SAAO;AAAA,IACL,aAAa,MAAsB;AAKjC,YAAM,SAAuB,CAAC;AAC9B,UAAI,QAAQ;AACZ,aAAO,QAAQ,MAAM;AACnB,YAAI,WAAW,GAAG,CAAC;AACnB,eAAO,KAAK,CAAC;AACb,iBAAS,EAAE;AAAA,MACb;AAEA,YAAM,OAAO,IAAI,WAAW,KAAK;AACjC,UAAI,SAAS;AACb,iBAAW,KAAK,QAAQ;AACtB,aAAK,IAAI,GAAG,MAAM;AAClB,kBAAU,EAAE;AAAA,MACd;AACA,YAAM,MAAM,KAAK,MAAM,GAAG,IAAI;AAK9B,UAAI,WAAW,GAAG,GAAG,OAAO;AAC5B,UAAI,WAAW,GAAG,CAAC;AAEnB,aAAO,UAAU,GAAG;AAAA,IACtB;AAAA,EACF;AACF;AAcA,eAAsB,yBACpB,MACiB;AAGjB,QAAM,SAAS,MAAM,OAAO,YAAY,GAAG;AAE3C,QAAM,OAAO;AAAA,IAAiB;AAAA,IAAM,CAAC,UACnC,MAAM,KAAK,OAAO,IAAI,OAAO,KAAK;AAAA,EACpC;AAGA,QAAM,EAAE,WAAW,IAAI,MAAM,IAAI,QAG9B,CAAC,SAAS,WAAW;AACtB,UAAM,IAAI,IAAI;AAAA,MACZ;AAAA,MACA;AAAA,MACA,EAAE,MAAM,WAAW,WAAW;AAAA,MAC9B,CAAC,KAAK,OAAQ,MAAM,OAAO,GAAG,IAAI,QAAQ,EAAE;AAAA,IAC9C;AAAA,EACF,CAAC;AAED,SAAO,MAAM,IAAI,gBAAgB,UAAU;AAC7C;","names":[]}