@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.
- package/LICENSE +201 -0
- package/README.md +1015 -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
|
-
#
|
|
1
|
+
# Majik BIP-39
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
[](https://www.thezelijah.world) 
|
|
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
|
+
   [](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
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
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
|
+
}
|