X25519 (RFC 7748) — Diffie-Hellman over Curve25519, primitive ECDH minimaliste.
Module x25519 | Source packages/front/fw/src/crypto/pkc/x25519.js | Deps none | Worker-safe yes
Outside NIST but a de facto standard (TLS 1.3, Signal, WireGuard). TweetNaCl-derived implementation (public domain; see provenance). isLowOrderPoint helper added for explicit rejection before scalarMult.
Resolve
const x25519 = runtime.resolve('x25519');
// Returns: { scalarMult, scalarMultBase, isLowOrderPoint, _internal }
API
| Method | Signature | Returns |
|---|---|---|
scalarMult(scalar, u) |
(Uint8Array(32), Uint8Array(32)) => Uint8Array(32) | false |
Shared secret (clamping auto per RFC 7748 §5) |
scalarMultBase(scalar) |
(Uint8Array(32)) => Uint8Array(32) |
scalarMult(scalar, basePoint=9) (public key) |
isLowOrderPoint(u) |
(Uint8Array(32)) => boolean |
true if u is low-order (cofactor 8) |
_internal.lowOrderPoints |
Uint8Array[7] |
Table of the 7 documented LOPs |
Examples
Diffie-Hellman
const { x25519, random } = fw.runtime.resolveAll(['x25519', 'random']);
const aPriv = random.bytes(32);
const aPub = x25519.scalarMultBase(aPriv);
const bPriv = random.bytes(32);
const bPub = x25519.scalarMultBase(bPriv);
// Exchange: Alice sends aPub, receives bPub
const sharedA = x25519.scalarMult(aPriv, bPub);
const sharedB = x25519.scalarMult(bPriv, aPub);
// sharedA === sharedB
Low-order point rejection (before scalarMult)
if (x25519.isLowOrderPoint(receivedPub)) {
console.warn('Reject: low-order public key');
return;
}
const shared = x25519.scalarMult(myPriv, receivedPub);
Worker Usage
const worker = fw.createWorker(
function ({ libs, args }) {
self.postMessage(libs.x25519.scalarMult(args[0], args[1]));
},
{ dependencies: ['x25519'], args: [scalar, u] }
);
Notes
- Automatic clamping per RFC 7748 §5 (clear low 3 bits, clear high bit, set bit 254).
- Low-order points:
scalarMult(scalar, lowOrderU) === 0...0. RFC 7748 §6.1 allows this (non-rejected by design);isLowOrderPointenables explicit caller-side rejection (constant-time vs 7 documented LOPs). scalarMultnot formally constant-time:_M/_SFloat64 + carry. Acceptable per RFC 7748 §A.1 in an interactive ECDH context.- RFC 7748 1M iterations validation gated on
CRYPTO_FULL=1.
See also
- ed25519 — signatures on the same curve
- Conformance x25519.acvp.md