# `keygen/multi-prime` ## Purpose Multi-prime RSA key generation per RFC 8017 §3 and PKCS #1 Appendix A.1.2 `OtherPrimeInfos` extension. Reachable via the public `generateRsaKeyPair({ primes: 3 | 4 | 5 })` entry point; this module is the algorithmic core. Multi-prime RSA trades a small reduction in security per bit (the modulus must be slightly larger to retain the same factoring hardness) for a substantial speedup of the private operation — each prime factor is smaller, and CRT-accelerated decryption runs `primes` exponentiations of `bitLength / primes`-sized operands instead of two exponentiations of `bitLength / 2`. ## Features - 3-, 4-, and 5-prime modes (PKCS #1 declares no upper bound but this module caps at 5 because beyond that the security margin per bit becomes uneconomical). - Reuses the two-prime `samplePrime` helper for each factor — same Miller-Rabin gate, same coprimality check, same `AbortSignal` threading. - Outputs a canonical `RsaPrivateKey` with the largest two primes in the standard `(p, q, dp, dq, qInv)` slots and the rest in the optional `otherPrimeInfos` field. - Round-trips through PKCS #1 (`serializeRsaPrivateKeyPkcs1` / `parseRsaPrivateKeyPkcs1`) — the serializer emits version 1 with the full `OtherPrimeInfos` SEQUENCE OF when `otherPrimeInfos` is present. ## Usage: Basic Example ```ts import { generateRsaKeyPair } from "@suaveplan/crypto-rsa/keygen/generate"; const key3 = await generateRsaKeyPair({ modulusBits: 2048, primes: 3, }); console.log(key3.otherPrimeInfos?.length); // 1 ``` ## Usage: Advanced Example Round-trip a 3-prime key through PKCS #1 DER: ```ts import { generateRsaKeyPair, parseRsaPrivateKeyPkcs1, serializeRsaPrivateKeyPkcs1, } from "@suaveplan/crypto-rsa"; const key = await generateRsaKeyPair({ modulusBits: 1536, primes: 3 }); const der = serializeRsaPrivateKeyPkcs1(key); const restored = parseRsaPrivateKeyPkcs1(der); console.log(restored.otherPrimeInfos?.length); // 1 ``` ## API Reference ### `generateMultiPrimeKey(options): Promise` Internal entry — public callers should use `generateRsaKeyPair`. - `options.modulusBits: number` - `options.publicExponent: bigint` - `options.primes: number` — must be 3, 4, or 5. - `options.rng: Rng` - `options.signal: AbortSignal | undefined` Throws `CRYPTO_RSA.PRIME_INVALID` on bad `primes`, `CRYPTO_RSA.KEYGEN_FAILED` on outer-loop exhaustion (32 attempts without producing a coprime modulus). ## Implementation Notes - The `(p, q)` selection picks the two largest primes so the standard CRT path operates on the bigger half of the modulus — this matches OpenSSL's multi-prime convention and mirrors what most PKCS #1 consumers expect when reading version 1 keys. - The `otherPrimeInfos[i].t` coefficient is `(r_1 * r_2 * ... * r_(i-1))^-1 mod r_i` per RFC 8017 §3 — we maintain `runningProduct` rather than recomputing each step. - Outer loop bails after `MAX_OUTER_ATTEMPTS = 32` attempts; in practice every well-formed `(modulusBits, primes)` pair succeeds on the first attempt because the small-prime trial division in `isProbablePrime` already culls most non-coprime candidates upstream. - `lcm(a, b) = (a / gcd(a, b)) * b` — the reverse `(a * b) / gcd` formulation overflows V8's bigint scratch for `λ(n)` with 4096-bit moduli; this rearrangement avoids it.