eff-mnemonic 0.0.2 → 0.0.4
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 +12 -14
- package/bin/eff-mnemonic +3 -0
- package/dist/cli.cjs +150 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +135 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.cjs +9 -87
- package/dist/index.mjs +6 -85
- package/dist/index.mjs.map +1 -1
- package/dist/mnemonic-BUQepJt4.cjs +127 -0
- package/dist/mnemonic-JeCBHZim.mjs +115 -0
- package/dist/mnemonic-JeCBHZim.mjs.map +1 -0
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# EFF
|
|
1
|
+
# EFF Mnemonic
|
|
2
2
|
|
|
3
|
-
Convert buffers to and from a human-readable mnemonic phrase using
|
|
3
|
+
Convert buffers to and from a human-readable mnemonic phrase using eff wordlists. This library was built with the purpose of generating mnemonics from passwords or private keys so that they can be easily written down on paper.
|
|
4
4
|
|
|
5
5
|
## CLI Usage
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ You can use the cli to encode and decode secret phrases or files.
|
|
|
9
9
|
#### Encode in interactive mode
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
>
|
|
12
|
+
> npx eff-mnemonic
|
|
13
13
|
🔑 # enter your secret phrase
|
|
14
14
|
┌─────────┬────────────┬───────────┬────────────┬──────────┬───────────┐
|
|
15
15
|
│ (index) │ 0 │ 1 │ 2 │ 3 │ 4 │
|
|
@@ -22,7 +22,7 @@ You can use the cli to encode and decode secret phrases or files.
|
|
|
22
22
|
#### Decode in interactive mode
|
|
23
23
|
|
|
24
24
|
```sh
|
|
25
|
-
|
|
25
|
+
npx eff-mnemonic -d
|
|
26
26
|
🔎 bloomers triceps shoptalk travel prodigy outlast shranK
|
|
27
27
|
hello world%
|
|
28
28
|
```
|
|
@@ -31,7 +31,7 @@ hello world%
|
|
|
31
31
|
|
|
32
32
|
```sh
|
|
33
33
|
# the cli pretty prints the mnemonic if output is not redirected
|
|
34
|
-
> echo -n "hello" |
|
|
34
|
+
> echo -n "hello" | npx eff-mnemonic
|
|
35
35
|
┌─────────┬───────────┬─────────┬─────────┐
|
|
36
36
|
│ (index) │ 0 │ 1 │ 2 │
|
|
37
37
|
├─────────┼───────────┼─────────┼─────────┤
|
|
@@ -39,11 +39,11 @@ hello world%
|
|
|
39
39
|
└─────────┴───────────┴─────────┴─────────┘
|
|
40
40
|
|
|
41
41
|
# the cli plays nice when the output is piped
|
|
42
|
-
> echo -n "hello" |
|
|
42
|
+
> echo -n "hello" | npx eff-mnemonic | npx eff-mnemonic -d | cat
|
|
43
43
|
hello%
|
|
44
44
|
|
|
45
45
|
# the cli plays nice when the output is redirected
|
|
46
|
-
> echo -n "hello" |
|
|
46
|
+
> echo -n "hello" | npx eff-mnemonic | npx eff-mnemonic -d > output.txt
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
## Programmatic Usage
|
|
@@ -63,27 +63,25 @@ const decoded = (await mnemonicToBuffer(encoded)).toString("utf8");
|
|
|
63
63
|
console.log(decoded); // hello world
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
### bufferToMnemonic(buffer, type)
|
|
66
|
+
### bufferToMnemonic(buffer[, type])
|
|
67
67
|
|
|
68
68
|
- `buffer` `<Buffer>` The buffer to encode.
|
|
69
|
-
- `type` `<"large" | "short_1" | "short_2_0">` The eff wordlist to use
|
|
69
|
+
- `type` `<"large" | "short_1" | "short_2_0">` The eff wordlist to use. Default `"large"`.
|
|
70
70
|
- Returns: `<string[]>` An array of mnemonic words.
|
|
71
71
|
|
|
72
72
|
Encodes abuffer into a human-readable mnemonic word array from the eff wordlist.
|
|
73
73
|
|
|
74
|
-
### mnemonicToBuffer(
|
|
75
|
-
|
|
76
|
-
Arguments
|
|
74
|
+
### mnemonicToBuffer(words[, type])
|
|
77
75
|
|
|
78
76
|
- `words` `<string[]>` An array of mnemonic words.
|
|
79
|
-
- `type` `<"large" | "short_1" | "short_2_0">` The eff wordlist to use
|
|
77
|
+
- `type` `<"large" | "short_1" | "short_2_0">` The eff wordlist to use. Default `"large"`
|
|
80
78
|
- Returns: `<Buffer>` The decoded buffer.
|
|
81
79
|
|
|
82
80
|
Decodes a mnemonic word array back into its original buffer.
|
|
83
81
|
|
|
84
82
|
## Quirks
|
|
85
83
|
|
|
86
|
-
Internally, null characters `0x00` are used to pad the input if it's not divisible by 5. So the decoding process strips preceeding null characters before returning the output.
|
|
84
|
+
Internally, null characters `0x00` are used to pad the input if it's not divisible by 5 for the large list or 4 for the short lists. So the decoding process strips preceeding null characters before returning the output.
|
|
87
85
|
|
|
88
86
|
#### Default behaviour
|
|
89
87
|
|
package/bin/eff-mnemonic
ADDED
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
23
|
+
const require_mnemonic = require("./mnemonic-BUQepJt4.cjs");
|
|
24
|
+
let node_readline = require("node:readline");
|
|
25
|
+
node_readline = __toESM(node_readline);
|
|
26
|
+
//#region src/cli.ts
|
|
27
|
+
const { values } = (0, require("node:util").parseArgs)({
|
|
28
|
+
options: {
|
|
29
|
+
encode: {
|
|
30
|
+
type: "boolean",
|
|
31
|
+
short: "e",
|
|
32
|
+
default: true
|
|
33
|
+
},
|
|
34
|
+
decode: {
|
|
35
|
+
type: "boolean",
|
|
36
|
+
short: "d"
|
|
37
|
+
},
|
|
38
|
+
wordlist: {
|
|
39
|
+
type: "string",
|
|
40
|
+
short: "w"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
tokens: true
|
|
44
|
+
});
|
|
45
|
+
const mode = values.decode ? "decode" : "encode";
|
|
46
|
+
if (values.wordlist === "large" || values.wordlist === "short_1" || values.wordlist === "short_2_0") values.wordlist;
|
|
47
|
+
else if (values.wordlist) {
|
|
48
|
+
console.error(`Error: Invalid value for wordlist, must be "large", "short_1", or "short_2_0"`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
/** Captures input to encode without printing it on screen */
|
|
52
|
+
function captureEncodeInput() {
|
|
53
|
+
const query = "🔑 ";
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const rl = node_readline.default.createInterface({
|
|
56
|
+
input: process.stdin,
|
|
57
|
+
output: process.stderr
|
|
58
|
+
});
|
|
59
|
+
const stdin = process.stdin;
|
|
60
|
+
stdin.setRawMode(true);
|
|
61
|
+
stdin.resume();
|
|
62
|
+
let password = "";
|
|
63
|
+
process.stderr.write(query);
|
|
64
|
+
const onData = (char) => {
|
|
65
|
+
const charStr = char.toString("utf8");
|
|
66
|
+
let end = false;
|
|
67
|
+
let exitCode;
|
|
68
|
+
switch (charStr) {
|
|
69
|
+
case "\n":
|
|
70
|
+
case "\r":
|
|
71
|
+
case "":
|
|
72
|
+
resolve(password);
|
|
73
|
+
end = true;
|
|
74
|
+
break;
|
|
75
|
+
case "":
|
|
76
|
+
exitCode = 130;
|
|
77
|
+
process.exit(130);
|
|
78
|
+
end = true;
|
|
79
|
+
break;
|
|
80
|
+
case "":
|
|
81
|
+
case "\b":
|
|
82
|
+
if (password.length > 0) password = password.slice(0, -1);
|
|
83
|
+
break;
|
|
84
|
+
default:
|
|
85
|
+
if (charStr.charCodeAt(0) >= 32) password += charStr;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
if (end) {
|
|
89
|
+
stdin.removeListener("data", onData);
|
|
90
|
+
stdin.setRawMode(false);
|
|
91
|
+
rl.close();
|
|
92
|
+
if (exitCode) process.exit(exitCode);
|
|
93
|
+
} else {
|
|
94
|
+
node_readline.default.clearLine(process.stderr, 0);
|
|
95
|
+
node_readline.default.cursorTo(process.stderr, 0);
|
|
96
|
+
process.stderr.write(query);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
stdin.on("data", onData);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/** Captures input to decode transparently */
|
|
103
|
+
function captureDecodeInput() {
|
|
104
|
+
const query = "🔎 ";
|
|
105
|
+
return new Promise((resolve) => {
|
|
106
|
+
const rl = node_readline.default.createInterface({
|
|
107
|
+
input: process.stdin,
|
|
108
|
+
output: process.stdout
|
|
109
|
+
});
|
|
110
|
+
rl.question(query, (value) => {
|
|
111
|
+
rl.close();
|
|
112
|
+
resolve(value);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async function main() {
|
|
117
|
+
let input;
|
|
118
|
+
if (process.stdin.isTTY) {
|
|
119
|
+
let text;
|
|
120
|
+
if (mode === "encode") text = await captureEncodeInput();
|
|
121
|
+
else text = await captureDecodeInput();
|
|
122
|
+
input = Buffer.from(text, "utf8");
|
|
123
|
+
} else {
|
|
124
|
+
const chunks = [];
|
|
125
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
126
|
+
input = Buffer.concat(chunks);
|
|
127
|
+
}
|
|
128
|
+
if (!input) {
|
|
129
|
+
console.error("Error: No input provided");
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
if (mode === "encode") {
|
|
133
|
+
const words = await require_mnemonic.bufferToMnemonic(input);
|
|
134
|
+
if (process.stdout.isTTY) {
|
|
135
|
+
const table = words.reduce((acc, it, i) => {
|
|
136
|
+
const j = Math.floor(i / 5);
|
|
137
|
+
const k = i % 5;
|
|
138
|
+
acc[j] ??= [];
|
|
139
|
+
acc[j][k] = it;
|
|
140
|
+
return acc;
|
|
141
|
+
}, []);
|
|
142
|
+
console.table(table);
|
|
143
|
+
} else process.stdout.write(words.join(" "));
|
|
144
|
+
} else {
|
|
145
|
+
const decoded = await require_mnemonic.mnemonicToBuffer(input.toString("utf8").replace(/[\s\t\-\_\,\:\;\.\n\'\"|\\]+/g, " ").trim().split(" "));
|
|
146
|
+
process.stdout.write(decoded);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
main();
|
|
150
|
+
//#endregion
|
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { n as init_mnemonic, p as __commonJSMin, r as mnemonicToBuffer, t as bufferToMnemonic } from "./mnemonic-JeCBHZim.mjs";
|
|
2
|
+
import readline from "node:readline";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
//#region src/cli.ts
|
|
5
|
+
var require_cli = /* @__PURE__ */ __commonJSMin((() => {
|
|
6
|
+
init_mnemonic();
|
|
7
|
+
const { values } = parseArgs({
|
|
8
|
+
options: {
|
|
9
|
+
encode: {
|
|
10
|
+
type: "boolean",
|
|
11
|
+
short: "e",
|
|
12
|
+
default: true
|
|
13
|
+
},
|
|
14
|
+
decode: {
|
|
15
|
+
type: "boolean",
|
|
16
|
+
short: "d"
|
|
17
|
+
},
|
|
18
|
+
wordlist: {
|
|
19
|
+
type: "string",
|
|
20
|
+
short: "w"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
tokens: true
|
|
24
|
+
});
|
|
25
|
+
const mode = values.decode ? "decode" : "encode";
|
|
26
|
+
if (values.wordlist === "large" || values.wordlist === "short_1" || values.wordlist === "short_2_0") values.wordlist;
|
|
27
|
+
else if (values.wordlist) {
|
|
28
|
+
console.error(`Error: Invalid value for wordlist, must be "large", "short_1", or "short_2_0"`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
/** Captures input to encode without printing it on screen */
|
|
32
|
+
function captureEncodeInput() {
|
|
33
|
+
const query = "🔑 ";
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
const rl = readline.createInterface({
|
|
36
|
+
input: process.stdin,
|
|
37
|
+
output: process.stderr
|
|
38
|
+
});
|
|
39
|
+
const stdin = process.stdin;
|
|
40
|
+
stdin.setRawMode(true);
|
|
41
|
+
stdin.resume();
|
|
42
|
+
let password = "";
|
|
43
|
+
process.stderr.write(query);
|
|
44
|
+
const onData = (char) => {
|
|
45
|
+
const charStr = char.toString("utf8");
|
|
46
|
+
let end = false;
|
|
47
|
+
let exitCode;
|
|
48
|
+
switch (charStr) {
|
|
49
|
+
case "\n":
|
|
50
|
+
case "\r":
|
|
51
|
+
case "":
|
|
52
|
+
resolve(password);
|
|
53
|
+
end = true;
|
|
54
|
+
break;
|
|
55
|
+
case "":
|
|
56
|
+
exitCode = 130;
|
|
57
|
+
process.exit(130);
|
|
58
|
+
end = true;
|
|
59
|
+
break;
|
|
60
|
+
case "":
|
|
61
|
+
case "\b":
|
|
62
|
+
if (password.length > 0) password = password.slice(0, -1);
|
|
63
|
+
break;
|
|
64
|
+
default:
|
|
65
|
+
if (charStr.charCodeAt(0) >= 32) password += charStr;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
if (end) {
|
|
69
|
+
stdin.removeListener("data", onData);
|
|
70
|
+
stdin.setRawMode(false);
|
|
71
|
+
rl.close();
|
|
72
|
+
if (exitCode) process.exit(exitCode);
|
|
73
|
+
} else {
|
|
74
|
+
readline.clearLine(process.stderr, 0);
|
|
75
|
+
readline.cursorTo(process.stderr, 0);
|
|
76
|
+
process.stderr.write(query);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
stdin.on("data", onData);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/** Captures input to decode transparently */
|
|
83
|
+
function captureDecodeInput() {
|
|
84
|
+
const query = "🔎 ";
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
const rl = readline.createInterface({
|
|
87
|
+
input: process.stdin,
|
|
88
|
+
output: process.stdout
|
|
89
|
+
});
|
|
90
|
+
rl.question(query, (value) => {
|
|
91
|
+
rl.close();
|
|
92
|
+
resolve(value);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
async function main() {
|
|
97
|
+
let input;
|
|
98
|
+
if (process.stdin.isTTY) {
|
|
99
|
+
let text;
|
|
100
|
+
if (mode === "encode") text = await captureEncodeInput();
|
|
101
|
+
else text = await captureDecodeInput();
|
|
102
|
+
input = Buffer.from(text, "utf8");
|
|
103
|
+
} else {
|
|
104
|
+
const chunks = [];
|
|
105
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
106
|
+
input = Buffer.concat(chunks);
|
|
107
|
+
}
|
|
108
|
+
if (!input) {
|
|
109
|
+
console.error("Error: No input provided");
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
if (mode === "encode") {
|
|
113
|
+
const words = await bufferToMnemonic(input);
|
|
114
|
+
if (process.stdout.isTTY) {
|
|
115
|
+
const table = words.reduce((acc, it, i) => {
|
|
116
|
+
const j = Math.floor(i / 5);
|
|
117
|
+
const k = i % 5;
|
|
118
|
+
acc[j] ??= [];
|
|
119
|
+
acc[j][k] = it;
|
|
120
|
+
return acc;
|
|
121
|
+
}, []);
|
|
122
|
+
console.table(table);
|
|
123
|
+
} else process.stdout.write(words.join(" "));
|
|
124
|
+
} else {
|
|
125
|
+
const decoded = await mnemonicToBuffer(input.toString("utf8").replace(/[\s\t\-\_\,\:\;\.\n\'\"|\\]+/g, " ").trim().split(" "));
|
|
126
|
+
process.stdout.write(decoded);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
main();
|
|
130
|
+
}));
|
|
131
|
+
//#endregion
|
|
132
|
+
export default require_cli();
|
|
133
|
+
export {};
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=cli.mjs.map
|
package/dist/cli.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["import readline from \"node:readline\";\nimport { parseArgs } from \"node:util\";\nimport { EffWordListType } from \"./data\";\nimport { bufferToMnemonic, mnemonicToBuffer } from \"./mnemonic\";\n\nconst { values } = parseArgs({\n options: {\n encode: { type: \"boolean\", short: \"e\", default: true },\n decode: { type: \"boolean\", short: \"d\" },\n wordlist: { type: \"string\", short: \"w\" },\n },\n tokens: true,\n});\n\n// determine mode\nconst mode = values.decode ? \"decode\" : \"encode\";\n\n// determine wordlist\nlet wordlist: EffWordListType;\nif (\n values.wordlist === \"large\" ||\n values.wordlist === \"short_1\" ||\n values.wordlist === \"short_2_0\"\n) {\n wordlist = values.wordlist;\n} else if (values.wordlist) {\n console.error(\n `Error: Invalid value for wordlist, must be \"large\", \"short_1\", or \"short_2_0\"`,\n );\n process.exit(1);\n}\n\n/** Captures input to encode without printing it on screen */\nfunction captureEncodeInput(): Promise<string> {\n const query = \"🔑 \";\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr, // write ui to stderr to keep stdout clear\n });\n\n const stdin = process.stdin;\n stdin.setRawMode(true);\n stdin.resume();\n\n let password = \"\";\n process.stderr.write(query);\n\n const onData = (char: Buffer) => {\n const charStr = char.toString(\"utf8\");\n\n let end = false;\n let exitCode;\n switch (charStr) {\n case \"\\n\":\n case \"\\r\":\n case \"\\u0004\": // ctrl+d\n resolve(password);\n end = true;\n break;\n case \"\\u0003\": // ctrl+c\n exitCode = 130;\n process.exit(130);\n end = true;\n break;\n case \"\\u007f\": // backspace\n case \"\\b\":\n if (password.length > 0) {\n password = password.slice(0, -1);\n }\n break;\n default:\n if (charStr.charCodeAt(0) >= 32) {\n password += charStr;\n }\n break;\n }\n\n if (end) {\n stdin.removeListener(\"data\", onData);\n stdin.setRawMode(false);\n rl.close();\n\n if (exitCode) {\n process.exit(exitCode);\n }\n } else {\n readline.clearLine(process.stderr, 0);\n readline.cursorTo(process.stderr, 0);\n process.stderr.write(query);\n }\n };\n\n stdin.on(\"data\", onData);\n });\n}\n\n/** Captures input to decode transparently */\nfunction captureDecodeInput(): Promise<string> {\n const query = \"🔎 \";\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n rl.question(query, (value) => {\n rl.close();\n resolve(value);\n });\n });\n}\n\nasync function main(): Promise<void> {\n let input;\n\n // capture tty input\n if (process.stdin.isTTY) {\n let text;\n if (mode === \"encode\") {\n text = await captureEncodeInput();\n } else {\n text = await captureDecodeInput();\n }\n\n input = Buffer.from(text, \"utf8\");\n }\n\n // capture piped input\n else {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk);\n }\n\n input = Buffer.concat(chunks);\n }\n\n if (!input) {\n console.error(\"Error: No input provided\");\n process.exit(1);\n }\n\n // handle encode or decode\n if (mode === \"encode\") {\n // encode mnemonic\n const words = await bufferToMnemonic(input);\n\n // handle tty output\n if (process.stdout.isTTY) {\n // pretty format\n const table = words.reduce((acc, it, i) => {\n const j = Math.floor(i / 5);\n const k = i % 5;\n acc[j] ??= [];\n acc[j][k] = it;\n\n return acc;\n }, [] as string[][]);\n\n // print table\n console.table(table);\n } else {\n // write directly to stdout\n process.stdout.write(words.join(\" \"));\n }\n } else {\n // sanitize and parse input\n const words = input\n .toString(\"utf8\")\n .replace(/[\\s\\t\\-\\_\\,\\:\\;\\.\\n\\'\\\"|\\\\]+/g, \" \")\n .trim()\n .split(\" \");\n\n // decode mnemonic\n const decoded = await mnemonicToBuffer(words);\n\n // write directly to stdout so it can be redirected\n process.stdout.write(decoded);\n }\n}\n\nvoid main();\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,88 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
//#endregion
|
|
13
|
-
//#region src/data.ts
|
|
14
|
-
const numberToWordMapByType = /* @__PURE__ */ new Map();
|
|
15
|
-
const wordToNumberMapByType = /* @__PURE__ */ new Map();
|
|
16
|
-
const getEffNumberToWordMap = async (type) => {
|
|
17
|
-
let map = numberToWordMapByType.get(type);
|
|
18
|
-
if (!map) {
|
|
19
|
-
if (type !== "large" && type !== "short_1" && type !== "short_2_0") throw new TypeError(`Invalid type "${type}"`);
|
|
20
|
-
const file = await (0, node_fs_promises.readFile)(__dirname + `/../data/eff_wordlist_${type}.txt`, "utf8");
|
|
21
|
-
map = new Map(file.split("\n").map((it) => it.split(" ")).map(([k, v]) => [oneToZeroBaseIndex(k), v]));
|
|
22
|
-
numberToWordMapByType.set(type, map);
|
|
23
|
-
}
|
|
24
|
-
return map;
|
|
25
|
-
};
|
|
26
|
-
const getEffWordToNumberMap = async (type) => {
|
|
27
|
-
let map = wordToNumberMapByType.get(type);
|
|
28
|
-
if (!map) {
|
|
29
|
-
const numberToWordMap = await getEffNumberToWordMap(type);
|
|
30
|
-
map = new Map(numberToWordMap.entries().map(([k, v]) => [v, k]));
|
|
31
|
-
wordToNumberMapByType.set(type, map);
|
|
32
|
-
}
|
|
33
|
-
return map;
|
|
34
|
-
};
|
|
35
|
-
const clearEffCache = () => {
|
|
36
|
-
numberToWordMapByType.clear();
|
|
37
|
-
wordToNumberMapByType.clear();
|
|
38
|
-
};
|
|
39
|
-
//#endregion
|
|
40
|
-
//#region src/parse-big-int.ts
|
|
41
|
-
function parseBigInt(string, radix) {
|
|
42
|
-
if (radix < 2 || radix > 36) throw new TypeError("Radix must be between 2 and 36");
|
|
43
|
-
const bigRadix = BigInt(radix);
|
|
44
|
-
let result = 0n;
|
|
45
|
-
for (const char of string) {
|
|
46
|
-
const digit = parseInt(char, radix);
|
|
47
|
-
if (isNaN(digit)) throw new TypeError(`Invalid character "${char}" for radix ${radix}`);
|
|
48
|
-
result = result * bigRadix + BigInt(digit);
|
|
49
|
-
}
|
|
50
|
-
return result;
|
|
51
|
-
}
|
|
52
|
-
//#endregion
|
|
53
|
-
//#region src/mnemonic.ts
|
|
54
|
-
async function bufferToMnemonic(buffer, type = "large") {
|
|
55
|
-
if (!buffer.length) return [];
|
|
56
|
-
const numberToWordMap = await getEffNumberToWordMap(type);
|
|
57
|
-
const base6 = BigInt("0x" + buffer.toString("hex")).toString(6);
|
|
58
|
-
const rolls = type === "large" ? 5 : 4;
|
|
59
|
-
const base6PaddedLength = Math.ceil(base6.length / rolls) * rolls;
|
|
60
|
-
return (base6.padStart(base6PaddedLength, "0").match(new RegExp(`.{1,${rolls}}`, "g")) ?? []).map((chunk) => {
|
|
61
|
-
const word = numberToWordMap.get(chunk);
|
|
62
|
-
if (!word) {
|
|
63
|
-
const sequence = zeroToOneBaseIndex(chunk);
|
|
64
|
-
throw TypeError(`Sequence "${sequence}" not in ${type} list`);
|
|
65
|
-
}
|
|
66
|
-
return word;
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
async function mnemonicToBuffer(words, type = "large") {
|
|
70
|
-
if (!words.length) return Buffer.alloc(0);
|
|
71
|
-
const wordToBase6Map = await getEffWordToNumberMap(type);
|
|
72
|
-
let hex = parseBigInt(words.map((word) => {
|
|
73
|
-
const chunk = wordToBase6Map.get(word.toLowerCase());
|
|
74
|
-
if (!chunk) throw TypeError(`Word "${word}" not ${type} list`);
|
|
75
|
-
return chunk;
|
|
76
|
-
}).join(""), 6).toString(16);
|
|
77
|
-
if (hex.length % 2 !== 0) hex = "0" + hex;
|
|
78
|
-
return Buffer.from(hex, "hex");
|
|
79
|
-
}
|
|
80
|
-
//#endregion
|
|
81
|
-
exports.bufferToMnemonic = bufferToMnemonic;
|
|
82
|
-
exports.clearEffCache = clearEffCache;
|
|
83
|
-
exports.getEffNumberToWordMap = getEffNumberToWordMap;
|
|
84
|
-
exports.getEffWordToNumberMap = getEffWordToNumberMap;
|
|
85
|
-
exports.mnemonicToBuffer = mnemonicToBuffer;
|
|
86
|
-
exports.oneToZeroBaseIndex = oneToZeroBaseIndex;
|
|
87
|
-
exports.parseBigInt = parseBigInt;
|
|
88
|
-
exports.zeroToOneBaseIndex = zeroToOneBaseIndex;
|
|
2
|
+
const require_mnemonic = require("./mnemonic-BUQepJt4.cjs");
|
|
3
|
+
exports.bufferToMnemonic = require_mnemonic.bufferToMnemonic;
|
|
4
|
+
exports.clearEffCache = require_mnemonic.clearEffCache;
|
|
5
|
+
exports.getEffNumberToWordMap = require_mnemonic.getEffNumberToWordMap;
|
|
6
|
+
exports.getEffWordToNumberMap = require_mnemonic.getEffWordToNumberMap;
|
|
7
|
+
exports.mnemonicToBuffer = require_mnemonic.mnemonicToBuffer;
|
|
8
|
+
exports.oneToZeroBaseIndex = require_mnemonic.oneToZeroBaseIndex;
|
|
9
|
+
exports.parseBigInt = require_mnemonic.parseBigInt;
|
|
10
|
+
exports.zeroToOneBaseIndex = require_mnemonic.zeroToOneBaseIndex;
|
package/dist/index.mjs
CHANGED
|
@@ -1,88 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
return string.replace(/\d/g, (d) => String(Number(d) - 1));
|
|
8
|
-
}
|
|
9
|
-
function zeroToOneBaseIndex(string) {
|
|
10
|
-
if (!/^[0-8]*$/.test(string)) throw new TypeError(`Input "${string}" contains characters other than 0-8`);
|
|
11
|
-
return string.replace(/\d/g, (d) => String(Number(d) + 1));
|
|
12
|
-
}
|
|
13
|
-
//#endregion
|
|
14
|
-
//#region node_modules/tsdown/esm-shims.js
|
|
15
|
-
const getFilename = () => fileURLToPath(import.meta.url);
|
|
16
|
-
const getDirname = () => path.dirname(getFilename());
|
|
17
|
-
const __dirname = /* @__PURE__ */ getDirname();
|
|
18
|
-
//#endregion
|
|
19
|
-
//#region src/data.ts
|
|
20
|
-
const numberToWordMapByType = /* @__PURE__ */ new Map();
|
|
21
|
-
const wordToNumberMapByType = /* @__PURE__ */ new Map();
|
|
22
|
-
const getEffNumberToWordMap = async (type) => {
|
|
23
|
-
let map = numberToWordMapByType.get(type);
|
|
24
|
-
if (!map) {
|
|
25
|
-
if (type !== "large" && type !== "short_1" && type !== "short_2_0") throw new TypeError(`Invalid type "${type}"`);
|
|
26
|
-
const file = await readFile(__dirname + `/../data/eff_wordlist_${type}.txt`, "utf8");
|
|
27
|
-
map = new Map(file.split("\n").map((it) => it.split(" ")).map(([k, v]) => [oneToZeroBaseIndex(k), v]));
|
|
28
|
-
numberToWordMapByType.set(type, map);
|
|
29
|
-
}
|
|
30
|
-
return map;
|
|
31
|
-
};
|
|
32
|
-
const getEffWordToNumberMap = async (type) => {
|
|
33
|
-
let map = wordToNumberMapByType.get(type);
|
|
34
|
-
if (!map) {
|
|
35
|
-
const numberToWordMap = await getEffNumberToWordMap(type);
|
|
36
|
-
map = new Map(numberToWordMap.entries().map(([k, v]) => [v, k]));
|
|
37
|
-
wordToNumberMapByType.set(type, map);
|
|
38
|
-
}
|
|
39
|
-
return map;
|
|
40
|
-
};
|
|
41
|
-
const clearEffCache = () => {
|
|
42
|
-
numberToWordMapByType.clear();
|
|
43
|
-
wordToNumberMapByType.clear();
|
|
44
|
-
};
|
|
45
|
-
//#endregion
|
|
46
|
-
//#region src/parse-big-int.ts
|
|
47
|
-
function parseBigInt(string, radix) {
|
|
48
|
-
if (radix < 2 || radix > 36) throw new TypeError("Radix must be between 2 and 36");
|
|
49
|
-
const bigRadix = BigInt(radix);
|
|
50
|
-
let result = 0n;
|
|
51
|
-
for (const char of string) {
|
|
52
|
-
const digit = parseInt(char, radix);
|
|
53
|
-
if (isNaN(digit)) throw new TypeError(`Invalid character "${char}" for radix ${radix}`);
|
|
54
|
-
result = result * bigRadix + BigInt(digit);
|
|
55
|
-
}
|
|
56
|
-
return result;
|
|
57
|
-
}
|
|
58
|
-
//#endregion
|
|
59
|
-
//#region src/mnemonic.ts
|
|
60
|
-
async function bufferToMnemonic(buffer, type = "large") {
|
|
61
|
-
if (!buffer.length) return [];
|
|
62
|
-
const numberToWordMap = await getEffNumberToWordMap(type);
|
|
63
|
-
const base6 = BigInt("0x" + buffer.toString("hex")).toString(6);
|
|
64
|
-
const rolls = type === "large" ? 5 : 4;
|
|
65
|
-
const base6PaddedLength = Math.ceil(base6.length / rolls) * rolls;
|
|
66
|
-
return (base6.padStart(base6PaddedLength, "0").match(new RegExp(`.{1,${rolls}}`, "g")) ?? []).map((chunk) => {
|
|
67
|
-
const word = numberToWordMap.get(chunk);
|
|
68
|
-
if (!word) {
|
|
69
|
-
const sequence = zeroToOneBaseIndex(chunk);
|
|
70
|
-
throw TypeError(`Sequence "${sequence}" not in ${type} list`);
|
|
71
|
-
}
|
|
72
|
-
return word;
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
async function mnemonicToBuffer(words, type = "large") {
|
|
76
|
-
if (!words.length) return Buffer.alloc(0);
|
|
77
|
-
const wordToBase6Map = await getEffWordToNumberMap(type);
|
|
78
|
-
let hex = parseBigInt(words.map((word) => {
|
|
79
|
-
const chunk = wordToBase6Map.get(word.toLowerCase());
|
|
80
|
-
if (!chunk) throw TypeError(`Word "${word}" not ${type} list`);
|
|
81
|
-
return chunk;
|
|
82
|
-
}).join(""), 6).toString(16);
|
|
83
|
-
if (hex.length % 2 !== 0) hex = "0" + hex;
|
|
84
|
-
return Buffer.from(hex, "hex");
|
|
85
|
-
}
|
|
1
|
+
import { a as parseBigInt, c as getEffWordToNumberMap, d as oneToZeroBaseIndex, f as zeroToOneBaseIndex, i as init_parse_big_int, l as init_data, n as init_mnemonic, o as clearEffCache, r as mnemonicToBuffer, s as getEffNumberToWordMap, t as bufferToMnemonic, u as init_base_index } from "./mnemonic-JeCBHZim.mjs";
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
init_base_index();
|
|
4
|
+
init_data();
|
|
5
|
+
init_mnemonic();
|
|
6
|
+
init_parse_big_int();
|
|
86
7
|
//#endregion
|
|
87
8
|
export { bufferToMnemonic, clearEffCache, getEffNumberToWordMap, getEffWordToNumberMap, mnemonicToBuffer, oneToZeroBaseIndex, parseBigInt, zeroToOneBaseIndex };
|
|
88
9
|
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export * from \"./base-index\";\nexport * from \"./data\";\nexport * from \"./mnemonic\";\nexport * from \"./parse-big-int\";\n"],"mappings":""}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
let node_fs_promises = require("node:fs/promises");
|
|
2
|
+
//#region src/base-index.ts
|
|
3
|
+
function oneToZeroBaseIndex(string) {
|
|
4
|
+
if (!/^[1-9]*$/.test(string)) throw new TypeError(`Input "${string}" contains characters other than 1-9`);
|
|
5
|
+
return string.replace(/\d/g, (d) => String(Number(d) - 1));
|
|
6
|
+
}
|
|
7
|
+
function zeroToOneBaseIndex(string) {
|
|
8
|
+
if (!/^[0-8]*$/.test(string)) throw new TypeError(`Input "${string}" contains characters other than 0-8`);
|
|
9
|
+
return string.replace(/\d/g, (d) => String(Number(d) + 1));
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/data.ts
|
|
13
|
+
const numberToWordMapByType = /* @__PURE__ */ new Map();
|
|
14
|
+
const wordToNumberMapByType = /* @__PURE__ */ new Map();
|
|
15
|
+
const getEffNumberToWordMap = async (type) => {
|
|
16
|
+
let map = numberToWordMapByType.get(type);
|
|
17
|
+
if (!map) {
|
|
18
|
+
if (type !== "large" && type !== "short_1" && type !== "short_2_0") throw new TypeError(`Invalid type "${type}"`);
|
|
19
|
+
const file = await (0, node_fs_promises.readFile)(__dirname + `/../data/eff_wordlist_${type}.txt`, "utf8");
|
|
20
|
+
map = new Map(file.split("\n").map((it) => it.split(" ")).map(([k, v]) => [oneToZeroBaseIndex(k), v]));
|
|
21
|
+
numberToWordMapByType.set(type, map);
|
|
22
|
+
}
|
|
23
|
+
return map;
|
|
24
|
+
};
|
|
25
|
+
const getEffWordToNumberMap = async (type) => {
|
|
26
|
+
let map = wordToNumberMapByType.get(type);
|
|
27
|
+
if (!map) {
|
|
28
|
+
const numberToWordMap = await getEffNumberToWordMap(type);
|
|
29
|
+
map = new Map(numberToWordMap.entries().map(([k, v]) => [v, k]));
|
|
30
|
+
wordToNumberMapByType.set(type, map);
|
|
31
|
+
}
|
|
32
|
+
return map;
|
|
33
|
+
};
|
|
34
|
+
const clearEffCache = () => {
|
|
35
|
+
numberToWordMapByType.clear();
|
|
36
|
+
wordToNumberMapByType.clear();
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/parse-big-int.ts
|
|
40
|
+
function parseBigInt(string, radix) {
|
|
41
|
+
if (radix < 2 || radix > 36) throw new TypeError("Radix must be between 2 and 36");
|
|
42
|
+
const bigRadix = BigInt(radix);
|
|
43
|
+
let result = 0n;
|
|
44
|
+
for (const char of string) {
|
|
45
|
+
const digit = parseInt(char, radix);
|
|
46
|
+
if (isNaN(digit)) throw new TypeError(`Invalid character "${char}" for radix ${radix}`);
|
|
47
|
+
result = result * bigRadix + BigInt(digit);
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/mnemonic.ts
|
|
53
|
+
async function bufferToMnemonic(buffer, type = "large") {
|
|
54
|
+
if (!buffer.length) return [];
|
|
55
|
+
const numberToWordMap = await getEffNumberToWordMap(type);
|
|
56
|
+
const base6 = BigInt("0x" + buffer.toString("hex")).toString(6);
|
|
57
|
+
const rolls = type === "large" ? 5 : 4;
|
|
58
|
+
const base6PaddedLength = Math.ceil(base6.length / rolls) * rolls;
|
|
59
|
+
return (base6.padStart(base6PaddedLength, "0").match(new RegExp(`.{1,${rolls}}`, "g")) ?? []).map((chunk) => {
|
|
60
|
+
const word = numberToWordMap.get(chunk);
|
|
61
|
+
if (!word) {
|
|
62
|
+
const sequence = zeroToOneBaseIndex(chunk);
|
|
63
|
+
throw TypeError(`Sequence "${sequence}" not in ${type} list`);
|
|
64
|
+
}
|
|
65
|
+
return word;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async function mnemonicToBuffer(words, type = "large") {
|
|
69
|
+
if (!words.length) return Buffer.alloc(0);
|
|
70
|
+
const wordToBase6Map = await getEffWordToNumberMap(type);
|
|
71
|
+
let hex = parseBigInt(words.map((word) => {
|
|
72
|
+
const chunk = wordToBase6Map.get(word.toLowerCase());
|
|
73
|
+
if (!chunk) throw TypeError(`Word "${word}" not ${type} list`);
|
|
74
|
+
return chunk;
|
|
75
|
+
}).join(""), 6).toString(16);
|
|
76
|
+
if (hex.length % 2 !== 0) hex = "0" + hex;
|
|
77
|
+
return Buffer.from(hex, "hex");
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
Object.defineProperty(exports, "bufferToMnemonic", {
|
|
81
|
+
enumerable: true,
|
|
82
|
+
get: function() {
|
|
83
|
+
return bufferToMnemonic;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
Object.defineProperty(exports, "clearEffCache", {
|
|
87
|
+
enumerable: true,
|
|
88
|
+
get: function() {
|
|
89
|
+
return clearEffCache;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
Object.defineProperty(exports, "getEffNumberToWordMap", {
|
|
93
|
+
enumerable: true,
|
|
94
|
+
get: function() {
|
|
95
|
+
return getEffNumberToWordMap;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
Object.defineProperty(exports, "getEffWordToNumberMap", {
|
|
99
|
+
enumerable: true,
|
|
100
|
+
get: function() {
|
|
101
|
+
return getEffWordToNumberMap;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
Object.defineProperty(exports, "mnemonicToBuffer", {
|
|
105
|
+
enumerable: true,
|
|
106
|
+
get: function() {
|
|
107
|
+
return mnemonicToBuffer;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
Object.defineProperty(exports, "oneToZeroBaseIndex", {
|
|
111
|
+
enumerable: true,
|
|
112
|
+
get: function() {
|
|
113
|
+
return oneToZeroBaseIndex;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
Object.defineProperty(exports, "parseBigInt", {
|
|
117
|
+
enumerable: true,
|
|
118
|
+
get: function() {
|
|
119
|
+
return parseBigInt;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
Object.defineProperty(exports, "zeroToOneBaseIndex", {
|
|
123
|
+
enumerable: true,
|
|
124
|
+
get: function() {
|
|
125
|
+
return zeroToOneBaseIndex;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
//#region \0rolldown/runtime.js
|
|
5
|
+
var __esmMin = (fn, res, err) => () => {
|
|
6
|
+
if (err) throw err[0];
|
|
7
|
+
try {
|
|
8
|
+
return fn && (res = fn(fn = 0)), res;
|
|
9
|
+
} catch (e) {
|
|
10
|
+
throw err = [e], e;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/base-index.ts
|
|
16
|
+
function oneToZeroBaseIndex(string) {
|
|
17
|
+
if (!/^[1-9]*$/.test(string)) throw new TypeError(`Input "${string}" contains characters other than 1-9`);
|
|
18
|
+
return string.replace(/\d/g, (d) => String(Number(d) - 1));
|
|
19
|
+
}
|
|
20
|
+
function zeroToOneBaseIndex(string) {
|
|
21
|
+
if (!/^[0-8]*$/.test(string)) throw new TypeError(`Input "${string}" contains characters other than 0-8`);
|
|
22
|
+
return string.replace(/\d/g, (d) => String(Number(d) + 1));
|
|
23
|
+
}
|
|
24
|
+
var init_base_index = __esmMin((() => {}));
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region node_modules/tsdown/esm-shims.js
|
|
27
|
+
var getFilename, getDirname, __dirname;
|
|
28
|
+
var init_esm_shims = __esmMin((() => {
|
|
29
|
+
getFilename = () => fileURLToPath(import.meta.url);
|
|
30
|
+
getDirname = () => path.dirname(getFilename());
|
|
31
|
+
__dirname = /* @__PURE__ */ getDirname();
|
|
32
|
+
}));
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/data.ts
|
|
35
|
+
var numberToWordMapByType, wordToNumberMapByType, getEffNumberToWordMap, getEffWordToNumberMap, clearEffCache;
|
|
36
|
+
var init_data = __esmMin((() => {
|
|
37
|
+
init_esm_shims();
|
|
38
|
+
init_base_index();
|
|
39
|
+
numberToWordMapByType = /* @__PURE__ */ new Map();
|
|
40
|
+
wordToNumberMapByType = /* @__PURE__ */ new Map();
|
|
41
|
+
getEffNumberToWordMap = async (type) => {
|
|
42
|
+
let map = numberToWordMapByType.get(type);
|
|
43
|
+
if (!map) {
|
|
44
|
+
if (type !== "large" && type !== "short_1" && type !== "short_2_0") throw new TypeError(`Invalid type "${type}"`);
|
|
45
|
+
const file = await readFile(__dirname + `/../data/eff_wordlist_${type}.txt`, "utf8");
|
|
46
|
+
map = new Map(file.split("\n").map((it) => it.split(" ")).map(([k, v]) => [oneToZeroBaseIndex(k), v]));
|
|
47
|
+
numberToWordMapByType.set(type, map);
|
|
48
|
+
}
|
|
49
|
+
return map;
|
|
50
|
+
};
|
|
51
|
+
getEffWordToNumberMap = async (type) => {
|
|
52
|
+
let map = wordToNumberMapByType.get(type);
|
|
53
|
+
if (!map) {
|
|
54
|
+
const numberToWordMap = await getEffNumberToWordMap(type);
|
|
55
|
+
map = new Map(numberToWordMap.entries().map(([k, v]) => [v, k]));
|
|
56
|
+
wordToNumberMapByType.set(type, map);
|
|
57
|
+
}
|
|
58
|
+
return map;
|
|
59
|
+
};
|
|
60
|
+
clearEffCache = () => {
|
|
61
|
+
numberToWordMapByType.clear();
|
|
62
|
+
wordToNumberMapByType.clear();
|
|
63
|
+
};
|
|
64
|
+
}));
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/parse-big-int.ts
|
|
67
|
+
function parseBigInt(string, radix) {
|
|
68
|
+
if (radix < 2 || radix > 36) throw new TypeError("Radix must be between 2 and 36");
|
|
69
|
+
const bigRadix = BigInt(radix);
|
|
70
|
+
let result = 0n;
|
|
71
|
+
for (const char of string) {
|
|
72
|
+
const digit = parseInt(char, radix);
|
|
73
|
+
if (isNaN(digit)) throw new TypeError(`Invalid character "${char}" for radix ${radix}`);
|
|
74
|
+
result = result * bigRadix + BigInt(digit);
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
var init_parse_big_int = __esmMin((() => {}));
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/mnemonic.ts
|
|
81
|
+
async function bufferToMnemonic(buffer, type = "large") {
|
|
82
|
+
if (!buffer.length) return [];
|
|
83
|
+
const numberToWordMap = await getEffNumberToWordMap(type);
|
|
84
|
+
const base6 = BigInt("0x" + buffer.toString("hex")).toString(6);
|
|
85
|
+
const rolls = type === "large" ? 5 : 4;
|
|
86
|
+
const base6PaddedLength = Math.ceil(base6.length / rolls) * rolls;
|
|
87
|
+
return (base6.padStart(base6PaddedLength, "0").match(new RegExp(`.{1,${rolls}}`, "g")) ?? []).map((chunk) => {
|
|
88
|
+
const word = numberToWordMap.get(chunk);
|
|
89
|
+
if (!word) {
|
|
90
|
+
const sequence = zeroToOneBaseIndex(chunk);
|
|
91
|
+
throw TypeError(`Sequence "${sequence}" not in ${type} list`);
|
|
92
|
+
}
|
|
93
|
+
return word;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
async function mnemonicToBuffer(words, type = "large") {
|
|
97
|
+
if (!words.length) return Buffer.alloc(0);
|
|
98
|
+
const wordToBase6Map = await getEffWordToNumberMap(type);
|
|
99
|
+
let hex = parseBigInt(words.map((word) => {
|
|
100
|
+
const chunk = wordToBase6Map.get(word.toLowerCase());
|
|
101
|
+
if (!chunk) throw TypeError(`Word "${word}" not ${type} list`);
|
|
102
|
+
return chunk;
|
|
103
|
+
}).join(""), 6).toString(16);
|
|
104
|
+
if (hex.length % 2 !== 0) hex = "0" + hex;
|
|
105
|
+
return Buffer.from(hex, "hex");
|
|
106
|
+
}
|
|
107
|
+
var init_mnemonic = __esmMin((() => {
|
|
108
|
+
init_base_index();
|
|
109
|
+
init_data();
|
|
110
|
+
init_parse_big_int();
|
|
111
|
+
}));
|
|
112
|
+
//#endregion
|
|
113
|
+
export { parseBigInt as a, getEffWordToNumberMap as c, oneToZeroBaseIndex as d, zeroToOneBaseIndex as f, init_parse_big_int as i, init_data as l, init_mnemonic as n, clearEffCache as o, __commonJSMin as p, mnemonicToBuffer as r, getEffNumberToWordMap as s, bufferToMnemonic as t, init_base_index as u };
|
|
114
|
+
|
|
115
|
+
//# sourceMappingURL=mnemonic-JeCBHZim.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mnemonic-JeCBHZim.mjs","names":[],"sources":["../src/base-index.ts","../node_modules/tsdown/esm-shims.js","../src/data.ts","../src/parse-big-int.ts","../src/mnemonic.ts"],"sourcesContent":["export function oneToZeroBaseIndex(string: string) {\n if (!/^[1-9]*$/.test(string)) {\n throw new TypeError(`Input \"${string}\" contains characters other than 1-9`);\n }\n\n return string.replace(/\\d/g, (d) => String(Number(d) - 1));\n}\n\nexport function zeroToOneBaseIndex(string: string) {\n if (!/^[0-8]*$/.test(string)) {\n throw new TypeError(`Input \"${string}\" contains characters other than 0-8`);\n }\n\n return string.replace(/\\d/g, (d) => String(Number(d) + 1));\n}\n","// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import { readFile } from \"node:fs/promises\";\nimport { oneToZeroBaseIndex } from \"./base-index\";\n\nconst numberToWordMapByType = new Map<EffWordListType, EffWordMap>();\nconst wordToNumberMapByType = new Map<EffWordListType, EffWordMap>();\n\nexport type EffWordListType = \"large\" | \"short_1\" | \"short_2_0\";\nexport type EffWordMap = Map<string, string>;\n\nexport const getEffNumberToWordMap = async (type: EffWordListType) => {\n let map = numberToWordMapByType.get(type);\n\n // load map from file if already not loaded\n if (!map) {\n if (type !== \"large\" && type !== \"short_1\" && type !== \"short_2_0\") {\n throw new TypeError(`Invalid type \"${type}\"`);\n }\n\n const file = await readFile(\n __dirname + `/../data/eff_wordlist_${type}.txt`,\n \"utf8\",\n );\n\n // parse wordlist and build a map\n // NOTE: the dice rolls use numbers from 1 to 6, we convert this to a\n // zero based index or a base6 number\n map = new Map(\n file\n .split(\"\\n\")\n .map((it) => it.split(\"\\t\") as [string, string])\n .map(([k, v]) => [oneToZeroBaseIndex(k), v]),\n );\n\n // cache map\n numberToWordMapByType.set(type, map);\n }\n\n return map;\n};\n\nexport const getEffWordToNumberMap = async (type: EffWordListType) => {\n let map = wordToNumberMapByType.get(type);\n\n // load map from file if already not loaded\n if (!map) {\n const numberToWordMap = await getEffNumberToWordMap(type);\n\n // invert number to word map\n map = new Map(numberToWordMap.entries().map(([k, v]) => [v, k]));\n\n // cache map\n wordToNumberMapByType.set(type, map);\n }\n\n return map;\n};\n\nexport const clearEffCache = () => {\n numberToWordMapByType.clear();\n wordToNumberMapByType.clear();\n};\n","export function parseBigInt(string: string, radix: number) {\n if (radix < 2 || radix > 36) {\n throw new TypeError(\"Radix must be between 2 and 36\");\n }\n\n const bigRadix = BigInt(radix);\n\n let result = 0n;\n for (const char of string) {\n const digit = parseInt(char, radix);\n\n if (isNaN(digit)) {\n throw new TypeError(`Invalid character \"${char}\" for radix ${radix}`);\n }\n\n result = result * bigRadix + BigInt(digit);\n }\n\n return result;\n}\n","import { zeroToOneBaseIndex } from \"./base-index\";\nimport {\n EffWordListType,\n getEffNumberToWordMap,\n getEffWordToNumberMap,\n} from \"./data\";\nimport { parseBigInt } from \"./parse-big-int\";\n\nexport async function bufferToMnemonic(\n buffer: Buffer,\n type: EffWordListType = \"large\",\n) {\n // handle empty input\n if (!buffer.length) {\n return [];\n }\n\n const numberToWordMap = await getEffNumberToWordMap(type);\n const bigint = BigInt(\"0x\" + buffer.toString(\"hex\"));\n const base6 = bigint.toString(6);\n\n // pad string to ensure length is a multiple of number of dice rolls\n const rolls = type === \"large\" ? 5 : 4;\n const base6PaddedLength = Math.ceil(base6.length / rolls) * rolls;\n const base6Padded = base6.padStart(base6PaddedLength, \"0\");\n\n // split base6 string into chunks and map to words\n const base6Chunks = base6Padded.match(new RegExp(`.{1,${rolls}}`, \"g\")) ?? [];\n return base6Chunks.map((chunk) => {\n const word = numberToWordMap.get(chunk);\n if (!word) {\n const sequence = zeroToOneBaseIndex(chunk);\n throw TypeError(`Sequence \"${sequence}\" not in ${type} list`);\n }\n return word;\n });\n}\n\nexport async function mnemonicToBuffer(\n words: string[],\n type: EffWordListType = \"large\",\n) {\n // handle empty input\n if (!words.length) {\n return Buffer.alloc(0);\n }\n\n const wordToBase6Map = await getEffWordToNumberMap(type);\n const base6Chunks = words.map((word) => {\n const chunk = wordToBase6Map.get(word.toLowerCase());\n if (!chunk) {\n throw TypeError(`Word \"${word}\" not ${type} list`);\n }\n return chunk;\n });\n\n const bigint = parseBigInt(base6Chunks.join(\"\"), 6);\n let hex = bigint.toString(16);\n\n // ensure hex has even length\n if (hex.length % 2 !== 0) {\n hex = \"0\" + hex;\n }\n\n return Buffer.from(hex, \"hex\");\n}\n"],"x_google_ignoreList":[1],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eff-mnemonic",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Convert buffers to and from a human-readable mnemonic phrase using the eff wordlists",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eff",
|
|
@@ -37,14 +37,19 @@
|
|
|
37
37
|
"require": "./dist/index.js"
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
+
"bin": {
|
|
41
|
+
"eff-mnemonic": "./bin/eff-mnemonic"
|
|
42
|
+
},
|
|
40
43
|
"files": [
|
|
44
|
+
"bin",
|
|
41
45
|
"data",
|
|
42
46
|
"dist"
|
|
43
47
|
],
|
|
44
48
|
"scripts": {
|
|
45
49
|
"test": "node --import tsx --test src/**/*.test.ts",
|
|
46
|
-
"build": "tsdown --shims --format cjs,esm --clean --dts src/index.ts",
|
|
47
|
-
"
|
|
50
|
+
"build": "tsdown --shims --format cjs,esm --clean --dts src/index.ts src/cli.ts",
|
|
51
|
+
"prepare": "npm run build",
|
|
52
|
+
"prepublishOnly": "npm run build && npm run test"
|
|
48
53
|
},
|
|
49
54
|
"devDependencies": {
|
|
50
55
|
"@types/node": "^26.1.1",
|