first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
# `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<RsaPrivateKey>`
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.