Files
2026-06-09 21:06:27 +01:00

29 KiB

@suaveplan/srp - SRP-6a zero-knowledge password proof (RFC 5054 / RFC 2945) — universal client+server roles, bundled 2048-bit safe-prime group, optional 1024/1536/3072/4096/6144/8192 groups under subpaths, augmented PAKE bridge for future OPAQUE drop-in.

Summary

SRP-6a zero-knowledge password proof per RFC 5054 / RFC 2945. Universal — client and server roles in one package, bundled 2048-bit safe-prime group, optional 1024 / 1536 / 3072 / 4096 / 6144 / 8192-bit groups under tree-shakeable subpaths, augmented-PAKE bridge (PakeProvider) for future OPAQUE drop-in, dual sync / async hash backends.

Documentation tree

  • client-finish — Complete the SRP-6a handshake on the client side after the server has emitted its public value B. Derives the shared…
  • client-start — Kick off the SRP-6a handshake on the client side. Draws a private exponent a ≥ 256 bits from an injectable Rng and…
  • client-verify — Verify the server's proof M2 = H(A | M1 | K) per RFC 2945 §3 on the client side. After the client emits M1 and the…
  • errors — (no submodules)
  • groups — (no submodules) - groups-1024 — _(no submodul…
  • hash — (no submodules)
  • k — Compute the SRP-6a multiplier parameter k = H(N | PAD(g)) per RFC 5054 §2.5.3. The multiplier is the structural chang…
  • modpow — Modular exponentiation primitive for @suaveplan/srp. This is a thin wrapper over @noble/curves's hardened `pow(num,…
  • pad — The PAD(x, N) helper from RFC 5054 §2.5.3. Returns a left-zero-extended copy of x whose length equals `N.byteLength…
  • proof — Internal helpers for computing the SRP-6a / RFC 2945 §3 mutual-authentication proofs M1 and M2. Both client and ser…
  • rng-bytes — Adapter helper that draws n bytes from any Rng implementing the @suaveplan/types contract. The Rng interface ma…
  • u — Compute the SRP-6a scrambling value u = H(PAD(A) | PAD(B)) per RFC 5054 §2.5.4. u mixes the two ephemeral public va…
  • (./src/math/x.md) — Compute the SRP-6a private exponent x = H(salt | H(I | ":" | P)) per RFC 5054 §2.6. x ties username + password + sa…
  • observability — (no submodules)
  • pake — (no submodules)
  • params — (no submodules)
  • schemas — (no submodules)
  • server-finish — Complete the SRP-6a handshake on the server side after receiving the client's public value A and proof M1. Validate…
  • server-m2 — Split-roundtrip helper that computes the server proof M2 = H(A | M1 | K) independently of serverFinishHandshake. Us…
  • server-start — Begin the SRP-6a handshake on the server side. Loads the stored verifier v (alongside the user's (I, salt)), draws…
  • verifier — (no submodules)
- [errors](./src/errors/errors.md) — _(no submodules)_- [groups](./src/groups/groups-2048.md) — _(no submodules)_- [1024](./src/groups/1024/groups-1024.md) — _(no submodules)_- [groups-1024](./src/groups/1024/groups-1024.md) — _(no submodules)_- [1536](./src/groups/1536/groups-1536.md) — _(no submodules)_- [groups-1536](./src/groups/1536/groups-1536.md) — _(no submodules)_- [3072](./src/groups/3072/groups-3072.md) — _(no submodules)_- [groups-3072](./src/groups/3072/groups-3072.md) — _(no submodules)_- [4096](./src/groups/4096/groups-4096.md) — _(no submodules)_- [groups-4096](./src/groups/4096/groups-4096.md) — _(no submodules)_- [6144](./src/groups/6144/groups-6144.md) — _(no submodules)_- [groups-6144](./src/groups/6144/groups-6144.md) — _(no submodules)_- [8192](./src/groups/8192/groups-8192.md) — _(no submodules)_- [groups-8192](./src/groups/8192/groups-8192.md) — _(no submodules)_- [groups-2048](./src/groups/groups-2048.md) — _(no submodules)_- [hash](./src/hash/hash-bridge.md) — _(no submodules)_- [hash-bridge](./src/hash/hash-bridge.md) — _(no submodules)_- [k](./src/math/k.md) — Compute the SRP-6a multiplier parameter `k = H(N | PAD(g))` per RFC 5054 §2.5.3. The multiplier is the structural chang…
  • modpow — Modular exponentiation primitive for @suaveplan/srp. This is a thin wrapper over @noble/curves's hardened `pow(num,…
  • pad — The PAD(x, N) helper from RFC 5054 §2.5.3. Returns a left-zero-extended copy of x whose length equals `N.byteLength…
  • proof — Internal helpers for computing the SRP-6a / RFC 2945 §3 mutual-authentication proofs M1 and M2. Both client and ser…
  • rng-bytes — Adapter helper that draws n bytes from any Rng implementing the @suaveplan/types contract. The Rng interface ma…
  • u — Compute the SRP-6a scrambling value u = H(PAD(A) | PAD(B)) per RFC 5054 §2.5.4. u mixes the two ephemeral public va…
  • (./src/math/x.md) — Compute the SRP-6a private exponent x = H(salt | H(I | ":" | P)) per RFC 5054 §2.6. x ties username + password + sa…
  • observability — (no submodules)- metrics — (no submodules)- pake — (no submodules)- pake-provider — (no submodules)- params — (no submodules)- params — (no submodules)- schemas — (no submodules)- schemas — (no submodules)- server-finish — Complete the SRP-6a handshake on the server side after receiving the client's public value A and proof M1. Validate…
  • server-m2 — Split-roundtrip helper that computes the server proof M2 = H(A | M1 | K) independently of serverFinishHandshake. Us…
  • server-start — Begin the SRP-6a handshake on the server side. Loads the stored verifier v (alongside the user's (I, salt)), draws…
  • verifier — (no submodules)- verifier — (no submodules)- errors — (no submodules)- groups — (no submodules)- groups-1024 — <!-- begin:aut…
  • hash — (no submodules)- hash-bridge — (no submodules)- k — Compute the SRP-6a multiplier parameter k = H(N | PAD(g)) per RFC 5054 §2.5.3. The multiplier is the structural chang…
  • modpow — Modular exponentiation primitive for @suaveplan/srp. This is a thin wrapper over @noble/curves's hardened `pow(num,…
  • pad — The PAD(x, N) helper from RFC 5054 §2.5.3. Returns a left-zero-extended copy of x whose length equals `N.byteLength…
  • proof — Internal helpers for computing the SRP-6a / RFC 2945 §3 mutual-authentication proofs M1 and M2. Both client and ser…
  • rng-bytes — Adapter helper that draws n bytes from any Rng implementing the @suaveplan/types contract. The Rng interface ma…
  • u — Compute the SRP-6a scrambling value u = H(PAD(A) | PAD(B)) per RFC 5054 §2.5.4. u mixes the two ephemeral public va…
  • (./src/math/x.md) — Compute the SRP-6a private exponent x = H(salt | H(I | ":" | P)) per RFC 5054 §2.6. x ties username + password + sa…
  • observability — (no submodules)- metrics — (no submodules)- pake — (no submodules)- pake-provider — (no submodules)- params — (no submodules)- params — (no submodules)- schemas — (no submodules)- schemas — (no submodules)- server-finish — Complete the SRP-6a handshake on the server side after receiving the client's public value A and proof M1. Validate…
  • server-m2 — Split-roundtrip helper that computes the server proof M2 = H(A | M1 | K) independently of serverFinishHandshake. Us…
  • server-start — Begin the SRP-6a handshake on the server side. Loads the stored verifier v (alongside the user's (I, salt)), draws…
  • verifier — (no submodules)- verifier — (no submodules)- errors — (no submodules)- groups — (no submodules)- groups-1024 — _(no submodu…
  • hash — (no submodules)- hash-bridge — (no submodules)- k — Compute the SRP-6a multiplier parameter k = H(N | PAD(g)) per RFC 5054 §2.5.3. The multiplier is the structural chang…
  • modpow — Modular exponentiation primitive for @suaveplan/srp. This is a thin wrapper over @noble/curves's hardened `pow(num,…
  • pad — The PAD(x, N) helper from RFC 5054 §2.5.3. Returns a left-zero-extended copy of x whose length equals `N.byteLength…
  • proof — Internal helpers for computing the SRP-6a / RFC 2945 §3 mutual-authentication proofs M1 and M2. Both client and ser…
  • rng-bytes — Adapter helper that draws n bytes from any Rng implementing the @suaveplan/types contract. The Rng interface ma…
  • u — Compute the SRP-6a scrambling value u = H(PAD(A) | PAD(B)) per RFC 5054 §2.5.4. u mixes the two ephemeral public va…
  • (./src/math/x.md) — Compute the SRP-6a private exponent x = H(salt | H(I | ":" | P)) per RFC 5054 §2.6. x ties username + password + sa…
  • observability — (no submodules)- metrics — (no submodules)- pake — (no submodules)- pake-provider — (no submodules)- params — (no submodules)- params — (no submodules)- schemas — (no submodules)- schemas — (no submodules)- server-finish — Complete the SRP-6a handshake on the server side after receiving the client's public value A and proof M1. Validate…
  • server-m2 — Split-roundtrip helper that computes the server proof M2 = H(A | M1 | K) independently of serverFinishHandshake. Us…
  • server-start — Begin the SRP-6a handshake on the server side. Loads the stored verifier v (alongside the user's (I, salt)), draws…
  • verifier — (no submodules)- verifier — (no submodules)- errors — (no submodules)- groups — (no submodules) - 1024 — (no submodules) - groups-1024 — (no submodules) - 1536 — (no submodules) - groups-1536 — (no submodules) - 3072 — (no submodules) - groups-3072 — (no submodules) - 4096 — (no submodules) - groups-4096 — (no submodules) - 6144 — (no submodules) - groups-6144 — (no submodules) - 8192 — (no submodules) - groups-8192 — (no submodules) - groups-2048 — (no submodules)- hash — (no submodules) - hash-bridge — (no submodules)- k — Compute the SRP-6a multiplier parameter k = H(N | PAD(g)) per RFC 5054 §2.5.3. The multiplier is the structural chang…
  • modpow — Modular exponentiation primitive for @suaveplan/srp. This is a thin wrapper over @noble/curves's hardened `pow(num,…
  • pad — The PAD(x, N) helper from RFC 5054 §2.5.3. Returns a left-zero-extended copy of x whose length equals `N.byteLength…
  • proof — Internal helpers for computing the SRP-6a / RFC 2945 §3 mutual-authentication proofs M1 and M2. Both client and ser…
  • rng-bytes — Adapter helper that draws n bytes from any Rng implementing the @suaveplan/types contract. The Rng interface ma…
  • u — Compute the SRP-6a scrambling value u = H(PAD(A) | PAD(B)) per RFC 5054 §2.5.4. u mixes the two ephemeral public va…
  • (./src/math/x.md) — Compute the SRP-6a private exponent x = H(salt | H(I | ":" | P)) per RFC 5054 §2.6. x ties username + password + sa…
  • observability — (no submodules) - metrics — (no submodules)- pake — (no submodules) - pake-provider — (no submodules)- params — (no submodules) - params — (no submodules)- schemas — (no submodules) - schemas — (no submodules)- server-finish — Complete the SRP-6a handshake on the server side after receiving the client's public value A and proof M1. Validate…
  • server-m2 — Split-roundtrip helper that computes the server proof M2 = H(A | M1 | K) independently of serverFinishHandshake. Us…
  • server-start — Begin the SRP-6a handshake on the server side. Loads the stored verifier v (alongside the user's (I, salt)), draws…
  • verifier — (no submodules) - verifier — (no submodules)

Install

bun add @suaveplan/srp

Quick start

import { computeVerifier } from "@suaveplan/srp/verifier";
import { clientStartHandshake, clientFinishHandshake } from "@suaveplan/srp/client";
import { serverStartHandshake, serverFinishHandshake } from "@suaveplan/srp/server";
import { params2048Sha256 } from "@suaveplan/srp/params";
import { nobleHashBridge } from "@suaveplan/srp/hash";

const params = params2048Sha256(nobleHashBridge("SHA256"));
const salt = crypto.getRandomValues(new Uint8Array(16));
const rng = {
    nextUint32: () => {
        const buf = new Uint32Array(1);
        crypto.getRandomValues(buf);
        return buf[0]!;
    },
    nextFloat: () => 0.5,
    nextBytes: (n: number) => crypto.getRandomValues(new Uint8Array(n)),
};

// Registration — client computes the verifier and ships { I, salt, v }.
const { v } = computeVerifier("alice", "password123", salt, params);
const serverRecord = { I: "alice", salt, v };

// Handshake — client and server exchange (A, B) then (M1, M2).
const { a, A } = clientStartHandshake(rng, params);
const { b, B } = serverStartHandshake(serverRecord.v, rng, params);
const client = clientFinishHandshake("alice", "password123", salt, A, B, a, params);
const server = serverFinishHandshake(
    "alice",
    salt,
    A,
    B,
    b,
    serverRecord.v,
    client.M1,
    params
);
// client.K === server.K; both sides have authenticated each other.

Modules

Module Subpath Description
groups/groups-2048 @suaveplan/srp/groups Default 2048-bit safe-prime group constants
groups/1024/groups-1024 @suaveplan/srp/groups/1024 RFC 5054 Appendix A 1024-bit group (legacy / vectors)
groups/1536/groups-1536 @suaveplan/srp/groups/1536 RFC 5054 Appendix A 1536-bit group
groups/3072/groups-3072 @suaveplan/srp/groups/3072 RFC 5054 Appendix A 3072-bit group
groups/4096/groups-4096 @suaveplan/srp/groups/4096 RFC 5054 Appendix A 4096-bit group
groups/6144/groups-6144 @suaveplan/srp/groups/6144 RFC 5054 Appendix A 6144-bit group
groups/8192/groups-8192 @suaveplan/srp/groups/8192 RFC 5054 Appendix A 8192-bit group
params/params @suaveplan/srp/params SrpParams + factory + validator
math/modpow (root) modPow + bigIntToBytes / bytesToBigInt
math/pad (root) RFC 5054 §2.5.3 PAD helper
math/k (root) computeK — multiplier parameter
math/u (root) computeU — scrambling value
math/x (root) computeX — private exponent derivation
math/proof (root) computeM1 / computeM2 proof formulae
math/rng-bytes (root) Rng → Uint8Array adapter
verifier/verifier @suaveplan/srp/verifier computeVerifier registration helper
client/client-start @suaveplan/srp/client clientStartHandshake
client/client-finish @suaveplan/srp/client clientFinishHandshake
client/client-verify @suaveplan/srp/client clientVerifyServerProof
server/server-start @suaveplan/srp/server serverStartHandshake
server/server-finish @suaveplan/srp/server serverFinishHandshake
server/server-m2 @suaveplan/srp/server serverComputeM2 split-roundtrip helper
pake/pake-provider @suaveplan/srp/pake Augmented-PAKE seam + SRP-6a impl
hash/hash-bridge @suaveplan/srp/hash nobleHashBridge / subtleHashBridge / default
errors/errors @suaveplan/srp/errors SRP_CODES + SrpError
observability/metrics (root) OTel srp.handshake_duration_ms + counters
schemas/schemas (root) Zod boundary schemas

Conformance

  • RFC 5054 Appendix B 1024/SHA-1 vectors — every intermediate (k, x, v, u, S) byte-exact.
  • 2048/SHA-256 locally-derived fixture (src/__fixtures__/vectors-2048-sha256.json) — generated by bun scripts/generate-srp-vectors.ts, byte-stable across runs.
  • Property test — 1000 random (I, P, salt) triples through the full handshake; client.K === server.K on every run.
  • All MUST-abort gates from RFC 5054 §2.5.4 (A ≡ 0, B ≡ 0, u ≡ 0) wired and tested.
  • Constant-time compare on M1, M2, and S via @suaveplan/crypto-utils.constantTimeEqual.

Test vector generator

bun scripts/generate-srp-vectors.ts [--seed=42]

Regenerates src/__fixtures__/vectors-2048-sha256.json deterministically.