@majikah/majik-key 0.3.0 → 0.3.2
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 +46 -39
- package/dist/core/crypto/crypto-provider.js +2 -1
- package/dist/core/crypto/encryption-engine.js +19 -8
- package/dist/core/validator.js +2 -0
- package/dist/core/web3/bitcoin/constants.d.ts +1 -1
- package/dist/core/web3/bitcoin/constants.js +1 -1
- package/dist/majik-key.d.ts +5 -1
- package/dist/majik-key.js +37 -6
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# Majik Key
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
|
|
3
5
|
[](https://www.thezelijah.world) 
|
|
4
|
-
|
|
6
|
+
|
|
7
|
+
[](https://doi.org/10.5281/zenodo.21339132)    [](https://opensource.org/licenses/Apache-2.0)
|
|
5
8
|
|
|
6
9
|
**Majik Key** turns a single BIP-39 mnemonic into a complete cryptographic identity — encryption, classical + post-quantum signing, and (experimentally) Bitcoin and Solana keys — encrypted at rest and ready to plug into the rest of the Majikah ecosystem.
|
|
7
10
|
|
|
@@ -157,10 +160,10 @@ Majik Key can derive **Bitcoin** and **Solana** key material directly from the s
|
|
|
157
160
|
- **Solana key derivation is on-demand.** Rather than storing a separate Solana keypair, Majik Key derives it deterministically from your Ed25519 signing key each time you access `key.web3.solana` (and caches it in memory for as long as the key stays unlocked). The base58 Solana address also works with no extra install.
|
|
158
161
|
- **The optional peer dependencies are only needed for chain-native address/transaction objects:**
|
|
159
162
|
|
|
160
|
-
| Chain
|
|
161
|
-
|
|
|
163
|
+
| Chain | Peer dependency | Needed for |
|
|
164
|
+
| :------ | :------------------ | :--------------------------------------------------------- |
|
|
162
165
|
| Bitcoin | `@scure/btc-signer` | Native SegWit (bech32) address encoding, PSBT construction |
|
|
163
|
-
| Solana
|
|
166
|
+
| Solana | `@solana/kit` | Real `KeyPairSigner` instances, kit-native `Address` type |
|
|
164
167
|
|
|
165
168
|
```bash
|
|
166
169
|
npm install @scure/btc-signer # for Bitcoin addresses
|
|
@@ -183,7 +186,7 @@ const standardBtc = await MajikKey.deriveStandardBitcoinFromMnemonic(mnemonic);
|
|
|
183
186
|
|
|
184
187
|
### Two Solana paths, on purpose
|
|
185
188
|
|
|
186
|
-
By default (`deriveSolanaKeypairFromEdSecretKey`), the Solana keypair is domain-separated from your Ed25519 message-signing key via `SHA256(edSeed || "
|
|
189
|
+
By default (`deriveSolanaKeypairFromEdSecretKey`), the Solana keypair is domain-separated from your Ed25519 message-signing key via `SHA256(edSeed || "MajikKeySolanaSeed")`, so the same private key never secures two different protocols. You can opt into reusing your Ed25519 message-signing key directly instead:
|
|
187
190
|
|
|
188
191
|
```typescript
|
|
189
192
|
// Recommended: domain-separated Solana key
|
|
@@ -234,38 +237,38 @@ localStorage.setItem('myKey', key.toString());
|
|
|
234
237
|
|
|
235
238
|
### Static Methods (Lifecycle & Generation)
|
|
236
239
|
|
|
237
|
-
| Method
|
|
238
|
-
|
|
|
239
|
-
| `create()`
|
|
240
|
-
| `fromJSON()`
|
|
241
|
-
| `fromMnemonicJSON()`
|
|
242
|
-
| `importFromMnemonicBackup()`
|
|
243
|
-
| `fromDangerousJSON()`
|
|
244
|
-
| `generateMnemonic()`
|
|
245
|
-
| `validateMnemonic()`
|
|
246
|
-
| `deriveStandardBitcoinFromMnemonic()` *(experimental)* | `mnemonic`, `mnemonicLanguage?`
|
|
240
|
+
| Method | Parameters | Returns | Description |
|
|
241
|
+
| :----------------------------------------------------- | :---------------------------------------------------------------- | :-------------------------------- | :---------------------------------------------------------------------------------------------------------------- |
|
|
242
|
+
| `create()` | `mnemonic`, `passphrase`, `label?`, `mnemonicLanguage?` | `Promise<MajikKey>` | Creates a new Argon2id-protected, fully post-quantum-capable account. |
|
|
243
|
+
| `fromJSON()` | `json` | `MajikKey` | Loads a locked key from safe JSON storage. |
|
|
244
|
+
| `fromMnemonicJSON()` | `mnemonicJson`, `passphrase`, `label?` | `Promise<MajikKey>` | Rebuilds a key straight from a portable seed export. |
|
|
245
|
+
| `importFromMnemonicBackup()` | `backup`, `mnemonic`, `passphrase`, `label?`, `mnemonicLanguage?` | `Promise<MajikKey>` | Full migration path — verifies the mnemonic, then re-derives and re-encrypts the complete identity with Argon2id. |
|
|
246
|
+
| `fromDangerousJSON()` | `json` | `MajikKey` | Reconstructs an already-unlocked key from a dangerous export. Server-side only — see warning below. |
|
|
247
|
+
| `generateMnemonic()` | `strength?` *(128 \| 256)*, `language?` | `Promise<string>` | Generates a 12- or 24-word BIP-39 phrase. |
|
|
248
|
+
| `validateMnemonic()` | `mnemonic` | `boolean` | Validates a BIP-39 mnemonic phrase. |
|
|
249
|
+
| `deriveStandardBitcoinFromMnemonic()` *(experimental)* | `mnemonic`, `mnemonicLanguage?` | `Promise<BitcoinKeypairMaterial>` | Derives the real BIP-84 mainnet Bitcoin key without needing a `MajikKey` instance. |
|
|
247
250
|
|
|
248
251
|
### Instance Methods (State & Management)
|
|
249
252
|
|
|
250
|
-
| Method
|
|
251
|
-
|
|
|
252
|
-
| `unlock()`
|
|
253
|
-
| `lock()`
|
|
254
|
-
| `verify()`
|
|
255
|
-
| `updatePassphrase()` | `currentPass`, `newPass` | `Promise<this>`
|
|
256
|
-
| `migrate()`
|
|
257
|
-
| `updateLabel()`
|
|
253
|
+
| Method | Parameters | Returns | Description |
|
|
254
|
+
| :------------------- | :----------------------- | :----------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
255
|
+
| `unlock()` | `passphrase` | `Promise<this>` | Decrypts keys into memory. Chainable. |
|
|
256
|
+
| `lock()` | None | `this` | Purges all private key material (including cached Web3 keys) from memory. Chainable. |
|
|
257
|
+
| `verify()` | `passphrase` | `Promise<boolean>` | Tests a passphrase without keeping keys in memory or requiring an unlock. |
|
|
258
|
+
| `updatePassphrase()` | `currentPass`, `newPass` | `Promise<this>` | Re-encrypts every stored key under a new passphrase and migrates to KDF v2 if needed. |
|
|
259
|
+
| `migrate()` | `passphrase` | `Promise<this>` | Upgrades the X25519 key's KDF from v1 to v2 only — does **not** add ML-KEM/Ed25519/ML-DSA/Bitcoin keys. Use `importFromMnemonicBackup()` for a full upgrade. |
|
|
260
|
+
| `updateLabel()` | `newLabel` | `this` | Updates the human-readable account label. |
|
|
258
261
|
|
|
259
262
|
### Export & Integration Methods
|
|
260
263
|
|
|
261
|
-
| Method
|
|
262
|
-
|
|
|
263
|
-
| `toJSON()` / `toString()`
|
|
264
|
-
| `toDangerousJSON()`
|
|
265
|
-
| `toMnemonicJSON()`
|
|
266
|
-
| `exportMnemonicBackup()`
|
|
267
|
-
| `toContact()`
|
|
268
|
-
| `toMajikMessageIdentity()` | `Promise<MajikMessageIdentity>` | Formats the key for direct use in Majik Message. Requires a `MajikUser`.
|
|
264
|
+
| Method | Returns | Description |
|
|
265
|
+
| :------------------------- | :------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
266
|
+
| `toJSON()` / `toString()` | `MajikKeyJSON` / `string` | Safe export for DB/LocalStorage. No raw keys. |
|
|
267
|
+
| `toDangerousJSON()` | `MajikKeyDangerousJSON` | ⚠️ Contains every raw private key. Server-side secret injection only — see warning below. |
|
|
268
|
+
| `toMnemonicJSON()` | `MnemonicJSON` | ⚠️ Contains the raw mnemonic words (and passphrase, if you pass one) in plaintext — a transport format, not an at-rest storage format. Requires the key to be unlocked. |
|
|
269
|
+
| `exportMnemonicBackup()` | `Promise<string>` | Encrypted backup string, decryptable only with the original mnemonic — used to verify a mnemonic before `importFromMnemonicBackup()` re-derives the identity. |
|
|
270
|
+
| `toContact()` | `MajikContact` | Extracts public identity data for sharing (the basis for Majik Universal ID). |
|
|
271
|
+
| `toMajikMessageIdentity()` | `Promise<MajikMessageIdentity>` | Formats the key for direct use in Majik Message. Requires a `MajikUser`. |
|
|
269
272
|
|
|
270
273
|
### Instance Getters
|
|
271
274
|
|
|
@@ -279,14 +282,14 @@ localStorage.setItem('myKey', key.toString());
|
|
|
279
282
|
|
|
280
283
|
### Web3 (Experimental)
|
|
281
284
|
|
|
282
|
-
| Member
|
|
283
|
-
|
|
|
284
|
-
| `web3` *(getter)*
|
|
285
|
-
| `getBitcoinKeypairMaterial()` | `BitcoinKeypairMaterial`
|
|
286
|
-
| `getBitcoinWIF()`
|
|
287
|
-
| `getSolanaKeypairMaterial()`
|
|
288
|
-
| `getSolanaKeypair()`
|
|
289
|
-
| `getSolanaAddress()`
|
|
285
|
+
| Member | Returns | Notes |
|
|
286
|
+
| :---------------------------- | :---------------------------------- | :----------------------------------------------------------------------------------------------------------------------------- |
|
|
287
|
+
| `web3` *(getter)* | `{ solana, bitcoin? } \| undefined` | `undefined` if locked or has no Ed25519 signing key. `bitcoin` is present only if the account has stored Bitcoin key material. |
|
|
288
|
+
| `getBitcoinKeypairMaterial()` | `BitcoinKeypairMaterial` | Raw Bitcoin keypair bytes. |
|
|
289
|
+
| `getBitcoinWIF()` | `string` | Wallet Import Format string, pastes into any standard Bitcoin wallet. |
|
|
290
|
+
| `getSolanaKeypairMaterial()` | `SolanaKeypairMaterial` | Raw Solana keypair bytes. |
|
|
291
|
+
| `getSolanaKeypair()` | `Promise<any>` | Real `@solana/kit` `KeyPairSigner`. Requires `@solana/kit`. |
|
|
292
|
+
| `getSolanaAddress()` | `string` | Base58 Solana address. No extra dependency required. |
|
|
290
293
|
|
|
291
294
|
---
|
|
292
295
|
|
|
@@ -391,9 +394,13 @@ Developed by **Josef Elijah Fabian (Zelijah)** | [Majikah Solutions OPC](https:/
|
|
|
391
394
|
|
|
392
395
|
|
|
393
396
|
**Developer**: [Josef Elijah Fabian](https://github.com/jedlsf)
|
|
397
|
+
|
|
394
398
|
**GitHub**: [https://github.com/Majikah](https://github.com/Majikah)
|
|
399
|
+
|
|
395
400
|
**Project Repository**: [https://github.com/Majikah/majik-signature](https://github.com/Majikah/majik-signature)
|
|
396
401
|
|
|
402
|
+
**Technical Whitepaper**: [https://zenodo.org/records/21339132](https://zenodo.org/records/21339132)
|
|
403
|
+
|
|
397
404
|
---
|
|
398
405
|
|
|
399
406
|
## Contact
|
|
@@ -11,10 +11,11 @@ import { argon2id as nobleArgon2id } from "@noble/hashes/argon2.js";
|
|
|
11
11
|
import { ARGON2_PARAMS } from "./constants";
|
|
12
12
|
import { ml_kem768 } from "@noble/post-quantum/ml-kem.js";
|
|
13
13
|
import { argon2id as hashWasmArgon2id } from "hash-wasm";
|
|
14
|
+
const secureGetRandomValues = crypto.getRandomValues.bind(crypto);
|
|
14
15
|
export const IV_LENGTH = 12;
|
|
15
16
|
export function generateRandomBytes(len) {
|
|
16
17
|
const b = new Uint8Array(len);
|
|
17
|
-
|
|
18
|
+
secureGetRandomValues(b);
|
|
18
19
|
return b;
|
|
19
20
|
}
|
|
20
21
|
export function generateEd25519Keypair() {
|
|
@@ -7,6 +7,7 @@ import { deriveMlKemKeypairFromSeed, fingerprintFromPublicRaw, } from "./crypto-
|
|
|
7
7
|
import { concatUint8Arrays } from "../utils";
|
|
8
8
|
import { hash } from "@stablelib/sha256";
|
|
9
9
|
import { MAJIK_SIGNATURE_SEED } from "./constants";
|
|
10
|
+
const secureFill = Uint8Array.prototype.fill;
|
|
10
11
|
/**
|
|
11
12
|
* EncryptionEngine
|
|
12
13
|
* ----------------
|
|
@@ -35,15 +36,15 @@ export class EncryptionEngine {
|
|
|
35
36
|
* seed[32..64] for the implicit rejection parameter `z`.
|
|
36
37
|
*/
|
|
37
38
|
static async deriveIdentityFromMnemonic(mnemonic) {
|
|
39
|
+
if (typeof mnemonic !== "string" || mnemonic.trim().length === 0) {
|
|
40
|
+
throw new CryptoError("Mnemonic must be a non-empty string");
|
|
41
|
+
}
|
|
42
|
+
// Step 1: BIP-39 seed → 64 bytes
|
|
43
|
+
const seed = mnemonicToSeedSync(mnemonic); // returns Buffer (Node) or Uint8Array
|
|
44
|
+
const seed64 = new Uint8Array(seed); // normalize to Uint8Array
|
|
45
|
+
// Step 2: X25519 identity from first 32 bytes (existing path)
|
|
46
|
+
const seed32 = seed64.subarray(0, 32);
|
|
38
47
|
try {
|
|
39
|
-
if (typeof mnemonic !== "string" || mnemonic.trim().length === 0) {
|
|
40
|
-
throw new CryptoError("Mnemonic must be a non-empty string");
|
|
41
|
-
}
|
|
42
|
-
// Step 1: BIP-39 seed → 64 bytes
|
|
43
|
-
const seed = mnemonicToSeedSync(mnemonic); // returns Buffer (Node) or Uint8Array
|
|
44
|
-
const seed64 = new Uint8Array(seed); // normalize to Uint8Array
|
|
45
|
-
// Step 2: X25519 identity from first 32 bytes (existing path)
|
|
46
|
-
const seed32 = seed64.subarray(0, 32);
|
|
47
48
|
const ed = ed25519.generateKeyPairFromSeed(seed32);
|
|
48
49
|
const skCurve = ed2curve.convertSecretKey(ed.secretKey);
|
|
49
50
|
const pkCurve = ed2curve.convertPublicKey(ed.publicKey);
|
|
@@ -77,6 +78,14 @@ export class EncryptionEngine {
|
|
|
77
78
|
catch (err) {
|
|
78
79
|
throw new CryptoError("Failed to derive identity from mnemonic", err);
|
|
79
80
|
}
|
|
81
|
+
finally {
|
|
82
|
+
// CRITICAL: Zeroize the master seed
|
|
83
|
+
secureFill.call(seed64, 0);
|
|
84
|
+
secureFill.call(seed32, 0);
|
|
85
|
+
if (seed instanceof Uint8Array) {
|
|
86
|
+
secureFill.call(seed, 0);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
80
89
|
}
|
|
81
90
|
/* ================================
|
|
82
91
|
* Fingerprinting
|
|
@@ -123,3 +132,5 @@ export class CryptoError extends Error {
|
|
|
123
132
|
this.cause = cause;
|
|
124
133
|
}
|
|
125
134
|
}
|
|
135
|
+
Object.freeze(EncryptionEngine);
|
|
136
|
+
Object.freeze(EncryptionEngine.prototype);
|
package/dist/core/validator.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const MAJIK_BITCOIN_STANDARD_PATH = "m/84'/0'/0'/0/0";
|
|
2
|
-
export declare const MAJIK_BITCOIN_DOMAIN_PATH = "m/84'/
|
|
2
|
+
export declare const MAJIK_BITCOIN_DOMAIN_PATH = "m/84'/1971'/0'/0/0";
|
|
@@ -4,4 +4,4 @@ export const MAJIK_BITCOIN_STANDARD_PATH = "m/84'/0'/0'/0/0";
|
|
|
4
4
|
// Unregistered/private coin-type index — domain-separates Majik's default
|
|
5
5
|
// Bitcoin key from a user's "real" BTC wallet, while remaining 100% standard
|
|
6
6
|
// BIP-32 math (just a different branch of the same tree).
|
|
7
|
-
export const MAJIK_BITCOIN_DOMAIN_PATH = "m/84'/
|
|
7
|
+
export const MAJIK_BITCOIN_DOMAIN_PATH = "m/84'/1971'/0'/0/0";
|
package/dist/majik-key.d.ts
CHANGED
|
@@ -319,7 +319,11 @@ export declare class MajikKey {
|
|
|
319
319
|
*/
|
|
320
320
|
static fromDangerousJSON(json: MajikKeyDangerousJSON | string): MajikKey;
|
|
321
321
|
toMnemonicJSON(mnemonic: string, passphrase?: string): MnemonicJSON;
|
|
322
|
-
static fromMnemonicJSON(mnemonicJson: MnemonicJSON | string, passphrase: string, label?: string
|
|
322
|
+
static fromMnemonicJSON(mnemonicJson: MnemonicJSON | string, passphrase: string, label?: string, options?: {
|
|
323
|
+
mnemonicLanguage?: MnemonicLanguage;
|
|
324
|
+
/** @experimental Set `false` to skip deriving the Bitcoin keypair. Defaults to `true` for backward compatibility. */
|
|
325
|
+
deriveBitcoin?: boolean;
|
|
326
|
+
}): Promise<MajikKey>;
|
|
323
327
|
updateLabel(newLabel: string): this;
|
|
324
328
|
updatePassphrase(currentPassphrase: string, newPassphrase: string): Promise<this>;
|
|
325
329
|
/**
|
package/dist/majik-key.js
CHANGED
|
@@ -14,6 +14,7 @@ import { MajikKeyError } from "./core/error";
|
|
|
14
14
|
import { MajikMessageIdentity } from "./core/database/system/identity";
|
|
15
15
|
import { WORDLISTS } from "./core/crypto/wordlist";
|
|
16
16
|
import { deriveBitcoinKeypairFromSeed, signWithBitcoinMaterial, toBitcoinAddress, toWIF, deriveSolanaKeypairFromEdSecretKey, signWithSolanaMaterial, solanaAddressFromPublicKey, solanaMaterialFromEd25519SecretKey, toSolanaAddress, toSolanaKeyPairSigner, } from "./core/web3";
|
|
17
|
+
const secureFill = Uint8Array.prototype.fill;
|
|
17
18
|
const SALT_SIZE = 32;
|
|
18
19
|
/**
|
|
19
20
|
* MajikKey
|
|
@@ -483,7 +484,10 @@ export class MajikKey {
|
|
|
483
484
|
phrase: passphrase?.trim() || undefined,
|
|
484
485
|
};
|
|
485
486
|
}
|
|
486
|
-
static async fromMnemonicJSON(mnemonicJson, passphrase, label
|
|
487
|
+
static async fromMnemonicJSON(mnemonicJson, passphrase, label, options = {
|
|
488
|
+
deriveBitcoin: true,
|
|
489
|
+
mnemonicLanguage: "en",
|
|
490
|
+
}) {
|
|
487
491
|
try {
|
|
488
492
|
const parsed = typeof mnemonicJson === "string"
|
|
489
493
|
? JSON.parse(mnemonicJson)
|
|
@@ -492,7 +496,7 @@ export class MajikKey {
|
|
|
492
496
|
throw new MajikKeyError("Invalid MnemonicJSON");
|
|
493
497
|
const mnemonic = seedArrayToString(parsed.seed);
|
|
494
498
|
MajikKeyValidator.validateMnemonic(mnemonic);
|
|
495
|
-
return await MajikKey.create(mnemonic, passphrase, label);
|
|
499
|
+
return await MajikKey.create(mnemonic, passphrase, label, options);
|
|
496
500
|
}
|
|
497
501
|
catch (err) {
|
|
498
502
|
if (err instanceof MajikKeyError)
|
|
@@ -507,11 +511,11 @@ export class MajikKey {
|
|
|
507
511
|
return this;
|
|
508
512
|
}
|
|
509
513
|
async updatePassphrase(currentPassphrase, newPassphrase) {
|
|
514
|
+
MajikKeyValidator.validatePassphrase(currentPassphrase, "Current passphrase");
|
|
515
|
+
MajikKeyValidator.validatePassphrase(newPassphrase, "New passphrase");
|
|
516
|
+
const salt = new Uint8Array(base64ToArrayBuffer(this._salt));
|
|
517
|
+
const privateKeyBuffer = await MajikKey._decryptPrivateKey(this._encryptedPrivateKey, currentPassphrase, salt, this._kdfVersion);
|
|
510
518
|
try {
|
|
511
|
-
MajikKeyValidator.validatePassphrase(currentPassphrase, "Current passphrase");
|
|
512
|
-
MajikKeyValidator.validatePassphrase(newPassphrase, "New passphrase");
|
|
513
|
-
const salt = new Uint8Array(base64ToArrayBuffer(this._salt));
|
|
514
|
-
const privateKeyBuffer = await MajikKey._decryptPrivateKey(this._encryptedPrivateKey, currentPassphrase, salt, this._kdfVersion);
|
|
515
519
|
let mlKemSecretKeyBytes;
|
|
516
520
|
if (this._encryptedMlKemSecretKey) {
|
|
517
521
|
mlKemSecretKeyBytes = await MajikKey._decryptMlKemSecretKey(this._encryptedMlKemSecretKey, currentPassphrase, salt);
|
|
@@ -556,6 +560,11 @@ export class MajikKey {
|
|
|
556
560
|
throw err;
|
|
557
561
|
throw new MajikKeyError("Failed to update passphrase", err);
|
|
558
562
|
}
|
|
563
|
+
finally {
|
|
564
|
+
// Clear the temporary unencrypted buffer
|
|
565
|
+
secureFill.call(new Uint8Array(privateKeyBuffer), 0);
|
|
566
|
+
secureFill.call(salt, 0);
|
|
567
|
+
}
|
|
559
568
|
}
|
|
560
569
|
/**
|
|
561
570
|
* Migrate KDF from PBKDF2 to Argon2id without changing passphrase.
|
|
@@ -585,6 +594,24 @@ export class MajikKey {
|
|
|
585
594
|
// ── LOCK / UNLOCK ────────────────────────────────────────────────────────────
|
|
586
595
|
// required
|
|
587
596
|
lock() {
|
|
597
|
+
// 1. Zeroize raw bytes of all active keys
|
|
598
|
+
// Apply the secure fill using .call(targetArray, value)
|
|
599
|
+
if (this._privateKey &&
|
|
600
|
+
"raw" in this._privateKey &&
|
|
601
|
+
this._privateKey.raw instanceof Uint8Array) {
|
|
602
|
+
secureFill.call(this._privateKey.raw, 0);
|
|
603
|
+
}
|
|
604
|
+
if (this._mlKemSecretKey)
|
|
605
|
+
secureFill.call(this._mlKemSecretKey, 0);
|
|
606
|
+
if (this._edSecretKey)
|
|
607
|
+
secureFill.call(this._edSecretKey, 0);
|
|
608
|
+
if (this._mlDsaSecretKey)
|
|
609
|
+
secureFill.call(this._mlDsaSecretKey, 0);
|
|
610
|
+
if (this._btcSecretKey)
|
|
611
|
+
secureFill.call(this._btcSecretKey, 0);
|
|
612
|
+
if (this._solanaKeypairMaterial) {
|
|
613
|
+
secureFill.call(this._solanaKeypairMaterial.secretKey, 0);
|
|
614
|
+
}
|
|
588
615
|
this._privateKey = undefined;
|
|
589
616
|
this._privateKeyBase64 = undefined;
|
|
590
617
|
this._mlKemSecretKey = undefined;
|
|
@@ -1207,3 +1234,7 @@ export class MajikKey {
|
|
|
1207
1234
|
return solanaAddressFromPublicKey(this.getSolanaKeypairMaterial(options).publicKey);
|
|
1208
1235
|
}
|
|
1209
1236
|
}
|
|
1237
|
+
// Freeze static methods (e.g., MajikKey.create, MajikKey.fromJSON)
|
|
1238
|
+
Object.freeze(MajikKey);
|
|
1239
|
+
// Freeze instance methods (e.g., this.lock, this.unlock)
|
|
1240
|
+
Object.freeze(MajikKey.prototype);
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@majikah/majik-key",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "A post-quantum ready seed phrase account library for the Majikah ecosystem. Manages deterministic X25519 and ML-KEM-768 identities with Argon2id protection and seamless legacy account migration.",
|
|
5
|
-
"version": "0.3.
|
|
5
|
+
"version": "0.3.2",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"author": "Zelijah",
|
|
8
8
|
"main": "./dist/index.js",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"package": "npm run build && npm version patch && git push && git push --tags",
|
|
49
49
|
"test": "vitest run",
|
|
50
50
|
"test:watch": "vitest",
|
|
51
|
+
"test:compat": "npx vitest test/majik-key-cross-compat.test.ts",
|
|
51
52
|
"test:web3:bitcoin": "npx vitest test/majik-key-bitcoin.test.ts",
|
|
52
53
|
"test:web3:solana": "npx vitest test/majik-key-solana.test.ts",
|
|
53
54
|
"test:web3": "npx vitest test/majik-key-bitcoin.test.ts test/majik-key-solana.test.ts",
|