@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 CHANGED
@@ -1,936 +1,295 @@
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
-
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
+ [![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)
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 has been upgraded to meet modern and future cryptographic standards.
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
- ### 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.
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
- ## Overview
114
-
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.
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
- ### Use Cases
32
+ %% Encryption branch
33
+ B --> E[Encryption]
34
+ E --> E1[ML-KEM-768]
35
+ E --> E2[AES-256-GCM]
127
36
 
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
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
- ## Features
46
+ S1 --> P2[Majik Buwiz]
47
+ S2 --> P2
48
+ E1 --> P2
49
+ E2 --> P2
50
+ I1 --> P2
51
+ I2 --> P2
137
52
 
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
- ---
53
+ E1 --> P3[Majik Message]
54
+ E2 --> P3
168
55
 
169
- ## Installation
56
+ I1 --> P4[Majik Universal ID]
57
+ I2 --> P4
170
58
 
171
- ```bash
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
- ## API Reference
67
+ ## Experimental Web3 Support
221
68
 
222
- ### Static Methods
69
+ Majik Key features experimental integration for deriving keys natively compatible with modern Web3 ecosystems, specifically **Bitcoin** and **Solana**.
223
70
 
224
- #### `MajikKey.create(mnemonic, passphrase, label?)`
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
- #### `MajikKey.fromJSON(json)`
244
- Load a Majik Key from JSON (locked state).
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
- #### `MajikKey.fromMnemonicJSON(mnemonicJson, passphrase, label?)`
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
- #### `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
- );
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
- #### `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
98
+ ## Features
314
99
 
315
- **Example:**
316
- ```ts
317
- const mnemonic12 = MajikKey.generateMnemonic(); // 12 words
318
- const mnemonic24 = MajikKey.generateMnemonic(256); // 24 words
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
- #### `MajikKey.validateMnemonic(mnemonic)`
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
- **Example:**
332
- ```ts
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
- ### 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
115
+ ## Quick Start (Core Identity)
345
116
 
346
- **Returns:** `Promise<this>` - This instance for chaining
117
+ Get up and running with a secure, unlockable account in seconds.
347
118
 
348
- **Throws:** `MajikKeyError` if passphrase is incorrect or key is already unlocked
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
- #### `lock()`
358
- Lock the Majik Key by clearing private keys from memory.
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
- **Returns:** `this` - This instance for chaining
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
- **Example:**
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
- **Example:**
451
- ```ts
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
- #### `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
- ```
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
- #### `publicKeyBase64: string`
551
- The public key in base64 format.
146
+ ### Static Methods (Lifecycle & Generation)
552
147
 
553
- #### `label: string`
554
- The user-defined label.
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
- #### `backup: string`
557
- The mnemonic backup identifier.
157
+ ### Instance Methods (State & Management)
558
158
 
559
- #### `timestamp: Date`
560
- The creation timestamp.
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
- #### `isLocked: boolean`
563
- Whether the key is currently locked.
167
+ ### Export & Integration Methods
564
168
 
565
- #### `isUnlocked: boolean`
566
- Whether the key is currently unlocked.
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
- #### `metadata: MajikKeyMetadata`
569
- Safe metadata object (no sensitive data).
177
+ ### Instance Getters
178
+ *Access public data at any time:*
179
+ `id`, `fingerprint`, `publicKey`, `publicKeyBase64`, `label`, `backup`, `timestamp`, `isLocked`, `isUnlocked`, `metadata`.
570
180
 
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
- ```
181
+ *Access restricted data (Throws `MajikKeyError` if locked):*
182
+ `getPrivateKey()`, `getPrivateKeyBase64()`.
582
183
 
583
184
  ---
584
185
 
585
186
  ## Usage Examples
586
187
 
587
- ### Example 1: Create and Manage a Key
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
- ### Example 2: Lock/Unlock Pattern
622
-
623
- ```ts
190
+ ```typescript
624
191
  import { MajikKey } from '@majikah/majik-key';
625
192
 
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
- }
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
- // 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!');
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
- ## Integration with Majik Message
225
+ ### [Majik Signature](https://majikah.solutions/products/majik-signature) — Flagship
226
+ **Post-quantum cryptographic file signing and verification.**
769
227
 
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.
228
+ [![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)
771
229
 
772
- ### Importing to Majik Message
230
+ [![Majik Signature Hero](https://github.com/user-attachments/assets/781bb778-9535-4b1f-bbc5-820550ecc864)](https://signature.majikah.solutions)
773
231
 
774
- ```ts
775
- import { MajikKey } from '@majikah/majik-key';
776
232
 
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');
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
- // Export to MnemonicJSON format for Majik Message
783
- const mnemonicData = key.toMnemonicJSON(mnemonic, 'password');
784
- const jsonString = JSON.stringify(mnemonicData);
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
- // Download this blob as a JSON locally
787
- const blob = new Blob([jsonString], {
788
- type: "application/json;charset=utf-8",
789
- });
240
+ ### Majik Signature Quick Start
790
241
 
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';
242
+ ```typescript
243
+ import { MajikSignature, MajikKey } from '@majikah/majik-key';
802
244
 
803
- async function createMessageIdentity() {
804
- const mnemonic = MajikKey.generateMnemonic();
805
- const key = await MajikKey.create(mnemonic, 'password', 'Message Identity');
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
- // Create/parse a MajikUser instance
808
- const user = new MajikUser({
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
- // Convert to Majik Message Identity
814
- const identity = await key.toMajikMessageIdentity(user, {
815
- label: 'My Message Account',
816
- restricted: false
817
- });
254
+ results.forEach(res => {
255
+ console.log(`Signer ${res.signerId} valid?`, res.valid);
256
+ });
818
257
 
819
- console.log('Majik Message Identity created:', identity);
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
- ### 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.
266
+ ## Security Best Practices
869
267
 
870
- - **Performance**: Lock keys when not in use to free memory and reduce attack surface.
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
- - **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.
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
- ## 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)
279
+ ## Ecosystem
895
280
 
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)
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
- ## About the Developer
287
+ ## License & Author
926
288
 
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
- ---
289
+ **License:** [Apache-2.0](LICENSE) — free for personal and commercial use.
932
290
 
933
- ## Contact
291
+ Developed by **Josef Elijah Fabian (Zelijah)** | [Majikah Solutions OPC](https://majikah.solutions/about)
934
292
 
935
- - **Business Email**: [business@thezelijah.world](mailto:business@thezelijah.world)
936
- - **Official Website**: [https://www.thezelijah.world](https://www.thezelijah.world)
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)