@noble/curves 1.9.2 → 1.9.3

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 (179) hide show
  1. package/README.md +186 -206
  2. package/_shortw_utils.d.ts +1 -0
  3. package/_shortw_utils.d.ts.map +1 -1
  4. package/_shortw_utils.js +1 -0
  5. package/_shortw_utils.js.map +1 -1
  6. package/abstract/bls.d.ts +87 -62
  7. package/abstract/bls.d.ts.map +1 -1
  8. package/abstract/bls.js +170 -163
  9. package/abstract/bls.js.map +1 -1
  10. package/abstract/curve.d.ts +109 -23
  11. package/abstract/curve.d.ts.map +1 -1
  12. package/abstract/curve.js +158 -156
  13. package/abstract/curve.js.map +1 -1
  14. package/abstract/edwards.d.ts +124 -70
  15. package/abstract/edwards.d.ts.map +1 -1
  16. package/abstract/edwards.js +212 -62
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/hash-to-curve.d.ts +8 -4
  19. package/abstract/hash-to-curve.d.ts.map +1 -1
  20. package/abstract/hash-to-curve.js +23 -11
  21. package/abstract/hash-to-curve.js.map +1 -1
  22. package/abstract/modular.d.ts +8 -3
  23. package/abstract/modular.d.ts.map +1 -1
  24. package/abstract/modular.js +79 -35
  25. package/abstract/modular.js.map +1 -1
  26. package/abstract/montgomery.d.ts +17 -4
  27. package/abstract/montgomery.d.ts.map +1 -1
  28. package/abstract/montgomery.js +19 -3
  29. package/abstract/montgomery.js.map +1 -1
  30. package/abstract/tower.d.ts +3 -3
  31. package/abstract/tower.d.ts.map +1 -1
  32. package/abstract/tower.js.map +1 -1
  33. package/abstract/weierstrass.d.ts +142 -116
  34. package/abstract/weierstrass.d.ts.map +1 -1
  35. package/abstract/weierstrass.js +414 -335
  36. package/abstract/weierstrass.js.map +1 -1
  37. package/bls12-381.d.ts.map +1 -1
  38. package/bls12-381.js +4 -4
  39. package/bls12-381.js.map +1 -1
  40. package/ed25519.d.ts +52 -66
  41. package/ed25519.d.ts.map +1 -1
  42. package/ed25519.js +128 -155
  43. package/ed25519.js.map +1 -1
  44. package/ed448.d.ts +57 -58
  45. package/ed448.d.ts.map +1 -1
  46. package/ed448.js +114 -131
  47. package/ed448.js.map +1 -1
  48. package/esm/_shortw_utils.d.ts +1 -0
  49. package/esm/_shortw_utils.d.ts.map +1 -1
  50. package/esm/_shortw_utils.js +1 -0
  51. package/esm/_shortw_utils.js.map +1 -1
  52. package/esm/abstract/bls.d.ts +87 -62
  53. package/esm/abstract/bls.d.ts.map +1 -1
  54. package/esm/abstract/bls.js +171 -164
  55. package/esm/abstract/bls.js.map +1 -1
  56. package/esm/abstract/curve.d.ts +109 -23
  57. package/esm/abstract/curve.d.ts.map +1 -1
  58. package/esm/abstract/curve.js +156 -155
  59. package/esm/abstract/curve.js.map +1 -1
  60. package/esm/abstract/edwards.d.ts +124 -70
  61. package/esm/abstract/edwards.d.ts.map +1 -1
  62. package/esm/abstract/edwards.js +210 -62
  63. package/esm/abstract/edwards.js.map +1 -1
  64. package/esm/abstract/hash-to-curve.d.ts +8 -4
  65. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  66. package/esm/abstract/hash-to-curve.js +22 -11
  67. package/esm/abstract/hash-to-curve.js.map +1 -1
  68. package/esm/abstract/modular.d.ts +8 -3
  69. package/esm/abstract/modular.d.ts.map +1 -1
  70. package/esm/abstract/modular.js +79 -35
  71. package/esm/abstract/modular.js.map +1 -1
  72. package/esm/abstract/montgomery.d.ts +17 -4
  73. package/esm/abstract/montgomery.d.ts.map +1 -1
  74. package/esm/abstract/montgomery.js +19 -3
  75. package/esm/abstract/montgomery.js.map +1 -1
  76. package/esm/abstract/tower.d.ts +3 -3
  77. package/esm/abstract/tower.d.ts.map +1 -1
  78. package/esm/abstract/tower.js.map +1 -1
  79. package/esm/abstract/weierstrass.d.ts +142 -116
  80. package/esm/abstract/weierstrass.d.ts.map +1 -1
  81. package/esm/abstract/weierstrass.js +411 -333
  82. package/esm/abstract/weierstrass.js.map +1 -1
  83. package/esm/bls12-381.d.ts.map +1 -1
  84. package/esm/bls12-381.js +4 -4
  85. package/esm/bls12-381.js.map +1 -1
  86. package/esm/ed25519.d.ts +52 -66
  87. package/esm/ed25519.d.ts.map +1 -1
  88. package/esm/ed25519.js +131 -157
  89. package/esm/ed25519.js.map +1 -1
  90. package/esm/ed448.d.ts +57 -58
  91. package/esm/ed448.d.ts.map +1 -1
  92. package/esm/ed448.js +116 -132
  93. package/esm/ed448.js.map +1 -1
  94. package/esm/index.js +7 -9
  95. package/esm/index.js.map +1 -1
  96. package/esm/jubjub.d.ts +3 -3
  97. package/esm/jubjub.d.ts.map +1 -1
  98. package/esm/jubjub.js +3 -3
  99. package/esm/jubjub.js.map +1 -1
  100. package/esm/misc.d.ts +3 -5
  101. package/esm/misc.d.ts.map +1 -1
  102. package/esm/misc.js +0 -3
  103. package/esm/misc.js.map +1 -1
  104. package/esm/nist.d.ts +0 -6
  105. package/esm/nist.d.ts.map +1 -1
  106. package/esm/nist.js +31 -15
  107. package/esm/nist.js.map +1 -1
  108. package/esm/p256.d.ts +4 -0
  109. package/esm/p256.d.ts.map +1 -1
  110. package/esm/p256.js +4 -0
  111. package/esm/p256.js.map +1 -1
  112. package/esm/p384.d.ts +4 -1
  113. package/esm/p384.d.ts.map +1 -1
  114. package/esm/p384.js +4 -1
  115. package/esm/p384.js.map +1 -1
  116. package/esm/p521.d.ts +4 -0
  117. package/esm/p521.d.ts.map +1 -1
  118. package/esm/p521.js +4 -0
  119. package/esm/p521.js.map +1 -1
  120. package/esm/secp256k1.d.ts +32 -15
  121. package/esm/secp256k1.d.ts.map +1 -1
  122. package/esm/secp256k1.js +72 -67
  123. package/esm/secp256k1.js.map +1 -1
  124. package/esm/utils.d.ts +1 -1
  125. package/esm/utils.js +1 -1
  126. package/index.js +7 -9
  127. package/index.js.map +1 -1
  128. package/jubjub.d.ts +3 -3
  129. package/jubjub.d.ts.map +1 -1
  130. package/jubjub.js +3 -3
  131. package/jubjub.js.map +1 -1
  132. package/misc.d.ts +3 -5
  133. package/misc.d.ts.map +1 -1
  134. package/misc.js +0 -3
  135. package/misc.js.map +1 -1
  136. package/nist.d.ts +0 -6
  137. package/nist.d.ts.map +1 -1
  138. package/nist.js +31 -15
  139. package/nist.js.map +1 -1
  140. package/p256.d.ts +4 -0
  141. package/p256.d.ts.map +1 -1
  142. package/p256.js +4 -0
  143. package/p256.js.map +1 -1
  144. package/p384.d.ts +4 -1
  145. package/p384.d.ts.map +1 -1
  146. package/p384.js +4 -1
  147. package/p384.js.map +1 -1
  148. package/p521.d.ts +4 -0
  149. package/p521.d.ts.map +1 -1
  150. package/p521.js +4 -0
  151. package/p521.js.map +1 -1
  152. package/package.json +4 -2
  153. package/secp256k1.d.ts +32 -15
  154. package/secp256k1.d.ts.map +1 -1
  155. package/secp256k1.js +70 -65
  156. package/secp256k1.js.map +1 -1
  157. package/src/_shortw_utils.ts +1 -0
  158. package/src/abstract/bls.ts +319 -257
  159. package/src/abstract/curve.ts +226 -170
  160. package/src/abstract/edwards.ts +350 -139
  161. package/src/abstract/hash-to-curve.ts +33 -16
  162. package/src/abstract/modular.ts +86 -35
  163. package/src/abstract/montgomery.ts +36 -9
  164. package/src/abstract/tower.ts +4 -4
  165. package/src/abstract/weierstrass.ts +567 -474
  166. package/src/bls12-381.ts +28 -20
  167. package/src/ed25519.ts +161 -179
  168. package/src/ed448.ts +150 -156
  169. package/src/index.ts +7 -9
  170. package/src/jubjub.ts +3 -3
  171. package/src/misc.ts +3 -7
  172. package/src/nist.ts +40 -16
  173. package/src/p256.ts +4 -0
  174. package/src/p384.ts +4 -2
  175. package/src/p521.ts +4 -0
  176. package/src/secp256k1.ts +91 -73
  177. package/src/utils.ts +1 -1
  178. package/utils.d.ts +1 -1
  179. package/utils.js +1 -1
@@ -37,11 +37,12 @@ import {
37
37
  import { getMinHashLength, mapHashToField, type IField } from './modular.ts';
38
38
  import type { Fp12, Fp12Bls, Fp2, Fp2Bls, Fp6Bls } from './tower.ts';
39
39
  import {
40
+ _normFnElement,
40
41
  weierstrassPoints,
41
42
  type CurvePointsRes,
42
43
  type CurvePointsType,
43
- type ProjConstructor,
44
- type ProjPointType,
44
+ type WeierstrassPoint,
45
+ type WeierstrassPointCons,
45
46
  } from './weierstrass.ts';
46
47
 
47
48
  type Fp = bigint; // Can be different field?
@@ -52,21 +53,29 @@ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
52
53
  export type TwistType = 'multiplicative' | 'divisive';
53
54
 
54
55
  export type ShortSignatureCoder<Fp> = {
55
- fromBytes(bytes: Uint8Array): ProjPointType<Fp>;
56
- fromHex(hex: Hex): ProjPointType<Fp>;
57
- toBytes(point: ProjPointType<Fp>): Uint8Array;
56
+ fromBytes(bytes: Uint8Array): WeierstrassPoint<Fp>;
57
+ fromHex(hex: Hex): WeierstrassPoint<Fp>;
58
+ toBytes(point: WeierstrassPoint<Fp>): Uint8Array;
58
59
  /** @deprecated use `toBytes` */
59
- toRawBytes(point: ProjPointType<Fp>): Uint8Array;
60
- toHex(point: ProjPointType<Fp>): string;
60
+ toRawBytes(point: WeierstrassPoint<Fp>): Uint8Array;
61
+ toHex(point: WeierstrassPoint<Fp>): string;
61
62
  };
62
63
 
63
64
  export type SignatureCoder<Fp> = {
64
- fromBytes(bytes: Uint8Array): ProjPointType<Fp>;
65
- fromHex(hex: Hex): ProjPointType<Fp>;
66
- toBytes(point: ProjPointType<Fp>): Uint8Array;
65
+ fromBytes(bytes: Uint8Array): WeierstrassPoint<Fp>;
66
+ fromHex(hex: Hex): WeierstrassPoint<Fp>;
67
+ toBytes(point: WeierstrassPoint<Fp>): Uint8Array;
67
68
  /** @deprecated use `toBytes` */
68
- toRawBytes(point: ProjPointType<Fp>): Uint8Array;
69
- toHex(point: ProjPointType<Fp>): string;
69
+ toRawBytes(point: WeierstrassPoint<Fp>): Uint8Array;
70
+ toHex(point: WeierstrassPoint<Fp>): string;
71
+ };
72
+
73
+ export type BlsFields = {
74
+ Fp: IField<Fp>;
75
+ Fr: IField<bigint>;
76
+ Fp2: Fp2Bls;
77
+ Fp6: Fp6Bls;
78
+ Fp12: Fp12Bls;
70
79
  };
71
80
 
72
81
  export type PostPrecomputePointAddFn = (
@@ -84,6 +93,27 @@ export type PostPrecomputeFn = (
84
93
  Qy: Fp2,
85
94
  pointAdd: PostPrecomputePointAddFn
86
95
  ) => void;
96
+ export type BlsPairing = {
97
+ Fp12: Fp12Bls;
98
+ calcPairingPrecomputes: (p: WeierstrassPoint<Fp2>) => Precompute;
99
+ millerLoopBatch: (pairs: [Precompute, Fp, Fp][]) => Fp12;
100
+ pairing: (P: WeierstrassPoint<Fp>, Q: WeierstrassPoint<Fp2>, withFinalExponent?: boolean) => Fp12;
101
+ pairingBatch: (
102
+ pairs: { g1: WeierstrassPoint<Fp>; g2: WeierstrassPoint<Fp2> }[],
103
+ withFinalExponent?: boolean
104
+ ) => Fp12;
105
+ };
106
+ // TODO: replace CurveType with this? It doesn't contain r however and has postPrecompute
107
+ export type BlsPairingParams = {
108
+ // NOTE: MSB is always ignored and used as marker for length,
109
+ // otherwise leading zeros will be lost.
110
+ // Can be different from 'X' (seed) param!
111
+ ateLoopSize: bigint;
112
+ xNegative: boolean;
113
+ twistType: TwistType; // BLS12-381: Multiplicative, BN254: Divisive
114
+ // This is super ugly hack for untwist point in BN254 after miller loop
115
+ postPrecompute?: PostPrecomputeFn;
116
+ };
87
117
  export type CurveType = {
88
118
  G1: CurvePointsType<Fp> & {
89
119
  ShortSignature: SignatureCoder<Fp>;
@@ -95,21 +125,15 @@ export type CurveType = {
95
125
  mapToCurve: MapToCurve<Fp2>;
96
126
  htfDefaults: H2COpts;
97
127
  };
98
- fields: {
99
- Fp: IField<Fp>;
100
- Fr: IField<bigint>;
101
- Fp2: Fp2Bls;
102
- Fp6: Fp6Bls;
103
- Fp12: Fp12Bls;
104
- };
128
+ fields: BlsFields;
105
129
  params: {
106
130
  // NOTE: MSB is always ignored and used as marker for length,
107
131
  // otherwise leading zeros will be lost.
108
132
  // Can be different from 'X' (seed) param!
109
- ateLoopSize: bigint;
110
- xNegative: boolean;
133
+ ateLoopSize: BlsPairingParams['ateLoopSize'];
134
+ xNegative: BlsPairingParams['xNegative'];
111
135
  r: bigint; // TODO: remove
112
- twistType: TwistType; // BLS12-381: Multiplicative, BN254: Divisive
136
+ twistType: BlsPairingParams['twistType']; // BLS12-381: Multiplicative, BN254: Divisive
113
137
  };
114
138
  htfDefaults: H2COpts;
115
139
  hash: CHash; // Because we need outputLen for DRBG
@@ -121,67 +145,92 @@ export type CurveType = {
121
145
  type PrecomputeSingle = [Fp2, Fp2, Fp2][];
122
146
  type Precompute = PrecomputeSingle[];
123
147
 
124
- export type CurveFn = {
148
+ /**
149
+ * BLS consists of two curves: G1 and G2:
150
+ * - G1 is a subgroup of (x, y) E(Fq) over y² = x³ + 4.
151
+ * - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1
152
+ */
153
+ export interface BLSCurvePair {
125
154
  longSignatures: BLSSigs<bigint, Fp2>;
126
155
  shortSignatures: BLSSigs<Fp2, bigint>;
156
+ millerLoopBatch: BlsPairing['millerLoopBatch'];
157
+ pairing: BlsPairing['pairing'];
158
+ pairingBatch: BlsPairing['pairingBatch'];
159
+ G1: { Point: WeierstrassPointCons<bigint> } & H2CHasher<Fp>;
160
+ G2: { Point: WeierstrassPointCons<Fp2> } & H2CHasher<Fp2>;
161
+ fields: {
162
+ Fp: IField<Fp>;
163
+ Fp2: Fp2Bls;
164
+ Fp6: Fp6Bls;
165
+ Fp12: Fp12Bls;
166
+ Fr: IField<bigint>;
167
+ };
168
+ utils: {
169
+ randomSecretKey: () => Uint8Array;
170
+ /** @deprecated use randomSecretKey */
171
+ randomPrivateKey: () => Uint8Array;
172
+ calcPairingPrecomputes: BlsPairing['calcPairingPrecomputes'];
173
+ };
174
+ }
127
175
 
128
- millerLoopBatch: (pairs: [Precompute, Fp, Fp][]) => Fp12;
129
- pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
130
- pairingBatch: (
131
- pairs: { g1: ProjPointType<Fp>; g2: ProjPointType<Fp2> }[],
132
- withFinalExponent?: boolean
133
- ) => Fp12;
134
-
176
+ export type CurveFn = BLSCurvePair & {
135
177
  /** @deprecated use `longSignatures.getPublicKey` */
136
- getPublicKey: (privateKey: PrivKey) => Uint8Array;
178
+ getPublicKey: (secretKey: PrivKey) => Uint8Array;
137
179
  /** @deprecated use `shortSignatures.getPublicKey` */
138
- getPublicKeyForShortSignatures: (privateKey: PrivKey) => Uint8Array;
180
+ getPublicKeyForShortSignatures: (secretKey: PrivKey) => Uint8Array;
139
181
  /** @deprecated use `longSignatures.sign` */
140
182
  sign: {
141
- (message: Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
142
- (message: ProjPointType<Fp2>, privateKey: PrivKey, htfOpts?: htfBasicOpts): ProjPointType<Fp2>;
183
+ (message: Hex, secretKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
184
+ (
185
+ message: WeierstrassPoint<Fp2>,
186
+ secretKey: PrivKey,
187
+ htfOpts?: htfBasicOpts
188
+ ): WeierstrassPoint<Fp2>;
143
189
  };
144
190
  /** @deprecated use `shortSignatures.sign` */
145
191
  signShortSignature: {
146
- (message: Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
147
- (message: ProjPointType<Fp>, privateKey: PrivKey, htfOpts?: htfBasicOpts): ProjPointType<Fp>;
192
+ (message: Hex, secretKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
193
+ (
194
+ message: WeierstrassPoint<Fp>,
195
+ secretKey: PrivKey,
196
+ htfOpts?: htfBasicOpts
197
+ ): WeierstrassPoint<Fp>;
148
198
  };
149
199
  /** @deprecated use `longSignatures.verify` */
150
200
  verify: (
151
- signature: Hex | ProjPointType<Fp2>,
152
- message: Hex | ProjPointType<Fp2>,
153
- publicKey: Hex | ProjPointType<Fp>,
201
+ signature: Hex | WeierstrassPoint<Fp2>,
202
+ message: Hex | WeierstrassPoint<Fp2>,
203
+ publicKey: Hex | WeierstrassPoint<Fp>,
154
204
  htfOpts?: htfBasicOpts
155
205
  ) => boolean;
156
206
  /** @deprecated use `shortSignatures.verify` */
157
207
  verifyShortSignature: (
158
- signature: Hex | ProjPointType<Fp>,
159
- message: Hex | ProjPointType<Fp>,
160
- publicKey: Hex | ProjPointType<Fp2>,
208
+ signature: Hex | WeierstrassPoint<Fp>,
209
+ message: Hex | WeierstrassPoint<Fp>,
210
+ publicKey: Hex | WeierstrassPoint<Fp2>,
161
211
  htfOpts?: htfBasicOpts
162
212
  ) => boolean;
163
213
  verifyBatch: (
164
- signature: Hex | ProjPointType<Fp2>,
165
- messages: (Hex | ProjPointType<Fp2>)[],
166
- publicKeys: (Hex | ProjPointType<Fp>)[],
214
+ signature: Hex | WeierstrassPoint<Fp2>,
215
+ messages: (Hex | WeierstrassPoint<Fp2>)[],
216
+ publicKeys: (Hex | WeierstrassPoint<Fp>)[],
167
217
  htfOpts?: htfBasicOpts
168
218
  ) => boolean;
169
219
  /** @deprecated use `longSignatures.aggregatePublicKeys` */
170
220
  aggregatePublicKeys: {
171
221
  (publicKeys: Hex[]): Uint8Array;
172
- (publicKeys: ProjPointType<Fp>[]): ProjPointType<Fp>;
222
+ (publicKeys: WeierstrassPoint<Fp>[]): WeierstrassPoint<Fp>;
173
223
  };
174
224
  /** @deprecated use `longSignatures.aggregateSignatures` */
175
225
  aggregateSignatures: {
176
226
  (signatures: Hex[]): Uint8Array;
177
- (signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
227
+ (signatures: WeierstrassPoint<Fp2>[]): WeierstrassPoint<Fp2>;
178
228
  };
179
229
  /** @deprecated use `shortSignatures.aggregateSignatures` */
180
230
  aggregateShortSignatures: {
181
231
  (signatures: Hex[]): Uint8Array;
182
- (signatures: ProjPointType<Fp>[]): ProjPointType<Fp>;
232
+ (signatures: WeierstrassPoint<Fp>[]): WeierstrassPoint<Fp>;
183
233
  };
184
- /** @deprecated use `curves.G1` and `curves.G2` */
185
234
  G1: CurvePointsRes<Fp> & H2CHasher<Fp>;
186
235
  G2: CurvePointsRes<Fp2> & H2CHasher<Fp2>;
187
236
  /** @deprecated use `longSignatures.Signature` */
@@ -197,35 +246,25 @@ export type CurveFn = {
197
246
  /** @deprecated */
198
247
  G2b: Fp2;
199
248
  };
200
- curves: {
201
- G1: ProjConstructor<bigint>;
202
- G2: ProjConstructor<Fp2>;
203
- };
204
- fields: {
205
- Fp: IField<Fp>;
206
- Fp2: Fp2Bls;
207
- Fp6: Fp6Bls;
208
- Fp12: Fp12Bls;
209
- Fr: IField<bigint>;
210
- };
211
- utils: {
212
- randomPrivateKey: () => Uint8Array;
213
- calcPairingPrecomputes: (p: ProjPointType<Fp2>) => Precompute;
214
- };
215
249
  };
216
250
 
217
251
  type BLSInput = Hex | Uint8Array;
218
252
  export interface BLSSigs<P, S> {
219
- getPublicKey(privateKey: PrivKey): ProjPointType<P>;
220
- sign(hashedMessage: ProjPointType<S>, privateKey: PrivKey): ProjPointType<S>;
253
+ getPublicKey(secretKey: PrivKey): WeierstrassPoint<P>;
254
+ sign(hashedMessage: WeierstrassPoint<S>, secretKey: PrivKey): WeierstrassPoint<S>;
221
255
  verify(
222
- signature: ProjPointType<S> | BLSInput,
223
- message: ProjPointType<S>,
224
- publicKey: ProjPointType<P> | BLSInput
256
+ signature: WeierstrassPoint<S> | BLSInput,
257
+ message: WeierstrassPoint<S>,
258
+ publicKey: WeierstrassPoint<P> | BLSInput
225
259
  ): boolean;
226
- aggregatePublicKeys(publicKeys: (ProjPointType<P> | BLSInput)[]): ProjPointType<P>;
227
- aggregateSignatures(signatures: (ProjPointType<S> | BLSInput)[]): ProjPointType<S>;
228
- hash(message: Uint8Array, DST?: string | Uint8Array, hashOpts?: H2CHashOpts): ProjPointType<S>;
260
+ verifyBatch: (
261
+ signature: WeierstrassPoint<S> | BLSInput,
262
+ messages: WeierstrassPoint<S>[],
263
+ publicKeys: (WeierstrassPoint<P> | BLSInput)[]
264
+ ) => boolean;
265
+ aggregatePublicKeys(publicKeys: (WeierstrassPoint<P> | BLSInput)[]): WeierstrassPoint<P>;
266
+ aggregateSignatures(signatures: (WeierstrassPoint<S> | BLSInput)[]): WeierstrassPoint<S>;
267
+ hash(message: Uint8Array, DST?: string | Uint8Array, hashOpts?: H2CHashOpts): WeierstrassPoint<S>;
229
268
  Signature: SignatureCoder<S>;
230
269
  }
231
270
 
@@ -243,39 +282,27 @@ function NAfDecomposition(a: bigint) {
243
282
  return res;
244
283
  }
245
284
 
246
- // G1_Point: ProjConstructor<bigint>, G2_Point: ProjConstructor<Fp2>,
247
- export function bls(CURVE: CurveType): CurveFn {
248
- // Fields are specific for curve, so for now we'll need to pass them with opts
249
- const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE.fields;
250
- const BLS_X_IS_NEGATIVE = CURVE.params.xNegative;
251
- const TWIST: TwistType = CURVE.params.twistType;
252
- // Point on G1 curve: (x, y)
253
- const G1_ = weierstrassPoints(CURVE.G1);
254
- const G1 = Object.assign(
255
- G1_,
256
- createHasher(G1_.Point, CURVE.G1.mapToCurve, {
257
- ...CURVE.htfDefaults,
258
- ...CURVE.G1.htfDefaults,
259
- })
260
- );
261
- // Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
262
- const G2_ = weierstrassPoints(CURVE.G2);
263
- const G2 = Object.assign(
264
- G2_,
265
- createHasher(G2_.Point as H2CPointConstructor<Fp2>, CURVE.G2.mapToCurve, {
266
- ...CURVE.htfDefaults,
267
- ...CURVE.G2.htfDefaults,
268
- })
269
- );
270
- type G1 = typeof G1.Point.BASE;
271
- type G2 = typeof G2.Point.BASE;
285
+ function aNonEmpty(arr: any[]) {
286
+ if (!Array.isArray(arr) || arr.length === 0) throw new Error('expected non-empty array');
287
+ }
272
288
 
289
+ // This should be enough for bn254, no need to export full stuff?
290
+ function createBlsPairing(
291
+ fields: BlsFields,
292
+ G1: WeierstrassPointCons<Fp>,
293
+ G2: WeierstrassPointCons<Fp2>,
294
+ params: BlsPairingParams
295
+ ): BlsPairing {
296
+ const { Fp2, Fp12 } = fields;
297
+ const { twistType, ateLoopSize, xNegative, postPrecompute } = params;
298
+ type G1 = typeof G1.BASE;
299
+ type G2 = typeof G2.BASE;
273
300
  // Applies sparse multiplication as line function
274
301
  let lineFunction: (c0: Fp2, c1: Fp2, c2: Fp2, f: Fp12, Px: Fp, Py: Fp) => Fp12;
275
- if (TWIST === 'multiplicative') {
302
+ if (twistType === 'multiplicative') {
276
303
  lineFunction = (c0: Fp2, c1: Fp2, c2: Fp2, f: Fp12, Px: Fp, Py: Fp) =>
277
304
  Fp12.mul014(f, c0, Fp2.mul(c1, Px), Fp2.mul(c2, Py));
278
- } else if (TWIST === 'divisive') {
305
+ } else if (twistType === 'divisive') {
279
306
  // NOTE: it should be [c0, c1, c2], but we use different order here to reduce complexity of
280
307
  // precompute calculations.
281
308
  lineFunction = (c0: Fp2, c1: Fp2, c2: Fp2, f: Fp12, Px: Fp, Py: Fp) =>
@@ -324,7 +351,7 @@ export function bls(CURVE: CurveType): CurveFn {
324
351
  // Point addition and point double calculations is reused for coefficients
325
352
  // pointAdd happens only if bit set, so wNAF is reasonable. Unfortunately we cannot combine
326
353
  // add + double in windowed precomputes here, otherwise it would be single op (since X is static)
327
- const ATE_NAF = NAfDecomposition(CURVE.params.ateLoopSize);
354
+ const ATE_NAF = NAfDecomposition(ateLoopSize);
328
355
 
329
356
  const calcPairingPrecomputes = memoized((point: G2) => {
330
357
  const p = point;
@@ -340,9 +367,9 @@ export function bls(CURVE: CurveType): CurveFn {
340
367
  if (bit) ({ Rx, Ry, Rz } = pointAdd(cur, Rx, Ry, Rz, Qx, bit === -1 ? negQy : Qy));
341
368
  ell.push(cur);
342
369
  }
343
- if (CURVE.postPrecompute) {
370
+ if (postPrecompute) {
344
371
  const last = ell[ell.length - 1];
345
- CURVE.postPrecompute(Rx, Ry, Rz, Qx, Qy, pointAdd.bind(null, last));
372
+ postPrecompute(Rx, Ry, Rz, Qx, Qy, pointAdd.bind(null, last));
346
373
  }
347
374
  return ell;
348
375
  });
@@ -362,7 +389,7 @@ export function bls(CURVE: CurveType): CurveFn {
362
389
  }
363
390
  }
364
391
  }
365
- if (BLS_X_IS_NEGATIVE) f12 = Fp12.conjugate(f12);
392
+ if (xNegative) f12 = Fp12.conjugate(f12);
366
393
  return withFinalExponent ? Fp12.finalExponentiate(f12) : f12;
367
394
  }
368
395
  type PairingInput = { g1: G1; g2: G2 };
@@ -372,13 +399,11 @@ export function bls(CURVE: CurveType): CurveFn {
372
399
  const res: MillerInput = [];
373
400
  // Cache precomputed toAffine for all points
374
401
  normalizeZ(
375
- G1.Point,
376
- 'pz',
402
+ G1,
377
403
  pairs.map(({ g1 }) => g1)
378
404
  );
379
405
  normalizeZ(
380
- G2.Point,
381
- 'pz',
406
+ G2,
382
407
  pairs.map(({ g2 }) => g2)
383
408
  );
384
409
  for (const { g1, g2 } of pairs) {
@@ -395,128 +420,201 @@ export function bls(CURVE: CurveType): CurveFn {
395
420
  function pairing(Q: G1, P: G2, withFinalExponent: boolean = true): Fp12 {
396
421
  return pairingBatch([{ g1: Q, g2: P }], withFinalExponent);
397
422
  }
398
-
399
- const rand = CURVE.randomBytes || randomBytes;
400
-
401
- const utils = {
402
- randomPrivateKey: (): Uint8Array => {
403
- const length = getMinHashLength(Fr.ORDER);
404
- return mapHashToField(rand(length), Fr.ORDER);
405
- },
423
+ return {
424
+ Fp12, // NOTE: we re-export Fp12 here because pairing results are Fp12!
425
+ millerLoopBatch,
426
+ pairing,
427
+ pairingBatch,
406
428
  calcPairingPrecomputes,
407
429
  };
430
+ }
408
431
 
409
- function aNonEmpty(arr: any[]) {
410
- if (!Array.isArray(arr) || arr.length === 0) throw new Error('expected non-empty array');
432
+ function createBlsSig<P, S>(
433
+ blsPairing: BlsPairing,
434
+ PubCurve: CurvePointsRes<P> & H2CHasher<P>,
435
+ SigCurve: CurvePointsRes<S> & H2CHasher<S>,
436
+ SignatureCoder: SignatureCoder<S>,
437
+ isSigG1: boolean
438
+ ): BLSSigs<P, S> {
439
+ const { Fp12, pairingBatch } = blsPairing;
440
+ type PubPoint = WeierstrassPoint<P>;
441
+ type SigPoint = WeierstrassPoint<S>;
442
+ function normPub(point: PubPoint | BLSInput): PubPoint {
443
+ return point instanceof PubCurve.Point ? (point as PubPoint) : PubCurve.Point.fromHex(point);
411
444
  }
412
-
413
- type G1Hex = Hex | G1;
414
- type G2Hex = Hex | G2;
415
- function normP1(point: G1Hex): G1 {
416
- return point instanceof G1.Point ? (point as G1) : G1.Point.fromHex(point);
445
+ function normSig(point: SigPoint | BLSInput): SigPoint {
446
+ return point instanceof SigCurve.Point ? (point as SigPoint) : SigCurve.Point.fromHex(point);
417
447
  }
418
- function normP2(point: G2Hex): G2 {
419
- return point instanceof G2.Point ? point : Signature.fromHex(point);
448
+ function amsg(m: unknown): SigPoint {
449
+ if (!(m instanceof SigCurve.Point))
450
+ throw new Error(`expected valid message hashed to ${!isSigG1 ? 'G2' : 'G1'} curve`);
451
+ return m as SigPoint;
420
452
  }
421
453
 
422
- // TODO: add verifyBatch, fix types, Export Signature property,
423
- // actually expose the generated APIs
424
- function createBls<P, S>(PubCurve: any, SigCurve: any): BLSSigs<P, S> {
425
- type PubPoint = ProjPointType<P>;
426
- type SigPoint = ProjPointType<S>;
427
- function normPub(point: PubPoint | BLSInput): PubPoint {
428
- return point instanceof PubCurve.Point ? (point as PubPoint) : PubCurve.Point.fromHex(point);
429
- }
430
- function normSig(point: SigPoint | BLSInput): SigPoint {
431
- return point instanceof SigCurve.Point ? (point as SigPoint) : SigCurve.Point.fromHex(point);
432
- }
433
- function amsg(m: unknown): SigPoint {
434
- if (!(m instanceof SigCurve.Point))
435
- throw new Error(`expected valid message hashed to ${isLongSigs ? 'G2' : 'G1'} curve`);
436
- return m as any;
437
- }
454
+ type G1 = CurvePointsRes<Fp>['Point']['BASE'];
455
+ type G2 = CurvePointsRes<Fp2>['Point']['BASE'];
456
+ type PairingInput = { g1: G1; g2: G2 };
457
+ // What matters here is what point pairing API accepts as G1 or G2, not actual size or names
458
+ const pair: (a: PubPoint, b: SigPoint) => PairingInput = !isSigG1
459
+ ? (a: PubPoint, b: SigPoint) => ({ g1: a, g2: b }) as PairingInput
460
+ : (a: PubPoint, b: SigPoint) => ({ g1: b, g2: a }) as PairingInput;
461
+ return {
462
+ // P = pk x G
463
+ getPublicKey(secretKey: PrivKey): PubPoint {
464
+ // TODO: replace with
465
+ // const sec = PubCurve.Point.Fn.fromBytes(secretKey);
466
+ const sec = _normFnElement(PubCurve.Point.Fn, secretKey);
467
+ return PubCurve.Point.BASE.multiply(sec);
468
+ },
469
+ // S = pk x H(m)
470
+ sign(message: SigPoint, secretKey: PrivKey, unusedArg?: any): SigPoint {
471
+ if (unusedArg != null) throw new Error('sign() expects 2 arguments');
472
+ // TODO: replace with
473
+ // PubCurve.Point.Fn.fromBytes(secretKey)
474
+ const sec = _normFnElement(PubCurve.Point.Fn, secretKey);
475
+ amsg(message).assertValidity();
476
+ return message.multiply(sec);
477
+ },
478
+ // Checks if pairing of public key & hash is equal to pairing of generator & signature.
479
+ // e(P, H(m)) == e(G, S)
480
+ // e(S, G) == e(H(m), P)
481
+ verify(
482
+ signature: SigPoint | BLSInput,
483
+ message: SigPoint,
484
+ publicKey: PubPoint | BLSInput,
485
+ unusedArg?: any
486
+ ): boolean {
487
+ if (unusedArg != null) throw new Error('verify() expects 3 arguments');
488
+ signature = normSig(signature);
489
+ publicKey = normPub(publicKey);
490
+ const P = publicKey.negate();
491
+ const G = PubCurve.Point.BASE;
492
+ const Hm = amsg(message);
493
+ const S = signature;
494
+ // This code was changed in 1.9.x:
495
+ // Before it was G.negate() in G2, now it's always pubKey.negate
496
+ // e(P, -Q)===e(-P, Q)==e(P, Q)^-1. Negate can be done anywhere (as long it is done once per pair).
497
+ // We just moving sign, but since pairing is multiplicative, we doing X * X^-1 = 1
498
+ const exp = pairingBatch([pair(P, Hm), pair(G, S)]);
499
+ return Fp12.eql(exp, Fp12.ONE);
500
+ },
501
+ // https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
502
+ // e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
503
+ // TODO: maybe `{message: G2Hex, publicKey: G1Hex}[]` instead?
504
+ verifyBatch(
505
+ signature: SigPoint | BLSInput,
506
+ messages: SigPoint[],
507
+ publicKeys: (PubPoint | BLSInput)[]
508
+ ): boolean {
509
+ aNonEmpty(messages);
510
+ if (publicKeys.length !== messages.length)
511
+ throw new Error('amount of public keys and messages should be equal');
512
+ const sig = normSig(signature);
513
+ const nMessages = messages;
514
+ const nPublicKeys = publicKeys.map(normPub);
515
+ // NOTE: this works only for exact same object
516
+ const messagePubKeyMap = new Map<SigPoint, PubPoint[]>();
517
+ for (let i = 0; i < nPublicKeys.length; i++) {
518
+ const pub = nPublicKeys[i];
519
+ const msg = nMessages[i];
520
+ let keys = messagePubKeyMap.get(msg);
521
+ if (keys === undefined) {
522
+ keys = [];
523
+ messagePubKeyMap.set(msg, keys);
524
+ }
525
+ keys.push(pub);
526
+ }
527
+ const paired = [];
528
+ const G = PubCurve.Point.BASE;
529
+ try {
530
+ for (const [msg, keys] of messagePubKeyMap) {
531
+ const groupPublicKey = keys.reduce((acc, msg) => acc.add(msg));
532
+ paired.push(pair(groupPublicKey, msg));
533
+ }
534
+ paired.push(pair(G.negate(), sig));
535
+ return Fp12.eql(pairingBatch(paired), Fp12.ONE);
536
+ } catch {
537
+ return false;
538
+ }
539
+ },
540
+ // Adds a bunch of public key points together.
541
+ // pk1 + pk2 + pk3 = pkA
542
+ aggregatePublicKeys(publicKeys: (PubPoint | BLSInput)[]): PubPoint {
543
+ aNonEmpty(publicKeys);
544
+ publicKeys = publicKeys.map((pub) => normPub(pub));
545
+ const agg = (publicKeys as PubPoint[]).reduce((sum, p) => sum.add(p), PubCurve.Point.ZERO);
546
+ agg.assertValidity();
547
+ return agg;
548
+ },
438
549
 
439
- // TODO: is this always ok?
440
- const isLongSigs = SigCurve.Point.Fp.BYTES > PubCurve.Point.Fp.BYTES;
441
- return {
442
- // P = pk x G
443
- getPublicKey(privateKey: PrivKey): PubPoint {
444
- return PubCurve.Point.fromPrivateKey(privateKey);
445
- },
446
- // S = pk x H(m)
447
- sign(message: SigPoint, privateKey: PrivKey, unusedArg?: any): SigPoint {
448
- if (unusedArg != null) throw new Error('sign() expects 2 arguments');
449
- amsg(message).assertValidity();
450
- return message.multiply(PubCurve.normPrivateKeyToScalar(privateKey));
451
- },
452
- // Checks if pairing of public key & hash is equal to pairing of generator & signature.
453
- // e(P, H(m)) == e(G, S)
454
- // e(S, G) == e(H(m), P)
455
- verify(
456
- signature: SigPoint | BLSInput,
457
- message: SigPoint,
458
- publicKey: PubPoint | BLSInput,
459
- unusedArg?: any
460
- ): boolean {
461
- if (unusedArg != null) throw new Error('verify() expects 3 arguments');
462
- signature = normSig(signature);
463
- publicKey = normPub(publicKey);
464
- const P = publicKey.negate();
465
- const G = PubCurve.Point.BASE;
466
- const Hm = amsg(message);
467
- const S = signature;
468
- // This code was changed in 1.9.x:
469
- // Before it was G.negate() in G2, now it's always pubKey.negate
470
- // TODO: understand if this is OK?
471
- // prettier-ignore
472
- const exp_ = isLongSigs ? [
473
- { g1: P, g2: Hm },
474
- { g1: G, g2: S }
475
- ] : [
476
- { g1: Hm, g2: P },
477
- { g1: S, g2: G }
478
- ];
479
- // TODO
480
- // @ts-ignore
481
- const exp = pairingBatch(exp_);
482
- return Fp12.eql(exp, Fp12.ONE);
483
- },
484
-
485
- // Adds a bunch of public key points together.
486
- // pk1 + pk2 + pk3 = pkA
487
- aggregatePublicKeys(publicKeys: (PubPoint | BLSInput)[]): PubPoint {
488
- aNonEmpty(publicKeys);
489
- publicKeys = publicKeys.map((pub) => normPub(pub));
490
- const agg = publicKeys.reduce((sum, p) => sum.add(p), PubCurve.Point.ZERO);
491
- agg.assertValidity();
492
- return agg;
493
- },
494
-
495
- // Adds a bunch of signature points together.
496
- // pk1 + pk2 + pk3 = pkA
497
- aggregateSignatures(signatures: (SigPoint | BLSInput)[]): SigPoint {
498
- aNonEmpty(signatures);
499
- signatures = signatures.map((sig) => normSig(sig));
500
- const agg = signatures.reduce((sum, s) => sum.add(s), SigCurve.Point.ZERO);
501
- agg.assertValidity();
502
- return agg;
503
- },
504
-
505
- hash(messageBytes: Uint8Array, DST?: string | Uint8Array): SigPoint {
506
- abytes(messageBytes);
507
- const opts = DST ? { DST } : undefined;
508
- return SigCurve.hashToCurve(messageBytes, opts);
509
- },
510
-
511
- // @ts-ignore
512
- Signature: isLongSigs ? CURVE.G2.Signature : CURVE.G1.ShortSignature,
513
- };
514
- }
550
+ // Adds a bunch of signature points together.
551
+ // pk1 + pk2 + pk3 = pkA
552
+ aggregateSignatures(signatures: (SigPoint | BLSInput)[]): SigPoint {
553
+ aNonEmpty(signatures);
554
+ signatures = signatures.map((sig) => normSig(sig));
555
+ const agg = (signatures as SigPoint[]).reduce((sum, s) => sum.add(s), SigCurve.Point.ZERO);
556
+ agg.assertValidity();
557
+ return agg;
558
+ },
515
559
 
516
- const longSignatures = createBls<bigint, Fp2>(G1, G2);
517
- const shortSignatures = createBls<Fp2, bigint>(G2, G1);
560
+ hash(messageBytes: Uint8Array, DST?: string | Uint8Array): SigPoint {
561
+ abytes(messageBytes);
562
+ const opts = DST ? { DST } : undefined;
563
+ return SigCurve.hashToCurve(messageBytes, opts) as SigPoint;
564
+ },
565
+ Signature: SignatureCoder,
566
+ };
567
+ }
568
+
569
+ // G1_Point: ProjConstructor<bigint>, G2_Point: ProjConstructor<Fp2>,
570
+ export function bls(CURVE: CurveType): CurveFn {
571
+ // Fields are specific for curve, so for now we'll need to pass them with opts
572
+ const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE.fields;
573
+ // Point on G1 curve: (x, y)
574
+ const G1_ = weierstrassPoints(CURVE.G1);
575
+ const G1 = Object.assign(
576
+ G1_,
577
+ createHasher(G1_.Point, CURVE.G1.mapToCurve, {
578
+ ...CURVE.htfDefaults,
579
+ ...CURVE.G1.htfDefaults,
580
+ })
581
+ );
582
+ // Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
583
+ const G2_ = weierstrassPoints(CURVE.G2);
584
+ const G2 = Object.assign(
585
+ G2_,
586
+ createHasher(G2_.Point as H2CPointConstructor<Fp2>, CURVE.G2.mapToCurve, {
587
+ ...CURVE.htfDefaults,
588
+ ...CURVE.G2.htfDefaults,
589
+ })
590
+ );
591
+ type G1 = typeof G1.Point.BASE;
592
+ type G2 = typeof G2.Point.BASE;
593
+
594
+ const pairingRes = createBlsPairing(CURVE.fields, G1.Point, G2.Point, {
595
+ ...CURVE.params,
596
+ postPrecompute: CURVE.postPrecompute,
597
+ });
598
+
599
+ const { millerLoopBatch, pairing, pairingBatch, calcPairingPrecomputes } = pairingRes;
600
+ const longSignatures = createBlsSig(pairingRes, G1, G2, CURVE.G2.Signature, false);
601
+ const shortSignatures = createBlsSig(pairingRes, G2, G1, CURVE.G1.ShortSignature, true);
602
+
603
+ const rand = CURVE.randomBytes || randomBytes;
604
+ const randomSecretKey = (): Uint8Array => {
605
+ const length = getMinHashLength(Fr.ORDER);
606
+ return mapHashToField(rand(length), Fr.ORDER);
607
+ };
608
+ const utils = {
609
+ randomSecretKey,
610
+ randomPrivateKey: randomSecretKey,
611
+ calcPairingPrecomputes,
612
+ };
518
613
 
519
614
  // LEGACY code
615
+ type G1Hex = Hex | G1;
616
+ type G2Hex = Hex | G2;
617
+
520
618
  const { ShortSignature } = CURVE.G1;
521
619
  const { Signature } = CURVE.G2;
522
620
 
@@ -595,45 +693,14 @@ export function bls(CURVE: CurveType): CurveFn {
595
693
  const agg = shortSignatures.aggregateSignatures(signatures);
596
694
  return signatures[0] instanceof G1.Point ? agg : ShortSignature.toBytes(agg);
597
695
  }
598
-
599
- // https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
600
- // e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
601
- // TODO: maybe `{message: G2Hex, publicKey: G1Hex}[]` instead?
602
696
  function verifyBatch(
603
697
  signature: G2Hex,
604
698
  messages: G2Hex[],
605
699
  publicKeys: G1Hex[],
606
700
  htfOpts?: htfBasicOpts
607
701
  ): boolean {
608
- aNonEmpty(messages);
609
- if (publicKeys.length !== messages.length)
610
- throw new Error('amount of public keys and messages should be equal');
611
- const sig = normP2(signature);
612
- const nMessages = messages.map((i) => normP2Hash(i, htfOpts));
613
- const nPublicKeys = publicKeys.map(normP1);
614
- // NOTE: this works only for exact same object
615
- const messagePubKeyMap = new Map<G2, G1[]>();
616
- for (let i = 0; i < nPublicKeys.length; i++) {
617
- const pub = nPublicKeys[i];
618
- const msg = nMessages[i];
619
- let keys = messagePubKeyMap.get(msg);
620
- if (keys === undefined) {
621
- keys = [];
622
- messagePubKeyMap.set(msg, keys);
623
- }
624
- keys.push(pub);
625
- }
626
- const paired = [];
627
- try {
628
- for (const [msg, keys] of messagePubKeyMap) {
629
- const groupPublicKey = keys.reduce((acc, msg) => acc.add(msg));
630
- paired.push({ g1: groupPublicKey, g2: msg });
631
- }
632
- paired.push({ g1: G1.Point.BASE.negate(), g2: sig });
633
- return Fp12.eql(pairingBatch(paired), Fp12.ONE);
634
- } catch {
635
- return false;
636
- }
702
+ const Hm = messages.map((m) => normP2Hash(m, htfOpts));
703
+ return longSignatures.verifyBatch(signature, Hm, publicKeys);
637
704
  }
638
705
 
639
706
  G1.Point.BASE.precompute(4);
@@ -644,12 +711,7 @@ export function bls(CURVE: CurveType): CurveFn {
644
711
  millerLoopBatch,
645
712
  pairing,
646
713
  pairingBatch,
647
- // TODO!!!
648
714
  verifyBatch,
649
- curves: {
650
- G1: G1_.Point,
651
- G2: G2_.Point,
652
- },
653
715
  fields: {
654
716
  Fr,
655
717
  Fp,