@noble/curves 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -92
- 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 +44 -26
- 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 +23 -65
- package/lib/abstract/utils.d.ts +17 -1
- package/lib/abstract/utils.js +57 -27
- package/lib/abstract/weierstrass.d.ts +10 -10
- package/lib/abstract/weierstrass.js +61 -79
- package/lib/esm/abstract/curve.js +11 -17
- package/lib/esm/abstract/edwards.js +46 -28
- package/lib/esm/abstract/hash-to-curve.js +1 -1
- package/lib/esm/abstract/modular.js +12 -14
- package/lib/esm/abstract/montgomery.js +24 -66
- package/lib/esm/abstract/poseidon.js +1 -1
- package/lib/esm/abstract/utils.js +55 -26
- package/lib/esm/abstract/weierstrass.js +62 -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
|
@@ -7,28 +7,16 @@ const utils_js_1 = require("./utils.js");
|
|
|
7
7
|
const _0n = BigInt(0);
|
|
8
8
|
const _1n = BigInt(1);
|
|
9
9
|
function validateOpts(curve) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
for (const fn of ['adjustScalarBytes', 'domain', 'powPminus2']) {
|
|
21
|
-
if (curve[fn] === undefined)
|
|
22
|
-
continue; // Optional
|
|
23
|
-
if (typeof curve[fn] !== 'function')
|
|
24
|
-
throw new Error(`Invalid ${fn} function`);
|
|
25
|
-
}
|
|
26
|
-
for (const i of ['Gu']) {
|
|
27
|
-
if (curve[i] === undefined)
|
|
28
|
-
continue; // Optional
|
|
29
|
-
if (typeof curve[i] !== 'string')
|
|
30
|
-
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
|
|
31
|
-
}
|
|
10
|
+
(0, utils_js_1.validateObject)(curve, {
|
|
11
|
+
a24: 'bigint',
|
|
12
|
+
}, {
|
|
13
|
+
montgomeryBits: 'isSafeInteger',
|
|
14
|
+
nByteLength: 'isSafeInteger',
|
|
15
|
+
adjustScalarBytes: 'function',
|
|
16
|
+
domain: 'function',
|
|
17
|
+
powPminus2: 'function',
|
|
18
|
+
Gu: 'string',
|
|
19
|
+
});
|
|
32
20
|
// Set defaults
|
|
33
21
|
return Object.freeze({ ...curve });
|
|
34
22
|
}
|
|
@@ -43,31 +31,7 @@ function montgomery(curveDef) {
|
|
|
43
31
|
const fieldLen = CURVE.nByteLength;
|
|
44
32
|
const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes);
|
|
45
33
|
const powPminus2 = CURVE.powPminus2 || ((x) => (0, modular_js_1.pow)(x, P - BigInt(2), P));
|
|
46
|
-
|
|
47
|
-
* Checks for num to be in range:
|
|
48
|
-
* For strict == true: `0 < num < max`.
|
|
49
|
-
* For strict == false: `0 <= num < max`.
|
|
50
|
-
* Converts non-float safe numbers to bigints.
|
|
51
|
-
*/
|
|
52
|
-
function normalizeScalar(num, max, strict = true) {
|
|
53
|
-
if (!max)
|
|
54
|
-
throw new TypeError('Specify max value');
|
|
55
|
-
if (typeof num === 'number' && Number.isSafeInteger(num))
|
|
56
|
-
num = BigInt(num);
|
|
57
|
-
if (typeof num === 'bigint' && num < max) {
|
|
58
|
-
if (strict) {
|
|
59
|
-
if (_0n < num)
|
|
60
|
-
return num;
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
if (_0n <= num)
|
|
64
|
-
return num;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
throw new TypeError('Expected valid scalar: 0 < scalar < max');
|
|
68
|
-
}
|
|
69
|
-
// cswap from RFC7748
|
|
70
|
-
// NOTE: cswap is not from RFC7748!
|
|
34
|
+
// cswap from RFC7748. But it is not from RFC7748!
|
|
71
35
|
/*
|
|
72
36
|
cswap(swap, x_2, x_3):
|
|
73
37
|
dummy = mask(swap) AND (x_2 XOR x_3)
|
|
@@ -83,6 +47,11 @@ function montgomery(curveDef) {
|
|
|
83
47
|
x_3 = modP(x_3 + dummy);
|
|
84
48
|
return [x_2, x_3];
|
|
85
49
|
}
|
|
50
|
+
function assertFieldElement(n) {
|
|
51
|
+
if (typeof n === 'bigint' && _0n <= n && n < P)
|
|
52
|
+
return n;
|
|
53
|
+
throw new Error('Expected valid scalar 0 < scalar < CURVE.P');
|
|
54
|
+
}
|
|
86
55
|
// x25519 from 4
|
|
87
56
|
/**
|
|
88
57
|
*
|
|
@@ -91,11 +60,10 @@ function montgomery(curveDef) {
|
|
|
91
60
|
* @returns new Point on Montgomery curve
|
|
92
61
|
*/
|
|
93
62
|
function montgomeryLadder(pointU, scalar) {
|
|
94
|
-
const
|
|
95
|
-
const u = normalizeScalar(pointU, P);
|
|
63
|
+
const u = assertFieldElement(pointU);
|
|
96
64
|
// Section 5: Implementations MUST accept non-canonical values and process them as
|
|
97
65
|
// if they had been reduced modulo the field prime.
|
|
98
|
-
const k =
|
|
66
|
+
const k = assertFieldElement(scalar);
|
|
99
67
|
// The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519
|
|
100
68
|
const a24 = CURVE.a24;
|
|
101
69
|
const x_1 = u;
|
|
@@ -148,12 +116,14 @@ function montgomery(curveDef) {
|
|
|
148
116
|
return (0, utils_js_1.numberToBytesLE)(modP(u), montgomeryBytes);
|
|
149
117
|
}
|
|
150
118
|
function decodeUCoordinate(uEnc) {
|
|
151
|
-
const u = (0, utils_js_1.ensureBytes)(uEnc, montgomeryBytes);
|
|
152
119
|
// Section 5: When receiving such an array, implementations of X25519
|
|
153
120
|
// MUST mask the most significant bit in the final byte.
|
|
154
121
|
// This is very ugly way, but it works because fieldLen-1 is outside of bounds for X448, so this becomes NOOP
|
|
155
122
|
// fieldLen - scalaryBytes = 1 for X448 and = 0 for X25519
|
|
156
|
-
u
|
|
123
|
+
const u = (0, utils_js_1.ensureBytes)(uEnc, montgomeryBytes);
|
|
124
|
+
// u[fieldLen-1] crashes QuickJS (TypeError: out-of-bound numeric index)
|
|
125
|
+
if (fieldLen === montgomeryBytes)
|
|
126
|
+
u[fieldLen - 1] &= 127; // 0b0111_1111
|
|
157
127
|
return (0, utils_js_1.bytesToNumberLE)(u);
|
|
158
128
|
}
|
|
159
129
|
function decodeScalar(n) {
|
|
@@ -162,13 +132,6 @@ function montgomery(curveDef) {
|
|
|
162
132
|
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${bytes.length}`);
|
|
163
133
|
return (0, utils_js_1.bytesToNumberLE)(adjustScalarBytes(bytes));
|
|
164
134
|
}
|
|
165
|
-
/**
|
|
166
|
-
* Computes shared secret between private key "scalar" and public key's "u" (x) coordinate.
|
|
167
|
-
* We can get 'y' coordinate from 'u',
|
|
168
|
-
* but Point.fromHex also wants 'x' coordinate oddity flag,
|
|
169
|
-
* and we cannot get 'x' without knowing 'v'.
|
|
170
|
-
* Need to add generic conversion between twisted edwards and complimentary curve for JubJub.
|
|
171
|
-
*/
|
|
172
135
|
function scalarMult(scalar, u) {
|
|
173
136
|
const pointU = decodeUCoordinate(u);
|
|
174
137
|
const _scalar = decodeScalar(scalar);
|
|
@@ -179,12 +142,7 @@ function montgomery(curveDef) {
|
|
|
179
142
|
throw new Error('Invalid private or public key received');
|
|
180
143
|
return encodeUCoordinate(pu);
|
|
181
144
|
}
|
|
182
|
-
|
|
183
|
-
* Computes public key from private.
|
|
184
|
-
* Executes scalar multiplication of curve's base point by scalar.
|
|
185
|
-
* @param scalar private key
|
|
186
|
-
* @returns new public key
|
|
187
|
-
*/
|
|
145
|
+
// Computes public key from private. By doing scalar multiplication of base point.
|
|
188
146
|
function scalarMultBase(scalar) {
|
|
189
147
|
return scalarMult(scalar, CURVE.Gu);
|
|
190
148
|
}
|
package/lib/abstract/utils.d.ts
CHANGED
|
@@ -19,9 +19,25 @@ export declare const numberToBytesBE: (n: bigint, len: number) => Uint8Array;
|
|
|
19
19
|
export declare const numberToBytesLE: (n: bigint, len: number) => Uint8Array;
|
|
20
20
|
export declare const numberToVarBytesBE: (n: bigint) => Uint8Array;
|
|
21
21
|
export declare function ensureBytes(hex: Hex, expectedLength?: number): Uint8Array;
|
|
22
|
-
export declare function concatBytes(...
|
|
22
|
+
export declare function concatBytes(...arrs: Uint8Array[]): Uint8Array;
|
|
23
23
|
export declare function equalBytes(b1: Uint8Array, b2: Uint8Array): boolean;
|
|
24
24
|
export declare function bitLen(n: bigint): number;
|
|
25
25
|
export declare const bitGet: (n: bigint, pos: number) => bigint;
|
|
26
26
|
export declare const bitSet: (n: bigint, pos: number, value: boolean) => bigint;
|
|
27
27
|
export declare const bitMask: (n: number) => bigint;
|
|
28
|
+
declare const validatorFns: {
|
|
29
|
+
readonly bigint: (val: any) => boolean;
|
|
30
|
+
readonly function: (val: any) => boolean;
|
|
31
|
+
readonly boolean: (val: any) => boolean;
|
|
32
|
+
readonly string: (val: any) => boolean;
|
|
33
|
+
readonly isSafeInteger: (val: any) => boolean;
|
|
34
|
+
readonly array: (val: any) => boolean;
|
|
35
|
+
readonly field: (val: any, object: any) => any;
|
|
36
|
+
readonly hash: (val: any) => boolean;
|
|
37
|
+
};
|
|
38
|
+
declare type Validator = keyof typeof validatorFns;
|
|
39
|
+
declare type ValMap<T extends Record<string, any>> = {
|
|
40
|
+
[K in keyof T]?: Validator;
|
|
41
|
+
};
|
|
42
|
+
export declare function validateObject<T extends Record<string, any>>(object: T, validators: ValMap<T>, optValidators?: ValMap<T>): T;
|
|
43
|
+
export {};
|
package/lib/abstract/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.bitMask = exports.bitSet = exports.bitGet = exports.bitLen = exports.equalBytes = exports.concatBytes = exports.ensureBytes = exports.numberToVarBytesBE = exports.numberToBytesLE = exports.numberToBytesBE = exports.bytesToNumberLE = exports.bytesToNumberBE = exports.hexToBytes = exports.hexToNumber = exports.numberToHexUnpadded = exports.bytesToHex = void 0;
|
|
3
|
+
exports.validateObject = exports.bitMask = exports.bitSet = exports.bitGet = exports.bitLen = exports.equalBytes = exports.concatBytes = exports.ensureBytes = exports.numberToVarBytesBE = exports.numberToBytesLE = exports.numberToBytesBE = exports.bytesToNumberLE = exports.bytesToNumberBE = exports.hexToBytes = exports.hexToNumber = exports.numberToHexUnpadded = exports.bytesToHex = void 0;
|
|
4
4
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
5
|
const _0n = BigInt(0);
|
|
6
6
|
const _1n = BigInt(1);
|
|
@@ -9,7 +9,7 @@ const u8a = (a) => a instanceof Uint8Array;
|
|
|
9
9
|
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
|
|
10
10
|
function bytesToHex(bytes) {
|
|
11
11
|
if (!u8a(bytes))
|
|
12
|
-
throw new Error('
|
|
12
|
+
throw new Error('Uint8Array expected');
|
|
13
13
|
// pre-caching improves the speed 6x
|
|
14
14
|
let hex = '';
|
|
15
15
|
for (let i = 0; i < bytes.length; i++) {
|
|
@@ -25,24 +25,24 @@ function numberToHexUnpadded(num) {
|
|
|
25
25
|
exports.numberToHexUnpadded = numberToHexUnpadded;
|
|
26
26
|
function hexToNumber(hex) {
|
|
27
27
|
if (typeof hex !== 'string')
|
|
28
|
-
throw new Error('
|
|
28
|
+
throw new Error('string expected, got ' + typeof hex);
|
|
29
29
|
// Big Endian
|
|
30
|
-
return BigInt(`0x${hex}`);
|
|
30
|
+
return BigInt(hex === '' ? '0' : `0x${hex}`);
|
|
31
31
|
}
|
|
32
32
|
exports.hexToNumber = hexToNumber;
|
|
33
33
|
// Caching slows it down 2-3x
|
|
34
34
|
function hexToBytes(hex) {
|
|
35
35
|
if (typeof hex !== 'string')
|
|
36
|
-
throw new Error('
|
|
36
|
+
throw new Error('string expected, got ' + typeof hex);
|
|
37
37
|
if (hex.length % 2)
|
|
38
|
-
throw new Error('
|
|
38
|
+
throw new Error('hex string is invalid: unpadded ' + hex.length);
|
|
39
39
|
const array = new Uint8Array(hex.length / 2);
|
|
40
40
|
for (let i = 0; i < array.length; i++) {
|
|
41
41
|
const j = i * 2;
|
|
42
42
|
const hexByte = hex.slice(j, j + 2);
|
|
43
43
|
const byte = Number.parseInt(hexByte, 16);
|
|
44
44
|
if (Number.isNaN(byte) || byte < 0)
|
|
45
|
-
throw new Error('
|
|
45
|
+
throw new Error('invalid byte sequence');
|
|
46
46
|
array[i] = byte;
|
|
47
47
|
}
|
|
48
48
|
return array;
|
|
@@ -55,7 +55,7 @@ function bytesToNumberBE(bytes) {
|
|
|
55
55
|
exports.bytesToNumberBE = bytesToNumberBE;
|
|
56
56
|
function bytesToNumberLE(bytes) {
|
|
57
57
|
if (!u8a(bytes))
|
|
58
|
-
throw new Error('
|
|
58
|
+
throw new Error('Uint8Array expected');
|
|
59
59
|
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
|
|
60
60
|
}
|
|
61
61
|
exports.bytesToNumberLE = bytesToNumberLE;
|
|
@@ -64,12 +64,7 @@ exports.numberToBytesBE = numberToBytesBE;
|
|
|
64
64
|
const numberToBytesLE = (n, len) => (0, exports.numberToBytesBE)(n, len).reverse();
|
|
65
65
|
exports.numberToBytesLE = numberToBytesLE;
|
|
66
66
|
// Returns variable number bytes (minimal bigint encoding?)
|
|
67
|
-
const numberToVarBytesBE = (n) =>
|
|
68
|
-
let hex = n.toString(16);
|
|
69
|
-
if (hex.length & 1)
|
|
70
|
-
hex = '0' + hex;
|
|
71
|
-
return hexToBytes(hex);
|
|
72
|
-
};
|
|
67
|
+
const numberToVarBytesBE = (n) => hexToBytes(numberToHexUnpadded(n));
|
|
73
68
|
exports.numberToVarBytesBE = numberToVarBytesBE;
|
|
74
69
|
function ensureBytes(hex, expectedLength) {
|
|
75
70
|
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
|
@@ -81,19 +76,16 @@ function ensureBytes(hex, expectedLength) {
|
|
|
81
76
|
}
|
|
82
77
|
exports.ensureBytes = ensureBytes;
|
|
83
78
|
// Copies several Uint8Arrays into one.
|
|
84
|
-
function concatBytes(...
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
pad += arr.length;
|
|
95
|
-
}
|
|
96
|
-
return result;
|
|
79
|
+
function concatBytes(...arrs) {
|
|
80
|
+
const r = new Uint8Array(arrs.reduce((sum, a) => sum + a.length, 0));
|
|
81
|
+
let pad = 0; // walk through each item, ensure they have proper type
|
|
82
|
+
arrs.forEach((a) => {
|
|
83
|
+
if (!u8a(a))
|
|
84
|
+
throw new Error('Uint8Array expected');
|
|
85
|
+
r.set(a, pad);
|
|
86
|
+
pad += a.length;
|
|
87
|
+
});
|
|
88
|
+
return r;
|
|
97
89
|
}
|
|
98
90
|
exports.concatBytes = concatBytes;
|
|
99
91
|
function equalBytes(b1, b2) {
|
|
@@ -126,3 +118,41 @@ exports.bitSet = bitSet;
|
|
|
126
118
|
// Not using ** operator with bigints for old engines.
|
|
127
119
|
const bitMask = (n) => (_2n << BigInt(n - 1)) - _1n;
|
|
128
120
|
exports.bitMask = bitMask;
|
|
121
|
+
const validatorFns = {
|
|
122
|
+
bigint: (val) => typeof val === 'bigint',
|
|
123
|
+
function: (val) => typeof val === 'function',
|
|
124
|
+
boolean: (val) => typeof val === 'boolean',
|
|
125
|
+
string: (val) => typeof val === 'string',
|
|
126
|
+
isSafeInteger: (val) => Number.isSafeInteger(val),
|
|
127
|
+
array: (val) => Array.isArray(val),
|
|
128
|
+
field: (val, object) => object.Fp.isValid(val),
|
|
129
|
+
hash: (val) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
|
|
130
|
+
};
|
|
131
|
+
// type Record<K extends string | number | symbol, T> = { [P in K]: T; }
|
|
132
|
+
function validateObject(object, validators, optValidators = {}) {
|
|
133
|
+
const checkField = (fieldName, type, isOptional) => {
|
|
134
|
+
const checkVal = validatorFns[type];
|
|
135
|
+
if (typeof checkVal !== 'function')
|
|
136
|
+
throw new Error(`Invalid validator "${type}", expected function`);
|
|
137
|
+
const val = object[fieldName];
|
|
138
|
+
if (isOptional && val === undefined)
|
|
139
|
+
return;
|
|
140
|
+
if (!checkVal(val, object)) {
|
|
141
|
+
throw new Error(`Invalid param ${String(fieldName)}=${val} (${typeof val}), expected ${type}`);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
for (const [fieldName, type] of Object.entries(validators))
|
|
145
|
+
checkField(fieldName, type, false);
|
|
146
|
+
for (const [fieldName, type] of Object.entries(optValidators))
|
|
147
|
+
checkField(fieldName, type, true);
|
|
148
|
+
return object;
|
|
149
|
+
}
|
|
150
|
+
exports.validateObject = validateObject;
|
|
151
|
+
// validate type tests
|
|
152
|
+
// const o: { a: number; b: number; c: number } = { a: 1, b: 5, c: 6 };
|
|
153
|
+
// const z0 = validateObject(o, { a: 'isSafeInteger' }, { c: 'bigint' }); // Ok!
|
|
154
|
+
// // Should fail type-check
|
|
155
|
+
// const z1 = validateObject(o, { a: 'tmp' }, { c: 'zz' });
|
|
156
|
+
// const z2 = validateObject(o, { a: 'isSafeInteger' }, { c: 'zz' });
|
|
157
|
+
// const z3 = validateObject(o, { test: 'boolean', z: 'bug' });
|
|
158
|
+
// const z4 = validateObject(o, { a: 'boolean', z: 'bug' });
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
import * as mod from './modular.js';
|
|
3
3
|
import * as ut from './utils.js';
|
|
4
|
-
import { Hex, PrivKey
|
|
5
|
-
import { Group, GroupConstructor,
|
|
4
|
+
import { CHash, Hex, PrivKey } from './utils.js';
|
|
5
|
+
import { Group, GroupConstructor, BasicCurve, AffinePoint } from './curve.js';
|
|
6
6
|
export type { AffinePoint };
|
|
7
7
|
declare type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;
|
|
8
8
|
declare type EndomorphismOpts = {
|
|
@@ -14,10 +14,10 @@ declare type EndomorphismOpts = {
|
|
|
14
14
|
k2: bigint;
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
|
-
export declare type
|
|
17
|
+
export declare type BasicWCurve<T> = BasicCurve<T> & {
|
|
18
18
|
a: T;
|
|
19
19
|
b: T;
|
|
20
|
-
|
|
20
|
+
allowedPrivateKeyLengths?: readonly number[];
|
|
21
21
|
wrapPrivateKey?: boolean;
|
|
22
22
|
endo?: EndomorphismOpts;
|
|
23
23
|
isTorsionFree?: (c: ProjConstructor<T>, point: ProjPointType<T>) => boolean;
|
|
@@ -77,7 +77,7 @@ export interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
|
|
|
77
77
|
fromPrivateKey(privateKey: PrivKey): ProjPointType<T>;
|
|
78
78
|
normalizeZ(points: ProjPointType<T>[]): ProjPointType<T>[];
|
|
79
79
|
}
|
|
80
|
-
export declare type CurvePointsType<T> =
|
|
80
|
+
export declare type CurvePointsType<T> = BasicWCurve<T> & {
|
|
81
81
|
fromBytes: (bytes: Uint8Array) => AffinePoint<T>;
|
|
82
82
|
toBytes: (c: ProjConstructor<T>, point: ProjPointType<T>, compressed: boolean) => Uint8Array;
|
|
83
83
|
};
|
|
@@ -117,11 +117,11 @@ declare type SignatureLike = {
|
|
|
117
117
|
s: bigint;
|
|
118
118
|
};
|
|
119
119
|
export declare type PubKey = Hex | ProjPointType<bigint>;
|
|
120
|
-
export declare type CurveType =
|
|
121
|
-
lowS?: boolean;
|
|
120
|
+
export declare type CurveType = BasicWCurve<bigint> & {
|
|
122
121
|
hash: CHash;
|
|
123
122
|
hmac: HmacFnSync;
|
|
124
123
|
randomBytes: (bytesLength?: number) => Uint8Array;
|
|
124
|
+
lowS?: boolean;
|
|
125
125
|
bits2int?: (bytes: Uint8Array) => bigint;
|
|
126
126
|
bits2int_modN?: (bytes: Uint8Array) => bigint;
|
|
127
127
|
};
|
|
@@ -134,18 +134,18 @@ declare function validateOpts(curve: CurveType): Readonly<{
|
|
|
134
134
|
readonly hEff?: bigint | undefined;
|
|
135
135
|
readonly Gx: bigint;
|
|
136
136
|
readonly Gy: bigint;
|
|
137
|
-
readonly wrapPrivateKey?: boolean | undefined;
|
|
138
137
|
readonly allowInfinityPoint?: boolean | undefined;
|
|
139
138
|
readonly a: bigint;
|
|
140
139
|
readonly b: bigint;
|
|
141
|
-
readonly
|
|
140
|
+
readonly allowedPrivateKeyLengths?: readonly number[] | undefined;
|
|
141
|
+
readonly wrapPrivateKey?: boolean | undefined;
|
|
142
142
|
readonly endo?: EndomorphismOpts | undefined;
|
|
143
143
|
readonly isTorsionFree?: ((c: ProjConstructor<bigint>, point: ProjPointType<bigint>) => boolean) | undefined;
|
|
144
144
|
readonly clearCofactor?: ((c: ProjConstructor<bigint>, point: ProjPointType<bigint>) => ProjPointType<bigint>) | undefined;
|
|
145
|
-
lowS: boolean;
|
|
146
145
|
readonly hash: ut.CHash;
|
|
147
146
|
readonly hmac: HmacFnSync;
|
|
148
147
|
readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
|
|
148
|
+
lowS: boolean;
|
|
149
149
|
readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
|
|
150
150
|
readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
|
|
151
151
|
}>;
|
|
@@ -8,21 +8,22 @@ const ut = require("./utils.js");
|
|
|
8
8
|
const utils_js_1 = require("./utils.js");
|
|
9
9
|
const curve_js_1 = require("./curve.js");
|
|
10
10
|
function validatePointOpts(curve) {
|
|
11
|
-
const opts = (0, curve_js_1.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
const opts = (0, curve_js_1.validateBasic)(curve);
|
|
12
|
+
ut.validateObject(opts, {
|
|
13
|
+
a: 'field',
|
|
14
|
+
b: 'field',
|
|
15
|
+
fromBytes: 'function',
|
|
16
|
+
toBytes: 'function',
|
|
17
|
+
}, {
|
|
18
|
+
allowedPrivateKeyLengths: 'array',
|
|
19
|
+
wrapPrivateKey: 'boolean',
|
|
20
|
+
isTorsionFree: 'function',
|
|
21
|
+
clearCofactor: 'function',
|
|
22
|
+
allowInfinityPoint: 'boolean',
|
|
23
|
+
});
|
|
24
|
+
const { endo, Fp, a } = opts;
|
|
24
25
|
if (endo) {
|
|
25
|
-
if (!Fp.eql(
|
|
26
|
+
if (!Fp.eql(a, Fp.ZERO)) {
|
|
26
27
|
throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
|
|
27
28
|
}
|
|
28
29
|
if (typeof endo !== 'object' ||
|
|
@@ -31,11 +32,6 @@ function validatePointOpts(curve) {
|
|
|
31
32
|
throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
|
-
if (typeof opts.fromBytes !== 'function')
|
|
35
|
-
throw new Error('Invalid fromBytes function');
|
|
36
|
-
if (typeof opts.toBytes !== 'function')
|
|
37
|
-
throw new Error('Invalid fromBytes function');
|
|
38
|
-
// Set defaults
|
|
39
35
|
return Object.freeze({ ...opts });
|
|
40
36
|
}
|
|
41
37
|
// ASN.1 DER encoding utilities
|
|
@@ -116,39 +112,28 @@ function weierstrassPoints(opts) {
|
|
|
116
112
|
if (!isWithinCurveOrder(num))
|
|
117
113
|
throw new Error('Expected valid bigint: 0 < bigint < curve.n');
|
|
118
114
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
* Supports two options, that are passed when CURVE is initialized:
|
|
122
|
-
* - `normalizePrivateKey()` executed before all checks
|
|
123
|
-
* - `wrapPrivateKey` when true, executed after most checks, but before `0 < key < n`
|
|
124
|
-
*/
|
|
115
|
+
// Validates if priv key is valid and converts it to bigint.
|
|
116
|
+
// Supports options CURVE.normalizePrivateKey and CURVE.wrapPrivateKey.
|
|
125
117
|
function normalizePrivateKey(key) {
|
|
126
|
-
const {
|
|
127
|
-
if (typeof
|
|
128
|
-
key
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
118
|
+
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
|
|
119
|
+
if (lengths && typeof key !== 'bigint') {
|
|
120
|
+
if (key instanceof Uint8Array)
|
|
121
|
+
key = ut.bytesToHex(key);
|
|
122
|
+
// Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
|
|
123
|
+
if (typeof key !== 'string' || !lengths.includes(key.length))
|
|
124
|
+
throw new Error('Invalid key');
|
|
125
|
+
key = key.padStart(nByteLength * 2, '0');
|
|
133
126
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// Validates individual octets
|
|
138
|
-
num = ut.bytesToNumberBE((0, utils_js_1.ensureBytes)(key));
|
|
139
|
-
}
|
|
140
|
-
else if (key instanceof Uint8Array) {
|
|
141
|
-
if (key.length !== groupLen)
|
|
142
|
-
throw new Error(`must be ${groupLen} bytes`);
|
|
143
|
-
num = ut.bytesToNumberBE(key);
|
|
127
|
+
let num;
|
|
128
|
+
try {
|
|
129
|
+
num = typeof key === 'bigint' ? key : ut.bytesToNumberBE((0, utils_js_1.ensureBytes)(key, nByteLength));
|
|
144
130
|
}
|
|
145
|
-
|
|
146
|
-
throw new Error(
|
|
131
|
+
catch (error) {
|
|
132
|
+
throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
|
|
147
133
|
}
|
|
148
|
-
// Useful for curves with cofactor != 1
|
|
149
134
|
if (wrapPrivateKey)
|
|
150
|
-
num = mod.mod(num, n);
|
|
151
|
-
assertGE(num);
|
|
135
|
+
num = mod.mod(num, n); // disabled by default, enabled for BLS
|
|
136
|
+
assertGE(num); // num in range [1..N-1]
|
|
152
137
|
return num;
|
|
153
138
|
}
|
|
154
139
|
const pointPrecomputes = new Map();
|
|
@@ -173,6 +158,8 @@ function weierstrassPoints(opts) {
|
|
|
173
158
|
if (pz == null || !Fp.isValid(pz))
|
|
174
159
|
throw new Error('z required');
|
|
175
160
|
}
|
|
161
|
+
// Does not validate if the point is on-curve.
|
|
162
|
+
// Use fromHex instead, or call assertValidity() later.
|
|
176
163
|
static fromAffine(p) {
|
|
177
164
|
const { x, y } = p || {};
|
|
178
165
|
if (!p || !Fp.isValid(x) || !Fp.isValid(y))
|
|
@@ -503,14 +490,16 @@ function weierstrassPoints(opts) {
|
|
|
503
490
|
}
|
|
504
491
|
exports.weierstrassPoints = weierstrassPoints;
|
|
505
492
|
function validateOpts(curve) {
|
|
506
|
-
const opts = (0, curve_js_1.
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
493
|
+
const opts = (0, curve_js_1.validateBasic)(curve);
|
|
494
|
+
ut.validateObject(opts, {
|
|
495
|
+
hash: 'hash',
|
|
496
|
+
hmac: 'function',
|
|
497
|
+
randomBytes: 'function',
|
|
498
|
+
}, {
|
|
499
|
+
bits2int: 'function',
|
|
500
|
+
bits2int_modN: 'function',
|
|
501
|
+
lowS: 'boolean',
|
|
502
|
+
});
|
|
514
503
|
return Object.freeze({ lowS: true, ...opts });
|
|
515
504
|
}
|
|
516
505
|
const u8n = (data) => new Uint8Array(data); // creates Uint8Array
|
|
@@ -619,7 +608,7 @@ function weierstrass(curveDef) {
|
|
|
619
608
|
return { x, y };
|
|
620
609
|
}
|
|
621
610
|
else {
|
|
622
|
-
throw new Error(`Point
|
|
611
|
+
throw new Error(`Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`);
|
|
623
612
|
}
|
|
624
613
|
},
|
|
625
614
|
});
|
|
@@ -681,7 +670,7 @@ function weierstrass(curveDef) {
|
|
|
681
670
|
const ir = invN(radj); // r^-1
|
|
682
671
|
const u1 = modN(-h * ir); // -hr^-1
|
|
683
672
|
const u2 = modN(s * ir); // sr^-1
|
|
684
|
-
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); //
|
|
673
|
+
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
|
|
685
674
|
if (!Q)
|
|
686
675
|
throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
|
|
687
676
|
Q.assertValidity();
|
|
@@ -804,9 +793,10 @@ function weierstrass(curveDef) {
|
|
|
804
793
|
const ORDER_MASK = ut.bitMask(CURVE.nBitLength);
|
|
805
794
|
function int2octets(num) {
|
|
806
795
|
if (typeof num !== 'bigint')
|
|
807
|
-
throw new Error('
|
|
796
|
+
throw new Error('bigint expected');
|
|
808
797
|
if (!(_0n <= num && num < ORDER_MASK))
|
|
809
|
-
|
|
798
|
+
// n in [0..ORDER_MASK-1]
|
|
799
|
+
throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
|
|
810
800
|
// works with order, can have different size than numToField!
|
|
811
801
|
return ut.numberToBytesBE(num, CURVE.nByteLength);
|
|
812
802
|
}
|
|
@@ -816,6 +806,7 @@ function weierstrass(curveDef) {
|
|
|
816
806
|
// NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.
|
|
817
807
|
// Also it can be bigger for P224 + SHA256
|
|
818
808
|
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
|
|
809
|
+
const { hash, randomBytes } = CURVE;
|
|
819
810
|
if (msgHash == null)
|
|
820
811
|
throw new Error(`sign: expected valid message hash, not "${msgHash}"`);
|
|
821
812
|
if (['recovered', 'canonical'].some((k) => k in opts))
|
|
@@ -823,28 +814,20 @@ function weierstrass(curveDef) {
|
|
|
823
814
|
throw new Error('sign() legacy options not supported');
|
|
824
815
|
let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
|
|
825
816
|
if (prehash)
|
|
826
|
-
msgHash =
|
|
817
|
+
msgHash = hash((0, utils_js_1.ensureBytes)(msgHash));
|
|
827
818
|
if (lowS == null)
|
|
828
|
-
lowS = true; // RFC6979 3.2: we skip step A, because
|
|
829
|
-
//
|
|
830
|
-
//
|
|
831
|
-
//
|
|
832
|
-
// However, we cannot later call bits2octets (which is truncateHash + int2octets), since nested bits2int is broken
|
|
833
|
-
// for curves where nBitLength % 8 !== 0, so we unwrap it here as int2octets call.
|
|
834
|
-
// const bits2octets = (bits)=>int2octets(bytesToNumberBE(truncateHash(bits)))
|
|
819
|
+
lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
|
|
820
|
+
// We can't later call bits2octets, since nested bits2int is broken for curves
|
|
821
|
+
// with nBitLength % 8 !== 0. Because of that, we unwrap it here as int2octets call.
|
|
822
|
+
// const bits2octets = (bits) => int2octets(bits2int_modN(bits))
|
|
835
823
|
const h1int = bits2int_modN((0, utils_js_1.ensureBytes)(msgHash));
|
|
836
|
-
const
|
|
837
|
-
const
|
|
838
|
-
//
|
|
839
|
-
const seedArgs = [int2octets(d), h1octets];
|
|
824
|
+
const d = normalizePrivateKey(privateKey); // validate private key, convert to bigint
|
|
825
|
+
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
826
|
+
// extraEntropy. RFC6979 3.6: additional k' (optional).
|
|
840
827
|
if (ent != null) {
|
|
841
|
-
//
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
const e = (0, utils_js_1.ensureBytes)(ent);
|
|
845
|
-
if (e.length !== Fp.BYTES)
|
|
846
|
-
throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`);
|
|
847
|
-
seedArgs.push(e);
|
|
828
|
+
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
|
829
|
+
// Either pass as-is, or generate random bytes. Then validate for being ui8a of size BYTES
|
|
830
|
+
seedArgs.push((0, utils_js_1.ensureBytes)(ent === true ? randomBytes(Fp.BYTES) : ent, Fp.BYTES));
|
|
848
831
|
}
|
|
849
832
|
const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
|
|
850
833
|
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
|
|
@@ -954,7 +937,6 @@ function weierstrass(curveDef) {
|
|
|
954
937
|
getSharedSecret,
|
|
955
938
|
sign,
|
|
956
939
|
verify,
|
|
957
|
-
// Point,
|
|
958
940
|
ProjectivePoint: Point,
|
|
959
941
|
Signature,
|
|
960
942
|
utils,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
// Abelian group utilities
|
|
3
3
|
import { validateField, nLength } from './modular.js';
|
|
4
|
+
import { validateObject } from './utils.js';
|
|
4
5
|
const _0n = BigInt(0);
|
|
5
6
|
const _1n = BigInt(1);
|
|
6
7
|
// Elliptic curve multiplication of Point by scalar. Complicated and fragile. Uses wNAF method.
|
|
@@ -121,24 +122,17 @@ export function wNAF(c, bits) {
|
|
|
121
122
|
},
|
|
122
123
|
};
|
|
123
124
|
}
|
|
124
|
-
export function
|
|
125
|
+
export function validateBasic(curve) {
|
|
125
126
|
validateField(curve.Fp);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
for (const i of ['nBitLength', 'nByteLength']) {
|
|
136
|
-
const val = curve[i];
|
|
137
|
-
if (val === undefined)
|
|
138
|
-
continue; // Optional
|
|
139
|
-
if (!Number.isSafeInteger(val))
|
|
140
|
-
throw new Error(`Invalid param ${i}=${val} (${typeof val})`);
|
|
141
|
-
}
|
|
127
|
+
validateObject(curve, {
|
|
128
|
+
n: 'bigint',
|
|
129
|
+
h: 'bigint',
|
|
130
|
+
Gx: 'field',
|
|
131
|
+
Gy: 'field',
|
|
132
|
+
}, {
|
|
133
|
+
nBitLength: 'isSafeInteger',
|
|
134
|
+
nByteLength: 'isSafeInteger',
|
|
135
|
+
});
|
|
142
136
|
// Set defaults
|
|
143
137
|
return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve });
|
|
144
138
|
}
|