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,53 @@
# `x`
## Purpose
Compute the SRP-6a private exponent `x = H(salt | H(I | ":" | P))` per RFC 5054 §2.6. `x` ties username + password + salt to a deterministic exponent in `Z_N`, producing the verifier `v = g^x mod N` that the server stores. Both `I` (username) and `P` (password) are encoded as UTF-8 bytes before hashing. The colon separator is fixed by RFC 5054 and is consumed verbatim — consumers MUST NOT pre-quote or escape colons inside `I` or `P`; that is the consumer's responsibility upstream.
## Features
- Pure function of `(I, P, salt, params)`.
- UTF-8 encoding of `I` and `P` so non-ASCII usernames work.
- Two-stage hash: inner `H(I | ":" | P)` then outer `H(salt | innerHash)`.
- Deterministic — same inputs always produce the same `x`.
## Usage: Basic Example
```ts
import { computeX } from "@suaveplan/srp";
import { params2048Sha256 } from "@suaveplan/srp/params";
import { nobleHashBridge } from "@suaveplan/srp/hash";
const params = params2048Sha256(nobleHashBridge("SHA256"));
const salt = new Uint8Array(16);
const x = computeX("alice@example.com", "correct horse battery staple", salt, params);
console.log(x.byteLength); // 32
```
## Usage: Advanced Example
```ts
import { computeX } from "@suaveplan/srp";
import { params2048Sha256 } from "@suaveplan/srp/params";
import { nobleHashBridge } from "@suaveplan/srp/hash";
const params = params2048Sha256(nobleHashBridge("SHA256"));
const salt = new Uint8Array([1, 2, 3, 4]);
// Determinism — both calls return byte-identical x for identical inputs.
const x1 = computeX("alice", "secret", salt, params);
const x2 = computeX("alice", "secret", salt, params);
console.log(x1.toString() === x2.toString());
```
## API Reference
### `computeX(I: string, P: string, salt: Uint8Array, params: SrpParams): Uint8Array`
Returns `H(salt | H(I | ":" | P))`. Result length equals `params.hash.digestSize`.
## Implementation Notes
The colon separator in `I | ":" | P` is part of the SRP-6a definition; without it, an attacker could pivot a credential with username `"ab"` + password `"cd"` against a credential with username `"abc"` + password `"d"` (same `I | P` byte stream). RFC 5054 §2.6 fixes the separator to `0x3a` (`":"`); we encode it as UTF-8 once at module load and reuse the cached buffer across calls.
`x` is only ever derived on the client side — the server stores the resulting verifier `v = g^x mod N` and never sees `x` directly. The function therefore lives in `math/` rather than `client/` because it is a primitive used by both `computeVerifier` and `clientFinishHandshake`; co-locating it under either of those modules would obscure the dependency relationship.