@noble/curves 1.9.7 → 2.0.0-beta.2

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 (242) hide show
  1. package/README.md +520 -505
  2. package/abstract/bls.d.ts +58 -120
  3. package/abstract/bls.d.ts.map +1 -1
  4. package/abstract/bls.js +108 -152
  5. package/abstract/bls.js.map +1 -1
  6. package/abstract/curve.d.ts +18 -54
  7. package/abstract/curve.d.ts.map +1 -1
  8. package/abstract/curve.js +30 -49
  9. package/abstract/curve.js.map +1 -1
  10. package/abstract/edwards.d.ts +18 -77
  11. package/abstract/edwards.d.ts.map +1 -1
  12. package/abstract/edwards.js +68 -144
  13. package/abstract/edwards.js.map +1 -1
  14. package/abstract/fft.js +14 -27
  15. package/abstract/fft.js.map +1 -1
  16. package/abstract/hash-to-curve.d.ts +35 -47
  17. package/abstract/hash-to-curve.d.ts.map +1 -1
  18. package/abstract/hash-to-curve.js +42 -46
  19. package/abstract/hash-to-curve.js.map +1 -1
  20. package/abstract/modular.d.ts +5 -17
  21. package/abstract/modular.d.ts.map +1 -1
  22. package/abstract/modular.js +170 -169
  23. package/abstract/modular.js.map +1 -1
  24. package/abstract/montgomery.d.ts +7 -12
  25. package/abstract/montgomery.d.ts.map +1 -1
  26. package/abstract/montgomery.js +22 -29
  27. package/abstract/montgomery.js.map +1 -1
  28. package/abstract/oprf.d.ts +282 -0
  29. package/abstract/oprf.d.ts.map +1 -0
  30. package/abstract/oprf.js +297 -0
  31. package/abstract/oprf.js.map +1 -0
  32. package/abstract/poseidon.d.ts.map +1 -1
  33. package/abstract/poseidon.js +26 -31
  34. package/abstract/poseidon.js.map +1 -1
  35. package/abstract/tower.d.ts.map +1 -1
  36. package/abstract/tower.js +43 -19
  37. package/abstract/tower.js.map +1 -1
  38. package/abstract/weierstrass.d.ts +77 -168
  39. package/abstract/weierstrass.d.ts.map +1 -1
  40. package/abstract/weierstrass.js +184 -389
  41. package/abstract/weierstrass.js.map +1 -1
  42. package/bls12-381.d.ts +5 -11
  43. package/bls12-381.d.ts.map +1 -1
  44. package/bls12-381.js +161 -181
  45. package/bls12-381.js.map +1 -1
  46. package/bn254.d.ts +59 -11
  47. package/bn254.d.ts.map +1 -1
  48. package/bn254.js +69 -97
  49. package/bn254.js.map +1 -1
  50. package/ed25519.d.ts +33 -48
  51. package/ed25519.d.ts.map +1 -1
  52. package/ed25519.js +147 -161
  53. package/ed25519.js.map +1 -1
  54. package/ed448.d.ts +27 -36
  55. package/ed448.d.ts.map +1 -1
  56. package/ed448.js +143 -164
  57. package/ed448.js.map +1 -1
  58. package/index.d.ts +1 -0
  59. package/index.js +20 -4
  60. package/index.js.map +1 -1
  61. package/misc.d.ts +10 -14
  62. package/misc.d.ts.map +1 -1
  63. package/misc.js +53 -62
  64. package/misc.js.map +1 -1
  65. package/nist.d.ts +31 -16
  66. package/nist.d.ts.map +1 -1
  67. package/nist.js +75 -64
  68. package/nist.js.map +1 -1
  69. package/package.json +20 -234
  70. package/secp256k1.d.ts +17 -30
  71. package/secp256k1.d.ts.map +1 -1
  72. package/secp256k1.js +59 -73
  73. package/secp256k1.js.map +1 -1
  74. package/src/abstract/bls.ts +207 -354
  75. package/src/abstract/curve.ts +25 -84
  76. package/src/abstract/edwards.ts +68 -193
  77. package/src/abstract/hash-to-curve.ts +71 -85
  78. package/src/abstract/modular.ts +150 -134
  79. package/src/abstract/montgomery.ts +28 -35
  80. package/src/abstract/oprf.ts +600 -0
  81. package/src/abstract/poseidon.ts +6 -8
  82. package/src/abstract/tower.ts +0 -3
  83. package/src/abstract/weierstrass.ts +203 -525
  84. package/src/bls12-381.ts +133 -139
  85. package/src/bn254.ts +69 -93
  86. package/src/ed25519.ts +106 -133
  87. package/src/ed448.ts +111 -138
  88. package/src/index.ts +19 -3
  89. package/src/misc.ts +68 -51
  90. package/src/nist.ts +77 -70
  91. package/src/secp256k1.ts +46 -81
  92. package/src/utils.ts +67 -137
  93. package/src/webcrypto.ts +403 -0
  94. package/utils.d.ts +31 -38
  95. package/utils.d.ts.map +1 -1
  96. package/utils.js +66 -185
  97. package/utils.js.map +1 -1
  98. package/webcrypto.d.ts +99 -0
  99. package/webcrypto.d.ts.map +1 -0
  100. package/webcrypto.js +256 -0
  101. package/webcrypto.js.map +1 -0
  102. package/_shortw_utils.d.ts +0 -19
  103. package/_shortw_utils.d.ts.map +0 -1
  104. package/_shortw_utils.js +0 -20
  105. package/_shortw_utils.js.map +0 -1
  106. package/abstract/utils.d.ts +0 -78
  107. package/abstract/utils.d.ts.map +0 -1
  108. package/abstract/utils.js +0 -73
  109. package/abstract/utils.js.map +0 -1
  110. package/esm/_shortw_utils.d.ts +0 -19
  111. package/esm/_shortw_utils.d.ts.map +0 -1
  112. package/esm/_shortw_utils.js +0 -16
  113. package/esm/_shortw_utils.js.map +0 -1
  114. package/esm/abstract/bls.d.ts +0 -190
  115. package/esm/abstract/bls.d.ts.map +0 -1
  116. package/esm/abstract/bls.js +0 -408
  117. package/esm/abstract/bls.js.map +0 -1
  118. package/esm/abstract/curve.d.ts +0 -231
  119. package/esm/abstract/curve.d.ts.map +0 -1
  120. package/esm/abstract/curve.js +0 -465
  121. package/esm/abstract/curve.js.map +0 -1
  122. package/esm/abstract/edwards.d.ts +0 -243
  123. package/esm/abstract/edwards.d.ts.map +0 -1
  124. package/esm/abstract/edwards.js +0 -627
  125. package/esm/abstract/edwards.js.map +0 -1
  126. package/esm/abstract/fft.d.ts +0 -122
  127. package/esm/abstract/fft.d.ts.map +0 -1
  128. package/esm/abstract/fft.js +0 -425
  129. package/esm/abstract/fft.js.map +0 -1
  130. package/esm/abstract/hash-to-curve.d.ts +0 -102
  131. package/esm/abstract/hash-to-curve.d.ts.map +0 -1
  132. package/esm/abstract/hash-to-curve.js +0 -203
  133. package/esm/abstract/hash-to-curve.js.map +0 -1
  134. package/esm/abstract/modular.d.ts +0 -171
  135. package/esm/abstract/modular.d.ts.map +0 -1
  136. package/esm/abstract/modular.js +0 -530
  137. package/esm/abstract/modular.js.map +0 -1
  138. package/esm/abstract/montgomery.d.ts +0 -30
  139. package/esm/abstract/montgomery.d.ts.map +0 -1
  140. package/esm/abstract/montgomery.js +0 -157
  141. package/esm/abstract/montgomery.js.map +0 -1
  142. package/esm/abstract/poseidon.d.ts +0 -68
  143. package/esm/abstract/poseidon.d.ts.map +0 -1
  144. package/esm/abstract/poseidon.js +0 -296
  145. package/esm/abstract/poseidon.js.map +0 -1
  146. package/esm/abstract/tower.d.ts +0 -95
  147. package/esm/abstract/tower.d.ts.map +0 -1
  148. package/esm/abstract/tower.js +0 -714
  149. package/esm/abstract/tower.js.map +0 -1
  150. package/esm/abstract/utils.d.ts +0 -78
  151. package/esm/abstract/utils.d.ts.map +0 -1
  152. package/esm/abstract/utils.js +0 -70
  153. package/esm/abstract/utils.js.map +0 -1
  154. package/esm/abstract/weierstrass.d.ts +0 -416
  155. package/esm/abstract/weierstrass.d.ts.map +0 -1
  156. package/esm/abstract/weierstrass.js +0 -1413
  157. package/esm/abstract/weierstrass.js.map +0 -1
  158. package/esm/bls12-381.d.ts +0 -16
  159. package/esm/bls12-381.d.ts.map +0 -1
  160. package/esm/bls12-381.js +0 -705
  161. package/esm/bls12-381.js.map +0 -1
  162. package/esm/bn254.d.ts +0 -18
  163. package/esm/bn254.d.ts.map +0 -1
  164. package/esm/bn254.js +0 -214
  165. package/esm/bn254.js.map +0 -1
  166. package/esm/ed25519.d.ts +0 -106
  167. package/esm/ed25519.d.ts.map +0 -1
  168. package/esm/ed25519.js +0 -467
  169. package/esm/ed25519.js.map +0 -1
  170. package/esm/ed448.d.ts +0 -100
  171. package/esm/ed448.d.ts.map +0 -1
  172. package/esm/ed448.js +0 -459
  173. package/esm/ed448.js.map +0 -1
  174. package/esm/index.d.ts +0 -2
  175. package/esm/index.d.ts.map +0 -1
  176. package/esm/index.js +0 -17
  177. package/esm/index.js.map +0 -1
  178. package/esm/jubjub.d.ts +0 -12
  179. package/esm/jubjub.d.ts.map +0 -1
  180. package/esm/jubjub.js +0 -12
  181. package/esm/jubjub.js.map +0 -1
  182. package/esm/misc.d.ts +0 -19
  183. package/esm/misc.d.ts.map +0 -1
  184. package/esm/misc.js +0 -109
  185. package/esm/misc.js.map +0 -1
  186. package/esm/nist.d.ts +0 -21
  187. package/esm/nist.d.ts.map +0 -1
  188. package/esm/nist.js +0 -132
  189. package/esm/nist.js.map +0 -1
  190. package/esm/p256.d.ts +0 -16
  191. package/esm/p256.d.ts.map +0 -1
  192. package/esm/p256.js +0 -16
  193. package/esm/p256.js.map +0 -1
  194. package/esm/p384.d.ts +0 -16
  195. package/esm/p384.d.ts.map +0 -1
  196. package/esm/p384.js +0 -16
  197. package/esm/p384.js.map +0 -1
  198. package/esm/p521.d.ts +0 -16
  199. package/esm/p521.d.ts.map +0 -1
  200. package/esm/p521.js +0 -16
  201. package/esm/p521.js.map +0 -1
  202. package/esm/package.json +0 -4
  203. package/esm/pasta.d.ts +0 -10
  204. package/esm/pasta.d.ts.map +0 -1
  205. package/esm/pasta.js +0 -10
  206. package/esm/pasta.js.map +0 -1
  207. package/esm/secp256k1.d.ts +0 -89
  208. package/esm/secp256k1.d.ts.map +0 -1
  209. package/esm/secp256k1.js +0 -294
  210. package/esm/secp256k1.js.map +0 -1
  211. package/esm/utils.d.ts +0 -110
  212. package/esm/utils.d.ts.map +0 -1
  213. package/esm/utils.js +0 -322
  214. package/esm/utils.js.map +0 -1
  215. package/jubjub.d.ts +0 -12
  216. package/jubjub.d.ts.map +0 -1
  217. package/jubjub.js +0 -15
  218. package/jubjub.js.map +0 -1
  219. package/p256.d.ts +0 -16
  220. package/p256.d.ts.map +0 -1
  221. package/p256.js +0 -13
  222. package/p256.js.map +0 -1
  223. package/p384.d.ts +0 -16
  224. package/p384.d.ts.map +0 -1
  225. package/p384.js +0 -13
  226. package/p384.js.map +0 -1
  227. package/p521.d.ts +0 -16
  228. package/p521.d.ts.map +0 -1
  229. package/p521.js +0 -13
  230. package/p521.js.map +0 -1
  231. package/pasta.d.ts +0 -10
  232. package/pasta.d.ts.map +0 -1
  233. package/pasta.js +0 -13
  234. package/pasta.js.map +0 -1
  235. package/src/_shortw_utils.ts +0 -21
  236. package/src/abstract/utils.ts +0 -80
  237. package/src/jubjub.ts +0 -12
  238. package/src/p256.ts +0 -15
  239. package/src/p384.ts +0 -15
  240. package/src/p521.ts +0 -15
  241. package/src/package.json +0 -3
  242. package/src/pasta.ts +0 -9
@@ -7,18 +7,18 @@
7
7
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
8
8
  import type { CHash } from '../utils.ts';
9
9
  import {
10
- _validateObject,
11
10
  abytes,
11
+ asafenumber,
12
+ asciiToBytes,
12
13
  bytesToNumberBE,
13
14
  concatBytes,
14
15
  isBytes,
15
- isHash,
16
- utf8ToBytes,
16
+ validateObject,
17
17
  } from '../utils.ts';
18
- import type { AffinePoint, Group, GroupConstructor } from './curve.ts';
18
+ import type { AffinePoint, PC_ANY, PC_F, PC_P } from './curve.ts';
19
19
  import { FpInvertBatch, mod, type IField } from './modular.ts';
20
20
 
21
- export type UnicodeOrBytes = string | Uint8Array;
21
+ export type AsciiOrBytes = string | Uint8Array;
22
22
 
23
23
  /**
24
24
  * * `DST` is a domain separation tag, defined in section 2.2.5
@@ -29,7 +29,7 @@ export type UnicodeOrBytes = string | Uint8Array;
29
29
  * * `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
30
30
  */
31
31
  export type H2COpts = {
32
- DST: UnicodeOrBytes;
32
+ DST: AsciiOrBytes;
33
33
  expand: 'xmd' | 'xof';
34
34
  hash: CHash;
35
35
  p: bigint;
@@ -40,16 +40,37 @@ export type H2CHashOpts = {
40
40
  expand: 'xmd' | 'xof';
41
41
  hash: CHash;
42
42
  };
43
- // todo: remove
44
- export type Opts = H2COpts;
43
+ export type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
44
+
45
+ // Separated from initialization opts, so users won't accidentally change per-curve parameters
46
+ // (changing DST is ok!)
47
+ export type H2CDSTOpts = { DST: AsciiOrBytes };
48
+ export type H2CHasherBase<PC extends PC_ANY> = {
49
+ hashToCurve(msg: Uint8Array, options?: H2CDSTOpts): PC_P<PC>;
50
+ hashToScalar(msg: Uint8Array, options?: H2CDSTOpts): bigint;
51
+ deriveToCurve?(msg: Uint8Array, options?: H2CDSTOpts): PC_P<PC>;
52
+ Point: PC;
53
+ };
54
+ /**
55
+ * RFC 9380 methods, with cofactor clearing. See https://www.rfc-editor.org/rfc/rfc9380#section-3.
56
+ *
57
+ * * hashToCurve: `map(hash(input))`, encodes RANDOM bytes to curve (WITH hashing)
58
+ * * encodeToCurve: `map(hash(input))`, encodes NON-UNIFORM bytes to curve (WITH hashing)
59
+ * * mapToCurve: `map(scalars)`, encodes NON-UNIFORM scalars to curve (NO hashing)
60
+ */
61
+ export type H2CHasher<PC extends PC_ANY> = H2CHasherBase<PC> & {
62
+ encodeToCurve(msg: Uint8Array, options?: H2CDSTOpts): PC_P<PC>;
63
+ mapToCurve: MapToCurve<PC_F<PC>>;
64
+ defaults: H2COpts & { encodeDST?: AsciiOrBytes };
65
+ };
45
66
 
46
67
  // Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE.
47
68
  const os2ip = bytesToNumberBE;
48
69
 
49
70
  // Integer to Octet Stream (numberToBytesBE)
50
71
  function i2osp(value: number, length: number): Uint8Array {
51
- anum(value);
52
- anum(length);
72
+ asafenumber(value);
73
+ asafenumber(length);
53
74
  if (value < 0 || value >= 1 << (8 * length)) throw new Error('invalid I2OSP input: ' + value);
54
75
  const res = Array.from({ length }).fill(0) as number[];
55
76
  for (let i = length - 1; i >= 0; i--) {
@@ -67,13 +88,12 @@ function strxor(a: Uint8Array, b: Uint8Array): Uint8Array {
67
88
  return arr;
68
89
  }
69
90
 
70
- function anum(item: unknown): void {
71
- if (!Number.isSafeInteger(item)) throw new Error('number expected');
72
- }
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;
91
+ // User can always use utf8 if they want, by passing Uint8Array.
92
+ // If string is passed, we treat it as ASCII: other formats are likely a mistake.
93
+ function normDST(DST: AsciiOrBytes): Uint8Array {
94
+ if (!isBytes(DST) && typeof DST !== 'string')
95
+ throw new Error('DST must be Uint8Array or ascii string');
96
+ return typeof DST === 'string' ? asciiToBytes(DST) : DST;
77
97
  }
78
98
 
79
99
  /**
@@ -82,15 +102,15 @@ function normDST(DST: UnicodeOrBytes): Uint8Array {
82
102
  */
83
103
  export function expand_message_xmd(
84
104
  msg: Uint8Array,
85
- DST: UnicodeOrBytes,
105
+ DST: AsciiOrBytes,
86
106
  lenInBytes: number,
87
107
  H: CHash
88
108
  ): Uint8Array {
89
109
  abytes(msg);
90
- anum(lenInBytes);
110
+ asafenumber(lenInBytes);
91
111
  DST = normDST(DST);
92
112
  // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
93
- if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST));
113
+ if (DST.length > 255) DST = H(concatBytes(asciiToBytes('H2C-OVERSIZE-DST-'), DST));
94
114
  const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
95
115
  const ell = Math.ceil(lenInBytes / b_in_bytes);
96
116
  if (lenInBytes > 65535 || ell > 255) throw new Error('expand_message_xmd: invalid lenInBytes');
@@ -117,19 +137,19 @@ export function expand_message_xmd(
117
137
  */
118
138
  export function expand_message_xof(
119
139
  msg: Uint8Array,
120
- DST: UnicodeOrBytes,
140
+ DST: AsciiOrBytes,
121
141
  lenInBytes: number,
122
142
  k: number,
123
143
  H: CHash
124
144
  ): Uint8Array {
125
145
  abytes(msg);
126
- anum(lenInBytes);
146
+ asafenumber(lenInBytes);
127
147
  DST = normDST(DST);
128
148
  // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
129
149
  // DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
130
150
  if (DST.length > 255) {
131
151
  const dkLen = Math.ceil((2 * k) / 8);
132
- DST = H.create({ dkLen }).update(utf8ToBytes('H2C-OVERSIZE-DST-')).update(DST).digest();
152
+ DST = H.create({ dkLen }).update(asciiToBytes('H2C-OVERSIZE-DST-')).update(DST).digest();
133
153
  }
134
154
  if (lenInBytes > 65535 || DST.length > 255)
135
155
  throw new Error('expand_message_xof: invalid lenInBytes');
@@ -153,16 +173,16 @@ export function expand_message_xof(
153
173
  * @returns [u_0, ..., u_(count - 1)], a list of field elements.
154
174
  */
155
175
  export function hash_to_field(msg: Uint8Array, count: number, options: H2COpts): bigint[][] {
156
- _validateObject(options, {
176
+ validateObject(options, {
157
177
  p: 'bigint',
158
178
  m: 'number',
159
179
  k: 'number',
160
180
  hash: 'function',
161
181
  });
162
182
  const { p, k, m, hash, expand, DST } = options;
163
- if (!isHash(options.hash)) throw new Error('expected valid hash');
183
+ asafenumber(hash.outputLen, 'valid hash');
164
184
  abytes(msg);
165
- anum(count);
185
+ asafenumber(count);
166
186
  const log2p = p.toString(2).length;
167
187
  const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above
168
188
  const len_in_bytes = count * m * L;
@@ -190,8 +210,8 @@ export function hash_to_field(msg: Uint8Array, count: number, options: H2COpts):
190
210
  return u;
191
211
  }
192
212
 
193
- export type XY<T> = (x: T, y: T) => { x: T; y: T };
194
- export type XYRatio<T> = [T[], T[], T[], T[]]; // xn/xd, yn/yd
213
+ type XY<T> = (x: T, y: T) => { x: T; y: T };
214
+ type XYRatio<T> = [T[], T[], T[], T[]]; // xn/xd, yn/yd
195
215
  export function isogenyMap<T, F extends IField<T>>(field: F, map: XYRatio<T>): XY<T> {
196
216
  // Make same order as in spec
197
217
  const coeff = map.map((i) => Array.from(i).reverse());
@@ -210,76 +230,37 @@ export function isogenyMap<T, F extends IField<T>>(field: F, map: XYRatio<T>): X
210
230
  };
211
231
  }
212
232
 
213
- /** Point interface, which curves must implement to work correctly with the module. */
214
- export interface H2CPoint<T> extends Group<H2CPoint<T>> {
215
- add(rhs: H2CPoint<T>): H2CPoint<T>;
216
- toAffine(iz?: bigint): AffinePoint<T>;
217
- clearCofactor(): H2CPoint<T>;
218
- assertValidity(): void;
219
- }
220
-
221
- export interface H2CPointConstructor<T> extends GroupConstructor<H2CPoint<T>> {
222
- fromAffine(ap: AffinePoint<T>): H2CPoint<T>;
223
- }
224
-
225
- export type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
226
-
227
- // Separated from initialization opts, so users won't accidentally change per-curve parameters
228
- // (changing DST is ok!)
229
- export type htfBasicOpts = { DST: UnicodeOrBytes };
230
- export type H2CMethod<T> = (msg: Uint8Array, options?: htfBasicOpts) => H2CPoint<T>;
231
- // TODO: remove
232
- export type HTFMethod<T> = H2CMethod<T>;
233
- export type MapMethod<T> = (scalars: bigint[]) => H2CPoint<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>;
247
- mapToCurve: MapMethod<T>;
248
- defaults: H2COpts & { encodeDST?: UnicodeOrBytes };
249
- };
250
- // TODO: remove
251
- export type Hasher<T> = H2CHasher<T>;
252
-
253
- export const _DST_scalar: Uint8Array = utf8ToBytes('HashToScalar-');
233
+ export const _DST_scalar: Uint8Array = asciiToBytes('HashToScalar-');
254
234
 
255
235
  /** Creates hash-to-curve methods from EC Point and mapToCurve function. See {@link H2CHasher}. */
256
- export function createHasher<T>(
257
- Point: H2CPointConstructor<T>,
258
- mapToCurve: MapToCurve<T>,
259
- defaults: H2COpts & { encodeDST?: UnicodeOrBytes }
260
- ): H2CHasher<T> {
236
+ export function createHasher<PC extends PC_ANY>(
237
+ Point: PC,
238
+ mapToCurve: MapToCurve<PC_F<PC>>,
239
+ defaults: H2COpts & { encodeDST?: AsciiOrBytes }
240
+ ): H2CHasher<PC> {
261
241
  if (typeof mapToCurve !== 'function') throw new Error('mapToCurve() must be defined');
262
- function map(num: bigint[]) {
263
- return Point.fromAffine(mapToCurve(num));
242
+ function map(num: bigint[]): PC_P<PC> {
243
+ return Point.fromAffine(mapToCurve(num)) as PC_P<PC>;
264
244
  }
265
- function clear(initial: H2CPoint<T>) {
245
+ function clear(initial: PC_P<PC>): PC_P<PC> {
266
246
  const P = initial.clearCofactor();
267
- if (P.equals(Point.ZERO)) return Point.ZERO; // zero will throw in assert
247
+ if (P.equals(Point.ZERO)) return Point.ZERO as PC_P<PC>; // zero will throw in assert
268
248
  P.assertValidity();
269
- return P;
249
+ return P as PC_P<PC>;
270
250
  }
271
251
 
272
252
  return {
273
- defaults,
253
+ defaults: Object.freeze(defaults),
254
+ Point,
274
255
 
275
- hashToCurve(msg: Uint8Array, options?: htfBasicOpts): H2CPoint<T> {
256
+ hashToCurve(msg: Uint8Array, options?: H2CDSTOpts): PC_P<PC> {
276
257
  const opts = Object.assign({}, defaults, options);
277
258
  const u = hash_to_field(msg, 2, opts);
278
259
  const u0 = map(u[0]);
279
260
  const u1 = map(u[1]);
280
- return clear(u0.add(u1));
261
+ return clear(u0.add(u1) as PC_P<PC>);
281
262
  },
282
- encodeToCurve(msg: Uint8Array, options?: htfBasicOpts): H2CPoint<T> {
263
+ encodeToCurve(msg: Uint8Array, options?: H2CDSTOpts): PC_P<PC> {
283
264
  const optsDst = defaults.encodeDST ? { DST: defaults.encodeDST } : {};
284
265
  const opts = Object.assign({}, defaults, optsDst, options);
285
266
  const u = hash_to_field(msg, 1, opts);
@@ -287,7 +268,12 @@ export function createHasher<T>(
287
268
  return clear(u0);
288
269
  },
289
270
  /** See {@link H2CHasher} */
290
- mapToCurve(scalars: bigint[]): H2CPoint<T> {
271
+ mapToCurve(scalars: bigint | bigint[]): PC_P<PC> {
272
+ // Curves with m=1 accept only single scalar
273
+ if (defaults.m === 1) {
274
+ if (typeof scalars !== 'bigint') throw new Error('expected bigint (m=1)');
275
+ return clear(map([scalars]));
276
+ }
291
277
  if (!Array.isArray(scalars)) throw new Error('expected array of bigints');
292
278
  for (const i of scalars)
293
279
  if (typeof i !== 'bigint') throw new Error('expected array of bigints');
@@ -296,7 +282,7 @@ export function createHasher<T>(
296
282
 
297
283
  // hash_to_scalar can produce 0: https://www.rfc-editor.org/errata/eid8393
298
284
  // RFC 9380, draft-irtf-cfrg-bbs-signatures-08
299
- hashToScalar(msg: Uint8Array, options?: htfBasicOpts): bigint {
285
+ hashToScalar(msg: Uint8Array, options?: H2CDSTOpts): bigint {
300
286
  // @ts-ignore
301
287
  const N = Point.Fn.ORDER;
302
288
  const opts = Object.assign({}, defaults, { p: N, m: 1, DST: _DST_scalar }, options);
@@ -6,22 +6,23 @@
6
6
  */
7
7
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
8
8
  import {
9
- _validateObject,
9
+ abytes,
10
10
  anumber,
11
- bitMask,
12
11
  bytesToNumberBE,
13
12
  bytesToNumberLE,
14
- ensureBytes,
15
13
  numberToBytesBE,
16
14
  numberToBytesLE,
15
+ validateObject,
17
16
  } from '../utils.ts';
18
17
 
18
+ // Numbers aren't used in x25519 / x448 builds
19
19
  // prettier-ignore
20
- const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
20
+ const _0n = /* @__PURE__ */ BigInt(0), _1n = /* @__PURE__ */ BigInt(1), _2n = /* @__PURE__ */ BigInt(2);
21
21
  // prettier-ignore
22
- const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _7n = /* @__PURE__ */ BigInt(7);
22
+ const _3n = /* @__PURE__ */ BigInt(3), _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5);
23
23
  // prettier-ignore
24
- const _8n = /* @__PURE__ */ BigInt(8), _9n = /* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);
24
+ const _7n = /* @__PURE__ */ BigInt(7), _8n = /* @__PURE__ */ BigInt(8), _9n = /* @__PURE__ */ BigInt(9);
25
+ const _16n = /* @__PURE__ */ BigInt(16);
25
26
 
26
27
  // Calculates a modulo b
27
28
  export function mod(a: bigint, b: bigint): bigint {
@@ -227,10 +228,9 @@ export const isNegativeLE = (num: bigint, modulo: bigint): boolean =>
227
228
  /** Field is not always over prime: for example, Fp2 has ORDER(q)=p^m. */
228
229
  export interface IField<T> {
229
230
  ORDER: bigint;
230
- isLE: boolean;
231
231
  BYTES: number;
232
232
  BITS: number;
233
- MASK: bigint;
233
+ isLE: boolean;
234
234
  ZERO: T;
235
235
  ONE: T;
236
236
  // 1-arg
@@ -260,7 +260,6 @@ export interface IField<T> {
260
260
  // [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#section-4.1).
261
261
  // NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
262
262
  isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
263
- allowedLengths?: number[];
264
263
  // legendre?(num: T): T;
265
264
  invertBatch: (lst: T[]) => T[];
266
265
  toBytes(num: T): Uint8Array;
@@ -277,7 +276,6 @@ const FIELD_FIELDS = [
277
276
  export function validateField<T>(field: IField<T>): IField<T> {
278
277
  const initial = {
279
278
  ORDER: 'bigint',
280
- MASK: 'bigint',
281
279
  BYTES: 'number',
282
280
  BITS: 'number',
283
281
  } as Record<string, string>;
@@ -285,7 +283,7 @@ export function validateField<T>(field: IField<T>): IField<T> {
285
283
  map[val] = 'function';
286
284
  return map;
287
285
  }, initial);
288
- _validateObject(field, opts);
286
+ validateObject(field, opts);
289
287
  // const max = 16384;
290
288
  // if (field.BYTES < 1 || field.BYTES > max) throw new Error('invalid field');
291
289
  // if (field.BITS < 1 || field.BITS > 8 * max) throw new Error('invalid field');
@@ -381,12 +379,147 @@ export function nLength(n: bigint, nBitLength?: number): NLength {
381
379
  type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
382
380
  type SqrtFn = (n: bigint) => bigint;
383
381
  type FieldOpts = Partial<{
384
- sqrt: SqrtFn;
385
382
  isLE: boolean;
386
383
  BITS: number;
387
- modFromBytes: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
384
+ sqrt: SqrtFn;
388
385
  allowedLengths?: readonly number[]; // for P521 (adds padding for smaller sizes)
386
+ modFromBytes: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
389
387
  }>;
388
+ class _Field implements IField<bigint> {
389
+ readonly ORDER: bigint;
390
+ readonly BITS: number;
391
+ readonly BYTES: number;
392
+ readonly isLE: boolean;
393
+ readonly ZERO = _0n;
394
+ readonly ONE = _1n;
395
+ readonly _lengths?: number[];
396
+ private _sqrt: ReturnType<typeof FpSqrt> | undefined; // cached sqrt
397
+ private readonly _mod?: boolean;
398
+ constructor(ORDER: bigint, opts: FieldOpts = {}) {
399
+ if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
400
+ let _nbitLength: number | undefined = undefined;
401
+ this.isLE = false;
402
+ if (opts != null && typeof opts === 'object') {
403
+ if (typeof opts.BITS === 'number') _nbitLength = opts.BITS;
404
+ if (typeof opts.sqrt === 'function') this.sqrt = opts.sqrt;
405
+ if (typeof opts.isLE === 'boolean') this.isLE = opts.isLE;
406
+ if (opts.allowedLengths) this._lengths = opts.allowedLengths?.slice();
407
+ if (typeof opts.modFromBytes === 'boolean') this._mod = opts.modFromBytes;
408
+ }
409
+ const { nBitLength, nByteLength } = nLength(ORDER, _nbitLength);
410
+ if (nByteLength > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');
411
+ this.ORDER = ORDER;
412
+ this.BITS = nBitLength;
413
+ this.BYTES = nByteLength;
414
+ this._sqrt = undefined;
415
+ Object.preventExtensions(this);
416
+ }
417
+
418
+ create(num: bigint) {
419
+ return mod(num, this.ORDER);
420
+ }
421
+ isValid(num: bigint) {
422
+ if (typeof num !== 'bigint')
423
+ throw new Error('invalid field element: expected bigint, got ' + typeof num);
424
+ return _0n <= num && num < this.ORDER; // 0 is valid element, but it's not invertible
425
+ }
426
+ is0(num: bigint) {
427
+ return num === _0n;
428
+ }
429
+ // is valid and invertible
430
+ isValidNot0(num: bigint) {
431
+ return !this.is0(num) && this.isValid(num);
432
+ }
433
+ isOdd(num: bigint) {
434
+ return (num & _1n) === _1n;
435
+ }
436
+ neg(num: bigint) {
437
+ return mod(-num, this.ORDER);
438
+ }
439
+ eql(lhs: bigint, rhs: bigint) {
440
+ return lhs === rhs;
441
+ }
442
+
443
+ sqr(num: bigint) {
444
+ return mod(num * num, this.ORDER);
445
+ }
446
+ add(lhs: bigint, rhs: bigint) {
447
+ return mod(lhs + rhs, this.ORDER);
448
+ }
449
+ sub(lhs: bigint, rhs: bigint) {
450
+ return mod(lhs - rhs, this.ORDER);
451
+ }
452
+ mul(lhs: bigint, rhs: bigint) {
453
+ return mod(lhs * rhs, this.ORDER);
454
+ }
455
+ pow(num: bigint, power: bigint): bigint {
456
+ return FpPow(this, num, power);
457
+ }
458
+ div(lhs: bigint, rhs: bigint) {
459
+ return mod(lhs * invert(rhs, this.ORDER), this.ORDER);
460
+ }
461
+
462
+ // Same as above, but doesn't normalize
463
+ sqrN(num: bigint) {
464
+ return num * num;
465
+ }
466
+ addN(lhs: bigint, rhs: bigint) {
467
+ return lhs + rhs;
468
+ }
469
+ subN(lhs: bigint, rhs: bigint) {
470
+ return lhs - rhs;
471
+ }
472
+ mulN(lhs: bigint, rhs: bigint) {
473
+ return lhs * rhs;
474
+ }
475
+
476
+ inv(num: bigint) {
477
+ return invert(num, this.ORDER);
478
+ }
479
+ sqrt(num: bigint): bigint {
480
+ // Caching _sqrt speeds up sqrt9mod16 by 5x and tonneli-shanks by 10%
481
+ if (!this._sqrt) this._sqrt = FpSqrt(this.ORDER);
482
+ return this._sqrt(this, num);
483
+ }
484
+ toBytes(num: bigint) {
485
+ return this.isLE ? numberToBytesLE(num, this.BYTES) : numberToBytesBE(num, this.BYTES);
486
+ }
487
+ fromBytes(bytes: Uint8Array, skipValidation = false) {
488
+ abytes(bytes);
489
+ const { _lengths: allowedLengths, BYTES, isLE, ORDER, _mod: modFromBytes } = this;
490
+ if (allowedLengths) {
491
+ if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
492
+ throw new Error(
493
+ 'Field.fromBytes: expected ' + allowedLengths + ' bytes, got ' + bytes.length
494
+ );
495
+ }
496
+ const padded = new Uint8Array(BYTES);
497
+ // isLE add 0 to right, !isLE to the left.
498
+ padded.set(bytes, isLE ? 0 : padded.length - bytes.length);
499
+ bytes = padded;
500
+ }
501
+ if (bytes.length !== BYTES)
502
+ throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
503
+ let scalar = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
504
+ if (modFromBytes) scalar = mod(scalar, ORDER);
505
+ if (!skipValidation)
506
+ if (!this.isValid(scalar))
507
+ throw new Error('invalid field element: outside of range 0..ORDER');
508
+ // NOTE: we don't validate scalar here, please use isValid. This done such way because some
509
+ // protocol may allow non-reduced scalar that reduced later or changed some other way.
510
+ return scalar;
511
+ }
512
+ // TODO: we don't need it here, move out to separate fn
513
+ invertBatch(lst: bigint[]): bigint[] {
514
+ return FpInvertBatch(this, lst);
515
+ }
516
+ // We can't move this out because Fp6, Fp12 implement it
517
+ // and it's unclear what to return in there.
518
+ cmov(a: bigint, b: bigint, condition: boolean) {
519
+ return condition ? b : a;
520
+ }
521
+ }
522
+
390
523
  /**
391
524
  * Creates a finite field. Major performance optimizations:
392
525
  * * 1. Denormalized operations like mulN instead of mul.
@@ -406,104 +539,8 @@ type FieldOpts = Partial<{
406
539
  * @param isLE (default: false) if encoding / decoding should be in little-endian
407
540
  * @param redef optional faster redefinitions of sqrt and other methods
408
541
  */
409
- export function Field(
410
- ORDER: bigint,
411
- bitLenOrOpts?: number | FieldOpts, // TODO: use opts only in v2?
412
- isLE = false,
413
- opts: { sqrt?: SqrtFn } = {}
414
- ): Readonly<FpField> {
415
- if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
416
- let _nbitLength: number | undefined = undefined;
417
- let _sqrt: SqrtFn | undefined = undefined;
418
- let modFromBytes: 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.modFromBytes === 'boolean') modFromBytes = _opts.modFromBytes;
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);
433
- if (BYTES > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');
434
- let sqrtP: ReturnType<typeof FpSqrt>; // cached sqrtP
435
- const f: Readonly<FpField> = Object.freeze({
436
- ORDER,
437
- isLE,
438
- BITS,
439
- BYTES,
440
- MASK: bitMask(BITS),
441
- ZERO: _0n,
442
- ONE: _1n,
443
- allowedLengths: allowedLengths,
444
- create: (num) => mod(num, ORDER),
445
- isValid: (num) => {
446
- if (typeof num !== 'bigint')
447
- throw new Error('invalid field element: expected bigint, got ' + typeof num);
448
- return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
449
- },
450
- is0: (num) => num === _0n,
451
- // is valid and invertible
452
- isValidNot0: (num: bigint) => !f.is0(num) && f.isValid(num),
453
- isOdd: (num) => (num & _1n) === _1n,
454
- neg: (num) => mod(-num, ORDER),
455
- eql: (lhs, rhs) => lhs === rhs,
456
-
457
- sqr: (num) => mod(num * num, ORDER),
458
- add: (lhs, rhs) => mod(lhs + rhs, ORDER),
459
- sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
460
- mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
461
- pow: (num, power) => FpPow(f, num, power),
462
- div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
463
-
464
- // Same as above, but doesn't normalize
465
- sqrN: (num) => num * num,
466
- addN: (lhs, rhs) => lhs + rhs,
467
- subN: (lhs, rhs) => lhs - rhs,
468
- mulN: (lhs, rhs) => lhs * rhs,
469
-
470
- inv: (num) => invert(num, ORDER),
471
- sqrt:
472
- _sqrt ||
473
- ((n) => {
474
- if (!sqrtP) sqrtP = FpSqrt(ORDER);
475
- return sqrtP(f, n);
476
- }),
477
- toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, 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
- }
490
- if (bytes.length !== BYTES)
491
- throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
492
- let scalar = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
493
- if (modFromBytes) 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;
499
- },
500
- // TODO: we don't need it here, move out to separate fn
501
- invertBatch: (lst) => FpInvertBatch(f, lst),
502
- // We can't move this out because Fp6, Fp12 implement it
503
- // and it's unclear what to return in there.
504
- cmov: (a, b, c) => (c ? b : a),
505
- } as FpField);
506
- return Object.freeze(f);
542
+ export function Field(ORDER: bigint, opts: FieldOpts = {}): Readonly<FpField> {
543
+ return new _Field(ORDER, opts);
507
544
  }
508
545
 
509
546
  // Generic random scalar, we can do same for other fields if via Fp2.mul(Fp2.ONE, Fp2.random)?
@@ -532,28 +569,6 @@ export function FpSqrtEven<T>(Fp: IField<T>, elm: T): T {
532
569
  return Fp.isOdd(root) ? Fp.neg(root) : root;
533
570
  }
534
571
 
535
- /**
536
- * "Constant-time" private key generation utility.
537
- * Same as mapKeyToField, but accepts less bytes (40 instead of 48 for 32-byte field).
538
- * Which makes it slightly more biased, less secure.
539
- * @deprecated use `mapKeyToField` instead
540
- */
541
- export function hashToPrivateScalar(
542
- hash: string | Uint8Array,
543
- groupOrder: bigint,
544
- isLE = false
545
- ): bigint {
546
- hash = ensureBytes('privateHash', hash);
547
- const hashLen = hash.length;
548
- const minLen = nLength(groupOrder).nByteLength + 8;
549
- if (minLen < 24 || hashLen < minLen || hashLen > 1024)
550
- throw new Error(
551
- 'hashToPrivateScalar: expected ' + minLen + '-1024 bytes of input, got ' + hashLen
552
- );
553
- const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
554
- return mod(num, groupOrder - _1n) + _1n;
555
- }
556
-
557
572
  /**
558
573
  * Returns total number of bytes consumed by the field element.
559
574
  * For example, 32 bytes for usual 256-bit weierstrass curve.
@@ -587,11 +602,12 @@ export function getMinHashLength(fieldOrder: bigint): number {
587
602
  * FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final
588
603
  * RFC 9380, https://www.rfc-editor.org/rfc/rfc9380#section-5
589
604
  * @param hash hash output from SHA3 or a similar function
590
- * @param groupOrder size of subgroup - (e.g. secp256k1.CURVE.n)
605
+ * @param groupOrder size of subgroup - (e.g. secp256k1.Point.Fn.ORDER)
591
606
  * @param isLE interpret hash bytes as LE num
592
607
  * @returns valid private scalar
593
608
  */
594
609
  export function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE = false): Uint8Array {
610
+ abytes(key);
595
611
  const len = key.length;
596
612
  const fieldLen = getFieldBytesLength(fieldOrder);
597
613
  const minLen = getMinHashLength(fieldOrder);