@noble/curves 0.6.0 → 0.6.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 +83 -53
- package/lib/_shortw_utils.d.ts +3 -3
- package/lib/abstract/curve.d.ts +3 -4
- package/lib/abstract/curve.js +13 -19
- package/lib/abstract/edwards.d.ts +5 -5
- package/lib/abstract/edwards.js +20 -25
- package/lib/abstract/hash-to-curve.js +1 -1
- package/lib/abstract/modular.d.ts +1 -1
- package/lib/abstract/modular.js +11 -13
- package/lib/abstract/montgomery.js +20 -64
- package/lib/abstract/utils.d.ts +4 -1
- package/lib/abstract/utils.js +48 -26
- package/lib/abstract/weierstrass.d.ts +10 -10
- package/lib/abstract/weierstrass.js +58 -79
- package/lib/esm/abstract/curve.js +11 -17
- package/lib/esm/abstract/edwards.js +22 -27
- package/lib/esm/abstract/hash-to-curve.js +1 -1
- package/lib/esm/abstract/modular.js +12 -14
- package/lib/esm/abstract/montgomery.js +21 -65
- package/lib/esm/abstract/poseidon.js +1 -1
- package/lib/esm/abstract/utils.js +46 -25
- package/lib/esm/abstract/weierstrass.js +59 -80
- package/lib/esm/p224.js +1 -1
- package/lib/esm/p521.js +1 -13
- package/lib/esm/secp256k1.js +34 -36
- package/lib/esm/stark.js +1 -1
- package/lib/p192.d.ts +6 -6
- package/lib/p224.d.ts +6 -6
- package/lib/p224.js +1 -1
- package/lib/p256.d.ts +6 -6
- package/lib/p384.d.ts +6 -6
- package/lib/p521.d.ts +16 -17
- package/lib/p521.js +1 -13
- package/lib/secp256k1.d.ts +17 -14
- package/lib/secp256k1.js +28 -30
- package/lib/stark.d.ts +3 -3
- package/lib/stark.js +1 -1
- package/package.json +4 -4
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
import { mod, pow } from './modular.js';
|
|
3
|
-
import { ensureBytes, numberToBytesLE,
|
|
3
|
+
import { bytesToNumberLE, ensureBytes, numberToBytesLE, validateObject } from './utils.js';
|
|
4
4
|
const _0n = BigInt(0);
|
|
5
5
|
const _1n = BigInt(1);
|
|
6
6
|
function validateOpts(curve) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
for (const fn of ['adjustScalarBytes', 'domain', 'powPminus2']) {
|
|
18
|
-
if (curve[fn] === undefined)
|
|
19
|
-
continue; // Optional
|
|
20
|
-
if (typeof curve[fn] !== 'function')
|
|
21
|
-
throw new Error(`Invalid ${fn} function`);
|
|
22
|
-
}
|
|
23
|
-
for (const i of ['Gu']) {
|
|
24
|
-
if (curve[i] === undefined)
|
|
25
|
-
continue; // Optional
|
|
26
|
-
if (typeof curve[i] !== 'string')
|
|
27
|
-
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
|
|
28
|
-
}
|
|
7
|
+
validateObject(curve, {
|
|
8
|
+
a24: 'bigint',
|
|
9
|
+
}, {
|
|
10
|
+
montgomeryBits: 'isSafeInteger',
|
|
11
|
+
nByteLength: 'isSafeInteger',
|
|
12
|
+
adjustScalarBytes: 'function',
|
|
13
|
+
domain: 'function',
|
|
14
|
+
powPminus2: 'function',
|
|
15
|
+
Gu: 'string',
|
|
16
|
+
});
|
|
29
17
|
// Set defaults
|
|
30
18
|
return Object.freeze({ ...curve });
|
|
31
19
|
}
|
|
@@ -40,31 +28,7 @@ export function montgomery(curveDef) {
|
|
|
40
28
|
const fieldLen = CURVE.nByteLength;
|
|
41
29
|
const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes);
|
|
42
30
|
const powPminus2 = CURVE.powPminus2 || ((x) => pow(x, P - BigInt(2), P));
|
|
43
|
-
|
|
44
|
-
* Checks for num to be in range:
|
|
45
|
-
* For strict == true: `0 < num < max`.
|
|
46
|
-
* For strict == false: `0 <= num < max`.
|
|
47
|
-
* Converts non-float safe numbers to bigints.
|
|
48
|
-
*/
|
|
49
|
-
function normalizeScalar(num, max, strict = true) {
|
|
50
|
-
if (!max)
|
|
51
|
-
throw new TypeError('Specify max value');
|
|
52
|
-
if (typeof num === 'number' && Number.isSafeInteger(num))
|
|
53
|
-
num = BigInt(num);
|
|
54
|
-
if (typeof num === 'bigint' && num < max) {
|
|
55
|
-
if (strict) {
|
|
56
|
-
if (_0n < num)
|
|
57
|
-
return num;
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
if (_0n <= num)
|
|
61
|
-
return num;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
throw new TypeError('Expected valid scalar: 0 < scalar < max');
|
|
65
|
-
}
|
|
66
|
-
// cswap from RFC7748
|
|
67
|
-
// NOTE: cswap is not from RFC7748!
|
|
31
|
+
// cswap from RFC7748. But it is not from RFC7748!
|
|
68
32
|
/*
|
|
69
33
|
cswap(swap, x_2, x_3):
|
|
70
34
|
dummy = mask(swap) AND (x_2 XOR x_3)
|
|
@@ -80,6 +44,11 @@ export function montgomery(curveDef) {
|
|
|
80
44
|
x_3 = modP(x_3 + dummy);
|
|
81
45
|
return [x_2, x_3];
|
|
82
46
|
}
|
|
47
|
+
function assertFieldElement(n) {
|
|
48
|
+
if (typeof n === 'bigint' && _0n <= n && n < P)
|
|
49
|
+
return n;
|
|
50
|
+
throw new Error('Expected valid scalar 0 < scalar < CURVE.P');
|
|
51
|
+
}
|
|
83
52
|
// x25519 from 4
|
|
84
53
|
/**
|
|
85
54
|
*
|
|
@@ -88,11 +57,10 @@ export function montgomery(curveDef) {
|
|
|
88
57
|
* @returns new Point on Montgomery curve
|
|
89
58
|
*/
|
|
90
59
|
function montgomeryLadder(pointU, scalar) {
|
|
91
|
-
const
|
|
92
|
-
const u = normalizeScalar(pointU, P);
|
|
60
|
+
const u = assertFieldElement(pointU);
|
|
93
61
|
// Section 5: Implementations MUST accept non-canonical values and process them as
|
|
94
62
|
// if they had been reduced modulo the field prime.
|
|
95
|
-
const k =
|
|
63
|
+
const k = assertFieldElement(scalar);
|
|
96
64
|
// The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519
|
|
97
65
|
const a24 = CURVE.a24;
|
|
98
66
|
const x_1 = u;
|
|
@@ -145,11 +113,11 @@ export function montgomery(curveDef) {
|
|
|
145
113
|
return numberToBytesLE(modP(u), montgomeryBytes);
|
|
146
114
|
}
|
|
147
115
|
function decodeUCoordinate(uEnc) {
|
|
148
|
-
const u = ensureBytes(uEnc, montgomeryBytes);
|
|
149
116
|
// Section 5: When receiving such an array, implementations of X25519
|
|
150
117
|
// MUST mask the most significant bit in the final byte.
|
|
151
118
|
// This is very ugly way, but it works because fieldLen-1 is outside of bounds for X448, so this becomes NOOP
|
|
152
119
|
// fieldLen - scalaryBytes = 1 for X448 and = 0 for X25519
|
|
120
|
+
const u = ensureBytes(uEnc, montgomeryBytes);
|
|
153
121
|
u[fieldLen - 1] &= 127; // 0b0111_1111
|
|
154
122
|
return bytesToNumberLE(u);
|
|
155
123
|
}
|
|
@@ -159,13 +127,6 @@ export function montgomery(curveDef) {
|
|
|
159
127
|
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${bytes.length}`);
|
|
160
128
|
return bytesToNumberLE(adjustScalarBytes(bytes));
|
|
161
129
|
}
|
|
162
|
-
/**
|
|
163
|
-
* Computes shared secret between private key "scalar" and public key's "u" (x) coordinate.
|
|
164
|
-
* We can get 'y' coordinate from 'u',
|
|
165
|
-
* but Point.fromHex also wants 'x' coordinate oddity flag,
|
|
166
|
-
* and we cannot get 'x' without knowing 'v'.
|
|
167
|
-
* Need to add generic conversion between twisted edwards and complimentary curve for JubJub.
|
|
168
|
-
*/
|
|
169
130
|
function scalarMult(scalar, u) {
|
|
170
131
|
const pointU = decodeUCoordinate(u);
|
|
171
132
|
const _scalar = decodeScalar(scalar);
|
|
@@ -176,12 +137,7 @@ export function montgomery(curveDef) {
|
|
|
176
137
|
throw new Error('Invalid private or public key received');
|
|
177
138
|
return encodeUCoordinate(pu);
|
|
178
139
|
}
|
|
179
|
-
|
|
180
|
-
* Computes public key from private.
|
|
181
|
-
* Executes scalar multiplication of curve's base point by scalar.
|
|
182
|
-
* @param scalar private key
|
|
183
|
-
* @returns new public key
|
|
184
|
-
*/
|
|
140
|
+
// Computes public key from private. By doing scalar multiplication of base point.
|
|
185
141
|
function scalarMultBase(scalar) {
|
|
186
142
|
return scalarMult(scalar, CURVE.Gu);
|
|
187
143
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
// Poseidon Hash: https://eprint.iacr.org/2019/458.pdf, https://www.poseidon-hash.info
|
|
3
|
-
import {
|
|
3
|
+
import { FpPow, validateField } from './modular.js';
|
|
4
4
|
export function validateOpts(opts) {
|
|
5
5
|
const { Fp } = opts;
|
|
6
6
|
validateField(Fp);
|
|
@@ -6,7 +6,7 @@ const u8a = (a) => a instanceof Uint8Array;
|
|
|
6
6
|
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
|
|
7
7
|
export function bytesToHex(bytes) {
|
|
8
8
|
if (!u8a(bytes))
|
|
9
|
-
throw new Error('
|
|
9
|
+
throw new Error('Uint8Array expected');
|
|
10
10
|
// pre-caching improves the speed 6x
|
|
11
11
|
let hex = '';
|
|
12
12
|
for (let i = 0; i < bytes.length; i++) {
|
|
@@ -20,23 +20,23 @@ export function numberToHexUnpadded(num) {
|
|
|
20
20
|
}
|
|
21
21
|
export function hexToNumber(hex) {
|
|
22
22
|
if (typeof hex !== 'string')
|
|
23
|
-
throw new Error('
|
|
23
|
+
throw new Error('string expected, got ' + typeof hex);
|
|
24
24
|
// Big Endian
|
|
25
25
|
return BigInt(`0x${hex}`);
|
|
26
26
|
}
|
|
27
27
|
// Caching slows it down 2-3x
|
|
28
28
|
export function hexToBytes(hex) {
|
|
29
29
|
if (typeof hex !== 'string')
|
|
30
|
-
throw new Error('
|
|
30
|
+
throw new Error('string expected, got ' + typeof hex);
|
|
31
31
|
if (hex.length % 2)
|
|
32
|
-
throw new Error('
|
|
32
|
+
throw new Error('hex string is invalid: unpadded ' + hex.length);
|
|
33
33
|
const array = new Uint8Array(hex.length / 2);
|
|
34
34
|
for (let i = 0; i < array.length; i++) {
|
|
35
35
|
const j = i * 2;
|
|
36
36
|
const hexByte = hex.slice(j, j + 2);
|
|
37
37
|
const byte = Number.parseInt(hexByte, 16);
|
|
38
38
|
if (Number.isNaN(byte) || byte < 0)
|
|
39
|
-
throw new Error('
|
|
39
|
+
throw new Error('invalid byte sequence');
|
|
40
40
|
array[i] = byte;
|
|
41
41
|
}
|
|
42
42
|
return array;
|
|
@@ -47,18 +47,13 @@ export function bytesToNumberBE(bytes) {
|
|
|
47
47
|
}
|
|
48
48
|
export function bytesToNumberLE(bytes) {
|
|
49
49
|
if (!u8a(bytes))
|
|
50
|
-
throw new Error('
|
|
50
|
+
throw new Error('Uint8Array expected');
|
|
51
51
|
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
|
|
52
52
|
}
|
|
53
53
|
export const numberToBytesBE = (n, len) => hexToBytes(n.toString(16).padStart(len * 2, '0'));
|
|
54
54
|
export const numberToBytesLE = (n, len) => numberToBytesBE(n, len).reverse();
|
|
55
55
|
// Returns variable number bytes (minimal bigint encoding?)
|
|
56
|
-
export const numberToVarBytesBE = (n) =>
|
|
57
|
-
let hex = n.toString(16);
|
|
58
|
-
if (hex.length & 1)
|
|
59
|
-
hex = '0' + hex;
|
|
60
|
-
return hexToBytes(hex);
|
|
61
|
-
};
|
|
56
|
+
export const numberToVarBytesBE = (n) => hexToBytes(numberToHexUnpadded(n));
|
|
62
57
|
export function ensureBytes(hex, expectedLength) {
|
|
63
58
|
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
|
64
59
|
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
|
@@ -68,19 +63,16 @@ export function ensureBytes(hex, expectedLength) {
|
|
|
68
63
|
return bytes;
|
|
69
64
|
}
|
|
70
65
|
// Copies several Uint8Arrays into one.
|
|
71
|
-
export function concatBytes(...
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
pad += arr.length;
|
|
82
|
-
}
|
|
83
|
-
return result;
|
|
66
|
+
export function concatBytes(...arrs) {
|
|
67
|
+
const r = new Uint8Array(arrs.reduce((sum, a) => sum + a.length, 0));
|
|
68
|
+
let pad = 0; // walk through each item, ensure they have proper type
|
|
69
|
+
arrs.forEach((a) => {
|
|
70
|
+
if (!u8a(a))
|
|
71
|
+
throw new Error('Uint8Array expected');
|
|
72
|
+
r.set(a, pad);
|
|
73
|
+
pad += a.length;
|
|
74
|
+
});
|
|
75
|
+
return r;
|
|
84
76
|
}
|
|
85
77
|
export function equalBytes(b1, b2) {
|
|
86
78
|
// We don't care about timing attacks here
|
|
@@ -107,3 +99,32 @@ export const bitSet = (n, pos, value) => n | ((value ? _1n : _0n) << BigInt(pos)
|
|
|
107
99
|
// Return mask for N bits (Same as BigInt(`0b${Array(i).fill('1').join('')}`))
|
|
108
100
|
// Not using ** operator with bigints for old engines.
|
|
109
101
|
export const bitMask = (n) => (_2n << BigInt(n - 1)) - _1n;
|
|
102
|
+
export function validateObject(object, validators, optValidators = {}) {
|
|
103
|
+
const validatorFns = {
|
|
104
|
+
bigint: (val) => typeof val === 'bigint',
|
|
105
|
+
function: (val) => typeof val === 'function',
|
|
106
|
+
boolean: (val) => typeof val === 'boolean',
|
|
107
|
+
string: (val) => typeof val === 'string',
|
|
108
|
+
isSafeInteger: (val) => Number.isSafeInteger(val),
|
|
109
|
+
array: (val) => Array.isArray(val),
|
|
110
|
+
field: (val) => object.Fp.isValid(val),
|
|
111
|
+
hash: (val) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
|
|
112
|
+
};
|
|
113
|
+
// type Key = keyof typeof validators;
|
|
114
|
+
const checkField = (fieldName, type, isOptional) => {
|
|
115
|
+
const checkVal = validatorFns[type];
|
|
116
|
+
if (typeof checkVal !== 'function')
|
|
117
|
+
throw new Error(`Invalid validator "${type}", expected function`);
|
|
118
|
+
const val = object[fieldName];
|
|
119
|
+
if (isOptional && val === undefined)
|
|
120
|
+
return;
|
|
121
|
+
if (!checkVal(val)) {
|
|
122
|
+
throw new Error(`Invalid param ${fieldName}=${val} (${typeof val}), expected ${type}`);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
for (let [fieldName, type] of Object.entries(validators))
|
|
126
|
+
checkField(fieldName, type, false);
|
|
127
|
+
for (let [fieldName, type] of Object.entries(optValidators))
|
|
128
|
+
checkField(fieldName, type, true);
|
|
129
|
+
return object;
|
|
130
|
+
}
|
|
@@ -3,23 +3,23 @@
|
|
|
3
3
|
import * as mod from './modular.js';
|
|
4
4
|
import * as ut from './utils.js';
|
|
5
5
|
import { ensureBytes } from './utils.js';
|
|
6
|
-
import { wNAF,
|
|
6
|
+
import { wNAF, validateBasic } from './curve.js';
|
|
7
7
|
function validatePointOpts(curve) {
|
|
8
|
-
const opts =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
const endo = opts
|
|
8
|
+
const opts = validateBasic(curve);
|
|
9
|
+
ut.validateObject(opts, {
|
|
10
|
+
a: 'field',
|
|
11
|
+
b: 'field',
|
|
12
|
+
fromBytes: 'function',
|
|
13
|
+
toBytes: 'function',
|
|
14
|
+
}, {
|
|
15
|
+
allowedPrivateKeyLengths: 'array',
|
|
16
|
+
wrapPrivateKey: 'boolean',
|
|
17
|
+
isTorsionFree: 'function',
|
|
18
|
+
clearCofactor: 'function',
|
|
19
|
+
});
|
|
20
|
+
const { endo, Fp, a } = opts;
|
|
21
21
|
if (endo) {
|
|
22
|
-
if (!Fp.eql(
|
|
22
|
+
if (!Fp.eql(a, Fp.ZERO)) {
|
|
23
23
|
throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
|
|
24
24
|
}
|
|
25
25
|
if (typeof endo !== 'object' ||
|
|
@@ -28,11 +28,6 @@ function validatePointOpts(curve) {
|
|
|
28
28
|
throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
if (typeof opts.fromBytes !== 'function')
|
|
32
|
-
throw new Error('Invalid fromBytes function');
|
|
33
|
-
if (typeof opts.toBytes !== 'function')
|
|
34
|
-
throw new Error('Invalid fromBytes function');
|
|
35
|
-
// Set defaults
|
|
36
31
|
return Object.freeze({ ...opts });
|
|
37
32
|
}
|
|
38
33
|
// ASN.1 DER encoding utilities
|
|
@@ -113,39 +108,28 @@ export function weierstrassPoints(opts) {
|
|
|
113
108
|
if (!isWithinCurveOrder(num))
|
|
114
109
|
throw new Error('Expected valid bigint: 0 < bigint < curve.n');
|
|
115
110
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
* Supports two options, that are passed when CURVE is initialized:
|
|
119
|
-
* - `normalizePrivateKey()` executed before all checks
|
|
120
|
-
* - `wrapPrivateKey` when true, executed after most checks, but before `0 < key < n`
|
|
121
|
-
*/
|
|
111
|
+
// Validates if priv key is valid and converts it to bigint.
|
|
112
|
+
// Supports options CURVE.normalizePrivateKey and CURVE.wrapPrivateKey.
|
|
122
113
|
function normalizePrivateKey(key) {
|
|
123
|
-
const {
|
|
124
|
-
if (typeof
|
|
125
|
-
key
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
114
|
+
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
|
|
115
|
+
if (lengths && typeof key !== 'bigint') {
|
|
116
|
+
if (key instanceof Uint8Array)
|
|
117
|
+
key = ut.bytesToHex(key);
|
|
118
|
+
// Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
|
|
119
|
+
if (typeof key !== 'string' || !lengths.includes(key.length))
|
|
120
|
+
throw new Error('Invalid key');
|
|
121
|
+
key = key.padStart(nByteLength * 2, '0');
|
|
130
122
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// Validates individual octets
|
|
135
|
-
num = ut.bytesToNumberBE(ensureBytes(key));
|
|
136
|
-
}
|
|
137
|
-
else if (key instanceof Uint8Array) {
|
|
138
|
-
if (key.length !== groupLen)
|
|
139
|
-
throw new Error(`must be ${groupLen} bytes`);
|
|
140
|
-
num = ut.bytesToNumberBE(key);
|
|
123
|
+
let num;
|
|
124
|
+
try {
|
|
125
|
+
num = typeof key === 'bigint' ? key : ut.bytesToNumberBE(ensureBytes(key, nByteLength));
|
|
141
126
|
}
|
|
142
|
-
|
|
143
|
-
throw new Error(
|
|
127
|
+
catch (error) {
|
|
128
|
+
throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
|
|
144
129
|
}
|
|
145
|
-
// Useful for curves with cofactor != 1
|
|
146
130
|
if (wrapPrivateKey)
|
|
147
|
-
num = mod.mod(num, n);
|
|
148
|
-
assertGE(num);
|
|
131
|
+
num = mod.mod(num, n); // disabled by default, enabled for BLS
|
|
132
|
+
assertGE(num); // num in range [1..N-1]
|
|
149
133
|
return num;
|
|
150
134
|
}
|
|
151
135
|
const pointPrecomputes = new Map();
|
|
@@ -499,14 +483,16 @@ export function weierstrassPoints(opts) {
|
|
|
499
483
|
};
|
|
500
484
|
}
|
|
501
485
|
function validateOpts(curve) {
|
|
502
|
-
const opts =
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
486
|
+
const opts = validateBasic(curve);
|
|
487
|
+
ut.validateObject(opts, {
|
|
488
|
+
hash: 'hash',
|
|
489
|
+
hmac: 'function',
|
|
490
|
+
randomBytes: 'function',
|
|
491
|
+
}, {
|
|
492
|
+
bits2int: 'function',
|
|
493
|
+
bits2int_modN: 'function',
|
|
494
|
+
lowS: 'boolean',
|
|
495
|
+
});
|
|
510
496
|
return Object.freeze({ lowS: true, ...opts });
|
|
511
497
|
}
|
|
512
498
|
const u8n = (data) => new Uint8Array(data); // creates Uint8Array
|
|
@@ -615,7 +601,7 @@ export function weierstrass(curveDef) {
|
|
|
615
601
|
return { x, y };
|
|
616
602
|
}
|
|
617
603
|
else {
|
|
618
|
-
throw new Error(`Point
|
|
604
|
+
throw new Error(`Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`);
|
|
619
605
|
}
|
|
620
606
|
},
|
|
621
607
|
});
|
|
@@ -677,7 +663,7 @@ export function weierstrass(curveDef) {
|
|
|
677
663
|
const ir = invN(radj); // r^-1
|
|
678
664
|
const u1 = modN(-h * ir); // -hr^-1
|
|
679
665
|
const u2 = modN(s * ir); // sr^-1
|
|
680
|
-
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); //
|
|
666
|
+
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
|
|
681
667
|
if (!Q)
|
|
682
668
|
throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
|
|
683
669
|
Q.assertValidity();
|
|
@@ -800,9 +786,10 @@ export function weierstrass(curveDef) {
|
|
|
800
786
|
const ORDER_MASK = ut.bitMask(CURVE.nBitLength);
|
|
801
787
|
function int2octets(num) {
|
|
802
788
|
if (typeof num !== 'bigint')
|
|
803
|
-
throw new Error('
|
|
789
|
+
throw new Error('bigint expected');
|
|
804
790
|
if (!(_0n <= num && num < ORDER_MASK))
|
|
805
|
-
|
|
791
|
+
// n in [0..ORDER_MASK-1]
|
|
792
|
+
throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
|
|
806
793
|
// works with order, can have different size than numToField!
|
|
807
794
|
return ut.numberToBytesBE(num, CURVE.nByteLength);
|
|
808
795
|
}
|
|
@@ -812,6 +799,7 @@ export function weierstrass(curveDef) {
|
|
|
812
799
|
// NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.
|
|
813
800
|
// Also it can be bigger for P224 + SHA256
|
|
814
801
|
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
|
|
802
|
+
const { hash, randomBytes } = CURVE;
|
|
815
803
|
if (msgHash == null)
|
|
816
804
|
throw new Error(`sign: expected valid message hash, not "${msgHash}"`);
|
|
817
805
|
if (['recovered', 'canonical'].some((k) => k in opts))
|
|
@@ -819,28 +807,20 @@ export function weierstrass(curveDef) {
|
|
|
819
807
|
throw new Error('sign() legacy options not supported');
|
|
820
808
|
let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
|
|
821
809
|
if (prehash)
|
|
822
|
-
msgHash =
|
|
810
|
+
msgHash = hash(ensureBytes(msgHash));
|
|
823
811
|
if (lowS == null)
|
|
824
|
-
lowS = true; // RFC6979 3.2: we skip step A, because
|
|
825
|
-
//
|
|
826
|
-
//
|
|
827
|
-
//
|
|
828
|
-
// However, we cannot later call bits2octets (which is truncateHash + int2octets), since nested bits2int is broken
|
|
829
|
-
// for curves where nBitLength % 8 !== 0, so we unwrap it here as int2octets call.
|
|
830
|
-
// const bits2octets = (bits)=>int2octets(bytesToNumberBE(truncateHash(bits)))
|
|
812
|
+
lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
|
|
813
|
+
// We can't later call bits2octets, since nested bits2int is broken for curves
|
|
814
|
+
// with nBitLength % 8 !== 0. Because of that, we unwrap it here as int2octets call.
|
|
815
|
+
// const bits2octets = (bits) => int2octets(bits2int_modN(bits))
|
|
831
816
|
const h1int = bits2int_modN(ensureBytes(msgHash));
|
|
832
|
-
const
|
|
833
|
-
const
|
|
834
|
-
//
|
|
835
|
-
const seedArgs = [int2octets(d), h1octets];
|
|
817
|
+
const d = normalizePrivateKey(privateKey); // validate private key, convert to bigint
|
|
818
|
+
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
819
|
+
// extraEntropy. RFC6979 3.6: additional k' (optional).
|
|
836
820
|
if (ent != null) {
|
|
837
|
-
//
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
const e = ensureBytes(ent);
|
|
841
|
-
if (e.length !== Fp.BYTES)
|
|
842
|
-
throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`);
|
|
843
|
-
seedArgs.push(e);
|
|
821
|
+
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
|
822
|
+
// Either pass as-is, or generate random bytes. Then validate for being ui8a of size BYTES
|
|
823
|
+
seedArgs.push(ensureBytes(ent === true ? randomBytes(Fp.BYTES) : ent, Fp.BYTES));
|
|
844
824
|
}
|
|
845
825
|
const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
|
|
846
826
|
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
|
|
@@ -950,7 +930,6 @@ export function weierstrass(curveDef) {
|
|
|
950
930
|
getSharedSecret,
|
|
951
931
|
sign,
|
|
952
932
|
verify,
|
|
953
|
-
// Point,
|
|
954
933
|
ProjectivePoint: Point,
|
|
955
934
|
Signature,
|
|
956
935
|
utils,
|
package/lib/esm/p224.js
CHANGED
|
@@ -8,7 +8,7 @@ export const P224 = createCurve({
|
|
|
8
8
|
// Params: a, b
|
|
9
9
|
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe'),
|
|
10
10
|
b: BigInt('0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4'),
|
|
11
|
-
// Field over which we'll do calculations;
|
|
11
|
+
// Field over which we'll do calculations;
|
|
12
12
|
Fp: Fp(BigInt('0xffffffffffffffffffffffffffffffff000000000000000000000001')),
|
|
13
13
|
// Curve order, total count of valid points in the field
|
|
14
14
|
n: BigInt('0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d'),
|
package/lib/esm/p521.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
import { createCurve } from './_shortw_utils.js';
|
|
3
3
|
import { sha512 } from '@noble/hashes/sha512';
|
|
4
|
-
import { bytesToHex } from './abstract/utils.js';
|
|
5
4
|
import { Fp as Field } from './abstract/modular.js';
|
|
6
5
|
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
|
7
6
|
import * as htf from './abstract/hash-to-curve.js';
|
|
@@ -33,18 +32,7 @@ export const P521 = createCurve({
|
|
|
33
32
|
Gy: BigInt('0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'),
|
|
34
33
|
h: BigInt(1),
|
|
35
34
|
lowS: false,
|
|
36
|
-
|
|
37
|
-
// Does not replace validation; invalid keys would still be rejected.
|
|
38
|
-
normalizePrivateKey(key) {
|
|
39
|
-
if (typeof key === 'bigint')
|
|
40
|
-
return key;
|
|
41
|
-
if (key instanceof Uint8Array)
|
|
42
|
-
key = bytesToHex(key);
|
|
43
|
-
if (typeof key !== 'string' || !([130, 131, 132].includes(key.length))) {
|
|
44
|
-
throw new Error('Invalid key');
|
|
45
|
-
}
|
|
46
|
-
return key.padStart(66 * 2, '0'); // ensure it's always 132 bytes
|
|
47
|
-
},
|
|
35
|
+
allowedPrivateKeyLengths: [130, 131, 132] // P521 keys are variable-length. Normalize to 132b
|
|
48
36
|
}, sha512);
|
|
49
37
|
export const secp521r1 = P521;
|
|
50
38
|
const { hashToCurve, encodeToCurve } = htf.hashToCurve(secp521r1.ProjectivePoint, (scalars) => mapSWU(scalars[0]), {
|