@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.
- package/README.md +143 -194
- package/abstract/bls.d.ts +29 -12
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +58 -8
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +1 -1
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +10 -21
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +5 -7
- package/abstract/montgomery.js.map +1 -1
- package/abstract/poseidon.js.map +1 -1
- package/abstract/utils.d.ts +4 -2
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +61 -36
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +24 -28
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +13 -7
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +138 -83
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +3 -2
- package/bn254.d.ts.map +1 -1
- package/bn254.js +3 -2
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +4 -2
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +8 -2
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +4 -2
- package/ed448.d.ts.map +1 -1
- package/ed448.js +10 -1
- package/ed448.js.map +1 -1
- package/esm/abstract/bls.js +58 -8
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/hash-to-curve.js +11 -22
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.js +5 -7
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/utils.js +58 -35
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.js +13 -7
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.js +139 -84
- package/esm/bls12-381.js.map +1 -1
- package/esm/bn254.js +3 -2
- package/esm/bn254.js.map +1 -1
- package/esm/ed25519.js +8 -2
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.js +10 -1
- package/esm/ed448.js.map +1 -1
- package/esm/index.js +1 -1
- package/esm/index.js.map +1 -1
- package/esm/jubjub.js.map +1 -1
- package/esm/p256.js +2 -2
- package/esm/p256.js.map +1 -1
- package/esm/p384.js +2 -2
- package/esm/p384.js.map +1 -1
- package/esm/p521.js +3 -3
- package/esm/p521.js.map +1 -1
- package/esm/secp256k1.js +6 -6
- package/esm/secp256k1.js.map +1 -1
- package/jubjub.js.map +1 -1
- package/p256.js +2 -2
- package/p256.js.map +1 -1
- package/p384.js +2 -2
- package/p384.js.map +1 -1
- package/p521.js +3 -3
- package/p521.js.map +1 -1
- package/package.json +7 -7
- package/secp256k1.js +6 -6
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +119 -21
- package/src/abstract/hash-to-curve.ts +12 -20
- package/src/abstract/montgomery.ts +4 -6
- package/src/abstract/utils.ts +57 -28
- package/src/abstract/weierstrass.ts +25 -10
- package/src/bls12-381.ts +128 -70
- package/src/bn254.ts +3 -2
- package/src/ed25519.ts +10 -2
- package/src/ed448.ts +18 -3
- 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
|
|
4
|
-
// - Construct zk-SNARKs at the
|
|
5
|
-
// -
|
|
6
|
-
//
|
|
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
|
-
//
|
|
29
|
-
//
|
|
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
|
-
|
|
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(
|
|
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
|
|
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(
|
|
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
|
-
|
|
1120
|
-
if (
|
|
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(
|
|
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
|
-
|
|
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 (
|
|
1169
|
+
} else if (value.length === 96 && !compressed) {
|
|
1135
1170
|
// Check if the infinity flag is set
|
|
1136
|
-
|
|
1137
|
-
const
|
|
1138
|
-
|
|
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
|
-
|
|
1151
|
-
|
|
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
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
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 (
|
|
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 (
|
|
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(
|
|
1258
|
-
const x_0 = slc(
|
|
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 =
|
|
1321
|
+
y = sort && Y_bit > 0 ? y : Fp2.neg(y);
|
|
1264
1322
|
return { x, y };
|
|
1265
|
-
} else if (
|
|
1266
|
-
|
|
1267
|
-
|
|
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(
|
|
1271
|
-
const x0 = slc(
|
|
1272
|
-
const y1 = slc(
|
|
1273
|
-
const y0 = slc(
|
|
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
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
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
|
-
|
|
1365
|
+
const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex));
|
|
1306
1366
|
const P = Fp.ORDER;
|
|
1307
|
-
const half =
|
|
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(
|
|
1311
|
-
const z2 = bytesToNumberBE(
|
|
1370
|
+
const z1 = bytesToNumberBE(value.slice(0, half));
|
|
1371
|
+
const z2 = bytesToNumberBE(value.slice(half));
|
|
1312
1372
|
// Indicates the infinity point
|
|
1313
|
-
|
|
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 =
|
|
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
|
-
*
|
|
10
|
-
*
|
|
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:
|
|
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
|
package/src/package.json
ADDED