@noble/curves 1.1.0 → 1.3.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 +295 -258
- package/abstract/bls.d.ts +27 -10
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +60 -10
- 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 +2 -2
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +22 -16
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +51 -11
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +79 -21
- 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.d.ts.map +1 -1
- package/abstract/poseidon.js +39 -41
- package/abstract/poseidon.js.map +1 -1
- package/abstract/utils.d.ts +3 -1
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +56 -31
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +25 -28
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +17 -15
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +142 -88
- 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 +5 -2
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +17 -8
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +53 -2
- package/ed448.d.ts.map +1 -1
- package/ed448.js +216 -29
- package/ed448.js.map +1 -1
- package/esm/abstract/bls.js +61 -11
- 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 +23 -17
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.js +75 -20
- 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 +39 -41
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/utils.js +54 -30
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.js +17 -15
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.js +143 -89
- 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 +17 -8
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.js +218 -32
- package/esm/ed448.js.map +1 -1
- package/esm/jubjub.js +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/package.json +1 -4
- 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 -6
- package/secp256k1.js +6 -6
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +120 -22
- package/src/abstract/hash-to-curve.ts +24 -17
- package/src/abstract/modular.ts +81 -22
- package/src/abstract/montgomery.ts +4 -6
- package/src/abstract/poseidon.ts +39 -40
- package/src/abstract/utils.ts +55 -26
- package/src/abstract/weierstrass.ts +29 -18
- package/src/bls12-381.ts +132 -75
- package/src/bn254.ts +3 -2
- package/src/ed25519.ts +19 -8
- package/src/ed448.ts +267 -34
- package/src/jubjub.ts +1 -1
package/esm/bls12-381.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
-
// bls12-381 pairing-friendly Barreto-Lynn-Scott elliptic curve construction
|
|
3
|
-
// - Construct zk-SNARKs at the
|
|
4
|
-
// -
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
|
|
8
|
-
// Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
|
|
9
|
-
// [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
|
10
|
-
// [bls-sigs-04](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
|
|
11
|
-
// [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12).
|
|
2
|
+
// bls12-381 is pairing-friendly Barreto-Lynn-Scott elliptic curve construction allowing to:
|
|
3
|
+
// - Construct zk-SNARKs at the 120-bit security
|
|
4
|
+
// - Efficiently verify N aggregate signatures with 1 pairing and N ec additions:
|
|
5
|
+
// the Boneh-Lynn-Shacham signature scheme is orders of magnitude more efficient than Schnorr
|
|
12
6
|
//
|
|
13
7
|
// ### Summary
|
|
14
8
|
// 1. BLS Relies on Bilinear Pairing (expensive)
|
|
@@ -24,13 +18,22 @@
|
|
|
24
18
|
// - `S = pk x H(m)` - signing
|
|
25
19
|
// - `e(P, H(m)) == e(G, S)` - verification using pairings
|
|
26
20
|
// - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
|
|
27
|
-
//
|
|
28
|
-
//
|
|
21
|
+
//
|
|
22
|
+
// ### Compatibility and notes
|
|
23
|
+
// 1. It is compatible with Algorand, Chia, Dfinity, Ethereum, Filecoin, ZEC
|
|
24
|
+
// Filecoin uses little endian byte arrays for private keys - make sure to reverse byte order.
|
|
25
|
+
// 2. Some projects use G2 for public keys and G1 for signatures. It's called "short signature"
|
|
26
|
+
// 3. Curve security level is about 120 bits as per Barbulescu-Duquesne 2017
|
|
27
|
+
// https://hal.science/hal-01534101/file/main.pdf
|
|
28
|
+
// 4. Compatible with specs:
|
|
29
|
+
// [cfrg-pairing-friendly-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
|
30
|
+
// [cfrg-bls-signature-05](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05),
|
|
31
|
+
// [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
|
|
29
32
|
import { sha256 } from '@noble/hashes/sha256';
|
|
30
33
|
import { randomBytes } from '@noble/hashes/utils';
|
|
31
34
|
import { bls } from './abstract/bls.js';
|
|
32
35
|
import * as mod from './abstract/modular.js';
|
|
33
|
-
import { concatBytes as concatB, ensureBytes, numberToBytesBE, bytesToNumberBE, bitLen,
|
|
36
|
+
import { concatBytes as concatB, ensureBytes, numberToBytesBE, bytesToNumberBE, bitLen, bitGet, bitMask, bytesToHex, } from './abstract/utils.js';
|
|
34
37
|
// Types
|
|
35
38
|
import { mapToCurveSimpleSWU, } from './abstract/weierstrass.js';
|
|
36
39
|
import { isogenyMap } from './abstract/hash-to-curve.js';
|
|
@@ -148,7 +151,7 @@ const Fp2 = {
|
|
|
148
151
|
return x1;
|
|
149
152
|
return x2;
|
|
150
153
|
},
|
|
151
|
-
// Same as
|
|
154
|
+
// Same as sgn0_m_eq_2 in RFC 9380
|
|
152
155
|
isOdd: (x) => {
|
|
153
156
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
|
154
157
|
const sign_0 = x0 % _2n;
|
|
@@ -257,14 +260,14 @@ const Fp6Square = ({ c0, c1, c2 }) => {
|
|
|
257
260
|
let t3 = Fp2.mul(Fp2.mul(c1, c2), _2n); // 2 * c1 * c2
|
|
258
261
|
let t4 = Fp2.sqr(c2); // c2²
|
|
259
262
|
return {
|
|
260
|
-
c0: Fp2.add(Fp2.mulByNonresidue(t3), t0),
|
|
261
|
-
c1: Fp2.add(Fp2.mulByNonresidue(t4), t1),
|
|
263
|
+
c0: Fp2.add(Fp2.mulByNonresidue(t3), t0), // T3 * (u + 1) + T0
|
|
264
|
+
c1: Fp2.add(Fp2.mulByNonresidue(t4), t1), // T4 * (u + 1) + T1
|
|
262
265
|
// T1 + (c0 - c1 + c2)² + T3 - T0 - T4
|
|
263
266
|
c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.sqr(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
|
|
264
267
|
};
|
|
265
268
|
};
|
|
266
269
|
const Fp6 = {
|
|
267
|
-
ORDER: Fp2.ORDER,
|
|
270
|
+
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
|
268
271
|
BITS: 3 * Fp2.BITS,
|
|
269
272
|
BYTES: 3 * Fp2.BYTES,
|
|
270
273
|
MASK: bitMask(3 * Fp2.BITS),
|
|
@@ -424,7 +427,7 @@ const Fp12Multiply = ({ c0, c1 }, rhs) => {
|
|
|
424
427
|
let t1 = Fp6.mul(c0, r0); // c0 * r0
|
|
425
428
|
let t2 = Fp6.mul(c1, r1); // c1 * r1
|
|
426
429
|
return {
|
|
427
|
-
c0: Fp6.add(t1, Fp6.mulByNonresidue(t2)),
|
|
430
|
+
c0: Fp6.add(t1, Fp6.mulByNonresidue(t2)), // T1 + T2 * v
|
|
428
431
|
// (c0 + c1) * (r0 + r1) - (T1 + T2)
|
|
429
432
|
c1: Fp6.sub(Fp6.mul(Fp6.add(c0, c1), Fp6.add(r0, r1)), Fp6.add(t1, t2)),
|
|
430
433
|
};
|
|
@@ -441,12 +444,12 @@ function Fp4Square(a, b) {
|
|
|
441
444
|
const a2 = Fp2.sqr(a);
|
|
442
445
|
const b2 = Fp2.sqr(b);
|
|
443
446
|
return {
|
|
444
|
-
first: Fp2.add(Fp2.mulByNonresidue(b2), a2),
|
|
447
|
+
first: Fp2.add(Fp2.mulByNonresidue(b2), a2), // b² * Nonresidue + a²
|
|
445
448
|
second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
|
|
446
449
|
};
|
|
447
450
|
}
|
|
448
451
|
const Fp12 = {
|
|
449
|
-
ORDER: Fp2.ORDER,
|
|
452
|
+
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
|
450
453
|
BITS: 2 * Fp2.BITS,
|
|
451
454
|
BYTES: 2 * Fp2.BYTES,
|
|
452
455
|
MASK: bitMask(2 * Fp2.BITS),
|
|
@@ -521,7 +524,7 @@ const Fp12 = {
|
|
|
521
524
|
let t0 = Fp6.multiplyBy01(c0, o0, o1);
|
|
522
525
|
let t1 = Fp6.multiplyBy1(c1, o4);
|
|
523
526
|
return {
|
|
524
|
-
c0: Fp6.add(Fp6.mulByNonresidue(t1), t0),
|
|
527
|
+
c0: Fp6.add(Fp6.mulByNonresidue(t1), t0), // T1 * v + T0
|
|
525
528
|
// (c1 + c0) * [o0, o1+o4] - T0 - T1
|
|
526
529
|
c1: Fp6.sub(Fp6.sub(Fp6.multiplyBy01(Fp6.add(c1, c0), o0, Fp2.add(o1, o4)), t0), t1),
|
|
527
530
|
};
|
|
@@ -544,13 +547,13 @@ const Fp12 = {
|
|
|
544
547
|
let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
|
|
545
548
|
return {
|
|
546
549
|
c0: Fp6.create({
|
|
547
|
-
c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3),
|
|
548
|
-
c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5),
|
|
550
|
+
c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0) + T3
|
|
551
|
+
c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5), // 2 * (T5 - c0c1) + T5
|
|
549
552
|
c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
|
|
550
|
-
}),
|
|
553
|
+
}), // 2 * (T7 - c0c2) + T7
|
|
551
554
|
c1: Fp6.create({
|
|
552
|
-
c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9),
|
|
553
|
-
c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4),
|
|
555
|
+
c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9), // 2 * (T9 + c1c0) + T9
|
|
556
|
+
c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4), // 2 * (T4 + c1c1) + T4
|
|
554
557
|
c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
|
|
555
558
|
}),
|
|
556
559
|
}; // 2 * (T6 + c1c2) + T6
|
|
@@ -635,8 +638,7 @@ const FP12_FROBENIUS_COEFFICIENTS = [
|
|
|
635
638
|
].map((n) => Fp2.fromBigTuple(n));
|
|
636
639
|
// END OF CURVE FIELDS
|
|
637
640
|
// HashToCurve
|
|
638
|
-
// 3-isogeny map from E' to E
|
|
639
|
-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-E.3
|
|
641
|
+
// 3-isogeny map from E' to E https://www.rfc-editor.org/rfc/rfc9380#appendix-E.3
|
|
640
642
|
const isogenyMapG2 = isogenyMap(Fp2, [
|
|
641
643
|
// xNum
|
|
642
644
|
[
|
|
@@ -777,8 +779,8 @@ const isogenyMapG1 = isogenyMap(Fp, [
|
|
|
777
779
|
].map((i) => i.map((j) => BigInt(j))));
|
|
778
780
|
// SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
|
|
779
781
|
const G2_SWU = mapToCurveSimpleSWU(Fp2, {
|
|
780
|
-
A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }),
|
|
781
|
-
B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }),
|
|
782
|
+
A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }), // A' = 240 * I
|
|
783
|
+
B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }), // B' = 1012 * (1 + I)
|
|
782
784
|
Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
|
|
783
785
|
});
|
|
784
786
|
// Optimized SWU Map - Fp to G1
|
|
@@ -820,7 +822,7 @@ function G2psi2(c, P) {
|
|
|
820
822
|
//
|
|
821
823
|
// Parameter definitions are in section 5.3 of the spec unless otherwise noted.
|
|
822
824
|
// Parameter values come from section 8.8.2 of the spec.
|
|
823
|
-
// https://
|
|
825
|
+
// https://www.rfc-editor.org/rfc/rfc9380#section-8.8.2
|
|
824
826
|
//
|
|
825
827
|
// Base field F is GF(p^m)
|
|
826
828
|
// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
|
|
@@ -851,11 +853,39 @@ const htfDefaults = Object.freeze({
|
|
|
851
853
|
});
|
|
852
854
|
// Encoding utils
|
|
853
855
|
// Point on G1 curve: (x, y)
|
|
854
|
-
const C_BIT_POS = Fp.BITS; // C_bit, compression bit for serialization flag
|
|
855
|
-
const I_BIT_POS = Fp.BITS + 1; // I_bit, point-at-infinity bit for serialization flag
|
|
856
|
-
const S_BIT_POS = Fp.BITS + 2; // S_bit, sign bit for serialization flag
|
|
857
856
|
// Compressed point of infinity
|
|
858
|
-
const COMPRESSED_ZERO = Fp.toBytes(
|
|
857
|
+
const COMPRESSED_ZERO = setMask(Fp.toBytes(_0n), { infinity: true, compressed: true }); // set compressed & point-at-infinity bits
|
|
858
|
+
function parseMask(bytes) {
|
|
859
|
+
// Copy, so we can remove mask data. It will be removed also later, when Fp.create will call modulo.
|
|
860
|
+
bytes = bytes.slice();
|
|
861
|
+
const mask = bytes[0] & 224;
|
|
862
|
+
const compressed = !!((mask >> 7) & 1); // compression bit (0b1000_0000)
|
|
863
|
+
const infinity = !!((mask >> 6) & 1); // point at infinity bit (0b0100_0000)
|
|
864
|
+
const sort = !!((mask >> 5) & 1); // sort bit (0b0010_0000)
|
|
865
|
+
bytes[0] &= 31; // clear mask (zero first 3 bits)
|
|
866
|
+
return { compressed, infinity, sort, value: bytes };
|
|
867
|
+
}
|
|
868
|
+
function setMask(bytes, mask) {
|
|
869
|
+
if (bytes[0] & 224)
|
|
870
|
+
throw new Error('setMask: non-empty mask');
|
|
871
|
+
if (mask.compressed)
|
|
872
|
+
bytes[0] |= 128;
|
|
873
|
+
if (mask.infinity)
|
|
874
|
+
bytes[0] |= 64;
|
|
875
|
+
if (mask.sort)
|
|
876
|
+
bytes[0] |= 32;
|
|
877
|
+
return bytes;
|
|
878
|
+
}
|
|
879
|
+
function signatureG1ToRawBytes(point) {
|
|
880
|
+
point.assertValidity();
|
|
881
|
+
const isZero = point.equals(bls12_381.G1.ProjectivePoint.ZERO);
|
|
882
|
+
const { x, y } = point.toAffine();
|
|
883
|
+
if (isZero)
|
|
884
|
+
return COMPRESSED_ZERO.slice();
|
|
885
|
+
const P = Fp.ORDER;
|
|
886
|
+
const sort = Boolean((y * _2n) / P);
|
|
887
|
+
return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
|
|
888
|
+
}
|
|
859
889
|
function signatureG2ToRawBytes(point) {
|
|
860
890
|
// NOTE: by some reasons it was missed in bls12-381, looks like bug
|
|
861
891
|
point.assertValidity();
|
|
@@ -866,13 +896,12 @@ function signatureG2ToRawBytes(point) {
|
|
|
866
896
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
|
867
897
|
const { re: y0, im: y1 } = Fp2.reim(y);
|
|
868
898
|
const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
|
|
869
|
-
const
|
|
870
|
-
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
|
|
899
|
+
const sort = Boolean((tmp / Fp.ORDER) & _1n);
|
|
871
900
|
const z2 = x0;
|
|
872
|
-
return concatB(numberToBytesBE(
|
|
901
|
+
return concatB(setMask(numberToBytesBE(x1, len), { sort, compressed: true }), numberToBytesBE(z2, len));
|
|
873
902
|
}
|
|
874
903
|
// To verify curve parameters, see pairing-friendly-curves spec:
|
|
875
|
-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-
|
|
904
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11
|
|
876
905
|
// Basic math is done over finite fields over p.
|
|
877
906
|
// More complicated math is done over polynominal extension fields.
|
|
878
907
|
// To simplify calculations in Fp12, we construct extension tower:
|
|
@@ -903,7 +932,7 @@ export const bls12_381 = bls({
|
|
|
903
932
|
Gy: BigInt('0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'),
|
|
904
933
|
a: Fp.ZERO,
|
|
905
934
|
b: _4n,
|
|
906
|
-
htfDefaults: { ...htfDefaults, m: 1 },
|
|
935
|
+
htfDefaults: { ...htfDefaults, m: 1, DST: 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_' },
|
|
907
936
|
wrapPrivateKey: true,
|
|
908
937
|
allowInfinityPoint: true,
|
|
909
938
|
// Checks is the point resides in prime-order subgroup.
|
|
@@ -932,7 +961,7 @@ export const bls12_381 = bls({
|
|
|
932
961
|
},
|
|
933
962
|
// Clear cofactor of G1
|
|
934
963
|
// https://eprint.iacr.org/2019/403
|
|
935
|
-
clearCofactor: (
|
|
964
|
+
clearCofactor: (_c, point) => {
|
|
936
965
|
// return this.multiplyUnsafe(CURVE.h);
|
|
937
966
|
return point.multiplyUnsafe(bls12_381.params.x).add(point); // x*P + P
|
|
938
967
|
},
|
|
@@ -941,31 +970,35 @@ export const bls12_381 = bls({
|
|
|
941
970
|
return isogenyMapG1(x, y);
|
|
942
971
|
},
|
|
943
972
|
fromBytes: (bytes) => {
|
|
944
|
-
|
|
945
|
-
if (
|
|
973
|
+
const { compressed, infinity, sort, value } = parseMask(bytes);
|
|
974
|
+
if (value.length === 48 && compressed) {
|
|
946
975
|
// TODO: Fp.bytes
|
|
947
976
|
const P = Fp.ORDER;
|
|
948
|
-
const compressedValue = bytesToNumberBE(
|
|
949
|
-
const bflag = bitGet(compressedValue, I_BIT_POS);
|
|
977
|
+
const compressedValue = bytesToNumberBE(value);
|
|
950
978
|
// Zero
|
|
951
|
-
if (bflag === _1n)
|
|
952
|
-
return { x: _0n, y: _0n };
|
|
953
979
|
const x = Fp.create(compressedValue & Fp.MASK);
|
|
980
|
+
if (infinity) {
|
|
981
|
+
if (x !== _0n)
|
|
982
|
+
throw new Error('G1: non-empty compressed point at infinity');
|
|
983
|
+
return { x: _0n, y: _0n };
|
|
984
|
+
}
|
|
954
985
|
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
|
|
955
986
|
let y = Fp.sqrt(right);
|
|
956
987
|
if (!y)
|
|
957
988
|
throw new Error('Invalid compressed G1 point');
|
|
958
|
-
|
|
959
|
-
if ((y * _2n) / P !== aflag)
|
|
989
|
+
if ((y * _2n) / P !== BigInt(sort))
|
|
960
990
|
y = Fp.neg(y);
|
|
961
991
|
return { x: Fp.create(x), y: Fp.create(y) };
|
|
962
992
|
}
|
|
963
|
-
else if (
|
|
993
|
+
else if (value.length === 96 && !compressed) {
|
|
964
994
|
// Check if the infinity flag is set
|
|
965
|
-
|
|
995
|
+
const x = bytesToNumberBE(value.subarray(0, Fp.BYTES));
|
|
996
|
+
const y = bytesToNumberBE(value.subarray(Fp.BYTES));
|
|
997
|
+
if (infinity) {
|
|
998
|
+
if (x !== _0n || y !== _0n)
|
|
999
|
+
throw new Error('G1: non-empty point at infinity');
|
|
966
1000
|
return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
|
|
967
|
-
|
|
968
|
-
const y = bytesToNumberBE(bytes.subarray(Fp.BYTES));
|
|
1001
|
+
}
|
|
969
1002
|
return { x: Fp.create(x), y: Fp.create(y) };
|
|
970
1003
|
}
|
|
971
1004
|
else {
|
|
@@ -979,10 +1012,8 @@ export const bls12_381 = bls({
|
|
|
979
1012
|
if (isZero)
|
|
980
1013
|
return COMPRESSED_ZERO.slice();
|
|
981
1014
|
const P = Fp.ORDER;
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
num = bitSet(num, S_BIT_POS, true);
|
|
985
|
-
return numberToBytesBE(num, Fp.BYTES);
|
|
1015
|
+
const sort = Boolean((y * _2n) / P);
|
|
1016
|
+
return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
|
|
986
1017
|
}
|
|
987
1018
|
else {
|
|
988
1019
|
if (isZero) {
|
|
@@ -995,6 +1026,33 @@ export const bls12_381 = bls({
|
|
|
995
1026
|
}
|
|
996
1027
|
}
|
|
997
1028
|
},
|
|
1029
|
+
ShortSignature: {
|
|
1030
|
+
fromHex(hex) {
|
|
1031
|
+
const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex, 48));
|
|
1032
|
+
const P = Fp.ORDER;
|
|
1033
|
+
const compressedValue = bytesToNumberBE(value);
|
|
1034
|
+
// Zero
|
|
1035
|
+
if (infinity)
|
|
1036
|
+
return bls12_381.G1.ProjectivePoint.ZERO;
|
|
1037
|
+
const x = Fp.create(compressedValue & Fp.MASK);
|
|
1038
|
+
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
|
|
1039
|
+
let y = Fp.sqrt(right);
|
|
1040
|
+
if (!y)
|
|
1041
|
+
throw new Error('Invalid compressed G1 point');
|
|
1042
|
+
const aflag = BigInt(sort);
|
|
1043
|
+
if ((y * _2n) / P !== aflag)
|
|
1044
|
+
y = Fp.neg(y);
|
|
1045
|
+
const point = bls12_381.G1.ProjectivePoint.fromAffine({ x, y });
|
|
1046
|
+
point.assertValidity();
|
|
1047
|
+
return point;
|
|
1048
|
+
},
|
|
1049
|
+
toRawBytes(point) {
|
|
1050
|
+
return signatureG1ToRawBytes(point);
|
|
1051
|
+
},
|
|
1052
|
+
toHex(point) {
|
|
1053
|
+
return bytesToHex(signatureG1ToRawBytes(point));
|
|
1054
|
+
},
|
|
1055
|
+
},
|
|
998
1056
|
},
|
|
999
1057
|
// G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
|
|
1000
1058
|
// where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
|
|
@@ -1054,45 +1112,45 @@ export const bls12_381 = bls({
|
|
|
1054
1112
|
return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
|
|
1055
1113
|
},
|
|
1056
1114
|
fromBytes: (bytes) => {
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1115
|
+
const { compressed, infinity, sort, value } = parseMask(bytes);
|
|
1116
|
+
if ((!compressed && !infinity && sort) || // 00100000
|
|
1117
|
+
(!compressed && infinity && sort) || // 01100000
|
|
1118
|
+
(sort && infinity && compressed) // 11100000
|
|
1119
|
+
) {
|
|
1120
|
+
throw new Error('Invalid encoding flag: ' + (bytes[0] & 224));
|
|
1061
1121
|
}
|
|
1062
|
-
const bitC = m_byte & 0x80; // compression bit
|
|
1063
|
-
const bitI = m_byte & 0x40; // point at infinity bit
|
|
1064
|
-
const bitS = m_byte & 0x20; // sign bit
|
|
1065
1122
|
const L = Fp.BYTES;
|
|
1066
1123
|
const slc = (b, from, to) => bytesToNumberBE(b.slice(from, to));
|
|
1067
|
-
if (
|
|
1124
|
+
if (value.length === 96 && compressed) {
|
|
1068
1125
|
const b = bls12_381.params.G2b;
|
|
1069
1126
|
const P = Fp.ORDER;
|
|
1070
|
-
|
|
1071
|
-
if (bitI) {
|
|
1127
|
+
if (infinity) {
|
|
1072
1128
|
// check that all bytes are 0
|
|
1073
|
-
if (
|
|
1129
|
+
if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
|
|
1074
1130
|
throw new Error('Invalid compressed G2 point');
|
|
1075
1131
|
}
|
|
1076
1132
|
return { x: Fp2.ZERO, y: Fp2.ZERO };
|
|
1077
1133
|
}
|
|
1078
|
-
const x_1 = slc(
|
|
1079
|
-
const x_0 = slc(
|
|
1134
|
+
const x_1 = slc(value, 0, L);
|
|
1135
|
+
const x_0 = slc(value, L, 2 * L);
|
|
1080
1136
|
const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
|
|
1081
1137
|
const right = Fp2.add(Fp2.pow(x, _3n), b); // y² = x³ + 4 * (u+1) = x³ + b
|
|
1082
1138
|
let y = Fp2.sqrt(right);
|
|
1083
1139
|
const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
|
|
1084
|
-
y =
|
|
1140
|
+
y = sort && Y_bit > 0 ? y : Fp2.neg(y);
|
|
1085
1141
|
return { x, y };
|
|
1086
1142
|
}
|
|
1087
|
-
else if (
|
|
1088
|
-
|
|
1089
|
-
|
|
1143
|
+
else if (value.length === 192 && !compressed) {
|
|
1144
|
+
if (infinity) {
|
|
1145
|
+
if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
|
|
1146
|
+
throw new Error('Invalid uncompressed G2 point');
|
|
1147
|
+
}
|
|
1090
1148
|
return { x: Fp2.ZERO, y: Fp2.ZERO };
|
|
1091
1149
|
}
|
|
1092
|
-
const x1 = slc(
|
|
1093
|
-
const x0 = slc(
|
|
1094
|
-
const y1 = slc(
|
|
1095
|
-
const y0 = slc(
|
|
1150
|
+
const x1 = slc(value, 0, L);
|
|
1151
|
+
const x0 = slc(value, L, 2 * L);
|
|
1152
|
+
const y1 = slc(value, 2 * L, 3 * L);
|
|
1153
|
+
const y0 = slc(value, 3 * L, 4 * L);
|
|
1096
1154
|
return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
|
|
1097
1155
|
}
|
|
1098
1156
|
else {
|
|
@@ -1107,10 +1165,7 @@ export const bls12_381 = bls({
|
|
|
1107
1165
|
if (isZero)
|
|
1108
1166
|
return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
|
1109
1167
|
const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
|
|
1110
|
-
|
|
1111
|
-
let x_1 = bitSet(x.c1, C_BIT_POS, flag);
|
|
1112
|
-
x_1 = bitSet(x_1, S_BIT_POS, true);
|
|
1113
|
-
return concatB(numberToBytesBE(x_1, len), numberToBytesBE(x.c0, len));
|
|
1168
|
+
return concatB(setMask(numberToBytesBE(x.c1, len), { compressed: true, sort: flag }), numberToBytesBE(x.c0, len));
|
|
1114
1169
|
}
|
|
1115
1170
|
else {
|
|
1116
1171
|
if (isZero)
|
|
@@ -1123,16 +1178,15 @@ export const bls12_381 = bls({
|
|
|
1123
1178
|
Signature: {
|
|
1124
1179
|
// TODO: Optimize, it's very slow because of sqrt.
|
|
1125
1180
|
fromHex(hex) {
|
|
1126
|
-
|
|
1181
|
+
const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex));
|
|
1127
1182
|
const P = Fp.ORDER;
|
|
1128
1183
|
const half = hex.length / 2;
|
|
1129
1184
|
if (half !== 48 && half !== 96)
|
|
1130
1185
|
throw new Error('Invalid compressed signature length, must be 96 or 192');
|
|
1131
|
-
const z1 = bytesToNumberBE(
|
|
1132
|
-
const z2 = bytesToNumberBE(
|
|
1186
|
+
const z1 = bytesToNumberBE(value.slice(0, half));
|
|
1187
|
+
const z2 = bytesToNumberBE(value.slice(half));
|
|
1133
1188
|
// Indicates the infinity point
|
|
1134
|
-
|
|
1135
|
-
if (bflag1 === _1n)
|
|
1189
|
+
if (infinity)
|
|
1136
1190
|
return bls12_381.G2.ProjectivePoint.ZERO;
|
|
1137
1191
|
const x1 = Fp.create(z1 & Fp.MASK);
|
|
1138
1192
|
const x2 = Fp.create(z2);
|
|
@@ -1145,7 +1199,7 @@ export const bls12_381 = bls({
|
|
|
1145
1199
|
// Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
|
|
1146
1200
|
// If y1 happens to be zero, then use the bit of y0
|
|
1147
1201
|
const { re: y0, im: y1 } = Fp2.reim(y);
|
|
1148
|
-
const aflag1 =
|
|
1202
|
+
const aflag1 = BigInt(sort);
|
|
1149
1203
|
const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
|
|
1150
1204
|
const isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
|
|
1151
1205
|
if (isGreater || isZero)
|
|
@@ -1163,7 +1217,7 @@ export const bls12_381 = bls({
|
|
|
1163
1217
|
},
|
|
1164
1218
|
},
|
|
1165
1219
|
params: {
|
|
1166
|
-
x: BLS_X,
|
|
1220
|
+
x: BLS_X, // The BLS parameter x for BLS12-381
|
|
1167
1221
|
r: Fr.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
|
|
1168
1222
|
},
|
|
1169
1223
|
htfDefaults,
|