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,52 @@
# `k`
## Purpose
Compute the SRP-6a multiplier parameter `k = H(N | PAD(g))` per RFC 5054 §2.5.3. The multiplier is the structural change that distinguishes SRP-6a from SRP-6 (the latter set `k = 3`, which broke under a generator-substitution attack). Mixing both `N` and the padded generator into a hash binds `k` to the chosen group so the multiplier cannot be transplanted between groups by an attacker who controls one side of the handshake.
## Features
- Pure function of `(N, g, hash)`.
- Returns the hash's native digest size (32 bytes for SHA-256, 20 for SHA-1).
- Uses `PAD` to zero-extend `g` to `byteLength(N)` before hashing, per RFC 5054 §2.5.3.
- Caller-side memoization safe — `params` is treated as immutable.
## Usage: Basic Example
```ts
import { computeK } from "@suaveplan/srp";
import { params2048Sha256 } from "@suaveplan/srp/params";
import { nobleHashBridge } from "@suaveplan/srp/hash";
const params = params2048Sha256(nobleHashBridge("SHA256"));
const k = computeK(params);
console.log(k.byteLength); // 32
```
## Usage: Advanced Example
```ts
import { computeK } from "@suaveplan/srp";
import { params2048Sha256 } from "@suaveplan/srp/params";
import { nobleHashBridge } from "@suaveplan/srp/hash";
const params = params2048Sha256(nobleHashBridge("SHA256"));
const kCached = computeK(params);
// Reuse k across many handshakes — k is a pure function of (N, g, hash).
function getCachedK(): Uint8Array {
return kCached;
}
console.log(getCachedK().byteLength);
```
## API Reference
### `computeK(params: SrpParams): Uint8Array`
Returns `H(N | PAD(g))` using `params.hash`. Result length equals `params.hash.digestSize`.
## Implementation Notes
`k` is a pure function of `(N, g, hash)` and is therefore safe to memoize across handshakes; consumers that mount a long-lived `SrpParams` value can cache `k` outside the per-request critical path. This package does NOT cache automatically because the `SrpParams.hash` field MAY be a stateful subtle bridge that the consumer rotates per session; deferring the memoization decision to the caller keeps the contract simple.
The digest call goes through `digestSync` (from `../hash/hash-bridge.js`), which throws `SRP.HASH_UNSUPPORTED` if the consumer accidentally wires an async `HashLike` into a sync handshake path. Without that gate, an awaited Promise would silently coerce to `[object Promise]` bytes downstream.