@noble/curves 1.9.1 → 1.9.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 +56 -25
- package/_shortw_utils.d.ts +7 -5
- package/_shortw_utils.d.ts.map +1 -1
- package/_shortw_utils.js +2 -8
- package/_shortw_utils.js.map +1 -1
- package/abstract/bls.d.ts +60 -24
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +158 -109
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +44 -9
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +86 -7
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +112 -25
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +138 -102
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +12 -10
- package/abstract/fft.d.ts.map +1 -1
- package/abstract/fft.js +12 -13
- package/abstract/fft.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +25 -11
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +17 -14
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +24 -11
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +49 -20
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +1 -1
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +5 -4
- package/abstract/montgomery.js.map +1 -1
- package/abstract/poseidon.d.ts +5 -13
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +12 -7
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts +20 -46
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +9 -3
- package/abstract/tower.js.map +1 -1
- package/abstract/utils.d.ts +1 -115
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +17 -371
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +132 -76
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +462 -398
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +2 -0
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +504 -466
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +2 -0
- package/bn254.d.ts.map +1 -1
- package/bn254.js +44 -32
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +8 -5
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +67 -54
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +10 -6
- package/ed448.d.ts.map +1 -1
- package/ed448.js +80 -57
- package/ed448.js.map +1 -1
- package/esm/_shortw_utils.d.ts +7 -5
- package/esm/_shortw_utils.d.ts.map +1 -1
- package/esm/_shortw_utils.js +2 -8
- package/esm/_shortw_utils.js.map +1 -1
- package/esm/abstract/bls.d.ts +60 -24
- package/esm/abstract/bls.d.ts.map +1 -1
- package/esm/abstract/bls.js +158 -109
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +44 -9
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +83 -8
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +112 -25
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +138 -104
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/fft.d.ts +12 -10
- package/esm/abstract/fft.d.ts.map +1 -1
- package/esm/abstract/fft.js +10 -11
- package/esm/abstract/fft.js.map +1 -1
- package/esm/abstract/hash-to-curve.d.ts +25 -11
- package/esm/abstract/hash-to-curve.d.ts.map +1 -1
- package/esm/abstract/hash-to-curve.js +17 -14
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.d.ts +24 -11
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +48 -19
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts +1 -1
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +5 -4
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/poseidon.d.ts +5 -13
- package/esm/abstract/poseidon.d.ts.map +1 -1
- package/esm/abstract/poseidon.js +12 -7
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/tower.d.ts +20 -46
- package/esm/abstract/tower.d.ts.map +1 -1
- package/esm/abstract/tower.js +9 -3
- package/esm/abstract/tower.js.map +1 -1
- package/esm/abstract/utils.d.ts +1 -115
- package/esm/abstract/utils.d.ts.map +1 -1
- package/esm/abstract/utils.js +3 -344
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +132 -76
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +460 -400
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.d.ts +2 -0
- package/esm/bls12-381.d.ts.map +1 -1
- package/esm/bls12-381.js +503 -465
- package/esm/bls12-381.js.map +1 -1
- package/esm/bn254.d.ts +2 -0
- package/esm/bn254.d.ts.map +1 -1
- package/esm/bn254.js +41 -29
- package/esm/bn254.js.map +1 -1
- package/esm/ed25519.d.ts +8 -5
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +62 -49
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +10 -6
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +74 -51
- package/esm/ed448.js.map +1 -1
- package/esm/misc.d.ts.map +1 -1
- package/esm/misc.js +31 -26
- package/esm/misc.js.map +1 -1
- package/esm/nist.d.ts +7 -16
- package/esm/nist.d.ts.map +1 -1
- package/esm/nist.js +86 -97
- package/esm/nist.js.map +1 -1
- package/esm/p256.d.ts +3 -3
- package/esm/p384.d.ts +3 -3
- package/esm/p521.d.ts +3 -3
- package/esm/secp256k1.d.ts +6 -6
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +43 -40
- package/esm/secp256k1.js.map +1 -1
- package/esm/utils.d.ts +96 -0
- package/esm/utils.d.ts.map +1 -0
- package/esm/utils.js +279 -0
- package/esm/utils.js.map +1 -0
- package/misc.d.ts.map +1 -1
- package/misc.js +35 -30
- package/misc.js.map +1 -1
- package/nist.d.ts +7 -16
- package/nist.d.ts.map +1 -1
- package/nist.js +86 -97
- package/nist.js.map +1 -1
- package/p256.d.ts +3 -3
- package/p384.d.ts +3 -3
- package/p521.d.ts +3 -3
- package/package.json +14 -5
- package/secp256k1.d.ts +6 -6
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +46 -43
- package/secp256k1.js.map +1 -1
- package/src/_shortw_utils.ts +5 -15
- package/src/abstract/bls.ts +260 -145
- package/src/abstract/curve.ts +115 -13
- package/src/abstract/edwards.ts +279 -138
- package/src/abstract/fft.ts +30 -19
- package/src/abstract/hash-to-curve.ts +51 -27
- package/src/abstract/modular.ts +49 -28
- package/src/abstract/montgomery.ts +9 -7
- package/src/abstract/poseidon.ts +22 -18
- package/src/abstract/tower.ts +36 -67
- package/src/abstract/utils.ts +3 -378
- package/src/abstract/weierstrass.ts +700 -453
- package/src/bls12-381.ts +540 -489
- package/src/bn254.ts +47 -35
- package/src/ed25519.ts +80 -64
- package/src/ed448.ts +129 -92
- package/src/misc.ts +39 -34
- package/src/nist.ts +138 -127
- package/src/p256.ts +3 -3
- package/src/p384.ts +3 -3
- package/src/p521.ts +3 -3
- package/src/secp256k1.ts +58 -46
- package/src/utils.ts +328 -0
- package/utils.d.ts +96 -0
- package/utils.d.ts.map +1 -0
- package/utils.js +313 -0
- package/utils.js.map +1 -0
package/src/abstract/fft.ts
CHANGED
|
@@ -76,8 +76,15 @@ function findGenerator(field: IField<bigint>) {
|
|
|
76
76
|
return G;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
export type RootsOfUnity = {
|
|
80
|
+
roots: (bits: number) => bigint[];
|
|
81
|
+
brp(bits: number): bigint[];
|
|
82
|
+
inverse(bits: number): bigint[];
|
|
83
|
+
omega: (bits: number) => bigint;
|
|
84
|
+
clear: () => void;
|
|
85
|
+
};
|
|
79
86
|
/** We limit roots up to 2**31, which is a lot: 2-billion polynomimal should be rare. */
|
|
80
|
-
export function rootsOfUnity(field: IField<bigint>, generator?: bigint) {
|
|
87
|
+
export function rootsOfUnity(field: IField<bigint>, generator?: bigint): RootsOfUnity {
|
|
81
88
|
// Factor field.ORDER-1 as oddFactor * 2^powerOfTwo
|
|
82
89
|
let oddFactor = field.ORDER - _1n;
|
|
83
90
|
let powerOfTwo = 0;
|
|
@@ -186,8 +193,7 @@ export type FFTCoreLoop<T> = <P extends Polynomial<T>>(values: P) => P;
|
|
|
186
193
|
* Cyclic NTT: Rq = Zq[x]/(x^n-1). butterfly_DIT+loop_DIT OR butterfly_DIF+loop_DIT, roots are omega
|
|
187
194
|
* Negacyclic NTT: Rq = Zq[x]/(x^n+1). butterfly_DIT+loop_DIF, at least for mlkem / mldsa
|
|
188
195
|
*/
|
|
189
|
-
export const FFTCore = <T, R>(
|
|
190
|
-
const { add, sub, mul } = opts; // inline to butteflies
|
|
196
|
+
export const FFTCore = <T, R>(F: FFTOpts<T, R>, coreOpts: FFTCoreOpts<R>): FFTCoreLoop<T> => {
|
|
191
197
|
const { N, roots, dit, invertButterflies = false, skipStages = 0, brp = true } = coreOpts;
|
|
192
198
|
const bits = log2(N);
|
|
193
199
|
if (!isPowerOfTwo(N)) throw new Error('FFT: Polynomial size should be power of two');
|
|
@@ -214,15 +220,15 @@ export const FFTCore = <T, R>(opts: FFTOpts<T, R>, coreOpts: FFTCoreOpts<R>): FF
|
|
|
214
220
|
const a = values[i0];
|
|
215
221
|
// Inlining gives us 10% perf in kyber vs functions
|
|
216
222
|
if (isDit) {
|
|
217
|
-
const t = mul(b, omega); // Standard DIT butterfly
|
|
218
|
-
values[i0] = add(a, t);
|
|
219
|
-
values[i1] = sub(a, t);
|
|
223
|
+
const t = F.mul(b, omega); // Standard DIT butterfly
|
|
224
|
+
values[i0] = F.add(a, t);
|
|
225
|
+
values[i1] = F.sub(a, t);
|
|
220
226
|
} else if (invertButterflies) {
|
|
221
|
-
values[i0] = add(b, a); // DIT loop + inverted butterflies (Kyber decode)
|
|
222
|
-
values[i1] = mul(sub(b, a), omega);
|
|
227
|
+
values[i0] = F.add(b, a); // DIT loop + inverted butterflies (Kyber decode)
|
|
228
|
+
values[i1] = F.mul(F.sub(b, a), omega);
|
|
223
229
|
} else {
|
|
224
|
-
values[i0] = add(a, b); // Standard DIF butterfly
|
|
225
|
-
values[i1] = mul(sub(a, b), omega);
|
|
230
|
+
values[i0] = F.add(a, b); // Standard DIF butterfly
|
|
231
|
+
values[i1] = F.mul(F.sub(a, b), omega);
|
|
226
232
|
}
|
|
227
233
|
}
|
|
228
234
|
}
|
|
@@ -232,11 +238,16 @@ export const FFTCore = <T, R>(opts: FFTOpts<T, R>, coreOpts: FFTCoreOpts<R>): FF
|
|
|
232
238
|
};
|
|
233
239
|
};
|
|
234
240
|
|
|
241
|
+
export type FFTMethods<T> = {
|
|
242
|
+
direct<P extends Polynomial<T>>(values: P, brpInput?: boolean, brpOutput?: boolean): P;
|
|
243
|
+
inverse<P extends Polynomial<T>>(values: P, brpInput?: boolean, brpOutput?: boolean): P;
|
|
244
|
+
};
|
|
245
|
+
|
|
235
246
|
/**
|
|
236
247
|
* NTT aka FFT over finite field (NOT over complex numbers).
|
|
237
248
|
* Naming mirrors other libraries.
|
|
238
249
|
*/
|
|
239
|
-
export
|
|
250
|
+
export function FFT<T>(roots: RootsOfUnity, opts: FFTOpts<T, bigint>): FFTMethods<T> {
|
|
240
251
|
const getLoop = (
|
|
241
252
|
N: number,
|
|
242
253
|
roots: Polynomial<bigint>,
|
|
@@ -272,12 +283,12 @@ export const FFT = <T>(roots: ReturnType<typeof rootsOfUnity>, opts: FFTOpts<T,
|
|
|
272
283
|
return res;
|
|
273
284
|
},
|
|
274
285
|
};
|
|
275
|
-
}
|
|
286
|
+
}
|
|
276
287
|
|
|
277
288
|
export type CreatePolyFn<P extends Polynomial<T>, T> = (len: number, elm?: T) => P;
|
|
278
289
|
|
|
279
290
|
export type PolyFn<P extends Polynomial<T>, T> = {
|
|
280
|
-
roots:
|
|
291
|
+
roots: RootsOfUnity;
|
|
281
292
|
create: CreatePolyFn<P, T>;
|
|
282
293
|
length?: number; // optional enforced size
|
|
283
294
|
|
|
@@ -318,23 +329,23 @@ export type PolyFn<P extends Polynomial<T>, T> = {
|
|
|
318
329
|
*/
|
|
319
330
|
export function poly<T>(
|
|
320
331
|
field: IField<T>,
|
|
321
|
-
roots:
|
|
332
|
+
roots: RootsOfUnity,
|
|
322
333
|
create?: undefined,
|
|
323
|
-
fft?:
|
|
334
|
+
fft?: FFTMethods<T>,
|
|
324
335
|
length?: number
|
|
325
336
|
): PolyFn<T[], T>;
|
|
326
337
|
export function poly<T, P extends Polynomial<T>>(
|
|
327
338
|
field: IField<T>,
|
|
328
|
-
roots:
|
|
339
|
+
roots: RootsOfUnity,
|
|
329
340
|
create: CreatePolyFn<P, T>,
|
|
330
|
-
fft?:
|
|
341
|
+
fft?: FFTMethods<T>,
|
|
331
342
|
length?: number
|
|
332
343
|
): PolyFn<P, T>;
|
|
333
344
|
export function poly<T, P extends Polynomial<T>>(
|
|
334
345
|
field: IField<T>,
|
|
335
|
-
roots:
|
|
346
|
+
roots: RootsOfUnity,
|
|
336
347
|
create?: CreatePolyFn<P, T>,
|
|
337
|
-
fft?:
|
|
348
|
+
fft?: FFTMethods<T>,
|
|
338
349
|
length?: number
|
|
339
350
|
): PolyFn<any, T> {
|
|
340
351
|
const F = field;
|
|
@@ -5,10 +5,18 @@
|
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
|
+
import type { CHash } from '../utils.ts';
|
|
9
|
+
import {
|
|
10
|
+
_validateObject,
|
|
11
|
+
abytes,
|
|
12
|
+
bytesToNumberBE,
|
|
13
|
+
concatBytes,
|
|
14
|
+
isBytes,
|
|
15
|
+
isHash,
|
|
16
|
+
utf8ToBytes,
|
|
17
|
+
} from '../utils.ts';
|
|
8
18
|
import type { AffinePoint, Group, GroupConstructor } from './curve.ts';
|
|
9
19
|
import { FpInvertBatch, type IField, mod } from './modular.ts';
|
|
10
|
-
import type { CHash } from './utils.ts';
|
|
11
|
-
import { abytes, bytesToNumberBE, concatBytes, utf8ToBytes, validateObject } from './utils.ts';
|
|
12
20
|
|
|
13
21
|
export type UnicodeOrBytes = string | Uint8Array;
|
|
14
22
|
|
|
@@ -20,14 +28,20 @@ export type UnicodeOrBytes = string | Uint8Array;
|
|
|
20
28
|
* * `expand` is `xmd` (SHA2, SHA3, BLAKE) or `xof` (SHAKE, BLAKE-XOF)
|
|
21
29
|
* * `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
|
|
22
30
|
*/
|
|
23
|
-
export type
|
|
31
|
+
export type H2COpts = {
|
|
24
32
|
DST: UnicodeOrBytes;
|
|
33
|
+
expand: 'xmd' | 'xof';
|
|
34
|
+
hash: CHash;
|
|
25
35
|
p: bigint;
|
|
26
36
|
m: number;
|
|
27
37
|
k: number;
|
|
38
|
+
};
|
|
39
|
+
export type H2CHashOpts = {
|
|
28
40
|
expand: 'xmd' | 'xof';
|
|
29
41
|
hash: CHash;
|
|
30
42
|
};
|
|
43
|
+
// todo: remove
|
|
44
|
+
export type Opts = H2COpts;
|
|
31
45
|
|
|
32
46
|
// Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE.
|
|
33
47
|
const os2ip = bytesToNumberBE;
|
|
@@ -133,15 +147,17 @@ export function expand_message_xof(
|
|
|
133
147
|
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
|
|
134
148
|
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
|
135
149
|
*/
|
|
136
|
-
export function hash_to_field(msg: Uint8Array, count: number, options:
|
|
137
|
-
|
|
138
|
-
DST: 'stringOrUint8Array',
|
|
150
|
+
export function hash_to_field(msg: Uint8Array, count: number, options: H2COpts): bigint[][] {
|
|
151
|
+
_validateObject(options, {
|
|
139
152
|
p: 'bigint',
|
|
140
|
-
m: '
|
|
141
|
-
k: '
|
|
142
|
-
hash: '
|
|
153
|
+
m: 'number',
|
|
154
|
+
k: 'number',
|
|
155
|
+
hash: 'function',
|
|
143
156
|
});
|
|
144
157
|
const { p, k, m, hash, expand, DST: _DST } = options;
|
|
158
|
+
if (!isBytes(_DST) && typeof _DST !== 'string')
|
|
159
|
+
throw new Error('DST must be string or uint8array');
|
|
160
|
+
if (!isHash(options.hash)) throw new Error('expected valid hash');
|
|
145
161
|
abytes(msg);
|
|
146
162
|
anum(count);
|
|
147
163
|
const DST = typeof _DST === 'string' ? utf8ToBytes(_DST) : _DST;
|
|
@@ -209,21 +225,32 @@ export type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
|
|
|
209
225
|
// Separated from initialization opts, so users won't accidentally change per-curve parameters
|
|
210
226
|
// (changing DST is ok!)
|
|
211
227
|
export type htfBasicOpts = { DST: UnicodeOrBytes };
|
|
212
|
-
export type
|
|
228
|
+
export type H2CMethod<T> = (msg: Uint8Array, options?: htfBasicOpts) => H2CPoint<T>;
|
|
229
|
+
// TODO: remove
|
|
230
|
+
export type HTFMethod<T> = H2CMethod<T>;
|
|
213
231
|
export type MapMethod<T> = (scalars: bigint[]) => H2CPoint<T>;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
232
|
+
/**
|
|
233
|
+
* RFC 9380 methods, with cofactor clearing. See https://www.rfc-editor.org/rfc/rfc9380#section-3.
|
|
234
|
+
*
|
|
235
|
+
* * hashToCurve: `map(hash(input))`, encodes RANDOM bytes to curve (WITH hashing)
|
|
236
|
+
* * encodeToCurve: `map(hash(input))`, encodes NON-UNIFORM bytes to curve (WITH hashing)
|
|
237
|
+
* * mapToCurve: `map(scalars)`, encodes NON-UNIFORM scalars to curve (NO hashing)
|
|
238
|
+
*/
|
|
239
|
+
export type H2CHasher<T> = {
|
|
240
|
+
hashToCurve: H2CMethod<T>;
|
|
241
|
+
encodeToCurve: H2CMethod<T>;
|
|
217
242
|
mapToCurve: MapMethod<T>;
|
|
218
|
-
defaults:
|
|
243
|
+
defaults: H2COpts & { encodeDST?: UnicodeOrBytes };
|
|
219
244
|
};
|
|
245
|
+
// TODO: remove
|
|
246
|
+
export type Hasher<T> = H2CHasher<T>;
|
|
220
247
|
|
|
221
|
-
/** Creates hash-to-curve methods from EC Point and mapToCurve function. */
|
|
248
|
+
/** Creates hash-to-curve methods from EC Point and mapToCurve function. See {@link H2CHasher}. */
|
|
222
249
|
export function createHasher<T>(
|
|
223
250
|
Point: H2CPointConstructor<T>,
|
|
224
251
|
mapToCurve: MapToCurve<T>,
|
|
225
|
-
defaults:
|
|
226
|
-
):
|
|
252
|
+
defaults: H2COpts & { encodeDST?: UnicodeOrBytes }
|
|
253
|
+
): H2CHasher<T> {
|
|
227
254
|
if (typeof mapToCurve !== 'function') throw new Error('mapToCurve() must be defined');
|
|
228
255
|
function map(num: bigint[]) {
|
|
229
256
|
return Point.fromAffine(mapToCurve(num));
|
|
@@ -237,24 +264,21 @@ export function createHasher<T>(
|
|
|
237
264
|
|
|
238
265
|
return {
|
|
239
266
|
defaults,
|
|
240
|
-
|
|
241
|
-
// Encodes byte string to elliptic curve.
|
|
242
|
-
// hash_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3
|
|
243
267
|
hashToCurve(msg: Uint8Array, options?: htfBasicOpts): H2CPoint<T> {
|
|
244
|
-
const
|
|
268
|
+
const dst = defaults.DST ? defaults.DST : {};
|
|
269
|
+
const opts = Object.assign({}, defaults, dst, options);
|
|
270
|
+
const u = hash_to_field(msg, 2, opts);
|
|
245
271
|
const u0 = map(u[0]);
|
|
246
272
|
const u1 = map(u[1]);
|
|
247
273
|
return clear(u0.add(u1));
|
|
248
274
|
},
|
|
249
|
-
|
|
250
|
-
// Encodes byte string to elliptic curve.
|
|
251
|
-
// encode_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3
|
|
252
275
|
encodeToCurve(msg: Uint8Array, options?: htfBasicOpts): H2CPoint<T> {
|
|
253
|
-
const
|
|
276
|
+
const dst = defaults.encodeDST ? defaults.encodeDST : {};
|
|
277
|
+
const opts = Object.assign({}, defaults, dst, options);
|
|
278
|
+
const u = hash_to_field(msg, 1, opts);
|
|
254
279
|
return clear(map(u[0]));
|
|
255
280
|
},
|
|
256
|
-
|
|
257
|
-
// Same as encodeToCurve, but without hash
|
|
281
|
+
/** See {@link H2CHasher} */
|
|
258
282
|
mapToCurve(scalars: bigint[]): H2CPoint<T> {
|
|
259
283
|
if (!Array.isArray(scalars)) throw new Error('expected array of bigints');
|
|
260
284
|
for (const i of scalars)
|
package/src/abstract/modular.ts
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Utils for modular division and
|
|
3
|
-
*
|
|
2
|
+
* Utils for modular division and fields.
|
|
3
|
+
* Field over 11 is a finite (Galois) field is integer number operations `mod 11`.
|
|
4
4
|
* There is no division: it is replaced by modular multiplicative inverse.
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
|
-
import { anumber } from '@noble/hashes/utils';
|
|
9
8
|
import {
|
|
9
|
+
_validateObject,
|
|
10
|
+
anumber,
|
|
10
11
|
bitMask,
|
|
11
12
|
bytesToNumberBE,
|
|
12
13
|
bytesToNumberLE,
|
|
13
14
|
ensureBytes,
|
|
14
15
|
numberToBytesBE,
|
|
15
16
|
numberToBytesLE,
|
|
16
|
-
|
|
17
|
-
} from './utils.ts';
|
|
17
|
+
} from '../utils.ts';
|
|
18
18
|
|
|
19
19
|
// prettier-ignore
|
|
20
20
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
|
|
21
21
|
// prettier-ignore
|
|
22
|
-
const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5)
|
|
22
|
+
const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5);
|
|
23
|
+
const _8n = /* @__PURE__ */ BigInt(8);
|
|
23
24
|
|
|
24
25
|
// Calculates a modulo b
|
|
25
26
|
export function mod(a: bigint, b: bigint): bigint {
|
|
@@ -29,7 +30,6 @@ export function mod(a: bigint, b: bigint): bigint {
|
|
|
29
30
|
/**
|
|
30
31
|
* Efficiently raise num to power and do modular division.
|
|
31
32
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
32
|
-
* TODO: remove.
|
|
33
33
|
* @example
|
|
34
34
|
* pow(2n, 6n, 11n) // 64n % 11n == 9n
|
|
35
35
|
*/
|
|
@@ -128,6 +128,7 @@ function sqrt5mod8<T>(Fp: IField<T>, n: T) {
|
|
|
128
128
|
*/
|
|
129
129
|
export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
|
130
130
|
// Initialization (precomputation).
|
|
131
|
+
// Caching initialization could boost perf by 7%.
|
|
131
132
|
if (P < BigInt(3)) throw new Error('sqrt is not defined for small field');
|
|
132
133
|
// Factor P - 1 = Q * 2^S, where Q is odd
|
|
133
134
|
let Q = P - _1n;
|
|
@@ -228,6 +229,7 @@ export interface IField<T> {
|
|
|
228
229
|
create: (num: T) => T;
|
|
229
230
|
isValid: (num: T) => boolean;
|
|
230
231
|
is0: (num: T) => boolean;
|
|
232
|
+
isValidNot0: (num: T) => boolean;
|
|
231
233
|
neg(num: T): T;
|
|
232
234
|
inv(num: T): T;
|
|
233
235
|
sqrt(num: T): T;
|
|
@@ -267,14 +269,18 @@ export function validateField<T>(field: IField<T>): IField<T> {
|
|
|
267
269
|
const initial = {
|
|
268
270
|
ORDER: 'bigint',
|
|
269
271
|
MASK: 'bigint',
|
|
270
|
-
BYTES: '
|
|
271
|
-
BITS: '
|
|
272
|
+
BYTES: 'number',
|
|
273
|
+
BITS: 'number',
|
|
272
274
|
} as Record<string, string>;
|
|
273
275
|
const opts = FIELD_FIELDS.reduce((map, val: string) => {
|
|
274
276
|
map[val] = 'function';
|
|
275
277
|
return map;
|
|
276
278
|
}, initial);
|
|
277
|
-
|
|
279
|
+
_validateObject(field, opts);
|
|
280
|
+
// const max = 16384;
|
|
281
|
+
// if (field.BYTES < 1 || field.BYTES > max) throw new Error('invalid field');
|
|
282
|
+
// if (field.BITS < 1 || field.BITS > 8 * max) throw new Error('invalid field');
|
|
283
|
+
return field;
|
|
278
284
|
}
|
|
279
285
|
|
|
280
286
|
// Generic field functions
|
|
@@ -353,14 +359,9 @@ export function FpIsSquare<T>(Fp: IField<T>, n: T): boolean {
|
|
|
353
359
|
return l === 1;
|
|
354
360
|
}
|
|
355
361
|
|
|
362
|
+
export type NLength = { nByteLength: number; nBitLength: number };
|
|
356
363
|
// CURVE.n lengths
|
|
357
|
-
export function nLength(
|
|
358
|
-
n: bigint,
|
|
359
|
-
nBitLength?: number
|
|
360
|
-
): {
|
|
361
|
-
nBitLength: number;
|
|
362
|
-
nByteLength: number;
|
|
363
|
-
} {
|
|
364
|
+
export function nLength(n: bigint, nBitLength?: number): NLength {
|
|
364
365
|
// Bit size, byte size of CURVE.n
|
|
365
366
|
if (nBitLength !== undefined) anumber(nBitLength);
|
|
366
367
|
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
|
|
@@ -369,29 +370,47 @@ export function nLength(
|
|
|
369
370
|
}
|
|
370
371
|
|
|
371
372
|
type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
|
|
373
|
+
type SqrtFn = (n: bigint) => bigint;
|
|
374
|
+
type FieldOpts = Partial<{ sqrt: SqrtFn; isLE: boolean; BITS: number }>;
|
|
372
375
|
/**
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* *
|
|
376
|
-
* *
|
|
377
|
-
* * c) Object.freeze
|
|
376
|
+
* Creates a finite field. Major performance optimizations:
|
|
377
|
+
* * 1. Denormalized operations like mulN instead of mul.
|
|
378
|
+
* * 2. Identical object shape: never add or remove keys.
|
|
379
|
+
* * 3. `Object.freeze`.
|
|
378
380
|
* Fragile: always run a benchmark on a change.
|
|
379
381
|
* Security note: operations don't check 'isValid' for all elements for performance reasons,
|
|
380
382
|
* it is caller responsibility to check this.
|
|
381
383
|
* This is low-level code, please make sure you know what you're doing.
|
|
382
|
-
*
|
|
384
|
+
*
|
|
385
|
+
* Note about field properties:
|
|
386
|
+
* * CHARACTERISTIC p = prime number, number of elements in main subgroup.
|
|
387
|
+
* * ORDER q = similar to cofactor in curves, may be composite `q = p^m`.
|
|
388
|
+
*
|
|
389
|
+
* @param ORDER field order, probably prime, or could be composite
|
|
383
390
|
* @param bitLen how many bits the field consumes
|
|
384
|
-
* @param isLE (
|
|
391
|
+
* @param isLE (default: false) if encoding / decoding should be in little-endian
|
|
385
392
|
* @param redef optional faster redefinitions of sqrt and other methods
|
|
386
393
|
*/
|
|
387
394
|
export function Field(
|
|
388
395
|
ORDER: bigint,
|
|
389
|
-
|
|
396
|
+
bitLenOrOpts?: number | FieldOpts,
|
|
390
397
|
isLE = false,
|
|
391
|
-
|
|
398
|
+
opts: { sqrt?: SqrtFn } = {}
|
|
392
399
|
): Readonly<FpField> {
|
|
393
400
|
if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
|
|
394
|
-
|
|
401
|
+
let _nbitLength: number | undefined = undefined;
|
|
402
|
+
let _sqrt: SqrtFn | undefined = undefined;
|
|
403
|
+
if (typeof bitLenOrOpts === 'object' && bitLenOrOpts != null) {
|
|
404
|
+
if (opts.sqrt || isLE) throw new Error('cannot specify opts in two arguments');
|
|
405
|
+
const _opts = bitLenOrOpts;
|
|
406
|
+
if (_opts.BITS) _nbitLength = _opts.BITS;
|
|
407
|
+
if (_opts.sqrt) _sqrt = _opts.sqrt;
|
|
408
|
+
if (typeof _opts.isLE === 'boolean') isLE = _opts.isLE;
|
|
409
|
+
} else {
|
|
410
|
+
if (typeof bitLenOrOpts === 'number') _nbitLength = bitLenOrOpts;
|
|
411
|
+
if (opts.sqrt) _sqrt = opts.sqrt;
|
|
412
|
+
}
|
|
413
|
+
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, _nbitLength);
|
|
395
414
|
if (BYTES > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');
|
|
396
415
|
let sqrtP: ReturnType<typeof FpSqrt>; // cached sqrtP
|
|
397
416
|
const f: Readonly<FpField> = Object.freeze({
|
|
@@ -409,6 +428,8 @@ export function Field(
|
|
|
409
428
|
return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
|
|
410
429
|
},
|
|
411
430
|
is0: (num) => num === _0n,
|
|
431
|
+
// is valid and invertible
|
|
432
|
+
isValidNot0: (num: bigint) => !f.is0(num) && f.isValid(num),
|
|
412
433
|
isOdd: (num) => (num & _1n) === _1n,
|
|
413
434
|
neg: (num) => mod(-num, ORDER),
|
|
414
435
|
eql: (lhs, rhs) => lhs === rhs,
|
|
@@ -428,7 +449,7 @@ export function Field(
|
|
|
428
449
|
|
|
429
450
|
inv: (num) => invert(num, ORDER),
|
|
430
451
|
sqrt:
|
|
431
|
-
|
|
452
|
+
_sqrt ||
|
|
432
453
|
((n) => {
|
|
433
454
|
if (!sqrtP) sqrtP = FpSqrt(ORDER);
|
|
434
455
|
return sqrtP(f, n);
|
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
|
-
import { mod } from './modular.ts';
|
|
9
8
|
import {
|
|
9
|
+
_validateObject,
|
|
10
10
|
aInRange,
|
|
11
11
|
bytesToNumberLE,
|
|
12
12
|
ensureBytes,
|
|
13
13
|
numberToBytesLE,
|
|
14
|
-
|
|
15
|
-
} from '
|
|
14
|
+
randomBytes,
|
|
15
|
+
} from '../utils.ts';
|
|
16
|
+
import { mod } from './modular.ts';
|
|
16
17
|
|
|
17
18
|
const _0n = BigInt(0);
|
|
18
19
|
const _1n = BigInt(1);
|
|
@@ -24,7 +25,7 @@ export type CurveType = {
|
|
|
24
25
|
type: 'x25519' | 'x448';
|
|
25
26
|
adjustScalarBytes: (bytes: Uint8Array) => Uint8Array;
|
|
26
27
|
powPminus2: (x: bigint) => bigint;
|
|
27
|
-
randomBytes
|
|
28
|
+
randomBytes?: (bytesLength?: number) => Uint8Array;
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
export type CurveFn = {
|
|
@@ -37,7 +38,7 @@ export type CurveFn = {
|
|
|
37
38
|
};
|
|
38
39
|
|
|
39
40
|
function validateOpts(curve: CurveType) {
|
|
40
|
-
|
|
41
|
+
_validateObject(curve, {
|
|
41
42
|
adjustScalarBytes: 'function',
|
|
42
43
|
powPminus2: 'function',
|
|
43
44
|
});
|
|
@@ -46,9 +47,10 @@ function validateOpts(curve: CurveType) {
|
|
|
46
47
|
|
|
47
48
|
export function montgomery(curveDef: CurveType): CurveFn {
|
|
48
49
|
const CURVE = validateOpts(curveDef);
|
|
49
|
-
const { P, type, adjustScalarBytes, powPminus2 } = CURVE;
|
|
50
|
+
const { P, type, adjustScalarBytes, powPminus2, randomBytes: rand } = CURVE;
|
|
50
51
|
const is25519 = type === 'x25519';
|
|
51
52
|
if (!is25519 && type !== 'x448') throw new Error('invalid type');
|
|
53
|
+
const randomBytes_ = rand || randomBytes;
|
|
52
54
|
|
|
53
55
|
const montgomeryBits = is25519 ? 255 : 448;
|
|
54
56
|
const fieldLen = is25519 ? 32 : 56;
|
|
@@ -159,7 +161,7 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
|
|
159
161
|
scalarMultBase,
|
|
160
162
|
getSharedSecret: (privateKey: Hex, publicKey: Hex) => scalarMult(privateKey, publicKey),
|
|
161
163
|
getPublicKey: (privateKey: Hex): Uint8Array => scalarMultBase(privateKey),
|
|
162
|
-
utils: { randomPrivateKey: () =>
|
|
164
|
+
utils: { randomPrivateKey: () => randomBytes_(fieldLen) },
|
|
163
165
|
GuBytes: GuBytes.slice(),
|
|
164
166
|
};
|
|
165
167
|
}
|
package/src/abstract/poseidon.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
10
|
+
import { _validateObject, bitGet } from '../utils.ts';
|
|
10
11
|
import { FpInvertBatch, FpPow, type IField, validateField } from './modular.ts';
|
|
11
|
-
import { bitGet } from './utils.ts';
|
|
12
12
|
|
|
13
13
|
// Grain LFSR (Linear-Feedback Shift Register): https://eprint.iacr.org/2009/109.pdf
|
|
14
14
|
function grainLFSR(state: number[]): () => boolean {
|
|
@@ -41,20 +41,28 @@ export type PoseidonBasicOpts = {
|
|
|
41
41
|
isSboxInverse?: boolean;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
function
|
|
44
|
+
function assertValidPosOpts(opts: PoseidonBasicOpts) {
|
|
45
45
|
const { Fp, roundsFull } = opts;
|
|
46
46
|
validateField(Fp);
|
|
47
|
+
_validateObject(
|
|
48
|
+
opts,
|
|
49
|
+
{
|
|
50
|
+
t: 'number',
|
|
51
|
+
roundsFull: 'number',
|
|
52
|
+
roundsPartial: 'number',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
isSboxInverse: 'boolean',
|
|
56
|
+
}
|
|
57
|
+
);
|
|
47
58
|
for (const i of ['t', 'roundsFull', 'roundsPartial'] as const) {
|
|
48
|
-
if (
|
|
49
|
-
throw new Error('invalid number ' + i);
|
|
59
|
+
if (!Number.isSafeInteger(opts[i]) || opts[i] < 1) throw new Error('invalid number ' + i);
|
|
50
60
|
}
|
|
51
|
-
if (opts.isSboxInverse !== undefined && typeof opts.isSboxInverse !== 'boolean')
|
|
52
|
-
throw new Error(`Poseidon: invalid param isSboxInverse=${opts.isSboxInverse}`);
|
|
53
61
|
if (roundsFull & 1) throw new Error('roundsFull is not even' + roundsFull);
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
function poseidonGrain(opts: PoseidonBasicOpts) {
|
|
57
|
-
|
|
65
|
+
assertValidPosOpts(opts);
|
|
58
66
|
const { Fp } = opts;
|
|
59
67
|
const state = Array(80).fill(1);
|
|
60
68
|
let pos = 0;
|
|
@@ -140,7 +148,7 @@ export function validateOpts(opts: PoseidonOpts): Readonly<{
|
|
|
140
148
|
sboxPower?: number;
|
|
141
149
|
reversePartialPowIdx?: boolean; // Hack for stark
|
|
142
150
|
}> {
|
|
143
|
-
|
|
151
|
+
assertValidPosOpts(opts);
|
|
144
152
|
const { Fp, mds, reversePartialPowIdx: rev, roundConstants: rc } = opts;
|
|
145
153
|
const { roundsFull, roundsPartial, sboxPower, t } = opts;
|
|
146
154
|
|
|
@@ -196,12 +204,13 @@ export function splitConstants(rc: bigint[], t: number): bigint[][] {
|
|
|
196
204
|
return res;
|
|
197
205
|
}
|
|
198
206
|
|
|
199
|
-
|
|
200
|
-
export function poseidon(opts: PoseidonOpts): {
|
|
207
|
+
export type PoseidonFn = {
|
|
201
208
|
(values: bigint[]): bigint[];
|
|
202
209
|
// For verification in tests
|
|
203
210
|
roundConstants: bigint[][];
|
|
204
|
-
}
|
|
211
|
+
};
|
|
212
|
+
/** Poseidon NTT-friendly hash. */
|
|
213
|
+
export function poseidon(opts: PoseidonOpts): PoseidonFn {
|
|
205
214
|
const _opts = validateOpts(opts);
|
|
206
215
|
const { Fp, mds, roundConstants, rounds: totalRounds, roundsPartial, sboxFn, t } = _opts;
|
|
207
216
|
const halfRoundsFull = _opts.roundsFull / 2;
|
|
@@ -242,17 +251,12 @@ export class PoseidonSponge {
|
|
|
242
251
|
private Fp: IField<bigint>;
|
|
243
252
|
readonly rate: number;
|
|
244
253
|
readonly capacity: number;
|
|
245
|
-
readonly hash:
|
|
254
|
+
readonly hash: PoseidonFn;
|
|
246
255
|
private state: bigint[]; // [...capacity, ...rate]
|
|
247
256
|
private pos = 0;
|
|
248
257
|
private isAbsorbing = true;
|
|
249
258
|
|
|
250
|
-
constructor(
|
|
251
|
-
Fp: IField<bigint>,
|
|
252
|
-
rate: number,
|
|
253
|
-
capacity: number,
|
|
254
|
-
hash: ReturnType<typeof poseidon>
|
|
255
|
-
) {
|
|
259
|
+
constructor(Fp: IField<bigint>, rate: number, capacity: number, hash: PoseidonFn) {
|
|
256
260
|
this.Fp = Fp;
|
|
257
261
|
this.hash = hash;
|
|
258
262
|
this.rate = rate;
|