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

kxco-pq-tls

v1.0.8

Published

Post-quantum encrypted channels for Node.js streams and WebSockets — ML-KEM-768 key exchange (NIST FIPS 203) with ML-DSA-65 mutual authentication (NIST FIPS 204).

Readme

kxco-pq-tls

npm Socket license node

Post-quantum encrypted channels for Node.js streams and WebSockets.

Wraps any duplex stream or WebSocket with ML-KEM-768 key exchange (NIST FIPS 203) and ML-DSA-65 mutual authentication (NIST FIPS 204). Both sides authenticate each other during the handshake — no anonymous connections.

When to use this

  • Institution-to-institution communication where both endpoints must prove identity before data flows
  • Institution-to-user encrypted messaging where a client authenticates to a server with a PQ identity key
  • Any scenario where TLS alone is not quantum-safe — TLS 1.3 uses X25519, which a sufficiently powerful quantum computer could break; this package combines X25519 with ML-KEM-768 so both must be broken simultaneously

If you need quantum-safe encryption at rest rather than in transit, use kxco-pq-vault.

Install

npm install kxco-pq-tls

Requires Node.js 20.19 or later.

Quick start

Node.js TCP streams

import net from 'node:net'
import { wrapStream } from 'kxco-pq-tls'

// Server — responder side
const server = net.createServer(async (socket) => {
  const channel = await wrapStream(socket, { role: 'responder' })
  channel.on('data', (buf) => console.log('server received:', buf.toString()))
  channel.write(Buffer.from('hello from server'))
})
server.listen(4000)

// Client — initiator side
const socket = net.connect(4000)
const channel = await wrapStream(socket, { role: 'initiator' })
channel.write(Buffer.from('hello from client'))
channel.on('data', (buf) => console.log('client received:', buf.toString()))

WebSocket (ws package or native WebSocket API)

import { WebSocketServer } from 'ws'
import WebSocket from 'ws'
import { wrapWebSocket } from 'kxco-pq-tls'

// Server
const wss = new WebSocketServer({ port: 4001 })
wss.on('connection', async (ws) => {
  const channel = await wrapWebSocket(ws, { role: 'responder' })
  channel.on('message', (buf) => console.log('server received:', buf.toString()))
  channel.send(Buffer.from('hello from server'))
})

// Client
const ws = new WebSocket('ws://localhost:4001')
ws.on('open', async () => {
  const channel = await wrapWebSocket(ws, { role: 'initiator' })
  channel.send(Buffer.from('hello from client'))
  channel.on('message', (buf) => console.log('client received:', buf.toString()))
})

With mutual authentication

Both sides pass an ML-DSA-65 keypair. The identity is verified during the handshake, before any application data is exchanged.

import { mlDsa } from 'kxco-post-quantum'
import { wrapStream } from 'kxco-pq-tls'

const serverIdentity = mlDsa.ml_dsa65.keygen()
const clientIdentity = mlDsa.ml_dsa65.keygen()

// Server
const channel = await wrapStream(socket, { role: 'responder', identity: serverIdentity })

// Client
const channel = await wrapStream(socket, { role: 'initiator', identity: clientIdentity })

If either side passes an identity and the peer does not, the handshake fails.

API

import {
  wrapStream,
  wrapWebSocket,
  initiatorHandshake,
  responderHandshake,
  PqTlsWebSocket,
  KxcoPqTlsError,
} from 'kxco-pq-tls'

wrapStream(socket, options)Promise<Duplex>

Wraps a Node.js Duplex stream (e.g. net.Socket) with a post-quantum secure channel. Resolves to an encrypted Duplex once the handshake completes. The returned stream behaves like a normal Node.js stream — write, data events, end.

interface ChannelOptions {
  role: 'initiator' | 'responder'
  identity?: { publicKey: Uint8Array, secretKey: Uint8Array }  // ML-DSA-65 keypair
}

wrapStream(socket: Duplex, options: ChannelOptions): Promise<Duplex>

wrapWebSocket(ws, options)Promise<PqTlsWebSocket>

Wraps a WebSocket with a post-quantum secure channel. Compatible with the ws npm package (Node.js) and the native WebSocket API (Cloudflare Workers, browsers, Node.js 22+). Resolves to a PqTlsWebSocket once the handshake completes.

wrapWebSocket(ws: unknown, options: ChannelOptions): Promise<PqTlsWebSocket>

PqTlsWebSocket

Returned by wrapWebSocket. Extends EventEmitter.

class PqTlsWebSocket extends EventEmitter {
  send(data: string | Buffer | Uint8Array): void
  close(code?: number, reason?: string | Buffer): void
}

Emits: message (Buffer), close (code, reason), error (Error).

initiatorHandshake(send, recv, options?)Promise<SessionKeys>

Low-level API. Run the initiator side of the handshake over custom send/recv functions. Use this when you are bringing your own transport.

type SendFn = (data: Buffer) => Promise<void>
type RecvFn = (n: number)   => Promise<Buffer>

interface SessionKeys {
  txKey: Uint8Array  // initiator → responder encryption key
  rxKey: Uint8Array  // responder → initiator encryption key
}

initiatorHandshake(send: SendFn, recv: RecvFn, options?: HandshakeOptions): Promise<SessionKeys>

responderHandshake(send, recv, options?)Promise<SessionKeys>

Low-level API. Run the responder side of the handshake. Returns txKey (responder→initiator) and rxKey (initiator→responder).

responderHandshake(send: SendFn, recv: RecvFn, options?: HandshakeOptions): Promise<SessionKeys>

KxcoPqTlsError

Thrown on handshake failure, authentication failure, or malformed frames.

Handshake protocol

ClientHello (1218 bytes):
  [1]    version = 0x01
  [1]    flags   (bit 0 = mutual_auth_requested)
  [1184] ML-KEM-768 ephemeral encapsulation key
  [32]   X25519 ephemeral public key

ServerHello (1122 bytes):
  [1]    version = 0x01
  [1]    flags
  [1088] ML-KEM-768 ciphertext
  [32]   X25519 ephemeral public key

Session keys: HKDF(ss_kem || ss_dh, salt = c_x25519_pk || s_x25519_pk, info = "kxco-pq-tls-v1")

If mutual authentication is requested, both sides exchange a Finished frame (encrypted under the new session keys) containing their ML-DSA-65 public key and a signature over SHA-256(clientHello || serverHello).

Session encryption uses AES-256-GCM with a per-message sequence number as the nonce.

What this does NOT do

Not a replacement for HTTPS/TLS on public servers. If you are running an HTTP server and want quantum-safe transport to browsers, put a PQ-capable reverse proxy (e.g. Cloudflare) in front of it. This package secures the channel between two Node.js processes that both run this code.

Not encryption at rest. For quantum-safe encryption of stored data or blobs, use kxco-pq-vault.

Not a certificate authority. This package does not manage or rotate long-lived identity keys. Key generation and storage is your responsibility — use kxco-pq-hsm if you need HSM-backed key management.

Security

Key exchange uses Noble post-quantum ML-KEM-768 combined with X25519 from Noble curves. Session encryption uses AES-256-GCM from Noble ciphers. All Noble libraries are independently audited by Cure53 (2024). A quantum adversary who breaks X25519 still cannot break the ML-KEM-768 component; both must be broken simultaneously.

To report a vulnerability, open a private security advisory or email [email protected].

Part of the KXCO stack

| Package | Role | |---|---| | kxco-post-quantum | ML-KEM-768 / ML-DSA-65 primitives (NIST FIPS 203 / 204) | | kxco-pq-tls | Encrypted channels for streams and WebSockets | | kxco-pq-hsm | HSM-backed key management | | kxco-pq-attest | Payload attestation envelopes | | kxco-pq-sdk | Integration layer |

License

Apache-2.0 © 2026 KXCO by Knightsbridge

Authors

Shayne Heffernan and John Heffernan — KXCO by Knightsbridge

Deployed in production at target150.com, knightsbridgelaw.com, livetradingnews.com.