3.3 KiB
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
samplePrimehelper for each factor — same Miller-Rabin gate, same coprimality check, sameAbortSignalthreading. - Outputs a canonical
RsaPrivateKeywith the largest two primes in the standard(p, q, dp, dq, qInv)slots and the rest in the optionalotherPrimeInfosfield. - Round-trips through PKCS #1 (
serializeRsaPrivateKeyPkcs1/parseRsaPrivateKeyPkcs1) — the serializer emits version 1 with the fullOtherPrimeInfosSEQUENCE OF whenotherPrimeInfosis present.
Usage: Basic Example
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:
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<RsaPrivateKey>
Internal entry — public callers should use generateRsaKeyPair.
options.modulusBits: numberoptions.publicExponent: bigintoptions.primes: number— must be 3, 4, or 5.options.rng: Rngoptions.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].tcoefficient is(r_1 * r_2 * ... * r_(i-1))^-1 mod r_iper RFC 8017 §3 — we maintainrunningProductrather than recomputing each step. - Outer loop bails after
MAX_OUTER_ATTEMPTS = 32attempts; in practice every well-formed(modulusBits, primes)pair succeeds on the first attempt because the small-prime trial division inisProbablePrimealready culls most non-coprime candidates upstream. lcm(a, b) = (a / gcd(a, b)) * b— the reverse(a * b) / gcdformulation overflows V8's bigint scratch forλ(n)with 4096-bit moduli; this rearrangement avoids it.