@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
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,7 +25,7 @@ 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
30
|
return BigInt(`0x${hex}`);
|
|
31
31
|
}
|
|
@@ -33,16 +33,16 @@ 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,33 @@ 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
|
+
function validateObject(object, validators, optValidators = {}) {
|
|
122
|
+
const validatorFns = {
|
|
123
|
+
bigint: (val) => typeof val === 'bigint',
|
|
124
|
+
function: (val) => typeof val === 'function',
|
|
125
|
+
boolean: (val) => typeof val === 'boolean',
|
|
126
|
+
string: (val) => typeof val === 'string',
|
|
127
|
+
isSafeInteger: (val) => Number.isSafeInteger(val),
|
|
128
|
+
array: (val) => Array.isArray(val),
|
|
129
|
+
field: (val) => object.Fp.isValid(val),
|
|
130
|
+
hash: (val) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
|
|
131
|
+
};
|
|
132
|
+
// type Key = keyof typeof validators;
|
|
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)) {
|
|
141
|
+
throw new Error(`Invalid param ${fieldName}=${val} (${typeof val}), expected ${type}`);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
for (let [fieldName, type] of Object.entries(validators))
|
|
145
|
+
checkField(fieldName, type, false);
|
|
146
|
+
for (let [fieldName, type] of Object.entries(optValidators))
|
|
147
|
+
checkField(fieldName, type, true);
|
|
148
|
+
return object;
|
|
149
|
+
}
|
|
150
|
+
exports.validateObject = validateObject;
|
|
@@ -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,21 @@ 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
|
-
const endo = opts
|
|
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
|
+
});
|
|
23
|
+
const { endo, Fp, a } = opts;
|
|
24
24
|
if (endo) {
|
|
25
|
-
if (!Fp.eql(
|
|
25
|
+
if (!Fp.eql(a, Fp.ZERO)) {
|
|
26
26
|
throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
|
|
27
27
|
}
|
|
28
28
|
if (typeof endo !== 'object' ||
|
|
@@ -31,11 +31,6 @@ function validatePointOpts(curve) {
|
|
|
31
31
|
throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
|
|
32
32
|
}
|
|
33
33
|
}
|
|
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
34
|
return Object.freeze({ ...opts });
|
|
40
35
|
}
|
|
41
36
|
// ASN.1 DER encoding utilities
|
|
@@ -116,39 +111,28 @@ function weierstrassPoints(opts) {
|
|
|
116
111
|
if (!isWithinCurveOrder(num))
|
|
117
112
|
throw new Error('Expected valid bigint: 0 < bigint < curve.n');
|
|
118
113
|
}
|
|
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
|
-
*/
|
|
114
|
+
// Validates if priv key is valid and converts it to bigint.
|
|
115
|
+
// Supports options CURVE.normalizePrivateKey and CURVE.wrapPrivateKey.
|
|
125
116
|
function normalizePrivateKey(key) {
|
|
126
|
-
const {
|
|
127
|
-
if (typeof
|
|
128
|
-
key
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
117
|
+
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
|
|
118
|
+
if (lengths && typeof key !== 'bigint') {
|
|
119
|
+
if (key instanceof Uint8Array)
|
|
120
|
+
key = ut.bytesToHex(key);
|
|
121
|
+
// Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
|
|
122
|
+
if (typeof key !== 'string' || !lengths.includes(key.length))
|
|
123
|
+
throw new Error('Invalid key');
|
|
124
|
+
key = key.padStart(nByteLength * 2, '0');
|
|
133
125
|
}
|
|
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);
|
|
126
|
+
let num;
|
|
127
|
+
try {
|
|
128
|
+
num = typeof key === 'bigint' ? key : ut.bytesToNumberBE((0, utils_js_1.ensureBytes)(key, nByteLength));
|
|
144
129
|
}
|
|
145
|
-
|
|
146
|
-
throw new Error(
|
|
130
|
+
catch (error) {
|
|
131
|
+
throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
|
|
147
132
|
}
|
|
148
|
-
// Useful for curves with cofactor != 1
|
|
149
133
|
if (wrapPrivateKey)
|
|
150
|
-
num = mod.mod(num, n);
|
|
151
|
-
assertGE(num);
|
|
134
|
+
num = mod.mod(num, n); // disabled by default, enabled for BLS
|
|
135
|
+
assertGE(num); // num in range [1..N-1]
|
|
152
136
|
return num;
|
|
153
137
|
}
|
|
154
138
|
const pointPrecomputes = new Map();
|
|
@@ -503,14 +487,16 @@ function weierstrassPoints(opts) {
|
|
|
503
487
|
}
|
|
504
488
|
exports.weierstrassPoints = weierstrassPoints;
|
|
505
489
|
function validateOpts(curve) {
|
|
506
|
-
const opts = (0, curve_js_1.
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
490
|
+
const opts = (0, curve_js_1.validateBasic)(curve);
|
|
491
|
+
ut.validateObject(opts, {
|
|
492
|
+
hash: 'hash',
|
|
493
|
+
hmac: 'function',
|
|
494
|
+
randomBytes: 'function',
|
|
495
|
+
}, {
|
|
496
|
+
bits2int: 'function',
|
|
497
|
+
bits2int_modN: 'function',
|
|
498
|
+
lowS: 'boolean',
|
|
499
|
+
});
|
|
514
500
|
return Object.freeze({ lowS: true, ...opts });
|
|
515
501
|
}
|
|
516
502
|
const u8n = (data) => new Uint8Array(data); // creates Uint8Array
|
|
@@ -619,7 +605,7 @@ function weierstrass(curveDef) {
|
|
|
619
605
|
return { x, y };
|
|
620
606
|
}
|
|
621
607
|
else {
|
|
622
|
-
throw new Error(`Point
|
|
608
|
+
throw new Error(`Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`);
|
|
623
609
|
}
|
|
624
610
|
},
|
|
625
611
|
});
|
|
@@ -681,7 +667,7 @@ function weierstrass(curveDef) {
|
|
|
681
667
|
const ir = invN(radj); // r^-1
|
|
682
668
|
const u1 = modN(-h * ir); // -hr^-1
|
|
683
669
|
const u2 = modN(s * ir); // sr^-1
|
|
684
|
-
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); //
|
|
670
|
+
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
|
|
685
671
|
if (!Q)
|
|
686
672
|
throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
|
|
687
673
|
Q.assertValidity();
|
|
@@ -804,9 +790,10 @@ function weierstrass(curveDef) {
|
|
|
804
790
|
const ORDER_MASK = ut.bitMask(CURVE.nBitLength);
|
|
805
791
|
function int2octets(num) {
|
|
806
792
|
if (typeof num !== 'bigint')
|
|
807
|
-
throw new Error('
|
|
793
|
+
throw new Error('bigint expected');
|
|
808
794
|
if (!(_0n <= num && num < ORDER_MASK))
|
|
809
|
-
|
|
795
|
+
// n in [0..ORDER_MASK-1]
|
|
796
|
+
throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
|
|
810
797
|
// works with order, can have different size than numToField!
|
|
811
798
|
return ut.numberToBytesBE(num, CURVE.nByteLength);
|
|
812
799
|
}
|
|
@@ -816,6 +803,7 @@ function weierstrass(curveDef) {
|
|
|
816
803
|
// NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.
|
|
817
804
|
// Also it can be bigger for P224 + SHA256
|
|
818
805
|
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
|
|
806
|
+
const { hash, randomBytes } = CURVE;
|
|
819
807
|
if (msgHash == null)
|
|
820
808
|
throw new Error(`sign: expected valid message hash, not "${msgHash}"`);
|
|
821
809
|
if (['recovered', 'canonical'].some((k) => k in opts))
|
|
@@ -823,28 +811,20 @@ function weierstrass(curveDef) {
|
|
|
823
811
|
throw new Error('sign() legacy options not supported');
|
|
824
812
|
let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
|
|
825
813
|
if (prehash)
|
|
826
|
-
msgHash =
|
|
814
|
+
msgHash = hash((0, utils_js_1.ensureBytes)(msgHash));
|
|
827
815
|
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)))
|
|
816
|
+
lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
|
|
817
|
+
// We can't later call bits2octets, since nested bits2int is broken for curves
|
|
818
|
+
// with nBitLength % 8 !== 0. Because of that, we unwrap it here as int2octets call.
|
|
819
|
+
// const bits2octets = (bits) => int2octets(bits2int_modN(bits))
|
|
835
820
|
const h1int = bits2int_modN((0, utils_js_1.ensureBytes)(msgHash));
|
|
836
|
-
const
|
|
837
|
-
const
|
|
838
|
-
//
|
|
839
|
-
const seedArgs = [int2octets(d), h1octets];
|
|
821
|
+
const d = normalizePrivateKey(privateKey); // validate private key, convert to bigint
|
|
822
|
+
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
823
|
+
// extraEntropy. RFC6979 3.6: additional k' (optional).
|
|
840
824
|
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);
|
|
825
|
+
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
|
826
|
+
// Either pass as-is, or generate random bytes. Then validate for being ui8a of size BYTES
|
|
827
|
+
seedArgs.push((0, utils_js_1.ensureBytes)(ent === true ? randomBytes(Fp.BYTES) : ent, Fp.BYTES));
|
|
848
828
|
}
|
|
849
829
|
const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
|
|
850
830
|
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
|
|
@@ -954,7 +934,6 @@ function weierstrass(curveDef) {
|
|
|
954
934
|
getSharedSecret,
|
|
955
935
|
sign,
|
|
956
936
|
verify,
|
|
957
|
-
// Point,
|
|
958
937
|
ProjectivePoint: Point,
|
|
959
938
|
Signature,
|
|
960
939
|
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
|
}
|
|
@@ -1,32 +1,27 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
|
|
3
3
|
import { mod } from './modular.js';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
4
|
+
import * as ut from './utils.js';
|
|
5
|
+
import { ensureBytes } from './utils.js';
|
|
6
|
+
import { wNAF, validateBasic } from './curve.js';
|
|
6
7
|
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
|
|
7
8
|
const _0n = BigInt(0);
|
|
8
9
|
const _1n = BigInt(1);
|
|
9
10
|
const _2n = BigInt(2);
|
|
10
11
|
const _8n = BigInt(8);
|
|
11
12
|
function validateOpts(curve) {
|
|
12
|
-
const opts =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
for (const fn of ['adjustScalarBytes', 'domain', 'uvRatio', 'mapToCurve']) {
|
|
25
|
-
if (opts[fn] === undefined)
|
|
26
|
-
continue; // Optional
|
|
27
|
-
if (typeof opts[fn] !== 'function')
|
|
28
|
-
throw new Error(`Invalid ${fn} function`);
|
|
29
|
-
}
|
|
13
|
+
const opts = validateBasic(curve);
|
|
14
|
+
ut.validateObject(curve, {
|
|
15
|
+
hash: 'function',
|
|
16
|
+
a: 'bigint',
|
|
17
|
+
d: 'bigint',
|
|
18
|
+
randomBytes: 'function',
|
|
19
|
+
}, {
|
|
20
|
+
adjustScalarBytes: 'function',
|
|
21
|
+
domain: 'function',
|
|
22
|
+
uvRatio: 'function',
|
|
23
|
+
mapToCurve: 'function',
|
|
24
|
+
});
|
|
30
25
|
// Set defaults
|
|
31
26
|
return Object.freeze({ ...opts });
|
|
32
27
|
}
|
|
@@ -261,7 +256,7 @@ export function twistedEdwards(curveDef) {
|
|
|
261
256
|
const normed = hex.slice(); // copy again, we'll manipulate it
|
|
262
257
|
const lastByte = hex[len - 1]; // select last byte
|
|
263
258
|
normed[len - 1] = lastByte & ~0x80; // clear last bit
|
|
264
|
-
const y = bytesToNumberLE(normed);
|
|
259
|
+
const y = ut.bytesToNumberLE(normed);
|
|
265
260
|
if (y === _0n) {
|
|
266
261
|
// y=0 is allowed
|
|
267
262
|
}
|
|
@@ -291,12 +286,12 @@ export function twistedEdwards(curveDef) {
|
|
|
291
286
|
}
|
|
292
287
|
toRawBytes() {
|
|
293
288
|
const { x, y } = this.toAffine();
|
|
294
|
-
const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
|
|
289
|
+
const bytes = ut.numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
|
|
295
290
|
bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
|
|
296
291
|
return bytes; // and use the last byte to encode sign of x
|
|
297
292
|
}
|
|
298
293
|
toHex() {
|
|
299
|
-
return bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string.
|
|
294
|
+
return ut.bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string.
|
|
300
295
|
}
|
|
301
296
|
}
|
|
302
297
|
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
|
|
@@ -308,7 +303,7 @@ export function twistedEdwards(curveDef) {
|
|
|
308
303
|
}
|
|
309
304
|
// Little-endian SHA512 with modulo n
|
|
310
305
|
function modN_LE(hash) {
|
|
311
|
-
return modN(bytesToNumberLE(hash));
|
|
306
|
+
return modN(ut.bytesToNumberLE(hash));
|
|
312
307
|
}
|
|
313
308
|
function isHex(item, err) {
|
|
314
309
|
if (typeof item !== 'string' && !(item instanceof Uint8Array))
|
|
@@ -334,7 +329,7 @@ export function twistedEdwards(curveDef) {
|
|
|
334
329
|
}
|
|
335
330
|
// int('LE', SHA512(dom2(F, C) || msgs)) mod N
|
|
336
331
|
function hashDomainToScalar(context = new Uint8Array(), ...msgs) {
|
|
337
|
-
const msg = concatBytes(...msgs);
|
|
332
|
+
const msg = ut.concatBytes(...msgs);
|
|
338
333
|
return modN_LE(cHash(domain(msg, ensureBytes(context), !!preHash)));
|
|
339
334
|
}
|
|
340
335
|
/** Signs message with privateKey. RFC8032 5.1.6 */
|
|
@@ -349,7 +344,7 @@ export function twistedEdwards(curveDef) {
|
|
|
349
344
|
const k = hashDomainToScalar(context, R, pointBytes, msg); // R || A || PH(M)
|
|
350
345
|
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
|
351
346
|
assertGE0(s); // 0 <= s < l
|
|
352
|
-
const res = concatBytes(R, numberToBytesLE(s, Fp.BYTES));
|
|
347
|
+
const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES));
|
|
353
348
|
return ensureBytes(res, nByteLength * 2); // 64-byte signature
|
|
354
349
|
}
|
|
355
350
|
function verify(sig, msg, publicKey, context) {
|
|
@@ -362,7 +357,7 @@ export function twistedEdwards(curveDef) {
|
|
|
362
357
|
msg = preHash(msg); // for ed25519ph, etc
|
|
363
358
|
const A = Point.fromHex(publicKey, false); // Check for s bounds, hex validity
|
|
364
359
|
const R = Point.fromHex(sig.slice(0, len), false); // 0 <= R < 2^256: ZIP215 R can be >= P
|
|
365
|
-
const s = bytesToNumberLE(sig.slice(len, 2 * len)); // 0 <= s < l
|
|
360
|
+
const s = ut.bytesToNumberLE(sig.slice(len, 2 * len)); // 0 <= s < l
|
|
366
361
|
const SB = G.multiplyUnsafe(s);
|
|
367
362
|
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
|
|
368
363
|
const RkA = R.add(A.multiplyUnsafe(k));
|
|
@@ -16,7 +16,7 @@ export function validateOpts(opts) {
|
|
|
16
16
|
}
|
|
17
17
|
export function stringToBytes(str) {
|
|
18
18
|
if (typeof str !== 'string') {
|
|
19
|
-
throw new
|
|
19
|
+
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
|
|
20
20
|
}
|
|
21
21
|
return new TextEncoder().encode(str);
|
|
22
22
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
// Utilities for modular arithmetics and finite fields
|
|
3
|
-
import { bitMask, numberToBytesBE, numberToBytesLE, bytesToNumberBE, bytesToNumberLE, ensureBytes, } from './utils.js';
|
|
3
|
+
import { bitMask, numberToBytesBE, numberToBytesLE, bytesToNumberBE, bytesToNumberLE, ensureBytes, validateObject, } from './utils.js';
|
|
4
4
|
// prettier-ignore
|
|
5
5
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
|
|
6
6
|
// prettier-ignore
|
|
@@ -34,7 +34,6 @@ export function pow(num, power, modulo) {
|
|
|
34
34
|
return res;
|
|
35
35
|
}
|
|
36
36
|
// Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
|
|
37
|
-
// TODO: Fp version?
|
|
38
37
|
export function pow2(x, power, modulo) {
|
|
39
38
|
let res = x;
|
|
40
39
|
while (power-- > _0n) {
|
|
@@ -193,18 +192,17 @@ const FIELD_FIELDS = [
|
|
|
193
192
|
'addN', 'subN', 'mulN', 'sqrN'
|
|
194
193
|
];
|
|
195
194
|
export function validateField(field) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
195
|
+
const initial = {
|
|
196
|
+
ORDER: 'bigint',
|
|
197
|
+
MASK: 'bigint',
|
|
198
|
+
BYTES: 'isSafeInteger',
|
|
199
|
+
BITS: 'isSafeInteger',
|
|
200
|
+
};
|
|
201
|
+
const opts = FIELD_FIELDS.reduce((map, val) => {
|
|
202
|
+
map[val] = 'function';
|
|
203
|
+
return map;
|
|
204
|
+
}, initial);
|
|
205
|
+
return validateObject(field, opts);
|
|
208
206
|
}
|
|
209
207
|
// Generic field functions
|
|
210
208
|
export function FpPow(f, num, power) {
|