# `pake-provider` _(no submodules)_ ## Purpose `PakeProvider` is the augmented-password-authenticated-key-exchange seam for `@suaveplan/srp`. SRP-6a is the first implementation (`srpPakeProvider`); the interface is intentionally minimal so a future OPAQUE provider (`@suaveplan/opaque`, not yet shipped) can drop in without changing the `@suaveplan/vault` consumer surface. The seam covers three lifecycle methods: `registerCredential` (turn `(I, P, salt)` into a server-storable record), `clientHandshake` (drive the client side once the server's public value `B` is known), and `serverHandshake` (drive the server side once the client's `A` and `M1` are known). ## Features - Stable interface shape independent of the underlying PAKE algorithm. - `srpPakeProvider(params)` returns a fully-wired SRP-6a implementation. - `clientHandshake` accepts the client's pre-drawn private exponent so callers can replay deterministic handshakes from a seeded RNG. - `serverHandshake` accepts the server's pre-drawn `(b, B)` so callers can replay deterministic handshakes symmetrically. - Outcome shape is consistent with `clientFinishHandshake` / `serverFinishHandshake` — `K`, `S`, `M1`/`M2` are all surfaced. ## Usage: Basic Example ```ts import { srpPakeProvider } from "@suaveplan/srp/pake"; import { params2048Sha256 } from "@suaveplan/srp/params"; import { nobleHashBridge } from "@suaveplan/srp/hash"; const provider = srpPakeProvider(params2048Sha256(nobleHashBridge("SHA256"))); const salt = new Uint8Array(16); const registration = provider.registerCredential("alice", "password123", salt); console.log(registration.v.byteLength); // 256 ``` ## Usage: Advanced Example ```ts import { srpPakeProvider } from "@suaveplan/srp/pake"; import { params2048Sha256 } from "@suaveplan/srp/params"; import { nobleHashBridge } from "@suaveplan/srp/hash"; import { clientStartHandshake } from "@suaveplan/srp/client"; import { serverStartHandshake } from "@suaveplan/srp/server"; const params = params2048Sha256(nobleHashBridge("SHA256")); const provider = srpPakeProvider(params); const rng = { nextUint32: () => 0, nextFloat: () => 0, nextBytes: (n: number) => crypto.getRandomValues(new Uint8Array(n)), }; const salt = new Uint8Array(16); const reg = provider.registerCredential("alice", "password123", salt); const { a } = clientStartHandshake(rng, params); const { b, B } = serverStartHandshake(reg.v, rng, params); const client = provider.clientHandshake("alice", "password123", salt, B, a); const server = provider.serverHandshake(reg, client.A, client.M1, B, b); console.log(Buffer.from(client.K).equals(Buffer.from(server.K))); // true ``` ## API Reference ### `srpPakeProvider(params: SrpParams): PakeProvider` Returns a SRP-6a implementation of the `PakeProvider` interface bound to the supplied `params`. ### `interface PakeProvider` | Method | Signature | Description | | -------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- | | `registerCredential` | `(I, P, salt) → PakeRegistration` | Compute `{ I, salt, v }` server-storable record. | | `clientHandshake` | `(I, P, salt, serverPublic, clientPrivate) → PakeClientHandshake` | Drive the client; `clientPrivate` is the `a` from `clientStartHandshake`. | | `serverHandshake` | `(stored, clientPublic, clientProof, B, b) → PakeServerHandshake` | Drive the server; `(B, b)` come from `serverStartHandshake`. | ## Implementation Notes `clientHandshake` accepts the client's private exponent and recomputes `A = g^a mod N` rather than accepting `A` directly. This costs one extra `modPow` per call but lets the seam absorb any future PAKE-algorithm change that derives `A`-equivalent values differently from `clientPrivate`. The cost is amortised against the dominant `modPow` chain inside `clientFinishHandshake`, so the wall-time impact is roughly +20%. The `PakeProvider` interface deliberately does NOT include `clientStartHandshake` / `serverStartHandshake` because the start step is a pure RNG draw plus a `modPow` — the values produced are not augmented-PAKE-specific, so the seam exposes only the augmented-step entry points. Consumers driving the seam externally call `clientStartHandshake` and `serverStartHandshake` from `@suaveplan/srp/client` and `@suaveplan/srp/server` respectively, then thread the resulting public values into `PakeProvider`.