fix bls lint errors

This commit is contained in:
Marin Petrunić 2019-08-28 17:18:51 +02:00
parent 89ed2e68e7
commit 57428df8ec
10 changed files with 183 additions and 177 deletions

View File

@ -24,7 +24,7 @@
"build-web": "webpack --mode production --entry ./lib/web.js --output ./dist/bls.min.js", "build-web": "webpack --mode production --entry ./lib/web.js --output ./dist/bls.min.js",
"check-types": "tsc --noEmit", "check-types": "tsc --noEmit",
"lint": "eslint --ext .ts src/", "lint": "eslint --ext .ts src/",
"lint-fix": "eslint --ext .ts src/ --fix", "lint:fix": "eslint --ext .ts src/ --fix",
"pretest": "yarn check-types", "pretest": "yarn check-types",
"prepublishOnly": "yarn build", "prepublishOnly": "yarn build",
"test:unit": "nyc --cache-dir .nyc_output/.cache -r lcov -e .ts mocha -r ./.babel-register 'test/unit/**/*.test.ts' && nyc report", "test:unit": "nyc --cache-dir .nyc_output/.cache -r lcov -e .ts mocha -r ./.babel-register 'test/unit/**/*.test.ts' && nyc report",

View File

@ -1,4 +1,4 @@
declare module 'keccak256' { declare module "keccak256" {
export default function hash(a: Buffer | (Buffer | string | number)[]): Buffer; export default function hash(a: Buffer | (Buffer | string | number)[]): Buffer;

View File

@ -15,6 +15,71 @@ export class G1point {
this.point = point; this.point = point;
} }
public static fromBytesCompressed(value: bytes48): G1point {
assert(value.length === FP_POINT_LENGTH, `Expected g1 compressed input to have ${FP_POINT_LENGTH} bytes`);
value = Buffer.from(value);
const aIn = (value[0] & (1 << 5)) != 0;
const bIn = (value[0] & (1 << 6)) != 0;
const cIn = (value[0] & (1 << 7)) != 0;
value[0] &= 31;
if (!cIn) {
throw new Error("The serialised input does not have the C flag set.");
}
const x = ctx.BIG.frombytearray(value, 0);
if (bIn) {
if (!aIn && x.iszilch()) {
// This is a correctly formed serialisation of infinity
return new G1point(new ctx.ECP());
} else {
// The input is malformed
throw new Error(
"The serialised input has B flag set, but A flag is set, or X is non-zero.");
}
}
const modulus = getModulus();
if (ctx.BIG.comp(modulus, x) <= 0) {
throw new Error("X coordinate is too large.");
}
const point = new ctx.ECP();
point.setx(x);
if (point.is_infinity()) {
throw new Error("X coordinate is not on the curve.");
}
// Did we get the right branch of the sqrt?
if (!point.is_infinity() && aIn != calculateYFlag(point.getY())) {
// We didn't: so choose the other branch of the sqrt.
const x = new ctx.FP(point.getX());
const yneg = new ctx.FP(point.getY());
yneg.neg();
point.setxy(x.redc(), yneg.redc());
}
return new G1point(point);
}
public static generator(): G1point {
return new G1point(ctx.ECP.generator());
}
public static random(): G1point {
let ecp: ECP;
do {
ecp = new ctx.ECP();
ecp.setx(
ctx.BIG.frombytearray(
random.randomBuffer(FP_POINT_LENGTH),
0
)
);
} while (ecp.is_infinity());
return new G1point(ecp);
}
public mul(value: BIG): G1point { public mul(value: BIG): G1point {
const newPoint = this.point.mul(value); const newPoint = this.point.mul(value);
return new G1point(newPoint); return new G1point(newPoint);
@ -54,69 +119,4 @@ export class G1point {
output[0] |= flags; output[0] |= flags;
return output; return output;
} }
public static fromBytesCompressed(value: bytes48): G1point {
assert(value.length === FP_POINT_LENGTH, `Expected g1 compressed input to have ${FP_POINT_LENGTH} bytes`);
value = Buffer.from(value);
const aIn = (value[0] & (1 << 5)) != 0;
const bIn = (value[0] & (1 << 6)) != 0;
const cIn = (value[0] & (1 << 7)) != 0;
value[0] &= 31;
if (!cIn) {
throw new Error("The serialised input does not have the C flag set.");
}
const x = ctx.BIG.frombytearray(value, 0);
if (bIn) {
if (!aIn && x.iszilch()) {
// This is a correctly formed serialisation of infinity
return new G1point(new ctx.ECP());
} else {
// The input is malformed
throw new Error(
"The serialised input has B flag set, but A flag is set, or X is non-zero.");
}
}
const modulus = getModulus();
if (ctx.BIG.comp(modulus, x) <= 0) {
throw new Error("X coordinate is too large.");
}
let point = new ctx.ECP();
point.setx(x);
if (point.is_infinity()) {
throw new Error("X coordinate is not on the curve.");
}
// Did we get the right branch of the sqrt?
if (!point.is_infinity() && aIn != calculateYFlag(point.getY())) {
// We didn't: so choose the other branch of the sqrt.
const x = new ctx.FP(point.getX());
const yneg = new ctx.FP(point.getY());
yneg.neg();
point.setxy(x.redc(), yneg.redc())
}
return new G1point(point);
}
public static generator(): G1point {
return new G1point(ctx.ECP.generator());
}
public static random(): G1point {
let ecp: ECP;
do {
ecp = new ctx.ECP();
ecp.setx(
ctx.BIG.frombytearray(
random.randomBuffer(FP_POINT_LENGTH),
0
)
)
} while (ecp.is_infinity());
return new G1point(ecp);
}
} }

View File

@ -1,7 +1,7 @@
import {BIG} from "@chainsafe/milagro-crypto-js/src/big"; import {BIG} from "@chainsafe/milagro-crypto-js/src/big";
import {ECP2} from "@chainsafe/milagro-crypto-js/src/ecp2"; import {ECP2} from "@chainsafe/milagro-crypto-js/src/ecp2";
import {BLSDomain, bytes32, bytes96} from "../types"; import {BLSDomain, bytes32, bytes96} from "../types";
import { sha256 } from 'js-sha256'; import {sha256} from "js-sha256";
import ctx from "../ctx"; import ctx from "../ctx";
import * as random from "secure-random"; import * as random from "secure-random";
import {calculateYFlag, getModulus, padLeft} from "./utils"; import {calculateYFlag, getModulus, padLeft} from "./utils";
@ -16,47 +16,6 @@ export class G2point {
this.point = point; this.point = point;
} }
public add(other: G2point): G2point {
const sum = new ctx.ECP2();
sum.add(this.point);
sum.add(other.point);
sum.affine();
return new G2point(sum);
}
public mul(value: BIG): G2point {
const newPoint = this.point.mul(value);
return new G2point(newPoint);
}
public equal(other: G2point): boolean {
return this.point.equals(other.point);
}
public getPoint(): ECP2 {
return this.point;
}
public toBytesCompressed(): Buffer {
const xReBytes = Buffer.alloc(FP_POINT_LENGTH, 0);
const xImBytes = Buffer.alloc(FP_POINT_LENGTH, 0);
this.point.getX().getA().tobytearray(xReBytes, 0);
this.point.getX().getB().tobytearray(xImBytes, 0);
const c1 = true;
const b1 = this.point.is_infinity();
const a1 = !b1 && calculateYFlag(this.point.getY().getB());
const flags = ((a1 ? 1 << 5 : 0) | (b1 ? 1 << 6 : 0) | (c1 ? 1 << 7 : 0));
const mask = 31;
xImBytes[0] &= mask;
xImBytes[0] |= flags;
xReBytes[0] &= mask;
return Buffer.concat([
xImBytes,
xReBytes
]);
}
public static hashToG2(message: bytes32, domain: BLSDomain): G2point { public static hashToG2(message: bytes32, domain: BLSDomain): G2point {
const padding = Buffer.alloc(G2_HASH_PADDING, 0); const padding = Buffer.alloc(G2_HASH_PADDING, 0);
@ -66,7 +25,7 @@ export class G2point {
Buffer.concat([ Buffer.concat([
message, message,
padLeft(domain, 8), padLeft(domain, 8),
Buffer.from('01', 'hex') Buffer.from("01", "hex")
]) ])
)) ))
]); ]);
@ -76,7 +35,7 @@ export class G2point {
Buffer.concat([ Buffer.concat([
message, message,
padLeft(domain, 8), padLeft(domain, 8),
Buffer.from('02', 'hex') Buffer.from("02", "hex")
]) ])
)) ))
]); ]);
@ -89,13 +48,13 @@ export class G2point {
xRe.add(one); xRe.add(one);
xRe.norm(); xRe.norm();
point = new ctx.ECP2(); point = new ctx.ECP2();
point.setx(new ctx.FP2(xRe, xIm)) point.setx(new ctx.FP2(xRe, xIm));
} }
return new G2point(G2point.scaleWithCofactor(G2point.normaliseY(point))); return new G2point(G2point.scaleWithCofactor(G2point.normaliseY(point)));
} }
public static fromCompressedBytes(value: bytes96): G2point { public static fromCompressedBytes(value: bytes96): G2point {
assert(value.length === 2 * FP_POINT_LENGTH, 'Expected signature of 96 bytes'); assert(value.length === 2 * FP_POINT_LENGTH, "Expected signature of 96 bytes");
value = Buffer.from(value); value = Buffer.from(value);
const xImBytes = value.slice(0, FP_POINT_LENGTH); const xImBytes = value.slice(0, FP_POINT_LENGTH);
const xReBytes = value.slice(FP_POINT_LENGTH); const xReBytes = value.slice(FP_POINT_LENGTH);
@ -114,8 +73,8 @@ export class G2point {
const xRe = ctx.BIG.frombytearray(xReBytes, 0); const xRe = ctx.BIG.frombytearray(xReBytes, 0);
if (bIn) { if (bIn) {
if (!aIn if (!aIn
&& xIm.iszilch() && xIm.iszilch()
&& xRe.iszilch() ) { && xRe.iszilch() ) {
// This is a correctly formed serialisation of infinity // This is a correctly formed serialisation of infinity
return new G2point(new ctx.ECP2()); return new G2point(new ctx.ECP2());
} else { } else {
@ -131,7 +90,7 @@ export class G2point {
"The deserialised X real or imaginary coordinate is too large."); "The deserialised X real or imaginary coordinate is too large.");
} }
let point = new ctx.ECP2(); const point = new ctx.ECP2();
point.setx(new ctx.FP2(xRe, xIm)); point.setx(new ctx.FP2(xRe, xIm));
if(point.is_infinity()) { if(point.is_infinity()) {
throw new Error("X coordinate is not on the curve."); throw new Error("X coordinate is not on the curve.");
@ -189,7 +148,7 @@ export class G2point {
0 0
) )
) )
) );
} while (point.is_infinity()); } while (point.is_infinity());
return new G2point(point); return new G2point(point);
} }
@ -235,14 +194,56 @@ export class G2point {
const yNeg = new ctx.FP2(y); const yNeg = new ctx.FP2(y);
yNeg.neg(); yNeg.neg();
if (ctx.BIG.comp(y.getB(), yNeg.getB()) < 0 if (ctx.BIG.comp(y.getB(), yNeg.getB()) < 0
|| ((ctx.BIG.comp(y.getB(), yNeg.getB()) == 0) || ((ctx.BIG.comp(y.getB(), yNeg.getB()) == 0)
&& ctx.BIG.comp(y.getA(), yNeg.getA()) < 0) && ctx.BIG.comp(y.getA(), yNeg.getA()) < 0)
) { ) {
const newPoint = new ctx.ECP2(); const newPoint = new ctx.ECP2();
newPoint.setxy(point.getX(), yNeg); newPoint.setxy(point.getX(), yNeg);
return newPoint return newPoint;
} else { } else {
return point; return point;
} }
} }
public add(other: G2point): G2point {
const sum = new ctx.ECP2();
sum.add(this.point);
sum.add(other.point);
sum.affine();
return new G2point(sum);
}
public mul(value: BIG): G2point {
const newPoint = this.point.mul(value);
return new G2point(newPoint);
}
public equal(other: G2point): boolean {
return this.point.equals(other.point);
}
public getPoint(): ECP2 {
return this.point;
}
public toBytesCompressed(): Buffer {
const xReBytes = Buffer.alloc(FP_POINT_LENGTH, 0);
const xImBytes = Buffer.alloc(FP_POINT_LENGTH, 0);
this.point.getX().getA().tobytearray(xReBytes, 0);
this.point.getX().getB().tobytearray(xImBytes, 0);
const c1 = true;
const b1 = this.point.is_infinity();
const a1 = !b1 && calculateYFlag(this.point.getY().getB());
const flags = ((a1 ? 1 << 5 : 0) | (b1 ? 1 << 6 : 0) | (c1 ? 1 << 7 : 0));
const mask = 31;
xImBytes[0] &= mask;
xImBytes[0] |= flags;
xReBytes[0] &= mask;
return Buffer.concat([
xImBytes,
xReBytes
]);
}
} }

View File

@ -9,7 +9,7 @@ import ctx from "../ctx";
* @param length * @param length
*/ */
export function padLeft(source: Buffer, length: number): Buffer { export function padLeft(source: Buffer, length: number): Buffer {
assert(source.length <= length, 'Given array must be smaller or equal to desired array size'); assert(source.length <= length, "Given array must be smaller or equal to desired array size");
const result = Buffer.alloc(length, 0); const result = Buffer.alloc(length, 0);
source.copy(result, length - source.length); source.copy(result, length - source.length);
return result; return result;
@ -19,11 +19,11 @@ export function padLeft(source: Buffer, length: number): Buffer {
export function getModulus(): BIG { export function getModulus(): BIG {
return ctx.BIG.frombytearray( return ctx.BIG.frombytearray(
Buffer.from( Buffer.from(
'1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab', "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab",
'hex' "hex"
), ),
0 0
) );
} }
export function calculateYFlag(yIm: BIG): boolean { export function calculateYFlag(yIm: BIG): boolean {

View File

@ -49,7 +49,7 @@ function sign(secretKey: BLSSecretKey, messageHash: bytes32, domain: BLSDomain):
*/ */
function aggregateSignatures(signatures: BLSSignature[]): BLSSignature { function aggregateSignatures(signatures: BLSSignature[]): BLSSignature {
return signatures.map((signature): Signature => { return signatures.map((signature): Signature => {
return Signature.fromCompressedBytes(signature) return Signature.fromCompressedBytes(signature);
}).reduce((previousValue, currentValue): Signature => { }).reduce((previousValue, currentValue): Signature => {
return previousValue.add(currentValue); return previousValue.add(currentValue);
}).toBytesCompressed(); }).toBytesCompressed();
@ -64,7 +64,7 @@ function aggregatePubkeys(publicKeys: BLSPubkey[]): BLSPubkey {
return new G1point(new ctx.ECP()).toBytesCompressed(); return new G1point(new ctx.ECP()).toBytesCompressed();
} }
return publicKeys.map((publicKey): G1point => { return publicKeys.map((publicKey): G1point => {
return G1point.fromBytesCompressed(publicKey) return G1point.fromBytesCompressed(publicKey);
}).reduce((previousValue, currentValue): G1point => { }).reduce((previousValue, currentValue): G1point => {
return previousValue.add(currentValue); return previousValue.add(currentValue);
}).toBytesCompressed(); }).toBytesCompressed();
@ -98,7 +98,12 @@ function verify(publicKey: BLSPubkey, messageHash: bytes32, signature: BLSSignat
* @param signature * @param signature
* @param domain * @param domain
*/ */
function verifyMultiple(publicKeys: BLSPubkey[], messageHashes: bytes32[], signature: BLSSignature, domain: bytes8): boolean { function verifyMultiple(
publicKeys: BLSPubkey[],
messageHashes: bytes32[],
signature: BLSSignature,
domain: bytes8
): boolean {
if(publicKeys.length === 0 || publicKeys.length != messageHashes.length) { if(publicKeys.length === 0 || publicKeys.length != messageHashes.length) {
return false; return false;
} }
@ -129,4 +134,4 @@ export default {
aggregatePubkeys, aggregatePubkeys,
verify, verify,
verifyMultiple verifyMultiple
} };

View File

@ -15,6 +15,31 @@ export class PrivateKey {
this.value = value; this.value = value;
} }
public static fromBytes(bytes: Uint8Array): PrivateKey {
assert(bytes.length === SECRET_KEY_LENGTH, "Private key should have 32 bytes");
const value = Buffer.from(bytes);
return new PrivateKey(
ctx.BIG.frombytearray(
padLeft(
value,
48
),
0
)
);
}
public static fromHexString(value: string): PrivateKey {
return PrivateKey.fromBytes(
Buffer.from(value.replace("0x", ""), "hex")
);
}
public static random(): PrivateKey {
return PrivateKey.fromBytes(random.randomBuffer(SECRET_KEY_LENGTH));
}
public getValue(): BIG { public getValue(): BIG {
return this.value; return this.value;
} }
@ -34,31 +59,7 @@ export class PrivateKey {
} }
public toHexString(): string { public toHexString(): string {
return `0x${this.toBytes().toString('hex')}`; return `0x${this.toBytes().toString("hex")}`;
}
public static fromBytes(bytes: Uint8Array): PrivateKey {
assert(bytes.length === SECRET_KEY_LENGTH, 'Private key should have 32 bytes');
const value = Buffer.from(bytes);
return new PrivateKey(
ctx.BIG.frombytearray(
padLeft(
value,
48
),
0
)
)
}
public static fromHexString(value: string): PrivateKey {
return PrivateKey.fromBytes(
Buffer.from(value.replace('0x', ''), 'hex')
);
}
public static random(): PrivateKey {
return PrivateKey.fromBytes(random.randomBuffer(SECRET_KEY_LENGTH));
} }
} }

View File

@ -9,19 +9,7 @@ export class PublicKey {
public constructor(point: G1point) { public constructor(point: G1point) {
this.point = point; this.point = point;
} }
public getPoint(): G1point {
return this.point;
}
public toBytesCompressed(): BLSPubkey {
return this.point.toBytesCompressed();
}
public toHexString(): string {
return `0x${this.toBytesCompressed().toString('hex')}`;
}
public static fromPrivateKey(privateKey: PrivateKey): PublicKey { public static fromPrivateKey(privateKey: PrivateKey): PublicKey {
return new PublicKey( return new PublicKey(
G1point.generator().mul(privateKey.getValue()) G1point.generator().mul(privateKey.getValue())
@ -33,4 +21,16 @@ export class PublicKey {
G1point.fromBytesCompressed(publicKey) G1point.fromBytesCompressed(publicKey)
); );
} }
public getPoint(): G1point {
return this.point;
}
public toBytesCompressed(): BLSPubkey {
return this.point.toBytesCompressed();
}
public toHexString(): string {
return `0x${this.toBytesCompressed().toString("hex")}`;
}
} }

View File

@ -11,6 +11,14 @@ export class Signature {
this.point = point; this.point = point;
} }
public static fromCompressedBytes(signature: BLSSignature): Signature {
assert(
signature.length === 2 * FP_POINT_LENGTH,
`Signature must have ${2 * FP_POINT_LENGTH} bytes`
);
return new Signature(G2point.fromCompressedBytes(signature));
}
public add(other: Signature): Signature { public add(other: Signature): Signature {
return new Signature( return new Signature(
this.point.add(other.point) this.point.add(other.point)
@ -24,12 +32,4 @@ export class Signature {
public toBytesCompressed(): BLSSignature { public toBytesCompressed(): BLSSignature {
return this.point.toBytesCompressed(); return this.point.toBytesCompressed();
} }
public static fromCompressedBytes(signature: BLSSignature): Signature {
assert(
signature.length === 2 * FP_POINT_LENGTH,
`Signature must have ${2 * FP_POINT_LENGTH} bytes`
);
return new Signature(G2point.fromCompressedBytes(signature));
}
} }

View File

@ -1,8 +1,7 @@
import bls from "./index" import bls from "./index";
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
// @ts-ignore
(function (window: any) { (function (window: any) {
window.bls = bls window.bls = bls;
// @ts-ignore // @ts-ignore
})(window); })(window);