npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bittery/srp6a

v1.0.1

Published

A modern SRP implementation for all JavaScript runtimes (Node.js, Bun, Deno, Browser, React Native).

Readme

@bittery/srp6a

Modern implementation of SRP-6a for all JavaScript runtimes: Node.js, Bun, Deno, browsers, and React Native.

Fork of srp.

Installation

npm install @bittery/srp6a
yarn add @bittery/srp6a
pnpm add @bittery/srp6a
bun add @bittery/srp6a

React Native

For React Native, you must install and import react-native-get-random-values before importing this library:

npm install react-native-get-random-values

Then at the top of your entry file (e.g., index.js or App.js):

import 'react-native-get-random-values';
import { createSRPClient } from '@bittery/srp6a';

Usage

Signing up

When creating an account with the server, the client will provide a salt and a verifier for the server to store. They are calculated by the client as follows:

import { createSRPClient } from '@bittery/srp6a';
const client = createSRPClient('SHA-256', 2048);

// These should come from the user signing up
const username = '[email protected]';
const password = '$uper$ecure';

const salt = client.generateSalt();
const privateKey = await client.deriveSafePrivateKey(salt, password);
const verifier = client.deriveVerifier(privateKey);

// Send `username`, `salt` and `verifier` to the server

Note: derivePrivateKey is also provided for completeness with the SRP-6a specification. However, it is recommended to use deriveSafePrivateKey instead, as derivePrivateKey is highly exposed to brute force attacks against the verifier. Additionally, using a username as part of the verifier calculation means that if it changes, the salt and verifier need to be updated too.

deriveSafePrivateKey uses PBKDF2 for "slow hashing". When using it instead of derivePrivateKey, pass an empty string to the deriveSession function instead of the username (""). The downside is that a server can perform an attack to determine whether two users have the same password. This is an acceptable trade-off.

Logging in

Authenticating with the server involves multiple steps.

1 - The client generates a secret/public ephemeral value pair.

import { createSRPClient } from '@bittery/srp6a';
const client = createSRPClient('SHA-256', 2048);

// This should come from the user logging in
const username = '[email protected]';
const clientEphemeral = client.generateEphemeral();

// Send `username` and `clientEphemeral.public` to the server

2 - The server receives the client's public ephemeral value and username. Using the username we retrieve the salt and verifier from our user database. We then generate our own ephemeral value pair.

Note: If no user can be found in the database, a bogus salt and ephemeral value should be returned, to avoid leaking which users have signed up.

import { createSRPServer } from '@bittery/srp6a';
const server = createSRPServer('SHA-256', 2048);

// This should come from the user database
const salt = 'fb95867e…';
const verifier = '9392093f…';

const serverEphemeral = await server.generateEphemeral(verifier);

// Store `serverEphemeral.secret` for later use
// Send `salt` and `serverEphemeral.public` to the client

3 - The client can now derive the shared strong session key and a proof of it to provide to the server.

import { createSRPClient } from '@bittery/srp6a';
const client = createSRPClient('SHA-256', 2048);

// This should come from the user logging in
const password = '$uper$ecret';
const privateKey = await client.deriveSafePrivateKey(salt, password);

const clientSession = await client.deriveSession(
  clientEphemeral.secret,
  serverPublicEphemeral,
  salt,
  '', // or `username` if you used `derivePrivateKey`
  privateKey,
);

// Send `clientSession.proof` to the server

4 - The server is also ready to derive the shared strong session key and can verify that the client has the same key using the provided proof.

import { createSRPServer } from '@bittery/srp6a';
const server = createSRPServer('SHA-256', 2048);

// Previously stored `serverEphemeral.secret`
const serverSecretEphemeral = '784d6e83…';

const serverSession = await server.deriveSession(
  serverSecretEphemeral,
  clientPublicEphemeral,
  salt,
  '', // or `username` if you used `derivePrivateKey`
  verifier,
  clientSessionProof,
);

// Send `serverSession.proof` to the client

5 - Finally, the client can verify that the server has derived the correct strong session key, using the proof that the server sent back.

import { createSRPClient } from '@bittery/srp6a';
const client = createSRPClient('SHA-256', 2048);

await client.verifySession(
  clientEphemeral.public,
  clientSession,
  serverSessionProof,
);

API

Client

import { createSRPClient } from '@bittery/srp6a';

type HashAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
type PrimeGroup = 1024 | 1536 | 2048 | 3072 | 4096 | 6144 | 8192;

const hashAlgorithm: HashAlgorithm = 'SHA-256';
const primeGroup: PrimeGroup = 2048;

const client = createSRPClient(hashAlgorithm, primeGroup);

client.generateSalt

Generate a salt suitable for computing the verifier with.

type generateSalt = () => string;

client.derivePrivateKey

Derives a private key suitable for computing the verifier with.

type derivePrivateKey = (
  salt: string,
  username: string,
  password: string,
) => Promise<string>;

client.deriveSafePrivateKey

Derives a private key suitable for computing the verifier with using PBKDF2. By default, it will use the iterations count recommended by OWASP.

type deriveSafePrivateKey = (
  salt: string,
  password: string,
  iterations?: number,
) => Promise<string>;

client.deriveVerifier

Derive a verifier to be stored for subsequent authentication attempts.

type deriveVerifier = (privateKey: string) => string;

client.generateEphemeral

Generate ephemeral values used to initiate an authentication session.

type generateEphemeral = () => {
  secret: string;
  public: string;
};

client.deriveSession

Compute a session key and proof. The proof is to be sent to the server for verification.

type deriveSession = (
  clientSecretEphemeral: string,
  serverPublicEphemeral: string,
  salt: string,
  username: string,
  privateKey: string,
) => Promise<{
  key: string;
  proof: string;
}>;

client.verifySession

Verifies the server provided session proof.

Warning: Throws SRPError if the session proof is invalid.

type verifySession = (
  clientPublicEphemeral: string,
  clientSession: Session,
  serverSessionProof: string,
) => Promise<void>;

Server

import { createSRPServer } from '@bittery/srp6a';

type HashAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
type PrimeGroup = 1024 | 1536 | 2048 | 3072 | 4096 | 6144 | 8192;

const hashAlgorithm: HashAlgorithm = 'SHA-256';
const primeGroup: PrimeGroup = 2048;

const server = createSRPServer(hashAlgorithm, primeGroup);

server.generateEphemeral

Generate ephemeral values used to continue an authentication session.

type generateEphemeral = (verifier: string) => Promise<{
  public: string;
  secret: string;
}>;

server.deriveSession

Compute a session key and proof. The proof is to be sent to the client for verification.

Warning: Throws SRPError if the session proof from the client is invalid.

type deriveSession = (
  serverSecretEphemeral: string,
  clientPublicEphemeral: string,
  salt: string,
  username: string,
  verifier: string,
  clientSessionProof: string,
) => Promise<{
  key: string;
  proof: string;
}>;

Advanced: Custom Crypto Provider

For advanced use cases, you can provide a custom crypto implementation:

import { setCryptoProvider, type CryptoProvider } from '@bittery/srp6a';

const customProvider: CryptoProvider = {
  getRandomValues: (array: Uint8Array) => {
    // Your implementation
  },
  digest: (hashAlgorithm, data) => {
    // Your implementation - return Promise<ArrayBuffer>
  },
  deriveKeyWithPBKDF2: (hashAlgorithm, salt, password, iterations) => {
    // Your implementation - return Promise<ArrayBuffer>
  },
};

setCryptoProvider(customProvider);

// Reset to auto-detection
setCryptoProvider(null);

Platform Support

| Platform | Status | |----------|--------| | Node.js 15+ | Native WebCrypto | | Bun | Native WebCrypto | | Deno | Native WebCrypto | | Modern browsers | Native WebCrypto | | React Native | Pure JS fallback (requires react-native-get-random-values) |

License

MIT