@noble/curves 0.5.2 → 0.6.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 (59) hide show
  1. package/README.md +49 -5
  2. package/lib/_shortw_utils.d.ts +10 -21
  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} +31 -1
  6. package/lib/abstract/{group.js → curve.js} +39 -2
  7. package/lib/abstract/edwards.d.ts +30 -72
  8. package/lib/abstract/edwards.js +197 -375
  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 +20 -7
  12. package/lib/abstract/modular.js +61 -35
  13. package/lib/abstract/montgomery.js +4 -5
  14. package/lib/abstract/poseidon.d.ts +29 -0
  15. package/lib/abstract/poseidon.js +115 -0
  16. package/lib/abstract/utils.d.ts +5 -36
  17. package/lib/abstract/utils.js +23 -71
  18. package/lib/abstract/weierstrass.d.ts +51 -74
  19. package/lib/abstract/weierstrass.js +455 -628
  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} +37 -1
  28. package/lib/esm/abstract/edwards.js +196 -374
  29. package/lib/esm/abstract/hash-to-curve.js +38 -11
  30. package/lib/esm/abstract/modular.js +58 -34
  31. package/lib/esm/abstract/montgomery.js +5 -6
  32. package/lib/esm/abstract/poseidon.js +109 -0
  33. package/lib/esm/abstract/utils.js +21 -66
  34. package/lib/esm/abstract/weierstrass.js +454 -627
  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/p256.js +11 -9
  41. package/lib/esm/p384.js +11 -9
  42. package/lib/esm/p521.js +13 -12
  43. package/lib/esm/secp256k1.js +115 -151
  44. package/lib/esm/stark.js +104 -40
  45. package/lib/jubjub.d.ts +2 -2
  46. package/lib/jubjub.js +1 -1
  47. package/lib/p192.d.ts +20 -42
  48. package/lib/p224.d.ts +20 -42
  49. package/lib/p256.d.ts +23 -42
  50. package/lib/p256.js +13 -10
  51. package/lib/p384.d.ts +23 -42
  52. package/lib/p384.js +13 -10
  53. package/lib/p521.d.ts +23 -42
  54. package/lib/p521.js +15 -13
  55. package/lib/secp256k1.d.ts +25 -37
  56. package/lib/secp256k1.js +115 -151
  57. package/lib/stark.d.ts +36 -19
  58. package/lib/stark.js +107 -40
  59. package/package.json +13 -8
@@ -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 TypeError(`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,9 +34,8 @@ 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;
@@ -48,8 +47,22 @@ 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
@@ -98,7 +97,7 @@ function tonelliShanks(P) {
98
97
  const p1div4 = (P + _1n) / _4n;
99
98
  return function tonelliFast(Fp, n) {
100
99
  const root = Fp.pow(n, p1div4);
101
- if (!Fp.equals(Fp.square(root), n))
100
+ if (!Fp.eql(Fp.sqr(root), n))
102
101
  throw new Error('Cannot find square root');
103
102
  return root;
104
103
  };
@@ -107,26 +106,26 @@ function tonelliShanks(P) {
107
106
  const Q1div2 = (Q + _1n) / _2n;
108
107
  return function tonelliSlow(Fp, n) {
109
108
  // 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))
109
+ if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE))
111
110
  throw new Error('Cannot find square root');
112
111
  let r = S;
113
112
  // TODO: will fail at Fp2/etc
114
113
  let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b
115
114
  let x = Fp.pow(n, Q1div2); // first guess at the square root
116
115
  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))
116
+ while (!Fp.eql(b, Fp.ONE)) {
117
+ if (Fp.eql(b, Fp.ZERO))
119
118
  return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
120
119
  // Find m such b^(2^m)==1
121
120
  let m = 1;
122
- for (let t2 = Fp.square(b); m < r; m++) {
123
- if (Fp.equals(t2, Fp.ONE))
121
+ for (let t2 = Fp.sqr(b); m < r; m++) {
122
+ if (Fp.eql(t2, Fp.ONE))
124
123
  break;
125
- t2 = Fp.square(t2); // t2 *= t2
124
+ t2 = Fp.sqr(t2); // t2 *= t2
126
125
  }
127
126
  // NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
128
127
  const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)
129
- g = Fp.square(ge); // g = ge * ge
128
+ g = Fp.sqr(ge); // g = ge * ge
130
129
  x = Fp.mul(x, ge); // x *= ge
131
130
  b = Fp.mul(b, g); // b *= g
132
131
  r = m;
@@ -149,7 +148,7 @@ function FpSqrt(P) {
149
148
  return function sqrt3mod4(Fp, n) {
150
149
  const root = Fp.pow(n, p1div4);
151
150
  // Throw if root**2 != n
152
- if (!Fp.equals(Fp.square(root), n))
151
+ if (!Fp.eql(Fp.sqr(root), n))
153
152
  throw new Error('Cannot find square root');
154
153
  return root;
155
154
  };
@@ -163,7 +162,7 @@ function FpSqrt(P) {
163
162
  const nv = Fp.mul(n, v);
164
163
  const i = Fp.mul(Fp.mul(nv, _2n), v);
165
164
  const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
166
- if (!Fp.equals(Fp.square(root), n))
165
+ if (!Fp.eql(Fp.sqr(root), n))
167
166
  throw new Error('Cannot find square root');
168
167
  return root;
169
168
  };
@@ -199,9 +198,9 @@ const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
199
198
  exports.isNegativeLE = isNegativeLE;
200
199
  // prettier-ignore
201
200
  const FIELD_FIELDS = [
202
- 'create', 'isValid', 'isZero', 'negate', 'invert', 'sqrt', 'square',
203
- 'equals', 'add', 'sub', 'mul', 'pow', 'div',
204
- 'addN', 'subN', 'mulN', 'squareN'
201
+ 'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
202
+ 'eql', 'add', 'sub', 'mul', 'pow', 'div',
203
+ 'addN', 'subN', 'mulN', 'sqrN'
205
204
  ];
206
205
  function validateField(field) {
207
206
  for (const i of ['ORDER', 'MASK']) {
@@ -233,7 +232,7 @@ function FpPow(f, num, power) {
233
232
  while (power > _0n) {
234
233
  if (power & _1n)
235
234
  p = f.mul(p, d);
236
- d = f.square(d);
235
+ d = f.sqr(d);
237
236
  power >>= 1n;
238
237
  }
239
238
  return p;
@@ -243,16 +242,16 @@ function FpInvertBatch(f, nums) {
243
242
  const tmp = new Array(nums.length);
244
243
  // Walk from first to last, multiply them by each other MOD p
245
244
  const lastMultiplied = nums.reduce((acc, num, i) => {
246
- if (f.isZero(num))
245
+ if (f.is0(num))
247
246
  return acc;
248
247
  tmp[i] = acc;
249
248
  return f.mul(acc, num);
250
249
  }, f.ONE);
251
250
  // Invert last element
252
- const inverted = f.invert(lastMultiplied);
251
+ const inverted = f.inv(lastMultiplied);
253
252
  // Walk from last to first, multiply them by inverted each other MOD p
254
253
  nums.reduceRight((acc, num, i) => {
255
- if (f.isZero(num))
254
+ if (f.is0(num))
256
255
  return acc;
257
256
  tmp[i] = f.mul(acc, tmp[i]);
258
257
  return f.mul(acc, num);
@@ -261,7 +260,7 @@ function FpInvertBatch(f, nums) {
261
260
  }
262
261
  exports.FpInvertBatch = FpInvertBatch;
263
262
  function FpDiv(f, lhs, rhs) {
264
- return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.invert(rhs));
263
+ return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
265
264
  }
266
265
  exports.FpDiv = FpDiv;
267
266
  // This function returns True whenever the value x is a square in the field F.
@@ -269,14 +268,22 @@ function FpIsSquare(f) {
269
268
  const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
270
269
  return (x) => {
271
270
  const p = f.pow(x, legendreConst);
272
- return f.equals(p, f.ZERO) || f.equals(p, f.ONE);
271
+ return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
273
272
  };
274
273
  }
275
274
  exports.FpIsSquare = FpIsSquare;
275
+ // CURVE.n lengths
276
+ function nLength(n, nBitLength) {
277
+ // Bit size, byte size of CURVE.n
278
+ const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
279
+ const nByteLength = Math.ceil(_nBitLength / 8);
280
+ return { nBitLength: _nBitLength, nByteLength };
281
+ }
282
+ exports.nLength = nLength;
276
283
  function Fp(ORDER, bitLen, isLE = false, redef = {}) {
277
284
  if (ORDER <= _0n)
278
285
  throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
279
- const { nBitLength: BITS, nByteLength: BYTES } = utils.nLength(ORDER, bitLen);
286
+ const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
280
287
  if (BYTES > 2048)
281
288
  throw new Error('Field lengths over 2048 bytes are not supported');
282
289
  const sqrtP = FpSqrt(ORDER);
@@ -284,41 +291,41 @@ function Fp(ORDER, bitLen, isLE = false, redef = {}) {
284
291
  ORDER,
285
292
  BITS,
286
293
  BYTES,
287
- MASK: utils.bitMask(BITS),
294
+ MASK: (0, utils_js_1.bitMask)(BITS),
288
295
  ZERO: _0n,
289
296
  ONE: _1n,
290
297
  create: (num) => mod(num, ORDER),
291
298
  isValid: (num) => {
292
299
  if (typeof num !== 'bigint')
293
300
  throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
294
- return _0n <= num && num < ORDER;
301
+ return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
295
302
  },
296
- isZero: (num) => num === _0n,
303
+ is0: (num) => num === _0n,
297
304
  isOdd: (num) => (num & _1n) === _1n,
298
- negate: (num) => mod(-num, ORDER),
299
- equals: (lhs, rhs) => lhs === rhs,
300
- square: (num) => mod(num * num, ORDER),
305
+ neg: (num) => mod(-num, ORDER),
306
+ eql: (lhs, rhs) => lhs === rhs,
307
+ sqr: (num) => mod(num * num, ORDER),
301
308
  add: (lhs, rhs) => mod(lhs + rhs, ORDER),
302
309
  sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
303
310
  mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
304
311
  pow: (num, power) => FpPow(f, num, power),
305
312
  div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
306
313
  // Same as above, but doesn't normalize
307
- squareN: (num) => num * num,
314
+ sqrN: (num) => num * num,
308
315
  addN: (lhs, rhs) => lhs + rhs,
309
316
  subN: (lhs, rhs) => lhs - rhs,
310
317
  mulN: (lhs, rhs) => lhs * rhs,
311
- invert: (num) => invert(num, ORDER),
318
+ inv: (num) => invert(num, ORDER),
312
319
  sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
313
320
  invertBatch: (lst) => FpInvertBatch(f, lst),
314
321
  // TODO: do we really need constant cmov?
315
322
  // We don't have const-time bigints anyway, so probably will be not very useful
316
323
  cmov: (a, b, c) => (c ? b : a),
317
- toBytes: (num) => isLE ? utils.numberToBytesLE(num, BYTES) : utils.numberToBytesBE(num, BYTES),
324
+ toBytes: (num) => (isLE ? (0, utils_js_1.numberToBytesLE)(num, BYTES) : (0, utils_js_1.numberToBytesBE)(num, BYTES)),
318
325
  fromBytes: (bytes) => {
319
326
  if (bytes.length !== BYTES)
320
327
  throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
321
- return isLE ? utils.bytesToNumberLE(bytes) : utils.bytesToNumberBE(bytes);
328
+ return isLE ? (0, utils_js_1.bytesToNumberLE)(bytes) : (0, utils_js_1.bytesToNumberBE)(bytes);
322
329
  },
323
330
  });
324
331
  return Object.freeze(f);
@@ -328,13 +335,32 @@ function FpSqrtOdd(Fp, elm) {
328
335
  if (!Fp.isOdd)
329
336
  throw new Error(`Field doesn't have isOdd`);
330
337
  const root = Fp.sqrt(elm);
331
- return Fp.isOdd(root) ? root : Fp.negate(root);
338
+ return Fp.isOdd(root) ? root : Fp.neg(root);
332
339
  }
333
340
  exports.FpSqrtOdd = FpSqrtOdd;
334
341
  function FpSqrtEven(Fp, elm) {
335
342
  if (!Fp.isOdd)
336
343
  throw new Error(`Field doesn't have isOdd`);
337
344
  const root = Fp.sqrt(elm);
338
- return Fp.isOdd(root) ? Fp.negate(root) : root;
345
+ return Fp.isOdd(root) ? Fp.neg(root) : root;
339
346
  }
340
347
  exports.FpSqrtEven = FpSqrtEven;
348
+ /**
349
+ * FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
350
+ * Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
351
+ * and convert them into private scalar, with the modulo bias being neglible.
352
+ * Needs at least 40 bytes of input for 32-byte private key.
353
+ * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
354
+ * @param hash hash output from SHA3 or a similar function
355
+ * @returns valid private scalar
356
+ */
357
+ function hashToPrivateScalar(hash, groupOrder, isLE = false) {
358
+ hash = (0, utils_js_1.ensureBytes)(hash);
359
+ const hashLen = hash.length;
360
+ const minLen = nLength(groupOrder).nByteLength + 8;
361
+ if (minLen < 24 || hashLen < minLen || hashLen > 1024)
362
+ throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);
363
+ const num = isLE ? (0, utils_js_1.bytesToNumberLE)(hash) : (0, utils_js_1.bytesToNumberBE)(hash);
364
+ return mod(num, groupOrder - _1n) + _1n;
365
+ }
366
+ exports.hashToPrivateScalar = hashToPrivateScalar;
@@ -2,7 +2,7 @@
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);
@@ -14,7 +14,7 @@ function validateOpts(curve) {
14
14
  for (const i of ['montgomeryBits', 'nByteLength']) {
15
15
  if (curve[i] === undefined)
16
16
  continue; // Optional
17
- if (!(0, utils_js_1.isPositiveInt)(curve[i]))
17
+ if (!Number.isSafeInteger(curve[i]))
18
18
  throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
19
19
  }
20
20
  for (const fn of ['adjustScalarBytes', 'domain', 'powPminus2']) {
@@ -30,7 +30,6 @@ function validateOpts(curve) {
30
30
  throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
31
31
  }
32
32
  // Set defaults
33
- // ...nLength(curve.n, curve.nBitLength),
34
33
  return Object.freeze({ ...curve });
35
34
  }
36
35
  // NOTE: not really montgomery curve, just bunch of very specific methods for X25519/X448 (RFC 7748, https://www.rfc-editor.org/rfc/rfc7748)
@@ -38,12 +37,12 @@ function validateOpts(curve) {
38
37
  function montgomery(curveDef) {
39
38
  const CURVE = validateOpts(curveDef);
40
39
  const { P } = CURVE;
41
- const modP = (a) => mod.mod(a, P);
40
+ const modP = (a) => (0, modular_js_1.mod)(a, P);
42
41
  const montgomeryBits = CURVE.montgomeryBits;
43
42
  const montgomeryBytes = Math.ceil(montgomeryBits / 8);
44
43
  const fieldLen = CURVE.nByteLength;
45
44
  const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes);
46
- const powPminus2 = CURVE.powPminus2 || ((x) => mod.pow(x, P - BigInt(2), P));
45
+ const powPminus2 = CURVE.powPminus2 || ((x) => (0, modular_js_1.pow)(x, P - BigInt(2), P));
47
46
  /**
48
47
  * Checks for num to be in range:
49
48
  * For strict == true: `0 < num < max`.
@@ -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
+ };
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.poseidon = exports.splitConstants = exports.validateOpts = void 0;
4
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5
+ // Poseidon Hash: https://eprint.iacr.org/2019/458.pdf, https://www.poseidon-hash.info
6
+ const modular_js_1 = require("./modular.js");
7
+ function validateOpts(opts) {
8
+ const { Fp } = opts;
9
+ (0, modular_js_1.validateField)(Fp);
10
+ for (const i of ['t', 'roundsFull', 'roundsPartial']) {
11
+ if (typeof opts[i] !== 'number' || !Number.isSafeInteger(opts[i]))
12
+ throw new Error(`Poseidon: invalid param ${i}=${opts[i]} (${typeof opts[i]})`);
13
+ }
14
+ if (opts.reversePartialPowIdx !== undefined && typeof opts.reversePartialPowIdx !== 'boolean')
15
+ throw new Error(`Poseidon: invalid param reversePartialPowIdx=${opts.reversePartialPowIdx}`);
16
+ // Default is 5, but by some reasons stark uses 3
17
+ let sboxPower = opts.sboxPower;
18
+ if (sboxPower === undefined)
19
+ sboxPower = 5;
20
+ if (typeof sboxPower !== 'number' || !Number.isSafeInteger(sboxPower))
21
+ throw new Error(`Poseidon wrong sboxPower=${sboxPower}`);
22
+ const _sboxPower = BigInt(sboxPower);
23
+ let sboxFn = (n) => (0, modular_js_1.FpPow)(Fp, n, _sboxPower);
24
+ // Unwrapped sbox power for common cases (195->142μs)
25
+ if (sboxPower === 3)
26
+ sboxFn = (n) => Fp.mul(Fp.sqrN(n), n);
27
+ else if (sboxPower === 5)
28
+ sboxFn = (n) => Fp.mul(Fp.sqrN(Fp.sqrN(n)), n);
29
+ if (opts.roundsFull % 2 !== 0)
30
+ throw new Error(`Poseidon roundsFull is not even: ${opts.roundsFull}`);
31
+ const rounds = opts.roundsFull + opts.roundsPartial;
32
+ if (!Array.isArray(opts.roundConstants) || opts.roundConstants.length !== rounds)
33
+ throw new Error('Poseidon: wrong round constants');
34
+ const roundConstants = opts.roundConstants.map((rc) => {
35
+ if (!Array.isArray(rc) || rc.length !== opts.t)
36
+ throw new Error(`Poseidon wrong round constants: ${rc}`);
37
+ return rc.map((i) => {
38
+ if (typeof i !== 'bigint' || !Fp.isValid(i))
39
+ throw new Error(`Poseidon wrong round constant=${i}`);
40
+ return Fp.create(i);
41
+ });
42
+ });
43
+ // MDS is TxT matrix
44
+ if (!Array.isArray(opts.mds) || opts.mds.length !== opts.t)
45
+ throw new Error('Poseidon: wrong MDS matrix');
46
+ const mds = opts.mds.map((mdsRow) => {
47
+ if (!Array.isArray(mdsRow) || mdsRow.length !== opts.t)
48
+ throw new Error(`Poseidon MDS matrix row: ${mdsRow}`);
49
+ return mdsRow.map((i) => {
50
+ if (typeof i !== 'bigint')
51
+ throw new Error(`Poseidon MDS matrix value=${i}`);
52
+ return Fp.create(i);
53
+ });
54
+ });
55
+ return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds });
56
+ }
57
+ exports.validateOpts = validateOpts;
58
+ function splitConstants(rc, t) {
59
+ if (typeof t !== 'number')
60
+ throw new Error('poseidonSplitConstants: wrong t');
61
+ if (!Array.isArray(rc) || rc.length % t)
62
+ throw new Error('poseidonSplitConstants: wrong rc');
63
+ const res = [];
64
+ let tmp = [];
65
+ for (let i = 0; i < rc.length; i++) {
66
+ tmp.push(rc[i]);
67
+ if (tmp.length === t) {
68
+ res.push(tmp);
69
+ tmp = [];
70
+ }
71
+ }
72
+ return res;
73
+ }
74
+ exports.splitConstants = splitConstants;
75
+ function poseidon(opts) {
76
+ const { t, Fp, rounds, sboxFn, reversePartialPowIdx } = validateOpts(opts);
77
+ const halfRoundsFull = Math.floor(opts.roundsFull / 2);
78
+ const partialIdx = reversePartialPowIdx ? t - 1 : 0;
79
+ const poseidonRound = (values, isFull, idx) => {
80
+ values = values.map((i, j) => Fp.add(i, opts.roundConstants[idx][j]));
81
+ if (isFull)
82
+ values = values.map((i) => sboxFn(i));
83
+ else
84
+ values[partialIdx] = sboxFn(values[partialIdx]);
85
+ // Matrix multiplication
86
+ values = opts.mds.map((i) => i.reduce((acc, i, j) => Fp.add(acc, Fp.mulN(i, values[j])), Fp.ZERO));
87
+ return values;
88
+ };
89
+ const poseidonHash = function poseidonHash(values) {
90
+ if (!Array.isArray(values) || values.length !== t)
91
+ throw new Error(`Poseidon: wrong values (expected array of bigints with length ${t})`);
92
+ values = values.map((i) => {
93
+ if (typeof i !== 'bigint')
94
+ throw new Error(`Poseidon: wrong value=${i} (${typeof i})`);
95
+ return Fp.create(i);
96
+ });
97
+ let round = 0;
98
+ // Apply r_f/2 full rounds.
99
+ for (let i = 0; i < halfRoundsFull; i++)
100
+ values = poseidonRound(values, true, round++);
101
+ // Apply r_p partial rounds.
102
+ for (let i = 0; i < opts.roundsPartial; i++)
103
+ values = poseidonRound(values, false, round++);
104
+ // Apply r_f/2 full rounds.
105
+ for (let i = 0; i < halfRoundsFull; i++)
106
+ values = poseidonRound(values, true, round++);
107
+ if (round !== rounds)
108
+ throw new Error(`Poseidon: wrong number of rounds: last round=${round}, total=${rounds}`);
109
+ return values;
110
+ };
111
+ // For verification in tests
112
+ poseidonHash.roundConstants = opts.roundConstants;
113
+ return poseidonHash;
114
+ }
115
+ exports.poseidon = poseidon;
@@ -1,7 +1,5 @@
1
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
- import * as mod from './modular.js';
3
1
  export declare type Hex = Uint8Array | string;
4
- export declare type PrivKey = Hex | bigint | number;
2
+ export declare type PrivKey = Hex | bigint;
5
3
  export declare type CHash = {
6
4
  (message: Uint8Array | string): Uint8Array;
7
5
  blockLen: number;
@@ -10,47 +8,18 @@ export declare type CHash = {
10
8
  dkLen?: number;
11
9
  }): any;
12
10
  };
13
- export declare type BasicCurve<T> = {
14
- Fp: mod.Field<T>;
15
- n: bigint;
16
- nBitLength?: number;
17
- nByteLength?: number;
18
- h: bigint;
19
- hEff?: bigint;
20
- Gx: T;
21
- Gy: T;
22
- wrapPrivateKey?: boolean;
23
- allowInfinityPoint?: boolean;
24
- };
25
- export declare function isPositiveInt(num: any): num is number;
26
- export declare function validateOpts<FP, T>(curve: BasicCurve<FP> & T): Readonly<{
27
- readonly nBitLength: number;
28
- readonly nByteLength: number;
29
- } & BasicCurve<FP> & T>;
30
- export declare function bytesToHex(uint8a: Uint8Array): string;
11
+ export declare type FHash = (message: Uint8Array | string) => Uint8Array;
12
+ export declare function bytesToHex(bytes: Uint8Array): string;
31
13
  export declare function numberToHexUnpadded(num: number | bigint): string;
32
14
  export declare function hexToNumber(hex: string): bigint;
33
15
  export declare function hexToBytes(hex: string): Uint8Array;
34
16
  export declare function bytesToNumberBE(bytes: Uint8Array): bigint;
35
- export declare function bytesToNumberLE(uint8a: Uint8Array): bigint;
17
+ export declare function bytesToNumberLE(bytes: Uint8Array): bigint;
36
18
  export declare const numberToBytesBE: (n: bigint, len: number) => Uint8Array;
37
19
  export declare const numberToBytesLE: (n: bigint, len: number) => Uint8Array;
20
+ export declare const numberToVarBytesBE: (n: bigint) => Uint8Array;
38
21
  export declare function ensureBytes(hex: Hex, expectedLength?: number): Uint8Array;
39
22
  export declare function concatBytes(...arrays: Uint8Array[]): Uint8Array;
40
- export declare function nLength(n: bigint, nBitLength?: number): {
41
- nBitLength: number;
42
- nByteLength: number;
43
- };
44
- /**
45
- * FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
46
- * Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
47
- * and convert them into private scalar, with the modulo bias being neglible.
48
- * Needs at least 40 bytes of input for 32-byte private key.
49
- * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
50
- * @param hash hash output from SHA3 or a similar function
51
- * @returns valid private scalar
52
- */
53
- export declare function hashToPrivateScalar(hash: Hex, groupOrder: bigint, isLE?: boolean): bigint;
54
23
  export declare function equalBytes(b1: Uint8Array, b2: Uint8Array): boolean;
55
24
  export declare function bitLen(n: bigint): number;
56
25
  export declare const bitGet: (n: bigint, pos: number) => bigint;