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

@stvor/web3

v0.3.0

Published

Post-quantum E2EE for TON Web3. ML-KEM-768 + Double Ratchet. Zero dependencies.

Downloads

349

Readme

@stvor/web3

Post-quantum end-to-end encryption for TON Web3.

The first E2EE library built for Web3 that is resistant to quantum computers — today.

Documentation: pqc.stvor.xyz

npm install @stvor/web3

Tests NIST FIPS 203 Zero dependencies TON


Why

Every message sent today can be stored and decrypted later by a quantum computer. This is called a "Store Now, Decrypt Later" attack. It is happening now.

@stvor/web3 uses ML-KEM-768 (NIST FIPS 203, finalized 2024) combined with classical P-256 X3DH in a hybrid scheme. Breaking the encryption requires breaking both — which no computer, classical or quantum, can do simultaneously.

Features

  • Hybrid post-quantum X3DH — ML-KEM-768 + P-256, HKDF-combined
  • Double Ratchet — forward secrecy and break-in recovery (Signal Protocol)
  • TON wallet identityuserId = wallet address. No accounts, no passwords
  • Account Abstraction — ERC-4337 (Safe, Coinbase, Biconomy, ZeroDev) + TON Wallet v5
  • UserOperation binding — cryptographically binds E2EE session to a specific AA op
  • On-chain key registry — public keys stored in a FunC smart contract
  • TON Storage delivery — encrypted messages stored off-chain, decentralised
  • Zero dependencies — 0 npm runtime dependencies. WASM crypto core (Rust)
  • NIST verified — 53 official ACVTS test vectors (ECDH, ECDSA, AES-GCM, HKDF)

Crypto stack

Identity:    TON wallet address (signed with Ed25519)
Key exchange: Hybrid X3DH
               ├── P-256 ECDH       (classical, NIST)
               └── ML-KEM-768       (post-quantum, NIST FIPS 203)
               └── HKDF-SHA256 combine → shared secret
Sessions:    Double Ratchet (Signal Protocol)
Encryption:  AES-256-GCM
Signing:     ECDSA P-256 / SHA-256
Implementation: Rust → WASM (270 KB, zero C dependencies)

Quick start

import { StvorWeb3 } from '@stvor/web3';
import initWasm from '@stvor/web3/wasm';

// 1. Load WASM crypto engine
const wasm = await initWasm();

// 2. Connect with TON wallet (TonConnect)
const alice = await StvorWeb3.connect({
  provider: tonConnectProvider,       // TonConnect wallet
  contractAddress: 'EQD...',          // stvor_registry on TON testnet
  tonApiUrl: 'https://testnet.toncenter.com/api/v2',
  wasm,
});

// 3. Listen for incoming messages
alice.onMessage(msg => {
  console.log(`From ${msg.from}:`, msg.data);
});

// 4. Send a post-quantum encrypted message
await alice.send('0:bob_address...', {
  text: 'Hello, quantum-safe Web3!'
});

// 5. Disconnect when done
await alice.disconnect();

Account Abstraction

Works with any EIP-1193 provider — EOA wallet or ERC-4337 smart wallet (Safe, Coinbase, Biconomy, ZeroDev). Also supports TON Wallet v5 extensions.

import { StvorAA } from '@stvor/web3';
import initWasm from '@stvor/web3/wasm';

const wasm = await initWasm();

// ── EVM — ERC-4337 (Safe, Coinbase Smart Wallet, ZeroDev, Biconomy…) ──
const client = await StvorAA.connectEVM({
  provider: window.ethereum,  // any EIP-1193 provider
  chainId: 1,
  wasm,
});
await client.send('0xrecipient...', { text: 'gm from AA wallet!' });

// ── TON — Wallet v5 ──
const tonClient = await StvorAA.connectTON({
  provider: tonConnectProvider,
  wasm,
});

// Bind E2EE session to a UserOperation (ERC-4337)
const binding = client.bindUserOp(userOpHash, sessionRootKey);
// binding.userOpHash / .identitySig / .sessionCommitment

// Verify peer's binding
const ok = client.verifyUserOp(binding, peerIdentityKey, sessionRootKey);

// Sign TON v5 extension body
const ext = tonClient.signTonExtension('deadbeef0102');
const valid = tonClient.verifyTonExtension(ext, peerIk);

How identity derivation works:

personal_sign("STVOR-AA-EVM-v1:{chainId}:{address}")
  → HKDF(sig, msg, "IK",  32)  →  P-256 identity keypair
  → HKDF(sig, msg, "SPK", 32)  →  P-256 signed pre-key
  → wasm_mlkem_keygen()         →  ML-KEM-768 keypair

Same signature always produces the same keys — deterministic and reproducible across sessions.


Installation

npm install @stvor/web3

Requirements: Browser or Node.js ≥ 18 with Web Crypto API and WebAssembly support (available everywhere since 2022).


API reference

StvorWeb3.connect(config)

Creates a client connected to the TON network.

const client = await StvorWeb3.connect({
  provider: TonConnectProvider,   // TON Connect wallet provider
  contractAddress: string,        // stvor_registry contract address
  tonApiUrl: string,              // TonCenter API endpoint
  wasm: WasmModule,               // initialized WASM module
  tonApiKey?: string,             // optional TonCenter API key
  pollIntervalMs?: number,        // message poll interval (default: 5000)
  pqc?: boolean,                  // enable hybrid PQC (default: true)
});

client.send(to, data)

Sends a post-quantum encrypted message to a TON wallet address.

await client.send('0:recipient_address...', {
  text: 'Hello!',
  // any JSON-serializable data
});

client.onMessage(handler)

Registers a handler for incoming messages. Returns an unsubscribe function.

const unsub = client.onMessage(msg => {
  console.log(msg.from);       // TON address
  console.log(msg.data);       // decrypted payload
  console.log(msg.timestamp);  // Date
  console.log(msg.id);         // message ID
});

// Later:
unsub();

client.address

The TON wallet address of this client.

console.log(client.address); // "0:abc123..."

client.chain

Network: 'mainnet' or 'testnet'.

client.disconnect()

Stops polling and clears session state.


Low-level WASM API

For advanced use cases, the Rust crypto primitives are directly accessible:

import initWasm, {
  WasmKeyPair,
  WasmSession,
  wasm_mlkem_keygen,
  wasm_mlkem_encaps,
  wasm_mlkem_decaps,
  wasm_hybrid_initiate,
  wasm_hybrid_respond,
  wasm_ec_sign,
  wasm_ec_verify,
  wasm_hkdf,
} from '@stvor/web3/wasm';

const wasm = await initWasm();

// ML-KEM-768 key generation
const { ek, dk } = JSON.parse(wasm_mlkem_keygen());
// ek = 1184-byte encapsulation key (base64url)
// dk = 64-byte decapsulation key seed (base64url)

// Encapsulate shared secret
const { ct, ss } = JSON.parse(wasm_mlkem_encaps(ek));

// Decapsulate
const ss2 = wasm_mlkem_decaps(dk, ct);
// ss === ss2

// Hybrid X3DH session
const aliceIK  = new WasmKeyPair();
const aliceSPK = new WasmKeyPair();
const bobIK    = new WasmKeyPair();
const bobSPK   = new WasmKeyPair();
const bobPqc   = JSON.parse(wasm_mlkem_keygen());

// Alice initiates
const { session_json, mlkem_ct } = JSON.parse(
  wasm_hybrid_session_initiate(aliceIK, aliceSPK, bobIK.public_key, bobSPK.public_key, bobPqc.ek)
);
const alice = WasmSession.from_json(session_json);

// Bob responds
const bob = wasm_hybrid_session_respond(
  bobIK, bobSPK, aliceIK.public_key, aliceSPK.public_key, bobPqc.dk, mlkem_ct
);

// Encrypted messaging
const ct2 = alice.encrypt(new TextEncoder().encode('gm'));
const pt  = bob.decrypt(ct2);
// new TextDecoder().decode(pt) === 'gm'

Smart contract

The stvor_registry FunC contract stores public keys on-chain and tracks message bag IDs.

Testnet address: not yet deployed. Run node contracts/deploy.mjs to get a live address.

ABI:

| Method | Type | Description | |--------|------|-------------| | register_keys | internal | Store IK + SPK + SIG + ML-KEM EK | | store_message | internal | Record a TON Storage bag ID | | delete_message | internal | Remove a bag ID (recipient only) | | get_keys(addr) | get-method | Read public keys for an address | | get_messages(addr) | get-method | List pending message bag IDs | | get_message_count(addr) | get-method | Count pending messages |


Security

Hybrid PQC scheme

shared_key = HKDF-SHA256(
  ikm  = ecdh_sk ‖ mlkem_ss,
  salt = 0x00...00,
  info = "STVOR-HYBRID-v1"
)

This is secure if either ECDH (P-256) or ML-KEM-768 is secure. An attacker must break both simultaneously — impossible with any known classical or quantum algorithm.

NIST ACVTS verification

All cryptographic primitives are verified against official NIST test vectors:

| Algorithm | Standard | Vectors | |-----------|----------|---------| | P-256 ECDH | NIST KAS ECC CDH | 25 | | ECDSA P-256/SHA-256 | NIST FIPS 186-3 SigVer | 15 | | AES-256-GCM | NIST SP 800-38D | 21 | | HKDF-SHA256 | RFC 5869 (NIST SP 800-56C) | 3 |

Forward secrecy

The Double Ratchet protocol ensures that compromising a session key does not expose past messages. Each message uses a fresh symmetric key derived from the ratchet chain.

Key zeroization

All private key material is zeroed from memory after use via the zeroize crate.


Comparison

| | @stvor/web3 | XMTP | Waku | Signal (libsignal) | |---|---|---|---|---| | Post-quantum (ML-KEM-768) | ✅ | ❌ | ❌ | ❌ | | TON wallet identity | ✅ | ❌ | ❌ | ❌ | | Double Ratchet | ✅ | ✅ | ❌ | ✅ | | On-chain key registry | ✅ | ❌ | ❌ | ❌ | | Zero npm dependencies | ✅ | ❌ | ❌ | ❌ | | NIST ACVTS verified | ✅ | ❌ | ❌ | ✅ | | Rust WASM crypto core | ✅ | ❌ | ❌ | ✅ |


Project structure

stvor-web3/
├── crypto-core/          Rust crypto engine
│   └── src/
│       ├── crypto.rs     P-256 ECDH/ECDSA, AES-256-GCM, HKDF, HMAC
│       ├── pqc.rs        ML-KEM-768 (NIST FIPS 203)
│       ├── ratchet.rs    X3DH + Double Ratchet session
│       ├── wasm.rs       WASM bindings (wasm-bindgen)
│       └── nist_tests.rs NIST ACVTS test vectors
│
├── sdk/
│   ├── wasm/             Compiled WASM + TypeScript types (270 KB)
│   └── src/
│       ├── wallet.ts     TON wallet → E2EE identity derivation
│       ├── ton-storage.ts TON Storage + contract client
│       ├── stvor.ts      Main client (StvorWeb3)
│       └── index.ts      Public API exports
│
└── contracts/
    ├── stvor_registry.fc FunC smart contract
    ├── StvorRegistry.ts  TypeScript wrapper
    └── deploy.mjs        Testnet deployment script

Deploy contract (testnet)

cd contracts
npm install

# Set your wallet mnemonic
export STVOR_MNEMONIC="word1 word2 ... word24"

# Deploy to TON testnet
node deploy.mjs

# Output:
# Contract address: EQD...
# ✓ Deployed successfully!

Get testnet TON from @testgiver_ton_bot.


Contributing

# Run all tests (53 total)
cd crypto-core && cargo test        # 28 Rust tests (incl. NIST vectors)
cd sdk && node --experimental-wasm-modules --import tsx/esm src/__tests__/wasm.test.ts  # 17 WASM tests
cd contracts && node --import tsx/esm tests/registry.test.ts  # 8 contract tests

# Rebuild WASM after Rust changes
cd crypto-core && wasm-pack build --target web --out-dir ../sdk/wasm

Current status and known limitations

Pre-production (v0.2.0). The cryptographic core is complete and NIST-verified. The TON integration layer is functional but requires a deployed contract.

ML-KEM decapsulation key representation

wasm_mlkem_keygen() returns a 64-byte dk value. This is the seed (d ‖ z) from FIPS 203 §7.1, not the 2400-byte expanded decapsulation key. The full expanded key is re-derived from the seed on every call to wasm_mlkem_decaps() — this is the canonical private key representation recommended by FIPS 203 and used by the RustCrypto ml-kem crate. The 64-byte seed is functionally equivalent and more compact. Keep it secret.

TON integration

| Component | Status | |---|---| | stvor_registry.fc FunC contract | ✅ Compiled, source open | | Contract deployment | ⚠️ Not yet deployed — run node contracts/deploy.mjs | | buildRegisterKeysBody() cell builder | ✅ Covers stvor_registry ABI | | fetchKeys() / fetchMessages() | ✅ Implemented via TonCenter v2 HTTP API | | parseMsgMetaDict() | ⚠️ Parses TonCenter v2 response format — test against your endpoint | | TON Storage message delivery | ⚠️ Requires TON Storage daemon on target network |

Open source

All source code — including the Rust cryptographic core (crypto-core/) — is published in this repository. The WASM binary in sdk/wasm/ is built deterministically from crypto-core/src/ using wasm-pack. To verify:

git clone https://github.com/sapogeth/web3-sdk
cd web3-sdk/crypto-core
cargo test                                          # run NIST test vectors
wasm-pack build --target web --out-dir ../sdk/wasm # reproduce the binary

License

MIT — stvor.xyz


Docs: pqc.stvor.xyz · npm: @stvor/web3 · TON: testnet