@noble/curves 0.5.2 → 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.
Files changed (61) hide show
  1. package/README.md +115 -41
  2. package/lib/_shortw_utils.d.ts +13 -24
  3. package/lib/abstract/bls.d.ts +39 -32
  4. package/lib/abstract/bls.js +74 -73
  5. package/lib/abstract/{group.d.ts → curve.d.ts} +30 -1
  6. package/lib/abstract/{group.js → curve.js} +33 -2
  7. package/lib/abstract/edwards.d.ts +30 -72
  8. package/lib/abstract/edwards.js +206 -389
  9. package/lib/abstract/hash-to-curve.d.ts +25 -6
  10. package/lib/abstract/hash-to-curve.js +40 -12
  11. package/lib/abstract/modular.d.ts +21 -8
  12. package/lib/abstract/modular.js +72 -48
  13. package/lib/abstract/montgomery.js +23 -68
  14. package/lib/abstract/poseidon.d.ts +29 -0
  15. package/lib/abstract/poseidon.js +115 -0
  16. package/lib/abstract/utils.d.ts +9 -37
  17. package/lib/abstract/utils.js +61 -87
  18. package/lib/abstract/weierstrass.d.ts +58 -81
  19. package/lib/abstract/weierstrass.js +485 -679
  20. package/lib/bls12-381.js +63 -58
  21. package/lib/bn.js +1 -1
  22. package/lib/ed25519.d.ts +7 -5
  23. package/lib/ed25519.js +82 -79
  24. package/lib/ed448.d.ts +3 -0
  25. package/lib/ed448.js +86 -83
  26. package/lib/esm/abstract/bls.js +75 -74
  27. package/lib/esm/abstract/{group.js → curve.js} +31 -1
  28. package/lib/esm/abstract/edwards.js +204 -387
  29. package/lib/esm/abstract/hash-to-curve.js +38 -11
  30. package/lib/esm/abstract/modular.js +69 -47
  31. package/lib/esm/abstract/montgomery.js +24 -69
  32. package/lib/esm/abstract/poseidon.js +109 -0
  33. package/lib/esm/abstract/utils.js +58 -82
  34. package/lib/esm/abstract/weierstrass.js +484 -678
  35. package/lib/esm/bls12-381.js +75 -70
  36. package/lib/esm/bn.js +1 -1
  37. package/lib/esm/ed25519.js +80 -78
  38. package/lib/esm/ed448.js +84 -82
  39. package/lib/esm/jubjub.js +1 -1
  40. package/lib/esm/p224.js +1 -1
  41. package/lib/esm/p256.js +11 -9
  42. package/lib/esm/p384.js +11 -9
  43. package/lib/esm/p521.js +12 -23
  44. package/lib/esm/secp256k1.js +124 -162
  45. package/lib/esm/stark.js +105 -41
  46. package/lib/jubjub.d.ts +2 -2
  47. package/lib/jubjub.js +1 -1
  48. package/lib/p192.d.ts +26 -48
  49. package/lib/p224.d.ts +26 -48
  50. package/lib/p224.js +1 -1
  51. package/lib/p256.d.ts +29 -48
  52. package/lib/p256.js +13 -10
  53. package/lib/p384.d.ts +29 -48
  54. package/lib/p384.js +13 -10
  55. package/lib/p521.d.ts +37 -57
  56. package/lib/p521.js +14 -24
  57. package/lib/secp256k1.d.ts +37 -46
  58. package/lib/secp256k1.js +124 -162
  59. package/lib/stark.d.ts +39 -22
  60. package/lib/stark.js +108 -41
  61. package/package.json +15 -10
@@ -1,15 +1,17 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
- import { CHash } from './utils.js';
3
- import * as mod from './modular.js';
4
- export declare type htfOpts = {
2
+ import type { Group, GroupConstructor, AffinePoint } from './curve.js';
3
+ import { Field } from './modular.js';
4
+ import { CHash, Hex } from './utils.js';
5
+ export declare type Opts = {
5
6
  DST: string;
7
+ encodeDST: string;
6
8
  p: bigint;
7
9
  m: number;
8
10
  k: number;
9
11
  expand?: 'xmd' | 'xof';
10
12
  hash: CHash;
11
13
  };
12
- export declare function validateHTFOpts(opts: htfOpts): void;
14
+ export declare function validateOpts(opts: Opts): void;
13
15
  export declare function stringToBytes(str: string): Uint8Array;
14
16
  export declare function expand_message_xmd(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H: CHash): Uint8Array;
15
17
  export declare function expand_message_xof(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, k: number, H: CHash): Uint8Array;
@@ -21,8 +23,25 @@ export declare function expand_message_xof(msg: Uint8Array, DST: Uint8Array, len
21
23
  * @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
22
24
  * @returns [u_0, ..., u_(count - 1)], a list of field elements.
23
25
  */
24
- export declare function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
25
- export declare function isogenyMap<T, F extends mod.Field<T>>(field: F, map: [T[], T[], T[], T[]]): (x: T, y: T) => {
26
+ export declare function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][];
27
+ export declare function isogenyMap<T, F extends Field<T>>(field: F, map: [T[], T[], T[], T[]]): (x: T, y: T) => {
26
28
  x: T;
27
29
  y: T;
28
30
  };
31
+ export interface H2CPoint<T> extends Group<H2CPoint<T>> {
32
+ add(rhs: H2CPoint<T>): H2CPoint<T>;
33
+ toAffine(iz?: bigint): AffinePoint<T>;
34
+ clearCofactor(): H2CPoint<T>;
35
+ assertValidity(): void;
36
+ }
37
+ export interface H2CPointConstructor<T> extends GroupConstructor<H2CPoint<T>> {
38
+ fromAffine(ap: AffinePoint<T>): H2CPoint<T>;
39
+ }
40
+ export declare type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
41
+ export declare type htfBasicOpts = {
42
+ DST: string;
43
+ };
44
+ export declare function hashToCurve<T>(Point: H2CPointConstructor<T>, mapToCurve: MapToCurve<T>, def: Opts): {
45
+ hashToCurve(msg: Hex, options?: htfBasicOpts): H2CPoint<T>;
46
+ encodeToCurve(msg: Hex, options?: htfBasicOpts): H2CPoint<T>;
47
+ };
@@ -1,10 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.stringToBytes = exports.validateHTFOpts = void 0;
4
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
3
+ exports.hashToCurve = exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.stringToBytes = exports.validateOpts = void 0;
4
+ const modular_js_1 = require("./modular.js");
5
5
  const utils_js_1 = require("./utils.js");
6
- const mod = require("./modular.js");
7
- function validateHTFOpts(opts) {
6
+ function validateOpts(opts) {
8
7
  if (typeof opts.DST !== 'string')
9
8
  throw new Error('Invalid htf/DST');
10
9
  if (typeof opts.p !== 'bigint')
@@ -18,14 +17,12 @@ function validateHTFOpts(opts) {
18
17
  if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
19
18
  throw new Error('Invalid htf/hash function');
20
19
  }
21
- exports.validateHTFOpts = validateHTFOpts;
22
- // UTF8 to ui8a
23
- // TODO: looks broken, ASCII only, why not TextEncoder/TextDecoder? it is in hashes anyway
20
+ exports.validateOpts = validateOpts;
24
21
  function stringToBytes(str) {
25
- const bytes = new Uint8Array(str.length);
26
- for (let i = 0; i < str.length; i++)
27
- bytes[i] = str.charCodeAt(i);
28
- return bytes;
22
+ if (typeof str !== 'string') {
23
+ throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
24
+ }
25
+ return new TextEncoder().encode(str);
29
26
  }
30
27
  exports.stringToBytes = stringToBytes;
31
28
  // Octet Stream to Integer (bytesToNumberBE)
@@ -127,7 +124,7 @@ function hash_to_field(msg, count, options) {
127
124
  for (let j = 0; j < options.m; j++) {
128
125
  const elm_offset = L * (j + i * options.m);
129
126
  const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L);
130
- e[j] = mod.mod(os2ip(tv), options.p);
127
+ e[j] = (0, modular_js_1.mod)(os2ip(tv), options.p);
131
128
  }
132
129
  u[i] = e;
133
130
  }
@@ -145,3 +142,34 @@ function isogenyMap(field, map) {
145
142
  };
146
143
  }
147
144
  exports.isogenyMap = isogenyMap;
145
+ function hashToCurve(Point, mapToCurve, def) {
146
+ validateOpts(def);
147
+ if (typeof mapToCurve !== 'function')
148
+ throw new Error('hashToCurve: mapToCurve() has not been defined');
149
+ return {
150
+ // Encodes byte string to elliptic curve
151
+ // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
152
+ hashToCurve(msg, options) {
153
+ if (!mapToCurve)
154
+ throw new Error('CURVE.mapToCurve() has not been defined');
155
+ msg = (0, utils_js_1.ensureBytes)(msg);
156
+ const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options });
157
+ const P = Point.fromAffine(mapToCurve(u[0]))
158
+ .add(Point.fromAffine(mapToCurve(u[1])))
159
+ .clearCofactor();
160
+ P.assertValidity();
161
+ return P;
162
+ },
163
+ // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
164
+ encodeToCurve(msg, options) {
165
+ if (!mapToCurve)
166
+ throw new Error('CURVE.mapToCurve() has not been defined');
167
+ msg = (0, utils_js_1.ensureBytes)(msg);
168
+ const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options });
169
+ const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
170
+ P.assertValidity();
171
+ return P;
172
+ },
173
+ };
174
+ }
175
+ exports.hashToCurve = hashToCurve;
@@ -20,12 +20,12 @@ export interface Field<T> {
20
20
  ONE: T;
21
21
  create: (num: T) => T;
22
22
  isValid: (num: T) => boolean;
23
- isZero: (num: T) => boolean;
24
- negate(num: T): T;
25
- invert(num: T): T;
23
+ is0: (num: T) => boolean;
24
+ neg(num: T): T;
25
+ inv(num: T): T;
26
26
  sqrt(num: T): T;
27
- square(num: T): T;
28
- equals(lhs: T, rhs: T): boolean;
27
+ sqr(num: T): T;
28
+ eql(lhs: T, rhs: T): boolean;
29
29
  add(lhs: T, rhs: T): T;
30
30
  sub(lhs: T, rhs: T): T;
31
31
  mul(lhs: T, rhs: T | bigint): T;
@@ -34,22 +34,35 @@ export interface Field<T> {
34
34
  addN(lhs: T, rhs: T): T;
35
35
  subN(lhs: T, rhs: T): T;
36
36
  mulN(lhs: T, rhs: T | bigint): T;
37
- squareN(num: T): T;
37
+ sqrN(num: T): T;
38
38
  isOdd?(num: T): boolean;
39
- legendre?(num: T): T;
40
39
  pow(lhs: T, power: bigint): T;
41
40
  invertBatch: (lst: T[]) => T[];
42
41
  toBytes(num: T): Uint8Array;
43
42
  fromBytes(bytes: Uint8Array): T;
44
43
  cmov(a: T, b: T, c: boolean): T;
45
44
  }
46
- export declare function validateField<T>(field: Field<T>): void;
45
+ export declare function validateField<T>(field: Field<T>): object;
47
46
  export declare function FpPow<T>(f: Field<T>, num: T, power: bigint): T;
48
47
  export declare function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[];
49
48
  export declare function FpDiv<T>(f: Field<T>, lhs: T, rhs: T | bigint): T;
50
49
  export declare function FpIsSquare<T>(f: Field<T>): (x: T) => boolean;
50
+ export declare function nLength(n: bigint, nBitLength?: number): {
51
+ nBitLength: number;
52
+ nByteLength: number;
53
+ };
51
54
  declare type FpField = Field<bigint> & Required<Pick<Field<bigint>, 'isOdd'>>;
52
55
  export declare function Fp(ORDER: bigint, bitLen?: number, isLE?: boolean, redef?: Partial<Field<bigint>>): Readonly<FpField>;
53
56
  export declare function FpSqrtOdd<T>(Fp: Field<T>, elm: T): T;
54
57
  export declare function FpSqrtEven<T>(Fp: Field<T>, elm: T): T;
58
+ /**
59
+ * FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
60
+ * Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
61
+ * and convert them into private scalar, with the modulo bias being neglible.
62
+ * Needs at least 40 bytes of input for 32-byte private key.
63
+ * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
64
+ * @param hash hash output from SHA3 or a similar function
65
+ * @returns valid private scalar
66
+ */
67
+ export declare function hashToPrivateScalar(hash: string | Uint8Array, groupOrder: bigint, isLE?: boolean): bigint;
55
68
  export {};
@@ -1,10 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FpSqrtEven = exports.FpSqrtOdd = exports.Fp = exports.FpIsSquare = exports.FpDiv = exports.FpInvertBatch = exports.FpPow = exports.validateField = exports.isNegativeLE = exports.FpSqrt = exports.tonelliShanks = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
3
+ exports.hashToPrivateScalar = exports.FpSqrtEven = exports.FpSqrtOdd = exports.Fp = exports.nLength = exports.FpIsSquare = exports.FpDiv = exports.FpInvertBatch = exports.FpPow = exports.validateField = exports.isNegativeLE = exports.FpSqrt = exports.tonelliShanks = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
4
4
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5
- // TODO: remove circular imports
6
- const utils = require("./utils.js");
7
5
  // Utilities for modular arithmetics and finite fields
6
+ const utils_js_1 = require("./utils.js");
8
7
  // prettier-ignore
9
8
  const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
10
9
  // prettier-ignore
@@ -40,7 +39,6 @@ function pow(num, power, modulo) {
40
39
  }
41
40
  exports.pow = pow;
42
41
  // Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
43
- // TODO: Fp version?
44
42
  function pow2(x, power, modulo) {
45
43
  let res = x;
46
44
  while (power-- > _0n) {
@@ -98,7 +96,7 @@ function tonelliShanks(P) {
98
96
  const p1div4 = (P + _1n) / _4n;
99
97
  return function tonelliFast(Fp, n) {
100
98
  const root = Fp.pow(n, p1div4);
101
- if (!Fp.equals(Fp.square(root), n))
99
+ if (!Fp.eql(Fp.sqr(root), n))
102
100
  throw new Error('Cannot find square root');
103
101
  return root;
104
102
  };
@@ -107,26 +105,26 @@ function tonelliShanks(P) {
107
105
  const Q1div2 = (Q + _1n) / _2n;
108
106
  return function tonelliSlow(Fp, n) {
109
107
  // Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
110
- if (Fp.pow(n, legendreC) === Fp.negate(Fp.ONE))
108
+ if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE))
111
109
  throw new Error('Cannot find square root');
112
110
  let r = S;
113
111
  // TODO: will fail at Fp2/etc
114
112
  let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b
115
113
  let x = Fp.pow(n, Q1div2); // first guess at the square root
116
114
  let b = Fp.pow(n, Q); // first guess at the fudge factor
117
- while (!Fp.equals(b, Fp.ONE)) {
118
- if (Fp.equals(b, Fp.ZERO))
115
+ while (!Fp.eql(b, Fp.ONE)) {
116
+ if (Fp.eql(b, Fp.ZERO))
119
117
  return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
120
118
  // Find m such b^(2^m)==1
121
119
  let m = 1;
122
- for (let t2 = Fp.square(b); m < r; m++) {
123
- if (Fp.equals(t2, Fp.ONE))
120
+ for (let t2 = Fp.sqr(b); m < r; m++) {
121
+ if (Fp.eql(t2, Fp.ONE))
124
122
  break;
125
- t2 = Fp.square(t2); // t2 *= t2
123
+ t2 = Fp.sqr(t2); // t2 *= t2
126
124
  }
127
125
  // NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
128
126
  const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)
129
- g = Fp.square(ge); // g = ge * ge
127
+ g = Fp.sqr(ge); // g = ge * ge
130
128
  x = Fp.mul(x, ge); // x *= ge
131
129
  b = Fp.mul(b, g); // b *= g
132
130
  r = m;
@@ -149,7 +147,7 @@ function FpSqrt(P) {
149
147
  return function sqrt3mod4(Fp, n) {
150
148
  const root = Fp.pow(n, p1div4);
151
149
  // Throw if root**2 != n
152
- if (!Fp.equals(Fp.square(root), n))
150
+ if (!Fp.eql(Fp.sqr(root), n))
153
151
  throw new Error('Cannot find square root');
154
152
  return root;
155
153
  };
@@ -163,7 +161,7 @@ function FpSqrt(P) {
163
161
  const nv = Fp.mul(n, v);
164
162
  const i = Fp.mul(Fp.mul(nv, _2n), v);
165
163
  const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
166
- if (!Fp.equals(Fp.square(root), n))
164
+ if (!Fp.eql(Fp.sqr(root), n))
167
165
  throw new Error('Cannot find square root');
168
166
  return root;
169
167
  };
@@ -199,23 +197,22 @@ const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
199
197
  exports.isNegativeLE = isNegativeLE;
200
198
  // prettier-ignore
201
199
  const FIELD_FIELDS = [
202
- 'create', 'isValid', 'isZero', 'negate', 'invert', 'sqrt', 'square',
203
- 'equals', 'add', 'sub', 'mul', 'pow', 'div',
204
- 'addN', 'subN', 'mulN', 'squareN'
200
+ 'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
201
+ 'eql', 'add', 'sub', 'mul', 'pow', 'div',
202
+ 'addN', 'subN', 'mulN', 'sqrN'
205
203
  ];
206
204
  function validateField(field) {
207
- for (const i of ['ORDER', 'MASK']) {
208
- if (typeof field[i] !== 'bigint')
209
- throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
210
- }
211
- for (const i of ['BYTES', 'BITS']) {
212
- if (typeof field[i] !== 'number')
213
- throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
214
- }
215
- for (const i of FIELD_FIELDS) {
216
- if (typeof field[i] !== 'function')
217
- throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
218
- }
205
+ const initial = {
206
+ ORDER: 'bigint',
207
+ MASK: 'bigint',
208
+ BYTES: 'isSafeInteger',
209
+ BITS: 'isSafeInteger',
210
+ };
211
+ const opts = FIELD_FIELDS.reduce((map, val) => {
212
+ map[val] = 'function';
213
+ return map;
214
+ }, initial);
215
+ return (0, utils_js_1.validateObject)(field, opts);
219
216
  }
220
217
  exports.validateField = validateField;
221
218
  // Generic field functions
@@ -233,7 +230,7 @@ function FpPow(f, num, power) {
233
230
  while (power > _0n) {
234
231
  if (power & _1n)
235
232
  p = f.mul(p, d);
236
- d = f.square(d);
233
+ d = f.sqr(d);
237
234
  power >>= 1n;
238
235
  }
239
236
  return p;
@@ -243,16 +240,16 @@ function FpInvertBatch(f, nums) {
243
240
  const tmp = new Array(nums.length);
244
241
  // Walk from first to last, multiply them by each other MOD p
245
242
  const lastMultiplied = nums.reduce((acc, num, i) => {
246
- if (f.isZero(num))
243
+ if (f.is0(num))
247
244
  return acc;
248
245
  tmp[i] = acc;
249
246
  return f.mul(acc, num);
250
247
  }, f.ONE);
251
248
  // Invert last element
252
- const inverted = f.invert(lastMultiplied);
249
+ const inverted = f.inv(lastMultiplied);
253
250
  // Walk from last to first, multiply them by inverted each other MOD p
254
251
  nums.reduceRight((acc, num, i) => {
255
- if (f.isZero(num))
252
+ if (f.is0(num))
256
253
  return acc;
257
254
  tmp[i] = f.mul(acc, tmp[i]);
258
255
  return f.mul(acc, num);
@@ -261,7 +258,7 @@ function FpInvertBatch(f, nums) {
261
258
  }
262
259
  exports.FpInvertBatch = FpInvertBatch;
263
260
  function FpDiv(f, lhs, rhs) {
264
- return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.invert(rhs));
261
+ return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
265
262
  }
266
263
  exports.FpDiv = FpDiv;
267
264
  // This function returns True whenever the value x is a square in the field F.
@@ -269,14 +266,22 @@ function FpIsSquare(f) {
269
266
  const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
270
267
  return (x) => {
271
268
  const p = f.pow(x, legendreConst);
272
- return f.equals(p, f.ZERO) || f.equals(p, f.ONE);
269
+ return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
273
270
  };
274
271
  }
275
272
  exports.FpIsSquare = FpIsSquare;
273
+ // CURVE.n lengths
274
+ function nLength(n, nBitLength) {
275
+ // Bit size, byte size of CURVE.n
276
+ const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
277
+ const nByteLength = Math.ceil(_nBitLength / 8);
278
+ return { nBitLength: _nBitLength, nByteLength };
279
+ }
280
+ exports.nLength = nLength;
276
281
  function Fp(ORDER, bitLen, isLE = false, redef = {}) {
277
282
  if (ORDER <= _0n)
278
283
  throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
279
- const { nBitLength: BITS, nByteLength: BYTES } = utils.nLength(ORDER, bitLen);
284
+ const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
280
285
  if (BYTES > 2048)
281
286
  throw new Error('Field lengths over 2048 bytes are not supported');
282
287
  const sqrtP = FpSqrt(ORDER);
@@ -284,41 +289,41 @@ function Fp(ORDER, bitLen, isLE = false, redef = {}) {
284
289
  ORDER,
285
290
  BITS,
286
291
  BYTES,
287
- MASK: utils.bitMask(BITS),
292
+ MASK: (0, utils_js_1.bitMask)(BITS),
288
293
  ZERO: _0n,
289
294
  ONE: _1n,
290
295
  create: (num) => mod(num, ORDER),
291
296
  isValid: (num) => {
292
297
  if (typeof num !== 'bigint')
293
298
  throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
294
- return _0n <= num && num < ORDER;
299
+ return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
295
300
  },
296
- isZero: (num) => num === _0n,
301
+ is0: (num) => num === _0n,
297
302
  isOdd: (num) => (num & _1n) === _1n,
298
- negate: (num) => mod(-num, ORDER),
299
- equals: (lhs, rhs) => lhs === rhs,
300
- square: (num) => mod(num * num, ORDER),
303
+ neg: (num) => mod(-num, ORDER),
304
+ eql: (lhs, rhs) => lhs === rhs,
305
+ sqr: (num) => mod(num * num, ORDER),
301
306
  add: (lhs, rhs) => mod(lhs + rhs, ORDER),
302
307
  sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
303
308
  mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
304
309
  pow: (num, power) => FpPow(f, num, power),
305
310
  div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
306
311
  // Same as above, but doesn't normalize
307
- squareN: (num) => num * num,
312
+ sqrN: (num) => num * num,
308
313
  addN: (lhs, rhs) => lhs + rhs,
309
314
  subN: (lhs, rhs) => lhs - rhs,
310
315
  mulN: (lhs, rhs) => lhs * rhs,
311
- invert: (num) => invert(num, ORDER),
316
+ inv: (num) => invert(num, ORDER),
312
317
  sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
313
318
  invertBatch: (lst) => FpInvertBatch(f, lst),
314
319
  // TODO: do we really need constant cmov?
315
320
  // We don't have const-time bigints anyway, so probably will be not very useful
316
321
  cmov: (a, b, c) => (c ? b : a),
317
- toBytes: (num) => isLE ? utils.numberToBytesLE(num, BYTES) : utils.numberToBytesBE(num, BYTES),
322
+ toBytes: (num) => (isLE ? (0, utils_js_1.numberToBytesLE)(num, BYTES) : (0, utils_js_1.numberToBytesBE)(num, BYTES)),
318
323
  fromBytes: (bytes) => {
319
324
  if (bytes.length !== BYTES)
320
325
  throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
321
- return isLE ? utils.bytesToNumberLE(bytes) : utils.bytesToNumberBE(bytes);
326
+ return isLE ? (0, utils_js_1.bytesToNumberLE)(bytes) : (0, utils_js_1.bytesToNumberBE)(bytes);
322
327
  },
323
328
  });
324
329
  return Object.freeze(f);
@@ -328,13 +333,32 @@ function FpSqrtOdd(Fp, elm) {
328
333
  if (!Fp.isOdd)
329
334
  throw new Error(`Field doesn't have isOdd`);
330
335
  const root = Fp.sqrt(elm);
331
- return Fp.isOdd(root) ? root : Fp.negate(root);
336
+ return Fp.isOdd(root) ? root : Fp.neg(root);
332
337
  }
333
338
  exports.FpSqrtOdd = FpSqrtOdd;
334
339
  function FpSqrtEven(Fp, elm) {
335
340
  if (!Fp.isOdd)
336
341
  throw new Error(`Field doesn't have isOdd`);
337
342
  const root = Fp.sqrt(elm);
338
- return Fp.isOdd(root) ? Fp.negate(root) : root;
343
+ return Fp.isOdd(root) ? Fp.neg(root) : root;
339
344
  }
340
345
  exports.FpSqrtEven = FpSqrtEven;
346
+ /**
347
+ * FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
348
+ * Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
349
+ * and convert them into private scalar, with the modulo bias being neglible.
350
+ * Needs at least 40 bytes of input for 32-byte private key.
351
+ * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
352
+ * @param hash hash output from SHA3 or a similar function
353
+ * @returns valid private scalar
354
+ */
355
+ function hashToPrivateScalar(hash, groupOrder, isLE = false) {
356
+ hash = (0, utils_js_1.ensureBytes)(hash);
357
+ const hashLen = hash.length;
358
+ const minLen = nLength(groupOrder).nByteLength + 8;
359
+ if (minLen < 24 || hashLen < minLen || hashLen > 1024)
360
+ throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);
361
+ const num = isLE ? (0, utils_js_1.bytesToNumberLE)(hash) : (0, utils_js_1.bytesToNumberBE)(hash);
362
+ return mod(num, groupOrder - _1n) + _1n;
363
+ }
364
+ exports.hashToPrivateScalar = hashToPrivateScalar;
@@ -2,35 +2,22 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.montgomery = void 0;
4
4
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5
- const mod = require("./modular.js");
5
+ const modular_js_1 = require("./modular.js");
6
6
  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
- for (const i of ['a24']) {
11
- if (typeof curve[i] !== 'bigint')
12
- throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
13
- }
14
- for (const i of ['montgomeryBits', 'nByteLength']) {
15
- if (curve[i] === undefined)
16
- continue; // Optional
17
- if (!(0, utils_js_1.isPositiveInt)(curve[i]))
18
- throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
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
- // ...nLength(curve.n, curve.nBitLength),
34
21
  return Object.freeze({ ...curve });
35
22
  }
36
23
  // NOTE: not really montgomery curve, just bunch of very specific methods for X25519/X448 (RFC 7748, https://www.rfc-editor.org/rfc/rfc7748)
@@ -38,37 +25,13 @@ function validateOpts(curve) {
38
25
  function montgomery(curveDef) {
39
26
  const CURVE = validateOpts(curveDef);
40
27
  const { P } = CURVE;
41
- const modP = (a) => mod.mod(a, P);
28
+ const modP = (a) => (0, modular_js_1.mod)(a, P);
42
29
  const montgomeryBits = CURVE.montgomeryBits;
43
30
  const montgomeryBytes = Math.ceil(montgomeryBits / 8);
44
31
  const fieldLen = CURVE.nByteLength;
45
32
  const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes);
46
- const powPminus2 = CURVE.powPminus2 || ((x) => mod.pow(x, P - BigInt(2), P));
47
- /**
48
- * Checks for num to be in range:
49
- * For strict == true: `0 < num < max`.
50
- * For strict == false: `0 <= num < max`.
51
- * Converts non-float safe numbers to bigints.
52
- */
53
- function normalizeScalar(num, max, strict = true) {
54
- if (!max)
55
- throw new TypeError('Specify max value');
56
- if (typeof num === 'number' && Number.isSafeInteger(num))
57
- num = BigInt(num);
58
- if (typeof num === 'bigint' && num < max) {
59
- if (strict) {
60
- if (_0n < num)
61
- return num;
62
- }
63
- else {
64
- if (_0n <= num)
65
- return num;
66
- }
67
- }
68
- throw new TypeError('Expected valid scalar: 0 < scalar < max');
69
- }
70
- // cswap from RFC7748
71
- // NOTE: cswap is not from RFC7748!
33
+ const powPminus2 = CURVE.powPminus2 || ((x) => (0, modular_js_1.pow)(x, P - BigInt(2), P));
34
+ // cswap from RFC7748. But it is not from RFC7748!
72
35
  /*
73
36
  cswap(swap, x_2, x_3):
74
37
  dummy = mask(swap) AND (x_2 XOR x_3)
@@ -84,6 +47,11 @@ function montgomery(curveDef) {
84
47
  x_3 = modP(x_3 + dummy);
85
48
  return [x_2, x_3];
86
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
+ }
87
55
  // x25519 from 4
88
56
  /**
89
57
  *
@@ -92,11 +60,10 @@ function montgomery(curveDef) {
92
60
  * @returns new Point on Montgomery curve
93
61
  */
94
62
  function montgomeryLadder(pointU, scalar) {
95
- const { P } = CURVE;
96
- const u = normalizeScalar(pointU, P);
63
+ const u = assertFieldElement(pointU);
97
64
  // Section 5: Implementations MUST accept non-canonical values and process them as
98
65
  // if they had been reduced modulo the field prime.
99
- const k = normalizeScalar(scalar, P);
66
+ const k = assertFieldElement(scalar);
100
67
  // The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519
101
68
  const a24 = CURVE.a24;
102
69
  const x_1 = u;
@@ -149,11 +116,11 @@ function montgomery(curveDef) {
149
116
  return (0, utils_js_1.numberToBytesLE)(modP(u), montgomeryBytes);
150
117
  }
151
118
  function decodeUCoordinate(uEnc) {
152
- const u = (0, utils_js_1.ensureBytes)(uEnc, montgomeryBytes);
153
119
  // Section 5: When receiving such an array, implementations of X25519
154
120
  // MUST mask the most significant bit in the final byte.
155
121
  // This is very ugly way, but it works because fieldLen-1 is outside of bounds for X448, so this becomes NOOP
156
122
  // fieldLen - scalaryBytes = 1 for X448 and = 0 for X25519
123
+ const u = (0, utils_js_1.ensureBytes)(uEnc, montgomeryBytes);
157
124
  u[fieldLen - 1] &= 127; // 0b0111_1111
158
125
  return (0, utils_js_1.bytesToNumberLE)(u);
159
126
  }
@@ -163,13 +130,6 @@ function montgomery(curveDef) {
163
130
  throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${bytes.length}`);
164
131
  return (0, utils_js_1.bytesToNumberLE)(adjustScalarBytes(bytes));
165
132
  }
166
- /**
167
- * Computes shared secret between private key "scalar" and public key's "u" (x) coordinate.
168
- * We can get 'y' coordinate from 'u',
169
- * but Point.fromHex also wants 'x' coordinate oddity flag,
170
- * and we cannot get 'x' without knowing 'v'.
171
- * Need to add generic conversion between twisted edwards and complimentary curve for JubJub.
172
- */
173
133
  function scalarMult(scalar, u) {
174
134
  const pointU = decodeUCoordinate(u);
175
135
  const _scalar = decodeScalar(scalar);
@@ -180,12 +140,7 @@ function montgomery(curveDef) {
180
140
  throw new Error('Invalid private or public key received');
181
141
  return encodeUCoordinate(pu);
182
142
  }
183
- /**
184
- * Computes public key from private.
185
- * Executes scalar multiplication of curve's base point by scalar.
186
- * @param scalar private key
187
- * @returns new public key
188
- */
143
+ // Computes public key from private. By doing scalar multiplication of base point.
189
144
  function scalarMultBase(scalar) {
190
145
  return scalarMult(scalar, CURVE.Gu);
191
146
  }
@@ -0,0 +1,29 @@
1
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
+ import { Field } from './modular.js';
3
+ export declare type PoseidonOpts = {
4
+ Fp: Field<bigint>;
5
+ t: number;
6
+ roundsFull: number;
7
+ roundsPartial: number;
8
+ sboxPower?: number;
9
+ reversePartialPowIdx?: boolean;
10
+ mds: bigint[][];
11
+ roundConstants: bigint[][];
12
+ };
13
+ export declare function validateOpts(opts: PoseidonOpts): Readonly<{
14
+ rounds: number;
15
+ sboxFn: (n: bigint) => bigint;
16
+ roundConstants: bigint[][];
17
+ mds: bigint[][];
18
+ Fp: Field<bigint>;
19
+ t: number;
20
+ roundsFull: number;
21
+ roundsPartial: number;
22
+ sboxPower?: number | undefined;
23
+ reversePartialPowIdx?: boolean | undefined;
24
+ }>;
25
+ export declare function splitConstants(rc: bigint[], t: number): bigint[][];
26
+ export declare function poseidon(opts: PoseidonOpts): {
27
+ (values: bigint[]): bigint[];
28
+ roundConstants: bigint[][];
29
+ };