Files
skills/docs/security-stack/security/srp/src/verifier/verifier.md
2026-05-29 08:20:56 +01:00

3.3 KiB

verifier

(no submodules)

Purpose

Compute the SRP-6a verifier v = g^x mod N where x = H(salt | H(I | ":" | P)), per RFC 5054 §2.6. The verifier is what the server stores on registration; the password never leaves the client. The deterministic mapping from (I, P, salt) to (x, v) means an attacker who steals the verifier database cannot recover passwords without solving a discrete-log problem in the chosen safe-prime group — for the bundled 2048-bit group, that puts the attacker at the same security level as a 2048-bit RSA key.

Features

  • Pure deterministic function of (I, P, salt, params).
  • Returns both x (private; consumer should zeroize immediately after use) and v (public; server-side storage).
  • v is zero-padded to byteLength(N) so on-wire / on-disk shape is fixed.
  • modPow routes through @noble/curves's hardened path.

Usage: Basic Example

import { computeVerifier } from "@suaveplan/srp/verifier";
import { params2048Sha256 } from "@suaveplan/srp/params";
import { nobleHashBridge } from "@suaveplan/srp/hash";

const params = params2048Sha256(nobleHashBridge("SHA256"));
const salt = new Uint8Array(16);
const { x, v } = computeVerifier("alice", "password123", salt, params);
console.log(x.byteLength, v.byteLength); // 32 256

Usage: Advanced Example

import { computeVerifier } from "@suaveplan/srp/verifier";
import { params2048Sha256 } from "@suaveplan/srp/params";
import { nobleHashBridge } from "@suaveplan/srp/hash";
import { zeroize } from "@suaveplan/crypto-utils";

const params = params2048Sha256(nobleHashBridge("SHA256"));
const salt = crypto.getRandomValues(new Uint8Array(16));
const { x, v } = computeVerifier("alice", "correct horse battery staple", salt, params);

// Persist v + salt server-side; zeroize x locally.
const serverRecord = { I: "alice", salt, v };
zeroize(x);
console.log(serverRecord.v.byteLength);

API Reference

computeVerifier(I, P, salt, params): { x, v }

Parameter Type Description
I string Username / identity, UTF-8 encoded.
P string Password, UTF-8 encoded.
salt Uint8Array Random per-user salt.
params SrpParams Group + hash bundle.

Returns { x, v }. x is params.hash.digestSize bytes; v is params.N.byteLength bytes.

Implementation Notes

The function returns BOTH x and v even though only v is sent to the server. The reason: most consumers compute the verifier as part of a multi-step registration flow that also needs x for an immediate clientFinishHandshake (e.g. "register, then log in" UX patterns). Returning x saves one redundant hash chain; consumers that never use x should zeroize(x) immediately after the call.

The bigIntToBytes(vInt, params.N.byteLength) call zero-pads v on the left to the modulus width. This matters because v is later mixed into hashes via PAD on the server side; storing the un-padded representation would force every server-side handshake step to re-pad on read, and would produce different on-disk bytes for the same logical verifier depending on its leading-zero pattern.