npm package: @smartledger/crypto
Description: Pluggable cryptographic signature suite abstraction for Lumen agents - Now with proper ML-DSA-44/65/87 implementations
Author: Gregory Ward
Latest version: 2.0.0

# @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](https://github.com/paulmillr/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

```bash
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

```typescript
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:

```typescript
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:

```typescript
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:

```typescript
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](https://github.com/paulmillr/noble-secp256k1) v2.2.0
- **Security**: Audited, constant-time
- **Key Size**: 32 bytes private, 33 bytes public (compressed)
- **Signature**: 64 bytes (compact)

```typescript
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

```typescript
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

```typescript
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

```typescript
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](../../ML-DSA_IMPLEMENTATION_STATUS.md).

---

## API Reference

### SuiteRegistry

#### `register(suite: SignatureSuite): void`

Register a signature suite.

```typescript
registry.register(new MlDsa87Suite());
```

#### `getSuite(suiteId: string): SignatureSuite`

Get a registered suite by ID.

```typescript
const suite = registry.getSuite('ml-dsa-87');
```

#### `listSuites(): string[]`

List all registered suite IDs.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
const allKeys = await keyRegistry.listKeys();
const agentKeys = await keyRegistry.listKeys('agent-1');
```

#### `deleteKey(keyId: string): Promise<void>`

Remove a key from storage.

```typescript
await keyRegistry.deleteKey('agent-1:pk-1');
```

---

## Storage Backends

### InMemoryKeyStorage

Default in-memory storage (resets on restart).

```typescript
const storage = new InMemoryKeyStorage();
const registry = new KeyRegistry(storage);
```

### Custom Storage

Implement `KeyStorage` interface for persistent storage:

```typescript
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

```typescript
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

```bash
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:

```bash
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](../keys/README.md) for full SDK usage.

---

## Browser Support

Full browser support via ESM bundle (161.6 KB gzipped):

```html
<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

- `@noble/secp256k1@2.2.0` - ECDSA implementation
- WASM bindings for ML-DSA (bundled)

### Development

- `typescript@5.3.3`
- `vitest@1.0.4`

**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