@majikah/majik-bip-39 0.0.0-stage → 0.1.0

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.
Files changed (3) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +1015 -3
  3. package/package.json +62 -4
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2026 Majikah Solutions OPC
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md CHANGED
@@ -1,4 +1,1016 @@
1
- # Temporary Holding Version
1
+ # Majik BIP-39
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
4
- If no other versions are published within 30 days, this package and version will be deleted.
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
+
5
+ Deterministically derive a **standard BIP-39 mnemonic** from supported binary inputs such as images.
6
+
7
+ `@majikah/majik-bip-39` converts an input into a **versioned canonical representation**, derives exactly **256 bits of entropy**, and encodes that entropy using the standard BIP-39 wordlists.
8
+
9
+ The library does **not redefine BIP-39**. It only provides a deterministic way to produce BIP-39-compatible entropy from structured input.
10
+
11
+ > **Current support:** PNG images
12
+ > **Planned:** additional media handlers such as WAV/audio and video
13
+ >
14
+
15
+ ![npm](https://img.shields.io/npm/v/@majikah/majik-bip-39) ![npm downloads](https://img.shields.io/npm/dm/@majikah/majik-bip-39) ![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)
16
+
17
+ ---
18
+
19
+ ## Table of Contents
20
+
21
+ - [Majik BIP-39](#majik-bip-39)
22
+ - [Table of Contents](#table-of-contents)
23
+ - [Features](#features)
24
+ - [Installation](#installation)
25
+ - [Quick Start](#quick-start)
26
+ - [Derive from bytes](#derive-from-bytes)
27
+ - [Derive from a browser `File`](#derive-from-a-browser-file)
28
+ - [How It Works](#how-it-works)
29
+ - [Passphrase mode](#passphrase-mode)
30
+ - [Determinism](#determinism)
31
+ - [Language does not change the entropy](#language-does-not-change-the-entropy)
32
+ - [Image Derivation](#image-derivation)
33
+ - [PNG Canonicalization](#png-canonicalization)
34
+ - [Supported image data](#supported-image-data)
35
+ - [Currently rejected](#currently-rejected)
36
+ - [Resource Limits](#resource-limits)
37
+ - [Passphrase Mode](#passphrase-mode-1)
38
+ - [Important](#important)
39
+ - [BIP-39 Helpers](#bip-39-helpers)
40
+ - [Entropy → mnemonic](#entropy--mnemonic)
41
+ - [Mnemonic → entropy](#mnemonic--entropy)
42
+ - [Validate a mnemonic](#validate-a-mnemonic)
43
+ - [Supported BIP-39 Languages](#supported-bip-39-languages)
44
+ - [API](#api)
45
+ - [`MajikBip39.fromBytes()`](#majikbip39frombytes)
46
+ - [`MajikBip39.fromFile()`](#majikbip39fromfile)
47
+ - [`MajikBip39.derive()`](#majikbip39derive)
48
+ - [`MajikBip39.deriveMnemonic()`](#majikbip39derivemnemonic)
49
+ - [`MajikBip39.deriveEntropy()`](#majikbip39deriveentropy)
50
+ - [`MajikBip39.toMnemonic()`](#majikbip39tomnemonic)
51
+ - [`MajikBip39.toEntropy()`](#majikbip39toentropy)
52
+ - [`MajikBip39.validateMnemonic()`](#majikbip39validatemnemonic)
53
+ - [`MajikBip39.listHandlers()`](#majikbip39listhandlers)
54
+ - [`MajikBip39.listSchemes()`](#majikbip39listschemes)
55
+ - [Scheme Resolution](#scheme-resolution)
56
+ - [Errors](#errors)
57
+ - [Versioned Derivation](#versioned-derivation)
58
+ - [Reproducibility](#reproducibility)
59
+ - [Security Considerations](#security-considerations)
60
+ - [This is deterministic derivation, not random generation](#this-is-deterministic-derivation-not-random-generation)
61
+ - [Do not expose the mnemonic](#do-not-expose-the-mnemonic)
62
+ - [Passphrase security](#passphrase-security)
63
+ - [Input entropy is not automatically wallet entropy](#input-entropy-is-not-automatically-wallet-entropy)
64
+ - [Privacy](#privacy)
65
+ - [Design Philosophy](#design-philosophy)
66
+ - [Current Status](#current-status)
67
+ - [Implemented](#implemented)
68
+ - [Planned](#planned)
69
+ - [Example: Complete Deterministic Flow](#example-complete-deterministic-flow)
70
+ - [Compatibility with BIP-39](#compatibility-with-bip-39)
71
+ - [Important Limitations](#important-limitations)
72
+ - [License](#license)
73
+ - [Author](#author)
74
+ - [Contact](#contact)
75
+
76
+
77
+ ---
78
+
79
+ ## Features
80
+
81
+ * Deterministic input → BIP-39 derivation
82
+ * Versioned, handler-specific canonicalization
83
+ * Metadata-independent PNG canonicalization
84
+ * Standard BIP-39 entropy and mnemonic encoding
85
+ * Optional Argon2id passphrase derivation
86
+ * Multiple BIP-39 languages
87
+ * Browser `Blob` / `File` support
88
+ * Node.js `Uint8Array` support
89
+ * Explicit resource limits for untrusted input
90
+ * Extensible handler architecture for future media types
91
+ * Strict scheme resolution; no silent format guessing when ambiguous
92
+ * Standard BIP-39 import/export helpers
93
+
94
+ ---
95
+
96
+ ## Installation
97
+
98
+ ```sh
99
+ npm install @majikah/majik-bip-39
100
+ ```
101
+
102
+ ---
103
+
104
+ ## Quick Start
105
+
106
+ ### Derive from bytes
107
+
108
+ ```js
109
+ import { readFile } from "node:fs/promises";
110
+ import { MajikBip39 } from "@majikah/majik-bip-39";
111
+
112
+ const image = new Uint8Array(
113
+ await readFile("./image.png")
114
+ );
115
+
116
+ const mnemonic = await MajikBip39.fromBytes(image, {
117
+ mediaType: "image/png",
118
+ });
119
+
120
+ console.log(mnemonic);
121
+ ```
122
+
123
+ The resulting mnemonic is a normal **24-word BIP-39 mnemonic**.
124
+
125
+ ---
126
+
127
+ ### Derive from a browser `File`
128
+
129
+ `fromFile()` accepts any `Blob` or `File` that provides `arrayBuffer()`.
130
+
131
+ ```js
132
+ const mnemonic = await MajikBip39.fromFile(file);
133
+
134
+ console.log(mnemonic);
135
+ ```
136
+
137
+ You may also provide derivation options:
138
+
139
+ ```js
140
+ const mnemonic = await MajikBip39.fromFile(file, {
141
+ mediaType: "image/png",
142
+ mnemonicLanguage: "en",
143
+ });
144
+ ```
145
+
146
+ ---
147
+
148
+ ## How It Works
149
+
150
+ Majik BIP-39 uses a two-stage model:
151
+
152
+ ```mermaid
153
+ flowchart TD
154
+ A[Input] --> B[Handler]
155
+
156
+ B --> C[Detect / validate input]
157
+ B --> D[Canonicalize content]
158
+ B --> E[Produce canonical chunks]
159
+
160
+ C --> F[Versioned domain]
161
+ D --> F
162
+ E --> F
163
+
164
+ F --> G[SHA-256]
165
+ G --> H[256-bit entropy]
166
+ H --> I[BIP-39]
167
+ I --> J[24-word mnemonic]
168
+ ```
169
+
170
+ For an input without a passphrase, the core derivation is conceptually:
171
+
172
+ ```text
173
+ digest =
174
+ SHA-256(
175
+ UTF-8(canonical-domain) ||
176
+ canonical-chunk-1 ||
177
+ canonical-chunk-2 ||
178
+ ...
179
+ )
180
+ ```
181
+
182
+ The resulting 32-byte digest is used directly as BIP-39 entropy.
183
+
184
+ ### Passphrase mode
185
+
186
+ When a passphrase is supplied, Majik BIP-39 derives the final entropy using Argon2id.
187
+
188
+ Conceptually:
189
+
190
+ ```text
191
+ digest =
192
+ SHA-256(
193
+ UTF-8(canonical-domain) ||
194
+ canonical-content
195
+ )
196
+
197
+ salt =
198
+ SHA-256(
199
+ UTF-8(canonical-domain + "/salt") ||
200
+ digest
201
+ )
202
+
203
+ entropy =
204
+ Argon2id(
205
+ passphrase,
206
+ salt,
207
+ versioned parameters
208
+ )
209
+ ```
210
+
211
+ The final result is still ordinary **32-byte BIP-39 entropy**.
212
+
213
+ This means the output remains compatible with software that understands standard BIP-39.
214
+
215
+ ---
216
+
217
+ ## Determinism
218
+
219
+ For a fixed scheme, canonical representation, passphrase, and BIP-39 wordlist, the same input produces the same mnemonic.
220
+
221
+ For example:
222
+
223
+ ```text
224
+ same image
225
+ +
226
+ same scheme
227
+ +
228
+ same passphrase
229
+ +
230
+ same canonicalization version
231
+ =
232
+ same entropy
233
+ =
234
+ same mnemonic
235
+ ```
236
+
237
+ Without a passphrase, the result depends only on the canonicalized content.
238
+
239
+ With a passphrase, the passphrase becomes part of the derivation.
240
+
241
+ ### Language does not change the entropy
242
+
243
+ Changing the BIP-39 language changes the **words used to represent the entropy**, not the underlying entropy itself.
244
+
245
+ For example, these are different textual representations of the same 256-bit value:
246
+
247
+ ```js
248
+ const entropy = await MajikBip39.deriveEntropy(image, {
249
+ mediaType: "image/png",
250
+ });
251
+
252
+ const english = await MajikBip39.toMnemonic(entropy, "en");
253
+ const japanese = await MajikBip39.toMnemonic(entropy, "ja");
254
+ ```
255
+
256
+ The entropy is identical; only the BIP-39 wordlist changes.
257
+
258
+ ---
259
+
260
+ # Image Derivation
261
+
262
+ The currently implemented handler is the PNG image handler.
263
+
264
+ The default scheme is:
265
+
266
+ ```text
267
+ image-v1
268
+ ```
269
+
270
+ You can explicitly request it:
271
+
272
+ ```js
273
+ const mnemonic = await MajikBip39.fromBytes(image, {
274
+ mediaType: "image/png",
275
+ scheme: "image-v1",
276
+ });
277
+ ```
278
+
279
+ Or inspect the complete derivation result:
280
+
281
+ ```js
282
+ const result = await MajikBip39.derive(image, {
283
+ mediaType: "image/png",
284
+ scheme: "image-v1",
285
+ });
286
+
287
+ console.log(result.mnemonic);
288
+ console.log(result.entropy);
289
+ console.log(result.scheme);
290
+ console.log(result.handler);
291
+ console.log(result.passphraseUsed);
292
+ console.log(result.canonicalization);
293
+ ```
294
+
295
+ A result has the following shape:
296
+
297
+ ```ts
298
+ interface Bip39DerivationResult {
299
+ mnemonic: string;
300
+ entropy: Uint8Array;
301
+ scheme: Scheme;
302
+ handler: HandlerId;
303
+ passphraseUsed: boolean;
304
+ canonicalization: unknown;
305
+ }
306
+ ```
307
+
308
+ The exact `canonicalization` metadata is handler-specific.
309
+
310
+ ---
311
+
312
+ ## PNG Canonicalization
313
+
314
+ `image-v1` does not hash the raw PNG file bytes directly.
315
+
316
+ Instead, the image handler decodes the PNG and constructs a canonical representation of its pixel data.
317
+
318
+ This is important because a PNG file can contain metadata or encoding differences while representing the same underlying image.
319
+
320
+ Consequently, image metadata and other non-canonical PNG information do not affect the derived mnemonic.
321
+
322
+ Conceptually:
323
+
324
+ ```text
325
+ PNG file
326
+ │
327
+ ├─ metadata
328
+ ├─ ancillary chunks
329
+ ├─ encoding details
330
+ └─ pixel data
331
+ │
332
+ ▼
333
+ canonical pixels
334
+ │
335
+ ▼
336
+ image-v1
337
+ │
338
+ ▼
339
+ SHA-256
340
+ ```
341
+
342
+ Two PNG files that canonicalize to the same representation produce the same result.
343
+
344
+ ### Supported image data
345
+
346
+ `image-v1` currently supports static, non-indexed PNG images using:
347
+
348
+ * 8-bit grayscale
349
+ * 16-bit grayscale
350
+ * 8-bit grayscale + alpha
351
+ * 16-bit grayscale + alpha
352
+ * 8-bit RGB
353
+ * 16-bit RGB
354
+ * 8-bit RGBA
355
+ * 16-bit RGBA
356
+
357
+ ### Currently rejected
358
+
359
+ The current handler rejects:
360
+
361
+ * animated PNGs
362
+ * indexed / palette-based PNGs
363
+ * `tRNS` transparency
364
+ * bit depths below 8 bits
365
+
366
+ Other image formats may be recognized at the input-detection layer, but their decoders are not yet implemented.
367
+
368
+ In particular, JPEG, BMP, WebP, and TIFF decoding are currently unavailable.
369
+
370
+ ---
371
+
372
+ # Resource Limits
373
+
374
+ Image processing operates on untrusted binary input, so the library applies explicit resource limits.
375
+
376
+ The default limits are:
377
+
378
+ | Limit | Default |
379
+ | -------------------- | ---------: |
380
+ | Maximum file size | 64 MiB |
381
+ | Maximum width | 16,384 px |
382
+ | Maximum height | 16,384 px |
383
+ | Maximum total pixels | 64,000,000 |
384
+
385
+ These limits can be overridden:
386
+
387
+ ```js
388
+ const mnemonic = await MajikBip39.fromBytes(image, {
389
+ mediaType: "image/png",
390
+ limits: {
391
+ maxFileBytes: 32 * 1024 * 1024,
392
+ maxWidth: 8192,
393
+ maxHeight: 8192,
394
+ maxPixels: 32_000_000,
395
+ },
396
+ });
397
+ ```
398
+
399
+ Use lower limits when processing untrusted files in memory-constrained environments.
400
+
401
+ Limits must be positive integers.
402
+
403
+ ---
404
+
405
+ # Passphrase Mode
406
+
407
+ An optional passphrase adds a password-based derivation step using **Argon2id**.
408
+
409
+ ```js
410
+ const mnemonic = await MajikBip39.fromBytes(image, {
411
+ mediaType: "image/png",
412
+ passphrase: "your private passphrase",
413
+ });
414
+ ```
415
+
416
+ A different passphrase produces a different entropy value and therefore a different mnemonic.
417
+
418
+ The passphrase is normalized before derivation.
419
+
420
+ ```text
421
+ same image + different passphrase
422
+ │
423
+ ▼
424
+ different entropy
425
+ │
426
+ ▼
427
+ different mnemonic
428
+ ```
429
+
430
+ ### Important
431
+
432
+ A passphrase is not automatically a secure password.
433
+
434
+ A weak, predictable, reused, or exposed passphrase remains weak.
435
+
436
+ Do not treat passphrase mode as protection against a low-entropy or publicly known input.
437
+
438
+ ---
439
+
440
+ # BIP-39 Helpers
441
+
442
+ Majik BIP-39 also exposes standard BIP-39 conversion and validation helpers.
443
+
444
+ These functions are independent of image derivation.
445
+
446
+ ## Entropy → mnemonic
447
+
448
+ ```js
449
+ const mnemonic = await MajikBip39.toMnemonic(
450
+ entropy,
451
+ "en",
452
+ );
453
+ ```
454
+
455
+ The standard BIP-39 entropy sizes are supported:
456
+
457
+ ```text
458
+ 16 bytes → 12 words
459
+ 20 bytes → 15 words
460
+ 24 bytes → 18 words
461
+ 28 bytes → 21 words
462
+ 32 bytes → 24 words
463
+ ```
464
+
465
+ Invalid entropy lengths are rejected.
466
+
467
+ ---
468
+
469
+ ## Mnemonic → entropy
470
+
471
+ ```js
472
+ const entropy = await MajikBip39.toEntropy(
473
+ mnemonic,
474
+ "en",
475
+ );
476
+ ```
477
+
478
+ The mnemonic is validated against the selected BIP-39 wordlist before entropy is returned.
479
+
480
+ ---
481
+
482
+ ## Validate a mnemonic
483
+
484
+ ```js
485
+ const result = await MajikBip39.validateMnemonic(
486
+ mnemonic,
487
+ "en",
488
+ );
489
+
490
+ console.log(result.valid);
491
+ console.log(result.wordCount);
492
+ ```
493
+
494
+ Example result:
495
+
496
+ ```js
497
+ {
498
+ valid: true,
499
+ wordCount: 24
500
+ }
501
+ ```
502
+
503
+ An invalid mnemonic returns `valid: false`.
504
+
505
+ An unsupported language is rejected.
506
+
507
+ ---
508
+
509
+ # Supported BIP-39 Languages
510
+
511
+ The following standard wordlists are currently supported:
512
+
513
+ | Language | Code |
514
+ | ------------------- | ------- |
515
+ | English | `en` |
516
+ | French | `fr` |
517
+ | Spanish | `es` |
518
+ | Italian | `it` |
519
+ | Japanese | `ja` |
520
+ | Korean | `ko` |
521
+ | Czech | `czech` |
522
+ | Portuguese | `pt` |
523
+ | Simplified Chinese | `zh-cn` |
524
+ | Traditional Chinese | `zh-tw` |
525
+
526
+ Example:
527
+
528
+ ```js
529
+ const mnemonic = await MajikBip39.fromBytes(image, {
530
+ mediaType: "image/png",
531
+ mnemonicLanguage: "ja",
532
+ });
533
+ ```
534
+
535
+ ---
536
+
537
+ # API
538
+
539
+ ## `MajikBip39.fromBytes()`
540
+
541
+ Derive a mnemonic from raw bytes.
542
+
543
+ ```ts
544
+ static async fromBytes(
545
+ bytes: Uint8Array,
546
+ options?: DeriveOptions,
547
+ ): Promise<string>
548
+ ```
549
+
550
+ This is the simplest entry point for Node.js and other byte-oriented environments.
551
+
552
+ ---
553
+
554
+ ## `MajikBip39.fromFile()`
555
+
556
+ Derive a mnemonic from a browser `File` or `Blob`.
557
+
558
+ ```ts
559
+ static async fromFile(
560
+ file: Blob,
561
+ options?: DeriveOptions,
562
+ ): Promise<string>
563
+ ```
564
+
565
+ The file contents are read into a `Uint8Array` before processing.
566
+
567
+ The file's MIME type is used as `mediaType` when available.
568
+
569
+ An explicitly supplied `mediaType` in `options` takes precedence over the automatic file MIME type.
570
+
571
+ ---
572
+
573
+ ## `MajikBip39.derive()`
574
+
575
+ Return the complete derivation result.
576
+
577
+ ```ts
578
+ static async derive(
579
+ bytes: Uint8Array,
580
+ options?: DeriveOptions,
581
+ ): Promise<Bip39DerivationResult>
582
+ ```
583
+
584
+ Use this when an application needs the entropy, scheme, handler, or canonicalization information in addition to the mnemonic.
585
+
586
+ ---
587
+
588
+ ## `MajikBip39.deriveMnemonic()`
589
+
590
+ Alias for mnemonic derivation:
591
+
592
+ ```ts
593
+ static async deriveMnemonic(
594
+ bytes: Uint8Array,
595
+ options?: DeriveOptions,
596
+ ): Promise<string>
597
+ ```
598
+
599
+ ---
600
+
601
+ ## `MajikBip39.deriveEntropy()`
602
+
603
+ Derive only the final BIP-39 entropy.
604
+
605
+ ```ts
606
+ static async deriveEntropy(
607
+ bytes: Uint8Array,
608
+ options?: DeriveOptions,
609
+ ): Promise<Uint8Array>
610
+ ```
611
+
612
+ The current image derivation produces 32 bytes / 256 bits of entropy.
613
+
614
+ ---
615
+
616
+ ## `MajikBip39.toMnemonic()`
617
+
618
+ Convert valid BIP-39 entropy to a mnemonic.
619
+
620
+ ```ts
621
+ static async toMnemonic(
622
+ entropy: Uint8Array,
623
+ language?: MnemonicLanguage,
624
+ ): Promise<string>
625
+ ```
626
+
627
+ ---
628
+
629
+ ## `MajikBip39.toEntropy()`
630
+
631
+ Convert and validate a BIP-39 mnemonic.
632
+
633
+ ```ts
634
+ static async toEntropy(
635
+ mnemonic: string,
636
+ language?: MnemonicLanguage,
637
+ ): Promise<Uint8Array>
638
+ ```
639
+
640
+ ---
641
+
642
+ ## `MajikBip39.validateMnemonic()`
643
+
644
+ Validate a mnemonic against the selected wordlist.
645
+
646
+ ```ts
647
+ static async validateMnemonic(
648
+ mnemonic: string,
649
+ language?: MnemonicLanguage,
650
+ ): Promise<MnemonicValidation>
651
+ ```
652
+
653
+ ---
654
+
655
+ ## `MajikBip39.listHandlers()`
656
+
657
+ List registered input handlers.
658
+
659
+ ```js
660
+ const handlers = MajikBip39.listHandlers();
661
+
662
+ console.log(handlers);
663
+ ```
664
+
665
+ This is useful for feature discovery in applications.
666
+
667
+ ---
668
+
669
+ ## `MajikBip39.listSchemes()`
670
+
671
+ List schemes currently exposed by the registered handlers.
672
+
673
+ ```js
674
+ const schemes = MajikBip39.listSchemes();
675
+
676
+ console.log(schemes);
677
+ ```
678
+
679
+ As additional handlers are added, this registry becomes the discovery mechanism for supported derivation schemes.
680
+
681
+ ---
682
+
683
+ # Scheme Resolution
684
+
685
+ Majik BIP-39 intentionally does not silently guess between multiple possible derivation schemes.
686
+
687
+ Resolution follows this order:
688
+
689
+ ```text
690
+ 1. Explicit scheme
691
+ ↓
692
+ 2. Declared media type
693
+ ↓
694
+ 3. Content detection
695
+ ```
696
+
697
+ For example:
698
+
699
+ ```js
700
+ const result = await MajikBip39.derive(image, {
701
+ mediaType: "image/png",
702
+ scheme: "image-v1",
703
+ });
704
+ ```
705
+
706
+ When no scheme is explicitly specified, the library attempts to determine the appropriate handler.
707
+
708
+ If no handler recognizes the input, derivation fails.
709
+
710
+ If multiple handlers recognize the input and no scheme was specified, derivation fails with an ambiguity error rather than selecting one arbitrarily.
711
+
712
+ This makes derivation behavior explicit and reproducible.
713
+
714
+ ---
715
+
716
+ # Errors
717
+
718
+ The library exposes specific error types for common failure conditions, including:
719
+
720
+ * `HandlerNotFoundError`
721
+ * `InvalidEntropyLengthError`
722
+ * `InvalidInputError`
723
+ * `InvalidMnemonicError`
724
+ * `InvalidOptionError`
725
+ * `UnsupportedSchemeError`
726
+
727
+ Example:
728
+
729
+ ```js
730
+ import {
731
+ HandlerNotFoundError,
732
+ UnsupportedSchemeError,
733
+ } from "@majikah/majik-bip-39";
734
+
735
+ try {
736
+ const mnemonic = await MajikBip39.fromBytes(input);
737
+ } catch (error) {
738
+ if (error instanceof HandlerNotFoundError) {
739
+ console.error("Unsupported input");
740
+ } else if (error instanceof UnsupportedSchemeError) {
741
+ console.error("Unsupported derivation scheme");
742
+ } else {
743
+ throw error;
744
+ }
745
+ }
746
+ ```
747
+
748
+ ---
749
+
750
+ # Versioned Derivation
751
+
752
+ Derivation schemes are explicitly versioned.
753
+
754
+ For example:
755
+
756
+ ```text
757
+ image-v1
758
+ ```
759
+
760
+ should be treated as a stable algorithm identifier rather than merely an implementation label.
761
+
762
+ Applications that need long-term reproducibility should persist the scheme alongside any other recovery information.
763
+
764
+ A future `image-v2` may use different canonicalization or derivation rules without changing the meaning of `image-v1`.
765
+
766
+ This separation allows the library to evolve without silently changing existing derivation results.
767
+
768
+ ---
769
+
770
+ # Reproducibility
771
+
772
+ For deterministic recovery, preserve enough information to reproduce the original derivation:
773
+
774
+ ```text
775
+ Input
776
+ Scheme
777
+ Passphrase
778
+ Canonicalization version
779
+ ```
780
+
781
+ The mnemonic language only affects the textual BIP-39 representation; the underlying entropy remains the same.
782
+
783
+ For long-term interoperability, storing the explicit scheme is recommended instead of relying on the current default.
784
+
785
+ ---
786
+
787
+ # Security Considerations
788
+
789
+ ## This is deterministic derivation, not random generation
790
+
791
+ A mnemonic derived from an image inherits its unpredictability from the image and any passphrase used.
792
+
793
+ A predictable or publicly available image can produce a predictable mnemonic.
794
+
795
+ For example, using a famous photograph, stock image, logo, or otherwise publicly known file should not be assumed to provide secret entropy.
796
+
797
+ ```text
798
+ public / guessable input
799
+ +
800
+ predictable derivation
801
+ =
802
+ guessable secret
803
+ ```
804
+
805
+ This is fundamentally different from generating a wallet mnemonic from a cryptographically secure random number generator.
806
+
807
+ ---
808
+
809
+ ## Do not expose the mnemonic
810
+
811
+ The resulting mnemonic and entropy are sensitive secrets.
812
+
813
+ Avoid:
814
+
815
+ * logging them
816
+ * sending them to analytics systems
817
+ * storing them in URLs
818
+ * embedding them in source code
819
+ * putting them in telemetry
820
+ * displaying them unnecessarily
821
+ * publishing the source image when the image itself is intended to be secret
822
+
823
+ Applications should handle derived entropy and mnemonics with the same care as other wallet secrets.
824
+
825
+ ---
826
+
827
+ ## Passphrase security
828
+
829
+ Argon2id increases the cost of passphrase guessing, but it cannot compensate for a weak or exposed passphrase.
830
+
831
+ Use a strong, unique passphrase when passphrase mode is part of the security model.
832
+
833
+ ---
834
+
835
+ ## Input entropy is not automatically wallet entropy
836
+
837
+ A deterministic image-to-mnemonic system can be useful for reproducibility, portability, experimentation, or specialized recovery workflows.
838
+
839
+ It should **not automatically be considered a replacement for cryptographically secure random wallet generation**.
840
+
841
+ Before using image-derived mnemonics for high-value assets, independently evaluate:
842
+
843
+ * input entropy
844
+ * attacker knowledge of the input
845
+ * passphrase strength
846
+ * recovery procedures
847
+ * canonicalization stability
848
+ * scheme/version persistence
849
+ * operational security
850
+
851
+ ---
852
+
853
+ # Privacy
854
+
855
+ Majik BIP-39 performs derivation locally from the supplied bytes.
856
+
857
+ The library itself does not require a remote service, account, or network-based derivation step.
858
+
859
+ Applications are still responsible for avoiding accidental disclosure through their own logging, storage, telemetry, synchronization, or UI layers.
860
+
861
+ ---
862
+
863
+ # Design Philosophy
864
+
865
+ Majik BIP-39 is intentionally split into two concerns:
866
+
867
+ ```text
868
+ Input-specific processing
869
+ │
870
+ ▼
871
+ Canonical representation
872
+ │
873
+ ▼
874
+ Deterministic entropy
875
+ │
876
+ ▼
877
+ Standard BIP-39
878
+ ```
879
+
880
+ The media handler is responsible for understanding a specific input type.
881
+
882
+ BIP-39 remains responsible for mnemonic encoding.
883
+
884
+ This separation makes it possible to add new handlers without creating a new mnemonic standard for every media type.
885
+
886
+ Future handlers may support inputs such as:
887
+
888
+ ```text
889
+ PNG
890
+ WAV
891
+ MP3
892
+ FLAC
893
+ MP4
894
+ ...
895
+ ```
896
+
897
+ while still producing ordinary BIP-39 entropy and mnemonics.
898
+
899
+ ---
900
+
901
+ # Current Status
902
+
903
+ ### Implemented
904
+
905
+ * PNG image handler
906
+ * `image-v1`
907
+ * deterministic canonicalization
908
+ * SHA-256 derivation
909
+ * optional Argon2id passphrase mode
910
+ * 256-bit entropy output
911
+ * BIP-39 mnemonic encoding
912
+ * BIP-39 mnemonic validation
913
+ * BIP-39 entropy ↔ mnemonic conversion
914
+ * 10 BIP-39 wordlists
915
+ * browser `Blob` / `File` input
916
+ * byte-oriented input
917
+ * image resource limits
918
+ * handler and scheme registry
919
+
920
+ ### Planned
921
+
922
+ Additional input handlers are intended to be added without changing the BIP-39 layer.
923
+
924
+ Examples include:
925
+
926
+ * WAV / PCM audio
927
+ * other audio formats
928
+ * video
929
+ * additional deterministic media representations
930
+
931
+ Each handler should define its own canonicalization and versioned scheme while preserving standard BIP-39 compatibility.
932
+
933
+ ---
934
+
935
+ # Example: Complete Deterministic Flow
936
+
937
+ ```js
938
+ import { readFile } from "node:fs/promises";
939
+ import { MajikBip39 } from "@majikah/majik-bip-39";
940
+
941
+ const image = new Uint8Array(
942
+ await readFile("./secret.png")
943
+ );
944
+
945
+ const result = await MajikBip39.derive(image, {
946
+ mediaType: "image/png",
947
+ scheme: "image-v1",
948
+ passphrase: "correct horse battery staple",
949
+ mnemonicLanguage: "en",
950
+ });
951
+
952
+ console.log("Mnemonic:", result.mnemonic);
953
+ console.log("Entropy:", result.entropy);
954
+ console.log("Scheme:", result.scheme);
955
+ console.log("Handler:", result.handler);
956
+ console.log("Passphrase used:", result.passphraseUsed);
957
+ console.log("Canonicalization:", result.canonicalization);
958
+ ```
959
+
960
+ The same canonical input, scheme, passphrase, and derivation parameters will reproduce the same underlying entropy.
961
+
962
+ ---
963
+
964
+ # Compatibility with BIP-39
965
+
966
+ The final output is a standard BIP-39 mnemonic.
967
+
968
+ That means applications can use the resulting mnemonic with existing BIP-39-compatible tooling, subject to the normal requirements of that application.
969
+
970
+ Majik BIP-39 does **not** introduce a custom mnemonic format.
971
+
972
+ Its purpose is to answer a different question:
973
+
974
+ > **How can deterministic input be converted into valid BIP-39 entropy?**
975
+
976
+ ---
977
+
978
+ # Important Limitations
979
+
980
+ This library currently should not be interpreted as:
981
+
982
+ * a general-purpose image hash
983
+ * a cryptographically random number generator
984
+ * a replacement for secure wallet generation
985
+ * a custom BIP-39 implementation
986
+ * a universal media decoder
987
+
988
+ Only supported handlers and explicitly supported schemes should be relied upon.
989
+
990
+ The current implementation supports PNG images through `image-v1`; additional image formats and media types are not yet fully implemented.
991
+
992
+ ---
993
+
994
+
995
+ ## License
996
+
997
+ **License:** [Apache-2.0](LICENSE) — free for personal and commercial use.
998
+
999
+ ## Author
1000
+
1001
+ Developed by **Josef Elijah Fabian (Zelijah)** | [Majikah Solutions OPC](https://majikah.solutions/about)
1002
+
1003
+ **Developer**: [Josef Elijah Fabian](https://github.com/jedlsf)
1004
+
1005
+ **GitHub**: [https://github.com/Majikah](https://github.com/Majikah)
1006
+
1007
+ **Project Repository**: [https://github.com/Majikah/majik-bip-39](https://github.com/Majikah/majik-bip-39)
1008
+
1009
+
1010
+ ---
1011
+
1012
+ ## Contact
1013
+
1014
+ - **Business Email**: [business@majikah.solutions](mailto:business@majikah.solutions)
1015
+ - **Official Website**: [https://www.thezelijah.world](https://www.thezelijah.world)
1016
+ - **Majikah Ecosystem**: [https://majikah.solutions](https://majikah.solutions)
package/package.json CHANGED
@@ -1,6 +1,64 @@
1
1
  {
2
2
  "name": "@majikah/majik-bip-39",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "description": "Derive deterministic BIP-39 mnemonics from PNG images, with optional Argon2id passphrase mode.",
6
+ "license": "Apache-2.0",
7
+ "author": "Zelijah",
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/Majikah/majik-bip-39.git"
14
+ },
15
+ "funding": {
16
+ "type": "github",
17
+ "url": "https://github.com/sponsors/jedlsf"
18
+ },
19
+ "keywords": [
20
+ "bip39",
21
+ "bip-39",
22
+ "mnemonic",
23
+ "seed-phrase",
24
+ "recovery-phrase",
25
+ "image-to-mnemonic",
26
+ "png",
27
+ "image",
28
+ "deterministic",
29
+ "entropy",
30
+ "argon2id",
31
+ "cryptography",
32
+ "wallet"
33
+ ],
34
+ "homepage": "https://github.com/Majikah/majik-bip-39#readme",
35
+ "bugs": {
36
+ "url": "https://github.com/Majikah/majik-bip-39/issues"
37
+ },
38
+ "exports": {
39
+ ".": {
40
+ "types": "./dist/index.d.ts",
41
+ "import": "./dist/index.js",
42
+ "default": "./dist/index.js"
43
+ }
44
+ },
45
+ "scripts": {
46
+ "build": "tsc -p tsconfig.json",
47
+ "test": "vitest run",
48
+ "typecheck": "tsc -p tsconfig.json --noEmit"
49
+ },
50
+ "dependencies": {
51
+ "@noble/hashes": "2.4.0",
52
+ "@scure/bip39": "2.4.0",
53
+ "fast-png": "8.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "26.6.4",
57
+ "typescript": "7.0.2",
58
+ "vitest": "5.0.3"
59
+ },
60
+ "files": [
61
+ "dist",
62
+ "docs"
63
+ ]
64
+ }