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

@webbuf/x25519

v3.8.0

Published

Rust/wasm X25519 ECDH (RFC 7748) for the web, node.js, deno, and bun.

Readme

@webbuf/x25519

X25519 elliptic-curve Diffie-Hellman (RFC 7748) for WebBuf, optimized with Rust/WASM.

X25519 is the standard ECDH primitive used by Signal, WireGuard, TLS 1.3, SSH, and the Chrome X25519MLKEM768 post-quantum hybrid handshake.

Installation

npm install @webbuf/x25519

Usage

import { x25519PublicKeyCreate, x25519SharedSecretRaw } from "@webbuf/x25519";
import { FixedBuf } from "@webbuf/fixedbuf";

// Each party generates a 32-byte private key and computes its public key.
const alicePriv = FixedBuf.fromRandom<32>(32);
const alicePub = x25519PublicKeyCreate(alicePriv);

const bobPriv = FixedBuf.fromRandom<32>(32);
const bobPub = x25519PublicKeyCreate(bobPriv);

// Each side computes the same shared secret independently.
const aliceSS = x25519SharedSecretRaw(alicePriv, bobPub);
const bobSS = x25519SharedSecretRaw(bobPriv, alicePub);
// aliceSS.toHex() === bobSS.toHex()

Output format

Public keys and shared secrets are 32-byte u-coordinates per RFC 7748 §5 — not the 33-byte SEC1-compressed shape used by @webbuf/p256 or @webbuf/secp256k1. The shared secret is the raw 32-byte scalar-mult output; consumers that need an AES key should run it through HKDF-SHA-256 (or use the higher-level @webbuf/aesgcm-x25519dh-mlkem package once it lands).

Clamping

X25519 requires private-key bit-clamping per RFC 7748 §5 (decodeScalar25519) before scalar multiplication. Clamping is applied internally by x25519PublicKeyCreate and x25519SharedSecretRaw. Callers can pass any 32-byte private key — the clamping happens transparently inside the WASM boundary, matching x25519-dalek's StaticSecret::from([u8; 32]) behavior. There's no need (and no API surface) to pre-clamp.

The Rust test clamping_is_internal proves this empirically: two private keys that differ only in clamped bits produce the same public key.

Small-order rejection

x25519SharedSecretRaw throws if the resulting shared secret is non-contributory — i.e. if the peer's public key is small-order. This protects hybrid encryption schemes from being collapsed to PQ-only by a malicious peer's small-order public key. The error message is stable:

X25519 shared secret is non-contributory (small-order public key)

The seven canonical small-order Curve25519 u-coordinates (Cremers & Jackson, "Prime, Order Please!" 2019) are exercised in both the Rust and TypeScript test suites.

RFC 7748 §6.1 says implementations may abort on a zero shared secret. WebBuf takes the conservative position: the primitive itself enforces, every consumer inherits the protection.

API

| Function | Description | | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | x25519PublicKeyCreate(privKey: FixedBuf<32>): FixedBuf<32> | Compute public key from a 32-byte private key (clamped internally) | | x25519SharedSecretRaw(privKey: FixedBuf<32>, pubKey: FixedBuf<32>): FixedBuf<32> | Compute raw 32-byte ECDH shared secret; throws on non-contributory result |

Audit posture

The curve25519-dalek and subtle crates received a security audit by Quarkslab in 2019 (commissioned by Tari Labs). That audit covered the pre-1.0 codebase. The current curve25519-dalek 4.x and x25519-dalek 2.x lines are not under the 2019 audit, but the pinned versions (=4.1.3 and =2.0.1) include the fix for RUSTSEC-2024-0344 (Scalar29::sub / Scalar52::sub LLVM-inserted timing leak, fixed in curve25519-dalek 4.1.3). There are no open advisories against x25519-dalek itself.

WebBuf pins these crates exactly. Cargo will not silently upgrade across RUSTSEC-fix points without an intentional bump in WebBuf's Cargo.toml.

See issues/0007-curve25519-hybrid-pq for the full crate-survey rationale and pinned-version decisions.

Tests

  • 6 Rust tests: RFC 7748 §6.1 worked example, §5.2 single-iteration vector, small-order rejection across all seven canonical u-coordinates, clamping invariance, hard-coded round-trip, input-length error wording.
  • TypeScript tests: round-trip on random keys, length invariants, deterministic public-key derivation, all-seven small-order rejections, the RFC 7748 §6.1 + §5.2 audit KATs.
pnpm test

License

MIT