@digitaldefiance/secrets 2.0.3
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 +8 -0
- package/README.md +445 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/browser-types.d.ts +112 -0
- package/dist/browser-types.d.ts.map +1 -0
- package/dist/browser-types.js +242 -0
- package/dist/browser-types.js.map +1 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +92 -0
- package/dist/errors.js.map +1 -0
- package/dist/esm/.tsbuildinfo +1 -0
- package/dist/esm/browser-types.d.ts +112 -0
- package/dist/esm/browser-types.d.ts.map +1 -0
- package/dist/esm/browser-types.js +201 -0
- package/dist/esm/browser-types.js.map +1 -0
- package/dist/esm/errors.d.ts +33 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +54 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/node-types.d.ts +87 -0
- package/dist/esm/node-types.d.ts.map +1 -0
- package/dist/esm/node-types.js +157 -0
- package/dist/esm/node-types.js.map +1 -0
- package/dist/esm/secrets.d.ts +262 -0
- package/dist/esm/secrets.d.ts.map +1 -0
- package/dist/esm/secrets.js +894 -0
- package/dist/esm/secrets.js.map +1 -0
- package/dist/esm/types.d.ts +249 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +61 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/validation.d.ts +34 -0
- package/dist/esm/validation.d.ts.map +1 -0
- package/dist/esm/validation.js +72 -0
- package/dist/esm/validation.js.map +1 -0
- package/dist/node-types.d.ts +87 -0
- package/dist/node-types.d.ts.map +1 -0
- package/dist/node-types.js +191 -0
- package/dist/node-types.js.map +1 -0
- package/dist/secrets.d.ts +262 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +897 -0
- package/dist/secrets.js.map +1 -0
- package/dist/types.d.ts +249 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +67 -0
- package/dist/types.js.map +1 -0
- package/dist/umd/.tsbuildinfo +1 -0
- package/dist/umd/browser-types.d.ts +112 -0
- package/dist/umd/browser-types.d.ts.map +1 -0
- package/dist/umd/browser-types.js +252 -0
- package/dist/umd/browser-types.js.map +1 -0
- package/dist/umd/errors.d.ts +33 -0
- package/dist/umd/errors.d.ts.map +1 -0
- package/dist/umd/errors.js +102 -0
- package/dist/umd/errors.js.map +1 -0
- package/dist/umd/node-types.d.ts +87 -0
- package/dist/umd/node-types.d.ts.map +1 -0
- package/dist/umd/node-types.js +201 -0
- package/dist/umd/node-types.js.map +1 -0
- package/dist/umd/secrets.d.ts +262 -0
- package/dist/umd/secrets.d.ts.map +1 -0
- package/dist/umd/secrets.js +907 -0
- package/dist/umd/secrets.js.map +1 -0
- package/dist/umd/secrets.min.js +2 -0
- package/dist/umd/types.d.ts +249 -0
- package/dist/umd/types.d.ts.map +1 -0
- package/dist/umd/types.js +77 -0
- package/dist/umd/types.js.map +1 -0
- package/dist/umd/validation.d.ts +34 -0
- package/dist/umd/validation.d.ts.map +1 -0
- package/dist/umd/validation.js +92 -0
- package/dist/umd/validation.js.map +1 -0
- package/dist/validation.d.ts +34 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +82 -0
- package/dist/validation.js.map +1 -0
- package/package.json +181 -0
|
@@ -0,0 +1,907 @@
|
|
|
1
|
+
// @preserve author Alexander Stetsyuk
|
|
2
|
+
// @preserve author Glenn Rempe <glenn@rempe.us>
|
|
3
|
+
// @license MIT
|
|
4
|
+
(function (factory) {
|
|
5
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
6
|
+
var v = factory(require, exports);
|
|
7
|
+
if (v !== undefined) module.exports = v;
|
|
8
|
+
}
|
|
9
|
+
else if (typeof define === "function" && define.amd) {
|
|
10
|
+
define(["require", "exports"], factory);
|
|
11
|
+
}
|
|
12
|
+
})(function (require, exports) {
|
|
13
|
+
"use strict";
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.newShare = exports.share = exports.random = exports.hex2str = exports.str2hex = exports.setRNG = exports.extractShareComponents = exports.getConfig = exports.combine = exports.init = void 0;
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Module State
|
|
18
|
+
// ============================================================================
|
|
19
|
+
var defaults;
|
|
20
|
+
var config;
|
|
21
|
+
var preGenPadding;
|
|
22
|
+
var runCSPRNGTest;
|
|
23
|
+
var CSPRNGTypes;
|
|
24
|
+
var byteToHex;
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Initialization and Reset
|
|
27
|
+
// ============================================================================
|
|
28
|
+
function reset() {
|
|
29
|
+
defaults = {
|
|
30
|
+
bits: 8,
|
|
31
|
+
radix: 16,
|
|
32
|
+
minBits: 3,
|
|
33
|
+
maxBits: 20,
|
|
34
|
+
bytesPerChar: 2,
|
|
35
|
+
maxBytesPerChar: 6,
|
|
36
|
+
primitivePolynomials: [
|
|
37
|
+
null, null, 1, 3, 3, 5, 3, 3, 29, 17, 9, 5, 83, 27, 43, 3,
|
|
38
|
+
45, 9, 39, 39, 9, 5, 3, 33, 27, 9, 71, 39, 9, 5, 83
|
|
39
|
+
]
|
|
40
|
+
};
|
|
41
|
+
config = {};
|
|
42
|
+
preGenPadding = new Array(1024).join("0");
|
|
43
|
+
runCSPRNGTest = true;
|
|
44
|
+
byteToHex = [];
|
|
45
|
+
for (var i = 0; i <= 0xff; i++) {
|
|
46
|
+
var hexOctet = i.toString(16);
|
|
47
|
+
if (hexOctet.length === 1) {
|
|
48
|
+
hexOctet = "0" + hexOctet;
|
|
49
|
+
}
|
|
50
|
+
byteToHex.push(hexOctet);
|
|
51
|
+
}
|
|
52
|
+
CSPRNGTypes = [
|
|
53
|
+
"nodeCryptoRandomBytes",
|
|
54
|
+
"browserCryptoGetRandomValues",
|
|
55
|
+
"testRandom"
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
function isSetRNG() {
|
|
59
|
+
if (config && config.rng && typeof config.rng === "function") {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// Utility Functions
|
|
66
|
+
// ============================================================================
|
|
67
|
+
function padLeft(str, multipleOfBits) {
|
|
68
|
+
var missing;
|
|
69
|
+
if (multipleOfBits === 0 || multipleOfBits === 1) {
|
|
70
|
+
return str;
|
|
71
|
+
}
|
|
72
|
+
if (multipleOfBits && multipleOfBits > 1024) {
|
|
73
|
+
throw new Error("Padding must be multiples of no larger than 1024 bits.");
|
|
74
|
+
}
|
|
75
|
+
var bits = multipleOfBits || config.bits;
|
|
76
|
+
if (str) {
|
|
77
|
+
missing = str.length % bits;
|
|
78
|
+
}
|
|
79
|
+
if (missing) {
|
|
80
|
+
return (preGenPadding + str).slice(-(bits - missing + str.length));
|
|
81
|
+
}
|
|
82
|
+
return str;
|
|
83
|
+
}
|
|
84
|
+
function hex2bin(str) {
|
|
85
|
+
var bin = "";
|
|
86
|
+
var num;
|
|
87
|
+
for (var i = str.length - 1; i >= 0; i--) {
|
|
88
|
+
num = parseInt(str[i], 16);
|
|
89
|
+
if (isNaN(num)) {
|
|
90
|
+
throw new Error("Invalid hex character.");
|
|
91
|
+
}
|
|
92
|
+
bin = padLeft(num.toString(2), 4) + bin;
|
|
93
|
+
}
|
|
94
|
+
return bin;
|
|
95
|
+
}
|
|
96
|
+
function bin2hex(str) {
|
|
97
|
+
var hex = "";
|
|
98
|
+
var num;
|
|
99
|
+
str = padLeft(str, 4);
|
|
100
|
+
for (var i = str.length; i >= 4; i -= 4) {
|
|
101
|
+
num = parseInt(str.slice(i - 4, i), 2);
|
|
102
|
+
if (isNaN(num)) {
|
|
103
|
+
throw new Error("Invalid binary character.");
|
|
104
|
+
}
|
|
105
|
+
hex = num.toString(16) + hex;
|
|
106
|
+
}
|
|
107
|
+
return hex;
|
|
108
|
+
}
|
|
109
|
+
function bytesToHex(bytes) {
|
|
110
|
+
var hex = "";
|
|
111
|
+
for (var i = 0; i < bytes.length; i++) {
|
|
112
|
+
hex += byteToHex[bytes[i]];
|
|
113
|
+
}
|
|
114
|
+
return hex;
|
|
115
|
+
}
|
|
116
|
+
// ============================================================================
|
|
117
|
+
// Crypto Environment Detection
|
|
118
|
+
// ============================================================================
|
|
119
|
+
function hasCryptoGetRandomValues() {
|
|
120
|
+
var crypto = (typeof window !== 'undefined' && window.crypto) || global.crypto;
|
|
121
|
+
if (crypto &&
|
|
122
|
+
typeof crypto === "object" &&
|
|
123
|
+
(typeof crypto.getRandomValues === "function" ||
|
|
124
|
+
typeof crypto.getRandomValues === "object") &&
|
|
125
|
+
(typeof Uint32Array === "function" || typeof Uint32Array === "object")) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
function hasCryptoRandomBytes() {
|
|
131
|
+
var crypto;
|
|
132
|
+
try {
|
|
133
|
+
crypto = require("crypto");
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
if (typeof crypto === "object" && typeof crypto.randomBytes === "function") {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
function getRNG(type) {
|
|
144
|
+
function construct(bits, arr, radix, size) {
|
|
145
|
+
var i = 0;
|
|
146
|
+
var len;
|
|
147
|
+
var str = "";
|
|
148
|
+
var parsedInt;
|
|
149
|
+
if (arr) {
|
|
150
|
+
len = arr.length - 1;
|
|
151
|
+
}
|
|
152
|
+
while (i < len || str.length < bits) {
|
|
153
|
+
parsedInt = Math.abs(parseInt(arr[i], radix));
|
|
154
|
+
str = str + padLeft(parsedInt.toString(2), size);
|
|
155
|
+
i++;
|
|
156
|
+
}
|
|
157
|
+
str = str.substr(-bits);
|
|
158
|
+
if ((str.match(/0/g) || []).length === str.length) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
return str;
|
|
162
|
+
}
|
|
163
|
+
function nodeCryptoRandomBytes(bits) {
|
|
164
|
+
var buf;
|
|
165
|
+
var bytes;
|
|
166
|
+
var radix = 16;
|
|
167
|
+
var size = 4;
|
|
168
|
+
var str = null;
|
|
169
|
+
bytes = Math.ceil(bits / 8);
|
|
170
|
+
var crypto = require("crypto");
|
|
171
|
+
while (str === null) {
|
|
172
|
+
buf = crypto.randomBytes(bytes);
|
|
173
|
+
str = construct(bits, bytesToHex(buf), radix, size);
|
|
174
|
+
}
|
|
175
|
+
return str;
|
|
176
|
+
}
|
|
177
|
+
function browserCryptoGetRandomValues(bits) {
|
|
178
|
+
var elems;
|
|
179
|
+
var radix = 10;
|
|
180
|
+
var size = 32;
|
|
181
|
+
var str = null;
|
|
182
|
+
elems = Math.ceil(bits / 32);
|
|
183
|
+
var crypto = (typeof window !== 'undefined' && window.crypto) || global.crypto;
|
|
184
|
+
while (str === null) {
|
|
185
|
+
str = construct(bits, crypto.getRandomValues(new Uint32Array(elems)), radix, size);
|
|
186
|
+
}
|
|
187
|
+
return str;
|
|
188
|
+
}
|
|
189
|
+
function testRandom(bits) {
|
|
190
|
+
var arr;
|
|
191
|
+
var elems;
|
|
192
|
+
var int = 123456789;
|
|
193
|
+
var radix = 10;
|
|
194
|
+
var size = 32;
|
|
195
|
+
var str = null;
|
|
196
|
+
elems = Math.ceil(bits / 32);
|
|
197
|
+
arr = new Uint32Array(elems);
|
|
198
|
+
for (var i = 0; i < arr.length; i++) {
|
|
199
|
+
arr[i] = int;
|
|
200
|
+
}
|
|
201
|
+
while (str === null) {
|
|
202
|
+
str = construct(bits, arr, radix, size);
|
|
203
|
+
}
|
|
204
|
+
return str;
|
|
205
|
+
}
|
|
206
|
+
if (type && type === "testRandom") {
|
|
207
|
+
config.typeCSPRNG = type;
|
|
208
|
+
return testRandom;
|
|
209
|
+
}
|
|
210
|
+
else if (type && type === "nodeCryptoRandomBytes") {
|
|
211
|
+
config.typeCSPRNG = type;
|
|
212
|
+
return nodeCryptoRandomBytes;
|
|
213
|
+
}
|
|
214
|
+
else if (type && type === "browserCryptoGetRandomValues") {
|
|
215
|
+
config.typeCSPRNG = type;
|
|
216
|
+
return browserCryptoGetRandomValues;
|
|
217
|
+
}
|
|
218
|
+
else if (hasCryptoRandomBytes()) {
|
|
219
|
+
config.typeCSPRNG = "nodeCryptoRandomBytes";
|
|
220
|
+
return nodeCryptoRandomBytes;
|
|
221
|
+
}
|
|
222
|
+
else if (hasCryptoGetRandomValues()) {
|
|
223
|
+
config.typeCSPRNG = "browserCryptoGetRandomValues";
|
|
224
|
+
return browserCryptoGetRandomValues;
|
|
225
|
+
}
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
// ============================================================================
|
|
229
|
+
// Core Algorithm Functions
|
|
230
|
+
// ============================================================================
|
|
231
|
+
function splitNumStringToIntArray(str, padLength) {
|
|
232
|
+
var parts = [];
|
|
233
|
+
if (padLength) {
|
|
234
|
+
str = padLeft(str, padLength);
|
|
235
|
+
}
|
|
236
|
+
var i;
|
|
237
|
+
for (i = str.length; i > config.bits; i -= config.bits) {
|
|
238
|
+
parts.push(parseInt(str.slice(i - config.bits, i), 2));
|
|
239
|
+
}
|
|
240
|
+
parts.push(parseInt(str.slice(0, i), 2));
|
|
241
|
+
return parts;
|
|
242
|
+
}
|
|
243
|
+
function horner(x, coeffs) {
|
|
244
|
+
var logx = config.logs[x];
|
|
245
|
+
var fx = 0;
|
|
246
|
+
for (var i = coeffs.length - 1; i >= 0; i--) {
|
|
247
|
+
if (fx !== 0) {
|
|
248
|
+
fx = config.exps[(logx + config.logs[fx]) % config.maxShares] ^ coeffs[i];
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
fx = coeffs[i];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return fx;
|
|
255
|
+
}
|
|
256
|
+
function lagrange(at, x, y) {
|
|
257
|
+
var sum = 0;
|
|
258
|
+
var len = x.length;
|
|
259
|
+
var product;
|
|
260
|
+
for (var i = 0; i < len; i++) {
|
|
261
|
+
if (y[i]) {
|
|
262
|
+
product = config.logs[y[i]];
|
|
263
|
+
for (var j = 0; j < len; j++) {
|
|
264
|
+
if (i !== j) {
|
|
265
|
+
if (at === x[j]) {
|
|
266
|
+
product = -1;
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
product =
|
|
270
|
+
(product +
|
|
271
|
+
config.logs[at ^ x[j]] -
|
|
272
|
+
config.logs[x[i] ^ x[j]] +
|
|
273
|
+
config.maxShares) %
|
|
274
|
+
config.maxShares;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
sum = product === -1 ? sum : sum ^ config.exps[product];
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return sum;
|
|
281
|
+
}
|
|
282
|
+
function getShares(secret, numShares, threshold) {
|
|
283
|
+
var shares = [];
|
|
284
|
+
var coeffs = [secret];
|
|
285
|
+
for (var i = 1; i < threshold; i++) {
|
|
286
|
+
coeffs[i] = parseInt(config.rng(config.bits), 2);
|
|
287
|
+
}
|
|
288
|
+
for (var i = 1, len = numShares + 1; i < len; i++) {
|
|
289
|
+
shares[i - 1] = {
|
|
290
|
+
x: i,
|
|
291
|
+
y: horner(i, coeffs)
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
return shares;
|
|
295
|
+
}
|
|
296
|
+
function constructPublicShareString(bits, id, data) {
|
|
297
|
+
var bitsNum = typeof bits === 'string' ? parseInt(bits, 10) : bits;
|
|
298
|
+
var bitsBase36 = bitsNum.toString(36).toUpperCase();
|
|
299
|
+
var idMax = Math.pow(2, bitsNum) - 1;
|
|
300
|
+
var numericId;
|
|
301
|
+
if (typeof id === "number") {
|
|
302
|
+
numericId = id;
|
|
303
|
+
}
|
|
304
|
+
else if (typeof id === "string") {
|
|
305
|
+
numericId = parseInt(id, 10);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
numericId = NaN;
|
|
309
|
+
}
|
|
310
|
+
if (typeof numericId !== "number" ||
|
|
311
|
+
numericId % 1 !== 0 ||
|
|
312
|
+
numericId < 1 ||
|
|
313
|
+
numericId > idMax ||
|
|
314
|
+
isNaN(numericId)) {
|
|
315
|
+
throw new Error("Share id must be an integer between 1 and " + idMax + ", inclusive.");
|
|
316
|
+
}
|
|
317
|
+
var idPaddingLen = idMax.toString(config.radix).length;
|
|
318
|
+
var idHex = padLeft(numericId.toString(config.radix), idPaddingLen);
|
|
319
|
+
var newShareString = bitsBase36 + idHex + data;
|
|
320
|
+
return newShareString;
|
|
321
|
+
}
|
|
322
|
+
// ============================================================================
|
|
323
|
+
// Public API
|
|
324
|
+
// ============================================================================
|
|
325
|
+
var SecretsLibrary = {
|
|
326
|
+
/**
|
|
327
|
+
* Initialize the secrets library with specified bit length and RNG type.
|
|
328
|
+
*
|
|
329
|
+
* This function sets up the Galois Field arithmetic tables (logs and exps)
|
|
330
|
+
* required for Shamir's Secret Sharing. It must be called before using
|
|
331
|
+
* share() or combine() operations.
|
|
332
|
+
*
|
|
333
|
+
* @param bits - Number of bits for the Galois Field (between 3 and 20, default 8).
|
|
334
|
+
* Determines the maximum number of shares (2^bits - 1).
|
|
335
|
+
* @param rngType - Type of cryptographically secure random number generator to use.
|
|
336
|
+
* If not specified, automatically detects the best available CSPRNG.
|
|
337
|
+
* @throws {Error} If bits is not an integer between 3 and 20, inclusive.
|
|
338
|
+
* @throws {Error} If rngType is invalid or RNG initialization fails.
|
|
339
|
+
* @throws {Error} If initialization fails for any reason.
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* ```typescript
|
|
343
|
+
* // Initialize with default 8 bits (max 255 shares)
|
|
344
|
+
* secrets.init();
|
|
345
|
+
*
|
|
346
|
+
* // Initialize with 10 bits (max 1023 shares)
|
|
347
|
+
* secrets.init(10);
|
|
348
|
+
*
|
|
349
|
+
* // Initialize with specific RNG type
|
|
350
|
+
* secrets.init(8, 'nodeCryptoRandomBytes');
|
|
351
|
+
* ```
|
|
352
|
+
*/
|
|
353
|
+
init: function (bits, rngType) {
|
|
354
|
+
var logs = [];
|
|
355
|
+
var exps = [];
|
|
356
|
+
var x = 1;
|
|
357
|
+
var primitive;
|
|
358
|
+
reset();
|
|
359
|
+
if (bits &&
|
|
360
|
+
(typeof bits !== "number" ||
|
|
361
|
+
bits % 1 !== 0 ||
|
|
362
|
+
bits < defaults.minBits ||
|
|
363
|
+
bits > defaults.maxBits)) {
|
|
364
|
+
throw new Error("Number of bits must be an integer between " +
|
|
365
|
+
defaults.minBits +
|
|
366
|
+
" and " +
|
|
367
|
+
defaults.maxBits +
|
|
368
|
+
", inclusive.");
|
|
369
|
+
}
|
|
370
|
+
if (rngType && CSPRNGTypes.indexOf(rngType) === -1) {
|
|
371
|
+
throw new Error("Invalid RNG type argument : '" + rngType + "'");
|
|
372
|
+
}
|
|
373
|
+
config.radix = defaults.radix;
|
|
374
|
+
config.bits = bits || defaults.bits;
|
|
375
|
+
config.size = Math.pow(2, config.bits);
|
|
376
|
+
config.maxShares = config.size - 1;
|
|
377
|
+
primitive = defaults.primitivePolynomials[config.bits];
|
|
378
|
+
for (var i = 0; i < config.size; i++) {
|
|
379
|
+
exps[i] = x;
|
|
380
|
+
logs[x] = i;
|
|
381
|
+
x = x << 1;
|
|
382
|
+
if (x >= config.size) {
|
|
383
|
+
x = x ^ primitive;
|
|
384
|
+
x = x & config.maxShares;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
config.logs = logs;
|
|
388
|
+
config.exps = exps;
|
|
389
|
+
if (rngType) {
|
|
390
|
+
this.setRNG(rngType);
|
|
391
|
+
}
|
|
392
|
+
if (!isSetRNG()) {
|
|
393
|
+
this.setRNG();
|
|
394
|
+
}
|
|
395
|
+
if (!isSetRNG() ||
|
|
396
|
+
!config.bits ||
|
|
397
|
+
!config.size ||
|
|
398
|
+
!config.maxShares ||
|
|
399
|
+
!config.logs ||
|
|
400
|
+
!config.exps ||
|
|
401
|
+
config.logs.length !== config.size ||
|
|
402
|
+
config.exps.length !== config.size) {
|
|
403
|
+
throw new Error("Initialization failed.");
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
/**
|
|
407
|
+
* Combine shares to reconstruct the original secret.
|
|
408
|
+
*
|
|
409
|
+
* Uses Lagrange interpolation to reconstruct the secret from a threshold
|
|
410
|
+
* number of shares. The shares must have been created with the same bit
|
|
411
|
+
* configuration.
|
|
412
|
+
*
|
|
413
|
+
* @param shares - Array of share strings to combine. Must contain at least
|
|
414
|
+
* the threshold number of shares used during secret creation.
|
|
415
|
+
* @param at - Point at which to evaluate the polynomial (default 0 for secret recovery).
|
|
416
|
+
* Use non-zero values to generate new shares.
|
|
417
|
+
* @returns The reconstructed secret as a hexadecimal string.
|
|
418
|
+
* @throws {Error} If shares have mismatched bit settings.
|
|
419
|
+
* @throws {Error} If share format is invalid.
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```typescript
|
|
423
|
+
* const shares = secrets.share('deadbeef', 5, 3);
|
|
424
|
+
* const secret = secrets.combine(shares.slice(0, 3));
|
|
425
|
+
* console.log(secret); // 'deadbeef'
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
combine: function (shares, at) {
|
|
429
|
+
var setBits;
|
|
430
|
+
var share;
|
|
431
|
+
var splitShare;
|
|
432
|
+
var x = [];
|
|
433
|
+
var y = [];
|
|
434
|
+
var result = "";
|
|
435
|
+
at = at || 0;
|
|
436
|
+
for (var i = 0, len = shares.length; i < len; i++) {
|
|
437
|
+
share = this.extractShareComponents(shares[i]);
|
|
438
|
+
if (setBits === undefined) {
|
|
439
|
+
setBits = share.bits;
|
|
440
|
+
}
|
|
441
|
+
else if (share.bits !== setBits) {
|
|
442
|
+
throw new Error("Mismatched shares: Different bit settings.");
|
|
443
|
+
}
|
|
444
|
+
if (config.bits !== setBits) {
|
|
445
|
+
this.init(setBits);
|
|
446
|
+
}
|
|
447
|
+
if (x.indexOf(share.id) === -1) {
|
|
448
|
+
x.push(share.id);
|
|
449
|
+
splitShare = splitNumStringToIntArray(hex2bin(share.data));
|
|
450
|
+
for (var j = 0, len2 = splitShare.length; j < len2; j++) {
|
|
451
|
+
y[j] = y[j] || [];
|
|
452
|
+
y[j][x.length - 1] = splitShare[j];
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
for (var i = 0, len = y.length; i < len; i++) {
|
|
457
|
+
result = padLeft(lagrange(at, x, y[i]).toString(2)) + result;
|
|
458
|
+
}
|
|
459
|
+
return bin2hex(at >= 1 ? result : result.slice(result.indexOf("1") + 1));
|
|
460
|
+
},
|
|
461
|
+
/**
|
|
462
|
+
* Get the current configuration of the secrets library.
|
|
463
|
+
*
|
|
464
|
+
* Returns information about the current Galois Field configuration,
|
|
465
|
+
* including bit length, radix, maximum shares, and RNG status.
|
|
466
|
+
*
|
|
467
|
+
* @returns Configuration object with current settings.
|
|
468
|
+
*
|
|
469
|
+
* @example
|
|
470
|
+
* ```typescript
|
|
471
|
+
* const config = secrets.getConfig();
|
|
472
|
+
* console.log(`Max shares: ${config.maxShares}`);
|
|
473
|
+
* console.log(`Has CSPRNG: ${config.hasCSPRNG}`);
|
|
474
|
+
* console.log(`RNG Type: ${config.typeCSPRNG}`);
|
|
475
|
+
* ```
|
|
476
|
+
*/
|
|
477
|
+
getConfig: function () {
|
|
478
|
+
var obj = {
|
|
479
|
+
radix: config.radix,
|
|
480
|
+
bits: config.bits,
|
|
481
|
+
maxShares: config.maxShares,
|
|
482
|
+
hasCSPRNG: isSetRNG(),
|
|
483
|
+
typeCSPRNG: config.typeCSPRNG
|
|
484
|
+
};
|
|
485
|
+
return obj;
|
|
486
|
+
},
|
|
487
|
+
/**
|
|
488
|
+
* Extract the components from a public share string.
|
|
489
|
+
*
|
|
490
|
+
* Parses a share string to extract the bit configuration, share ID,
|
|
491
|
+
* and share data. Useful for inspecting shares or validating share format.
|
|
492
|
+
*
|
|
493
|
+
* @param share - The share string to parse.
|
|
494
|
+
* @returns Object containing bits, id, and data components.
|
|
495
|
+
* @throws {Error} If share format is invalid.
|
|
496
|
+
* @throws {Error} If share ID is out of valid range.
|
|
497
|
+
*
|
|
498
|
+
* @example
|
|
499
|
+
* ```typescript
|
|
500
|
+
* const shares = secrets.share('abc123', 5, 3);
|
|
501
|
+
* const components = secrets.extractShareComponents(shares[0]);
|
|
502
|
+
* console.log(`Bits: ${components.bits}`);
|
|
503
|
+
* console.log(`ID: ${components.id}`);
|
|
504
|
+
* console.log(`Data: ${components.data}`);
|
|
505
|
+
* ```
|
|
506
|
+
*/
|
|
507
|
+
extractShareComponents: function (share) {
|
|
508
|
+
var bits;
|
|
509
|
+
var id;
|
|
510
|
+
var idLen;
|
|
511
|
+
var max;
|
|
512
|
+
var regexStr;
|
|
513
|
+
var shareComponents;
|
|
514
|
+
bits = parseInt(share.substr(0, 1), 36);
|
|
515
|
+
if (bits &&
|
|
516
|
+
(typeof bits !== "number" ||
|
|
517
|
+
bits % 1 !== 0 ||
|
|
518
|
+
bits < defaults.minBits ||
|
|
519
|
+
bits > defaults.maxBits)) {
|
|
520
|
+
throw new Error("Invalid share : Number of bits must be an integer between " +
|
|
521
|
+
defaults.minBits +
|
|
522
|
+
" and " +
|
|
523
|
+
defaults.maxBits +
|
|
524
|
+
", inclusive.");
|
|
525
|
+
}
|
|
526
|
+
max = Math.pow(2, bits) - 1;
|
|
527
|
+
idLen = (Math.pow(2, bits) - 1).toString(config.radix).length;
|
|
528
|
+
regexStr = "^([a-kA-K3-9]{1})([a-fA-F0-9]{" + idLen + "})([a-fA-F0-9]+)$";
|
|
529
|
+
shareComponents = new RegExp(regexStr).exec(share);
|
|
530
|
+
if (shareComponents) {
|
|
531
|
+
id = parseInt(shareComponents[2], config.radix);
|
|
532
|
+
}
|
|
533
|
+
if (typeof id !== "number" || id % 1 !== 0 || id < 1 || id > max) {
|
|
534
|
+
throw new Error("Invalid share : Share id must be an integer between 1 and " +
|
|
535
|
+
config.maxShares +
|
|
536
|
+
", inclusive.");
|
|
537
|
+
}
|
|
538
|
+
if (shareComponents && shareComponents[3]) {
|
|
539
|
+
return {
|
|
540
|
+
bits: bits,
|
|
541
|
+
id: id,
|
|
542
|
+
data: shareComponents[3]
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
throw new Error("The share data provided is invalid : " + share);
|
|
546
|
+
},
|
|
547
|
+
/**
|
|
548
|
+
* Set the random number generator to use for share generation.
|
|
549
|
+
*
|
|
550
|
+
* Allows specifying a custom RNG or selecting a specific CSPRNG type.
|
|
551
|
+
* If no argument is provided, automatically detects and uses the best
|
|
552
|
+
* available CSPRNG for the current environment.
|
|
553
|
+
*
|
|
554
|
+
* @param rng - Either a CSPRNG type string or a custom RNG function.
|
|
555
|
+
* Custom functions must return a binary string of specified length.
|
|
556
|
+
* @returns True if RNG was successfully set.
|
|
557
|
+
* @throws {Error} If RNG type is invalid.
|
|
558
|
+
* @throws {Error} If custom RNG function fails validation tests.
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* ```typescript
|
|
562
|
+
* // Use specific CSPRNG type
|
|
563
|
+
* secrets.setRNG('nodeCryptoRandomBytes');
|
|
564
|
+
*
|
|
565
|
+
* // Use custom RNG function
|
|
566
|
+
* secrets.setRNG((bits) => {
|
|
567
|
+
* // Return binary string of specified length
|
|
568
|
+
* return customRandomBits(bits);
|
|
569
|
+
* });
|
|
570
|
+
* ```
|
|
571
|
+
*/
|
|
572
|
+
setRNG: function (rng) {
|
|
573
|
+
var errPrefix = "Random number generator is invalid ";
|
|
574
|
+
var errSuffix = " Supply an CSPRNG of the form function(bits){} that returns a string containing 'bits' number of random 1's and 0's.";
|
|
575
|
+
if (rng &&
|
|
576
|
+
typeof rng === "string" &&
|
|
577
|
+
CSPRNGTypes.indexOf(rng) === -1) {
|
|
578
|
+
throw new Error("Invalid RNG type argument : '" + rng + "'");
|
|
579
|
+
}
|
|
580
|
+
var rngFunc;
|
|
581
|
+
if (!rng) {
|
|
582
|
+
rngFunc = getRNG();
|
|
583
|
+
}
|
|
584
|
+
else if (typeof rng === "string") {
|
|
585
|
+
rngFunc = getRNG(rng);
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
rngFunc = rng;
|
|
589
|
+
}
|
|
590
|
+
if (runCSPRNGTest && rngFunc) {
|
|
591
|
+
if (typeof rngFunc !== "function") {
|
|
592
|
+
throw new Error(errPrefix + "(Not a function)." + errSuffix);
|
|
593
|
+
}
|
|
594
|
+
if (typeof rngFunc(config.bits) !== "string") {
|
|
595
|
+
throw new Error(errPrefix + "(Output is not a string)." + errSuffix);
|
|
596
|
+
}
|
|
597
|
+
if (!parseInt(rngFunc(config.bits), 2)) {
|
|
598
|
+
throw new Error(errPrefix +
|
|
599
|
+
"(Binary string output not parseable to an Integer)." +
|
|
600
|
+
errSuffix);
|
|
601
|
+
}
|
|
602
|
+
if (rngFunc(config.bits).length > config.bits) {
|
|
603
|
+
throw new Error(errPrefix + "(Output length is greater than config.bits)." + errSuffix);
|
|
604
|
+
}
|
|
605
|
+
if (rngFunc(config.bits).length < config.bits) {
|
|
606
|
+
throw new Error(errPrefix + "(Output length is less than config.bits)." + errSuffix);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
config.rng = rngFunc;
|
|
610
|
+
return true;
|
|
611
|
+
},
|
|
612
|
+
/**
|
|
613
|
+
* Convert a UTF-16 string to hexadecimal representation.
|
|
614
|
+
*
|
|
615
|
+
* Each character is represented by bytesPerChar bytes in the output.
|
|
616
|
+
* Useful for converting text secrets to hex format before sharing.
|
|
617
|
+
*
|
|
618
|
+
* @param str - The string to convert to hexadecimal.
|
|
619
|
+
* @param bytesPerChar - Number of bytes per character (1-6, default 2).
|
|
620
|
+
* Higher values support larger character codes.
|
|
621
|
+
* @returns Hexadecimal string representation.
|
|
622
|
+
* @throws {Error} If input is not a string.
|
|
623
|
+
* @throws {Error} If bytesPerChar is not an integer between 1 and 6.
|
|
624
|
+
* @throws {Error} If character code exceeds maximum for bytesPerChar.
|
|
625
|
+
*
|
|
626
|
+
* @example
|
|
627
|
+
* ```typescript
|
|
628
|
+
* const hex = secrets.str2hex('Hello');
|
|
629
|
+
* const shares = secrets.share(hex, 5, 3);
|
|
630
|
+
* ```
|
|
631
|
+
*/
|
|
632
|
+
str2hex: function (str, bytesPerChar) {
|
|
633
|
+
var hexChars;
|
|
634
|
+
var max;
|
|
635
|
+
var out = "";
|
|
636
|
+
var neededBytes;
|
|
637
|
+
var num;
|
|
638
|
+
if (typeof str !== "string") {
|
|
639
|
+
throw new Error("Input must be a character string.");
|
|
640
|
+
}
|
|
641
|
+
if (!bytesPerChar) {
|
|
642
|
+
bytesPerChar = defaults.bytesPerChar;
|
|
643
|
+
}
|
|
644
|
+
if (typeof bytesPerChar !== "number" ||
|
|
645
|
+
bytesPerChar < 1 ||
|
|
646
|
+
bytesPerChar > defaults.maxBytesPerChar ||
|
|
647
|
+
bytesPerChar % 1 !== 0) {
|
|
648
|
+
throw new Error("Bytes per character must be an integer between 1 and " +
|
|
649
|
+
defaults.maxBytesPerChar +
|
|
650
|
+
", inclusive.");
|
|
651
|
+
}
|
|
652
|
+
hexChars = 2 * bytesPerChar;
|
|
653
|
+
max = Math.pow(16, hexChars) - 1;
|
|
654
|
+
for (var i = 0, len = str.length; i < len; i++) {
|
|
655
|
+
num = str[i].charCodeAt(0);
|
|
656
|
+
if (isNaN(num)) {
|
|
657
|
+
throw new Error("Invalid character: " + str[i]);
|
|
658
|
+
}
|
|
659
|
+
if (num > max) {
|
|
660
|
+
neededBytes = Math.ceil(Math.log(num + 1) / Math.log(256));
|
|
661
|
+
throw new Error("Invalid character code (" +
|
|
662
|
+
num +
|
|
663
|
+
"). Maximum allowable is 256^bytes-1 (" +
|
|
664
|
+
max +
|
|
665
|
+
"). To convert this character, use at least " +
|
|
666
|
+
neededBytes +
|
|
667
|
+
" bytes.");
|
|
668
|
+
}
|
|
669
|
+
out = padLeft(num.toString(16), hexChars) + out;
|
|
670
|
+
}
|
|
671
|
+
return out;
|
|
672
|
+
},
|
|
673
|
+
/**
|
|
674
|
+
* Convert a hexadecimal string to UTF-16 string representation.
|
|
675
|
+
*
|
|
676
|
+
* Reverses the str2hex operation. Each bytesPerChar bytes in the input
|
|
677
|
+
* represents one character in the output.
|
|
678
|
+
*
|
|
679
|
+
* @param str - The hexadecimal string to convert.
|
|
680
|
+
* @param bytesPerChar - Number of bytes per character (1-6, default 2).
|
|
681
|
+
* Must match the value used in str2hex.
|
|
682
|
+
* @returns UTF-16 string representation.
|
|
683
|
+
* @throws {Error} If input is not a hexadecimal string.
|
|
684
|
+
* @throws {Error} If bytesPerChar is not an integer between 1 and 6.
|
|
685
|
+
*
|
|
686
|
+
* @example
|
|
687
|
+
* ```typescript
|
|
688
|
+
* const shares = secrets.share(secrets.str2hex('Hello'), 5, 3);
|
|
689
|
+
* const recovered = secrets.hex2str(secrets.combine(shares));
|
|
690
|
+
* console.log(recovered); // 'Hello'
|
|
691
|
+
* ```
|
|
692
|
+
*/
|
|
693
|
+
hex2str: function (str, bytesPerChar) {
|
|
694
|
+
var hexChars;
|
|
695
|
+
var out = "";
|
|
696
|
+
if (typeof str !== "string") {
|
|
697
|
+
throw new Error("Input must be a hexadecimal string.");
|
|
698
|
+
}
|
|
699
|
+
bytesPerChar = bytesPerChar || defaults.bytesPerChar;
|
|
700
|
+
if (typeof bytesPerChar !== "number" ||
|
|
701
|
+
bytesPerChar % 1 !== 0 ||
|
|
702
|
+
bytesPerChar < 1 ||
|
|
703
|
+
bytesPerChar > defaults.maxBytesPerChar) {
|
|
704
|
+
throw new Error("Bytes per character must be an integer between 1 and " +
|
|
705
|
+
defaults.maxBytesPerChar +
|
|
706
|
+
", inclusive.");
|
|
707
|
+
}
|
|
708
|
+
hexChars = 2 * bytesPerChar;
|
|
709
|
+
str = padLeft(str, hexChars);
|
|
710
|
+
for (var i = 0, len = str.length; i < len; i += hexChars) {
|
|
711
|
+
out = String.fromCharCode(parseInt(str.slice(i, i + hexChars), 16)) + out;
|
|
712
|
+
}
|
|
713
|
+
return out;
|
|
714
|
+
},
|
|
715
|
+
/**
|
|
716
|
+
* Generate a random hexadecimal string of specified bit length.
|
|
717
|
+
*
|
|
718
|
+
* Uses the configured CSPRNG to generate cryptographically secure
|
|
719
|
+
* random numbers. Useful for generating random secrets.
|
|
720
|
+
*
|
|
721
|
+
* @param bits - Number of random bits to generate (2-65536).
|
|
722
|
+
* @returns Random hexadecimal string.
|
|
723
|
+
* @throws {Error} If bits is not an integer between 2 and 65536.
|
|
724
|
+
*
|
|
725
|
+
* @example
|
|
726
|
+
* ```typescript
|
|
727
|
+
* const randomSecret = secrets.random(128);
|
|
728
|
+
* const shares = secrets.share(randomSecret, 5, 3);
|
|
729
|
+
* ```
|
|
730
|
+
*/
|
|
731
|
+
random: function (bits) {
|
|
732
|
+
if (typeof bits !== "number" ||
|
|
733
|
+
bits % 1 !== 0 ||
|
|
734
|
+
bits < 2 ||
|
|
735
|
+
bits > 65536) {
|
|
736
|
+
throw new Error("Number of bits must be an Integer between 1 and 65536.");
|
|
737
|
+
}
|
|
738
|
+
return bin2hex(config.rng(bits));
|
|
739
|
+
},
|
|
740
|
+
/**
|
|
741
|
+
* Split a secret into shares using Shamir's Secret Sharing.
|
|
742
|
+
*
|
|
743
|
+
* Creates numShares shares such that any threshold number of shares
|
|
744
|
+
* can reconstruct the original secret, but fewer shares reveal no
|
|
745
|
+
* information about the secret.
|
|
746
|
+
*
|
|
747
|
+
* @param secret - The secret to split, as a hexadecimal string.
|
|
748
|
+
* @param numShares - Total number of shares to generate (2 to 2^bits-1).
|
|
749
|
+
* @param threshold - Minimum number of shares needed to reconstruct (2 to numShares).
|
|
750
|
+
* @param padLength - Zero-pad the secret to a multiple of this length (0-1024, default 128).
|
|
751
|
+
* @returns Array of share strings.
|
|
752
|
+
* @throws {Error} If secret is not a string.
|
|
753
|
+
* @throws {Error} If numShares or threshold are invalid.
|
|
754
|
+
* @throws {Error} If threshold exceeds numShares.
|
|
755
|
+
* @throws {Error} If padLength is invalid.
|
|
756
|
+
*
|
|
757
|
+
* @example
|
|
758
|
+
* ```typescript
|
|
759
|
+
* // Split a hex secret into 5 shares, requiring 3 to reconstruct
|
|
760
|
+
* const shares = secrets.share('deadbeef', 5, 3);
|
|
761
|
+
*
|
|
762
|
+
* // Any 3 shares can reconstruct the secret
|
|
763
|
+
* const recovered = secrets.combine([shares[0], shares[2], shares[4]]);
|
|
764
|
+
* console.log(recovered); // 'deadbeef'
|
|
765
|
+
* ```
|
|
766
|
+
*/
|
|
767
|
+
share: function (secret, numShares, threshold, padLength) {
|
|
768
|
+
var neededBits;
|
|
769
|
+
var subShares;
|
|
770
|
+
var x = new Array(numShares);
|
|
771
|
+
var y = new Array(numShares);
|
|
772
|
+
padLength = padLength || 128;
|
|
773
|
+
if (typeof secret !== "string") {
|
|
774
|
+
throw new Error("Secret must be a string.");
|
|
775
|
+
}
|
|
776
|
+
if (typeof numShares !== "number" ||
|
|
777
|
+
numShares % 1 !== 0 ||
|
|
778
|
+
numShares < 2) {
|
|
779
|
+
throw new Error("Number of shares must be an integer between 2 and 2^bits-1 (" +
|
|
780
|
+
config.maxShares +
|
|
781
|
+
"), inclusive.");
|
|
782
|
+
}
|
|
783
|
+
if (numShares > config.maxShares) {
|
|
784
|
+
neededBits = Math.ceil(Math.log(numShares + 1) / Math.LN2);
|
|
785
|
+
throw new Error("Number of shares must be an integer between 2 and 2^bits-1 (" +
|
|
786
|
+
config.maxShares +
|
|
787
|
+
"), inclusive. To create " +
|
|
788
|
+
numShares +
|
|
789
|
+
" shares, use at least " +
|
|
790
|
+
neededBits +
|
|
791
|
+
" bits.");
|
|
792
|
+
}
|
|
793
|
+
if (typeof threshold !== "number" ||
|
|
794
|
+
threshold % 1 !== 0 ||
|
|
795
|
+
threshold < 2) {
|
|
796
|
+
throw new Error("Threshold number of shares must be an integer between 2 and 2^bits-1 (" +
|
|
797
|
+
config.maxShares +
|
|
798
|
+
"), inclusive.");
|
|
799
|
+
}
|
|
800
|
+
if (threshold > config.maxShares) {
|
|
801
|
+
neededBits = Math.ceil(Math.log(threshold + 1) / Math.LN2);
|
|
802
|
+
throw new Error("Threshold number of shares must be an integer between 2 and 2^bits-1 (" +
|
|
803
|
+
config.maxShares +
|
|
804
|
+
"), inclusive. To use a threshold of " +
|
|
805
|
+
threshold +
|
|
806
|
+
", use at least " +
|
|
807
|
+
neededBits +
|
|
808
|
+
" bits.");
|
|
809
|
+
}
|
|
810
|
+
if (threshold > numShares) {
|
|
811
|
+
throw new Error("Threshold number of shares was " +
|
|
812
|
+
threshold +
|
|
813
|
+
" but must be less than or equal to the " +
|
|
814
|
+
numShares +
|
|
815
|
+
" shares specified as the total to generate.");
|
|
816
|
+
}
|
|
817
|
+
if (typeof padLength !== "number" ||
|
|
818
|
+
padLength % 1 !== 0 ||
|
|
819
|
+
padLength < 0 ||
|
|
820
|
+
padLength > 1024) {
|
|
821
|
+
throw new Error("Zero-pad length must be an integer between 0 and 1024 inclusive.");
|
|
822
|
+
}
|
|
823
|
+
var secretBin = "1" + hex2bin(secret);
|
|
824
|
+
var secretParts = splitNumStringToIntArray(secretBin, padLength);
|
|
825
|
+
for (var i = 0, len = secretParts.length; i < len; i++) {
|
|
826
|
+
subShares = getShares(secretParts[i], numShares, threshold);
|
|
827
|
+
for (var j = 0; j < numShares; j++) {
|
|
828
|
+
x[j] = x[j] || subShares[j].x;
|
|
829
|
+
y[j] = padLeft(subShares[j].y.toString(2)) + (y[j] || "");
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
for (var i = 0; i < numShares; i++) {
|
|
833
|
+
x[i] = constructPublicShareString(config.bits, x[i], bin2hex(y[i]));
|
|
834
|
+
}
|
|
835
|
+
return x;
|
|
836
|
+
},
|
|
837
|
+
/**
|
|
838
|
+
* Generate a new share with a specific ID from existing shares.
|
|
839
|
+
*
|
|
840
|
+
* Uses Lagrange interpolation to create a new share at the specified
|
|
841
|
+
* ID point. Useful for generating additional shares without access to
|
|
842
|
+
* the original secret.
|
|
843
|
+
*
|
|
844
|
+
* @param id - The ID for the new share (1 to 2^bits-1).
|
|
845
|
+
* @param shares - Array of existing shares (at least threshold number).
|
|
846
|
+
* @returns New share string with the specified ID.
|
|
847
|
+
* @throws {Error} If id is invalid.
|
|
848
|
+
* @throws {Error} If shares array is invalid or empty.
|
|
849
|
+
*
|
|
850
|
+
* @example
|
|
851
|
+
* ```typescript
|
|
852
|
+
* const shares = secrets.share('abc123', 5, 3);
|
|
853
|
+
* // Generate a new share with ID 10
|
|
854
|
+
* const newShare = secrets.newShare(10, shares.slice(0, 3));
|
|
855
|
+
* ```
|
|
856
|
+
*/
|
|
857
|
+
newShare: function (id, shares) {
|
|
858
|
+
var share;
|
|
859
|
+
var numericId;
|
|
860
|
+
if (typeof id === "string") {
|
|
861
|
+
numericId = parseInt(id, 10);
|
|
862
|
+
}
|
|
863
|
+
else if (typeof id === "number") {
|
|
864
|
+
numericId = Math.floor(id);
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
numericId = NaN;
|
|
868
|
+
}
|
|
869
|
+
if (numericId && shares && shares[0]) {
|
|
870
|
+
share = this.extractShareComponents(shares[0]);
|
|
871
|
+
return constructPublicShareString(share.bits, numericId, this.combine(shares, numericId));
|
|
872
|
+
}
|
|
873
|
+
throw new Error("Invalid 'id' or 'shares' Array argument to newShare().");
|
|
874
|
+
},
|
|
875
|
+
// Private functions exported for testing
|
|
876
|
+
_reset: reset,
|
|
877
|
+
_padLeft: padLeft,
|
|
878
|
+
_hex2bin: hex2bin,
|
|
879
|
+
_bin2hex: bin2hex,
|
|
880
|
+
_bytesToHex: bytesToHex,
|
|
881
|
+
_hasCryptoGetRandomValues: hasCryptoGetRandomValues,
|
|
882
|
+
_hasCryptoRandomBytes: hasCryptoRandomBytes,
|
|
883
|
+
_getRNG: getRNG,
|
|
884
|
+
_isSetRNG: isSetRNG,
|
|
885
|
+
_splitNumStringToIntArray: splitNumStringToIntArray,
|
|
886
|
+
_horner: horner,
|
|
887
|
+
_lagrange: lagrange,
|
|
888
|
+
_getShares: getShares,
|
|
889
|
+
_constructPublicShareString: constructPublicShareString
|
|
890
|
+
};
|
|
891
|
+
// Initialize with default settings
|
|
892
|
+
SecretsLibrary.init();
|
|
893
|
+
// Export for different module systems
|
|
894
|
+
// For CommonJS/Node.js
|
|
895
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
896
|
+
module.exports = SecretsLibrary;
|
|
897
|
+
}
|
|
898
|
+
// For browser globals (UMD)
|
|
899
|
+
if (typeof window !== 'undefined') {
|
|
900
|
+
window.secrets = SecretsLibrary;
|
|
901
|
+
}
|
|
902
|
+
// For ES Modules
|
|
903
|
+
exports.default = SecretsLibrary;
|
|
904
|
+
// Named exports for ES Modules
|
|
905
|
+
exports.init = SecretsLibrary.init, exports.combine = SecretsLibrary.combine, exports.getConfig = SecretsLibrary.getConfig, exports.extractShareComponents = SecretsLibrary.extractShareComponents, exports.setRNG = SecretsLibrary.setRNG, exports.str2hex = SecretsLibrary.str2hex, exports.hex2str = SecretsLibrary.hex2str, exports.random = SecretsLibrary.random, exports.share = SecretsLibrary.share, exports.newShare = SecretsLibrary.newShare;
|
|
906
|
+
});
|
|
907
|
+
//# sourceMappingURL=secrets.js.map
|