@noble/curves 1.7.0 → 1.8.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/README.md +40 -21
- package/_shortw_utils.d.ts +9 -55
- package/_shortw_utils.d.ts.map +1 -1
- package/_shortw_utils.js +6 -2
- package/_shortw_utils.js.map +1 -1
- package/abstract/bls.d.ts +8 -6
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +17 -1
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +27 -32
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +19 -12
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +14 -25
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +5 -1
- package/abstract/edwards.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +29 -9
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +15 -10
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +30 -5
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +36 -16
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +6 -1
- package/abstract/montgomery.js.map +1 -1
- package/abstract/poseidon.d.ts +10 -1
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +9 -1
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts +12 -1
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +14 -11
- package/abstract/tower.js.map +1 -1
- package/abstract/utils.d.ts +10 -5
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +5 -1
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +51 -85
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +42 -15
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +12 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +72 -60
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +4 -3
- package/bn254.d.ts.map +1 -1
- package/bn254.js +23 -20
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +27 -7
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +30 -6
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +25 -10
- package/ed448.d.ts.map +1 -1
- package/ed448.js +30 -8
- package/ed448.js.map +1 -1
- package/esm/_shortw_utils.d.ts +9 -55
- package/esm/_shortw_utils.d.ts.map +1 -1
- package/esm/_shortw_utils.js +6 -2
- package/esm/_shortw_utils.js.map +1 -1
- package/esm/abstract/bls.d.ts +8 -6
- package/esm/abstract/bls.d.ts.map +1 -1
- package/esm/abstract/bls.js +17 -1
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +27 -32
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +21 -14
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +14 -25
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +8 -4
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/hash-to-curve.d.ts +29 -9
- package/esm/abstract/hash-to-curve.d.ts.map +1 -1
- package/esm/abstract/hash-to-curve.js +15 -10
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.d.ts +30 -5
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +36 -16
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +6 -1
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/poseidon.d.ts +10 -1
- package/esm/abstract/poseidon.d.ts.map +1 -1
- package/esm/abstract/poseidon.js +9 -1
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/tower.d.ts +12 -1
- package/esm/abstract/tower.d.ts.map +1 -1
- package/esm/abstract/tower.js +14 -11
- package/esm/abstract/tower.js.map +1 -1
- package/esm/abstract/utils.d.ts +10 -5
- package/esm/abstract/utils.d.ts.map +1 -1
- package/esm/abstract/utils.js +4 -0
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +51 -85
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +42 -16
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.d.ts +12 -1
- package/esm/bls12-381.d.ts.map +1 -1
- package/esm/bls12-381.js +73 -61
- package/esm/bls12-381.js.map +1 -1
- package/esm/bn254.d.ts +4 -3
- package/esm/bn254.d.ts.map +1 -1
- package/esm/bn254.js +23 -20
- package/esm/bn254.js.map +1 -1
- package/esm/ed25519.d.ts +27 -7
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +31 -7
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +25 -10
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +31 -9
- package/esm/ed448.js.map +1 -1
- package/esm/index.js +16 -0
- package/esm/index.js.map +1 -1
- package/esm/jubjub.d.ts +4 -8
- package/esm/jubjub.d.ts.map +1 -1
- package/esm/jubjub.js +6 -5
- package/esm/jubjub.js.map +1 -1
- package/esm/p256.d.ts +10 -104
- package/esm/p256.d.ts.map +1 -1
- package/esm/p256.js +9 -2
- package/esm/p256.js.map +1 -1
- package/esm/p384.d.ts +10 -104
- package/esm/p384.d.ts.map +1 -1
- package/esm/p384.js +9 -2
- package/esm/p384.js.map +1 -1
- package/esm/p521.d.ts +11 -104
- package/esm/p521.d.ts.map +1 -1
- package/esm/p521.js +11 -3
- package/esm/p521.js.map +1 -1
- package/esm/pasta.d.ts +5 -2
- package/esm/pasta.d.ts.map +1 -1
- package/esm/pasta.js +6 -2
- package/esm/pasta.js.map +1 -1
- package/esm/secp256k1.d.ts +30 -58
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +34 -8
- package/esm/secp256k1.js.map +1 -1
- package/index.js +16 -0
- package/index.js.map +1 -1
- package/jubjub.d.ts +4 -8
- package/jubjub.d.ts.map +1 -1
- package/jubjub.js +6 -5
- package/jubjub.js.map +1 -1
- package/p256.d.ts +10 -104
- package/p256.d.ts.map +1 -1
- package/p256.js +9 -2
- package/p256.js.map +1 -1
- package/p384.d.ts +10 -104
- package/p384.d.ts.map +1 -1
- package/p384.js +9 -2
- package/p384.js.map +1 -1
- package/p521.d.ts +11 -104
- package/p521.d.ts.map +1 -1
- package/p521.js +11 -3
- package/p521.js.map +1 -1
- package/package.json +16 -13
- package/pasta.d.ts +5 -2
- package/pasta.d.ts.map +1 -1
- package/pasta.js +6 -2
- package/pasta.js.map +1 -1
- package/secp256k1.d.ts +30 -58
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +33 -7
- package/secp256k1.js.map +1 -1
- package/src/_shortw_utils.ts +19 -9
- package/src/abstract/bls.ts +20 -18
- package/src/abstract/curve.ts +52 -19
- package/src/abstract/edwards.ts +18 -12
- package/src/abstract/hash-to-curve.ts +42 -17
- package/src/abstract/modular.ts +55 -27
- package/src/abstract/montgomery.ts +7 -1
- package/src/abstract/poseidon.ts +29 -7
- package/src/abstract/tower.ts +59 -14
- package/src/abstract/utils.ts +26 -19
- package/src/abstract/weierstrass.ts +91 -50
- package/src/bls12-381.ts +80 -66
- package/src/bn254.ts +30 -24
- package/src/ed25519.ts +52 -23
- package/src/ed448.ts +50 -23
- package/src/index.ts +16 -0
- package/src/jubjub.ts +10 -10
- package/src/p256.ts +15 -9
- package/src/p384.ts +15 -9
- package/src/p521.ts +17 -10
- package/src/pasta.ts +15 -7
- package/src/secp256k1.ts +57 -15
package/src/abstract/modular.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utils for modular division and finite fields.
|
|
3
|
+
* A finite field over 11 is integer number operations `mod 11`.
|
|
4
|
+
* There is no division: it is replaced by modular multiplicative inverse.
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
1
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
-
// Utilities for modular arithmetics and finite fields
|
|
3
8
|
import {
|
|
4
9
|
bitMask,
|
|
5
10
|
bytesToNumberBE,
|
|
@@ -9,6 +14,7 @@ import {
|
|
|
9
14
|
numberToBytesLE,
|
|
10
15
|
validateObject,
|
|
11
16
|
} from './utils.js';
|
|
17
|
+
|
|
12
18
|
// prettier-ignore
|
|
13
19
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
|
|
14
20
|
// prettier-ignore
|
|
@@ -24,10 +30,10 @@ export function mod(a: bigint, b: bigint): bigint {
|
|
|
24
30
|
/**
|
|
25
31
|
* Efficiently raise num to power and do modular division.
|
|
26
32
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
33
|
+
* @todo use field version && remove
|
|
27
34
|
* @example
|
|
28
35
|
* pow(2n, 6n, 11n) // 64n % 11n == 9n
|
|
29
36
|
*/
|
|
30
|
-
// TODO: use field version && remove
|
|
31
37
|
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
|
32
38
|
if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
|
|
33
39
|
if (modulo <= _0n) throw new Error('invalid modulus');
|
|
@@ -41,7 +47,7 @@ export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
|
|
41
47
|
return res;
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
|
|
50
|
+
/** Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)` */
|
|
45
51
|
export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
|
|
46
52
|
let res = x;
|
|
47
53
|
while (power-- > _0n) {
|
|
@@ -51,11 +57,13 @@ export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
|
|
|
51
57
|
return res;
|
|
52
58
|
}
|
|
53
59
|
|
|
54
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Inverses number over modulo.
|
|
62
|
+
* Implemented using [Euclidean GCD](https://brilliant.org/wiki/extended-euclidean-algorithm/).
|
|
63
|
+
*/
|
|
55
64
|
export function invert(number: bigint, modulo: bigint): bigint {
|
|
56
65
|
if (number === _0n) throw new Error('invert: expected non-zero number');
|
|
57
66
|
if (modulo <= _0n) throw new Error('invert: expected positive modulus, got ' + modulo);
|
|
58
|
-
// Euclidean GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
|
|
59
67
|
// Fermat's little theorem "CT-like" version inv(n) = n^(m-2) mod m is 30x slower.
|
|
60
68
|
let a = mod(number, modulo);
|
|
61
69
|
let b = modulo;
|
|
@@ -83,7 +91,7 @@ export function invert(number: bigint, modulo: bigint): bigint {
|
|
|
83
91
|
* @param P field order
|
|
84
92
|
* @returns function that takes field Fp (created from P) and number n
|
|
85
93
|
*/
|
|
86
|
-
export function tonelliShanks(P: bigint) {
|
|
94
|
+
export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
|
87
95
|
// Legendre constant: used to calculate Legendre symbol (a | p),
|
|
88
96
|
// which denotes the value of a^((p-1)/2) (mod p).
|
|
89
97
|
// (a | p) ≡ 1 if a is a square (mod p)
|
|
@@ -142,10 +150,18 @@ export function tonelliShanks(P: bigint) {
|
|
|
142
150
|
};
|
|
143
151
|
}
|
|
144
152
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Square root for a finite field. It will try to check if optimizations are applicable and fall back to 4:
|
|
155
|
+
*
|
|
156
|
+
* 1. P ≡ 3 (mod 4)
|
|
157
|
+
* 2. P ≡ 5 (mod 8)
|
|
158
|
+
* 3. P ≡ 9 (mod 16)
|
|
159
|
+
* 4. Tonelli-Shanks algorithm
|
|
160
|
+
*
|
|
161
|
+
* Different algorithms can give different roots, it is up to user to decide which one they want.
|
|
162
|
+
* For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
|
|
163
|
+
*/
|
|
164
|
+
export function FpSqrt(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
|
149
165
|
// P ≡ 3 (mod 4)
|
|
150
166
|
// √n = n^((P+1)/4)
|
|
151
167
|
if (P % _4n === _3n) {
|
|
@@ -203,11 +219,13 @@ export function FpSqrt(P: bigint) {
|
|
|
203
219
|
}
|
|
204
220
|
|
|
205
221
|
// Little-endian check for first LE bit (last BE bit);
|
|
206
|
-
export const isNegativeLE = (num: bigint, modulo: bigint) =>
|
|
222
|
+
export const isNegativeLE = (num: bigint, modulo: bigint): boolean =>
|
|
223
|
+
(mod(num, modulo) & _1n) === _1n;
|
|
207
224
|
|
|
208
|
-
|
|
225
|
+
/** Field is not always over prime: for example, Fp2 has ORDER(q)=p^m. */
|
|
209
226
|
export interface IField<T> {
|
|
210
227
|
ORDER: bigint;
|
|
228
|
+
isLE: boolean;
|
|
211
229
|
BYTES: number;
|
|
212
230
|
BITS: number;
|
|
213
231
|
MASK: bigint;
|
|
@@ -253,7 +271,7 @@ const FIELD_FIELDS = [
|
|
|
253
271
|
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
|
254
272
|
'addN', 'subN', 'mulN', 'sqrN'
|
|
255
273
|
] as const;
|
|
256
|
-
export function validateField<T>(field: IField<T>) {
|
|
274
|
+
export function validateField<T>(field: IField<T>): IField<T> {
|
|
257
275
|
const initial = {
|
|
258
276
|
ORDER: 'bigint',
|
|
259
277
|
MASK: 'bigint',
|
|
@@ -316,16 +334,19 @@ export function FpDiv<T>(f: IField<T>, lhs: T, rhs: T | bigint): T {
|
|
|
316
334
|
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
|
|
317
335
|
}
|
|
318
336
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
337
|
+
/**
|
|
338
|
+
* Legendre symbol.
|
|
339
|
+
* * (a | p) ≡ 1 if a is a square (mod p), quadratic residue
|
|
340
|
+
* * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
|
|
341
|
+
* * (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
342
|
+
*/
|
|
343
|
+
export function FpLegendre(order: bigint): <T>(f: IField<T>, x: T) => T {
|
|
323
344
|
const legendreConst = (order - _1n) / _2n; // Integer arithmetic
|
|
324
345
|
return <T>(f: IField<T>, x: T): T => f.pow(x, legendreConst);
|
|
325
346
|
}
|
|
326
347
|
|
|
327
348
|
// This function returns True whenever the value x is a square in the field F.
|
|
328
|
-
export function FpIsSquare<T>(f: IField<T>) {
|
|
349
|
+
export function FpIsSquare<T>(f: IField<T>): (x: T) => boolean {
|
|
329
350
|
const legendre = FpLegendre(f.ORDER);
|
|
330
351
|
return (x: T): boolean => {
|
|
331
352
|
const p = legendre(f, x);
|
|
@@ -334,7 +355,13 @@ export function FpIsSquare<T>(f: IField<T>) {
|
|
|
334
355
|
}
|
|
335
356
|
|
|
336
357
|
// CURVE.n lengths
|
|
337
|
-
export function nLength(
|
|
358
|
+
export function nLength(
|
|
359
|
+
n: bigint,
|
|
360
|
+
nBitLength?: number
|
|
361
|
+
): {
|
|
362
|
+
nBitLength: number;
|
|
363
|
+
nByteLength: number;
|
|
364
|
+
} {
|
|
338
365
|
// Bit size, byte size of CURVE.n
|
|
339
366
|
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
|
|
340
367
|
const nByteLength = Math.ceil(_nBitLength / 8);
|
|
@@ -343,15 +370,15 @@ export function nLength(n: bigint, nBitLength?: number) {
|
|
|
343
370
|
|
|
344
371
|
type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
|
|
345
372
|
/**
|
|
346
|
-
* Initializes a finite field over prime.
|
|
347
|
-
* Do not init in loop: slow. Very fragile: always run a benchmark on a change.
|
|
373
|
+
* Initializes a finite field over prime.
|
|
348
374
|
* Major performance optimizations:
|
|
349
375
|
* * a) denormalized operations like mulN instead of mul
|
|
350
376
|
* * b) same object shape: never add or remove keys
|
|
351
377
|
* * c) Object.freeze
|
|
352
|
-
*
|
|
378
|
+
* Fragile: always run a benchmark on a change.
|
|
379
|
+
* Security note: operations don't check 'isValid' for all elements for performance reasons,
|
|
353
380
|
* it is caller responsibility to check this.
|
|
354
|
-
* This is low-level code, please make sure you know what you doing.
|
|
381
|
+
* This is low-level code, please make sure you know what you're doing.
|
|
355
382
|
* @param ORDER prime positive bigint
|
|
356
383
|
* @param bitLen how many bits the field consumes
|
|
357
384
|
* @param isLE (def: false) if encoding / decoding should be in little-endian
|
|
@@ -369,6 +396,7 @@ export function Field(
|
|
|
369
396
|
let sqrtP: ReturnType<typeof FpSqrt>; // cached sqrtP
|
|
370
397
|
const f: Readonly<FpField> = Object.freeze({
|
|
371
398
|
ORDER,
|
|
399
|
+
isLE,
|
|
372
400
|
BITS,
|
|
373
401
|
BYTES,
|
|
374
402
|
MASK: bitMask(BITS),
|
|
@@ -419,13 +447,13 @@ export function Field(
|
|
|
419
447
|
return Object.freeze(f);
|
|
420
448
|
}
|
|
421
449
|
|
|
422
|
-
export function FpSqrtOdd<T>(Fp: IField<T>, elm: T) {
|
|
450
|
+
export function FpSqrtOdd<T>(Fp: IField<T>, elm: T): T {
|
|
423
451
|
if (!Fp.isOdd) throw new Error("Field doesn't have isOdd");
|
|
424
452
|
const root = Fp.sqrt(elm);
|
|
425
453
|
return Fp.isOdd(root) ? root : Fp.neg(root);
|
|
426
454
|
}
|
|
427
455
|
|
|
428
|
-
export function FpSqrtEven<T>(Fp: IField<T>, elm: T) {
|
|
456
|
+
export function FpSqrtEven<T>(Fp: IField<T>, elm: T): T {
|
|
429
457
|
if (!Fp.isOdd) throw new Error("Field doesn't have isOdd");
|
|
430
458
|
const root = Fp.sqrt(elm);
|
|
431
459
|
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
|
@@ -435,7 +463,7 @@ export function FpSqrtEven<T>(Fp: IField<T>, elm: T) {
|
|
|
435
463
|
* "Constant-time" private key generation utility.
|
|
436
464
|
* Same as mapKeyToField, but accepts less bytes (40 instead of 48 for 32-byte field).
|
|
437
465
|
* Which makes it slightly more biased, less secure.
|
|
438
|
-
* @deprecated use mapKeyToField instead
|
|
466
|
+
* @deprecated use `mapKeyToField` instead
|
|
439
467
|
*/
|
|
440
468
|
export function hashToPrivateScalar(
|
|
441
469
|
hash: string | Uint8Array,
|
|
@@ -497,7 +525,7 @@ export function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE = false
|
|
|
497
525
|
// No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
|
|
498
526
|
if (len < 16 || len < minLen || len > 1024)
|
|
499
527
|
throw new Error('expected ' + minLen + '-1024 bytes of input, got ' + len);
|
|
500
|
-
const num = isLE ?
|
|
528
|
+
const num = isLE ? bytesToNumberLE(key) : bytesToNumberBE(key);
|
|
501
529
|
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
|
502
530
|
const reduced = mod(num, fieldOrder - _1n) + _1n;
|
|
503
531
|
return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Montgomery curve methods. It's not really whole montgomery curve,
|
|
3
|
+
* just bunch of very specific methods for X25519 / X448 from
|
|
4
|
+
* [RFC 7748](https://www.rfc-editor.org/rfc/rfc7748)
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
1
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
8
|
import { mod, pow } from './modular.js';
|
|
3
9
|
import {
|
|
@@ -24,6 +30,7 @@ export type CurveType = {
|
|
|
24
30
|
Gu: bigint;
|
|
25
31
|
randomBytes?: (bytesLength?: number) => Uint8Array;
|
|
26
32
|
};
|
|
33
|
+
|
|
27
34
|
export type CurveFn = {
|
|
28
35
|
scalarMult: (scalar: Hex, u: Hex) => Uint8Array;
|
|
29
36
|
scalarMultBase: (scalar: Hex) => Uint8Array;
|
|
@@ -52,7 +59,6 @@ function validateOpts(curve: CurveType) {
|
|
|
52
59
|
return Object.freeze({ ...curve } as const);
|
|
53
60
|
}
|
|
54
61
|
|
|
55
|
-
// NOTE: not really montgomery curve, just bunch of very specific methods for X25519/X448 (RFC 7748, https://www.rfc-editor.org/rfc/rfc7748)
|
|
56
62
|
// Uses only one coordinate instead of two
|
|
57
63
|
export function montgomery(curveDef: CurveType): CurveFn {
|
|
58
64
|
const CURVE = validateOpts(curveDef);
|
package/src/abstract/poseidon.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash.
|
|
3
|
+
*
|
|
4
|
+
* There are many poseidon variants with different constants.
|
|
5
|
+
* We don't provide them: you should construct them manually.
|
|
6
|
+
* Check out [micro-starknet](https://github.com/paulmillr/micro-starknet) package for a proper example.
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
1
9
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// We don't provide any constants, since different implementations use different constants.
|
|
5
|
-
// For reference constants see './test/poseidon.test.js'.
|
|
10
|
+
import { FpPow, type IField, validateField } from './modular.js';
|
|
11
|
+
|
|
6
12
|
export type PoseidonOpts = {
|
|
7
13
|
Fp: IField<bigint>;
|
|
8
14
|
t: number;
|
|
@@ -14,7 +20,18 @@ export type PoseidonOpts = {
|
|
|
14
20
|
roundConstants: bigint[][];
|
|
15
21
|
};
|
|
16
22
|
|
|
17
|
-
export function validateOpts(opts: PoseidonOpts) {
|
|
23
|
+
export function validateOpts(opts: PoseidonOpts): Readonly<{
|
|
24
|
+
rounds: number;
|
|
25
|
+
sboxFn: (n: bigint) => bigint;
|
|
26
|
+
roundConstants: bigint[][];
|
|
27
|
+
mds: bigint[][];
|
|
28
|
+
Fp: IField<bigint>;
|
|
29
|
+
t: number;
|
|
30
|
+
roundsFull: number;
|
|
31
|
+
roundsPartial: number;
|
|
32
|
+
sboxPower?: number;
|
|
33
|
+
reversePartialPowIdx?: boolean; // Hack for stark
|
|
34
|
+
}> {
|
|
18
35
|
const { Fp, mds, reversePartialPowIdx: rev, roundConstants: rc } = opts;
|
|
19
36
|
const { roundsFull, roundsPartial, sboxPower, t } = opts;
|
|
20
37
|
|
|
@@ -61,7 +78,7 @@ export function validateOpts(opts: PoseidonOpts) {
|
|
|
61
78
|
return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds: _mds });
|
|
62
79
|
}
|
|
63
80
|
|
|
64
|
-
export function splitConstants(rc: bigint[], t: number) {
|
|
81
|
+
export function splitConstants(rc: bigint[], t: number): bigint[][] {
|
|
65
82
|
if (typeof t !== 'number') throw new Error('poseidonSplitConstants: invalid t');
|
|
66
83
|
if (!Array.isArray(rc) || rc.length % t) throw new Error('poseidonSplitConstants: invalid rc');
|
|
67
84
|
const res = [];
|
|
@@ -76,7 +93,12 @@ export function splitConstants(rc: bigint[], t: number) {
|
|
|
76
93
|
return res;
|
|
77
94
|
}
|
|
78
95
|
|
|
79
|
-
|
|
96
|
+
/** Poseidon NTT-friendly hash. */
|
|
97
|
+
export function poseidon(opts: PoseidonOpts): {
|
|
98
|
+
(values: bigint[]): bigint[];
|
|
99
|
+
// For verification in tests
|
|
100
|
+
roundConstants: bigint[][];
|
|
101
|
+
} {
|
|
80
102
|
const _opts = validateOpts(opts);
|
|
81
103
|
const { Fp, mds, roundConstants, rounds: totalRounds, roundsPartial, sboxFn, t } = _opts;
|
|
82
104
|
const halfRoundsFull = _opts.roundsFull / 2;
|
package/src/abstract/tower.ts
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Towered extension fields.
|
|
3
|
+
* Rather than implementing a massive 12th-degree extension directly, it is more efficient
|
|
4
|
+
* to build it up from smaller extensions: a tower of extensions.
|
|
5
|
+
*
|
|
6
|
+
* For BLS12-381, the Fp12 field is implemented as a quadratic (degree two) extension,
|
|
7
|
+
* on top of a cubic (degree three) extension, on top of a quadratic extension of Fp.
|
|
8
|
+
*
|
|
9
|
+
* For more info: "Pairings for beginners" by Costello, section 7.3.
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
1
12
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
13
|
import * as mod from './modular.js';
|
|
3
14
|
import { bitLen, bitMask, concatBytes, notImplemented } from './utils.js';
|
|
4
15
|
import type { ProjConstructor, ProjPointType } from './weierstrass.js';
|
|
5
16
|
|
|
6
|
-
/*
|
|
7
|
-
Towered extension fields
|
|
8
|
-
|
|
9
|
-
Rather than implementing a massive 12th-degree extension directly, it is more efficient
|
|
10
|
-
to build it up from smaller extensions: a tower of extensions.
|
|
11
|
-
|
|
12
|
-
For BLS12-381, the Fp12 field is implemented as a quadratic (degree two) extension,
|
|
13
|
-
on top of a cubic (degree three) extension, on top of a quadratic extension of Fp.
|
|
14
|
-
|
|
15
|
-
For more info: "Pairings for beginners" by Costello, section 7.3.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
17
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
|
19
18
|
// prettier-ignore
|
|
20
19
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
|
|
@@ -75,7 +74,20 @@ function calcFrobeniusCoefficients<T>(
|
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
// This works same at least for bls12-381, bn254 and bls12-377
|
|
78
|
-
export function psiFrobenius(
|
|
77
|
+
export function psiFrobenius(
|
|
78
|
+
Fp: mod.IField<Fp>,
|
|
79
|
+
Fp2: Fp2Bls,
|
|
80
|
+
base: Fp2
|
|
81
|
+
): {
|
|
82
|
+
psi: (x: Fp2, y: Fp2) => [Fp2, Fp2];
|
|
83
|
+
psi2: (x: Fp2, y: Fp2) => [Fp2, Fp2];
|
|
84
|
+
G2psi: (c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) => ProjPointType<Fp2>;
|
|
85
|
+
G2psi2: (c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) => ProjPointType<Fp2>;
|
|
86
|
+
PSI_X: Fp2;
|
|
87
|
+
PSI_Y: Fp2;
|
|
88
|
+
PSI2_X: Fp2;
|
|
89
|
+
PSI2_Y: Fp2;
|
|
90
|
+
} {
|
|
79
91
|
// Ψ endomorphism
|
|
80
92
|
const PSI_X = Fp2.pow(base, (Fp.ORDER - _1n) / _3n); // u^((p-1)/3)
|
|
81
93
|
const PSI_Y = Fp2.pow(base, (Fp.ORDER - _1n) / _2n); // u^((p-1)/2)
|
|
@@ -120,7 +132,37 @@ export type Tower12Opts = {
|
|
|
120
132
|
Fp12finalExponentiate: (num: Fp12) => Fp12;
|
|
121
133
|
};
|
|
122
134
|
|
|
123
|
-
export function tower12(opts: Tower12Opts) {
|
|
135
|
+
export function tower12(opts: Tower12Opts): {
|
|
136
|
+
Fp: Readonly<mod.IField<bigint> & Required<Pick<mod.IField<bigint>, 'isOdd'>>>;
|
|
137
|
+
Fp2: mod.IField<Fp2> & {
|
|
138
|
+
NONRESIDUE: Fp2;
|
|
139
|
+
fromBigTuple: (tuple: BigintTuple | bigint[]) => Fp2;
|
|
140
|
+
reim: (num: Fp2) => { re: bigint; im: bigint };
|
|
141
|
+
mulByNonresidue: (num: Fp2) => Fp2;
|
|
142
|
+
mulByB: (num: Fp2) => Fp2;
|
|
143
|
+
frobeniusMap(num: Fp2, power: number): Fp2;
|
|
144
|
+
};
|
|
145
|
+
Fp6: mod.IField<Fp6> & {
|
|
146
|
+
fromBigSix: (tuple: BigintSix) => Fp6;
|
|
147
|
+
mulByNonresidue: (num: Fp6) => Fp6;
|
|
148
|
+
frobeniusMap(num: Fp6, power: number): Fp6;
|
|
149
|
+
mul1(num: Fp6, b1: Fp2): Fp6;
|
|
150
|
+
mul01(num: Fp6, b0: Fp2, b1: Fp2): Fp6;
|
|
151
|
+
mulByFp2(lhs: Fp6, rhs: Fp2): Fp6;
|
|
152
|
+
};
|
|
153
|
+
Fp4Square: (a: Fp2, b: Fp2) => { first: Fp2; second: Fp2 };
|
|
154
|
+
Fp12: mod.IField<Fp12> & {
|
|
155
|
+
fromBigTwelve: (t: BigintTwelve) => Fp12;
|
|
156
|
+
frobeniusMap(num: Fp12, power: number): Fp12;
|
|
157
|
+
mul014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
|
158
|
+
mul034(num: Fp12, o0: Fp2, o3: Fp2, o4: Fp2): Fp12;
|
|
159
|
+
mulByFp2(lhs: Fp12, rhs: Fp2): Fp12;
|
|
160
|
+
conjugate(num: Fp12): Fp12;
|
|
161
|
+
finalExponentiate(num: Fp12): Fp12;
|
|
162
|
+
_cyclotomicSquare(num: Fp12): Fp12;
|
|
163
|
+
_cyclotomicExp(num: Fp12, n: bigint): Fp12;
|
|
164
|
+
};
|
|
165
|
+
} {
|
|
124
166
|
const { ORDER } = opts;
|
|
125
167
|
// Fp
|
|
126
168
|
const Fp = mod.Field(ORDER);
|
|
@@ -173,6 +215,7 @@ export function tower12(opts: Tower12Opts) {
|
|
|
173
215
|
const Fp2Nonresidue = Fp2fromBigTuple(opts.FP2_NONRESIDUE);
|
|
174
216
|
const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
|
175
217
|
ORDER: FP2_ORDER,
|
|
218
|
+
isLE: Fp.isLE,
|
|
176
219
|
NONRESIDUE: Fp2Nonresidue,
|
|
177
220
|
BITS: bitLen(FP2_ORDER),
|
|
178
221
|
BYTES: Math.ceil(bitLen(FP2_ORDER) / 8),
|
|
@@ -339,6 +382,7 @@ export function tower12(opts: Tower12Opts) {
|
|
|
339
382
|
|
|
340
383
|
const Fp6: mod.IField<Fp6> & Fp6Utils = {
|
|
341
384
|
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
|
385
|
+
isLE: Fp2.isLE,
|
|
342
386
|
BITS: 3 * Fp2.BITS,
|
|
343
387
|
BYTES: 3 * Fp2.BYTES,
|
|
344
388
|
MASK: bitMask(3 * Fp2.BITS),
|
|
@@ -495,6 +539,7 @@ export function tower12(opts: Tower12Opts) {
|
|
|
495
539
|
|
|
496
540
|
const Fp12: mod.IField<Fp12> & Fp12Utils = {
|
|
497
541
|
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
|
542
|
+
isLE: Fp6.isLE,
|
|
498
543
|
BITS: 2 * Fp2.BITS,
|
|
499
544
|
BYTES: 2 * Fp2.BYTES,
|
|
500
545
|
MASK: bitMask(2 * Fp2.BITS),
|
package/src/abstract/utils.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hex, bytes and number utilities.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
1
5
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
6
|
+
|
|
2
7
|
// 100 lines of code in the file are duplicated from noble-hashes (utils).
|
|
3
8
|
// This is OK: `abstract` directory does not use noble-hashes.
|
|
4
9
|
// User may opt-in into using different hashing library. This way, noble-hashes
|
|
@@ -155,7 +160,7 @@ export function concatBytes(...arrays: Uint8Array[]): Uint8Array {
|
|
|
155
160
|
}
|
|
156
161
|
|
|
157
162
|
// Compares 2 u8a-s in kinda constant time
|
|
158
|
-
export function equalBytes(a: Uint8Array, b: Uint8Array) {
|
|
163
|
+
export function equalBytes(a: Uint8Array, b: Uint8Array): boolean {
|
|
159
164
|
if (a.length !== b.length) return false;
|
|
160
165
|
let diff = 0;
|
|
161
166
|
for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
|
|
@@ -177,7 +182,7 @@ export function utf8ToBytes(str: string): Uint8Array {
|
|
|
177
182
|
// Is positive bigint
|
|
178
183
|
const isPosBig = (n: bigint) => typeof n === 'bigint' && _0n <= n;
|
|
179
184
|
|
|
180
|
-
export function inRange(n: bigint, min: bigint, max: bigint) {
|
|
185
|
+
export function inRange(n: bigint, min: bigint, max: bigint): boolean {
|
|
181
186
|
return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
|
|
182
187
|
}
|
|
183
188
|
|
|
@@ -186,7 +191,7 @@ export function inRange(n: bigint, min: bigint, max: bigint) {
|
|
|
186
191
|
* @example
|
|
187
192
|
* aInRange('x', x, 1n, 256n); // would assume x is in (1n..255n)
|
|
188
193
|
*/
|
|
189
|
-
export function aInRange(title: string, n: bigint, min: bigint, max: bigint) {
|
|
194
|
+
export function aInRange(title: string, n: bigint, min: bigint, max: bigint): void {
|
|
190
195
|
// Why min <= n < max and not a (min < n < max) OR b (min <= n <= max)?
|
|
191
196
|
// consider P=256n, min=0n, max=P
|
|
192
197
|
// - a for min=0 would require -1: `inRange('x', x, -1n, P)`
|
|
@@ -202,7 +207,7 @@ export function aInRange(title: string, n: bigint, min: bigint, max: bigint) {
|
|
|
202
207
|
* Calculates amount of bits in a bigint.
|
|
203
208
|
* Same as `n.toString(2).length`
|
|
204
209
|
*/
|
|
205
|
-
export function bitLen(n: bigint) {
|
|
210
|
+
export function bitLen(n: bigint): number {
|
|
206
211
|
let len;
|
|
207
212
|
for (len = 0; n > _0n; n >>= _1n, len += 1);
|
|
208
213
|
return len;
|
|
@@ -213,14 +218,14 @@ export function bitLen(n: bigint) {
|
|
|
213
218
|
* NOTE: first bit position is 0 (same as arrays)
|
|
214
219
|
* Same as `!!+Array.from(n.toString(2)).reverse()[pos]`
|
|
215
220
|
*/
|
|
216
|
-
export function bitGet(n: bigint, pos: number) {
|
|
221
|
+
export function bitGet(n: bigint, pos: number): bigint {
|
|
217
222
|
return (n >> BigInt(pos)) & _1n;
|
|
218
223
|
}
|
|
219
224
|
|
|
220
225
|
/**
|
|
221
226
|
* Sets single bit at position.
|
|
222
227
|
*/
|
|
223
|
-
export function bitSet(n: bigint, pos: number, value: boolean) {
|
|
228
|
+
export function bitSet(n: bigint, pos: number, value: boolean): bigint {
|
|
224
229
|
return n | ((value ? _1n : _0n) << BigInt(pos));
|
|
225
230
|
}
|
|
226
231
|
|
|
@@ -228,7 +233,7 @@ export function bitSet(n: bigint, pos: number, value: boolean) {
|
|
|
228
233
|
* Calculate mask for N bits. Not using ** operator with bigints because of old engines.
|
|
229
234
|
* Same as BigInt(`0b${Array(i).fill('1').join('')}`)
|
|
230
235
|
*/
|
|
231
|
-
export const bitMask = (n: number) => (_2n << BigInt(n - 1)) - _1n;
|
|
236
|
+
export const bitMask = (n: number): bigint => (_2n << BigInt(n - 1)) - _1n;
|
|
232
237
|
|
|
233
238
|
// DRBG
|
|
234
239
|
|
|
@@ -295,15 +300,15 @@ export function createHmacDrbg<T>(
|
|
|
295
300
|
// Validating curves and fields
|
|
296
301
|
|
|
297
302
|
const validatorFns = {
|
|
298
|
-
bigint: (val: any) => typeof val === 'bigint',
|
|
299
|
-
function: (val: any) => typeof val === 'function',
|
|
300
|
-
boolean: (val: any) => typeof val === 'boolean',
|
|
301
|
-
string: (val: any) => typeof val === 'string',
|
|
302
|
-
stringOrUint8Array: (val: any) => typeof val === 'string' || isBytes(val),
|
|
303
|
-
isSafeInteger: (val: any) => Number.isSafeInteger(val),
|
|
304
|
-
array: (val: any) => Array.isArray(val),
|
|
305
|
-
field: (val: any, object: any) => (object as any).Fp.isValid(val),
|
|
306
|
-
hash: (val: any) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
|
|
303
|
+
bigint: (val: any): boolean => typeof val === 'bigint',
|
|
304
|
+
function: (val: any): boolean => typeof val === 'function',
|
|
305
|
+
boolean: (val: any): boolean => typeof val === 'boolean',
|
|
306
|
+
string: (val: any): boolean => typeof val === 'string',
|
|
307
|
+
stringOrUint8Array: (val: any): boolean => typeof val === 'string' || isBytes(val),
|
|
308
|
+
isSafeInteger: (val: any): boolean => Number.isSafeInteger(val),
|
|
309
|
+
array: (val: any): boolean => Array.isArray(val),
|
|
310
|
+
field: (val: any, object: any): any => (object as any).Fp.isValid(val),
|
|
311
|
+
hash: (val: any): boolean => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
|
|
307
312
|
} as const;
|
|
308
313
|
type Validator = keyof typeof validatorFns;
|
|
309
314
|
type ValMap<T extends Record<string, any>> = { [K in keyof T]?: Validator };
|
|
@@ -313,7 +318,7 @@ export function validateObject<T extends Record<string, any>>(
|
|
|
313
318
|
object: T,
|
|
314
319
|
validators: ValMap<T>,
|
|
315
320
|
optValidators: ValMap<T> = {}
|
|
316
|
-
) {
|
|
321
|
+
): T {
|
|
317
322
|
const checkField = (fieldName: keyof T, type: Validator, isOptional: boolean) => {
|
|
318
323
|
const checkVal = validatorFns[type];
|
|
319
324
|
if (typeof checkVal !== 'function') throw new Error('invalid validator function');
|
|
@@ -342,7 +347,7 @@ export function validateObject<T extends Record<string, any>>(
|
|
|
342
347
|
/**
|
|
343
348
|
* throws not implemented error
|
|
344
349
|
*/
|
|
345
|
-
export const notImplemented = () => {
|
|
350
|
+
export const notImplemented = (): never => {
|
|
346
351
|
throw new Error('not implemented');
|
|
347
352
|
};
|
|
348
353
|
|
|
@@ -350,7 +355,9 @@ export const notImplemented = () => {
|
|
|
350
355
|
* Memoizes (caches) computation result.
|
|
351
356
|
* Uses WeakMap: the value is going auto-cleaned by GC after last reference is removed.
|
|
352
357
|
*/
|
|
353
|
-
export function memoized<T extends object, R, O extends any[]>(
|
|
358
|
+
export function memoized<T extends object, R, O extends any[]>(
|
|
359
|
+
fn: (arg: T, ...args: O) => R
|
|
360
|
+
): (arg: T, ...args: O) => R {
|
|
354
361
|
const map = new WeakMap<T, R>();
|
|
355
362
|
return (arg: T, ...args: O): R => {
|
|
356
363
|
const val = map.get(arg);
|