@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
package/README.md CHANGED
@@ -6,7 +6,9 @@ Minimal, auditable JS implementation of elliptic curve cryptography.
6
6
  - ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
7
7
  - [hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/)
8
8
  for encoding or hashing an arbitrary string to a point on an elliptic curve
9
- - Auditable, [fast](#speed)
9
+ - [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
10
+ - Auditable
11
+ - 🏎 [Ultra-fast](#speed), hand-optimized for caveats of JS engines
10
12
  - 🔍 Unique tests ensure correctness. Wycheproof vectors included
11
13
  - 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app
12
14
 
@@ -24,7 +26,6 @@ Curves incorporate work from previous noble packages
24
26
  [ed25519](https://github.com/paulmillr/noble-ed25519),
25
27
  [bls12-381](https://github.com/paulmillr/noble-bls12-381)),
26
28
  which had security audits and were developed from 2019 to 2022.
27
- The goal is to replace them with lean UMD builds based on single-codebase noble-curves.
28
29
 
29
30
  ### This library belongs to _noble_ crypto
30
31
 
@@ -88,6 +89,7 @@ To define a custom curve, check out API below.
88
89
  - [abstract/montgomery: Montgomery curve](#abstractmontgomery-montgomery-curve)
89
90
  - [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
90
91
  - [abstract/hash-to-curve: Hashing strings to curve points](#abstracthash-to-curve-hashing-strings-to-curve-points)
92
+ - [abstract/poseidon: Poseidon hash](#abstractposeidon-poseidon-hash)
91
93
  - [abstract/modular](#abstractmodular)
92
94
  - [abstract/utils](#abstractutils)
93
95
 
@@ -302,13 +304,12 @@ const shared = secp256k1.getSharedSecret(key, someonesPubkey);
302
304
  export type CurveFn = {
303
305
  CURVE: ReturnType<typeof validateOpts>;
304
306
  getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
305
- getSharedSecret: (privateA: PrivKey, publicB: PubKey, isCompressed?: boolean) => Uint8Array;
307
+ getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
306
308
  sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
307
- signUnhashed: (msg: Uint8Array, privKey: PrivKey, opts?: SignOpts) => SignatureType;
308
309
  verify: (
309
310
  signature: Hex | SignatureType,
310
311
  msgHash: Hex,
311
- publicKey: PubKey,
312
+ publicKey: Hex,
312
313
  opts?: { lowS?: boolean }
313
314
  ) => boolean;
314
315
  Point: PointConstructor;
@@ -370,6 +371,30 @@ hashes arbitrary-length byte strings to a list of one or more elements of a fini
370
371
  };
371
372
  ```
372
373
 
374
+ ### abstract/poseidon: Poseidon hash
375
+
376
+ Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash.
377
+
378
+ There are many poseidon instances with different constants. We don't provide them,
379
+ but we provide ability to specify them manually. For actual usage, check out
380
+ stark curve source code.
381
+
382
+ ```ts
383
+ import { poseidon } from '@noble/curves/abstract/poseidon';
384
+
385
+ type PoseidonOpts = {
386
+ Fp: Field<bigint>;
387
+ t: number;
388
+ roundsFull: number;
389
+ roundsPartial: number;
390
+ sboxPower?: number;
391
+ reversePartialPowIdx?: boolean; // Hack for stark
392
+ mds: bigint[][];
393
+ roundConstants: bigint[][];
394
+ };
395
+ const instance = poseidon(opts: PoseidonOpts);
396
+ ```
397
+
373
398
  ### abstract/modular
374
399
 
375
400
  Modular arithmetics utilities.
@@ -459,6 +484,25 @@ verify
459
484
  noble x 698 ops/sec @ 1ms/op
460
485
  ```
461
486
 
487
+ ## Upgrading
488
+
489
+ Differences from @noble/secp256k1 1.7:
490
+
491
+ 1. Different double() formula (but same addition)
492
+ 2. Different sqrt() function
493
+ 3. DRBG supports outputLen bigger than outputLen of hmac
494
+ 4. Support for different hash functions
495
+
496
+ Differences from @noble/ed25519 1.7:
497
+
498
+ 1. Variable field element lengths between EDDSA/ECDH:
499
+ EDDSA (RFC8032) is 456 bits / 57 bytes, ECDH (RFC7748) is 448 bits / 56 bytes
500
+ 2. Different addition formula (doubling is same)
501
+ 3. uvRatio differs between curves (half-expected, not only pow fn changes)
502
+ 4. Point decompression code is different (unexpected), now using generalized formula
503
+ 5. Domain function was no-op for ed25519, but adds some data even with empty context for ed448
504
+
505
+
462
506
  ## Contributing & testing
463
507
 
464
508
  1. Clone the repository
@@ -32,37 +32,26 @@ export declare function createCurve(curveDef: CurveDef, defHash: CHash): Readonl
32
32
  k2: bigint;
33
33
  };
34
34
  } | undefined;
35
- readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => boolean) | undefined;
36
- readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjectivePointType<bigint>) => import("./abstract/weierstrass.js").ProjectivePointType<bigint>) | undefined;
37
- readonly htfDefaults?: import("./abstract/hash-to-curve.js").htfOpts | undefined;
38
- readonly mapToCurve?: ((scalar: bigint[]) => {
39
- x: bigint;
40
- y: bigint;
41
- }) | undefined;
35
+ readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
36
+ readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
42
37
  lowS: boolean;
43
38
  readonly hash: CHash;
44
39
  readonly hmac: (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;
45
40
  readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
46
- readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
41
+ readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
42
+ readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
47
43
  }>;
48
44
  getPublicKey: (privateKey: import("./abstract/utils.js").PrivKey, isCompressed?: boolean | undefined) => Uint8Array;
49
- getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/weierstrass.js").PubKey, isCompressed?: boolean | undefined) => Uint8Array;
45
+ getSharedSecret: (privateA: import("./abstract/utils.js").PrivKey, publicB: import("./abstract/utils.js").Hex, isCompressed?: boolean | undefined) => Uint8Array;
50
46
  sign: (msgHash: import("./abstract/utils.js").Hex, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
51
- signUnhashed: (msg: Uint8Array, privKey: import("./abstract/utils.js").PrivKey, opts?: import("./abstract/weierstrass.js").SignOpts | undefined) => import("./abstract/weierstrass.js").SignatureType;
52
- verify: (signature: import("./abstract/utils.js").Hex | import("./abstract/weierstrass.js").SignatureType, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/weierstrass.js").PubKey, opts?: {
53
- lowS?: boolean | undefined;
54
- } | undefined) => boolean;
55
- Point: import("./abstract/weierstrass.js").PointConstructor<bigint>;
56
- ProjectivePoint: import("./abstract/weierstrass.js").ProjectiveConstructor<bigint>;
47
+ verify: (signature: import("./abstract/utils.js").Hex | {
48
+ r: bigint;
49
+ s: bigint;
50
+ }, msgHash: import("./abstract/utils.js").Hex, publicKey: import("./abstract/utils.js").Hex, opts?: import("./abstract/weierstrass.js").VerOpts | undefined) => boolean;
51
+ ProjectivePoint: import("./abstract/weierstrass.js").ProjConstructor<bigint>;
57
52
  Signature: import("./abstract/weierstrass.js").SignatureConstructor;
58
53
  utils: {
59
- _bigintToBytes: (num: bigint) => Uint8Array;
60
- _bigintToString: (num: bigint) => string;
61
54
  _normalizePrivateKey: (key: import("./abstract/utils.js").PrivKey) => bigint;
62
- _normalizePublicKey: (publicKey: import("./abstract/weierstrass.js").PubKey) => import("./abstract/weierstrass.js").PointType<bigint>;
63
- _isWithinCurveOrder: (num: bigint) => boolean;
64
- _isValidFieldElement: (num: bigint) => boolean;
65
- _weierstrassEquation: (x: bigint) => bigint;
66
55
  isValidPrivateKey(privateKey: import("./abstract/utils.js").PrivKey): boolean;
67
56
  hashToPrivateKey: (hash: import("./abstract/utils.js").Hex) => Uint8Array;
68
57
  randomPrivateKey: () => Uint8Array;
@@ -11,26 +11,31 @@
11
11
  * We are using Fp for private keys (shorter) and Fp₂ for signatures (longer).
12
12
  * Some projects may prefer to swap this relation, it is not supported for now.
13
13
  */
14
- import * as mod from './modular.js';
15
- import * as ut from './utils.js';
16
- import { Hex, PrivKey } from './utils.js';
17
- import { htfOpts, stringToBytes, hash_to_field as hashToField, expand_message_xmd as expandMessageXMD } from './hash-to-curve.js';
18
- import { CurvePointsType, PointType, CurvePointsRes } from './weierstrass.js';
14
+ import { AffinePoint } from './curve.js';
15
+ import { Field } from './modular.js';
16
+ import { Hex, PrivKey, CHash } from './utils.js';
17
+ import * as htf from './hash-to-curve.js';
18
+ import { CurvePointsType, ProjPointType as ProjPointType, CurvePointsRes } from './weierstrass.js';
19
19
  declare type Fp = bigint;
20
20
  export declare type SignatureCoder<Fp2> = {
21
- decode(hex: Hex): PointType<Fp2>;
22
- encode(point: PointType<Fp2>): Uint8Array;
21
+ decode(hex: Hex): ProjPointType<Fp2>;
22
+ encode(point: ProjPointType<Fp2>): Uint8Array;
23
23
  };
24
24
  export declare type CurveType<Fp, Fp2, Fp6, Fp12> = {
25
25
  r: bigint;
26
- G1: Omit<CurvePointsType<Fp>, 'n'>;
26
+ G1: Omit<CurvePointsType<Fp>, 'n'> & {
27
+ mapToCurve: htf.MapToCurve<Fp>;
28
+ htfDefaults: htf.Opts;
29
+ };
27
30
  G2: Omit<CurvePointsType<Fp2>, 'n'> & {
28
31
  Signature: SignatureCoder<Fp2>;
32
+ mapToCurve: htf.MapToCurve<Fp2>;
33
+ htfDefaults: htf.Opts;
29
34
  };
30
35
  x: bigint;
31
- Fp: mod.Field<Fp>;
32
- Fr: mod.Field<bigint>;
33
- Fp2: mod.Field<Fp2> & {
36
+ Fp: Field<Fp>;
37
+ Fr: Field<bigint>;
38
+ Fp2: Field<Fp2> & {
34
39
  reim: (num: Fp2) => {
35
40
  re: bigint;
36
41
  im: bigint;
@@ -38,51 +43,53 @@ export declare type CurveType<Fp, Fp2, Fp6, Fp12> = {
38
43
  multiplyByB: (num: Fp2) => Fp2;
39
44
  frobeniusMap(num: Fp2, power: number): Fp2;
40
45
  };
41
- Fp6: mod.Field<Fp6>;
42
- Fp12: mod.Field<Fp12> & {
46
+ Fp6: Field<Fp6>;
47
+ Fp12: Field<Fp12> & {
43
48
  frobeniusMap(num: Fp12, power: number): Fp12;
44
49
  multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
45
50
  conjugate(num: Fp12): Fp12;
46
51
  finalExponentiate(num: Fp12): Fp12;
47
52
  };
48
- htfDefaults: htfOpts;
49
- hash: ut.CHash;
53
+ htfDefaults: htf.Opts;
54
+ hash: CHash;
50
55
  randomBytes: (bytesLength?: number) => Uint8Array;
51
56
  };
52
57
  export declare type CurveFn<Fp, Fp2, Fp6, Fp12> = {
53
58
  CURVE: CurveType<Fp, Fp2, Fp6, Fp12>;
54
- Fr: mod.Field<bigint>;
55
- Fp: mod.Field<Fp>;
56
- Fp2: mod.Field<Fp2>;
57
- Fp6: mod.Field<Fp6>;
58
- Fp12: mod.Field<Fp12>;
59
+ Fr: Field<bigint>;
60
+ Fp: Field<Fp>;
61
+ Fp2: Field<Fp2>;
62
+ Fp6: Field<Fp6>;
63
+ Fp12: Field<Fp12>;
59
64
  G1: CurvePointsRes<Fp>;
60
65
  G2: CurvePointsRes<Fp2>;
61
66
  Signature: SignatureCoder<Fp2>;
62
67
  millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
63
- calcPairingPrecomputes: (x: Fp2, y: Fp2) => [Fp2, Fp2, Fp2][];
64
- pairing: (P: PointType<Fp>, Q: PointType<Fp2>, withFinalExponent?: boolean) => Fp12;
68
+ calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
69
+ hashToCurve: {
70
+ G1: ReturnType<(typeof htf.hashToCurve<Fp>)>;
71
+ G2: ReturnType<(typeof htf.hashToCurve<Fp2>)>;
72
+ };
73
+ pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
65
74
  getPublicKey: (privateKey: PrivKey) => Uint8Array;
66
75
  sign: {
67
76
  (message: Hex, privateKey: PrivKey): Uint8Array;
68
- (message: PointType<Fp2>, privateKey: PrivKey): PointType<Fp2>;
77
+ (message: ProjPointType<Fp2>, privateKey: PrivKey): ProjPointType<Fp2>;
69
78
  };
70
- verify: (signature: Hex | PointType<Fp2>, message: Hex | PointType<Fp2>, publicKey: Hex | PointType<Fp>) => boolean;
79
+ verify: (signature: Hex | ProjPointType<Fp2>, message: Hex | ProjPointType<Fp2>, publicKey: Hex | ProjPointType<Fp>) => boolean;
71
80
  aggregatePublicKeys: {
72
81
  (publicKeys: Hex[]): Uint8Array;
73
- (publicKeys: PointType<Fp>[]): PointType<Fp>;
82
+ (publicKeys: ProjPointType<Fp>[]): ProjPointType<Fp>;
74
83
  };
75
84
  aggregateSignatures: {
76
85
  (signatures: Hex[]): Uint8Array;
77
- (signatures: PointType<Fp2>[]): PointType<Fp2>;
86
+ (signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
78
87
  };
79
- verifyBatch: (signature: Hex | PointType<Fp2>, messages: (Hex | PointType<Fp2>)[], publicKeys: (Hex | PointType<Fp>)[]) => boolean;
88
+ verifyBatch: (signature: Hex | ProjPointType<Fp2>, messages: (Hex | ProjPointType<Fp2>)[], publicKeys: (Hex | ProjPointType<Fp>)[]) => boolean;
80
89
  utils: {
81
- stringToBytes: typeof stringToBytes;
82
- hashToField: typeof hashToField;
83
- expandMessageXMD: typeof expandMessageXMD;
84
- getDSTLabel: () => string;
85
- setDSTLabel(newLabel: string): void;
90
+ stringToBytes: typeof htf.stringToBytes;
91
+ hashToField: typeof htf.hash_to_field;
92
+ expandMessageXMD: typeof htf.expand_message_xmd;
86
93
  };
87
94
  };
88
95
  export declare function bls<Fp2, Fp6, Fp12>(CURVE: CurveType<Fp, Fp2, Fp6, Fp12>): CurveFn<Fp, Fp2, Fp6, Fp12>;
@@ -1,17 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.bls = void 0;
4
- const ut = require("./utils.js");
5
- const hash_to_curve_js_1 = require("./hash-to-curve.js");
4
+ const modular_js_1 = require("./modular.js");
5
+ const utils_js_1 = require("./utils.js");
6
+ const htf = require("./hash-to-curve.js");
6
7
  const weierstrass_js_1 = require("./weierstrass.js");
7
8
  function bls(CURVE) {
8
9
  // Fields looks pretty specific for curve, so for now we need to pass them with options
9
10
  const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE;
10
- const BLS_X_LEN = ut.bitLen(CURVE.x);
11
+ const BLS_X_LEN = (0, utils_js_1.bitLen)(CURVE.x);
11
12
  const groupLen = 32; // TODO: calculate; hardcoded for now
12
13
  // Pre-compute coefficients for sparse multiplication
13
14
  // Point addition and point double calculations is reused for coefficients
14
- function calcPairingPrecomputes(x, y) {
15
+ function calcPairingPrecomputes(p) {
16
+ const { x, y } = p;
15
17
  // prettier-ignore
16
18
  const Qx = x, Qy = y, Qz = Fp2.ONE;
17
19
  // prettier-ignore
@@ -19,32 +21,32 @@ function bls(CURVE) {
19
21
  let ell_coeff = [];
20
22
  for (let i = BLS_X_LEN - 2; i >= 0; i--) {
21
23
  // Double
22
- let t0 = Fp2.square(Ry); // Ry²
23
- let t1 = Fp2.square(Rz); // Rz²
24
+ let t0 = Fp2.sqr(Ry); // Ry²
25
+ let t1 = Fp2.sqr(Rz); // Rz²
24
26
  let t2 = Fp2.multiplyByB(Fp2.mul(t1, 3n)); // 3 * T1 * B
25
27
  let t3 = Fp2.mul(t2, 3n); // 3 * T2
26
- let t4 = Fp2.sub(Fp2.sub(Fp2.square(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
28
+ let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
27
29
  ell_coeff.push([
28
30
  Fp2.sub(t2, t0),
29
- Fp2.mul(Fp2.square(Rx), 3n),
30
- Fp2.negate(t4), // -T4
31
+ Fp2.mul(Fp2.sqr(Rx), 3n),
32
+ Fp2.neg(t4), // -T4
31
33
  ]);
32
34
  Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
33
- Ry = Fp2.sub(Fp2.square(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.square(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
35
+ Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.sqr(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
34
36
  Rz = Fp2.mul(t0, t4); // T0 * T4
35
- if (ut.bitGet(CURVE.x, i)) {
37
+ if ((0, utils_js_1.bitGet)(CURVE.x, i)) {
36
38
  // Addition
37
39
  let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
38
40
  let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
39
41
  ell_coeff.push([
40
42
  Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)),
41
- Fp2.negate(t0),
43
+ Fp2.neg(t0),
42
44
  t1, // T1
43
45
  ]);
44
- let t2 = Fp2.square(t1); // T1²
46
+ let t2 = Fp2.sqr(t1); // T1²
45
47
  let t3 = Fp2.mul(t2, t1); // T2 * T1
46
48
  let t4 = Fp2.mul(t2, Rx); // T2 * Rx
47
- let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.square(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
49
+ let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
48
50
  Rx = Fp2.mul(t1, t5); // T1 * T5
49
51
  Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
50
52
  Rz = Fp2.mul(Rz, t3); // Rz * T3
@@ -60,115 +62,114 @@ function bls(CURVE) {
60
62
  for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
61
63
  const E = ell[j];
62
64
  f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
63
- if (ut.bitGet(x, i)) {
65
+ if ((0, utils_js_1.bitGet)(x, i)) {
64
66
  j += 1;
65
67
  const F = ell[j];
66
68
  f12 = Fp12.multiplyBy014(f12, F[0], Fp2.mul(F[1], Px), Fp2.mul(F[2], Py));
67
69
  }
68
70
  if (i !== 0)
69
- f12 = Fp12.square(f12);
71
+ f12 = Fp12.sqr(f12);
70
72
  }
71
73
  return Fp12.conjugate(f12);
72
74
  }
73
75
  const utils = {
74
- hexToBytes: ut.hexToBytes,
75
- bytesToHex: ut.bytesToHex,
76
- stringToBytes: hash_to_curve_js_1.stringToBytes,
76
+ hexToBytes: utils_js_1.hexToBytes,
77
+ bytesToHex: utils_js_1.bytesToHex,
78
+ stringToBytes: htf.stringToBytes,
77
79
  // TODO: do we need to export it here?
78
- hashToField: (msg, count, options = {}) => (0, hash_to_curve_js_1.hash_to_field)(msg, count, { ...CURVE.htfDefaults, ...options }),
79
- expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => (0, hash_to_curve_js_1.expand_message_xmd)(msg, DST, lenInBytes, H),
80
- hashToPrivateKey: (hash) => Fr.toBytes(ut.hashToPrivateScalar(hash, CURVE.r)),
80
+ hashToField: (msg, count, options = {}) => htf.hash_to_field(msg, count, { ...CURVE.htfDefaults, ...options }),
81
+ expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => htf.expand_message_xmd(msg, DST, lenInBytes, H),
82
+ hashToPrivateKey: (hash) => Fr.toBytes((0, modular_js_1.hashToPrivateScalar)(hash, CURVE.r)),
81
83
  randomBytes: (bytesLength = groupLen) => CURVE.randomBytes(bytesLength),
82
84
  randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(groupLen + 8)),
83
- getDSTLabel: () => CURVE.htfDefaults.DST,
84
- setDSTLabel(newLabel) {
85
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3.1
86
- if (typeof newLabel !== 'string' || newLabel.length > 2048 || newLabel.length === 0) {
87
- throw new TypeError('Invalid DST');
88
- }
89
- CURVE.htfDefaults.DST = newLabel;
90
- },
91
85
  };
92
86
  // Point on G1 curve: (x, y)
93
87
  const G1 = (0, weierstrass_js_1.weierstrassPoints)({
94
88
  n: Fr.ORDER,
95
89
  ...CURVE.G1,
96
90
  });
91
+ const G1HashToCurve = htf.hashToCurve(G1.ProjectivePoint, CURVE.G1.mapToCurve, {
92
+ ...CURVE.htfDefaults,
93
+ ...CURVE.G1.htfDefaults,
94
+ });
97
95
  function pairingPrecomputes(point) {
98
96
  const p = point;
99
97
  if (p._PPRECOMPUTES)
100
98
  return p._PPRECOMPUTES;
101
- p._PPRECOMPUTES = calcPairingPrecomputes(p.x, p.y);
99
+ p._PPRECOMPUTES = calcPairingPrecomputes(point.toAffine());
102
100
  return p._PPRECOMPUTES;
103
101
  }
104
- function clearPairingPrecomputes(point) {
105
- const p = point;
106
- p._PPRECOMPUTES = undefined;
107
- }
108
- clearPairingPrecomputes;
109
- function millerLoopG1(Q, P) {
110
- return millerLoop(pairingPrecomputes(P), [Q.x, Q.y]);
111
- }
102
+ // TODO: export
103
+ // function clearPairingPrecomputes(point: G2) {
104
+ // const p = point as G2 & withPairingPrecomputes;
105
+ // p._PPRECOMPUTES = undefined;
106
+ // }
112
107
  // Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
113
108
  const G2 = (0, weierstrass_js_1.weierstrassPoints)({
114
109
  n: Fr.ORDER,
115
110
  ...CURVE.G2,
116
111
  });
112
+ const C = G2.ProjectivePoint; // TODO: fix
113
+ const G2HashToCurve = htf.hashToCurve(C, CURVE.G2.mapToCurve, {
114
+ ...CURVE.htfDefaults,
115
+ ...CURVE.G2.htfDefaults,
116
+ });
117
117
  const { Signature } = CURVE.G2;
118
118
  // Calculates bilinear pairing
119
- function pairing(P, Q, withFinalExponent = true) {
120
- if (P.equals(G1.Point.ZERO) || Q.equals(G2.Point.ZERO))
121
- throw new Error('No pairings at point of Infinity');
122
- P.assertValidity();
119
+ function pairing(Q, P, withFinalExponent = true) {
120
+ if (Q.equals(G1.ProjectivePoint.ZERO) || P.equals(G2.ProjectivePoint.ZERO))
121
+ throw new Error('pairing is not available for ZERO point');
123
122
  Q.assertValidity();
123
+ P.assertValidity();
124
124
  // Performance: 9ms for millerLoop and ~14ms for exp.
125
- const looped = millerLoopG1(P, Q);
125
+ const Qa = Q.toAffine();
126
+ const looped = millerLoop(pairingPrecomputes(P), [Qa.x, Qa.y]);
126
127
  return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
127
128
  }
128
129
  function normP1(point) {
129
- return point instanceof G1.Point ? point : G1.Point.fromHex(point);
130
+ return point instanceof G1.ProjectivePoint ? point : G1.ProjectivePoint.fromHex(point);
130
131
  }
131
132
  function normP2(point) {
132
- return point instanceof G2.Point ? point : Signature.decode(point);
133
+ return point instanceof G2.ProjectivePoint ? point : Signature.decode(point);
133
134
  }
134
- function normP2Hash(point) {
135
- return point instanceof G2.Point ? point : G2.Point.hashToCurve(point);
135
+ function normP2Hash(point, htfOpts) {
136
+ return point instanceof G2.ProjectivePoint
137
+ ? point
138
+ : G2HashToCurve.hashToCurve(point, htfOpts);
136
139
  }
137
140
  // Multiplies generator by private key.
138
141
  // P = pk x G
139
142
  function getPublicKey(privateKey) {
140
- return G1.Point.fromPrivateKey(privateKey).toRawBytes(true);
143
+ return G1.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
141
144
  }
142
- function sign(message, privateKey) {
143
- const msgPoint = normP2Hash(message);
145
+ function sign(message, privateKey, htfOpts) {
146
+ const msgPoint = normP2Hash(message, htfOpts);
144
147
  msgPoint.assertValidity();
145
148
  const sigPoint = msgPoint.multiply(G1.normalizePrivateKey(privateKey));
146
- if (message instanceof G2.Point)
149
+ if (message instanceof G2.ProjectivePoint)
147
150
  return sigPoint;
148
151
  return Signature.encode(sigPoint);
149
152
  }
150
153
  // Checks if pairing of public key & hash is equal to pairing of generator & signature.
151
154
  // e(P, H(m)) == e(G, S)
152
- function verify(signature, message, publicKey) {
155
+ function verify(signature, message, publicKey, htfOpts) {
153
156
  const P = normP1(publicKey);
154
- const Hm = normP2Hash(message);
155
- const G = G1.Point.BASE;
157
+ const Hm = normP2Hash(message, htfOpts);
158
+ const G = G1.ProjectivePoint.BASE;
156
159
  const S = normP2(signature);
157
160
  // Instead of doing 2 exponentiations, we use property of billinear maps
158
161
  // and do one exp after multiplying 2 points.
159
162
  const ePHm = pairing(P.negate(), Hm, false);
160
163
  const eGS = pairing(G, S, false);
161
164
  const exp = Fp12.finalExponentiate(Fp12.mul(eGS, ePHm));
162
- return Fp12.equals(exp, Fp12.ONE);
165
+ return Fp12.eql(exp, Fp12.ONE);
163
166
  }
164
167
  function aggregatePublicKeys(publicKeys) {
165
168
  if (!publicKeys.length)
166
169
  throw new Error('Expected non-empty array');
167
- const agg = publicKeys
168
- .map(normP1)
169
- .reduce((sum, p) => sum.add(G1.ProjectivePoint.fromAffine(p)), G1.ProjectivePoint.ZERO);
170
- const aggAffine = agg.toAffine();
171
- if (publicKeys[0] instanceof G1.Point) {
170
+ const agg = publicKeys.map(normP1).reduce((sum, p) => sum.add(p), G1.ProjectivePoint.ZERO);
171
+ const aggAffine = agg; //.toAffine();
172
+ if (publicKeys[0] instanceof G1.ProjectivePoint) {
172
173
  aggAffine.assertValidity();
173
174
  return aggAffine;
174
175
  }
@@ -178,11 +179,9 @@ function bls(CURVE) {
178
179
  function aggregateSignatures(signatures) {
179
180
  if (!signatures.length)
180
181
  throw new Error('Expected non-empty array');
181
- const agg = signatures
182
- .map(normP2)
183
- .reduce((sum, s) => sum.add(G2.ProjectivePoint.fromAffine(s)), G2.ProjectivePoint.ZERO);
184
- const aggAffine = agg.toAffine();
185
- if (signatures[0] instanceof G2.Point) {
182
+ const agg = signatures.map(normP2).reduce((sum, s) => sum.add(s), G2.ProjectivePoint.ZERO);
183
+ const aggAffine = agg; //.toAffine();
184
+ if (signatures[0] instanceof G2.ProjectivePoint) {
186
185
  aggAffine.assertValidity();
187
186
  return aggAffine;
188
187
  }
@@ -190,33 +189,34 @@ function bls(CURVE) {
190
189
  }
191
190
  // https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
192
191
  // e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
193
- function verifyBatch(signature, messages, publicKeys) {
192
+ function verifyBatch(signature, messages, publicKeys, htfOpts) {
193
+ // @ts-ignore
194
+ // console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
194
195
  if (!messages.length)
195
196
  throw new Error('Expected non-empty messages array');
196
197
  if (publicKeys.length !== messages.length)
197
198
  throw new Error('Pubkey count should equal msg count');
198
199
  const sig = normP2(signature);
199
- const nMessages = messages.map(normP2Hash);
200
+ const nMessages = messages.map((i) => normP2Hash(i, htfOpts));
200
201
  const nPublicKeys = publicKeys.map(normP1);
201
202
  try {
202
203
  const paired = [];
203
204
  for (const message of new Set(nMessages)) {
204
- const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.Point.ZERO);
205
+ const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.ProjectivePoint.ZERO);
205
206
  // const msg = message instanceof PointG2 ? message : await PointG2.hashToCurve(message);
206
207
  // Possible to batch pairing for same msg with different groupPublicKey here
207
208
  paired.push(pairing(groupPublicKey, message, false));
208
209
  }
209
- paired.push(pairing(G1.Point.BASE.negate(), sig, false));
210
+ paired.push(pairing(G1.ProjectivePoint.BASE.negate(), sig, false));
210
211
  const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
211
212
  const exp = Fp12.finalExponentiate(product);
212
- return Fp12.equals(exp, Fp12.ONE);
213
+ return Fp12.eql(exp, Fp12.ONE);
213
214
  }
214
215
  catch {
215
216
  return false;
216
217
  }
217
218
  }
218
- // Pre-compute points. Refer to README.
219
- G1.Point.BASE._setWindowSize(4);
219
+ G1.ProjectivePoint.BASE._setWindowSize(4);
220
220
  return {
221
221
  CURVE,
222
222
  Fr,
@@ -229,6 +229,7 @@ function bls(CURVE) {
229
229
  Signature,
230
230
  millerLoop,
231
231
  calcPairingPrecomputes,
232
+ hashToCurve: { G1: G1HashToCurve, G2: G2HashToCurve },
232
233
  pairing,
233
234
  getPublicKey,
234
235
  sign,
@@ -1,15 +1,25 @@
1
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
+ import { Field } from './modular.js';
3
+ export declare type AffinePoint<T> = {
4
+ x: T;
5
+ y: T;
6
+ } & {
7
+ z?: never;
8
+ t?: never;
9
+ };
1
10
  export interface Group<T extends Group<T>> {
2
11
  double(): T;
3
12
  negate(): T;
4
13
  add(other: T): T;
5
14
  subtract(other: T): T;
6
15
  equals(other: T): boolean;
7
- multiply(scalar: number | bigint): T;
16
+ multiply(scalar: bigint): T;
8
17
  }
9
18
  export declare type GroupConstructor<T> = {
10
19
  BASE: T;
11
20
  ZERO: T;
12
21
  };
22
+ export declare type Mapper<T> = (i: T[]) => T[];
13
23
  export declare function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number): {
14
24
  constTimeNegate: (condition: boolean, item: T) => T;
15
25
  unsafeLadder(elm: T, n: bigint): T;
@@ -31,4 +41,24 @@ export declare function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: n
31
41
  p: T;
32
42
  f: T;
33
43
  };
44
+ wNAFCached(P: T, precomputesMap: Map<T, T[]>, n: bigint, transform: Mapper<T>): {
45
+ p: T;
46
+ f: T;
47
+ };
48
+ };
49
+ export declare type AbstractCurve<T> = {
50
+ Fp: Field<T>;
51
+ n: bigint;
52
+ nBitLength?: number;
53
+ nByteLength?: number;
54
+ h: bigint;
55
+ hEff?: bigint;
56
+ Gx: T;
57
+ Gy: T;
58
+ wrapPrivateKey?: boolean;
59
+ allowInfinityPoint?: boolean;
34
60
  };
61
+ export declare function validateAbsOpts<FP, T>(curve: AbstractCurve<FP> & T): Readonly<{
62
+ readonly nBitLength: number;
63
+ readonly nByteLength: number;
64
+ } & AbstractCurve<FP> & T>;