first commit
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user