@noble/curves 1.4.2 → 1.6.0

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 (130) hide show
  1. package/README.md +159 -128
  2. package/_shortw_utils.d.ts.map +1 -1
  3. package/abstract/bls.d.ts +37 -34
  4. package/abstract/bls.d.ts.map +1 -1
  5. package/abstract/bls.js +167 -115
  6. package/abstract/bls.js.map +1 -1
  7. package/abstract/curve.d.ts +14 -1
  8. package/abstract/curve.d.ts.map +1 -1
  9. package/abstract/curve.js +77 -7
  10. package/abstract/curve.js.map +1 -1
  11. package/abstract/edwards.d.ts +12 -0
  12. package/abstract/edwards.d.ts.map +1 -1
  13. package/abstract/edwards.js +84 -75
  14. package/abstract/edwards.js.map +1 -1
  15. package/abstract/hash-to-curve.d.ts.map +1 -1
  16. package/abstract/hash-to-curve.js +4 -2
  17. package/abstract/hash-to-curve.js.map +1 -1
  18. package/abstract/modular.d.ts +4 -0
  19. package/abstract/modular.d.ts.map +1 -1
  20. package/abstract/modular.js +13 -2
  21. package/abstract/modular.js.map +1 -1
  22. package/abstract/montgomery.d.ts.map +1 -1
  23. package/abstract/montgomery.js +4 -9
  24. package/abstract/montgomery.js.map +1 -1
  25. package/abstract/tower.d.ts +107 -0
  26. package/abstract/tower.d.ts.map +1 -0
  27. package/abstract/tower.js +498 -0
  28. package/abstract/tower.js.map +1 -0
  29. package/abstract/utils.d.ts +17 -0
  30. package/abstract/utils.d.ts.map +1 -1
  31. package/abstract/utils.js +50 -1
  32. package/abstract/utils.js.map +1 -1
  33. package/abstract/weierstrass.d.ts +25 -3
  34. package/abstract/weierstrass.d.ts.map +1 -1
  35. package/abstract/weierstrass.js +189 -113
  36. package/abstract/weierstrass.js.map +1 -1
  37. package/bls12-381.d.ts +1 -65
  38. package/bls12-381.d.ts.map +1 -1
  39. package/bls12-381.js +48 -575
  40. package/bls12-381.js.map +1 -1
  41. package/bn254.d.ts +10 -6
  42. package/bn254.d.ts.map +1 -1
  43. package/bn254.js +207 -10
  44. package/bn254.js.map +1 -1
  45. package/ed25519.d.ts +7 -4
  46. package/ed25519.d.ts.map +1 -1
  47. package/ed25519.js +3 -0
  48. package/ed25519.js.map +1 -1
  49. package/esm/_shortw_utils.d.ts.map +1 -1
  50. package/esm/abstract/bls.d.ts +37 -34
  51. package/esm/abstract/bls.d.ts.map +1 -1
  52. package/esm/abstract/bls.js +168 -116
  53. package/esm/abstract/bls.js.map +1 -1
  54. package/esm/abstract/curve.d.ts +14 -1
  55. package/esm/abstract/curve.d.ts.map +1 -1
  56. package/esm/abstract/curve.js +77 -8
  57. package/esm/abstract/curve.js.map +1 -1
  58. package/esm/abstract/edwards.d.ts +12 -0
  59. package/esm/abstract/edwards.d.ts.map +1 -1
  60. package/esm/abstract/edwards.js +87 -78
  61. package/esm/abstract/edwards.js.map +1 -1
  62. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  63. package/esm/abstract/hash-to-curve.js +4 -2
  64. package/esm/abstract/hash-to-curve.js.map +1 -1
  65. package/esm/abstract/modular.d.ts +4 -0
  66. package/esm/abstract/modular.d.ts.map +1 -1
  67. package/esm/abstract/modular.js +12 -2
  68. package/esm/abstract/modular.js.map +1 -1
  69. package/esm/abstract/montgomery.d.ts.map +1 -1
  70. package/esm/abstract/montgomery.js +5 -10
  71. package/esm/abstract/montgomery.js.map +1 -1
  72. package/esm/abstract/tower.d.ts +107 -0
  73. package/esm/abstract/tower.d.ts.map +1 -0
  74. package/esm/abstract/tower.js +494 -0
  75. package/esm/abstract/tower.js.map +1 -0
  76. package/esm/abstract/utils.d.ts +17 -0
  77. package/esm/abstract/utils.d.ts.map +1 -1
  78. package/esm/abstract/utils.js +44 -0
  79. package/esm/abstract/utils.js.map +1 -1
  80. package/esm/abstract/weierstrass.d.ts +25 -3
  81. package/esm/abstract/weierstrass.d.ts.map +1 -1
  82. package/esm/abstract/weierstrass.js +191 -115
  83. package/esm/abstract/weierstrass.js.map +1 -1
  84. package/esm/bls12-381.d.ts +1 -65
  85. package/esm/bls12-381.d.ts.map +1 -1
  86. package/esm/bls12-381.js +50 -577
  87. package/esm/bls12-381.js.map +1 -1
  88. package/esm/bn254.d.ts +10 -6
  89. package/esm/bn254.d.ts.map +1 -1
  90. package/esm/bn254.js +206 -9
  91. package/esm/bn254.js.map +1 -1
  92. package/esm/ed25519.d.ts +7 -4
  93. package/esm/ed25519.d.ts.map +1 -1
  94. package/esm/ed25519.js +3 -0
  95. package/esm/ed25519.js.map +1 -1
  96. package/esm/jubjub.d.ts.map +1 -1
  97. package/esm/jubjub.js +8 -2
  98. package/esm/jubjub.js.map +1 -1
  99. package/esm/p256.d.ts.map +1 -1
  100. package/esm/p384.d.ts.map +1 -1
  101. package/esm/p521.d.ts.map +1 -1
  102. package/esm/secp256k1.d.ts +6 -0
  103. package/esm/secp256k1.d.ts.map +1 -1
  104. package/esm/secp256k1.js +17 -13
  105. package/esm/secp256k1.js.map +1 -1
  106. package/jubjub.d.ts.map +1 -1
  107. package/jubjub.js +8 -2
  108. package/jubjub.js.map +1 -1
  109. package/p256.d.ts.map +1 -1
  110. package/p384.d.ts.map +1 -1
  111. package/p521.d.ts.map +1 -1
  112. package/package.json +27 -19
  113. package/secp256k1.d.ts +6 -0
  114. package/secp256k1.d.ts.map +1 -1
  115. package/secp256k1.js +16 -12
  116. package/secp256k1.js.map +1 -1
  117. package/src/abstract/bls.ts +222 -168
  118. package/src/abstract/curve.ts +80 -8
  119. package/src/abstract/edwards.ts +97 -70
  120. package/src/abstract/hash-to-curve.ts +3 -1
  121. package/src/abstract/modular.ts +13 -3
  122. package/src/abstract/montgomery.ts +11 -10
  123. package/src/abstract/tower.ts +605 -0
  124. package/src/abstract/utils.ts +49 -0
  125. package/src/abstract/weierstrass.ts +179 -104
  126. package/src/bls12-381.ts +53 -707
  127. package/src/bn254.ts +224 -9
  128. package/src/ed25519.ts +5 -2
  129. package/src/jubjub.ts +7 -2
  130. package/src/secp256k1.ts +24 -12
package/src/bn254.ts CHANGED
@@ -1,20 +1,235 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  import { sha256 } from '@noble/hashes/sha256';
3
3
  import { getHash } from './_shortw_utils.js';
4
- import { Field } from './abstract/modular.js';
5
4
  import { weierstrass } from './abstract/weierstrass.js';
5
+ import { randomBytes } from '@noble/hashes/utils';
6
+ import { bls, CurveFn } from './abstract/bls.js';
7
+ import { Field } from './abstract/modular.js';
8
+ import { bitGet, bitLen, notImplemented } from './abstract/utils.js';
9
+ import { tower12, psiFrobenius } from './abstract/tower.js';
10
+ // Types
11
+ import type { Fp, Fp2, Fp6, Fp12 } from './abstract/tower.js';
12
+ // prettier-ignore
13
+ const _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
14
+ // prettier-ignore
15
+ const _6n = BigInt(6);
16
+
17
+ /*
18
+ bn254, previously known as alt_bn_128, when it had 128-bit security.
19
+ Barbulescu-Duquesne 2017 shown it's weaker: just about 100 bits,
20
+ so the naming has been adjusted to its prime bit count:
21
+ https://hal.science/hal-01534101/file/main.pdf
22
+
23
+ There are huge compatibility issues in the ecosystem:
24
+
25
+ 1. Different libraries call it in different ways: "bn254", "bn256", "alt_bn128", "bn128".
26
+ 2. libff has bn128, but it's a different curve with different G2:
27
+ https://github.com/scipr-lab/libff/blob/a44f482e18b8ac04d034c193bd9d7df7817ad73f/libff/algebra/curves/bn128/bn128_init.cpp#L166-L169
28
+ 3. halo2curves bn256 is also incompatible and returns different outputs
29
+
30
+ The goal of our implementation is to support "Ethereum" variant of the curve,
31
+ because it at least has specs:
32
+
33
+ - EIP196 (https://eips.ethereum.org/EIPS/eip-196) describes bn254 ECADD and ECMUL opcodes for EVM
34
+ - EIP197 (https://eips.ethereum.org/EIPS/eip-197) describes bn254 pairings
35
+ - It's hard: EIPs don't have proper tests. EIP-197 returns boolean output instead of Fp12
36
+ - The existing implementations are bad. Some are deprecated:
37
+ - https://github.com/paritytech/bn (old version)
38
+ - https://github.com/ewasm/ethereum-bn128.rs (uses paritytech/bn)
39
+ - https://github.com/zcash-hackworks/bn
40
+ - https://github.com/arkworks-rs/curves/blob/master/bn254/src/lib.rs
41
+ - Python implementations use different towers and produce different Fp12 outputs:
42
+ - https://github.com/ethereum/py_pairing
43
+ - https://github.com/ethereum/execution-specs/blob/master/src/ethereum/crypto/alt_bn128.py
44
+ - Points are encoded differently in different implementations
45
+ */
46
+
47
+ /*
48
+ Seed (X): 4965661367192848881
49
+ Fr: (36x⁴+36x³+18x²+6x+1)
50
+ Fp: (36x⁴+36x³+24x²+6x+1)
51
+ (E / Fp ): Y² = X³+3
52
+ (Et / Fp²): Y² = X³+3/(u+9) (D-type twist)
53
+ Ate loop size: 6x+2
54
+
55
+ Towers:
56
+ - Fp²[u] = Fp/u²+1
57
+ - Fp⁶[v] = Fp²/v³-9-u
58
+ - Fp¹²[w] = Fp⁶/w²-v
59
+ */
60
+ const BN_X = BigInt('4965661367192848881');
61
+ const BN_X_LEN = bitLen(BN_X);
62
+ const SIX_X_SQUARED = _6n * BN_X ** _2n;
63
+
64
+ // Finite field over r. It's for convenience and is not used in the code below.
65
+ const Fr = Field(
66
+ BigInt('21888242871839275222246405745257275088548364400416034343698204186575808495617')
67
+ );
68
+ // Fp2.div(Fp2.mul(Fp2.ONE, _3n), Fp2.NONRESIDUE)
69
+ const Fp2B = {
70
+ c0: BigInt('19485874751759354771024239261021720505790618469301721065564631296452457478373'),
71
+ c1: BigInt('266929791119991161246907387137283842545076965332900288569378510910307636690'),
72
+ };
73
+
74
+ const { Fp, Fp2, Fp6, Fp4Square, Fp12 } = tower12({
75
+ ORDER: BigInt('21888242871839275222246405745257275088696311157297823662689037894645226208583'),
76
+ FP2_NONRESIDUE: [BigInt(9), _1n],
77
+ Fp2mulByB: (num) => Fp2.mul(num, Fp2B),
78
+ // The result of any pairing is in a cyclotomic subgroup
79
+ // https://eprint.iacr.org/2009/565.pdf
80
+ Fp12cyclotomicSquare: ({ c0, c1 }): Fp12 => {
81
+ const { c0: c0c0, c1: c0c1, c2: c0c2 } = c0;
82
+ const { c0: c1c0, c1: c1c1, c2: c1c2 } = c1;
83
+ const { first: t3, second: t4 } = Fp4Square(c0c0, c1c1);
84
+ const { first: t5, second: t6 } = Fp4Square(c1c0, c0c2);
85
+ const { first: t7, second: t8 } = Fp4Square(c0c1, c1c2);
86
+ let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
87
+ return {
88
+ c0: Fp6.create({
89
+ c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0) + T3
90
+ c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5), // 2 * (T5 - c0c1) + T5
91
+ c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
92
+ }), // 2 * (T7 - c0c2) + T7
93
+ c1: Fp6.create({
94
+ c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9), // 2 * (T9 + c1c0) + T9
95
+ c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4), // 2 * (T4 + c1c1) + T4
96
+ c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
97
+ }),
98
+ }; // 2 * (T6 + c1c2) + T6
99
+ },
100
+ Fp12cyclotomicExp(num, n) {
101
+ let z = Fp12.ONE;
102
+ for (let i = BN_X_LEN - 1; i >= 0; i--) {
103
+ z = Fp12._cyclotomicSquare(z);
104
+ if (bitGet(n, i)) z = Fp12.mul(z, num);
105
+ }
106
+ return z;
107
+ },
108
+ // https://eprint.iacr.org/2010/354.pdf
109
+ // https://eprint.iacr.org/2009/565.pdf
110
+ Fp12finalExponentiate: (num) => {
111
+ const powMinusX = (num: Fp12) => Fp12.conjugate(Fp12._cyclotomicExp(num, BN_X));
112
+ const r0 = Fp12.mul(Fp12.conjugate(num), Fp12.inv(num));
113
+ const r = Fp12.mul(Fp12.frobeniusMap(r0, 2), r0);
114
+ const y1 = Fp12._cyclotomicSquare(powMinusX(r));
115
+ const y2 = Fp12.mul(Fp12._cyclotomicSquare(y1), y1);
116
+ const y4 = powMinusX(y2);
117
+ const y6 = powMinusX(Fp12._cyclotomicSquare(y4));
118
+ const y8 = Fp12.mul(Fp12.mul(Fp12.conjugate(y6), y4), Fp12.conjugate(y2));
119
+ const y9 = Fp12.mul(y8, y1);
120
+ return Fp12.mul(
121
+ Fp12.frobeniusMap(Fp12.mul(Fp12.conjugate(r), y9), 3),
122
+ Fp12.mul(
123
+ Fp12.frobeniusMap(y8, 2),
124
+ Fp12.mul(Fp12.frobeniusMap(y9, 1), Fp12.mul(Fp12.mul(y8, y4), r))
125
+ )
126
+ );
127
+ },
128
+ });
129
+
130
+ // END OF CURVE FIELDS
131
+ const { G2psi, psi } = psiFrobenius(Fp, Fp2, Fp2.NONRESIDUE);
132
+
133
+ /*
134
+ No hashToCurve for now (and signatures):
135
+
136
+ - RFC 9380 doesn't mention bn254 and doesn't provide test vectors
137
+ - Overall seems like nobody is using BLS signatures on top of bn254
138
+ - Seems like it can utilize SVDW, which is not implemented yet
139
+ */
140
+ const htfDefaults = Object.freeze({
141
+ // DST: a domain separation tag defined in section 2.2.5
142
+ DST: 'BN254G2_XMD:SHA-256_SVDW_RO_',
143
+ encodeDST: 'BN254G2_XMD:SHA-256_SVDW_RO_',
144
+ p: Fp.ORDER,
145
+ m: 2,
146
+ k: 128,
147
+ expand: 'xmd',
148
+ hash: sha256,
149
+ } as const);
150
+
151
+ /**
152
+ * bn254 (a.k.a. alt_bn128) pairing-friendly curve.
153
+ * Contains G1 / G2 operations and pairings.
154
+ */
155
+ export const bn254: CurveFn = bls({
156
+ // Fields
157
+ fields: { Fp, Fp2, Fp6, Fp12, Fr },
158
+ G1: {
159
+ Fp,
160
+ h: BigInt(1),
161
+ Gx: BigInt(1),
162
+ Gy: BigInt(2),
163
+ a: Fp.ZERO,
164
+ b: _3n,
165
+ htfDefaults: { ...htfDefaults, m: 1, DST: 'BN254G2_XMD:SHA-256_SVDW_RO_' },
166
+ wrapPrivateKey: true,
167
+ allowInfinityPoint: true,
168
+ mapToCurve: notImplemented,
169
+ fromBytes: notImplemented,
170
+ toBytes: notImplemented,
171
+ ShortSignature: {
172
+ fromHex: notImplemented,
173
+ toRawBytes: notImplemented,
174
+ toHex: notImplemented,
175
+ },
176
+ },
177
+ G2: {
178
+ Fp: Fp2,
179
+ // cofactor: (36 * X^4) + (36 * X^3) + (30 * X^2) + 6*X + 1
180
+ h: BigInt('21888242871839275222246405745257275088844257914179612981679871602714643921549'),
181
+ Gx: Fp2.fromBigTuple([
182
+ BigInt('10857046999023057135944570762232829481370756359578518086990519993285655852781'),
183
+ BigInt('11559732032986387107991004021392285783925812861821192530917403151452391805634'),
184
+ ]),
185
+ Gy: Fp2.fromBigTuple([
186
+ BigInt('8495653923123431417604973247489272438418190587263600148770280649306958101930'),
187
+ BigInt('4082367875863433681332203403145435568316851327593401208105741076214120093531'),
188
+ ]),
189
+ a: Fp2.ZERO,
190
+ b: Fp2B,
191
+ hEff: BigInt('21888242871839275222246405745257275088844257914179612981679871602714643921549'),
192
+ htfDefaults: { ...htfDefaults },
193
+ wrapPrivateKey: true,
194
+ allowInfinityPoint: true,
195
+ isTorsionFree: (c, P) => P.multiplyUnsafe(SIX_X_SQUARED).equals(G2psi(c, P)), // [p]P = [6X^2]P
196
+ mapToCurve: notImplemented,
197
+ fromBytes: notImplemented,
198
+ toBytes: notImplemented,
199
+ Signature: {
200
+ fromHex: notImplemented,
201
+ toRawBytes: notImplemented,
202
+ toHex: notImplemented,
203
+ },
204
+ },
205
+ params: {
206
+ ateLoopSize: BN_X * _6n + _2n,
207
+ r: Fr.ORDER,
208
+ xNegative: false,
209
+ twistType: 'divisive',
210
+ },
211
+ htfDefaults,
212
+ hash: sha256,
213
+ randomBytes,
214
+
215
+ postPrecompute: (Rx, Ry, Rz, Qx, Qy, pointAdd) => {
216
+ const q = psi(Qx, Qy);
217
+ ({ Rx, Ry, Rz } = pointAdd(Rx, Ry, Rz, q[0], q[1]));
218
+ const q2 = psi(q[0], q[1]);
219
+ pointAdd(Rx, Ry, Rz, q2[0], Fp2.neg(q2[1]));
220
+ },
221
+ });
222
+
6
223
  /**
7
- * bn254 pairing-friendly curve.
8
- * Previously known as alt_bn_128, when it had 128-bit security.
9
- * Barbulescu-Duquesne 2017 shown it's weaker: just about 100 bits,
10
- * so the naming has been adjusted to its prime bit count
11
- * https://hal.science/hal-01534101/file/main.pdf
224
+ * bn254 weierstrass curve with ECDSA.
225
+ * This is very rare and probably not used anywhere.
226
+ * Instead, you should use G1 / G2, defined above.
12
227
  */
13
- export const bn254 = weierstrass({
228
+ export const bn254_weierstrass = weierstrass({
14
229
  a: BigInt(0),
15
230
  b: BigInt(3),
16
- Fp: Field(BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')),
17
- n: BigInt('0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001'),
231
+ Fp,
232
+ n: BigInt('21888242871839275222246405745257275088548364400416034343698204186575808495617'),
18
233
  Gx: BigInt(1),
19
234
  Gy: BigInt(2),
20
235
  h: BigInt(1),
package/src/ed25519.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import { sha512 } from '@noble/hashes/sha512';
3
3
  import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
4
4
  import { AffinePoint, Group } from './abstract/curve.js';
5
- import { ExtPointType, twistedEdwards } from './abstract/edwards.js';
5
+ import { CurveFn, ExtPointType, twistedEdwards } from './abstract/edwards.js';
6
6
  import { createHasher, expand_message_xmd, htfBasicOpts } from './abstract/hash-to-curve.js';
7
7
  import { Field, FpSqrtEven, isNegativeLE, mod, pow2 } from './abstract/modular.js';
8
8
  import { montgomery } from './abstract/montgomery.js';
@@ -126,7 +126,10 @@ const ed25519Defaults = /* @__PURE__ */ (() =>
126
126
  uvRatio,
127
127
  }) as const)();
128
128
 
129
- export const ed25519 = /* @__PURE__ */ (() => twistedEdwards(ed25519Defaults))();
129
+ /**
130
+ * ed25519 curve with EdDSA signatures.
131
+ */
132
+ export const ed25519: CurveFn = /* @__PURE__ */ (() => twistedEdwards(ed25519Defaults))();
130
133
 
131
134
  function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
132
135
  if (ctx.length > 255) throw new Error('Context is too big');
package/src/jubjub.ts CHANGED
@@ -46,13 +46,18 @@ export function groupHash(tag: Uint8Array, personalization: Uint8Array) {
46
46
  return p;
47
47
  }
48
48
 
49
+ // No secret data is leaked here at all.
50
+ // It operates over public data:
51
+ // const G_SPEND = jubjub.findGroupHash(new Uint8Array(), utf8ToBytes('Item_G_'));
49
52
  export function findGroupHash(m: Uint8Array, personalization: Uint8Array) {
50
53
  const tag = concatBytes(m, new Uint8Array([0]));
54
+ const hashes = [];
51
55
  for (let i = 0; i < 256; i++) {
52
56
  tag[tag.length - 1] = i;
53
57
  try {
54
- return groupHash(tag, personalization);
58
+ hashes.push(groupHash(tag, personalization));
55
59
  } catch (e) {}
56
60
  }
57
- throw new Error('findGroupHash tag overflow');
61
+ if (!hashes.length) throw new Error('findGroupHash tag overflow');
62
+ return hashes[0];
58
63
  }
package/src/secp256k1.ts CHANGED
@@ -5,7 +5,14 @@ import { createCurve } from './_shortw_utils.js';
5
5
  import { createHasher, isogenyMap } from './abstract/hash-to-curve.js';
6
6
  import { Field, mod, pow2 } from './abstract/modular.js';
7
7
  import type { Hex, PrivKey } from './abstract/utils.js';
8
- import { bytesToNumberBE, concatBytes, ensureBytes, numberToBytesBE } from './abstract/utils.js';
8
+ import {
9
+ inRange,
10
+ aInRange,
11
+ bytesToNumberBE,
12
+ concatBytes,
13
+ ensureBytes,
14
+ numberToBytesBE,
15
+ } from './abstract/utils.js';
9
16
  import { ProjPointType as PointType, mapToCurveSimpleSWU } from './abstract/weierstrass.js';
10
17
 
11
18
  const secp256k1P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
@@ -44,6 +51,9 @@ function sqrtMod(y: bigint): bigint {
44
51
 
45
52
  const Fp = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
46
53
 
54
+ /**
55
+ * secp256k1 short weierstrass curve and ECDSA signatures over it.
56
+ */
47
57
  export const secp256k1 = createCurve(
48
58
  {
49
59
  a: BigInt(0), // equation params: a, b
@@ -92,8 +102,6 @@ export const secp256k1 = createCurve(
92
102
  // Schnorr signatures are superior to ECDSA from above. Below is Schnorr-specific BIP0340 code.
93
103
  // https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
94
104
  const _0n = BigInt(0);
95
- const fe = (x: bigint) => typeof x === 'bigint' && _0n < x && x < secp256k1P;
96
- const ge = (x: bigint) => typeof x === 'bigint' && _0n < x && x < secp256k1N;
97
105
  /** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
98
106
  const TAGGED_HASH_PREFIXES: { [tag: string]: Uint8Array } = {};
99
107
  function taggedHash(tag: string, ...messages: Uint8Array[]): Uint8Array {
@@ -127,7 +135,7 @@ function schnorrGetExtPubKey(priv: PrivKey) {
127
135
  * @returns valid point checked for being on-curve
128
136
  */
129
137
  function lift_x(x: bigint): PointType<bigint> {
130
- if (!fe(x)) throw new Error('bad x: need 0 < x < p'); // Fail if x ≥ p.
138
+ aInRange('x', x, _1n, secp256k1P); // Fail if x ≥ p.
131
139
  const xx = modP(x * x);
132
140
  const c = modP(xx * x + BigInt(7)); // Let c = x³ + 7 mod p.
133
141
  let y = sqrtMod(c); // Let y = c^(p+1)/4 mod p.
@@ -136,11 +144,12 @@ function lift_x(x: bigint): PointType<bigint> {
136
144
  p.assertValidity();
137
145
  return p;
138
146
  }
147
+ const num = bytesToNumberBE;
139
148
  /**
140
149
  * Create tagged hash, convert it to bigint, reduce modulo-n.
141
150
  */
142
151
  function challenge(...args: Uint8Array[]): bigint {
143
- return modN(bytesToNumberBE(taggedHash('BIP0340/challenge', ...args)));
152
+ return modN(num(taggedHash('BIP0340/challenge', ...args)));
144
153
  }
145
154
 
146
155
  /**
@@ -162,9 +171,9 @@ function schnorrSign(
162
171
  const m = ensureBytes('message', message);
163
172
  const { bytes: px, scalar: d } = schnorrGetExtPubKey(privateKey); // checks for isWithinCurveOrder
164
173
  const a = ensureBytes('auxRand', auxRand, 32); // Auxiliary random data a: a 32-byte array
165
- const t = numTo32b(d ^ bytesToNumberBE(taggedHash('BIP0340/aux', a))); // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
174
+ const t = numTo32b(d ^ num(taggedHash('BIP0340/aux', a))); // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
166
175
  const rand = taggedHash('BIP0340/nonce', t, px, m); // Let rand = hash/nonce(t || bytes(P) || m)
167
- const k_ = modN(bytesToNumberBE(rand)); // Let k' = int(rand) mod n
176
+ const k_ = modN(num(rand)); // Let k' = int(rand) mod n
168
177
  if (k_ === _0n) throw new Error('sign failed: k is zero'); // Fail if k' = 0.
169
178
  const { bytes: rx, scalar: k } = schnorrGetExtPubKey(k_); // Let R = k'⋅G.
170
179
  const e = challenge(rx, px, m); // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
@@ -185,11 +194,11 @@ function schnorrVerify(signature: Hex, message: Hex, publicKey: Hex): boolean {
185
194
  const m = ensureBytes('message', message);
186
195
  const pub = ensureBytes('publicKey', publicKey, 32);
187
196
  try {
188
- const P = lift_x(bytesToNumberBE(pub)); // P = lift_x(int(pk)); fail if that fails
189
- const r = bytesToNumberBE(sig.subarray(0, 32)); // Let r = int(sig[0:32]); fail if r ≥ p.
190
- if (!fe(r)) return false;
191
- const s = bytesToNumberBE(sig.subarray(32, 64)); // Let s = int(sig[32:64]); fail if s ≥ n.
192
- if (!ge(s)) return false;
197
+ const P = lift_x(num(pub)); // P = lift_x(int(pk)); fail if that fails
198
+ const r = num(sig.subarray(0, 32)); // Let r = int(sig[0:32]); fail if r ≥ p.
199
+ if (!inRange(r, _1n, secp256k1P)) return false;
200
+ const s = num(sig.subarray(32, 64)); // Let s = int(sig[32:64]); fail if s ≥ n.
201
+ if (!inRange(s, _1n, secp256k1N)) return false;
193
202
  const e = challenge(numTo32b(r), pointToBytes(P), m); // int(challenge(bytes(r)||bytes(P)||m))%n
194
203
  const R = GmulAdd(P, s, modN(-e)); // R = s⋅G - e⋅P
195
204
  if (!R || !R.hasEvenY() || R.toAffine().x !== r) return false; // -eP == (n-e)P
@@ -199,6 +208,9 @@ function schnorrVerify(signature: Hex, message: Hex, publicKey: Hex): boolean {
199
208
  }
200
209
  }
201
210
 
211
+ /**
212
+ * Schnorr signatures over secp256k1.
213
+ */
202
214
  export const schnorr = /* @__PURE__ */ (() => ({
203
215
  getPublicKey: schnorrGetPublicKey,
204
216
  sign: schnorrSign,