@noble/curves 0.6.4 → 0.7.1

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 (172) hide show
  1. package/README.md +486 -298
  2. package/{lib/_shortw_utils.d.ts → _shortw_utils.d.ts} +1 -1
  3. package/_shortw_utils.d.ts.map +1 -0
  4. package/{lib/_shortw_utils.js → _shortw_utils.js} +2 -0
  5. package/_shortw_utils.js.map +1 -0
  6. package/{lib/abstract → abstract}/bls.d.ts +4 -9
  7. package/abstract/bls.d.ts.map +1 -0
  8. package/{lib/abstract → abstract}/bls.js +13 -26
  9. package/abstract/bls.js.map +1 -0
  10. package/{lib/abstract → abstract}/curve.d.ts +1 -0
  11. package/abstract/curve.d.ts.map +1 -0
  12. package/{lib/abstract → abstract}/curve.js +1 -0
  13. package/abstract/curve.js.map +1 -0
  14. package/{lib/abstract → abstract}/edwards.d.ts +1 -0
  15. package/abstract/edwards.d.ts.map +1 -0
  16. package/{lib/abstract → abstract}/edwards.js +9 -15
  17. package/abstract/edwards.js.map +1 -0
  18. package/{lib/abstract → abstract}/hash-to-curve.d.ts +5 -5
  19. package/abstract/hash-to-curve.d.ts.map +1 -0
  20. package/{lib/abstract → abstract}/hash-to-curve.js +41 -38
  21. package/abstract/hash-to-curve.js.map +1 -0
  22. package/{lib/abstract → abstract}/modular.d.ts +1 -0
  23. package/abstract/modular.d.ts.map +1 -0
  24. package/{lib/abstract → abstract}/modular.js +2 -1
  25. package/abstract/modular.js.map +1 -0
  26. package/{lib/abstract → abstract}/montgomery.d.ts +4 -3
  27. package/abstract/montgomery.d.ts.map +1 -0
  28. package/{lib/abstract → abstract}/montgomery.js +12 -9
  29. package/abstract/montgomery.js.map +1 -0
  30. package/{lib/abstract → abstract}/poseidon.d.ts +1 -0
  31. package/abstract/poseidon.d.ts.map +1 -0
  32. package/{lib/abstract → abstract}/poseidon.js +1 -0
  33. package/abstract/poseidon.js.map +1 -0
  34. package/{lib/abstract → abstract}/utils.d.ts +12 -1
  35. package/abstract/utils.d.ts.map +1 -0
  36. package/{lib/abstract → abstract}/utils.js +96 -10
  37. package/abstract/utils.js.map +1 -0
  38. package/{lib/abstract → abstract}/weierstrass.d.ts +6 -6
  39. package/abstract/weierstrass.d.ts.map +1 -0
  40. package/{lib/abstract → abstract}/weierstrass.js +74 -115
  41. package/abstract/weierstrass.js.map +1 -0
  42. package/{lib/bls12-381.d.ts → bls12-381.d.ts} +1 -0
  43. package/bls12-381.d.ts.map +1 -0
  44. package/{lib/bls12-381.js → bls12-381.js} +41 -7
  45. package/bls12-381.js.map +1 -0
  46. package/{lib/bn.d.ts → bn.d.ts} +1 -0
  47. package/bn.d.ts.map +1 -0
  48. package/{lib/bn.js → bn.js} +1 -0
  49. package/bn.js.map +1 -0
  50. package/{lib/ed25519.d.ts → ed25519.d.ts} +2 -1
  51. package/ed25519.d.ts.map +1 -0
  52. package/{lib/ed25519.js → ed25519.js} +6 -5
  53. package/ed25519.js.map +1 -0
  54. package/{lib/ed448.d.ts → ed448.d.ts} +2 -1
  55. package/ed448.d.ts.map +1 -0
  56. package/{lib/ed448.js → ed448.js} +4 -3
  57. package/ed448.js.map +1 -0
  58. package/{lib/esm → esm}/_shortw_utils.js +2 -0
  59. package/esm/_shortw_utils.js.map +1 -0
  60. package/{lib/esm → esm}/abstract/bls.js +14 -27
  61. package/esm/abstract/bls.js.map +1 -0
  62. package/{lib/esm → esm}/abstract/curve.js +1 -0
  63. package/esm/abstract/curve.js.map +1 -0
  64. package/{lib/esm → esm}/abstract/edwards.js +9 -15
  65. package/esm/abstract/edwards.js.map +1 -0
  66. package/{lib/esm → esm}/abstract/hash-to-curve.js +40 -36
  67. package/esm/abstract/hash-to-curve.js.map +1 -0
  68. package/{lib/esm → esm}/abstract/modular.js +2 -1
  69. package/esm/abstract/modular.js.map +1 -0
  70. package/{lib/esm → esm}/abstract/montgomery.js +12 -9
  71. package/esm/abstract/montgomery.js.map +1 -0
  72. package/{lib/esm → esm}/abstract/poseidon.js +1 -0
  73. package/esm/abstract/poseidon.js.map +1 -0
  74. package/{lib/esm → esm}/abstract/utils.js +93 -9
  75. package/esm/abstract/utils.js.map +1 -0
  76. package/{lib/esm → esm}/abstract/weierstrass.js +74 -115
  77. package/esm/abstract/weierstrass.js.map +1 -0
  78. package/{lib/esm → esm}/bls12-381.js +41 -7
  79. package/esm/bls12-381.js.map +1 -0
  80. package/{lib/esm → esm}/bn.js +1 -0
  81. package/esm/bn.js.map +1 -0
  82. package/{lib/esm → esm}/ed25519.js +7 -6
  83. package/esm/ed25519.js.map +1 -0
  84. package/{lib/esm → esm}/ed448.js +4 -3
  85. package/esm/ed448.js.map +1 -0
  86. package/{lib → esm}/index.js +1 -0
  87. package/esm/index.js.map +1 -0
  88. package/{lib/esm → esm}/jubjub.js +1 -0
  89. package/esm/jubjub.js.map +1 -0
  90. package/{lib/esm → esm}/p192.js +1 -0
  91. package/esm/p192.js.map +1 -0
  92. package/{lib/esm → esm}/p224.js +1 -0
  93. package/esm/p224.js.map +1 -0
  94. package/{lib/esm → esm}/p256.js +2 -1
  95. package/esm/p256.js.map +1 -0
  96. package/{lib/esm → esm}/p384.js +2 -1
  97. package/esm/p384.js.map +1 -0
  98. package/{lib/esm → esm}/p521.js +2 -1
  99. package/esm/p521.js.map +1 -0
  100. package/{lib/esm → esm}/package.json +0 -0
  101. package/{lib/esm → esm}/pasta.js +1 -0
  102. package/esm/pasta.js.map +1 -0
  103. package/{lib/esm → esm}/secp256k1.js +51 -50
  104. package/esm/secp256k1.js.map +1 -0
  105. package/{lib/esm → esm}/stark.js +5 -4
  106. package/esm/stark.js.map +1 -0
  107. package/index.d.ts +1 -0
  108. package/index.d.ts.map +1 -0
  109. package/index.js +3 -0
  110. package/index.js.map +1 -0
  111. package/{lib/jubjub.d.ts → jubjub.d.ts} +1 -0
  112. package/jubjub.d.ts.map +1 -0
  113. package/{lib/jubjub.js → jubjub.js} +1 -0
  114. package/jubjub.js.map +1 -0
  115. package/{lib/p192.d.ts → p192.d.ts} +1 -2
  116. package/p192.d.ts.map +1 -0
  117. package/{lib/p192.js → p192.js} +1 -0
  118. package/p192.js.map +1 -0
  119. package/{lib/p224.d.ts → p224.d.ts} +1 -2
  120. package/p224.d.ts.map +1 -0
  121. package/{lib/p224.js → p224.js} +1 -0
  122. package/p224.js.map +1 -0
  123. package/{lib/p256.d.ts → p256.d.ts} +2 -3
  124. package/p256.d.ts.map +1 -0
  125. package/{lib/p256.js → p256.js} +2 -1
  126. package/p256.js.map +1 -0
  127. package/{lib/p384.d.ts → p384.d.ts} +2 -3
  128. package/p384.d.ts.map +1 -0
  129. package/{lib/p384.js → p384.js} +2 -1
  130. package/p384.js.map +1 -0
  131. package/{lib/p521.d.ts → p521.d.ts} +2 -3
  132. package/p521.d.ts.map +1 -0
  133. package/{lib/p521.js → p521.js} +2 -1
  134. package/p521.js.map +1 -0
  135. package/package.json +84 -79
  136. package/{lib/pasta.d.ts → pasta.d.ts} +1 -0
  137. package/pasta.d.ts.map +1 -0
  138. package/{lib/pasta.js → pasta.js} +1 -0
  139. package/pasta.js.map +1 -0
  140. package/{lib/secp256k1.d.ts → secp256k1.d.ts} +20 -6
  141. package/secp256k1.d.ts.map +1 -0
  142. package/{lib/secp256k1.js → secp256k1.js} +48 -47
  143. package/secp256k1.js.map +1 -0
  144. package/src/_shortw_utils.ts +20 -0
  145. package/src/abstract/bls.ts +376 -0
  146. package/src/abstract/curve.ts +199 -0
  147. package/src/abstract/edwards.ts +479 -0
  148. package/src/abstract/hash-to-curve.ts +220 -0
  149. package/src/abstract/modular.ts +417 -0
  150. package/src/abstract/montgomery.ts +186 -0
  151. package/src/abstract/poseidon.ts +119 -0
  152. package/src/abstract/utils.ts +246 -0
  153. package/src/abstract/weierstrass.ts +1177 -0
  154. package/src/bls12-381.ts +1274 -0
  155. package/src/bn.ts +21 -0
  156. package/src/ed25519.ts +428 -0
  157. package/src/ed448.ts +241 -0
  158. package/{lib/esm/index.js → src/index.ts} +0 -1
  159. package/src/jubjub.ts +58 -0
  160. package/src/p192.ts +25 -0
  161. package/src/p224.ts +25 -0
  162. package/src/p256.ts +53 -0
  163. package/src/p384.ts +57 -0
  164. package/src/p521.ts +57 -0
  165. package/src/pasta.ts +31 -0
  166. package/src/secp256k1.ts +270 -0
  167. package/src/stark.ts +356 -0
  168. package/{lib/stark.d.ts → stark.d.ts} +1 -1
  169. package/stark.d.ts.map +1 -0
  170. package/{lib/stark.js → stark.js} +5 -4
  171. package/stark.js.map +1 -0
  172. package/lib/index.d.ts +0 -0
package/src/bn.ts ADDED
@@ -0,0 +1,21 @@
1
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
+ import { sha256 } from '@noble/hashes/sha256';
3
+ import { weierstrass } from './abstract/weierstrass.js';
4
+ import { getHash } from './_shortw_utils.js';
5
+ import { Fp } from './abstract/modular.js';
6
+ /**
7
+ * bn254 pairing-friendly curve.
8
+ * Previously known as alt_bn_128, when it had 128-bit security.
9
+ * Recent research shown it's weaker, the naming has been adjusted to its prime bit count.
10
+ * https://github.com/zcash/zcash/issues/2502
11
+ */
12
+ export const bn254 = weierstrass({
13
+ a: BigInt(0),
14
+ b: BigInt(3),
15
+ Fp: Fp(BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')),
16
+ n: BigInt('0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001'),
17
+ Gx: BigInt(1),
18
+ Gy: BigInt(2),
19
+ h: BigInt(1),
20
+ ...getHash(sha256),
21
+ });
package/src/ed25519.ts ADDED
@@ -0,0 +1,428 @@
1
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
+ import { sha512 } from '@noble/hashes/sha512';
3
+ import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
4
+ import { twistedEdwards, ExtPointType } from './abstract/edwards.js';
5
+ import { montgomery } from './abstract/montgomery.js';
6
+ import { mod, pow2, isNegativeLE, Fp as Field, FpSqrtEven } from './abstract/modular.js';
7
+ import {
8
+ equalBytes,
9
+ bytesToHex,
10
+ bytesToNumberLE,
11
+ numberToBytesLE,
12
+ Hex,
13
+ ensureBytes,
14
+ } from './abstract/utils.js';
15
+ import * as htf from './abstract/hash-to-curve.js';
16
+
17
+ /**
18
+ * ed25519 Twisted Edwards curve with following addons:
19
+ * - X25519 ECDH
20
+ * - Ristretto cofactor elimination
21
+ * - Elligator hash-to-group / point indistinguishability
22
+ */
23
+
24
+ const ED25519_P = BigInt(
25
+ '57896044618658097711785492504343953926634992332820282019728792003956564819949'
26
+ );
27
+ // √(-1) aka √(a) aka 2^((p-1)/4)
28
+ const ED25519_SQRT_M1 = BigInt(
29
+ '19681161376707505956807079304988542015446066515923890162744021073123829784752'
30
+ );
31
+
32
+ // prettier-ignore
33
+ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _5n = BigInt(5);
34
+ // prettier-ignore
35
+ const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80);
36
+ function ed25519_pow_2_252_3(x: bigint) {
37
+ const P = ED25519_P;
38
+ const x2 = (x * x) % P;
39
+ const b2 = (x2 * x) % P; // x^3, 11
40
+ const b4 = (pow2(b2, _2n, P) * b2) % P; // x^15, 1111
41
+ const b5 = (pow2(b4, _1n, P) * x) % P; // x^31
42
+ const b10 = (pow2(b5, _5n, P) * b5) % P;
43
+ const b20 = (pow2(b10, _10n, P) * b10) % P;
44
+ const b40 = (pow2(b20, _20n, P) * b20) % P;
45
+ const b80 = (pow2(b40, _40n, P) * b40) % P;
46
+ const b160 = (pow2(b80, _80n, P) * b80) % P;
47
+ const b240 = (pow2(b160, _80n, P) * b80) % P;
48
+ const b250 = (pow2(b240, _10n, P) * b10) % P;
49
+ const pow_p_5_8 = (pow2(b250, _2n, P) * x) % P;
50
+ // ^ To pow to (p+3)/8, multiply it by x.
51
+ return { pow_p_5_8, b2 };
52
+ }
53
+ function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
54
+ // Section 5: For X25519, in order to decode 32 random bytes as an integer scalar,
55
+ // set the three least significant bits of the first byte
56
+ bytes[0] &= 248; // 0b1111_1000
57
+ // and the most significant bit of the last to zero,
58
+ bytes[31] &= 127; // 0b0111_1111
59
+ // set the second most significant bit of the last byte to 1
60
+ bytes[31] |= 64; // 0b0100_0000
61
+ return bytes;
62
+ }
63
+ // sqrt(u/v)
64
+ function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
65
+ const P = ED25519_P;
66
+ const v3 = mod(v * v * v, P); // v³
67
+ const v7 = mod(v3 * v3 * v, P); // v⁷
68
+ // (p+3)/8 and (p-5)/8
69
+ const pow = ed25519_pow_2_252_3(u * v7).pow_p_5_8;
70
+ let x = mod(u * v3 * pow, P); // (uv³)(uv⁷)^(p-5)/8
71
+ const vx2 = mod(v * x * x, P); // vx²
72
+ const root1 = x; // First root candidate
73
+ const root2 = mod(x * ED25519_SQRT_M1, P); // Second root candidate
74
+ const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root
75
+ const useRoot2 = vx2 === mod(-u, P); // If vx² = -u, set x <-- x * 2^((p-1)/4)
76
+ const noRoot = vx2 === mod(-u * ED25519_SQRT_M1, P); // There is no valid root, vx² = -u√(-1)
77
+ if (useRoot1) x = root1;
78
+ if (useRoot2 || noRoot) x = root2; // We return root2 anyway, for const-time
79
+ if (isNegativeLE(x, P)) x = mod(-x, P);
80
+ return { isValid: useRoot1 || useRoot2, value: x };
81
+ }
82
+
83
+ // Just in case
84
+ export const ED25519_TORSION_SUBGROUP = [
85
+ '0100000000000000000000000000000000000000000000000000000000000000',
86
+ 'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a',
87
+ '0000000000000000000000000000000000000000000000000000000000000080',
88
+ '26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05',
89
+ 'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
90
+ '26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85',
91
+ '0000000000000000000000000000000000000000000000000000000000000000',
92
+ 'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
93
+ ];
94
+
95
+ const Fp = Field(ED25519_P, undefined, true);
96
+
97
+ const ED25519_DEF = {
98
+ // Param: a
99
+ a: BigInt(-1),
100
+ // Equal to -121665/121666 over finite field.
101
+ // Negative number is P - number, and division is invert(number, P)
102
+ d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
103
+ // Finite field 𝔽p over which we'll do calculations; 2n ** 255n - 19n
104
+ Fp,
105
+ // Subgroup order: how many points ed25519 has
106
+ // 2n ** 252n + 27742317777372353535851937790883648493n;
107
+ n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
108
+ // Cofactor
109
+ h: BigInt(8),
110
+ // Base point (x, y) aka generator point
111
+ Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'),
112
+ Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'),
113
+ hash: sha512,
114
+ randomBytes,
115
+ adjustScalarBytes,
116
+ // dom2
117
+ // Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3.
118
+ // Constant-time, u/√v
119
+ uvRatio,
120
+ } as const;
121
+
122
+ export const ed25519 = twistedEdwards(ED25519_DEF);
123
+ function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
124
+ if (ctx.length > 255) throw new Error('Context is too big');
125
+ return concatBytes(
126
+ utf8ToBytes('SigEd25519 no Ed25519 collisions'),
127
+ new Uint8Array([phflag ? 1 : 0, ctx.length]),
128
+ ctx,
129
+ data
130
+ );
131
+ }
132
+ export const ed25519ctx = twistedEdwards({ ...ED25519_DEF, domain: ed25519_domain });
133
+ export const ed25519ph = twistedEdwards({
134
+ ...ED25519_DEF,
135
+ domain: ed25519_domain,
136
+ preHash: sha512,
137
+ });
138
+
139
+ export const x25519 = montgomery({
140
+ P: ED25519_P,
141
+ a: BigInt(486662),
142
+ montgomeryBits: 255, // n is 253 bits
143
+ nByteLength: 32,
144
+ Gu: BigInt(9),
145
+ powPminus2: (x: bigint): bigint => {
146
+ const P = ED25519_P;
147
+ // x^(p-2) aka x^(2^255-21)
148
+ const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x);
149
+ return mod(pow2(pow_p_5_8, BigInt(3), P) * b2, P);
150
+ },
151
+ adjustScalarBytes,
152
+ });
153
+
154
+ // Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)
155
+ // NOTE: very important part is usage of FpSqrtEven for ELL2_C1_EDWARDS, since
156
+ // SageMath returns different root first and everything falls apart
157
+
158
+ const ELL2_C1 = (Fp.ORDER + BigInt(3)) / BigInt(8); // 1. c1 = (q + 3) / 8 # Integer arithmetic
159
+
160
+ const ELL2_C2 = Fp.pow(_2n, ELL2_C1); // 2. c2 = 2^c1
161
+ const ELL2_C3 = Fp.sqrt(Fp.neg(Fp.ONE)); // 3. c3 = sqrt(-1)
162
+ const ELL2_C4 = (Fp.ORDER - BigInt(5)) / BigInt(8); // 4. c4 = (q - 5) / 8 # Integer arithmetic
163
+ const ELL2_J = BigInt(486662);
164
+
165
+ // prettier-ignore
166
+ function map_to_curve_elligator2_curve25519(u: bigint) {
167
+ let tv1 = Fp.sqr(u); // 1. tv1 = u^2
168
+ tv1 = Fp.mul(tv1, _2n); // 2. tv1 = 2 * tv1
169
+ let xd = Fp.add(tv1, Fp.ONE); // 3. xd = tv1 + 1 # Nonzero: -1 is square (mod p), tv1 is not
170
+ let x1n = Fp.neg(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
171
+ let tv2 = Fp.sqr(xd); // 5. tv2 = xd^2
172
+ let gxd = Fp.mul(tv2, xd); // 6. gxd = tv2 * xd # gxd = xd^3
173
+ let gx1 = Fp.mul(tv1, ELL2_J); // 7. gx1 = J * tv1 # x1n + J * xd
174
+ gx1 = Fp.mul(gx1, x1n); // 8. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
175
+ gx1 = Fp.add(gx1, tv2); // 9. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
176
+ gx1 = Fp.mul(gx1, x1n); // 10. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
177
+ let tv3 = Fp.sqr(gxd); // 11. tv3 = gxd^2
178
+ tv2 = Fp.sqr(tv3); // 12. tv2 = tv3^2 # gxd^4
179
+ tv3 = Fp.mul(tv3, gxd); // 13. tv3 = tv3 * gxd # gxd^3
180
+ tv3 = Fp.mul(tv3, gx1); // 14. tv3 = tv3 * gx1 # gx1 * gxd^3
181
+ tv2 = Fp.mul(tv2, tv3); // 15. tv2 = tv2 * tv3 # gx1 * gxd^7
182
+ let y11 = Fp.pow(tv2, ELL2_C4); // 16. y11 = tv2^c4 # (gx1 * gxd^7)^((p - 5) / 8)
183
+ y11 = Fp.mul(y11, tv3); // 17. y11 = y11 * tv3 # gx1*gxd^3*(gx1*gxd^7)^((p-5)/8)
184
+ let y12 = Fp.mul(y11, ELL2_C3); // 18. y12 = y11 * c3
185
+ tv2 = Fp.sqr(y11); // 19. tv2 = y11^2
186
+ tv2 = Fp.mul(tv2, gxd); // 20. tv2 = tv2 * gxd
187
+ let e1 = Fp.eql(tv2, gx1); // 21. e1 = tv2 == gx1
188
+ let y1 = Fp.cmov(y12, y11, e1); // 22. y1 = CMOV(y12, y11, e1) # If g(x1) is square, this is its sqrt
189
+ let x2n = Fp.mul(x1n, tv1); // 23. x2n = x1n * tv1 # x2 = x2n / xd = 2 * u^2 * x1n / xd
190
+ let y21 = Fp.mul(y11, u); // 24. y21 = y11 * u
191
+ y21 = Fp.mul(y21, ELL2_C2); // 25. y21 = y21 * c2
192
+ let y22 = Fp.mul(y21, ELL2_C3); // 26. y22 = y21 * c3
193
+ let gx2 = Fp.mul(gx1, tv1); // 27. gx2 = gx1 * tv1 # g(x2) = gx2 / gxd = 2 * u^2 * g(x1)
194
+ tv2 = Fp.sqr(y21); // 28. tv2 = y21^2
195
+ tv2 = Fp.mul(tv2, gxd); // 29. tv2 = tv2 * gxd
196
+ let e2 = Fp.eql(tv2, gx2); // 30. e2 = tv2 == gx2
197
+ let y2 = Fp.cmov(y22, y21, e2); // 31. y2 = CMOV(y22, y21, e2) # If g(x2) is square, this is its sqrt
198
+ tv2 = Fp.sqr(y1); // 32. tv2 = y1^2
199
+ tv2 = Fp.mul(tv2, gxd); // 33. tv2 = tv2 * gxd
200
+ let e3 = Fp.eql(tv2, gx1); // 34. e3 = tv2 == gx1
201
+ let xn = Fp.cmov(x2n, x1n, e3); // 35. xn = CMOV(x2n, x1n, e3) # If e3, x = x1, else x = x2
202
+ let y = Fp.cmov(y2, y1, e3); // 36. y = CMOV(y2, y1, e3) # If e3, y = y1, else y = y2
203
+ let e4 = Fp.isOdd(y); // 37. e4 = sgn0(y) == 1 # Fix sign of y
204
+ y = Fp.cmov(y, Fp.neg(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4)
205
+ return { xMn: xn, xMd: xd, yMn: y, yMd: 1n }; // 39. return (xn, xd, y, 1)
206
+ }
207
+
208
+ const ELL2_C1_EDWARDS = FpSqrtEven(Fp, Fp.neg(BigInt(486664))); // sgn0(c1) MUST equal 0
209
+ function map_to_curve_elligator2_edwards25519(u: bigint) {
210
+ const { xMn, xMd, yMn, yMd } = map_to_curve_elligator2_curve25519(u); // 1. (xMn, xMd, yMn, yMd) = map_to_curve_elligator2_curve25519(u)
211
+ let xn = Fp.mul(xMn, yMd); // 2. xn = xMn * yMd
212
+ xn = Fp.mul(xn, ELL2_C1_EDWARDS); // 3. xn = xn * c1
213
+ let xd = Fp.mul(xMd, yMn); // 4. xd = xMd * yMn # xn / xd = c1 * xM / yM
214
+ let yn = Fp.sub(xMn, xMd); // 5. yn = xMn - xMd
215
+ let yd = Fp.add(xMn, xMd); // 6. yd = xMn + xMd # (n / d - 1) / (n / d + 1) = (n - d) / (n + d)
216
+ let tv1 = Fp.mul(xd, yd); // 7. tv1 = xd * yd
217
+ let e = Fp.eql(tv1, Fp.ZERO); // 8. e = tv1 == 0
218
+ xn = Fp.cmov(xn, Fp.ZERO, e); // 9. xn = CMOV(xn, 0, e)
219
+ xd = Fp.cmov(xd, Fp.ONE, e); // 10. xd = CMOV(xd, 1, e)
220
+ yn = Fp.cmov(yn, Fp.ONE, e); // 11. yn = CMOV(yn, 1, e)
221
+ yd = Fp.cmov(yd, Fp.ONE, e); // 12. yd = CMOV(yd, 1, e)
222
+
223
+ const inv = Fp.invertBatch([xd, yd]); // batch division
224
+ return { x: Fp.mul(xn, inv[0]), y: Fp.mul(yn, inv[1]) }; // 13. return (xn, xd, yn, yd)
225
+ }
226
+ const { hashToCurve, encodeToCurve } = htf.createHasher(
227
+ ed25519.ExtendedPoint,
228
+ (scalars: bigint[]) => map_to_curve_elligator2_edwards25519(scalars[0]),
229
+ {
230
+ DST: 'edwards25519_XMD:SHA-512_ELL2_RO_',
231
+ encodeDST: 'edwards25519_XMD:SHA-512_ELL2_NU_',
232
+ p: Fp.ORDER,
233
+ m: 1,
234
+ k: 128,
235
+ expand: 'xmd',
236
+ hash: sha512,
237
+ }
238
+ );
239
+ export { hashToCurve, encodeToCurve };
240
+
241
+ function assertRstPoint(other: unknown) {
242
+ if (!(other instanceof RistrettoPoint)) throw new Error('RistrettoPoint expected');
243
+ }
244
+ // √(-1) aka √(a) aka 2^((p-1)/4)
245
+ const SQRT_M1 = BigInt(
246
+ '19681161376707505956807079304988542015446066515923890162744021073123829784752'
247
+ );
248
+ // √(ad - 1)
249
+ const SQRT_AD_MINUS_ONE = BigInt(
250
+ '25063068953384623474111414158702152701244531502492656460079210482610430750235'
251
+ );
252
+ // 1 / √(a-d)
253
+ const INVSQRT_A_MINUS_D = BigInt(
254
+ '54469307008909316920995813868745141605393597292927456921205312896311721017578'
255
+ );
256
+ // 1-d²
257
+ const ONE_MINUS_D_SQ = BigInt(
258
+ '1159843021668779879193775521855586647937357759715417654439879720876111806838'
259
+ );
260
+ // (d-1)²
261
+ const D_MINUS_ONE_SQ = BigInt(
262
+ '40440834346308536858101042469323190826248399146238708352240133220865137265952'
263
+ );
264
+ // Calculates 1/√(number)
265
+ const invertSqrt = (number: bigint) => uvRatio(_1n, number);
266
+
267
+ const MAX_255B = BigInt('0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
268
+ const bytes255ToNumberLE = (bytes: Uint8Array) =>
269
+ ed25519.CURVE.Fp.create(bytesToNumberLE(bytes) & MAX_255B);
270
+
271
+ type ExtendedPoint = ExtPointType;
272
+
273
+ // Computes Elligator map for Ristretto
274
+ // https://ristretto.group/formulas/elligator.html
275
+ function calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
276
+ const { d } = ed25519.CURVE;
277
+ const P = ed25519.CURVE.Fp.ORDER;
278
+ const mod = ed25519.CURVE.Fp.create;
279
+ const r = mod(SQRT_M1 * r0 * r0); // 1
280
+ const Ns = mod((r + _1n) * ONE_MINUS_D_SQ); // 2
281
+ let c = BigInt(-1); // 3
282
+ const D = mod((c - d * r) * mod(r + d)); // 4
283
+ let { isValid: Ns_D_is_sq, value: s } = uvRatio(Ns, D); // 5
284
+ let s_ = mod(s * r0); // 6
285
+ if (!isNegativeLE(s_, P)) s_ = mod(-s_);
286
+ if (!Ns_D_is_sq) s = s_; // 7
287
+ if (!Ns_D_is_sq) c = r; // 8
288
+ const Nt = mod(c * (r - _1n) * D_MINUS_ONE_SQ - D); // 9
289
+ const s2 = s * s;
290
+ const W0 = mod((s + s) * D); // 10
291
+ const W1 = mod(Nt * SQRT_AD_MINUS_ONE); // 11
292
+ const W2 = mod(_1n - s2); // 12
293
+ const W3 = mod(_1n + s2); // 13
294
+ return new ed25519.ExtendedPoint(mod(W0 * W3), mod(W2 * W1), mod(W1 * W3), mod(W0 * W2));
295
+ }
296
+
297
+ /**
298
+ * Each ed25519/ExtendedPoint has 8 different equivalent points. This can be
299
+ * a source of bugs for protocols like ring signatures. Ristretto was created to solve this.
300
+ * Ristretto point operates in X:Y:Z:T extended coordinates like ExtendedPoint,
301
+ * but it should work in its own namespace: do not combine those two.
302
+ * https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448
303
+ */
304
+ export class RistrettoPoint {
305
+ static BASE = new RistrettoPoint(ed25519.ExtendedPoint.BASE);
306
+ static ZERO = new RistrettoPoint(ed25519.ExtendedPoint.ZERO);
307
+
308
+ // Private property to discourage combining ExtendedPoint + RistrettoPoint
309
+ // Always use Ristretto encoding/decoding instead.
310
+ constructor(private readonly ep: ExtendedPoint) {}
311
+ /**
312
+ * Takes uniform output of 64-bit hash function like sha512 and converts it to `RistrettoPoint`.
313
+ * The hash-to-group operation applies Elligator twice and adds the results.
314
+ * **Note:** this is one-way map, there is no conversion from point to hash.
315
+ * https://ristretto.group/formulas/elligator.html
316
+ * @param hex 64-bit output of a hash function
317
+ */
318
+ static hashToCurve(hex: Hex): RistrettoPoint {
319
+ hex = ensureBytes('ristrettoHash', hex, 64);
320
+ const r1 = bytes255ToNumberLE(hex.slice(0, 32));
321
+ const R1 = calcElligatorRistrettoMap(r1);
322
+ const r2 = bytes255ToNumberLE(hex.slice(32, 64));
323
+ const R2 = calcElligatorRistrettoMap(r2);
324
+ return new RistrettoPoint(R1.add(R2));
325
+ }
326
+
327
+ /**
328
+ * Converts ristretto-encoded string to ristretto point.
329
+ * https://ristretto.group/formulas/decoding.html
330
+ * @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
331
+ */
332
+ static fromHex(hex: Hex): RistrettoPoint {
333
+ hex = ensureBytes('ristrettoHex', hex, 32);
334
+ const { a, d } = ed25519.CURVE;
335
+ const P = ed25519.CURVE.Fp.ORDER;
336
+ const mod = ed25519.CURVE.Fp.create;
337
+ const emsg = 'RistrettoPoint.fromHex: the hex is not valid encoding of RistrettoPoint';
338
+ const s = bytes255ToNumberLE(hex);
339
+ // 1. Check that s_bytes is the canonical encoding of a field element, or else abort.
340
+ // 3. Check that s is non-negative, or else abort
341
+ if (!equalBytes(numberToBytesLE(s, 32), hex) || isNegativeLE(s, P)) throw new Error(emsg);
342
+ const s2 = mod(s * s);
343
+ const u1 = mod(_1n + a * s2); // 4 (a is -1)
344
+ const u2 = mod(_1n - a * s2); // 5
345
+ const u1_2 = mod(u1 * u1);
346
+ const u2_2 = mod(u2 * u2);
347
+ const v = mod(a * d * u1_2 - u2_2); // 6
348
+ const { isValid, value: I } = invertSqrt(mod(v * u2_2)); // 7
349
+ const Dx = mod(I * u2); // 8
350
+ const Dy = mod(I * Dx * v); // 9
351
+ let x = mod((s + s) * Dx); // 10
352
+ if (isNegativeLE(x, P)) x = mod(-x); // 10
353
+ const y = mod(u1 * Dy); // 11
354
+ const t = mod(x * y); // 12
355
+ if (!isValid || isNegativeLE(t, P) || y === _0n) throw new Error(emsg);
356
+ return new RistrettoPoint(new ed25519.ExtendedPoint(x, y, _1n, t));
357
+ }
358
+
359
+ /**
360
+ * Encodes ristretto point to Uint8Array.
361
+ * https://ristretto.group/formulas/encoding.html
362
+ */
363
+ toRawBytes(): Uint8Array {
364
+ let { ex: x, ey: y, ez: z, et: t } = this.ep;
365
+ const P = ed25519.CURVE.Fp.ORDER;
366
+ const mod = ed25519.CURVE.Fp.create;
367
+ const u1 = mod(mod(z + y) * mod(z - y)); // 1
368
+ const u2 = mod(x * y); // 2
369
+ // Square root always exists
370
+ const u2sq = mod(u2 * u2);
371
+ const { value: invsqrt } = invertSqrt(mod(u1 * u2sq)); // 3
372
+ const D1 = mod(invsqrt * u1); // 4
373
+ const D2 = mod(invsqrt * u2); // 5
374
+ const zInv = mod(D1 * D2 * t); // 6
375
+ let D: bigint; // 7
376
+ if (isNegativeLE(t * zInv, P)) {
377
+ let _x = mod(y * SQRT_M1);
378
+ let _y = mod(x * SQRT_M1);
379
+ x = _x;
380
+ y = _y;
381
+ D = mod(D1 * INVSQRT_A_MINUS_D);
382
+ } else {
383
+ D = D2; // 8
384
+ }
385
+ if (isNegativeLE(x * zInv, P)) y = mod(-y); // 9
386
+ let s = mod((z - y) * D); // 10 (check footer's note, no sqrt(-a))
387
+ if (isNegativeLE(s, P)) s = mod(-s);
388
+ return numberToBytesLE(s, 32); // 11
389
+ }
390
+
391
+ toHex(): string {
392
+ return bytesToHex(this.toRawBytes());
393
+ }
394
+
395
+ toString(): string {
396
+ return this.toHex();
397
+ }
398
+
399
+ // Compare one point to another.
400
+ equals(other: RistrettoPoint): boolean {
401
+ assertRstPoint(other);
402
+ const { ex: X1, ey: Y1 } = this.ep;
403
+ const { ex: X2, ey: Y2 } = this.ep;
404
+ const mod = ed25519.CURVE.Fp.create;
405
+ // (x1 * y2 == y1 * x2) | (y1 * y2 == x1 * x2)
406
+ const one = mod(X1 * Y2) === mod(Y1 * X2);
407
+ const two = mod(Y1 * Y2) === mod(X1 * X2);
408
+ return one || two;
409
+ }
410
+
411
+ add(other: RistrettoPoint): RistrettoPoint {
412
+ assertRstPoint(other);
413
+ return new RistrettoPoint(this.ep.add(other.ep));
414
+ }
415
+
416
+ subtract(other: RistrettoPoint): RistrettoPoint {
417
+ assertRstPoint(other);
418
+ return new RistrettoPoint(this.ep.subtract(other.ep));
419
+ }
420
+
421
+ multiply(scalar: bigint): RistrettoPoint {
422
+ return new RistrettoPoint(this.ep.multiply(scalar));
423
+ }
424
+
425
+ multiplyUnsafe(scalar: bigint): RistrettoPoint {
426
+ return new RistrettoPoint(this.ep.multiplyUnsafe(scalar));
427
+ }
428
+ }