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

@majikah/majik-key

v0.1.8

Published

A post-quantum ready seed phrase account library for the Majikah ecosystem. Manages deterministic X25519 and ML-KEM-768 identities with Argon2id protection and seamless legacy account migration.

Readme

Majik Key

Developed by Zelijah GitHub Sponsors

Majik Key is a next-generation seed phrase account library for creating and managing mnemonic-based identities. It provides a post-quantum ready, high-security bridge between BIP39 mnemonics and the Majikah ecosystem.

npm npm downloads npm bundle size License TypeScript



Next-Gen Security Architecture

Majik Key has been upgraded to meet modern and future cryptographic standards.

1. Post-Quantum Ready (ML-KEM)

Every identity now generates a dual-key system derived deterministically from a 64-byte BIP39 seed:

  • X25519 (Curve25519): Derived from the first 32 bytes of the seed. Used for fingerprints, contact identity, and legacy compatibility.
  • ML-KEM-768 (FIPS-203): Derived from the full 64-byte seed. Provides post-quantum key encapsulation for "v3" secure envelopes.

2. Argon2id Key Derivation

We have transitioned to Argon2id (KDF v2) for encrypting private keys at rest.

  • Memory-Hard: Configured with 64 MB of memory, 3 iterations, and 4 parallelism factors.
  • Brute-Force Resistant: Engineered to defeat GPU and ASIC-based cracking attempts that easily bypass older PBKDF2 implementations.

3. Seamless Auto-Migration

The library handles "Security Debt" automatically during standard workflows:

  • On Import: importFromMnemonicBackup() detects v1 (PBKDF2) accounts and performs a full upgrade to v2.
  • Deterministic Recovery: If ML-KEM keys are missing from an old backup, they are re-derived from the mnemonic during the upgrade process.
  • Password Updates: Changing a passphrase via updatePassphrase() automatically migrates the account to the latest Argon2id standard.

Overview

Majik Key is a comprehensive library for managing seed phrase-based cryptographic accounts. It provides a secure, intuitive way to create, store, and manage mnemonic-based identities with built-in encryption, backup, and recovery features.

What is a Majik Key?

A Majik Key is a seed phrase account that:

  • Derives cryptographic key pairs from BIP39 mnemonic phrases
  • Encrypts private keys at rest with a user-defined passphrase
  • Supports secure backup and recovery via mnemonic encryption
  • Provides locked/unlocked state management for enhanced security
  • Is fully compatible with Majik Message and other Majikah products

Use Cases

  • Majik Message Integration: Create seed phrase accounts that can be imported directly into Majik Message
  • Cryptographic Identity Management: Manage multiple identities with deterministic key derivation
  • Secure Messaging: Generate signing keys for end-to-end encrypted communication
  • Blockchain Applications: Create wallet-like accounts from mnemonic phrases
  • Majikah Ecosystem: Use across all Majikah products and services

Features

Security & Post-Quantum Readiness

  • Post-Quantum Ready: Implements ML-KEM-768 (FIPS-203) for key encapsulation, ensuring identities are secure against future quantum computing threats.
  • Argon2id Key Derivation: Uses memory-hard Argon2id (KDF v2) for passphrase encryption (64 MB / 3 iterations / 4 parallelism), providing industry-leading resistance to GPU/ASIC brute-force attacks.
  • Seamless Auto-Migration: Automatically detects and upgrades legacy v1 (PBKDF2) accounts to v2 (Argon2id) during import, re-deriving missing ML-KEM keys deterministically from the seed.
  • AES-GCM Authenticated Encryption: Industry-standard encryption for private keys at rest with unique, per-identity salts and random IVs.
  • Locked/Unlocked States: Private keys are only decrypted into memory when explicitly unlocked and are purged immediately upon calling .lock().

BIP39 Compliance & Key Derivation

  • Standard Mnemonic Generation: Generate high-entropy 12 or 24-word seed phrases (128/256-bit strength).
  • Deterministic Multi-Key Derivation:
    • X25519 (Curve25519): Derived from the first 32 bytes of the seed for legacy compatibility and fingerprints.
    • ML-KEM-768: Derived from the full 64-byte seed for post-quantum security.
  • Built-in Validation: Full BIP39 mnemonic validation and error handling.

Developer Experience

  • First-Class TypeScript Support: Full type definitions included for all interfaces and classes.
  • Fluent API: Intuitive method chaining for common operations (e.g., key.unlock(p).updateLabel(l)).
  • Comprehensive Error Handling: Specialized MajikKeyError and CryptoError classes for precise debugging.
  • Isomorphic Support: Works across Node.js and modern browser environments.

Import / Export & Storage

  • Security-Minded JSON Serialization: Export accounts to JSON format for storage without ever exposing raw private keys or seed phrases.
  • MnemonicJSON Format: A secure, portable format for seed phrase storage and recovery.
  • Mnemonic-Encrypted Backups: Export and import specialized backup strings that utilize the mnemonic as a secondary encryption layer.

Interoperability

  • Majik Message Integration: Native support for exporting identities compatible with Majik Message v3 envelopes.
  • Contact Portability: Convert Majik Keys directly into contact formats for easy sharing of public identities.
  • Ecosystem Ready: Designed as the core identity provider for all current and future Majikah products.

Installation

# Using npm
npm install @majikah/majik-key

Quick Start

import { MajikKey } from '@majikah/majik-key';

// Generate a new mnemonic
const mnemonic = MajikKey.generateMnemonic(); // 12 words
console.log('Save this mnemonic:', mnemonic);

// Create a new Majik Key (unlocked state)
const key = await MajikKey.create(mnemonic, 'secure-passphrase', 'My PQ Account');

// 2. Access your keys (requires unlock)
console.log('Fingerprint:', key.fingerprint);
console.log('PQ Ready:', key.metadata.kdfVersion); // 'argon2id'
console.log('Key ID:', key.id);
console.log('Is Unlocked:', key.isUnlocked); // true

// Lock the key (clear private keys from memory)
key.lock();
console.log('Is Locked:', key.isLocked); // true

// Unlock when needed
await key.unlock('my-secure-passphrase');
console.log('Is Unlocked:', key.isUnlocked); // true

// Access private key (only when unlocked)
const privateKey = key.getPrivateKey();
const privateKeyBase64 = key.getPrivateKeyBase64();

// Save to storage (private keys never included)
const json = key.toJSON();
localStorage.setItem('myKey', JSON.stringify(json));

// Load from storage (locked state)
const loadedKey = MajikKey.fromJSON(json);
await loadedKey.unlock('my-secure-passphrase');

API Reference

Static Methods

MajikKey.create(mnemonic, passphrase, label?)

Create a new Majik Key from a mnemonic phrase. Generates a new Argon2id-protected account.

Parameters:

  • mnemonic: string - BIP39 mnemonic phrase (12-24 words)
  • passphrase: string - Passphrase to encrypt the private key at rest
  • label?: string - Optional label for the key

Returns: Promise<MajikKey> - A new unlocked MajikKey instance

Example:

const mnemonic = 'witch collapse practice feed shame open despair creek road again ice least';
const key = await MajikKey.create(mnemonic, 'my-password', 'Personal Account');

MajikKey.fromJSON(json)

Load a Majik Key from JSON (locked state).

Parameters:

  • json: MajikKeyJSON | string - JSON object or string

Returns: MajikKey - A locked MajikKey instance

Example:

const json = localStorage.getItem('myKey');
const key = MajikKey.fromJSON(json);
await key.unlock('my-password');

MajikKey.fromMnemonicJSON(mnemonicJson, passphrase, label?)

Create a Majik Key from MnemonicJSON format. Auto-migrates legacy PBKDF2 accounts to Argon2id + ML-KEM.

Parameters:

  • mnemonicJson: MnemonicJSON | string - MnemonicJSON object or string
  • passphrase: string - Passphrase to encrypt the key at rest
  • label?: string - Optional label for the key

Returns: Promise<MajikKey> - A new unlocked MajikKey instance

Example:

const mnemonicData = {
  id: 'backup-id',
  seed: ['word1', 'word2', ...],
  phrase: 'optional-encryption-phrase'
};

const key = await MajikKey.fromMnemonicJSON(mnemonicData, 'my-password');

MajikKey.importFromMnemonicBackup(backup, mnemonic, passphrase, label?)

Import a Majik Key from a mnemonic-encrypted backup. Auto-migrates legacy PBKDF2 accounts to Argon2id + ML-KEM.

Parameters:

  • backup: string - Base64-encoded backup string
  • mnemonic: string - The mnemonic phrase used to encrypt the backup
  • passphrase: string - Passphrase to encrypt the imported key
  • label?: string - Optional label for the key

Returns: Promise<MajikKey> - A new unlocked MajikKey instance

Example:

const backupString = 'eT8xY2F...'; // From exportMnemonicBackup()
const key = await MajikKey.importFromMnemonicBackup(
  backupString,
  mnemonic,
  'new-password',
  'Restored Account'
);

MajikKey.generateMnemonic(strength?)

Generate a new BIP39 mnemonic phrase.

Parameters:

  • strength?: 128 | 256 - Entropy strength (128 = 12 words, 256 = 24 words). Default: 128

Returns: string - A new mnemonic phrase

Example:

const mnemonic12 = MajikKey.generateMnemonic();      // 12 words
const mnemonic24 = MajikKey.generateMnemonic(256);   // 24 words

MajikKey.validateMnemonic(mnemonic)

Validate a BIP39 mnemonic phrase.

Parameters:

  • mnemonic: string - Mnemonic phrase to validate

Returns: boolean - true if valid, false otherwise

Example:

const isValid = MajikKey.validateMnemonic('witch collapse practice...');

Instance Methods

unlock(passphrase)

Unlock the Majik Key by decrypting the private key. Decrypts X25519 and ML-KEM private keys into memory.

Parameters:

  • passphrase: string - Passphrase to decrypt the private key

Returns: Promise<this> - This instance for chaining

Throws: MajikKeyError if passphrase is incorrect or key is already unlocked

Example:

await key.unlock('my-password');

lock()

Lock the Majik Key by clearing private keys from memory.

Returns: this - This instance for chaining

Example:

key.lock();

verify(passphrase)

Verify that a passphrase can decrypt the private key.

Parameters:

  • passphrase: string - Passphrase to verify

Returns: Promise<boolean> - true if valid, false otherwise

Example:

const isValid = await key.verify('my-password');

updateLabel(newLabel)

Update the label of the Majik Key.

Parameters:

  • newLabel: string - New label value

Returns: this - This instance for chaining

Example:

key.updateLabel('Work Account');

updatePassphrase(currentPassphrase, newPassphrase)

Change the passphrase used to encrypt the private key. Re-encrypts keys and triggers an auto-migration to KDF v2.

Parameters:

  • currentPassphrase: string - Current passphrase
  • newPassphrase: string - New passphrase

Returns: Promise<this> - This instance for chaining

Throws: MajikKeyError if current passphrase is incorrect

Example:

await key.updatePassphrase('old-password', 'new-password');

getPrivateKey()

Get the private key (only when unlocked).

Returns: CryptoKey | { raw: Uint8Array } - The private key

Throws: MajikKeyError if the key is locked

Example:

const privateKey = key.getPrivateKey();

getPrivateKeyBase64()

Get the private key as base64 (only when unlocked).

Returns: string - The private key in base64 format

Throws: MajikKeyError if the key is locked

Example:

const privateKeyBase64 = key.getPrivateKeyBase64();

toJSON()

Export to JSON format (safe for storage).

Returns: MajikKeyJSON - JSON representation (private keys never included)

Example:

const json = key.toJSON();
localStorage.setItem('myKey', JSON.stringify(json));

toString(pretty?)

Export to JSON string.

Parameters:

  • pretty?: boolean - Whether to pretty-print. Default: false

Returns: string - JSON string representation

Example:

const jsonString = key.toString(true);

toMnemonicJSON(mnemonic, passphrase?)

Export to MnemonicJSON format.

Parameters:

  • mnemonic: string - The BIP39 mnemonic phrase
  • passphrase?: string - Optional passphrase

Returns: MnemonicJSON - MnemonicJSON object

Throws: MajikKeyError if the key is locked

Example:

const mnemonicData = key.toMnemonicJSON(mnemonic, 'encryption-phrase');

exportMnemonicBackup(mnemonic)

Export a mnemonic-encrypted backup.

Parameters:

  • mnemonic: string - The original mnemonic phrase

Returns: Promise<string> - Base64-encoded backup string

Throws: MajikKeyError if the key is locked

Example:

const backup = await key.exportMnemonicBackup(mnemonic);

toContact()

Create a MajikContact from this Majik Key.

Returns: MajikContact - A MajikContact instance

Example:

const contact = key.toContact();

toMajikMessageIdentity(user, options?)

Convert to MajikMessageIdentity for use in Majik Message.

Parameters:

  • user: MajikUser - MajikUser instance
  • options?: { label?: string, restricted?: boolean } - Optional configuration

Returns: Promise<MajikMessageIdentity> - MajikMessageIdentity instance

Example:

const identity = await key.toMajikMessageIdentity(user, {
  label: 'My Account',
  restricted: false
});

Getters

id: string

The unique identifier (fingerprint).

fingerprint: string

The cryptographic fingerprint.

publicKey: CryptoKey | { raw: Uint8Array }

The public key.

publicKeyBase64: string

The public key in base64 format.

label: string

The user-defined label.

backup: string

The mnemonic backup identifier.

timestamp: Date

The creation timestamp.

isLocked: boolean

Whether the key is currently locked.

isUnlocked: boolean

Whether the key is currently unlocked.

metadata: MajikKeyMetadata

Safe metadata object (no sensitive data).

Example:

console.log(key.metadata);
// {
//   id: 'fingerprint-id',
//   fingerprint: 'fingerprint-id',
//   label: 'My Key',
//   timestamp: Date,
//   isLocked: false
// }

Usage Examples

Example 1: Create and Manage a Key

import { MajikKey } from '@majikah/majik-key';

async function createKey() {
  // Generate mnemonic
  const mnemonic = MajikKey.generateMnemonic();
  console.log('🔑 Save this mnemonic safely:', mnemonic);

  // Create key
  const key = await MajikKey.create(
    mnemonic,
    'secure-passphrase',
    'Personal Account'
  );

  console.log('✅ Key created!');
  console.log('ID:', key.id);
  console.log('Fingerprint:', key.fingerprint);
  console.log('Label:', key.label);

  // Save to storage
  const json = key.toJSON();
  localStorage.setItem('myKey', JSON.stringify(json));

  return { key, mnemonic };
}

createKey();

Example 2: Lock/Unlock Pattern

import { MajikKey } from '@majikah/majik-key';

async function secureLockPattern() {
  const json = localStorage.getItem('myKey');
  const key = MajikKey.fromJSON(json);

  // Key is locked by default when loaded from JSON
  console.log('Locked:', key.isLocked); // true

  try {
    // This will throw an error
    const privateKey = key.getPrivateKey();
  } catch (error) {
    console.log('❌ Cannot access private key when locked');
  }

  // Unlock to use private key
  await key.unlock('secure-passphrase');
  console.log('Unlocked:', key.isUnlocked); // true

  // Now we can access private keys
  const privateKey = key.getPrivateKey();
  const privateKeyBase64 = key.getPrivateKeyBase64();

  // Use the key for cryptographic operations
  // ...

  // Lock again when done
  key.lock();
  console.log('🔒 Key locked again');
}

secureLockPattern();

Example 3: Backup and Recovery

import { MajikKey } from '@majikah/majik-key';

async function backupAndRecover() {
  const mnemonic = MajikKey.generateMnemonic();
  const key = await MajikKey.create(mnemonic, 'password123', 'Original Key');

  //Download as Blob JSON File

  const jsonData = await key.toMnemonicJSON(mnemonic, 'password123');
  const jsonString = JSON.stringify(jsonData);
  const blob = new Blob([jsonString], {
    type: "application/json;charset=utf-8",
  });
  downloadBlob(
    blob,
    "json",
    `${label} | ${key.id} | SEED KEY`,
  );



  // Later... recover from backup

  //Parse the downloaded JSON into this object
  const jsonData: MnemonicJSON = {
    id: "abc123",
    seed: ["word1", "word2", ...],
    phrase: 'password123',
  };

  const recoveredKey = await MajikKey.importFromMnemonicBackup(
    jsonData.id,
    seedArrayToString(jsonData.seed),
    jsonData.phrase,
    'Recovered Key'
  );

  console.log('✅ Key recovered!');
  console.log('Same fingerprint:', key.fingerprint === recoveredKey.fingerprint);
}

backupAndRecover();

Example 4: Update Passphrase

import { MajikKey } from '@majikah/majik-key';

async function changePassphrase() {
  const json = localStorage.getItem('myKey');
  const key = MajikKey.fromJSON(json);

  // Must unlock first
  await key.unlock('old-password');

  // Change passphrase
  await key.updatePassphrase('old-password', 'new-secure-password');
  console.log('✅ Passphrase updated!');

  // Save updated key
  localStorage.setItem('myKey', JSON.stringify(key.toJSON()));

  // Verify new passphrase works
  key.lock();
  await key.unlock('new-secure-password');
  console.log('✅ New passphrase verified!');
}

changePassphrase();

Example 5: Verify Passphrase

import { MajikKey } from '@majikah/majik-key';

async function verifyPassphrase() {
  const json = localStorage.getItem('myKey');
  const key = MajikKey.fromJSON(json);

  // Verify without unlocking
  const isValid = await key.verify('user-entered-password');

  if (isValid) {
    console.log('✅ Passphrase is correct');
    await key.unlock('user-entered-password');
    // Proceed with operations...
  } else {
    console.log('❌ Invalid passphrase');
    // Show error to user
  }
}

verifyPassphrase();

Integration with Majik Message

Majik Key is fully compatible with Majik Message as its seed phrase account implementation. Keys created with Majik Key can be directly imported into Majik Message.

Importing to Majik Message

import { MajikKey } from '@majikah/majik-key';

async function importToMajikMessage() {
  // Create or load a Majik Key
  const mnemonic = MajikKey.generateMnemonic();
  const key = await MajikKey.create(mnemonic, 'password', 'Message Account');

  // Export to MnemonicJSON format for Majik Message
  const mnemonicData = key.toMnemonicJSON(mnemonic, 'password');
  const jsonString = JSON.stringify(mnemonicData);

  // Download this blob as a JSON locally
  const blob = new Blob([jsonString], {
    type: "application/json;charset=utf-8",
  });

  // This mnemonicData can be imported directly into Majik Message
  // as a seed phrase account
  console.log('Import the saved JSON to Majik Message:', mnemonicData);
}

Converting to Majik Message Identity

import { MajikKey } from '@majikah/majik-key';
import { MajikUser } from '@thezelijah/majik-user';

async function createMessageIdentity() {
  const mnemonic = MajikKey.generateMnemonic();
  const key = await MajikKey.create(mnemonic, 'password', 'Message Identity');

  // Create/parse a MajikUser instance
  const user = new MajikUser({
    username: 'myusername',
    // ... other user properties
  });

  // Convert to Majik Message Identity
  const identity = await key.toMajikMessageIdentity(user, {
    label: 'My Message Account',
    restricted: false
  });

  console.log('Majik Message Identity created:', identity);
}

Security Considerations

Best Practices

  1. Never expose mnemonics: Treat mnemonic phrases like root passwords. Never log or store them unencrypted.

  2. Lock when not in use: Always call .lock() when private key access is no longer required to purge the heap.

  3. PQ Readiness: For all new communication protocols, ensure you are utilizing the mlKemPublicKey.

Security Summary

  • Primary KDF: Argon2id (64 / 3t / 4p).

  • Legacy KDF: PBKDF2-SHA256 (250,000 iterations).

  • Encryption: AES-256-GCM with unique salts and IVs.

  • Post-Quantum: ML-KEM-768 (Lattice-based cryptography).

What NOT to Do

DON'T store mnemonics in code or version control
DON'T transmit mnemonics over insecure channels
DON'T use weak passphrases like "password123"
DON'T share mnemonics or passphrases with anyone
DON'T screenshot or photograph mnemonics

What TO Do

DO use password managers for mnemonic storage
DO write mnemonics on paper and store securely
DO use hardware security modules when possible
DO test recovery procedures before relying on them
DO keep multiple encrypted backups in different locations


Tips & Reminders

For Developers

  • Remember: Always validate user input before creating or unlocking keys.

  • Security: Never log sensitive data (mnemonics, private keys, passphrases) in production.

  • Performance: Lock keys when not in use to free memory and reduce attack surface.

  • Testing: Test backup/recovery procedures in development before deploying to production.

  • Dependencies: Keep @scure/bip39 and other crypto dependencies up to date.

For Users

  • Backup: Always keep multiple backups of your mnemonic phrase in secure locations.

  • Passphrase: Use a strong, unique passphrase for each Majik Key.

  • Recovery: Test your ability to recover keys from backups before you need to.

  • Organization: Use meaningful labels to identify different keys.

  • Loss Prevention: Losing your mnemonic phrase means permanent loss of access to your key.


Related Projects

Majik Message

Secure messaging platform using Majik Keys

Read more about Majik Message here

Majik Message Thumbnail

Click the image to try Majik Message live.

Read Docs

Also available on Microsoft Store for free.

Official Repository SDK Library


Contributing

If you want to contribute or help extend support to more platforms, reach out via email. All contributions are welcome!


License

Apache-2.0 — free for personal and commercial use.


Author

Made with 💙 by @thezelijah

About the Developer


Contact