Refactor BLS, change API
This commit is contained in:
parent
37ebe6c40f
commit
c15c964f77
74
README.md
74
README.md
@ -214,6 +214,7 @@ There are following zero-dependency algorithms:
|
||||
- [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
|
||||
- [abstract/edwards: Twisted Edwards curve](#abstractedwards-twisted-edwards-curve)
|
||||
- [abstract/montgomery: Montgomery curve](#abstractmontgomery-montgomery-curve)
|
||||
- [abstract/bls: BLS curves](#abstractbls-bls-curves)
|
||||
- [abstract/hash-to-curve: Hashing strings to curve points](#abstracthash-to-curve-hashing-strings-to-curve-points)
|
||||
- [abstract/poseidon: Poseidon hash](#abstractposeidon-poseidon-hash)
|
||||
- [abstract/modular: Modular arithmetics utilities](#abstractmodular-modular-arithmetics-utilities)
|
||||
@ -491,6 +492,74 @@ Proper Elliptic Curve Points are not implemented yet.
|
||||
|
||||
You must specify curve params `Fp`, `a`, `Gu` coordinate of u, `montgomeryBits` and `nByteLength`.
|
||||
|
||||
### abstract/bls: BLS curves
|
||||
|
||||
The module abstracts BLS (Barreto-Lynn-Scott) primitives.
|
||||
|
||||
Right now we only implement BLS12-381, but in theory defining BLS12-377, BLS24
|
||||
should be straightforward.
|
||||
|
||||
Main methods and properties are:
|
||||
|
||||
- `getPublicKey(privateKey)`
|
||||
- `sign(message, privateKey)`
|
||||
- `verify(signature, message, publicKey)`
|
||||
- `aggregatePublicKeys(publicKeys)`
|
||||
- `aggregateSignatures(signatures)`
|
||||
- `G1` and `G2` curves containing `CURVE` and `ProjectivePoint`
|
||||
- `Signature` property with `fromHex`, `toHex` methods
|
||||
- `fields` containing `Fp`, `Fp2`, `Fp6`, `Fp12`, `Fr`
|
||||
|
||||
Full types:
|
||||
|
||||
```ts
|
||||
getPublicKey: (privateKey: PrivKey) => Uint8Array;
|
||||
sign: {
|
||||
(message: Hex, privateKey: PrivKey): Uint8Array;
|
||||
(message: ProjPointType<Fp2>, privateKey: PrivKey): ProjPointType<Fp2>;
|
||||
};
|
||||
verify: (
|
||||
signature: Hex | ProjPointType<Fp2>,
|
||||
message: Hex | ProjPointType<Fp2>,
|
||||
publicKey: Hex | ProjPointType<Fp>
|
||||
) => boolean;
|
||||
verifyBatch: (
|
||||
signature: Hex | ProjPointType<Fp2>,
|
||||
messages: (Hex | ProjPointType<Fp2>)[],
|
||||
publicKeys: (Hex | ProjPointType<Fp>)[]
|
||||
) => boolean;
|
||||
aggregatePublicKeys: {
|
||||
(publicKeys: Hex[]): Uint8Array;
|
||||
(publicKeys: ProjPointType<Fp>[]): ProjPointType<Fp>;
|
||||
};
|
||||
aggregateSignatures: {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
|
||||
};
|
||||
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
||||
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
||||
G1: CurvePointsRes<Fp> & ReturnType<typeof htf.createHasher<Fp>>;
|
||||
G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>;
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
params: {
|
||||
x: bigint;
|
||||
r: bigint;
|
||||
G1b: bigint;
|
||||
G2b: Fp2;
|
||||
};
|
||||
fields: {
|
||||
Fp: IField<Fp>;
|
||||
Fp2: IField<Fp2>;
|
||||
Fp6: IField<Fp6>;
|
||||
Fp12: IField<Fp12>;
|
||||
Fr: IField<bigint>;
|
||||
};
|
||||
utils: {
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
|
||||
};
|
||||
```
|
||||
|
||||
### abstract/hash-to-curve: Hashing strings to curve points
|
||||
|
||||
The module allows to hash arbitrary strings to elliptic curve points. Implements [hash-to-curve v16](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16).
|
||||
@ -589,11 +658,6 @@ type PoseidonOpts = {
|
||||
const instance = poseidon(opts: PoseidonOpts);
|
||||
```
|
||||
|
||||
### abstract/bls
|
||||
|
||||
The module abstracts BLS (Barreto-Lynn-Scott) primitives. In theory you should be able to write BLS12-377, BLS24,
|
||||
and others with it.
|
||||
|
||||
### abstract/modular: Modular arithmetics utilities
|
||||
|
||||
```ts
|
||||
|
@ -24,13 +24,16 @@ import {
|
||||
|
||||
type Fp = bigint; // Can be different field?
|
||||
|
||||
// prettier-ignore
|
||||
const _2n = BigInt(2), _3n = BigInt(3);
|
||||
|
||||
export type SignatureCoder<Fp2> = {
|
||||
decode(hex: Hex): ProjPointType<Fp2>;
|
||||
encode(point: ProjPointType<Fp2>): Uint8Array;
|
||||
fromHex(hex: Hex): ProjPointType<Fp2>;
|
||||
toRawBytes(point: ProjPointType<Fp2>): Uint8Array;
|
||||
toHex(point: ProjPointType<Fp2>): string;
|
||||
};
|
||||
|
||||
export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
||||
r: bigint;
|
||||
G1: Omit<CurvePointsType<Fp>, 'n'> & {
|
||||
mapToCurve: htf.MapToCurve<Fp>;
|
||||
htfDefaults: htf.Opts;
|
||||
@ -40,20 +43,25 @@ export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
||||
mapToCurve: htf.MapToCurve<Fp2>;
|
||||
htfDefaults: htf.Opts;
|
||||
};
|
||||
x: bigint;
|
||||
Fp: IField<Fp>;
|
||||
Fr: IField<bigint>;
|
||||
Fp2: IField<Fp2> & {
|
||||
reim: (num: Fp2) => { re: bigint; im: bigint };
|
||||
multiplyByB: (num: Fp2) => Fp2;
|
||||
frobeniusMap(num: Fp2, power: number): Fp2;
|
||||
fields: {
|
||||
Fp: IField<Fp>;
|
||||
Fr: IField<bigint>;
|
||||
Fp2: IField<Fp2> & {
|
||||
reim: (num: Fp2) => { re: bigint; im: bigint };
|
||||
multiplyByB: (num: Fp2) => Fp2;
|
||||
frobeniusMap(num: Fp2, power: number): Fp2;
|
||||
};
|
||||
Fp6: IField<Fp6>;
|
||||
Fp12: IField<Fp12> & {
|
||||
frobeniusMap(num: Fp12, power: number): Fp12;
|
||||
multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
||||
conjugate(num: Fp12): Fp12;
|
||||
finalExponentiate(num: Fp12): Fp12;
|
||||
};
|
||||
};
|
||||
Fp6: IField<Fp6>;
|
||||
Fp12: IField<Fp12> & {
|
||||
frobeniusMap(num: Fp12, power: number): Fp12;
|
||||
multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
||||
conjugate(num: Fp12): Fp12;
|
||||
finalExponentiate(num: Fp12): Fp12;
|
||||
params: {
|
||||
x: bigint;
|
||||
r: bigint;
|
||||
};
|
||||
htfDefaults: htf.Opts;
|
||||
hash: CHash; // Because we need outputLen for DRBG
|
||||
@ -61,18 +69,6 @@ export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
||||
};
|
||||
|
||||
export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
||||
CURVE: CurveType<Fp, Fp2, Fp6, Fp12>;
|
||||
Fr: IField<bigint>;
|
||||
Fp: IField<Fp>;
|
||||
Fp2: IField<Fp2>;
|
||||
Fp6: IField<Fp6>;
|
||||
Fp12: IField<Fp12>;
|
||||
G1: CurvePointsRes<Fp> & ReturnType<typeof htf.createHasher<Fp>>;
|
||||
G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>;
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
||||
calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
|
||||
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
||||
getPublicKey: (privateKey: PrivKey) => Uint8Array;
|
||||
sign: {
|
||||
(message: Hex, privateKey: PrivKey): Uint8Array;
|
||||
@ -83,6 +79,11 @@ export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
||||
message: Hex | ProjPointType<Fp2>,
|
||||
publicKey: Hex | ProjPointType<Fp>
|
||||
) => boolean;
|
||||
verifyBatch: (
|
||||
signature: Hex | ProjPointType<Fp2>,
|
||||
messages: (Hex | ProjPointType<Fp2>)[],
|
||||
publicKeys: (Hex | ProjPointType<Fp>)[]
|
||||
) => boolean;
|
||||
aggregatePublicKeys: {
|
||||
(publicKeys: Hex[]): Uint8Array;
|
||||
(publicKeys: ProjPointType<Fp>[]): ProjPointType<Fp>;
|
||||
@ -91,22 +92,36 @@ export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
|
||||
};
|
||||
verifyBatch: (
|
||||
signature: Hex | ProjPointType<Fp2>,
|
||||
messages: (Hex | ProjPointType<Fp2>)[],
|
||||
publicKeys: (Hex | ProjPointType<Fp>)[]
|
||||
) => boolean;
|
||||
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
||||
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
||||
G1: CurvePointsRes<Fp> & ReturnType<typeof htf.createHasher<Fp>>;
|
||||
G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>;
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
params: {
|
||||
x: bigint;
|
||||
r: bigint;
|
||||
G1b: bigint;
|
||||
G2b: Fp2;
|
||||
};
|
||||
fields: {
|
||||
Fp: IField<Fp>;
|
||||
Fp2: IField<Fp2>;
|
||||
Fp6: IField<Fp6>;
|
||||
Fp12: IField<Fp12>;
|
||||
Fr: IField<bigint>;
|
||||
};
|
||||
utils: {
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
|
||||
};
|
||||
};
|
||||
|
||||
export function bls<Fp2, Fp6, Fp12>(
|
||||
CURVE: CurveType<Fp, Fp2, Fp6, Fp12>
|
||||
): CurveFn<Fp, Fp2, Fp6, Fp12> {
|
||||
// Fields looks pretty specific for curve, so for now we need to pass them with opts
|
||||
const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE;
|
||||
const BLS_X_LEN = bitLen(CURVE.x);
|
||||
// Fields are specific for curve, so for now we'll need to pass them with opts
|
||||
const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE.fields;
|
||||
const BLS_X_LEN = bitLen(CURVE.params.x);
|
||||
const groupLen = 32; // TODO: calculate; hardcoded for now
|
||||
|
||||
// Pre-compute coefficients for sparse multiplication
|
||||
@ -122,18 +137,18 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
// Double
|
||||
let t0 = Fp2.sqr(Ry); // Ry²
|
||||
let t1 = Fp2.sqr(Rz); // Rz²
|
||||
let t2 = Fp2.multiplyByB(Fp2.mul(t1, 3n)); // 3 * T1 * B
|
||||
let t3 = Fp2.mul(t2, 3n); // 3 * T2
|
||||
let t2 = Fp2.multiplyByB(Fp2.mul(t1, _3n)); // 3 * T1 * B
|
||||
let t3 = Fp2.mul(t2, _3n); // 3 * T2
|
||||
let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
|
||||
ell_coeff.push([
|
||||
Fp2.sub(t2, t0), // T2 - T0
|
||||
Fp2.mul(Fp2.sqr(Rx), 3n), // 3 * Rx²
|
||||
Fp2.mul(Fp2.sqr(Rx), _3n), // 3 * Rx²
|
||||
Fp2.neg(t4), // -T4
|
||||
]);
|
||||
Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
|
||||
Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.sqr(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
|
||||
Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), _2n); // ((T0 - T3) * Rx * Ry) / 2
|
||||
Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), _2n)), Fp2.mul(Fp2.sqr(t2), _3n)); // ((T0 + T3) / 2)² - 3 * T2²
|
||||
Rz = Fp2.mul(t0, t4); // T0 * T4
|
||||
if (bitGet(CURVE.x, i)) {
|
||||
if (bitGet(CURVE.params.x, i)) {
|
||||
// Addition
|
||||
let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
|
||||
let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
|
||||
@ -145,7 +160,7 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
let t2 = Fp2.sqr(t1); // T1²
|
||||
let t3 = Fp2.mul(t2, t1); // T2 * T1
|
||||
let t4 = Fp2.mul(t2, Rx); // T2 * Rx
|
||||
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
|
||||
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, _2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
|
||||
Rx = Fp2.mul(t1, t5); // T1 * T5
|
||||
Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
|
||||
Rz = Fp2.mul(Rz, t3); // Rz * T3
|
||||
@ -155,7 +170,7 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
}
|
||||
|
||||
function millerLoop(ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]): Fp12 {
|
||||
const { x } = CURVE;
|
||||
const { x } = CURVE.params;
|
||||
const Px = g1[0];
|
||||
const Py = g1[1];
|
||||
let f12 = Fp12.ONE;
|
||||
@ -174,8 +189,9 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
|
||||
const utils = {
|
||||
randomPrivateKey: (): Uint8Array => {
|
||||
return Fr.toBytes(hashToPrivateScalar(CURVE.randomBytes(groupLen + 8), CURVE.r));
|
||||
return Fr.toBytes(hashToPrivateScalar(CURVE.randomBytes(groupLen + 8), CURVE.params.r));
|
||||
},
|
||||
calcPairingPrecomputes,
|
||||
};
|
||||
|
||||
// Point on G1 curve: (x, y)
|
||||
@ -236,7 +252,7 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
return point instanceof G1.ProjectivePoint ? (point as G1) : G1.ProjectivePoint.fromHex(point);
|
||||
}
|
||||
function normP2(point: G2Hex): G2 {
|
||||
return point instanceof G2.ProjectivePoint ? point : Signature.decode(point);
|
||||
return point instanceof G2.ProjectivePoint ? point : Signature.fromHex(point);
|
||||
}
|
||||
function normP2Hash(point: G2Hex, htfOpts?: htf.htfBasicOpts): G2 {
|
||||
return point instanceof G2.ProjectivePoint
|
||||
@ -259,7 +275,7 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
msgPoint.assertValidity();
|
||||
const sigPoint = msgPoint.multiply(G1.normPrivateKeyToScalar(privateKey));
|
||||
if (message instanceof G2.ProjectivePoint) return sigPoint;
|
||||
return Signature.encode(sigPoint);
|
||||
return Signature.toRawBytes(sigPoint);
|
||||
}
|
||||
|
||||
// Checks if pairing of public key & hash is equal to pairing of generator & signature.
|
||||
@ -309,7 +325,7 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
aggAffine.assertValidity();
|
||||
return aggAffine;
|
||||
}
|
||||
return Signature.encode(aggAffine);
|
||||
return Signature.toRawBytes(aggAffine);
|
||||
}
|
||||
|
||||
// https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
|
||||
@ -353,24 +369,30 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
G1.ProjectivePoint.BASE._setWindowSize(4);
|
||||
|
||||
return {
|
||||
CURVE,
|
||||
Fr,
|
||||
Fp,
|
||||
Fp2,
|
||||
Fp6,
|
||||
Fp12,
|
||||
G1,
|
||||
G2,
|
||||
Signature,
|
||||
millerLoop,
|
||||
calcPairingPrecomputes,
|
||||
pairing,
|
||||
getPublicKey,
|
||||
sign,
|
||||
verify,
|
||||
verifyBatch,
|
||||
aggregatePublicKeys,
|
||||
aggregateSignatures,
|
||||
verifyBatch,
|
||||
millerLoop,
|
||||
pairing,
|
||||
G1,
|
||||
G2,
|
||||
Signature,
|
||||
fields: {
|
||||
Fr,
|
||||
Fp,
|
||||
Fp2,
|
||||
Fp6,
|
||||
Fp12,
|
||||
},
|
||||
params: {
|
||||
x: CURVE.params.x,
|
||||
r: CURVE.params.r,
|
||||
G1b: CURVE.G1.b,
|
||||
G2b: CURVE.G2.b,
|
||||
},
|
||||
utils,
|
||||
};
|
||||
}
|
||||
|
@ -123,12 +123,12 @@ export function utf8ToBytes(str: string): Uint8Array {
|
||||
// Amount of bits inside bigint (Same as n.toString(2).length)
|
||||
export function bitLen(n: bigint) {
|
||||
let len;
|
||||
for (len = 0; n > 0n; n >>= _1n, len += 1);
|
||||
for (len = 0; n > _0n; n >>= _1n, len += 1);
|
||||
return len;
|
||||
}
|
||||
// Gets single bit at position. NOTE: first bit position is 0 (same as arrays)
|
||||
// Same as !!+Array.from(n.toString(2)).reverse()[pos]
|
||||
export const bitGet = (n: bigint, pos: number) => (n >> BigInt(pos)) & 1n;
|
||||
export const bitGet = (n: bigint, pos: number) => (n >> BigInt(pos)) & _1n;
|
||||
// Sets single bit at position
|
||||
export const bitSet = (n: bigint, pos: number, value: boolean) =>
|
||||
n | ((value ? _1n : _0n) << BigInt(pos));
|
||||
|
110
src/bls12-381.ts
110
src/bls12-381.ts
@ -59,6 +59,7 @@ import {
|
||||
bitGet,
|
||||
Hex,
|
||||
bitMask,
|
||||
bytesToHex,
|
||||
} from './abstract/utils.js';
|
||||
// Types
|
||||
import {
|
||||
@ -72,8 +73,8 @@ import { isogenyMap } from './abstract/hash-to-curve.js';
|
||||
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
||||
// prettier-ignore
|
||||
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
|
||||
const _8n = BigInt(8),
|
||||
_16n = BigInt(16);
|
||||
// prettier-ignore
|
||||
const _8n = BigInt(8), _16n = BigInt(16);
|
||||
|
||||
// CURVE FIELDS
|
||||
// Finite field over p.
|
||||
@ -950,9 +951,9 @@ const isogenyMapG1 = isogenyMap(
|
||||
|
||||
// SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
|
||||
const G2_SWU = mapToCurveSimpleSWU(Fp2, {
|
||||
A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(240n) }), // A' = 240 * I
|
||||
B: Fp2.create({ c0: Fp.create(1012n), c1: Fp.create(1012n) }), // B' = 1012 * (1 + I)
|
||||
Z: Fp2.create({ c0: Fp.create(-2n), c1: Fp.create(-1n) }), // Z: -(2 + I)
|
||||
A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }), // A' = 240 * I
|
||||
B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }), // B' = 1012 * (1 + I)
|
||||
Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
|
||||
});
|
||||
// Optimized SWU Map - Fp to G1
|
||||
const G1_SWU = mapToCurveSimpleSWU(Fp, {
|
||||
@ -966,7 +967,7 @@ const G1_SWU = mapToCurveSimpleSWU(Fp, {
|
||||
'0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0'
|
||||
)
|
||||
),
|
||||
Z: Fp.create(11n),
|
||||
Z: Fp.create(BigInt(11)),
|
||||
});
|
||||
|
||||
// Endomorphisms (for fast cofactor clearing)
|
||||
@ -1042,7 +1043,23 @@ const C_BIT_POS = Fp.BITS; // C_bit, compression bit for serialization flag
|
||||
const I_BIT_POS = Fp.BITS + 1; // I_bit, point-at-infinity bit for serialization flag
|
||||
const S_BIT_POS = Fp.BITS + 2; // S_bit, sign bit for serialization flag
|
||||
// Compressed point of infinity
|
||||
const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(0n, I_BIT_POS, true), S_BIT_POS, true)); // set compressed & point-at-infinity bits
|
||||
const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(_0n, I_BIT_POS, true), S_BIT_POS, true)); // set compressed & point-at-infinity bits
|
||||
|
||||
function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
|
||||
// NOTE: by some reasons it was missed in bls12-381, looks like bug
|
||||
point.assertValidity();
|
||||
const len = Fp.BYTES;
|
||||
if (point.equals(bls12_381.G2.ProjectivePoint.ZERO))
|
||||
return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
||||
const { x, y } = point.toAffine();
|
||||
const { re: x0, im: x1 } = Fp2.reim(x);
|
||||
const { re: y0, im: y1 } = Fp2.reim(y);
|
||||
const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
|
||||
const aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
|
||||
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
|
||||
const z2 = x0;
|
||||
return concatB(numberToBytesBE(z1, len), numberToBytesBE(z2, len));
|
||||
}
|
||||
|
||||
// To verify curve parameters, see pairing-friendly-curves spec:
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09
|
||||
@ -1056,13 +1073,13 @@ const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(0n, I_BIT_POS, true), S_BIT_POS
|
||||
// Here goes constants && point encoding format
|
||||
export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
// Fields
|
||||
Fr,
|
||||
Fp,
|
||||
Fp2,
|
||||
Fp6,
|
||||
Fp12,
|
||||
// order; z⁴ − z² + 1
|
||||
r: Fr.ORDER, // Same as N in other curves
|
||||
fields: {
|
||||
Fp,
|
||||
Fp2,
|
||||
Fp6,
|
||||
Fp12,
|
||||
Fr,
|
||||
},
|
||||
// G1 is the order-q subgroup of E1(Fp) : y² = x³ + 4, #E1(Fp) = h1q, where
|
||||
// characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
|
||||
G1: {
|
||||
@ -1095,8 +1112,8 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
|
||||
|
||||
// todo: unroll
|
||||
const xP = point.multiplyUnsafe(bls12_381.CURVE.x).negate(); // [x]P
|
||||
const u2P = xP.multiplyUnsafe(bls12_381.CURVE.x); // [u2]P
|
||||
const xP = point.multiplyUnsafe(bls12_381.params.x).negate(); // [x]P
|
||||
const u2P = xP.multiplyUnsafe(bls12_381.params.x); // [u2]P
|
||||
return u2P.equals(phi);
|
||||
|
||||
// https://eprint.iacr.org/2019/814.pdf
|
||||
@ -1115,21 +1132,23 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
// https://eprint.iacr.org/2019/403
|
||||
clearCofactor: (c, point) => {
|
||||
// return this.multiplyUnsafe(CURVE.h);
|
||||
return point.multiplyUnsafe(bls12_381.CURVE.x).add(point); // x*P + P
|
||||
return point.multiplyUnsafe(bls12_381.params.x).add(point); // x*P + P
|
||||
},
|
||||
mapToCurve: (scalars: bigint[]) => {
|
||||
const { x, y } = G1_SWU(Fp.create(scalars[0]));
|
||||
return isogenyMapG1(x, y);
|
||||
},
|
||||
fromBytes: (bytes: Uint8Array): AffinePoint<Fp> => {
|
||||
bytes = bytes.slice();
|
||||
if (bytes.length === 48) {
|
||||
// TODO: Fp.bytes
|
||||
const P = Fp.ORDER;
|
||||
const compressedValue = bytesToNumberBE(bytes);
|
||||
const bflag = bitGet(compressedValue, I_BIT_POS);
|
||||
// Zero
|
||||
if (bflag === _1n) return { x: _0n, y: _0n };
|
||||
const x = Fp.create(compressedValue & Fp.MASK);
|
||||
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.CURVE.G1.b)); // y² = x³ + b
|
||||
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
|
||||
let y = Fp.sqrt(right);
|
||||
if (!y) throw new Error('Invalid compressed G1 point');
|
||||
const aflag = bitGet(compressedValue, C_BIT_POS);
|
||||
@ -1138,8 +1157,8 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
} else if (bytes.length === 96) {
|
||||
// Check if the infinity flag is set
|
||||
if ((bytes[0] & (1 << 6)) !== 0) return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
|
||||
const x = bytesToNumberBE(bytes.slice(0, Fp.BYTES));
|
||||
const y = bytesToNumberBE(bytes.slice(Fp.BYTES));
|
||||
const x = bytesToNumberBE(bytes.subarray(0, Fp.BYTES));
|
||||
const y = bytesToNumberBE(bytes.subarray(Fp.BYTES));
|
||||
return { x: Fp.create(x), y: Fp.create(y) };
|
||||
} else {
|
||||
throw new Error('Invalid point G1, expected 48/96 bytes');
|
||||
@ -1212,7 +1231,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
// It returns false for shitty points.
|
||||
// https://eprint.iacr.org/2021/1130.pdf
|
||||
isTorsionFree: (c, P): boolean => {
|
||||
return P.multiplyUnsafe(bls12_381.CURVE.x).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
|
||||
return P.multiplyUnsafe(bls12_381.params.x).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
|
||||
// Older version: https://eprint.iacr.org/2019/814.pdf
|
||||
// Ψ²(P) => Ψ³(P) => [z]Ψ³(P) where z = -x => [z]Ψ³(P) - Ψ²(P) + P == O
|
||||
// return P.psi2().psi().mulNegX().subtract(psi2).add(P).isZero();
|
||||
@ -1222,7 +1241,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
// https://eprint.iacr.org/2017/419.pdf
|
||||
// prettier-ignore
|
||||
clearCofactor: (c, P) => {
|
||||
const { x } = bls12_381.CURVE;
|
||||
const x = bls12_381.params.x;
|
||||
let t1 = P.multiplyUnsafe(x).negate(); // [-x]P
|
||||
let t2 = G2psi(c, P); // Ψ(P)
|
||||
let t3 = P.double(); // 2P
|
||||
@ -1236,6 +1255,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
|
||||
},
|
||||
fromBytes: (bytes: Uint8Array): AffinePoint<Fp2> => {
|
||||
bytes = bytes.slice();
|
||||
const m_byte = bytes[0] & 0xe0;
|
||||
if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
|
||||
throw new Error('Invalid encoding flag: ' + m_byte);
|
||||
@ -1246,7 +1266,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
const L = Fp.BYTES;
|
||||
const slc = (b: Uint8Array, from: number, to?: number) => bytesToNumberBE(b.slice(from, to));
|
||||
if (bytes.length === 96 && bitC) {
|
||||
const { b } = bls12_381.CURVE.G2;
|
||||
const b = bls12_381.params.G2b;
|
||||
const P = Fp.ORDER;
|
||||
|
||||
bytes[0] = bytes[0] & 0x1f; // clear flags
|
||||
@ -1280,31 +1300,31 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
}
|
||||
},
|
||||
toBytes: (c, point, isCompressed) => {
|
||||
const { BYTES: len, ORDER: P } = Fp;
|
||||
const isZero = point.equals(c.ZERO);
|
||||
const { x, y } = point.toAffine();
|
||||
if (isCompressed) {
|
||||
const P = Fp.ORDER;
|
||||
if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES));
|
||||
if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
||||
const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
|
||||
// set compressed & sign bits (looks like different offsets than for G1/Fp?)
|
||||
let x_1 = bitSet(x.c1, C_BIT_POS, flag);
|
||||
x_1 = bitSet(x_1, S_BIT_POS, true);
|
||||
return concatB(numberToBytesBE(x_1, Fp.BYTES), numberToBytesBE(x.c0, Fp.BYTES));
|
||||
return concatB(numberToBytesBE(x_1, len), numberToBytesBE(x.c0, len));
|
||||
} else {
|
||||
if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 * Fp.BYTES - 1)); // bytes[0] |= 1 << 6;
|
||||
if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 * len - 1)); // bytes[0] |= 1 << 6;
|
||||
const { re: x0, im: x1 } = Fp2.reim(x);
|
||||
const { re: y0, im: y1 } = Fp2.reim(y);
|
||||
return concatB(
|
||||
numberToBytesBE(x1, Fp.BYTES),
|
||||
numberToBytesBE(x0, Fp.BYTES),
|
||||
numberToBytesBE(y1, Fp.BYTES),
|
||||
numberToBytesBE(y0, Fp.BYTES)
|
||||
numberToBytesBE(x1, len),
|
||||
numberToBytesBE(x0, len),
|
||||
numberToBytesBE(y1, len),
|
||||
numberToBytesBE(y0, len)
|
||||
);
|
||||
}
|
||||
},
|
||||
Signature: {
|
||||
// TODO: Optimize, it's very slow because of sqrt.
|
||||
decode(hex: Hex): ProjPointType<Fp2> {
|
||||
fromHex(hex: Hex): ProjPointType<Fp2> {
|
||||
hex = ensureBytes('signatureHex', hex);
|
||||
const P = Fp.ORDER;
|
||||
const half = hex.length / 2;
|
||||
@ -1319,7 +1339,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
const x1 = Fp.create(z1 & Fp.MASK);
|
||||
const x2 = Fp.create(z2);
|
||||
const x = Fp2.create({ c0: x2, c1: x1 });
|
||||
const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381.CURVE.G2.b); // y² = x³ + 4
|
||||
const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381.params.G2b); // y² = x³ + 4
|
||||
// The slow part
|
||||
let y = Fp2.sqrt(y2);
|
||||
if (!y) throw new Error('Failed to find a square root');
|
||||
@ -1335,24 +1355,18 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
point.assertValidity();
|
||||
return point;
|
||||
},
|
||||
encode(point: ProjPointType<Fp2>) {
|
||||
// NOTE: by some reasons it was missed in bls12-381, looks like bug
|
||||
point.assertValidity();
|
||||
if (point.equals(bls12_381.G2.ProjectivePoint.ZERO))
|
||||
return concatB(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES));
|
||||
const a = point.toAffine();
|
||||
const { re: x0, im: x1 } = Fp2.reim(a.x);
|
||||
const { re: y0, im: y1 } = Fp2.reim(a.y);
|
||||
const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
|
||||
const aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
|
||||
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
|
||||
const z2 = x0;
|
||||
return concatB(numberToBytesBE(z1, Fp.BYTES), numberToBytesBE(z2, Fp.BYTES));
|
||||
toRawBytes(point: ProjPointType<Fp2>) {
|
||||
return signatureG2ToRawBytes(point);
|
||||
},
|
||||
toHex(point: ProjPointType<Fp2>) {
|
||||
return bytesToHex(signatureG2ToRawBytes(point));
|
||||
},
|
||||
},
|
||||
},
|
||||
// The BLS parameter x for BLS12-381
|
||||
x: BLS_X,
|
||||
params: {
|
||||
x: BLS_X, // The BLS parameter x for BLS12-381
|
||||
r: Fr.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
|
||||
},
|
||||
htfDefaults,
|
||||
hash: sha256,
|
||||
randomBytes,
|
||||
|
@ -30,19 +30,19 @@ const FIELDS = {
|
||||
pallas: { Fp: [pallas.CURVE.Fp] },
|
||||
vesta: { Fp: [vesta.CURVE.Fp] },
|
||||
bls12: {
|
||||
Fp: [bls12_381.CURVE.Fp],
|
||||
Fp: [bls12_381.fields.Fp],
|
||||
Fp2: [
|
||||
bls12_381.CURVE.Fp2,
|
||||
fc.array(fc.bigInt(1n, bls12_381.CURVE.Fp.ORDER - 1n), {
|
||||
bls12_381.fields.Fp2,
|
||||
fc.array(fc.bigInt(1n, bls12_381.fields.Fp.ORDER - 1n), {
|
||||
minLength: 2,
|
||||
maxLength: 2,
|
||||
}),
|
||||
(Fp2, num) => Fp2.fromBigTuple([num[0], num[1]]),
|
||||
],
|
||||
// Fp6: [bls12_381.CURVE.Fp6],
|
||||
// Fp6: [bls12_381.fields.Fp6],
|
||||
Fp12: [
|
||||
bls12_381.CURVE.Fp12,
|
||||
fc.array(fc.bigInt(1n, bls12_381.CURVE.Fp.ORDER - 1n), {
|
||||
bls12_381.fields.Fp12,
|
||||
fc.array(fc.bigInt(1n, bls12_381.fields.Fp.ORDER - 1n), {
|
||||
minLength: 12,
|
||||
maxLength: 12,
|
||||
}),
|
||||
@ -221,7 +221,7 @@ for (const c in FIELDS) {
|
||||
|
||||
const isSquare = mod.FpIsSquare(Fp);
|
||||
// Not implemented
|
||||
if (Fp !== bls12_381.CURVE.Fp12) {
|
||||
if (Fp !== bls12_381.fields.Fp12) {
|
||||
should('multiply/sqrt', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
|
@ -24,11 +24,10 @@ const SCALAR_VECTORS = readFileSync('./test/bls12-381/bls12-381-scalar-test-vect
|
||||
const NUM_RUNS = Number(process.env.RUNS_COUNT || 10); // reduce to 1 to shorten test time
|
||||
fc.configureGlobal({ numRuns: NUM_RUNS });
|
||||
|
||||
const { Fp2 } = bls;
|
||||
const G1Point = bls.G1.ProjectivePoint;
|
||||
const G2Point = bls.G2.ProjectivePoint;
|
||||
const G1Aff = (x, y) => G1Point.fromAffine({ x, y });
|
||||
const CURVE_ORDER = bls.CURVE.r;
|
||||
const CURVE_ORDER = bls.params.r;
|
||||
|
||||
const FC_MSG = fc.hexaString({ minLength: 64, maxLength: 64 });
|
||||
const FC_MSG_5 = fc.array(FC_MSG, { minLength: 5, maxLength: 5 });
|
||||
@ -42,10 +41,10 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
function equal(a, b, comment) {
|
||||
deepStrictEqual(a.equals(b), true, `eq(${comment})`);
|
||||
}
|
||||
const { Fp, Fp2 } = bls.fields;
|
||||
|
||||
// Fp
|
||||
describe('bls12-381 Fp', () => {
|
||||
const Fp = bls.Fp;
|
||||
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
||||
|
||||
should('multiply/sqrt', () => {
|
||||
@ -60,8 +59,7 @@ describe('bls12-381 Fp', () => {
|
||||
|
||||
// Fp2
|
||||
describe('bls12-381 Fp2', () => {
|
||||
const Fp = bls.Fp;
|
||||
const Fp2 = bls.Fp2;
|
||||
const { Fp, Fp2 } = bls.fields;
|
||||
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
||||
const FC_BIGINT_2 = fc.array(FC_BIGINT, { minLength: 2, maxLength: 2 });
|
||||
|
||||
@ -149,7 +147,7 @@ describe('bls12-381 Fp2', () => {
|
||||
|
||||
// Point
|
||||
describe('bls12-381 Point', () => {
|
||||
const Fp = bls.Fp;
|
||||
const { Fp } = bls.fields;
|
||||
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
||||
const PointG1 = G1Point;
|
||||
const PointG2 = G2Point;
|
||||
@ -557,9 +555,12 @@ describe('bls12-381 Point', () => {
|
||||
];
|
||||
// Use wNAF allow scalars higher than CURVE.r
|
||||
const w = wNAF(G2Point, 1);
|
||||
const hEff = BigInt(
|
||||
'0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'
|
||||
);
|
||||
for (let p of points) {
|
||||
const ours = p.clearCofactor();
|
||||
const shouldBe = w.unsafeLadder(p, bls.CURVE.G2.hEff);
|
||||
const shouldBe = w.unsafeLadder(p, hEff);
|
||||
deepStrictEqual(ours.equals(shouldBe), true, 'clearLast');
|
||||
}
|
||||
});
|
||||
@ -577,12 +578,12 @@ describe('bls12-381/basic', () => {
|
||||
deepStrictEqual(g1.x, G1Point.ZERO.x);
|
||||
deepStrictEqual(g1.y, G1Point.ZERO.y);
|
||||
// Test Non-Zero
|
||||
const x = bls.Fp.create(
|
||||
const x = Fp.create(
|
||||
BigInt(
|
||||
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
||||
)
|
||||
);
|
||||
const y = bls.Fp.create(
|
||||
const y = Fp.create(
|
||||
BigInt(
|
||||
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||
)
|
||||
@ -603,12 +604,12 @@ describe('bls12-381/basic', () => {
|
||||
deepStrictEqual(g1.x, G1Point.ZERO.x);
|
||||
deepStrictEqual(g1.y, G1Point.ZERO.y);
|
||||
// Test Non-Zero
|
||||
const x = bls.Fp.create(
|
||||
const x = Fp.create(
|
||||
BigInt(
|
||||
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
||||
)
|
||||
);
|
||||
const y = bls.Fp.create(
|
||||
const y = Fp.create(
|
||||
BigInt(
|
||||
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||
)
|
||||
@ -689,12 +690,12 @@ describe('bls12-381/basic', () => {
|
||||
// Test Zero
|
||||
deepStrictEqual(G1Point.ZERO.toHex(false), B_192_40);
|
||||
// Test Non-Zero
|
||||
const x = bls.Fp.create(
|
||||
const x = Fp.create(
|
||||
BigInt(
|
||||
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
||||
)
|
||||
);
|
||||
const y = bls.Fp.create(
|
||||
const y = Fp.create(
|
||||
BigInt(
|
||||
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||
)
|
||||
@ -710,12 +711,12 @@ describe('bls12-381/basic', () => {
|
||||
// Test Zero
|
||||
deepStrictEqual(G1Point.ZERO.toHex(false), B_192_40);
|
||||
// Test Non-Zero
|
||||
const x = bls.Fp.create(
|
||||
const x = Fp.create(
|
||||
BigInt(
|
||||
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
||||
)
|
||||
);
|
||||
const y = bls.Fp.create(
|
||||
const y = Fp.create(
|
||||
BigInt(
|
||||
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||
)
|
||||
@ -801,32 +802,32 @@ describe('bls12-381/basic', () => {
|
||||
throws(() => G2Point.fromPrivateKey(0n));
|
||||
});
|
||||
const VALID_G1 = new G1Point(
|
||||
bls.Fp.create(
|
||||
Fp.create(
|
||||
3609742242174788176010452839163620388872641749536604986743596621604118973777515189035770461528205168143692110933639n
|
||||
),
|
||||
bls.Fp.create(
|
||||
Fp.create(
|
||||
1619277690257184054444116778047375363103842303863153349133480657158810226683757397206929105479676799650932070320089n
|
||||
),
|
||||
bls.Fp.create(1n)
|
||||
Fp.create(1n)
|
||||
);
|
||||
const VALID_G1_2 = new G1Point(
|
||||
bls.Fp.create(
|
||||
Fp.create(
|
||||
1206972466279728255044019580914616126536509750250979180256809997983196363639429409634110400978470384566664128085207n
|
||||
),
|
||||
bls.Fp.create(
|
||||
Fp.create(
|
||||
2991142246317096160788653339959532007292638191110818490939476869616372888657136539642598243964263069435065725313423n
|
||||
),
|
||||
bls.Fp.create(1n)
|
||||
Fp.create(1n)
|
||||
);
|
||||
|
||||
const INVALID_G1 = new G1Point(
|
||||
bls.Fp.create(
|
||||
Fp.create(
|
||||
499001545268060011619089734015590154568173930614466321429631711131511181286230338880376679848890024401335766847607n
|
||||
),
|
||||
bls.Fp.create(
|
||||
Fp.create(
|
||||
3934582309586258715640230772291917282844636728991757779640464479794033391537662970190753981664259511166946374555673n
|
||||
),
|
||||
bls.Fp.create(1n)
|
||||
Fp.create(1n)
|
||||
);
|
||||
|
||||
should('aggregate pubkeys', () => {
|
||||
@ -855,7 +856,7 @@ describe('bls12-381/basic', () => {
|
||||
});
|
||||
should(`produce correct scalars (${SCALAR_VECTORS.length} vectors)`, () => {
|
||||
const options = {
|
||||
p: bls.CURVE.r,
|
||||
p: bls.params.r,
|
||||
m: 1,
|
||||
expand: undefined,
|
||||
};
|
||||
@ -863,7 +864,7 @@ describe('bls12-381/basic', () => {
|
||||
const [okmAscii, expectedHex] = vector;
|
||||
const expected = BigInt('0x' + expectedHex);
|
||||
const okm = utf8ToBytes(okmAscii);
|
||||
const scalars = hash_to_field(okm, 1, Object.assign({}, bls.CURVE.htfDefaults, options));
|
||||
const scalars = hash_to_field(okm, 1, Object.assign({}, bls.G2.CURVE.htfDefaults, options));
|
||||
deepStrictEqual(scalars[0][0], expected);
|
||||
}
|
||||
});
|
||||
@ -871,7 +872,8 @@ describe('bls12-381/basic', () => {
|
||||
|
||||
// Pairing
|
||||
describe('pairing', () => {
|
||||
const { pairing, Fp12 } = bls;
|
||||
const { pairing } = bls;
|
||||
const { Fp12 } = bls.fields;
|
||||
const G1 = G1Point.BASE;
|
||||
const G2 = G2Point.BASE;
|
||||
|
||||
@ -1000,7 +1002,7 @@ describe('hash-to-curve', () => {
|
||||
];
|
||||
for (let i = 0; i < VECTORS_G1.length; i++) {
|
||||
const t = VECTORS_G1[i];
|
||||
should(`hashToCurve/G1 Killic (${i})`, () => {
|
||||
should(`G1 Killic (${i})`, () => {
|
||||
const p = bls.G1.hashToCurve(t.msg, {
|
||||
DST: 'BLS12381G1_XMD:SHA-256_SSWU_RO_TESTGEN',
|
||||
});
|
||||
@ -1259,7 +1261,7 @@ describe('bls12-381 deterministic', () => {
|
||||
.reverse()
|
||||
.reduce((acc, i) => acc + i);
|
||||
|
||||
const Fp12 = bls.Fp12;
|
||||
const { Fp12 } = bls.fields;
|
||||
|
||||
should('Killic based/Pairing', () => {
|
||||
const t = bls.pairing(G1Point.BASE, G2Point.BASE);
|
||||
|
@ -407,7 +407,7 @@ describe('ed25519', () => {
|
||||
ed25519.verify(sig_invalid, message, publicKey);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
should('not accept point without z, t', () => {
|
||||
const t = 81718630521762619991978402609047527194981150691135404693881672112315521837062n;
|
||||
const point = ed25519.ExtendedPoint.fromAffine({ x: t, y: t });
|
||||
|
Loading…
Reference in New Issue
Block a user