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

@smartledger/crypto

v2.0.0

Published

Pluggable cryptographic signature suite abstraction for Lumen agents - Now with proper ML-DSA-44/65/87 implementations

Readme

@smartledger/crypto

Production-ready cryptographic abstractions for post-quantum cryptography.

Version: 1.0.0
Status: ✅ Production Ready
Tests: 68/68 passing


Overview

@smartledger/crypto provides a unified interface for classical and post-quantum cryptographic algorithms. Built on industry-standard implementations:

  • ECDSA (secp256k1) via @noble/secp256k1 - Audited, constant-time
  • ML-DSA-87 (FIPS 204) via native WASM bindings - NIST-standardized post-quantum signatures

This is the low-level foundation for the SmartLedger key management SDK.


Installation

npm install @smartledger/crypto

Why This Package?

Problems It Solves

Without unified abstractions:

  • Different APIs for ECDSA vs ML-DSA
  • Scattered suite registration across repos
  • Hard to swap algorithms (tight coupling)
  • Manual format conversions (hex, base64, Uint8Array)

With @smartledger/crypto:

  • Single SignatureSuite interface for all algorithms
  • Registry pattern for runtime suite selection
  • Crypto agility: Suite is config, not code
  • Consistent keypair/signature handling

Quick Start

import {
  BsvEcdsaSuite,
  MlDsa87Suite,
  SuiteRegistry,
} from '@smartledger/crypto';

// Setup registry
const registry = new SuiteRegistry();
registry.register(new BsvEcdsaSuite());
registry.register(new MlDsa87Suite());

// Generate ML-DSA keypair
const mlDsaSuite = registry.getSuite('ml-dsa-87');
const mlKeypair = await mlDsaSuite.generateKeypair();

// Sign
const message = new TextEncoder().encode('hello quantum world');
const signature = await mlDsaSuite.sign(mlKeypair.privateKey, message);

// Verify
const valid = await mlDsaSuite.verify(mlKeypair.publicKey, message, signature);
console.log(valid); // true

Core Concepts

SignatureSuite Interface

All signature algorithms implement this interface:

interface SignatureSuite {
  suiteId: string;
  
  generateKeypair(): Promise<KeypairResult>;
  sign(privateKey: Uint8Array, message: Uint8Array): Promise<Uint8Array>;
  verify(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array): Promise<boolean>;
  
  formatPublicKey?(publicKey: Uint8Array): string;
  formatPrivateKey?(privateKey: Uint8Array): string;
  formatSignature?(signature: Uint8Array): string;
}

Suite Registry

Runtime suite selection without tight coupling:

const registry = new SuiteRegistry();
registry.register(new BsvEcdsaSuite());
registry.register(new MlDsa87Suite());

// Get suite by ID
const suite = registry.getSuite('ml-dsa-87');

// List available suites
const suiteIds = registry.listSuites(); // ['bsv-ecdsa-secp256k1', 'ml-dsa-87']

Key Storage

Low-level key registry for storing keypairs:

import { KeyRegistry, InMemoryKeyStorage } from '@smartledger/crypto';

const keyRegistry = new KeyRegistry(new InMemoryKeyStorage());

// Register a key
await keyRegistry.registerKey('my-key-id', keypair, 'ml-dsa-87');

// Retrieve
const stored = await keyRegistry.getKey('my-key-id');
console.log(stored.meta.suiteId); // 'ml-dsa-87'
console.log(stored.keypair.publicKey); // Uint8Array

Available Suites

BsvEcdsaSuite (bsv-ecdsa-secp256k1)

Classical ECDSA using secp256k1 curve (Bitcoin/BSV compatible).

  • Implementation: @noble/secp256k1 v2.2.0
  • Security: Audited, constant-time
  • Key Size: 32 bytes private, 33 bytes public (compressed)
  • Signature: 64 bytes (compact)
const suite = new BsvEcdsaSuite();
const keypair = await suite.generateKeypair();
// keypair.publicKey: 33 bytes
// keypair.privateKey: 32 bytes

const sig = await suite.sign(keypair.privateKey, message);
// sig: 64 bytes

ML-DSA Suites (Post-Quantum)

⚠️ IMPORTANT: All ML-DSA suites currently use the ML-DSA-87 implementation.

MlDsa87Suite (ml-dsa-87) ✅ Correct Implementation

Post-quantum ML-DSA (FIPS 204, security level 5).

  • Implementation: Native WASM via dilithium-crystals
  • Security: NIST Level 5 (equivalent to AES-256), quantum-resistant
  • Key Size: 4864 bytes private, 2592 bytes public
  • Signature: ~4597 bytes
  • Status: ✅ Fully implemented correctly
const suite = new MlDsa87Suite();
const keypair = await suite.generateKeypair();
// keypair.publicKey: 2592 bytes
// keypair.privateKey: 4864 bytes

const sig = await suite.sign(keypair.privateKey, message);
// sig: ~4597 bytes

MlDsa65Suite (ml-dsa-65) ⚠️ Uses ML-DSA-87

Intended: NIST Level 3 (AES-192 equivalent)
Actual: Uses ML-DSA-87 implementation (Level 5)

  • Claimed Spec: 1952 byte public keys, 3309 byte signatures
  • Actual Sizes: 2592 byte public keys, 4597 byte signatures (same as ML-DSA-87)
  • Security: ✅ Enhanced (Level 5 instead of Level 3)
  • Size Overhead: ⚠️ 33-39% larger than intended
  • Status: Placeholder - proper implementation coming in v2.0.0
const suite = new MlDsa65Suite();
// Currently produces ML-DSA-87 sized keys/signatures
// See ML-DSA_IMPLEMENTATION_STATUS.md for details

MlDsa44Suite (ml-dsa-44) ⚠️ Uses ML-DSA-87

Intended: NIST Level 2 (AES-128 equivalent)
Actual: Uses ML-DSA-87 implementation (Level 5)

  • Claimed Spec: 1312 byte public keys, 2420 byte signatures
  • Actual Sizes: 2592 byte public keys, 4597 byte signatures (same as ML-DSA-87)
  • Security: ✅ Enhanced (Level 5 instead of Level 2)
  • Size Overhead: ⚠️ 90% larger than intended
  • Status: Placeholder - proper implementation coming in v2.0.0
const suite = new MlDsa44Suite();
// Currently produces ML-DSA-87 sized keys/signatures
// See ML-DSA_IMPLEMENTATION_STATUS.md for details

Recommendation: Use MlDsa87Suite directly until v2.0.0 implements true ML-DSA-44/65 support.

For complete details, see ML-DSA_IMPLEMENTATION_STATUS.md.


API Reference

SuiteRegistry

register(suite: SignatureSuite): void

Register a signature suite.

registry.register(new MlDsa87Suite());

getSuite(suiteId: string): SignatureSuite

Get a registered suite by ID.

const suite = registry.getSuite('ml-dsa-87');

listSuites(): string[]

List all registered suite IDs.

const ids = registry.listSuites(); // ['bsv-ecdsa-secp256k1', 'ml-dsa-87']

KeyRegistry

registerKey(keyId: string, keypair: KeypairResult, suiteId: string, meta?: Partial<KeyMeta>): Promise<void>

Store a keypair.

await keyRegistry.registerKey('agent-1:pk-1', keypair, 'ml-dsa-87', {
  agentId: 'agent-1',
  status: 'active',
});

getKey(keyId: string): Promise<StoredKey | null>

Retrieve a stored keypair.

const stored = await keyRegistry.getKey('agent-1:pk-1');
if (stored) {
  console.log(stored.meta.suiteId);
  console.log(stored.keypair.publicKey);
}

listKeys(agentId?: string): Promise<KeyMeta[]>

List all keys, optionally filtered by agent.

const allKeys = await keyRegistry.listKeys();
const agentKeys = await keyRegistry.listKeys('agent-1');

deleteKey(keyId: string): Promise<void>

Remove a key from storage.

await keyRegistry.deleteKey('agent-1:pk-1');

Storage Backends

InMemoryKeyStorage

Default in-memory storage (resets on restart).

const storage = new InMemoryKeyStorage();
const registry = new KeyRegistry(storage);

Custom Storage

Implement KeyStorage interface for persistent storage:

interface KeyStorage {
  get(keyId: string): Promise<StoredKey | null>;
  set(keyId: string, key: StoredKey): Promise<void>;
  delete(keyId: string): Promise<void>;
  list(agentId?: string): Promise<KeyMeta[]>;
}

Example: File-based storage

class FileKeyStorage implements KeyStorage {
  async get(keyId: string) { /* read from file */ }
  async set(keyId: string, key: StoredKey) { /* write to file */ }
  // ...
}

const registry = new KeyRegistry(new FileKeyStorage());

Testing

npm test

Coverage:

  • ✅ 68 tests passing
  • ✅ ECDSA: Sign/verify, keypair generation, format utils
  • ✅ ML-DSA: Sign/verify, keypair generation, large messages
  • ✅ Registry: Suite registration, lookup, errors
  • ✅ KeyRegistry: Store/retrieve/list/delete operations

Security Notes

ECDSA (Noble)

  • Audited by Cure53 and independent researchers
  • Constant-time scalar multiplication (timing-attack resistant)
  • No dependencies (minimal supply chain risk)
  • Deterministic signatures (RFC 6979)

ML-DSA (WASM)

  • NIST-standardized (FIPS 204)
  • Reference implementation bindings
  • Quantum-resistant (lattice-based)
  • Deterministic (no random oracle in signing)

General

  • Never log private keys
  • Use KeyRegistry for secure storage
  • Rotate keys regularly (see @smartledger/keys SDK)
  • Validate all inputs before cryptographic operations

Integration

This package is the foundation layer. Most users should use the higher-level SDK:

npm install @smartledger/keys

The @smartledger/keys SDK provides:

  • Agent-based key management
  • Automatic key rotation
  • Crypto profiles
  • Private key hiding
  • Idempotent operations

See @smartledger/keys documentation for full SDK usage.


Browser Support

Full browser support via ESM bundle (161.6 KB gzipped):

<script type="module">
  import { BsvEcdsaSuite, MlDsa87Suite } from '@smartledger/keys/browser';
  
  const suite = new MlDsa87Suite();
  const keypair = await suite.generateKeypair();
</script>

Browser bundle includes WASM for ML-DSA.


Dependencies

Production

Development

Total size: ~46 KB (without WASM, ~200 KB with ML-DSA WASM)


What's Next?

  • Additional PQ suites (ML-KEM-768 for encryption)
  • Falcon support (smaller signatures)
  • Hardware security module (HSM) integration
  • Key derivation functions (KDF)

Summary

@smartledger/crypto provides the cryptographic foundation:

✅ 68 tests passing
✅ Unified interface (ECDSA + ML-DSA)
✅ Registry pattern (crypto agility)
✅ Audited implementations
✅ Production-ready

Use @smartledger/keys SDK for high-level key management.


Version: 1.0.0
License: MIT
Last Updated: November 28, 2025