@majikah/majik-key 0.2.11 → 0.2.13
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 +179 -820
- package/dist/core/types.d.ts +7 -0
- package/dist/core/web3/bitcoin/bitcoin.d.ts +71 -0
- package/dist/core/web3/bitcoin/bitcoin.js +126 -0
- package/dist/core/web3/bitcoin/constants.d.ts +2 -0
- package/dist/core/web3/bitcoin/constants.js +7 -0
- package/dist/core/web3/bitcoin/types.d.ts +23 -0
- package/dist/core/web3/bitcoin/types.js +1 -0
- package/dist/core/web3/index.d.ts +5 -0
- package/dist/core/web3/index.js +2 -0
- package/dist/core/web3/solana/constants.d.ts +1 -0
- package/dist/core/web3/solana/constants.js +1 -0
- package/dist/core/web3/solana/solana.d.ts +73 -0
- package/dist/core/web3/solana/solana.js +120 -0
- package/dist/core/web3/solana/types.d.ts +18 -0
- package/dist/core/web3/solana/types.js +1 -0
- package/dist/core/web3/types.d.ts +7 -0
- package/dist/core/web3/types.js +1 -0
- package/dist/core/web3/utils.d.ts +1 -0
- package/dist/core/web3/utils.js +27 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/majik-key.d.ts +73 -0
- package/dist/majik-key.js +209 -3
- package/package.json +24 -4
package/README.md
CHANGED
|
@@ -1,936 +1,295 @@
|
|
|
1
1
|
# Majik Key
|
|
2
2
|
|
|
3
|
-
[](https://thezelijah.world) 
|
|
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
|
-
   [](https://opensource.org/licenses/Apache-2.0) 
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
---
|
|
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
|
-
|
|
3
|
+
[](https://www.thezelijah.world) 
|
|
4
|
+
   [](https://opensource.org/licenses/Apache-2.0)
|
|
86
5
|
|
|
6
|
+
**Majik Key** is a next-generation seed phrase account library for creating and managing mnemonic-based identities. It serves as a post-quantum ready, high-security bridge between BIP39 mnemonics and the broader Majikah ecosystem.
|
|
87
7
|
|
|
88
8
|
---
|
|
89
9
|
|
|
90
10
|
## Next-Gen Security Architecture
|
|
91
11
|
|
|
92
|
-
Majik Key
|
|
93
|
-
|
|
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.
|
|
12
|
+
Majik Key is engineered to meet and exceed modern cryptographic standards.
|
|
98
13
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* **
|
|
102
|
-
*
|
|
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.
|
|
14
|
+
* **Self-Encrypted at Rest:** Majik Keys are self-encrypted by default. Private keys are **always Argon2id hashed at rest**, which completely protects them from unauthorized access even if the underlying storage medium is compromised.
|
|
15
|
+
* **Post-Quantum Ready (ML-KEM):** Generates a deterministic dual-key system from a 64-byte BIP39 seed, featuring **X25519** for legacy compatibility and **ML-KEM-768 (FIPS-203)** for post-quantum key encapsulation.
|
|
16
|
+
* **Argon2id Key Derivation:** Private keys at rest are protected by memory-hard **Argon2id (KDF v2)**, configured to defeat GPU/ASIC brute-force attacks (64 MB memory / 3 iterations / 4 parallelism).
|
|
17
|
+
* **Seamless Auto-Migration:** Automatically detects and upgrades legacy v1 (PBKDF2) accounts to v2 upon import, deterministically re-deriving missing ML-KEM keys from the seed.
|
|
18
|
+
|
|
109
19
|
---
|
|
110
20
|
|
|
21
|
+
## The Majik Key
|
|
111
22
|
|
|
23
|
+
```mermaid
|
|
24
|
+
flowchart TD
|
|
25
|
+
A[12-word BIP-39 Seed Phrase] --> B[Majik Key]
|
|
112
26
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
### What is a Majik Key?
|
|
118
|
-
|
|
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
|
|
27
|
+
%% Signing branch
|
|
28
|
+
B --> S[Signing]
|
|
29
|
+
S --> S1[Ed25519]
|
|
30
|
+
S --> S2[ML-DSA-87]
|
|
125
31
|
|
|
126
|
-
|
|
32
|
+
%% Encryption branch
|
|
33
|
+
B --> E[Encryption]
|
|
34
|
+
E --> E1[ML-KEM-768]
|
|
35
|
+
E --> E2[AES-256-GCM]
|
|
127
36
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
- **Majikah Ecosystem**: Use across all Majikah products and services
|
|
37
|
+
%% Identity branch
|
|
38
|
+
B --> I[Identity]
|
|
39
|
+
I --> I1[BIP-39]
|
|
40
|
+
I --> I2[X25519]
|
|
133
41
|
|
|
134
|
-
|
|
42
|
+
%% Products (fan-in)
|
|
43
|
+
S1 --> P1[Majik Signature]
|
|
44
|
+
S2 --> P1
|
|
135
45
|
|
|
136
|
-
|
|
46
|
+
S1 --> P2[Majik Buwiz]
|
|
47
|
+
S2 --> P2
|
|
48
|
+
E1 --> P2
|
|
49
|
+
E2 --> P2
|
|
50
|
+
I1 --> P2
|
|
51
|
+
I2 --> P2
|
|
137
52
|
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
---
|
|
53
|
+
E1 --> P3[Majik Message]
|
|
54
|
+
E2 --> P3
|
|
168
55
|
|
|
169
|
-
|
|
56
|
+
I1 --> P4[Majik Universal ID]
|
|
57
|
+
I2 --> P4
|
|
170
58
|
|
|
171
|
-
|
|
172
|
-
# Using npm
|
|
173
|
-
npm install @majikah/majik-key
|
|
59
|
+
P4 --> P5[Majik SLink]
|
|
174
60
|
|
|
175
61
|
```
|
|
176
62
|
|
|
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
|
-
```
|
|
63
|
+
Your Majik Key is generated entirely offline. No network request is made during key creation — verifiable in source code.
|
|
217
64
|
|
|
218
65
|
---
|
|
219
66
|
|
|
220
|
-
##
|
|
67
|
+
## Experimental Web3 Support
|
|
221
68
|
|
|
222
|
-
|
|
69
|
+
Majik Key features experimental integration for deriving keys natively compatible with modern Web3 ecosystems, specifically **Bitcoin** and **Solana**.
|
|
223
70
|
|
|
224
|
-
|
|
225
|
-
Create a new Majik Key from a mnemonic phrase. Generates a new Argon2id-protected account.
|
|
226
|
-
|
|
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
|
|
231
|
-
|
|
232
|
-
**Returns:** `Promise<MajikKey>` - A new unlocked MajikKey instance
|
|
233
|
-
|
|
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');
|
|
71
|
+
To utilize these features, you must install the optional peer dependencies associated with your target chain:
|
|
238
72
|
|
|
73
|
+
### Bitcoin
|
|
74
|
+
Requires the `@scure/btc-signer` peer dependency.
|
|
75
|
+
```bash
|
|
76
|
+
npm install @scure/btc-signer
|
|
239
77
|
```
|
|
240
78
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
**Parameters:**
|
|
247
|
-
- `json: MajikKeyJSON | string` - JSON object or string
|
|
248
|
-
|
|
249
|
-
**Returns:** `MajikKey` - A locked MajikKey instance
|
|
250
|
-
|
|
251
|
-
**Example:**
|
|
252
|
-
```ts
|
|
253
|
-
const json = localStorage.getItem('myKey');
|
|
254
|
-
const key = MajikKey.fromJSON(json);
|
|
255
|
-
await key.unlock('my-password');
|
|
79
|
+
### Solana
|
|
80
|
+
Requires the `@solana/kit` peer dependency.
|
|
81
|
+
```bash
|
|
82
|
+
npm install @solana/kit
|
|
256
83
|
```
|
|
257
84
|
|
|
258
85
|
---
|
|
259
86
|
|
|
260
|
-
|
|
261
|
-
Create a Majik Key from MnemonicJSON format. Auto-migrates legacy PBKDF2 accounts to Argon2id + ML-KEM.
|
|
262
|
-
|
|
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
|
|
267
|
-
|
|
268
|
-
**Returns:** `Promise<MajikKey>` - A new unlocked MajikKey instance
|
|
269
|
-
|
|
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
|
-
```
|
|
87
|
+
## Overview
|
|
280
88
|
|
|
281
|
-
|
|
89
|
+
Majik Key provides a secure, intuitive way to create, store, and manage mnemonic-based cryptographic identities.
|
|
282
90
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
**
|
|
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
|
-
);
|
|
303
|
-
```
|
|
91
|
+
### Use Cases
|
|
92
|
+
* **Majik Message Integration:** Natively generate identities compatible with Majik Message v3 secure envelopes.
|
|
93
|
+
* **Cryptographic Identity Management:** Manage multiple identities with deterministic multi-key derivation.
|
|
94
|
+
* **Secure Storage & Recovery:** Built-in AES-GCM authenticated encryption for private keys at rest, with secure backup/recovery workflows.
|
|
304
95
|
|
|
305
96
|
---
|
|
306
97
|
|
|
307
|
-
|
|
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
|
|
98
|
+
## Features
|
|
314
99
|
|
|
315
|
-
**
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
```
|
|
100
|
+
* **Maximum Security:** ML-KEM-768 readiness and Argon2id derivation. Private keys are purged from memory immediately upon calling `.lock()`.
|
|
101
|
+
* **BIP39 Compliance:** High-entropy 12 or 24-word seed generation with built-in validation.
|
|
102
|
+
* **Isomorphic DX:** First-class TypeScript support, fluent method chaining, and compatibility across Node.js and modern browsers.
|
|
103
|
+
* **Portable Storage:** Safe JSON serialization and MnemonicJSON formats that never expose raw private keys.
|
|
320
104
|
|
|
321
105
|
---
|
|
322
106
|
|
|
323
|
-
|
|
324
|
-
Validate a BIP39 mnemonic phrase.
|
|
325
|
-
|
|
326
|
-
**Parameters:**
|
|
327
|
-
- `mnemonic: string` - Mnemonic phrase to validate
|
|
328
|
-
|
|
329
|
-
**Returns:** `boolean` - true if valid, false otherwise
|
|
107
|
+
## Installation
|
|
330
108
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const isValid = MajikKey.validateMnemonic('witch collapse practice...');
|
|
109
|
+
```bash
|
|
110
|
+
npm install @majikah/majik-key
|
|
334
111
|
```
|
|
335
112
|
|
|
336
113
|
---
|
|
337
114
|
|
|
338
|
-
|
|
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
|
|
115
|
+
## Quick Start (Core Identity)
|
|
345
116
|
|
|
346
|
-
|
|
117
|
+
Get up and running with a secure, unlockable account in seconds.
|
|
347
118
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
**Example:**
|
|
351
|
-
```ts
|
|
352
|
-
await key.unlock('my-password');
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
---
|
|
119
|
+
```typescript
|
|
120
|
+
import { MajikKey } from '@majikah/majik-key';
|
|
356
121
|
|
|
357
|
-
|
|
358
|
-
|
|
122
|
+
// 1. Generate & Create
|
|
123
|
+
const mnemonic = MajikKey.generateMnemonic(); // Generates 12 words
|
|
124
|
+
const key = await MajikKey.create(mnemonic, 'super-secure-passphrase', 'My PQ Account');
|
|
359
125
|
|
|
360
|
-
|
|
126
|
+
// 2. Access Identity
|
|
127
|
+
console.log('Fingerprint:', key.fingerprint);
|
|
128
|
+
console.log('Key ID:', key.id);
|
|
129
|
+
console.log('Unlocked?', key.isUnlocked); // true
|
|
361
130
|
|
|
362
|
-
|
|
363
|
-
```ts
|
|
131
|
+
// 3. Lock to purge private keys from memory
|
|
364
132
|
key.lock();
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
---
|
|
368
|
-
|
|
369
|
-
#### `verify(passphrase)`
|
|
370
|
-
Verify that a passphrase can decrypt the private key.
|
|
371
|
-
|
|
372
|
-
**Parameters:**
|
|
373
|
-
- `passphrase: string` - Passphrase to verify
|
|
374
|
-
|
|
375
|
-
**Returns:** `Promise<boolean>` - true if valid, false otherwise
|
|
376
|
-
|
|
377
|
-
**Example:**
|
|
378
|
-
```ts
|
|
379
|
-
const isValid = await key.verify('my-password');
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
---
|
|
383
|
-
|
|
384
|
-
#### `updateLabel(newLabel)`
|
|
385
|
-
Update the label of the Majik Key.
|
|
386
|
-
|
|
387
|
-
**Parameters:**
|
|
388
|
-
- `newLabel: string` - New label value
|
|
389
|
-
|
|
390
|
-
**Returns:** `this` - This instance for chaining
|
|
391
|
-
|
|
392
|
-
**Example:**
|
|
393
|
-
```ts
|
|
394
|
-
key.updateLabel('Work Account');
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
---
|
|
398
|
-
|
|
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
|
|
409
|
-
|
|
410
|
-
**Example:**
|
|
411
|
-
```ts
|
|
412
|
-
await key.updatePassphrase('old-password', 'new-password');
|
|
413
|
-
```
|
|
414
133
|
|
|
415
|
-
|
|
416
|
-
|
|
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
|
-
```
|
|
428
|
-
|
|
429
|
-
---
|
|
430
|
-
|
|
431
|
-
#### `getPrivateKeyBase64()`
|
|
432
|
-
Get the private key as base64 (only when unlocked).
|
|
433
|
-
|
|
434
|
-
**Returns:** `string` - The private key in base64 format
|
|
435
|
-
|
|
436
|
-
**Throws:** `MajikKeyError` if the key is locked
|
|
437
|
-
|
|
438
|
-
**Example:**
|
|
439
|
-
```ts
|
|
134
|
+
// 4. Unlock when cryptographic operations are needed
|
|
135
|
+
await key.unlock('super-secure-passphrase');
|
|
440
136
|
const privateKeyBase64 = key.getPrivateKeyBase64();
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
---
|
|
444
|
-
|
|
445
|
-
#### `toJSON()`
|
|
446
|
-
Export to JSON format (safe for storage).
|
|
447
|
-
|
|
448
|
-
**Returns:** `MajikKeyJSON` - JSON representation (private keys never included)
|
|
449
137
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
const json = key.toJSON();
|
|
453
|
-
localStorage.setItem('myKey', JSON.stringify(json));
|
|
138
|
+
// 5. Safe Storage (Private keys are encrypted at rest)
|
|
139
|
+
localStorage.setItem('myKey', key.toString());
|
|
454
140
|
```
|
|
455
141
|
|
|
456
142
|
---
|
|
457
143
|
|
|
458
|
-
|
|
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
|
-
```
|
|
536
|
-
|
|
537
|
-
---
|
|
538
|
-
|
|
539
|
-
### Getters
|
|
540
|
-
|
|
541
|
-
#### `id: string`
|
|
542
|
-
The unique identifier (fingerprint).
|
|
543
|
-
|
|
544
|
-
#### `fingerprint: string`
|
|
545
|
-
The cryptographic fingerprint.
|
|
546
|
-
|
|
547
|
-
#### `publicKey: CryptoKey | { raw: Uint8Array }`
|
|
548
|
-
The public key.
|
|
144
|
+
## API Reference
|
|
549
145
|
|
|
550
|
-
|
|
551
|
-
The public key in base64 format.
|
|
146
|
+
### Static Methods (Lifecycle & Generation)
|
|
552
147
|
|
|
553
|
-
|
|
554
|
-
|
|
148
|
+
| Method | Parameters | Returns | Description |
|
|
149
|
+
| :--------------------------- | :------------------------------------------- | :------------------ | :-------------------------------------------------- |
|
|
150
|
+
| `create()` | `mnemonic`, `passphrase`, `label?` | `Promise<MajikKey>` | Creates a new Argon2id-protected account. |
|
|
151
|
+
| `fromJSON()` | `json` | `MajikKey` | Loads a locked key from safe JSON storage. |
|
|
152
|
+
| `fromMnemonicJSON()` | `mnemonicJson`, `passphrase`, `label?` | `Promise<MajikKey>` | Auto-migrates legacy accounts to Argon2id + ML-KEM. |
|
|
153
|
+
| `importFromMnemonicBackup()` | `backup`, `mnemonic`, `passphrase`, `label?` | `Promise<MajikKey>` | Restores a key from a mnemonic-encrypted string. |
|
|
154
|
+
| `generateMnemonic()` | `strength?` *(128 \| 256)* | `string` | Generates a 12 or 24-word BIP39 phrase. |
|
|
155
|
+
| `validateMnemonic()` | `mnemonic` | `boolean` | Validates a BIP39 mnemonic phrase. |
|
|
555
156
|
|
|
556
|
-
|
|
557
|
-
The mnemonic backup identifier.
|
|
157
|
+
### Instance Methods (State & Management)
|
|
558
158
|
|
|
559
|
-
|
|
560
|
-
|
|
159
|
+
| Method | Parameters | Returns | Description |
|
|
160
|
+
| :------------------- | :----------------------- | :----------------- | :------------------------------------------------- |
|
|
161
|
+
| `unlock()` | `passphrase` | `Promise<this>` | Decrypts keys into memory. Chainable. |
|
|
162
|
+
| `lock()` | None | `this` | Purges private keys from memory. Chainable. |
|
|
163
|
+
| `verify()` | `passphrase` | `Promise<boolean>` | Tests a passphrase without keeping keys in memory. |
|
|
164
|
+
| `updatePassphrase()` | `currentPass`, `newPass` | `Promise<this>` | Changes passphrase and auto-migrates to KDF v2. |
|
|
165
|
+
| `updateLabel()` | `newLabel` | `this` | Updates the human-readable account label. |
|
|
561
166
|
|
|
562
|
-
|
|
563
|
-
Whether the key is currently locked.
|
|
167
|
+
### Export & Integration Methods
|
|
564
168
|
|
|
565
|
-
|
|
566
|
-
|
|
169
|
+
| Method | Returns | Description |
|
|
170
|
+
| :------------------------- | :------------------------ | :-------------------------------------------------- |
|
|
171
|
+
| `toJSON()` / `toString()` | `MajikKeyJSON` / `string` | Safe export for DB/LocalStorage. No raw keys. |
|
|
172
|
+
| `toMnemonicJSON()` | `MnemonicJSON` | Portable seed format (Requires key to be unlocked). |
|
|
173
|
+
| `exportMnemonicBackup()` | `Promise<string>` | Base64-encoded encrypted backup string. |
|
|
174
|
+
| `toContact()` | `MajikContact` | Extracts public identity data for sharing. |
|
|
175
|
+
| `toMajikMessageIdentity()` | `Promise<Identity>` | Formats key for direct use in Majik Message. |
|
|
567
176
|
|
|
568
|
-
|
|
569
|
-
|
|
177
|
+
### Instance Getters
|
|
178
|
+
*Access public data at any time:*
|
|
179
|
+
`id`, `fingerprint`, `publicKey`, `publicKeyBase64`, `label`, `backup`, `timestamp`, `isLocked`, `isUnlocked`, `metadata`.
|
|
570
180
|
|
|
571
|
-
|
|
572
|
-
|
|
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
|
-
```
|
|
181
|
+
*Access restricted data (Throws `MajikKeyError` if locked):*
|
|
182
|
+
`getPrivateKey()`, `getPrivateKeyBase64()`.
|
|
582
183
|
|
|
583
184
|
---
|
|
584
185
|
|
|
585
186
|
## Usage Examples
|
|
586
187
|
|
|
587
|
-
###
|
|
588
|
-
|
|
589
|
-
```ts
|
|
590
|
-
import { MajikKey } from '@majikah/majik-key';
|
|
591
|
-
|
|
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();
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
---
|
|
188
|
+
### 1. Secure Backup & Recovery Workflow
|
|
620
189
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
```ts
|
|
190
|
+
```typescript
|
|
624
191
|
import { MajikKey } from '@majikah/majik-key';
|
|
625
192
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
// Unlock to use private key
|
|
641
|
-
await key.unlock('secure-passphrase');
|
|
642
|
-
console.log('Unlocked:', key.isUnlocked); // true
|
|
643
|
-
|
|
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');
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
secureLockPattern();
|
|
657
|
-
```
|
|
658
|
-
|
|
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
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
// Later... recover from backup
|
|
686
|
-
|
|
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();
|
|
193
|
+
// -- EXPORTING --
|
|
194
|
+
const jsonData = key.toMnemonicJSON(mnemonic, 'password123');
|
|
195
|
+
const blob = new Blob([JSON.stringify(jsonData)], { type: "application/json" });
|
|
196
|
+
// Save blob locally...
|
|
197
|
+
|
|
198
|
+
// -- RECOVERING --
|
|
199
|
+
const recoveredData = JSON.parse(await blob.text());
|
|
200
|
+
const recoveredKey = await MajikKey.importFromMnemonicBackup(
|
|
201
|
+
recoveredData.id,
|
|
202
|
+
recoveredData.seed.join(" "),
|
|
203
|
+
recoveredData.phrase,
|
|
204
|
+
'Recovered Key'
|
|
205
|
+
);
|
|
706
206
|
```
|
|
707
207
|
|
|
208
|
+
### 2. Password Verification Before Action
|
|
708
209
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
### Example 4: Update Passphrase
|
|
712
|
-
|
|
713
|
-
```ts
|
|
714
|
-
import { MajikKey } from '@majikah/majik-key';
|
|
715
|
-
|
|
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');
|
|
210
|
+
```typescript
|
|
211
|
+
const key = MajikKey.fromJSON(storedJson);
|
|
722
212
|
|
|
723
|
-
|
|
724
|
-
await key.
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
// Verify new passphrase works
|
|
731
|
-
key.lock();
|
|
732
|
-
await key.unlock('new-secure-password');
|
|
733
|
-
console.log('✅ New passphrase verified!');
|
|
213
|
+
if (await key.verify('user-input-password')) {
|
|
214
|
+
await key.unlock('user-input-password');
|
|
215
|
+
// ... proceed with signing/encryption
|
|
216
|
+
key.lock(); // Always clean up!
|
|
217
|
+
} else {
|
|
218
|
+
throw new Error("Invalid passphrase");
|
|
734
219
|
}
|
|
735
|
-
|
|
736
|
-
changePassphrase();
|
|
737
220
|
```
|
|
738
221
|
|
|
739
|
-
---
|
|
740
|
-
|
|
741
|
-
### Example 5: Verify Passphrase
|
|
742
|
-
|
|
743
|
-
```ts
|
|
744
|
-
import { MajikKey } from '@majikah/majik-key';
|
|
745
|
-
|
|
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
|
-
```
|
|
765
222
|
|
|
766
223
|
---
|
|
767
224
|
|
|
768
|
-
|
|
225
|
+
### [Majik Signature](https://majikah.solutions/products/majik-signature) — Flagship
|
|
226
|
+
**Post-quantum cryptographic file signing and verification.**
|
|
769
227
|
|
|
770
|
-
|
|
228
|
+
[](https://www.npmjs.com/package/@majikah/majik-signature) [](https://www.npmjs.com/package/@majikah/majik-signature) [](https://bundlephobia.com/package/@majikah/majik-signature) [](https://opensource.org/licenses/Apache-2.0)
|
|
771
229
|
|
|
772
|
-
|
|
230
|
+
[](https://signature.majikah.solutions)
|
|
773
231
|
|
|
774
|
-
```ts
|
|
775
|
-
import { MajikKey } from '@majikah/majik-key';
|
|
776
232
|
|
|
777
|
-
|
|
778
|
-
// Create or load a Majik Key
|
|
779
|
-
const mnemonic = MajikKey.generateMnemonic();
|
|
780
|
-
const key = await MajikKey.create(mnemonic, 'password', 'Message Account');
|
|
233
|
+
**Majik Signature** is the flagship feature of the ecosystem, providing hybrid classical and post-quantum content signing. It secures your files by requiring both an **Ed25519** (classical) and an **ML-DSA-87** (post-quantum) signature to pass verification.
|
|
781
234
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
235
|
+
* **Hybrid Security:** Verification requires BOTH signatures to pass, ensuring robust forward-secrecy.
|
|
236
|
+
* **Embedded Multi-Sig:** Seamlessly embeds signatures into files with full support for multi-signature envelopes.
|
|
237
|
+
* **Cryptographic Allowlists:** Establish an expected list of signers. Non-listed signers are rejected cryptographically.
|
|
238
|
+
* **Sealing:** The issuer can compute a SHA3-512 seal over the signatories, preventing any further signing attempts.
|
|
785
239
|
|
|
786
|
-
|
|
787
|
-
const blob = new Blob([jsonString], {
|
|
788
|
-
type: "application/json;charset=utf-8",
|
|
789
|
-
});
|
|
240
|
+
### Majik Signature Quick Start
|
|
790
241
|
|
|
791
|
-
|
|
792
|
-
|
|
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';
|
|
242
|
+
```typescript
|
|
243
|
+
import { MajikSignature, MajikKey } from '@majikah/majik-key';
|
|
802
244
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
245
|
+
// 1. Sign a file and embed the signature (Requires an unlocked key with signing keys)
|
|
246
|
+
const { blob, signature } = await MajikSignature.signFile(myFileBlob, myUnlockedKey, {
|
|
247
|
+
// Optional: restrict future signers
|
|
248
|
+
expectedSigners: [ MajikSignature.expectedSignerFromKey(myUnlockedKey) ]
|
|
249
|
+
});
|
|
806
250
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
username: 'myusername',
|
|
810
|
-
// ... other user properties
|
|
811
|
-
});
|
|
251
|
+
// 2. Verify a signed file's embedded signatures
|
|
252
|
+
const results = await MajikSignature.verifyFile(blob, myUnlockedKey);
|
|
812
253
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
restricted: false
|
|
817
|
-
});
|
|
254
|
+
results.forEach(res => {
|
|
255
|
+
console.log(`Signer ${res.signerId} valid?`, res.valid);
|
|
256
|
+
});
|
|
818
257
|
|
|
819
|
-
|
|
820
|
-
}
|
|
258
|
+
// 3. Seal a multi-sig file to prevent further signatures
|
|
259
|
+
const { sealInfo } = await MajikSignature.seal(blob, myUnlockedKey);
|
|
260
|
+
console.log("File sealed at:", sealInfo.sealTimestamp);
|
|
821
261
|
```
|
|
822
262
|
|
|
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
263
|
|
|
860
264
|
---
|
|
861
265
|
|
|
862
|
-
|
|
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.
|
|
266
|
+
## Security Best Practices
|
|
869
267
|
|
|
870
|
-
|
|
268
|
+
✅ **DO:**
|
|
269
|
+
* Lock keys (`.lock()`) immediately after signing or decrypting payloads to free memory.
|
|
270
|
+
* Utilize `mlKemPublicKey` for all new communication protocols to ensure PQ-readiness.
|
|
271
|
+
* Keep `@scure/bip39` and underlying crypto dependencies updated.
|
|
871
272
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
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.
|
|
273
|
+
❌ **DON'T:**
|
|
274
|
+
* Log `mnemonic` phrases or `privateKeyBase64` outputs in production environments.
|
|
275
|
+
* Use `toDangerousJSON()` unless handling highly specific server-side secret injections.
|
|
886
276
|
|
|
887
277
|
---
|
|
888
278
|
|
|
889
|
-
##
|
|
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)
|
|
279
|
+
## Ecosystem
|
|
895
280
|
|
|
896
|
-
[
|
|
897
|
-
|
|
898
|
-
|
|
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)
|
|
907
|
-
|
|
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.
|
|
281
|
+
* [Majik Signature Web App](https://signature.majikah.solutions)
|
|
282
|
+
* [Majik Signature on Microsoft Store](https://apps.microsoft.com/detail/9pl9g3xzvd1x)
|
|
283
|
+
* [Majik Signature Official Repository](https://github.com/Majikah/majik-signature)
|
|
919
284
|
|
|
920
285
|
---
|
|
921
|
-
## Author
|
|
922
|
-
|
|
923
|
-
Made with 💙 by [@thezelijah](https://github.com/jedlsf)
|
|
924
286
|
|
|
925
|
-
##
|
|
287
|
+
## License & Author
|
|
926
288
|
|
|
927
|
-
-
|
|
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
|
-
---
|
|
289
|
+
**License:** [Apache-2.0](LICENSE) — free for personal and commercial use.
|
|
932
290
|
|
|
933
|
-
|
|
291
|
+
Developed by **Josef Elijah Fabian (Zelijah)** | [Majikah Solutions OPC](https://majikah.solutions/about)
|
|
934
292
|
|
|
935
|
-
|
|
936
|
-
|
|
293
|
+
* **GitHub:** [@jedlsf](https://github.com/jedlsf)
|
|
294
|
+
* **Website:** [https://www.thezelijah.world](https://www.thezelijah.world)
|
|
295
|
+
* **Email:** [business@thezelijah.world](mailto:business@thezelijah.world)
|