@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
package/lib/ed448.js CHANGED
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.x448 = exports.ed448ph = exports.ed448 = void 0;
3
+ exports.encodeToCurve = exports.hashToCurve = exports.x448 = exports.ed448ph = exports.ed448 = void 0;
4
4
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5
5
  const sha3_1 = require("@noble/hashes/sha3");
6
6
  const utils_1 = require("@noble/hashes/utils");
7
7
  const edwards_js_1 = require("./abstract/edwards.js");
8
8
  const modular_js_1 = require("./abstract/modular.js");
9
9
  const montgomery_js_1 = require("./abstract/montgomery.js");
10
+ const htf = require("./abstract/hash-to-curve.js");
10
11
  /**
11
12
  * Edwards448 (not Ed448-Goldilocks) curve with following addons:
12
13
  * * X448 ECDH
@@ -49,79 +50,6 @@ function adjustScalarBytes(bytes) {
49
50
  return bytes;
50
51
  }
51
52
  const Fp = (0, modular_js_1.Fp)(ed448P, 456, true);
52
- // Hash To Curve Elligator2 Map
53
- const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
54
- const ELL2_J = BigInt(156326);
55
- function map_to_curve_elligator2_curve448(u) {
56
- let tv1 = Fp.square(u); // 1. tv1 = u^2
57
- let e1 = Fp.equals(tv1, Fp.ONE); // 2. e1 = tv1 == 1
58
- tv1 = Fp.cmov(tv1, Fp.ZERO, e1); // 3. tv1 = CMOV(tv1, 0, e1) # If Z * u^2 == -1, set tv1 = 0
59
- let xd = Fp.sub(Fp.ONE, tv1); // 4. xd = 1 - tv1
60
- let x1n = Fp.negate(ELL2_J); // 5. x1n = -J
61
- let tv2 = Fp.square(xd); // 6. tv2 = xd^2
62
- let gxd = Fp.mul(tv2, xd); // 7. gxd = tv2 * xd # gxd = xd^3
63
- let gx1 = Fp.mul(tv1, Fp.negate(ELL2_J)); // 8. gx1 = -J * tv1 # x1n + J * xd
64
- gx1 = Fp.mul(gx1, x1n); // 9. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
65
- gx1 = Fp.add(gx1, tv2); // 10. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
66
- gx1 = Fp.mul(gx1, x1n); // 11. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
67
- let tv3 = Fp.square(gxd); // 12. tv3 = gxd^2
68
- tv2 = Fp.mul(gx1, gxd); // 13. tv2 = gx1 * gxd # gx1 * gxd
69
- tv3 = Fp.mul(tv3, tv2); // 14. tv3 = tv3 * tv2 # gx1 * gxd^3
70
- let y1 = Fp.pow(tv3, ELL2_C1); // 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
71
- y1 = Fp.mul(y1, tv2); // 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
72
- let x2n = Fp.mul(x1n, Fp.negate(tv1)); // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
73
- let y2 = Fp.mul(y1, u); // 18. y2 = y1 * u
74
- y2 = Fp.cmov(y2, Fp.ZERO, e1); // 19. y2 = CMOV(y2, 0, e1)
75
- tv2 = Fp.square(y1); // 20. tv2 = y1^2
76
- tv2 = Fp.mul(tv2, gxd); // 21. tv2 = tv2 * gxd
77
- let e2 = Fp.equals(tv2, gx1); // 22. e2 = tv2 == gx1
78
- let xn = Fp.cmov(x2n, x1n, e2); // 23. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2
79
- let y = Fp.cmov(y2, y1, e2); // 24. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2
80
- let e3 = Fp.isOdd(y); // 25. e3 = sgn0(y) == 1 # Fix sign of y
81
- y = Fp.cmov(y, Fp.negate(y), e2 !== e3); // 26. y = CMOV(y, -y, e2 XOR e3)
82
- return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
83
- }
84
- function map_to_curve_elligator2_edwards448(u) {
85
- let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u); // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
86
- let xn2 = Fp.square(xn); // 2. xn2 = xn^2
87
- let xd2 = Fp.square(xd); // 3. xd2 = xd^2
88
- let xd4 = Fp.square(xd2); // 4. xd4 = xd2^2
89
- let yn2 = Fp.square(yn); // 5. yn2 = yn^2
90
- let yd2 = Fp.square(yd); // 6. yd2 = yd^2
91
- let xEn = Fp.sub(xn2, xd2); // 7. xEn = xn2 - xd2
92
- let tv2 = Fp.sub(xEn, xd2); // 8. tv2 = xEn - xd2
93
- xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2
94
- xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd
95
- xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn
96
- xEn = Fp.mul(xEn, 4n); // 12. xEn = xEn * 4
97
- tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2
98
- tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2
99
- let tv3 = Fp.mul(yn2, 4n); // 15. tv3 = 4 * yn2
100
- let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2
101
- tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4
102
- let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2
103
- tv2 = Fp.mul(tv2, xn); // 19. tv2 = tv2 * xn
104
- let tv4 = Fp.mul(xn, xd4); // 20. tv4 = xn * xd4
105
- let yEn = Fp.sub(tv3, yd2); // 21. yEn = tv3 - yd2
106
- yEn = Fp.mul(yEn, tv4); // 22. yEn = yEn * tv4
107
- yEn = Fp.sub(yEn, tv2); // 23. yEn = yEn - tv2
108
- tv1 = Fp.add(xn2, xd2); // 24. tv1 = xn2 + xd2
109
- tv1 = Fp.mul(tv1, xd2); // 25. tv1 = tv1 * xd2
110
- tv1 = Fp.mul(tv1, xd); // 26. tv1 = tv1 * xd
111
- tv1 = Fp.mul(tv1, yn2); // 27. tv1 = tv1 * yn2
112
- tv1 = Fp.mul(tv1, BigInt(-2)); // 28. tv1 = -2 * tv1
113
- let yEd = Fp.add(tv2, tv1); // 29. yEd = tv2 + tv1
114
- tv4 = Fp.mul(tv4, yd2); // 30. tv4 = tv4 * yd2
115
- yEd = Fp.add(yEd, tv4); // 31. yEd = yEd + tv4
116
- tv1 = Fp.mul(xEd, yEd); // 32. tv1 = xEd * yEd
117
- let e = Fp.equals(tv1, Fp.ZERO); // 33. e = tv1 == 0
118
- xEn = Fp.cmov(xEn, Fp.ZERO, e); // 34. xEn = CMOV(xEn, 0, e)
119
- xEd = Fp.cmov(xEd, Fp.ONE, e); // 35. xEd = CMOV(xEd, 1, e)
120
- yEn = Fp.cmov(yEn, Fp.ONE, e); // 36. yEn = CMOV(yEn, 1, e)
121
- yEd = Fp.cmov(yEd, Fp.ONE, e); // 37. yEd = CMOV(yEd, 1, e)
122
- const inv = Fp.invertBatch([xEd, yEd]); // batch division
123
- return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
124
- }
125
53
  const ED448_DEF = {
126
54
  // Param: a
127
55
  a: BigInt(1),
@@ -169,15 +97,6 @@ const ED448_DEF = {
169
97
  // square root exists, and the decoding fails.
170
98
  return { isValid: (0, modular_js_1.mod)(x2 * v, P) === u, value: x };
171
99
  },
172
- htfDefaults: {
173
- DST: 'edwards448_XOF:SHAKE256_ELL2_RO_',
174
- p: Fp.ORDER,
175
- m: 1,
176
- k: 224,
177
- expand: 'xof',
178
- hash: sha3_1.shake256,
179
- },
180
- mapToCurve: (scalars) => map_to_curve_elligator2_edwards448(scalars[0]),
181
100
  };
182
101
  exports.ed448 = (0, edwards_js_1.twistedEdwards)(ED448_DEF);
183
102
  // NOTE: there is no ed448ctx, since ed448 supports ctx by default
@@ -210,3 +129,87 @@ exports.x448 = (0, montgomery_js_1.montgomery)({
210
129
  // return numberToBytesLE(u, 56);
211
130
  // },
212
131
  });
132
+ // Hash To Curve Elligator2 Map
133
+ const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
134
+ const ELL2_J = BigInt(156326);
135
+ function map_to_curve_elligator2_curve448(u) {
136
+ let tv1 = Fp.sqr(u); // 1. tv1 = u^2
137
+ let e1 = Fp.eql(tv1, Fp.ONE); // 2. e1 = tv1 == 1
138
+ tv1 = Fp.cmov(tv1, Fp.ZERO, e1); // 3. tv1 = CMOV(tv1, 0, e1) # If Z * u^2 == -1, set tv1 = 0
139
+ let xd = Fp.sub(Fp.ONE, tv1); // 4. xd = 1 - tv1
140
+ let x1n = Fp.neg(ELL2_J); // 5. x1n = -J
141
+ let tv2 = Fp.sqr(xd); // 6. tv2 = xd^2
142
+ let gxd = Fp.mul(tv2, xd); // 7. gxd = tv2 * xd # gxd = xd^3
143
+ let gx1 = Fp.mul(tv1, Fp.neg(ELL2_J)); // 8. gx1 = -J * tv1 # x1n + J * xd
144
+ gx1 = Fp.mul(gx1, x1n); // 9. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
145
+ gx1 = Fp.add(gx1, tv2); // 10. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
146
+ gx1 = Fp.mul(gx1, x1n); // 11. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
147
+ let tv3 = Fp.sqr(gxd); // 12. tv3 = gxd^2
148
+ tv2 = Fp.mul(gx1, gxd); // 13. tv2 = gx1 * gxd # gx1 * gxd
149
+ tv3 = Fp.mul(tv3, tv2); // 14. tv3 = tv3 * tv2 # gx1 * gxd^3
150
+ let y1 = Fp.pow(tv3, ELL2_C1); // 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
151
+ y1 = Fp.mul(y1, tv2); // 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
152
+ let x2n = Fp.mul(x1n, Fp.neg(tv1)); // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
153
+ let y2 = Fp.mul(y1, u); // 18. y2 = y1 * u
154
+ y2 = Fp.cmov(y2, Fp.ZERO, e1); // 19. y2 = CMOV(y2, 0, e1)
155
+ tv2 = Fp.sqr(y1); // 20. tv2 = y1^2
156
+ tv2 = Fp.mul(tv2, gxd); // 21. tv2 = tv2 * gxd
157
+ let e2 = Fp.eql(tv2, gx1); // 22. e2 = tv2 == gx1
158
+ let xn = Fp.cmov(x2n, x1n, e2); // 23. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2
159
+ let y = Fp.cmov(y2, y1, e2); // 24. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2
160
+ let e3 = Fp.isOdd(y); // 25. e3 = sgn0(y) == 1 # Fix sign of y
161
+ y = Fp.cmov(y, Fp.neg(y), e2 !== e3); // 26. y = CMOV(y, -y, e2 XOR e3)
162
+ return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
163
+ }
164
+ function map_to_curve_elligator2_edwards448(u) {
165
+ let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u); // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
166
+ let xn2 = Fp.sqr(xn); // 2. xn2 = xn^2
167
+ let xd2 = Fp.sqr(xd); // 3. xd2 = xd^2
168
+ let xd4 = Fp.sqr(xd2); // 4. xd4 = xd2^2
169
+ let yn2 = Fp.sqr(yn); // 5. yn2 = yn^2
170
+ let yd2 = Fp.sqr(yd); // 6. yd2 = yd^2
171
+ let xEn = Fp.sub(xn2, xd2); // 7. xEn = xn2 - xd2
172
+ let tv2 = Fp.sub(xEn, xd2); // 8. tv2 = xEn - xd2
173
+ xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2
174
+ xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd
175
+ xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn
176
+ xEn = Fp.mul(xEn, 4n); // 12. xEn = xEn * 4
177
+ tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2
178
+ tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2
179
+ let tv3 = Fp.mul(yn2, 4n); // 15. tv3 = 4 * yn2
180
+ let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2
181
+ tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4
182
+ let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2
183
+ tv2 = Fp.mul(tv2, xn); // 19. tv2 = tv2 * xn
184
+ let tv4 = Fp.mul(xn, xd4); // 20. tv4 = xn * xd4
185
+ let yEn = Fp.sub(tv3, yd2); // 21. yEn = tv3 - yd2
186
+ yEn = Fp.mul(yEn, tv4); // 22. yEn = yEn * tv4
187
+ yEn = Fp.sub(yEn, tv2); // 23. yEn = yEn - tv2
188
+ tv1 = Fp.add(xn2, xd2); // 24. tv1 = xn2 + xd2
189
+ tv1 = Fp.mul(tv1, xd2); // 25. tv1 = tv1 * xd2
190
+ tv1 = Fp.mul(tv1, xd); // 26. tv1 = tv1 * xd
191
+ tv1 = Fp.mul(tv1, yn2); // 27. tv1 = tv1 * yn2
192
+ tv1 = Fp.mul(tv1, BigInt(-2)); // 28. tv1 = -2 * tv1
193
+ let yEd = Fp.add(tv2, tv1); // 29. yEd = tv2 + tv1
194
+ tv4 = Fp.mul(tv4, yd2); // 30. tv4 = tv4 * yd2
195
+ yEd = Fp.add(yEd, tv4); // 31. yEd = yEd + tv4
196
+ tv1 = Fp.mul(xEd, yEd); // 32. tv1 = xEd * yEd
197
+ let e = Fp.eql(tv1, Fp.ZERO); // 33. e = tv1 == 0
198
+ xEn = Fp.cmov(xEn, Fp.ZERO, e); // 34. xEn = CMOV(xEn, 0, e)
199
+ xEd = Fp.cmov(xEd, Fp.ONE, e); // 35. xEd = CMOV(xEd, 1, e)
200
+ yEn = Fp.cmov(yEn, Fp.ONE, e); // 36. yEn = CMOV(yEn, 1, e)
201
+ yEd = Fp.cmov(yEd, Fp.ONE, e); // 37. yEd = CMOV(yEd, 1, e)
202
+ const inv = Fp.invertBatch([xEd, yEd]); // batch division
203
+ return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
204
+ }
205
+ const { hashToCurve, encodeToCurve } = htf.hashToCurve(exports.ed448.ExtendedPoint, (scalars) => map_to_curve_elligator2_edwards448(scalars[0]), {
206
+ DST: 'edwards448_XOF:SHAKE256_ELL2_RO_',
207
+ encodeDST: 'edwards448_XOF:SHAKE256_ELL2_NU_',
208
+ p: Fp.ORDER,
209
+ m: 1,
210
+ k: 224,
211
+ expand: 'xof',
212
+ hash: sha3_1.shake256,
213
+ });
214
+ exports.hashToCurve = hashToCurve;
215
+ exports.encodeToCurve = encodeToCurve;
@@ -1,14 +1,16 @@
1
- import * as ut from './utils.js';
2
- import { stringToBytes, hash_to_field as hashToField, expand_message_xmd as expandMessageXMD, } from './hash-to-curve.js';
3
- import { weierstrassPoints } from './weierstrass.js';
1
+ import { hashToPrivateScalar } from './modular.js';
2
+ import { bitLen, bitGet, hexToBytes, bytesToHex } from './utils.js';
3
+ import * as htf from './hash-to-curve.js';
4
+ import { weierstrassPoints, } from './weierstrass.js';
4
5
  export function bls(CURVE) {
5
6
  // Fields looks pretty specific for curve, so for now we need to pass them with options
6
7
  const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE;
7
- const BLS_X_LEN = ut.bitLen(CURVE.x);
8
+ const BLS_X_LEN = bitLen(CURVE.x);
8
9
  const groupLen = 32; // TODO: calculate; hardcoded for now
9
10
  // Pre-compute coefficients for sparse multiplication
10
11
  // Point addition and point double calculations is reused for coefficients
11
- function calcPairingPrecomputes(x, y) {
12
+ function calcPairingPrecomputes(p) {
13
+ const { x, y } = p;
12
14
  // prettier-ignore
13
15
  const Qx = x, Qy = y, Qz = Fp2.ONE;
14
16
  // prettier-ignore
@@ -16,32 +18,32 @@ export function bls(CURVE) {
16
18
  let ell_coeff = [];
17
19
  for (let i = BLS_X_LEN - 2; i >= 0; i--) {
18
20
  // Double
19
- let t0 = Fp2.square(Ry); // Ry²
20
- let t1 = Fp2.square(Rz); // Rz²
21
+ let t0 = Fp2.sqr(Ry); // Ry²
22
+ let t1 = Fp2.sqr(Rz); // Rz²
21
23
  let t2 = Fp2.multiplyByB(Fp2.mul(t1, 3n)); // 3 * T1 * B
22
24
  let t3 = Fp2.mul(t2, 3n); // 3 * T2
23
- let t4 = Fp2.sub(Fp2.sub(Fp2.square(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
25
+ let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
24
26
  ell_coeff.push([
25
27
  Fp2.sub(t2, t0),
26
- Fp2.mul(Fp2.square(Rx), 3n),
27
- Fp2.negate(t4), // -T4
28
+ Fp2.mul(Fp2.sqr(Rx), 3n),
29
+ Fp2.neg(t4), // -T4
28
30
  ]);
29
31
  Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
30
- Ry = Fp2.sub(Fp2.square(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.square(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
32
+ Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.sqr(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
31
33
  Rz = Fp2.mul(t0, t4); // T0 * T4
32
- if (ut.bitGet(CURVE.x, i)) {
34
+ if (bitGet(CURVE.x, i)) {
33
35
  // Addition
34
36
  let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
35
37
  let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
36
38
  ell_coeff.push([
37
39
  Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)),
38
- Fp2.negate(t0),
40
+ Fp2.neg(t0),
39
41
  t1, // T1
40
42
  ]);
41
- let t2 = Fp2.square(t1); // T1²
43
+ let t2 = Fp2.sqr(t1); // T1²
42
44
  let t3 = Fp2.mul(t2, t1); // T2 * T1
43
45
  let t4 = Fp2.mul(t2, Rx); // T2 * Rx
44
- let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.square(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
46
+ let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
45
47
  Rx = Fp2.mul(t1, t5); // T1 * T5
46
48
  Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
47
49
  Rz = Fp2.mul(Rz, t3); // Rz * T3
@@ -57,115 +59,114 @@ export function bls(CURVE) {
57
59
  for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
58
60
  const E = ell[j];
59
61
  f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
60
- if (ut.bitGet(x, i)) {
62
+ if (bitGet(x, i)) {
61
63
  j += 1;
62
64
  const F = ell[j];
63
65
  f12 = Fp12.multiplyBy014(f12, F[0], Fp2.mul(F[1], Px), Fp2.mul(F[2], Py));
64
66
  }
65
67
  if (i !== 0)
66
- f12 = Fp12.square(f12);
68
+ f12 = Fp12.sqr(f12);
67
69
  }
68
70
  return Fp12.conjugate(f12);
69
71
  }
70
72
  const utils = {
71
- hexToBytes: ut.hexToBytes,
72
- bytesToHex: ut.bytesToHex,
73
- stringToBytes: stringToBytes,
73
+ hexToBytes: hexToBytes,
74
+ bytesToHex: bytesToHex,
75
+ stringToBytes: htf.stringToBytes,
74
76
  // TODO: do we need to export it here?
75
- hashToField: (msg, count, options = {}) => hashToField(msg, count, { ...CURVE.htfDefaults, ...options }),
76
- expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => expandMessageXMD(msg, DST, lenInBytes, H),
77
- hashToPrivateKey: (hash) => Fr.toBytes(ut.hashToPrivateScalar(hash, CURVE.r)),
77
+ hashToField: (msg, count, options = {}) => htf.hash_to_field(msg, count, { ...CURVE.htfDefaults, ...options }),
78
+ expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => htf.expand_message_xmd(msg, DST, lenInBytes, H),
79
+ hashToPrivateKey: (hash) => Fr.toBytes(hashToPrivateScalar(hash, CURVE.r)),
78
80
  randomBytes: (bytesLength = groupLen) => CURVE.randomBytes(bytesLength),
79
81
  randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(groupLen + 8)),
80
- getDSTLabel: () => CURVE.htfDefaults.DST,
81
- setDSTLabel(newLabel) {
82
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3.1
83
- if (typeof newLabel !== 'string' || newLabel.length > 2048 || newLabel.length === 0) {
84
- throw new TypeError('Invalid DST');
85
- }
86
- CURVE.htfDefaults.DST = newLabel;
87
- },
88
82
  };
89
83
  // Point on G1 curve: (x, y)
90
84
  const G1 = weierstrassPoints({
91
85
  n: Fr.ORDER,
92
86
  ...CURVE.G1,
93
87
  });
88
+ const G1HashToCurve = htf.hashToCurve(G1.ProjectivePoint, CURVE.G1.mapToCurve, {
89
+ ...CURVE.htfDefaults,
90
+ ...CURVE.G1.htfDefaults,
91
+ });
94
92
  function pairingPrecomputes(point) {
95
93
  const p = point;
96
94
  if (p._PPRECOMPUTES)
97
95
  return p._PPRECOMPUTES;
98
- p._PPRECOMPUTES = calcPairingPrecomputes(p.x, p.y);
96
+ p._PPRECOMPUTES = calcPairingPrecomputes(point.toAffine());
99
97
  return p._PPRECOMPUTES;
100
98
  }
101
- function clearPairingPrecomputes(point) {
102
- const p = point;
103
- p._PPRECOMPUTES = undefined;
104
- }
105
- clearPairingPrecomputes;
106
- function millerLoopG1(Q, P) {
107
- return millerLoop(pairingPrecomputes(P), [Q.x, Q.y]);
108
- }
99
+ // TODO: export
100
+ // function clearPairingPrecomputes(point: G2) {
101
+ // const p = point as G2 & withPairingPrecomputes;
102
+ // p._PPRECOMPUTES = undefined;
103
+ // }
109
104
  // Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
110
105
  const G2 = weierstrassPoints({
111
106
  n: Fr.ORDER,
112
107
  ...CURVE.G2,
113
108
  });
109
+ const C = G2.ProjectivePoint; // TODO: fix
110
+ const G2HashToCurve = htf.hashToCurve(C, CURVE.G2.mapToCurve, {
111
+ ...CURVE.htfDefaults,
112
+ ...CURVE.G2.htfDefaults,
113
+ });
114
114
  const { Signature } = CURVE.G2;
115
115
  // Calculates bilinear pairing
116
- function pairing(P, Q, withFinalExponent = true) {
117
- if (P.equals(G1.Point.ZERO) || Q.equals(G2.Point.ZERO))
118
- throw new Error('No pairings at point of Infinity');
119
- P.assertValidity();
116
+ function pairing(Q, P, withFinalExponent = true) {
117
+ if (Q.equals(G1.ProjectivePoint.ZERO) || P.equals(G2.ProjectivePoint.ZERO))
118
+ throw new Error('pairing is not available for ZERO point');
120
119
  Q.assertValidity();
120
+ P.assertValidity();
121
121
  // Performance: 9ms for millerLoop and ~14ms for exp.
122
- const looped = millerLoopG1(P, Q);
122
+ const Qa = Q.toAffine();
123
+ const looped = millerLoop(pairingPrecomputes(P), [Qa.x, Qa.y]);
123
124
  return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
124
125
  }
125
126
  function normP1(point) {
126
- return point instanceof G1.Point ? point : G1.Point.fromHex(point);
127
+ return point instanceof G1.ProjectivePoint ? point : G1.ProjectivePoint.fromHex(point);
127
128
  }
128
129
  function normP2(point) {
129
- return point instanceof G2.Point ? point : Signature.decode(point);
130
+ return point instanceof G2.ProjectivePoint ? point : Signature.decode(point);
130
131
  }
131
- function normP2Hash(point) {
132
- return point instanceof G2.Point ? point : G2.Point.hashToCurve(point);
132
+ function normP2Hash(point, htfOpts) {
133
+ return point instanceof G2.ProjectivePoint
134
+ ? point
135
+ : G2HashToCurve.hashToCurve(point, htfOpts);
133
136
  }
134
137
  // Multiplies generator by private key.
135
138
  // P = pk x G
136
139
  function getPublicKey(privateKey) {
137
- return G1.Point.fromPrivateKey(privateKey).toRawBytes(true);
140
+ return G1.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
138
141
  }
139
- function sign(message, privateKey) {
140
- const msgPoint = normP2Hash(message);
142
+ function sign(message, privateKey, htfOpts) {
143
+ const msgPoint = normP2Hash(message, htfOpts);
141
144
  msgPoint.assertValidity();
142
145
  const sigPoint = msgPoint.multiply(G1.normalizePrivateKey(privateKey));
143
- if (message instanceof G2.Point)
146
+ if (message instanceof G2.ProjectivePoint)
144
147
  return sigPoint;
145
148
  return Signature.encode(sigPoint);
146
149
  }
147
150
  // Checks if pairing of public key & hash is equal to pairing of generator & signature.
148
151
  // e(P, H(m)) == e(G, S)
149
- function verify(signature, message, publicKey) {
152
+ function verify(signature, message, publicKey, htfOpts) {
150
153
  const P = normP1(publicKey);
151
- const Hm = normP2Hash(message);
152
- const G = G1.Point.BASE;
154
+ const Hm = normP2Hash(message, htfOpts);
155
+ const G = G1.ProjectivePoint.BASE;
153
156
  const S = normP2(signature);
154
157
  // Instead of doing 2 exponentiations, we use property of billinear maps
155
158
  // and do one exp after multiplying 2 points.
156
159
  const ePHm = pairing(P.negate(), Hm, false);
157
160
  const eGS = pairing(G, S, false);
158
161
  const exp = Fp12.finalExponentiate(Fp12.mul(eGS, ePHm));
159
- return Fp12.equals(exp, Fp12.ONE);
162
+ return Fp12.eql(exp, Fp12.ONE);
160
163
  }
161
164
  function aggregatePublicKeys(publicKeys) {
162
165
  if (!publicKeys.length)
163
166
  throw new Error('Expected non-empty array');
164
- const agg = publicKeys
165
- .map(normP1)
166
- .reduce((sum, p) => sum.add(G1.ProjectivePoint.fromAffine(p)), G1.ProjectivePoint.ZERO);
167
- const aggAffine = agg.toAffine();
168
- if (publicKeys[0] instanceof G1.Point) {
167
+ const agg = publicKeys.map(normP1).reduce((sum, p) => sum.add(p), G1.ProjectivePoint.ZERO);
168
+ const aggAffine = agg; //.toAffine();
169
+ if (publicKeys[0] instanceof G1.ProjectivePoint) {
169
170
  aggAffine.assertValidity();
170
171
  return aggAffine;
171
172
  }
@@ -175,11 +176,9 @@ export function bls(CURVE) {
175
176
  function aggregateSignatures(signatures) {
176
177
  if (!signatures.length)
177
178
  throw new Error('Expected non-empty array');
178
- const agg = signatures
179
- .map(normP2)
180
- .reduce((sum, s) => sum.add(G2.ProjectivePoint.fromAffine(s)), G2.ProjectivePoint.ZERO);
181
- const aggAffine = agg.toAffine();
182
- if (signatures[0] instanceof G2.Point) {
179
+ const agg = signatures.map(normP2).reduce((sum, s) => sum.add(s), G2.ProjectivePoint.ZERO);
180
+ const aggAffine = agg; //.toAffine();
181
+ if (signatures[0] instanceof G2.ProjectivePoint) {
183
182
  aggAffine.assertValidity();
184
183
  return aggAffine;
185
184
  }
@@ -187,33 +186,34 @@ export function bls(CURVE) {
187
186
  }
188
187
  // https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
189
188
  // e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
190
- function verifyBatch(signature, messages, publicKeys) {
189
+ function verifyBatch(signature, messages, publicKeys, htfOpts) {
190
+ // @ts-ignore
191
+ // console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
191
192
  if (!messages.length)
192
193
  throw new Error('Expected non-empty messages array');
193
194
  if (publicKeys.length !== messages.length)
194
195
  throw new Error('Pubkey count should equal msg count');
195
196
  const sig = normP2(signature);
196
- const nMessages = messages.map(normP2Hash);
197
+ const nMessages = messages.map((i) => normP2Hash(i, htfOpts));
197
198
  const nPublicKeys = publicKeys.map(normP1);
198
199
  try {
199
200
  const paired = [];
200
201
  for (const message of new Set(nMessages)) {
201
- const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.Point.ZERO);
202
+ const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.ProjectivePoint.ZERO);
202
203
  // const msg = message instanceof PointG2 ? message : await PointG2.hashToCurve(message);
203
204
  // Possible to batch pairing for same msg with different groupPublicKey here
204
205
  paired.push(pairing(groupPublicKey, message, false));
205
206
  }
206
- paired.push(pairing(G1.Point.BASE.negate(), sig, false));
207
+ paired.push(pairing(G1.ProjectivePoint.BASE.negate(), sig, false));
207
208
  const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
208
209
  const exp = Fp12.finalExponentiate(product);
209
- return Fp12.equals(exp, Fp12.ONE);
210
+ return Fp12.eql(exp, Fp12.ONE);
210
211
  }
211
212
  catch {
212
213
  return false;
213
214
  }
214
215
  }
215
- // Pre-compute points. Refer to README.
216
- G1.Point.BASE._setWindowSize(4);
216
+ G1.ProjectivePoint.BASE._setWindowSize(4);
217
217
  return {
218
218
  CURVE,
219
219
  Fr,
@@ -226,6 +226,7 @@ export function bls(CURVE) {
226
226
  Signature,
227
227
  millerLoop,
228
228
  calcPairingPrecomputes,
229
+ hashToCurve: { G1: G1HashToCurve, G2: G2HashToCurve },
229
230
  pairing,
230
231
  getPublicKey,
231
232
  sign,
@@ -1,8 +1,11 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  // Abelian group utilities
3
+ import { validateField, nLength } from './modular.js';
4
+ import { validateObject } from './utils.js';
3
5
  const _0n = BigInt(0);
4
6
  const _1n = BigInt(1);
5
- // Not big, but pretty complex and it is easy to break stuff. To avoid too much copy paste
7
+ // Elliptic curve multiplication of Point by scalar. Complicated and fragile. Uses wNAF method.
8
+ // Windowed method is 10% faster, but takes 2x longer to generate & consumes 2x memory.
6
9
  export function wNAF(c, bits) {
7
10
  const constTimeNegate = (condition, item) => {
8
11
  const neg = item.negate();
@@ -104,5 +107,32 @@ export function wNAF(c, bits) {
104
107
  // which makes it less const-time: around 1 bigint multiply.
105
108
  return { p, f };
106
109
  },
110
+ wNAFCached(P, precomputesMap, n, transform) {
111
+ // @ts-ignore
112
+ const W = P._WINDOW_SIZE || 1;
113
+ // Calculate precomputes on a first run, reuse them after
114
+ let comp = precomputesMap.get(P);
115
+ if (!comp) {
116
+ comp = this.precomputeWindow(P, W);
117
+ if (W !== 1) {
118
+ precomputesMap.set(P, transform(comp));
119
+ }
120
+ }
121
+ return this.wNAF(W, comp, n);
122
+ },
107
123
  };
108
124
  }
125
+ export function validateBasic(curve) {
126
+ validateField(curve.Fp);
127
+ validateObject(curve, {
128
+ n: 'bigint',
129
+ h: 'bigint',
130
+ Gx: 'field',
131
+ Gy: 'field',
132
+ }, {
133
+ nBitLength: 'isSafeInteger',
134
+ nByteLength: 'isSafeInteger',
135
+ });
136
+ // Set defaults
137
+ return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve });
138
+ }