@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.
Files changed (70) hide show
  1. package/README.md +2 -1
  2. package/lib/bls.d.ts +79 -0
  3. package/lib/bls.js +304 -0
  4. package/lib/edwards.d.ts +10 -6
  5. package/lib/edwards.js +16 -11
  6. package/lib/esm/bls.js +300 -0
  7. package/lib/esm/edwards.js +17 -12
  8. package/lib/esm/group.js +2 -2
  9. package/lib/esm/hashToCurve.js +105 -0
  10. package/lib/esm/modular.js +131 -50
  11. package/lib/esm/utils.js +25 -19
  12. package/lib/esm/weierstrass.js +351 -272
  13. package/lib/group.js +2 -2
  14. package/lib/hashToCurve.d.ts +13 -0
  15. package/lib/hashToCurve.js +112 -0
  16. package/lib/modular.d.ts +37 -17
  17. package/lib/modular.js +138 -54
  18. package/lib/utils.d.ts +28 -10
  19. package/lib/utils.js +31 -22
  20. package/lib/weierstrass.d.ts +106 -69
  21. package/lib/weierstrass.js +352 -272
  22. package/package.json +23 -44
  23. package/lib/crypto.d.ts +0 -4
  24. package/lib/crypto.js +0 -8
  25. package/lib/cryptoBrowser.d.ts +0 -4
  26. package/lib/cryptoBrowser.js +0 -7
  27. package/lib/definitions/_shortw_utils.d.ts +0 -63
  28. package/lib/definitions/_shortw_utils.js +0 -18
  29. package/lib/definitions/bn.d.ts +0 -7
  30. package/lib/definitions/bn.js +0 -23
  31. package/lib/definitions/ed25519.d.ts +0 -49
  32. package/lib/definitions/ed25519.js +0 -308
  33. package/lib/definitions/ed448.d.ts +0 -3
  34. package/lib/definitions/ed448.js +0 -127
  35. package/lib/definitions/index.d.ts +0 -0
  36. package/lib/definitions/index.js +0 -2
  37. package/lib/definitions/jubjub.d.ts +0 -7
  38. package/lib/definitions/jubjub.js +0 -55
  39. package/lib/definitions/p192.d.ts +0 -112
  40. package/lib/definitions/p192.js +0 -23
  41. package/lib/definitions/p224.d.ts +0 -112
  42. package/lib/definitions/p224.js +0 -24
  43. package/lib/definitions/p256.d.ts +0 -112
  44. package/lib/definitions/p256.js +0 -23
  45. package/lib/definitions/p384.d.ts +0 -112
  46. package/lib/definitions/p384.js +0 -24
  47. package/lib/definitions/p521.d.ts +0 -113
  48. package/lib/definitions/p521.js +0 -36
  49. package/lib/definitions/pasta.d.ts +0 -2
  50. package/lib/definitions/pasta.js +0 -32
  51. package/lib/definitions/secp256k1.d.ts +0 -87
  52. package/lib/definitions/secp256k1.js +0 -245
  53. package/lib/definitions/stark.d.ts +0 -62
  54. package/lib/definitions/stark.js +0 -248
  55. package/lib/esm/crypto.js +0 -5
  56. package/lib/esm/cryptoBrowser.js +0 -4
  57. package/lib/esm/definitions/_shortw_utils.js +0 -13
  58. package/lib/esm/definitions/bn.js +0 -20
  59. package/lib/esm/definitions/ed25519.js +0 -304
  60. package/lib/esm/definitions/ed448.js +0 -124
  61. package/lib/esm/definitions/index.js +0 -2
  62. package/lib/esm/definitions/jubjub.js +0 -50
  63. package/lib/esm/definitions/p192.js +0 -20
  64. package/lib/esm/definitions/p224.js +0 -21
  65. package/lib/esm/definitions/p256.js +0 -20
  66. package/lib/esm/definitions/p384.js +0 -21
  67. package/lib/esm/definitions/p521.js +0 -33
  68. package/lib/esm/definitions/pasta.js +0 -29
  69. package/lib/esm/definitions/secp256k1.js +0 -241
  70. 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, P: bigint): 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.isNegativeLE = exports.sqrt = exports.legendre = exports.invertBatch = exports.div = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
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, P) {
117
- return pow(num, (P - _1n) / _2n, P);
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
- return pow(n, p1div4, P);
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
- // An idea on modular arithmetic for bls12-381:
178
- // const FIELD = {add, pow, sqrt, mul};
179
- // Functions will take field elements, no need for an additional class
180
- // Could be faster. 1 bigint field will just do operations and mod later:
181
- // instead of 'r = mod(r * b, P)' we will write r = mul(r, b);
182
- // Could be insecure without shape check, so it needs to be done.
183
- // Functions could be inlined by JIT.
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 BasicCurve = {
5
- P: bigint;
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
- Gx: bigint;
11
- Gy: bigint;
17
+ hEff?: bigint;
18
+ Gx: T;
19
+ Gy: T;
20
+ wrapPrivateKey?: boolean;
21
+ allowInfinityPoint?: boolean;
12
22
  };
13
- export declare function validateOpts<T extends BasicCurve>(curve: T): Readonly<{
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
- * Cryptographically secure PRNG
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 randomBytes(bytesLength?: number): Uint8Array;
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.randomBytes = 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;
5
- // The import here is via the package name. This is to ensure
6
- // that exports mapping/resolution does fall into place.
7
- const crypto_1 = require("@noble/curves/crypto");
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
- for (const i of ['P', 'n', 'h', 'Gx', 'Gy']) {
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
- * Cryptographically secure PRNG
147
- */
148
- function randomBytes(bytesLength = 32) {
149
- if (crypto_1.crypto.web) {
150
- return crypto_1.crypto.web.getRandomValues(new Uint8Array(bytesLength));
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.randomBytes = randomBytes;
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;