@majikah/majik-key 0.2.12 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,936 +1,392 @@
1
1
  # Majik Key
2
2
 
3
- [![Developed by Zelijah](https://img.shields.io/badge/Developed%20by-Zelijah-red?logo=github&logoColor=white)](https://thezelijah.world) ![GitHub Sponsors](https://img.shields.io/github/sponsors/jedlsf?style=plastic&label=Sponsors&link=https%3A%2F%2Fgithub.com%2Fsponsors%2Fjedlsf)
4
-
5
- **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.
6
-
7
- ![npm](https://img.shields.io/npm/v/@majikah/majik-key) ![npm downloads](https://img.shields.io/npm/dm/@majikah/majik-key) ![npm bundle size](https://img.shields.io/bundlephobia/min/%40majikah%2Fmajik-key) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) ![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue)
8
-
3
+ [![Developed by Zelijah](https://img.shields.io/badge/Developed%20by-Zelijah-red?logo=github&logoColor=white)](https://www.thezelijah.world) ![GitHub Sponsors](https://img.shields.io/github/sponsors/jedlsf?style=plastic&label=Sponsors&link=https%3A%2F%2Fgithub.com%2Fsponsors%2Fjedlsf)
4
+ ![npm](https://img.shields.io/npm/v/@majikah/majik-key) ![npm downloads](https://img.shields.io/npm/dm/@majikah/majik-key) ![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
9
5
 
6
+ **Majik Key** turns a single BIP-39 mnemonic into a complete cryptographic identity — encryption, classical + post-quantum signing, and (experimentally) Bitcoin and Solana keys — encrypted at rest and ready to plug into the rest of the Majikah ecosystem.
10
7
 
11
8
  ---
12
- - [Majik Key](#majik-key)
13
- - [Next-Gen Security Architecture](#next-gen-security-architecture)
14
- - [1. Post-Quantum Ready (ML-KEM)](#1-post-quantum-ready-ml-kem)
15
- - [2. Argon2id Key Derivation](#2-argon2id-key-derivation)
16
- - [3. Seamless Auto-Migration](#3-seamless-auto-migration)
17
- - [Overview](#overview)
18
- - [What is a Majik Key?](#what-is-a-majik-key)
19
- - [Use Cases](#use-cases)
20
- - [Features](#features)
21
- - [Security \& Post-Quantum Readiness](#security--post-quantum-readiness)
22
- - [BIP39 Compliance \& Key Derivation](#bip39-compliance--key-derivation)
23
- - [Developer Experience](#developer-experience)
24
- - [Import / Export \& Storage](#import--export--storage)
25
- - [Interoperability](#interoperability)
26
- - [Installation](#installation)
27
- - [Quick Start](#quick-start)
28
- - [API Reference](#api-reference)
29
- - [Static Methods](#static-methods)
30
- - [`MajikKey.create(mnemonic, passphrase, label?)`](#majikkeycreatemnemonic-passphrase-label)
31
- - [`MajikKey.fromJSON(json)`](#majikkeyfromjsonjson)
32
- - [`MajikKey.fromMnemonicJSON(mnemonicJson, passphrase, label?)`](#majikkeyfrommnemonicjsonmnemonicjson-passphrase-label)
33
- - [`MajikKey.importFromMnemonicBackup(backup, mnemonic, passphrase, label?)`](#majikkeyimportfrommnemonicbackupbackup-mnemonic-passphrase-label)
34
- - [`MajikKey.generateMnemonic(strength?)`](#majikkeygeneratemnemonicstrength)
35
- - [`MajikKey.validateMnemonic(mnemonic)`](#majikkeyvalidatemnemonicmnemonic)
36
- - [Instance Methods](#instance-methods)
37
- - [`unlock(passphrase)`](#unlockpassphrase)
38
- - [`lock()`](#lock)
39
- - [`verify(passphrase)`](#verifypassphrase)
40
- - [`updateLabel(newLabel)`](#updatelabelnewlabel)
41
- - [`updatePassphrase(currentPassphrase, newPassphrase)`](#updatepassphrasecurrentpassphrase-newpassphrase)
42
- - [`getPrivateKey()`](#getprivatekey)
43
- - [`getPrivateKeyBase64()`](#getprivatekeybase64)
44
- - [`toJSON()`](#tojson)
45
- - [`toString(pretty?)`](#tostringpretty)
46
- - [`toMnemonicJSON(mnemonic, passphrase?)`](#tomnemonicjsonmnemonic-passphrase)
47
- - [`exportMnemonicBackup(mnemonic)`](#exportmnemonicbackupmnemonic)
48
- - [`toContact()`](#tocontact)
49
- - [`toMajikMessageIdentity(user, options?)`](#tomajikmessageidentityuser-options)
50
- - [Getters](#getters)
51
- - [`id: string`](#id-string)
52
- - [`fingerprint: string`](#fingerprint-string)
53
- - [`publicKey: CryptoKey | { raw: Uint8Array }`](#publickey-cryptokey---raw-uint8array-)
54
- - [`publicKeyBase64: string`](#publickeybase64-string)
55
- - [`label: string`](#label-string)
56
- - [`backup: string`](#backup-string)
57
- - [`timestamp: Date`](#timestamp-date)
58
- - [`isLocked: boolean`](#islocked-boolean)
59
- - [`isUnlocked: boolean`](#isunlocked-boolean)
60
- - [`metadata: MajikKeyMetadata`](#metadata-majikkeymetadata)
61
- - [Usage Examples](#usage-examples)
62
- - [Example 1: Create and Manage a Key](#example-1-create-and-manage-a-key)
63
- - [Example 2: Lock/Unlock Pattern](#example-2-lockunlock-pattern)
64
- - [Example 3: Backup and Recovery](#example-3-backup-and-recovery)
65
- - [Example 4: Update Passphrase](#example-4-update-passphrase)
66
- - [Example 5: Verify Passphrase](#example-5-verify-passphrase)
67
- - [Integration with Majik Message](#integration-with-majik-message)
68
- - [Importing to Majik Message](#importing-to-majik-message)
69
- - [Converting to Majik Message Identity](#converting-to-majik-message-identity)
70
- - [Security Considerations](#security-considerations)
71
- - [Best Practices](#best-practices)
72
- - [What NOT to Do](#what-not-to-do)
73
- - [What TO Do](#what-to-do)
74
- - [Tips \& Reminders](#tips--reminders)
75
- - [For Developers](#for-developers)
76
- - [For Users](#for-users)
77
- - [Related Projects](#related-projects)
78
- - [Majik Message](#majik-message)
79
- - [Contributing](#contributing)
80
- - [License](#license)
81
- - [Author](#author)
82
- - [About the Developer](#about-the-developer)
83
- - [Contact](#contact)
84
-
85
9
 
10
+ ## Why Majik Key
86
11
 
12
+ - **One seed, one identity, five key pairs.** A 12- or 24-word mnemonic deterministically derives X25519, ML-KEM-768, Ed25519, ML-DSA-87, and (by default) a domain-separated Bitcoin key — all reproducible from the mnemonic alone.
13
+ - **Post-quantum from day one.** Every account gets an ML-KEM-768 (FIPS-203) encryption keypair and an ML-DSA-87 signing keypair alongside their classical counterparts (X25519, Ed25519) — no separate migration project required later.
14
+ - **Encrypted at rest, always.** Private key material is never persisted in plaintext. Everything is AES-256-GCM encrypted using a key derived with Argon2id.
15
+ - **Local-first.** Key generation and derivation run entirely offline — no network request is made in the process, verifiable directly in source.
16
+ - **Built for the Majikah ecosystem**, but usable standalone in any TypeScript/JavaScript project.
87
17
 
88
18
  ---
89
19
 
90
- ## Next-Gen Security Architecture
20
+ ## Security Architecture
91
21
 
92
- Majik Key has been upgraded to meet modern and future cryptographic standards.
22
+ - **Encrypted at rest, not "hashed."** Private keys are **AES-256-GCM encrypted**, using a 256-bit key **derived via Argon2id** from your passphrase. (Argon2id is a key-derivation function, not applied to the private key directly — the private key itself is encrypted, not hashed.)
23
+ - **Argon2id KDF (v2), memory-hard by design.** Passphrase-based encryption uses Argon2id at **64 MB memory / 3 iterations / 4 parallel lanes**, tuned to resist GPU/ASIC brute-force attacks. A WASM implementation (`hash-wasm`) is used when available in the runtime, with an automatic, transparent fallback to a pure-JS implementation (`@noble/hashes`) — output is bit-identical either way, so switching implementations never breaks decryption.
24
+ - **Post-quantum ready.** ML-KEM-768 (FIPS-203) is derived from the full 64-byte BIP-39 seed for encryption/key-encapsulation, and ML-DSA-87 is derived from a domain-separated hash of that same seed for signing — both deterministic and fully recoverable from the mnemonic.
25
+ - **Legacy KDF read support.** Older accounts encrypted with KDF v1 (PBKDF2-SHA256, 200k–250k iterations) can still be unlocked. New accounts, and any account whose passphrase is changed via `updatePassphrase()`, always land on Argon2id (v2).
26
+ - **Full migration path.** `importFromMnemonicBackup()` re-derives a complete identity straight from the mnemonic — X25519, ML-KEM-768, Ed25519, ML-DSA-87, and Bitcoin — and re-encrypts everything with Argon2id in one step, so an old account becomes fully post-quantum capable automatically. A lighter `migrate()` method is also available if you only want to upgrade the KDF version without re-deriving the newer key types.
27
+ - **Isomorphic by design.** Uses native WebCrypto (ECDH/X25519) where the runtime supports it, and transparently falls back to a raw keypair representation where it doesn't (e.g. Node environments without X25519 in WebCrypto) — the public API is identical either way.
28
+ - **Multi-language mnemonics.** BIP-39 wordlists for English, French, Spanish, Italian, Japanese, Korean, Czech, Portuguese, Simplified Chinese, and Traditional Chinese are supported, lazy-loaded per language so you only pay for the ones you use.
93
29
 
94
- ### 1. Post-Quantum Ready (ML-KEM)
95
- Every identity now generates a dual-key system derived deterministically from a 64-byte BIP39 seed:
96
- * **X25519 (Curve25519):** Derived from the first 32 bytes of the seed. Used for fingerprints, contact identity, and legacy compatibility.
97
- * **ML-KEM-768 (FIPS-203):** Derived from the full 64-byte seed. Provides post-quantum key encapsulation for "v3" secure envelopes.
98
-
99
- ### 2. Argon2id Key Derivation
100
- We have transitioned to **Argon2id** (KDF v2) for encrypting private keys at rest.
101
- * **Memory-Hard:** Configured with 64 MB of memory, 3 iterations, and 4 parallelism factors.
102
- * **Brute-Force Resistant:** Engineered to defeat GPU and ASIC-based cracking attempts that easily bypass older PBKDF2 implementations.
103
-
104
- ### 3. Seamless Auto-Migration
105
- The library handles "Security Debt" automatically during standard workflows:
106
- * **On Import:** `importFromMnemonicBackup()` detects v1 (PBKDF2) accounts and performs a full upgrade to v2.
107
- * **Deterministic Recovery:** If ML-KEM keys are missing from an old backup, they are re-derived from the mnemonic during the upgrade process.
108
- * **Password Updates:** Changing a passphrase via `updatePassphrase()` automatically migrates the account to the latest Argon2id standard.
109
30
  ---
110
31
 
32
+ ## Architecture
111
33
 
34
+ ```mermaid
35
+ flowchart TD
36
+ A[12/24-word BIP-39 Seed Phrase] --> B[Majik Key]
112
37
 
113
- ## Overview
38
+ %% Signing branch
39
+ B --> S[Signing]
40
+ S --> S1[Ed25519]
41
+ S --> S2[ML-DSA-87]
114
42
 
115
- **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.
43
+ %% Encryption branch
44
+ B --> E[Encryption]
45
+ E --> E1[ML-KEM-768]
46
+ E --> E2[AES-256-GCM]
116
47
 
117
- ### What is a Majik Key?
48
+ %% Identity branch
49
+ B --> I[Identity]
50
+ I --> I1[BIP-39]
51
+ I --> I2[X25519]
118
52
 
119
- A Majik Key is a seed phrase account that:
120
- - Derives cryptographic key pairs from BIP39 mnemonic phrases
121
- - Encrypts private keys at rest with a user-defined passphrase
122
- - Supports secure backup and recovery via mnemonic encryption
123
- - Provides locked/unlocked state management for enhanced security
124
- - Is fully compatible with **Majik Message** and other Majikah products
53
+ %% Experimental Web3 branch
54
+ B -.-> W[Web3 - Experimental]
55
+ W -.-> W1[Bitcoin - BIP-32/84]
56
+ W -.-> W2[Solana - Ed25519-derived]
125
57
 
126
- ### Use Cases
58
+ %% Products (fan-in)
59
+ S1 --> P1[Majik Signature]
60
+ S2 --> P1
127
61
 
128
- - **Majik Message Integration**: Create seed phrase accounts that can be imported directly into Majik Message
129
- - **Cryptographic Identity Management**: Manage multiple identities with deterministic key derivation
130
- - **Secure Messaging**: Generate signing keys for end-to-end encrypted communication
131
- - **Blockchain Applications**: Create wallet-like accounts from mnemonic phrases
132
- - **Majikah Ecosystem**: Use across all Majikah products and services
62
+ S1 --> P2[Majik Buwiz]
63
+ S2 --> P2
64
+ E1 --> P2
65
+ E2 --> P2
66
+ I1 --> P2
67
+ I2 --> P2
68
+
133
69
 
134
- ---
70
+ E1 --> P3[Majik Message]
71
+ E2 --> P3
135
72
 
136
- ## Features
137
-
138
- ### Security & Post-Quantum Readiness
139
- - **Post-Quantum Ready**: Implements **ML-KEM-768 (FIPS-203)** for key encapsulation, ensuring identities are secure against future quantum computing threats.
140
- - **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.
141
- - **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.
142
- - **AES-GCM Authenticated Encryption**: Industry-standard encryption for private keys at rest with unique, per-identity salts and random IVs.
143
- - **Locked/Unlocked States**: Private keys are only decrypted into memory when explicitly unlocked and are purged immediately upon calling `.lock()`.
144
-
145
- ### BIP39 Compliance & Key Derivation
146
- - **Standard Mnemonic Generation**: Generate high-entropy 12 or 24-word seed phrases (128/256-bit strength).
147
- - **Deterministic Multi-Key Derivation**:
148
- - **X25519 (Curve25519)**: Derived from the first 32 bytes of the seed for legacy compatibility and fingerprints.
149
- - **ML-KEM-768**: Derived from the full 64-byte seed for post-quantum security.
150
- - **Built-in Validation**: Full BIP39 mnemonic validation and error handling.
151
-
152
- ### Developer Experience
153
- - **First-Class TypeScript Support**: Full type definitions included for all interfaces and classes.
154
- - **Fluent API**: Intuitive method chaining for common operations (e.g., `key.unlock(p).updateLabel(l)`).
155
- - **Comprehensive Error Handling**: Specialized `MajikKeyError` and `CryptoError` classes for precise debugging.
156
- - **Isomorphic Support**: Works across Node.js and modern browser environments.
157
-
158
- ### Import / Export & Storage
159
- - **Security-Minded JSON Serialization**: Export accounts to JSON format for storage without ever exposing raw private keys or seed phrases.
160
- - **MnemonicJSON Format**: A secure, portable format for seed phrase storage and recovery.
161
- - **Mnemonic-Encrypted Backups**: Export and import specialized backup strings that utilize the mnemonic as a secondary encryption layer.
162
-
163
- ### Interoperability
164
- - **Majik Message Integration**: Native support for exporting identities compatible with **Majik Message v3** envelopes.
165
- - **Contact Portability**: Convert Majik Keys directly into contact formats for easy sharing of public identities.
166
- - **Ecosystem Ready**: Designed as the core identity provider for all current and future Majikah products.
167
- ---
168
-
169
- ## Installation
170
-
171
- ```bash
172
- # Using npm
173
- npm install @majikah/majik-key
73
+ I1 --> P4[Majik Universal ID]
74
+ I2 --> P4
174
75
 
76
+ P4 --> P5[Majik SLink]
175
77
  ```
176
78
 
177
- ---
178
-
179
- ## Quick Start
180
-
181
- ```ts
182
- import { MajikKey } from '@majikah/majik-key';
183
-
184
- // Generate a new mnemonic
185
- const mnemonic = MajikKey.generateMnemonic(); // 12 words
186
- console.log('Save this mnemonic:', mnemonic);
187
-
188
- // Create a new Majik Key (unlocked state)
189
- const key = await MajikKey.create(mnemonic, 'secure-passphrase', 'My PQ Account');
190
-
191
- // 2. Access your keys (requires unlock)
192
- console.log('Fingerprint:', key.fingerprint);
193
- console.log('PQ Ready:', key.metadata.kdfVersion); // 'argon2id'
194
- console.log('Key ID:', key.id);
195
- console.log('Is Unlocked:', key.isUnlocked); // true
196
-
197
- // Lock the key (clear private keys from memory)
198
- key.lock();
199
- console.log('Is Locked:', key.isLocked); // true
200
-
201
- // Unlock when needed
202
- await key.unlock('my-secure-passphrase');
203
- console.log('Is Unlocked:', key.isUnlocked); // true
204
-
205
- // Access private key (only when unlocked)
206
- const privateKey = key.getPrivateKey();
207
- const privateKeyBase64 = key.getPrivateKeyBase64();
208
-
209
- // Save to storage (private keys never included)
210
- const json = key.toJSON();
211
- localStorage.setItem('myKey', JSON.stringify(json));
212
-
213
- // Load from storage (locked state)
214
- const loadedKey = MajikKey.fromJSON(json);
215
- await loadedKey.unlock('my-secure-passphrase');
216
- ```
79
+ Your Majik Key is generated entirely offline. No network request is made during key creation — verifiable in source code.
217
80
 
218
81
  ---
219
82
 
220
- ## API Reference
221
-
222
- ### Static Methods
83
+ ## Powering the Majikah Ecosystem
223
84
 
224
- #### `MajikKey.create(mnemonic, passphrase, label?)`
225
- Create a new Majik Key from a mnemonic phrase. Generates a new Argon2id-protected account.
85
+ Majik Key is the shared identity layer underneath every Majikah product. Here's what each one draws from it.
226
86
 
227
- **Parameters:**
228
- - `mnemonic: string` - BIP39 mnemonic phrase (12-24 words)
229
- - `passphrase: string` - Passphrase to encrypt the private key at rest
230
- - `label?: string` - Optional label for the key
87
+ ### [Majik Signature](https://majikah.solutions/products/majik-signature) — Flagship
231
88
 
232
- **Returns:** `Promise<MajikKey>` - A new unlocked MajikKey instance
89
+ **Post-quantum cryptographic file signing and verification.**
233
90
 
234
- **Example:**
235
- ```ts
236
- const mnemonic = 'witch collapse practice feed shame open despair creek road again ice least';
237
- const key = await MajikKey.create(mnemonic, 'my-password', 'Personal Account');
91
+ [![npm](https://img.shields.io/npm/v/@majikah/majik-signature)](https://www.npmjs.com/package/@majikah/majik-signature) [![npm downloads](https://img.shields.io/npm/dm/@majikah/majik-signature)](https://www.npmjs.com/package/@majikah/majik-signature) [![npm bundle size](https://img.shields.io/bundlephobia/min/%40majikah%2Fmajik-signature)](https://bundlephobia.com/package/@majikah/majik-signature) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
238
92
 
239
- ```
93
+ [![Majik Signature Hero](https://github.com/user-attachments/assets/781bb778-9535-4b1f-bbc5-820550ecc864)](https://signature.majikah.solutions)
240
94
 
241
- ---
95
+ Majik Signature consumes a Majik Key's **Ed25519** and **ML-DSA-87** signing keypairs to require *both* a classical and a post-quantum signature before a file verifies — hybrid security with forward secrecy against future quantum attacks on either scheme alone.
242
96
 
243
- #### `MajikKey.fromJSON(json)`
244
- Load a Majik Key from JSON (locked state).
97
+ ```typescript
98
+ import { MajikKey } from '@majikah/majik-key';
99
+ import { MajikSignature } from '@majikah/majik-signature';
245
100
 
246
- **Parameters:**
247
- - `json: MajikKeyJSON | string` - JSON object or string
101
+ // 1. Sign a file and embed the signature (requires an unlocked key with signing keys)
102
+ const { blob, signature } = await MajikSignature.signFile(myFileBlob, myUnlockedKey, {
103
+ // Optional: restrict future signers
104
+ expectedSigners: [ MajikSignature.expectedSignerFromKey(myUnlockedKey) ]
105
+ });
248
106
 
249
- **Returns:** `MajikKey` - A locked MajikKey instance
107
+ // 2. Verify a signed file's embedded signatures
108
+ const results = await MajikSignature.verifyFile(blob, myUnlockedKey);
109
+ results.forEach(res => {
110
+ console.log(`Signer ${res.signerId} valid?`, res.valid);
111
+ });
250
112
 
251
- **Example:**
252
- ```ts
253
- const json = localStorage.getItem('myKey');
254
- const key = MajikKey.fromJSON(json);
255
- await key.unlock('my-password');
113
+ // 3. Seal a multi-sig file to prevent further signatures
114
+ const { sealInfo } = await MajikSignature.seal(blob, myUnlockedKey);
115
+ console.log("File sealed at:", sealInfo.sealTimestamp);
256
116
  ```
257
117
 
258
- ---
118
+ ### Majik Message
259
119
 
260
- #### `MajikKey.fromMnemonicJSON(mnemonicJson, passphrase, label?)`
261
- Create a Majik Key from MnemonicJSON format. Auto-migrates legacy PBKDF2 accounts to Argon2id + ML-KEM.
120
+ **Post-quantum secure messaging envelopes.**
262
121
 
263
- **Parameters:**
264
- - `mnemonicJson: MnemonicJSON | string` - MnemonicJSON object or string
265
- - `passphrase: string` - Passphrase to encrypt the key at rest
266
- - `label?: string` - Optional label for the key
122
+ Majik Key derives an ML-KEM-768 keypair specifically so it can be used for Majik Message's v3 secure envelopes — the ML-KEM-768 keypair handles post-quantum key encapsulation, and AES-256-GCM handles the actual payload encryption once a shared secret is established.
267
123
 
268
- **Returns:** `Promise<MajikKey>` - A new unlocked MajikKey instance
124
+ Majik Key ships a direct integration point for this: `toMajikMessageIdentity()` converts an unlocked key into a `MajikMessageIdentity`, ready to hand to Majik Message.
269
125
 
270
- **Example:**
271
- ```ts
272
- const mnemonicData = {
273
- id: 'backup-id',
274
- seed: ['word1', 'word2', ...],
275
- phrase: 'optional-encryption-phrase'
276
- };
277
-
278
- const key = await MajikKey.fromMnemonicJSON(mnemonicData, 'my-password');
279
- ```
280
-
281
- ---
126
+ ```typescript
127
+ import { MajikKey } from '@majikah/majik-key';
282
128
 
283
- #### `MajikKey.importFromMnemonicBackup(backup, mnemonic, passphrase, label?)`
284
- Import a Majik Key from a mnemonic-encrypted backup. Auto-migrates legacy PBKDF2 accounts to Argon2id + ML-KEM.
285
-
286
- **Parameters:**
287
- - `backup: string` - Base64-encoded backup string
288
- - `mnemonic: string` - The mnemonic phrase used to encrypt the backup
289
- - `passphrase: string` - Passphrase to encrypt the imported key
290
- - `label?: string` - Optional label for the key
291
-
292
- **Returns:** `Promise<MajikKey>` - A new unlocked MajikKey instance
293
-
294
- **Example:**
295
- ```ts
296
- const backupString = 'eT8xY2F...'; // From exportMnemonicBackup()
297
- const key = await MajikKey.importFromMnemonicBackup(
298
- backupString,
299
- mnemonic,
300
- 'new-password',
301
- 'Restored Account'
302
- );
129
+ // user: an existing MajikUser instance (from @thezelijah/majik-user)
130
+ const identity = await key.toMajikMessageIdentity(user, {
131
+ label: 'My Device',
132
+ restricted: false,
133
+ });
303
134
  ```
304
135
 
305
- ---
306
-
307
- #### `MajikKey.generateMnemonic(strength?)`
308
- Generate a new BIP39 mnemonic phrase.
309
-
310
- **Parameters:**
311
- - `strength?: 128 | 256` - Entropy strength (128 = 12 words, 256 = 24 words). Default: 128
312
-
313
- **Returns:** `string` - A new mnemonic phrase
314
-
315
- **Example:**
316
- ```ts
317
- const mnemonic12 = MajikKey.generateMnemonic(); // 12 words
318
- const mnemonic24 = MajikKey.generateMnemonic(256); // 24 words
319
- ```
136
+ ### Majik Buwiz
320
137
 
321
- ---
138
+ **Multi-key custody built on the full Majik Key stack.**
322
139
 
323
- #### `MajikKey.validateMnemonic(mnemonic)`
324
- Validate a BIP39 mnemonic phrase.
140
+ Majik Buwiz is built on Majik Key's complete key set: Ed25519/ML-DSA-87 for signing, ML-KEM-768/AES-256-GCM for encryption, and X25519/BIP-39 for identity — plus the experimental Bitcoin and Solana keys described below for multi-chain support. Everything a Buwiz account needs is derivable from, and recoverable with, the same mnemonic.
325
141
 
326
- **Parameters:**
327
- - `mnemonic: string` - Mnemonic phrase to validate
142
+ ### Majik Universal ID & Majik SLink
328
143
 
329
- **Returns:** `boolean` - true if valid, false otherwise
144
+ **A portable identity primitive, and shareable links built on top of it.**
330
145
 
331
- **Example:**
332
- ```ts
333
- const isValid = MajikKey.validateMnemonic('witch collapse practice...');
334
- ```
146
+ Majik Universal ID is built on the Identity branch of Majik Key — the BIP-39-derived X25519 keypair, public key, and fingerprint, exportable via `toContact()` as a `MajikContact` for use across apps. Majik SLink extends that identity layer downstream, per the architecture above. Both are separate Majikah packages; consult [majikah.solutions](https://majikah.solutions) for the latest on their APIs.
335
147
 
336
148
  ---
337
149
 
338
- ### Instance Methods
339
-
340
- #### `unlock(passphrase)`
341
- Unlock the Majik Key by decrypting the private key. Decrypts X25519 and ML-KEM private keys into memory.
342
-
343
- **Parameters:**
344
- - `passphrase: string` - Passphrase to decrypt the private key
150
+ ## Experimental Web3 Support
345
151
 
346
- **Returns:** `Promise<this>` - This instance for chaining
347
-
348
- **Throws:** `MajikKeyError` if passphrase is incorrect or key is already unlocked
349
-
350
- **Example:**
351
- ```ts
352
- await key.unlock('my-password');
353
- ```
152
+ Majik Key can derive **Bitcoin** and **Solana** key material directly from the same mnemonic. This is marked experimental — the shape of the `web3` namespace may change without a major version bump.
354
153
 
355
- ---
154
+ ### What's built in vs. what needs an extra install
356
155
 
357
- #### `lock()`
358
- Lock the Majik Key by clearing private keys from memory.
156
+ - **Bitcoin key derivation is automatic.** Every account created via `create()` or `importFromMnemonicBackup()` also derives and encrypts a Bitcoin keypair (real BIP-32 HD derivation off the raw 64-byte seed, using a Majik-specific domain-separated path by default). This works out of the box — no extra install needed for the private key, public key, or WIF export.
157
+ - **Solana key derivation is on-demand.** Rather than storing a separate Solana keypair, Majik Key derives it deterministically from your Ed25519 signing key each time you access `key.web3.solana` (and caches it in memory for as long as the key stays unlocked). The base58 Solana address also works with no extra install.
158
+ - **The optional peer dependencies are only needed for chain-native address/transaction objects:**
359
159
 
360
- **Returns:** `this` - This instance for chaining
160
+ | Chain | Peer dependency | Needed for |
161
+ | :--- | :--- | :--- |
162
+ | Bitcoin | `@scure/btc-signer` | Native SegWit (bech32) address encoding, PSBT construction |
163
+ | Solana | `@solana/kit` | Real `KeyPairSigner` instances, kit-native `Address` type |
361
164
 
362
- **Example:**
363
- ```ts
364
- key.lock();
165
+ ```bash
166
+ npm install @scure/btc-signer # for Bitcoin addresses
167
+ npm install @solana/kit # for Solana signer/address objects
365
168
  ```
366
169
 
367
- ---
170
+ Everything else — raw key bytes, WIF export, message signing (ECDSA/Schnorr for Bitcoin, Ed25519 for Solana), and base58 Solana addresses — works with zero extra dependencies.
368
171
 
369
- #### `verify(passphrase)`
370
- Verify that a passphrase can decrypt the private key.
172
+ ### Two Bitcoin paths, on purpose
371
173
 
372
- **Parameters:**
373
- - `passphrase: string` - Passphrase to verify
174
+ By default, Bitcoin keys use `MAJIK_BITCOIN_DOMAIN_PATH` — a real, standard BIP-32 derivation, but not the path a generic wallet would derive by default, so it stays effectively private to Majik. Pass `{ standard: true }` to derive the actual BIP-84 mainnet path instead — the address any standard wallet would show for the same mnemonic:
374
175
 
375
- **Returns:** `Promise<boolean>` - true if valid, false otherwise
176
+ ```typescript
177
+ // Majik's default (domain-separated, stored on the key)
178
+ const wif = key.getBitcoinWIF();
376
179
 
377
- **Example:**
378
- ```ts
379
- const isValid = await key.verify('my-password');
180
+ // The real BIP-84 mainnet key — recoverable in any standard wallet
181
+ const standardBtc = await MajikKey.deriveStandardBitcoinFromMnemonic(mnemonic);
380
182
  ```
381
183
 
382
- ---
383
-
384
- #### `updateLabel(newLabel)`
385
- Update the label of the Majik Key.
184
+ ### Two Solana paths, on purpose
386
185
 
387
- **Parameters:**
388
- - `newLabel: string` - New label value
186
+ By default (`deriveSolanaKeypairFromEdSecretKey`), the Solana keypair is domain-separated from your Ed25519 message-signing key via `SHA256(edSeed || "MajikMessageSolanaSeed")`, so the same private key never secures two different protocols. You can opt into reusing your Ed25519 message-signing key directly instead:
389
187
 
390
- **Returns:** `this` - This instance for chaining
188
+ ```typescript
189
+ // Recommended: domain-separated Solana key
190
+ const solanaAddress = key.getSolanaAddress();
391
191
 
392
- **Example:**
393
- ```ts
394
- key.updateLabel('Work Account');
192
+ // Opt-in: reuse the Ed25519 message-signing key as-is (not recommended)
193
+ const reusedAddress = key.getSolanaAddress({ reuseMessageKey: true });
395
194
  ```
396
195
 
397
196
  ---
398
197
 
399
- #### `updatePassphrase(currentPassphrase, newPassphrase)`
400
- Change the passphrase used to encrypt the private key. Re-encrypts keys and triggers an auto-migration to KDF v2.
401
-
402
- **Parameters:**
403
- - `currentPassphrase: string` - Current passphrase
404
- - `newPassphrase: string` - New passphrase
405
-
406
- **Returns:** `Promise<this>` - This instance for chaining
407
-
408
- **Throws:** `MajikKeyError` if current passphrase is incorrect
198
+ ## Installation
409
199
 
410
- **Example:**
411
- ```ts
412
- await key.updatePassphrase('old-password', 'new-password');
200
+ ```bash
201
+ npm install @majikah/majik-key
413
202
  ```
414
203
 
415
204
  ---
416
205
 
417
- #### `getPrivateKey()`
418
- Get the private key (only when unlocked).
419
-
420
- **Returns:** `CryptoKey | { raw: Uint8Array }` - The private key
421
-
422
- **Throws:** `MajikKeyError` if the key is locked
423
-
424
- **Example:**
425
- ```ts
426
- const privateKey = key.getPrivateKey();
427
- ```
206
+ ## Quick Start (Core Identity)
428
207
 
429
- ---
208
+ ```typescript
209
+ import { MajikKey } from '@majikah/majik-key';
430
210
 
431
- #### `getPrivateKeyBase64()`
432
- Get the private key as base64 (only when unlocked).
211
+ // 1. Generate & Create
212
+ const mnemonic = await MajikKey.generateMnemonic(); // 12 words (128-bit)
213
+ const key = await MajikKey.create(mnemonic, 'super-secure-passphrase', 'My PQ Account');
433
214
 
434
- **Returns:** `string` - The private key in base64 format
215
+ // 2. Access Identity
216
+ console.log('Fingerprint:', key.fingerprint);
217
+ console.log('Key ID:', key.id);
218
+ console.log('Unlocked?', key.isUnlocked); // true — create() returns an already-unlocked key
435
219
 
436
- **Throws:** `MajikKeyError` if the key is locked
220
+ // 3. Lock to purge private key material from memory
221
+ key.lock();
437
222
 
438
- **Example:**
439
- ```ts
223
+ // 4. Unlock again when cryptographic operations are needed
224
+ await key.unlock('super-secure-passphrase');
440
225
  const privateKeyBase64 = key.getPrivateKeyBase64();
441
- ```
442
226
 
443
- ---
444
-
445
- #### `toJSON()`
446
- Export to JSON format (safe for storage).
447
-
448
- **Returns:** `MajikKeyJSON` - JSON representation (private keys never included)
449
-
450
- **Example:**
451
- ```ts
452
- const json = key.toJSON();
453
- localStorage.setItem('myKey', JSON.stringify(json));
227
+ // 5. Safe storage — toJSON()/toString() never include raw private keys
228
+ localStorage.setItem('myKey', key.toString());
454
229
  ```
455
230
 
456
231
  ---
457
232
 
458
- #### `toString(pretty?)`
459
- Export to JSON string.
460
-
461
- **Parameters:**
462
- - `pretty?: boolean` - Whether to pretty-print. Default: false
463
-
464
- **Returns:** `string` - JSON string representation
465
-
466
- **Example:**
467
- ```ts
468
- const jsonString = key.toString(true);
469
- ```
470
-
471
- ---
472
-
473
- #### `toMnemonicJSON(mnemonic, passphrase?)`
474
- Export to MnemonicJSON format.
475
-
476
- **Parameters:**
477
- - `mnemonic: string` - The BIP39 mnemonic phrase
478
- - `passphrase?: string` - Optional passphrase
479
-
480
- **Returns:** `MnemonicJSON` - MnemonicJSON object
481
-
482
- **Throws:** `MajikKeyError` if the key is locked
483
-
484
- **Example:**
485
- ```ts
486
- const mnemonicData = key.toMnemonicJSON(mnemonic, 'encryption-phrase');
487
- ```
488
-
489
- ---
490
-
491
- #### `exportMnemonicBackup(mnemonic)`
492
- Export a mnemonic-encrypted backup.
493
-
494
- **Parameters:**
495
- - `mnemonic: string` - The original mnemonic phrase
496
-
497
- **Returns:** `Promise<string>` - Base64-encoded backup string
498
-
499
- **Throws:** `MajikKeyError` if the key is locked
500
-
501
- **Example:**
502
- ```ts
503
- const backup = await key.exportMnemonicBackup(mnemonic);
504
- ```
505
-
506
- ---
507
-
508
- #### `toContact()`
509
- Create a MajikContact from this Majik Key.
510
-
511
- **Returns:** `MajikContact` - A MajikContact instance
512
-
513
- **Example:**
514
- ```ts
515
- const contact = key.toContact();
516
- ```
517
-
518
- ---
519
-
520
- #### `toMajikMessageIdentity(user, options?)`
521
- Convert to MajikMessageIdentity for use in Majik Message.
522
-
523
- **Parameters:**
524
- - `user: MajikUser` - MajikUser instance
525
- - `options?: { label?: string, restricted?: boolean }` - Optional configuration
526
-
527
- **Returns:** `Promise<MajikMessageIdentity>` - MajikMessageIdentity instance
528
-
529
- **Example:**
530
- ```ts
531
- const identity = await key.toMajikMessageIdentity(user, {
532
- label: 'My Account',
533
- restricted: false
534
- });
535
- ```
233
+ ## API Reference
536
234
 
537
- ---
235
+ ### Static Methods (Lifecycle & Generation)
538
236
 
539
- ### Getters
237
+ | Method | Parameters | Returns | Description |
238
+ | :--- | :--- | :--- | :--- |
239
+ | `create()` | `mnemonic`, `passphrase`, `label?`, `mnemonicLanguage?` | `Promise<MajikKey>` | Creates a new Argon2id-protected, fully post-quantum-capable account. |
240
+ | `fromJSON()` | `json` | `MajikKey` | Loads a locked key from safe JSON storage. |
241
+ | `fromMnemonicJSON()` | `mnemonicJson`, `passphrase`, `label?` | `Promise<MajikKey>` | Rebuilds a key straight from a portable seed export. |
242
+ | `importFromMnemonicBackup()` | `backup`, `mnemonic`, `passphrase`, `label?`, `mnemonicLanguage?` | `Promise<MajikKey>` | Full migration path — verifies the mnemonic, then re-derives and re-encrypts the complete identity with Argon2id. |
243
+ | `fromDangerousJSON()` | `json` | `MajikKey` | Reconstructs an already-unlocked key from a dangerous export. Server-side only — see warning below. |
244
+ | `generateMnemonic()` | `strength?` *(128 \| 256)*, `language?` | `Promise<string>` | Generates a 12- or 24-word BIP-39 phrase. |
245
+ | `validateMnemonic()` | `mnemonic` | `boolean` | Validates a BIP-39 mnemonic phrase. |
246
+ | `deriveStandardBitcoinFromMnemonic()` *(experimental)* | `mnemonic`, `mnemonicLanguage?` | `Promise<BitcoinKeypairMaterial>` | Derives the real BIP-84 mainnet Bitcoin key without needing a `MajikKey` instance. |
540
247
 
541
- #### `id: string`
542
- The unique identifier (fingerprint).
248
+ ### Instance Methods (State & Management)
543
249
 
544
- #### `fingerprint: string`
545
- The cryptographic fingerprint.
250
+ | Method | Parameters | Returns | Description |
251
+ | :--- | :--- | :--- | :--- |
252
+ | `unlock()` | `passphrase` | `Promise<this>` | Decrypts keys into memory. Chainable. |
253
+ | `lock()` | None | `this` | Purges all private key material (including cached Web3 keys) from memory. Chainable. |
254
+ | `verify()` | `passphrase` | `Promise<boolean>` | Tests a passphrase without keeping keys in memory or requiring an unlock. |
255
+ | `updatePassphrase()` | `currentPass`, `newPass` | `Promise<this>` | Re-encrypts every stored key under a new passphrase and migrates to KDF v2 if needed. |
256
+ | `migrate()` | `passphrase` | `Promise<this>` | Upgrades the X25519 key's KDF from v1 to v2 only — does **not** add ML-KEM/Ed25519/ML-DSA/Bitcoin keys. Use `importFromMnemonicBackup()` for a full upgrade. |
257
+ | `updateLabel()` | `newLabel` | `this` | Updates the human-readable account label. |
546
258
 
547
- #### `publicKey: CryptoKey | { raw: Uint8Array }`
548
- The public key.
259
+ ### Export & Integration Methods
549
260
 
550
- #### `publicKeyBase64: string`
551
- The public key in base64 format.
261
+ | Method | Returns | Description |
262
+ | :--- | :--- | :--- |
263
+ | `toJSON()` / `toString()` | `MajikKeyJSON` / `string` | Safe export for DB/LocalStorage. No raw keys. |
264
+ | `toDangerousJSON()` | `MajikKeyDangerousJSON` | ⚠️ Contains every raw private key. Server-side secret injection only — see warning below. |
265
+ | `toMnemonicJSON()` | `MnemonicJSON` | ⚠️ Contains the raw mnemonic words (and passphrase, if you pass one) in plaintext — a transport format, not an at-rest storage format. Requires the key to be unlocked. |
266
+ | `exportMnemonicBackup()` | `Promise<string>` | Encrypted backup string, decryptable only with the original mnemonic — used to verify a mnemonic before `importFromMnemonicBackup()` re-derives the identity. |
267
+ | `toContact()` | `MajikContact` | Extracts public identity data for sharing (the basis for Majik Universal ID). |
268
+ | `toMajikMessageIdentity()` | `Promise<MajikMessageIdentity>` | Formats the key for direct use in Majik Message. Requires a `MajikUser`. |
552
269
 
553
- #### `label: string`
554
- The user-defined label.
270
+ ### Instance Getters
555
271
 
556
- #### `backup: string`
557
- The mnemonic backup identifier.
272
+ *Public — available at any time, regardless of lock state:*
558
273
 
559
- #### `timestamp: Date`
560
- The creation timestamp.
274
+ `id`, `fingerprint`, `publicKey`, `publicKeyBase64`, `label`, `backup`, `timestamp`, `mnemonicLanguage`, `kdfVersion`, `isArgon2id`, `isLocked`, `isUnlocked`, `isFullyUpgraded`, `mlKemPublicKey`, `hasMlKem`, `edPublicKey`, `mlDsaPublicKey`, `hasSigningKeys`, `btcPublicKey`, `hasBitcoin`, `hasSolanaKeypair`, `hasBitcoinKeypair`, `metadata`.
561
275
 
562
- #### `isLocked: boolean`
563
- Whether the key is currently locked.
276
+ *Restricted — throws `MajikKeyError` if locked (or if that key type isn't present, e.g. on an account not yet fully migrated):*
564
277
 
565
- #### `isUnlocked: boolean`
566
- Whether the key is currently unlocked.
278
+ `getPrivateKey()`, `getPrivateKeyBase64()`, `getMlKemSecretKey()`, `getEdSecretKey()`, `getMlDsaSecretKey()`, `getBtcSecretKey()`.
567
279
 
568
- #### `metadata: MajikKeyMetadata`
569
- Safe metadata object (no sensitive data).
280
+ ### Web3 (Experimental)
570
281
 
571
- **Example:**
572
- ```ts
573
- console.log(key.metadata);
574
- // {
575
- // id: 'fingerprint-id',
576
- // fingerprint: 'fingerprint-id',
577
- // label: 'My Key',
578
- // timestamp: Date,
579
- // isLocked: false
580
- // }
581
- ```
282
+ | Member | Returns | Notes |
283
+ | :--- | :--- | :--- |
284
+ | `web3` *(getter)* | `{ solana, bitcoin? } \| undefined` | `undefined` if locked or has no Ed25519 signing key. `bitcoin` is present only if the account has stored Bitcoin key material. |
285
+ | `getBitcoinKeypairMaterial()` | `BitcoinKeypairMaterial` | Raw Bitcoin keypair bytes. |
286
+ | `getBitcoinWIF()` | `string` | Wallet Import Format string, pastes into any standard Bitcoin wallet. |
287
+ | `getSolanaKeypairMaterial()` | `SolanaKeypairMaterial` | Raw Solana keypair bytes. |
288
+ | `getSolanaKeypair()` | `Promise<any>` | Real `@solana/kit` `KeyPairSigner`. Requires `@solana/kit`. |
289
+ | `getSolanaAddress()` | `string` | Base58 Solana address. No extra dependency required. |
582
290
 
583
291
  ---
584
292
 
585
293
  ## Usage Examples
586
294
 
587
- ### Example 1: Create and Manage a Key
295
+ ### 1. Secure Backup & Recovery Workflow
588
296
 
589
- ```ts
297
+ ```typescript
590
298
  import { MajikKey } from '@majikah/majik-key';
591
299
 
592
- async function createKey() {
593
- // Generate mnemonic
594
- const mnemonic = MajikKey.generateMnemonic();
595
- console.log('🔑 Save this mnemonic safely:', mnemonic);
596
-
597
- // Create key
598
- const key = await MajikKey.create(
599
- mnemonic,
600
- 'secure-passphrase',
601
- 'Personal Account'
602
- );
603
-
604
- console.log('✅ Key created!');
605
- console.log('ID:', key.id);
606
- console.log('Fingerprint:', key.fingerprint);
607
- console.log('Label:', key.label);
608
-
609
- // Save to storage
610
- const json = key.toJSON();
611
- localStorage.setItem('myKey', JSON.stringify(json));
612
-
613
- return { key, mnemonic };
614
- }
615
-
616
- createKey();
300
+ // -- EXPORTING --
301
+ // ⚠️ jsonData contains the raw mnemonic (and passphrase, if provided) in
302
+ // plaintext. Treat this exactly like the mnemonic itself — encrypt the
303
+ // file yourself, or keep it offline. This is a transport format, not a
304
+ // safe-storage format.
305
+ const jsonData = key.toMnemonicJSON(mnemonic, 'password123');
306
+ const blob = new Blob([JSON.stringify(jsonData)], { type: "application/json" });
307
+ // Save blob to a secure location...
308
+
309
+ // -- RECOVERING --
310
+ const recoveredData = JSON.parse(await blob.text());
311
+ const recoveredKey = await MajikKey.importFromMnemonicBackup(
312
+ recoveredData.id,
313
+ recoveredData.seed.join(" "),
314
+ recoveredData.phrase,
315
+ 'Recovered Key',
316
+ );
617
317
  ```
618
318
 
619
- ---
620
-
621
- ### Example 2: Lock/Unlock Pattern
622
-
623
- ```ts
624
- import { MajikKey } from '@majikah/majik-key';
625
-
626
- async function secureLockPattern() {
627
- const json = localStorage.getItem('myKey');
628
- const key = MajikKey.fromJSON(json);
629
-
630
- // Key is locked by default when loaded from JSON
631
- console.log('Locked:', key.isLocked); // true
632
-
633
- try {
634
- // This will throw an error
635
- const privateKey = key.getPrivateKey();
636
- } catch (error) {
637
- console.log('❌ Cannot access private key when locked');
638
- }
319
+ ### 2. Password Verification Before Action
639
320
 
640
- // Unlock to use private key
641
- await key.unlock('secure-passphrase');
642
- console.log('Unlocked:', key.isUnlocked); // true
321
+ ```typescript
322
+ const key = MajikKey.fromJSON(storedJson);
643
323
 
644
- // Now we can access private keys
645
- const privateKey = key.getPrivateKey();
646
- const privateKeyBase64 = key.getPrivateKeyBase64();
647
-
648
- // Use the key for cryptographic operations
649
- // ...
650
-
651
- // Lock again when done
652
- key.lock();
653
- console.log('🔒 Key locked again');
324
+ if (await key.verify('user-input-password')) {
325
+ await key.unlock('user-input-password');
326
+ // ... proceed with signing/encryption
327
+ key.lock(); // Always clean up!
328
+ } else {
329
+ throw new Error("Invalid passphrase");
654
330
  }
655
-
656
- secureLockPattern();
657
331
  ```
658
332
 
659
- ---
660
-
661
- ### Example 3: Backup and Recovery
662
-
663
- ```ts
664
- import { MajikKey } from '@majikah/majik-key';
665
-
666
- async function backupAndRecover() {
667
- const mnemonic = MajikKey.generateMnemonic();
668
- const key = await MajikKey.create(mnemonic, 'password123', 'Original Key');
669
-
670
- //Download as Blob JSON File
671
-
672
- const jsonData = await key.toMnemonicJSON(mnemonic, 'password123');
673
- const jsonString = JSON.stringify(jsonData);
674
- const blob = new Blob([jsonString], {
675
- type: "application/json;charset=utf-8",
676
- });
677
- downloadBlob(
678
- blob,
679
- "json",
680
- `${label} | ${key.id} | SEED KEY`,
681
- );
682
-
333
+ ### 3. Server-Side Secret Injection (Dangerous JSON)
683
334
 
335
+ `toDangerousJSON()` / `fromDangerousJSON()` skip encryption entirely — no KDF, no AES-GCM, instant reconstruction. This exists for one narrow case: injecting a pre-unlocked signing key into a server process, not for anything that touches a database, log, or the network.
684
336
 
685
- // Later... recover from backup
337
+ ```typescript
338
+ // At deploy time, generated once and stored in your secrets manager:
339
+ const dangerousJson = unlockedKey.toDangerousJSON();
686
340
 
687
- //Parse the downloaded JSON into this object
688
- const jsonData: MnemonicJSON = {
689
- id: "abc123",
690
- seed: ["word1", "word2", ...],
691
- phrase: 'password123',
692
- };
693
-
694
- const recoveredKey = await MajikKey.importFromMnemonicBackup(
695
- jsonData.id,
696
- seedArrayToString(jsonData.seed),
697
- jsonData.phrase,
698
- 'Recovered Key'
699
- );
700
-
701
- console.log('✅ Key recovered!');
702
- console.log('Same fingerprint:', key.fingerprint === recoveredKey.fingerprint);
703
- }
704
-
705
- backupAndRecover();
341
+ // At server boot:
342
+ const serverKey = MajikKey.fromDangerousJSON(process.env.MAJIK_SIGNING_KEY!);
343
+ // serverKey is already unlocked — no passphrase needed, no KDF cost.
706
344
  ```
707
345
 
346
+ ### 4. Experimental Web3 Usage
708
347
 
709
- ---
710
-
711
- ### Example 4: Update Passphrase
712
-
713
- ```ts
714
- import { MajikKey } from '@majikah/majik-key';
348
+ ```typescript
349
+ // Bitcoin — key material is already derived and stored on any account
350
+ console.log('Bitcoin WIF:', key.getBitcoinWIF());
351
+ console.log('Bitcoin address:', await key.web3?.bitcoin?.getBitcoinAddress()); // needs @scure/btc-signer
715
352
 
716
- async function changePassphrase() {
717
- const json = localStorage.getItem('myKey');
718
- const key = MajikKey.fromJSON(json);
719
-
720
- // Must unlock first
721
- await key.unlock('old-password');
722
-
723
- // Change passphrase
724
- await key.updatePassphrase('old-password', 'new-secure-password');
725
- console.log('✅ Passphrase updated!');
726
-
727
- // Save updated key
728
- localStorage.setItem('myKey', JSON.stringify(key.toJSON()));
729
-
730
- // Verify new passphrase works
731
- key.lock();
732
- await key.unlock('new-secure-password');
733
- console.log('✅ New passphrase verified!');
734
- }
735
-
736
- changePassphrase();
353
+ // Solana — derived on demand from your Ed25519 signing key
354
+ console.log('Solana address:', key.getSolanaAddress()); // no extra dependency
355
+ const solanaSigner = await key.getSolanaKeypair(); // needs @solana/kit
737
356
  ```
738
357
 
739
358
  ---
740
359
 
741
- ### Example 5: Verify Passphrase
360
+ ## Security Best Practices
742
361
 
743
- ```ts
744
- import { MajikKey } from '@majikah/majik-key';
362
+ ✅ **DO:**
363
+ - Call `.lock()` immediately after signing or decrypting payloads to free key material from memory.
364
+ - Use `mlKemPublicKey` for all new communication protocols to stay post-quantum ready.
365
+ - Keep `@scure/bip39` and the underlying crypto dependencies up to date.
366
+ - Treat any `toMnemonicJSON()` export, and the mnemonic itself, as the master secret — it recovers everything.
745
367
 
746
- async function verifyPassphrase() {
747
- const json = localStorage.getItem('myKey');
748
- const key = MajikKey.fromJSON(json);
749
-
750
- // Verify without unlocking
751
- const isValid = await key.verify('user-entered-password');
752
-
753
- if (isValid) {
754
- console.log('✅ Passphrase is correct');
755
- await key.unlock('user-entered-password');
756
- // Proceed with operations...
757
- } else {
758
- console.log('❌ Invalid passphrase');
759
- // Show error to user
760
- }
761
- }
762
-
763
- verifyPassphrase();
764
- ```
368
+ ❌ **DON'T:**
369
+ - Log `mnemonic` phrases, `privateKeyBase64`, or any `*SecretKeyBase64` value in production.
370
+ - Use `toDangerousJSON()` / `fromDangerousJSON()` outside of controlled, server-side secret injection.
371
+ - Store the output of `toMnemonicJSON()` unencrypted — it is not the same as `toJSON()`/`toString()`.
765
372
 
766
373
  ---
767
374
 
768
- ## Integration with Majik Message
769
-
770
- 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.
771
-
772
- ### Importing to Majik Message
773
-
774
- ```ts
775
- import { MajikKey } from '@majikah/majik-key';
776
-
777
- async function importToMajikMessage() {
778
- // Create or load a Majik Key
779
- const mnemonic = MajikKey.generateMnemonic();
780
- const key = await MajikKey.create(mnemonic, 'password', 'Message Account');
781
-
782
- // Export to MnemonicJSON format for Majik Message
783
- const mnemonicData = key.toMnemonicJSON(mnemonic, 'password');
784
- const jsonString = JSON.stringify(mnemonicData);
375
+ ## Ecosystem
785
376
 
786
- // Download this blob as a JSON locally
787
- const blob = new Blob([jsonString], {
788
- type: "application/json;charset=utf-8",
789
- });
790
-
791
- // This mnemonicData can be imported directly into Majik Message
792
- // as a seed phrase account
793
- console.log('Import the saved JSON to Majik Message:', mnemonicData);
794
- }
795
- ```
796
-
797
- ### Converting to Majik Message Identity
798
-
799
- ```ts
800
- import { MajikKey } from '@majikah/majik-key';
801
- import { MajikUser } from '@thezelijah/majik-user';
802
-
803
- async function createMessageIdentity() {
804
- const mnemonic = MajikKey.generateMnemonic();
805
- const key = await MajikKey.create(mnemonic, 'password', 'Message Identity');
806
-
807
- // Create/parse a MajikUser instance
808
- const user = new MajikUser({
809
- username: 'myusername',
810
- // ... other user properties
811
- });
812
-
813
- // Convert to Majik Message Identity
814
- const identity = await key.toMajikMessageIdentity(user, {
815
- label: 'My Message Account',
816
- restricted: false
817
- });
818
-
819
- console.log('Majik Message Identity created:', identity);
820
- }
821
- ```
822
-
823
- ---
824
-
825
- ## Security Considerations
826
-
827
- ### Best Practices
828
-
829
- 1. **Never expose mnemonics**: Treat mnemonic phrases like root passwords. Never log or store them unencrypted.
830
-
831
- 2. **Lock when not in use**: Always call .lock() when private key access is no longer required to purge the heap.
832
-
833
- 3. **PQ Readiness**: For all new communication protocols, ensure you are utilizing the mlKemPublicKey.
834
-
835
- Security Summary
836
- - **Primary KDF**: Argon2id (64 / 3t / 4p).
837
-
838
- - **Legacy KDF**: PBKDF2-SHA256 (250,000 iterations).
839
-
840
- - **Encryption**: AES-256-GCM with unique salts and IVs.
841
-
842
- - **Post-Quantum**: ML-KEM-768 (Lattice-based cryptography).
843
-
844
- ### What NOT to Do
845
-
846
- ❌ **DON'T** store mnemonics in code or version control
847
- ❌ **DON'T** transmit mnemonics over insecure channels
848
- ❌ **DON'T** use weak passphrases like "password123"
849
- ❌ **DON'T** share mnemonics or passphrases with anyone
850
- ❌ **DON'T** screenshot or photograph mnemonics
851
-
852
- ### What TO Do
853
-
854
- ✅ **DO** use password managers for mnemonic storage
855
- ✅ **DO** write mnemonics on paper and store securely
856
- ✅ **DO** use hardware security modules when possible
857
- ✅ **DO** test recovery procedures before relying on them
858
- ✅ **DO** keep multiple encrypted backups in different locations
859
-
860
- ---
861
-
862
- ### Tips & Reminders
863
-
864
- #### For Developers
865
-
866
- - **Remember**: Always validate user input before creating or unlocking keys.
867
-
868
- - **Security**: Never log sensitive data (mnemonics, private keys, passphrases) in production.
869
-
870
- - **Performance**: Lock keys when not in use to free memory and reduce attack surface.
871
-
872
- - **Testing**: Test backup/recovery procedures in development before deploying to production.
873
-
874
- - **Dependencies**: Keep `@scure/bip39` and other crypto dependencies up to date.
875
-
876
- #### For Users
877
-
878
- - **Backup**: Always keep multiple backups of your mnemonic phrase in secure locations.
879
-
880
- - **Passphrase**: Use a strong, unique passphrase for each Majik Key.
881
-
882
- - **Recovery**: Test your ability to recover keys from backups before you need to.
883
-
884
- - **Organization**: Use meaningful labels to identify different keys.
885
- - **Loss Prevention**: Losing your mnemonic phrase means permanent loss of access to your key.
377
+ - [Majik Signature Web App](https://signature.majikah.solutions)
378
+ - [Majik Signature on Microsoft Store](https://apps.microsoft.com/detail/9pl9g3xzvd1x)
379
+ - [Majik Signature Official Repository](https://github.com/Majikah/majik-signature)
380
+ - [Majikah Solutions](https://majikah.solutions)
886
381
 
887
382
  ---
888
383
 
889
- ## Related Projects
890
-
891
- ### [Majik Message](https://message.majikah.solutions)
892
- Secure messaging platform using Majik Keys
893
-
894
- [Read more about Majik Message here](https://majikah.solutions/products/majik-message)
895
-
896
- [![Majik Message Thumbnail](https://github.com/user-attachments/assets/6355cbd3-63e4-4a95-a370-64ba27cbb4a7)](https://message.majikah.solutions)
897
-
898
- > Click the image to try Majik Message live.
899
-
900
- [Read Docs](https://majikah.solutions/products/majik-message/docs)
901
-
902
-
903
- Also available on [Microsoft Store](https://apps.microsoft.com/detail/9pmjgvzzjspn) for free.
904
-
905
- [Official Repository](https://github.com/Majikah/majik-message)
906
- [SDK Library](https://www.npmjs.com/package/@majikah/majik-message)
384
+ ## License & Author
907
385
 
908
- ---
909
-
910
- ## Contributing
911
-
912
- If you want to contribute or help extend support to more platforms, reach out via email. All contributions are welcome!
913
-
914
- ---
915
-
916
- ## License
917
-
918
- [Apache-2.0](LICENSE) — free for personal and commercial use.
919
-
920
- ---
921
- ## Author
922
-
923
- Made with 💙 by [@thezelijah](https://github.com/jedlsf)
924
-
925
- ## About the Developer
926
-
927
- - **Developer**: Josef Elijah Fabian
928
- - **GitHub**: [https://github.com/jedlsf](https://github.com/jedlsf)
929
- - **Project Repository**: [https://github.com/Majikah/majik-key](https://github.com/Majikah/majik-key)
930
-
931
- ---
386
+ **License:** [Apache-2.0](LICENSE) — free for personal and commercial use.
932
387
 
933
- ## Contact
388
+ Developed by **Josef Elijah Fabian (Zelijah)** | [Majikah Solutions OPC](https://majikah.solutions/about)
934
389
 
935
- - **Business Email**: [business@thezelijah.world](mailto:business@thezelijah.world)
936
- - **Official Website**: [https://www.thezelijah.world](https://www.thezelijah.world)
390
+ - **GitHub:** [@jedlsf](https://github.com/jedlsf)
391
+ - **Website:** [https://www.thezelijah.world](https://www.thezelijah.world)
392
+ - **Email:** [business@thezelijah.world](mailto:business@thezelijah.world)