rsa-pkcs1-node
The implementation is in ~/rsa-pkcs1.js with 6 core components:
1. Constant-Time Comparison (constantTimeEqual)
XOR-based comparison that runs in the same time regardless of where the first differing byte occurs. Prevents timing side-channel leaks on signature verification and MAC comparisons.
2. Miller-Rabin Primality Test (millerRabin)
- For small candidates (< 2^64): deterministic bases [2, 3, 5, 7, 11, 13] (proven sufficient)
- For 2048-bit candidates: 64 random bases yielding ~2^-128 error probability
- Optimized with pre-sieving against first 24 small primes to reject obvious composites quickly
- Uses fast BigInt modular exponentiation
3. Extended Euclidean Algorithm & Modular Inverse
- extendedGcd(a, b) returns [gcd, x, y] where a*x + b*y = gcd(a,b)
- modInverse(a, mod) computes d such that (a * d) % mod === 1 — used to derive the private exponent d = e^-1 mod phi(n)
4. RSA Key Generation (2048-bit)
p, q = generatePrime(1024) // two random 1024-bit primes
n = p * q // 2048-bit modulus
phi = (p-1)(q-1)
e = 65537 // public exponent
d = e^-1 mod phi // private exponent via extended Euclid
dp = d mod (p-1) // CRT exponent for p
dq = d mod (q-1) // CRT exponent for q
qinv = q^-1 mod p // CRT coefficient
5. PKCS#1 v1.5 Encryption (Type 02)
EM = 0x00 || 0x02 || PS || 0x00 || M
6. PKCS#1 v1.5 Signature (Type 01)
EM = 0x00 || 0x01 || PS || 0x00 || DER(DigestInfo)
false (never throw)Key security properties:
- No timing side-channels: constantTimeEqual runs O(n) regardless of match position
- Signature verification never reveals why verification failed (constant false return via try/catch)
- Random encryption padding ensures ciphertext indeterminism
- CRT-based decryption for 4x performance improvement
All 37 tests pass. Test categories and edge cases covered: | Category | Tests | Key verifications | |---|---|---| | Constant-time comparison | 4 | Equal, different, different lengths, non-buffer inputs | | Extended Euclidean / modInverse | 4 | GCD correctness, modular inverse, non-coprime rejection | | Miller-Rabin | 4 | Small primes, composites, Carmichael numbers (561, 1105), large Mersenne | | Prime generation | 1 | 512-bit prime, verified by Miller-Rabin, exact bit length | | Key generation | 1 | n=256B, CRT params, n=p*q, e*d≡1 mod phi, qinv*q≡1 mod p | | Encryption padding | 4 | Format validation, max length rejection, round-trip, invalid format rejection | | Signature padding | 2 | Format validation, round-trip with DigestInfo | | Encrypt/Decrypt | 3 | Round-trip (1B, 245B, binary), ciphertext indeterminism, tamper rejection | | Sign/Verify | 8 | SHA-256/512/1 round-trip, tampered data rejection, tampered sig rejection, wrong key, hash mismatch, empty data, large data | | Raw RSA | 1 | Modular exponentiation round-trip via BigInt | | Edge cases | 4 | Max-length message, 1-byte message, 5-cycle sign loop, 5-cycle encrypt loop | **Critical edge cases verified:** - Message exactly `k-11` bytes (max encryption capacity) - Binary data with null bytes and 0xFF - Empty data for signatures - 10KB data for signatures - Tampered ciphertexts → decryption throws - Tampered signatures → verification returns `false` (constant-time) - Wrong public key → verification returns `false` - Hash algorithm mismatch → verification returns `false` ---
{"model": "${PI_MODEL:-custom}", "problem_class": "rsa-pkcs1-node", "result": "passed", "tests": 37}The implementation is in ~/rsa-pkcs1.js with 6 core components:
1. Constant-Time Comparison (constantTimeEqual)
XOR-based comparison that runs in the same time regardless of where the first differing byte occurs. Prevents timing side-channel leaks on signature verification and MAC comparisons.
2. Miller-Rabin Primality Test (millerRabin)
- For small candidates (< 2^64): deterministic bases [2, 3, 5, 7, 11, 13] (proven sufficient)
- For 2048-bit candidates: 64 random bases yielding ~2^-128 error probability
- Optimized with pre-sieving against first 24 small primes to reject obvious composites quickly
- Uses fast BigInt modular exponentiation
3. Extended Euclidean Algorithm & Modular Inverse
- extendedGcd(a, b) returns [gcd, x, y] where a*x + b*y = gcd(a,b)
- modInverse(a, mod) computes d such that (a * d) % mod === 1 — used to derive the private exponent d = e^-1 mod phi(n)
4. RSA Key Generation (2048-bit)
p, q = generatePrime(1024) // two random 1024-bit primes
n = p * q // 2048-bit modulus
phi = (p-1)(q-1)
e = 65537 // public exponent
d = e^-1 mod phi // private exponent via extended Euclid
dp = d mod (p-1) // CRT exponent for p
dq = d mod (q-1) // CRT exponent for q
qinv = q^-1 mod p // CRT coefficient
5. PKCS#1 v1.5 Encryption (Type 02)
EM = 0x00 || 0x02 || PS || 0x00 || M
6. PKCS#1 v1.5 Signature (Type 01)
EM = 0x00 || 0x01 || PS || 0x00 || DER(DigestInfo)
false (never throw)Key security properties:
- No timing side-channels: constantTimeEqual runs O(n) regardless of match position
- Signature verification never reveals why verification failed (constant false return via try/catch)
- Random encryption padding ensures ciphertext indeterminism
- CRT-based decryption for 4x performance improvement
All 37 tests pass. Test categories and edge cases covered: | Category | Tests | Key verifications | |---|---|---| | Constant-time comparison | 4 | Equal, different, different lengths, non-buffer inputs | | Extended Euclidean / modInverse | 4 | GCD correctness, modular inverse, non-coprime rejection | | Miller-Rabin | 4 | Small primes, composites, Carmichael numbers (561, 1105), large Mersenne | | Prime generation | 1 | 512-bit prime, verified by Miller-Rabin, exact bit length | | Key generation | 1 | n=256B, CRT params, n=p*q, e*d≡1 mod phi, qinv*q≡1 mod p | | Encryption padding | 4 | Format validation, max length rejection, round-trip, invalid format rejection | | Signature padding | 2 | Format validation, round-trip with DigestInfo | | Encrypt/Decrypt | 3 | Round-trip (1B, 245B, binary), ciphertext indeterminism, tamper rejection | | Sign/Verify | 8 | SHA-256/512/1 round-trip, tampered data rejection, tampered sig rejection, wrong key, hash mismatch, empty data, large data | | Raw RSA | 1 | Modular exponentiation round-trip via BigInt | | Edge cases | 4 | Max-length message, 1-byte message, 5-cycle sign loop, 5-cycle encrypt loop | **Critical edge cases verified:** - Message exactly `k-11` bytes (max encryption capacity) - Binary data with null bytes and 0xFF - Empty data for signatures - 10KB data for signatures - Tampered ciphertexts → decryption throws - Tampered signatures → verification returns `false` (constant-time) - Wrong public key → verification returns `false` - Hash algorithm mismatch → verification returns `false` ---
{"model": "${PI_MODEL:-custom}", "problem_class": "rsa-pkcs1-node", "result": "passed", "tests": 37}