@noble/curves 0.3.1 → 0.4.0
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 +2 -1
- package/lib/bls.d.ts +79 -0
- package/lib/bls.js +304 -0
- package/lib/edwards.d.ts +10 -6
- package/lib/edwards.js +16 -11
- package/lib/esm/bls.js +300 -0
- package/lib/esm/edwards.js +17 -12
- package/lib/esm/group.js +2 -2
- package/lib/esm/hashToCurve.js +105 -0
- package/lib/esm/modular.js +131 -50
- package/lib/esm/utils.js +25 -19
- package/lib/esm/weierstrass.js +351 -272
- package/lib/group.js +2 -2
- package/lib/hashToCurve.d.ts +13 -0
- package/lib/hashToCurve.js +112 -0
- package/lib/modular.d.ts +37 -17
- package/lib/modular.js +138 -54
- package/lib/utils.d.ts +28 -10
- package/lib/utils.js +31 -22
- package/lib/weierstrass.d.ts +106 -69
- package/lib/weierstrass.js +352 -272
- package/package.json +23 -44
- package/lib/crypto.d.ts +0 -4
- package/lib/crypto.js +0 -8
- package/lib/cryptoBrowser.d.ts +0 -4
- package/lib/cryptoBrowser.js +0 -7
- package/lib/definitions/_shortw_utils.d.ts +0 -63
- package/lib/definitions/_shortw_utils.js +0 -18
- package/lib/definitions/bn.d.ts +0 -7
- package/lib/definitions/bn.js +0 -23
- package/lib/definitions/ed25519.d.ts +0 -49
- package/lib/definitions/ed25519.js +0 -308
- package/lib/definitions/ed448.d.ts +0 -3
- package/lib/definitions/ed448.js +0 -127
- package/lib/definitions/index.d.ts +0 -0
- package/lib/definitions/index.js +0 -2
- package/lib/definitions/jubjub.d.ts +0 -7
- package/lib/definitions/jubjub.js +0 -55
- package/lib/definitions/p192.d.ts +0 -112
- package/lib/definitions/p192.js +0 -23
- package/lib/definitions/p224.d.ts +0 -112
- package/lib/definitions/p224.js +0 -24
- package/lib/definitions/p256.d.ts +0 -112
- package/lib/definitions/p256.js +0 -23
- package/lib/definitions/p384.d.ts +0 -112
- package/lib/definitions/p384.js +0 -24
- package/lib/definitions/p521.d.ts +0 -113
- package/lib/definitions/p521.js +0 -36
- package/lib/definitions/pasta.d.ts +0 -2
- package/lib/definitions/pasta.js +0 -32
- package/lib/definitions/secp256k1.d.ts +0 -87
- package/lib/definitions/secp256k1.js +0 -245
- package/lib/definitions/stark.d.ts +0 -62
- package/lib/definitions/stark.js +0 -248
- package/lib/esm/crypto.js +0 -5
- package/lib/esm/cryptoBrowser.js +0 -4
- package/lib/esm/definitions/_shortw_utils.js +0 -13
- package/lib/esm/definitions/bn.js +0 -20
- package/lib/esm/definitions/ed25519.js +0 -304
- package/lib/esm/definitions/ed448.js +0 -124
- package/lib/esm/definitions/index.js +0 -2
- package/lib/esm/definitions/jubjub.js +0 -50
- package/lib/esm/definitions/p192.js +0 -20
- package/lib/esm/definitions/p224.js +0 -21
- package/lib/esm/definitions/p256.js +0 -20
- package/lib/esm/definitions/p384.js +0 -21
- package/lib/esm/definitions/p521.js +0 -33
- package/lib/esm/definitions/pasta.js +0 -29
- package/lib/esm/definitions/secp256k1.js +0 -241
- package/lib/esm/definitions/stark.js +0 -227
package/lib/group.js
CHANGED
|
@@ -12,8 +12,6 @@ function wNAF(c, bits) {
|
|
|
12
12
|
return condition ? neg : item;
|
|
13
13
|
};
|
|
14
14
|
const opts = (W) => {
|
|
15
|
-
if (256 % W)
|
|
16
|
-
throw new Error('Invalid precomputation window, must be power of 2');
|
|
17
15
|
const windows = Math.ceil(bits / W) + 1; // +1, because
|
|
18
16
|
const windowSize = 2 ** (W - 1); // -1 because we skip zero
|
|
19
17
|
return { windows, windowSize };
|
|
@@ -62,6 +60,8 @@ function wNAF(c, bits) {
|
|
|
62
60
|
* @returns real and fake (for const-time) points
|
|
63
61
|
*/
|
|
64
62
|
wNAF(W, precomputes, n) {
|
|
63
|
+
// TODO: maybe check that scalar is less than group order? wNAF will fail otherwise
|
|
64
|
+
// But need to carefully remove other checks before wNAF. ORDER == bits here
|
|
65
65
|
const { windows, windowSize } = opts(W);
|
|
66
66
|
let p = c.ZERO;
|
|
67
67
|
let f = c.BASE;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CHash } from './utils.js';
|
|
2
|
+
export declare type htfOpts = {
|
|
3
|
+
DST: string;
|
|
4
|
+
p: bigint;
|
|
5
|
+
m: number;
|
|
6
|
+
k: number;
|
|
7
|
+
expand: boolean;
|
|
8
|
+
hash: CHash;
|
|
9
|
+
};
|
|
10
|
+
export declare function validateHTFOpts(opts: htfOpts): void;
|
|
11
|
+
export declare function stringToBytes(str: string): Uint8Array;
|
|
12
|
+
export declare function expand_message_xmd(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H: CHash): Uint8Array;
|
|
13
|
+
export declare function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hash_to_field = exports.expand_message_xmd = exports.stringToBytes = exports.validateHTFOpts = void 0;
|
|
4
|
+
const utils_js_1 = require("./utils.js");
|
|
5
|
+
const mod = require("./modular.js");
|
|
6
|
+
function validateHTFOpts(opts) {
|
|
7
|
+
if (typeof opts.DST !== 'string')
|
|
8
|
+
throw new Error('Invalid htf/DST');
|
|
9
|
+
if (typeof opts.p !== 'bigint')
|
|
10
|
+
throw new Error('Invalid htf/p');
|
|
11
|
+
if (typeof opts.m !== 'number')
|
|
12
|
+
throw new Error('Invalid htf/m');
|
|
13
|
+
if (typeof opts.k !== 'number')
|
|
14
|
+
throw new Error('Invalid htf/k');
|
|
15
|
+
if (typeof opts.expand !== 'boolean')
|
|
16
|
+
throw new Error('Invalid htf/expand');
|
|
17
|
+
if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
|
|
18
|
+
throw new Error('Invalid htf/hash function');
|
|
19
|
+
}
|
|
20
|
+
exports.validateHTFOpts = validateHTFOpts;
|
|
21
|
+
// UTF8 to ui8a
|
|
22
|
+
function stringToBytes(str) {
|
|
23
|
+
const bytes = new Uint8Array(str.length);
|
|
24
|
+
for (let i = 0; i < str.length; i++)
|
|
25
|
+
bytes[i] = str.charCodeAt(i);
|
|
26
|
+
return bytes;
|
|
27
|
+
}
|
|
28
|
+
exports.stringToBytes = stringToBytes;
|
|
29
|
+
// Octet Stream to Integer (bytesToNumberBE)
|
|
30
|
+
function os2ip(bytes) {
|
|
31
|
+
let result = 0n;
|
|
32
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
33
|
+
result <<= 8n;
|
|
34
|
+
result += BigInt(bytes[i]);
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
// Integer to Octet Stream
|
|
39
|
+
function i2osp(value, length) {
|
|
40
|
+
if (value < 0 || value >= 1 << (8 * length)) {
|
|
41
|
+
throw new Error(`bad I2OSP call: value=${value} length=${length}`);
|
|
42
|
+
}
|
|
43
|
+
const res = Array.from({ length }).fill(0);
|
|
44
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
45
|
+
res[i] = value & 0xff;
|
|
46
|
+
value >>>= 8;
|
|
47
|
+
}
|
|
48
|
+
return new Uint8Array(res);
|
|
49
|
+
}
|
|
50
|
+
function strxor(a, b) {
|
|
51
|
+
const arr = new Uint8Array(a.length);
|
|
52
|
+
for (let i = 0; i < a.length; i++) {
|
|
53
|
+
arr[i] = a[i] ^ b[i];
|
|
54
|
+
}
|
|
55
|
+
return arr;
|
|
56
|
+
}
|
|
57
|
+
// Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits
|
|
58
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1
|
|
59
|
+
function expand_message_xmd(msg, DST, lenInBytes, H) {
|
|
60
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3
|
|
61
|
+
if (DST.length > 255)
|
|
62
|
+
DST = H((0, utils_js_1.concatBytes)(stringToBytes('H2C-OVERSIZE-DST-'), DST));
|
|
63
|
+
const b_in_bytes = H.outputLen;
|
|
64
|
+
const r_in_bytes = b_in_bytes * 2;
|
|
65
|
+
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
|
66
|
+
if (ell > 255)
|
|
67
|
+
throw new Error('Invalid xmd length');
|
|
68
|
+
const DST_prime = (0, utils_js_1.concatBytes)(DST, i2osp(DST.length, 1));
|
|
69
|
+
const Z_pad = i2osp(0, r_in_bytes);
|
|
70
|
+
const l_i_b_str = i2osp(lenInBytes, 2);
|
|
71
|
+
const b = new Array(ell);
|
|
72
|
+
const b_0 = H((0, utils_js_1.concatBytes)(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime));
|
|
73
|
+
b[0] = H((0, utils_js_1.concatBytes)(b_0, i2osp(1, 1), DST_prime));
|
|
74
|
+
for (let i = 1; i <= ell; i++) {
|
|
75
|
+
const args = [strxor(b_0, b[i - 1]), i2osp(i + 1, 1), DST_prime];
|
|
76
|
+
b[i] = H((0, utils_js_1.concatBytes)(...args));
|
|
77
|
+
}
|
|
78
|
+
const pseudo_random_bytes = (0, utils_js_1.concatBytes)(...b);
|
|
79
|
+
return pseudo_random_bytes.slice(0, lenInBytes);
|
|
80
|
+
}
|
|
81
|
+
exports.expand_message_xmd = expand_message_xmd;
|
|
82
|
+
// hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
|
83
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
|
84
|
+
// Inputs:
|
|
85
|
+
// msg - a byte string containing the message to hash.
|
|
86
|
+
// count - the number of elements of F to output.
|
|
87
|
+
// Outputs:
|
|
88
|
+
// [u_0, ..., u_(count - 1)], a list of field elements.
|
|
89
|
+
function hash_to_field(msg, count, options) {
|
|
90
|
+
// if options is provided but incomplete, fill any missing fields with the
|
|
91
|
+
// value in hftDefaults (ie hash to G2).
|
|
92
|
+
const log2p = options.p.toString(2).length;
|
|
93
|
+
const L = Math.ceil((log2p + options.k) / 8); // section 5.1 of ietf draft link above
|
|
94
|
+
const len_in_bytes = count * options.m * L;
|
|
95
|
+
const DST = stringToBytes(options.DST);
|
|
96
|
+
let pseudo_random_bytes = msg;
|
|
97
|
+
if (options.expand) {
|
|
98
|
+
pseudo_random_bytes = expand_message_xmd(msg, DST, len_in_bytes, options.hash);
|
|
99
|
+
}
|
|
100
|
+
const u = new Array(count);
|
|
101
|
+
for (let i = 0; i < count; i++) {
|
|
102
|
+
const e = new Array(options.m);
|
|
103
|
+
for (let j = 0; j < options.m; j++) {
|
|
104
|
+
const elm_offset = L * (j + i * options.m);
|
|
105
|
+
const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L);
|
|
106
|
+
e[j] = mod.mod(os2ip(tv), options.p);
|
|
107
|
+
}
|
|
108
|
+
u[i] = e;
|
|
109
|
+
}
|
|
110
|
+
return u;
|
|
111
|
+
}
|
|
112
|
+
exports.hash_to_field = hash_to_field;
|
package/lib/modular.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
1
|
export declare function mod(a: bigint, b: bigint): bigint;
|
|
3
2
|
/**
|
|
4
3
|
* Efficiently exponentiate num to power and do modular division.
|
|
@@ -9,30 +8,51 @@ export declare function mod(a: bigint, b: bigint): bigint;
|
|
|
9
8
|
export declare function pow(num: bigint, power: bigint, modulo: bigint): bigint;
|
|
10
9
|
export declare function pow2(x: bigint, power: bigint, modulo: bigint): bigint;
|
|
11
10
|
export declare function invert(number: bigint, modulo: bigint): bigint;
|
|
12
|
-
/**
|
|
13
|
-
* Division over finite field.
|
|
14
|
-
* `a/b mod p == a * invert(b) mod p`
|
|
15
|
-
*/
|
|
16
|
-
export declare function div(numerator: bigint, denominator: bigint, modulo: bigint): bigint;
|
|
17
|
-
/**
|
|
18
|
-
* Takes a list of numbers, efficiently inverts all of them.
|
|
19
|
-
* @param nums list of bigints
|
|
20
|
-
* @param p modulo
|
|
21
|
-
* @returns list of inverted bigints
|
|
22
|
-
* @example
|
|
23
|
-
* invertBatch([1n, 2n, 4n], 21n);
|
|
24
|
-
* // => [1n, 11n, 16n]
|
|
25
|
-
*/
|
|
26
|
-
export declare function invertBatch(nums: bigint[], modulo: bigint): bigint[];
|
|
27
11
|
/**
|
|
28
12
|
* Calculates Legendre symbol (a | p), which denotes the value of a^((p-1)/2) (mod p).
|
|
29
13
|
* * (a | p) ≡ 1 if a is a square (mod p)
|
|
30
14
|
* * (a | p) ≡ -1 if a is not a square (mod p)
|
|
31
15
|
* * (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
32
16
|
*/
|
|
33
|
-
export declare function legendre(num: bigint,
|
|
17
|
+
export declare function legendre(num: bigint, fieldPrime: bigint): bigint;
|
|
34
18
|
/**
|
|
35
19
|
* Calculates square root of a number in a finite field.
|
|
36
20
|
*/
|
|
37
21
|
export declare function sqrt(number: bigint, modulo: bigint): bigint;
|
|
38
22
|
export declare const isNegativeLE: (num: bigint, modulo: bigint) => boolean;
|
|
23
|
+
export interface Field<T> {
|
|
24
|
+
ORDER: bigint;
|
|
25
|
+
BYTES: number;
|
|
26
|
+
BITS: number;
|
|
27
|
+
MASK: bigint;
|
|
28
|
+
ZERO: T;
|
|
29
|
+
ONE: T;
|
|
30
|
+
create: (num: T) => T;
|
|
31
|
+
isValid: (num: T) => boolean;
|
|
32
|
+
isZero: (num: T) => boolean;
|
|
33
|
+
negate(num: T): T;
|
|
34
|
+
invert(num: T): T;
|
|
35
|
+
sqrt(num: T): T;
|
|
36
|
+
square(num: T): T;
|
|
37
|
+
equals(lhs: T, rhs: T): boolean;
|
|
38
|
+
add(lhs: T, rhs: T): T;
|
|
39
|
+
subtract(lhs: T, rhs: T): T;
|
|
40
|
+
multiply(lhs: T, rhs: T | bigint): T;
|
|
41
|
+
pow(lhs: T, power: bigint): T;
|
|
42
|
+
div(lhs: T, rhs: T | bigint): T;
|
|
43
|
+
addN(lhs: T, rhs: T): T;
|
|
44
|
+
subtractN(lhs: T, rhs: T): T;
|
|
45
|
+
multiplyN(lhs: T, rhs: T | bigint): T;
|
|
46
|
+
squareN(num: T): T;
|
|
47
|
+
isOdd?(num: T): boolean;
|
|
48
|
+
legendre?(num: T): T;
|
|
49
|
+
pow(lhs: T, power: bigint): T;
|
|
50
|
+
invertBatch: (lst: T[]) => T[];
|
|
51
|
+
toBytes(num: T): Uint8Array;
|
|
52
|
+
fromBytes(bytes: Uint8Array): T;
|
|
53
|
+
}
|
|
54
|
+
export declare function validateField<T>(field: Field<T>): void;
|
|
55
|
+
export declare function FpPow<T>(f: Field<T>, num: T, power: bigint): T;
|
|
56
|
+
export declare function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[];
|
|
57
|
+
export declare function FpDiv<T>(f: Field<T>, lhs: T, rhs: T | bigint): T;
|
|
58
|
+
export declare function Fp(ORDER: bigint, bitLen?: number, isLE?: boolean, redef?: Partial<Field<bigint>>): Readonly<Field<bigint>>;
|
package/lib/modular.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
3
|
+
exports.Fp = exports.FpDiv = exports.FpInvertBatch = exports.FpPow = exports.validateField = exports.isNegativeLE = exports.sqrt = exports.legendre = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
|
|
4
|
+
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
|
+
const utils = require("./utils.js");
|
|
5
6
|
// Utilities for modular arithmetics
|
|
6
7
|
const _0n = BigInt(0);
|
|
7
8
|
const _1n = BigInt(1);
|
|
@@ -18,6 +19,7 @@ exports.mod = mod;
|
|
|
18
19
|
* @example
|
|
19
20
|
* powMod(2n, 6n, 11n) // 64n % 11n == 9n
|
|
20
21
|
*/
|
|
22
|
+
// TODO: use field version && remove
|
|
21
23
|
function pow(num, power, modulo) {
|
|
22
24
|
if (modulo <= _0n || power < _0n)
|
|
23
25
|
throw new Error('Expected power/modulo > 0');
|
|
@@ -34,6 +36,7 @@ function pow(num, power, modulo) {
|
|
|
34
36
|
}
|
|
35
37
|
exports.pow = pow;
|
|
36
38
|
// Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
|
|
39
|
+
// TODO: Fp version?
|
|
37
40
|
function pow2(x, power, modulo) {
|
|
38
41
|
let res = x;
|
|
39
42
|
while (power-- > _0n) {
|
|
@@ -67,59 +70,20 @@ function invert(number, modulo) {
|
|
|
67
70
|
return mod(x, modulo);
|
|
68
71
|
}
|
|
69
72
|
exports.invert = invert;
|
|
70
|
-
/**
|
|
71
|
-
* Division over finite field.
|
|
72
|
-
* `a/b mod p == a * invert(b) mod p`
|
|
73
|
-
*/
|
|
74
|
-
function div(numerator, denominator, modulo) {
|
|
75
|
-
const num = mod(numerator, modulo);
|
|
76
|
-
const iden = invert(denominator, modulo);
|
|
77
|
-
return mod(num * iden, modulo);
|
|
78
|
-
}
|
|
79
|
-
exports.div = div;
|
|
80
|
-
/**
|
|
81
|
-
* Takes a list of numbers, efficiently inverts all of them.
|
|
82
|
-
* @param nums list of bigints
|
|
83
|
-
* @param p modulo
|
|
84
|
-
* @returns list of inverted bigints
|
|
85
|
-
* @example
|
|
86
|
-
* invertBatch([1n, 2n, 4n], 21n);
|
|
87
|
-
* // => [1n, 11n, 16n]
|
|
88
|
-
*/
|
|
89
|
-
function invertBatch(nums, modulo) {
|
|
90
|
-
const scratch = new Array(nums.length);
|
|
91
|
-
// Walk from first to last, multiply them by each other MOD p
|
|
92
|
-
const lastMultiplied = nums.reduce((acc, num, i) => {
|
|
93
|
-
if (num === _0n)
|
|
94
|
-
return acc;
|
|
95
|
-
scratch[i] = acc;
|
|
96
|
-
return mod(acc * num, modulo);
|
|
97
|
-
}, _1n);
|
|
98
|
-
// Invert last element
|
|
99
|
-
const inverted = invert(lastMultiplied, modulo);
|
|
100
|
-
// Walk from last to first, multiply them by inverted each other MOD p
|
|
101
|
-
nums.reduceRight((acc, num, i) => {
|
|
102
|
-
if (num === _0n)
|
|
103
|
-
return acc;
|
|
104
|
-
scratch[i] = mod(acc * scratch[i], modulo);
|
|
105
|
-
return mod(acc * num, modulo);
|
|
106
|
-
}, inverted);
|
|
107
|
-
return scratch;
|
|
108
|
-
}
|
|
109
|
-
exports.invertBatch = invertBatch;
|
|
110
73
|
/**
|
|
111
74
|
* Calculates Legendre symbol (a | p), which denotes the value of a^((p-1)/2) (mod p).
|
|
112
75
|
* * (a | p) ≡ 1 if a is a square (mod p)
|
|
113
76
|
* * (a | p) ≡ -1 if a is not a square (mod p)
|
|
114
77
|
* * (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
115
78
|
*/
|
|
116
|
-
function legendre(num,
|
|
117
|
-
return pow(num, (
|
|
79
|
+
function legendre(num, fieldPrime) {
|
|
80
|
+
return pow(num, (fieldPrime - _1n) / _2n, fieldPrime);
|
|
118
81
|
}
|
|
119
82
|
exports.legendre = legendre;
|
|
120
83
|
/**
|
|
121
84
|
* Calculates square root of a number in a finite field.
|
|
122
85
|
*/
|
|
86
|
+
// TODO: rewrite as generic Fp function && remove bls versions
|
|
123
87
|
function sqrt(number, modulo) {
|
|
124
88
|
// prettier-ignore
|
|
125
89
|
const _3n = BigInt(3), _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);
|
|
@@ -128,8 +92,17 @@ function sqrt(number, modulo) {
|
|
|
128
92
|
const p1div4 = (P + _1n) / _4n;
|
|
129
93
|
// P ≡ 3 (mod 4)
|
|
130
94
|
// sqrt n = n^((P+1)/4)
|
|
131
|
-
if (P % _4n === _3n)
|
|
132
|
-
|
|
95
|
+
if (P % _4n === _3n) {
|
|
96
|
+
// Not all roots possible!
|
|
97
|
+
// const ORDER =
|
|
98
|
+
// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
|
|
99
|
+
// const NUM = 72057594037927816n;
|
|
100
|
+
// TODO: fix sqrtMod in secp256k1
|
|
101
|
+
const root = pow(n, p1div4, P);
|
|
102
|
+
if (mod(root * root, modulo) !== number)
|
|
103
|
+
throw new Error('Cannot find square root');
|
|
104
|
+
return root;
|
|
105
|
+
}
|
|
133
106
|
// P ≡ 5 (mod 8)
|
|
134
107
|
if (P % _8n === _5n) {
|
|
135
108
|
const n2 = mod(n * _2n, P);
|
|
@@ -140,7 +113,6 @@ function sqrt(number, modulo) {
|
|
|
140
113
|
return r;
|
|
141
114
|
}
|
|
142
115
|
// Other cases: Tonelli-Shanks algorithm
|
|
143
|
-
// Check whether n is square
|
|
144
116
|
if (legendre(n, P) !== _1n)
|
|
145
117
|
throw new Error('Cannot find square root');
|
|
146
118
|
let q, s, z;
|
|
@@ -174,10 +146,122 @@ exports.sqrt = sqrt;
|
|
|
174
146
|
// Little-endian check for first LE bit (last BE bit);
|
|
175
147
|
const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
|
|
176
148
|
exports.isNegativeLE = isNegativeLE;
|
|
177
|
-
//
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
149
|
+
// prettier-ignore
|
|
150
|
+
const FIELD_FIELDS = [
|
|
151
|
+
'create', 'isValid', 'isZero', 'negate', 'invert', 'sqrt', 'square',
|
|
152
|
+
'equals', 'add', 'subtract', 'multiply', 'pow', 'div',
|
|
153
|
+
'addN', 'subtractN', 'multiplyN', 'squareN'
|
|
154
|
+
];
|
|
155
|
+
function validateField(field) {
|
|
156
|
+
for (const i of ['ORDER', 'MASK']) {
|
|
157
|
+
if (typeof field[i] !== 'bigint')
|
|
158
|
+
throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
|
|
159
|
+
}
|
|
160
|
+
for (const i of ['BYTES', 'BITS']) {
|
|
161
|
+
if (typeof field[i] !== 'number')
|
|
162
|
+
throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
|
|
163
|
+
}
|
|
164
|
+
for (const i of FIELD_FIELDS) {
|
|
165
|
+
if (typeof field[i] !== 'function')
|
|
166
|
+
throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
exports.validateField = validateField;
|
|
170
|
+
// Generic field functions
|
|
171
|
+
function FpPow(f, num, power) {
|
|
172
|
+
// Should have same speed as pow for bigints
|
|
173
|
+
// TODO: benchmark!
|
|
174
|
+
if (power < _0n)
|
|
175
|
+
throw new Error('Expected power > 0');
|
|
176
|
+
if (power === _0n)
|
|
177
|
+
return f.ONE;
|
|
178
|
+
if (power === _1n)
|
|
179
|
+
return num;
|
|
180
|
+
let p = f.ONE;
|
|
181
|
+
let d = num;
|
|
182
|
+
while (power > _0n) {
|
|
183
|
+
if (power & _1n)
|
|
184
|
+
p = f.multiply(p, d);
|
|
185
|
+
d = f.square(d);
|
|
186
|
+
power >>= 1n;
|
|
187
|
+
}
|
|
188
|
+
return p;
|
|
189
|
+
}
|
|
190
|
+
exports.FpPow = FpPow;
|
|
191
|
+
function FpInvertBatch(f, nums) {
|
|
192
|
+
const tmp = new Array(nums.length);
|
|
193
|
+
// Walk from first to last, multiply them by each other MOD p
|
|
194
|
+
const lastMultiplied = nums.reduce((acc, num, i) => {
|
|
195
|
+
if (f.isZero(num))
|
|
196
|
+
return acc;
|
|
197
|
+
tmp[i] = acc;
|
|
198
|
+
return f.multiply(acc, num);
|
|
199
|
+
}, f.ONE);
|
|
200
|
+
// Invert last element
|
|
201
|
+
const inverted = f.invert(lastMultiplied);
|
|
202
|
+
// Walk from last to first, multiply them by inverted each other MOD p
|
|
203
|
+
nums.reduceRight((acc, num, i) => {
|
|
204
|
+
if (f.isZero(num))
|
|
205
|
+
return acc;
|
|
206
|
+
tmp[i] = f.multiply(acc, tmp[i]);
|
|
207
|
+
return f.multiply(acc, num);
|
|
208
|
+
}, inverted);
|
|
209
|
+
return tmp;
|
|
210
|
+
}
|
|
211
|
+
exports.FpInvertBatch = FpInvertBatch;
|
|
212
|
+
function FpDiv(f, lhs, rhs) {
|
|
213
|
+
return f.multiply(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.invert(rhs));
|
|
214
|
+
}
|
|
215
|
+
exports.FpDiv = FpDiv;
|
|
216
|
+
// NOTE: very fragile, always bench. Major performance points:
|
|
217
|
+
// - NonNormalized ops
|
|
218
|
+
// - Object.freeze
|
|
219
|
+
// - same shape of object (don't add/remove keys)
|
|
220
|
+
function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
221
|
+
if (ORDER <= _0n)
|
|
222
|
+
throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
|
|
223
|
+
const { nBitLength: BITS, nByteLength: BYTES } = utils.nLength(ORDER, bitLen);
|
|
224
|
+
if (BYTES > 2048)
|
|
225
|
+
throw new Error('Field lengths over 2048 bytes are not supported');
|
|
226
|
+
const sqrtP = (num) => sqrt(num, ORDER);
|
|
227
|
+
const f = Object.freeze({
|
|
228
|
+
ORDER,
|
|
229
|
+
BITS,
|
|
230
|
+
BYTES,
|
|
231
|
+
MASK: utils.bitMask(BITS),
|
|
232
|
+
ZERO: _0n,
|
|
233
|
+
ONE: _1n,
|
|
234
|
+
create: (num) => mod(num, ORDER),
|
|
235
|
+
isValid: (num) => {
|
|
236
|
+
if (typeof num !== 'bigint')
|
|
237
|
+
throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
|
|
238
|
+
return _0n <= num && num < ORDER;
|
|
239
|
+
},
|
|
240
|
+
isZero: (num) => num === _0n,
|
|
241
|
+
isOdd: (num) => (num & _1n) === _1n,
|
|
242
|
+
negate: (num) => mod(-num, ORDER),
|
|
243
|
+
equals: (lhs, rhs) => lhs === rhs,
|
|
244
|
+
square: (num) => mod(num * num, ORDER),
|
|
245
|
+
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
|
|
246
|
+
subtract: (lhs, rhs) => mod(lhs - rhs, ORDER),
|
|
247
|
+
multiply: (lhs, rhs) => mod(lhs * rhs, ORDER),
|
|
248
|
+
pow: (num, power) => FpPow(f, num, power),
|
|
249
|
+
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
|
|
250
|
+
// Same as above, but doesn't normalize
|
|
251
|
+
squareN: (num) => num * num,
|
|
252
|
+
addN: (lhs, rhs) => lhs + rhs,
|
|
253
|
+
subtractN: (lhs, rhs) => lhs - rhs,
|
|
254
|
+
multiplyN: (lhs, rhs) => lhs * rhs,
|
|
255
|
+
invert: (num) => invert(num, ORDER),
|
|
256
|
+
sqrt: redef.sqrt || sqrtP,
|
|
257
|
+
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
258
|
+
toBytes: (num) => isLE ? utils.numberToBytesLE(num, BYTES) : utils.numberToBytesBE(num, BYTES),
|
|
259
|
+
fromBytes: (bytes) => {
|
|
260
|
+
if (bytes.length !== BYTES)
|
|
261
|
+
throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
|
|
262
|
+
return isLE ? utils.bytesToNumberLE(bytes) : utils.bytesToNumberBE(bytes);
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
return Object.freeze(f);
|
|
266
|
+
}
|
|
267
|
+
exports.Fp = Fp;
|
package/lib/utils.d.ts
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
+
import * as mod from './modular.js';
|
|
2
3
|
export declare type Hex = Uint8Array | string;
|
|
3
4
|
export declare type PrivKey = Hex | bigint | number;
|
|
4
|
-
export declare type
|
|
5
|
-
|
|
5
|
+
export declare type CHash = {
|
|
6
|
+
(message: Uint8Array | string): Uint8Array;
|
|
7
|
+
blockLen: number;
|
|
8
|
+
outputLen: number;
|
|
9
|
+
create(): any;
|
|
10
|
+
};
|
|
11
|
+
export declare type BasicCurve<T> = {
|
|
12
|
+
Fp: mod.Field<T>;
|
|
6
13
|
n: bigint;
|
|
7
14
|
nBitLength?: number;
|
|
8
15
|
nByteLength?: number;
|
|
9
16
|
h: bigint;
|
|
10
|
-
|
|
11
|
-
|
|
17
|
+
hEff?: bigint;
|
|
18
|
+
Gx: T;
|
|
19
|
+
Gy: T;
|
|
20
|
+
wrapPrivateKey?: boolean;
|
|
21
|
+
allowInfinityPoint?: boolean;
|
|
12
22
|
};
|
|
13
|
-
export declare function validateOpts<T
|
|
23
|
+
export declare function validateOpts<FP, T>(curve: BasicCurve<FP> & T): Readonly<{
|
|
14
24
|
readonly nBitLength: number;
|
|
15
25
|
readonly nByteLength: number;
|
|
16
|
-
} & T>;
|
|
26
|
+
} & BasicCurve<FP> & T>;
|
|
17
27
|
export declare function bytesToHex(uint8a: Uint8Array): string;
|
|
18
28
|
export declare function numberToHexUnpadded(num: number | bigint): string;
|
|
19
29
|
export declare function hexToNumber(hex: string): bigint;
|
|
@@ -28,9 +38,17 @@ export declare function nLength(n: bigint, nBitLength?: number): {
|
|
|
28
38
|
nBitLength: number;
|
|
29
39
|
nByteLength: number;
|
|
30
40
|
};
|
|
31
|
-
export declare function hashToPrivateScalar(hash: Hex, CURVE_ORDER: bigint, isLE?: boolean): bigint;
|
|
32
|
-
export declare function equalBytes(b1: Uint8Array, b2: Uint8Array): boolean;
|
|
33
41
|
/**
|
|
34
|
-
*
|
|
42
|
+
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
43
|
+
* and convert them into private scalar, with the modulo bias being neglible.
|
|
44
|
+
* As per FIPS 186 B.4.1.
|
|
45
|
+
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
46
|
+
* @param hash hash output from sha512, or a similar function
|
|
47
|
+
* @returns valid private scalar
|
|
35
48
|
*/
|
|
36
|
-
export declare function
|
|
49
|
+
export declare function hashToPrivateScalar(hash: Hex, CURVE_ORDER: bigint, isLE?: boolean): bigint;
|
|
50
|
+
export declare function equalBytes(b1: Uint8Array, b2: Uint8Array): boolean;
|
|
51
|
+
export declare function bitLen(n: bigint): number;
|
|
52
|
+
export declare const bitGet: (n: bigint, pos: number) => bigint;
|
|
53
|
+
export declare const bitSet: (n: bigint, pos: number, value: boolean) => bigint;
|
|
54
|
+
export declare const bitMask: (n: number) => bigint;
|
package/lib/utils.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
3
|
+
exports.bitMask = exports.bitSet = exports.bitGet = exports.bitLen = exports.equalBytes = exports.hashToPrivateScalar = exports.nLength = exports.concatBytes = exports.ensureBytes = exports.numberToBytesLE = exports.numberToBytesBE = exports.bytesToNumberLE = exports.bytesToNumberBE = exports.hexToBytes = exports.hexToNumber = exports.numberToHexUnpadded = exports.bytesToHex = exports.validateOpts = void 0;
|
|
4
|
+
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
|
+
const mod = require("./modular.js");
|
|
6
|
+
const _0n = BigInt(0);
|
|
7
|
+
const _1n = BigInt(1);
|
|
8
|
+
const _2n = BigInt(2);
|
|
8
9
|
function validateOpts(curve) {
|
|
9
|
-
|
|
10
|
+
mod.validateField(curve.Fp);
|
|
11
|
+
for (const i of ['n', 'h']) {
|
|
10
12
|
if (typeof curve[i] !== 'bigint')
|
|
11
13
|
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
|
|
12
14
|
}
|
|
15
|
+
if (!curve.Fp.isValid(curve.Gx))
|
|
16
|
+
throw new Error('Invalid generator X coordinate Fp element');
|
|
17
|
+
if (!curve.Fp.isValid(curve.Gy))
|
|
18
|
+
throw new Error('Invalid generator Y coordinate Fp element');
|
|
13
19
|
for (const i of ['nBitLength', 'nByteLength']) {
|
|
14
20
|
if (curve[i] === undefined)
|
|
15
21
|
continue; // Optional
|
|
@@ -20,7 +26,6 @@ function validateOpts(curve) {
|
|
|
20
26
|
return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve });
|
|
21
27
|
}
|
|
22
28
|
exports.validateOpts = validateOpts;
|
|
23
|
-
const mod = require("./modular.js");
|
|
24
29
|
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
|
|
25
30
|
function bytesToHex(uint8a) {
|
|
26
31
|
if (!(uint8a instanceof Uint8Array))
|
|
@@ -121,7 +126,6 @@ exports.nLength = nLength;
|
|
|
121
126
|
* @param hash hash output from sha512, or a similar function
|
|
122
127
|
* @returns valid private scalar
|
|
123
128
|
*/
|
|
124
|
-
const _1n = BigInt(1);
|
|
125
129
|
function hashToPrivateScalar(hash, CURVE_ORDER, isLE = false) {
|
|
126
130
|
hash = ensureBytes(hash);
|
|
127
131
|
const orderLen = nLength(CURVE_ORDER).nByteLength;
|
|
@@ -142,18 +146,23 @@ function equalBytes(b1, b2) {
|
|
|
142
146
|
return true;
|
|
143
147
|
}
|
|
144
148
|
exports.equalBytes = equalBytes;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
else if (crypto_1.crypto.node) {
|
|
153
|
-
return new Uint8Array(crypto_1.crypto.node.randomBytes(bytesLength).buffer);
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
throw new Error("The environment doesn't have randomBytes function");
|
|
157
|
-
}
|
|
149
|
+
// Bit operations
|
|
150
|
+
// Amount of bits inside bigint (Same as n.toString(2).length)
|
|
151
|
+
function bitLen(n) {
|
|
152
|
+
let len;
|
|
153
|
+
for (len = 0; n > 0n; n >>= _1n, len += 1)
|
|
154
|
+
;
|
|
155
|
+
return len;
|
|
158
156
|
}
|
|
159
|
-
exports.
|
|
157
|
+
exports.bitLen = bitLen;
|
|
158
|
+
// Gets single bit at position. NOTE: first bit position is 0 (same as arrays)
|
|
159
|
+
// Same as !!+Array.from(n.toString(2)).reverse()[pos]
|
|
160
|
+
const bitGet = (n, pos) => (n >> BigInt(pos)) & 1n;
|
|
161
|
+
exports.bitGet = bitGet;
|
|
162
|
+
// Sets single bit at position
|
|
163
|
+
const bitSet = (n, pos, value) => n | ((value ? _1n : _0n) << BigInt(pos));
|
|
164
|
+
exports.bitSet = bitSet;
|
|
165
|
+
// Return mask for N bits (Same as BigInt(`0b${Array(i).fill('1').join('')}`))
|
|
166
|
+
// Not using ** operator with bigints for old engines.
|
|
167
|
+
const bitMask = (n) => (_2n << BigInt(n - 1)) - _1n;
|
|
168
|
+
exports.bitMask = bitMask;
|