@noble/curves 1.9.1 → 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 (223) hide show
  1. package/README.md +238 -227
  2. package/_shortw_utils.d.ts +8 -5
  3. package/_shortw_utils.d.ts.map +1 -1
  4. package/_shortw_utils.js +3 -8
  5. package/_shortw_utils.js.map +1 -1
  6. package/abstract/bls.d.ts +123 -62
  7. package/abstract/bls.d.ts.map +1 -1
  8. package/abstract/bls.js +219 -163
  9. package/abstract/bls.js.map +1 -1
  10. package/abstract/curve.d.ts +142 -21
  11. package/abstract/curve.d.ts.map +1 -1
  12. package/abstract/curve.js +224 -143
  13. package/abstract/curve.js.map +1 -1
  14. package/abstract/edwards.d.ts +190 -49
  15. package/abstract/edwards.d.ts.map +1 -1
  16. package/abstract/edwards.js +322 -136
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/fft.d.ts +12 -10
  19. package/abstract/fft.d.ts.map +1 -1
  20. package/abstract/fft.js +12 -13
  21. package/abstract/fft.js.map +1 -1
  22. package/abstract/hash-to-curve.d.ts +31 -13
  23. package/abstract/hash-to-curve.d.ts.map +1 -1
  24. package/abstract/hash-to-curve.js +34 -19
  25. package/abstract/hash-to-curve.js.map +1 -1
  26. package/abstract/modular.d.ts +31 -13
  27. package/abstract/modular.d.ts.map +1 -1
  28. package/abstract/modular.js +125 -52
  29. package/abstract/modular.js.map +1 -1
  30. package/abstract/montgomery.d.ts +18 -5
  31. package/abstract/montgomery.d.ts.map +1 -1
  32. package/abstract/montgomery.js +23 -6
  33. package/abstract/montgomery.js.map +1 -1
  34. package/abstract/poseidon.d.ts +5 -13
  35. package/abstract/poseidon.d.ts.map +1 -1
  36. package/abstract/poseidon.js +12 -7
  37. package/abstract/poseidon.js.map +1 -1
  38. package/abstract/tower.d.ts +23 -49
  39. package/abstract/tower.d.ts.map +1 -1
  40. package/abstract/tower.js +9 -3
  41. package/abstract/tower.js.map +1 -1
  42. package/abstract/utils.d.ts +1 -115
  43. package/abstract/utils.d.ts.map +1 -1
  44. package/abstract/utils.js +17 -371
  45. package/abstract/utils.js.map +1 -1
  46. package/abstract/weierstrass.d.ts +206 -124
  47. package/abstract/weierstrass.d.ts.map +1 -1
  48. package/abstract/weierstrass.js +747 -604
  49. package/abstract/weierstrass.js.map +1 -1
  50. package/bls12-381.d.ts +2 -0
  51. package/bls12-381.d.ts.map +1 -1
  52. package/bls12-381.js +504 -466
  53. package/bls12-381.js.map +1 -1
  54. package/bn254.d.ts +2 -0
  55. package/bn254.d.ts.map +1 -1
  56. package/bn254.js +44 -32
  57. package/bn254.js.map +1 -1
  58. package/ed25519.d.ts +55 -66
  59. package/ed25519.d.ts.map +1 -1
  60. package/ed25519.js +172 -186
  61. package/ed25519.js.map +1 -1
  62. package/ed448.d.ts +60 -57
  63. package/ed448.d.ts.map +1 -1
  64. package/ed448.js +172 -166
  65. package/ed448.js.map +1 -1
  66. package/esm/_shortw_utils.d.ts +8 -5
  67. package/esm/_shortw_utils.d.ts.map +1 -1
  68. package/esm/_shortw_utils.js +3 -8
  69. package/esm/_shortw_utils.js.map +1 -1
  70. package/esm/abstract/bls.d.ts +123 -62
  71. package/esm/abstract/bls.d.ts.map +1 -1
  72. package/esm/abstract/bls.js +220 -164
  73. package/esm/abstract/bls.js.map +1 -1
  74. package/esm/abstract/curve.d.ts +142 -21
  75. package/esm/abstract/curve.d.ts.map +1 -1
  76. package/esm/abstract/curve.js +219 -143
  77. package/esm/abstract/curve.js.map +1 -1
  78. package/esm/abstract/edwards.d.ts +190 -49
  79. package/esm/abstract/edwards.d.ts.map +1 -1
  80. package/esm/abstract/edwards.js +320 -138
  81. package/esm/abstract/edwards.js.map +1 -1
  82. package/esm/abstract/fft.d.ts +12 -10
  83. package/esm/abstract/fft.d.ts.map +1 -1
  84. package/esm/abstract/fft.js +10 -11
  85. package/esm/abstract/fft.js.map +1 -1
  86. package/esm/abstract/hash-to-curve.d.ts +31 -13
  87. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  88. package/esm/abstract/hash-to-curve.js +33 -19
  89. package/esm/abstract/hash-to-curve.js.map +1 -1
  90. package/esm/abstract/modular.d.ts +31 -13
  91. package/esm/abstract/modular.d.ts.map +1 -1
  92. package/esm/abstract/modular.js +124 -51
  93. package/esm/abstract/modular.js.map +1 -1
  94. package/esm/abstract/montgomery.d.ts +18 -5
  95. package/esm/abstract/montgomery.d.ts.map +1 -1
  96. package/esm/abstract/montgomery.js +23 -6
  97. package/esm/abstract/montgomery.js.map +1 -1
  98. package/esm/abstract/poseidon.d.ts +5 -13
  99. package/esm/abstract/poseidon.d.ts.map +1 -1
  100. package/esm/abstract/poseidon.js +12 -7
  101. package/esm/abstract/poseidon.js.map +1 -1
  102. package/esm/abstract/tower.d.ts +23 -49
  103. package/esm/abstract/tower.d.ts.map +1 -1
  104. package/esm/abstract/tower.js +9 -3
  105. package/esm/abstract/tower.js.map +1 -1
  106. package/esm/abstract/utils.d.ts +1 -115
  107. package/esm/abstract/utils.d.ts.map +1 -1
  108. package/esm/abstract/utils.js +3 -344
  109. package/esm/abstract/utils.js.map +1 -1
  110. package/esm/abstract/weierstrass.d.ts +206 -124
  111. package/esm/abstract/weierstrass.d.ts.map +1 -1
  112. package/esm/abstract/weierstrass.js +743 -605
  113. package/esm/abstract/weierstrass.js.map +1 -1
  114. package/esm/bls12-381.d.ts +2 -0
  115. package/esm/bls12-381.d.ts.map +1 -1
  116. package/esm/bls12-381.js +503 -465
  117. package/esm/bls12-381.js.map +1 -1
  118. package/esm/bn254.d.ts +2 -0
  119. package/esm/bn254.d.ts.map +1 -1
  120. package/esm/bn254.js +41 -29
  121. package/esm/bn254.js.map +1 -1
  122. package/esm/ed25519.d.ts +55 -66
  123. package/esm/ed25519.d.ts.map +1 -1
  124. package/esm/ed25519.js +170 -183
  125. package/esm/ed25519.js.map +1 -1
  126. package/esm/ed448.d.ts +60 -57
  127. package/esm/ed448.d.ts.map +1 -1
  128. package/esm/ed448.js +169 -162
  129. package/esm/ed448.js.map +1 -1
  130. package/esm/index.js +7 -9
  131. package/esm/index.js.map +1 -1
  132. package/esm/jubjub.d.ts +3 -3
  133. package/esm/jubjub.d.ts.map +1 -1
  134. package/esm/jubjub.js +3 -3
  135. package/esm/jubjub.js.map +1 -1
  136. package/esm/misc.d.ts +3 -5
  137. package/esm/misc.d.ts.map +1 -1
  138. package/esm/misc.js +31 -29
  139. package/esm/misc.js.map +1 -1
  140. package/esm/nist.d.ts +7 -22
  141. package/esm/nist.d.ts.map +1 -1
  142. package/esm/nist.js +106 -101
  143. package/esm/nist.js.map +1 -1
  144. package/esm/p256.d.ts +7 -3
  145. package/esm/p256.d.ts.map +1 -1
  146. package/esm/p256.js +4 -0
  147. package/esm/p256.js.map +1 -1
  148. package/esm/p384.d.ts +7 -4
  149. package/esm/p384.d.ts.map +1 -1
  150. package/esm/p384.js +4 -1
  151. package/esm/p384.js.map +1 -1
  152. package/esm/p521.d.ts +7 -3
  153. package/esm/p521.d.ts.map +1 -1
  154. package/esm/p521.js +4 -0
  155. package/esm/p521.js.map +1 -1
  156. package/esm/secp256k1.d.ts +38 -21
  157. package/esm/secp256k1.d.ts.map +1 -1
  158. package/esm/secp256k1.js +112 -104
  159. package/esm/secp256k1.js.map +1 -1
  160. package/esm/utils.d.ts +96 -0
  161. package/esm/utils.d.ts.map +1 -0
  162. package/esm/utils.js +279 -0
  163. package/esm/utils.js.map +1 -0
  164. package/index.js +7 -9
  165. package/index.js.map +1 -1
  166. package/jubjub.d.ts +3 -3
  167. package/jubjub.d.ts.map +1 -1
  168. package/jubjub.js +3 -3
  169. package/jubjub.js.map +1 -1
  170. package/misc.d.ts +3 -5
  171. package/misc.d.ts.map +1 -1
  172. package/misc.js +35 -33
  173. package/misc.js.map +1 -1
  174. package/nist.d.ts +7 -22
  175. package/nist.d.ts.map +1 -1
  176. package/nist.js +106 -101
  177. package/nist.js.map +1 -1
  178. package/p256.d.ts +7 -3
  179. package/p256.d.ts.map +1 -1
  180. package/p256.js +4 -0
  181. package/p256.js.map +1 -1
  182. package/p384.d.ts +7 -4
  183. package/p384.d.ts.map +1 -1
  184. package/p384.js +4 -1
  185. package/p384.js.map +1 -1
  186. package/p521.d.ts +7 -3
  187. package/p521.d.ts.map +1 -1
  188. package/p521.js +4 -0
  189. package/p521.js.map +1 -1
  190. package/package.json +17 -6
  191. package/secp256k1.d.ts +38 -21
  192. package/secp256k1.d.ts.map +1 -1
  193. package/secp256k1.js +112 -104
  194. package/secp256k1.js.map +1 -1
  195. package/src/_shortw_utils.ts +6 -15
  196. package/src/abstract/bls.ts +428 -251
  197. package/src/abstract/curve.ts +307 -149
  198. package/src/abstract/edwards.ts +555 -203
  199. package/src/abstract/fft.ts +30 -19
  200. package/src/abstract/hash-to-curve.ts +75 -34
  201. package/src/abstract/modular.ts +131 -59
  202. package/src/abstract/montgomery.ts +44 -15
  203. package/src/abstract/poseidon.ts +22 -18
  204. package/src/abstract/tower.ts +40 -71
  205. package/src/abstract/utils.ts +3 -378
  206. package/src/abstract/weierstrass.ts +1086 -746
  207. package/src/bls12-381.ts +549 -490
  208. package/src/bn254.ts +47 -35
  209. package/src/ed25519.ts +214 -216
  210. package/src/ed448.ts +251 -220
  211. package/src/index.ts +7 -9
  212. package/src/jubjub.ts +3 -3
  213. package/src/misc.ts +41 -40
  214. package/src/nist.ts +161 -126
  215. package/src/p256.ts +7 -3
  216. package/src/p384.ts +7 -5
  217. package/src/p521.ts +7 -3
  218. package/src/secp256k1.ts +145 -115
  219. package/src/utils.ts +328 -0
  220. package/utils.d.ts +96 -0
  221. package/utils.d.ts.map +1 -0
  222. package/utils.js +313 -0
  223. package/utils.js.map +1 -0
@@ -76,8 +76,15 @@ function findGenerator(field: IField<bigint>) {
76
76
  return G;
77
77
  }
78
78
 
79
+ export type RootsOfUnity = {
80
+ roots: (bits: number) => bigint[];
81
+ brp(bits: number): bigint[];
82
+ inverse(bits: number): bigint[];
83
+ omega: (bits: number) => bigint;
84
+ clear: () => void;
85
+ };
79
86
  /** We limit roots up to 2**31, which is a lot: 2-billion polynomimal should be rare. */
80
- export function rootsOfUnity(field: IField<bigint>, generator?: bigint) {
87
+ export function rootsOfUnity(field: IField<bigint>, generator?: bigint): RootsOfUnity {
81
88
  // Factor field.ORDER-1 as oddFactor * 2^powerOfTwo
82
89
  let oddFactor = field.ORDER - _1n;
83
90
  let powerOfTwo = 0;
@@ -186,8 +193,7 @@ export type FFTCoreLoop<T> = <P extends Polynomial<T>>(values: P) => P;
186
193
  * Cyclic NTT: Rq = Zq[x]/(x^n-1). butterfly_DIT+loop_DIT OR butterfly_DIF+loop_DIT, roots are omega
187
194
  * Negacyclic NTT: Rq = Zq[x]/(x^n+1). butterfly_DIT+loop_DIF, at least for mlkem / mldsa
188
195
  */
189
- export const FFTCore = <T, R>(opts: FFTOpts<T, R>, coreOpts: FFTCoreOpts<R>): FFTCoreLoop<T> => {
190
- const { add, sub, mul } = opts; // inline to butteflies
196
+ export const FFTCore = <T, R>(F: FFTOpts<T, R>, coreOpts: FFTCoreOpts<R>): FFTCoreLoop<T> => {
191
197
  const { N, roots, dit, invertButterflies = false, skipStages = 0, brp = true } = coreOpts;
192
198
  const bits = log2(N);
193
199
  if (!isPowerOfTwo(N)) throw new Error('FFT: Polynomial size should be power of two');
@@ -214,15 +220,15 @@ export const FFTCore = <T, R>(opts: FFTOpts<T, R>, coreOpts: FFTCoreOpts<R>): FF
214
220
  const a = values[i0];
215
221
  // Inlining gives us 10% perf in kyber vs functions
216
222
  if (isDit) {
217
- const t = mul(b, omega); // Standard DIT butterfly
218
- values[i0] = add(a, t);
219
- values[i1] = sub(a, t);
223
+ const t = F.mul(b, omega); // Standard DIT butterfly
224
+ values[i0] = F.add(a, t);
225
+ values[i1] = F.sub(a, t);
220
226
  } else if (invertButterflies) {
221
- values[i0] = add(b, a); // DIT loop + inverted butterflies (Kyber decode)
222
- values[i1] = mul(sub(b, a), omega);
227
+ values[i0] = F.add(b, a); // DIT loop + inverted butterflies (Kyber decode)
228
+ values[i1] = F.mul(F.sub(b, a), omega);
223
229
  } else {
224
- values[i0] = add(a, b); // Standard DIF butterfly
225
- values[i1] = mul(sub(a, b), omega);
230
+ values[i0] = F.add(a, b); // Standard DIF butterfly
231
+ values[i1] = F.mul(F.sub(a, b), omega);
226
232
  }
227
233
  }
228
234
  }
@@ -232,11 +238,16 @@ export const FFTCore = <T, R>(opts: FFTOpts<T, R>, coreOpts: FFTCoreOpts<R>): FF
232
238
  };
233
239
  };
234
240
 
241
+ export type FFTMethods<T> = {
242
+ direct<P extends Polynomial<T>>(values: P, brpInput?: boolean, brpOutput?: boolean): P;
243
+ inverse<P extends Polynomial<T>>(values: P, brpInput?: boolean, brpOutput?: boolean): P;
244
+ };
245
+
235
246
  /**
236
247
  * NTT aka FFT over finite field (NOT over complex numbers).
237
248
  * Naming mirrors other libraries.
238
249
  */
239
- export const FFT = <T>(roots: ReturnType<typeof rootsOfUnity>, opts: FFTOpts<T, bigint>) => {
250
+ export function FFT<T>(roots: RootsOfUnity, opts: FFTOpts<T, bigint>): FFTMethods<T> {
240
251
  const getLoop = (
241
252
  N: number,
242
253
  roots: Polynomial<bigint>,
@@ -272,12 +283,12 @@ export const FFT = <T>(roots: ReturnType<typeof rootsOfUnity>, opts: FFTOpts<T,
272
283
  return res;
273
284
  },
274
285
  };
275
- };
286
+ }
276
287
 
277
288
  export type CreatePolyFn<P extends Polynomial<T>, T> = (len: number, elm?: T) => P;
278
289
 
279
290
  export type PolyFn<P extends Polynomial<T>, T> = {
280
- roots: ReturnType<typeof rootsOfUnity>;
291
+ roots: RootsOfUnity;
281
292
  create: CreatePolyFn<P, T>;
282
293
  length?: number; // optional enforced size
283
294
 
@@ -318,23 +329,23 @@ export type PolyFn<P extends Polynomial<T>, T> = {
318
329
  */
319
330
  export function poly<T>(
320
331
  field: IField<T>,
321
- roots: ReturnType<typeof rootsOfUnity>,
332
+ roots: RootsOfUnity,
322
333
  create?: undefined,
323
- fft?: ReturnType<typeof FFT<T>>,
334
+ fft?: FFTMethods<T>,
324
335
  length?: number
325
336
  ): PolyFn<T[], T>;
326
337
  export function poly<T, P extends Polynomial<T>>(
327
338
  field: IField<T>,
328
- roots: ReturnType<typeof rootsOfUnity>,
339
+ roots: RootsOfUnity,
329
340
  create: CreatePolyFn<P, T>,
330
- fft?: ReturnType<typeof FFT<T>>,
341
+ fft?: FFTMethods<T>,
331
342
  length?: number
332
343
  ): PolyFn<P, T>;
333
344
  export function poly<T, P extends Polynomial<T>>(
334
345
  field: IField<T>,
335
- roots: ReturnType<typeof rootsOfUnity>,
346
+ roots: RootsOfUnity,
336
347
  create?: CreatePolyFn<P, T>,
337
- fft?: ReturnType<typeof FFT<T>>,
348
+ fft?: FFTMethods<T>,
338
349
  length?: number
339
350
  ): PolyFn<any, T> {
340
351
  const F = field;
@@ -5,10 +5,18 @@
5
5
  * @module
6
6
  */
7
7
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
8
+ import type { CHash } from '../utils.ts';
9
+ import {
10
+ _validateObject,
11
+ abytes,
12
+ bytesToNumberBE,
13
+ concatBytes,
14
+ isBytes,
15
+ isHash,
16
+ utf8ToBytes,
17
+ } from '../utils.ts';
8
18
  import type { AffinePoint, Group, GroupConstructor } from './curve.ts';
9
- import { FpInvertBatch, type IField, mod } from './modular.ts';
10
- import type { CHash } from './utils.ts';
11
- import { abytes, bytesToNumberBE, concatBytes, utf8ToBytes, validateObject } from './utils.ts';
19
+ import { FpInvertBatch, mod, type IField } from './modular.ts';
12
20
 
13
21
  export type UnicodeOrBytes = string | Uint8Array;
14
22
 
@@ -20,14 +28,20 @@ export type UnicodeOrBytes = string | Uint8Array;
20
28
  * * `expand` is `xmd` (SHA2, SHA3, BLAKE) or `xof` (SHAKE, BLAKE-XOF)
21
29
  * * `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
22
30
  */
23
- export type Opts = {
31
+ export type H2COpts = {
24
32
  DST: UnicodeOrBytes;
33
+ expand: 'xmd' | 'xof';
34
+ hash: CHash;
25
35
  p: bigint;
26
36
  m: number;
27
37
  k: number;
38
+ };
39
+ export type H2CHashOpts = {
28
40
  expand: 'xmd' | 'xof';
29
41
  hash: CHash;
30
42
  };
43
+ // todo: remove
44
+ export type Opts = H2COpts;
31
45
 
32
46
  // Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE.
33
47
  const os2ip = bytesToNumberBE;
@@ -57,19 +71,24 @@ function anum(item: unknown): void {
57
71
  if (!Number.isSafeInteger(item)) throw new Error('number expected');
58
72
  }
59
73
 
74
+ function normDST(DST: UnicodeOrBytes): Uint8Array {
75
+ if (!isBytes(DST) && typeof DST !== 'string') throw new Error('DST must be Uint8Array or string');
76
+ return typeof DST === 'string' ? utf8ToBytes(DST) : DST;
77
+ }
78
+
60
79
  /**
61
80
  * Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits.
62
81
  * [RFC 9380 5.3.1](https://www.rfc-editor.org/rfc/rfc9380#section-5.3.1).
63
82
  */
64
83
  export function expand_message_xmd(
65
84
  msg: Uint8Array,
66
- DST: Uint8Array,
85
+ DST: UnicodeOrBytes,
67
86
  lenInBytes: number,
68
87
  H: CHash
69
88
  ): Uint8Array {
70
89
  abytes(msg);
71
- abytes(DST);
72
90
  anum(lenInBytes);
91
+ DST = normDST(DST);
73
92
  // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
74
93
  if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST));
75
94
  const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
@@ -98,14 +117,14 @@ export function expand_message_xmd(
98
117
  */
99
118
  export function expand_message_xof(
100
119
  msg: Uint8Array,
101
- DST: Uint8Array,
120
+ DST: UnicodeOrBytes,
102
121
  lenInBytes: number,
103
122
  k: number,
104
123
  H: CHash
105
124
  ): Uint8Array {
106
125
  abytes(msg);
107
- abytes(DST);
108
126
  anum(lenInBytes);
127
+ DST = normDST(DST);
109
128
  // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
110
129
  // DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
111
130
  if (DST.length > 255) {
@@ -133,18 +152,17 @@ export function expand_message_xof(
133
152
  * @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
134
153
  * @returns [u_0, ..., u_(count - 1)], a list of field elements.
135
154
  */
136
- export function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][] {
137
- validateObject(options, {
138
- DST: 'stringOrUint8Array',
155
+ export function hash_to_field(msg: Uint8Array, count: number, options: H2COpts): bigint[][] {
156
+ _validateObject(options, {
139
157
  p: 'bigint',
140
- m: 'isSafeInteger',
141
- k: 'isSafeInteger',
142
- hash: 'hash',
158
+ m: 'number',
159
+ k: 'number',
160
+ hash: 'function',
143
161
  });
144
- const { p, k, m, hash, expand, DST: _DST } = options;
162
+ const { p, k, m, hash, expand, DST } = options;
163
+ if (!isHash(options.hash)) throw new Error('expected valid hash');
145
164
  abytes(msg);
146
165
  anum(count);
147
- const DST = typeof _DST === 'string' ? utf8ToBytes(_DST) : _DST;
148
166
  const log2p = p.toString(2).length;
149
167
  const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above
150
168
  const len_in_bytes = count * m * L;
@@ -209,21 +227,37 @@ export type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
209
227
  // Separated from initialization opts, so users won't accidentally change per-curve parameters
210
228
  // (changing DST is ok!)
211
229
  export type htfBasicOpts = { DST: UnicodeOrBytes };
212
- export type HTFMethod<T> = (msg: Uint8Array, options?: htfBasicOpts) => H2CPoint<T>;
230
+ export type H2CMethod<T> = (msg: Uint8Array, options?: htfBasicOpts) => H2CPoint<T>;
231
+ // TODO: remove
232
+ export type HTFMethod<T> = H2CMethod<T>;
213
233
  export type MapMethod<T> = (scalars: bigint[]) => H2CPoint<T>;
214
- export type Hasher<T> = {
215
- hashToCurve: HTFMethod<T>;
216
- encodeToCurve: HTFMethod<T>;
234
+ export type H2CHasherBase<T> = {
235
+ hashToCurve: H2CMethod<T>;
236
+ hashToScalar: (msg: Uint8Array, options: htfBasicOpts) => bigint;
237
+ };
238
+ /**
239
+ * RFC 9380 methods, with cofactor clearing. See https://www.rfc-editor.org/rfc/rfc9380#section-3.
240
+ *
241
+ * * hashToCurve: `map(hash(input))`, encodes RANDOM bytes to curve (WITH hashing)
242
+ * * encodeToCurve: `map(hash(input))`, encodes NON-UNIFORM bytes to curve (WITH hashing)
243
+ * * mapToCurve: `map(scalars)`, encodes NON-UNIFORM scalars to curve (NO hashing)
244
+ */
245
+ export type H2CHasher<T> = H2CHasherBase<T> & {
246
+ encodeToCurve: H2CMethod<T>;
217
247
  mapToCurve: MapMethod<T>;
218
- defaults: Opts & { encodeDST?: UnicodeOrBytes };
248
+ defaults: H2COpts & { encodeDST?: UnicodeOrBytes };
219
249
  };
250
+ // TODO: remove
251
+ export type Hasher<T> = H2CHasher<T>;
252
+
253
+ export const _DST_scalar: Uint8Array = utf8ToBytes('HashToScalar-');
220
254
 
221
- /** Creates hash-to-curve methods from EC Point and mapToCurve function. */
255
+ /** Creates hash-to-curve methods from EC Point and mapToCurve function. See {@link H2CHasher}. */
222
256
  export function createHasher<T>(
223
257
  Point: H2CPointConstructor<T>,
224
258
  mapToCurve: MapToCurve<T>,
225
- defaults: Opts & { encodeDST?: UnicodeOrBytes }
226
- ): Hasher<T> {
259
+ defaults: H2COpts & { encodeDST?: UnicodeOrBytes }
260
+ ): H2CHasher<T> {
227
261
  if (typeof mapToCurve !== 'function') throw new Error('mapToCurve() must be defined');
228
262
  function map(num: bigint[]) {
229
263
  return Point.fromAffine(mapToCurve(num));
@@ -238,28 +272,35 @@ export function createHasher<T>(
238
272
  return {
239
273
  defaults,
240
274
 
241
- // Encodes byte string to elliptic curve.
242
- // hash_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3
243
275
  hashToCurve(msg: Uint8Array, options?: htfBasicOpts): H2CPoint<T> {
244
- const u = hash_to_field(msg, 2, { ...defaults, DST: defaults.DST, ...options } as Opts);
276
+ const opts = Object.assign({}, defaults, options);
277
+ const u = hash_to_field(msg, 2, opts);
245
278
  const u0 = map(u[0]);
246
279
  const u1 = map(u[1]);
247
280
  return clear(u0.add(u1));
248
281
  },
249
-
250
- // Encodes byte string to elliptic curve.
251
- // encode_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3
252
282
  encodeToCurve(msg: Uint8Array, options?: htfBasicOpts): H2CPoint<T> {
253
- const u = hash_to_field(msg, 1, { ...defaults, DST: defaults.encodeDST, ...options } as Opts);
254
- return clear(map(u[0]));
283
+ const optsDst = defaults.encodeDST ? { DST: defaults.encodeDST } : {};
284
+ const opts = Object.assign({}, defaults, optsDst, options);
285
+ const u = hash_to_field(msg, 1, opts);
286
+ const u0 = map(u[0]);
287
+ return clear(u0);
255
288
  },
256
-
257
- // Same as encodeToCurve, but without hash
289
+ /** See {@link H2CHasher} */
258
290
  mapToCurve(scalars: bigint[]): H2CPoint<T> {
259
291
  if (!Array.isArray(scalars)) throw new Error('expected array of bigints');
260
292
  for (const i of scalars)
261
293
  if (typeof i !== 'bigint') throw new Error('expected array of bigints');
262
294
  return clear(map(scalars));
263
295
  },
296
+
297
+ // hash_to_scalar can produce 0: https://www.rfc-editor.org/errata/eid8393
298
+ // RFC 9380, draft-irtf-cfrg-bbs-signatures-08
299
+ hashToScalar(msg: Uint8Array, options?: htfBasicOpts): bigint {
300
+ // @ts-ignore
301
+ const N = Point.Fn.ORDER;
302
+ const opts = Object.assign({}, defaults, { p: N, m: 1, DST: _DST_scalar }, options);
303
+ return hash_to_field(msg, 1, opts)[0][0];
304
+ },
264
305
  };
265
306
  }
@@ -1,25 +1,27 @@
1
1
  /**
2
- * Utils for modular division and finite fields.
3
- * A finite field over 11 is integer number operations `mod 11`.
2
+ * Utils for modular division and fields.
3
+ * Field over 11 is a finite (Galois) field is integer number operations `mod 11`.
4
4
  * There is no division: it is replaced by modular multiplicative inverse.
5
5
  * @module
6
6
  */
7
7
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
8
- import { anumber } from '@noble/hashes/utils';
9
8
  import {
9
+ _validateObject,
10
+ anumber,
10
11
  bitMask,
11
12
  bytesToNumberBE,
12
13
  bytesToNumberLE,
13
14
  ensureBytes,
14
15
  numberToBytesBE,
15
16
  numberToBytesLE,
16
- validateObject,
17
- } from './utils.ts';
17
+ } from '../utils.ts';
18
18
 
19
19
  // prettier-ignore
20
20
  const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
21
21
  // prettier-ignore
22
- const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _8n = /* @__PURE__ */ BigInt(8);
22
+ const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _7n = /* @__PURE__ */ BigInt(7);
23
+ // prettier-ignore
24
+ const _8n = /* @__PURE__ */ BigInt(8), _9n = /* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);
23
25
 
24
26
  // Calculates a modulo b
25
27
  export function mod(a: bigint, b: bigint): bigint {
@@ -29,7 +31,6 @@ export function mod(a: bigint, b: bigint): bigint {
29
31
  /**
30
32
  * Efficiently raise num to power and do modular division.
31
33
  * Unsafe in some contexts: uses ladder, so can expose bigint bits.
32
- * TODO: remove.
33
34
  * @example
34
35
  * pow(2n, 6n, 11n) // 64n % 11n == 9n
35
36
  */
@@ -73,6 +74,10 @@ export function invert(number: bigint, modulo: bigint): bigint {
73
74
  return mod(x, modulo);
74
75
  }
75
76
 
77
+ function assertIsSquare<T>(Fp: IField<T>, root: T, n: T): void {
78
+ if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
79
+ }
80
+
76
81
  // Not all roots are possible! Example which will throw:
77
82
  // const NUM =
78
83
  // n = 72057594037927816n;
@@ -80,8 +85,7 @@ export function invert(number: bigint, modulo: bigint): bigint {
80
85
  function sqrt3mod4<T>(Fp: IField<T>, n: T) {
81
86
  const p1div4 = (Fp.ORDER + _1n) / _4n;
82
87
  const root = Fp.pow(n, p1div4);
83
- // Throw if root^2 != n
84
- if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
88
+ assertIsSquare(Fp, root, n);
85
89
  return root;
86
90
  }
87
91
 
@@ -92,32 +96,34 @@ function sqrt5mod8<T>(Fp: IField<T>, n: T) {
92
96
  const nv = Fp.mul(n, v);
93
97
  const i = Fp.mul(Fp.mul(nv, _2n), v);
94
98
  const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
95
- if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
99
+ assertIsSquare(Fp, root, n);
96
100
  return root;
97
101
  }
98
102
 
99
- // TODO: Commented-out for now. Provide test vectors.
100
- // Tonelli is too slow for extension fields Fp2.
101
- // That means we can't use sqrt (c1, c2...) even for initialization constants.
102
- // if (P % _16n === _9n) return sqrt9mod16;
103
- // // prettier-ignore
104
- // function sqrt9mod16<T>(Fp: IField<T>, n: T, p7div16?: bigint) {
105
- // if (p7div16 === undefined) p7div16 = (Fp.ORDER + BigInt(7)) / _16n;
106
- // const c1 = Fp.sqrt(Fp.neg(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
107
- // const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
108
- // const c3 = Fp.sqrt(Fp.neg(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
109
- // const c4 = p7div16; // 4. c4 = (q + 7) / 16 # Integer arithmetic
110
- // let tv1 = Fp.pow(n, c4); // 1. tv1 = x^c4
111
- // let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
112
- // const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
113
- // let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
114
- // const e1 = Fp.eql(Fp.sqr(tv2), n); // 5. e1 = (tv2^2) == x
115
- // const e2 = Fp.eql(Fp.sqr(tv3), n); // 6. e2 = (tv3^2) == x
116
- // tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
117
- // tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
118
- // const e3 = Fp.eql(Fp.sqr(tv2), n); // 9. e3 = (tv2^2) == x
119
- // return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
120
- // }
103
+ // Based on RFC9380, Kong algorithm
104
+ // prettier-ignore
105
+ function sqrt9mod16(P: bigint): <T>(Fp: IField<T>, n: T) => T {
106
+ const Fp_ = Field(P);
107
+ const tn = tonelliShanks(P);
108
+ const c1 = tn(Fp_, Fp_.neg(Fp_.ONE));// 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
109
+ const c2 = tn(Fp_, c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
110
+ const c3 = tn(Fp_, Fp_.neg(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
111
+ const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
112
+ return <T>(Fp: IField<T>, n: T) => {
113
+ let tv1 = Fp.pow(n, c4); // 1. tv1 = x^c4
114
+ let tv2 = Fp.mul(tv1, c1); // 2. tv2 = c1 * tv1
115
+ const tv3 = Fp.mul(tv1, c2); // 3. tv3 = c2 * tv1
116
+ const tv4 = Fp.mul(tv1, c3); // 4. tv4 = c3 * tv1
117
+ const e1 = Fp.eql(Fp.sqr(tv2), n); // 5. e1 = (tv2^2) == x
118
+ const e2 = Fp.eql(Fp.sqr(tv3), n); // 6. e2 = (tv3^2) == x
119
+ tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
120
+ tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
121
+ const e3 = Fp.eql(Fp.sqr(tv2), n); // 9. e3 = (tv2^2) == x
122
+ const root = Fp.cmov(tv1, tv2, e3);// 10. z = CMOV(tv1, tv2, e3) # Select sqrt from tv1 & tv2
123
+ assertIsSquare(Fp, root, n);
124
+ return root;
125
+ };
126
+ }
121
127
 
122
128
  /**
123
129
  * Tonelli-Shanks square root search algorithm.
@@ -128,7 +134,8 @@ function sqrt5mod8<T>(Fp: IField<T>, n: T) {
128
134
  */
129
135
  export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
130
136
  // Initialization (precomputation).
131
- if (P < BigInt(3)) throw new Error('sqrt is not defined for small field');
137
+ // Caching initialization could boost perf by 7%.
138
+ if (P < _3n) throw new Error('sqrt is not defined for small field');
132
139
  // Factor P - 1 = Q * 2^S, where Q is odd
133
140
  let Q = P - _1n;
134
141
  let S = 0;
@@ -196,7 +203,8 @@ export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
196
203
  *
197
204
  * 1. P ≡ 3 (mod 4)
198
205
  * 2. P ≡ 5 (mod 8)
199
- * 3. Tonelli-Shanks algorithm
206
+ * 3. P ≡ 9 (mod 16)
207
+ * 4. Tonelli-Shanks algorithm
200
208
  *
201
209
  * Different algorithms can give different roots, it is up to user to decide which one they want.
202
210
  * For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
@@ -206,7 +214,8 @@ export function FpSqrt(P: bigint): <T>(Fp: IField<T>, n: T) => T {
206
214
  if (P % _4n === _3n) return sqrt3mod4;
207
215
  // P ≡ 5 (mod 8) => Atkin algorithm, page 10 of https://eprint.iacr.org/2012/685.pdf
208
216
  if (P % _8n === _5n) return sqrt5mod8;
209
- // P ≡ 9 (mod 16) not implemented, see above
217
+ // P ≡ 9 (mod 16) => Kong algorithm, page 11 of https://eprint.iacr.org/2012/685.pdf (algorithm 4)
218
+ if (P % _16n === _9n) return sqrt9mod16(P);
210
219
  // Tonelli-Shanks algorithm
211
220
  return tonelliShanks(P);
212
221
  }
@@ -228,6 +237,7 @@ export interface IField<T> {
228
237
  create: (num: T) => T;
229
238
  isValid: (num: T) => boolean;
230
239
  is0: (num: T) => boolean;
240
+ isValidNot0: (num: T) => boolean;
231
241
  neg(num: T): T;
232
242
  inv(num: T): T;
233
243
  sqrt(num: T): T;
@@ -250,10 +260,11 @@ export interface IField<T> {
250
260
  // [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#section-4.1).
251
261
  // NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
252
262
  isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
263
+ allowedLengths?: number[];
253
264
  // legendre?(num: T): T;
254
265
  invertBatch: (lst: T[]) => T[];
255
266
  toBytes(num: T): Uint8Array;
256
- fromBytes(bytes: Uint8Array): T;
267
+ fromBytes(bytes: Uint8Array, skipValidation?: boolean): T;
257
268
  // If c is False, CMOV returns a, otherwise it returns b.
258
269
  cmov(a: T, b: T, c: boolean): T;
259
270
  }
@@ -267,14 +278,18 @@ export function validateField<T>(field: IField<T>): IField<T> {
267
278
  const initial = {
268
279
  ORDER: 'bigint',
269
280
  MASK: 'bigint',
270
- BYTES: 'isSafeInteger',
271
- BITS: 'isSafeInteger',
281
+ BYTES: 'number',
282
+ BITS: 'number',
272
283
  } as Record<string, string>;
273
284
  const opts = FIELD_FIELDS.reduce((map, val: string) => {
274
285
  map[val] = 'function';
275
286
  return map;
276
287
  }, initial);
277
- return validateObject(field, opts);
288
+ _validateObject(field, opts);
289
+ // const max = 16384;
290
+ // if (field.BYTES < 1 || field.BYTES > max) throw new Error('invalid field');
291
+ // if (field.BITS < 1 || field.BITS > 8 * max) throw new Error('invalid field');
292
+ return field;
278
293
  }
279
294
 
280
295
  // Generic field functions
@@ -353,14 +368,9 @@ export function FpIsSquare<T>(Fp: IField<T>, n: T): boolean {
353
368
  return l === 1;
354
369
  }
355
370
 
371
+ export type NLength = { nByteLength: number; nBitLength: number };
356
372
  // CURVE.n lengths
357
- export function nLength(
358
- n: bigint,
359
- nBitLength?: number
360
- ): {
361
- nBitLength: number;
362
- nByteLength: number;
363
- } {
373
+ export function nLength(n: bigint, nBitLength?: number): NLength {
364
374
  // Bit size, byte size of CURVE.n
365
375
  if (nBitLength !== undefined) anumber(nBitLength);
366
376
  const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
@@ -369,29 +379,57 @@ export function nLength(
369
379
  }
370
380
 
371
381
  type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
382
+ type SqrtFn = (n: bigint) => bigint;
383
+ type FieldOpts = Partial<{
384
+ sqrt: SqrtFn;
385
+ isLE: boolean;
386
+ BITS: number;
387
+ modOnDecode: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
388
+ allowedLengths?: readonly number[]; // for P521 (adds padding for smaller sizes)
389
+ }>;
372
390
  /**
373
- * Initializes a finite field over prime.
374
- * Major performance optimizations:
375
- * * a) denormalized operations like mulN instead of mul
376
- * * b) same object shape: never add or remove keys
377
- * * c) Object.freeze
391
+ * Creates a finite field. Major performance optimizations:
392
+ * * 1. Denormalized operations like mulN instead of mul.
393
+ * * 2. Identical object shape: never add or remove keys.
394
+ * * 3. `Object.freeze`.
378
395
  * Fragile: always run a benchmark on a change.
379
396
  * Security note: operations don't check 'isValid' for all elements for performance reasons,
380
397
  * it is caller responsibility to check this.
381
398
  * This is low-level code, please make sure you know what you're doing.
382
- * @param ORDER prime positive bigint
399
+ *
400
+ * Note about field properties:
401
+ * * CHARACTERISTIC p = prime number, number of elements in main subgroup.
402
+ * * ORDER q = similar to cofactor in curves, may be composite `q = p^m`.
403
+ *
404
+ * @param ORDER field order, probably prime, or could be composite
383
405
  * @param bitLen how many bits the field consumes
384
- * @param isLE (def: false) if encoding / decoding should be in little-endian
406
+ * @param isLE (default: false) if encoding / decoding should be in little-endian
385
407
  * @param redef optional faster redefinitions of sqrt and other methods
386
408
  */
387
409
  export function Field(
388
410
  ORDER: bigint,
389
- bitLen?: number,
411
+ bitLenOrOpts?: number | FieldOpts, // TODO: use opts only in v2?
390
412
  isLE = false,
391
- redef: Partial<IField<bigint>> = {}
413
+ opts: { sqrt?: SqrtFn } = {}
392
414
  ): Readonly<FpField> {
393
415
  if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
394
- const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
416
+ let _nbitLength: number | undefined = undefined;
417
+ let _sqrt: SqrtFn | undefined = undefined;
418
+ let modOnDecode: boolean = false;
419
+ let allowedLengths: undefined | readonly number[] = undefined;
420
+ if (typeof bitLenOrOpts === 'object' && bitLenOrOpts != null) {
421
+ if (opts.sqrt || isLE) throw new Error('cannot specify opts in two arguments');
422
+ const _opts = bitLenOrOpts;
423
+ if (_opts.BITS) _nbitLength = _opts.BITS;
424
+ if (_opts.sqrt) _sqrt = _opts.sqrt;
425
+ if (typeof _opts.isLE === 'boolean') isLE = _opts.isLE;
426
+ if (typeof _opts.modOnDecode === 'boolean') modOnDecode = _opts.modOnDecode;
427
+ allowedLengths = _opts.allowedLengths;
428
+ } else {
429
+ if (typeof bitLenOrOpts === 'number') _nbitLength = bitLenOrOpts;
430
+ if (opts.sqrt) _sqrt = opts.sqrt;
431
+ }
432
+ const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, _nbitLength);
395
433
  if (BYTES > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');
396
434
  let sqrtP: ReturnType<typeof FpSqrt>; // cached sqrtP
397
435
  const f: Readonly<FpField> = Object.freeze({
@@ -402,6 +440,7 @@ export function Field(
402
440
  MASK: bitMask(BITS),
403
441
  ZERO: _0n,
404
442
  ONE: _1n,
443
+ allowedLengths: allowedLengths,
405
444
  create: (num) => mod(num, ORDER),
406
445
  isValid: (num) => {
407
446
  if (typeof num !== 'bigint')
@@ -409,6 +448,8 @@ export function Field(
409
448
  return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
410
449
  },
411
450
  is0: (num) => num === _0n,
451
+ // is valid and invertible
452
+ isValidNot0: (num: bigint) => !f.is0(num) && f.isValid(num),
412
453
  isOdd: (num) => (num & _1n) === _1n,
413
454
  neg: (num) => mod(-num, ORDER),
414
455
  eql: (lhs, rhs) => lhs === rhs,
@@ -428,16 +469,33 @@ export function Field(
428
469
 
429
470
  inv: (num) => invert(num, ORDER),
430
471
  sqrt:
431
- redef.sqrt ||
472
+ _sqrt ||
432
473
  ((n) => {
433
474
  if (!sqrtP) sqrtP = FpSqrt(ORDER);
434
475
  return sqrtP(f, n);
435
476
  }),
436
477
  toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),
437
- fromBytes: (bytes) => {
478
+ fromBytes: (bytes, skipValidation = true) => {
479
+ if (allowedLengths) {
480
+ if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
481
+ throw new Error(
482
+ 'Field.fromBytes: expected ' + allowedLengths + ' bytes, got ' + bytes.length
483
+ );
484
+ }
485
+ const padded = new Uint8Array(BYTES);
486
+ // isLE add 0 to right, !isLE to the left.
487
+ padded.set(bytes, isLE ? 0 : padded.length - bytes.length);
488
+ bytes = padded;
489
+ }
438
490
  if (bytes.length !== BYTES)
439
491
  throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
440
- return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
492
+ let scalar = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
493
+ if (modOnDecode) scalar = mod(scalar, ORDER);
494
+ if (!skipValidation)
495
+ if (!f.isValid(scalar)) throw new Error('invalid field element: outside of range 0..ORDER');
496
+ // NOTE: we don't validate scalar here, please use isValid. This done such way because some
497
+ // protocol may allow non-reduced scalar that reduced later or changed some other way.
498
+ return scalar;
441
499
  },
442
500
  // TODO: we don't need it here, move out to separate fn
443
501
  invertBatch: (lst) => FpInvertBatch(f, lst),
@@ -448,6 +506,20 @@ export function Field(
448
506
  return Object.freeze(f);
449
507
  }
450
508
 
509
+ // Generic random scalar, we can do same for other fields if via Fp2.mul(Fp2.ONE, Fp2.random)?
510
+ // This allows unsafe methods like ignore bias or zero. These unsafe, but often used in different protocols (if deterministic RNG).
511
+ // which mean we cannot force this via opts.
512
+ // Not sure what to do with randomBytes, we can accept it inside opts if wanted.
513
+ // Probably need to export getMinHashLength somewhere?
514
+ // random(bytes?: Uint8Array, unsafeAllowZero = false, unsafeAllowBias = false) {
515
+ // const LEN = !unsafeAllowBias ? getMinHashLength(ORDER) : BYTES;
516
+ // if (bytes === undefined) bytes = randomBytes(LEN); // _opts.randomBytes?
517
+ // const num = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
518
+ // // `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
519
+ // const reduced = unsafeAllowZero ? mod(num, ORDER) : mod(num, ORDER - _1n) + _1n;
520
+ // return reduced;
521
+ // },
522
+
451
523
  export function FpSqrtOdd<T>(Fp: IField<T>, elm: T): T {
452
524
  if (!Fp.isOdd) throw new Error("Field doesn't have isOdd");
453
525
  const root = Fp.sqrt(elm);