@noble/curves 1.9.0 → 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 +78 -34
- 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 +99 -11
- 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 +141 -92
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +122 -0
- package/abstract/fft.d.ts.map +1 -0
- package/abstract/fft.js +438 -0
- package/abstract/fft.js.map +1 -0
- 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 +28 -17
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +156 -139
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +3 -8
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +73 -93
- 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 +10 -4
- 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 +152 -73
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +487 -404
- 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 -480
- 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 +25 -9
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +89 -65
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +29 -10
- package/ed448.d.ts.map +1 -1
- package/ed448.js +116 -81
- 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 +96 -12
- 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 +141 -94
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/fft.d.ts +122 -0
- package/esm/abstract/fft.d.ts.map +1 -0
- package/esm/abstract/fft.js +425 -0
- package/esm/abstract/fft.js.map +1 -0
- 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 +28 -17
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +155 -138
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts +3 -8
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +74 -94
- 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 +10 -4
- 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 +152 -73
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +485 -406
- 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 -479
- 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 +25 -9
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +84 -60
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +29 -10
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +113 -78
- package/esm/ed448.js.map +1 -1
- package/esm/jubjub.d.ts +4 -0
- package/esm/jubjub.d.ts.map +1 -1
- package/esm/jubjub.js +4 -0
- package/esm/jubjub.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 +8 -16
- package/esm/nist.d.ts.map +1 -1
- package/esm/nist.js +87 -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/pasta.d.ts +4 -0
- package/esm/pasta.d.ts.map +1 -1
- package/esm/pasta.js +4 -0
- package/esm/pasta.js.map +1 -1
- package/esm/secp256k1.d.ts +6 -6
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +44 -41
- 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/jubjub.d.ts +4 -0
- package/jubjub.d.ts.map +1 -1
- package/jubjub.js +4 -0
- package/jubjub.js.map +1 -1
- package/misc.d.ts.map +1 -1
- package/misc.js +35 -30
- package/misc.js.map +1 -1
- package/nist.d.ts +8 -16
- package/nist.d.ts.map +1 -1
- package/nist.js +87 -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 +26 -8
- package/pasta.d.ts +4 -0
- package/pasta.d.ts.map +1 -1
- package/pasta.js +4 -0
- package/pasta.js.map +1 -1
- package/secp256k1.d.ts +6 -6
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +47 -44
- 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 +125 -18
- package/src/abstract/edwards.ts +282 -127
- package/src/abstract/fft.ts +519 -0
- package/src/abstract/hash-to-curve.ts +51 -27
- package/src/abstract/modular.ts +156 -143
- package/src/abstract/montgomery.ts +81 -111
- package/src/abstract/poseidon.ts +22 -18
- package/src/abstract/tower.ts +37 -68
- package/src/abstract/utils.ts +3 -378
- package/src/abstract/weierstrass.ts +752 -461
- package/src/bls12-381.ts +542 -507
- package/src/bn254.ts +47 -35
- package/src/ed25519.ts +104 -76
- package/src/ed448.ts +156 -105
- package/src/jubjub.ts +4 -0
- package/src/misc.ts +39 -34
- package/src/nist.ts +138 -126
- package/src/p256.ts +3 -3
- package/src/p384.ts +3 -3
- package/src/p521.ts +3 -3
- package/src/pasta.ts +5 -1
- package/src/secp256k1.ts +59 -47
- 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/modular.ts
CHANGED
|
@@ -1,27 +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)
|
|
23
|
-
|
|
24
|
-
const _9n =/* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);
|
|
22
|
+
const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5);
|
|
23
|
+
const _8n = /* @__PURE__ */ BigInt(8);
|
|
25
24
|
|
|
26
25
|
// Calculates a modulo b
|
|
27
26
|
export function mod(a: bigint, b: bigint): bigint {
|
|
@@ -31,21 +30,11 @@ export function mod(a: bigint, b: bigint): bigint {
|
|
|
31
30
|
/**
|
|
32
31
|
* Efficiently raise num to power and do modular division.
|
|
33
32
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
34
|
-
* TODO: remove.
|
|
35
33
|
* @example
|
|
36
34
|
* pow(2n, 6n, 11n) // 64n % 11n == 9n
|
|
37
35
|
*/
|
|
38
36
|
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
|
39
|
-
|
|
40
|
-
if (modulo <= _0n) throw new Error('invalid modulus');
|
|
41
|
-
if (modulo === _1n) return _0n;
|
|
42
|
-
let res = _1n;
|
|
43
|
-
while (power > _0n) {
|
|
44
|
-
if (power & _1n) res = (res * num) % modulo;
|
|
45
|
-
num = (num * num) % modulo;
|
|
46
|
-
power >>= _1n;
|
|
47
|
-
}
|
|
48
|
-
return res;
|
|
37
|
+
return FpPow(Field(modulo), num, power);
|
|
49
38
|
}
|
|
50
39
|
|
|
51
40
|
/** Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)` */
|
|
@@ -84,6 +73,52 @@ export function invert(number: bigint, modulo: bigint): bigint {
|
|
|
84
73
|
return mod(x, modulo);
|
|
85
74
|
}
|
|
86
75
|
|
|
76
|
+
// Not all roots are possible! Example which will throw:
|
|
77
|
+
// const NUM =
|
|
78
|
+
// n = 72057594037927816n;
|
|
79
|
+
// Fp = Field(BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'));
|
|
80
|
+
function sqrt3mod4<T>(Fp: IField<T>, n: T) {
|
|
81
|
+
const p1div4 = (Fp.ORDER + _1n) / _4n;
|
|
82
|
+
const root = Fp.pow(n, p1div4);
|
|
83
|
+
// Throw if root^2 != n
|
|
84
|
+
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
|
85
|
+
return root;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function sqrt5mod8<T>(Fp: IField<T>, n: T) {
|
|
89
|
+
const p5div8 = (Fp.ORDER - _5n) / _8n;
|
|
90
|
+
const n2 = Fp.mul(n, _2n);
|
|
91
|
+
const v = Fp.pow(n2, p5div8);
|
|
92
|
+
const nv = Fp.mul(n, v);
|
|
93
|
+
const i = Fp.mul(Fp.mul(nv, _2n), v);
|
|
94
|
+
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
|
95
|
+
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
|
96
|
+
return root;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// TODO: Commented-out for now. Provide test vectors.
|
|
100
|
+
// Tonelli is too slow for extension fields Fp2.
|
|
101
|
+
// That means we can't use sqrt (c1, c2...) even for initialization constants.
|
|
102
|
+
// if (P % _16n === _9n) return sqrt9mod16;
|
|
103
|
+
// // prettier-ignore
|
|
104
|
+
// function sqrt9mod16<T>(Fp: IField<T>, n: T, p7div16?: bigint) {
|
|
105
|
+
// if (p7div16 === undefined) p7div16 = (Fp.ORDER + BigInt(7)) / _16n;
|
|
106
|
+
// const c1 = Fp.sqrt(Fp.neg(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
107
|
+
// const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
108
|
+
// const c3 = Fp.sqrt(Fp.neg(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
109
|
+
// const c4 = p7div16; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
110
|
+
// let tv1 = Fp.pow(n, c4); // 1. tv1 = x^c4
|
|
111
|
+
// let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
|
|
112
|
+
// const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
|
|
113
|
+
// let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
|
|
114
|
+
// const e1 = Fp.eql(Fp.sqr(tv2), n); // 5. e1 = (tv2^2) == x
|
|
115
|
+
// const e2 = Fp.eql(Fp.sqr(tv3), n); // 6. e2 = (tv3^2) == x
|
|
116
|
+
// tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
117
|
+
// tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
118
|
+
// const e3 = Fp.eql(Fp.sqr(tv2), n); // 9. e3 = (tv2^2) == x
|
|
119
|
+
// return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
|
|
120
|
+
// }
|
|
121
|
+
|
|
87
122
|
/**
|
|
88
123
|
* Tonelli-Shanks square root search algorithm.
|
|
89
124
|
* 1. https://eprint.iacr.org/2012/685.pdf (page 12)
|
|
@@ -92,9 +127,10 @@ export function invert(number: bigint, modulo: bigint): bigint {
|
|
|
92
127
|
* @returns function that takes field Fp (created from P) and number n
|
|
93
128
|
*/
|
|
94
129
|
export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
130
|
+
// Initialization (precomputation).
|
|
131
|
+
// Caching initialization could boost perf by 7%.
|
|
132
|
+
if (P < BigInt(3)) throw new Error('sqrt is not defined for small field');
|
|
133
|
+
// Factor P - 1 = Q * 2^S, where Q is odd
|
|
98
134
|
let Q = P - _1n;
|
|
99
135
|
let S = 0;
|
|
100
136
|
while (Q % _2n === _0n) {
|
|
@@ -102,120 +138,77 @@ export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
|
|
102
138
|
S++;
|
|
103
139
|
}
|
|
104
140
|
|
|
105
|
-
//
|
|
141
|
+
// Find the first quadratic non-residue Z >= 2
|
|
106
142
|
let Z = _2n;
|
|
107
143
|
const _Fp = Field(P);
|
|
108
|
-
while (
|
|
144
|
+
while (FpLegendre(_Fp, Z) === 1) {
|
|
145
|
+
// Basic primality test for P. After x iterations, chance of
|
|
146
|
+
// not finding quadratic non-residue is 2^x, so 2^1000.
|
|
109
147
|
if (Z++ > 1000) throw new Error('Cannot find square root: probably non-prime P');
|
|
110
148
|
}
|
|
149
|
+
// Fast-path; usually done before Z, but we do "primality test".
|
|
150
|
+
if (S === 1) return sqrt3mod4;
|
|
111
151
|
|
|
112
|
-
// Fast-path
|
|
113
|
-
if (S === 1) {
|
|
114
|
-
const p1div4 = (P + _1n) / _4n;
|
|
115
|
-
return function tonelliFast<T>(Fp: IField<T>, n: T) {
|
|
116
|
-
const root = Fp.pow(n, p1div4);
|
|
117
|
-
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
|
118
|
-
return root;
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
152
|
// Slow-path
|
|
153
|
+
// TODO: test on Fp2 and others
|
|
154
|
+
let cc = _Fp.pow(Z, Q); // c = z^Q
|
|
122
155
|
const Q1div2 = (Q + _1n) / _2n;
|
|
123
156
|
return function tonelliSlow<T>(Fp: IField<T>, n: T): T {
|
|
124
|
-
|
|
125
|
-
if
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
let
|
|
130
|
-
let
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
157
|
+
if (Fp.is0(n)) return n;
|
|
158
|
+
// Check if n is a quadratic residue using Legendre symbol
|
|
159
|
+
if (FpLegendre(Fp, n) !== 1) throw new Error('Cannot find square root');
|
|
160
|
+
|
|
161
|
+
// Initialize variables for the main loop
|
|
162
|
+
let M = S;
|
|
163
|
+
let c = Fp.mul(Fp.ONE, cc); // c = z^Q, move cc from field _Fp into field Fp
|
|
164
|
+
let t = Fp.pow(n, Q); // t = n^Q, first guess at the fudge factor
|
|
165
|
+
let R = Fp.pow(n, Q1div2); // R = n^((Q+1)/2), first guess at the square root
|
|
166
|
+
|
|
167
|
+
// Main loop
|
|
168
|
+
// while t != 1
|
|
169
|
+
while (!Fp.eql(t, Fp.ONE)) {
|
|
170
|
+
if (Fp.is0(t)) return Fp.ZERO; // if t=0 return R=0
|
|
171
|
+
let i = 1;
|
|
172
|
+
|
|
173
|
+
// Find the smallest i >= 1 such that t^(2^i) ≡ 1 (mod P)
|
|
174
|
+
let t_tmp = Fp.sqr(t); // t^(2^1)
|
|
175
|
+
while (!Fp.eql(t_tmp, Fp.ONE)) {
|
|
176
|
+
i++;
|
|
177
|
+
t_tmp = Fp.sqr(t_tmp); // t^(2^2)...
|
|
178
|
+
if (i === M) throw new Error('Cannot find square root');
|
|
141
179
|
}
|
|
142
|
-
|
|
143
|
-
//
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
180
|
+
|
|
181
|
+
// Calculate the exponent for b: 2^(M - i - 1)
|
|
182
|
+
const exponent = _1n << BigInt(M - i - 1); // bigint is important
|
|
183
|
+
const b = Fp.pow(c, exponent); // b = 2^(M - i - 1)
|
|
184
|
+
|
|
185
|
+
// Update variables
|
|
186
|
+
M = i;
|
|
187
|
+
c = Fp.sqr(b); // c = b^2
|
|
188
|
+
t = Fp.mul(t, c); // t = (t * b^2)
|
|
189
|
+
R = Fp.mul(R, b); // R = R*b
|
|
149
190
|
}
|
|
150
|
-
return
|
|
191
|
+
return R;
|
|
151
192
|
};
|
|
152
193
|
}
|
|
153
194
|
|
|
154
195
|
/**
|
|
155
|
-
* Square root for a finite field.
|
|
196
|
+
* Square root for a finite field. Will try optimized versions first:
|
|
156
197
|
*
|
|
157
198
|
* 1. P ≡ 3 (mod 4)
|
|
158
199
|
* 2. P ≡ 5 (mod 8)
|
|
159
|
-
* 3.
|
|
160
|
-
* 4. Tonelli-Shanks algorithm
|
|
200
|
+
* 3. Tonelli-Shanks algorithm
|
|
161
201
|
*
|
|
162
202
|
* Different algorithms can give different roots, it is up to user to decide which one they want.
|
|
163
203
|
* For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
|
|
164
204
|
*/
|
|
165
205
|
export function FpSqrt(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
|
166
|
-
// P ≡ 3 (mod 4)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
// const NUM = 72057594037927816n;
|
|
173
|
-
return function sqrt3mod4<T>(Fp: IField<T>, n: T) {
|
|
174
|
-
const p1div4 = (P + _1n) / _4n;
|
|
175
|
-
const root = Fp.pow(n, p1div4);
|
|
176
|
-
// Throw if root**2 != n
|
|
177
|
-
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
|
178
|
-
return root;
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
|
|
183
|
-
if (P % _8n === _5n) {
|
|
184
|
-
return function sqrt5mod8<T>(Fp: IField<T>, n: T) {
|
|
185
|
-
const n2 = Fp.mul(n, _2n);
|
|
186
|
-
const c1 = (P - _5n) / _8n;
|
|
187
|
-
const v = Fp.pow(n2, c1);
|
|
188
|
-
const nv = Fp.mul(n, v);
|
|
189
|
-
const i = Fp.mul(Fp.mul(nv, _2n), v);
|
|
190
|
-
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
|
191
|
-
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
|
192
|
-
return root;
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// P ≡ 9 (mod 16)
|
|
197
|
-
if (P % _16n === _9n) {
|
|
198
|
-
// NOTE: tonelli is too slow for bls-Fp2 calculations even on start
|
|
199
|
-
// Means we cannot use sqrt for constants at all!
|
|
200
|
-
//
|
|
201
|
-
// const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
202
|
-
// const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
203
|
-
// const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
204
|
-
// const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
205
|
-
// sqrt = (x) => {
|
|
206
|
-
// let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
|
|
207
|
-
// let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
|
|
208
|
-
// const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
|
|
209
|
-
// let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
|
|
210
|
-
// const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
|
|
211
|
-
// const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
|
|
212
|
-
// tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
213
|
-
// tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
214
|
-
// const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
|
|
215
|
-
// return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
|
|
216
|
-
// }
|
|
217
|
-
}
|
|
218
|
-
// Other cases: Tonelli-Shanks algorithm
|
|
206
|
+
// P ≡ 3 (mod 4) => √n = n^((P+1)/4)
|
|
207
|
+
if (P % _4n === _3n) return sqrt3mod4;
|
|
208
|
+
// P ≡ 5 (mod 8) => Atkin algorithm, page 10 of https://eprint.iacr.org/2012/685.pdf
|
|
209
|
+
if (P % _8n === _5n) return sqrt5mod8;
|
|
210
|
+
// P ≡ 9 (mod 16) not implemented, see above
|
|
211
|
+
// Tonelli-Shanks algorithm
|
|
219
212
|
return tonelliShanks(P);
|
|
220
213
|
}
|
|
221
214
|
|
|
@@ -236,6 +229,7 @@ export interface IField<T> {
|
|
|
236
229
|
create: (num: T) => T;
|
|
237
230
|
isValid: (num: T) => boolean;
|
|
238
231
|
is0: (num: T) => boolean;
|
|
232
|
+
isValidNot0: (num: T) => boolean;
|
|
239
233
|
neg(num: T): T;
|
|
240
234
|
inv(num: T): T;
|
|
241
235
|
sqrt(num: T): T;
|
|
@@ -259,7 +253,6 @@ export interface IField<T> {
|
|
|
259
253
|
// NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
|
|
260
254
|
isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
|
|
261
255
|
// legendre?(num: T): T;
|
|
262
|
-
pow(lhs: T, power: bigint): T;
|
|
263
256
|
invertBatch: (lst: T[]) => T[];
|
|
264
257
|
toBytes(num: T): Uint8Array;
|
|
265
258
|
fromBytes(bytes: Uint8Array): T;
|
|
@@ -276,14 +269,18 @@ export function validateField<T>(field: IField<T>): IField<T> {
|
|
|
276
269
|
const initial = {
|
|
277
270
|
ORDER: 'bigint',
|
|
278
271
|
MASK: 'bigint',
|
|
279
|
-
BYTES: '
|
|
280
|
-
BITS: '
|
|
272
|
+
BYTES: 'number',
|
|
273
|
+
BITS: 'number',
|
|
281
274
|
} as Record<string, string>;
|
|
282
275
|
const opts = FIELD_FIELDS.reduce((map, val: string) => {
|
|
283
276
|
map[val] = 'function';
|
|
284
277
|
return map;
|
|
285
278
|
}, initial);
|
|
286
|
-
|
|
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;
|
|
287
284
|
}
|
|
288
285
|
|
|
289
286
|
// Generic field functions
|
|
@@ -296,7 +293,6 @@ export function FpPow<T>(Fp: IField<T>, num: T, power: bigint): T {
|
|
|
296
293
|
if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
|
|
297
294
|
if (power === _0n) return Fp.ONE;
|
|
298
295
|
if (power === _1n) return num;
|
|
299
|
-
// @ts-ignore
|
|
300
296
|
let p = Fp.ONE;
|
|
301
297
|
let d = num;
|
|
302
298
|
while (power > _0n) {
|
|
@@ -339,36 +335,33 @@ export function FpDiv<T>(Fp: IField<T>, lhs: T, rhs: T | bigint): T {
|
|
|
339
335
|
/**
|
|
340
336
|
* Legendre symbol.
|
|
341
337
|
* Legendre constant is used to calculate Legendre symbol (a | p)
|
|
342
|
-
* which denotes the value of a^((p-1)/2) (mod p)
|
|
338
|
+
* which denotes the value of a^((p-1)/2) (mod p).
|
|
343
339
|
*
|
|
344
340
|
* * (a | p) ≡ 1 if a is a square (mod p), quadratic residue
|
|
345
341
|
* * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
|
|
346
342
|
* * (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
347
343
|
*/
|
|
348
|
-
export function FpLegendre<T>(Fp: IField<T>, n: T):
|
|
349
|
-
|
|
350
|
-
|
|
344
|
+
export function FpLegendre<T>(Fp: IField<T>, n: T): -1 | 0 | 1 {
|
|
345
|
+
// We can use 3rd argument as optional cache of this value
|
|
346
|
+
// but seems unneeded for now. The operation is very fast.
|
|
347
|
+
const p1mod2 = (Fp.ORDER - _1n) / _2n;
|
|
348
|
+
const powered = Fp.pow(n, p1mod2);
|
|
351
349
|
const yes = Fp.eql(powered, Fp.ONE);
|
|
352
350
|
const zero = Fp.eql(powered, Fp.ZERO);
|
|
353
351
|
const no = Fp.eql(powered, Fp.neg(Fp.ONE));
|
|
354
|
-
if (!yes && !zero && !no) throw new Error('
|
|
352
|
+
if (!yes && !zero && !no) throw new Error('invalid Legendre symbol result');
|
|
355
353
|
return yes ? 1 : zero ? 0 : -1;
|
|
356
354
|
}
|
|
357
355
|
|
|
358
356
|
// This function returns True whenever the value x is a square in the field F.
|
|
359
357
|
export function FpIsSquare<T>(Fp: IField<T>, n: T): boolean {
|
|
360
358
|
const l = FpLegendre(Fp, n);
|
|
361
|
-
return l ===
|
|
359
|
+
return l === 1;
|
|
362
360
|
}
|
|
363
361
|
|
|
362
|
+
export type NLength = { nByteLength: number; nBitLength: number };
|
|
364
363
|
// CURVE.n lengths
|
|
365
|
-
export function nLength(
|
|
366
|
-
n: bigint,
|
|
367
|
-
nBitLength?: number
|
|
368
|
-
): {
|
|
369
|
-
nBitLength: number;
|
|
370
|
-
nByteLength: number;
|
|
371
|
-
} {
|
|
364
|
+
export function nLength(n: bigint, nBitLength?: number): NLength {
|
|
372
365
|
// Bit size, byte size of CURVE.n
|
|
373
366
|
if (nBitLength !== undefined) anumber(nBitLength);
|
|
374
367
|
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
|
|
@@ -377,29 +370,47 @@ export function nLength(
|
|
|
377
370
|
}
|
|
378
371
|
|
|
379
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 }>;
|
|
380
375
|
/**
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
* *
|
|
384
|
-
* *
|
|
385
|
-
* * 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`.
|
|
386
380
|
* Fragile: always run a benchmark on a change.
|
|
387
381
|
* Security note: operations don't check 'isValid' for all elements for performance reasons,
|
|
388
382
|
* it is caller responsibility to check this.
|
|
389
383
|
* This is low-level code, please make sure you know what you're doing.
|
|
390
|
-
*
|
|
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
|
|
391
390
|
* @param bitLen how many bits the field consumes
|
|
392
|
-
* @param isLE (
|
|
391
|
+
* @param isLE (default: false) if encoding / decoding should be in little-endian
|
|
393
392
|
* @param redef optional faster redefinitions of sqrt and other methods
|
|
394
393
|
*/
|
|
395
394
|
export function Field(
|
|
396
395
|
ORDER: bigint,
|
|
397
|
-
|
|
396
|
+
bitLenOrOpts?: number | FieldOpts,
|
|
398
397
|
isLE = false,
|
|
399
|
-
|
|
398
|
+
opts: { sqrt?: SqrtFn } = {}
|
|
400
399
|
): Readonly<FpField> {
|
|
401
400
|
if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
|
|
402
|
-
|
|
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);
|
|
403
414
|
if (BYTES > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');
|
|
404
415
|
let sqrtP: ReturnType<typeof FpSqrt>; // cached sqrtP
|
|
405
416
|
const f: Readonly<FpField> = Object.freeze({
|
|
@@ -417,6 +428,8 @@ export function Field(
|
|
|
417
428
|
return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
|
|
418
429
|
},
|
|
419
430
|
is0: (num) => num === _0n,
|
|
431
|
+
// is valid and invertible
|
|
432
|
+
isValidNot0: (num: bigint) => !f.is0(num) && f.isValid(num),
|
|
420
433
|
isOdd: (num) => (num & _1n) === _1n,
|
|
421
434
|
neg: (num) => mod(-num, ORDER),
|
|
422
435
|
eql: (lhs, rhs) => lhs === rhs,
|
|
@@ -436,7 +449,7 @@ export function Field(
|
|
|
436
449
|
|
|
437
450
|
inv: (num) => invert(num, ORDER),
|
|
438
451
|
sqrt:
|
|
439
|
-
|
|
452
|
+
_sqrt ||
|
|
440
453
|
((n) => {
|
|
441
454
|
if (!sqrtP) sqrtP = FpSqrt(ORDER);
|
|
442
455
|
return sqrtP(f, n);
|