@noble/curves 1.8.2 → 1.9.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 +49 -24
- package/abstract/bls.js +1 -1
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +1 -1
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +13 -4
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +17 -3
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +120 -0
- package/abstract/fft.d.ts.map +1 -0
- package/abstract/fft.js +439 -0
- package/abstract/fft.js.map +1 -0
- package/abstract/hash-to-curve.d.ts +10 -5
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +31 -23
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +13 -12
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +158 -158
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +4 -9
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +70 -90
- package/abstract/montgomery.js.map +1 -1
- package/abstract/poseidon.d.ts +39 -2
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +183 -4
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +4 -5
- package/abstract/tower.js.map +1 -1
- package/abstract/utils.d.ts +1 -0
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +2 -0
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +31 -9
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +67 -48
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +9 -23
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +1 -0
- package/bn254.d.ts.map +1 -1
- package/bn254.js +10 -0
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +19 -5
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +29 -18
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +21 -5
- package/ed448.d.ts.map +1 -1
- package/ed448.js +46 -34
- package/ed448.js.map +1 -1
- package/esm/abstract/bls.js +1 -1
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +1 -1
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +13 -4
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +19 -5
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/fft.d.ts +120 -0
- package/esm/abstract/fft.d.ts.map +1 -0
- package/esm/abstract/fft.js +426 -0
- package/esm/abstract/fft.js.map +1 -0
- package/esm/abstract/hash-to-curve.d.ts +10 -5
- package/esm/abstract/hash-to-curve.d.ts.map +1 -1
- package/esm/abstract/hash-to-curve.js +32 -24
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.d.ts +13 -12
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +158 -158
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts +4 -9
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +71 -91
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/poseidon.d.ts +39 -2
- package/esm/abstract/poseidon.d.ts.map +1 -1
- package/esm/abstract/poseidon.js +180 -5
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/tower.d.ts.map +1 -1
- package/esm/abstract/tower.js +4 -5
- package/esm/abstract/tower.js.map +1 -1
- package/esm/abstract/utils.d.ts +1 -0
- package/esm/abstract/utils.d.ts.map +1 -1
- package/esm/abstract/utils.js +2 -0
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +31 -9
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +69 -50
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.d.ts.map +1 -1
- package/esm/bls12-381.js +9 -23
- package/esm/bls12-381.js.map +1 -1
- package/esm/bn254.d.ts +1 -0
- package/esm/bn254.d.ts.map +1 -1
- package/esm/bn254.js +10 -0
- package/esm/bn254.js.map +1 -1
- package/esm/ed25519.d.ts +19 -5
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +29 -18
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +21 -5
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +47 -35
- package/esm/ed448.js.map +1 -1
- package/esm/jubjub.d.ts +11 -1
- package/esm/jubjub.d.ts.map +1 -1
- package/esm/jubjub.js +11 -1
- package/esm/jubjub.js.map +1 -1
- package/esm/misc.d.ts +8 -2
- package/esm/misc.d.ts.map +1 -1
- package/esm/misc.js +10 -4
- package/esm/misc.js.map +1 -1
- package/esm/nist.d.ts +30 -0
- package/esm/nist.d.ts.map +1 -0
- package/esm/nist.js +121 -0
- package/esm/nist.js.map +1 -0
- package/esm/p256.d.ts +7 -9
- package/esm/p256.d.ts.map +1 -1
- package/esm/p256.js +6 -44
- package/esm/p256.js.map +1 -1
- package/esm/p384.d.ts +9 -10
- package/esm/p384.d.ts.map +1 -1
- package/esm/p384.js +7 -46
- package/esm/p384.js.map +1 -1
- package/esm/p521.d.ts +7 -8
- package/esm/p521.d.ts.map +1 -1
- package/esm/p521.js +6 -46
- package/esm/p521.js.map +1 -1
- package/esm/pasta.d.ts +9 -1
- package/esm/pasta.d.ts.map +1 -1
- package/esm/pasta.js +9 -1
- package/esm/pasta.js.map +1 -1
- package/esm/secp256k1.d.ts +3 -3
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +8 -9
- package/esm/secp256k1.js.map +1 -1
- package/jubjub.d.ts +11 -1
- package/jubjub.d.ts.map +1 -1
- package/jubjub.js +12 -5
- package/jubjub.js.map +1 -1
- package/misc.d.ts +8 -2
- package/misc.d.ts.map +1 -1
- package/misc.js +11 -5
- package/misc.js.map +1 -1
- package/nist.d.ts +30 -0
- package/nist.d.ts.map +1 -0
- package/nist.js +124 -0
- package/nist.js.map +1 -0
- package/p256.d.ts +7 -9
- package/p256.d.ts.map +1 -1
- package/p256.js +5 -49
- package/p256.js.map +1 -1
- package/p384.d.ts +9 -10
- package/p384.d.ts.map +1 -1
- package/p384.js +6 -51
- package/p384.js.map +1 -1
- package/p521.d.ts +7 -8
- package/p521.d.ts.map +1 -1
- package/p521.js +5 -51
- package/p521.js.map +1 -1
- package/package.json +117 -8
- package/pasta.d.ts +9 -1
- package/pasta.d.ts.map +1 -1
- package/pasta.js +9 -3
- package/pasta.js.map +1 -1
- package/secp256k1.d.ts +3 -3
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +9 -10
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +1 -1
- package/src/abstract/curve.ts +11 -6
- package/src/abstract/edwards.ts +26 -12
- package/src/abstract/fft.ts +508 -0
- package/src/abstract/hash-to-curve.ts +44 -36
- package/src/abstract/modular.ts +154 -153
- package/src/abstract/montgomery.ts +78 -109
- package/src/abstract/poseidon.ts +208 -13
- package/src/abstract/tower.ts +4 -5
- package/src/abstract/utils.ts +2 -0
- package/src/abstract/weierstrass.ts +109 -61
- package/src/bls12-381.ts +11 -27
- package/src/bn254.ts +10 -0
- package/src/ed25519.ts +32 -19
- package/src/ed448.ts +91 -75
- package/src/jubjub.ts +12 -5
- package/src/misc.ts +10 -4
- package/src/nist.ts +155 -0
- package/src/p256.ts +6 -50
- package/src/p384.ts +8 -56
- package/src/p521.ts +6 -65
- package/src/pasta.ts +9 -1
- package/src/secp256k1.ts +12 -11
package/src/abstract/modular.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
|
+
import { anumber } from '@noble/hashes/utils';
|
|
8
9
|
import {
|
|
9
10
|
bitMask,
|
|
10
11
|
bytesToNumberBE,
|
|
@@ -19,8 +20,6 @@ import {
|
|
|
19
20
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
|
|
20
21
|
// prettier-ignore
|
|
21
22
|
const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _8n = /* @__PURE__ */ BigInt(8);
|
|
22
|
-
// prettier-ignore
|
|
23
|
-
const _9n =/* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);
|
|
24
23
|
|
|
25
24
|
// Calculates a modulo b
|
|
26
25
|
export function mod(a: bigint, b: bigint): bigint {
|
|
@@ -30,21 +29,12 @@ export function mod(a: bigint, b: bigint): bigint {
|
|
|
30
29
|
/**
|
|
31
30
|
* Efficiently raise num to power and do modular division.
|
|
32
31
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
33
|
-
*
|
|
32
|
+
* TODO: remove.
|
|
34
33
|
* @example
|
|
35
34
|
* pow(2n, 6n, 11n) // 64n % 11n == 9n
|
|
36
35
|
*/
|
|
37
36
|
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
|
38
|
-
|
|
39
|
-
if (modulo <= _0n) throw new Error('invalid modulus');
|
|
40
|
-
if (modulo === _1n) return _0n;
|
|
41
|
-
let res = _1n;
|
|
42
|
-
while (power > _0n) {
|
|
43
|
-
if (power & _1n) res = (res * num) % modulo;
|
|
44
|
-
num = (num * num) % modulo;
|
|
45
|
-
power >>= _1n;
|
|
46
|
-
}
|
|
47
|
-
return res;
|
|
37
|
+
return FpPow(Field(modulo), num, power);
|
|
48
38
|
}
|
|
49
39
|
|
|
50
40
|
/** Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)` */
|
|
@@ -83,138 +73,141 @@ export function invert(number: bigint, modulo: bigint): bigint {
|
|
|
83
73
|
return mod(x, modulo);
|
|
84
74
|
}
|
|
85
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
|
+
|
|
86
122
|
/**
|
|
87
123
|
* Tonelli-Shanks square root search algorithm.
|
|
88
124
|
* 1. https://eprint.iacr.org/2012/685.pdf (page 12)
|
|
89
125
|
* 2. Square Roots from 1; 24, 51, 10 to Dan Shanks
|
|
90
|
-
* Will start an infinite loop if field order P is not prime.
|
|
91
126
|
* @param P field order
|
|
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
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// Step 1: By factoring out powers of 2 from p - 1,
|
|
104
|
-
// find q and s such that p - 1 = q*(2^s) with q odd
|
|
105
|
-
for (Q = P - _1n, S = 0; Q % _2n === _0n; Q /= _2n, S++);
|
|
106
|
-
|
|
107
|
-
// Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
|
|
108
|
-
for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++) {
|
|
109
|
-
// Crash instead of infinity loop, we cannot reasonable count until P.
|
|
110
|
-
if (Z > 1000) throw new Error('Cannot find square root: likely non-prime P');
|
|
130
|
+
// Initialization (precomputation).
|
|
131
|
+
if (P < BigInt(3)) throw new Error('sqrt is not defined for small field');
|
|
132
|
+
// Factor P - 1 = Q * 2^S, where Q is odd
|
|
133
|
+
let Q = P - _1n;
|
|
134
|
+
let S = 0;
|
|
135
|
+
while (Q % _2n === _0n) {
|
|
136
|
+
Q /= _2n;
|
|
137
|
+
S++;
|
|
111
138
|
}
|
|
112
139
|
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
};
|
|
140
|
+
// Find the first quadratic non-residue Z >= 2
|
|
141
|
+
let Z = _2n;
|
|
142
|
+
const _Fp = Field(P);
|
|
143
|
+
while (FpLegendre(_Fp, Z) === 1) {
|
|
144
|
+
// Basic primality test for P. After x iterations, chance of
|
|
145
|
+
// not finding quadratic non-residue is 2^x, so 2^1000.
|
|
146
|
+
if (Z++ > 1000) throw new Error('Cannot find square root: probably non-prime P');
|
|
121
147
|
}
|
|
148
|
+
// Fast-path; usually done before Z, but we do "primality test".
|
|
149
|
+
if (S === 1) return sqrt3mod4;
|
|
122
150
|
|
|
123
151
|
// Slow-path
|
|
152
|
+
// TODO: test on Fp2 and others
|
|
153
|
+
let cc = _Fp.pow(Z, Q); // c = z^Q
|
|
124
154
|
const Q1div2 = (Q + _1n) / _2n;
|
|
125
155
|
return function tonelliSlow<T>(Fp: IField<T>, n: T): T {
|
|
126
|
-
|
|
127
|
-
if
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
let
|
|
132
|
-
let
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
156
|
+
if (Fp.is0(n)) return n;
|
|
157
|
+
// Check if n is a quadratic residue using Legendre symbol
|
|
158
|
+
if (FpLegendre(Fp, n) !== 1) throw new Error('Cannot find square root');
|
|
159
|
+
|
|
160
|
+
// Initialize variables for the main loop
|
|
161
|
+
let M = S;
|
|
162
|
+
let c = Fp.mul(Fp.ONE, cc); // c = z^Q, move cc from field _Fp into field Fp
|
|
163
|
+
let t = Fp.pow(n, Q); // t = n^Q, first guess at the fudge factor
|
|
164
|
+
let R = Fp.pow(n, Q1div2); // R = n^((Q+1)/2), first guess at the square root
|
|
165
|
+
|
|
166
|
+
// Main loop
|
|
167
|
+
// while t != 1
|
|
168
|
+
while (!Fp.eql(t, Fp.ONE)) {
|
|
169
|
+
if (Fp.is0(t)) return Fp.ZERO; // if t=0 return R=0
|
|
170
|
+
let i = 1;
|
|
171
|
+
|
|
172
|
+
// Find the smallest i >= 1 such that t^(2^i) ≡ 1 (mod P)
|
|
173
|
+
let t_tmp = Fp.sqr(t); // t^(2^1)
|
|
174
|
+
while (!Fp.eql(t_tmp, Fp.ONE)) {
|
|
175
|
+
i++;
|
|
176
|
+
t_tmp = Fp.sqr(t_tmp); // t^(2^2)...
|
|
177
|
+
if (i === M) throw new Error('Cannot find square root');
|
|
141
178
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
179
|
+
|
|
180
|
+
// Calculate the exponent for b: 2^(M - i - 1)
|
|
181
|
+
const exponent = _1n << BigInt(M - i - 1); // bigint is important
|
|
182
|
+
const b = Fp.pow(c, exponent); // b = 2^(M - i - 1)
|
|
183
|
+
|
|
184
|
+
// Update variables
|
|
185
|
+
M = i;
|
|
186
|
+
c = Fp.sqr(b); // c = b^2
|
|
187
|
+
t = Fp.mul(t, c); // t = (t * b^2)
|
|
188
|
+
R = Fp.mul(R, b); // R = R*b
|
|
148
189
|
}
|
|
149
|
-
return
|
|
190
|
+
return R;
|
|
150
191
|
};
|
|
151
192
|
}
|
|
152
193
|
|
|
153
194
|
/**
|
|
154
|
-
* Square root for a finite field.
|
|
195
|
+
* Square root for a finite field. Will try optimized versions first:
|
|
155
196
|
*
|
|
156
197
|
* 1. P ≡ 3 (mod 4)
|
|
157
198
|
* 2. P ≡ 5 (mod 8)
|
|
158
|
-
* 3.
|
|
159
|
-
* 4. Tonelli-Shanks algorithm
|
|
199
|
+
* 3. Tonelli-Shanks algorithm
|
|
160
200
|
*
|
|
161
201
|
* Different algorithms can give different roots, it is up to user to decide which one they want.
|
|
162
202
|
* For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
|
|
163
203
|
*/
|
|
164
204
|
export function FpSqrt(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
|
165
|
-
// P ≡ 3 (mod 4)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
// const NUM = 72057594037927816n;
|
|
172
|
-
const p1div4 = (P + _1n) / _4n;
|
|
173
|
-
return function sqrt3mod4<T>(Fp: IField<T>, n: T) {
|
|
174
|
-
const root = Fp.pow(n, p1div4);
|
|
175
|
-
// Throw if root**2 != n
|
|
176
|
-
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
|
177
|
-
return root;
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
|
|
182
|
-
if (P % _8n === _5n) {
|
|
183
|
-
const c1 = (P - _5n) / _8n;
|
|
184
|
-
return function sqrt5mod8<T>(Fp: IField<T>, n: T) {
|
|
185
|
-
const n2 = Fp.mul(n, _2n);
|
|
186
|
-
const v = Fp.pow(n2, c1);
|
|
187
|
-
const nv = Fp.mul(n, v);
|
|
188
|
-
const i = Fp.mul(Fp.mul(nv, _2n), v);
|
|
189
|
-
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
|
190
|
-
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
|
191
|
-
return root;
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// P ≡ 9 (mod 16)
|
|
196
|
-
if (P % _16n === _9n) {
|
|
197
|
-
// NOTE: tonelli is too slow for bls-Fp2 calculations even on start
|
|
198
|
-
// Means we cannot use sqrt for constants at all!
|
|
199
|
-
//
|
|
200
|
-
// const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
201
|
-
// const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
202
|
-
// const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
203
|
-
// const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
204
|
-
// sqrt = (x) => {
|
|
205
|
-
// let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
|
|
206
|
-
// let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
|
|
207
|
-
// const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
|
|
208
|
-
// let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
|
|
209
|
-
// const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
|
|
210
|
-
// const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
|
|
211
|
-
// tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
212
|
-
// tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
213
|
-
// const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
|
|
214
|
-
// return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
|
|
215
|
-
// }
|
|
216
|
-
}
|
|
217
|
-
// Other cases: Tonelli-Shanks algorithm
|
|
205
|
+
// P ≡ 3 (mod 4) => √n = n^((P+1)/4)
|
|
206
|
+
if (P % _4n === _3n) return sqrt3mod4;
|
|
207
|
+
// P ≡ 5 (mod 8) => Atkin algorithm, page 10 of https://eprint.iacr.org/2012/685.pdf
|
|
208
|
+
if (P % _8n === _5n) return sqrt5mod8;
|
|
209
|
+
// P ≡ 9 (mod 16) not implemented, see above
|
|
210
|
+
// Tonelli-Shanks algorithm
|
|
218
211
|
return tonelliShanks(P);
|
|
219
212
|
}
|
|
220
213
|
|
|
@@ -258,7 +251,6 @@ export interface IField<T> {
|
|
|
258
251
|
// NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
|
|
259
252
|
isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
|
|
260
253
|
// legendre?(num: T): T;
|
|
261
|
-
pow(lhs: T, power: bigint): T;
|
|
262
254
|
invertBatch: (lst: T[]) => T[];
|
|
263
255
|
toBytes(num: T): Uint8Array;
|
|
264
256
|
fromBytes(bytes: Uint8Array): T;
|
|
@@ -291,17 +283,15 @@ export function validateField<T>(field: IField<T>): IField<T> {
|
|
|
291
283
|
* Same as `pow` but for Fp: non-constant-time.
|
|
292
284
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
293
285
|
*/
|
|
294
|
-
export function FpPow<T>(
|
|
295
|
-
// Should have same speed as pow for bigints
|
|
296
|
-
// TODO: benchmark!
|
|
286
|
+
export function FpPow<T>(Fp: IField<T>, num: T, power: bigint): T {
|
|
297
287
|
if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
|
|
298
|
-
if (power === _0n) return
|
|
288
|
+
if (power === _0n) return Fp.ONE;
|
|
299
289
|
if (power === _1n) return num;
|
|
300
|
-
let p =
|
|
290
|
+
let p = Fp.ONE;
|
|
301
291
|
let d = num;
|
|
302
292
|
while (power > _0n) {
|
|
303
|
-
if (power & _1n) p =
|
|
304
|
-
d =
|
|
293
|
+
if (power & _1n) p = Fp.mul(p, d);
|
|
294
|
+
d = Fp.sqr(d);
|
|
305
295
|
power >>= _1n;
|
|
306
296
|
}
|
|
307
297
|
return p;
|
|
@@ -309,49 +299,58 @@ export function FpPow<T>(f: IField<T>, num: T, power: bigint): T {
|
|
|
309
299
|
|
|
310
300
|
/**
|
|
311
301
|
* Efficiently invert an array of Field elements.
|
|
312
|
-
*
|
|
302
|
+
* Exception-free. Will return `undefined` for 0 elements.
|
|
303
|
+
* @param passZero map 0 to 0 (instead of undefined)
|
|
313
304
|
*/
|
|
314
|
-
export function FpInvertBatch<T>(
|
|
315
|
-
const
|
|
305
|
+
export function FpInvertBatch<T>(Fp: IField<T>, nums: T[], passZero = false): T[] {
|
|
306
|
+
const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : undefined);
|
|
316
307
|
// Walk from first to last, multiply them by each other MOD p
|
|
317
|
-
const
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
return
|
|
321
|
-
},
|
|
308
|
+
const multipliedAcc = nums.reduce((acc, num, i) => {
|
|
309
|
+
if (Fp.is0(num)) return acc;
|
|
310
|
+
inverted[i] = acc;
|
|
311
|
+
return Fp.mul(acc, num);
|
|
312
|
+
}, Fp.ONE);
|
|
322
313
|
// Invert last element
|
|
323
|
-
const
|
|
314
|
+
const invertedAcc = Fp.inv(multipliedAcc);
|
|
324
315
|
// Walk from last to first, multiply them by inverted each other MOD p
|
|
325
316
|
nums.reduceRight((acc, num, i) => {
|
|
326
|
-
if (
|
|
327
|
-
|
|
328
|
-
return
|
|
329
|
-
},
|
|
330
|
-
return
|
|
317
|
+
if (Fp.is0(num)) return acc;
|
|
318
|
+
inverted[i] = Fp.mul(acc, inverted[i]);
|
|
319
|
+
return Fp.mul(acc, num);
|
|
320
|
+
}, invertedAcc);
|
|
321
|
+
return inverted;
|
|
331
322
|
}
|
|
332
323
|
|
|
333
|
-
|
|
334
|
-
|
|
324
|
+
// TODO: remove
|
|
325
|
+
export function FpDiv<T>(Fp: IField<T>, lhs: T, rhs: T | bigint): T {
|
|
326
|
+
return Fp.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, Fp.ORDER) : Fp.inv(rhs));
|
|
335
327
|
}
|
|
336
328
|
|
|
337
329
|
/**
|
|
338
330
|
* Legendre symbol.
|
|
331
|
+
* Legendre constant is used to calculate Legendre symbol (a | p)
|
|
332
|
+
* which denotes the value of a^((p-1)/2) (mod p).
|
|
333
|
+
*
|
|
339
334
|
* * (a | p) ≡ 1 if a is a square (mod p), quadratic residue
|
|
340
335
|
* * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
|
|
341
336
|
* * (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
342
337
|
*/
|
|
343
|
-
export function FpLegendre
|
|
344
|
-
|
|
345
|
-
|
|
338
|
+
export function FpLegendre<T>(Fp: IField<T>, n: T): -1 | 0 | 1 {
|
|
339
|
+
// We can use 3rd argument as optional cache of this value
|
|
340
|
+
// but seems unneeded for now. The operation is very fast.
|
|
341
|
+
const p1mod2 = (Fp.ORDER - _1n) / _2n;
|
|
342
|
+
const powered = Fp.pow(n, p1mod2);
|
|
343
|
+
const yes = Fp.eql(powered, Fp.ONE);
|
|
344
|
+
const zero = Fp.eql(powered, Fp.ZERO);
|
|
345
|
+
const no = Fp.eql(powered, Fp.neg(Fp.ONE));
|
|
346
|
+
if (!yes && !zero && !no) throw new Error('invalid Legendre symbol result');
|
|
347
|
+
return yes ? 1 : zero ? 0 : -1;
|
|
346
348
|
}
|
|
347
349
|
|
|
348
350
|
// This function returns True whenever the value x is a square in the field F.
|
|
349
|
-
export function FpIsSquare<T>(
|
|
350
|
-
const
|
|
351
|
-
return
|
|
352
|
-
const p = legendre(f, x);
|
|
353
|
-
return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
|
|
354
|
-
};
|
|
351
|
+
export function FpIsSquare<T>(Fp: IField<T>, n: T): boolean {
|
|
352
|
+
const l = FpLegendre(Fp, n);
|
|
353
|
+
return l === 1;
|
|
355
354
|
}
|
|
356
355
|
|
|
357
356
|
// CURVE.n lengths
|
|
@@ -363,6 +362,7 @@ export function nLength(
|
|
|
363
362
|
nByteLength: number;
|
|
364
363
|
} {
|
|
365
364
|
// Bit size, byte size of CURVE.n
|
|
365
|
+
if (nBitLength !== undefined) anumber(nBitLength);
|
|
366
366
|
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
|
|
367
367
|
const nByteLength = Math.ceil(_nBitLength / 8);
|
|
368
368
|
return { nBitLength: _nBitLength, nByteLength };
|
|
@@ -433,16 +433,17 @@ export function Field(
|
|
|
433
433
|
if (!sqrtP) sqrtP = FpSqrt(ORDER);
|
|
434
434
|
return sqrtP(f, n);
|
|
435
435
|
}),
|
|
436
|
-
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
437
|
-
// TODO: do we really need constant cmov?
|
|
438
|
-
// We don't have const-time bigints anyway, so probably will be not very useful
|
|
439
|
-
cmov: (a, b, c) => (c ? b : a),
|
|
440
436
|
toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),
|
|
441
437
|
fromBytes: (bytes) => {
|
|
442
438
|
if (bytes.length !== BYTES)
|
|
443
439
|
throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
|
|
444
440
|
return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
|
445
441
|
},
|
|
442
|
+
// TODO: we don't need it here, move out to separate fn
|
|
443
|
+
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
444
|
+
// We can't move this out because Fp6, Fp12 implement it
|
|
445
|
+
// and it's unclear what to return in there.
|
|
446
|
+
cmov: (a, b, c) => (c ? b : a),
|
|
446
447
|
} as FpField);
|
|
447
448
|
return Object.freeze(f);
|
|
448
449
|
}
|