@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
@@ -27,8 +27,9 @@ import {
27
27
  wNAF,
28
28
  type AffinePoint,
29
29
  type BasicCurve,
30
- type Group,
31
- type GroupConstructor,
30
+ type CurveInfo,
31
+ type CurvePoint,
32
+ type CurvePointCons,
32
33
  } from './curve.ts';
33
34
  import { Field, type IField, type NLength } from './modular.ts';
34
35
 
@@ -38,7 +39,7 @@ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _8n = BigInt(8);
38
39
 
39
40
  export type UVRatio = (u: bigint, v: bigint) => { isValid: boolean; value: bigint };
40
41
 
41
- /** Edwards curves must declare params a & d. */
42
+ // TODO: remove
42
43
  export type CurveType = BasicCurve<bigint> & {
43
44
  a: bigint; // curve param a
44
45
  d: bigint; // curve param d
@@ -51,45 +52,45 @@ export type CurveType = BasicCurve<bigint> & {
51
52
  mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>; // for hash-to-curve standard
52
53
  };
53
54
 
55
+ // TODO: remove
54
56
  export type CurveTypeWithLength = Readonly<CurveType & Partial<NLength>>;
55
57
 
56
- // verification rule is either zip215 or rfc8032 / nist186-5. Consult fromHex:
57
- const VERIFY_DEFAULT = { zip215: true };
58
-
59
58
  /** Instance of Extended Point with coordinates in X, Y, Z, T. */
60
- export interface ExtPointType extends Group<ExtPointType> {
61
- readonly ex: bigint;
62
- readonly ey: bigint;
63
- readonly ez: bigint;
64
- readonly et: bigint;
65
- get x(): bigint;
66
- get y(): bigint;
67
- assertValidity(): void;
68
- multiply(scalar: bigint): ExtPointType;
69
- multiplyUnsafe(scalar: bigint): ExtPointType;
70
- is0(): boolean;
71
- isSmallOrder(): boolean;
72
- isTorsionFree(): boolean;
73
- clearCofactor(): ExtPointType;
74
- toAffine(iz?: bigint): AffinePoint<bigint>;
75
- toBytes(): Uint8Array;
59
+ export interface EdwardsPoint extends CurvePoint<bigint, EdwardsPoint> {
60
+ /** extended X coordinate. Different from affine x. */
61
+ readonly X: bigint;
62
+ /** extended Y coordinate. Different from affine y. */
63
+ readonly Y: bigint;
64
+ /** extended Z coordinate */
65
+ readonly Z: bigint;
66
+ /** extended T coordinate */
67
+ readonly T: bigint;
68
+
76
69
  /** @deprecated use `toBytes` */
77
70
  toRawBytes(): Uint8Array;
78
- toHex(): string;
79
- precompute(windowSize?: number, isLazy?: boolean): ExtPointType;
80
71
  /** @deprecated use `p.precompute(windowSize)` */
81
72
  _setWindowSize(windowSize: number): void;
73
+ /** @deprecated use .X */
74
+ readonly ex: bigint;
75
+ /** @deprecated use .Y */
76
+ readonly ey: bigint;
77
+ /** @deprecated use .Z */
78
+ readonly ez: bigint;
79
+ /** @deprecated use .T */
80
+ readonly et: bigint;
82
81
  }
83
82
  /** Static methods of Extended Point with coordinates in X, Y, Z, T. */
84
- export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
85
- new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;
86
- Fp: IField<bigint>;
87
- Fn: IField<bigint>;
88
- fromAffine(p: AffinePoint<bigint>): ExtPointType;
89
- fromBytes(bytes: Uint8Array, zip215?: boolean): ExtPointType;
90
- fromHex(hex: Hex, zip215?: boolean): ExtPointType;
91
- msm(points: ExtPointType[], scalars: bigint[]): ExtPointType;
83
+ export interface EdwardsPointCons extends CurvePointCons<bigint, EdwardsPoint> {
84
+ new (X: bigint, Y: bigint, Z: bigint, T: bigint): EdwardsPoint;
85
+ fromBytes(bytes: Uint8Array, zip215?: boolean): EdwardsPoint;
86
+ fromHex(hex: Hex, zip215?: boolean): EdwardsPoint;
87
+ /** @deprecated use `import { pippenger } from '@noble/curves/abstract/curve.js';` */
88
+ msm(points: EdwardsPoint[], scalars: bigint[]): EdwardsPoint;
92
89
  }
90
+ /** @deprecated use EdwardsPoint */
91
+ export type ExtPointType = EdwardsPoint;
92
+ /** @deprecated use EdwardsPointCons */
93
+ export type ExtPointConstructor = EdwardsPointCons;
93
94
 
94
95
  /**
95
96
  * Twisted Edwards curve options.
@@ -103,11 +104,11 @@ export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
103
104
  * * Gy: y coordinate of generator point
104
105
  */
105
106
  export type EdwardsOpts = Readonly<{
106
- a: bigint;
107
- d: bigint;
108
107
  p: bigint;
109
108
  n: bigint;
110
109
  h: bigint;
110
+ a: bigint;
111
+ d: bigint;
111
112
  Gx: bigint;
112
113
  Gy: bigint;
113
114
  }>;
@@ -128,76 +129,90 @@ export type EdwardsExtraOpts = Partial<{
128
129
  /**
129
130
  * EdDSA (Edwards Digital Signature algorithm) options.
130
131
  *
131
- * * hash: hash function used to hash private keys and messages
132
+ * * hash: hash function used to hash secret keys and messages
132
133
  * * adjustScalarBytes: clears bits to get valid field element
133
134
  * * domain: Used for hashing
134
135
  * * mapToCurve: for hash-to-curve standard
135
136
  * * prehash: RFC 8032 pre-hashing of messages to sign() / verify()
136
- * * randomBytes: function generating random bytes, used for randomPrivateKey
137
+ * * randomBytes: function generating random bytes, used for randomSecretKey
137
138
  */
138
- export type EdDSAOpts = {
139
- hash: FHash;
140
- adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array;
141
- domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array;
142
- mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>;
143
- prehash?: FHash;
144
- randomBytes?: (bytesLength?: number) => Uint8Array;
145
- };
139
+ export type EdDSAOpts = Partial<{
140
+ adjustScalarBytes: (bytes: Uint8Array) => Uint8Array;
141
+ domain: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array;
142
+ mapToCurve: (scalar: bigint[]) => AffinePoint<bigint>;
143
+ prehash: FHash;
144
+ randomBytes: (bytesLength?: number) => Uint8Array;
145
+ }>;
146
146
 
147
147
  /**
148
148
  * EdDSA (Edwards Digital Signature algorithm) interface.
149
149
  *
150
- * Allows to create and verify signatures, create public and private keys.
150
+ * Allows to create and verify signatures, create public and secret keys.
151
151
  */
152
152
  export interface EdDSA {
153
- getPublicKey: (privateKey: Hex) => Uint8Array;
154
- sign: (message: Hex, privateKey: Hex, options?: { context?: Hex }) => Uint8Array;
153
+ keygen: (seed?: Uint8Array) => { secretKey: Uint8Array; publicKey: Uint8Array };
154
+ getPublicKey: (secretKey: Hex) => Uint8Array;
155
+ sign: (message: Hex, secretKey: Hex, options?: { context?: Hex }) => Uint8Array;
155
156
  verify: (
156
157
  sig: Hex,
157
158
  message: Hex,
158
159
  publicKey: Hex,
159
160
  options?: { context?: Hex; zip215: boolean }
160
161
  ) => boolean;
161
- Point: ExtPointConstructor;
162
+ Point: EdwardsPointCons;
162
163
  utils: {
163
- randomPrivateKey: () => Uint8Array;
164
+ randomSecretKey: (seed?: Uint8Array) => Uint8Array;
165
+ isValidSecretKey: (secretKey: Uint8Array) => boolean;
166
+ isValidPublicKey: (publicKey: Uint8Array, zip215?: boolean) => boolean;
167
+
168
+ /**
169
+ * Converts ed public key to x public key.
170
+ * @example
171
+ * ```js
172
+ * const someonesPub = ed25519.getPublicKey(ed25519.utils.randomSecretKey());
173
+ * const aPriv = x25519.utils.randomSecretKey();
174
+ * x25519.getSharedSecret(aPriv, ed25519.utils.toMontgomery(someonesPub))
175
+ * ```
176
+ */
177
+ toMontgomery: (publicKey: Uint8Array) => Uint8Array;
178
+ /**
179
+ * Converts ed secret key to x secret key.
180
+ * @example
181
+ * ```js
182
+ * const someonesPub = x25519.getPublicKey(x25519.utils.randomSecretKey());
183
+ * const aPriv = ed25519.utils.randomSecretKey();
184
+ * x25519.getSharedSecret(ed25519.utils.toMontgomeryPriv(aPriv), someonesPub)
185
+ * ```
186
+ */
187
+ toMontgomeryPriv: (privateKey: Uint8Array) => Uint8Array;
164
188
  getExtendedPublicKey: (key: Hex) => {
165
189
  head: Uint8Array;
166
190
  prefix: Uint8Array;
167
191
  scalar: bigint;
168
- point: ExtPointType;
192
+ point: EdwardsPoint;
169
193
  pointBytes: Uint8Array;
170
194
  };
195
+
196
+ /** @deprecated use `randomSecretKey` */
197
+ randomPrivateKey: (seed?: Uint8Array) => Uint8Array;
171
198
  /** @deprecated use `point.precompute()` */
172
- precompute: (windowSize?: number, point?: ExtPointType) => ExtPointType;
199
+ precompute: (windowSize?: number, point?: EdwardsPoint) => EdwardsPoint;
173
200
  };
201
+ info: CurveInfo;
174
202
  }
175
203
 
176
204
  // Legacy params. TODO: remove
177
205
  export type CurveFn = {
178
206
  CURVE: CurveType;
179
- getPublicKey: (privateKey: Hex) => Uint8Array;
180
- sign: (message: Hex, privateKey: Hex, options?: { context?: Hex }) => Uint8Array;
181
- verify: (
182
- sig: Hex,
183
- message: Hex,
184
- publicKey: Hex,
185
- options?: { context?: Hex; zip215: boolean }
186
- ) => boolean;
187
- Point: ExtPointConstructor;
207
+ keygen: EdDSA['keygen'];
208
+ getPublicKey: EdDSA['getPublicKey'];
209
+ sign: EdDSA['sign'];
210
+ verify: EdDSA['verify'];
211
+ Point: EdwardsPointCons;
188
212
  /** @deprecated use `Point` */
189
- ExtendedPoint: ExtPointConstructor;
190
- utils: {
191
- randomPrivateKey: () => Uint8Array;
192
- getExtendedPublicKey: (key: Hex) => {
193
- head: Uint8Array;
194
- prefix: Uint8Array;
195
- scalar: bigint;
196
- point: ExtPointType;
197
- pointBytes: Uint8Array;
198
- };
199
- precompute: (windowSize?: number, point?: ExtPointType) => ExtPointType;
200
- };
213
+ ExtendedPoint: EdwardsPointCons;
214
+ utils: EdDSA['utils'];
215
+ info: CurveInfo;
201
216
  };
202
217
 
203
218
  function isEdValidXY(Fp: IField<bigint>, CURVE: EdwardsOpts, x: bigint, y: bigint): boolean {
@@ -208,7 +223,7 @@ function isEdValidXY(Fp: IField<bigint>, CURVE: EdwardsOpts, x: bigint, y: bigin
208
223
  return Fp.eql(left, right);
209
224
  }
210
225
 
211
- export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): ExtPointConstructor {
226
+ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): EdwardsPointCons {
212
227
  const { Fp, Fn } = _createCurveFields('edwards', CURVE, curveOpts);
213
228
  const { h: cofactor, n: CURVE_ORDER } = CURVE;
214
229
  _validateObject(curveOpts, {}, { uvRatio: 'function' });
@@ -252,22 +267,22 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
252
267
  // Converts Extended point to default (x, y) coordinates.
253
268
  // Can accept precomputed Z^-1 - for example, from invertBatch.
254
269
  const toAffineMemo = memoized((p: Point, iz?: bigint): AffinePoint<bigint> => {
255
- const { ex: x, ey: y, ez: z } = p;
270
+ const { X, Y, Z } = p;
256
271
  const is0 = p.is0();
257
- if (iz == null) iz = is0 ? _8n : (Fp.inv(z) as bigint); // 8 was chosen arbitrarily
258
- const ax = modP(x * iz);
259
- const ay = modP(y * iz);
260
- const zz = modP(z * iz);
272
+ if (iz == null) iz = is0 ? _8n : (Fp.inv(Z) as bigint); // 8 was chosen arbitrarily
273
+ const x = modP(X * iz);
274
+ const y = modP(Y * iz);
275
+ const zz = Fp.mul(Z, iz);
261
276
  if (is0) return { x: _0n, y: _1n };
262
277
  if (zz !== _1n) throw new Error('invZ was invalid');
263
- return { x: ax, y: ay };
278
+ return { x, y };
264
279
  });
265
280
  const assertValidMemo = memoized((p: Point) => {
266
281
  const { a, d } = CURVE;
267
282
  if (p.is0()) throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?
268
283
  // Equation in affine coordinates: ax² + y² = 1 + dx²y²
269
284
  // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
270
- const { ex: X, ey: Y, ez: Z, et: T } = p;
285
+ const { X, Y, Z, T } = p;
271
286
  const X2 = modP(X * X); // X²
272
287
  const Y2 = modP(Y * Y); // Y²
273
288
  const Z2 = modP(Z * Z); // Z²
@@ -285,7 +300,7 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
285
300
 
286
301
  // Extended Point works in extended coordinates: (X, Y, Z, T) ∋ (x=X/Z, y=Y/Z, T=xy).
287
302
  // https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
288
- class Point implements ExtPointType {
303
+ class Point implements EdwardsPoint {
289
304
  // base / generator point
290
305
  static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
291
306
  // zero / infinity / identity point
@@ -294,16 +309,16 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
294
309
  static readonly Fp = Fp;
295
310
  static readonly Fn = Fn;
296
311
 
297
- readonly ex: bigint;
298
- readonly ey: bigint;
299
- readonly ez: bigint;
300
- readonly et: bigint;
312
+ readonly X: bigint;
313
+ readonly Y: bigint;
314
+ readonly Z: bigint;
315
+ readonly T: bigint;
301
316
 
302
- constructor(ex: bigint, ey: bigint, ez: bigint, et: bigint) {
303
- this.ex = acoord('x', ex);
304
- this.ey = acoord('y', ey);
305
- this.ez = acoord('z', ez, true);
306
- this.et = acoord('t', et);
317
+ constructor(X: bigint, Y: bigint, Z: bigint, T: bigint) {
318
+ this.X = acoord('x', X);
319
+ this.Y = acoord('y', Y);
320
+ this.Z = acoord('z', Z, true);
321
+ this.T = acoord('t', T);
307
322
  Object.freeze(this);
308
323
  }
309
324
 
@@ -314,32 +329,44 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
314
329
  return this.toAffine().y;
315
330
  }
316
331
 
317
- static fromAffine(p: AffinePoint<bigint>): Point {
318
- if (p instanceof Point) throw new Error('extended point not allowed');
319
- const { x, y } = p || {};
320
- acoord('x', x);
321
- acoord('y', y);
322
- return new Point(x, y, _1n, modP(x * y));
332
+ // TODO: remove
333
+ get ex(): bigint {
334
+ return this.X;
335
+ }
336
+ get ey(): bigint {
337
+ return this.Y;
338
+ }
339
+ get ez(): bigint {
340
+ return this.Z;
341
+ }
342
+ get et(): bigint {
343
+ return this.T;
323
344
  }
324
345
  static normalizeZ(points: Point[]): Point[] {
325
- return normalizeZ(Point, 'ez', points);
346
+ return normalizeZ(Point, points);
326
347
  }
327
- // Multiscalar Multiplication
328
348
  static msm(points: Point[], scalars: bigint[]): Point {
329
349
  return pippenger(Point, Fn, points, scalars);
330
350
  }
331
-
332
- // "Private method", don't use it directly
333
351
  _setWindowSize(windowSize: number) {
334
352
  this.precompute(windowSize);
335
353
  }
354
+
355
+ static fromAffine(p: AffinePoint<bigint>): Point {
356
+ if (p instanceof Point) throw new Error('extended point not allowed');
357
+ const { x, y } = p || {};
358
+ acoord('x', x);
359
+ acoord('y', y);
360
+ return new Point(x, y, _1n, modP(x * y));
361
+ }
362
+
336
363
  precompute(windowSize: number = 8, isLazy = true) {
337
- wnaf.setWindowSize(this, windowSize);
364
+ wnaf.createCache(this, windowSize);
338
365
  if (!isLazy) this.multiply(_2n); // random number
339
366
  return this;
340
367
  }
341
- // Not required for fromHex(), which always creates valid points.
342
- // Could be useful for fromAffine().
368
+
369
+ // Useful in fromAffine() - not for fromBytes(), which always created valid points.
343
370
  assertValidity(): void {
344
371
  assertValidMemo(this);
345
372
  }
@@ -347,8 +374,8 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
347
374
  // Compare one point to another.
348
375
  equals(other: Point): boolean {
349
376
  aextpoint(other);
350
- const { ex: X1, ey: Y1, ez: Z1 } = this;
351
- const { ex: X2, ey: Y2, ez: Z2 } = other;
377
+ const { X: X1, Y: Y1, Z: Z1 } = this;
378
+ const { X: X2, Y: Y2, Z: Z2 } = other;
352
379
  const X1Z2 = modP(X1 * Z2);
353
380
  const X2Z1 = modP(X2 * Z1);
354
381
  const Y1Z2 = modP(Y1 * Z2);
@@ -362,7 +389,7 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
362
389
 
363
390
  negate(): Point {
364
391
  // Flips point sign to a negative one (-x, y in affine coords)
365
- return new Point(modP(-this.ex), this.ey, this.ez, modP(-this.et));
392
+ return new Point(modP(-this.X), this.Y, this.Z, modP(-this.T));
366
393
  }
367
394
 
368
395
  // Fast algo for doubling Extended Point.
@@ -370,7 +397,7 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
370
397
  // Cost: 4M + 4S + 1*a + 6add + 1*2.
371
398
  double(): Point {
372
399
  const { a } = CURVE;
373
- const { ex: X1, ey: Y1, ez: Z1 } = this;
400
+ const { X: X1, Y: Y1, Z: Z1 } = this;
374
401
  const A = modP(X1 * X1); // A = X12
375
402
  const B = modP(Y1 * Y1); // B = Y12
376
403
  const C = modP(_2n * modP(Z1 * Z1)); // C = 2*Z12
@@ -393,8 +420,8 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
393
420
  add(other: Point) {
394
421
  aextpoint(other);
395
422
  const { a, d } = CURVE;
396
- const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
397
- const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other;
423
+ const { X: X1, Y: Y1, Z: Z1, T: T1 } = this;
424
+ const { X: X2, Y: Y2, Z: Z2, T: T2 } = other;
398
425
  const A = modP(X1 * X2); // A = X1*X2
399
426
  const B = modP(Y1 * Y2); // B = Y1*Y2
400
427
  const C = modP(T1 * d * T2); // C = T1*d*T2
@@ -418,8 +445,8 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
418
445
  multiply(scalar: bigint): Point {
419
446
  const n = scalar;
420
447
  aInRange('scalar', n, _1n, CURVE_ORDER); // 1 <= scalar < L
421
- const { p, f } = wnaf.wNAFCached(this, n, Point.normalizeZ);
422
- return Point.normalizeZ([p, f])[0];
448
+ const { p, f } = wnaf.cached(this, n, (p) => normalizeZ(Point, p));
449
+ return normalizeZ(Point, [p, f])[0];
423
450
  }
424
451
 
425
452
  // Non-constant-time multiplication. Uses double-and-add algorithm.
@@ -432,7 +459,7 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
432
459
  aInRange('scalar', n, _0n, CURVE_ORDER); // 0 <= scalar < L
433
460
  if (n === _0n) return Point.ZERO;
434
461
  if (this.is0() || n === _1n) return this;
435
- return wnaf.wNAFCachedUnsafe(this, n, Point.normalizeZ, acc);
462
+ return wnaf.unsafe(this, n, (p) => normalizeZ(Point, p), acc);
436
463
  }
437
464
 
438
465
  // Checks if point is of small order.
@@ -446,7 +473,7 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
446
473
  // Multiplies point by curve order and checks if the result is 0.
447
474
  // Returns `false` is the point is dirty.
448
475
  isTorsionFree(): boolean {
449
- return wnaf.wNAFCachedUnsafe(this, CURVE_ORDER).is0();
476
+ return wnaf.unsafe(this, CURVE_ORDER).is0();
450
477
  }
451
478
 
452
479
  // Converts Extended point to default (x, y) coordinates.
@@ -462,7 +489,7 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
462
489
 
463
490
  static fromBytes(bytes: Uint8Array, zip215 = false): Point {
464
491
  abytes(bytes);
465
- return this.fromHex(bytes, zip215);
492
+ return Point.fromHex(bytes, zip215);
466
493
  }
467
494
 
468
495
  // Converts hash string or Uint8Array to Point.
@@ -499,9 +526,6 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
499
526
  if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x
500
527
  return Point.fromAffine({ x, y });
501
528
  }
502
- static fromPrivateScalar(scalar: bigint): Point {
503
- return Point.BASE.multiply(scalar);
504
- }
505
529
  toBytes(): Uint8Array {
506
530
  const { x, y } = this.toAffine();
507
531
  const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
@@ -520,19 +544,128 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
520
544
  return `<Point ${this.is0() ? 'ZERO' : this.toHex()}>`;
521
545
  }
522
546
  }
523
- const wnaf = wNAF(Point, Fn.BYTES * 8); // Fn.BITS?
547
+ const wnaf = new wNAF(Point, Fn.BYTES * 8); // Fn.BITS?
524
548
  return Point;
525
549
  }
526
550
 
551
+ /**
552
+ * Base class for prime-order points like Ristretto255 and Decaf448.
553
+ * These points eliminate cofactor issues by representing equivalence classes
554
+ * of Edwards curve points.
555
+ */
556
+ export abstract class PrimeEdwardsPoint<T extends PrimeEdwardsPoint<T>>
557
+ implements CurvePoint<bigint, T>
558
+ {
559
+ static BASE: PrimeEdwardsPoint<any>;
560
+ static ZERO: PrimeEdwardsPoint<any>;
561
+ static Fp: IField<bigint>;
562
+ static Fn: IField<bigint>;
563
+
564
+ protected readonly ep: EdwardsPoint;
565
+
566
+ constructor(ep: EdwardsPoint) {
567
+ this.ep = ep;
568
+ }
569
+
570
+ // Abstract methods that must be implemented by subclasses
571
+ abstract toBytes(): Uint8Array;
572
+ abstract equals(other: T): boolean;
573
+
574
+ // Static methods that must be implemented by subclasses
575
+ static fromBytes(_bytes: Uint8Array): any {
576
+ throw new Error('fromBytes must be implemented by subclass');
577
+ }
578
+
579
+ static fromHex(_hex: Hex): any {
580
+ throw new Error('fromHex must be implemented by subclass');
581
+ }
582
+
583
+ get x(): bigint {
584
+ return this.toAffine().x;
585
+ }
586
+ get y(): bigint {
587
+ return this.toAffine().y;
588
+ }
589
+
590
+ // Common implementations
591
+ clearCofactor(): T {
592
+ // no-op for prime-order groups
593
+ return this as any;
594
+ }
595
+
596
+ assertValidity(): void {
597
+ this.ep.assertValidity();
598
+ }
599
+
600
+ toAffine(invertedZ?: bigint): AffinePoint<bigint> {
601
+ return this.ep.toAffine(invertedZ);
602
+ }
603
+
604
+ /** @deprecated use `toBytes` */
605
+ toRawBytes(): Uint8Array {
606
+ return this.toBytes();
607
+ }
608
+
609
+ toHex(): string {
610
+ return bytesToHex(this.toBytes());
611
+ }
612
+
613
+ toString(): string {
614
+ return this.toHex();
615
+ }
616
+
617
+ isTorsionFree(): boolean {
618
+ return true;
619
+ }
620
+
621
+ isSmallOrder(): boolean {
622
+ return false;
623
+ }
624
+
625
+ add(other: T): T {
626
+ this.assertSame(other);
627
+ return this.init(this.ep.add(other.ep));
628
+ }
629
+
630
+ subtract(other: T): T {
631
+ this.assertSame(other);
632
+ return this.init(this.ep.subtract(other.ep));
633
+ }
634
+
635
+ multiply(scalar: bigint): T {
636
+ return this.init(this.ep.multiply(scalar));
637
+ }
638
+
639
+ multiplyUnsafe(scalar: bigint): T {
640
+ return this.init(this.ep.multiplyUnsafe(scalar));
641
+ }
642
+
643
+ double(): T {
644
+ return this.init(this.ep.double());
645
+ }
646
+
647
+ negate(): T {
648
+ return this.init(this.ep.negate());
649
+ }
650
+
651
+ precompute(windowSize?: number, isLazy?: boolean): T {
652
+ return this.init(this.ep.precompute(windowSize, isLazy));
653
+ }
654
+
655
+ // Helper methods
656
+ abstract is0(): boolean;
657
+ protected abstract assertSame(other: T): void;
658
+ protected abstract init(ep: EdwardsPoint): T;
659
+ }
660
+
527
661
  /**
528
662
  * Initializes EdDSA signatures over given Edwards curve.
529
663
  */
530
- export function eddsa(Point: ExtPointConstructor, eddsaOpts: EdDSAOpts): EdDSA {
664
+ export function eddsa(Point: EdwardsPointCons, cHash: FHash, eddsaOpts: EdDSAOpts): EdDSA {
665
+ if (typeof cHash !== 'function') throw new Error('"hash" function param is required');
531
666
  _validateObject(
532
667
  eddsaOpts,
533
- {
534
- hash: 'function',
535
- },
668
+ {},
536
669
  {
537
670
  adjustScalarBytes: 'function',
538
671
  randomBytes: 'function',
@@ -542,7 +675,7 @@ export function eddsa(Point: ExtPointConstructor, eddsaOpts: EdDSAOpts): EdDSA {
542
675
  }
543
676
  );
544
677
 
545
- const { prehash, hash: cHash } = eddsaOpts;
678
+ const { prehash } = eddsaOpts;
546
679
  const { BASE: G, Fp, Fn } = Point;
547
680
  const CURVE_ORDER = Fn.ORDER;
548
681
 
@@ -559,6 +692,7 @@ export function eddsa(Point: ExtPointConstructor, eddsaOpts: EdDSAOpts): EdDSA {
559
692
  function modN(a: bigint) {
560
693
  return Fn.create(a);
561
694
  }
695
+
562
696
  // Little-endian SHA512 with modulo n
563
697
  function modN_LE(hash: Uint8Array): bigint {
564
698
  // Not using Fn.fromBytes: hash can be 2*Fn.BYTES
@@ -578,17 +712,17 @@ export function eddsa(Point: ExtPointConstructor, eddsaOpts: EdDSAOpts): EdDSA {
578
712
  return { head, prefix, scalar };
579
713
  }
580
714
 
581
- // Convenience method that creates public key from scalar. RFC8032 5.1.5
582
- function getExtendedPublicKey(key: Hex) {
583
- const { head, prefix, scalar } = getPrivateScalar(key);
715
+ /** Convenience method that creates public key from scalar. RFC8032 5.1.5 */
716
+ function getExtendedPublicKey(secretKey: Hex) {
717
+ const { head, prefix, scalar } = getPrivateScalar(secretKey);
584
718
  const point = G.multiply(scalar); // Point on Edwards curve aka public key
585
719
  const pointBytes = point.toBytes();
586
720
  return { head, prefix, scalar, point, pointBytes };
587
721
  }
588
722
 
589
- // Calculates EdDSA pub key. RFC8032 5.1.5. Privkey is hashed. Use first half with 3 bits cleared
590
- function getPublicKey(privKey: Hex): Uint8Array {
591
- return getExtendedPublicKey(privKey).pointBytes;
723
+ /** Calculates EdDSA pub key. RFC8032 5.1.5. */
724
+ function getPublicKey(secretKey: Hex): Uint8Array {
725
+ return getExtendedPublicKey(secretKey).pointBytes;
592
726
  }
593
727
 
594
728
  // int('LE', SHA512(dom2(F, C) || msgs)) mod N
@@ -598,10 +732,10 @@ export function eddsa(Point: ExtPointConstructor, eddsaOpts: EdDSAOpts): EdDSA {
598
732
  }
599
733
 
600
734
  /** Signs message with privateKey. RFC8032 5.1.6 */
601
- function sign(msg: Hex, privKey: Hex, options: { context?: Hex } = {}): Uint8Array {
735
+ function sign(msg: Hex, secretKey: Hex, options: { context?: Hex } = {}): Uint8Array {
602
736
  msg = ensureBytes('message', msg);
603
737
  if (prehash) msg = prehash(msg); // for ed25519ph etc.
604
- const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
738
+ const { prefix, scalar, pointBytes } = getExtendedPublicKey(secretKey);
605
739
  const r = hashDomainToScalar(options.context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
606
740
  const R = G.multiply(r).toBytes(); // R = rG
607
741
  const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)
@@ -612,7 +746,8 @@ export function eddsa(Point: ExtPointConstructor, eddsaOpts: EdDSAOpts): EdDSA {
612
746
  return ensureBytes('result', res, L * 2); // 64-byte signature
613
747
  }
614
748
 
615
- const verifyOpts: { context?: Hex; zip215?: boolean } = VERIFY_DEFAULT;
749
+ // verification rule is either zip215 or rfc8032 / nist186-5. Consult fromHex:
750
+ const verifyOpts: { context?: Hex; zip215?: boolean } = { zip215: true };
616
751
 
617
752
  /**
618
753
  * Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
@@ -650,10 +785,54 @@ export function eddsa(Point: ExtPointConstructor, eddsaOpts: EdDSAOpts): EdDSA {
650
785
 
651
786
  G.precompute(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
652
787
 
788
+ const size = Fp.BYTES;
789
+ const lengths = {
790
+ secret: size,
791
+ public: size,
792
+ signature: 2 * size,
793
+ seed: size,
794
+ };
795
+ function randomSecretKey(seed = randomBytes_!(lengths.seed)): Uint8Array {
796
+ return seed;
797
+ }
798
+
653
799
  const utils = {
654
800
  getExtendedPublicKey,
655
801
  /** ed25519 priv keys are uniform 32b. No need to check for modulo bias, like in secp256k1. */
656
- randomPrivateKey: (): Uint8Array => randomBytes_!(Fp.BYTES),
802
+ randomSecretKey,
803
+
804
+ isValidSecretKey,
805
+ isValidPublicKey,
806
+
807
+ randomPrivateKey: randomSecretKey,
808
+
809
+ /**
810
+ * Converts ed public key to x public key. Uses formula:
811
+ * - ed25519:
812
+ * - `(u, v) = ((1+y)/(1-y), sqrt(-486664)*u/x)`
813
+ * - `(x, y) = (sqrt(-486664)*u/v, (u-1)/(u+1))`
814
+ * - ed448:
815
+ * - `(u, v) = ((y-1)/(y+1), sqrt(156324)*u/x)`
816
+ * - `(x, y) = (sqrt(156324)*u/v, (1+u)/(1-u))`
817
+ *
818
+ * There is NO `fromMontgomery`:
819
+ * - There are 2 valid ed25519 points for every x25519, with flipped coordinate
820
+ * - Sometimes there are 0 valid ed25519 points, because x25519 *additionally*
821
+ * accepts inputs on the quadratic twist, which can't be moved to ed25519
822
+ */
823
+ toMontgomery(publicKey: Uint8Array): Uint8Array {
824
+ const { y } = Point.fromBytes(publicKey);
825
+ const is25519 = size === 32;
826
+ if (!is25519 && size !== 57) throw new Error('only defined for 25519 and 448');
827
+ const u = is25519 ? Fp.div(_1n + y, _1n - y) : Fp.div(y - _1n, y + _1n);
828
+ return Fp.toBytes(u);
829
+ },
830
+
831
+ toMontgomeryPriv(privateKey: Uint8Array): Uint8Array {
832
+ abytes(privateKey, size);
833
+ const hashed = cHash(privateKey.subarray(0, size));
834
+ return adjustScalarBytes(hashed).subarray(0, size);
835
+ },
657
836
 
658
837
  /**
659
838
  * We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
@@ -661,19 +840,51 @@ export function eddsa(Point: ExtPointConstructor, eddsaOpts: EdDSAOpts): EdDSA {
661
840
  * but allows to speed-up subsequent getPublicKey() calls up to 20x.
662
841
  * @param windowSize 2, 4, 8, 16
663
842
  */
664
- precompute(windowSize = 8, point: ExtPointType = Point.BASE): ExtPointType {
843
+ precompute(windowSize = 8, point: EdwardsPoint = Point.BASE): EdwardsPoint {
665
844
  return point.precompute(windowSize, false);
666
845
  },
667
846
  };
668
847
 
669
- return { getPublicKey, sign, verify, utils, Point };
848
+ function keygen(seed?: Uint8Array) {
849
+ const secretKey = utils.randomSecretKey(seed);
850
+ return { secretKey, publicKey: getPublicKey(secretKey) };
851
+ }
852
+
853
+ function isValidSecretKey(key: Uint8Array): boolean {
854
+ try {
855
+ return !!Fn.fromBytes(key, false);
856
+ } catch (error) {
857
+ return false;
858
+ }
859
+ }
860
+
861
+ function isValidPublicKey(key: Uint8Array, zip215?: boolean): boolean {
862
+ try {
863
+ return !!Point.fromBytes(key, zip215);
864
+ } catch (error) {
865
+ return false;
866
+ }
867
+ }
868
+
869
+ return Object.freeze({
870
+ keygen,
871
+ getPublicKey,
872
+ sign,
873
+ verify,
874
+ utils,
875
+ Point,
876
+ info: { type: 'edwards' as const, lengths },
877
+ });
670
878
  }
671
879
 
880
+ // TODO: remove
672
881
  export type EdComposed = {
673
882
  CURVE: EdwardsOpts;
674
883
  curveOpts: EdwardsExtraOpts;
884
+ hash: FHash;
675
885
  eddsaOpts: EdDSAOpts;
676
886
  };
887
+ // TODO: remove
677
888
  function _eddsa_legacy_opts_to_new(c: CurveTypeWithLength): EdComposed {
678
889
  const CURVE: EdwardsOpts = {
679
890
  a: c.a,
@@ -688,23 +899,23 @@ function _eddsa_legacy_opts_to_new(c: CurveTypeWithLength): EdComposed {
688
899
  const Fn = Field(CURVE.n, c.nBitLength, true);
689
900
  const curveOpts: EdwardsExtraOpts = { Fp, Fn, uvRatio: c.uvRatio };
690
901
  const eddsaOpts: EdDSAOpts = {
691
- hash: c.hash,
692
902
  randomBytes: c.randomBytes,
693
903
  adjustScalarBytes: c.adjustScalarBytes,
694
904
  domain: c.domain,
695
905
  prehash: c.prehash,
696
906
  mapToCurve: c.mapToCurve,
697
907
  };
698
- return { CURVE, curveOpts, eddsaOpts };
908
+ return { CURVE, curveOpts, hash: c.hash, eddsaOpts };
699
909
  }
910
+ // TODO: remove
700
911
  function _eddsa_new_output_to_legacy(c: CurveTypeWithLength, eddsa: EdDSA): CurveFn {
701
912
  const legacy = Object.assign({}, eddsa, { ExtendedPoint: eddsa.Point, CURVE: c });
702
913
  return legacy;
703
914
  }
704
915
  // TODO: remove. Use eddsa
705
916
  export function twistedEdwards(c: CurveTypeWithLength): CurveFn {
706
- const { CURVE, curveOpts, eddsaOpts } = _eddsa_legacy_opts_to_new(c);
917
+ const { CURVE, curveOpts, hash, eddsaOpts } = _eddsa_legacy_opts_to_new(c);
707
918
  const Point = edwards(CURVE, curveOpts);
708
- const EDDSA = eddsa(Point, eddsaOpts);
919
+ const EDDSA = eddsa(Point, hash, eddsaOpts);
709
920
  return _eddsa_new_output_to_legacy(c, EDDSA);
710
921
  }