Skip to content

Commit 81150f2

Browse files
authored
Merge pull request #167 from ChainSafe/mkeil/napi-rebuild-2
feat: implement napi build
2 parents 46ecf80 + bcaec4d commit 81150f2

File tree

17 files changed

+736
-310
lines changed

17 files changed

+736
-310
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: Unit tests
2626
run: yarn test:unit
2727
- name: Download spec tests
28-
run: yarn download-test-cases
28+
run: yarn download-spec-tests
2929
- name: Spec tests
3030
run: yarn test:spec
3131
- name: Web tests

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@chainsafe/bls",
3-
"version": "7.1.3",
3+
"version": "8.0.0",
44
"description": "Implementation of bls signature verification for ethereum 2.0",
55
"engines": {
66
"node": ">=18"
@@ -73,7 +73,7 @@
7373
"test:coverage": "nyc --cache-dir .nyc_output/.cache -r lcov -e .ts mocha 'test/unit/**/*.test.ts' && nyc report",
7474
"test:spec": "mocha 'test/spec/**/*.test.ts'",
7575
"test": "yarn run test:unit && yarn run test:spec",
76-
"download-test-cases": "node --loader ts-node/esm test/downloadSpecTests.ts",
76+
"download-spec-tests": "node --loader ts-node/esm test/downloadSpecTests.ts",
7777
"coverage": "codecov -F bls",
7878
"benchmark": "node --loader ts-node/esm benchmark/index.ts",
7979
"benchmark:all": "cd benchmark && yarn install && yarn benchmark:all"
@@ -83,7 +83,7 @@
8383
"bls-eth-wasm": "^1.1.1"
8484
},
8585
"devDependencies": {
86-
"@chainsafe/blst": "^0.2.4",
86+
"@chainsafe/blst": "^1.0.0",
8787
"@chainsafe/eslint-plugin-node": "^11.2.3",
8888
"@chainsafe/threads": "^1.9.0",
8989
"@lodestar/spec-test-util": "1.13.0",
@@ -106,6 +106,7 @@
106106
"karma-spec-reporter": "^0.0.32",
107107
"karma-webpack": "^5.0.0",
108108
"mocha": "^10.0.0",
109+
"null-loader": "^4.0.1",
109110
"nyc": "^15.0.0",
110111
"prettier": "^2.1.2",
111112
"resolve-typescript-plugin": "^1.2.0",
@@ -120,7 +121,7 @@
120121
"v8-profiler-next": "1.10.0"
121122
},
122123
"peerDependencies": {
123-
"@chainsafe/blst": "^0.2.4"
124+
"@chainsafe/blst": "^1.0.0"
124125
},
125126
"peerDependenciesMeta": {
126127
"@chainsafe/blst": {

src/blst-native/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import {SecretKey} from "./secretKey.js";
22
import {PublicKey} from "./publicKey.js";
33
import {Signature} from "./signature.js";
4-
import {IBls} from "../types.js";
4+
import {IBls, Implementation} from "../types.js";
55
import {functionalInterfaceFactory} from "../functional.js";
66
export * from "../constants.js";
77

88
export {SecretKey, PublicKey, Signature};
99

10+
const implementation: Implementation = "blst-native";
1011
export const bls: IBls = {
11-
implementation: "blst-native",
12+
implementation,
1213
SecretKey,
1314
PublicKey,
1415
Signature,
1516

16-
...functionalInterfaceFactory({SecretKey, PublicKey, Signature}),
17+
...functionalInterfaceFactory({implementation, SecretKey, PublicKey, Signature}),
1718
};
1819

1920
export default bls;

src/blst-native/publicKey.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
import * as blst from "@chainsafe/blst";
1+
import blst from "@chainsafe/blst";
22
import {EmptyAggregateError} from "../errors.js";
33
import {bytesToHex, hexToBytes} from "../helpers/index.js";
4-
import {PointFormat, PublicKey as IPublicKey} from "../types.js";
4+
import {CoordType, PointFormat, PublicKey as IPublicKey} from "../types.js";
55

6-
export class PublicKey extends blst.PublicKey implements IPublicKey {
7-
constructor(value: ConstructorParameters<typeof blst.PublicKey>[0]) {
8-
super(value);
9-
}
6+
export class PublicKey implements IPublicKey {
7+
private constructor(private readonly value: blst.PublicKey) {}
108

119
/** @param type Defaults to `CoordType.jacobian` */
12-
static fromBytes(bytes: Uint8Array, type?: blst.CoordType, validate?: boolean): PublicKey {
13-
const pk = blst.PublicKey.fromBytes(bytes, type);
10+
static fromBytes(bytes: Uint8Array, type?: CoordType, validate = true): PublicKey {
11+
// need to hack the CoordType so @chainsafe/blst is not a required dep
12+
const pk = blst.PublicKey.deserialize(bytes, (type as unknown) as blst.CoordType);
1413
if (validate) pk.keyValidate();
15-
return new PublicKey(pk.value);
14+
return new PublicKey(pk);
1615
}
1716

1817
static fromHex(hex: string): PublicKey {
@@ -24,19 +23,30 @@ export class PublicKey extends blst.PublicKey implements IPublicKey {
2423
throw new EmptyAggregateError();
2524
}
2625

27-
const pk = blst.aggregatePubkeys(publicKeys);
28-
return new PublicKey(pk.value);
26+
const pk = blst.aggregatePublicKeys(publicKeys.map(({value}) => value));
27+
return new PublicKey(pk);
28+
}
29+
30+
/**
31+
* Implemented for SecretKey to be able to call .toPublicKey()
32+
*/
33+
private static friendBuild(key: blst.PublicKey): PublicKey {
34+
return new PublicKey(key);
2935
}
3036

3137
toBytes(format?: PointFormat): Uint8Array {
3238
if (format === PointFormat.uncompressed) {
33-
return this.value.serialize();
39+
return this.value.serialize(false);
3440
} else {
35-
return this.value.compress();
41+
return this.value.serialize(true);
3642
}
3743
}
3844

3945
toHex(format?: PointFormat): string {
4046
return bytesToHex(this.toBytes(format));
4147
}
48+
49+
multiplyBy(bytes: Uint8Array): PublicKey {
50+
return new PublicKey(this.value.multiplyBy(bytes));
51+
}
4252
}

src/blst-native/secretKey.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as blst from "@chainsafe/blst";
1+
import blst from "@chainsafe/blst";
22
import crypto from "crypto";
33
import {bytesToHex, hexToBytes, isZeroUint8Array} from "../helpers/index.js";
44
import {SECRET_KEY_LENGTH} from "../constants.js";
@@ -8,18 +8,15 @@ import {Signature} from "./signature.js";
88
import {ZeroSecretKeyError} from "../errors.js";
99

1010
export class SecretKey implements ISecretKey {
11-
readonly value: blst.SecretKey;
12-
constructor(value: blst.SecretKey) {
13-
this.value = value;
14-
}
11+
constructor(private readonly value: blst.SecretKey) {}
1512

1613
static fromBytes(bytes: Uint8Array): SecretKey {
1714
// draft-irtf-cfrg-bls-signature-04 does not allow SK == 0
1815
if (isZeroUint8Array(bytes)) {
1916
throw new ZeroSecretKeyError();
2017
}
2118

22-
const sk = blst.SecretKey.fromBytes(bytes);
19+
const sk = blst.SecretKey.deserialize(bytes);
2320
return new SecretKey(sk);
2421
}
2522

@@ -33,16 +30,18 @@ export class SecretKey implements ISecretKey {
3330
}
3431

3532
sign(message: Uint8Array): Signature {
36-
return new Signature(this.value.sign(message).value);
33+
// @ts-expect-error Need to hack private constructor with static method
34+
return Signature.friendBuild(this.value.sign(message));
3735
}
3836

3937
toPublicKey(): PublicKey {
4038
const pk = this.value.toPublicKey();
41-
return new PublicKey(pk.value);
39+
// @ts-expect-error Need to hack private constructor with static method
40+
return PublicKey.friendBuild(pk);
4241
}
4342

4443
toBytes(): Uint8Array {
45-
return this.value.toBytes();
44+
return this.value.serialize();
4645
}
4746

4847
toHex(): string {

src/blst-native/signature.ts

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import * as blst from "@chainsafe/blst";
1+
import blst from "@chainsafe/blst";
22
import {bytesToHex, hexToBytes} from "../helpers/index.js";
3-
import {PointFormat, Signature as ISignature} from "../types.js";
3+
import {CoordType, PointFormat, Signature as ISignature} from "../types.js";
44
import {PublicKey} from "./publicKey.js";
55
import {EmptyAggregateError, ZeroSignatureError} from "../errors.js";
66

7-
export class Signature extends blst.Signature implements ISignature {
8-
constructor(value: ConstructorParameters<typeof blst.Signature>[0]) {
9-
super(value);
10-
}
7+
export class Signature implements ISignature {
8+
private constructor(private readonly value: blst.Signature) {}
119

1210
/** @param type Defaults to `CoordType.affine` */
13-
static fromBytes(bytes: Uint8Array, type?: blst.CoordType, validate = true): Signature {
14-
const sig = blst.Signature.fromBytes(bytes, type);
11+
static fromBytes(bytes: Uint8Array, type?: CoordType, validate = true): Signature {
12+
// need to hack the CoordType so @chainsafe/blst is not a required dep
13+
const sig = blst.Signature.deserialize(bytes, (type as unknown) as blst.CoordType);
1514
if (validate) sig.sigValidate();
16-
return new Signature(sig.value);
15+
return new Signature(sig);
1716
}
1817

1918
static fromHex(hex: string): Signature {
@@ -25,53 +24,75 @@ export class Signature extends blst.Signature implements ISignature {
2524
throw new EmptyAggregateError();
2625
}
2726

28-
const agg = blst.aggregateSignatures(signatures);
29-
return new Signature(agg.value);
27+
const agg = blst.aggregateSignatures(signatures.map(({value}) => value));
28+
return new Signature(agg);
3029
}
3130

3231
static verifyMultipleSignatures(sets: {publicKey: PublicKey; message: Uint8Array; signature: Signature}[]): boolean {
3332
return blst.verifyMultipleAggregateSignatures(
34-
sets.map((s) => ({msg: s.message, pk: s.publicKey, sig: s.signature}))
33+
// @ts-expect-error Need to hack type to get access to the private `value`
34+
sets.map((s) => ({message: s.message, publicKey: s.publicKey.value, signature: s.signature.value}))
3535
);
3636
}
3737

38+
/**
39+
* Implemented for SecretKey to be able to call .sign()
40+
*/
41+
private static friendBuild(sig: blst.Signature): Signature {
42+
return new Signature(sig);
43+
}
44+
3845
verify(publicKey: PublicKey, message: Uint8Array): boolean {
3946
// Individual infinity signatures are NOT okay. Aggregated signatures MAY be infinity
40-
if (this.value.is_inf()) {
47+
if (this.value.isInfinity()) {
4148
throw new ZeroSignatureError();
4249
}
4350

44-
return blst.verify(message, publicKey, this);
51+
// @ts-expect-error Need to hack type to get access to the private `value`
52+
return blst.verify(message, publicKey.value, this.value);
4553
}
4654

4755
verifyAggregate(publicKeys: PublicKey[], message: Uint8Array): boolean {
48-
return blst.fastAggregateVerify(message, publicKeys, this);
56+
return blst.fastAggregateVerify(
57+
message,
58+
// @ts-expect-error Need to hack type to get access to the private `value`
59+
publicKeys.map((pk) => pk.value),
60+
this.value
61+
);
4962
}
5063

5164
verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[]): boolean {
52-
return blst.aggregateVerify(messages, publicKeys, this);
65+
return this.aggregateVerify(
66+
messages,
67+
// @ts-expect-error Need to hack type to get access to the private `value`
68+
publicKeys.map((pk) => pk.value)
69+
);
5370
}
5471

5572
toBytes(format?: PointFormat): Uint8Array {
5673
if (format === PointFormat.uncompressed) {
57-
return this.value.serialize();
74+
return this.value.serialize(false);
5875
} else {
59-
return this.value.compress();
76+
return this.value.serialize(true);
6077
}
6178
}
6279

6380
toHex(format?: PointFormat): string {
6481
return bytesToHex(this.toBytes(format));
6582
}
6683

84+
multiplyBy(bytes: Uint8Array): Signature {
85+
return new Signature(this.value.multiplyBy(bytes));
86+
}
87+
6788
private aggregateVerify(msgs: Uint8Array[], pks: blst.PublicKey[]): boolean {
6889
// If this set is simply an infinity signature and infinity publicKey then skip verification.
6990
// This has the effect of always declaring that this sig/publicKey combination is valid.
7091
// for Eth2.0 specs tests
71-
if (this.value.is_inf() && pks.length === 1 && pks[0].value.is_inf()) {
92+
if (this.value.isInfinity() && pks.length === 1 && pks[0].isInfinity()) {
7293
return true;
7394
}
7495

75-
return blst.aggregateVerify(msgs, pks, this);
96+
return blst.aggregateVerify(msgs, pks, this.value);
7697
}
7798
}

0 commit comments

Comments
 (0)