@bcts/seedtool-cli 1.0.0-alpha.14
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 +48 -0
- package/README.md +11 -0
- package/dist/index.cjs +1370 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +654 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +654 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1304 -0
- package/dist/index.mjs.map +1 -0
- package/dist/main.mjs +1375 -0
- package/dist/main.mjs.map +1 -0
- package/package.json +95 -0
- package/src/cli.ts +345 -0
- package/src/formats/base10.ts +39 -0
- package/src/formats/base6.ts +39 -0
- package/src/formats/bip39.ts +43 -0
- package/src/formats/bits.ts +39 -0
- package/src/formats/bytewords-minimal.ts +35 -0
- package/src/formats/bytewords-standard.ts +35 -0
- package/src/formats/bytewords-uri.ts +35 -0
- package/src/formats/cards.ts +100 -0
- package/src/formats/dice.ts +39 -0
- package/src/formats/envelope.ts +34 -0
- package/src/formats/format.ts +145 -0
- package/src/formats/hex.ts +34 -0
- package/src/formats/index.ts +31 -0
- package/src/formats/ints.ts +37 -0
- package/src/formats/multipart.ts +64 -0
- package/src/formats/random.ts +28 -0
- package/src/formats/seed-format.ts +37 -0
- package/src/formats/sskr.ts +290 -0
- package/src/index.ts +44 -0
- package/src/main.ts +227 -0
- package/src/random.ts +130 -0
- package/src/seed.ts +300 -0
- package/src/styles.ts +50 -0
- package/src/util.ts +140 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1370 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
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") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
let readline = require("readline");
|
|
29
|
+
readline = __toESM(readline);
|
|
30
|
+
let _bcts_components = require("@bcts/components");
|
|
31
|
+
let _bcts_envelope = require("@bcts/envelope");
|
|
32
|
+
let _bcts_known_values = require("@bcts/known-values");
|
|
33
|
+
let _bcts_dcbor = require("@bcts/dcbor");
|
|
34
|
+
let _noble_hashes_sha256 = require("@noble/hashes/sha256");
|
|
35
|
+
let _noble_hashes_hkdf = require("@noble/hashes/hkdf");
|
|
36
|
+
let _scure_bip39 = require("@scure/bip39");
|
|
37
|
+
let _scure_bip39_wordlists_english = require("@scure/bip39/wordlists/english");
|
|
38
|
+
let _bcts_uniform_resources = require("@bcts/uniform-resources");
|
|
39
|
+
let _bcts_tags = require("@bcts/tags");
|
|
40
|
+
|
|
41
|
+
//#region src/cli.ts
|
|
42
|
+
/**
|
|
43
|
+
* CLI types and interfaces
|
|
44
|
+
* Ported from seedtool-cli-rust/src/cli.rs
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* Input format keys.
|
|
48
|
+
* Matches Rust InputFormatKey enum in format.rs
|
|
49
|
+
*/
|
|
50
|
+
let InputFormatKey = /* @__PURE__ */ function(InputFormatKey$1) {
|
|
51
|
+
InputFormatKey$1["Random"] = "random";
|
|
52
|
+
InputFormatKey$1["Hex"] = "hex";
|
|
53
|
+
InputFormatKey$1["Btw"] = "btw";
|
|
54
|
+
InputFormatKey$1["Btwu"] = "btwu";
|
|
55
|
+
InputFormatKey$1["Btwm"] = "btwm";
|
|
56
|
+
InputFormatKey$1["Bits"] = "bits";
|
|
57
|
+
InputFormatKey$1["Cards"] = "cards";
|
|
58
|
+
InputFormatKey$1["Dice"] = "dice";
|
|
59
|
+
InputFormatKey$1["Base6"] = "base6";
|
|
60
|
+
InputFormatKey$1["Base10"] = "base10";
|
|
61
|
+
InputFormatKey$1["Ints"] = "ints";
|
|
62
|
+
InputFormatKey$1["Bip39"] = "bip39";
|
|
63
|
+
InputFormatKey$1["Sskr"] = "sskr";
|
|
64
|
+
InputFormatKey$1["Envelope"] = "envelope";
|
|
65
|
+
InputFormatKey$1["Multipart"] = "multipart";
|
|
66
|
+
InputFormatKey$1["Seed"] = "seed";
|
|
67
|
+
return InputFormatKey$1;
|
|
68
|
+
}({});
|
|
69
|
+
/**
|
|
70
|
+
* Output format keys.
|
|
71
|
+
* Matches Rust OutputFormatKey enum in format.rs
|
|
72
|
+
*/
|
|
73
|
+
let OutputFormatKey = /* @__PURE__ */ function(OutputFormatKey$1) {
|
|
74
|
+
OutputFormatKey$1["Hex"] = "hex";
|
|
75
|
+
OutputFormatKey$1["Btw"] = "btw";
|
|
76
|
+
OutputFormatKey$1["Btwu"] = "btwu";
|
|
77
|
+
OutputFormatKey$1["Btwm"] = "btwm";
|
|
78
|
+
OutputFormatKey$1["Bits"] = "bits";
|
|
79
|
+
OutputFormatKey$1["Cards"] = "cards";
|
|
80
|
+
OutputFormatKey$1["Dice"] = "dice";
|
|
81
|
+
OutputFormatKey$1["Base6"] = "base6";
|
|
82
|
+
OutputFormatKey$1["Base10"] = "base10";
|
|
83
|
+
OutputFormatKey$1["Ints"] = "ints";
|
|
84
|
+
OutputFormatKey$1["Bip39"] = "bip39";
|
|
85
|
+
OutputFormatKey$1["Sskr"] = "sskr";
|
|
86
|
+
OutputFormatKey$1["Envelope"] = "envelope";
|
|
87
|
+
OutputFormatKey$1["Multipart"] = "multipart";
|
|
88
|
+
OutputFormatKey$1["Seed"] = "seed";
|
|
89
|
+
return OutputFormatKey$1;
|
|
90
|
+
}({});
|
|
91
|
+
/**
|
|
92
|
+
* SSKR output format keys.
|
|
93
|
+
* Matches Rust SSKRFormatKey enum in sskr.rs
|
|
94
|
+
*/
|
|
95
|
+
let SSKRFormatKey = /* @__PURE__ */ function(SSKRFormatKey$1) {
|
|
96
|
+
SSKRFormatKey$1["Envelope"] = "envelope";
|
|
97
|
+
SSKRFormatKey$1["Btw"] = "btw";
|
|
98
|
+
SSKRFormatKey$1["Btwm"] = "btwm";
|
|
99
|
+
SSKRFormatKey$1["Btwu"] = "btwu";
|
|
100
|
+
SSKRFormatKey$1["Ur"] = "ur";
|
|
101
|
+
return SSKRFormatKey$1;
|
|
102
|
+
}({});
|
|
103
|
+
/**
|
|
104
|
+
* Parse and validate low int (0-254).
|
|
105
|
+
* Matches Rust parse_low_int function.
|
|
106
|
+
*/
|
|
107
|
+
function parseLowInt(s) {
|
|
108
|
+
const n = parseInt(s, 10);
|
|
109
|
+
if (isNaN(n) || n < 0 || n > 254) throw new Error(`Invalid low value: ${s}. Must be 0-254.`);
|
|
110
|
+
return n;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Parse and validate high int (1-255).
|
|
114
|
+
* Matches Rust parse_high_int function.
|
|
115
|
+
*/
|
|
116
|
+
function parseHighInt(s) {
|
|
117
|
+
const n = parseInt(s, 10);
|
|
118
|
+
if (isNaN(n) || n < 1 || n > 255) throw new Error(`Invalid high value: ${s}. Must be 1-255.`);
|
|
119
|
+
return n;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Parse and validate group threshold (1-16).
|
|
123
|
+
* Matches Rust parse_group_threshold function.
|
|
124
|
+
*/
|
|
125
|
+
function parseGroupThreshold(s) {
|
|
126
|
+
const n = parseInt(s, 10);
|
|
127
|
+
if (isNaN(n) || n < 1 || n > 16) throw new Error(`Invalid group threshold: ${s}. Must be 1-16.`);
|
|
128
|
+
return n;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Parse date string.
|
|
132
|
+
* Accepts "now" or ISO-8601 format.
|
|
133
|
+
* Matches Rust parse_date function.
|
|
134
|
+
*/
|
|
135
|
+
function parseDate(s) {
|
|
136
|
+
if (s === "now") return /* @__PURE__ */ new Date();
|
|
137
|
+
const date = new Date(s);
|
|
138
|
+
if (isNaN(date.getTime())) throw new Error(`Invalid date: ${s}. Use ISO-8601 format or 'now'.`);
|
|
139
|
+
return date;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Parse SSKR group specification "M-of-N".
|
|
143
|
+
* Returns SSKRGroupSpec instance.
|
|
144
|
+
*/
|
|
145
|
+
function parseGroupSpec(s) {
|
|
146
|
+
const match = s.match(/^(\d+)-of-(\d+)$/i);
|
|
147
|
+
if (!match) throw new Error(`Invalid group specification: ${s}. Use format 'M-of-N' (e.g., '2-of-3').`);
|
|
148
|
+
const threshold = parseInt(match[1], 10);
|
|
149
|
+
const count = parseInt(match[2], 10);
|
|
150
|
+
return _bcts_components.SSKRGroupSpec.new(threshold, count);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* CLI state and configuration.
|
|
154
|
+
* Matches Rust Cli struct.
|
|
155
|
+
*/
|
|
156
|
+
var Cli = class Cli {
|
|
157
|
+
/** The input to be transformed. If required and not present, will be read from stdin. */
|
|
158
|
+
input;
|
|
159
|
+
/** The number of output units (hex bytes, base-10 digits, etc.) */
|
|
160
|
+
count = 16;
|
|
161
|
+
/** The input format. Default: Random */
|
|
162
|
+
in = InputFormatKey.Random;
|
|
163
|
+
/** The output format. Default: Hex */
|
|
164
|
+
out = OutputFormatKey.Hex;
|
|
165
|
+
/** The lowest int returned (0-254). Default: 0 */
|
|
166
|
+
low = 0;
|
|
167
|
+
/** The highest int returned (1-255), low < high. Default: 9 */
|
|
168
|
+
high = 9;
|
|
169
|
+
/** The name of the seed. */
|
|
170
|
+
name;
|
|
171
|
+
/** The note associated with the seed. */
|
|
172
|
+
note;
|
|
173
|
+
/** The seed's creation date, in ISO-8601 format. May also be `now`. */
|
|
174
|
+
date;
|
|
175
|
+
/** For `multipart` output, max fragment length. Default: 500 */
|
|
176
|
+
maxFragmentLen = 500;
|
|
177
|
+
/** For `multipart` output, additional parts for fountain encoding. Default: 0 */
|
|
178
|
+
additionalParts = 0;
|
|
179
|
+
/** Group specifications for SSKR. */
|
|
180
|
+
groups = [];
|
|
181
|
+
/** The number of groups that must meet their threshold. Default: 1 */
|
|
182
|
+
groupThreshold = 1;
|
|
183
|
+
/** SSKR output format. Default: Envelope */
|
|
184
|
+
sskrFormat = SSKRFormatKey.Envelope;
|
|
185
|
+
/** Deterministic RNG seed string. */
|
|
186
|
+
deterministic;
|
|
187
|
+
/** The seed being processed (internal state). */
|
|
188
|
+
seed;
|
|
189
|
+
/** The RNG source (internal state). */
|
|
190
|
+
rng;
|
|
191
|
+
/**
|
|
192
|
+
* Get input from argument or read from stdin.
|
|
193
|
+
* Matches Rust expect_input method.
|
|
194
|
+
*/
|
|
195
|
+
expectInput() {
|
|
196
|
+
if (this.input !== void 0) return this.input;
|
|
197
|
+
throw new Error("Input required but not provided. Use stdin or pass as argument.");
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Get input from argument or read from stdin asynchronously.
|
|
201
|
+
* This is the async version for actual CLI use.
|
|
202
|
+
*/
|
|
203
|
+
async expectInputAsync() {
|
|
204
|
+
if (this.input !== void 0) return this.input;
|
|
205
|
+
return new Promise((resolve, reject) => {
|
|
206
|
+
let data = "";
|
|
207
|
+
const rl = readline.createInterface({
|
|
208
|
+
input: process.stdin,
|
|
209
|
+
output: process.stdout,
|
|
210
|
+
terminal: false
|
|
211
|
+
});
|
|
212
|
+
rl.on("line", (line) => {
|
|
213
|
+
data += line + "\n";
|
|
214
|
+
});
|
|
215
|
+
rl.on("close", () => {
|
|
216
|
+
resolve(data.trim());
|
|
217
|
+
});
|
|
218
|
+
rl.on("error", (err) => {
|
|
219
|
+
reject(err);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get the seed, throwing if not initialized.
|
|
225
|
+
* Matches Rust expect_seed method.
|
|
226
|
+
*/
|
|
227
|
+
expectSeed() {
|
|
228
|
+
if (this.seed === void 0) throw new Error("Seed not initialized");
|
|
229
|
+
return this.seed;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Generate random data using the configured RNG.
|
|
233
|
+
* Matches Rust random_data method.
|
|
234
|
+
*/
|
|
235
|
+
randomData(size) {
|
|
236
|
+
if (this.rng === void 0) throw new Error("RNG not initialized");
|
|
237
|
+
if (this.rng.type === "secure") return this.rng.rng.randomData(size);
|
|
238
|
+
else return this.rng.rng.deterministicRandomData(size);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get the seed with CLI overrides applied (name, note, date).
|
|
242
|
+
* Matches Rust seed_with_overrides method.
|
|
243
|
+
*/
|
|
244
|
+
seedWithOverrides() {
|
|
245
|
+
const seed = this.expectSeed().clone();
|
|
246
|
+
if (this.name !== void 0) seed.setName(this.name);
|
|
247
|
+
if (this.note !== void 0) seed.setNote(this.note);
|
|
248
|
+
if (this.date !== void 0) seed.setCreationDate(this.date);
|
|
249
|
+
return seed;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Convert the seed (with overrides) to an Envelope.
|
|
253
|
+
* Matches Rust to_envelope method.
|
|
254
|
+
*/
|
|
255
|
+
toEnvelope() {
|
|
256
|
+
return this.seedWithOverrides().toEnvelope();
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Build SSKR spec from CLI options.
|
|
260
|
+
* Matches Rust sskr_spec method.
|
|
261
|
+
*/
|
|
262
|
+
sskrSpec() {
|
|
263
|
+
return _bcts_components.SSKRSpec.new(this.groupThreshold, this.groups);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Clone the CLI state.
|
|
267
|
+
*/
|
|
268
|
+
clone() {
|
|
269
|
+
const cli = new Cli();
|
|
270
|
+
cli.input = this.input;
|
|
271
|
+
cli.count = this.count;
|
|
272
|
+
cli.in = this.in;
|
|
273
|
+
cli.out = this.out;
|
|
274
|
+
cli.low = this.low;
|
|
275
|
+
cli.high = this.high;
|
|
276
|
+
cli.name = this.name;
|
|
277
|
+
cli.note = this.note;
|
|
278
|
+
cli.date = this.date;
|
|
279
|
+
cli.maxFragmentLen = this.maxFragmentLen;
|
|
280
|
+
cli.additionalParts = this.additionalParts;
|
|
281
|
+
cli.groups = [...this.groups];
|
|
282
|
+
cli.groupThreshold = this.groupThreshold;
|
|
283
|
+
cli.sskrFormat = this.sskrFormat;
|
|
284
|
+
cli.deterministic = this.deterministic;
|
|
285
|
+
cli.seed = this.seed?.clone();
|
|
286
|
+
cli.rng = this.rng;
|
|
287
|
+
return cli;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
//#endregion
|
|
292
|
+
//#region src/seed.ts
|
|
293
|
+
/**
|
|
294
|
+
* Seed type for seedtool-cli
|
|
295
|
+
* Ported from seedtool-cli-rust/src/seed.rs
|
|
296
|
+
*
|
|
297
|
+
* This is a local Seed type that wraps the seed data with metadata
|
|
298
|
+
* and provides Envelope conversion. It differs from @bcts/components Seed
|
|
299
|
+
* in that it doesn't enforce minimum length (for CLI flexibility) and
|
|
300
|
+
* has direct Envelope conversion methods.
|
|
301
|
+
*/
|
|
302
|
+
/**
|
|
303
|
+
* Seed with optional metadata.
|
|
304
|
+
* Matches Rust Seed struct in seed.rs.
|
|
305
|
+
*/
|
|
306
|
+
var Seed = class Seed {
|
|
307
|
+
_data;
|
|
308
|
+
_name;
|
|
309
|
+
_note;
|
|
310
|
+
_creationDate;
|
|
311
|
+
/**
|
|
312
|
+
* Create a new Seed with the given data.
|
|
313
|
+
* Matches Rust Seed::new function.
|
|
314
|
+
*/
|
|
315
|
+
constructor(data) {
|
|
316
|
+
this._data = new Uint8Array(data);
|
|
317
|
+
this._name = "";
|
|
318
|
+
this._note = "";
|
|
319
|
+
this._creationDate = void 0;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Create a new Seed with data and optional metadata.
|
|
323
|
+
* Matches Rust Seed::new_opt function.
|
|
324
|
+
*/
|
|
325
|
+
static newOpt(data, name, note, creationDate) {
|
|
326
|
+
const seed = new Seed(data);
|
|
327
|
+
seed._name = name;
|
|
328
|
+
seed._note = note;
|
|
329
|
+
seed._creationDate = creationDate;
|
|
330
|
+
return seed;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Create a new Seed from raw data.
|
|
334
|
+
* Convenience factory method.
|
|
335
|
+
*/
|
|
336
|
+
static new(data) {
|
|
337
|
+
return new Seed(data);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Get the seed data.
|
|
341
|
+
* Matches Rust seed.data() method.
|
|
342
|
+
*/
|
|
343
|
+
data() {
|
|
344
|
+
return this._data;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Get the seed name.
|
|
348
|
+
* Matches Rust seed.name() method.
|
|
349
|
+
* Returns empty string if not set.
|
|
350
|
+
*/
|
|
351
|
+
name() {
|
|
352
|
+
return this._name;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Set the seed name.
|
|
356
|
+
* Matches Rust seed.set_name() method.
|
|
357
|
+
*/
|
|
358
|
+
setName(name) {
|
|
359
|
+
this._name = name;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Get the seed note.
|
|
363
|
+
* Matches Rust seed.note() method.
|
|
364
|
+
* Returns empty string if not set.
|
|
365
|
+
*/
|
|
366
|
+
note() {
|
|
367
|
+
return this._note;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Set the seed note.
|
|
371
|
+
* Matches Rust seed.set_note() method.
|
|
372
|
+
*/
|
|
373
|
+
setNote(note) {
|
|
374
|
+
this._note = note;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Get the creation date.
|
|
378
|
+
* Matches Rust seed.creation_date() method.
|
|
379
|
+
*/
|
|
380
|
+
creationDate() {
|
|
381
|
+
return this._creationDate;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Set the creation date.
|
|
385
|
+
* Matches Rust seed.set_creation_date() method.
|
|
386
|
+
*/
|
|
387
|
+
setCreationDate(date) {
|
|
388
|
+
this._creationDate = date;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Clone the seed.
|
|
392
|
+
*/
|
|
393
|
+
clone() {
|
|
394
|
+
return Seed.newOpt(new Uint8Array(this._data), this._name, this._note, this._creationDate);
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Convert to Envelope.
|
|
398
|
+
* Matches Rust impl From<Seed> for Envelope.
|
|
399
|
+
*
|
|
400
|
+
* Creates an envelope with:
|
|
401
|
+
* - Subject: byte string of seed data
|
|
402
|
+
* - Type assertion: 'Seed'
|
|
403
|
+
* - Optional date assertion
|
|
404
|
+
* - Optional name assertion (if not empty)
|
|
405
|
+
* - Optional note assertion (if not empty)
|
|
406
|
+
*/
|
|
407
|
+
toEnvelope() {
|
|
408
|
+
let envelope = _bcts_envelope.Envelope.new((0, _bcts_dcbor.toByteString)(this._data));
|
|
409
|
+
envelope = envelope.addType(_bcts_known_values.SEED_TYPE);
|
|
410
|
+
if (this._creationDate !== void 0) {
|
|
411
|
+
const cborDate = _bcts_dcbor.CborDate.fromDatetime(this._creationDate);
|
|
412
|
+
envelope = envelope.addAssertion(_bcts_known_values.DATE, cborDate);
|
|
413
|
+
}
|
|
414
|
+
if (this._name.length > 0) envelope = envelope.addAssertion(_bcts_known_values.NAME, this._name);
|
|
415
|
+
if (this._note.length > 0) envelope = envelope.addAssertion(_bcts_known_values.NOTE, this._note);
|
|
416
|
+
return envelope;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Create a Seed from an Envelope.
|
|
420
|
+
* Matches Rust impl TryFrom<Envelope> for Seed.
|
|
421
|
+
*/
|
|
422
|
+
static fromEnvelope(envelope) {
|
|
423
|
+
envelope.checkTypeValue(_bcts_known_values.SEED_TYPE);
|
|
424
|
+
const leaf = envelope.subject().asLeaf();
|
|
425
|
+
if (leaf === void 0) throw new Error("Seed envelope must have a leaf subject");
|
|
426
|
+
const data = leaf.asByteString();
|
|
427
|
+
if (data === void 0) throw new Error("Seed envelope subject must be a byte string");
|
|
428
|
+
let name = "";
|
|
429
|
+
try {
|
|
430
|
+
const nameObj = envelope.objectForPredicate(_bcts_known_values.NAME);
|
|
431
|
+
if (nameObj !== void 0) {
|
|
432
|
+
const nameStr = nameObj.asText();
|
|
433
|
+
if (nameStr !== void 0) name = nameStr;
|
|
434
|
+
}
|
|
435
|
+
} catch {}
|
|
436
|
+
let note = "";
|
|
437
|
+
try {
|
|
438
|
+
const noteObj = envelope.objectForPredicate(_bcts_known_values.NOTE);
|
|
439
|
+
if (noteObj !== void 0) {
|
|
440
|
+
const noteStr = noteObj.asText();
|
|
441
|
+
if (noteStr !== void 0) note = noteStr;
|
|
442
|
+
}
|
|
443
|
+
} catch {}
|
|
444
|
+
let creationDate;
|
|
445
|
+
try {
|
|
446
|
+
const dateObj = envelope.objectForPredicate(_bcts_known_values.DATE);
|
|
447
|
+
if (dateObj !== void 0) {
|
|
448
|
+
const leaf$1 = dateObj.asLeaf();
|
|
449
|
+
if (leaf$1 !== void 0) creationDate = _bcts_dcbor.CborDate.fromTaggedCbor(leaf$1).datetime();
|
|
450
|
+
}
|
|
451
|
+
} catch {
|
|
452
|
+
try {
|
|
453
|
+
const dateObj = envelope.objectForPredicate(_bcts_known_values.DATE);
|
|
454
|
+
if (dateObj !== void 0) {
|
|
455
|
+
const dateStr = dateObj.asText();
|
|
456
|
+
if (dateStr !== void 0) creationDate = new Date(dateStr);
|
|
457
|
+
}
|
|
458
|
+
} catch {}
|
|
459
|
+
}
|
|
460
|
+
return Seed.newOpt(data, name, note, creationDate);
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Convert to @bcts/components Seed.
|
|
464
|
+
* Matches Rust impl TryFrom<&Seed> for ComponentsSeed.
|
|
465
|
+
*/
|
|
466
|
+
toComponentsSeed() {
|
|
467
|
+
return _bcts_components.Seed.newOpt(this._data, this._name.length > 0 ? this._name : void 0, this._note.length > 0 ? this._note : void 0, this._creationDate);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Create from @bcts/components Seed.
|
|
471
|
+
* Matches Rust impl From<ComponentsSeed> for Seed.
|
|
472
|
+
*/
|
|
473
|
+
static fromComponentsSeed(seed) {
|
|
474
|
+
return Seed.newOpt(seed.asBytes(), seed.name(), seed.note(), seed.creationDate());
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Get string representation.
|
|
478
|
+
*/
|
|
479
|
+
toString() {
|
|
480
|
+
return `Seed(${Array.from(this._data.slice(0, 8)).map((b) => b.toString(16).padStart(2, "0")).join("")}..., ${this._data.length} bytes)`;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Check equality with another Seed.
|
|
484
|
+
*/
|
|
485
|
+
equals(other) {
|
|
486
|
+
if (this._data.length !== other._data.length) return false;
|
|
487
|
+
for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false;
|
|
488
|
+
if (this._name !== other._name) return false;
|
|
489
|
+
if (this._note !== other._note) return false;
|
|
490
|
+
if (this._creationDate?.getTime() !== other._creationDate?.getTime()) return false;
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
//#endregion
|
|
496
|
+
//#region src/random.ts
|
|
497
|
+
/**
|
|
498
|
+
* Random number generation utilities
|
|
499
|
+
* Ported from seedtool-cli-rust/src/random.rs
|
|
500
|
+
*/
|
|
501
|
+
/** SHA256 output size in bytes */
|
|
502
|
+
const SHA256_SIZE = 32;
|
|
503
|
+
/**
|
|
504
|
+
* Deterministic random number generator.
|
|
505
|
+
* Matches Rust DeterministicRandomNumberGenerator struct.
|
|
506
|
+
*
|
|
507
|
+
* Uses HKDF-HMAC-SHA256 to generate deterministic random data
|
|
508
|
+
* from a seed, with an incrementing salt for each call.
|
|
509
|
+
*/
|
|
510
|
+
var DeterministicRandomNumberGenerator = class DeterministicRandomNumberGenerator {
|
|
511
|
+
seed;
|
|
512
|
+
salt;
|
|
513
|
+
/**
|
|
514
|
+
* Create a new deterministic RNG from a 32-byte seed.
|
|
515
|
+
*/
|
|
516
|
+
constructor(seed) {
|
|
517
|
+
if (seed.length !== SHA256_SIZE) throw new Error(`Seed must be ${SHA256_SIZE} bytes, got ${seed.length}`);
|
|
518
|
+
this.seed = new Uint8Array(seed);
|
|
519
|
+
this.salt = 0n;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Create a new deterministic RNG from a seed string.
|
|
523
|
+
* The string is hashed with SHA256 to produce the seed.
|
|
524
|
+
* Matches Rust new_with_seed function.
|
|
525
|
+
*/
|
|
526
|
+
static newWithSeed(seedString) {
|
|
527
|
+
return new DeterministicRandomNumberGenerator((0, _noble_hashes_sha256.sha256)(new TextEncoder().encode(seedString)));
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Generate deterministic random data.
|
|
531
|
+
* Matches Rust deterministic_random_data method.
|
|
532
|
+
*
|
|
533
|
+
* Each call increments the salt and uses HKDF to derive
|
|
534
|
+
* the requested number of bytes.
|
|
535
|
+
*/
|
|
536
|
+
deterministicRandomData(size) {
|
|
537
|
+
this.salt += 1n;
|
|
538
|
+
const saltBytes = new Uint8Array(8);
|
|
539
|
+
const view = new DataView(saltBytes.buffer);
|
|
540
|
+
const low = Number(this.salt & 4294967295n);
|
|
541
|
+
const high = Number(this.salt >> 32n & 4294967295n);
|
|
542
|
+
view.setUint32(0, low, true);
|
|
543
|
+
view.setUint32(4, high, true);
|
|
544
|
+
return hkdfHmacSha256(this.seed, saltBytes, size);
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Clone the RNG state.
|
|
548
|
+
*/
|
|
549
|
+
clone() {
|
|
550
|
+
const rng = new DeterministicRandomNumberGenerator(this.seed);
|
|
551
|
+
rng.salt = this.salt;
|
|
552
|
+
return rng;
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
/**
|
|
556
|
+
* HKDF-HMAC-SHA256 key derivation.
|
|
557
|
+
* Matches Rust hkdf_hmac_sha256 function from bc-crypto.
|
|
558
|
+
*/
|
|
559
|
+
function hkdfHmacSha256(ikm, salt, length) {
|
|
560
|
+
return (0, _noble_hashes_hkdf.hkdf)(_noble_hashes_sha256.sha256, ikm, salt, new Uint8Array(0), length);
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Generate deterministic random data from entropy using SHA256.
|
|
564
|
+
* If n <= 32, returns the first n bytes of SHA256(entropy).
|
|
565
|
+
* Matches Rust sha256_deterministic_random function.
|
|
566
|
+
*
|
|
567
|
+
* @param entropy - The entropy bytes to hash
|
|
568
|
+
* @param n - Number of bytes to return (must be <= 32)
|
|
569
|
+
* @throws Error if n > 32
|
|
570
|
+
*/
|
|
571
|
+
function sha256DeterministicRandom(entropy, n) {
|
|
572
|
+
const seed = (0, _noble_hashes_sha256.sha256)(entropy);
|
|
573
|
+
if (n <= seed.length) return seed.slice(0, n);
|
|
574
|
+
else throw new Error("Random number generator limits reached.");
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Generate deterministic random data from a string using SHA256.
|
|
578
|
+
* Matches Rust sha256_deterministic_random_string function.
|
|
579
|
+
*
|
|
580
|
+
* @param str - The string to hash
|
|
581
|
+
* @param n - Number of bytes to return (must be <= 32)
|
|
582
|
+
* @throws Error if n > 32
|
|
583
|
+
*/
|
|
584
|
+
function sha256DeterministicRandomString(str, n) {
|
|
585
|
+
return sha256DeterministicRandom(new TextEncoder().encode(str), n);
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Generate deterministic random data from entropy using HKDF.
|
|
589
|
+
* This can generate any length output.
|
|
590
|
+
* Matches Rust deterministic_random function.
|
|
591
|
+
*
|
|
592
|
+
* @param entropy - The entropy bytes
|
|
593
|
+
* @param n - Number of bytes to return
|
|
594
|
+
*/
|
|
595
|
+
function deterministicRandom(entropy, n) {
|
|
596
|
+
return hkdfHmacSha256((0, _noble_hashes_sha256.sha256)(entropy), new Uint8Array(0), n);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
//#endregion
|
|
600
|
+
//#region src/util.ts
|
|
601
|
+
/**
|
|
602
|
+
* Utility functions for data conversion
|
|
603
|
+
* Ported from seedtool-cli-rust/src/util.rs
|
|
604
|
+
*/
|
|
605
|
+
/**
|
|
606
|
+
* Convert bytes to hex string.
|
|
607
|
+
* Matches Rust data_to_hex function.
|
|
608
|
+
*/
|
|
609
|
+
function dataToHex(bytes) {
|
|
610
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Convert hex string to bytes.
|
|
614
|
+
* Matches Rust hex_to_data function.
|
|
615
|
+
*/
|
|
616
|
+
function hexToData(hex) {
|
|
617
|
+
if (hex.length % 2 !== 0) throw new Error("Hex string must have even length");
|
|
618
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
619
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
620
|
+
const byte = parseInt(hex.substring(i, i + 2), 16);
|
|
621
|
+
if (isNaN(byte)) throw new Error(`Invalid hex character at position ${i}`);
|
|
622
|
+
bytes[i / 2] = byte;
|
|
623
|
+
}
|
|
624
|
+
return bytes;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Convert byte values to a different base range [0, base-1].
|
|
628
|
+
* Each byte (0-255) is scaled proportionally to the target base.
|
|
629
|
+
* Matches Rust data_to_base function.
|
|
630
|
+
*
|
|
631
|
+
* @param buf - Input bytes
|
|
632
|
+
* @param base - Target base (e.g., 6 for base-6)
|
|
633
|
+
* @returns Array of values in range [0, base-1]
|
|
634
|
+
*/
|
|
635
|
+
function dataToBase(buf, base) {
|
|
636
|
+
const result = new Uint8Array(buf.length);
|
|
637
|
+
for (let i = 0; i < buf.length; i++) result[i] = Math.round(buf[i] / 255 * (base - 1));
|
|
638
|
+
return result;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Convert bytes to an alphabet string using a base and alphabet function.
|
|
642
|
+
* Matches Rust data_to_alphabet function.
|
|
643
|
+
*
|
|
644
|
+
* @param buf - Input bytes
|
|
645
|
+
* @param base - Target base
|
|
646
|
+
* @param toAlphabet - Function to convert index to character
|
|
647
|
+
* @returns String of alphabet characters
|
|
648
|
+
*/
|
|
649
|
+
function dataToAlphabet(buf, base, toAlphabet) {
|
|
650
|
+
const data = dataToBase(buf, base);
|
|
651
|
+
return Array.from(data).map((b) => toAlphabet(b)).join("");
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Parse whitespace-separated integers.
|
|
655
|
+
* Matches Rust parse_ints function.
|
|
656
|
+
*
|
|
657
|
+
* @param input - Space-separated integer string
|
|
658
|
+
* @returns Array of bytes
|
|
659
|
+
* @throws Error if any integer is out of range [0, 255]
|
|
660
|
+
*/
|
|
661
|
+
function parseInts(input) {
|
|
662
|
+
const parts = input.trim().split(/\s+/);
|
|
663
|
+
const result = [];
|
|
664
|
+
for (const s of parts) {
|
|
665
|
+
if (s === "") continue;
|
|
666
|
+
const i = parseInt(s, 10);
|
|
667
|
+
if (isNaN(i)) throw new Error(`Invalid integer: ${s}`);
|
|
668
|
+
if (i < 0 || i > 255) throw new Error("Integer out of range. Allowed: [0-255]");
|
|
669
|
+
result.push(i);
|
|
670
|
+
}
|
|
671
|
+
return new Uint8Array(result);
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Convert bytes to a string of integers in a given range.
|
|
675
|
+
* Matches Rust data_to_ints function.
|
|
676
|
+
*
|
|
677
|
+
* @param buf - Input bytes
|
|
678
|
+
* @param low - Lowest output value (0-254)
|
|
679
|
+
* @param high - Highest output value (1-255), low < high
|
|
680
|
+
* @param separator - String to separate values
|
|
681
|
+
* @returns String of integers
|
|
682
|
+
* @throws Error if range is invalid
|
|
683
|
+
*/
|
|
684
|
+
function dataToInts(buf, low, high, separator) {
|
|
685
|
+
if (!(low < high && high <= 255)) throw new Error("Int conversion range must be in 0 <= low < high <= 255.");
|
|
686
|
+
const data = dataToBase(buf, high - low + 1);
|
|
687
|
+
return Array.from(data).map((b) => (b + low).toString()).join(separator);
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Parse a string of digits in a given range to bytes.
|
|
691
|
+
* Matches Rust digits_to_data function.
|
|
692
|
+
*
|
|
693
|
+
* @param inStr - String of digits
|
|
694
|
+
* @param low - Lowest valid digit
|
|
695
|
+
* @param high - Highest valid digit
|
|
696
|
+
* @returns Array of digit values
|
|
697
|
+
* @throws Error if any digit is out of range
|
|
698
|
+
*/
|
|
699
|
+
function digitsToData(inStr, low, high) {
|
|
700
|
+
const result = [];
|
|
701
|
+
for (const c of inStr) {
|
|
702
|
+
const n = c.charCodeAt(0) - "0".charCodeAt(0);
|
|
703
|
+
if (n < low || n > high) throw new Error(`Invalid digit: ${c}. Expected range [${low}-${high}].`);
|
|
704
|
+
result.push(n);
|
|
705
|
+
}
|
|
706
|
+
return new Uint8Array(result);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
//#endregion
|
|
710
|
+
//#region src/formats/hex.ts
|
|
711
|
+
/**
|
|
712
|
+
* Hexadecimal format handler.
|
|
713
|
+
* Round-trippable: hex → seed → hex.
|
|
714
|
+
*/
|
|
715
|
+
var HexFormat = class {
|
|
716
|
+
name() {
|
|
717
|
+
return "hex";
|
|
718
|
+
}
|
|
719
|
+
roundTrippable() {
|
|
720
|
+
return true;
|
|
721
|
+
}
|
|
722
|
+
processInput(state) {
|
|
723
|
+
const input = state.expectInput();
|
|
724
|
+
state.seed = Seed.new(hexToData(input));
|
|
725
|
+
return state;
|
|
726
|
+
}
|
|
727
|
+
processOutput(state) {
|
|
728
|
+
return dataToHex(state.expectSeed().data());
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
//#endregion
|
|
733
|
+
//#region src/formats/bip39.ts
|
|
734
|
+
/**
|
|
735
|
+
* BIP39 mnemonic format handler.
|
|
736
|
+
* Round-trippable: mnemonic → seed → mnemonic.
|
|
737
|
+
*/
|
|
738
|
+
var Bip39Format = class {
|
|
739
|
+
name() {
|
|
740
|
+
return "bip39";
|
|
741
|
+
}
|
|
742
|
+
roundTrippable() {
|
|
743
|
+
return true;
|
|
744
|
+
}
|
|
745
|
+
processInput(state) {
|
|
746
|
+
const normalized = state.expectInput().toLowerCase().trim().replace(/\s+/g, " ");
|
|
747
|
+
if (!(0, _scure_bip39.validateMnemonic)(normalized, _scure_bip39_wordlists_english.wordlist)) throw new Error("Invalid BIP39 mnemonic");
|
|
748
|
+
const entropy = (0, _scure_bip39.mnemonicToEntropy)(normalized, _scure_bip39_wordlists_english.wordlist);
|
|
749
|
+
state.seed = Seed.new(entropy);
|
|
750
|
+
return state;
|
|
751
|
+
}
|
|
752
|
+
processOutput(state) {
|
|
753
|
+
return (0, _scure_bip39.entropyToMnemonic)(state.expectSeed().data(), _scure_bip39_wordlists_english.wordlist);
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
//#endregion
|
|
758
|
+
//#region src/formats/sskr.ts
|
|
759
|
+
/**
|
|
760
|
+
* SSKR format handler.
|
|
761
|
+
* Round-trippable: sskr shares → seed → sskr shares.
|
|
762
|
+
* Supports multiple sub-formats: envelope, btw, btwm, btwu, ur.
|
|
763
|
+
*/
|
|
764
|
+
var SSKRFormat = class {
|
|
765
|
+
name() {
|
|
766
|
+
return "sskr";
|
|
767
|
+
}
|
|
768
|
+
roundTrippable() {
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
processInput(state) {
|
|
772
|
+
state.seed = parseSskrSeed(state.expectInput());
|
|
773
|
+
return state;
|
|
774
|
+
}
|
|
775
|
+
processOutput(state) {
|
|
776
|
+
const spec = state.sskrSpec();
|
|
777
|
+
const seed = state.expectSeed();
|
|
778
|
+
const format = state.sskrFormat;
|
|
779
|
+
return outputSskrSeed(seed, spec, format);
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
function outputSskrSeed(seed, spec, format) {
|
|
783
|
+
switch (format) {
|
|
784
|
+
case "envelope": {
|
|
785
|
+
const envelope = seed.toEnvelope();
|
|
786
|
+
const contentKey = _bcts_envelope.SymmetricKey.new();
|
|
787
|
+
return envelope.wrap().encryptSubject(contentKey).sskrSplitFlattened(spec, contentKey).map((envelope$1) => envelope$1.urString()).join("\n");
|
|
788
|
+
}
|
|
789
|
+
case "btw": return makeBytewordsShares(spec, seed, _bcts_uniform_resources.BytewordsStyle.Standard);
|
|
790
|
+
case "btwm": return makeBytewordsShares(spec, seed, _bcts_uniform_resources.BytewordsStyle.Minimal);
|
|
791
|
+
case "btwu": return makeBytewordsShares(spec, seed, _bcts_uniform_resources.BytewordsStyle.Uri);
|
|
792
|
+
case "ur": return makeShares(spec, seed).map((share) => {
|
|
793
|
+
return _bcts_uniform_resources.UR.fromCbor("sskr", (0, _bcts_dcbor.toByteString)(share.asBytes())).toString();
|
|
794
|
+
}).join("\n");
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
function makeShares(spec, seed) {
|
|
798
|
+
const shareGroups = (0, _bcts_components.sskrGenerate)(spec, _bcts_components.SSKRSecret.new(seed.data()));
|
|
799
|
+
const flatShares = [];
|
|
800
|
+
for (const group of shareGroups) for (const shareData of group) flatShares.push(_bcts_components.SSKRShare.fromData(shareData));
|
|
801
|
+
return flatShares;
|
|
802
|
+
}
|
|
803
|
+
function makeBytewordsShares(spec, seed, style) {
|
|
804
|
+
return makeShares(spec, seed).map((share) => (0, _bcts_dcbor.toTaggedValue)(_bcts_tags.SSKR_SHARE.value, (0, _bcts_dcbor.toByteString)(share.asBytes()))).map((share) => (0, _bcts_uniform_resources.encodeBytewords)(share.toData(), style)).join("\n");
|
|
805
|
+
}
|
|
806
|
+
function parseEnvelopes(input) {
|
|
807
|
+
try {
|
|
808
|
+
const shareStrings = input.split(/\s+/).filter((s) => s.length > 0);
|
|
809
|
+
const shareEnvelopes = [];
|
|
810
|
+
for (const str of shareStrings) try {
|
|
811
|
+
const envelope = _bcts_envelope.Envelope.fromURString(str);
|
|
812
|
+
shareEnvelopes.push(envelope);
|
|
813
|
+
} catch {}
|
|
814
|
+
if (shareEnvelopes.length === 0) return null;
|
|
815
|
+
const recoveredEnvelope = _bcts_envelope.Envelope.sskrJoin(shareEnvelopes).unwrap();
|
|
816
|
+
return Seed.fromEnvelope(recoveredEnvelope);
|
|
817
|
+
} catch {
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
function fromUntaggedCborShares(untaggedCborShares) {
|
|
822
|
+
try {
|
|
823
|
+
const recoveredSecret = (0, _bcts_components.sskrCombine)(untaggedCborShares);
|
|
824
|
+
return Seed.new(recoveredSecret.getData());
|
|
825
|
+
} catch {
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
function fromTaggedCborShares(taggedCborDataShares) {
|
|
830
|
+
try {
|
|
831
|
+
const untaggedShares = [];
|
|
832
|
+
for (const data of taggedCborDataShares) {
|
|
833
|
+
const cbor = (0, _bcts_dcbor.decodeCbor)(data);
|
|
834
|
+
const tagged = cbor;
|
|
835
|
+
if (tagged.tag !== _bcts_tags.SSKR_SHARE.value && tagged.tag !== _bcts_tags.SSKR_SHARE_V1.value) return null;
|
|
836
|
+
const bytes = (0, _bcts_dcbor.expectBytes)(tagged.value || cbor);
|
|
837
|
+
untaggedShares.push(bytes);
|
|
838
|
+
}
|
|
839
|
+
return fromUntaggedCborShares(untaggedShares);
|
|
840
|
+
} catch {
|
|
841
|
+
return null;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
function parseBytewords(input, style) {
|
|
845
|
+
try {
|
|
846
|
+
let shareStrings;
|
|
847
|
+
if (style === _bcts_uniform_resources.BytewordsStyle.Standard) shareStrings = input.split("\n").filter((s) => s.length > 0);
|
|
848
|
+
else shareStrings = input.split(/\s+/).filter((s) => s.length > 0);
|
|
849
|
+
const cborDataShares = [];
|
|
850
|
+
for (const s of shareStrings) try {
|
|
851
|
+
const decoded = (0, _bcts_uniform_resources.decodeBytewords)(s, style);
|
|
852
|
+
cborDataShares.push(decoded);
|
|
853
|
+
} catch {}
|
|
854
|
+
if (cborDataShares.length === 0) return null;
|
|
855
|
+
return fromTaggedCborShares(cborDataShares);
|
|
856
|
+
} catch {
|
|
857
|
+
return null;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
function parseUr(input, expectedTagValue, allowTaggedCbor) {
|
|
861
|
+
try {
|
|
862
|
+
const expectedType = expectedTagValue === _bcts_tags.SSKR_SHARE.value ? "sskr" : "crypto-sskr";
|
|
863
|
+
const shareStrings = input.split(/\s+/).filter((s) => s.length > 0);
|
|
864
|
+
const urs = [];
|
|
865
|
+
for (const str of shareStrings) try {
|
|
866
|
+
const ur = _bcts_uniform_resources.UR.fromURString(str);
|
|
867
|
+
urs.push(ur);
|
|
868
|
+
} catch {}
|
|
869
|
+
if (urs.length === 0) return null;
|
|
870
|
+
for (const ur of urs) if (ur.type() !== expectedType) return null;
|
|
871
|
+
const untaggedCborShares = [];
|
|
872
|
+
for (const ur of urs) {
|
|
873
|
+
let cbor = ur.cbor();
|
|
874
|
+
if (allowTaggedCbor) try {
|
|
875
|
+
const tagged = (0, _bcts_dcbor.decodeCbor)(cbor.toData());
|
|
876
|
+
if (tagged.tag === _bcts_tags.SSKR_SHARE.value || tagged.tag === _bcts_tags.SSKR_SHARE_V1.value) cbor = tagged.value;
|
|
877
|
+
} catch {}
|
|
878
|
+
const bytes = (0, _bcts_dcbor.expectBytes)(cbor);
|
|
879
|
+
untaggedCborShares.push(bytes);
|
|
880
|
+
}
|
|
881
|
+
return fromUntaggedCborShares(untaggedCborShares);
|
|
882
|
+
} catch {
|
|
883
|
+
return null;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
function parseSskrSeed(input) {
|
|
887
|
+
const envelopeResult = parseEnvelopes(input);
|
|
888
|
+
if (envelopeResult !== null) return envelopeResult;
|
|
889
|
+
const btwResult = parseBytewords(input, _bcts_uniform_resources.BytewordsStyle.Standard);
|
|
890
|
+
if (btwResult !== null) return btwResult;
|
|
891
|
+
const btwmResult = parseBytewords(input, _bcts_uniform_resources.BytewordsStyle.Minimal);
|
|
892
|
+
if (btwmResult !== null) return btwmResult;
|
|
893
|
+
const btwuResult = parseBytewords(input, _bcts_uniform_resources.BytewordsStyle.Uri);
|
|
894
|
+
if (btwuResult !== null) return btwuResult;
|
|
895
|
+
const urResult = parseUr(input, _bcts_tags.SSKR_SHARE.value, false);
|
|
896
|
+
if (urResult !== null) return urResult;
|
|
897
|
+
const urLegacyResult = parseUr(input, _bcts_tags.SSKR_SHARE_V1.value, true);
|
|
898
|
+
if (urLegacyResult !== null) return urLegacyResult;
|
|
899
|
+
throw new Error("Insufficient or invalid SSKR shares.");
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
//#endregion
|
|
903
|
+
//#region src/formats/envelope.ts
|
|
904
|
+
/**
|
|
905
|
+
* Gordian Envelope format handler.
|
|
906
|
+
* Round-trippable: envelope UR → seed → envelope UR.
|
|
907
|
+
*/
|
|
908
|
+
var EnvelopeFormat = class {
|
|
909
|
+
name() {
|
|
910
|
+
return "envelope";
|
|
911
|
+
}
|
|
912
|
+
roundTrippable() {
|
|
913
|
+
return true;
|
|
914
|
+
}
|
|
915
|
+
processInput(state) {
|
|
916
|
+
const input = state.expectInput();
|
|
917
|
+
const envelope = _bcts_envelope.Envelope.fromURString(input);
|
|
918
|
+
state.seed = Seed.fromEnvelope(envelope);
|
|
919
|
+
return state;
|
|
920
|
+
}
|
|
921
|
+
processOutput(state) {
|
|
922
|
+
return state.toEnvelope().urString();
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
//#endregion
|
|
927
|
+
//#region src/formats/seed-format.ts
|
|
928
|
+
/**
|
|
929
|
+
* Seed UR format handler.
|
|
930
|
+
* Round-trippable: seed UR → seed → seed UR.
|
|
931
|
+
* Uses the ur:seed format from bc-components.
|
|
932
|
+
*/
|
|
933
|
+
var SeedFormat = class {
|
|
934
|
+
name() {
|
|
935
|
+
return "seed";
|
|
936
|
+
}
|
|
937
|
+
roundTrippable() {
|
|
938
|
+
return true;
|
|
939
|
+
}
|
|
940
|
+
processInput(state) {
|
|
941
|
+
const input = state.expectInput();
|
|
942
|
+
const componentsSeed = _bcts_components.Seed.fromURString(input);
|
|
943
|
+
state.seed = Seed.fromComponentsSeed(componentsSeed);
|
|
944
|
+
return state;
|
|
945
|
+
}
|
|
946
|
+
processOutput(state) {
|
|
947
|
+
return state.seedWithOverrides().toComponentsSeed().urString();
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
|
|
951
|
+
//#endregion
|
|
952
|
+
//#region src/formats/multipart.ts
|
|
953
|
+
/**
|
|
954
|
+
* Multipart UR format handler.
|
|
955
|
+
* Round-trippable: multipart URs → seed → multipart URs.
|
|
956
|
+
* Uses fountain encoding for reliable transmission.
|
|
957
|
+
*/
|
|
958
|
+
var MultipartFormat = class {
|
|
959
|
+
name() {
|
|
960
|
+
return "multipart";
|
|
961
|
+
}
|
|
962
|
+
roundTrippable() {
|
|
963
|
+
return true;
|
|
964
|
+
}
|
|
965
|
+
processInput(state) {
|
|
966
|
+
const shares = state.expectInput().split(/\s+/).filter((s) => s.length > 0);
|
|
967
|
+
const decoder = new _bcts_uniform_resources.MultipartDecoder();
|
|
968
|
+
for (const share of shares) {
|
|
969
|
+
decoder.receive(share);
|
|
970
|
+
if (decoder.isComplete()) break;
|
|
971
|
+
}
|
|
972
|
+
if (!decoder.isComplete()) throw new Error("Insufficient multipart shares");
|
|
973
|
+
const ur = decoder.message();
|
|
974
|
+
if (ur === void 0) throw new Error("Failed to decode multipart message");
|
|
975
|
+
const envelope = _bcts_envelope.Envelope.fromUR(ur);
|
|
976
|
+
state.seed = Seed.fromEnvelope(envelope);
|
|
977
|
+
return state;
|
|
978
|
+
}
|
|
979
|
+
processOutput(state) {
|
|
980
|
+
const encoder = new _bcts_uniform_resources.MultipartEncoder(state.toEnvelope().ur(), state.maxFragmentLen);
|
|
981
|
+
const partsCount = encoder.partsCount() + state.additionalParts;
|
|
982
|
+
const parts = [];
|
|
983
|
+
for (let i = 0; i < partsCount; i++) parts.push(encoder.nextPart());
|
|
984
|
+
return parts.join("\n");
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
//#endregion
|
|
989
|
+
//#region src/formats/random.ts
|
|
990
|
+
/**
|
|
991
|
+
* Random seed generation format.
|
|
992
|
+
* Input-only: generates a new random seed.
|
|
993
|
+
*/
|
|
994
|
+
var RandomFormat = class {
|
|
995
|
+
name() {
|
|
996
|
+
return "random";
|
|
997
|
+
}
|
|
998
|
+
roundTrippable() {
|
|
999
|
+
return true;
|
|
1000
|
+
}
|
|
1001
|
+
processInput(state) {
|
|
1002
|
+
const data = state.randomData(state.count);
|
|
1003
|
+
state.seed = Seed.new(data);
|
|
1004
|
+
return state;
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
|
|
1008
|
+
//#endregion
|
|
1009
|
+
//#region src/formats/base6.ts
|
|
1010
|
+
/**
|
|
1011
|
+
* Base-6 format handler.
|
|
1012
|
+
* NOT round-trippable: input is entropy source.
|
|
1013
|
+
* Digits 0-5 (compatible with https://iancoleman.io/bip39/).
|
|
1014
|
+
*/
|
|
1015
|
+
var Base6Format = class {
|
|
1016
|
+
name() {
|
|
1017
|
+
return "base6";
|
|
1018
|
+
}
|
|
1019
|
+
roundTrippable() {
|
|
1020
|
+
return false;
|
|
1021
|
+
}
|
|
1022
|
+
processInput(state) {
|
|
1023
|
+
const input = state.expectInput();
|
|
1024
|
+
digitsToData(input, 0, 5);
|
|
1025
|
+
const data = sha256DeterministicRandomString(input, state.count);
|
|
1026
|
+
state.seed = Seed.new(data);
|
|
1027
|
+
return state;
|
|
1028
|
+
}
|
|
1029
|
+
processOutput(state) {
|
|
1030
|
+
return dataToInts(state.expectSeed().data(), 0, 5, "");
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
//#endregion
|
|
1035
|
+
//#region src/formats/base10.ts
|
|
1036
|
+
/**
|
|
1037
|
+
* Base-10 format handler.
|
|
1038
|
+
* NOT round-trippable: input is entropy source.
|
|
1039
|
+
* Digits 0-9 (compatible with https://iancoleman.io/bip39/).
|
|
1040
|
+
*/
|
|
1041
|
+
var Base10Format = class {
|
|
1042
|
+
name() {
|
|
1043
|
+
return "base10";
|
|
1044
|
+
}
|
|
1045
|
+
roundTrippable() {
|
|
1046
|
+
return false;
|
|
1047
|
+
}
|
|
1048
|
+
processInput(state) {
|
|
1049
|
+
const input = state.expectInput();
|
|
1050
|
+
digitsToData(input, 0, 9);
|
|
1051
|
+
const data = sha256DeterministicRandomString(input, state.count);
|
|
1052
|
+
state.seed = Seed.new(data);
|
|
1053
|
+
return state;
|
|
1054
|
+
}
|
|
1055
|
+
processOutput(state) {
|
|
1056
|
+
return dataToInts(state.expectSeed().data(), 0, 9, "");
|
|
1057
|
+
}
|
|
1058
|
+
};
|
|
1059
|
+
|
|
1060
|
+
//#endregion
|
|
1061
|
+
//#region src/formats/bits.ts
|
|
1062
|
+
/**
|
|
1063
|
+
* Binary format handler.
|
|
1064
|
+
* NOT round-trippable: input is entropy source.
|
|
1065
|
+
* Bits 0-1 (compatible with https://iancoleman.io/bip39/).
|
|
1066
|
+
*/
|
|
1067
|
+
var BitsFormat = class {
|
|
1068
|
+
name() {
|
|
1069
|
+
return "bits";
|
|
1070
|
+
}
|
|
1071
|
+
roundTrippable() {
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
processInput(state) {
|
|
1075
|
+
const input = state.expectInput();
|
|
1076
|
+
digitsToData(input, 0, 1);
|
|
1077
|
+
const data = sha256DeterministicRandomString(input, state.count);
|
|
1078
|
+
state.seed = Seed.new(data);
|
|
1079
|
+
return state;
|
|
1080
|
+
}
|
|
1081
|
+
processOutput(state) {
|
|
1082
|
+
return dataToInts(state.expectSeed().data(), 0, 1, "");
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
|
|
1086
|
+
//#endregion
|
|
1087
|
+
//#region src/formats/dice.ts
|
|
1088
|
+
/**
|
|
1089
|
+
* Dice roll format handler.
|
|
1090
|
+
* NOT round-trippable: input is entropy source.
|
|
1091
|
+
* Digits 1-6 (compatible with https://iancoleman.io/bip39/).
|
|
1092
|
+
*/
|
|
1093
|
+
var DiceFormat = class {
|
|
1094
|
+
name() {
|
|
1095
|
+
return "dice";
|
|
1096
|
+
}
|
|
1097
|
+
roundTrippable() {
|
|
1098
|
+
return false;
|
|
1099
|
+
}
|
|
1100
|
+
processInput(state) {
|
|
1101
|
+
const input = state.expectInput();
|
|
1102
|
+
digitsToData(input, 1, 6);
|
|
1103
|
+
const data = sha256DeterministicRandomString(input, state.count);
|
|
1104
|
+
state.seed = Seed.new(data);
|
|
1105
|
+
return state;
|
|
1106
|
+
}
|
|
1107
|
+
processOutput(state) {
|
|
1108
|
+
return dataToInts(state.expectSeed().data(), 1, 6, "");
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
|
|
1112
|
+
//#endregion
|
|
1113
|
+
//#region src/formats/cards.ts
|
|
1114
|
+
const CARD_SUITS = "cdhs";
|
|
1115
|
+
const CARD_RANKS = "a23456789tjqk";
|
|
1116
|
+
/**
|
|
1117
|
+
* Parse a card rank character.
|
|
1118
|
+
* Returns index 0-12.
|
|
1119
|
+
*/
|
|
1120
|
+
function parseRank(c) {
|
|
1121
|
+
const lower = c.toLowerCase();
|
|
1122
|
+
const index = CARD_RANKS.indexOf(lower);
|
|
1123
|
+
if (index === -1) throw new Error(`Invalid card rank: ${c}. Allowed: [A,2-9,T,J,Q,K]`);
|
|
1124
|
+
return index;
|
|
1125
|
+
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Parse a card suit character.
|
|
1128
|
+
* Returns index 0-3.
|
|
1129
|
+
*/
|
|
1130
|
+
function parseSuit(c) {
|
|
1131
|
+
const lower = c.toLowerCase();
|
|
1132
|
+
const index = CARD_SUITS.indexOf(lower);
|
|
1133
|
+
if (index === -1) throw new Error(`Invalid card suit: ${c}. Allowed: [C,D,H,S]`);
|
|
1134
|
+
return index;
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Convert card string to byte array.
|
|
1138
|
+
* Each pair of characters represents one card.
|
|
1139
|
+
*/
|
|
1140
|
+
function cardsToData(cards) {
|
|
1141
|
+
const len = cards.length;
|
|
1142
|
+
if (len % 2 !== 0) throw new Error("Cards string must have even number of characters.");
|
|
1143
|
+
const count = len / 2;
|
|
1144
|
+
const result = new Uint8Array(count);
|
|
1145
|
+
for (let i = 0; i < count; i++) {
|
|
1146
|
+
const rank = parseRank(cards[i * 2]);
|
|
1147
|
+
result[i] = parseSuit(cards[i * 2 + 1]) * 13 + rank;
|
|
1148
|
+
}
|
|
1149
|
+
return result;
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Convert a card index (0-51) to card string.
|
|
1153
|
+
*/
|
|
1154
|
+
function toCard(n) {
|
|
1155
|
+
if (n > 51) throw new Error(`Card index out of range: ${n}`);
|
|
1156
|
+
const rank = n % 13;
|
|
1157
|
+
const suit = Math.floor(n / 13);
|
|
1158
|
+
return CARD_RANKS[rank] + CARD_SUITS[suit];
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* Playing cards format handler.
|
|
1162
|
+
* NOT round-trippable: input is entropy source.
|
|
1163
|
+
* Card notation: rank (A,2-9,T,J,Q,K) + suit (C,D,H,S).
|
|
1164
|
+
*/
|
|
1165
|
+
var CardsFormat = class {
|
|
1166
|
+
name() {
|
|
1167
|
+
return "cards";
|
|
1168
|
+
}
|
|
1169
|
+
roundTrippable() {
|
|
1170
|
+
return false;
|
|
1171
|
+
}
|
|
1172
|
+
processInput(state) {
|
|
1173
|
+
const data = deterministicRandom(cardsToData(state.expectInput()), state.count);
|
|
1174
|
+
state.seed = Seed.new(data);
|
|
1175
|
+
return state;
|
|
1176
|
+
}
|
|
1177
|
+
processOutput(state) {
|
|
1178
|
+
return dataToAlphabet(state.expectSeed().data(), 52, toCard);
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
|
|
1182
|
+
//#endregion
|
|
1183
|
+
//#region src/formats/ints.ts
|
|
1184
|
+
/**
|
|
1185
|
+
* Integer list format handler.
|
|
1186
|
+
* NOT round-trippable: input is entropy source.
|
|
1187
|
+
* Configurable range via --low and --high CLI options.
|
|
1188
|
+
*/
|
|
1189
|
+
var IntsFormat = class {
|
|
1190
|
+
name() {
|
|
1191
|
+
return "ints";
|
|
1192
|
+
}
|
|
1193
|
+
roundTrippable() {
|
|
1194
|
+
return false;
|
|
1195
|
+
}
|
|
1196
|
+
processInput(state) {
|
|
1197
|
+
const data = deterministicRandom(parseInts(state.expectInput()), state.count);
|
|
1198
|
+
state.seed = Seed.new(data);
|
|
1199
|
+
return state;
|
|
1200
|
+
}
|
|
1201
|
+
processOutput(state) {
|
|
1202
|
+
return dataToInts(state.expectSeed().data(), state.low, state.high, " ");
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
|
|
1206
|
+
//#endregion
|
|
1207
|
+
//#region src/formats/bytewords-standard.ts
|
|
1208
|
+
/**
|
|
1209
|
+
* Bytewords Standard format handler.
|
|
1210
|
+
* Round-trippable: bytewords → seed → bytewords.
|
|
1211
|
+
* Uses full words separated by spaces.
|
|
1212
|
+
*/
|
|
1213
|
+
var BytewordsStandardFormat = class {
|
|
1214
|
+
name() {
|
|
1215
|
+
return "btw";
|
|
1216
|
+
}
|
|
1217
|
+
roundTrippable() {
|
|
1218
|
+
return true;
|
|
1219
|
+
}
|
|
1220
|
+
processInput(state) {
|
|
1221
|
+
const data = (0, _bcts_uniform_resources.decodeBytewords)(state.expectInput(), _bcts_uniform_resources.BytewordsStyle.Standard);
|
|
1222
|
+
state.seed = Seed.new(data);
|
|
1223
|
+
return state;
|
|
1224
|
+
}
|
|
1225
|
+
processOutput(state) {
|
|
1226
|
+
return (0, _bcts_uniform_resources.encodeBytewords)(state.expectSeed().data(), _bcts_uniform_resources.BytewordsStyle.Standard);
|
|
1227
|
+
}
|
|
1228
|
+
};
|
|
1229
|
+
|
|
1230
|
+
//#endregion
|
|
1231
|
+
//#region src/formats/bytewords-minimal.ts
|
|
1232
|
+
/**
|
|
1233
|
+
* Bytewords Minimal format handler.
|
|
1234
|
+
* Round-trippable: bytewords → seed → bytewords.
|
|
1235
|
+
* Uses 2-letter abbreviations without separators.
|
|
1236
|
+
*/
|
|
1237
|
+
var BytewordsMinimalFormat = class {
|
|
1238
|
+
name() {
|
|
1239
|
+
return "btwm";
|
|
1240
|
+
}
|
|
1241
|
+
roundTrippable() {
|
|
1242
|
+
return true;
|
|
1243
|
+
}
|
|
1244
|
+
processInput(state) {
|
|
1245
|
+
const data = (0, _bcts_uniform_resources.decodeBytewords)(state.expectInput(), _bcts_uniform_resources.BytewordsStyle.Minimal);
|
|
1246
|
+
state.seed = Seed.new(data);
|
|
1247
|
+
return state;
|
|
1248
|
+
}
|
|
1249
|
+
processOutput(state) {
|
|
1250
|
+
return (0, _bcts_uniform_resources.encodeBytewords)(state.expectSeed().data(), _bcts_uniform_resources.BytewordsStyle.Minimal);
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
1253
|
+
|
|
1254
|
+
//#endregion
|
|
1255
|
+
//#region src/formats/bytewords-uri.ts
|
|
1256
|
+
/**
|
|
1257
|
+
* Bytewords URI format handler.
|
|
1258
|
+
* Round-trippable: bytewords → seed → bytewords.
|
|
1259
|
+
* Uses full words separated by hyphens (URI-safe).
|
|
1260
|
+
*/
|
|
1261
|
+
var BytewordsUriFormat = class {
|
|
1262
|
+
name() {
|
|
1263
|
+
return "btwu";
|
|
1264
|
+
}
|
|
1265
|
+
roundTrippable() {
|
|
1266
|
+
return true;
|
|
1267
|
+
}
|
|
1268
|
+
processInput(state) {
|
|
1269
|
+
const data = (0, _bcts_uniform_resources.decodeBytewords)(state.expectInput(), _bcts_uniform_resources.BytewordsStyle.Uri);
|
|
1270
|
+
state.seed = Seed.new(data);
|
|
1271
|
+
return state;
|
|
1272
|
+
}
|
|
1273
|
+
processOutput(state) {
|
|
1274
|
+
return (0, _bcts_uniform_resources.encodeBytewords)(state.expectSeed().data(), _bcts_uniform_resources.BytewordsStyle.Uri);
|
|
1275
|
+
}
|
|
1276
|
+
};
|
|
1277
|
+
|
|
1278
|
+
//#endregion
|
|
1279
|
+
//#region src/formats/format.ts
|
|
1280
|
+
/**
|
|
1281
|
+
* Select input format by key.
|
|
1282
|
+
* Matches Rust select_input_format function.
|
|
1283
|
+
*/
|
|
1284
|
+
function selectInputFormat(key) {
|
|
1285
|
+
switch (key) {
|
|
1286
|
+
case "random": return new RandomFormat();
|
|
1287
|
+
case "hex": return new HexFormat();
|
|
1288
|
+
case "btw": return new BytewordsStandardFormat();
|
|
1289
|
+
case "btwu": return new BytewordsUriFormat();
|
|
1290
|
+
case "btwm": return new BytewordsMinimalFormat();
|
|
1291
|
+
case "bits": return new BitsFormat();
|
|
1292
|
+
case "cards": return new CardsFormat();
|
|
1293
|
+
case "dice": return new DiceFormat();
|
|
1294
|
+
case "base6": return new Base6Format();
|
|
1295
|
+
case "base10": return new Base10Format();
|
|
1296
|
+
case "ints": return new IntsFormat();
|
|
1297
|
+
case "bip39": return new Bip39Format();
|
|
1298
|
+
case "sskr": return new SSKRFormat();
|
|
1299
|
+
case "envelope": return new EnvelopeFormat();
|
|
1300
|
+
case "multipart": return new MultipartFormat();
|
|
1301
|
+
case "seed": return new SeedFormat();
|
|
1302
|
+
default: throw new Error(`Unknown input format: ${key}`);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* Select output format by key.
|
|
1307
|
+
* Matches Rust select_output_format function.
|
|
1308
|
+
*/
|
|
1309
|
+
function selectOutputFormat(key) {
|
|
1310
|
+
switch (key) {
|
|
1311
|
+
case "hex": return new HexFormat();
|
|
1312
|
+
case "btw": return new BytewordsStandardFormat();
|
|
1313
|
+
case "btwu": return new BytewordsUriFormat();
|
|
1314
|
+
case "btwm": return new BytewordsMinimalFormat();
|
|
1315
|
+
case "bits": return new BitsFormat();
|
|
1316
|
+
case "cards": return new CardsFormat();
|
|
1317
|
+
case "dice": return new DiceFormat();
|
|
1318
|
+
case "base6": return new Base6Format();
|
|
1319
|
+
case "base10": return new Base10Format();
|
|
1320
|
+
case "ints": return new IntsFormat();
|
|
1321
|
+
case "bip39": return new Bip39Format();
|
|
1322
|
+
case "sskr": return new SSKRFormat();
|
|
1323
|
+
case "envelope": return new EnvelopeFormat();
|
|
1324
|
+
case "multipart": return new MultipartFormat();
|
|
1325
|
+
case "seed": return new SeedFormat();
|
|
1326
|
+
default: throw new Error(`Unknown output format: ${key}`);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
//#endregion
|
|
1331
|
+
exports.Base10Format = Base10Format;
|
|
1332
|
+
exports.Base6Format = Base6Format;
|
|
1333
|
+
exports.Bip39Format = Bip39Format;
|
|
1334
|
+
exports.BitsFormat = BitsFormat;
|
|
1335
|
+
exports.BytewordsMinimalFormat = BytewordsMinimalFormat;
|
|
1336
|
+
exports.BytewordsStandardFormat = BytewordsStandardFormat;
|
|
1337
|
+
exports.BytewordsUriFormat = BytewordsUriFormat;
|
|
1338
|
+
exports.CardsFormat = CardsFormat;
|
|
1339
|
+
exports.Cli = Cli;
|
|
1340
|
+
exports.DeterministicRandomNumberGenerator = DeterministicRandomNumberGenerator;
|
|
1341
|
+
exports.DiceFormat = DiceFormat;
|
|
1342
|
+
exports.EnvelopeFormat = EnvelopeFormat;
|
|
1343
|
+
exports.HexFormat = HexFormat;
|
|
1344
|
+
exports.InputFormatKey = InputFormatKey;
|
|
1345
|
+
exports.IntsFormat = IntsFormat;
|
|
1346
|
+
exports.MultipartFormat = MultipartFormat;
|
|
1347
|
+
exports.OutputFormatKey = OutputFormatKey;
|
|
1348
|
+
exports.RandomFormat = RandomFormat;
|
|
1349
|
+
exports.SSKRFormat = SSKRFormat;
|
|
1350
|
+
exports.SSKRFormatKey = SSKRFormatKey;
|
|
1351
|
+
exports.Seed = Seed;
|
|
1352
|
+
exports.SeedFormat = SeedFormat;
|
|
1353
|
+
exports.dataToAlphabet = dataToAlphabet;
|
|
1354
|
+
exports.dataToBase = dataToBase;
|
|
1355
|
+
exports.dataToHex = dataToHex;
|
|
1356
|
+
exports.dataToInts = dataToInts;
|
|
1357
|
+
exports.deterministicRandom = deterministicRandom;
|
|
1358
|
+
exports.digitsToData = digitsToData;
|
|
1359
|
+
exports.hexToData = hexToData;
|
|
1360
|
+
exports.hkdfHmacSha256 = hkdfHmacSha256;
|
|
1361
|
+
exports.parseDate = parseDate;
|
|
1362
|
+
exports.parseGroupSpec = parseGroupSpec;
|
|
1363
|
+
exports.parseGroupThreshold = parseGroupThreshold;
|
|
1364
|
+
exports.parseHighInt = parseHighInt;
|
|
1365
|
+
exports.parseInts = parseInts;
|
|
1366
|
+
exports.parseLowInt = parseLowInt;
|
|
1367
|
+
exports.selectInputFormat = selectInputFormat;
|
|
1368
|
+
exports.selectOutputFormat = selectOutputFormat;
|
|
1369
|
+
exports.sha256DeterministicRandom = sha256DeterministicRandom;
|
|
1370
|
+
//# sourceMappingURL=index.cjs.map
|