@noble/curves 1.9.0 → 1.9.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 (207) hide show
  1. package/README.md +78 -34
  2. package/_shortw_utils.d.ts +7 -5
  3. package/_shortw_utils.d.ts.map +1 -1
  4. package/_shortw_utils.js +2 -8
  5. package/_shortw_utils.js.map +1 -1
  6. package/abstract/bls.d.ts +60 -24
  7. package/abstract/bls.d.ts.map +1 -1
  8. package/abstract/bls.js +158 -109
  9. package/abstract/bls.js.map +1 -1
  10. package/abstract/curve.d.ts +44 -9
  11. package/abstract/curve.d.ts.map +1 -1
  12. package/abstract/curve.js +99 -11
  13. package/abstract/curve.js.map +1 -1
  14. package/abstract/edwards.d.ts +112 -25
  15. package/abstract/edwards.d.ts.map +1 -1
  16. package/abstract/edwards.js +141 -92
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/fft.d.ts +122 -0
  19. package/abstract/fft.d.ts.map +1 -0
  20. package/abstract/fft.js +438 -0
  21. package/abstract/fft.js.map +1 -0
  22. package/abstract/hash-to-curve.d.ts +25 -11
  23. package/abstract/hash-to-curve.d.ts.map +1 -1
  24. package/abstract/hash-to-curve.js +17 -14
  25. package/abstract/hash-to-curve.js.map +1 -1
  26. package/abstract/modular.d.ts +28 -17
  27. package/abstract/modular.d.ts.map +1 -1
  28. package/abstract/modular.js +156 -139
  29. package/abstract/modular.js.map +1 -1
  30. package/abstract/montgomery.d.ts +3 -8
  31. package/abstract/montgomery.d.ts.map +1 -1
  32. package/abstract/montgomery.js +73 -93
  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 +20 -46
  39. package/abstract/tower.d.ts.map +1 -1
  40. package/abstract/tower.js +10 -4
  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 +152 -73
  47. package/abstract/weierstrass.d.ts.map +1 -1
  48. package/abstract/weierstrass.js +487 -404
  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 -480
  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 +25 -9
  59. package/ed25519.d.ts.map +1 -1
  60. package/ed25519.js +89 -65
  61. package/ed25519.js.map +1 -1
  62. package/ed448.d.ts +29 -10
  63. package/ed448.d.ts.map +1 -1
  64. package/ed448.js +116 -81
  65. package/ed448.js.map +1 -1
  66. package/esm/_shortw_utils.d.ts +7 -5
  67. package/esm/_shortw_utils.d.ts.map +1 -1
  68. package/esm/_shortw_utils.js +2 -8
  69. package/esm/_shortw_utils.js.map +1 -1
  70. package/esm/abstract/bls.d.ts +60 -24
  71. package/esm/abstract/bls.d.ts.map +1 -1
  72. package/esm/abstract/bls.js +158 -109
  73. package/esm/abstract/bls.js.map +1 -1
  74. package/esm/abstract/curve.d.ts +44 -9
  75. package/esm/abstract/curve.d.ts.map +1 -1
  76. package/esm/abstract/curve.js +96 -12
  77. package/esm/abstract/curve.js.map +1 -1
  78. package/esm/abstract/edwards.d.ts +112 -25
  79. package/esm/abstract/edwards.d.ts.map +1 -1
  80. package/esm/abstract/edwards.js +141 -94
  81. package/esm/abstract/edwards.js.map +1 -1
  82. package/esm/abstract/fft.d.ts +122 -0
  83. package/esm/abstract/fft.d.ts.map +1 -0
  84. package/esm/abstract/fft.js +425 -0
  85. package/esm/abstract/fft.js.map +1 -0
  86. package/esm/abstract/hash-to-curve.d.ts +25 -11
  87. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  88. package/esm/abstract/hash-to-curve.js +17 -14
  89. package/esm/abstract/hash-to-curve.js.map +1 -1
  90. package/esm/abstract/modular.d.ts +28 -17
  91. package/esm/abstract/modular.d.ts.map +1 -1
  92. package/esm/abstract/modular.js +155 -138
  93. package/esm/abstract/modular.js.map +1 -1
  94. package/esm/abstract/montgomery.d.ts +3 -8
  95. package/esm/abstract/montgomery.d.ts.map +1 -1
  96. package/esm/abstract/montgomery.js +74 -94
  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 +20 -46
  103. package/esm/abstract/tower.d.ts.map +1 -1
  104. package/esm/abstract/tower.js +10 -4
  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 +152 -73
  111. package/esm/abstract/weierstrass.d.ts.map +1 -1
  112. package/esm/abstract/weierstrass.js +485 -406
  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 -479
  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 +25 -9
  123. package/esm/ed25519.d.ts.map +1 -1
  124. package/esm/ed25519.js +84 -60
  125. package/esm/ed25519.js.map +1 -1
  126. package/esm/ed448.d.ts +29 -10
  127. package/esm/ed448.d.ts.map +1 -1
  128. package/esm/ed448.js +113 -78
  129. package/esm/ed448.js.map +1 -1
  130. package/esm/jubjub.d.ts +4 -0
  131. package/esm/jubjub.d.ts.map +1 -1
  132. package/esm/jubjub.js +4 -0
  133. package/esm/jubjub.js.map +1 -1
  134. package/esm/misc.d.ts.map +1 -1
  135. package/esm/misc.js +31 -26
  136. package/esm/misc.js.map +1 -1
  137. package/esm/nist.d.ts +8 -16
  138. package/esm/nist.d.ts.map +1 -1
  139. package/esm/nist.js +87 -97
  140. package/esm/nist.js.map +1 -1
  141. package/esm/p256.d.ts +3 -3
  142. package/esm/p384.d.ts +3 -3
  143. package/esm/p521.d.ts +3 -3
  144. package/esm/pasta.d.ts +4 -0
  145. package/esm/pasta.d.ts.map +1 -1
  146. package/esm/pasta.js +4 -0
  147. package/esm/pasta.js.map +1 -1
  148. package/esm/secp256k1.d.ts +6 -6
  149. package/esm/secp256k1.d.ts.map +1 -1
  150. package/esm/secp256k1.js +44 -41
  151. package/esm/secp256k1.js.map +1 -1
  152. package/esm/utils.d.ts +96 -0
  153. package/esm/utils.d.ts.map +1 -0
  154. package/esm/utils.js +279 -0
  155. package/esm/utils.js.map +1 -0
  156. package/jubjub.d.ts +4 -0
  157. package/jubjub.d.ts.map +1 -1
  158. package/jubjub.js +4 -0
  159. package/jubjub.js.map +1 -1
  160. package/misc.d.ts.map +1 -1
  161. package/misc.js +35 -30
  162. package/misc.js.map +1 -1
  163. package/nist.d.ts +8 -16
  164. package/nist.d.ts.map +1 -1
  165. package/nist.js +87 -97
  166. package/nist.js.map +1 -1
  167. package/p256.d.ts +3 -3
  168. package/p384.d.ts +3 -3
  169. package/p521.d.ts +3 -3
  170. package/package.json +26 -8
  171. package/pasta.d.ts +4 -0
  172. package/pasta.d.ts.map +1 -1
  173. package/pasta.js +4 -0
  174. package/pasta.js.map +1 -1
  175. package/secp256k1.d.ts +6 -6
  176. package/secp256k1.d.ts.map +1 -1
  177. package/secp256k1.js +47 -44
  178. package/secp256k1.js.map +1 -1
  179. package/src/_shortw_utils.ts +5 -15
  180. package/src/abstract/bls.ts +260 -145
  181. package/src/abstract/curve.ts +125 -18
  182. package/src/abstract/edwards.ts +282 -127
  183. package/src/abstract/fft.ts +519 -0
  184. package/src/abstract/hash-to-curve.ts +51 -27
  185. package/src/abstract/modular.ts +156 -143
  186. package/src/abstract/montgomery.ts +81 -111
  187. package/src/abstract/poseidon.ts +22 -18
  188. package/src/abstract/tower.ts +37 -68
  189. package/src/abstract/utils.ts +3 -378
  190. package/src/abstract/weierstrass.ts +752 -461
  191. package/src/bls12-381.ts +542 -507
  192. package/src/bn254.ts +47 -35
  193. package/src/ed25519.ts +104 -76
  194. package/src/ed448.ts +156 -105
  195. package/src/jubjub.ts +4 -0
  196. package/src/misc.ts +39 -34
  197. package/src/nist.ts +138 -126
  198. package/src/p256.ts +3 -3
  199. package/src/p384.ts +3 -3
  200. package/src/p521.ts +3 -3
  201. package/src/pasta.ts +5 -1
  202. package/src/secp256k1.ts +59 -47
  203. package/src/utils.ts +328 -0
  204. package/utils.d.ts +96 -0
  205. package/utils.d.ts.map +1 -0
  206. package/utils.js +313 -0
  207. package/utils.js.map +1 -0
@@ -1,65 +1,61 @@
1
1
  /**
2
2
  * Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y².
3
3
  * For design rationale of types / exports, see weierstrass module documentation.
4
+ * Untwisted Edwards curves exist, but they aren't used in real-world protocols.
4
5
  * @module
5
6
  */
6
7
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
7
- // prettier-ignore
8
8
  import {
9
- pippenger, validateBasic, wNAF,
10
- type AffinePoint, type BasicCurve, type Group, type GroupConstructor
11
- } from './curve.ts';
12
- import { Field, FpInvertBatch, mod } from './modular.ts';
13
- // prettier-ignore
9
+ _validateObject,
10
+ abool,
11
+ abytes,
12
+ aInRange,
13
+ bytesToHex,
14
+ bytesToNumberLE,
15
+ concatBytes,
16
+ ensureBytes,
17
+ memoized,
18
+ numberToBytesLE,
19
+ randomBytes,
20
+ type FHash,
21
+ type Hex,
22
+ } from '../utils.ts';
14
23
  import {
15
- abool, aInRange, bytesToHex, bytesToNumberLE, concatBytes,
16
- ensureBytes, memoized, numberToBytesLE, validateObject,
17
- type FHash, type Hex
18
- } from './utils.ts';
24
+ _createCurveFields,
25
+ normalizeZ,
26
+ pippenger,
27
+ wNAF,
28
+ type AffinePoint,
29
+ type BasicCurve,
30
+ type Group,
31
+ type GroupConstructor,
32
+ } from './curve.ts';
33
+ import { Field, type IField, type NLength } from './modular.ts';
19
34
 
20
35
  // Be friendly to bad ECMAScript parsers by not using bigint literals
21
36
  // prettier-ignore
22
37
  const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _8n = BigInt(8);
23
38
 
39
+ export type UVRatio = (u: bigint, v: bigint) => { isValid: boolean; value: bigint };
40
+
24
41
  /** Edwards curves must declare params a & d. */
25
42
  export type CurveType = BasicCurve<bigint> & {
26
43
  a: bigint; // curve param a
27
44
  d: bigint; // curve param d
28
45
  hash: FHash; // Hashing
29
- randomBytes: (bytesLength?: number) => Uint8Array; // CSPRNG
46
+ randomBytes?: (bytesLength?: number) => Uint8Array; // CSPRNG
30
47
  adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // clears bits to get valid field elemtn
31
48
  domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing
32
- uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint }; // Ratio √(u/v)
49
+ uvRatio?: UVRatio; // Ratio √(u/v)
33
50
  prehash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify()
34
51
  mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>; // for hash-to-curve standard
35
52
  };
36
53
 
37
- export type CurveTypeWithLength = Readonly<CurveType & { nByteLength: number; nBitLength: number }>;
54
+ export type CurveTypeWithLength = Readonly<CurveType & Partial<NLength>>;
38
55
 
39
56
  // verification rule is either zip215 or rfc8032 / nist186-5. Consult fromHex:
40
57
  const VERIFY_DEFAULT = { zip215: true };
41
58
 
42
- function validateOpts(curve: CurveType): CurveTypeWithLength {
43
- const opts = validateBasic(curve);
44
- validateObject(
45
- curve,
46
- {
47
- hash: 'function',
48
- a: 'bigint',
49
- d: 'bigint',
50
- randomBytes: 'function',
51
- },
52
- {
53
- adjustScalarBytes: 'function',
54
- domain: 'function',
55
- uvRatio: 'function',
56
- mapToCurve: 'function',
57
- }
58
- );
59
- // Set defaults
60
- return Object.freeze({ ...opts } as const);
61
- }
62
-
63
59
  /** Instance of Extended Point with coordinates in X, Y, Z, T. */
64
60
  export interface ExtPointType extends Group<ExtPointType> {
65
61
  readonly ex: bigint;
@@ -71,29 +67,115 @@ export interface ExtPointType extends Group<ExtPointType> {
71
67
  assertValidity(): void;
72
68
  multiply(scalar: bigint): ExtPointType;
73
69
  multiplyUnsafe(scalar: bigint): ExtPointType;
70
+ is0(): boolean;
74
71
  isSmallOrder(): boolean;
75
72
  isTorsionFree(): boolean;
76
73
  clearCofactor(): ExtPointType;
77
74
  toAffine(iz?: bigint): AffinePoint<bigint>;
78
- toRawBytes(isCompressed?: boolean): Uint8Array;
79
- toHex(isCompressed?: boolean): string;
75
+ toBytes(): Uint8Array;
76
+ /** @deprecated use `toBytes` */
77
+ toRawBytes(): Uint8Array;
78
+ toHex(): string;
79
+ precompute(windowSize?: number, isLazy?: boolean): ExtPointType;
80
+ /** @deprecated use `p.precompute(windowSize)` */
80
81
  _setWindowSize(windowSize: number): void;
81
82
  }
82
83
  /** Static methods of Extended Point with coordinates in X, Y, Z, T. */
83
84
  export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
84
85
  new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;
86
+ Fp: IField<bigint>;
87
+ Fn: IField<bigint>;
85
88
  fromAffine(p: AffinePoint<bigint>): ExtPointType;
86
- fromHex(hex: Hex): ExtPointType;
87
- fromPrivateKey(privateKey: Hex): ExtPointType;
89
+ fromBytes(bytes: Uint8Array, zip215?: boolean): ExtPointType;
90
+ fromHex(hex: Hex, zip215?: boolean): ExtPointType;
88
91
  msm(points: ExtPointType[], scalars: bigint[]): ExtPointType;
89
92
  }
90
93
 
91
94
  /**
92
- * Edwards Curve interface.
93
- * Main methods: `getPublicKey(priv)`, `sign(msg, priv)`, `verify(sig, msg, pub)`.
95
+ * Twisted Edwards curve options.
96
+ *
97
+ * * a: formula param
98
+ * * d: formula param
99
+ * * p: prime characteristic (order) of finite field, in which arithmetics is done
100
+ * * n: order of prime subgroup a.k.a total amount of valid curve points
101
+ * * h: cofactor. h*n is group order; n is subgroup order
102
+ * * Gx: x coordinate of generator point a.k.a. base point
103
+ * * Gy: y coordinate of generator point
104
+ */
105
+ export type EdwardsOpts = Readonly<{
106
+ a: bigint;
107
+ d: bigint;
108
+ p: bigint;
109
+ n: bigint;
110
+ h: bigint;
111
+ Gx: bigint;
112
+ Gy: bigint;
113
+ }>;
114
+
115
+ /**
116
+ * Extra curve options for Twisted Edwards.
117
+ *
118
+ * * Fp: redefined Field over curve.p
119
+ * * Fn: redefined Field over curve.n
120
+ * * uvRatio: helper function for decompression, calculating √(u/v)
94
121
  */
122
+ export type EdwardsExtraOpts = Partial<{
123
+ Fp: IField<bigint>;
124
+ Fn: IField<bigint>;
125
+ uvRatio: (u: bigint, v: bigint) => { isValid: boolean; value: bigint };
126
+ }>;
127
+
128
+ /**
129
+ * EdDSA (Edwards Digital Signature algorithm) options.
130
+ *
131
+ * * hash: hash function used to hash private keys and messages
132
+ * * adjustScalarBytes: clears bits to get valid field element
133
+ * * domain: Used for hashing
134
+ * * mapToCurve: for hash-to-curve standard
135
+ * * prehash: RFC 8032 pre-hashing of messages to sign() / verify()
136
+ * * randomBytes: function generating random bytes, used for randomPrivateKey
137
+ */
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
+ };
146
+
147
+ /**
148
+ * EdDSA (Edwards Digital Signature algorithm) interface.
149
+ *
150
+ * Allows to create and verify signatures, create public and private keys.
151
+ */
152
+ export interface EdDSA {
153
+ getPublicKey: (privateKey: Hex) => Uint8Array;
154
+ sign: (message: Hex, privateKey: Hex, options?: { context?: Hex }) => Uint8Array;
155
+ verify: (
156
+ sig: Hex,
157
+ message: Hex,
158
+ publicKey: Hex,
159
+ options?: { context?: Hex; zip215: boolean }
160
+ ) => boolean;
161
+ Point: ExtPointConstructor;
162
+ utils: {
163
+ randomPrivateKey: () => Uint8Array;
164
+ getExtendedPublicKey: (key: Hex) => {
165
+ head: Uint8Array;
166
+ prefix: Uint8Array;
167
+ scalar: bigint;
168
+ point: ExtPointType;
169
+ pointBytes: Uint8Array;
170
+ };
171
+ /** @deprecated use `point.precompute()` */
172
+ precompute: (windowSize?: number, point?: ExtPointType) => ExtPointType;
173
+ };
174
+ }
175
+
176
+ // Legacy params. TODO: remove
95
177
  export type CurveFn = {
96
- CURVE: ReturnType<typeof validateOpts>;
178
+ CURVE: CurveType;
97
179
  getPublicKey: (privateKey: Hex) => Uint8Array;
98
180
  sign: (message: Hex, privateKey: Hex, options?: { context?: Hex }) => Uint8Array;
99
181
  verify: (
@@ -102,6 +184,8 @@ export type CurveFn = {
102
184
  publicKey: Hex,
103
185
  options?: { context?: Hex; zip215: boolean }
104
186
  ) => boolean;
187
+ Point: ExtPointConstructor;
188
+ /** @deprecated use `Point` */
105
189
  ExtendedPoint: ExtPointConstructor;
106
190
  utils: {
107
191
  randomPrivateKey: () => Uint8Array;
@@ -116,55 +200,50 @@ export type CurveFn = {
116
200
  };
117
201
  };
118
202
 
119
- /**
120
- * Creates Twisted Edwards curve with EdDSA signatures.
121
- * @example
122
- * import { Field } from '@noble/curves/abstract/modular';
123
- * // Before that, define BigInt-s: a, d, p, n, Gx, Gy, h
124
- * const curve = twistedEdwards({ a, d, Fp: Field(p), n, Gx, Gy, h })
125
- */
126
- export function twistedEdwards(curveDef: CurveType): CurveFn {
127
- const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
128
- const {
129
- Fp,
130
- n: CURVE_ORDER,
131
- prehash: prehash,
132
- hash: cHash,
133
- randomBytes,
134
- nByteLength,
135
- h: cofactor,
136
- } = CURVE;
203
+ function isEdValidXY(Fp: IField<bigint>, CURVE: EdwardsOpts, x: bigint, y: bigint): boolean {
204
+ const x2 = Fp.sqr(x);
205
+ const y2 = Fp.sqr(y);
206
+ const left = Fp.add(Fp.mul(CURVE.a, x2), y2);
207
+ const right = Fp.add(Fp.ONE, Fp.mul(CURVE.d, Fp.mul(x2, y2)));
208
+ return Fp.eql(left, right);
209
+ }
210
+
211
+ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): ExtPointConstructor {
212
+ const { Fp, Fn } = _createCurveFields('edwards', CURVE, curveOpts);
213
+ const { h: cofactor, n: CURVE_ORDER } = CURVE;
214
+ _validateObject(curveOpts, {}, { uvRatio: 'function' });
215
+
137
216
  // Important:
138
217
  // There are some places where Fp.BYTES is used instead of nByteLength.
139
218
  // So far, everything has been tested with curves of Fp.BYTES == nByteLength.
140
219
  // TODO: test and find curves which behave otherwise.
141
- const MASK = _2n << (BigInt(nByteLength * 8) - _1n);
142
- const modP = Fp.create; // Function overrides
143
- const Fn = Field(CURVE.n, CURVE.nBitLength);
220
+ const MASK = _2n << (BigInt(Fn.BYTES * 8) - _1n);
221
+ const modP = (n: bigint) => Fp.create(n); // Function overrides
144
222
 
145
223
  // sqrt(u/v)
146
224
  const uvRatio =
147
- CURVE.uvRatio ||
225
+ curveOpts.uvRatio ||
148
226
  ((u: bigint, v: bigint) => {
149
227
  try {
150
- return { isValid: true, value: Fp.sqrt(u * Fp.inv(v)) };
228
+ return { isValid: true, value: Fp.sqrt(Fp.div(u, v)) };
151
229
  } catch (e) {
152
230
  return { isValid: false, value: _0n };
153
231
  }
154
232
  });
155
- const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes: Uint8Array) => bytes); // NOOP
156
- const domain =
157
- CURVE.domain ||
158
- ((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
159
- abool('phflag', phflag);
160
- if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
161
- return data;
162
- }); // NOOP
163
- // 0 <= n < MASK
164
- // Coordinates larger than Fp.ORDER are allowed for zip215
165
- function aCoordinate(title: string, n: bigint, banZero = false) {
233
+
234
+ // Validate whether the passed curve params are valid.
235
+ // equation ax² + y² = 1 + dx²y² should work for generator point.
236
+ if (!isEdValidXY(Fp, CURVE, CURVE.Gx, CURVE.Gy))
237
+ throw new Error('bad curve params: generator point');
238
+
239
+ /**
240
+ * Asserts coordinate is valid: 0 <= n < MASK.
241
+ * Coordinates >= Fp.ORDER are allowed for zip215.
242
+ */
243
+ function acoord(title: string, n: bigint, banZero = false) {
166
244
  const min = banZero ? _1n : _0n;
167
245
  aInRange('coordinate ' + title, n, min, MASK);
246
+ return n;
168
247
  }
169
248
 
170
249
  function aextpoint(other: unknown) {
@@ -204,25 +283,27 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
204
283
  return true;
205
284
  });
206
285
 
207
- // Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
286
+ // Extended Point works in extended coordinates: (X, Y, Z, T) ∋ (x=X/Z, y=Y/Z, T=xy).
208
287
  // https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
209
288
  class Point implements ExtPointType {
289
+ // base / generator point
210
290
  static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
291
+ // zero / infinity / identity point
211
292
  static readonly ZERO = new Point(_0n, _1n, _1n, _0n); // 0, 1, 1, 0
293
+ // fields
294
+ static readonly Fp = Fp;
295
+ static readonly Fn = Fn;
296
+
212
297
  readonly ex: bigint;
213
298
  readonly ey: bigint;
214
299
  readonly ez: bigint;
215
300
  readonly et: bigint;
216
301
 
217
302
  constructor(ex: bigint, ey: bigint, ez: bigint, et: bigint) {
218
- aCoordinate('x', ex);
219
- aCoordinate('y', ey);
220
- aCoordinate('z', ez, true);
221
- aCoordinate('t', et);
222
- this.ex = ex;
223
- this.ey = ey;
224
- this.ez = ez;
225
- this.et = et;
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);
226
307
  Object.freeze(this);
227
308
  }
228
309
 
@@ -236,16 +317,12 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
236
317
  static fromAffine(p: AffinePoint<bigint>): Point {
237
318
  if (p instanceof Point) throw new Error('extended point not allowed');
238
319
  const { x, y } = p || {};
239
- aCoordinate('x', x);
240
- aCoordinate('y', y);
320
+ acoord('x', x);
321
+ acoord('y', y);
241
322
  return new Point(x, y, _1n, modP(x * y));
242
323
  }
243
324
  static normalizeZ(points: Point[]): Point[] {
244
- const toInv = FpInvertBatch(
245
- Fp,
246
- points.map((p) => p.ez)
247
- );
248
- return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
325
+ return normalizeZ(Point, 'ez', points);
249
326
  }
250
327
  // Multiscalar Multiplication
251
328
  static msm(points: Point[], scalars: bigint[]): Point {
@@ -254,7 +331,12 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
254
331
 
255
332
  // "Private method", don't use it directly
256
333
  _setWindowSize(windowSize: number) {
334
+ this.precompute(windowSize);
335
+ }
336
+ precompute(windowSize: number = 8, isLazy = true) {
257
337
  wnaf.setWindowSize(this, windowSize);
338
+ if (!isLazy) this.multiply(_2n); // random number
339
+ return this;
258
340
  }
259
341
  // Not required for fromHex(), which always creates valid points.
260
342
  // Could be useful for fromAffine().
@@ -332,15 +414,11 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
332
414
  return this.add(other.negate());
333
415
  }
334
416
 
335
- private wNAF(n: bigint): { p: Point; f: Point } {
336
- return wnaf.wNAFCached(this, n, Point.normalizeZ);
337
- }
338
-
339
417
  // Constant-time multiplication.
340
418
  multiply(scalar: bigint): Point {
341
419
  const n = scalar;
342
420
  aInRange('scalar', n, _1n, CURVE_ORDER); // 1 <= scalar < L
343
- const { p, f } = this.wNAF(n);
421
+ const { p, f } = wnaf.wNAFCached(this, n, Point.normalizeZ);
344
422
  return Point.normalizeZ([p, f])[0];
345
423
  }
346
424
 
@@ -352,7 +430,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
352
430
  multiplyUnsafe(scalar: bigint, acc = Point.ZERO): Point {
353
431
  const n = scalar;
354
432
  aInRange('scalar', n, _0n, CURVE_ORDER); // 0 <= scalar < L
355
- if (n === _0n) return I;
433
+ if (n === _0n) return Point.ZERO;
356
434
  if (this.is0() || n === _1n) return this;
357
435
  return wnaf.wNAFCachedUnsafe(this, n, Point.normalizeZ, acc);
358
436
  }
@@ -368,21 +446,25 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
368
446
  // Multiplies point by curve order and checks if the result is 0.
369
447
  // Returns `false` is the point is dirty.
370
448
  isTorsionFree(): boolean {
371
- return wnaf.unsafeLadder(this, CURVE_ORDER).is0();
449
+ return wnaf.wNAFCachedUnsafe(this, CURVE_ORDER).is0();
372
450
  }
373
451
 
374
452
  // Converts Extended point to default (x, y) coordinates.
375
453
  // Can accept precomputed Z^-1 - for example, from invertBatch.
376
- toAffine(iz?: bigint): AffinePoint<bigint> {
377
- return toAffineMemo(this, iz);
454
+ toAffine(invertedZ?: bigint): AffinePoint<bigint> {
455
+ return toAffineMemo(this, invertedZ);
378
456
  }
379
457
 
380
458
  clearCofactor(): Point {
381
- const { h: cofactor } = CURVE;
382
459
  if (cofactor === _1n) return this;
383
460
  return this.multiplyUnsafe(cofactor);
384
461
  }
385
462
 
463
+ static fromBytes(bytes: Uint8Array, zip215 = false): Point {
464
+ abytes(bytes);
465
+ return this.fromHex(bytes, zip215);
466
+ }
467
+
386
468
  // Converts hash string or Uint8Array to Point.
387
469
  // Uses algo from RFC8032 5.1.3.
388
470
  static fromHex(hex: Hex, zip215 = false): Point {
@@ -417,28 +499,69 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
417
499
  if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x
418
500
  return Point.fromAffine({ x, y });
419
501
  }
420
- static fromPrivateKey(privKey: Hex): Point {
421
- const { scalar } = getPrivateScalar(privKey);
422
- return G.multiply(scalar); // reduced one call of `toRawBytes`
502
+ static fromPrivateScalar(scalar: bigint): Point {
503
+ return Point.BASE.multiply(scalar);
423
504
  }
424
- toRawBytes(): Uint8Array {
505
+ toBytes(): Uint8Array {
425
506
  const { x, y } = this.toAffine();
426
507
  const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
427
508
  bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
428
509
  return bytes; // and use the last byte to encode sign of x
429
510
  }
511
+ /** @deprecated use `toBytes` */
512
+ toRawBytes(): Uint8Array {
513
+ return this.toBytes();
514
+ }
430
515
  toHex(): string {
431
- return bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string.
516
+ return bytesToHex(this.toBytes());
517
+ }
518
+
519
+ toString() {
520
+ return `<Point ${this.is0() ? 'ZERO' : this.toHex()}>`;
432
521
  }
433
522
  }
434
- const { BASE: G, ZERO: I } = Point;
435
- const wnaf = wNAF(Point, nByteLength * 8);
523
+ const wnaf = wNAF(Point, Fn.BYTES * 8); // Fn.BITS?
524
+ return Point;
525
+ }
526
+
527
+ /**
528
+ * Initializes EdDSA signatures over given Edwards curve.
529
+ */
530
+ export function eddsa(Point: ExtPointConstructor, eddsaOpts: EdDSAOpts): EdDSA {
531
+ _validateObject(
532
+ eddsaOpts,
533
+ {
534
+ hash: 'function',
535
+ },
536
+ {
537
+ adjustScalarBytes: 'function',
538
+ randomBytes: 'function',
539
+ domain: 'function',
540
+ prehash: 'function',
541
+ mapToCurve: 'function',
542
+ }
543
+ );
544
+
545
+ const { prehash, hash: cHash } = eddsaOpts;
546
+ const { BASE: G, Fp, Fn } = Point;
547
+ const CURVE_ORDER = Fn.ORDER;
548
+
549
+ const randomBytes_ = eddsaOpts.randomBytes || randomBytes;
550
+ const adjustScalarBytes = eddsaOpts.adjustScalarBytes || ((bytes: Uint8Array) => bytes); // NOOP
551
+ const domain =
552
+ eddsaOpts.domain ||
553
+ ((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
554
+ abool('phflag', phflag);
555
+ if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
556
+ return data;
557
+ }); // NOOP
436
558
 
437
559
  function modN(a: bigint) {
438
- return mod(a, CURVE_ORDER);
560
+ return Fn.create(a);
439
561
  }
440
562
  // Little-endian SHA512 with modulo n
441
563
  function modN_LE(hash: Uint8Array): bigint {
564
+ // Not using Fn.fromBytes: hash can be 2*Fn.BYTES
442
565
  return modN(bytesToNumberLE(hash));
443
566
  }
444
567
 
@@ -459,7 +582,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
459
582
  function getExtendedPublicKey(key: Hex) {
460
583
  const { head, prefix, scalar } = getPrivateScalar(key);
461
584
  const point = G.multiply(scalar); // Point on Edwards curve aka public key
462
- const pointBytes = point.toRawBytes(); // Uint8Array representation
585
+ const pointBytes = point.toBytes();
463
586
  return { head, prefix, scalar, point, pointBytes };
464
587
  }
465
588
 
@@ -480,12 +603,13 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
480
603
  if (prehash) msg = prehash(msg); // for ed25519ph etc.
481
604
  const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
482
605
  const r = hashDomainToScalar(options.context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
483
- const R = G.multiply(r).toRawBytes(); // R = rG
606
+ const R = G.multiply(r).toBytes(); // R = rG
484
607
  const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)
485
608
  const s = modN(r + k * scalar); // S = (r + k * s) mod L
486
609
  aInRange('signature.s', s, _0n, CURVE_ORDER); // 0 <= s < l
487
- const res = concatBytes(R, numberToBytesLE(s, Fp.BYTES));
488
- return ensureBytes('result', res, Fp.BYTES * 2); // 64-byte signature
610
+ const L = Fp.BYTES;
611
+ const res = concatBytes(R, numberToBytesLE(s, L));
612
+ return ensureBytes('result', res, L * 2); // 64-byte signature
489
613
  }
490
614
 
491
615
  const verifyOpts: { context?: Hex; zip215?: boolean } = VERIFY_DEFAULT;
@@ -517,19 +641,19 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
517
641
  }
518
642
  if (!zip215 && A.isSmallOrder()) return false;
519
643
 
520
- const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
644
+ const k = hashDomainToScalar(context, R.toBytes(), A.toBytes(), msg);
521
645
  const RkA = R.add(A.multiplyUnsafe(k));
522
646
  // Extended group equation
523
647
  // [8][S]B = [8]R + [8][k]A'
524
- return RkA.subtract(SB).clearCofactor().equals(Point.ZERO);
648
+ return RkA.subtract(SB).clearCofactor().is0();
525
649
  }
526
650
 
527
- G._setWindowSize(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
651
+ G.precompute(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
528
652
 
529
653
  const utils = {
530
654
  getExtendedPublicKey,
531
655
  /** ed25519 priv keys are uniform 32b. No need to check for modulo bias, like in secp256k1. */
532
- randomPrivateKey: (): Uint8Array => randomBytes(Fp.BYTES),
656
+ randomPrivateKey: (): Uint8Array => randomBytes_!(Fp.BYTES),
533
657
 
534
658
  /**
535
659
  * We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
@@ -538,18 +662,49 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
538
662
  * @param windowSize 2, 4, 8, 16
539
663
  */
540
664
  precompute(windowSize = 8, point: ExtPointType = Point.BASE): ExtPointType {
541
- point._setWindowSize(windowSize);
542
- point.multiply(BigInt(3));
543
- return point;
665
+ return point.precompute(windowSize, false);
544
666
  },
545
667
  };
546
668
 
547
- return {
548
- CURVE,
549
- getPublicKey,
550
- sign,
551
- verify,
552
- ExtendedPoint: Point,
553
- utils,
669
+ return { getPublicKey, sign, verify, utils, Point };
670
+ }
671
+
672
+ export type EdComposed = {
673
+ CURVE: EdwardsOpts;
674
+ curveOpts: EdwardsExtraOpts;
675
+ eddsaOpts: EdDSAOpts;
676
+ };
677
+ function _eddsa_legacy_opts_to_new(c: CurveTypeWithLength): EdComposed {
678
+ const CURVE: EdwardsOpts = {
679
+ a: c.a,
680
+ d: c.d,
681
+ p: c.Fp.ORDER,
682
+ n: c.n,
683
+ h: c.h,
684
+ Gx: c.Gx,
685
+ Gy: c.Gy,
554
686
  };
687
+ const Fp = c.Fp;
688
+ const Fn = Field(CURVE.n, c.nBitLength, true);
689
+ const curveOpts: EdwardsExtraOpts = { Fp, Fn, uvRatio: c.uvRatio };
690
+ const eddsaOpts: EdDSAOpts = {
691
+ hash: c.hash,
692
+ randomBytes: c.randomBytes,
693
+ adjustScalarBytes: c.adjustScalarBytes,
694
+ domain: c.domain,
695
+ prehash: c.prehash,
696
+ mapToCurve: c.mapToCurve,
697
+ };
698
+ return { CURVE, curveOpts, eddsaOpts };
699
+ }
700
+ function _eddsa_new_output_to_legacy(c: CurveTypeWithLength, eddsa: EdDSA): CurveFn {
701
+ const legacy = Object.assign({}, eddsa, { ExtendedPoint: eddsa.Point, CURVE: c });
702
+ return legacy;
703
+ }
704
+ // TODO: remove. Use eddsa
705
+ export function twistedEdwards(c: CurveTypeWithLength): CurveFn {
706
+ const { CURVE, curveOpts, eddsaOpts } = _eddsa_legacy_opts_to_new(c);
707
+ const Point = edwards(CURVE, curveOpts);
708
+ const EDDSA = eddsa(Point, eddsaOpts);
709
+ return _eddsa_new_output_to_legacy(c, EDDSA);
555
710
  }