shogun-core 5.2.0 → 5.2.1
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/dist/browser/defaultVendors-node_modules_hpke_chacha20poly1305_esm_mod_js.shogun-core.js +1220 -0
- package/dist/browser/defaultVendors-node_modules_hpke_chacha20poly1305_esm_mod_js.shogun-core.js.map +1 -0
- package/dist/browser/defaultVendors-node_modules_hpke_hybridkem-x-wing_esm_mod_js.shogun-core.js +844 -0
- package/dist/browser/defaultVendors-node_modules_hpke_hybridkem-x-wing_esm_mod_js.shogun-core.js.map +1 -0
- package/dist/browser/defaultVendors-node_modules_mlkem_esm_mod_js.shogun-core.js +2335 -0
- package/dist/browser/defaultVendors-node_modules_mlkem_esm_mod_js.shogun-core.js.map +1 -0
- package/dist/browser/defaultVendors-node_modules_noble_ciphers_chacha_js.shogun-core.js +999 -0
- package/dist/browser/defaultVendors-node_modules_noble_ciphers_chacha_js.shogun-core.js.map +1 -0
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_abstract_curve_js-node_modules_noble_curves_esm_-1ce4ed.shogun-core.js +1651 -0
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_abstract_curve_js-node_modules_noble_curves_esm_-1ce4ed.shogun-core.js.map +1 -0
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_abstract_edwards_js-node_modules_noble_curves_es-a82056.shogun-core.js +825 -0
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_abstract_edwards_js-node_modules_noble_curves_es-a82056.shogun-core.js.map +1 -0
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_ed25519_js.shogun-core.js +508 -0
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_ed25519_js.shogun-core.js.map +1 -0
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_ed448_js.shogun-core.js +747 -0
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_ed448_js.shogun-core.js.map +1 -0
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_nist_js.shogun-core.js +1608 -0
- package/dist/browser/defaultVendors-node_modules_noble_curves_esm_nist_js.shogun-core.js.map +1 -0
- package/dist/browser/defaultVendors-node_modules_noble_post-quantum_ml-dsa_js.shogun-core.js +2117 -0
- package/dist/browser/defaultVendors-node_modules_noble_post-quantum_ml-dsa_js.shogun-core.js.map +1 -0
- package/dist/browser/defaultVendors-node_modules_openpgp_dist_openpgp_min_mjs.shogun-core.js +86 -0
- package/dist/browser/defaultVendors-node_modules_openpgp_dist_openpgp_min_mjs.shogun-core.js.map +1 -0
- package/dist/browser/node_modules_hpke_ml-kem_esm_mod_js.shogun-core.js +539 -0
- package/dist/browser/node_modules_hpke_ml-kem_esm_mod_js.shogun-core.js.map +1 -0
- package/dist/browser/shogun-core.js +160386 -0
- package/dist/browser/shogun-core.js.map +1 -0
- package/dist/config/simplified-config.js +236 -0
- package/dist/core.js +329 -0
- package/dist/crypto/asymmetric.js +99 -0
- package/dist/crypto/double-ratchet.js +370 -0
- package/dist/crypto/file-encryption.js +213 -0
- package/dist/crypto/hashing.js +87 -0
- package/dist/crypto/index.js +34 -0
- package/dist/crypto/mls-codec.js +202 -0
- package/dist/crypto/mls.js +550 -0
- package/dist/crypto/pgp.js +390 -0
- package/dist/crypto/random-generation.js +341 -0
- package/dist/crypto/sframe.js +350 -0
- package/dist/crypto/signal-protocol.js +376 -0
- package/dist/crypto/symmetric.js +91 -0
- package/dist/crypto/types.js +2 -0
- package/dist/crypto/utils.js +140 -0
- package/dist/examples/auth-test.js +253 -0
- package/dist/examples/crypto-identity-example.js +151 -0
- package/dist/examples/crypto-working-test.js +83 -0
- package/dist/examples/double-ratchet-test.js +155 -0
- package/dist/examples/mls-advanced-example.js +294 -0
- package/dist/examples/mls-sframe-test.js +304 -0
- package/dist/examples/pgp-example.js +200 -0
- package/dist/examples/quick-auth-test.js +61 -0
- package/dist/examples/random-generation-test.js +151 -0
- package/dist/examples/signal-protocol-test.js +38 -0
- package/dist/examples/simple-api-test.js +114 -0
- package/dist/examples/simple-crypto-identity-example.js +84 -0
- package/dist/examples/timeout-test.js +227 -0
- package/dist/examples/zkproof-credentials-example.js +212 -0
- package/dist/examples/zkproof-example.js +201 -0
- package/dist/gundb/api.js +435 -0
- package/dist/gundb/crypto.js +283 -0
- package/dist/gundb/db.js +1946 -0
- package/dist/gundb/derive.js +232 -0
- package/dist/gundb/errors.js +76 -0
- package/dist/gundb/index.js +22 -0
- package/dist/gundb/rxjs.js +447 -0
- package/dist/gundb/types.js +5 -0
- package/dist/index.js +58 -0
- package/dist/interfaces/common.js +2 -0
- package/dist/interfaces/events.js +40 -0
- package/dist/interfaces/plugin.js +2 -0
- package/dist/interfaces/shogun.js +37 -0
- package/dist/managers/AuthManager.js +226 -0
- package/dist/managers/CoreInitializer.js +228 -0
- package/dist/managers/CryptoIdentityManager.js +366 -0
- package/dist/managers/EventManager.js +70 -0
- package/dist/managers/PluginManager.js +299 -0
- package/dist/plugins/base.js +50 -0
- package/dist/plugins/index.js +32 -0
- package/dist/plugins/nostr/index.js +20 -0
- package/dist/plugins/nostr/nostrConnector.js +419 -0
- package/dist/plugins/nostr/nostrConnectorPlugin.js +453 -0
- package/dist/plugins/nostr/nostrSigner.js +319 -0
- package/dist/plugins/nostr/types.js +2 -0
- package/dist/plugins/smartwallet/index.js +18 -0
- package/dist/plugins/smartwallet/smartWalletPlugin.js +511 -0
- package/dist/plugins/smartwallet/types.js +2 -0
- package/dist/plugins/web3/index.js +20 -0
- package/dist/plugins/web3/types.js +2 -0
- package/dist/plugins/web3/web3Connector.js +533 -0
- package/dist/plugins/web3/web3ConnectorPlugin.js +455 -0
- package/dist/plugins/web3/web3Signer.js +314 -0
- package/dist/plugins/webauthn/index.js +19 -0
- package/dist/plugins/webauthn/types.js +14 -0
- package/dist/plugins/webauthn/webauthn.js +496 -0
- package/dist/plugins/webauthn/webauthnPlugin.js +489 -0
- package/dist/plugins/webauthn/webauthnSigner.js +310 -0
- package/dist/plugins/zkproof/index.js +53 -0
- package/dist/plugins/zkproof/types.js +2 -0
- package/dist/plugins/zkproof/zkCredentials.js +213 -0
- package/dist/plugins/zkproof/zkProofConnector.js +198 -0
- package/dist/plugins/zkproof/zkProofPlugin.js +272 -0
- package/dist/storage/storage.js +145 -0
- package/dist/types/config/simplified-config.d.ts +114 -0
- package/dist/types/core.d.ts +305 -0
- package/dist/types/crypto/asymmetric.d.ts +6 -0
- package/dist/types/crypto/double-ratchet.d.ts +22 -0
- package/dist/types/crypto/file-encryption.d.ts +19 -0
- package/dist/types/crypto/hashing.d.ts +9 -0
- package/dist/types/crypto/index.d.ts +13 -0
- package/dist/types/crypto/mls-codec.d.ts +39 -0
- package/dist/types/crypto/mls.d.ts +130 -0
- package/dist/types/crypto/pgp.d.ts +95 -0
- package/dist/types/crypto/random-generation.d.ts +35 -0
- package/dist/types/crypto/sframe.d.ts +102 -0
- package/dist/types/crypto/signal-protocol.d.ts +26 -0
- package/dist/types/crypto/symmetric.d.ts +9 -0
- package/dist/types/crypto/types.d.ts +144 -0
- package/dist/types/crypto/utils.d.ts +22 -0
- package/dist/types/examples/auth-test.d.ts +8 -0
- package/dist/types/examples/crypto-identity-example.d.ts +5 -0
- package/dist/types/examples/crypto-working-test.d.ts +1 -0
- package/dist/types/examples/double-ratchet-test.d.ts +1 -0
- package/dist/types/examples/mls-advanced-example.d.ts +53 -0
- package/dist/types/examples/mls-sframe-test.d.ts +1 -0
- package/dist/types/examples/pgp-example.d.ts +75 -0
- package/dist/types/examples/quick-auth-test.d.ts +8 -0
- package/dist/types/examples/random-generation-test.d.ts +1 -0
- package/dist/types/examples/signal-protocol-test.d.ts +1 -0
- package/dist/types/examples/simple-api-test.d.ts +10 -0
- package/dist/types/examples/simple-crypto-identity-example.d.ts +6 -0
- package/dist/types/examples/timeout-test.d.ts +8 -0
- package/dist/types/examples/zkproof-credentials-example.d.ts +12 -0
- package/dist/types/examples/zkproof-example.d.ts +11 -0
- package/dist/types/gundb/api.d.ts +185 -0
- package/dist/types/gundb/crypto.d.ts +95 -0
- package/dist/types/gundb/db.d.ts +397 -0
- package/dist/types/gundb/derive.d.ts +21 -0
- package/dist/types/gundb/errors.d.ts +42 -0
- package/dist/types/gundb/index.d.ts +3 -0
- package/dist/types/gundb/rxjs.d.ts +110 -0
- package/dist/types/gundb/types.d.ts +255 -0
- package/dist/types/index.d.ts +16 -0
- package/dist/types/interfaces/common.d.ts +85 -0
- package/dist/types/interfaces/events.d.ts +131 -0
- package/dist/types/interfaces/plugin.d.ts +162 -0
- package/dist/types/interfaces/shogun.d.ts +208 -0
- package/dist/types/managers/AuthManager.d.ts +72 -0
- package/dist/types/managers/CoreInitializer.d.ts +40 -0
- package/dist/types/managers/CryptoIdentityManager.d.ts +102 -0
- package/dist/types/managers/EventManager.d.ts +49 -0
- package/dist/types/managers/PluginManager.d.ts +145 -0
- package/dist/types/plugins/base.d.ts +35 -0
- package/dist/types/plugins/index.d.ts +18 -0
- package/dist/types/plugins/nostr/index.d.ts +4 -0
- package/dist/types/plugins/nostr/nostrConnector.d.ts +119 -0
- package/dist/types/plugins/nostr/nostrConnectorPlugin.d.ts +163 -0
- package/dist/types/plugins/nostr/nostrSigner.d.ts +105 -0
- package/dist/types/plugins/nostr/types.d.ts +122 -0
- package/dist/types/plugins/smartwallet/index.d.ts +2 -0
- package/dist/types/plugins/smartwallet/smartWalletPlugin.d.ts +67 -0
- package/dist/types/plugins/smartwallet/types.d.ts +80 -0
- package/dist/types/plugins/web3/index.d.ts +4 -0
- package/dist/types/plugins/web3/types.d.ts +107 -0
- package/dist/types/plugins/web3/web3Connector.d.ts +129 -0
- package/dist/types/plugins/web3/web3ConnectorPlugin.d.ts +160 -0
- package/dist/types/plugins/web3/web3Signer.d.ts +114 -0
- package/dist/types/plugins/webauthn/index.d.ts +3 -0
- package/dist/types/plugins/webauthn/types.d.ts +183 -0
- package/dist/types/plugins/webauthn/webauthn.d.ts +129 -0
- package/dist/types/plugins/webauthn/webauthnPlugin.d.ts +179 -0
- package/dist/types/plugins/webauthn/webauthnSigner.d.ts +91 -0
- package/dist/types/plugins/zkproof/index.d.ts +48 -0
- package/dist/types/plugins/zkproof/types.d.ts +123 -0
- package/dist/types/plugins/zkproof/zkCredentials.d.ts +112 -0
- package/dist/types/plugins/zkproof/zkProofConnector.d.ts +46 -0
- package/dist/types/plugins/zkproof/zkProofPlugin.d.ts +76 -0
- package/dist/types/storage/storage.d.ts +51 -0
- package/dist/types/utils/errorHandler.d.ts +119 -0
- package/dist/types/utils/eventEmitter.d.ts +39 -0
- package/dist/types/utils/seedPhrase.d.ts +50 -0
- package/dist/types/utils/validation.d.ts +27 -0
- package/dist/utils/errorHandler.js +246 -0
- package/dist/utils/eventEmitter.js +79 -0
- package/dist/utils/seedPhrase.js +97 -0
- package/dist/utils/validation.js +81 -0
- package/package.json +10 -1
|
@@ -0,0 +1,1651 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
(this["webpackChunkShogunCore"] = this["webpackChunkShogunCore"] || []).push([["defaultVendors-node_modules_noble_curves_esm_abstract_curve_js-node_modules_noble_curves_esm_-1ce4ed"],{
|
|
3
|
+
|
|
4
|
+
/***/ "./node_modules/@noble/curves/esm/abstract/curve.js":
|
|
5
|
+
/*!**********************************************************!*\
|
|
6
|
+
!*** ./node_modules/@noble/curves/esm/abstract/curve.js ***!
|
|
7
|
+
\**********************************************************/
|
|
8
|
+
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
9
|
+
|
|
10
|
+
__webpack_require__.r(__webpack_exports__);
|
|
11
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
12
|
+
/* harmony export */ _createCurveFields: () => (/* binding */ _createCurveFields),
|
|
13
|
+
/* harmony export */ mulEndoUnsafe: () => (/* binding */ mulEndoUnsafe),
|
|
14
|
+
/* harmony export */ negateCt: () => (/* binding */ negateCt),
|
|
15
|
+
/* harmony export */ normalizeZ: () => (/* binding */ normalizeZ),
|
|
16
|
+
/* harmony export */ pippenger: () => (/* binding */ pippenger),
|
|
17
|
+
/* harmony export */ precomputeMSMUnsafe: () => (/* binding */ precomputeMSMUnsafe),
|
|
18
|
+
/* harmony export */ validateBasic: () => (/* binding */ validateBasic),
|
|
19
|
+
/* harmony export */ wNAF: () => (/* binding */ wNAF)
|
|
20
|
+
/* harmony export */ });
|
|
21
|
+
/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils.js */ "./node_modules/@noble/curves/esm/utils.js");
|
|
22
|
+
/* harmony import */ var _modular_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modular.js */ "./node_modules/@noble/curves/esm/abstract/modular.js");
|
|
23
|
+
/**
|
|
24
|
+
* Methods for elliptic curve multiplication by scalars.
|
|
25
|
+
* Contains wNAF, pippenger.
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const _0n = BigInt(0);
|
|
32
|
+
const _1n = BigInt(1);
|
|
33
|
+
function negateCt(condition, item) {
|
|
34
|
+
const neg = item.negate();
|
|
35
|
+
return condition ? neg : item;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Takes a bunch of Projective Points but executes only one
|
|
39
|
+
* inversion on all of them. Inversion is very slow operation,
|
|
40
|
+
* so this improves performance massively.
|
|
41
|
+
* Optimization: converts a list of projective points to a list of identical points with Z=1.
|
|
42
|
+
*/
|
|
43
|
+
function normalizeZ(c, points) {
|
|
44
|
+
const invertedZs = (0,_modular_js__WEBPACK_IMPORTED_MODULE_1__.FpInvertBatch)(c.Fp, points.map((p) => p.Z));
|
|
45
|
+
return points.map((p, i) => c.fromAffine(p.toAffine(invertedZs[i])));
|
|
46
|
+
}
|
|
47
|
+
function validateW(W, bits) {
|
|
48
|
+
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
|
|
49
|
+
throw new Error('invalid window size, expected [1..' + bits + '], got W=' + W);
|
|
50
|
+
}
|
|
51
|
+
function calcWOpts(W, scalarBits) {
|
|
52
|
+
validateW(W, scalarBits);
|
|
53
|
+
const windows = Math.ceil(scalarBits / W) + 1; // W=8 33. Not 32, because we skip zero
|
|
54
|
+
const windowSize = 2 ** (W - 1); // W=8 128. Not 256, because we skip zero
|
|
55
|
+
const maxNumber = 2 ** W; // W=8 256
|
|
56
|
+
const mask = (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bitMask)(W); // W=8 255 == mask 0b11111111
|
|
57
|
+
const shiftBy = BigInt(W); // W=8 8
|
|
58
|
+
return { windows, windowSize, mask, maxNumber, shiftBy };
|
|
59
|
+
}
|
|
60
|
+
function calcOffsets(n, window, wOpts) {
|
|
61
|
+
const { windowSize, mask, maxNumber, shiftBy } = wOpts;
|
|
62
|
+
let wbits = Number(n & mask); // extract W bits.
|
|
63
|
+
let nextN = n >> shiftBy; // shift number by W bits.
|
|
64
|
+
// What actually happens here:
|
|
65
|
+
// const highestBit = Number(mask ^ (mask >> 1n));
|
|
66
|
+
// let wbits2 = wbits - 1; // skip zero
|
|
67
|
+
// if (wbits2 & highestBit) { wbits2 ^= Number(mask); // (~);
|
|
68
|
+
// split if bits > max: +224 => 256-32
|
|
69
|
+
if (wbits > windowSize) {
|
|
70
|
+
// we skip zero, which means instead of `>= size-1`, we do `> size`
|
|
71
|
+
wbits -= maxNumber; // -32, can be maxNumber - wbits, but then we need to set isNeg here.
|
|
72
|
+
nextN += _1n; // +256 (carry)
|
|
73
|
+
}
|
|
74
|
+
const offsetStart = window * windowSize;
|
|
75
|
+
const offset = offsetStart + Math.abs(wbits) - 1; // -1 because we skip zero
|
|
76
|
+
const isZero = wbits === 0; // is current window slice a 0?
|
|
77
|
+
const isNeg = wbits < 0; // is current window slice negative?
|
|
78
|
+
const isNegF = window % 2 !== 0; // fake random statement for noise
|
|
79
|
+
const offsetF = offsetStart; // fake offset for noise
|
|
80
|
+
return { nextN, offset, isZero, isNeg, isNegF, offsetF };
|
|
81
|
+
}
|
|
82
|
+
function validateMSMPoints(points, c) {
|
|
83
|
+
if (!Array.isArray(points))
|
|
84
|
+
throw new Error('array expected');
|
|
85
|
+
points.forEach((p, i) => {
|
|
86
|
+
if (!(p instanceof c))
|
|
87
|
+
throw new Error('invalid point at index ' + i);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function validateMSMScalars(scalars, field) {
|
|
91
|
+
if (!Array.isArray(scalars))
|
|
92
|
+
throw new Error('array of scalars expected');
|
|
93
|
+
scalars.forEach((s, i) => {
|
|
94
|
+
if (!field.isValid(s))
|
|
95
|
+
throw new Error('invalid scalar at index ' + i);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
// Since points in different groups cannot be equal (different object constructor),
|
|
99
|
+
// we can have single place to store precomputes.
|
|
100
|
+
// Allows to make points frozen / immutable.
|
|
101
|
+
const pointPrecomputes = new WeakMap();
|
|
102
|
+
const pointWindowSizes = new WeakMap();
|
|
103
|
+
function getW(P) {
|
|
104
|
+
// To disable precomputes:
|
|
105
|
+
// return 1;
|
|
106
|
+
return pointWindowSizes.get(P) || 1;
|
|
107
|
+
}
|
|
108
|
+
function assert0(n) {
|
|
109
|
+
if (n !== _0n)
|
|
110
|
+
throw new Error('invalid wNAF');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Elliptic curve multiplication of Point by scalar. Fragile.
|
|
114
|
+
* Table generation takes **30MB of ram and 10ms on high-end CPU**,
|
|
115
|
+
* but may take much longer on slow devices. Actual generation will happen on
|
|
116
|
+
* first call of `multiply()`. By default, `BASE` point is precomputed.
|
|
117
|
+
*
|
|
118
|
+
* Scalars should always be less than curve order: this should be checked inside of a curve itself.
|
|
119
|
+
* Creates precomputation tables for fast multiplication:
|
|
120
|
+
* - private scalar is split by fixed size windows of W bits
|
|
121
|
+
* - every window point is collected from window's table & added to accumulator
|
|
122
|
+
* - since windows are different, same point inside tables won't be accessed more than once per calc
|
|
123
|
+
* - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar)
|
|
124
|
+
* - +1 window is neccessary for wNAF
|
|
125
|
+
* - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication
|
|
126
|
+
*
|
|
127
|
+
* @todo Research returning 2d JS array of windows, instead of a single window.
|
|
128
|
+
* This would allow windows to be in different memory locations
|
|
129
|
+
*/
|
|
130
|
+
class wNAF {
|
|
131
|
+
// Parametrized with a given Point class (not individual point)
|
|
132
|
+
constructor(Point, bits) {
|
|
133
|
+
this.BASE = Point.BASE;
|
|
134
|
+
this.ZERO = Point.ZERO;
|
|
135
|
+
this.Fn = Point.Fn;
|
|
136
|
+
this.bits = bits;
|
|
137
|
+
}
|
|
138
|
+
// non-const time multiplication ladder
|
|
139
|
+
_unsafeLadder(elm, n, p = this.ZERO) {
|
|
140
|
+
let d = elm;
|
|
141
|
+
while (n > _0n) {
|
|
142
|
+
if (n & _1n)
|
|
143
|
+
p = p.add(d);
|
|
144
|
+
d = d.double();
|
|
145
|
+
n >>= _1n;
|
|
146
|
+
}
|
|
147
|
+
return p;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Creates a wNAF precomputation window. Used for caching.
|
|
151
|
+
* Default window size is set by `utils.precompute()` and is equal to 8.
|
|
152
|
+
* Number of precomputed points depends on the curve size:
|
|
153
|
+
* 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
|
|
154
|
+
* - 𝑊 is the window size
|
|
155
|
+
* - 𝑛 is the bitlength of the curve order.
|
|
156
|
+
* For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
|
|
157
|
+
* @param point Point instance
|
|
158
|
+
* @param W window size
|
|
159
|
+
* @returns precomputed point tables flattened to a single array
|
|
160
|
+
*/
|
|
161
|
+
precomputeWindow(point, W) {
|
|
162
|
+
const { windows, windowSize } = calcWOpts(W, this.bits);
|
|
163
|
+
const points = [];
|
|
164
|
+
let p = point;
|
|
165
|
+
let base = p;
|
|
166
|
+
for (let window = 0; window < windows; window++) {
|
|
167
|
+
base = p;
|
|
168
|
+
points.push(base);
|
|
169
|
+
// i=1, bc we skip 0
|
|
170
|
+
for (let i = 1; i < windowSize; i++) {
|
|
171
|
+
base = base.add(p);
|
|
172
|
+
points.push(base);
|
|
173
|
+
}
|
|
174
|
+
p = base.double();
|
|
175
|
+
}
|
|
176
|
+
return points;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
|
|
180
|
+
* More compact implementation:
|
|
181
|
+
* https://github.com/paulmillr/noble-secp256k1/blob/47cb1669b6e506ad66b35fe7d76132ae97465da2/index.ts#L502-L541
|
|
182
|
+
* @returns real and fake (for const-time) points
|
|
183
|
+
*/
|
|
184
|
+
wNAF(W, precomputes, n) {
|
|
185
|
+
// Scalar should be smaller than field order
|
|
186
|
+
if (!this.Fn.isValid(n))
|
|
187
|
+
throw new Error('invalid scalar');
|
|
188
|
+
// Accumulators
|
|
189
|
+
let p = this.ZERO;
|
|
190
|
+
let f = this.BASE;
|
|
191
|
+
// This code was first written with assumption that 'f' and 'p' will never be infinity point:
|
|
192
|
+
// since each addition is multiplied by 2 ** W, it cannot cancel each other. However,
|
|
193
|
+
// there is negate now: it is possible that negated element from low value
|
|
194
|
+
// would be the same as high element, which will create carry into next window.
|
|
195
|
+
// It's not obvious how this can fail, but still worth investigating later.
|
|
196
|
+
const wo = calcWOpts(W, this.bits);
|
|
197
|
+
for (let window = 0; window < wo.windows; window++) {
|
|
198
|
+
// (n === _0n) is handled and not early-exited. isEven and offsetF are used for noise
|
|
199
|
+
const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
|
|
200
|
+
n = nextN;
|
|
201
|
+
if (isZero) {
|
|
202
|
+
// bits are 0: add garbage to fake point
|
|
203
|
+
// Important part for const-time getPublicKey: add random "noise" point to f.
|
|
204
|
+
f = f.add(negateCt(isNegF, precomputes[offsetF]));
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
// bits are 1: add to result point
|
|
208
|
+
p = p.add(negateCt(isNeg, precomputes[offset]));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
assert0(n);
|
|
212
|
+
// Return both real and fake points: JIT won't eliminate f.
|
|
213
|
+
// At this point there is a way to F be infinity-point even if p is not,
|
|
214
|
+
// which makes it less const-time: around 1 bigint multiply.
|
|
215
|
+
return { p, f };
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.
|
|
219
|
+
* @param acc accumulator point to add result of multiplication
|
|
220
|
+
* @returns point
|
|
221
|
+
*/
|
|
222
|
+
wNAFUnsafe(W, precomputes, n, acc = this.ZERO) {
|
|
223
|
+
const wo = calcWOpts(W, this.bits);
|
|
224
|
+
for (let window = 0; window < wo.windows; window++) {
|
|
225
|
+
if (n === _0n)
|
|
226
|
+
break; // Early-exit, skip 0 value
|
|
227
|
+
const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
|
|
228
|
+
n = nextN;
|
|
229
|
+
if (isZero) {
|
|
230
|
+
// Window bits are 0: skip processing.
|
|
231
|
+
// Move to next window.
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
const item = precomputes[offset];
|
|
236
|
+
acc = acc.add(isNeg ? item.negate() : item); // Re-using acc allows to save adds in MSM
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
assert0(n);
|
|
240
|
+
return acc;
|
|
241
|
+
}
|
|
242
|
+
getPrecomputes(W, point, transform) {
|
|
243
|
+
// Calculate precomputes on a first run, reuse them after
|
|
244
|
+
let comp = pointPrecomputes.get(point);
|
|
245
|
+
if (!comp) {
|
|
246
|
+
comp = this.precomputeWindow(point, W);
|
|
247
|
+
if (W !== 1) {
|
|
248
|
+
// Doing transform outside of if brings 15% perf hit
|
|
249
|
+
if (typeof transform === 'function')
|
|
250
|
+
comp = transform(comp);
|
|
251
|
+
pointPrecomputes.set(point, comp);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return comp;
|
|
255
|
+
}
|
|
256
|
+
cached(point, scalar, transform) {
|
|
257
|
+
const W = getW(point);
|
|
258
|
+
return this.wNAF(W, this.getPrecomputes(W, point, transform), scalar);
|
|
259
|
+
}
|
|
260
|
+
unsafe(point, scalar, transform, prev) {
|
|
261
|
+
const W = getW(point);
|
|
262
|
+
if (W === 1)
|
|
263
|
+
return this._unsafeLadder(point, scalar, prev); // For W=1 ladder is ~x2 faster
|
|
264
|
+
return this.wNAFUnsafe(W, this.getPrecomputes(W, point, transform), scalar, prev);
|
|
265
|
+
}
|
|
266
|
+
// We calculate precomputes for elliptic curve point multiplication
|
|
267
|
+
// using windowed method. This specifies window size and
|
|
268
|
+
// stores precomputed values. Usually only base point would be precomputed.
|
|
269
|
+
createCache(P, W) {
|
|
270
|
+
validateW(W, this.bits);
|
|
271
|
+
pointWindowSizes.set(P, W);
|
|
272
|
+
pointPrecomputes.delete(P);
|
|
273
|
+
}
|
|
274
|
+
hasCache(elm) {
|
|
275
|
+
return getW(elm) !== 1;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Endomorphism-specific multiplication for Koblitz curves.
|
|
280
|
+
* Cost: 128 dbl, 0-256 adds.
|
|
281
|
+
*/
|
|
282
|
+
function mulEndoUnsafe(Point, point, k1, k2) {
|
|
283
|
+
let acc = point;
|
|
284
|
+
let p1 = Point.ZERO;
|
|
285
|
+
let p2 = Point.ZERO;
|
|
286
|
+
while (k1 > _0n || k2 > _0n) {
|
|
287
|
+
if (k1 & _1n)
|
|
288
|
+
p1 = p1.add(acc);
|
|
289
|
+
if (k2 & _1n)
|
|
290
|
+
p2 = p2.add(acc);
|
|
291
|
+
acc = acc.double();
|
|
292
|
+
k1 >>= _1n;
|
|
293
|
+
k2 >>= _1n;
|
|
294
|
+
}
|
|
295
|
+
return { p1, p2 };
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Pippenger algorithm for multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
|
|
299
|
+
* 30x faster vs naive addition on L=4096, 10x faster than precomputes.
|
|
300
|
+
* For N=254bit, L=1, it does: 1024 ADD + 254 DBL. For L=5: 1536 ADD + 254 DBL.
|
|
301
|
+
* Algorithmically constant-time (for same L), even when 1 point + scalar, or when scalar = 0.
|
|
302
|
+
* @param c Curve Point constructor
|
|
303
|
+
* @param fieldN field over CURVE.N - important that it's not over CURVE.P
|
|
304
|
+
* @param points array of L curve points
|
|
305
|
+
* @param scalars array of L scalars (aka secret keys / bigints)
|
|
306
|
+
*/
|
|
307
|
+
function pippenger(c, fieldN, points, scalars) {
|
|
308
|
+
// If we split scalars by some window (let's say 8 bits), every chunk will only
|
|
309
|
+
// take 256 buckets even if there are 4096 scalars, also re-uses double.
|
|
310
|
+
// TODO:
|
|
311
|
+
// - https://eprint.iacr.org/2024/750.pdf
|
|
312
|
+
// - https://tches.iacr.org/index.php/TCHES/article/view/10287
|
|
313
|
+
// 0 is accepted in scalars
|
|
314
|
+
validateMSMPoints(points, c);
|
|
315
|
+
validateMSMScalars(scalars, fieldN);
|
|
316
|
+
const plength = points.length;
|
|
317
|
+
const slength = scalars.length;
|
|
318
|
+
if (plength !== slength)
|
|
319
|
+
throw new Error('arrays of points and scalars must have equal length');
|
|
320
|
+
// if (plength === 0) throw new Error('array must be of length >= 2');
|
|
321
|
+
const zero = c.ZERO;
|
|
322
|
+
const wbits = (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bitLen)(BigInt(plength));
|
|
323
|
+
let windowSize = 1; // bits
|
|
324
|
+
if (wbits > 12)
|
|
325
|
+
windowSize = wbits - 3;
|
|
326
|
+
else if (wbits > 4)
|
|
327
|
+
windowSize = wbits - 2;
|
|
328
|
+
else if (wbits > 0)
|
|
329
|
+
windowSize = 2;
|
|
330
|
+
const MASK = (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bitMask)(windowSize);
|
|
331
|
+
const buckets = new Array(Number(MASK) + 1).fill(zero); // +1 for zero array
|
|
332
|
+
const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize;
|
|
333
|
+
let sum = zero;
|
|
334
|
+
for (let i = lastBits; i >= 0; i -= windowSize) {
|
|
335
|
+
buckets.fill(zero);
|
|
336
|
+
for (let j = 0; j < slength; j++) {
|
|
337
|
+
const scalar = scalars[j];
|
|
338
|
+
const wbits = Number((scalar >> BigInt(i)) & MASK);
|
|
339
|
+
buckets[wbits] = buckets[wbits].add(points[j]);
|
|
340
|
+
}
|
|
341
|
+
let resI = zero; // not using this will do small speed-up, but will lose ct
|
|
342
|
+
// Skip first bucket, because it is zero
|
|
343
|
+
for (let j = buckets.length - 1, sumI = zero; j > 0; j--) {
|
|
344
|
+
sumI = sumI.add(buckets[j]);
|
|
345
|
+
resI = resI.add(sumI);
|
|
346
|
+
}
|
|
347
|
+
sum = sum.add(resI);
|
|
348
|
+
if (i !== 0)
|
|
349
|
+
for (let j = 0; j < windowSize; j++)
|
|
350
|
+
sum = sum.double();
|
|
351
|
+
}
|
|
352
|
+
return sum;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Precomputed multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
|
|
356
|
+
* @param c Curve Point constructor
|
|
357
|
+
* @param fieldN field over CURVE.N - important that it's not over CURVE.P
|
|
358
|
+
* @param points array of L curve points
|
|
359
|
+
* @returns function which multiplies points with scaars
|
|
360
|
+
*/
|
|
361
|
+
function precomputeMSMUnsafe(c, fieldN, points, windowSize) {
|
|
362
|
+
/**
|
|
363
|
+
* Performance Analysis of Window-based Precomputation
|
|
364
|
+
*
|
|
365
|
+
* Base Case (256-bit scalar, 8-bit window):
|
|
366
|
+
* - Standard precomputation requires:
|
|
367
|
+
* - 31 additions per scalar × 256 scalars = 7,936 ops
|
|
368
|
+
* - Plus 255 summary additions = 8,191 total ops
|
|
369
|
+
* Note: Summary additions can be optimized via accumulator
|
|
370
|
+
*
|
|
371
|
+
* Chunked Precomputation Analysis:
|
|
372
|
+
* - Using 32 chunks requires:
|
|
373
|
+
* - 255 additions per chunk
|
|
374
|
+
* - 256 doublings
|
|
375
|
+
* - Total: (255 × 32) + 256 = 8,416 ops
|
|
376
|
+
*
|
|
377
|
+
* Memory Usage Comparison:
|
|
378
|
+
* Window Size | Standard Points | Chunked Points
|
|
379
|
+
* ------------|-----------------|---------------
|
|
380
|
+
* 4-bit | 520 | 15
|
|
381
|
+
* 8-bit | 4,224 | 255
|
|
382
|
+
* 10-bit | 13,824 | 1,023
|
|
383
|
+
* 16-bit | 557,056 | 65,535
|
|
384
|
+
*
|
|
385
|
+
* Key Advantages:
|
|
386
|
+
* 1. Enables larger window sizes due to reduced memory overhead
|
|
387
|
+
* 2. More efficient for smaller scalar counts:
|
|
388
|
+
* - 16 chunks: (16 × 255) + 256 = 4,336 ops
|
|
389
|
+
* - ~2x faster than standard 8,191 ops
|
|
390
|
+
*
|
|
391
|
+
* Limitations:
|
|
392
|
+
* - Not suitable for plain precomputes (requires 256 constant doublings)
|
|
393
|
+
* - Performance degrades with larger scalar counts:
|
|
394
|
+
* - Optimal for ~256 scalars
|
|
395
|
+
* - Less efficient for 4096+ scalars (Pippenger preferred)
|
|
396
|
+
*/
|
|
397
|
+
validateW(windowSize, fieldN.BITS);
|
|
398
|
+
validateMSMPoints(points, c);
|
|
399
|
+
const zero = c.ZERO;
|
|
400
|
+
const tableSize = 2 ** windowSize - 1; // table size (without zero)
|
|
401
|
+
const chunks = Math.ceil(fieldN.BITS / windowSize); // chunks of item
|
|
402
|
+
const MASK = (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bitMask)(windowSize);
|
|
403
|
+
const tables = points.map((p) => {
|
|
404
|
+
const res = [];
|
|
405
|
+
for (let i = 0, acc = p; i < tableSize; i++) {
|
|
406
|
+
res.push(acc);
|
|
407
|
+
acc = acc.add(p);
|
|
408
|
+
}
|
|
409
|
+
return res;
|
|
410
|
+
});
|
|
411
|
+
return (scalars) => {
|
|
412
|
+
validateMSMScalars(scalars, fieldN);
|
|
413
|
+
if (scalars.length > points.length)
|
|
414
|
+
throw new Error('array of scalars must be smaller than array of points');
|
|
415
|
+
let res = zero;
|
|
416
|
+
for (let i = 0; i < chunks; i++) {
|
|
417
|
+
// No need to double if accumulator is still zero.
|
|
418
|
+
if (res !== zero)
|
|
419
|
+
for (let j = 0; j < windowSize; j++)
|
|
420
|
+
res = res.double();
|
|
421
|
+
const shiftBy = BigInt(chunks * windowSize - (i + 1) * windowSize);
|
|
422
|
+
for (let j = 0; j < scalars.length; j++) {
|
|
423
|
+
const n = scalars[j];
|
|
424
|
+
const curr = Number((n >> shiftBy) & MASK);
|
|
425
|
+
if (!curr)
|
|
426
|
+
continue; // skip zero scalars chunks
|
|
427
|
+
res = res.add(tables[j][curr - 1]);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return res;
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
// TODO: remove
|
|
434
|
+
/** @deprecated */
|
|
435
|
+
function validateBasic(curve) {
|
|
436
|
+
(0,_modular_js__WEBPACK_IMPORTED_MODULE_1__.validateField)(curve.Fp);
|
|
437
|
+
(0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.validateObject)(curve, {
|
|
438
|
+
n: 'bigint',
|
|
439
|
+
h: 'bigint',
|
|
440
|
+
Gx: 'field',
|
|
441
|
+
Gy: 'field',
|
|
442
|
+
}, {
|
|
443
|
+
nBitLength: 'isSafeInteger',
|
|
444
|
+
nByteLength: 'isSafeInteger',
|
|
445
|
+
});
|
|
446
|
+
// Set defaults
|
|
447
|
+
return Object.freeze({
|
|
448
|
+
...(0,_modular_js__WEBPACK_IMPORTED_MODULE_1__.nLength)(curve.n, curve.nBitLength),
|
|
449
|
+
...curve,
|
|
450
|
+
...{ p: curve.Fp.ORDER },
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
function createField(order, field, isLE) {
|
|
454
|
+
if (field) {
|
|
455
|
+
if (field.ORDER !== order)
|
|
456
|
+
throw new Error('Field.ORDER must match order: Fp == p, Fn == n');
|
|
457
|
+
(0,_modular_js__WEBPACK_IMPORTED_MODULE_1__.validateField)(field);
|
|
458
|
+
return field;
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
return (0,_modular_js__WEBPACK_IMPORTED_MODULE_1__.Field)(order, { isLE });
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/** Validates CURVE opts and creates fields */
|
|
465
|
+
function _createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) {
|
|
466
|
+
if (FpFnLE === undefined)
|
|
467
|
+
FpFnLE = type === 'edwards';
|
|
468
|
+
if (!CURVE || typeof CURVE !== 'object')
|
|
469
|
+
throw new Error(`expected valid ${type} CURVE object`);
|
|
470
|
+
for (const p of ['p', 'n', 'h']) {
|
|
471
|
+
const val = CURVE[p];
|
|
472
|
+
if (!(typeof val === 'bigint' && val > _0n))
|
|
473
|
+
throw new Error(`CURVE.${p} must be positive bigint`);
|
|
474
|
+
}
|
|
475
|
+
const Fp = createField(CURVE.p, curveOpts.Fp, FpFnLE);
|
|
476
|
+
const Fn = createField(CURVE.n, curveOpts.Fn, FpFnLE);
|
|
477
|
+
const _b = type === 'weierstrass' ? 'b' : 'd';
|
|
478
|
+
const params = ['Gx', 'Gy', 'a', _b];
|
|
479
|
+
for (const p of params) {
|
|
480
|
+
// @ts-ignore
|
|
481
|
+
if (!Fp.isValid(CURVE[p]))
|
|
482
|
+
throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
|
|
483
|
+
}
|
|
484
|
+
CURVE = Object.freeze(Object.assign({}, CURVE));
|
|
485
|
+
return { CURVE, Fp, Fn };
|
|
486
|
+
}
|
|
487
|
+
//# sourceMappingURL=curve.js.map
|
|
488
|
+
|
|
489
|
+
/***/ }),
|
|
490
|
+
|
|
491
|
+
/***/ "./node_modules/@noble/curves/esm/abstract/hash-to-curve.js":
|
|
492
|
+
/*!******************************************************************!*\
|
|
493
|
+
!*** ./node_modules/@noble/curves/esm/abstract/hash-to-curve.js ***!
|
|
494
|
+
\******************************************************************/
|
|
495
|
+
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
496
|
+
|
|
497
|
+
__webpack_require__.r(__webpack_exports__);
|
|
498
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
499
|
+
/* harmony export */ _DST_scalar: () => (/* binding */ _DST_scalar),
|
|
500
|
+
/* harmony export */ createHasher: () => (/* binding */ createHasher),
|
|
501
|
+
/* harmony export */ expand_message_xmd: () => (/* binding */ expand_message_xmd),
|
|
502
|
+
/* harmony export */ expand_message_xof: () => (/* binding */ expand_message_xof),
|
|
503
|
+
/* harmony export */ hash_to_field: () => (/* binding */ hash_to_field),
|
|
504
|
+
/* harmony export */ isogenyMap: () => (/* binding */ isogenyMap)
|
|
505
|
+
/* harmony export */ });
|
|
506
|
+
/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils.js */ "./node_modules/@noble/curves/esm/utils.js");
|
|
507
|
+
/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils.js */ "./node_modules/@noble/hashes/esm/utils.js");
|
|
508
|
+
/* harmony import */ var _modular_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./modular.js */ "./node_modules/@noble/curves/esm/abstract/modular.js");
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
// Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE.
|
|
512
|
+
const os2ip = _utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToNumberBE;
|
|
513
|
+
// Integer to Octet Stream (numberToBytesBE)
|
|
514
|
+
function i2osp(value, length) {
|
|
515
|
+
anum(value);
|
|
516
|
+
anum(length);
|
|
517
|
+
if (value < 0 || value >= 1 << (8 * length))
|
|
518
|
+
throw new Error('invalid I2OSP input: ' + value);
|
|
519
|
+
const res = Array.from({ length }).fill(0);
|
|
520
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
521
|
+
res[i] = value & 0xff;
|
|
522
|
+
value >>>= 8;
|
|
523
|
+
}
|
|
524
|
+
return new Uint8Array(res);
|
|
525
|
+
}
|
|
526
|
+
function strxor(a, b) {
|
|
527
|
+
const arr = new Uint8Array(a.length);
|
|
528
|
+
for (let i = 0; i < a.length; i++) {
|
|
529
|
+
arr[i] = a[i] ^ b[i];
|
|
530
|
+
}
|
|
531
|
+
return arr;
|
|
532
|
+
}
|
|
533
|
+
function anum(item) {
|
|
534
|
+
if (!Number.isSafeInteger(item))
|
|
535
|
+
throw new Error('number expected');
|
|
536
|
+
}
|
|
537
|
+
function normDST(DST) {
|
|
538
|
+
if (!(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.isBytes)(DST) && typeof DST !== 'string')
|
|
539
|
+
throw new Error('DST must be Uint8Array or string');
|
|
540
|
+
return typeof DST === 'string' ? (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.utf8ToBytes)(DST) : DST;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits.
|
|
544
|
+
* [RFC 9380 5.3.1](https://www.rfc-editor.org/rfc/rfc9380#section-5.3.1).
|
|
545
|
+
*/
|
|
546
|
+
function expand_message_xmd(msg, DST, lenInBytes, H) {
|
|
547
|
+
(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.abytes)(msg);
|
|
548
|
+
anum(lenInBytes);
|
|
549
|
+
DST = normDST(DST);
|
|
550
|
+
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
|
|
551
|
+
if (DST.length > 255)
|
|
552
|
+
DST = H((0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.concatBytes)((0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.utf8ToBytes)('H2C-OVERSIZE-DST-'), DST));
|
|
553
|
+
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
|
|
554
|
+
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
|
555
|
+
if (lenInBytes > 65535 || ell > 255)
|
|
556
|
+
throw new Error('expand_message_xmd: invalid lenInBytes');
|
|
557
|
+
const DST_prime = (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.concatBytes)(DST, i2osp(DST.length, 1));
|
|
558
|
+
const Z_pad = i2osp(0, r_in_bytes);
|
|
559
|
+
const l_i_b_str = i2osp(lenInBytes, 2); // len_in_bytes_str
|
|
560
|
+
const b = new Array(ell);
|
|
561
|
+
const b_0 = H((0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.concatBytes)(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime));
|
|
562
|
+
b[0] = H((0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.concatBytes)(b_0, i2osp(1, 1), DST_prime));
|
|
563
|
+
for (let i = 1; i <= ell; i++) {
|
|
564
|
+
const args = [strxor(b_0, b[i - 1]), i2osp(i + 1, 1), DST_prime];
|
|
565
|
+
b[i] = H((0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.concatBytes)(...args));
|
|
566
|
+
}
|
|
567
|
+
const pseudo_random_bytes = (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.concatBytes)(...b);
|
|
568
|
+
return pseudo_random_bytes.slice(0, lenInBytes);
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Produces a uniformly random byte string using an extendable-output function (XOF) H.
|
|
572
|
+
* 1. The collision resistance of H MUST be at least k bits.
|
|
573
|
+
* 2. H MUST be an XOF that has been proved indifferentiable from
|
|
574
|
+
* a random oracle under a reasonable cryptographic assumption.
|
|
575
|
+
* [RFC 9380 5.3.2](https://www.rfc-editor.org/rfc/rfc9380#section-5.3.2).
|
|
576
|
+
*/
|
|
577
|
+
function expand_message_xof(msg, DST, lenInBytes, k, H) {
|
|
578
|
+
(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.abytes)(msg);
|
|
579
|
+
anum(lenInBytes);
|
|
580
|
+
DST = normDST(DST);
|
|
581
|
+
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
|
|
582
|
+
// DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
|
|
583
|
+
if (DST.length > 255) {
|
|
584
|
+
const dkLen = Math.ceil((2 * k) / 8);
|
|
585
|
+
DST = H.create({ dkLen }).update((0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.utf8ToBytes)('H2C-OVERSIZE-DST-')).update(DST).digest();
|
|
586
|
+
}
|
|
587
|
+
if (lenInBytes > 65535 || DST.length > 255)
|
|
588
|
+
throw new Error('expand_message_xof: invalid lenInBytes');
|
|
589
|
+
return (H.create({ dkLen: lenInBytes })
|
|
590
|
+
.update(msg)
|
|
591
|
+
.update(i2osp(lenInBytes, 2))
|
|
592
|
+
// 2. DST_prime = DST || I2OSP(len(DST), 1)
|
|
593
|
+
.update(DST)
|
|
594
|
+
.update(i2osp(DST.length, 1))
|
|
595
|
+
.digest());
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
|
|
599
|
+
* [RFC 9380 5.2](https://www.rfc-editor.org/rfc/rfc9380#section-5.2).
|
|
600
|
+
* @param msg a byte string containing the message to hash
|
|
601
|
+
* @param count the number of elements of F to output
|
|
602
|
+
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
|
|
603
|
+
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
|
604
|
+
*/
|
|
605
|
+
function hash_to_field(msg, count, options) {
|
|
606
|
+
(0,_utils_js__WEBPACK_IMPORTED_MODULE_0__._validateObject)(options, {
|
|
607
|
+
p: 'bigint',
|
|
608
|
+
m: 'number',
|
|
609
|
+
k: 'number',
|
|
610
|
+
hash: 'function',
|
|
611
|
+
});
|
|
612
|
+
const { p, k, m, hash, expand, DST } = options;
|
|
613
|
+
if (!(0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.isHash)(options.hash))
|
|
614
|
+
throw new Error('expected valid hash');
|
|
615
|
+
(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.abytes)(msg);
|
|
616
|
+
anum(count);
|
|
617
|
+
const log2p = p.toString(2).length;
|
|
618
|
+
const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above
|
|
619
|
+
const len_in_bytes = count * m * L;
|
|
620
|
+
let prb; // pseudo_random_bytes
|
|
621
|
+
if (expand === 'xmd') {
|
|
622
|
+
prb = expand_message_xmd(msg, DST, len_in_bytes, hash);
|
|
623
|
+
}
|
|
624
|
+
else if (expand === 'xof') {
|
|
625
|
+
prb = expand_message_xof(msg, DST, len_in_bytes, k, hash);
|
|
626
|
+
}
|
|
627
|
+
else if (expand === '_internal_pass') {
|
|
628
|
+
// for internal tests only
|
|
629
|
+
prb = msg;
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
throw new Error('expand must be "xmd" or "xof"');
|
|
633
|
+
}
|
|
634
|
+
const u = new Array(count);
|
|
635
|
+
for (let i = 0; i < count; i++) {
|
|
636
|
+
const e = new Array(m);
|
|
637
|
+
for (let j = 0; j < m; j++) {
|
|
638
|
+
const elm_offset = L * (j + i * m);
|
|
639
|
+
const tv = prb.subarray(elm_offset, elm_offset + L);
|
|
640
|
+
e[j] = (0,_modular_js__WEBPACK_IMPORTED_MODULE_2__.mod)(os2ip(tv), p);
|
|
641
|
+
}
|
|
642
|
+
u[i] = e;
|
|
643
|
+
}
|
|
644
|
+
return u;
|
|
645
|
+
}
|
|
646
|
+
function isogenyMap(field, map) {
|
|
647
|
+
// Make same order as in spec
|
|
648
|
+
const coeff = map.map((i) => Array.from(i).reverse());
|
|
649
|
+
return (x, y) => {
|
|
650
|
+
const [xn, xd, yn, yd] = coeff.map((val) => val.reduce((acc, i) => field.add(field.mul(acc, x), i)));
|
|
651
|
+
// 6.6.3
|
|
652
|
+
// Exceptional cases of iso_map are inputs that cause the denominator of
|
|
653
|
+
// either rational function to evaluate to zero; such cases MUST return
|
|
654
|
+
// the identity point on E.
|
|
655
|
+
const [xd_inv, yd_inv] = (0,_modular_js__WEBPACK_IMPORTED_MODULE_2__.FpInvertBatch)(field, [xd, yd], true);
|
|
656
|
+
x = field.mul(xn, xd_inv); // xNum / xDen
|
|
657
|
+
y = field.mul(y, field.mul(yn, yd_inv)); // y * (yNum / yDev)
|
|
658
|
+
return { x, y };
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
const _DST_scalar = (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.utf8ToBytes)('HashToScalar-');
|
|
662
|
+
/** Creates hash-to-curve methods from EC Point and mapToCurve function. See {@link H2CHasher}. */
|
|
663
|
+
function createHasher(Point, mapToCurve, defaults) {
|
|
664
|
+
if (typeof mapToCurve !== 'function')
|
|
665
|
+
throw new Error('mapToCurve() must be defined');
|
|
666
|
+
function map(num) {
|
|
667
|
+
return Point.fromAffine(mapToCurve(num));
|
|
668
|
+
}
|
|
669
|
+
function clear(initial) {
|
|
670
|
+
const P = initial.clearCofactor();
|
|
671
|
+
if (P.equals(Point.ZERO))
|
|
672
|
+
return Point.ZERO; // zero will throw in assert
|
|
673
|
+
P.assertValidity();
|
|
674
|
+
return P;
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
defaults,
|
|
678
|
+
hashToCurve(msg, options) {
|
|
679
|
+
const opts = Object.assign({}, defaults, options);
|
|
680
|
+
const u = hash_to_field(msg, 2, opts);
|
|
681
|
+
const u0 = map(u[0]);
|
|
682
|
+
const u1 = map(u[1]);
|
|
683
|
+
return clear(u0.add(u1));
|
|
684
|
+
},
|
|
685
|
+
encodeToCurve(msg, options) {
|
|
686
|
+
const optsDst = defaults.encodeDST ? { DST: defaults.encodeDST } : {};
|
|
687
|
+
const opts = Object.assign({}, defaults, optsDst, options);
|
|
688
|
+
const u = hash_to_field(msg, 1, opts);
|
|
689
|
+
const u0 = map(u[0]);
|
|
690
|
+
return clear(u0);
|
|
691
|
+
},
|
|
692
|
+
/** See {@link H2CHasher} */
|
|
693
|
+
mapToCurve(scalars) {
|
|
694
|
+
if (!Array.isArray(scalars))
|
|
695
|
+
throw new Error('expected array of bigints');
|
|
696
|
+
for (const i of scalars)
|
|
697
|
+
if (typeof i !== 'bigint')
|
|
698
|
+
throw new Error('expected array of bigints');
|
|
699
|
+
return clear(map(scalars));
|
|
700
|
+
},
|
|
701
|
+
// hash_to_scalar can produce 0: https://www.rfc-editor.org/errata/eid8393
|
|
702
|
+
// RFC 9380, draft-irtf-cfrg-bbs-signatures-08
|
|
703
|
+
hashToScalar(msg, options) {
|
|
704
|
+
// @ts-ignore
|
|
705
|
+
const N = Point.Fn.ORDER;
|
|
706
|
+
const opts = Object.assign({}, defaults, { p: N, m: 1, DST: _DST_scalar }, options);
|
|
707
|
+
return hash_to_field(msg, 1, opts)[0][0];
|
|
708
|
+
},
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
//# sourceMappingURL=hash-to-curve.js.map
|
|
712
|
+
|
|
713
|
+
/***/ }),
|
|
714
|
+
|
|
715
|
+
/***/ "./node_modules/@noble/curves/esm/abstract/modular.js":
|
|
716
|
+
/*!************************************************************!*\
|
|
717
|
+
!*** ./node_modules/@noble/curves/esm/abstract/modular.js ***!
|
|
718
|
+
\************************************************************/
|
|
719
|
+
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
720
|
+
|
|
721
|
+
__webpack_require__.r(__webpack_exports__);
|
|
722
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
723
|
+
/* harmony export */ Field: () => (/* binding */ Field),
|
|
724
|
+
/* harmony export */ FpDiv: () => (/* binding */ FpDiv),
|
|
725
|
+
/* harmony export */ FpInvertBatch: () => (/* binding */ FpInvertBatch),
|
|
726
|
+
/* harmony export */ FpIsSquare: () => (/* binding */ FpIsSquare),
|
|
727
|
+
/* harmony export */ FpLegendre: () => (/* binding */ FpLegendre),
|
|
728
|
+
/* harmony export */ FpPow: () => (/* binding */ FpPow),
|
|
729
|
+
/* harmony export */ FpSqrt: () => (/* binding */ FpSqrt),
|
|
730
|
+
/* harmony export */ FpSqrtEven: () => (/* binding */ FpSqrtEven),
|
|
731
|
+
/* harmony export */ FpSqrtOdd: () => (/* binding */ FpSqrtOdd),
|
|
732
|
+
/* harmony export */ getFieldBytesLength: () => (/* binding */ getFieldBytesLength),
|
|
733
|
+
/* harmony export */ getMinHashLength: () => (/* binding */ getMinHashLength),
|
|
734
|
+
/* harmony export */ hashToPrivateScalar: () => (/* binding */ hashToPrivateScalar),
|
|
735
|
+
/* harmony export */ invert: () => (/* binding */ invert),
|
|
736
|
+
/* harmony export */ isNegativeLE: () => (/* binding */ isNegativeLE),
|
|
737
|
+
/* harmony export */ mapHashToField: () => (/* binding */ mapHashToField),
|
|
738
|
+
/* harmony export */ mod: () => (/* binding */ mod),
|
|
739
|
+
/* harmony export */ nLength: () => (/* binding */ nLength),
|
|
740
|
+
/* harmony export */ pow: () => (/* binding */ pow),
|
|
741
|
+
/* harmony export */ pow2: () => (/* binding */ pow2),
|
|
742
|
+
/* harmony export */ tonelliShanks: () => (/* binding */ tonelliShanks),
|
|
743
|
+
/* harmony export */ validateField: () => (/* binding */ validateField)
|
|
744
|
+
/* harmony export */ });
|
|
745
|
+
/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils.js */ "./node_modules/@noble/curves/esm/utils.js");
|
|
746
|
+
/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils.js */ "./node_modules/@noble/hashes/esm/utils.js");
|
|
747
|
+
/**
|
|
748
|
+
* Utils for modular division and fields.
|
|
749
|
+
* Field over 11 is a finite (Galois) field is integer number operations `mod 11`.
|
|
750
|
+
* There is no division: it is replaced by modular multiplicative inverse.
|
|
751
|
+
* @module
|
|
752
|
+
*/
|
|
753
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
754
|
+
|
|
755
|
+
// prettier-ignore
|
|
756
|
+
const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
|
|
757
|
+
// prettier-ignore
|
|
758
|
+
const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _7n = /* @__PURE__ */ BigInt(7);
|
|
759
|
+
// prettier-ignore
|
|
760
|
+
const _8n = /* @__PURE__ */ BigInt(8), _9n = /* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);
|
|
761
|
+
// Calculates a modulo b
|
|
762
|
+
function mod(a, b) {
|
|
763
|
+
const result = a % b;
|
|
764
|
+
return result >= _0n ? result : b + result;
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Efficiently raise num to power and do modular division.
|
|
768
|
+
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
769
|
+
* @example
|
|
770
|
+
* pow(2n, 6n, 11n) // 64n % 11n == 9n
|
|
771
|
+
*/
|
|
772
|
+
function pow(num, power, modulo) {
|
|
773
|
+
return FpPow(Field(modulo), num, power);
|
|
774
|
+
}
|
|
775
|
+
/** Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)` */
|
|
776
|
+
function pow2(x, power, modulo) {
|
|
777
|
+
let res = x;
|
|
778
|
+
while (power-- > _0n) {
|
|
779
|
+
res *= res;
|
|
780
|
+
res %= modulo;
|
|
781
|
+
}
|
|
782
|
+
return res;
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Inverses number over modulo.
|
|
786
|
+
* Implemented using [Euclidean GCD](https://brilliant.org/wiki/extended-euclidean-algorithm/).
|
|
787
|
+
*/
|
|
788
|
+
function invert(number, modulo) {
|
|
789
|
+
if (number === _0n)
|
|
790
|
+
throw new Error('invert: expected non-zero number');
|
|
791
|
+
if (modulo <= _0n)
|
|
792
|
+
throw new Error('invert: expected positive modulus, got ' + modulo);
|
|
793
|
+
// Fermat's little theorem "CT-like" version inv(n) = n^(m-2) mod m is 30x slower.
|
|
794
|
+
let a = mod(number, modulo);
|
|
795
|
+
let b = modulo;
|
|
796
|
+
// prettier-ignore
|
|
797
|
+
let x = _0n, y = _1n, u = _1n, v = _0n;
|
|
798
|
+
while (a !== _0n) {
|
|
799
|
+
// JIT applies optimization if those two lines follow each other
|
|
800
|
+
const q = b / a;
|
|
801
|
+
const r = b % a;
|
|
802
|
+
const m = x - u * q;
|
|
803
|
+
const n = y - v * q;
|
|
804
|
+
// prettier-ignore
|
|
805
|
+
b = a, a = r, x = u, y = v, u = m, v = n;
|
|
806
|
+
}
|
|
807
|
+
const gcd = b;
|
|
808
|
+
if (gcd !== _1n)
|
|
809
|
+
throw new Error('invert: does not exist');
|
|
810
|
+
return mod(x, modulo);
|
|
811
|
+
}
|
|
812
|
+
function assertIsSquare(Fp, root, n) {
|
|
813
|
+
if (!Fp.eql(Fp.sqr(root), n))
|
|
814
|
+
throw new Error('Cannot find square root');
|
|
815
|
+
}
|
|
816
|
+
// Not all roots are possible! Example which will throw:
|
|
817
|
+
// const NUM =
|
|
818
|
+
// n = 72057594037927816n;
|
|
819
|
+
// Fp = Field(BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'));
|
|
820
|
+
function sqrt3mod4(Fp, n) {
|
|
821
|
+
const p1div4 = (Fp.ORDER + _1n) / _4n;
|
|
822
|
+
const root = Fp.pow(n, p1div4);
|
|
823
|
+
assertIsSquare(Fp, root, n);
|
|
824
|
+
return root;
|
|
825
|
+
}
|
|
826
|
+
function sqrt5mod8(Fp, n) {
|
|
827
|
+
const p5div8 = (Fp.ORDER - _5n) / _8n;
|
|
828
|
+
const n2 = Fp.mul(n, _2n);
|
|
829
|
+
const v = Fp.pow(n2, p5div8);
|
|
830
|
+
const nv = Fp.mul(n, v);
|
|
831
|
+
const i = Fp.mul(Fp.mul(nv, _2n), v);
|
|
832
|
+
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
|
833
|
+
assertIsSquare(Fp, root, n);
|
|
834
|
+
return root;
|
|
835
|
+
}
|
|
836
|
+
// Based on RFC9380, Kong algorithm
|
|
837
|
+
// prettier-ignore
|
|
838
|
+
function sqrt9mod16(P) {
|
|
839
|
+
const Fp_ = Field(P);
|
|
840
|
+
const tn = tonelliShanks(P);
|
|
841
|
+
const c1 = tn(Fp_, Fp_.neg(Fp_.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
842
|
+
const c2 = tn(Fp_, c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
843
|
+
const c3 = tn(Fp_, Fp_.neg(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
844
|
+
const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
845
|
+
return (Fp, n) => {
|
|
846
|
+
let tv1 = Fp.pow(n, c4); // 1. tv1 = x^c4
|
|
847
|
+
let tv2 = Fp.mul(tv1, c1); // 2. tv2 = c1 * tv1
|
|
848
|
+
const tv3 = Fp.mul(tv1, c2); // 3. tv3 = c2 * tv1
|
|
849
|
+
const tv4 = Fp.mul(tv1, c3); // 4. tv4 = c3 * tv1
|
|
850
|
+
const e1 = Fp.eql(Fp.sqr(tv2), n); // 5. e1 = (tv2^2) == x
|
|
851
|
+
const e2 = Fp.eql(Fp.sqr(tv3), n); // 6. e2 = (tv3^2) == x
|
|
852
|
+
tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
853
|
+
tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
854
|
+
const e3 = Fp.eql(Fp.sqr(tv2), n); // 9. e3 = (tv2^2) == x
|
|
855
|
+
const root = Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select sqrt from tv1 & tv2
|
|
856
|
+
assertIsSquare(Fp, root, n);
|
|
857
|
+
return root;
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Tonelli-Shanks square root search algorithm.
|
|
862
|
+
* 1. https://eprint.iacr.org/2012/685.pdf (page 12)
|
|
863
|
+
* 2. Square Roots from 1; 24, 51, 10 to Dan Shanks
|
|
864
|
+
* @param P field order
|
|
865
|
+
* @returns function that takes field Fp (created from P) and number n
|
|
866
|
+
*/
|
|
867
|
+
function tonelliShanks(P) {
|
|
868
|
+
// Initialization (precomputation).
|
|
869
|
+
// Caching initialization could boost perf by 7%.
|
|
870
|
+
if (P < _3n)
|
|
871
|
+
throw new Error('sqrt is not defined for small field');
|
|
872
|
+
// Factor P - 1 = Q * 2^S, where Q is odd
|
|
873
|
+
let Q = P - _1n;
|
|
874
|
+
let S = 0;
|
|
875
|
+
while (Q % _2n === _0n) {
|
|
876
|
+
Q /= _2n;
|
|
877
|
+
S++;
|
|
878
|
+
}
|
|
879
|
+
// Find the first quadratic non-residue Z >= 2
|
|
880
|
+
let Z = _2n;
|
|
881
|
+
const _Fp = Field(P);
|
|
882
|
+
while (FpLegendre(_Fp, Z) === 1) {
|
|
883
|
+
// Basic primality test for P. After x iterations, chance of
|
|
884
|
+
// not finding quadratic non-residue is 2^x, so 2^1000.
|
|
885
|
+
if (Z++ > 1000)
|
|
886
|
+
throw new Error('Cannot find square root: probably non-prime P');
|
|
887
|
+
}
|
|
888
|
+
// Fast-path; usually done before Z, but we do "primality test".
|
|
889
|
+
if (S === 1)
|
|
890
|
+
return sqrt3mod4;
|
|
891
|
+
// Slow-path
|
|
892
|
+
// TODO: test on Fp2 and others
|
|
893
|
+
let cc = _Fp.pow(Z, Q); // c = z^Q
|
|
894
|
+
const Q1div2 = (Q + _1n) / _2n;
|
|
895
|
+
return function tonelliSlow(Fp, n) {
|
|
896
|
+
if (Fp.is0(n))
|
|
897
|
+
return n;
|
|
898
|
+
// Check if n is a quadratic residue using Legendre symbol
|
|
899
|
+
if (FpLegendre(Fp, n) !== 1)
|
|
900
|
+
throw new Error('Cannot find square root');
|
|
901
|
+
// Initialize variables for the main loop
|
|
902
|
+
let M = S;
|
|
903
|
+
let c = Fp.mul(Fp.ONE, cc); // c = z^Q, move cc from field _Fp into field Fp
|
|
904
|
+
let t = Fp.pow(n, Q); // t = n^Q, first guess at the fudge factor
|
|
905
|
+
let R = Fp.pow(n, Q1div2); // R = n^((Q+1)/2), first guess at the square root
|
|
906
|
+
// Main loop
|
|
907
|
+
// while t != 1
|
|
908
|
+
while (!Fp.eql(t, Fp.ONE)) {
|
|
909
|
+
if (Fp.is0(t))
|
|
910
|
+
return Fp.ZERO; // if t=0 return R=0
|
|
911
|
+
let i = 1;
|
|
912
|
+
// Find the smallest i >= 1 such that t^(2^i) ≡ 1 (mod P)
|
|
913
|
+
let t_tmp = Fp.sqr(t); // t^(2^1)
|
|
914
|
+
while (!Fp.eql(t_tmp, Fp.ONE)) {
|
|
915
|
+
i++;
|
|
916
|
+
t_tmp = Fp.sqr(t_tmp); // t^(2^2)...
|
|
917
|
+
if (i === M)
|
|
918
|
+
throw new Error('Cannot find square root');
|
|
919
|
+
}
|
|
920
|
+
// Calculate the exponent for b: 2^(M - i - 1)
|
|
921
|
+
const exponent = _1n << BigInt(M - i - 1); // bigint is important
|
|
922
|
+
const b = Fp.pow(c, exponent); // b = 2^(M - i - 1)
|
|
923
|
+
// Update variables
|
|
924
|
+
M = i;
|
|
925
|
+
c = Fp.sqr(b); // c = b^2
|
|
926
|
+
t = Fp.mul(t, c); // t = (t * b^2)
|
|
927
|
+
R = Fp.mul(R, b); // R = R*b
|
|
928
|
+
}
|
|
929
|
+
return R;
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Square root for a finite field. Will try optimized versions first:
|
|
934
|
+
*
|
|
935
|
+
* 1. P ≡ 3 (mod 4)
|
|
936
|
+
* 2. P ≡ 5 (mod 8)
|
|
937
|
+
* 3. P ≡ 9 (mod 16)
|
|
938
|
+
* 4. Tonelli-Shanks algorithm
|
|
939
|
+
*
|
|
940
|
+
* Different algorithms can give different roots, it is up to user to decide which one they want.
|
|
941
|
+
* For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
|
|
942
|
+
*/
|
|
943
|
+
function FpSqrt(P) {
|
|
944
|
+
// P ≡ 3 (mod 4) => √n = n^((P+1)/4)
|
|
945
|
+
if (P % _4n === _3n)
|
|
946
|
+
return sqrt3mod4;
|
|
947
|
+
// P ≡ 5 (mod 8) => Atkin algorithm, page 10 of https://eprint.iacr.org/2012/685.pdf
|
|
948
|
+
if (P % _8n === _5n)
|
|
949
|
+
return sqrt5mod8;
|
|
950
|
+
// P ≡ 9 (mod 16) => Kong algorithm, page 11 of https://eprint.iacr.org/2012/685.pdf (algorithm 4)
|
|
951
|
+
if (P % _16n === _9n)
|
|
952
|
+
return sqrt9mod16(P);
|
|
953
|
+
// Tonelli-Shanks algorithm
|
|
954
|
+
return tonelliShanks(P);
|
|
955
|
+
}
|
|
956
|
+
// Little-endian check for first LE bit (last BE bit);
|
|
957
|
+
const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
|
|
958
|
+
// prettier-ignore
|
|
959
|
+
const FIELD_FIELDS = [
|
|
960
|
+
'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
|
|
961
|
+
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
|
962
|
+
'addN', 'subN', 'mulN', 'sqrN'
|
|
963
|
+
];
|
|
964
|
+
function validateField(field) {
|
|
965
|
+
const initial = {
|
|
966
|
+
ORDER: 'bigint',
|
|
967
|
+
MASK: 'bigint',
|
|
968
|
+
BYTES: 'number',
|
|
969
|
+
BITS: 'number',
|
|
970
|
+
};
|
|
971
|
+
const opts = FIELD_FIELDS.reduce((map, val) => {
|
|
972
|
+
map[val] = 'function';
|
|
973
|
+
return map;
|
|
974
|
+
}, initial);
|
|
975
|
+
(0,_utils_js__WEBPACK_IMPORTED_MODULE_0__._validateObject)(field, opts);
|
|
976
|
+
// const max = 16384;
|
|
977
|
+
// if (field.BYTES < 1 || field.BYTES > max) throw new Error('invalid field');
|
|
978
|
+
// if (field.BITS < 1 || field.BITS > 8 * max) throw new Error('invalid field');
|
|
979
|
+
return field;
|
|
980
|
+
}
|
|
981
|
+
// Generic field functions
|
|
982
|
+
/**
|
|
983
|
+
* Same as `pow` but for Fp: non-constant-time.
|
|
984
|
+
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
985
|
+
*/
|
|
986
|
+
function FpPow(Fp, num, power) {
|
|
987
|
+
if (power < _0n)
|
|
988
|
+
throw new Error('invalid exponent, negatives unsupported');
|
|
989
|
+
if (power === _0n)
|
|
990
|
+
return Fp.ONE;
|
|
991
|
+
if (power === _1n)
|
|
992
|
+
return num;
|
|
993
|
+
let p = Fp.ONE;
|
|
994
|
+
let d = num;
|
|
995
|
+
while (power > _0n) {
|
|
996
|
+
if (power & _1n)
|
|
997
|
+
p = Fp.mul(p, d);
|
|
998
|
+
d = Fp.sqr(d);
|
|
999
|
+
power >>= _1n;
|
|
1000
|
+
}
|
|
1001
|
+
return p;
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Efficiently invert an array of Field elements.
|
|
1005
|
+
* Exception-free. Will return `undefined` for 0 elements.
|
|
1006
|
+
* @param passZero map 0 to 0 (instead of undefined)
|
|
1007
|
+
*/
|
|
1008
|
+
function FpInvertBatch(Fp, nums, passZero = false) {
|
|
1009
|
+
const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : undefined);
|
|
1010
|
+
// Walk from first to last, multiply them by each other MOD p
|
|
1011
|
+
const multipliedAcc = nums.reduce((acc, num, i) => {
|
|
1012
|
+
if (Fp.is0(num))
|
|
1013
|
+
return acc;
|
|
1014
|
+
inverted[i] = acc;
|
|
1015
|
+
return Fp.mul(acc, num);
|
|
1016
|
+
}, Fp.ONE);
|
|
1017
|
+
// Invert last element
|
|
1018
|
+
const invertedAcc = Fp.inv(multipliedAcc);
|
|
1019
|
+
// Walk from last to first, multiply them by inverted each other MOD p
|
|
1020
|
+
nums.reduceRight((acc, num, i) => {
|
|
1021
|
+
if (Fp.is0(num))
|
|
1022
|
+
return acc;
|
|
1023
|
+
inverted[i] = Fp.mul(acc, inverted[i]);
|
|
1024
|
+
return Fp.mul(acc, num);
|
|
1025
|
+
}, invertedAcc);
|
|
1026
|
+
return inverted;
|
|
1027
|
+
}
|
|
1028
|
+
// TODO: remove
|
|
1029
|
+
function FpDiv(Fp, lhs, rhs) {
|
|
1030
|
+
return Fp.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, Fp.ORDER) : Fp.inv(rhs));
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Legendre symbol.
|
|
1034
|
+
* Legendre constant is used to calculate Legendre symbol (a | p)
|
|
1035
|
+
* which denotes the value of a^((p-1)/2) (mod p).
|
|
1036
|
+
*
|
|
1037
|
+
* * (a | p) ≡ 1 if a is a square (mod p), quadratic residue
|
|
1038
|
+
* * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
|
|
1039
|
+
* * (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
1040
|
+
*/
|
|
1041
|
+
function FpLegendre(Fp, n) {
|
|
1042
|
+
// We can use 3rd argument as optional cache of this value
|
|
1043
|
+
// but seems unneeded for now. The operation is very fast.
|
|
1044
|
+
const p1mod2 = (Fp.ORDER - _1n) / _2n;
|
|
1045
|
+
const powered = Fp.pow(n, p1mod2);
|
|
1046
|
+
const yes = Fp.eql(powered, Fp.ONE);
|
|
1047
|
+
const zero = Fp.eql(powered, Fp.ZERO);
|
|
1048
|
+
const no = Fp.eql(powered, Fp.neg(Fp.ONE));
|
|
1049
|
+
if (!yes && !zero && !no)
|
|
1050
|
+
throw new Error('invalid Legendre symbol result');
|
|
1051
|
+
return yes ? 1 : zero ? 0 : -1;
|
|
1052
|
+
}
|
|
1053
|
+
// This function returns True whenever the value x is a square in the field F.
|
|
1054
|
+
function FpIsSquare(Fp, n) {
|
|
1055
|
+
const l = FpLegendre(Fp, n);
|
|
1056
|
+
return l === 1;
|
|
1057
|
+
}
|
|
1058
|
+
// CURVE.n lengths
|
|
1059
|
+
function nLength(n, nBitLength) {
|
|
1060
|
+
// Bit size, byte size of CURVE.n
|
|
1061
|
+
if (nBitLength !== undefined)
|
|
1062
|
+
(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.anumber)(nBitLength);
|
|
1063
|
+
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
|
|
1064
|
+
const nByteLength = Math.ceil(_nBitLength / 8);
|
|
1065
|
+
return { nBitLength: _nBitLength, nByteLength };
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Creates a finite field. Major performance optimizations:
|
|
1069
|
+
* * 1. Denormalized operations like mulN instead of mul.
|
|
1070
|
+
* * 2. Identical object shape: never add or remove keys.
|
|
1071
|
+
* * 3. `Object.freeze`.
|
|
1072
|
+
* Fragile: always run a benchmark on a change.
|
|
1073
|
+
* Security note: operations don't check 'isValid' for all elements for performance reasons,
|
|
1074
|
+
* it is caller responsibility to check this.
|
|
1075
|
+
* This is low-level code, please make sure you know what you're doing.
|
|
1076
|
+
*
|
|
1077
|
+
* Note about field properties:
|
|
1078
|
+
* * CHARACTERISTIC p = prime number, number of elements in main subgroup.
|
|
1079
|
+
* * ORDER q = similar to cofactor in curves, may be composite `q = p^m`.
|
|
1080
|
+
*
|
|
1081
|
+
* @param ORDER field order, probably prime, or could be composite
|
|
1082
|
+
* @param bitLen how many bits the field consumes
|
|
1083
|
+
* @param isLE (default: false) if encoding / decoding should be in little-endian
|
|
1084
|
+
* @param redef optional faster redefinitions of sqrt and other methods
|
|
1085
|
+
*/
|
|
1086
|
+
function Field(ORDER, bitLenOrOpts, // TODO: use opts only in v2?
|
|
1087
|
+
isLE = false, opts = {}) {
|
|
1088
|
+
if (ORDER <= _0n)
|
|
1089
|
+
throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
|
|
1090
|
+
let _nbitLength = undefined;
|
|
1091
|
+
let _sqrt = undefined;
|
|
1092
|
+
let modFromBytes = false;
|
|
1093
|
+
let allowedLengths = undefined;
|
|
1094
|
+
if (typeof bitLenOrOpts === 'object' && bitLenOrOpts != null) {
|
|
1095
|
+
if (opts.sqrt || isLE)
|
|
1096
|
+
throw new Error('cannot specify opts in two arguments');
|
|
1097
|
+
const _opts = bitLenOrOpts;
|
|
1098
|
+
if (_opts.BITS)
|
|
1099
|
+
_nbitLength = _opts.BITS;
|
|
1100
|
+
if (_opts.sqrt)
|
|
1101
|
+
_sqrt = _opts.sqrt;
|
|
1102
|
+
if (typeof _opts.isLE === 'boolean')
|
|
1103
|
+
isLE = _opts.isLE;
|
|
1104
|
+
if (typeof _opts.modFromBytes === 'boolean')
|
|
1105
|
+
modFromBytes = _opts.modFromBytes;
|
|
1106
|
+
allowedLengths = _opts.allowedLengths;
|
|
1107
|
+
}
|
|
1108
|
+
else {
|
|
1109
|
+
if (typeof bitLenOrOpts === 'number')
|
|
1110
|
+
_nbitLength = bitLenOrOpts;
|
|
1111
|
+
if (opts.sqrt)
|
|
1112
|
+
_sqrt = opts.sqrt;
|
|
1113
|
+
}
|
|
1114
|
+
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, _nbitLength);
|
|
1115
|
+
if (BYTES > 2048)
|
|
1116
|
+
throw new Error('invalid field: expected ORDER of <= 2048 bytes');
|
|
1117
|
+
let sqrtP; // cached sqrtP
|
|
1118
|
+
const f = Object.freeze({
|
|
1119
|
+
ORDER,
|
|
1120
|
+
isLE,
|
|
1121
|
+
BITS,
|
|
1122
|
+
BYTES,
|
|
1123
|
+
MASK: (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bitMask)(BITS),
|
|
1124
|
+
ZERO: _0n,
|
|
1125
|
+
ONE: _1n,
|
|
1126
|
+
allowedLengths: allowedLengths,
|
|
1127
|
+
create: (num) => mod(num, ORDER),
|
|
1128
|
+
isValid: (num) => {
|
|
1129
|
+
if (typeof num !== 'bigint')
|
|
1130
|
+
throw new Error('invalid field element: expected bigint, got ' + typeof num);
|
|
1131
|
+
return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
|
|
1132
|
+
},
|
|
1133
|
+
is0: (num) => num === _0n,
|
|
1134
|
+
// is valid and invertible
|
|
1135
|
+
isValidNot0: (num) => !f.is0(num) && f.isValid(num),
|
|
1136
|
+
isOdd: (num) => (num & _1n) === _1n,
|
|
1137
|
+
neg: (num) => mod(-num, ORDER),
|
|
1138
|
+
eql: (lhs, rhs) => lhs === rhs,
|
|
1139
|
+
sqr: (num) => mod(num * num, ORDER),
|
|
1140
|
+
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
|
|
1141
|
+
sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
|
|
1142
|
+
mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
|
|
1143
|
+
pow: (num, power) => FpPow(f, num, power),
|
|
1144
|
+
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
|
|
1145
|
+
// Same as above, but doesn't normalize
|
|
1146
|
+
sqrN: (num) => num * num,
|
|
1147
|
+
addN: (lhs, rhs) => lhs + rhs,
|
|
1148
|
+
subN: (lhs, rhs) => lhs - rhs,
|
|
1149
|
+
mulN: (lhs, rhs) => lhs * rhs,
|
|
1150
|
+
inv: (num) => invert(num, ORDER),
|
|
1151
|
+
sqrt: _sqrt ||
|
|
1152
|
+
((n) => {
|
|
1153
|
+
if (!sqrtP)
|
|
1154
|
+
sqrtP = FpSqrt(ORDER);
|
|
1155
|
+
return sqrtP(f, n);
|
|
1156
|
+
}),
|
|
1157
|
+
toBytes: (num) => (isLE ? (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.numberToBytesLE)(num, BYTES) : (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.numberToBytesBE)(num, BYTES)),
|
|
1158
|
+
fromBytes: (bytes, skipValidation = true) => {
|
|
1159
|
+
if (allowedLengths) {
|
|
1160
|
+
if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
|
|
1161
|
+
throw new Error('Field.fromBytes: expected ' + allowedLengths + ' bytes, got ' + bytes.length);
|
|
1162
|
+
}
|
|
1163
|
+
const padded = new Uint8Array(BYTES);
|
|
1164
|
+
// isLE add 0 to right, !isLE to the left.
|
|
1165
|
+
padded.set(bytes, isLE ? 0 : padded.length - bytes.length);
|
|
1166
|
+
bytes = padded;
|
|
1167
|
+
}
|
|
1168
|
+
if (bytes.length !== BYTES)
|
|
1169
|
+
throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
|
|
1170
|
+
let scalar = isLE ? (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToNumberLE)(bytes) : (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToNumberBE)(bytes);
|
|
1171
|
+
if (modFromBytes)
|
|
1172
|
+
scalar = mod(scalar, ORDER);
|
|
1173
|
+
if (!skipValidation)
|
|
1174
|
+
if (!f.isValid(scalar))
|
|
1175
|
+
throw new Error('invalid field element: outside of range 0..ORDER');
|
|
1176
|
+
// NOTE: we don't validate scalar here, please use isValid. This done such way because some
|
|
1177
|
+
// protocol may allow non-reduced scalar that reduced later or changed some other way.
|
|
1178
|
+
return scalar;
|
|
1179
|
+
},
|
|
1180
|
+
// TODO: we don't need it here, move out to separate fn
|
|
1181
|
+
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
1182
|
+
// We can't move this out because Fp6, Fp12 implement it
|
|
1183
|
+
// and it's unclear what to return in there.
|
|
1184
|
+
cmov: (a, b, c) => (c ? b : a),
|
|
1185
|
+
});
|
|
1186
|
+
return Object.freeze(f);
|
|
1187
|
+
}
|
|
1188
|
+
// Generic random scalar, we can do same for other fields if via Fp2.mul(Fp2.ONE, Fp2.random)?
|
|
1189
|
+
// This allows unsafe methods like ignore bias or zero. These unsafe, but often used in different protocols (if deterministic RNG).
|
|
1190
|
+
// which mean we cannot force this via opts.
|
|
1191
|
+
// Not sure what to do with randomBytes, we can accept it inside opts if wanted.
|
|
1192
|
+
// Probably need to export getMinHashLength somewhere?
|
|
1193
|
+
// random(bytes?: Uint8Array, unsafeAllowZero = false, unsafeAllowBias = false) {
|
|
1194
|
+
// const LEN = !unsafeAllowBias ? getMinHashLength(ORDER) : BYTES;
|
|
1195
|
+
// if (bytes === undefined) bytes = randomBytes(LEN); // _opts.randomBytes?
|
|
1196
|
+
// const num = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
|
1197
|
+
// // `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
|
1198
|
+
// const reduced = unsafeAllowZero ? mod(num, ORDER) : mod(num, ORDER - _1n) + _1n;
|
|
1199
|
+
// return reduced;
|
|
1200
|
+
// },
|
|
1201
|
+
function FpSqrtOdd(Fp, elm) {
|
|
1202
|
+
if (!Fp.isOdd)
|
|
1203
|
+
throw new Error("Field doesn't have isOdd");
|
|
1204
|
+
const root = Fp.sqrt(elm);
|
|
1205
|
+
return Fp.isOdd(root) ? root : Fp.neg(root);
|
|
1206
|
+
}
|
|
1207
|
+
function FpSqrtEven(Fp, elm) {
|
|
1208
|
+
if (!Fp.isOdd)
|
|
1209
|
+
throw new Error("Field doesn't have isOdd");
|
|
1210
|
+
const root = Fp.sqrt(elm);
|
|
1211
|
+
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1214
|
+
* "Constant-time" private key generation utility.
|
|
1215
|
+
* Same as mapKeyToField, but accepts less bytes (40 instead of 48 for 32-byte field).
|
|
1216
|
+
* Which makes it slightly more biased, less secure.
|
|
1217
|
+
* @deprecated use `mapKeyToField` instead
|
|
1218
|
+
*/
|
|
1219
|
+
function hashToPrivateScalar(hash, groupOrder, isLE = false) {
|
|
1220
|
+
hash = (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.ensureBytes)('privateHash', hash);
|
|
1221
|
+
const hashLen = hash.length;
|
|
1222
|
+
const minLen = nLength(groupOrder).nByteLength + 8;
|
|
1223
|
+
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
|
|
1224
|
+
throw new Error('hashToPrivateScalar: expected ' + minLen + '-1024 bytes of input, got ' + hashLen);
|
|
1225
|
+
const num = isLE ? (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToNumberLE)(hash) : (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToNumberBE)(hash);
|
|
1226
|
+
return mod(num, groupOrder - _1n) + _1n;
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Returns total number of bytes consumed by the field element.
|
|
1230
|
+
* For example, 32 bytes for usual 256-bit weierstrass curve.
|
|
1231
|
+
* @param fieldOrder number of field elements, usually CURVE.n
|
|
1232
|
+
* @returns byte length of field
|
|
1233
|
+
*/
|
|
1234
|
+
function getFieldBytesLength(fieldOrder) {
|
|
1235
|
+
if (typeof fieldOrder !== 'bigint')
|
|
1236
|
+
throw new Error('field order must be bigint');
|
|
1237
|
+
const bitLength = fieldOrder.toString(2).length;
|
|
1238
|
+
return Math.ceil(bitLength / 8);
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Returns minimal amount of bytes that can be safely reduced
|
|
1242
|
+
* by field order.
|
|
1243
|
+
* Should be 2^-128 for 128-bit curve such as P256.
|
|
1244
|
+
* @param fieldOrder number of field elements, usually CURVE.n
|
|
1245
|
+
* @returns byte length of target hash
|
|
1246
|
+
*/
|
|
1247
|
+
function getMinHashLength(fieldOrder) {
|
|
1248
|
+
const length = getFieldBytesLength(fieldOrder);
|
|
1249
|
+
return length + Math.ceil(length / 2);
|
|
1250
|
+
}
|
|
1251
|
+
/**
|
|
1252
|
+
* "Constant-time" private key generation utility.
|
|
1253
|
+
* Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
1254
|
+
* and convert them into private scalar, with the modulo bias being negligible.
|
|
1255
|
+
* Needs at least 48 bytes of input for 32-byte private key.
|
|
1256
|
+
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
1257
|
+
* FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final
|
|
1258
|
+
* RFC 9380, https://www.rfc-editor.org/rfc/rfc9380#section-5
|
|
1259
|
+
* @param hash hash output from SHA3 or a similar function
|
|
1260
|
+
* @param groupOrder size of subgroup - (e.g. secp256k1.CURVE.n)
|
|
1261
|
+
* @param isLE interpret hash bytes as LE num
|
|
1262
|
+
* @returns valid private scalar
|
|
1263
|
+
*/
|
|
1264
|
+
function mapHashToField(key, fieldOrder, isLE = false) {
|
|
1265
|
+
const len = key.length;
|
|
1266
|
+
const fieldLen = getFieldBytesLength(fieldOrder);
|
|
1267
|
+
const minLen = getMinHashLength(fieldOrder);
|
|
1268
|
+
// No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
|
|
1269
|
+
if (len < 16 || len < minLen || len > 1024)
|
|
1270
|
+
throw new Error('expected ' + minLen + '-1024 bytes of input, got ' + len);
|
|
1271
|
+
const num = isLE ? (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToNumberLE)(key) : (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToNumberBE)(key);
|
|
1272
|
+
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
|
1273
|
+
const reduced = mod(num, fieldOrder - _1n) + _1n;
|
|
1274
|
+
return isLE ? (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.numberToBytesLE)(reduced, fieldLen) : (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.numberToBytesBE)(reduced, fieldLen);
|
|
1275
|
+
}
|
|
1276
|
+
//# sourceMappingURL=modular.js.map
|
|
1277
|
+
|
|
1278
|
+
/***/ }),
|
|
1279
|
+
|
|
1280
|
+
/***/ "./node_modules/@noble/curves/esm/utils.js":
|
|
1281
|
+
/*!*************************************************!*\
|
|
1282
|
+
!*** ./node_modules/@noble/curves/esm/utils.js ***!
|
|
1283
|
+
\*************************************************/
|
|
1284
|
+
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
1285
|
+
|
|
1286
|
+
__webpack_require__.r(__webpack_exports__);
|
|
1287
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1288
|
+
/* harmony export */ _abool2: () => (/* binding */ _abool2),
|
|
1289
|
+
/* harmony export */ _abytes2: () => (/* binding */ _abytes2),
|
|
1290
|
+
/* harmony export */ _validateObject: () => (/* binding */ _validateObject),
|
|
1291
|
+
/* harmony export */ aInRange: () => (/* binding */ aInRange),
|
|
1292
|
+
/* harmony export */ abool: () => (/* binding */ abool),
|
|
1293
|
+
/* harmony export */ abytes: () => (/* reexport safe */ _noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.abytes),
|
|
1294
|
+
/* harmony export */ anumber: () => (/* reexport safe */ _noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.anumber),
|
|
1295
|
+
/* harmony export */ asciiToBytes: () => (/* binding */ asciiToBytes),
|
|
1296
|
+
/* harmony export */ bitGet: () => (/* binding */ bitGet),
|
|
1297
|
+
/* harmony export */ bitLen: () => (/* binding */ bitLen),
|
|
1298
|
+
/* harmony export */ bitMask: () => (/* binding */ bitMask),
|
|
1299
|
+
/* harmony export */ bitSet: () => (/* binding */ bitSet),
|
|
1300
|
+
/* harmony export */ bytesToHex: () => (/* reexport safe */ _noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToHex),
|
|
1301
|
+
/* harmony export */ bytesToNumberBE: () => (/* binding */ bytesToNumberBE),
|
|
1302
|
+
/* harmony export */ bytesToNumberLE: () => (/* binding */ bytesToNumberLE),
|
|
1303
|
+
/* harmony export */ bytesToUtf8: () => (/* reexport safe */ _noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToUtf8),
|
|
1304
|
+
/* harmony export */ concatBytes: () => (/* reexport safe */ _noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.concatBytes),
|
|
1305
|
+
/* harmony export */ copyBytes: () => (/* binding */ copyBytes),
|
|
1306
|
+
/* harmony export */ createHmacDrbg: () => (/* binding */ createHmacDrbg),
|
|
1307
|
+
/* harmony export */ ensureBytes: () => (/* binding */ ensureBytes),
|
|
1308
|
+
/* harmony export */ equalBytes: () => (/* binding */ equalBytes),
|
|
1309
|
+
/* harmony export */ hexToBytes: () => (/* reexport safe */ _noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.hexToBytes),
|
|
1310
|
+
/* harmony export */ hexToNumber: () => (/* binding */ hexToNumber),
|
|
1311
|
+
/* harmony export */ inRange: () => (/* binding */ inRange),
|
|
1312
|
+
/* harmony export */ isBytes: () => (/* reexport safe */ _noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.isBytes),
|
|
1313
|
+
/* harmony export */ isHash: () => (/* binding */ isHash),
|
|
1314
|
+
/* harmony export */ memoized: () => (/* binding */ memoized),
|
|
1315
|
+
/* harmony export */ notImplemented: () => (/* binding */ notImplemented),
|
|
1316
|
+
/* harmony export */ numberToBytesBE: () => (/* binding */ numberToBytesBE),
|
|
1317
|
+
/* harmony export */ numberToBytesLE: () => (/* binding */ numberToBytesLE),
|
|
1318
|
+
/* harmony export */ numberToHexUnpadded: () => (/* binding */ numberToHexUnpadded),
|
|
1319
|
+
/* harmony export */ numberToVarBytesBE: () => (/* binding */ numberToVarBytesBE),
|
|
1320
|
+
/* harmony export */ randomBytes: () => (/* reexport safe */ _noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.randomBytes),
|
|
1321
|
+
/* harmony export */ utf8ToBytes: () => (/* reexport safe */ _noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.utf8ToBytes),
|
|
1322
|
+
/* harmony export */ validateObject: () => (/* binding */ validateObject)
|
|
1323
|
+
/* harmony export */ });
|
|
1324
|
+
/* harmony import */ var _noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @noble/hashes/utils.js */ "./node_modules/@noble/hashes/esm/utils.js");
|
|
1325
|
+
/**
|
|
1326
|
+
* Hex, bytes and number utilities.
|
|
1327
|
+
* @module
|
|
1328
|
+
*/
|
|
1329
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
1330
|
+
|
|
1331
|
+
|
|
1332
|
+
const _0n = /* @__PURE__ */ BigInt(0);
|
|
1333
|
+
const _1n = /* @__PURE__ */ BigInt(1);
|
|
1334
|
+
function abool(title, value) {
|
|
1335
|
+
if (typeof value !== 'boolean')
|
|
1336
|
+
throw new Error(title + ' boolean expected, got ' + value);
|
|
1337
|
+
}
|
|
1338
|
+
// tmp name until v2
|
|
1339
|
+
function _abool2(value, title = '') {
|
|
1340
|
+
if (typeof value !== 'boolean') {
|
|
1341
|
+
const prefix = title && `"${title}"`;
|
|
1342
|
+
throw new Error(prefix + 'expected boolean, got type=' + typeof value);
|
|
1343
|
+
}
|
|
1344
|
+
return value;
|
|
1345
|
+
}
|
|
1346
|
+
// tmp name until v2
|
|
1347
|
+
/** Asserts something is Uint8Array. */
|
|
1348
|
+
function _abytes2(value, length, title = '') {
|
|
1349
|
+
const bytes = (0,_noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.isBytes)(value);
|
|
1350
|
+
const len = value?.length;
|
|
1351
|
+
const needsLen = length !== undefined;
|
|
1352
|
+
if (!bytes || (needsLen && len !== length)) {
|
|
1353
|
+
const prefix = title && `"${title}" `;
|
|
1354
|
+
const ofLen = needsLen ? ` of length ${length}` : '';
|
|
1355
|
+
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
1356
|
+
throw new Error(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);
|
|
1357
|
+
}
|
|
1358
|
+
return value;
|
|
1359
|
+
}
|
|
1360
|
+
// Used in weierstrass, der
|
|
1361
|
+
function numberToHexUnpadded(num) {
|
|
1362
|
+
const hex = num.toString(16);
|
|
1363
|
+
return hex.length & 1 ? '0' + hex : hex;
|
|
1364
|
+
}
|
|
1365
|
+
function hexToNumber(hex) {
|
|
1366
|
+
if (typeof hex !== 'string')
|
|
1367
|
+
throw new Error('hex string expected, got ' + typeof hex);
|
|
1368
|
+
return hex === '' ? _0n : BigInt('0x' + hex); // Big Endian
|
|
1369
|
+
}
|
|
1370
|
+
// BE: Big Endian, LE: Little Endian
|
|
1371
|
+
function bytesToNumberBE(bytes) {
|
|
1372
|
+
return hexToNumber((0,_noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToHex)(bytes));
|
|
1373
|
+
}
|
|
1374
|
+
function bytesToNumberLE(bytes) {
|
|
1375
|
+
(0,_noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.abytes)(bytes);
|
|
1376
|
+
return hexToNumber((0,_noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.bytesToHex)(Uint8Array.from(bytes).reverse()));
|
|
1377
|
+
}
|
|
1378
|
+
function numberToBytesBE(n, len) {
|
|
1379
|
+
return (0,_noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.hexToBytes)(n.toString(16).padStart(len * 2, '0'));
|
|
1380
|
+
}
|
|
1381
|
+
function numberToBytesLE(n, len) {
|
|
1382
|
+
return numberToBytesBE(n, len).reverse();
|
|
1383
|
+
}
|
|
1384
|
+
// Unpadded, rarely used
|
|
1385
|
+
function numberToVarBytesBE(n) {
|
|
1386
|
+
return (0,_noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.hexToBytes)(numberToHexUnpadded(n));
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Takes hex string or Uint8Array, converts to Uint8Array.
|
|
1390
|
+
* Validates output length.
|
|
1391
|
+
* Will throw error for other types.
|
|
1392
|
+
* @param title descriptive title for an error e.g. 'secret key'
|
|
1393
|
+
* @param hex hex string or Uint8Array
|
|
1394
|
+
* @param expectedLength optional, will compare to result array's length
|
|
1395
|
+
* @returns
|
|
1396
|
+
*/
|
|
1397
|
+
function ensureBytes(title, hex, expectedLength) {
|
|
1398
|
+
let res;
|
|
1399
|
+
if (typeof hex === 'string') {
|
|
1400
|
+
try {
|
|
1401
|
+
res = (0,_noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.hexToBytes)(hex);
|
|
1402
|
+
}
|
|
1403
|
+
catch (e) {
|
|
1404
|
+
throw new Error(title + ' must be hex string or Uint8Array, cause: ' + e);
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
else if ((0,_noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.isBytes)(hex)) {
|
|
1408
|
+
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
|
1409
|
+
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
|
1410
|
+
res = Uint8Array.from(hex);
|
|
1411
|
+
}
|
|
1412
|
+
else {
|
|
1413
|
+
throw new Error(title + ' must be hex string or Uint8Array');
|
|
1414
|
+
}
|
|
1415
|
+
const len = res.length;
|
|
1416
|
+
if (typeof expectedLength === 'number' && len !== expectedLength)
|
|
1417
|
+
throw new Error(title + ' of length ' + expectedLength + ' expected, got ' + len);
|
|
1418
|
+
return res;
|
|
1419
|
+
}
|
|
1420
|
+
// Compares 2 u8a-s in kinda constant time
|
|
1421
|
+
function equalBytes(a, b) {
|
|
1422
|
+
if (a.length !== b.length)
|
|
1423
|
+
return false;
|
|
1424
|
+
let diff = 0;
|
|
1425
|
+
for (let i = 0; i < a.length; i++)
|
|
1426
|
+
diff |= a[i] ^ b[i];
|
|
1427
|
+
return diff === 0;
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1430
|
+
* Copies Uint8Array. We can't use u8a.slice(), because u8a can be Buffer,
|
|
1431
|
+
* and Buffer#slice creates mutable copy. Never use Buffers!
|
|
1432
|
+
*/
|
|
1433
|
+
function copyBytes(bytes) {
|
|
1434
|
+
return Uint8Array.from(bytes);
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Decodes 7-bit ASCII string to Uint8Array, throws on non-ascii symbols
|
|
1438
|
+
* Should be safe to use for things expected to be ASCII.
|
|
1439
|
+
* Returns exact same result as utf8ToBytes for ASCII or throws.
|
|
1440
|
+
*/
|
|
1441
|
+
function asciiToBytes(ascii) {
|
|
1442
|
+
return Uint8Array.from(ascii, (c, i) => {
|
|
1443
|
+
const charCode = c.charCodeAt(0);
|
|
1444
|
+
if (c.length !== 1 || charCode > 127) {
|
|
1445
|
+
throw new Error(`string contains non-ASCII character "${ascii[i]}" with code ${charCode} at position ${i}`);
|
|
1446
|
+
}
|
|
1447
|
+
return charCode;
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
|
|
1452
|
+
*/
|
|
1453
|
+
// export const utf8ToBytes: typeof utf8ToBytes_ = utf8ToBytes_;
|
|
1454
|
+
/**
|
|
1455
|
+
* Converts bytes to string using UTF8 encoding.
|
|
1456
|
+
* @example bytesToUtf8(Uint8Array.from([97, 98, 99])) // 'abc'
|
|
1457
|
+
*/
|
|
1458
|
+
// export const bytesToUtf8: typeof bytesToUtf8_ = bytesToUtf8_;
|
|
1459
|
+
// Is positive bigint
|
|
1460
|
+
const isPosBig = (n) => typeof n === 'bigint' && _0n <= n;
|
|
1461
|
+
function inRange(n, min, max) {
|
|
1462
|
+
return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Asserts min <= n < max. NOTE: It's < max and not <= max.
|
|
1466
|
+
* @example
|
|
1467
|
+
* aInRange('x', x, 1n, 256n); // would assume x is in (1n..255n)
|
|
1468
|
+
*/
|
|
1469
|
+
function aInRange(title, n, min, max) {
|
|
1470
|
+
// Why min <= n < max and not a (min < n < max) OR b (min <= n <= max)?
|
|
1471
|
+
// consider P=256n, min=0n, max=P
|
|
1472
|
+
// - a for min=0 would require -1: `inRange('x', x, -1n, P)`
|
|
1473
|
+
// - b would commonly require subtraction: `inRange('x', x, 0n, P - 1n)`
|
|
1474
|
+
// - our way is the cleanest: `inRange('x', x, 0n, P)
|
|
1475
|
+
if (!inRange(n, min, max))
|
|
1476
|
+
throw new Error('expected valid ' + title + ': ' + min + ' <= n < ' + max + ', got ' + n);
|
|
1477
|
+
}
|
|
1478
|
+
// Bit operations
|
|
1479
|
+
/**
|
|
1480
|
+
* Calculates amount of bits in a bigint.
|
|
1481
|
+
* Same as `n.toString(2).length`
|
|
1482
|
+
* TODO: merge with nLength in modular
|
|
1483
|
+
*/
|
|
1484
|
+
function bitLen(n) {
|
|
1485
|
+
let len;
|
|
1486
|
+
for (len = 0; n > _0n; n >>= _1n, len += 1)
|
|
1487
|
+
;
|
|
1488
|
+
return len;
|
|
1489
|
+
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Gets single bit at position.
|
|
1492
|
+
* NOTE: first bit position is 0 (same as arrays)
|
|
1493
|
+
* Same as `!!+Array.from(n.toString(2)).reverse()[pos]`
|
|
1494
|
+
*/
|
|
1495
|
+
function bitGet(n, pos) {
|
|
1496
|
+
return (n >> BigInt(pos)) & _1n;
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Sets single bit at position.
|
|
1500
|
+
*/
|
|
1501
|
+
function bitSet(n, pos, value) {
|
|
1502
|
+
return n | ((value ? _1n : _0n) << BigInt(pos));
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* Calculate mask for N bits. Not using ** operator with bigints because of old engines.
|
|
1506
|
+
* Same as BigInt(`0b${Array(i).fill('1').join('')}`)
|
|
1507
|
+
*/
|
|
1508
|
+
const bitMask = (n) => (_1n << BigInt(n)) - _1n;
|
|
1509
|
+
/**
|
|
1510
|
+
* Minimal HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
|
|
1511
|
+
* @returns function that will call DRBG until 2nd arg returns something meaningful
|
|
1512
|
+
* @example
|
|
1513
|
+
* const drbg = createHmacDRBG<Key>(32, 32, hmac);
|
|
1514
|
+
* drbg(seed, bytesToKey); // bytesToKey must return Key or undefined
|
|
1515
|
+
*/
|
|
1516
|
+
function createHmacDrbg(hashLen, qByteLen, hmacFn) {
|
|
1517
|
+
if (typeof hashLen !== 'number' || hashLen < 2)
|
|
1518
|
+
throw new Error('hashLen must be a number');
|
|
1519
|
+
if (typeof qByteLen !== 'number' || qByteLen < 2)
|
|
1520
|
+
throw new Error('qByteLen must be a number');
|
|
1521
|
+
if (typeof hmacFn !== 'function')
|
|
1522
|
+
throw new Error('hmacFn must be a function');
|
|
1523
|
+
// Step B, Step C: set hashLen to 8*ceil(hlen/8)
|
|
1524
|
+
const u8n = (len) => new Uint8Array(len); // creates Uint8Array
|
|
1525
|
+
const u8of = (byte) => Uint8Array.of(byte); // another shortcut
|
|
1526
|
+
let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
|
|
1527
|
+
let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same
|
|
1528
|
+
let i = 0; // Iterations counter, will throw when over 1000
|
|
1529
|
+
const reset = () => {
|
|
1530
|
+
v.fill(1);
|
|
1531
|
+
k.fill(0);
|
|
1532
|
+
i = 0;
|
|
1533
|
+
};
|
|
1534
|
+
const h = (...b) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)
|
|
1535
|
+
const reseed = (seed = u8n(0)) => {
|
|
1536
|
+
// HMAC-DRBG reseed() function. Steps D-G
|
|
1537
|
+
k = h(u8of(0x00), seed); // k = hmac(k || v || 0x00 || seed)
|
|
1538
|
+
v = h(); // v = hmac(k || v)
|
|
1539
|
+
if (seed.length === 0)
|
|
1540
|
+
return;
|
|
1541
|
+
k = h(u8of(0x01), seed); // k = hmac(k || v || 0x01 || seed)
|
|
1542
|
+
v = h(); // v = hmac(k || v)
|
|
1543
|
+
};
|
|
1544
|
+
const gen = () => {
|
|
1545
|
+
// HMAC-DRBG generate() function
|
|
1546
|
+
if (i++ >= 1000)
|
|
1547
|
+
throw new Error('drbg: tried 1000 values');
|
|
1548
|
+
let len = 0;
|
|
1549
|
+
const out = [];
|
|
1550
|
+
while (len < qByteLen) {
|
|
1551
|
+
v = h();
|
|
1552
|
+
const sl = v.slice();
|
|
1553
|
+
out.push(sl);
|
|
1554
|
+
len += v.length;
|
|
1555
|
+
}
|
|
1556
|
+
return (0,_noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.concatBytes)(...out);
|
|
1557
|
+
};
|
|
1558
|
+
const genUntil = (seed, pred) => {
|
|
1559
|
+
reset();
|
|
1560
|
+
reseed(seed); // Steps D-G
|
|
1561
|
+
let res = undefined; // Step H: grind until k is in [1..n-1]
|
|
1562
|
+
while (!(res = pred(gen())))
|
|
1563
|
+
reseed();
|
|
1564
|
+
reset();
|
|
1565
|
+
return res;
|
|
1566
|
+
};
|
|
1567
|
+
return genUntil;
|
|
1568
|
+
}
|
|
1569
|
+
// Validating curves and fields
|
|
1570
|
+
const validatorFns = {
|
|
1571
|
+
bigint: (val) => typeof val === 'bigint',
|
|
1572
|
+
function: (val) => typeof val === 'function',
|
|
1573
|
+
boolean: (val) => typeof val === 'boolean',
|
|
1574
|
+
string: (val) => typeof val === 'string',
|
|
1575
|
+
stringOrUint8Array: (val) => typeof val === 'string' || (0,_noble_hashes_utils_js__WEBPACK_IMPORTED_MODULE_0__.isBytes)(val),
|
|
1576
|
+
isSafeInteger: (val) => Number.isSafeInteger(val),
|
|
1577
|
+
array: (val) => Array.isArray(val),
|
|
1578
|
+
field: (val, object) => object.Fp.isValid(val),
|
|
1579
|
+
hash: (val) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
|
|
1580
|
+
};
|
|
1581
|
+
// type Record<K extends string | number | symbol, T> = { [P in K]: T; }
|
|
1582
|
+
function validateObject(object, validators, optValidators = {}) {
|
|
1583
|
+
const checkField = (fieldName, type, isOptional) => {
|
|
1584
|
+
const checkVal = validatorFns[type];
|
|
1585
|
+
if (typeof checkVal !== 'function')
|
|
1586
|
+
throw new Error('invalid validator function');
|
|
1587
|
+
const val = object[fieldName];
|
|
1588
|
+
if (isOptional && val === undefined)
|
|
1589
|
+
return;
|
|
1590
|
+
if (!checkVal(val, object)) {
|
|
1591
|
+
throw new Error('param ' + String(fieldName) + ' is invalid. Expected ' + type + ', got ' + val);
|
|
1592
|
+
}
|
|
1593
|
+
};
|
|
1594
|
+
for (const [fieldName, type] of Object.entries(validators))
|
|
1595
|
+
checkField(fieldName, type, false);
|
|
1596
|
+
for (const [fieldName, type] of Object.entries(optValidators))
|
|
1597
|
+
checkField(fieldName, type, true);
|
|
1598
|
+
return object;
|
|
1599
|
+
}
|
|
1600
|
+
// validate type tests
|
|
1601
|
+
// const o: { a: number; b: number; c: number } = { a: 1, b: 5, c: 6 };
|
|
1602
|
+
// const z0 = validateObject(o, { a: 'isSafeInteger' }, { c: 'bigint' }); // Ok!
|
|
1603
|
+
// // Should fail type-check
|
|
1604
|
+
// const z1 = validateObject(o, { a: 'tmp' }, { c: 'zz' });
|
|
1605
|
+
// const z2 = validateObject(o, { a: 'isSafeInteger' }, { c: 'zz' });
|
|
1606
|
+
// const z3 = validateObject(o, { test: 'boolean', z: 'bug' });
|
|
1607
|
+
// const z4 = validateObject(o, { a: 'boolean', z: 'bug' });
|
|
1608
|
+
function isHash(val) {
|
|
1609
|
+
return typeof val === 'function' && Number.isSafeInteger(val.outputLen);
|
|
1610
|
+
}
|
|
1611
|
+
function _validateObject(object, fields, optFields = {}) {
|
|
1612
|
+
if (!object || typeof object !== 'object')
|
|
1613
|
+
throw new Error('expected valid options object');
|
|
1614
|
+
function checkField(fieldName, expectedType, isOpt) {
|
|
1615
|
+
const val = object[fieldName];
|
|
1616
|
+
if (isOpt && val === undefined)
|
|
1617
|
+
return;
|
|
1618
|
+
const current = typeof val;
|
|
1619
|
+
if (current !== expectedType || val === null)
|
|
1620
|
+
throw new Error(`param "${fieldName}" is invalid: expected ${expectedType}, got ${current}`);
|
|
1621
|
+
}
|
|
1622
|
+
Object.entries(fields).forEach(([k, v]) => checkField(k, v, false));
|
|
1623
|
+
Object.entries(optFields).forEach(([k, v]) => checkField(k, v, true));
|
|
1624
|
+
}
|
|
1625
|
+
/**
|
|
1626
|
+
* throws not implemented error
|
|
1627
|
+
*/
|
|
1628
|
+
const notImplemented = () => {
|
|
1629
|
+
throw new Error('not implemented');
|
|
1630
|
+
};
|
|
1631
|
+
/**
|
|
1632
|
+
* Memoizes (caches) computation result.
|
|
1633
|
+
* Uses WeakMap: the value is going auto-cleaned by GC after last reference is removed.
|
|
1634
|
+
*/
|
|
1635
|
+
function memoized(fn) {
|
|
1636
|
+
const map = new WeakMap();
|
|
1637
|
+
return (arg, ...args) => {
|
|
1638
|
+
const val = map.get(arg);
|
|
1639
|
+
if (val !== undefined)
|
|
1640
|
+
return val;
|
|
1641
|
+
const computed = fn(arg, ...args);
|
|
1642
|
+
map.set(arg, computed);
|
|
1643
|
+
return computed;
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
//# sourceMappingURL=utils.js.map
|
|
1647
|
+
|
|
1648
|
+
/***/ })
|
|
1649
|
+
|
|
1650
|
+
}]);
|
|
1651
|
+
//# sourceMappingURL=defaultVendors-node_modules_noble_curves_esm_abstract_curve_js-node_modules_noble_curves_esm_-1ce4ed.shogun-core.js.map
|