@noble/curves 1.9.1 → 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 (189) hide show
  1. package/README.md +56 -25
  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 +86 -7
  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 +138 -102
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/fft.d.ts +12 -10
  19. package/abstract/fft.d.ts.map +1 -1
  20. package/abstract/fft.js +12 -13
  21. package/abstract/fft.js.map +1 -1
  22. package/abstract/hash-to-curve.d.ts +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 +24 -11
  27. package/abstract/modular.d.ts.map +1 -1
  28. package/abstract/modular.js +49 -20
  29. package/abstract/modular.js.map +1 -1
  30. package/abstract/montgomery.d.ts +1 -1
  31. package/abstract/montgomery.d.ts.map +1 -1
  32. package/abstract/montgomery.js +5 -4
  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 +9 -3
  41. package/abstract/tower.js.map +1 -1
  42. package/abstract/utils.d.ts +1 -115
  43. package/abstract/utils.d.ts.map +1 -1
  44. package/abstract/utils.js +17 -371
  45. package/abstract/utils.js.map +1 -1
  46. package/abstract/weierstrass.d.ts +132 -76
  47. package/abstract/weierstrass.d.ts.map +1 -1
  48. package/abstract/weierstrass.js +462 -398
  49. package/abstract/weierstrass.js.map +1 -1
  50. package/bls12-381.d.ts +2 -0
  51. package/bls12-381.d.ts.map +1 -1
  52. package/bls12-381.js +504 -466
  53. package/bls12-381.js.map +1 -1
  54. package/bn254.d.ts +2 -0
  55. package/bn254.d.ts.map +1 -1
  56. package/bn254.js +44 -32
  57. package/bn254.js.map +1 -1
  58. package/ed25519.d.ts +8 -5
  59. package/ed25519.d.ts.map +1 -1
  60. package/ed25519.js +67 -54
  61. package/ed25519.js.map +1 -1
  62. package/ed448.d.ts +10 -6
  63. package/ed448.d.ts.map +1 -1
  64. package/ed448.js +80 -57
  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 +83 -8
  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 +138 -104
  81. package/esm/abstract/edwards.js.map +1 -1
  82. package/esm/abstract/fft.d.ts +12 -10
  83. package/esm/abstract/fft.d.ts.map +1 -1
  84. package/esm/abstract/fft.js +10 -11
  85. package/esm/abstract/fft.js.map +1 -1
  86. package/esm/abstract/hash-to-curve.d.ts +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 +24 -11
  91. package/esm/abstract/modular.d.ts.map +1 -1
  92. package/esm/abstract/modular.js +48 -19
  93. package/esm/abstract/modular.js.map +1 -1
  94. package/esm/abstract/montgomery.d.ts +1 -1
  95. package/esm/abstract/montgomery.d.ts.map +1 -1
  96. package/esm/abstract/montgomery.js +5 -4
  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 +9 -3
  105. package/esm/abstract/tower.js.map +1 -1
  106. package/esm/abstract/utils.d.ts +1 -115
  107. package/esm/abstract/utils.d.ts.map +1 -1
  108. package/esm/abstract/utils.js +3 -344
  109. package/esm/abstract/utils.js.map +1 -1
  110. package/esm/abstract/weierstrass.d.ts +132 -76
  111. package/esm/abstract/weierstrass.d.ts.map +1 -1
  112. package/esm/abstract/weierstrass.js +460 -400
  113. package/esm/abstract/weierstrass.js.map +1 -1
  114. package/esm/bls12-381.d.ts +2 -0
  115. package/esm/bls12-381.d.ts.map +1 -1
  116. package/esm/bls12-381.js +503 -465
  117. package/esm/bls12-381.js.map +1 -1
  118. package/esm/bn254.d.ts +2 -0
  119. package/esm/bn254.d.ts.map +1 -1
  120. package/esm/bn254.js +41 -29
  121. package/esm/bn254.js.map +1 -1
  122. package/esm/ed25519.d.ts +8 -5
  123. package/esm/ed25519.d.ts.map +1 -1
  124. package/esm/ed25519.js +62 -49
  125. package/esm/ed25519.js.map +1 -1
  126. package/esm/ed448.d.ts +10 -6
  127. package/esm/ed448.d.ts.map +1 -1
  128. package/esm/ed448.js +74 -51
  129. package/esm/ed448.js.map +1 -1
  130. package/esm/misc.d.ts.map +1 -1
  131. package/esm/misc.js +31 -26
  132. package/esm/misc.js.map +1 -1
  133. package/esm/nist.d.ts +7 -16
  134. package/esm/nist.d.ts.map +1 -1
  135. package/esm/nist.js +86 -97
  136. package/esm/nist.js.map +1 -1
  137. package/esm/p256.d.ts +3 -3
  138. package/esm/p384.d.ts +3 -3
  139. package/esm/p521.d.ts +3 -3
  140. package/esm/secp256k1.d.ts +6 -6
  141. package/esm/secp256k1.d.ts.map +1 -1
  142. package/esm/secp256k1.js +43 -40
  143. package/esm/secp256k1.js.map +1 -1
  144. package/esm/utils.d.ts +96 -0
  145. package/esm/utils.d.ts.map +1 -0
  146. package/esm/utils.js +279 -0
  147. package/esm/utils.js.map +1 -0
  148. package/misc.d.ts.map +1 -1
  149. package/misc.js +35 -30
  150. package/misc.js.map +1 -1
  151. package/nist.d.ts +7 -16
  152. package/nist.d.ts.map +1 -1
  153. package/nist.js +86 -97
  154. package/nist.js.map +1 -1
  155. package/p256.d.ts +3 -3
  156. package/p384.d.ts +3 -3
  157. package/p521.d.ts +3 -3
  158. package/package.json +14 -5
  159. package/secp256k1.d.ts +6 -6
  160. package/secp256k1.d.ts.map +1 -1
  161. package/secp256k1.js +46 -43
  162. package/secp256k1.js.map +1 -1
  163. package/src/_shortw_utils.ts +5 -15
  164. package/src/abstract/bls.ts +260 -145
  165. package/src/abstract/curve.ts +115 -13
  166. package/src/abstract/edwards.ts +279 -138
  167. package/src/abstract/fft.ts +30 -19
  168. package/src/abstract/hash-to-curve.ts +51 -27
  169. package/src/abstract/modular.ts +49 -28
  170. package/src/abstract/montgomery.ts +9 -7
  171. package/src/abstract/poseidon.ts +22 -18
  172. package/src/abstract/tower.ts +36 -67
  173. package/src/abstract/utils.ts +3 -378
  174. package/src/abstract/weierstrass.ts +700 -453
  175. package/src/bls12-381.ts +540 -489
  176. package/src/bn254.ts +47 -35
  177. package/src/ed25519.ts +80 -64
  178. package/src/ed448.ts +129 -92
  179. package/src/misc.ts +39 -34
  180. package/src/nist.ts +138 -127
  181. package/src/p256.ts +3 -3
  182. package/src/p384.ts +3 -3
  183. package/src/p521.ts +3 -3
  184. package/src/secp256k1.ts +58 -46
  185. package/src/utils.ts +328 -0
  186. package/utils.d.ts +96 -0
  187. package/utils.d.ts.map +1 -0
  188. package/utils.js +313 -0
  189. 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)
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.
94
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,67 +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);
144
-
145
- function isEdValidXY(x: bigint, y: bigint): boolean {
146
- const x2 = Fp.sqr(x);
147
- const y2 = Fp.sqr(y);
148
- const left = Fp.add(Fp.mul(CURVE.a, x2), y2);
149
- const right = Fp.add(Fp.ONE, Fp.mul(CURVE.d, Fp.mul(x2, y2)));
150
- return Fp.eql(left, right);
151
- }
152
-
153
- // Validate whether the passed curve params are valid.
154
- // equation ax² + y² = 1 + dx²y² should work for generator point.
155
- if (!isEdValidXY(CURVE.Gx, CURVE.Gy)) throw new Error('bad curve params: generator point');
220
+ const MASK = _2n << (BigInt(Fn.BYTES * 8) - _1n);
221
+ const modP = (n: bigint) => Fp.create(n); // Function overrides
156
222
 
157
223
  // sqrt(u/v)
158
224
  const uvRatio =
159
- CURVE.uvRatio ||
225
+ curveOpts.uvRatio ||
160
226
  ((u: bigint, v: bigint) => {
161
227
  try {
162
- return { isValid: true, value: Fp.sqrt(u * Fp.inv(v)) };
228
+ return { isValid: true, value: Fp.sqrt(Fp.div(u, v)) };
163
229
  } catch (e) {
164
230
  return { isValid: false, value: _0n };
165
231
  }
166
232
  });
167
- const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes: Uint8Array) => bytes); // NOOP
168
- const domain =
169
- CURVE.domain ||
170
- ((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
171
- abool('phflag', phflag);
172
- if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
173
- return data;
174
- }); // NOOP
175
- // 0 <= n < MASK
176
- // Coordinates larger than Fp.ORDER are allowed for zip215
177
- 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) {
178
244
  const min = banZero ? _1n : _0n;
179
245
  aInRange('coordinate ' + title, n, min, MASK);
246
+ return n;
180
247
  }
181
248
 
182
249
  function aextpoint(other: unknown) {
@@ -223,20 +290,20 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
223
290
  static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
224
291
  // zero / infinity / identity point
225
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
+
226
297
  readonly ex: bigint;
227
298
  readonly ey: bigint;
228
299
  readonly ez: bigint;
229
300
  readonly et: bigint;
230
301
 
231
302
  constructor(ex: bigint, ey: bigint, ez: bigint, et: bigint) {
232
- aCoordinate('x', ex);
233
- aCoordinate('y', ey);
234
- aCoordinate('z', ez, true);
235
- aCoordinate('t', et);
236
- this.ex = ex;
237
- this.ey = ey;
238
- this.ez = ez;
239
- 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);
240
307
  Object.freeze(this);
241
308
  }
242
309
 
@@ -250,16 +317,12 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
250
317
  static fromAffine(p: AffinePoint<bigint>): Point {
251
318
  if (p instanceof Point) throw new Error('extended point not allowed');
252
319
  const { x, y } = p || {};
253
- aCoordinate('x', x);
254
- aCoordinate('y', y);
320
+ acoord('x', x);
321
+ acoord('y', y);
255
322
  return new Point(x, y, _1n, modP(x * y));
256
323
  }
257
324
  static normalizeZ(points: Point[]): Point[] {
258
- const toInv = FpInvertBatch(
259
- Fp,
260
- points.map((p) => p.ez)
261
- );
262
- return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
325
+ return normalizeZ(Point, 'ez', points);
263
326
  }
264
327
  // Multiscalar Multiplication
265
328
  static msm(points: Point[], scalars: bigint[]): Point {
@@ -268,7 +331,12 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
268
331
 
269
332
  // "Private method", don't use it directly
270
333
  _setWindowSize(windowSize: number) {
334
+ this.precompute(windowSize);
335
+ }
336
+ precompute(windowSize: number = 8, isLazy = true) {
271
337
  wnaf.setWindowSize(this, windowSize);
338
+ if (!isLazy) this.multiply(_2n); // random number
339
+ return this;
272
340
  }
273
341
  // Not required for fromHex(), which always creates valid points.
274
342
  // Could be useful for fromAffine().
@@ -346,15 +414,11 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
346
414
  return this.add(other.negate());
347
415
  }
348
416
 
349
- private wNAF(n: bigint): { p: Point; f: Point } {
350
- return wnaf.wNAFCached(this, n, Point.normalizeZ);
351
- }
352
-
353
417
  // Constant-time multiplication.
354
418
  multiply(scalar: bigint): Point {
355
419
  const n = scalar;
356
420
  aInRange('scalar', n, _1n, CURVE_ORDER); // 1 <= scalar < L
357
- const { p, f } = this.wNAF(n);
421
+ const { p, f } = wnaf.wNAFCached(this, n, Point.normalizeZ);
358
422
  return Point.normalizeZ([p, f])[0];
359
423
  }
360
424
 
@@ -366,7 +430,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
366
430
  multiplyUnsafe(scalar: bigint, acc = Point.ZERO): Point {
367
431
  const n = scalar;
368
432
  aInRange('scalar', n, _0n, CURVE_ORDER); // 0 <= scalar < L
369
- if (n === _0n) return I;
433
+ if (n === _0n) return Point.ZERO;
370
434
  if (this.is0() || n === _1n) return this;
371
435
  return wnaf.wNAFCachedUnsafe(this, n, Point.normalizeZ, acc);
372
436
  }
@@ -382,21 +446,25 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
382
446
  // Multiplies point by curve order and checks if the result is 0.
383
447
  // Returns `false` is the point is dirty.
384
448
  isTorsionFree(): boolean {
385
- return wnaf.unsafeLadder(this, CURVE_ORDER).is0();
449
+ return wnaf.wNAFCachedUnsafe(this, CURVE_ORDER).is0();
386
450
  }
387
451
 
388
452
  // Converts Extended point to default (x, y) coordinates.
389
453
  // Can accept precomputed Z^-1 - for example, from invertBatch.
390
- toAffine(iz?: bigint): AffinePoint<bigint> {
391
- return toAffineMemo(this, iz);
454
+ toAffine(invertedZ?: bigint): AffinePoint<bigint> {
455
+ return toAffineMemo(this, invertedZ);
392
456
  }
393
457
 
394
458
  clearCofactor(): Point {
395
- const { h: cofactor } = CURVE;
396
459
  if (cofactor === _1n) return this;
397
460
  return this.multiplyUnsafe(cofactor);
398
461
  }
399
462
 
463
+ static fromBytes(bytes: Uint8Array, zip215 = false): Point {
464
+ abytes(bytes);
465
+ return this.fromHex(bytes, zip215);
466
+ }
467
+
400
468
  // Converts hash string or Uint8Array to Point.
401
469
  // Uses algo from RFC8032 5.1.3.
402
470
  static fromHex(hex: Hex, zip215 = false): Point {
@@ -431,28 +499,69 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
431
499
  if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x
432
500
  return Point.fromAffine({ x, y });
433
501
  }
434
- static fromPrivateKey(privKey: Hex): Point {
435
- const { scalar } = getPrivateScalar(privKey);
436
- return G.multiply(scalar); // reduced one call of `toRawBytes`
502
+ static fromPrivateScalar(scalar: bigint): Point {
503
+ return Point.BASE.multiply(scalar);
437
504
  }
438
- toRawBytes(): Uint8Array {
505
+ toBytes(): Uint8Array {
439
506
  const { x, y } = this.toAffine();
440
507
  const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
441
508
  bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
442
509
  return bytes; // and use the last byte to encode sign of x
443
510
  }
511
+ /** @deprecated use `toBytes` */
512
+ toRawBytes(): Uint8Array {
513
+ return this.toBytes();
514
+ }
444
515
  toHex(): string {
445
- 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()}>`;
446
521
  }
447
522
  }
448
- const { BASE: G, ZERO: I } = Point;
449
- 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
450
558
 
451
559
  function modN(a: bigint) {
452
- return mod(a, CURVE_ORDER);
560
+ return Fn.create(a);
453
561
  }
454
562
  // Little-endian SHA512 with modulo n
455
563
  function modN_LE(hash: Uint8Array): bigint {
564
+ // Not using Fn.fromBytes: hash can be 2*Fn.BYTES
456
565
  return modN(bytesToNumberLE(hash));
457
566
  }
458
567
 
@@ -473,7 +582,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
473
582
  function getExtendedPublicKey(key: Hex) {
474
583
  const { head, prefix, scalar } = getPrivateScalar(key);
475
584
  const point = G.multiply(scalar); // Point on Edwards curve aka public key
476
- const pointBytes = point.toRawBytes(); // Uint8Array representation
585
+ const pointBytes = point.toBytes();
477
586
  return { head, prefix, scalar, point, pointBytes };
478
587
  }
479
588
 
@@ -494,12 +603,13 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
494
603
  if (prehash) msg = prehash(msg); // for ed25519ph etc.
495
604
  const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
496
605
  const r = hashDomainToScalar(options.context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
497
- const R = G.multiply(r).toRawBytes(); // R = rG
606
+ const R = G.multiply(r).toBytes(); // R = rG
498
607
  const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)
499
608
  const s = modN(r + k * scalar); // S = (r + k * s) mod L
500
609
  aInRange('signature.s', s, _0n, CURVE_ORDER); // 0 <= s < l
501
- const res = concatBytes(R, numberToBytesLE(s, Fp.BYTES));
502
- 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
503
613
  }
504
614
 
505
615
  const verifyOpts: { context?: Hex; zip215?: boolean } = VERIFY_DEFAULT;
@@ -531,19 +641,19 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
531
641
  }
532
642
  if (!zip215 && A.isSmallOrder()) return false;
533
643
 
534
- const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
644
+ const k = hashDomainToScalar(context, R.toBytes(), A.toBytes(), msg);
535
645
  const RkA = R.add(A.multiplyUnsafe(k));
536
646
  // Extended group equation
537
647
  // [8][S]B = [8]R + [8][k]A'
538
- return RkA.subtract(SB).clearCofactor().equals(Point.ZERO);
648
+ return RkA.subtract(SB).clearCofactor().is0();
539
649
  }
540
650
 
541
- 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.
542
652
 
543
653
  const utils = {
544
654
  getExtendedPublicKey,
545
655
  /** ed25519 priv keys are uniform 32b. No need to check for modulo bias, like in secp256k1. */
546
- randomPrivateKey: (): Uint8Array => randomBytes(Fp.BYTES),
656
+ randomPrivateKey: (): Uint8Array => randomBytes_!(Fp.BYTES),
547
657
 
548
658
  /**
549
659
  * We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
@@ -552,18 +662,49 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
552
662
  * @param windowSize 2, 4, 8, 16
553
663
  */
554
664
  precompute(windowSize = 8, point: ExtPointType = Point.BASE): ExtPointType {
555
- point._setWindowSize(windowSize);
556
- point.multiply(BigInt(3));
557
- return point;
665
+ return point.precompute(windowSize, false);
558
666
  },
559
667
  };
560
668
 
561
- return {
562
- CURVE,
563
- getPublicKey,
564
- sign,
565
- verify,
566
- ExtendedPoint: Point,
567
- 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,
568
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);
569
710
  }