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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@tectonic-labs/hybrid-hd-wallet

v0.1.0-rc.1

Published

Hybrid HD wallet with ECDSA and Falcon-512 signatures from single mnemonic (Rust + WASM)

Readme

Hybrid HD Wallet

A hybrid hierarchical deterministic wallet supporting both classical (ECDSA secp256k1) and post-quantum (Falcon-512) signature schemes from a single BIP-39 mnemonic.

Built with Rust and compiled to WebAssembly for maximum performance and security.


Features

  • Multi-Scheme Support: Derive keys for multiple signature schemes (ECDSA secp256k1, Falcon-512)
  • Single Mnemonic: Use one BIP-39 mnemonic to derive all scheme-specific seeds
  • BIP-85 Derivation: Derive scheme-specific seeds using the BIP-85 standard
  • Deterministic: All keys are deterministically derived from the master seed
  • Cryptographic Separation: Each signature scheme uses independent derivation paths
  • WebAssembly: Works in Node.js, browsers, and modern bundlers (Vite, Webpack, Rollup)
  • Type-Safe: Full TypeScript definitions included

Installation

npm install @tectonic-labs/hybrid-hd-wallet
# or
yarn add @tectonic-labs/hybrid-hd-wallet
# or
pnpm add @tectonic-labs/hybrid-hd-wallet

Quick Start

Node.js

import { HHDWallet, SignatureScheme } from "@tectonic-labs/hybrid-hd-wallet";

// Create wallet with both signature schemes
const wallet = new HHDWallet(
  [SignatureScheme.EcdsaSecp256k1, SignatureScheme.Falcon512],
  null // Optional BIP-39 passphrase
);

// Get mnemonic phrase (24 words)
const mnemonic = wallet.mnemonic();
console.log("Mnemonic:", mnemonic);

// Derive keypair for ECDSA at address index 0
const ecdsaKeypair = wallet.deriveKeypairForScheme(
  SignatureScheme.EcdsaSecp256k1,
  0
);
console.log("ECDSA Public Key:", ecdsaKeypair.publicKey);
console.log("ECDSA Private Key:", ecdsaKeypair.privateKey);

// Sign with ECDSA
const message = "Hello, Web3!";
const signature = wallet.signWithScheme(
  SignatureScheme.EcdsaSecp256k1,
  0, // address index
  message
);

// Verify signature
const isValid = wallet.verifyWithScheme(
  SignatureScheme.EcdsaSecp256k1,
  0,
  message,
  signature
);
console.log("Valid:", isValid); // true

// Clean up WASM resources when done
ecdsaKeypair.free();
wallet.free();

Browser with Vite

Step 1: Install the Vite WASM plugin:

npm install vite-plugin-wasm

Step 2: Configure your vite.config.ts:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import wasm from "vite-plugin-wasm";

export default defineConfig({
  plugins: [react(), wasm()],
});

Step 3: Initialize WASM and use the library:

import init, {
  HHDWallet,
  SignatureScheme,
} from "@tectonic-labs/hybrid-hd-wallet";

// IMPORTANT: Call init() before using any WASM functionality
// The vite-plugin-wasm helps load .wasm files, but doesn't auto-initialize
await init();

// Now create wallet
const wallet = new HHDWallet(
  [SignatureScheme.EcdsaSecp256k1, SignatureScheme.Falcon512],
  null
);

// Derive keypair
const keypair = wallet.deriveKeypairForScheme(
  SignatureScheme.EcdsaSecp256k1,
  0
);
console.log("Public key:", keypair.publicKey);

// Don't forget to clean up!
keypair.free();
wallet.free();

Note: For Web Workers or other browser environments, you can also manually load the WASM:

import init from "@tectonic-labs/hybrid-hd-wallet";

// Fetch and initialize manually
const wasmUrl = new URL(
  "@tectonic-labs/hybrid-hd-wallet/dist/web/hybrid_hd_wallet_bg.wasm",
  import.meta.url
);
const response = await fetch(wasmUrl);
const wasmBytes = await response.arrayBuffer();
await init(wasmBytes);

Environment Support

Node.js

  • Node.js 18+ (ESM and CommonJS)
  • Auto-detects and uses Node.js-optimized build
  • WASM auto-initializes - no setup needed

Browser (with bundlers)

  • Vite - Requires vite-plugin-wasm plugin (see example above)
  • Webpack 5+ - Auto-handles WASM (may need config for Webpack 4)
  • Rollup - Works with @rollup/plugin-wasm
  • Next.js - Works with next.config.js wasm config
  • Important: Call await init() before using the library in browser environments

Browser Support

  • Chrome/Edge 91+
  • Firefox 89+
  • Safari 15+
  • Requires WebAssembly support

API Reference

WASM Initialization

init()

init(module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>

Initializes the WASM module. Required for browser/web environments before using any other functions. Node.js auto-initializes, so this is a no-op there.

Example:

import init, { HHDWallet, SignatureScheme } from "@tectonic-labs/hybrid-hd-wallet";

// Browser: Initialize once before using the library
await init();

// Now you can use the library
const wallet = new HHDWallet([SignatureScheme.EcdsaSecp256k1], null);

HHDWallet

Constructor

new HHDWallet(schemes: number[], passphrase: string | null)

Creates a new wallet with a random mnemonic.

  • schemes: Array of signature schemes to enable (e.g., [SignatureScheme.EcdsaSecp256k1])
  • passphrase: Optional BIP-39 passphrase for additional security

Static Methods

HHDWallet.newFromMnemonic(
  mnemonic: string,
  schemes: number[],
  passphrase: string | null
): HHDWallet

Creates a wallet from an existing BIP-39 mnemonic phrase (24 words).

Instance Methods

mnemonic(): string

Returns the wallet's BIP-39 mnemonic phrase (24 words).

deriveKeypairForScheme(scheme: SignatureScheme, addressIndex: number): Keypair

Derives a keypair for the specified scheme and address index. Returns a Keypair object with publicKey and privateKey as Uint8Array.

Important: Call keypair.free() when done to release WASM memory.

signWithScheme(
  scheme: SignatureScheme,
  addressIndex: number,
  message: string
): string

Signs a message with the specified scheme and address index. Returns hex-encoded signature.

verifyWithScheme(
  scheme: SignatureScheme,
  addressIndex: number,
  message: string,
  signature: string
): boolean

Verifies a signature. Returns true if valid.

signWithAllSchemes(addressIndex: number, message: string): Map<number, string>

Signs with all enabled schemes. Returns a map of scheme ID to signature.

verifyWithAllSchemes(
  addressIndex: number,
  message: string,
  signatures: Map<number, string>
): boolean

Verifies signatures for all enabled schemes. Returns true if all are valid.

free(): void

Releases WASM memory. Call this when you're done with the wallet instance.

SignatureScheme

Enum of available signature schemes:

enum SignatureScheme {
  EcdsaSecp256k1 = 1,
  Falcon512 = 2,
}

Keypair

class Keypair {
  publicKey: Uint8Array; // Raw public key bytes
  privateKey: Uint8Array; // Raw private key bytes
  free(): void; // Release WASM memory
}

Utility Functions

generateMnemonic(): string

Generates a new 24-word BIP-39 mnemonic phrase.

validateMnemonic(mnemonic: string): boolean

Validates a BIP-39 mnemonic phrase.


Architecture

The hybrid HD wallet architecture enables multiple signature schemes to coexist within a single wallet structure while maintaining cryptographic separation.

Derivation Paths

BIP-85 Scheme Seed Derivation

Each signature scheme gets its own unique seed through BIP-85 derivation:

  • ECDSA secp256k1: m/83696968'/83286642'/1'
  • Falcon-512: m/83696968'/83286642'/2'

The base path m/83696968' is the standard BIP-85 path, /83286642' stands for "Tectonic" in T9 keypad encoding, and the final component identifies the signature scheme.

Key Derivation Paths

ECDSA secp256k1 (BIP-32, BIP-44):

  • Domain separator: Bitcoin seed
  • Full path: m/44'/60'/0'/0/{address_index}
  • Standard: BIP-32 (non-hardened address index)

Falcon-512 (SLIP-0010, hardened):

  • Domain separator: Falcon-512-v1 seed
  • Full path: m/44'/60'/0'/0'/{address_index}'
  • Standard: SLIP-0010 (all components hardened)

For more details, see the Architecture documentation.


Standards Used

  • BIP-39: Mnemonic code for generating deterministic keys
  • BIP-32: Hierarchical Deterministic Wallets
  • BIP-44: Multi-Account Hierarchy for Deterministic Wallets
  • BIP-85: Deterministic Entropy From BIP32 Keychains
  • SLIP-0010: Universal private key derivation from master private key

Security

This library handles sensitive cryptographic material. Always:

  • Store mnemonics securely (never in plain text)
  • Use BIP-39 passphrases for additional security
  • Verify signatures before trusting them
  • Keep your dependencies up to date
  • Call .free() on WASM objects to clear memory

Note: While Falcon-512 is a NIST-selected post-quantum algorithm, this library is provided as-is for research and development. Conduct your own security audit before using in production.


FAQ

Why post-quantum cryptography?

Quantum computers pose a threat to current cryptographic systems like ECDSA. Falcon-512 is a NIST-selected post-quantum signature scheme that remains secure against quantum attacks.

Can I use just ECDSA or just Falcon?

Yes! Specify only the schemes you need when creating the wallet:

// ECDSA only
const wallet = new HHDWallet([SignatureScheme.EcdsaSecp256k1], null);

// Falcon only
const wallet = new HHDWallet([SignatureScheme.Falcon512], null);

Is the mnemonic compatible with other wallets?

The mnemonic is BIP-39 compatible (24 words). However, the scheme-specific derivation uses BIP-85, so you'll need this library to restore the same keys. Standard BIP-44 wallets will derive different keys.

Do I need to call .free()?

Yes, for optimal memory management. WebAssembly doesn't have automatic garbage collection, so you should call .free() on wallet and keypair objects when you're done with them.


License

MIT © Tectonic Labs