@noble/curves 2.0.0 → 2.2.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 (110) hide show
  1. package/README.md +214 -122
  2. package/abstract/bls.d.ts +299 -16
  3. package/abstract/bls.d.ts.map +1 -1
  4. package/abstract/bls.js +89 -24
  5. package/abstract/bls.js.map +1 -1
  6. package/abstract/curve.d.ts +274 -27
  7. package/abstract/curve.d.ts.map +1 -1
  8. package/abstract/curve.js +177 -23
  9. package/abstract/curve.js.map +1 -1
  10. package/abstract/edwards.d.ts +166 -30
  11. package/abstract/edwards.d.ts.map +1 -1
  12. package/abstract/edwards.js +221 -86
  13. package/abstract/edwards.js.map +1 -1
  14. package/abstract/fft.d.ts +327 -10
  15. package/abstract/fft.d.ts.map +1 -1
  16. package/abstract/fft.js +155 -12
  17. package/abstract/fft.js.map +1 -1
  18. package/abstract/frost.d.ts +293 -0
  19. package/abstract/frost.d.ts.map +1 -0
  20. package/abstract/frost.js +704 -0
  21. package/abstract/frost.js.map +1 -0
  22. package/abstract/hash-to-curve.d.ts +173 -24
  23. package/abstract/hash-to-curve.d.ts.map +1 -1
  24. package/abstract/hash-to-curve.js +170 -31
  25. package/abstract/hash-to-curve.js.map +1 -1
  26. package/abstract/modular.d.ts +429 -37
  27. package/abstract/modular.d.ts.map +1 -1
  28. package/abstract/modular.js +414 -119
  29. package/abstract/modular.js.map +1 -1
  30. package/abstract/montgomery.d.ts +83 -12
  31. package/abstract/montgomery.d.ts.map +1 -1
  32. package/abstract/montgomery.js +32 -7
  33. package/abstract/montgomery.js.map +1 -1
  34. package/abstract/oprf.d.ts +164 -91
  35. package/abstract/oprf.d.ts.map +1 -1
  36. package/abstract/oprf.js +88 -29
  37. package/abstract/oprf.js.map +1 -1
  38. package/abstract/poseidon.d.ts +138 -7
  39. package/abstract/poseidon.d.ts.map +1 -1
  40. package/abstract/poseidon.js +178 -15
  41. package/abstract/poseidon.js.map +1 -1
  42. package/abstract/tower.d.ts +122 -3
  43. package/abstract/tower.d.ts.map +1 -1
  44. package/abstract/tower.js +323 -139
  45. package/abstract/tower.js.map +1 -1
  46. package/abstract/weierstrass.d.ts +339 -76
  47. package/abstract/weierstrass.d.ts.map +1 -1
  48. package/abstract/weierstrass.js +395 -205
  49. package/abstract/weierstrass.js.map +1 -1
  50. package/bls12-381.d.ts +16 -2
  51. package/bls12-381.d.ts.map +1 -1
  52. package/bls12-381.js +199 -209
  53. package/bls12-381.js.map +1 -1
  54. package/bn254.d.ts +11 -2
  55. package/bn254.d.ts.map +1 -1
  56. package/bn254.js +93 -38
  57. package/bn254.js.map +1 -1
  58. package/ed25519.d.ts +135 -14
  59. package/ed25519.d.ts.map +1 -1
  60. package/ed25519.js +207 -41
  61. package/ed25519.js.map +1 -1
  62. package/ed448.d.ts +108 -14
  63. package/ed448.d.ts.map +1 -1
  64. package/ed448.js +194 -42
  65. package/ed448.js.map +1 -1
  66. package/index.js +7 -1
  67. package/index.js.map +1 -1
  68. package/misc.d.ts +106 -7
  69. package/misc.d.ts.map +1 -1
  70. package/misc.js +141 -32
  71. package/misc.js.map +1 -1
  72. package/nist.d.ts +112 -11
  73. package/nist.d.ts.map +1 -1
  74. package/nist.js +139 -17
  75. package/nist.js.map +1 -1
  76. package/package.json +34 -6
  77. package/secp256k1.d.ts +92 -15
  78. package/secp256k1.d.ts.map +1 -1
  79. package/secp256k1.js +211 -28
  80. package/secp256k1.js.map +1 -1
  81. package/src/abstract/bls.ts +356 -69
  82. package/src/abstract/curve.ts +327 -44
  83. package/src/abstract/edwards.ts +367 -143
  84. package/src/abstract/fft.ts +371 -36
  85. package/src/abstract/frost.ts +1092 -0
  86. package/src/abstract/hash-to-curve.ts +255 -56
  87. package/src/abstract/modular.ts +591 -144
  88. package/src/abstract/montgomery.ts +114 -30
  89. package/src/abstract/oprf.ts +383 -194
  90. package/src/abstract/poseidon.ts +235 -35
  91. package/src/abstract/tower.ts +428 -159
  92. package/src/abstract/weierstrass.ts +710 -312
  93. package/src/bls12-381.ts +239 -236
  94. package/src/bn254.ts +107 -46
  95. package/src/ed25519.ts +234 -56
  96. package/src/ed448.ts +227 -57
  97. package/src/index.ts +7 -1
  98. package/src/misc.ts +154 -35
  99. package/src/nist.ts +143 -20
  100. package/src/secp256k1.ts +284 -41
  101. package/src/utils.ts +583 -81
  102. package/src/webcrypto.ts +302 -73
  103. package/utils.d.ts +457 -24
  104. package/utils.d.ts.map +1 -1
  105. package/utils.js +410 -53
  106. package/utils.js.map +1 -1
  107. package/webcrypto.d.ts +167 -25
  108. package/webcrypto.d.ts.map +1 -1
  109. package/webcrypto.js +165 -58
  110. package/webcrypto.js.map +1 -1
@@ -15,13 +15,12 @@
15
15
  * @module
16
16
  **/
17
17
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
18
- import { abytes, memoized, notImplemented, randomBytes } from '../utils.ts';
19
- import { normalizeZ, type CurveLengths } from './curve.ts';
18
+ import { abytes, notImplemented, randomBytes, type TArg, type TRet } from '../utils.ts';
19
+ import { type CurveLengths } from './curve.ts';
20
20
  import {
21
21
  createHasher,
22
22
  type H2CDSTOpts,
23
23
  type H2CHasher,
24
- type H2CHashOpts,
25
24
  type H2COpts,
26
25
  type MapToCurve,
27
26
  } from './hash-to-curve.ts';
@@ -34,30 +33,99 @@ type Fp = bigint; // Can be different field?
34
33
  // prettier-ignore
35
34
  const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
36
35
 
36
+ /**
37
+ * Twist convention used by the pairing formulas for a concrete curve family.
38
+ * BLS12-381 uses a multiplicative twist, while BN254 uses a divisive one.
39
+ */
37
40
  export type BlsTwistType = 'multiplicative' | 'divisive';
38
41
 
42
+ /**
43
+ * Codec exposed as `curve.shortSignatures.Signature`.
44
+ * Use it to parse or serialize G1 signatures in short-signature mode.
45
+ * In this mode, public keys live in G2.
46
+ */
39
47
  export type BlsShortSignatureCoder<Fp> = {
40
- fromBytes(bytes: Uint8Array): WeierstrassPoint<Fp>;
48
+ /**
49
+ * Parse a compressed signature from raw bytes.
50
+ * @param bytes - Compressed signature bytes.
51
+ * @returns Parsed signature point.
52
+ */
53
+ fromBytes(bytes: TArg<Uint8Array>): WeierstrassPoint<Fp>;
54
+ /**
55
+ * Parse a compressed signature from a hex string.
56
+ * @param hex - Compressed signature hex string.
57
+ * @returns Parsed signature point.
58
+ */
41
59
  fromHex(hex: string): WeierstrassPoint<Fp>;
42
- toBytes(point: WeierstrassPoint<Fp>): Uint8Array;
60
+ /**
61
+ * Encode a signature point into compressed bytes.
62
+ * @param point - Signature point.
63
+ * @returns Compressed signature bytes.
64
+ */
65
+ toBytes(point: WeierstrassPoint<Fp>): TRet<Uint8Array>;
66
+ /**
67
+ * Encode a signature point into a hex string.
68
+ * @param point - Signature point.
69
+ * @returns Compressed signature hex.
70
+ */
43
71
  toHex(point: WeierstrassPoint<Fp>): string;
44
72
  };
45
73
 
74
+ /**
75
+ * Codec exposed as `curve.longSignatures.Signature`.
76
+ * Use it to parse or serialize G2 signatures in long-signature mode.
77
+ * In this mode, public keys live in G1.
78
+ */
46
79
  export type BlsLongSignatureCoder<Fp> = {
47
- fromBytes(bytes: Uint8Array): WeierstrassPoint<Fp>;
80
+ /**
81
+ * Parse a compressed signature from raw bytes.
82
+ * @param bytes - Compressed signature bytes.
83
+ * @returns Parsed signature point.
84
+ */
85
+ fromBytes(bytes: TArg<Uint8Array>): WeierstrassPoint<Fp>;
86
+ /**
87
+ * Parse a compressed signature from a hex string.
88
+ * @param hex - Compressed signature hex string.
89
+ * @returns Parsed signature point.
90
+ */
48
91
  fromHex(hex: string): WeierstrassPoint<Fp>;
49
- toBytes(point: WeierstrassPoint<Fp>): Uint8Array;
92
+ /**
93
+ * Encode a signature point into compressed bytes.
94
+ * @param point - Signature point.
95
+ * @returns Compressed signature bytes.
96
+ */
97
+ toBytes(point: WeierstrassPoint<Fp>): TRet<Uint8Array>;
98
+ /**
99
+ * Encode a signature point into a hex string.
100
+ * @param point - Signature point.
101
+ * @returns Compressed signature hex.
102
+ */
50
103
  toHex(point: WeierstrassPoint<Fp>): string;
51
104
  };
52
105
 
106
+ /** Tower fields needed by pairing code, hash-to-curve, and subgroup arithmetic. */
53
107
  export type BlsFields = {
108
+ /** Base field of G1 coordinates. */
54
109
  Fp: IField<Fp>;
110
+ /** Scalar field used for secret scalars and subgroup order arithmetic. */
55
111
  Fr: IField<bigint>;
112
+ /** Quadratic extension field used by G2. */
56
113
  Fp2: Fp2Bls;
114
+ /** Sextic extension field used inside pairing arithmetic. */
57
115
  Fp6: Fp6Bls;
116
+ /** Degree-12 extension field that contains the GT target group. */
58
117
  Fp12: Fp12Bls;
59
118
  };
60
119
 
120
+ /**
121
+ * Callback used by pairing post-processing hooks to add one more G2 point to the Miller-loop state.
122
+ * @param Rx - Current projective X coordinate.
123
+ * @param Ry - Current projective Y coordinate.
124
+ * @param Rz - Current projective Z coordinate.
125
+ * @param Qx - G2 affine x coordinate.
126
+ * @param Qy - G2 affine y coordinate.
127
+ * @returns Updated projective accumulator coordinates.
128
+ */
61
129
  export type BlsPostPrecomputePointAddFn = (
62
130
  Rx: Fp2,
63
131
  Ry: Fp2,
@@ -65,6 +133,15 @@ export type BlsPostPrecomputePointAddFn = (
65
133
  Qx: Fp2,
66
134
  Qy: Fp2
67
135
  ) => { Rx: Fp2; Ry: Fp2; Rz: Fp2 };
136
+ /**
137
+ * Hook for curve-specific pairing cleanup after the Miller loop precomputes are built.
138
+ * @param Rx - Current projective X coordinate.
139
+ * @param Ry - Current projective Y coordinate.
140
+ * @param Rz - Current projective Z coordinate.
141
+ * @param Qx - G2 affine x coordinate.
142
+ * @param Qy - G2 affine y coordinate.
143
+ * @param pointAdd - Callback used to fold one more point into the accumulator.
144
+ */
68
145
  export type BlsPostPrecomputeFn = (
69
146
  Rx: Fp2,
70
147
  Ry: Fp2,
@@ -73,34 +150,97 @@ export type BlsPostPrecomputeFn = (
73
150
  Qy: Fp2,
74
151
  pointAdd: BlsPostPrecomputePointAddFn
75
152
  ) => void;
153
+ /** Low-level pairing helpers shared by BLS curve bundles. */
76
154
  export type BlsPairing = {
155
+ /** Byte lengths for keys and signatures exposed by this pairing family. */
77
156
  lengths: CurveLengths;
157
+ /** Scalar field used by the pairing and signing helpers. */
78
158
  Fr: IField<bigint>;
159
+ /** Target field used for the GT result of pairings. */
79
160
  Fp12: Fp12Bls;
161
+ /**
162
+ * Build Miller-loop precomputes for one G2 point.
163
+ * @param p - G2 point to precompute.
164
+ * @returns Pairing precompute table.
165
+ */
80
166
  calcPairingPrecomputes: (p: WeierstrassPoint<Fp2>) => Precompute;
167
+ /**
168
+ * Evaluate a batch of Miller loops from precomputed line coefficients.
169
+ * @param pairs - Precomputed Miller-loop inputs.
170
+ * @returns Accumulated GT value before or after final exponentiation.
171
+ */
81
172
  millerLoopBatch: (pairs: [Precompute, Fp, Fp][]) => Fp12;
173
+ /**
174
+ * Pair one G1 point with one G2 point.
175
+ * @param P - G1 point.
176
+ * @param Q - G2 point.
177
+ * @param withFinalExponent - Whether to apply the final exponentiation step.
178
+ * @returns GT pairing result.
179
+ * @throws If either point is the point at infinity. {@link Error}
180
+ */
82
181
  pairing: (P: WeierstrassPoint<Fp>, Q: WeierstrassPoint<Fp2>, withFinalExponent?: boolean) => Fp12;
182
+ /**
183
+ * Pair many G1/G2 pairs in one batch.
184
+ * @param pairs - Point pairs to accumulate.
185
+ * @param withFinalExponent - Whether to apply the final exponentiation step.
186
+ * @returns GT pairing result. Empty input returns the multiplicative identity in GT.
187
+ */
83
188
  pairingBatch: (
84
189
  pairs: { g1: WeierstrassPoint<Fp>; g2: WeierstrassPoint<Fp2> }[],
85
190
  withFinalExponent?: boolean
86
191
  ) => Fp12;
87
- randomSecretKey: (seed?: Uint8Array) => Uint8Array;
192
+ /**
193
+ * Generate a random secret key for this pairing family.
194
+ * @param seed - Optional seed material.
195
+ * @returns Secret key bytes.
196
+ */
197
+ randomSecretKey: (seed?: TArg<Uint8Array>) => TRet<Uint8Array>;
88
198
  };
89
199
 
200
+ /**
201
+ * Parameters that define the Miller-loop shape and twist handling
202
+ * for a concrete pairing family.
203
+ */
90
204
  export type BlsPairingParams = {
91
205
  // MSB is always ignored and used as marker for length, otherwise leading zeros will be lost.
92
206
  // Can be different from `X` (seed) param.
207
+ /** Signed loop parameter used by the Miller loop. */
93
208
  ateLoopSize: bigint;
209
+ /** Whether the signed Miller-loop parameter is negative. */
94
210
  xNegative: boolean;
95
- twistType: BlsTwistType; // BLS12-381: Multiplicative, BN254: Divisive
96
- randomBytes?: (len?: number) => Uint8Array;
97
- postPrecompute?: BlsPostPrecomputeFn; // Ugly hack to untwist point in BN254 after miller loop
211
+ /**
212
+ * Twist convention used by the pairing formulas.
213
+ * BLS12-381 is multiplicative; BN254 is divisive.
214
+ */
215
+ twistType: BlsTwistType;
216
+ /**
217
+ * Optional RNG override used by helper constructors.
218
+ * Receives the requested byte length and returns random bytes.
219
+ */
220
+ randomBytes?: (len?: number) => TRet<Uint8Array>;
221
+ /**
222
+ * Optional hook for curve-specific untwisting after precomputation.
223
+ * Used by BN254 after the Miller loop.
224
+ */
225
+ postPrecompute?: BlsPostPrecomputeFn;
98
226
  };
227
+ /** Hash-to-curve settings shared by the G1 and G2 hashers inside a BLS curve bundle. */
99
228
  export type BlsHasherParams = {
229
+ /**
230
+ * Optional map-to-curve override for G1.
231
+ * Receives the hash-to-field tuple and returns one affine G1 point.
232
+ */
100
233
  mapToG1?: MapToCurve<Fp>;
234
+ /**
235
+ * Optional map-to-curve override for G2.
236
+ * Receives the hash-to-field tuple and returns one affine G2 point.
237
+ */
101
238
  mapToG2?: MapToCurve<Fp2>;
239
+ /** Shared baseline hash-to-curve options. */
102
240
  hasherOpts: H2COpts;
241
+ /** G1-specific hash-to-curve options merged on top of `hasherOpts`. */
103
242
  hasherOptsG1: H2COpts;
243
+ /** G2-specific hash-to-curve options merged on top of `hasherOpts`. */
104
244
  hasherOptsG2: H2COpts;
105
245
  };
106
246
  type PrecomputeSingle = [Fp2, Fp2, Fp2][];
@@ -112,12 +252,35 @@ type Precompute = PrecomputeSingle[];
112
252
  * - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1
113
253
  */
114
254
  export interface BlsCurvePair {
255
+ /** Byte lengths for keys and signatures exposed by this curve family. */
115
256
  lengths: CurveLengths;
257
+ /**
258
+ * Shared Miller-loop batch evaluator.
259
+ * @param pairs - Precomputed Miller-loop inputs.
260
+ * @returns Accumulated GT value.
261
+ */
116
262
  millerLoopBatch: BlsPairing['millerLoopBatch'];
263
+ /**
264
+ * Pair one G1 point with one G2 point.
265
+ * @param P - G1 point.
266
+ * @param Q - G2 point.
267
+ * @param withFinalExponent - Whether to apply the final exponentiation step.
268
+ * @returns GT pairing result.
269
+ * @throws If either point is the point at infinity. {@link Error}
270
+ */
117
271
  pairing: BlsPairing['pairing'];
272
+ /**
273
+ * Pair many G1/G2 pairs in one batch.
274
+ * @param pairs - Point pairs to accumulate.
275
+ * @param withFinalExponent - Whether to apply the final exponentiation step.
276
+ * @returns GT pairing result. Empty input returns the multiplicative identity in GT.
277
+ */
118
278
  pairingBatch: BlsPairing['pairingBatch'];
279
+ /** G1 point constructor for the base field subgroup. */
119
280
  G1: { Point: WeierstrassPointCons<Fp> };
281
+ /** G2 point constructor for the twist subgroup. */
120
282
  G2: { Point: WeierstrassPointCons<Fp2> };
283
+ /** Tower fields exposed by the pairing implementation. */
121
284
  fields: {
122
285
  Fp: IField<Fp>;
123
286
  Fp2: Fp2Bls;
@@ -125,51 +288,112 @@ export interface BlsCurvePair {
125
288
  Fp12: Fp12Bls;
126
289
  Fr: IField<bigint>;
127
290
  };
291
+ /** Utility helpers shared by hashers and signers. */
128
292
  utils: {
129
- randomSecretKey: (seed?: Uint8Array) => Uint8Array;
293
+ randomSecretKey: (seed?: TArg<Uint8Array>) => TRet<Uint8Array>;
130
294
  calcPairingPrecomputes: BlsPairing['calcPairingPrecomputes'];
131
295
  };
296
+ /** Public pairing parameters exposed for introspection. */
132
297
  params: {
133
298
  ateLoopSize: bigint;
134
299
  twistType: BlsTwistType;
135
300
  };
136
301
  }
137
302
 
303
+ /** BLS curve bundle extended with hash-to-curve helpers for G1 and G2. */
138
304
  export interface BlsCurvePairWithHashers extends BlsCurvePair {
305
+ /** G1 hasher bundle with RFC 9380 helpers. */
139
306
  G1: H2CHasher<WeierstrassPointCons<Fp>>;
307
+ /** G2 hasher bundle with RFC 9380 helpers. */
140
308
  G2: H2CHasher<WeierstrassPointCons<Fp2>>;
141
309
  }
142
310
 
311
+ /** BLS curve bundle extended with both hashers and signature helpers. */
143
312
  export interface BlsCurvePairWithSignatures extends BlsCurvePairWithHashers {
313
+ /** Long-signature mode: G1 public keys and G2 signatures. */
144
314
  longSignatures: BlsSigs<bigint, Fp2>;
315
+ /** Short-signature mode: G2 public keys and G1 signatures. */
145
316
  shortSignatures: BlsSigs<Fp2, bigint>;
146
317
  }
147
318
 
148
- type BLSInput = Uint8Array;
319
+ type BLSInput = TArg<Uint8Array>;
320
+ /** BLS signer helpers for one signature mode. */
149
321
  export interface BlsSigs<P, S> {
322
+ /** Byte lengths for secret keys, public keys, and signatures. */
150
323
  lengths: CurveLengths;
151
- keygen(seed?: Uint8Array): {
152
- secretKey: Uint8Array;
324
+ /**
325
+ * Generate a secret/public key pair for this signature mode.
326
+ * @param seed - Optional seed material.
327
+ * @returns Secret and public key pair.
328
+ */
329
+ keygen(seed?: TArg<Uint8Array>): {
330
+ secretKey: TRet<Uint8Array>;
153
331
  publicKey: WeierstrassPoint<P>;
154
332
  };
155
- getPublicKey(secretKey: Uint8Array): WeierstrassPoint<P>;
156
- sign(hashedMessage: WeierstrassPoint<S>, secretKey: Uint8Array): WeierstrassPoint<S>;
333
+ /**
334
+ * Derive the public key from a secret key.
335
+ * @param secretKey - Secret key bytes.
336
+ * @returns Public-key point.
337
+ */
338
+ getPublicKey(secretKey: TArg<Uint8Array>): WeierstrassPoint<P>;
339
+ /**
340
+ * Sign a message already hashed onto the signature subgroup.
341
+ * @param hashedMessage - Message mapped to the signature subgroup.
342
+ * @param secretKey - Secret key bytes.
343
+ * @returns Signature point.
344
+ */
345
+ sign(hashedMessage: WeierstrassPoint<S>, secretKey: TArg<Uint8Array>): WeierstrassPoint<S>;
346
+ /**
347
+ * Verify one signature against one public key and hashed message.
348
+ * @param signature - Signature point or encoded signature.
349
+ * @param message - Hashed message point.
350
+ * @param publicKey - Public-key point or encoded key.
351
+ * @returns Whether the signature is valid.
352
+ */
157
353
  verify(
158
354
  signature: WeierstrassPoint<S> | BLSInput,
159
355
  message: WeierstrassPoint<S>,
160
356
  publicKey: WeierstrassPoint<P> | BLSInput
161
357
  ): boolean;
358
+ /**
359
+ * Verify one aggregated signature against many `(message, publicKey)` pairs.
360
+ * @param signature - Aggregated signature.
361
+ * @param items - Message/public-key pairs.
362
+ * @returns Whether the aggregated signature is valid. Same-message aggregate verification still
363
+ * requires proof of possession or another rogue-key defense from the caller.
364
+ */
162
365
  verifyBatch: (
163
366
  signature: WeierstrassPoint<S> | BLSInput,
164
367
  items: { message: WeierstrassPoint<S>; publicKey: WeierstrassPoint<P> | BLSInput }[]
165
368
  ) => boolean;
369
+ /**
370
+ * Add many public keys into one aggregate point.
371
+ * @param publicKeys - Public keys to aggregate.
372
+ * @returns Aggregated public-key point. This is raw point addition and does not add proof of
373
+ * possession or rogue-key protection on its own.
374
+ */
166
375
  aggregatePublicKeys(publicKeys: (WeierstrassPoint<P> | BLSInput)[]): WeierstrassPoint<P>;
376
+ /**
377
+ * Add many signatures into one aggregate point.
378
+ * @param signatures - Signatures to aggregate.
379
+ * @returns Aggregated signature point. This is raw point addition and does not change the proof
380
+ * of possession requirements of the aggregate-verification scheme.
381
+ */
167
382
  aggregateSignatures(signatures: (WeierstrassPoint<S> | BLSInput)[]): WeierstrassPoint<S>;
168
- hash(message: Uint8Array, DST?: string | Uint8Array, hashOpts?: H2CHashOpts): WeierstrassPoint<S>;
383
+ /**
384
+ * Hash an arbitrary message onto the signature subgroup.
385
+ * @param message - Message bytes.
386
+ * @param DST - Optional domain separation tag.
387
+ * @returns Curve point on the signature subgroup.
388
+ */
389
+ hash(message: TArg<Uint8Array>, DST?: TArg<string | Uint8Array>): WeierstrassPoint<S>;
390
+ /** Signature codec for this mode. */
169
391
  Signature: BlsLongSignatureCoder<S>;
170
392
  }
171
393
 
172
- // Not used with BLS12-381 (no sequential `11` in X). Useful for other curves.
394
+ // Signed non-adjacent decomposition of the spec-defined Miller-loop parameter.
395
+ // BN254 benefits most because `6x+2` has multiple adjacent `11` runs, but BLS12-381's
396
+ // stored `|x|` still starts with `11`, so the Miller loop must also handle one `-1` digit there.
173
397
  function NAfDecomposition(a: bigint) {
174
398
  const res = [];
175
399
  // a>1 because of marker bit
@@ -182,17 +406,19 @@ function NAfDecomposition(a: bigint) {
182
406
  }
183
407
  return res;
184
408
  }
185
-
186
409
  function aNonEmpty(arr: any[]) {
410
+ // Aggregate helpers use this to reject empty variable-length inputs consistently.
411
+ // Without the guard, each caller would fall through into a different empty-input / identity
412
+ // case and hide missing inputs behind outputs that still look structurally valid.
187
413
  if (!Array.isArray(arr) || arr.length === 0) throw new Error('expected non-empty array');
188
414
  }
189
415
 
190
416
  // This should be enough for bn254, no need to export full stuff?
191
417
  function createBlsPairing(
192
- fields: BlsFields,
418
+ fields: TArg<BlsFields>,
193
419
  G1: WeierstrassPointCons<Fp>,
194
420
  G2: WeierstrassPointCons<Fp2>,
195
- params: BlsPairingParams
421
+ params: TArg<BlsPairingParams>
196
422
  ): BlsPairing {
197
423
  const { Fr, Fp2, Fp12 } = fields;
198
424
  const { twistType, ateLoopSize, xNegative, postPrecompute } = params;
@@ -224,7 +450,8 @@ function createBlsPairing(
224
450
  ell.push([c0, c1, c2]);
225
451
 
226
452
  Rx = Fp2.mul(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), Fp2div2); // ((T0 - T3) * Rx * Ry) / 2
227
- Ry = Fp2.sub(Fp2.sqr(Fp2.mul(Fp2.add(t0, t3), Fp2div2)), Fp2.mul(Fp2.sqr(t2), _3n)); // ((T0 + T3) / 2)² - 3 * T2²
453
+ // ((T0 + T3) / 2)² - 3 * T2²
454
+ Ry = Fp2.sub(Fp2.sqr(Fp2.mul(Fp2.add(t0, t3), Fp2div2)), Fp2.mul(Fp2.sqr(t2), _3n));
228
455
  Rz = Fp2.mul(t0, t4); // T0 * T4
229
456
  return { Rx, Ry, Rz };
230
457
  }
@@ -241,7 +468,8 @@ function createBlsPairing(
241
468
  const t2 = Fp2.sqr(t1); // T1²
242
469
  const t3 = Fp2.mul(t2, t1); // T2 * T1
243
470
  const t4 = Fp2.mul(t2, Rx); // T2 * Rx
244
- const t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, _2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
471
+ // T3 - 2 * T4 + T0² * Rz
472
+ const t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, _2n)), Fp2.mul(Fp2.sqr(t0), Rz));
245
473
  Rx = Fp2.mul(t1, t5); // T1 * T5
246
474
  Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
247
475
  Rz = Fp2.mul(Rz, t3); // Rz * T3
@@ -254,7 +482,7 @@ function createBlsPairing(
254
482
  // add + double in windowed precomputes here, otherwise it would be single op (since X is static)
255
483
  const ATE_NAF = NAfDecomposition(ateLoopSize);
256
484
 
257
- const calcPairingPrecomputes = memoized((point: G2) => {
485
+ const calcPairingPrecomputes = (point: G2) => {
258
486
  const p = point;
259
487
  const { x, y } = p.toAffine();
260
488
  // prettier-ignore
@@ -273,7 +501,7 @@ function createBlsPairing(
273
501
  postPrecompute(Rx, Ry, Rz, Qx, Qy, pointAdd.bind(null, last));
274
502
  }
275
503
  return ell;
276
- });
504
+ };
277
505
 
278
506
  // Main pairing logic is here. Computes product of miller loops + final exponentiate
279
507
  // Applies calculated precomputes
@@ -298,16 +526,11 @@ function createBlsPairing(
298
526
  // This up to x2 faster than just `map(({g1, g2})=>pairing({g1,g2}))`
299
527
  function pairingBatch(pairs: PairingInput[], withFinalExponent: boolean = true) {
300
528
  const res: MillerInput = [];
301
- // Cache precomputed toAffine for all points
302
- normalizeZ(
303
- G1,
304
- pairs.map(({ g1 }) => g1)
305
- );
306
- normalizeZ(
307
- G2,
308
- pairs.map(({ g2 }) => g2)
309
- );
310
529
  for (const { g1, g2 } of pairs) {
530
+ // Mathematically, a zero pairing term contributes GT.ONE. We still reject it here because
531
+ // this API mainly backs BLS verification, where ZERO inputs usually mean broken hash /
532
+ // wiring. Silently skipping them would turn those failures into a neutral pairing product.
533
+ // Callers that want the algebraic neutral-element behavior can filter ZERO terms first.
311
534
  if (g1.is0() || g2.is0()) throw new Error('pairing is not available for ZERO point');
312
535
  // This uses toAffine inside
313
536
  g1.assertValidity();
@@ -324,11 +547,15 @@ function createBlsPairing(
324
547
  const lengths = {
325
548
  seed: getMinHashLength(Fr.ORDER),
326
549
  };
327
- const rand = params.randomBytes || randomBytes;
328
- const randomSecretKey = (seed = rand(lengths.seed)): Uint8Array => {
550
+ const rand = params.randomBytes === undefined ? randomBytes : params.randomBytes;
551
+ // Seeded calls deterministically reduce exactly `lengths.seed` bytes into `1..Fr.ORDER-1`;
552
+ // omitting `seed` just fills that input buffer from the configured RNG first.
553
+ const randomSecretKey = (seed?: TArg<Uint8Array>): TRet<Uint8Array> => {
554
+ seed = seed === undefined ? rand(lengths.seed) : seed;
329
555
  abytes(seed, lengths.seed, 'seed');
330
- return mapHashToField(seed, Fr.ORDER);
556
+ return mapHashToField(seed, Fr.ORDER) as TRet<Uint8Array>;
331
557
  };
558
+ Object.freeze(lengths);
332
559
  return {
333
560
  lengths,
334
561
  Fr,
@@ -346,7 +573,7 @@ function createBlsSig<P, S>(
346
573
  PubPoint: WeierstrassPointCons<P>,
347
574
  SigPoint: WeierstrassPointCons<S>,
348
575
  isSigG1: boolean,
349
- hashToSigCurve: (msg: Uint8Array, options?: H2CDSTOpts) => WeierstrassPoint<S>,
576
+ hashToSigCurve: (msg: TArg<Uint8Array>, options?: TArg<H2CDSTOpts>) => WeierstrassPoint<S>,
350
577
  SignatureCoder?: BlsLongSignatureCoder<S>
351
578
  ): BlsSigs<P, S> {
352
579
  const { Fr, Fp12, pairingBatch, randomSecretKey, lengths } = blsPairing;
@@ -366,6 +593,9 @@ function createBlsSig<P, S>(
366
593
  function normSig(point: SigPoint | BLSInput): SigPoint {
367
594
  return point instanceof SigPoint ? (point as SigPoint) : SigPoint.fromBytes(point);
368
595
  }
596
+ // Sign/verify here take points already hashed onto the signature subgroup.
597
+ // Raw bytes and points from the other subgroup must fail this constructor-brand
598
+ // check before later validity checks run.
369
599
  function amsg(m: unknown): SigPoint {
370
600
  if (!(m instanceof SigPoint))
371
601
  throw new Error(`expected valid message hashed to ${!isSigG1 ? 'G2' : 'G1'} curve`);
@@ -380,14 +610,14 @@ function createBlsSig<P, S>(
380
610
  ? (a: PubPoint, b: SigPoint) => ({ g1: a, g2: b }) as PairingInput
381
611
  : (a: PubPoint, b: SigPoint) => ({ g1: b, g2: a }) as PairingInput;
382
612
  return Object.freeze({
383
- lengths: { ...lengths, secretKey: Fr.BYTES },
384
- keygen(seed?: Uint8Array) {
613
+ lengths: Object.freeze({ ...lengths, secretKey: Fr.BYTES }),
614
+ keygen(seed?: TArg<Uint8Array>) {
385
615
  const secretKey = randomSecretKey(seed);
386
616
  const publicKey = this.getPublicKey(secretKey);
387
617
  return { secretKey, publicKey };
388
618
  },
389
619
  // P = pk x G
390
- getPublicKey(secretKey: Uint8Array): PubPoint {
620
+ getPublicKey(secretKey: TArg<Uint8Array>): PubPoint {
391
621
  let sec;
392
622
  try {
393
623
  sec = PubPoint.Fn.fromBytes(secretKey);
@@ -398,7 +628,7 @@ function createBlsSig<P, S>(
398
628
  return PubPoint.BASE.multiply(sec);
399
629
  },
400
630
  // S = pk x H(m)
401
- sign(message: SigPoint, secretKey: Uint8Array, unusedArg?: any): SigPoint {
631
+ sign(message: SigPoint, secretKey: TArg<Uint8Array>, unusedArg?: any): SigPoint {
402
632
  if (unusedArg != null) throw new Error('sign() expects 2 arguments');
403
633
  const sec = PubPoint.Fn.fromBytes(secretKey);
404
634
  amsg(message).assertValidity();
@@ -424,8 +654,12 @@ function createBlsSig<P, S>(
424
654
  // Before it was G.negate() in G2, now it's always pubKey.negate
425
655
  // e(P, -Q)===e(-P, Q)==e(P, Q)^-1. Negate can be done anywhere (as long it is done once per pair).
426
656
  // We just moving sign, but since pairing is multiplicative, we doing X * X^-1 = 1
427
- const exp = pairingBatch([pair(P, Hm), pair(G, S)]);
428
- return Fp12.eql(exp, Fp12.ONE);
657
+ try {
658
+ const exp = pairingBatch([pair(P, Hm), pair(G, S)]);
659
+ return Fp12.eql(exp, Fp12.ONE);
660
+ } catch {
661
+ return false;
662
+ }
429
663
  },
430
664
  // https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
431
665
  // e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
@@ -483,12 +717,12 @@ function createBlsSig<P, S>(
483
717
  return agg;
484
718
  },
485
719
 
486
- hash(messageBytes: Uint8Array, DST?: string | Uint8Array): SigPoint {
720
+ hash(messageBytes: TArg<Uint8Array>, DST?: TArg<string | Uint8Array>): SigPoint {
487
721
  abytes(messageBytes);
488
722
  const opts = DST ? { DST } : undefined;
489
723
  return hashToSigCurve(messageBytes, opts);
490
724
  },
491
- Signature: SignatureCoder,
725
+ Signature: Object.freeze({ ...SignatureCoder }),
492
726
  }) /*satisfies Signer */;
493
727
  }
494
728
 
@@ -498,11 +732,30 @@ type BlsSignatureCoders = Partial<{
498
732
  }>;
499
733
 
500
734
  // NOTE: separate function instead of function override, so we don't depend on hasher in bn254.
735
+ /**
736
+ * @param fields - Tower field implementations.
737
+ * @param G1_Point - G1 point constructor.
738
+ * @param G2_Point - G2 point constructor.
739
+ * @param params - Pairing parameters. See {@link BlsPairingParams}.
740
+ * @returns Pairing-only BLS helpers. The returned pairing surface rejects infinity inputs, while
741
+ * empty `pairingBatch(...)` calls return the multiplicative identity in GT. This keeps the
742
+ * low-level pairing API fail-closed for BLS-style callers, where identity points usually signal
743
+ * broken hash / wiring instead of an intentionally neutral pairing term. This also eagerly
744
+ * precomputes the G1 base-point table as a performance side effect.
745
+ * @throws If the pairing parameters or underlying curve helpers are inconsistent. {@link Error}
746
+ * @example
747
+ * ```ts
748
+ * import { blsBasic } from '@noble/curves/abstract/bls.js';
749
+ * import { bn254 } from '@noble/curves/bn254.js';
750
+ * // Pair a G1 point with a G2 point without the higher-level signer helpers.
751
+ * const gt = bn254.pairing(bn254.G1.Point.BASE, bn254.G2.Point.BASE);
752
+ * ```
753
+ */
501
754
  export function blsBasic(
502
- fields: BlsFields,
755
+ fields: TArg<BlsFields>,
503
756
  G1_Point: WeierstrassPointCons<Fp>,
504
757
  G2_Point: WeierstrassPointCons<Fp2>,
505
- params: BlsPairingParams
758
+ params: TArg<BlsPairingParams>
506
759
  ): BlsCurvePair {
507
760
  // Fields are specific for curve, so for now we'll need to pass them with opts
508
761
  const { Fp, Fr, Fp2, Fp6, Fp12 } = fields;
@@ -523,53 +776,87 @@ export function blsBasic(
523
776
  } = pairingRes;
524
777
 
525
778
  G1.Point.BASE.precompute(4);
779
+ Object.freeze(G1);
780
+ Object.freeze(G2);
526
781
  return Object.freeze({
527
- lengths,
782
+ lengths: Object.freeze(lengths),
528
783
  millerLoopBatch,
529
784
  pairing,
530
785
  pairingBatch,
531
786
  G1,
532
787
  G2,
533
- fields: { Fr, Fp, Fp2, Fp6, Fp12 },
534
- params: {
788
+ fields: Object.freeze({ Fr, Fp, Fp2, Fp6, Fp12 }),
789
+ params: Object.freeze({
535
790
  ateLoopSize: params.ateLoopSize,
536
791
  twistType: params.twistType,
537
- },
538
- utils: {
792
+ }),
793
+ utils: Object.freeze({
539
794
  randomSecretKey,
540
795
  calcPairingPrecomputes,
541
- },
796
+ }),
542
797
  });
543
798
  }
544
799
 
545
800
  // We can export this too, but seems there is not much reasons for now? If user wants hasher, they can just create hasher.
546
801
  function blsHashers(
547
- fields: BlsFields,
802
+ fields: TArg<BlsFields>,
548
803
  G1_Point: WeierstrassPointCons<Fp>,
549
804
  G2_Point: WeierstrassPointCons<Fp2>,
550
- params: BlsPairingParams,
551
- hasherParams: BlsHasherParams
805
+ params: TArg<BlsPairingParams>,
806
+ hasherParams: TArg<BlsHasherParams>
552
807
  ): BlsCurvePairWithHashers {
553
808
  const base = blsBasic(fields, G1_Point, G2_Point, params);
554
- const G1Hasher = createHasher(G1_Point, hasherParams.mapToG1 || notImplemented, {
555
- ...hasherParams.hasherOpts,
556
- ...hasherParams.hasherOptsG1,
557
- });
558
- const G2Hasher = createHasher(G2_Point, hasherParams.mapToG2 || notImplemented, {
559
- ...hasherParams.hasherOpts,
560
- ...hasherParams.hasherOptsG2,
561
- });
809
+ // Missing map hooks intentionally fail closed via notImplemented on first hash use.
810
+ const G1Hasher = createHasher(
811
+ G1_Point,
812
+ hasherParams.mapToG1 === undefined ? notImplemented : hasherParams.mapToG1,
813
+ {
814
+ ...hasherParams.hasherOpts,
815
+ ...hasherParams.hasherOptsG1,
816
+ }
817
+ );
818
+ const G2Hasher = createHasher(
819
+ G2_Point,
820
+ hasherParams.mapToG2 === undefined ? notImplemented : hasherParams.mapToG2,
821
+ {
822
+ ...hasherParams.hasherOpts,
823
+ ...hasherParams.hasherOptsG2,
824
+ }
825
+ );
562
826
  return Object.freeze({ ...base, G1: G1Hasher, G2: G2Hasher });
563
827
  }
564
828
 
565
829
  // G1_Point: ProjConstructor<bigint>, G2_Point: ProjConstructor<Fp2>,
566
830
  // Rename to blsSignatures?
831
+ /**
832
+ * @param fields - Tower field implementations.
833
+ * @param G1_Point - G1 point constructor.
834
+ * @param G2_Point - G2 point constructor.
835
+ * @param params - Pairing parameters. See {@link BlsPairingParams}.
836
+ * @param hasherParams - Hash-to-curve configuration. See {@link BlsHasherParams}.
837
+ * @param signatureCoders - Signature codecs.
838
+ * @returns BLS helpers with signers. The inherited pairing surface still rejects infinity inputs,
839
+ * and empty `pairingBatch(...)` calls still return the multiplicative identity in GT. Aggregate
840
+ * verification still requires proof of possession or another rogue-key defense from the caller.
841
+ * @throws If the pairing, hashing, or signature helpers are configured inconsistently. {@link Error}
842
+ * @example
843
+ * ```ts
844
+ * import { bls } from '@noble/curves/abstract/bls.js';
845
+ * import { bls12_381 } from '@noble/curves/bls12-381.js';
846
+ * const sigs = bls12_381.longSignatures;
847
+ * // Use the full BLS helper set when you need hashing, keygen, signing, and verification.
848
+ * const { secretKey, publicKey } = sigs.keygen();
849
+ * const msg = sigs.hash(new TextEncoder().encode('hello noble'));
850
+ * const sig = sigs.sign(msg, secretKey);
851
+ * const isValid = sigs.verify(sig, msg, publicKey);
852
+ * ```
853
+ */
567
854
  export function bls(
568
- fields: BlsFields,
855
+ fields: TArg<BlsFields>,
569
856
  G1_Point: WeierstrassPointCons<Fp>,
570
857
  G2_Point: WeierstrassPointCons<Fp2>,
571
- params: BlsPairingParams,
572
- hasherParams: BlsHasherParams,
858
+ params: TArg<BlsPairingParams>,
859
+ hasherParams: TArg<BlsHasherParams>,
573
860
  signatureCoders: BlsSignatureCoders
574
861
  ): BlsCurvePairWithSignatures {
575
862
  const base = blsHashers(fields, G1_Point, G2_Point, params, hasherParams);