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

@cheny56/pqc-wallet

v1.0.0

Published

Post-Quantum Cryptography wallet library for Ethereum/Quorum with BIP-39 mnemonic, ML-DSA-65 keys, and Bech32m addresses

Readme

@pqc-chain/wallet

A Post-Quantum Cryptography wallet library for Ethereum/Quorum with BIP-39 mnemonic support, ML-DSA (Dilithium) keys, and Bech32m addresses.

Features

  • BIP-39 Mnemonic: Standard 12/24-word mnemonic generation and recovery
  • Quantum-Safe Keys: ML-DSA (NIST FIPS 204) post-quantum signatures
  • Multiple Algorithms: ML-DSA-44, ML-DSA-65, ML-DSA-87 support
  • Hybrid Scheme: Combined ECDSA + PQC for gradual migration
  • Bech32m Addresses: Human-readable addresses with error detection
  • Explicit Algorithm HRPs: Algorithm-specific address encoding
  • Multi-Algorithm Future: Support for SLH-DSA and FN-DSA HRPs
  • 32-byte Addresses: Enhanced security with full hash addresses
  • TypeScript: Full type definitions included

Installation

npm install @pqc-chain/wallet

Quick Start

import { createWallet, restoreWallet } from '@pqc-chain/wallet';

// Create a new hybrid wallet (ECDSA + PQC)
const wallet = createWallet({ addressScheme: 'hybrid' });
console.log('Mnemonic:', wallet.mnemonic);

// Get first address
const address = wallet.getAddress(0);
console.log('Address:', address.address);        // pqch1p... (Bech32m)
console.log('Legacy:', address.legacyAddress);   // pqch1q... (Bech32)

// Restore from existing mnemonic
const restored = restoreWallet('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');

ML-DSA Algorithm Support

The library supports all three ML-DSA (Dilithium) variants from NIST FIPS 204:

| Algorithm | Security Level | Public Key | Private Key | Signature | Use Case | |-----------|---------------|------------|-------------|-----------|----------| | ML-DSA-44 | NIST Level 2 | 1,312 bytes | 2,560 bytes | 2,420 bytes | IoT, constrained devices | | ML-DSA-65 | NIST Level 3 | 1,952 bytes | 4,032 bytes | 3,309 bytes | Recommended (default) | | ML-DSA-87 | NIST Level 5 | 2,592 bytes | 4,896 bytes | 4,627 bytes | High-value, long-term |

// Use different algorithms
const wallet44 = createWallet({ pqcAlgorithm: 'ML-DSA-44' });
const wallet65 = createWallet({ pqcAlgorithm: 'ML-DSA-65' }); // default
const wallet87 = createWallet({ pqcAlgorithm: 'ML-DSA-87' });

Specifications

Mnemonic (BIP-39)

| Strength | Words | Entropy | Checksum | Security | |----------|-------|---------|----------|----------| | 128 bits | 12 | 128 | 4 bits | Standard | | 256 bits | 24 | 256 | 8 bits | High |

The seed is always 64 bytes (512 bits), derived using PBKDF2-HMAC-SHA512 with 2048 iterations.

Key Derivation

ECDSA (secp256k1)

  • Method: BIP-32/BIP-44 hierarchical deterministic derivation
  • Default Path: m/44'/60'/0'/0 (Ethereum compatible)
  • Private Key: 32 bytes
  • Public Key: 33 bytes (compressed) / 65 bytes (uncompressed)

PQC (ML-DSA)

  • Method: HKDF-SHA256 with domain separation
  • Domain: pqc-wallet-v1 (default)
  • Info Format: {domain}/{algorithm}/key/{index}
HKDF-Expand(seed, info="pqc-wallet-v1/ML-DSA-65/key/{index}", length=32) → ML-DSA keygen seed

Address Formats

The library supports two HRP naming conventions for maximum flexibility.

HRP Format Overview

Address Format: <hrp>1<version_char><data><checksum>

HRP Types:
  1. Generic (algorithm auto-detected): pqc, pqch
  2. Explicit (algorithm embedded):     mld65, slh128s, fnd512, etc.

Version Characters:
  q - Version 0 (20 bytes, legacy, Bech32)
  p - Version 1 (32 bytes, quantum-safe, Bech32m)

Generic HRPs (Auto-detect Algorithm)

| Type | Version | Bytes | Format | Example | |------|---------|-------|--------|---------| | PQC (legacy) | 0 | 20 | pqc1q<data> | pqc1q... | | PQC (quantum-safe) | 1 | 32 | pqc1p<data> | pqc1p... | | Hybrid (legacy) | 0 | 20 | pqch1q<data> | pqch1q... | | Hybrid (quantum-safe) | 1 | 32 | pqch1p<data> | pqch1p... | | Testnet PQC | 0/1 | 20/32 | tpqc1... | tpqc1p... | | Testnet Hybrid | 0/1 | 20/32 | tpqch1... | tpqch1p... |

Explicit Algorithm HRPs

The explicit format embeds the algorithm in the address HRP: <family><variant>[h]

ML-DSA (Dilithium) - NIST FIPS 204

| Algorithm | PQC HRP | Hybrid HRP | Testnet PQC | Testnet Hybrid | |-----------|---------|------------|-------------|----------------| | ML-DSA-44 | mld44 | mld44h | tmld44 | tmld44h | | ML-DSA-65 | mld65 | mld65h | tmld65 | tmld65h | | ML-DSA-87 | mld87 | mld87h | tmld87 | tmld87h |

SLH-DSA (SPHINCS+) - NIST FIPS 205

| Algorithm | PQC HRP | Hybrid HRP | Description | |-----------|---------|------------|-------------| | SLH-DSA-128s | slh128s | slh128sh | Small signatures, slower | | SLH-DSA-128f | slh128f | slh128fh | Fast signatures, larger | | SLH-DSA-192s | slh192s | slh192sh | Medium security, small | | SLH-DSA-192f | slh192f | slh192fh | Medium security, fast | | SLH-DSA-256s | slh256s | slh256sh | Highest security, small | | SLH-DSA-256f | slh256f | slh256fh | Highest security, fast |

FN-DSA (Falcon) - Expected NIST 2024

| Algorithm | PQC HRP | Hybrid HRP | Description | |-----------|---------|------------|-------------| | FN-DSA-512 | fnd512 | fnd512h | Compact signatures | | FN-DSA-1024 | fnd1024 | fnd1024h | Maximum security |

Using Explicit Algorithm HRPs

import { 
  createWallet, 
  createPQCAddress, 
  parseAddressWithAlgorithm,
  getHRPForFullAlgorithm 
} from '@pqc-chain/wallet';

// Method 1: Create wallet with explicit algorithm in addresses
const wallet = createWallet({
  addressScheme: 'hybrid',
  pqcAlgorithm: 'ML-DSA-65',
  useExplicitAlgorithmHRP: true  // Addresses will start with mld65h1p...
});

// Method 2: Create individual addresses with explicit algorithm
const address = createPQCAddress(publicKey, {
  explicitAlgorithm: 'ML-DSA-65'  // Results in mld651p...
});

// Parse address to extract algorithm hint
const parsed = parseAddressWithAlgorithm('mld651p...');
console.log(parsed.algorithm);  // 'ML-DSA-65'
console.log(parsed.hrp);        // 'mld65'

// Get HRP for any algorithm
const hrp = getHRPForFullAlgorithm('SLH-DSA-128s', false, false); // 'slh128s'
const hybridHrp = getHRPForFullAlgorithm('FN-DSA-512', true, false); // 'fnd512h'

When to Use Each HRP Style

| Scenario | Recommended HRP | Reason | |----------|-----------------|--------| | General use | Generic (pqc, pqch) | Maximum compatibility | | Multi-algorithm deployment | Explicit (mld65, etc.) | Clear algorithm identification | | Debugging | Explicit | Immediate algorithm visibility | | UI display | Explicit | Better user understanding | | Future-proofing | Generic | Flexibility for upgrades |

Address Derivation

PQC Address:
  address = keccak256(pqc_public_key)
  v0 (20 bytes) = address[12:32]
  v1 (32 bytes) = address[0:32]

Hybrid Address:
  address = keccak256(ecdsa_public_key || pqc_public_key)
  v0 (20 bytes) = address[12:32]
  v1 (32 bytes) = address[0:32]

API Reference

Wallet Functions

createWallet(options?)

Create a new wallet with a generated mnemonic.

const wallet = createWallet({
  mnemonicStrength: 256,        // 128 (12 words) or 256 (24 words)
  passphrase: '',               // Optional BIP-39 passphrase
  addressScheme: 'hybrid',      // 'ecdsa', 'pqc', or 'hybrid'
  bip44Path: "m/44'/60'/0'/0",  // BIP-44 path for ECDSA
  pqcAlgorithm: 'ML-DSA-65',    // 'ML-DSA-44', 'ML-DSA-65', or 'ML-DSA-87'
  pqcDomain: 'pqc-wallet-v1',   // Domain separator for PQC
  testnet: false,               // Use testnet HRP
  useLegacyFormat: false,       // Use 20-byte addresses
  useExplicitAlgorithmHRP: false, // Use explicit algorithm in HRP
});

restoreWallet(mnemonic, options?)

Restore a wallet from an existing mnemonic.

const wallet = restoreWallet('word1 word2 ...', {
  addressScheme: 'hybrid',
});

wallet.getAddress(index)

Get address info at a specific derivation index.

const info = wallet.getAddress(0);
console.log(info.address);          // Primary Bech32m address
console.log(info.legacyAddress);    // Legacy Bech32 address
console.log(info.addressBytes);     // Raw address bytes
console.log(info.ecdsaKeyPair);     // ECDSA key pair (if hybrid/ecdsa)
console.log(info.pqcKeyPair);       // PQC key pair (if hybrid/pqc)

Mnemonic Functions

import {
  generateMnemonic,
  validateMnemonic,
  mnemonicToSeed,
  getMnemonicInfo,
} from '@pqc-chain/wallet';

// Generate new mnemonic
const mnemonic = generateMnemonic(256); // 24 words

// Validate mnemonic
const isValid = validateMnemonic(mnemonic); // true

// Convert to seed
const seed = mnemonicToSeed(mnemonic, 'optional-passphrase');
console.log(seed.length); // 64

// Get mnemonic info
const info = getMnemonicInfo(mnemonic);
console.log(info.wordCount);   // 24
console.log(info.entropyBits); // 256

Key Functions

import {
  deriveECDSAKey,
  derivePQCKey,
  derivePQCKey44,
  derivePQCKey87,
  deriveHybridKeys,
  signPQC,
  verifyPQC,
} from '@pqc-chain/wallet';

// Derive ECDSA key
const ecdsaKey = deriveECDSAKey(seed, "m/44'/60'/0'/0", 0);

// Derive PQC key (default ML-DSA-65)
const pqcKey = derivePQCKey(seed, 0);

// Derive PQC key with specific algorithm
const pqcKey44 = derivePQCKey44(seed, 0);
const pqcKey87 = derivePQCKey87(seed, 0);

// Derive both (hybrid)
const { ecdsa, pqc } = deriveHybridKeys(seed, 0, 'ML-DSA-65');

// Sign with PQC
const signature = signPQC(messageHash, pqcKey.privateKey);

// Verify PQC signature (auto-detects algorithm from key size)
const isValid = verifyPQC(messageHash, signature, pqcKey.publicKey);

Address Functions

import {
  createPQCAddress,
  createHybridAddress,
  detectAddressType,
  parseAddress,
  parseAddressWithAlgorithm,
  validateAddress,
  toEVMAddress,
  toBech32m,
  getHRPForFullAlgorithm,
  getFullAlgorithmFromHRP,
  getAlgorithmFamilyFromHRP,
} from '@pqc-chain/wallet';

// Create PQC address (generic HRP)
const pqcAddr = createPQCAddress(publicKey, { testnet: false });

// Create PQC address (explicit algorithm HRP)
const explicitAddr = createPQCAddress(publicKey, { 
  explicitAlgorithm: 'ML-DSA-65' 
});

// Create hybrid address
const hybridAddr = createHybridAddress(ecdsaPubKey, pqcPubKey);

// Create hybrid address with explicit algorithm
const hybridExplicit = createHybridAddress(ecdsaPubKey, pqcPubKey, {
  explicitAlgorithm: 'ML-DSA-87'
});

// Detect address type
const type = detectAddressType('pqc1p...'); // 'pqc-bech32m'

// Parse address with algorithm extraction
const parsed = parseAddressWithAlgorithm('mld651p...');
console.log(parsed.hrp);       // 'mld65'
console.log(parsed.algorithm); // 'ML-DSA-65'
console.log(parsed.data);      // Uint8Array

// Get HRP for algorithm
const hrp = getHRPForFullAlgorithm('SLH-DSA-128s', true, false); // 'slh128sh'

// Extract algorithm from HRP
const algo = getFullAlgorithmFromHRP('mld87h'); // 'ML-DSA-87'
const family = getAlgorithmFamilyFromHRP('slh256s'); // 'SLH-DSA'

// Validate address
const valid = validateAddress('pqc1p...'); // true

// Convert to EVM address
const evmAddr = toEVMAddress('pqc1p...'); // 0x...

HRP Utility Functions

import {
  HRP,
  isHybridHRP,
  isTestnetHRP,
  isValidHRP,
} from '@pqc-chain/wallet';

// Access HRP constants
console.log(HRP.PQC);           // 'pqc'
console.log(HRP.MLDSA_65);      // 'mld65'
console.log(HRP.SLHDSA_128S);   // 'slh128s'
console.log(HRP.FNDSA_512);     // 'fnd512'

// Check HRP properties
console.log(isHybridHRP('mld65h'));   // true
console.log(isTestnetHRP('tmld65'));  // true
console.log(isValidHRP('mld65'));     // true

Bech32m Functions

import {
  encodePQCAddress,
  decodePQCAddress,
  validatePQCBech32Address,
} from '@pqc-chain/wallet';

// Encode address with any valid HRP
const address = encodePQCAddress('mld65', AddressVersion.V1_QUANTUM, addressBytes);

// Decode address
const { hrp, version, data } = decodePQCAddress('mld651p...');

// Validate
const valid = validatePQCBech32Address('mld651p...');

Security Considerations

Quantum Resilience

| Component | Classical Security | Post-Quantum Security | |-----------|-------------------|----------------------| | ECDSA (secp256k1) | 128 bits | 0 bits (broken by Shor) | | ML-DSA-44 | 128 bits | ~100 bits (NIST Level 2) | | ML-DSA-65 | 192 bits | ~128 bits (NIST Level 3) | | ML-DSA-87 | 256 bits | ~192 bits (NIST Level 5) | | Hybrid | min(ECDSA, PQC) | min(ECDSA, PQC) | | 20-byte address | 80 bits* | ~53 bits** | | 32-byte address | 128 bits* | ~85 bits** |

* Against preimage attacks ** Against quantum collision attacks (Grover/BHT)

Recommendations

  1. Use Hybrid Scheme: Provides security even if one algorithm is broken
  2. Use 32-byte Addresses: Better quantum collision resistance
  3. Use 24-word Mnemonic: Higher entropy for long-term security
  4. Use ML-DSA-65 or Higher: Recommended for most use cases
  5. Use Explicit Algorithm HRPs: When clarity about algorithm is important
  6. Backup Securely: Store mnemonic offline in multiple locations
  7. Use Passphrase: Additional protection layer for high-value wallets

Compatibility

Node Compatibility

The wallet library is compatible with the Quorum node's PQC implementation:

  • Same address derivation (keccak256)
  • Same Bech32m encoding with all HRP variants
  • Same ML-DSA parameters (44, 65, 87)
  • Full HRP recognition (generic and explicit)
  • Interoperable signatures

EVM Compatibility

32-byte PQC addresses can be converted to 20-byte EVM addresses for smart contract interaction:

const evmAddress = toEVMAddress(pqcAddress);
// Takes last 20 bytes of the 32-byte address

Examples

The examples/ directory contains comprehensive examples:

| Example | Description | |---------|-------------| | 01-basic-wallet.js | Creating and restoring wallets | | 02-ml-dsa-algorithms.js | Using ML-DSA-44, ML-DSA-65, ML-DSA-87 | | 03-signing-verification.js | Signing and verifying messages | | 04-address-formats.js | Bech32m encoding, HRPs, and conversion | | 05-mnemonic-advanced.js | Mnemonic generation and validation | | 06-typescript-usage.ts | Type-safe TypeScript usage | | 07-key-derivation.js | BIP-44 and HKDF key derivation | | 08-explicit-algorithm-hrp.js | Explicit algorithm HRPs comprehensive guide |

Run an example:

cd pqc-wallet
npm install
node examples/01-basic-wallet.js

Example: Create Wallet with Explicit Algorithm HRP

import { createWallet } from '@pqc-chain/wallet';

// Create wallet with explicit ML-DSA-65 in address HRP
const wallet = createWallet({
  mnemonicStrength: 256,
  addressScheme: 'hybrid',
  pqcAlgorithm: 'ML-DSA-65',
  useExplicitAlgorithmHRP: true,  // Enable explicit HRP
});

// Address will start with mld65h1p... instead of pqch1p...
const address = wallet.getAddress(0);
console.log(address.address);  // mld65h1p...

Example: Parse and Identify Algorithm

import { 
  parseAddressWithAlgorithm, 
  getAlgorithmFamilyFromHRP 
} from '@pqc-chain/wallet';

const address = 'mld651pqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq...';
const parsed = parseAddressWithAlgorithm(address);

console.log('HRP:', parsed.hrp);              // 'mld65'
console.log('Algorithm:', parsed.algorithm);  // 'ML-DSA-65'
console.log('Family:', getAlgorithmFamilyFromHRP(parsed.hrp)); // 'ML-DSA'
console.log('Is Hybrid:', parsed.hrp.endsWith('h')); // false

License

MIT

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

Related