@noble/curves 1.2.0 → 1.4.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 (92) hide show
  1. package/README.md +143 -194
  2. package/abstract/bls.d.ts +29 -12
  3. package/abstract/bls.d.ts.map +1 -1
  4. package/abstract/bls.js +58 -8
  5. package/abstract/bls.js.map +1 -1
  6. package/abstract/curve.js.map +1 -1
  7. package/abstract/edwards.js.map +1 -1
  8. package/abstract/hash-to-curve.d.ts +1 -1
  9. package/abstract/hash-to-curve.d.ts.map +1 -1
  10. package/abstract/hash-to-curve.js +10 -21
  11. package/abstract/hash-to-curve.js.map +1 -1
  12. package/abstract/modular.js.map +1 -1
  13. package/abstract/montgomery.d.ts.map +1 -1
  14. package/abstract/montgomery.js +5 -7
  15. package/abstract/montgomery.js.map +1 -1
  16. package/abstract/poseidon.js.map +1 -1
  17. package/abstract/utils.d.ts +4 -2
  18. package/abstract/utils.d.ts.map +1 -1
  19. package/abstract/utils.js +61 -36
  20. package/abstract/utils.js.map +1 -1
  21. package/abstract/weierstrass.d.ts +24 -28
  22. package/abstract/weierstrass.d.ts.map +1 -1
  23. package/abstract/weierstrass.js +13 -7
  24. package/abstract/weierstrass.js.map +1 -1
  25. package/bls12-381.d.ts.map +1 -1
  26. package/bls12-381.js +138 -83
  27. package/bls12-381.js.map +1 -1
  28. package/bn254.d.ts +3 -2
  29. package/bn254.d.ts.map +1 -1
  30. package/bn254.js +3 -2
  31. package/bn254.js.map +1 -1
  32. package/ed25519.d.ts +4 -2
  33. package/ed25519.d.ts.map +1 -1
  34. package/ed25519.js +8 -2
  35. package/ed25519.js.map +1 -1
  36. package/ed448.d.ts +4 -2
  37. package/ed448.d.ts.map +1 -1
  38. package/ed448.js +10 -1
  39. package/ed448.js.map +1 -1
  40. package/esm/abstract/bls.js +58 -8
  41. package/esm/abstract/bls.js.map +1 -1
  42. package/esm/abstract/curve.js.map +1 -1
  43. package/esm/abstract/edwards.js.map +1 -1
  44. package/esm/abstract/hash-to-curve.js +11 -22
  45. package/esm/abstract/hash-to-curve.js.map +1 -1
  46. package/esm/abstract/modular.js.map +1 -1
  47. package/esm/abstract/montgomery.js +5 -7
  48. package/esm/abstract/montgomery.js.map +1 -1
  49. package/esm/abstract/poseidon.js.map +1 -1
  50. package/esm/abstract/utils.js +58 -35
  51. package/esm/abstract/utils.js.map +1 -1
  52. package/esm/abstract/weierstrass.js +13 -7
  53. package/esm/abstract/weierstrass.js.map +1 -1
  54. package/esm/bls12-381.js +139 -84
  55. package/esm/bls12-381.js.map +1 -1
  56. package/esm/bn254.js +3 -2
  57. package/esm/bn254.js.map +1 -1
  58. package/esm/ed25519.js +8 -2
  59. package/esm/ed25519.js.map +1 -1
  60. package/esm/ed448.js +10 -1
  61. package/esm/ed448.js.map +1 -1
  62. package/esm/index.js +1 -1
  63. package/esm/index.js.map +1 -1
  64. package/esm/jubjub.js.map +1 -1
  65. package/esm/p256.js +2 -2
  66. package/esm/p256.js.map +1 -1
  67. package/esm/p384.js +2 -2
  68. package/esm/p384.js.map +1 -1
  69. package/esm/p521.js +3 -3
  70. package/esm/p521.js.map +1 -1
  71. package/esm/secp256k1.js +6 -6
  72. package/esm/secp256k1.js.map +1 -1
  73. package/jubjub.js.map +1 -1
  74. package/p256.js +2 -2
  75. package/p256.js.map +1 -1
  76. package/p384.js +2 -2
  77. package/p384.js.map +1 -1
  78. package/p521.js +3 -3
  79. package/p521.js.map +1 -1
  80. package/package.json +7 -7
  81. package/secp256k1.js +6 -6
  82. package/secp256k1.js.map +1 -1
  83. package/src/abstract/bls.ts +119 -21
  84. package/src/abstract/hash-to-curve.ts +12 -20
  85. package/src/abstract/montgomery.ts +4 -6
  86. package/src/abstract/utils.ts +57 -28
  87. package/src/abstract/weierstrass.ts +25 -10
  88. package/src/bls12-381.ts +128 -70
  89. package/src/bn254.ts +3 -2
  90. package/src/ed25519.ts +10 -2
  91. package/src/ed448.ts +18 -3
  92. package/src/package.json +3 -0
package/src/bls12-381.ts CHANGED
@@ -1,15 +1,9 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
 
3
- // bls12-381 pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to:
4
- // - Construct zk-SNARKs at the 128-bit security
5
- // - Use threshold signatures, which allows a user to sign lots of messages with one signature and
6
- // verify them swiftly in a batch, using Boneh-Lynn-Shacham signature scheme.
7
- //
8
- // The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
9
- // Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
10
- // [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
11
- // [bls-sigs-04](https:/cfrg-hash-to/tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
12
- // [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf--curve-12).
3
+ // bls12-381 is pairing-friendly Barreto-Lynn-Scott elliptic curve construction allowing to:
4
+ // - Construct zk-SNARKs at the 120-bit security
5
+ // - Efficiently verify N aggregate signatures with 1 pairing and N ec additions:
6
+ // the Boneh-Lynn-Shacham signature scheme is orders of magnitude more efficient than Schnorr
13
7
  //
14
8
  // ### Summary
15
9
  // 1. BLS Relies on Bilinear Pairing (expensive)
@@ -25,8 +19,17 @@
25
19
  // - `S = pk x H(m)` - signing
26
20
  // - `e(P, H(m)) == e(G, S)` - verification using pairings
27
21
  // - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
28
- // Filecoin uses little endian byte arrays for private keys -
29
- // so ensure to reverse byte order if you'll use it with FIL.
22
+ //
23
+ // ### Compatibility and notes
24
+ // 1. It is compatible with Algorand, Chia, Dfinity, Ethereum, Filecoin, ZEC
25
+ // Filecoin uses little endian byte arrays for private keys - make sure to reverse byte order.
26
+ // 2. Some projects use G2 for public keys and G1 for signatures. It's called "short signature"
27
+ // 3. Curve security level is about 120 bits as per Barbulescu-Duquesne 2017
28
+ // https://hal.science/hal-01534101/file/main.pdf
29
+ // 4. Compatible with specs:
30
+ // [cfrg-pairing-friendly-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
31
+ // [cfrg-bls-signature-05](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05),
32
+ // [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
30
33
  import { sha256 } from '@noble/hashes/sha256';
31
34
  import { randomBytes } from '@noble/hashes/utils';
32
35
  import { bls, CurveFn } from './abstract/bls.js';
@@ -37,7 +40,6 @@ import {
37
40
  numberToBytesBE,
38
41
  bytesToNumberBE,
39
42
  bitLen,
40
- bitSet,
41
43
  bitGet,
42
44
  Hex,
43
45
  bitMask,
@@ -1016,11 +1018,41 @@ const htfDefaults = Object.freeze({
1016
1018
 
1017
1019
  // Encoding utils
1018
1020
  // Point on G1 curve: (x, y)
1019
- const C_BIT_POS = Fp.BITS; // C_bit, compression bit for serialization flag
1020
- const I_BIT_POS = Fp.BITS + 1; // I_bit, point-at-infinity bit for serialization flag
1021
- const S_BIT_POS = Fp.BITS + 2; // S_bit, sign bit for serialization flag
1021
+
1022
1022
  // Compressed point of infinity
1023
- const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(_0n, I_BIT_POS, true), S_BIT_POS, true)); // set compressed & point-at-infinity bits
1023
+ const COMPRESSED_ZERO = setMask(Fp.toBytes(_0n), { infinity: true, compressed: true }); // set compressed & point-at-infinity bits
1024
+
1025
+ function parseMask(bytes: Uint8Array) {
1026
+ // Copy, so we can remove mask data. It will be removed also later, when Fp.create will call modulo.
1027
+ bytes = bytes.slice();
1028
+ const mask = bytes[0] & 0b1110_0000;
1029
+ const compressed = !!((mask >> 7) & 1); // compression bit (0b1000_0000)
1030
+ const infinity = !!((mask >> 6) & 1); // point at infinity bit (0b0100_0000)
1031
+ const sort = !!((mask >> 5) & 1); // sort bit (0b0010_0000)
1032
+ bytes[0] &= 0b0001_1111; // clear mask (zero first 3 bits)
1033
+ return { compressed, infinity, sort, value: bytes };
1034
+ }
1035
+
1036
+ function setMask(
1037
+ bytes: Uint8Array,
1038
+ mask: { compressed?: boolean; infinity?: boolean; sort?: boolean }
1039
+ ) {
1040
+ if (bytes[0] & 0b1110_0000) throw new Error('setMask: non-empty mask');
1041
+ if (mask.compressed) bytes[0] |= 0b1000_0000;
1042
+ if (mask.infinity) bytes[0] |= 0b0100_0000;
1043
+ if (mask.sort) bytes[0] |= 0b0010_0000;
1044
+ return bytes;
1045
+ }
1046
+
1047
+ function signatureG1ToRawBytes(point: ProjPointType<Fp>) {
1048
+ point.assertValidity();
1049
+ const isZero = point.equals(bls12_381.G1.ProjectivePoint.ZERO);
1050
+ const { x, y } = point.toAffine();
1051
+ if (isZero) return COMPRESSED_ZERO.slice();
1052
+ const P = Fp.ORDER;
1053
+ const sort = Boolean((y * _2n) / P);
1054
+ return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
1055
+ }
1024
1056
 
1025
1057
  function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
1026
1058
  // NOTE: by some reasons it was missed in bls12-381, looks like bug
@@ -1032,10 +1064,12 @@ function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
1032
1064
  const { re: x0, im: x1 } = Fp2.reim(x);
1033
1065
  const { re: y0, im: y1 } = Fp2.reim(y);
1034
1066
  const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
1035
- const aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
1036
- const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
1067
+ const sort = Boolean((tmp / Fp.ORDER) & _1n);
1037
1068
  const z2 = x0;
1038
- return concatB(numberToBytesBE(z1, len), numberToBytesBE(z2, len));
1069
+ return concatB(
1070
+ setMask(numberToBytesBE(x1, len), { sort, compressed: true }),
1071
+ numberToBytesBE(z2, len)
1072
+ );
1039
1073
  }
1040
1074
 
1041
1075
  // To verify curve parameters, see pairing-friendly-curves spec:
@@ -1074,7 +1108,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
1074
1108
  ),
1075
1109
  a: Fp.ZERO,
1076
1110
  b: _4n,
1077
- htfDefaults: { ...htfDefaults, m: 1 },
1111
+ htfDefaults: { ...htfDefaults, m: 1, DST: 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_' },
1078
1112
  wrapPrivateKey: true,
1079
1113
  allowInfinityPoint: true,
1080
1114
  // Checks is the point resides in prime-order subgroup.
@@ -1116,26 +1150,30 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
1116
1150
  return isogenyMapG1(x, y);
1117
1151
  },
1118
1152
  fromBytes: (bytes: Uint8Array): AffinePoint<Fp> => {
1119
- bytes = bytes.slice();
1120
- if (bytes.length === 48) {
1153
+ const { compressed, infinity, sort, value } = parseMask(bytes);
1154
+ if (value.length === 48 && compressed) {
1121
1155
  // TODO: Fp.bytes
1122
1156
  const P = Fp.ORDER;
1123
- const compressedValue = bytesToNumberBE(bytes);
1124
- const bflag = bitGet(compressedValue, I_BIT_POS);
1157
+ const compressedValue = bytesToNumberBE(value);
1125
1158
  // Zero
1126
- if (bflag === _1n) return { x: _0n, y: _0n };
1127
1159
  const x = Fp.create(compressedValue & Fp.MASK);
1160
+ if (infinity) {
1161
+ if (x !== _0n) throw new Error('G1: non-empty compressed point at infinity');
1162
+ return { x: _0n, y: _0n };
1163
+ }
1128
1164
  const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
1129
1165
  let y = Fp.sqrt(right);
1130
1166
  if (!y) throw new Error('Invalid compressed G1 point');
1131
- const aflag = bitGet(compressedValue, C_BIT_POS);
1132
- if ((y * _2n) / P !== aflag) y = Fp.neg(y);
1167
+ if ((y * _2n) / P !== BigInt(sort)) y = Fp.neg(y);
1133
1168
  return { x: Fp.create(x), y: Fp.create(y) };
1134
- } else if (bytes.length === 96) {
1169
+ } else if (value.length === 96 && !compressed) {
1135
1170
  // Check if the infinity flag is set
1136
- if ((bytes[0] & (1 << 6)) !== 0) return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
1137
- const x = bytesToNumberBE(bytes.subarray(0, Fp.BYTES));
1138
- const y = bytesToNumberBE(bytes.subarray(Fp.BYTES));
1171
+ const x = bytesToNumberBE(value.subarray(0, Fp.BYTES));
1172
+ const y = bytesToNumberBE(value.subarray(Fp.BYTES));
1173
+ if (infinity) {
1174
+ if (x !== _0n || y !== _0n) throw new Error('G1: non-empty point at infinity');
1175
+ return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
1176
+ }
1139
1177
  return { x: Fp.create(x), y: Fp.create(y) };
1140
1178
  } else {
1141
1179
  throw new Error('Invalid point G1, expected 48/96 bytes');
@@ -1147,10 +1185,8 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
1147
1185
  if (isCompressed) {
1148
1186
  if (isZero) return COMPRESSED_ZERO.slice();
1149
1187
  const P = Fp.ORDER;
1150
- let num;
1151
- num = bitSet(x, C_BIT_POS, Boolean((y * _2n) / P)); // set aflag
1152
- num = bitSet(num, S_BIT_POS, true);
1153
- return numberToBytesBE(num, Fp.BYTES);
1188
+ const sort = Boolean((y * _2n) / P);
1189
+ return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
1154
1190
  } else {
1155
1191
  if (isZero) {
1156
1192
  // 2x PUBLIC_KEY_LENGTH
@@ -1161,6 +1197,30 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
1161
1197
  }
1162
1198
  }
1163
1199
  },
1200
+ ShortSignature: {
1201
+ fromHex(hex: Hex): ProjPointType<Fp> {
1202
+ const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex, 48));
1203
+ const P = Fp.ORDER;
1204
+ const compressedValue = bytesToNumberBE(value);
1205
+ // Zero
1206
+ if (infinity) return bls12_381.G1.ProjectivePoint.ZERO;
1207
+ const x = Fp.create(compressedValue & Fp.MASK);
1208
+ const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
1209
+ let y = Fp.sqrt(right);
1210
+ if (!y) throw new Error('Invalid compressed G1 point');
1211
+ const aflag = BigInt(sort);
1212
+ if ((y * _2n) / P !== aflag) y = Fp.neg(y);
1213
+ const point = bls12_381.G1.ProjectivePoint.fromAffine({ x, y });
1214
+ point.assertValidity();
1215
+ return point;
1216
+ },
1217
+ toRawBytes(point: ProjPointType<Fp>) {
1218
+ return signatureG1ToRawBytes(point);
1219
+ },
1220
+ toHex(point: ProjPointType<Fp>) {
1221
+ return bytesToHex(signatureG1ToRawBytes(point));
1222
+ },
1223
+ },
1164
1224
  },
1165
1225
  // G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
1166
1226
  // where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
@@ -1232,45 +1292,45 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
1232
1292
  return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
1233
1293
  },
1234
1294
  fromBytes: (bytes: Uint8Array): AffinePoint<Fp2> => {
1235
- bytes = bytes.slice();
1236
- const m_byte = bytes[0] & 0xe0;
1237
- if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
1238
- throw new Error('Invalid encoding flag: ' + m_byte);
1295
+ const { compressed, infinity, sort, value } = parseMask(bytes);
1296
+ if (
1297
+ (!compressed && !infinity && sort) || // 00100000
1298
+ (!compressed && infinity && sort) || // 01100000
1299
+ (sort && infinity && compressed) // 11100000
1300
+ ) {
1301
+ throw new Error('Invalid encoding flag: ' + (bytes[0] & 0b1110_0000));
1239
1302
  }
1240
- const bitC = m_byte & 0x80; // compression bit
1241
- const bitI = m_byte & 0x40; // point at infinity bit
1242
- const bitS = m_byte & 0x20; // sign bit
1243
1303
  const L = Fp.BYTES;
1244
1304
  const slc = (b: Uint8Array, from: number, to?: number) => bytesToNumberBE(b.slice(from, to));
1245
- if (bytes.length === 96 && bitC) {
1305
+ if (value.length === 96 && compressed) {
1246
1306
  const b = bls12_381.params.G2b;
1247
1307
  const P = Fp.ORDER;
1248
-
1249
- bytes[0] = bytes[0] & 0x1f; // clear flags
1250
- if (bitI) {
1308
+ if (infinity) {
1251
1309
  // check that all bytes are 0
1252
- if (bytes.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
1310
+ if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
1253
1311
  throw new Error('Invalid compressed G2 point');
1254
1312
  }
1255
1313
  return { x: Fp2.ZERO, y: Fp2.ZERO };
1256
1314
  }
1257
- const x_1 = slc(bytes, 0, L);
1258
- const x_0 = slc(bytes, L, 2 * L);
1315
+ const x_1 = slc(value, 0, L);
1316
+ const x_0 = slc(value, L, 2 * L);
1259
1317
  const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
1260
1318
  const right = Fp2.add(Fp2.pow(x, _3n), b); // y² = x³ + 4 * (u+1) = x³ + b
1261
1319
  let y = Fp2.sqrt(right);
1262
1320
  const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
1263
- y = bitS > 0 && Y_bit > 0 ? y : Fp2.neg(y);
1321
+ y = sort && Y_bit > 0 ? y : Fp2.neg(y);
1264
1322
  return { x, y };
1265
- } else if (bytes.length === 192 && !bitC) {
1266
- // Check if the infinity flag is set
1267
- if ((bytes[0] & (1 << 6)) !== 0) {
1323
+ } else if (value.length === 192 && !compressed) {
1324
+ if (infinity) {
1325
+ if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
1326
+ throw new Error('Invalid uncompressed G2 point');
1327
+ }
1268
1328
  return { x: Fp2.ZERO, y: Fp2.ZERO };
1269
1329
  }
1270
- const x1 = slc(bytes, 0, L);
1271
- const x0 = slc(bytes, L, 2 * L);
1272
- const y1 = slc(bytes, 2 * L, 3 * L);
1273
- const y0 = slc(bytes, 3 * L, 4 * L);
1330
+ const x1 = slc(value, 0, L);
1331
+ const x0 = slc(value, L, 2 * L);
1332
+ const y1 = slc(value, 2 * L, 3 * L);
1333
+ const y0 = slc(value, 3 * L, 4 * L);
1274
1334
  return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
1275
1335
  } else {
1276
1336
  throw new Error('Invalid point G2, expected 96/192 bytes');
@@ -1283,10 +1343,10 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
1283
1343
  if (isCompressed) {
1284
1344
  if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
1285
1345
  const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
1286
- // set compressed & sign bits (looks like different offsets than for G1/Fp?)
1287
- let x_1 = bitSet(x.c1, C_BIT_POS, flag);
1288
- x_1 = bitSet(x_1, S_BIT_POS, true);
1289
- return concatB(numberToBytesBE(x_1, len), numberToBytesBE(x.c0, len));
1346
+ return concatB(
1347
+ setMask(numberToBytesBE(x.c1, len), { compressed: true, sort: flag }),
1348
+ numberToBytesBE(x.c0, len)
1349
+ );
1290
1350
  } else {
1291
1351
  if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 * len - 1)); // bytes[0] |= 1 << 6;
1292
1352
  const { re: x0, im: x1 } = Fp2.reim(x);
@@ -1302,17 +1362,15 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
1302
1362
  Signature: {
1303
1363
  // TODO: Optimize, it's very slow because of sqrt.
1304
1364
  fromHex(hex: Hex): ProjPointType<Fp2> {
1305
- hex = ensureBytes('signatureHex', hex);
1365
+ const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex));
1306
1366
  const P = Fp.ORDER;
1307
- const half = hex.length / 2;
1367
+ const half = value.length / 2;
1308
1368
  if (half !== 48 && half !== 96)
1309
1369
  throw new Error('Invalid compressed signature length, must be 96 or 192');
1310
- const z1 = bytesToNumberBE(hex.slice(0, half));
1311
- const z2 = bytesToNumberBE(hex.slice(half));
1370
+ const z1 = bytesToNumberBE(value.slice(0, half));
1371
+ const z2 = bytesToNumberBE(value.slice(half));
1312
1372
  // Indicates the infinity point
1313
- const bflag1 = bitGet(z1, I_BIT_POS);
1314
- if (bflag1 === _1n) return bls12_381.G2.ProjectivePoint.ZERO;
1315
-
1373
+ if (infinity) return bls12_381.G2.ProjectivePoint.ZERO;
1316
1374
  const x1 = Fp.create(z1 & Fp.MASK);
1317
1375
  const x2 = Fp.create(z2);
1318
1376
  const x = Fp2.create({ c0: x2, c1: x1 });
@@ -1324,7 +1382,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
1324
1382
  // Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
1325
1383
  // If y1 happens to be zero, then use the bit of y0
1326
1384
  const { re: y0, im: y1 } = Fp2.reim(y);
1327
- const aflag1 = bitGet(z1, 381);
1385
+ const aflag1 = BigInt(sort);
1328
1386
  const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
1329
1387
  const isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
1330
1388
  if (isGreater || isZero) y = Fp2.neg(y);
package/src/bn254.ts CHANGED
@@ -6,8 +6,9 @@ import { Field } from './abstract/modular.js';
6
6
  /**
7
7
  * bn254 pairing-friendly curve.
8
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
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
11
12
  */
12
13
  export const bn254 = weierstrass({
13
14
  a: BigInt(0),
package/src/ed25519.ts CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  numberToBytesLE,
14
14
  } from './abstract/utils.js';
15
15
  import { createHasher, htfBasicOpts, expand_message_xmd } from './abstract/hash-to-curve.js';
16
- import { AffinePoint } from './abstract/curve.js';
16
+ import { AffinePoint, Group } from './abstract/curve.js';
17
17
 
18
18
  /**
19
19
  * ed25519 Twisted Edwards curve with following addons:
@@ -343,7 +343,7 @@ function calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
343
343
  * but it should work in its own namespace: do not combine those two.
344
344
  * https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448
345
345
  */
346
- class RistPoint {
346
+ class RistPoint implements Group<RistPoint> {
347
347
  static BASE: RistPoint;
348
348
  static ZERO: RistPoint;
349
349
  // Private property to discourage combining ExtendedPoint + RistrettoPoint
@@ -471,6 +471,14 @@ class RistPoint {
471
471
  multiplyUnsafe(scalar: bigint): RistPoint {
472
472
  return new RistPoint(this.ep.multiplyUnsafe(scalar));
473
473
  }
474
+
475
+ double(): RistPoint {
476
+ return new RistPoint(this.ep.double());
477
+ }
478
+
479
+ negate(): RistPoint {
480
+ return new RistPoint(this.ep.negate());
481
+ }
474
482
  }
475
483
  export const RistrettoPoint = /* @__PURE__ */ (() => {
476
484
  if (!RistPoint.BASE) RistPoint.BASE = new RistPoint(ed25519.ExtendedPoint.BASE);
package/src/ed448.ts CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  Hex,
14
14
  numberToBytesLE,
15
15
  } from './abstract/utils.js';
16
- import { AffinePoint } from './abstract/curve.js';
16
+ import { AffinePoint, Group } from './abstract/curve.js';
17
17
 
18
18
  /**
19
19
  * Edwards448 (not Ed448-Goldilocks) curve with following addons:
@@ -103,6 +103,7 @@ const ED448_DEF = {
103
103
  n: BigInt(
104
104
  '181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779'
105
105
  ),
106
+ // RFC 7748 has 56-byte keys, RFC 8032 has 57-byte keys
106
107
  nBitLength: 456,
107
108
  // Cofactor
108
109
  h: BigInt(4),
@@ -137,8 +138,9 @@ export const ed448ph = /* @__PURE__ */ twistedEdwards({ ...ED448_DEF, prehash: s
137
138
  export const x448 = /* @__PURE__ */ (() =>
138
139
  montgomery({
139
140
  a: BigInt(156326),
141
+ // RFC 7748 has 56-byte keys, RFC 8032 has 57-byte keys
140
142
  montgomeryBits: 448,
141
- nByteLength: 57,
143
+ nByteLength: 56,
142
144
  P: ed448P,
143
145
  Gu: BigInt(5),
144
146
  powPminus2: (x: bigint): bigint => {
@@ -164,11 +166,14 @@ export function edwardsToMontgomeryPub(edwardsPub: string | Uint8Array): Uint8Ar
164
166
  const _1n = BigInt(1);
165
167
  return Fp.toBytes(Fp.create((y - _1n) * Fp.inv(y + _1n)));
166
168
  }
169
+
167
170
  export const edwardsToMontgomery = edwardsToMontgomeryPub; // deprecated
171
+ // TODO: add edwardsToMontgomeryPriv, similar to ed25519 version
168
172
 
169
173
  // Hash To Curve Elligator2 Map
170
174
  const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
171
175
  const ELL2_J = BigInt(156326);
176
+
172
177
  function map_to_curve_elligator2_curve448(u: bigint) {
173
178
  let tv1 = Fp.sqr(u); // 1. tv1 = u^2
174
179
  let e1 = Fp.eql(tv1, Fp.ONE); // 2. e1 = tv1 == 1
@@ -198,6 +203,7 @@ function map_to_curve_elligator2_curve448(u: bigint) {
198
203
  y = Fp.cmov(y, Fp.neg(y), e2 !== e3); // 26. y = CMOV(y, -y, e2 XOR e3)
199
204
  return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
200
205
  }
206
+
201
207
  function map_to_curve_elligator2_edwards448(u: bigint) {
202
208
  let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u); // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
203
209
  let xn2 = Fp.sqr(xn); // 2. xn2 = xn^2
@@ -323,7 +329,7 @@ function calcElligatorDecafMap(r0: bigint): ExtendedPoint {
323
329
  * but it should work in its own namespace: do not combine those two.
324
330
  * https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448
325
331
  */
326
- class DcfPoint {
332
+ class DcfPoint implements Group<DcfPoint> {
327
333
  static BASE: DcfPoint;
328
334
  static ZERO: DcfPoint;
329
335
  // Private property to discourage combining ExtendedPoint + DecafPoint
@@ -445,7 +451,16 @@ class DcfPoint {
445
451
  multiplyUnsafe(scalar: bigint): DcfPoint {
446
452
  return new DcfPoint(this.ep.multiplyUnsafe(scalar));
447
453
  }
454
+
455
+ double(): DcfPoint {
456
+ return new DcfPoint(this.ep.double());
457
+ }
458
+
459
+ negate(): DcfPoint {
460
+ return new DcfPoint(this.ep.negate());
461
+ }
448
462
  }
463
+
449
464
  export const DecafPoint = /* @__PURE__ */ (() => {
450
465
  // decaf448 base point is ed448 base x 2
451
466
  // https://github.com/dalek-cryptography/curve25519-dalek/blob/59837c6ecff02b77b9d5ff84dbc239d0cf33ef90/vendor/ristretto.sage#L699
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }