@noble/curves 1.9.7 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +520 -505
- package/abstract/bls.d.ts +58 -120
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +108 -152
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +18 -54
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +30 -49
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +18 -77
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +68 -144
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.js +14 -27
- package/abstract/fft.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +35 -47
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +42 -46
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +5 -17
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +170 -169
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +7 -12
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +22 -29
- package/abstract/montgomery.js.map +1 -1
- package/abstract/oprf.d.ts +282 -0
- package/abstract/oprf.d.ts.map +1 -0
- package/abstract/oprf.js +297 -0
- package/abstract/oprf.js.map +1 -0
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +26 -31
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +43 -19
- package/abstract/tower.js.map +1 -1
- package/abstract/weierstrass.d.ts +77 -168
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +184 -389
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +5 -11
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +161 -181
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +59 -11
- package/bn254.d.ts.map +1 -1
- package/bn254.js +69 -97
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +33 -48
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +147 -161
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +27 -36
- package/ed448.d.ts.map +1 -1
- package/ed448.js +143 -164
- package/ed448.js.map +1 -1
- package/index.d.ts +1 -0
- package/index.js +20 -4
- package/index.js.map +1 -1
- package/misc.d.ts +10 -14
- package/misc.d.ts.map +1 -1
- package/misc.js +53 -62
- package/misc.js.map +1 -1
- package/nist.d.ts +31 -16
- package/nist.d.ts.map +1 -1
- package/nist.js +75 -64
- package/nist.js.map +1 -1
- package/package.json +20 -234
- package/secp256k1.d.ts +17 -30
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +59 -73
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +207 -354
- package/src/abstract/curve.ts +25 -84
- package/src/abstract/edwards.ts +68 -193
- package/src/abstract/hash-to-curve.ts +71 -85
- package/src/abstract/modular.ts +150 -134
- package/src/abstract/montgomery.ts +28 -35
- package/src/abstract/oprf.ts +600 -0
- package/src/abstract/poseidon.ts +6 -8
- package/src/abstract/tower.ts +0 -3
- package/src/abstract/weierstrass.ts +203 -525
- package/src/bls12-381.ts +133 -139
- package/src/bn254.ts +69 -93
- package/src/ed25519.ts +106 -133
- package/src/ed448.ts +111 -138
- package/src/index.ts +19 -3
- package/src/misc.ts +68 -51
- package/src/nist.ts +77 -70
- package/src/secp256k1.ts +46 -81
- package/src/utils.ts +67 -137
- package/src/webcrypto.ts +403 -0
- package/utils.d.ts +31 -38
- package/utils.d.ts.map +1 -1
- package/utils.js +66 -185
- package/utils.js.map +1 -1
- package/webcrypto.d.ts +99 -0
- package/webcrypto.d.ts.map +1 -0
- package/webcrypto.js +256 -0
- package/webcrypto.js.map +1 -0
- package/_shortw_utils.d.ts +0 -19
- package/_shortw_utils.d.ts.map +0 -1
- package/_shortw_utils.js +0 -20
- package/_shortw_utils.js.map +0 -1
- package/abstract/utils.d.ts +0 -78
- package/abstract/utils.d.ts.map +0 -1
- package/abstract/utils.js +0 -73
- package/abstract/utils.js.map +0 -1
- package/esm/_shortw_utils.d.ts +0 -19
- package/esm/_shortw_utils.d.ts.map +0 -1
- package/esm/_shortw_utils.js +0 -16
- package/esm/_shortw_utils.js.map +0 -1
- package/esm/abstract/bls.d.ts +0 -190
- package/esm/abstract/bls.d.ts.map +0 -1
- package/esm/abstract/bls.js +0 -408
- package/esm/abstract/bls.js.map +0 -1
- package/esm/abstract/curve.d.ts +0 -231
- package/esm/abstract/curve.d.ts.map +0 -1
- package/esm/abstract/curve.js +0 -465
- package/esm/abstract/curve.js.map +0 -1
- package/esm/abstract/edwards.d.ts +0 -243
- package/esm/abstract/edwards.d.ts.map +0 -1
- package/esm/abstract/edwards.js +0 -627
- package/esm/abstract/edwards.js.map +0 -1
- package/esm/abstract/fft.d.ts +0 -122
- package/esm/abstract/fft.d.ts.map +0 -1
- package/esm/abstract/fft.js +0 -425
- package/esm/abstract/fft.js.map +0 -1
- package/esm/abstract/hash-to-curve.d.ts +0 -102
- package/esm/abstract/hash-to-curve.d.ts.map +0 -1
- package/esm/abstract/hash-to-curve.js +0 -203
- package/esm/abstract/hash-to-curve.js.map +0 -1
- package/esm/abstract/modular.d.ts +0 -171
- package/esm/abstract/modular.d.ts.map +0 -1
- package/esm/abstract/modular.js +0 -530
- package/esm/abstract/modular.js.map +0 -1
- package/esm/abstract/montgomery.d.ts +0 -30
- package/esm/abstract/montgomery.d.ts.map +0 -1
- package/esm/abstract/montgomery.js +0 -157
- package/esm/abstract/montgomery.js.map +0 -1
- package/esm/abstract/poseidon.d.ts +0 -68
- package/esm/abstract/poseidon.d.ts.map +0 -1
- package/esm/abstract/poseidon.js +0 -296
- package/esm/abstract/poseidon.js.map +0 -1
- package/esm/abstract/tower.d.ts +0 -95
- package/esm/abstract/tower.d.ts.map +0 -1
- package/esm/abstract/tower.js +0 -714
- package/esm/abstract/tower.js.map +0 -1
- package/esm/abstract/utils.d.ts +0 -78
- package/esm/abstract/utils.d.ts.map +0 -1
- package/esm/abstract/utils.js +0 -70
- package/esm/abstract/utils.js.map +0 -1
- package/esm/abstract/weierstrass.d.ts +0 -416
- package/esm/abstract/weierstrass.d.ts.map +0 -1
- package/esm/abstract/weierstrass.js +0 -1413
- package/esm/abstract/weierstrass.js.map +0 -1
- package/esm/bls12-381.d.ts +0 -16
- package/esm/bls12-381.d.ts.map +0 -1
- package/esm/bls12-381.js +0 -705
- package/esm/bls12-381.js.map +0 -1
- package/esm/bn254.d.ts +0 -18
- package/esm/bn254.d.ts.map +0 -1
- package/esm/bn254.js +0 -214
- package/esm/bn254.js.map +0 -1
- package/esm/ed25519.d.ts +0 -106
- package/esm/ed25519.d.ts.map +0 -1
- package/esm/ed25519.js +0 -467
- package/esm/ed25519.js.map +0 -1
- package/esm/ed448.d.ts +0 -100
- package/esm/ed448.d.ts.map +0 -1
- package/esm/ed448.js +0 -459
- package/esm/ed448.js.map +0 -1
- package/esm/index.d.ts +0 -2
- package/esm/index.d.ts.map +0 -1
- package/esm/index.js +0 -17
- package/esm/index.js.map +0 -1
- package/esm/jubjub.d.ts +0 -12
- package/esm/jubjub.d.ts.map +0 -1
- package/esm/jubjub.js +0 -12
- package/esm/jubjub.js.map +0 -1
- package/esm/misc.d.ts +0 -19
- package/esm/misc.d.ts.map +0 -1
- package/esm/misc.js +0 -109
- package/esm/misc.js.map +0 -1
- package/esm/nist.d.ts +0 -21
- package/esm/nist.d.ts.map +0 -1
- package/esm/nist.js +0 -132
- package/esm/nist.js.map +0 -1
- package/esm/p256.d.ts +0 -16
- package/esm/p256.d.ts.map +0 -1
- package/esm/p256.js +0 -16
- package/esm/p256.js.map +0 -1
- package/esm/p384.d.ts +0 -16
- package/esm/p384.d.ts.map +0 -1
- package/esm/p384.js +0 -16
- package/esm/p384.js.map +0 -1
- package/esm/p521.d.ts +0 -16
- package/esm/p521.d.ts.map +0 -1
- package/esm/p521.js +0 -16
- package/esm/p521.js.map +0 -1
- package/esm/package.json +0 -4
- package/esm/pasta.d.ts +0 -10
- package/esm/pasta.d.ts.map +0 -1
- package/esm/pasta.js +0 -10
- package/esm/pasta.js.map +0 -1
- package/esm/secp256k1.d.ts +0 -89
- package/esm/secp256k1.d.ts.map +0 -1
- package/esm/secp256k1.js +0 -294
- package/esm/secp256k1.js.map +0 -1
- package/esm/utils.d.ts +0 -110
- package/esm/utils.d.ts.map +0 -1
- package/esm/utils.js +0 -322
- package/esm/utils.js.map +0 -1
- package/jubjub.d.ts +0 -12
- package/jubjub.d.ts.map +0 -1
- package/jubjub.js +0 -15
- package/jubjub.js.map +0 -1
- package/p256.d.ts +0 -16
- package/p256.d.ts.map +0 -1
- package/p256.js +0 -13
- package/p256.js.map +0 -1
- package/p384.d.ts +0 -16
- package/p384.d.ts.map +0 -1
- package/p384.js +0 -13
- package/p384.js.map +0 -1
- package/p521.d.ts +0 -16
- package/p521.d.ts.map +0 -1
- package/p521.js +0 -13
- package/p521.js.map +0 -1
- package/pasta.d.ts +0 -10
- package/pasta.d.ts.map +0 -1
- package/pasta.js +0 -13
- package/pasta.js.map +0 -1
- package/src/_shortw_utils.ts +0 -21
- package/src/abstract/utils.ts +0 -80
- package/src/jubjub.ts +0 -12
- package/src/p256.ts +0 -15
- package/src/p384.ts +0 -15
- package/src/p521.ts +0 -15
- package/src/package.json +0 -3
- package/src/pasta.ts +0 -9
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
8
|
import type { CHash } from '../utils.ts';
|
|
9
9
|
import {
|
|
10
|
-
_validateObject,
|
|
11
10
|
abytes,
|
|
11
|
+
asafenumber,
|
|
12
|
+
asciiToBytes,
|
|
12
13
|
bytesToNumberBE,
|
|
13
14
|
concatBytes,
|
|
14
15
|
isBytes,
|
|
15
|
-
|
|
16
|
-
utf8ToBytes,
|
|
16
|
+
validateObject,
|
|
17
17
|
} from '../utils.ts';
|
|
18
|
-
import type { AffinePoint,
|
|
18
|
+
import type { AffinePoint, PC_ANY, PC_F, PC_P } from './curve.ts';
|
|
19
19
|
import { FpInvertBatch, mod, type IField } from './modular.ts';
|
|
20
20
|
|
|
21
|
-
export type
|
|
21
|
+
export type AsciiOrBytes = string | Uint8Array;
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* * `DST` is a domain separation tag, defined in section 2.2.5
|
|
@@ -29,7 +29,7 @@ export type UnicodeOrBytes = string | Uint8Array;
|
|
|
29
29
|
* * `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
|
|
30
30
|
*/
|
|
31
31
|
export type H2COpts = {
|
|
32
|
-
DST:
|
|
32
|
+
DST: AsciiOrBytes;
|
|
33
33
|
expand: 'xmd' | 'xof';
|
|
34
34
|
hash: CHash;
|
|
35
35
|
p: bigint;
|
|
@@ -40,16 +40,37 @@ export type H2CHashOpts = {
|
|
|
40
40
|
expand: 'xmd' | 'xof';
|
|
41
41
|
hash: CHash;
|
|
42
42
|
};
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
export type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
|
|
44
|
+
|
|
45
|
+
// Separated from initialization opts, so users won't accidentally change per-curve parameters
|
|
46
|
+
// (changing DST is ok!)
|
|
47
|
+
export type H2CDSTOpts = { DST: AsciiOrBytes };
|
|
48
|
+
export type H2CHasherBase<PC extends PC_ANY> = {
|
|
49
|
+
hashToCurve(msg: Uint8Array, options?: H2CDSTOpts): PC_P<PC>;
|
|
50
|
+
hashToScalar(msg: Uint8Array, options?: H2CDSTOpts): bigint;
|
|
51
|
+
deriveToCurve?(msg: Uint8Array, options?: H2CDSTOpts): PC_P<PC>;
|
|
52
|
+
Point: PC;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* RFC 9380 methods, with cofactor clearing. See https://www.rfc-editor.org/rfc/rfc9380#section-3.
|
|
56
|
+
*
|
|
57
|
+
* * hashToCurve: `map(hash(input))`, encodes RANDOM bytes to curve (WITH hashing)
|
|
58
|
+
* * encodeToCurve: `map(hash(input))`, encodes NON-UNIFORM bytes to curve (WITH hashing)
|
|
59
|
+
* * mapToCurve: `map(scalars)`, encodes NON-UNIFORM scalars to curve (NO hashing)
|
|
60
|
+
*/
|
|
61
|
+
export type H2CHasher<PC extends PC_ANY> = H2CHasherBase<PC> & {
|
|
62
|
+
encodeToCurve(msg: Uint8Array, options?: H2CDSTOpts): PC_P<PC>;
|
|
63
|
+
mapToCurve: MapToCurve<PC_F<PC>>;
|
|
64
|
+
defaults: H2COpts & { encodeDST?: AsciiOrBytes };
|
|
65
|
+
};
|
|
45
66
|
|
|
46
67
|
// Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE.
|
|
47
68
|
const os2ip = bytesToNumberBE;
|
|
48
69
|
|
|
49
70
|
// Integer to Octet Stream (numberToBytesBE)
|
|
50
71
|
function i2osp(value: number, length: number): Uint8Array {
|
|
51
|
-
|
|
52
|
-
|
|
72
|
+
asafenumber(value);
|
|
73
|
+
asafenumber(length);
|
|
53
74
|
if (value < 0 || value >= 1 << (8 * length)) throw new Error('invalid I2OSP input: ' + value);
|
|
54
75
|
const res = Array.from({ length }).fill(0) as number[];
|
|
55
76
|
for (let i = length - 1; i >= 0; i--) {
|
|
@@ -67,13 +88,12 @@ function strxor(a: Uint8Array, b: Uint8Array): Uint8Array {
|
|
|
67
88
|
return arr;
|
|
68
89
|
}
|
|
69
90
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return typeof DST === 'string' ? utf8ToBytes(DST) : DST;
|
|
91
|
+
// User can always use utf8 if they want, by passing Uint8Array.
|
|
92
|
+
// If string is passed, we treat it as ASCII: other formats are likely a mistake.
|
|
93
|
+
function normDST(DST: AsciiOrBytes): Uint8Array {
|
|
94
|
+
if (!isBytes(DST) && typeof DST !== 'string')
|
|
95
|
+
throw new Error('DST must be Uint8Array or ascii string');
|
|
96
|
+
return typeof DST === 'string' ? asciiToBytes(DST) : DST;
|
|
77
97
|
}
|
|
78
98
|
|
|
79
99
|
/**
|
|
@@ -82,15 +102,15 @@ function normDST(DST: UnicodeOrBytes): Uint8Array {
|
|
|
82
102
|
*/
|
|
83
103
|
export function expand_message_xmd(
|
|
84
104
|
msg: Uint8Array,
|
|
85
|
-
DST:
|
|
105
|
+
DST: AsciiOrBytes,
|
|
86
106
|
lenInBytes: number,
|
|
87
107
|
H: CHash
|
|
88
108
|
): Uint8Array {
|
|
89
109
|
abytes(msg);
|
|
90
|
-
|
|
110
|
+
asafenumber(lenInBytes);
|
|
91
111
|
DST = normDST(DST);
|
|
92
112
|
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
|
|
93
|
-
if (DST.length > 255) DST = H(concatBytes(
|
|
113
|
+
if (DST.length > 255) DST = H(concatBytes(asciiToBytes('H2C-OVERSIZE-DST-'), DST));
|
|
94
114
|
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
|
|
95
115
|
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
|
96
116
|
if (lenInBytes > 65535 || ell > 255) throw new Error('expand_message_xmd: invalid lenInBytes');
|
|
@@ -117,19 +137,19 @@ export function expand_message_xmd(
|
|
|
117
137
|
*/
|
|
118
138
|
export function expand_message_xof(
|
|
119
139
|
msg: Uint8Array,
|
|
120
|
-
DST:
|
|
140
|
+
DST: AsciiOrBytes,
|
|
121
141
|
lenInBytes: number,
|
|
122
142
|
k: number,
|
|
123
143
|
H: CHash
|
|
124
144
|
): Uint8Array {
|
|
125
145
|
abytes(msg);
|
|
126
|
-
|
|
146
|
+
asafenumber(lenInBytes);
|
|
127
147
|
DST = normDST(DST);
|
|
128
148
|
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
|
|
129
149
|
// DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
|
|
130
150
|
if (DST.length > 255) {
|
|
131
151
|
const dkLen = Math.ceil((2 * k) / 8);
|
|
132
|
-
DST = H.create({ dkLen }).update(
|
|
152
|
+
DST = H.create({ dkLen }).update(asciiToBytes('H2C-OVERSIZE-DST-')).update(DST).digest();
|
|
133
153
|
}
|
|
134
154
|
if (lenInBytes > 65535 || DST.length > 255)
|
|
135
155
|
throw new Error('expand_message_xof: invalid lenInBytes');
|
|
@@ -153,16 +173,16 @@ export function expand_message_xof(
|
|
|
153
173
|
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
|
154
174
|
*/
|
|
155
175
|
export function hash_to_field(msg: Uint8Array, count: number, options: H2COpts): bigint[][] {
|
|
156
|
-
|
|
176
|
+
validateObject(options, {
|
|
157
177
|
p: 'bigint',
|
|
158
178
|
m: 'number',
|
|
159
179
|
k: 'number',
|
|
160
180
|
hash: 'function',
|
|
161
181
|
});
|
|
162
182
|
const { p, k, m, hash, expand, DST } = options;
|
|
163
|
-
|
|
183
|
+
asafenumber(hash.outputLen, 'valid hash');
|
|
164
184
|
abytes(msg);
|
|
165
|
-
|
|
185
|
+
asafenumber(count);
|
|
166
186
|
const log2p = p.toString(2).length;
|
|
167
187
|
const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above
|
|
168
188
|
const len_in_bytes = count * m * L;
|
|
@@ -190,8 +210,8 @@ export function hash_to_field(msg: Uint8Array, count: number, options: H2COpts):
|
|
|
190
210
|
return u;
|
|
191
211
|
}
|
|
192
212
|
|
|
193
|
-
|
|
194
|
-
|
|
213
|
+
type XY<T> = (x: T, y: T) => { x: T; y: T };
|
|
214
|
+
type XYRatio<T> = [T[], T[], T[], T[]]; // xn/xd, yn/yd
|
|
195
215
|
export function isogenyMap<T, F extends IField<T>>(field: F, map: XYRatio<T>): XY<T> {
|
|
196
216
|
// Make same order as in spec
|
|
197
217
|
const coeff = map.map((i) => Array.from(i).reverse());
|
|
@@ -210,76 +230,37 @@ export function isogenyMap<T, F extends IField<T>>(field: F, map: XYRatio<T>): X
|
|
|
210
230
|
};
|
|
211
231
|
}
|
|
212
232
|
|
|
213
|
-
|
|
214
|
-
export interface H2CPoint<T> extends Group<H2CPoint<T>> {
|
|
215
|
-
add(rhs: H2CPoint<T>): H2CPoint<T>;
|
|
216
|
-
toAffine(iz?: bigint): AffinePoint<T>;
|
|
217
|
-
clearCofactor(): H2CPoint<T>;
|
|
218
|
-
assertValidity(): void;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export interface H2CPointConstructor<T> extends GroupConstructor<H2CPoint<T>> {
|
|
222
|
-
fromAffine(ap: AffinePoint<T>): H2CPoint<T>;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
|
|
226
|
-
|
|
227
|
-
// Separated from initialization opts, so users won't accidentally change per-curve parameters
|
|
228
|
-
// (changing DST is ok!)
|
|
229
|
-
export type htfBasicOpts = { DST: UnicodeOrBytes };
|
|
230
|
-
export type H2CMethod<T> = (msg: Uint8Array, options?: htfBasicOpts) => H2CPoint<T>;
|
|
231
|
-
// TODO: remove
|
|
232
|
-
export type HTFMethod<T> = H2CMethod<T>;
|
|
233
|
-
export type MapMethod<T> = (scalars: bigint[]) => H2CPoint<T>;
|
|
234
|
-
export type H2CHasherBase<T> = {
|
|
235
|
-
hashToCurve: H2CMethod<T>;
|
|
236
|
-
hashToScalar: (msg: Uint8Array, options: htfBasicOpts) => bigint;
|
|
237
|
-
};
|
|
238
|
-
/**
|
|
239
|
-
* RFC 9380 methods, with cofactor clearing. See https://www.rfc-editor.org/rfc/rfc9380#section-3.
|
|
240
|
-
*
|
|
241
|
-
* * hashToCurve: `map(hash(input))`, encodes RANDOM bytes to curve (WITH hashing)
|
|
242
|
-
* * encodeToCurve: `map(hash(input))`, encodes NON-UNIFORM bytes to curve (WITH hashing)
|
|
243
|
-
* * mapToCurve: `map(scalars)`, encodes NON-UNIFORM scalars to curve (NO hashing)
|
|
244
|
-
*/
|
|
245
|
-
export type H2CHasher<T> = H2CHasherBase<T> & {
|
|
246
|
-
encodeToCurve: H2CMethod<T>;
|
|
247
|
-
mapToCurve: MapMethod<T>;
|
|
248
|
-
defaults: H2COpts & { encodeDST?: UnicodeOrBytes };
|
|
249
|
-
};
|
|
250
|
-
// TODO: remove
|
|
251
|
-
export type Hasher<T> = H2CHasher<T>;
|
|
252
|
-
|
|
253
|
-
export const _DST_scalar: Uint8Array = utf8ToBytes('HashToScalar-');
|
|
233
|
+
export const _DST_scalar: Uint8Array = asciiToBytes('HashToScalar-');
|
|
254
234
|
|
|
255
235
|
/** Creates hash-to-curve methods from EC Point and mapToCurve function. See {@link H2CHasher}. */
|
|
256
|
-
export function createHasher<
|
|
257
|
-
Point:
|
|
258
|
-
mapToCurve: MapToCurve<
|
|
259
|
-
defaults: H2COpts & { encodeDST?:
|
|
260
|
-
): H2CHasher<
|
|
236
|
+
export function createHasher<PC extends PC_ANY>(
|
|
237
|
+
Point: PC,
|
|
238
|
+
mapToCurve: MapToCurve<PC_F<PC>>,
|
|
239
|
+
defaults: H2COpts & { encodeDST?: AsciiOrBytes }
|
|
240
|
+
): H2CHasher<PC> {
|
|
261
241
|
if (typeof mapToCurve !== 'function') throw new Error('mapToCurve() must be defined');
|
|
262
|
-
function map(num: bigint[]) {
|
|
263
|
-
return Point.fromAffine(mapToCurve(num))
|
|
242
|
+
function map(num: bigint[]): PC_P<PC> {
|
|
243
|
+
return Point.fromAffine(mapToCurve(num)) as PC_P<PC>;
|
|
264
244
|
}
|
|
265
|
-
function clear(initial:
|
|
245
|
+
function clear(initial: PC_P<PC>): PC_P<PC> {
|
|
266
246
|
const P = initial.clearCofactor();
|
|
267
|
-
if (P.equals(Point.ZERO)) return Point.ZERO
|
|
247
|
+
if (P.equals(Point.ZERO)) return Point.ZERO as PC_P<PC>; // zero will throw in assert
|
|
268
248
|
P.assertValidity();
|
|
269
|
-
return P
|
|
249
|
+
return P as PC_P<PC>;
|
|
270
250
|
}
|
|
271
251
|
|
|
272
252
|
return {
|
|
273
|
-
defaults,
|
|
253
|
+
defaults: Object.freeze(defaults),
|
|
254
|
+
Point,
|
|
274
255
|
|
|
275
|
-
hashToCurve(msg: Uint8Array, options?:
|
|
256
|
+
hashToCurve(msg: Uint8Array, options?: H2CDSTOpts): PC_P<PC> {
|
|
276
257
|
const opts = Object.assign({}, defaults, options);
|
|
277
258
|
const u = hash_to_field(msg, 2, opts);
|
|
278
259
|
const u0 = map(u[0]);
|
|
279
260
|
const u1 = map(u[1]);
|
|
280
|
-
return clear(u0.add(u1));
|
|
261
|
+
return clear(u0.add(u1) as PC_P<PC>);
|
|
281
262
|
},
|
|
282
|
-
encodeToCurve(msg: Uint8Array, options?:
|
|
263
|
+
encodeToCurve(msg: Uint8Array, options?: H2CDSTOpts): PC_P<PC> {
|
|
283
264
|
const optsDst = defaults.encodeDST ? { DST: defaults.encodeDST } : {};
|
|
284
265
|
const opts = Object.assign({}, defaults, optsDst, options);
|
|
285
266
|
const u = hash_to_field(msg, 1, opts);
|
|
@@ -287,7 +268,12 @@ export function createHasher<T>(
|
|
|
287
268
|
return clear(u0);
|
|
288
269
|
},
|
|
289
270
|
/** See {@link H2CHasher} */
|
|
290
|
-
mapToCurve(scalars: bigint[]):
|
|
271
|
+
mapToCurve(scalars: bigint | bigint[]): PC_P<PC> {
|
|
272
|
+
// Curves with m=1 accept only single scalar
|
|
273
|
+
if (defaults.m === 1) {
|
|
274
|
+
if (typeof scalars !== 'bigint') throw new Error('expected bigint (m=1)');
|
|
275
|
+
return clear(map([scalars]));
|
|
276
|
+
}
|
|
291
277
|
if (!Array.isArray(scalars)) throw new Error('expected array of bigints');
|
|
292
278
|
for (const i of scalars)
|
|
293
279
|
if (typeof i !== 'bigint') throw new Error('expected array of bigints');
|
|
@@ -296,7 +282,7 @@ export function createHasher<T>(
|
|
|
296
282
|
|
|
297
283
|
// hash_to_scalar can produce 0: https://www.rfc-editor.org/errata/eid8393
|
|
298
284
|
// RFC 9380, draft-irtf-cfrg-bbs-signatures-08
|
|
299
|
-
hashToScalar(msg: Uint8Array, options?:
|
|
285
|
+
hashToScalar(msg: Uint8Array, options?: H2CDSTOpts): bigint {
|
|
300
286
|
// @ts-ignore
|
|
301
287
|
const N = Point.Fn.ORDER;
|
|
302
288
|
const opts = Object.assign({}, defaults, { p: N, m: 1, DST: _DST_scalar }, options);
|
package/src/abstract/modular.ts
CHANGED
|
@@ -6,22 +6,23 @@
|
|
|
6
6
|
*/
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
8
|
import {
|
|
9
|
-
|
|
9
|
+
abytes,
|
|
10
10
|
anumber,
|
|
11
|
-
bitMask,
|
|
12
11
|
bytesToNumberBE,
|
|
13
12
|
bytesToNumberLE,
|
|
14
|
-
ensureBytes,
|
|
15
13
|
numberToBytesBE,
|
|
16
14
|
numberToBytesLE,
|
|
15
|
+
validateObject,
|
|
17
16
|
} from '../utils.ts';
|
|
18
17
|
|
|
18
|
+
// Numbers aren't used in x25519 / x448 builds
|
|
19
19
|
// prettier-ignore
|
|
20
|
-
const _0n =
|
|
20
|
+
const _0n = /* @__PURE__ */ BigInt(0), _1n = /* @__PURE__ */ BigInt(1), _2n = /* @__PURE__ */ BigInt(2);
|
|
21
21
|
// prettier-ignore
|
|
22
|
-
const
|
|
22
|
+
const _3n = /* @__PURE__ */ BigInt(3), _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5);
|
|
23
23
|
// prettier-ignore
|
|
24
|
-
const
|
|
24
|
+
const _7n = /* @__PURE__ */ BigInt(7), _8n = /* @__PURE__ */ BigInt(8), _9n = /* @__PURE__ */ BigInt(9);
|
|
25
|
+
const _16n = /* @__PURE__ */ BigInt(16);
|
|
25
26
|
|
|
26
27
|
// Calculates a modulo b
|
|
27
28
|
export function mod(a: bigint, b: bigint): bigint {
|
|
@@ -227,10 +228,9 @@ export const isNegativeLE = (num: bigint, modulo: bigint): boolean =>
|
|
|
227
228
|
/** Field is not always over prime: for example, Fp2 has ORDER(q)=p^m. */
|
|
228
229
|
export interface IField<T> {
|
|
229
230
|
ORDER: bigint;
|
|
230
|
-
isLE: boolean;
|
|
231
231
|
BYTES: number;
|
|
232
232
|
BITS: number;
|
|
233
|
-
|
|
233
|
+
isLE: boolean;
|
|
234
234
|
ZERO: T;
|
|
235
235
|
ONE: T;
|
|
236
236
|
// 1-arg
|
|
@@ -260,7 +260,6 @@ export interface IField<T> {
|
|
|
260
260
|
// [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#section-4.1).
|
|
261
261
|
// NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
|
|
262
262
|
isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
|
|
263
|
-
allowedLengths?: number[];
|
|
264
263
|
// legendre?(num: T): T;
|
|
265
264
|
invertBatch: (lst: T[]) => T[];
|
|
266
265
|
toBytes(num: T): Uint8Array;
|
|
@@ -277,7 +276,6 @@ const FIELD_FIELDS = [
|
|
|
277
276
|
export function validateField<T>(field: IField<T>): IField<T> {
|
|
278
277
|
const initial = {
|
|
279
278
|
ORDER: 'bigint',
|
|
280
|
-
MASK: 'bigint',
|
|
281
279
|
BYTES: 'number',
|
|
282
280
|
BITS: 'number',
|
|
283
281
|
} as Record<string, string>;
|
|
@@ -285,7 +283,7 @@ export function validateField<T>(field: IField<T>): IField<T> {
|
|
|
285
283
|
map[val] = 'function';
|
|
286
284
|
return map;
|
|
287
285
|
}, initial);
|
|
288
|
-
|
|
286
|
+
validateObject(field, opts);
|
|
289
287
|
// const max = 16384;
|
|
290
288
|
// if (field.BYTES < 1 || field.BYTES > max) throw new Error('invalid field');
|
|
291
289
|
// if (field.BITS < 1 || field.BITS > 8 * max) throw new Error('invalid field');
|
|
@@ -381,12 +379,147 @@ export function nLength(n: bigint, nBitLength?: number): NLength {
|
|
|
381
379
|
type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
|
|
382
380
|
type SqrtFn = (n: bigint) => bigint;
|
|
383
381
|
type FieldOpts = Partial<{
|
|
384
|
-
sqrt: SqrtFn;
|
|
385
382
|
isLE: boolean;
|
|
386
383
|
BITS: number;
|
|
387
|
-
|
|
384
|
+
sqrt: SqrtFn;
|
|
388
385
|
allowedLengths?: readonly number[]; // for P521 (adds padding for smaller sizes)
|
|
386
|
+
modFromBytes: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
|
|
389
387
|
}>;
|
|
388
|
+
class _Field implements IField<bigint> {
|
|
389
|
+
readonly ORDER: bigint;
|
|
390
|
+
readonly BITS: number;
|
|
391
|
+
readonly BYTES: number;
|
|
392
|
+
readonly isLE: boolean;
|
|
393
|
+
readonly ZERO = _0n;
|
|
394
|
+
readonly ONE = _1n;
|
|
395
|
+
readonly _lengths?: number[];
|
|
396
|
+
private _sqrt: ReturnType<typeof FpSqrt> | undefined; // cached sqrt
|
|
397
|
+
private readonly _mod?: boolean;
|
|
398
|
+
constructor(ORDER: bigint, opts: FieldOpts = {}) {
|
|
399
|
+
if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
|
|
400
|
+
let _nbitLength: number | undefined = undefined;
|
|
401
|
+
this.isLE = false;
|
|
402
|
+
if (opts != null && typeof opts === 'object') {
|
|
403
|
+
if (typeof opts.BITS === 'number') _nbitLength = opts.BITS;
|
|
404
|
+
if (typeof opts.sqrt === 'function') this.sqrt = opts.sqrt;
|
|
405
|
+
if (typeof opts.isLE === 'boolean') this.isLE = opts.isLE;
|
|
406
|
+
if (opts.allowedLengths) this._lengths = opts.allowedLengths?.slice();
|
|
407
|
+
if (typeof opts.modFromBytes === 'boolean') this._mod = opts.modFromBytes;
|
|
408
|
+
}
|
|
409
|
+
const { nBitLength, nByteLength } = nLength(ORDER, _nbitLength);
|
|
410
|
+
if (nByteLength > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');
|
|
411
|
+
this.ORDER = ORDER;
|
|
412
|
+
this.BITS = nBitLength;
|
|
413
|
+
this.BYTES = nByteLength;
|
|
414
|
+
this._sqrt = undefined;
|
|
415
|
+
Object.preventExtensions(this);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
create(num: bigint) {
|
|
419
|
+
return mod(num, this.ORDER);
|
|
420
|
+
}
|
|
421
|
+
isValid(num: bigint) {
|
|
422
|
+
if (typeof num !== 'bigint')
|
|
423
|
+
throw new Error('invalid field element: expected bigint, got ' + typeof num);
|
|
424
|
+
return _0n <= num && num < this.ORDER; // 0 is valid element, but it's not invertible
|
|
425
|
+
}
|
|
426
|
+
is0(num: bigint) {
|
|
427
|
+
return num === _0n;
|
|
428
|
+
}
|
|
429
|
+
// is valid and invertible
|
|
430
|
+
isValidNot0(num: bigint) {
|
|
431
|
+
return !this.is0(num) && this.isValid(num);
|
|
432
|
+
}
|
|
433
|
+
isOdd(num: bigint) {
|
|
434
|
+
return (num & _1n) === _1n;
|
|
435
|
+
}
|
|
436
|
+
neg(num: bigint) {
|
|
437
|
+
return mod(-num, this.ORDER);
|
|
438
|
+
}
|
|
439
|
+
eql(lhs: bigint, rhs: bigint) {
|
|
440
|
+
return lhs === rhs;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
sqr(num: bigint) {
|
|
444
|
+
return mod(num * num, this.ORDER);
|
|
445
|
+
}
|
|
446
|
+
add(lhs: bigint, rhs: bigint) {
|
|
447
|
+
return mod(lhs + rhs, this.ORDER);
|
|
448
|
+
}
|
|
449
|
+
sub(lhs: bigint, rhs: bigint) {
|
|
450
|
+
return mod(lhs - rhs, this.ORDER);
|
|
451
|
+
}
|
|
452
|
+
mul(lhs: bigint, rhs: bigint) {
|
|
453
|
+
return mod(lhs * rhs, this.ORDER);
|
|
454
|
+
}
|
|
455
|
+
pow(num: bigint, power: bigint): bigint {
|
|
456
|
+
return FpPow(this, num, power);
|
|
457
|
+
}
|
|
458
|
+
div(lhs: bigint, rhs: bigint) {
|
|
459
|
+
return mod(lhs * invert(rhs, this.ORDER), this.ORDER);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Same as above, but doesn't normalize
|
|
463
|
+
sqrN(num: bigint) {
|
|
464
|
+
return num * num;
|
|
465
|
+
}
|
|
466
|
+
addN(lhs: bigint, rhs: bigint) {
|
|
467
|
+
return lhs + rhs;
|
|
468
|
+
}
|
|
469
|
+
subN(lhs: bigint, rhs: bigint) {
|
|
470
|
+
return lhs - rhs;
|
|
471
|
+
}
|
|
472
|
+
mulN(lhs: bigint, rhs: bigint) {
|
|
473
|
+
return lhs * rhs;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
inv(num: bigint) {
|
|
477
|
+
return invert(num, this.ORDER);
|
|
478
|
+
}
|
|
479
|
+
sqrt(num: bigint): bigint {
|
|
480
|
+
// Caching _sqrt speeds up sqrt9mod16 by 5x and tonneli-shanks by 10%
|
|
481
|
+
if (!this._sqrt) this._sqrt = FpSqrt(this.ORDER);
|
|
482
|
+
return this._sqrt(this, num);
|
|
483
|
+
}
|
|
484
|
+
toBytes(num: bigint) {
|
|
485
|
+
return this.isLE ? numberToBytesLE(num, this.BYTES) : numberToBytesBE(num, this.BYTES);
|
|
486
|
+
}
|
|
487
|
+
fromBytes(bytes: Uint8Array, skipValidation = false) {
|
|
488
|
+
abytes(bytes);
|
|
489
|
+
const { _lengths: allowedLengths, BYTES, isLE, ORDER, _mod: modFromBytes } = this;
|
|
490
|
+
if (allowedLengths) {
|
|
491
|
+
if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
|
|
492
|
+
throw new Error(
|
|
493
|
+
'Field.fromBytes: expected ' + allowedLengths + ' bytes, got ' + bytes.length
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
const padded = new Uint8Array(BYTES);
|
|
497
|
+
// isLE add 0 to right, !isLE to the left.
|
|
498
|
+
padded.set(bytes, isLE ? 0 : padded.length - bytes.length);
|
|
499
|
+
bytes = padded;
|
|
500
|
+
}
|
|
501
|
+
if (bytes.length !== BYTES)
|
|
502
|
+
throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
|
|
503
|
+
let scalar = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
|
504
|
+
if (modFromBytes) scalar = mod(scalar, ORDER);
|
|
505
|
+
if (!skipValidation)
|
|
506
|
+
if (!this.isValid(scalar))
|
|
507
|
+
throw new Error('invalid field element: outside of range 0..ORDER');
|
|
508
|
+
// NOTE: we don't validate scalar here, please use isValid. This done such way because some
|
|
509
|
+
// protocol may allow non-reduced scalar that reduced later or changed some other way.
|
|
510
|
+
return scalar;
|
|
511
|
+
}
|
|
512
|
+
// TODO: we don't need it here, move out to separate fn
|
|
513
|
+
invertBatch(lst: bigint[]): bigint[] {
|
|
514
|
+
return FpInvertBatch(this, lst);
|
|
515
|
+
}
|
|
516
|
+
// We can't move this out because Fp6, Fp12 implement it
|
|
517
|
+
// and it's unclear what to return in there.
|
|
518
|
+
cmov(a: bigint, b: bigint, condition: boolean) {
|
|
519
|
+
return condition ? b : a;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
390
523
|
/**
|
|
391
524
|
* Creates a finite field. Major performance optimizations:
|
|
392
525
|
* * 1. Denormalized operations like mulN instead of mul.
|
|
@@ -406,104 +539,8 @@ type FieldOpts = Partial<{
|
|
|
406
539
|
* @param isLE (default: false) if encoding / decoding should be in little-endian
|
|
407
540
|
* @param redef optional faster redefinitions of sqrt and other methods
|
|
408
541
|
*/
|
|
409
|
-
export function Field(
|
|
410
|
-
ORDER
|
|
411
|
-
bitLenOrOpts?: number | FieldOpts, // TODO: use opts only in v2?
|
|
412
|
-
isLE = false,
|
|
413
|
-
opts: { sqrt?: SqrtFn } = {}
|
|
414
|
-
): Readonly<FpField> {
|
|
415
|
-
if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
|
|
416
|
-
let _nbitLength: number | undefined = undefined;
|
|
417
|
-
let _sqrt: SqrtFn | undefined = undefined;
|
|
418
|
-
let modFromBytes: boolean = false;
|
|
419
|
-
let allowedLengths: undefined | readonly number[] = undefined;
|
|
420
|
-
if (typeof bitLenOrOpts === 'object' && bitLenOrOpts != null) {
|
|
421
|
-
if (opts.sqrt || isLE) throw new Error('cannot specify opts in two arguments');
|
|
422
|
-
const _opts = bitLenOrOpts;
|
|
423
|
-
if (_opts.BITS) _nbitLength = _opts.BITS;
|
|
424
|
-
if (_opts.sqrt) _sqrt = _opts.sqrt;
|
|
425
|
-
if (typeof _opts.isLE === 'boolean') isLE = _opts.isLE;
|
|
426
|
-
if (typeof _opts.modFromBytes === 'boolean') modFromBytes = _opts.modFromBytes;
|
|
427
|
-
allowedLengths = _opts.allowedLengths;
|
|
428
|
-
} else {
|
|
429
|
-
if (typeof bitLenOrOpts === 'number') _nbitLength = bitLenOrOpts;
|
|
430
|
-
if (opts.sqrt) _sqrt = opts.sqrt;
|
|
431
|
-
}
|
|
432
|
-
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, _nbitLength);
|
|
433
|
-
if (BYTES > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');
|
|
434
|
-
let sqrtP: ReturnType<typeof FpSqrt>; // cached sqrtP
|
|
435
|
-
const f: Readonly<FpField> = Object.freeze({
|
|
436
|
-
ORDER,
|
|
437
|
-
isLE,
|
|
438
|
-
BITS,
|
|
439
|
-
BYTES,
|
|
440
|
-
MASK: bitMask(BITS),
|
|
441
|
-
ZERO: _0n,
|
|
442
|
-
ONE: _1n,
|
|
443
|
-
allowedLengths: allowedLengths,
|
|
444
|
-
create: (num) => mod(num, ORDER),
|
|
445
|
-
isValid: (num) => {
|
|
446
|
-
if (typeof num !== 'bigint')
|
|
447
|
-
throw new Error('invalid field element: expected bigint, got ' + typeof num);
|
|
448
|
-
return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
|
|
449
|
-
},
|
|
450
|
-
is0: (num) => num === _0n,
|
|
451
|
-
// is valid and invertible
|
|
452
|
-
isValidNot0: (num: bigint) => !f.is0(num) && f.isValid(num),
|
|
453
|
-
isOdd: (num) => (num & _1n) === _1n,
|
|
454
|
-
neg: (num) => mod(-num, ORDER),
|
|
455
|
-
eql: (lhs, rhs) => lhs === rhs,
|
|
456
|
-
|
|
457
|
-
sqr: (num) => mod(num * num, ORDER),
|
|
458
|
-
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
|
|
459
|
-
sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
|
|
460
|
-
mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
|
|
461
|
-
pow: (num, power) => FpPow(f, num, power),
|
|
462
|
-
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
|
|
463
|
-
|
|
464
|
-
// Same as above, but doesn't normalize
|
|
465
|
-
sqrN: (num) => num * num,
|
|
466
|
-
addN: (lhs, rhs) => lhs + rhs,
|
|
467
|
-
subN: (lhs, rhs) => lhs - rhs,
|
|
468
|
-
mulN: (lhs, rhs) => lhs * rhs,
|
|
469
|
-
|
|
470
|
-
inv: (num) => invert(num, ORDER),
|
|
471
|
-
sqrt:
|
|
472
|
-
_sqrt ||
|
|
473
|
-
((n) => {
|
|
474
|
-
if (!sqrtP) sqrtP = FpSqrt(ORDER);
|
|
475
|
-
return sqrtP(f, n);
|
|
476
|
-
}),
|
|
477
|
-
toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),
|
|
478
|
-
fromBytes: (bytes, skipValidation = true) => {
|
|
479
|
-
if (allowedLengths) {
|
|
480
|
-
if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
|
|
481
|
-
throw new Error(
|
|
482
|
-
'Field.fromBytes: expected ' + allowedLengths + ' bytes, got ' + bytes.length
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
|
-
const padded = new Uint8Array(BYTES);
|
|
486
|
-
// isLE add 0 to right, !isLE to the left.
|
|
487
|
-
padded.set(bytes, isLE ? 0 : padded.length - bytes.length);
|
|
488
|
-
bytes = padded;
|
|
489
|
-
}
|
|
490
|
-
if (bytes.length !== BYTES)
|
|
491
|
-
throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
|
|
492
|
-
let scalar = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
|
493
|
-
if (modFromBytes) scalar = mod(scalar, ORDER);
|
|
494
|
-
if (!skipValidation)
|
|
495
|
-
if (!f.isValid(scalar)) throw new Error('invalid field element: outside of range 0..ORDER');
|
|
496
|
-
// NOTE: we don't validate scalar here, please use isValid. This done such way because some
|
|
497
|
-
// protocol may allow non-reduced scalar that reduced later or changed some other way.
|
|
498
|
-
return scalar;
|
|
499
|
-
},
|
|
500
|
-
// TODO: we don't need it here, move out to separate fn
|
|
501
|
-
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
502
|
-
// We can't move this out because Fp6, Fp12 implement it
|
|
503
|
-
// and it's unclear what to return in there.
|
|
504
|
-
cmov: (a, b, c) => (c ? b : a),
|
|
505
|
-
} as FpField);
|
|
506
|
-
return Object.freeze(f);
|
|
542
|
+
export function Field(ORDER: bigint, opts: FieldOpts = {}): Readonly<FpField> {
|
|
543
|
+
return new _Field(ORDER, opts);
|
|
507
544
|
}
|
|
508
545
|
|
|
509
546
|
// Generic random scalar, we can do same for other fields if via Fp2.mul(Fp2.ONE, Fp2.random)?
|
|
@@ -532,28 +569,6 @@ export function FpSqrtEven<T>(Fp: IField<T>, elm: T): T {
|
|
|
532
569
|
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
|
533
570
|
}
|
|
534
571
|
|
|
535
|
-
/**
|
|
536
|
-
* "Constant-time" private key generation utility.
|
|
537
|
-
* Same as mapKeyToField, but accepts less bytes (40 instead of 48 for 32-byte field).
|
|
538
|
-
* Which makes it slightly more biased, less secure.
|
|
539
|
-
* @deprecated use `mapKeyToField` instead
|
|
540
|
-
*/
|
|
541
|
-
export function hashToPrivateScalar(
|
|
542
|
-
hash: string | Uint8Array,
|
|
543
|
-
groupOrder: bigint,
|
|
544
|
-
isLE = false
|
|
545
|
-
): bigint {
|
|
546
|
-
hash = ensureBytes('privateHash', hash);
|
|
547
|
-
const hashLen = hash.length;
|
|
548
|
-
const minLen = nLength(groupOrder).nByteLength + 8;
|
|
549
|
-
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
|
|
550
|
-
throw new Error(
|
|
551
|
-
'hashToPrivateScalar: expected ' + minLen + '-1024 bytes of input, got ' + hashLen
|
|
552
|
-
);
|
|
553
|
-
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
|
|
554
|
-
return mod(num, groupOrder - _1n) + _1n;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
572
|
/**
|
|
558
573
|
* Returns total number of bytes consumed by the field element.
|
|
559
574
|
* For example, 32 bytes for usual 256-bit weierstrass curve.
|
|
@@ -587,11 +602,12 @@ export function getMinHashLength(fieldOrder: bigint): number {
|
|
|
587
602
|
* FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final
|
|
588
603
|
* RFC 9380, https://www.rfc-editor.org/rfc/rfc9380#section-5
|
|
589
604
|
* @param hash hash output from SHA3 or a similar function
|
|
590
|
-
* @param groupOrder size of subgroup - (e.g. secp256k1.
|
|
605
|
+
* @param groupOrder size of subgroup - (e.g. secp256k1.Point.Fn.ORDER)
|
|
591
606
|
* @param isLE interpret hash bytes as LE num
|
|
592
607
|
* @returns valid private scalar
|
|
593
608
|
*/
|
|
594
609
|
export function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE = false): Uint8Array {
|
|
610
|
+
abytes(key);
|
|
595
611
|
const len = key.length;
|
|
596
612
|
const fieldLen = getFieldBytesLength(fieldOrder);
|
|
597
613
|
const minLen = getMinHashLength(fieldOrder);
|