@noble/curves 1.9.5 → 2.0.0-beta.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 +267 -421
- package/abstract/bls.d.ts +49 -111
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +108 -152
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +7 -48
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +22 -47
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +17 -68
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +98 -175
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.js +14 -27
- package/abstract/fft.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +11 -24
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +30 -35
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +5 -17
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +166 -167
- 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 +17 -20
- package/abstract/montgomery.js.map +1 -1
- package/abstract/oprf.d.ts +282 -0
- package/abstract/oprf.d.ts.map +1 -0
- package/abstract/oprf.js +297 -0
- package/abstract/oprf.js.map +1 -0
- package/abstract/poseidon.js +20 -24
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts +9 -7
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +600 -364
- package/abstract/tower.js.map +1 -1
- package/abstract/weierstrass.d.ts +12 -145
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +153 -377
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +2 -2
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +174 -216
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +58 -10
- package/bn254.d.ts.map +1 -1
- package/bn254.js +70 -130
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +12 -31
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +104 -146
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +14 -33
- package/ed448.d.ts.map +1 -1
- package/ed448.js +105 -132
- package/ed448.js.map +1 -1
- package/index.js +1 -1
- package/misc.d.ts +10 -14
- package/misc.d.ts.map +1 -1
- package/misc.js +51 -60
- package/misc.js.map +1 -1
- package/nist.d.ts +11 -14
- package/nist.d.ts.map +1 -1
- package/nist.js +46 -55
- package/nist.js.map +1 -1
- package/package.json +9 -224
- package/secp256k1.d.ts +7 -23
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +72 -83
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +197 -344
- package/src/abstract/curve.ts +10 -83
- package/src/abstract/edwards.ts +96 -223
- package/src/abstract/hash-to-curve.ts +32 -45
- package/src/abstract/modular.ts +144 -130
- package/src/abstract/montgomery.ts +21 -22
- package/src/abstract/oprf.ts +600 -0
- package/src/abstract/tower.ts +627 -382
- package/src/abstract/weierstrass.ts +101 -482
- package/src/bls12-381.ts +148 -176
- package/src/bn254.ts +67 -122
- package/src/ed25519.ts +65 -118
- package/src/ed448.ts +63 -113
- package/src/index.ts +1 -1
- package/src/misc.ts +66 -49
- package/src/nist.ts +48 -57
- package/src/secp256k1.ts +56 -88
- package/src/utils.ts +41 -61
- package/src/webcrypto.ts +362 -0
- package/utils.d.ts +28 -19
- package/utils.d.ts.map +1 -1
- package/utils.js +45 -121
- package/utils.js.map +1 -1
- package/webcrypto.d.ts +47 -0
- package/webcrypto.d.ts.map +1 -0
- package/webcrypto.js +231 -0
- package/webcrypto.js.map +1 -0
- package/esm/_shortw_utils.d.ts +0 -19
- package/esm/_shortw_utils.d.ts.map +0 -1
- package/esm/_shortw_utils.js +0 -16
- package/esm/_shortw_utils.js.map +0 -1
- package/esm/abstract/bls.d.ts +0 -190
- package/esm/abstract/bls.d.ts.map +0 -1
- package/esm/abstract/bls.js +0 -408
- package/esm/abstract/bls.js.map +0 -1
- package/esm/abstract/curve.d.ts +0 -231
- package/esm/abstract/curve.d.ts.map +0 -1
- package/esm/abstract/curve.js +0 -465
- package/esm/abstract/curve.js.map +0 -1
- package/esm/abstract/edwards.d.ts +0 -237
- package/esm/abstract/edwards.d.ts.map +0 -1
- package/esm/abstract/edwards.js +0 -632
- package/esm/abstract/edwards.js.map +0 -1
- package/esm/abstract/fft.d.ts +0 -122
- package/esm/abstract/fft.d.ts.map +0 -1
- package/esm/abstract/fft.js +0 -425
- package/esm/abstract/fft.js.map +0 -1
- package/esm/abstract/hash-to-curve.d.ts +0 -102
- package/esm/abstract/hash-to-curve.d.ts.map +0 -1
- package/esm/abstract/hash-to-curve.js +0 -203
- package/esm/abstract/hash-to-curve.js.map +0 -1
- package/esm/abstract/modular.d.ts +0 -171
- package/esm/abstract/modular.d.ts.map +0 -1
- package/esm/abstract/modular.js +0 -530
- package/esm/abstract/modular.js.map +0 -1
- package/esm/abstract/montgomery.d.ts +0 -30
- package/esm/abstract/montgomery.d.ts.map +0 -1
- package/esm/abstract/montgomery.js +0 -157
- package/esm/abstract/montgomery.js.map +0 -1
- package/esm/abstract/poseidon.d.ts +0 -68
- package/esm/abstract/poseidon.d.ts.map +0 -1
- package/esm/abstract/poseidon.js +0 -296
- package/esm/abstract/poseidon.js.map +0 -1
- package/esm/abstract/tower.d.ts +0 -93
- package/esm/abstract/tower.d.ts.map +0 -1
- package/esm/abstract/tower.js +0 -502
- package/esm/abstract/tower.js.map +0 -1
- package/esm/abstract/utils.d.ts +0 -5
- package/esm/abstract/utils.d.ts.map +0 -1
- package/esm/abstract/utils.js +0 -7
- package/esm/abstract/utils.js.map +0 -1
- package/esm/abstract/weierstrass.d.ts +0 -412
- package/esm/abstract/weierstrass.d.ts.map +0 -1
- package/esm/abstract/weierstrass.js +0 -1428
- package/esm/abstract/weierstrass.js.map +0 -1
- package/esm/bls12-381.d.ts +0 -16
- package/esm/bls12-381.d.ts.map +0 -1
- package/esm/bls12-381.js +0 -738
- package/esm/bls12-381.js.map +0 -1
- package/esm/bn254.d.ts +0 -18
- package/esm/bn254.d.ts.map +0 -1
- package/esm/bn254.js +0 -246
- package/esm/bn254.js.map +0 -1
- package/esm/ed25519.d.ts +0 -106
- package/esm/ed25519.d.ts.map +0 -1
- package/esm/ed25519.js +0 -467
- package/esm/ed25519.js.map +0 -1
- package/esm/ed448.d.ts +0 -101
- package/esm/ed448.d.ts.map +0 -1
- package/esm/ed448.js +0 -448
- package/esm/ed448.js.map +0 -1
- package/esm/index.d.ts +0 -2
- package/esm/index.d.ts.map +0 -1
- package/esm/index.js +0 -17
- package/esm/index.js.map +0 -1
- package/esm/jubjub.d.ts +0 -12
- package/esm/jubjub.d.ts.map +0 -1
- package/esm/jubjub.js +0 -12
- package/esm/jubjub.js.map +0 -1
- package/esm/misc.d.ts +0 -19
- package/esm/misc.d.ts.map +0 -1
- package/esm/misc.js +0 -109
- package/esm/misc.js.map +0 -1
- package/esm/nist.d.ts +0 -21
- package/esm/nist.d.ts.map +0 -1
- package/esm/nist.js +0 -132
- package/esm/nist.js.map +0 -1
- package/esm/p256.d.ts +0 -16
- package/esm/p256.d.ts.map +0 -1
- package/esm/p256.js +0 -16
- package/esm/p256.js.map +0 -1
- package/esm/p384.d.ts +0 -16
- package/esm/p384.d.ts.map +0 -1
- package/esm/p384.js +0 -16
- package/esm/p384.js.map +0 -1
- package/esm/p521.d.ts +0 -16
- package/esm/p521.d.ts.map +0 -1
- package/esm/p521.js +0 -16
- package/esm/p521.js.map +0 -1
- package/esm/package.json +0 -4
- package/esm/pasta.d.ts +0 -10
- package/esm/pasta.d.ts.map +0 -1
- package/esm/pasta.js +0 -10
- package/esm/pasta.js.map +0 -1
- package/esm/secp256k1.d.ts +0 -89
- package/esm/secp256k1.d.ts.map +0 -1
- package/esm/secp256k1.js +0 -292
- package/esm/secp256k1.js.map +0 -1
- package/esm/utils.d.ts +0 -110
- package/esm/utils.d.ts.map +0 -1
- package/esm/utils.js +0 -322
- package/esm/utils.js.map +0 -1
- package/src/_shortw_utils.ts +0 -21
- package/src/abstract/utils.ts +0 -7
- package/src/jubjub.ts +0 -12
- package/src/p256.ts +0 -15
- package/src/p384.ts +0 -15
- package/src/p521.ts +0 -15
- package/src/package.json +0 -3
- package/src/pasta.ts +0 -9
package/abstract/weierstrass.js
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DER = exports.DERErr = void 0;
|
|
4
|
-
exports._splitEndoScalar = _splitEndoScalar;
|
|
5
|
-
exports._normFnElement = _normFnElement;
|
|
6
|
-
exports.weierstrassN = weierstrassN;
|
|
7
|
-
exports.SWUFpSqrtRatio = SWUFpSqrtRatio;
|
|
8
|
-
exports.mapToCurveSimpleSWU = mapToCurveSimpleSWU;
|
|
9
|
-
exports.ecdh = ecdh;
|
|
10
|
-
exports.ecdsa = ecdsa;
|
|
11
|
-
exports.weierstrassPoints = weierstrassPoints;
|
|
12
|
-
exports._legacyHelperEquat = _legacyHelperEquat;
|
|
13
|
-
exports.weierstrass = weierstrass;
|
|
14
1
|
/**
|
|
15
2
|
* Short Weierstrass curve methods. The formula is: y² = x³ + ax + b.
|
|
16
3
|
*
|
|
@@ -38,17 +25,17 @@ exports.weierstrass = weierstrass;
|
|
|
38
25
|
* @module
|
|
39
26
|
*/
|
|
40
27
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
28
|
+
import { hmac as nobleHmac } from '@noble/hashes/hmac.js';
|
|
29
|
+
import { ahash } from '@noble/hashes/utils.js';
|
|
30
|
+
import { _validateObject, abool, abytes, aInRange, bitLen, bitMask, bytesToHex, bytesToNumberBE, concatBytes, createHmacDrbg, hexToBytes, isBytes, memoized, numberToHexUnpadded, randomBytes as wcRandomBytes, } from "../utils.js";
|
|
31
|
+
import { _createCurveFields, mulEndoUnsafe, negateCt, normalizeZ, wNAF, } from "./curve.js";
|
|
32
|
+
import { FpInvertBatch, getMinHashLength, mapHashToField, validateField, } from "./modular.js";
|
|
46
33
|
// We construct basis in such way that den is always positive and equals n, but num sign depends on basis (not on secret value)
|
|
47
34
|
const divNearest = (num, den) => (num + (num >= 0 ? den : -den) / _2n) / den;
|
|
48
35
|
/**
|
|
49
36
|
* Splits scalar for GLV endomorphism.
|
|
50
37
|
*/
|
|
51
|
-
function _splitEndoScalar(k, basis, n) {
|
|
38
|
+
export function _splitEndoScalar(k, basis, n) {
|
|
52
39
|
// Split scalar into two such that part is ~half bits: `abs(part) < sqrt(N)`
|
|
53
40
|
// Since part can be negative, we need to do this on point.
|
|
54
41
|
// TODO: verifyScalar function which consumes lambda
|
|
@@ -67,7 +54,7 @@ function _splitEndoScalar(k, basis, n) {
|
|
|
67
54
|
k2 = -k2;
|
|
68
55
|
// Double check that resulting scalar less than half bits of N: otherwise wNAF will fail.
|
|
69
56
|
// This should only happen on wrong basises. Also, math inside is too complex and I don't trust it.
|
|
70
|
-
const MAX_NUM =
|
|
57
|
+
const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n; // Half bits of N
|
|
71
58
|
if (k1 < _0n || k1 >= MAX_NUM || k2 < _0n || k2 >= MAX_NUM) {
|
|
72
59
|
throw new Error('splitScalar (endomorphism): failed, k=' + k);
|
|
73
60
|
}
|
|
@@ -84,18 +71,17 @@ function validateSigOpts(opts, def) {
|
|
|
84
71
|
// @ts-ignore
|
|
85
72
|
optsn[optName] = opts[optName] === undefined ? def[optName] : opts[optName];
|
|
86
73
|
}
|
|
87
|
-
(
|
|
88
|
-
(
|
|
74
|
+
abool(optsn.lowS, 'lowS');
|
|
75
|
+
abool(optsn.prehash, 'prehash');
|
|
89
76
|
if (optsn.format !== undefined)
|
|
90
77
|
validateSigFormat(optsn.format);
|
|
91
78
|
return optsn;
|
|
92
79
|
}
|
|
93
|
-
class DERErr extends Error {
|
|
80
|
+
export class DERErr extends Error {
|
|
94
81
|
constructor(m = '') {
|
|
95
82
|
super(m);
|
|
96
83
|
}
|
|
97
84
|
}
|
|
98
|
-
exports.DERErr = DERErr;
|
|
99
85
|
/**
|
|
100
86
|
* ASN.1 DER encoding utilities. ASN is very complex & fragile. Format:
|
|
101
87
|
*
|
|
@@ -103,42 +89,42 @@ exports.DERErr = DERErr;
|
|
|
103
89
|
*
|
|
104
90
|
* Docs: https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/, https://luca.ntop.org/Teaching/Appunti/asn1.html
|
|
105
91
|
*/
|
|
106
|
-
|
|
92
|
+
export const DER = {
|
|
107
93
|
// asn.1 DER encoding utils
|
|
108
94
|
Err: DERErr,
|
|
109
95
|
// Basic building block is TLV (Tag-Length-Value)
|
|
110
96
|
_tlv: {
|
|
111
97
|
encode: (tag, data) => {
|
|
112
|
-
const { Err: E } =
|
|
98
|
+
const { Err: E } = DER;
|
|
113
99
|
if (tag < 0 || tag > 256)
|
|
114
100
|
throw new E('tlv.encode: wrong tag');
|
|
115
101
|
if (data.length & 1)
|
|
116
102
|
throw new E('tlv.encode: unpadded data');
|
|
117
103
|
const dataLen = data.length / 2;
|
|
118
|
-
const len =
|
|
119
|
-
if ((len.length / 2) &
|
|
104
|
+
const len = numberToHexUnpadded(dataLen);
|
|
105
|
+
if ((len.length / 2) & 0b1000_0000)
|
|
120
106
|
throw new E('tlv.encode: long form length too big');
|
|
121
107
|
// length of length with long form flag
|
|
122
|
-
const lenLen = dataLen > 127 ?
|
|
123
|
-
const t =
|
|
108
|
+
const lenLen = dataLen > 127 ? numberToHexUnpadded((len.length / 2) | 0b1000_0000) : '';
|
|
109
|
+
const t = numberToHexUnpadded(tag);
|
|
124
110
|
return t + lenLen + len + data;
|
|
125
111
|
},
|
|
126
112
|
// v - value, l - left bytes (unparsed)
|
|
127
113
|
decode(tag, data) {
|
|
128
|
-
const { Err: E } =
|
|
114
|
+
const { Err: E } = DER;
|
|
129
115
|
let pos = 0;
|
|
130
116
|
if (tag < 0 || tag > 256)
|
|
131
117
|
throw new E('tlv.encode: wrong tag');
|
|
132
118
|
if (data.length < 2 || data[pos++] !== tag)
|
|
133
119
|
throw new E('tlv.decode: wrong tlv');
|
|
134
120
|
const first = data[pos++];
|
|
135
|
-
const isLong = !!(first &
|
|
121
|
+
const isLong = !!(first & 0b1000_0000); // First bit of first length byte is flag for short/long form
|
|
136
122
|
let length = 0;
|
|
137
123
|
if (!isLong)
|
|
138
124
|
length = first;
|
|
139
125
|
else {
|
|
140
126
|
// Long form: [longFlag(1bit), lengthLength(7bit), length (BE)]
|
|
141
|
-
const lenLen = first &
|
|
127
|
+
const lenLen = first & 0b0111_1111;
|
|
142
128
|
if (!lenLen)
|
|
143
129
|
throw new E('tlv.decode(long): indefinite length not supported');
|
|
144
130
|
if (lenLen > 4)
|
|
@@ -166,10 +152,10 @@ exports.DER = {
|
|
|
166
152
|
// - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
|
|
167
153
|
_int: {
|
|
168
154
|
encode(num) {
|
|
169
|
-
const { Err: E } =
|
|
155
|
+
const { Err: E } = DER;
|
|
170
156
|
if (num < _0n)
|
|
171
157
|
throw new E('integer: negative integers are not allowed');
|
|
172
|
-
let hex =
|
|
158
|
+
let hex = numberToHexUnpadded(num);
|
|
173
159
|
// Pad with zero byte if negative flag is present
|
|
174
160
|
if (Number.parseInt(hex[0], 16) & 0b1000)
|
|
175
161
|
hex = '00' + hex;
|
|
@@ -178,18 +164,18 @@ exports.DER = {
|
|
|
178
164
|
return hex;
|
|
179
165
|
},
|
|
180
166
|
decode(data) {
|
|
181
|
-
const { Err: E } =
|
|
182
|
-
if (data[0] &
|
|
167
|
+
const { Err: E } = DER;
|
|
168
|
+
if (data[0] & 0b1000_0000)
|
|
183
169
|
throw new E('invalid signature integer: negative');
|
|
184
|
-
if (data[0] === 0x00 && !(data[1] &
|
|
170
|
+
if (data[0] === 0x00 && !(data[1] & 0b1000_0000))
|
|
185
171
|
throw new E('invalid signature integer: unnecessary leading zero');
|
|
186
|
-
return
|
|
172
|
+
return bytesToNumberBE(data);
|
|
187
173
|
},
|
|
188
174
|
},
|
|
189
|
-
toSig(
|
|
175
|
+
toSig(bytes) {
|
|
190
176
|
// parse DER signature
|
|
191
|
-
const { Err: E, _int: int, _tlv: tlv } =
|
|
192
|
-
const data = (
|
|
177
|
+
const { Err: E, _int: int, _tlv: tlv } = DER;
|
|
178
|
+
const data = abytes(bytes, undefined, 'signature');
|
|
193
179
|
const { v: seqBytes, l: seqLeftBytes } = tlv.decode(0x30, data);
|
|
194
180
|
if (seqLeftBytes.length)
|
|
195
181
|
throw new E('invalid signature: left bytes after parsing');
|
|
@@ -200,7 +186,7 @@ exports.DER = {
|
|
|
200
186
|
return { r: int.decode(rBytes), s: int.decode(sBytes) };
|
|
201
187
|
},
|
|
202
188
|
hexFromSig(sig) {
|
|
203
|
-
const { _tlv: tlv, _int: int } =
|
|
189
|
+
const { _tlv: tlv, _int: int } = DER;
|
|
204
190
|
const rs = tlv.encode(0x02, int.encode(sig.r));
|
|
205
191
|
const ss = tlv.encode(0x02, int.encode(sig.s));
|
|
206
192
|
const seq = rs + ss;
|
|
@@ -210,25 +196,6 @@ exports.DER = {
|
|
|
210
196
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
|
211
197
|
// prettier-ignore
|
|
212
198
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
|
|
213
|
-
function _normFnElement(Fn, key) {
|
|
214
|
-
const { BYTES: expected } = Fn;
|
|
215
|
-
let num;
|
|
216
|
-
if (typeof key === 'bigint') {
|
|
217
|
-
num = key;
|
|
218
|
-
}
|
|
219
|
-
else {
|
|
220
|
-
let bytes = (0, utils_ts_1.ensureBytes)('private key', key);
|
|
221
|
-
try {
|
|
222
|
-
num = Fn.fromBytes(bytes);
|
|
223
|
-
}
|
|
224
|
-
catch (error) {
|
|
225
|
-
throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
if (!Fn.isValidNot0(num))
|
|
229
|
-
throw new Error('invalid private key: out of range [1..N-1]');
|
|
230
|
-
return num;
|
|
231
|
-
}
|
|
232
199
|
/**
|
|
233
200
|
* Creates weierstrass Point constructor, based on specified curve options.
|
|
234
201
|
*
|
|
@@ -246,12 +213,12 @@ const opts = {
|
|
|
246
213
|
const p256_Point = weierstrass(opts);
|
|
247
214
|
```
|
|
248
215
|
*/
|
|
249
|
-
function
|
|
250
|
-
const validated =
|
|
216
|
+
export function weierstrass(params, extraOpts = {}) {
|
|
217
|
+
const validated = _createCurveFields('weierstrass', params, extraOpts);
|
|
251
218
|
const { Fp, Fn } = validated;
|
|
252
219
|
let CURVE = validated.CURVE;
|
|
253
220
|
const { h: cofactor, n: CURVE_ORDER } = CURVE;
|
|
254
|
-
|
|
221
|
+
_validateObject(extraOpts, {}, {
|
|
255
222
|
allowInfinityPoint: 'boolean',
|
|
256
223
|
clearCofactor: 'function',
|
|
257
224
|
isTorsionFree: 'function',
|
|
@@ -276,19 +243,19 @@ function weierstrassN(params, extraOpts = {}) {
|
|
|
276
243
|
function pointToBytes(_c, point, isCompressed) {
|
|
277
244
|
const { x, y } = point.toAffine();
|
|
278
245
|
const bx = Fp.toBytes(x);
|
|
279
|
-
(
|
|
246
|
+
abool(isCompressed, 'isCompressed');
|
|
280
247
|
if (isCompressed) {
|
|
281
248
|
assertCompressionIsSupported();
|
|
282
249
|
const hasEvenY = !Fp.isOdd(y);
|
|
283
|
-
return
|
|
250
|
+
return concatBytes(pprefix(hasEvenY), bx);
|
|
284
251
|
}
|
|
285
252
|
else {
|
|
286
|
-
return
|
|
253
|
+
return concatBytes(Uint8Array.of(0x04), bx, Fp.toBytes(y));
|
|
287
254
|
}
|
|
288
255
|
}
|
|
289
256
|
function pointFromBytes(bytes) {
|
|
290
|
-
(
|
|
291
|
-
const {
|
|
257
|
+
abytes(bytes, undefined, 'Point');
|
|
258
|
+
const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths; // e.g. for 32-byte: 33, 65
|
|
292
259
|
const length = bytes.length;
|
|
293
260
|
const head = bytes[0];
|
|
294
261
|
const tail = bytes.subarray(1);
|
|
@@ -369,7 +336,7 @@ function weierstrassN(params, extraOpts = {}) {
|
|
|
369
336
|
// Converts Projective point to affine (x, y) coordinates.
|
|
370
337
|
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
|
371
338
|
// (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
|
|
372
|
-
const toAffineMemo =
|
|
339
|
+
const toAffineMemo = memoized((p, iz) => {
|
|
373
340
|
const { X, Y, Z } = p;
|
|
374
341
|
// Fast-path for normalized points
|
|
375
342
|
if (Fp.eql(Z, Fp.ONE))
|
|
@@ -390,7 +357,7 @@ function weierstrassN(params, extraOpts = {}) {
|
|
|
390
357
|
});
|
|
391
358
|
// NOTE: on exception this will crash 'cached' and no value will be set.
|
|
392
359
|
// Otherwise true will be return
|
|
393
|
-
const assertValidMemo =
|
|
360
|
+
const assertValidMemo = memoized((p) => {
|
|
394
361
|
if (p.is0()) {
|
|
395
362
|
// (0, 1, 0) aka ZERO is invalid in most contexts.
|
|
396
363
|
// In BLS, ZERO can be serialized, so we allow it.
|
|
@@ -411,8 +378,8 @@ function weierstrassN(params, extraOpts = {}) {
|
|
|
411
378
|
});
|
|
412
379
|
function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
|
|
413
380
|
k2p = new Point(Fp.mul(k2p.X, endoBeta), k2p.Y, k2p.Z);
|
|
414
|
-
k1p =
|
|
415
|
-
k2p =
|
|
381
|
+
k1p = negateCt(k1neg, k1p);
|
|
382
|
+
k2p = negateCt(k2neg, k2p);
|
|
416
383
|
return k1p.add(k2p);
|
|
417
384
|
}
|
|
418
385
|
/**
|
|
@@ -421,6 +388,17 @@ function weierstrassN(params, extraOpts = {}) {
|
|
|
421
388
|
* We're doing calculations in projective, because its operations don't require costly inversion.
|
|
422
389
|
*/
|
|
423
390
|
class Point {
|
|
391
|
+
// base / generator point
|
|
392
|
+
static BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
|
393
|
+
// zero / infinity / identity point
|
|
394
|
+
static ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); // 0, 1, 0
|
|
395
|
+
// math field
|
|
396
|
+
static Fp = Fp;
|
|
397
|
+
// scalar field
|
|
398
|
+
static Fn = Fn;
|
|
399
|
+
X;
|
|
400
|
+
Y;
|
|
401
|
+
Z;
|
|
424
402
|
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
|
425
403
|
constructor(X, Y, Z) {
|
|
426
404
|
this.X = acoord('x', X);
|
|
@@ -444,12 +422,12 @@ function weierstrassN(params, extraOpts = {}) {
|
|
|
444
422
|
return new Point(x, y, Fp.ONE);
|
|
445
423
|
}
|
|
446
424
|
static fromBytes(bytes) {
|
|
447
|
-
const P = Point.fromAffine(decodePoint((
|
|
425
|
+
const P = Point.fromAffine(decodePoint(abytes(bytes, undefined, 'point')));
|
|
448
426
|
P.assertValidity();
|
|
449
427
|
return P;
|
|
450
428
|
}
|
|
451
429
|
static fromHex(hex) {
|
|
452
|
-
return Point.fromBytes((
|
|
430
|
+
return Point.fromBytes(hexToBytes(hex));
|
|
453
431
|
}
|
|
454
432
|
get x() {
|
|
455
433
|
return this.toAffine().x;
|
|
@@ -608,7 +586,7 @@ function weierstrassN(params, extraOpts = {}) {
|
|
|
608
586
|
if (!Fn.isValidNot0(scalar))
|
|
609
587
|
throw new Error('invalid scalar: out of range'); // 0 is invalid
|
|
610
588
|
let point, fake; // Fake point is used to const-time mult
|
|
611
|
-
const mul = (n) => wnaf.cached(this, n, (p) =>
|
|
589
|
+
const mul = (n) => wnaf.cached(this, n, (p) => normalizeZ(Point, p));
|
|
612
590
|
/** See docs for {@link EndomorphismOpts} */
|
|
613
591
|
if (endo) {
|
|
614
592
|
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar);
|
|
@@ -623,7 +601,7 @@ function weierstrassN(params, extraOpts = {}) {
|
|
|
623
601
|
fake = f;
|
|
624
602
|
}
|
|
625
603
|
// Normalize `z` for both points, but return only real one
|
|
626
|
-
return
|
|
604
|
+
return normalizeZ(Point, [point, fake])[0];
|
|
627
605
|
}
|
|
628
606
|
/**
|
|
629
607
|
* Non-constant-time multiplication. Uses double-and-add algorithm.
|
|
@@ -643,7 +621,7 @@ function weierstrassN(params, extraOpts = {}) {
|
|
|
643
621
|
return this.multiply(sc);
|
|
644
622
|
if (endo) {
|
|
645
623
|
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc);
|
|
646
|
-
const { p1, p2 } =
|
|
624
|
+
const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2); // 30% faster vs wnaf.unsafe
|
|
647
625
|
return finishEndo(endo.beta, p1, p2, k1neg, k2neg);
|
|
648
626
|
}
|
|
649
627
|
else {
|
|
@@ -686,52 +664,20 @@ function weierstrassN(params, extraOpts = {}) {
|
|
|
686
664
|
return this.multiplyUnsafe(cofactor).is0();
|
|
687
665
|
}
|
|
688
666
|
toBytes(isCompressed = true) {
|
|
689
|
-
(
|
|
667
|
+
abool(isCompressed, 'isCompressed');
|
|
690
668
|
this.assertValidity();
|
|
691
669
|
return encodePoint(Point, this, isCompressed);
|
|
692
670
|
}
|
|
693
671
|
toHex(isCompressed = true) {
|
|
694
|
-
return
|
|
672
|
+
return bytesToHex(this.toBytes(isCompressed));
|
|
695
673
|
}
|
|
696
674
|
toString() {
|
|
697
675
|
return `<Point ${this.is0() ? 'ZERO' : this.toHex()}>`;
|
|
698
676
|
}
|
|
699
|
-
// TODO: remove
|
|
700
|
-
get px() {
|
|
701
|
-
return this.X;
|
|
702
|
-
}
|
|
703
|
-
get py() {
|
|
704
|
-
return this.X;
|
|
705
|
-
}
|
|
706
|
-
get pz() {
|
|
707
|
-
return this.Z;
|
|
708
|
-
}
|
|
709
|
-
toRawBytes(isCompressed = true) {
|
|
710
|
-
return this.toBytes(isCompressed);
|
|
711
|
-
}
|
|
712
|
-
_setWindowSize(windowSize) {
|
|
713
|
-
this.precompute(windowSize);
|
|
714
|
-
}
|
|
715
|
-
static normalizeZ(points) {
|
|
716
|
-
return (0, curve_ts_1.normalizeZ)(Point, points);
|
|
717
|
-
}
|
|
718
|
-
static msm(points, scalars) {
|
|
719
|
-
return (0, curve_ts_1.pippenger)(Point, Fn, points, scalars);
|
|
720
|
-
}
|
|
721
|
-
static fromPrivateKey(privateKey) {
|
|
722
|
-
return Point.BASE.multiply(_normFnElement(Fn, privateKey));
|
|
723
|
-
}
|
|
724
677
|
}
|
|
725
|
-
// base / generator point
|
|
726
|
-
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
|
727
|
-
// zero / infinity / identity point
|
|
728
|
-
Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); // 0, 1, 0
|
|
729
|
-
// math field
|
|
730
|
-
Point.Fp = Fp;
|
|
731
|
-
// scalar field
|
|
732
|
-
Point.Fn = Fn;
|
|
733
678
|
const bits = Fn.BITS;
|
|
734
|
-
const wnaf = new
|
|
679
|
+
const wnaf = new wNAF(Point, extraOpts.endo ? Math.ceil(bits / 2) : bits);
|
|
680
|
+
Point.BASE.precompute(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
735
681
|
return Point;
|
|
736
682
|
}
|
|
737
683
|
// Points start with byte 0x02 when y is even; otherwise 0x03
|
|
@@ -747,7 +693,7 @@ function pprefix(hasEvenY) {
|
|
|
747
693
|
* @param Z
|
|
748
694
|
* @returns
|
|
749
695
|
*/
|
|
750
|
-
function SWUFpSqrtRatio(Fp, Z) {
|
|
696
|
+
export function SWUFpSqrtRatio(Fp, Z) {
|
|
751
697
|
// Generic implementation
|
|
752
698
|
const q = Fp.ORDER;
|
|
753
699
|
let l = _0n;
|
|
@@ -820,8 +766,8 @@ function SWUFpSqrtRatio(Fp, Z) {
|
|
|
820
766
|
* Simplified Shallue-van de Woestijne-Ulas Method
|
|
821
767
|
* https://www.rfc-editor.org/rfc/rfc9380#section-6.6.2
|
|
822
768
|
*/
|
|
823
|
-
function mapToCurveSimpleSWU(Fp, opts) {
|
|
824
|
-
|
|
769
|
+
export function mapToCurveSimpleSWU(Fp, opts) {
|
|
770
|
+
validateField(Fp);
|
|
825
771
|
const { A, B, Z } = opts;
|
|
826
772
|
if (!Fp.isValid(A) || !Fp.isValid(B) || !Fp.isValid(Z))
|
|
827
773
|
throw new Error('mapToCurveSimpleSWU: invalid opts');
|
|
@@ -857,16 +803,16 @@ function mapToCurveSimpleSWU(Fp, opts) {
|
|
|
857
803
|
y = Fp.cmov(y, value, isValid); // 22. y = CMOV(y, y1, is_gx1_square)
|
|
858
804
|
const e1 = Fp.isOdd(u) === Fp.isOdd(y); // 23. e1 = sgn0(u) == sgn0(y)
|
|
859
805
|
y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
|
|
860
|
-
const tv4_inv =
|
|
806
|
+
const tv4_inv = FpInvertBatch(Fp, [tv4], true)[0];
|
|
861
807
|
x = Fp.mul(x, tv4_inv); // 25. x = x / tv4
|
|
862
808
|
return { x, y };
|
|
863
809
|
};
|
|
864
810
|
}
|
|
865
811
|
function getWLengths(Fp, Fn) {
|
|
866
812
|
return {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
813
|
+
secretKey: Fn.BYTES,
|
|
814
|
+
publicKey: 1 + Fp.BYTES,
|
|
815
|
+
publicKeyUncompressed: 1 + 2 * Fp.BYTES,
|
|
870
816
|
publicKeyHasPrefix: true,
|
|
871
817
|
signature: 2 * Fn.BYTES,
|
|
872
818
|
};
|
|
@@ -875,25 +821,26 @@ function getWLengths(Fp, Fn) {
|
|
|
875
821
|
* Sometimes users only need getPublicKey, getSharedSecret, and secret key handling.
|
|
876
822
|
* This helper ensures no signature functionality is present. Less code, smaller bundle size.
|
|
877
823
|
*/
|
|
878
|
-
function ecdh(Point, ecdhOpts = {}) {
|
|
824
|
+
export function ecdh(Point, ecdhOpts = {}) {
|
|
879
825
|
const { Fn } = Point;
|
|
880
|
-
const randomBytes_ = ecdhOpts.randomBytes ||
|
|
881
|
-
const lengths = Object.assign(getWLengths(Point.Fp, Fn), { seed:
|
|
826
|
+
const randomBytes_ = ecdhOpts.randomBytes || wcRandomBytes;
|
|
827
|
+
const lengths = Object.assign(getWLengths(Point.Fp, Fn), { seed: getMinHashLength(Fn.ORDER) });
|
|
882
828
|
function isValidSecretKey(secretKey) {
|
|
883
829
|
try {
|
|
884
|
-
|
|
830
|
+
const num = Fn.fromBytes(secretKey);
|
|
831
|
+
return Fn.isValidNot0(num);
|
|
885
832
|
}
|
|
886
833
|
catch (error) {
|
|
887
834
|
return false;
|
|
888
835
|
}
|
|
889
836
|
}
|
|
890
837
|
function isValidPublicKey(publicKey, isCompressed) {
|
|
891
|
-
const {
|
|
838
|
+
const { publicKey: comp, publicKeyUncompressed } = lengths;
|
|
892
839
|
try {
|
|
893
840
|
const l = publicKey.length;
|
|
894
841
|
if (isCompressed === true && l !== comp)
|
|
895
842
|
return false;
|
|
896
|
-
if (isCompressed === false && l !==
|
|
843
|
+
if (isCompressed === false && l !== publicKeyUncompressed)
|
|
897
844
|
return false;
|
|
898
845
|
return !!Point.fromBytes(publicKey);
|
|
899
846
|
}
|
|
@@ -906,7 +853,7 @@ function ecdh(Point, ecdhOpts = {}) {
|
|
|
906
853
|
* (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
|
|
907
854
|
*/
|
|
908
855
|
function randomSecretKey(seed = randomBytes_(lengths.seed)) {
|
|
909
|
-
return
|
|
856
|
+
return mapHashToField(abytes(seed, lengths.seed, 'seed'), Fn.ORDER);
|
|
910
857
|
}
|
|
911
858
|
/**
|
|
912
859
|
* Computes public key for a secret key. Checks for validity of the secret key.
|
|
@@ -914,7 +861,7 @@ function ecdh(Point, ecdhOpts = {}) {
|
|
|
914
861
|
* @returns Public key, full when isCompressed=false; short when isCompressed=true
|
|
915
862
|
*/
|
|
916
863
|
function getPublicKey(secretKey, isCompressed = true) {
|
|
917
|
-
return Point.BASE.multiply(
|
|
864
|
+
return Point.BASE.multiply(Fn.fromBytes(secretKey)).toBytes(isCompressed);
|
|
918
865
|
}
|
|
919
866
|
function keygen(seed) {
|
|
920
867
|
const secretKey = randomSecretKey(seed);
|
|
@@ -924,14 +871,13 @@ function ecdh(Point, ecdhOpts = {}) {
|
|
|
924
871
|
* Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
|
|
925
872
|
*/
|
|
926
873
|
function isProbPub(item) {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
if (Fn.allowedLengths || lengths.secret === lengths.public)
|
|
874
|
+
const { secretKey, publicKey, publicKeyUncompressed } = lengths;
|
|
875
|
+
if (!isBytes(item))
|
|
876
|
+
return undefined;
|
|
877
|
+
if (('_lengths' in Fn && Fn._lengths) || secretKey === publicKey)
|
|
932
878
|
return undefined;
|
|
933
|
-
const l = (
|
|
934
|
-
return l ===
|
|
879
|
+
const l = abytes(item, undefined, 'key').length;
|
|
880
|
+
return l === publicKey || l === publicKeyUncompressed;
|
|
935
881
|
}
|
|
936
882
|
/**
|
|
937
883
|
* ECDH (Elliptic Curve Diffie Hellman).
|
|
@@ -946,21 +892,14 @@ function ecdh(Point, ecdhOpts = {}) {
|
|
|
946
892
|
throw new Error('first arg must be private key');
|
|
947
893
|
if (isProbPub(publicKeyB) === false)
|
|
948
894
|
throw new Error('second arg must be public key');
|
|
949
|
-
const s =
|
|
950
|
-
const b = Point.
|
|
895
|
+
const s = Fn.fromBytes(secretKeyA);
|
|
896
|
+
const b = Point.fromBytes(publicKeyB); // checks for being on-curve
|
|
951
897
|
return b.multiply(s).toBytes(isCompressed);
|
|
952
898
|
}
|
|
953
899
|
const utils = {
|
|
954
900
|
isValidSecretKey,
|
|
955
901
|
isValidPublicKey,
|
|
956
902
|
randomSecretKey,
|
|
957
|
-
// TODO: remove
|
|
958
|
-
isValidPrivateKey: isValidSecretKey,
|
|
959
|
-
randomPrivateKey: randomSecretKey,
|
|
960
|
-
normPrivateKeyToScalar: (key) => _normFnElement(Fn, key),
|
|
961
|
-
precompute(windowSize = 8, point = Point.BASE) {
|
|
962
|
-
return point.precompute(windowSize, false);
|
|
963
|
-
},
|
|
964
903
|
};
|
|
965
904
|
return Object.freeze({ getPublicKey, getSharedSecret, keygen, Point, utils, lengths });
|
|
966
905
|
}
|
|
@@ -977,46 +916,53 @@ function ecdh(Point, ecdhOpts = {}) {
|
|
|
977
916
|
* const p256_Point = weierstrass(...);
|
|
978
917
|
* const p256_sha256 = ecdsa(p256_Point, sha256);
|
|
979
918
|
* const p256_sha224 = ecdsa(p256_Point, sha224);
|
|
919
|
+
* const p256_sha224_r = ecdsa(p256_Point, sha224, { randomBytes: (length) => { ... } });
|
|
980
920
|
* ```
|
|
981
921
|
*/
|
|
982
|
-
function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
983
|
-
|
|
984
|
-
|
|
922
|
+
export function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
923
|
+
ahash(hash);
|
|
924
|
+
_validateObject(ecdsaOpts, {}, {
|
|
985
925
|
hmac: 'function',
|
|
986
926
|
lowS: 'boolean',
|
|
987
927
|
randomBytes: 'function',
|
|
988
928
|
bits2int: 'function',
|
|
989
929
|
bits2int_modN: 'function',
|
|
990
930
|
});
|
|
991
|
-
|
|
992
|
-
const
|
|
993
|
-
|
|
931
|
+
ecdsaOpts = Object.assign({}, ecdsaOpts);
|
|
932
|
+
const randomBytes = ecdsaOpts.randomBytes || wcRandomBytes;
|
|
933
|
+
const hmac = ecdsaOpts.hmac ||
|
|
934
|
+
((key, ...msgs) => nobleHmac(hash, key, concatBytes(...msgs)));
|
|
994
935
|
const { Fp, Fn } = Point;
|
|
995
936
|
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
|
|
996
937
|
const { keygen, getPublicKey, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
|
|
997
938
|
const defaultSigOpts = {
|
|
998
|
-
prehash:
|
|
999
|
-
lowS: typeof ecdsaOpts.lowS === 'boolean' ? ecdsaOpts.lowS :
|
|
1000
|
-
format:
|
|
939
|
+
prehash: true,
|
|
940
|
+
lowS: typeof ecdsaOpts.lowS === 'boolean' ? ecdsaOpts.lowS : true,
|
|
941
|
+
format: 'compact',
|
|
1001
942
|
extraEntropy: false,
|
|
1002
943
|
};
|
|
1003
|
-
const defaultSigOpts_format = 'compact';
|
|
1004
944
|
function isBiggerThanHalfOrder(number) {
|
|
1005
945
|
const HALF = CURVE_ORDER >> _1n;
|
|
1006
946
|
return number > HALF;
|
|
1007
947
|
}
|
|
1008
|
-
function normalizeS(s) {
|
|
1009
|
-
return isBiggerThanHalfOrder(s) ? Fn.neg(s) : s;
|
|
1010
|
-
}
|
|
1011
948
|
function validateRS(title, num) {
|
|
1012
949
|
if (!Fn.isValidNot0(num))
|
|
1013
950
|
throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`);
|
|
1014
951
|
return num;
|
|
1015
952
|
}
|
|
953
|
+
function validateSigLength(bytes, format) {
|
|
954
|
+
validateSigFormat(format);
|
|
955
|
+
const size = lengths.signature;
|
|
956
|
+
const sizer = format === 'compact' ? size : format === 'recovered' ? size + 1 : undefined;
|
|
957
|
+
return abytes(bytes, sizer);
|
|
958
|
+
}
|
|
1016
959
|
/**
|
|
1017
960
|
* ECDSA signature with its (r, s) properties. Supports compact, recovered & DER representations.
|
|
1018
961
|
*/
|
|
1019
962
|
class Signature {
|
|
963
|
+
r;
|
|
964
|
+
s;
|
|
965
|
+
recovery;
|
|
1020
966
|
constructor(r, s, recovery) {
|
|
1021
967
|
this.r = validateRS('r', r); // r in [1..N-1];
|
|
1022
968
|
this.s = validateRS('s', s); // s in [1..N-1];
|
|
@@ -1024,33 +970,30 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1024
970
|
this.recovery = recovery;
|
|
1025
971
|
Object.freeze(this);
|
|
1026
972
|
}
|
|
1027
|
-
static fromBytes(bytes, format =
|
|
1028
|
-
|
|
1029
|
-
const size = lengths.signature;
|
|
973
|
+
static fromBytes(bytes, format = defaultSigOpts.format) {
|
|
974
|
+
validateSigLength(bytes, format);
|
|
1030
975
|
let recid;
|
|
1031
976
|
if (format === 'der') {
|
|
1032
|
-
const { r, s } =
|
|
977
|
+
const { r, s } = DER.toSig(abytes(bytes));
|
|
1033
978
|
return new Signature(r, s);
|
|
1034
979
|
}
|
|
1035
980
|
if (format === 'recovered') {
|
|
1036
|
-
(0, utils_ts_1._abytes2)(bytes, size + 1);
|
|
1037
981
|
recid = bytes[0];
|
|
1038
982
|
format = 'compact';
|
|
1039
983
|
bytes = bytes.subarray(1);
|
|
1040
984
|
}
|
|
1041
|
-
|
|
1042
|
-
const L = size / 2;
|
|
985
|
+
const L = lengths.signature / 2;
|
|
1043
986
|
const r = bytes.subarray(0, L);
|
|
1044
987
|
const s = bytes.subarray(L, L * 2);
|
|
1045
988
|
return new Signature(Fn.fromBytes(r), Fn.fromBytes(s), recid);
|
|
1046
989
|
}
|
|
1047
990
|
static fromHex(hex, format) {
|
|
1048
|
-
return this.fromBytes(
|
|
991
|
+
return this.fromBytes(hexToBytes(hex), format);
|
|
1049
992
|
}
|
|
1050
993
|
addRecoveryBit(recovery) {
|
|
1051
994
|
return new Signature(this.r, this.s, recovery);
|
|
1052
995
|
}
|
|
1053
|
-
recoverPublicKey(
|
|
996
|
+
recoverPublicKey(messageHash) {
|
|
1054
997
|
const FIELD_ORDER = Fp.ORDER;
|
|
1055
998
|
const { r, s, recovery: rec } = this;
|
|
1056
999
|
if (rec == null || ![0, 1, 2, 3].includes(rec))
|
|
@@ -1070,9 +1013,9 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1070
1013
|
if (!Fp.isValid(radj))
|
|
1071
1014
|
throw new Error('recovery id 2 or 3 invalid');
|
|
1072
1015
|
const x = Fp.toBytes(radj);
|
|
1073
|
-
const R = Point.fromBytes(
|
|
1016
|
+
const R = Point.fromBytes(concatBytes(pprefix((rec & 1) === 0), x));
|
|
1074
1017
|
const ir = Fn.inv(radj); // r^-1
|
|
1075
|
-
const h = bits2int_modN((
|
|
1018
|
+
const h = bits2int_modN(abytes(messageHash, undefined, 'msgHash')); // Truncate hash
|
|
1076
1019
|
const u1 = Fn.create(-h * ir); // -hr^-1
|
|
1077
1020
|
const u2 = Fn.create(s * ir); // sr^-1
|
|
1078
1021
|
// (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1). unsafe is fine: there is no private data.
|
|
@@ -1086,44 +1029,21 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1086
1029
|
hasHighS() {
|
|
1087
1030
|
return isBiggerThanHalfOrder(this.s);
|
|
1088
1031
|
}
|
|
1089
|
-
toBytes(format =
|
|
1032
|
+
toBytes(format = defaultSigOpts.format) {
|
|
1090
1033
|
validateSigFormat(format);
|
|
1091
1034
|
if (format === 'der')
|
|
1092
|
-
return
|
|
1035
|
+
return hexToBytes(DER.hexFromSig(this));
|
|
1093
1036
|
const r = Fn.toBytes(this.r);
|
|
1094
1037
|
const s = Fn.toBytes(this.s);
|
|
1095
1038
|
if (format === 'recovered') {
|
|
1096
1039
|
if (this.recovery == null)
|
|
1097
1040
|
throw new Error('recovery bit must be present');
|
|
1098
|
-
return
|
|
1041
|
+
return concatBytes(Uint8Array.of(this.recovery), r, s);
|
|
1099
1042
|
}
|
|
1100
|
-
return
|
|
1043
|
+
return concatBytes(r, s);
|
|
1101
1044
|
}
|
|
1102
1045
|
toHex(format) {
|
|
1103
|
-
return
|
|
1104
|
-
}
|
|
1105
|
-
// TODO: remove
|
|
1106
|
-
assertValidity() { }
|
|
1107
|
-
static fromCompact(hex) {
|
|
1108
|
-
return Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', hex), 'compact');
|
|
1109
|
-
}
|
|
1110
|
-
static fromDER(hex) {
|
|
1111
|
-
return Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', hex), 'der');
|
|
1112
|
-
}
|
|
1113
|
-
normalizeS() {
|
|
1114
|
-
return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this;
|
|
1115
|
-
}
|
|
1116
|
-
toDERRawBytes() {
|
|
1117
|
-
return this.toBytes('der');
|
|
1118
|
-
}
|
|
1119
|
-
toDERHex() {
|
|
1120
|
-
return (0, utils_ts_1.bytesToHex)(this.toBytes('der'));
|
|
1121
|
-
}
|
|
1122
|
-
toCompactRawBytes() {
|
|
1123
|
-
return this.toBytes('compact');
|
|
1124
|
-
}
|
|
1125
|
-
toCompactHex() {
|
|
1126
|
-
return (0, utils_ts_1.bytesToHex)(this.toBytes('compact'));
|
|
1046
|
+
return bytesToHex(this.toBytes(format));
|
|
1127
1047
|
}
|
|
1128
1048
|
}
|
|
1129
1049
|
// RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
|
|
@@ -1131,30 +1051,32 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1131
1051
|
// bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.
|
|
1132
1052
|
// int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
|
|
1133
1053
|
const bits2int = ecdsaOpts.bits2int ||
|
|
1134
|
-
function (bytes) {
|
|
1054
|
+
function bits2int_def(bytes) {
|
|
1135
1055
|
// Our custom check "just in case", for protection against DoS
|
|
1136
1056
|
if (bytes.length > 8192)
|
|
1137
1057
|
throw new Error('input is too large');
|
|
1138
1058
|
// For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
|
|
1139
1059
|
// for some cases, since bytes.length * 8 is not actual bitLength.
|
|
1140
|
-
const num =
|
|
1060
|
+
const num = bytesToNumberBE(bytes); // check for == u8 done here
|
|
1141
1061
|
const delta = bytes.length * 8 - fnBits; // truncate to nBitLength leftmost bits
|
|
1142
1062
|
return delta > 0 ? num >> BigInt(delta) : num;
|
|
1143
1063
|
};
|
|
1144
1064
|
const bits2int_modN = ecdsaOpts.bits2int_modN ||
|
|
1145
|
-
function (bytes) {
|
|
1065
|
+
function bits2int_modN_def(bytes) {
|
|
1146
1066
|
return Fn.create(bits2int(bytes)); // can't use bytesToNumberBE here
|
|
1147
1067
|
};
|
|
1148
|
-
//
|
|
1149
|
-
const ORDER_MASK =
|
|
1150
|
-
/**
|
|
1151
|
-
* Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
|
|
1152
|
-
*/
|
|
1068
|
+
// Pads output with zero as per spec
|
|
1069
|
+
const ORDER_MASK = bitMask(fnBits);
|
|
1070
|
+
/** Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`. */
|
|
1153
1071
|
function int2octets(num) {
|
|
1154
1072
|
// IMPORTANT: the check ensures working for case `Fn.BYTES != Fn.BITS * 8`
|
|
1155
|
-
|
|
1073
|
+
aInRange('num < 2^' + fnBits, num, _0n, ORDER_MASK);
|
|
1156
1074
|
return Fn.toBytes(num);
|
|
1157
1075
|
}
|
|
1076
|
+
function validateMsgAndHash(message, prehash) {
|
|
1077
|
+
abytes(message, undefined, 'message');
|
|
1078
|
+
return prehash ? abytes(hash(message), undefined, 'prehashed message') : message;
|
|
1079
|
+
}
|
|
1158
1080
|
/**
|
|
1159
1081
|
* Steps A, D of RFC6979 3.2.
|
|
1160
1082
|
* Creates RFC6979 seed; converts msg/privKey to numbers.
|
|
@@ -1164,28 +1086,25 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1164
1086
|
* this will be invalid at least for P521. Also it can be bigger for P224 + SHA256.
|
|
1165
1087
|
*/
|
|
1166
1088
|
function prepSig(message, privateKey, opts) {
|
|
1167
|
-
if (['recovered', 'canonical'].some((k) => k in opts))
|
|
1168
|
-
throw new Error('sign() legacy options not supported');
|
|
1169
1089
|
const { lowS, prehash, extraEntropy } = validateSigOpts(opts, defaultSigOpts);
|
|
1170
|
-
// RFC6979 3.2
|
|
1171
|
-
message = (0, utils_ts_1._abytes2)(message, undefined, 'message');
|
|
1172
|
-
if (prehash)
|
|
1173
|
-
message = (0, utils_ts_1._abytes2)(hash(message), undefined, 'prehashed message');
|
|
1090
|
+
message = validateMsgAndHash(message, prehash); // RFC6979 3.2 A: h1 = H(m)
|
|
1174
1091
|
// We can't later call bits2octets, since nested bits2int is broken for curves
|
|
1175
1092
|
// with fnBits % 8 !== 0. Because of that, we unwrap it here as int2octets call.
|
|
1176
1093
|
// const bits2octets = (bits) => int2octets(bits2int_modN(bits))
|
|
1177
1094
|
const h1int = bits2int_modN(message);
|
|
1178
|
-
const d =
|
|
1095
|
+
const d = Fn.fromBytes(privateKey); // validate secret key, convert to bigint
|
|
1096
|
+
if (!Fn.isValidNot0(d))
|
|
1097
|
+
throw new Error('invalid private key');
|
|
1179
1098
|
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
1180
1099
|
// extraEntropy. RFC6979 3.6: additional k' (optional).
|
|
1181
1100
|
if (extraEntropy != null && extraEntropy !== false) {
|
|
1182
1101
|
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
|
1183
1102
|
// gen random bytes OR pass as-is
|
|
1184
|
-
const e = extraEntropy === true ?
|
|
1185
|
-
seedArgs.push((
|
|
1103
|
+
const e = extraEntropy === true ? randomBytes(lengths.secretKey) : extraEntropy;
|
|
1104
|
+
seedArgs.push(abytes(e, undefined, 'extraEntropy')); // check for being bytes
|
|
1186
1105
|
}
|
|
1187
|
-
const seed =
|
|
1188
|
-
const m = h1int; //
|
|
1106
|
+
const seed = concatBytes(...seedArgs); // Step D of RFC6979 3.2
|
|
1107
|
+
const m = h1int; // no need to call bits2int second time here, it is inside truncateHash!
|
|
1189
1108
|
// Converts signature params into point w r/s, checks result for validity.
|
|
1190
1109
|
// To transform k => Signature:
|
|
1191
1110
|
// q = k⋅G
|
|
@@ -1197,7 +1116,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1197
1116
|
function k2sig(kBytes) {
|
|
1198
1117
|
// RFC 6979 Section 3.2, step 3: k = bits2int(T)
|
|
1199
1118
|
// Important: all mod() calls here must be done over N
|
|
1200
|
-
const k = bits2int(kBytes); //
|
|
1119
|
+
const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
|
|
1201
1120
|
if (!Fn.isValidNot0(k))
|
|
1202
1121
|
return; // Valid scalars (including k) must be in 1..N-1
|
|
1203
1122
|
const ik = Fn.inv(k); // k^-1 mod n
|
|
@@ -1211,7 +1130,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1211
1130
|
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)
|
|
1212
1131
|
let normS = s;
|
|
1213
1132
|
if (lowS && isBiggerThanHalfOrder(s)) {
|
|
1214
|
-
normS =
|
|
1133
|
+
normS = Fn.neg(s); // if lowS was passed, ensure s is always
|
|
1215
1134
|
recovery ^= 1; // // in the bottom half of N
|
|
1216
1135
|
}
|
|
1217
1136
|
return new Signature(r, normS, recovery); // use normS, not s
|
|
@@ -1230,14 +1149,11 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1230
1149
|
* ```
|
|
1231
1150
|
*/
|
|
1232
1151
|
function sign(message, secretKey, opts = {}) {
|
|
1233
|
-
message = (0, utils_ts_1.ensureBytes)('message', message);
|
|
1234
1152
|
const { seed, k2sig } = prepSig(message, secretKey, opts); // Steps A, D of RFC6979 3.2.
|
|
1235
|
-
const drbg =
|
|
1153
|
+
const drbg = createHmacDrbg(hash.outputLen, Fn.BYTES, hmac);
|
|
1236
1154
|
const sig = drbg(seed, k2sig); // Steps B, C, D, E, F, G
|
|
1237
|
-
return sig;
|
|
1155
|
+
return sig.toBytes(opts.format);
|
|
1238
1156
|
}
|
|
1239
|
-
// Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
1240
|
-
Point.BASE.precompute(8);
|
|
1241
1157
|
/**
|
|
1242
1158
|
* Verifies a signature against message and public key.
|
|
1243
1159
|
* Rejects lowS signatures by default: see {@link ECDSAVerifyOpts}.
|
|
@@ -1252,68 +1168,20 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1252
1168
|
* ```
|
|
1253
1169
|
*/
|
|
1254
1170
|
function verify(signature, message, publicKey, opts = {}) {
|
|
1255
|
-
const sg = signature;
|
|
1256
|
-
message = (0, utils_ts_1.ensureBytes)('msgHash', message);
|
|
1257
|
-
publicKey = (0, utils_ts_1.ensureBytes)('publicKey', publicKey);
|
|
1258
1171
|
const { lowS, prehash, format } = validateSigOpts(opts, defaultSigOpts);
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
if (
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
// Try to deduce format
|
|
1265
|
-
const isHex = typeof sg === 'string' || (0, utils_ts_1.isBytes)(sg);
|
|
1266
|
-
const isObj = !isHex &&
|
|
1267
|
-
sg !== null &&
|
|
1268
|
-
typeof sg === 'object' &&
|
|
1269
|
-
typeof sg.r === 'bigint' &&
|
|
1270
|
-
typeof sg.s === 'bigint';
|
|
1271
|
-
if (!isHex && !isObj)
|
|
1272
|
-
throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
|
|
1273
|
-
if (isObj) {
|
|
1274
|
-
_sig = new Signature(sg.r, sg.s);
|
|
1275
|
-
}
|
|
1276
|
-
else if (isHex) {
|
|
1277
|
-
// TODO: remove this malleable check
|
|
1278
|
-
// Signature can be represented in 2 ways: compact (2*Fn.BYTES) & DER (variable-length).
|
|
1279
|
-
// Since DER can also be 2*Fn.BYTES bytes, we check for it first.
|
|
1280
|
-
try {
|
|
1281
|
-
_sig = Signature.fromDER(sg);
|
|
1282
|
-
}
|
|
1283
|
-
catch (derError) {
|
|
1284
|
-
if (!(derError instanceof exports.DER.Err))
|
|
1285
|
-
throw derError;
|
|
1286
|
-
}
|
|
1287
|
-
if (!_sig) {
|
|
1288
|
-
try {
|
|
1289
|
-
_sig = Signature.fromCompact(sg);
|
|
1290
|
-
}
|
|
1291
|
-
catch (error) {
|
|
1292
|
-
return false;
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
else {
|
|
1298
|
-
if (format === 'compact' || format === 'der') {
|
|
1299
|
-
if (typeof sg !== 'string' && !(0, utils_ts_1.isBytes)(sg))
|
|
1300
|
-
throw new Error('"der" / "compact" format expects Uint8Array signature');
|
|
1301
|
-
_sig = Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', sg), format);
|
|
1302
|
-
}
|
|
1303
|
-
else {
|
|
1304
|
-
throw new Error('format must be "compact", "der" or "js"');
|
|
1305
|
-
}
|
|
1172
|
+
publicKey = abytes(publicKey, undefined, 'publicKey');
|
|
1173
|
+
message = validateMsgAndHash(message, prehash);
|
|
1174
|
+
if (!isBytes(signature)) {
|
|
1175
|
+
const end = signature instanceof Signature ? ', use sig.toBytes()' : '';
|
|
1176
|
+
throw new Error('verify expects Uint8Array signature' + end);
|
|
1306
1177
|
}
|
|
1307
|
-
|
|
1308
|
-
return false;
|
|
1178
|
+
validateSigLength(signature, format); // execute this twice because we want loud error
|
|
1309
1179
|
try {
|
|
1310
|
-
|
|
1311
|
-
|
|
1180
|
+
const sig = Signature.fromBytes(signature, format);
|
|
1181
|
+
const P = Point.fromBytes(publicKey);
|
|
1182
|
+
if (lowS && sig.hasHighS())
|
|
1312
1183
|
return false;
|
|
1313
|
-
|
|
1314
|
-
if (prehash)
|
|
1315
|
-
message = hash(message);
|
|
1316
|
-
const { r, s } = _sig;
|
|
1184
|
+
const { r, s } = sig;
|
|
1317
1185
|
const h = bits2int_modN(message); // mod n, not mod p
|
|
1318
1186
|
const is = Fn.inv(s); // s^-1 mod n
|
|
1319
1187
|
const u1 = Fn.create(h * is); // u1 = hs^-1 mod n
|
|
@@ -1329,11 +1197,8 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1329
1197
|
}
|
|
1330
1198
|
}
|
|
1331
1199
|
function recoverPublicKey(signature, message, opts = {}) {
|
|
1332
|
-
const
|
|
1333
|
-
|
|
1334
|
-
message = (0, utils_ts_1._abytes2)(message, undefined, 'message');
|
|
1335
|
-
if (prehash)
|
|
1336
|
-
message = (0, utils_ts_1._abytes2)(hash(message), undefined, 'prehashed message');
|
|
1200
|
+
const { prehash } = validateSigOpts(opts, defaultSigOpts);
|
|
1201
|
+
message = validateMsgAndHash(message, prehash);
|
|
1337
1202
|
return Signature.fromBytes(signature, 'recovered').recoverPublicKey(message).toBytes();
|
|
1338
1203
|
}
|
|
1339
1204
|
return Object.freeze({
|
|
@@ -1350,93 +1215,4 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
1350
1215
|
hash,
|
|
1351
1216
|
});
|
|
1352
1217
|
}
|
|
1353
|
-
/** @deprecated use `weierstrass` in newer releases */
|
|
1354
|
-
function weierstrassPoints(c) {
|
|
1355
|
-
const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
|
|
1356
|
-
const Point = weierstrassN(CURVE, curveOpts);
|
|
1357
|
-
return _weierstrass_new_output_to_legacy(c, Point);
|
|
1358
|
-
}
|
|
1359
|
-
function _weierstrass_legacy_opts_to_new(c) {
|
|
1360
|
-
const CURVE = {
|
|
1361
|
-
a: c.a,
|
|
1362
|
-
b: c.b,
|
|
1363
|
-
p: c.Fp.ORDER,
|
|
1364
|
-
n: c.n,
|
|
1365
|
-
h: c.h,
|
|
1366
|
-
Gx: c.Gx,
|
|
1367
|
-
Gy: c.Gy,
|
|
1368
|
-
};
|
|
1369
|
-
const Fp = c.Fp;
|
|
1370
|
-
let allowedLengths = c.allowedPrivateKeyLengths
|
|
1371
|
-
? Array.from(new Set(c.allowedPrivateKeyLengths.map((l) => Math.ceil(l / 2))))
|
|
1372
|
-
: undefined;
|
|
1373
|
-
const Fn = (0, modular_ts_1.Field)(CURVE.n, {
|
|
1374
|
-
BITS: c.nBitLength,
|
|
1375
|
-
allowedLengths: allowedLengths,
|
|
1376
|
-
modFromBytes: c.wrapPrivateKey,
|
|
1377
|
-
});
|
|
1378
|
-
const curveOpts = {
|
|
1379
|
-
Fp,
|
|
1380
|
-
Fn,
|
|
1381
|
-
allowInfinityPoint: c.allowInfinityPoint,
|
|
1382
|
-
endo: c.endo,
|
|
1383
|
-
isTorsionFree: c.isTorsionFree,
|
|
1384
|
-
clearCofactor: c.clearCofactor,
|
|
1385
|
-
fromBytes: c.fromBytes,
|
|
1386
|
-
toBytes: c.toBytes,
|
|
1387
|
-
};
|
|
1388
|
-
return { CURVE, curveOpts };
|
|
1389
|
-
}
|
|
1390
|
-
function _ecdsa_legacy_opts_to_new(c) {
|
|
1391
|
-
const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
|
|
1392
|
-
const ecdsaOpts = {
|
|
1393
|
-
hmac: c.hmac,
|
|
1394
|
-
randomBytes: c.randomBytes,
|
|
1395
|
-
lowS: c.lowS,
|
|
1396
|
-
bits2int: c.bits2int,
|
|
1397
|
-
bits2int_modN: c.bits2int_modN,
|
|
1398
|
-
};
|
|
1399
|
-
return { CURVE, curveOpts, hash: c.hash, ecdsaOpts };
|
|
1400
|
-
}
|
|
1401
|
-
function _legacyHelperEquat(Fp, a, b) {
|
|
1402
|
-
/**
|
|
1403
|
-
* y² = x³ + ax + b: Short weierstrass curve formula. Takes x, returns y².
|
|
1404
|
-
* @returns y²
|
|
1405
|
-
*/
|
|
1406
|
-
function weierstrassEquation(x) {
|
|
1407
|
-
const x2 = Fp.sqr(x); // x * x
|
|
1408
|
-
const x3 = Fp.mul(x2, x); // x² * x
|
|
1409
|
-
return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x³ + a * x + b
|
|
1410
|
-
}
|
|
1411
|
-
return weierstrassEquation;
|
|
1412
|
-
}
|
|
1413
|
-
function _weierstrass_new_output_to_legacy(c, Point) {
|
|
1414
|
-
const { Fp, Fn } = Point;
|
|
1415
|
-
function isWithinCurveOrder(num) {
|
|
1416
|
-
return (0, utils_ts_1.inRange)(num, _1n, Fn.ORDER);
|
|
1417
|
-
}
|
|
1418
|
-
const weierstrassEquation = _legacyHelperEquat(Fp, c.a, c.b);
|
|
1419
|
-
return Object.assign({}, {
|
|
1420
|
-
CURVE: c,
|
|
1421
|
-
Point: Point,
|
|
1422
|
-
ProjectivePoint: Point,
|
|
1423
|
-
normPrivateKeyToScalar: (key) => _normFnElement(Fn, key),
|
|
1424
|
-
weierstrassEquation,
|
|
1425
|
-
isWithinCurveOrder,
|
|
1426
|
-
});
|
|
1427
|
-
}
|
|
1428
|
-
function _ecdsa_new_output_to_legacy(c, _ecdsa) {
|
|
1429
|
-
const Point = _ecdsa.Point;
|
|
1430
|
-
return Object.assign({}, _ecdsa, {
|
|
1431
|
-
ProjectivePoint: Point,
|
|
1432
|
-
CURVE: Object.assign({}, c, (0, modular_ts_1.nLength)(Point.Fn.ORDER, Point.Fn.BITS)),
|
|
1433
|
-
});
|
|
1434
|
-
}
|
|
1435
|
-
// _ecdsa_legacy
|
|
1436
|
-
function weierstrass(c) {
|
|
1437
|
-
const { CURVE, curveOpts, hash, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
|
|
1438
|
-
const Point = weierstrassN(CURVE, curveOpts);
|
|
1439
|
-
const signs = ecdsa(Point, hash, ecdsaOpts);
|
|
1440
|
-
return _ecdsa_new_output_to_legacy(c, signs);
|
|
1441
|
-
}
|
|
1442
1218
|
//# sourceMappingURL=weierstrass.js.map
|