Skip to content

Commit

Permalink
Merge e79ebad into 122a0f8
Browse files Browse the repository at this point in the history
  • Loading branch information
wemeetagain committed May 1, 2024
2 parents 122a0f8 + e79ebad commit f411caf
Show file tree
Hide file tree
Showing 91 changed files with 376 additions and 335 deletions.
3 changes: 1 addition & 2 deletions packages/beacon-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@
},
"dependencies": {
"@chainsafe/as-sha256": "^0.4.1",
"@chainsafe/bls": "^8.1.0",
"@chainsafe/blst": "^1.0.0",
"@chainsafe/blst": "^1.0.1",
"@chainsafe/discv5": "^9.0.0",
"@chainsafe/enr": "^3.0.0",
"@chainsafe/libp2p-gossipsub": "^11.2.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/beacon-node/src/chain/bls/interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {PublicKey} from "@chainsafe/bls/types";
import {PublicKey} from "@chainsafe/blst";
import {ISignatureSet} from "@lodestar/state-transition";

export type VerifySignatureOpts = {
Expand Down
25 changes: 16 additions & 9 deletions packages/beacon-node/src/chain/bls/jobItem.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import bls from "@chainsafe/bls";
import {CoordType, PointFormat, PublicKey} from "@chainsafe/bls/types";
import {
CoordType,
Signature,
PublicKey,
aggregatePublicKeys,
aggregateSignatures,
randomBytesNonZero,
} from "@chainsafe/blst";
import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition";
import {LinkedList} from "../../util/array.js";
import {Metrics} from "../../metrics/metrics.js";
import {VerifySignatureOpts} from "./interface.js";
import {getAggregatedPubkey} from "./utils.js";
import {BlsWorkReq} from "./types.js";
import {randomBytesNonZero} from "./utils.js";

export type JobQueueItem = JobQueueItemDefault | JobQueueItemSameMessage;

Expand Down Expand Up @@ -50,7 +55,7 @@ export function jobItemSigSets(job: JobQueueItem): number {
* Prepare BlsWorkReq from JobQueueItem
* WARNING: May throw with untrusted user input
*/
export function jobItemWorkReq(job: JobQueueItem, format: PointFormat, metrics: Metrics | null): BlsWorkReq {
export function jobItemWorkReq(job: JobQueueItem, metrics: Metrics | null): BlsWorkReq {
switch (job.type) {
case JobQueueItemType.default:
return {
Expand All @@ -71,11 +76,13 @@ export function jobItemWorkReq(job: JobQueueItem, format: PointFormat, metrics:
// and not a problem in the near future
// this is monitored on v1.11.0 https://github.com/ChainSafe/lodestar/pull/5912#issuecomment-1700320307
const timer = metrics?.blsThreadPool.signatureDeserializationMainThreadDuration.startTimer();
const signatures = job.sets.map((set) => bls.Signature.fromBytes(set.signature, CoordType.affine, true));
const signatures = job.sets.map((set) => {
const sig = Signature.deserialize(set.signature, CoordType.affine);
sig.sigValidate();
return sig;
});
timer?.();

// adding verification randomness is napi specific. must not attempt with herumi until
// @chainsafe/bls is updated to support it with herumi
const randomness: Uint8Array[] = [];
for (let i = 0; i < job.sets.length; i++) {
randomness.push(randomBytesNonZero(8));
Expand All @@ -85,8 +92,8 @@ export function jobItemWorkReq(job: JobQueueItem, format: PointFormat, metrics:
sets: [
{
message: job.message,
publicKey: bls.PublicKey.aggregate(job.sets.map((set, i) => set.publicKey.multiplyBy(randomness[i]))),
signature: bls.Signature.aggregate(signatures.map((sig, i) => sig.multiplyBy(randomness[i]))),
publicKey: aggregatePublicKeys(job.sets.map((set, i) => set.publicKey.multiplyBy(randomness[i]))),
signature: aggregateSignatures(signatures.map((sig, i) => sig.multiplyBy(randomness[i]))),
},
],
};
Expand Down
11 changes: 2 additions & 9 deletions packages/beacon-node/src/chain/bls/multiThread.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import os from "node:os";
import bls from "@chainsafe/bls";
import {PointFormat, PublicKey} from "@chainsafe/bls/types";
import {PublicKey} from "@chainsafe/blst";
import {Logger} from "@lodestar/utils";
import {ISignatureSet} from "@lodestar/state-transition";
import {QueueError, QueueErrorCode} from "../../util/queue/index.js";
Expand Down Expand Up @@ -75,8 +74,6 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
private readonly logger: Logger;
private readonly metrics: Metrics | null;

private readonly format = PointFormat.uncompressed;

private blsPoolSize: number;
private workersBusy = 0;

Expand All @@ -92,10 +89,6 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
private closed = false;

constructor(options: BlsMultiThreadWorkerPoolOptions, modules: BlsMultiThreadWorkerPoolModules) {
if (bls.implementation === "herumi") {
throw new Error("Herumi BLS implementation is not supported");
}

this.logger = modules.logger;
this.blsVerifyAllMultiThread = options.blsVerifyAllMultiThread ?? false;

Expand Down Expand Up @@ -297,7 +290,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
try {
// Note: This can throw, must be handled per-job.
// Pubkey and signature aggregation is defered here
workReq = jobItemWorkReq(job, this.format, this.metrics);
workReq = jobItemWorkReq(job, this.metrics);
} catch (e) {
this.metrics?.blsThreadPool.errorAggregateSignatureSetsCount.inc({type: job.type});

Expand Down
16 changes: 8 additions & 8 deletions packages/beacon-node/src/chain/bls/singleThread.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {PublicKey, Signature} from "@chainsafe/bls/types";
import bls from "@chainsafe/bls";
import {CoordType} from "@chainsafe/bls/types";
import {CoordType, PublicKey, Signature, aggregatePublicKeys, aggregateSignatures, verify} from "@chainsafe/blst";
import {ISignatureSet} from "@lodestar/state-transition";
import {Metrics} from "../../metrics/index.js";
import {IBlsVerifier} from "./interface.js";
Expand Down Expand Up @@ -40,12 +38,14 @@ export class BlsSingleThreadVerifier implements IBlsVerifier {
message: Uint8Array
): Promise<boolean[]> {
const timer = this.metrics?.blsThreadPool.mainThreadDurationInThreadPool.startTimer();
const pubkey = bls.PublicKey.aggregate(sets.map((set) => set.publicKey));
const pubkey = aggregatePublicKeys(sets.map((set) => set.publicKey));
let isAllValid = true;
// validate signature = true
const signatures = sets.map((set) => {
try {
return bls.Signature.fromBytes(set.signature, CoordType.affine, true);
const sig = Signature.deserialize(set.signature, CoordType.affine);
sig.sigValidate();
return sig;
} catch (_) {
// at least one set has malformed signature
isAllValid = false;
Expand All @@ -54,8 +54,8 @@ export class BlsSingleThreadVerifier implements IBlsVerifier {
});

if (isAllValid) {
const signature = bls.Signature.aggregate(signatures as Signature[]);
isAllValid = signature.verify(pubkey, message);
const signature = aggregateSignatures(signatures as Signature[]);
isAllValid = verify(message, pubkey, signature);
}

let result: boolean[];
Expand All @@ -67,7 +67,7 @@ export class BlsSingleThreadVerifier implements IBlsVerifier {
if (sig === null) {
return false;
}
return sig.verify(set.publicKey, message);
return verify(message, set.publicKey, sig);
});
}

Expand Down
2 changes: 1 addition & 1 deletion packages/beacon-node/src/chain/bls/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {PublicKey, Signature} from "@chainsafe/bls/types";
import {PublicKey, Signature} from "@chainsafe/blst";
import {VerifySignatureOpts} from "./interface.js";

export type DeserializedKeySet = {
Expand Down
18 changes: 2 additions & 16 deletions packages/beacon-node/src/chain/bls/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import bls from "@chainsafe/bls";
import {PublicKey} from "@chainsafe/bls/types";
import {PublicKey, aggregatePublicKeys} from "@chainsafe/blst";
import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition";
import {Metrics} from "../../metrics/metrics.js";
import {WorkResultError} from "./types.js";
Expand All @@ -11,7 +10,7 @@ export function getAggregatedPubkey(signatureSet: ISignatureSet, metrics: Metric

case SignatureSetType.aggregate: {
const timer = metrics?.blsThreadPool.pubkeysAggregationMainThreadDuration.startTimer();
const pubkeys = bls.PublicKey.aggregate(signatureSet.pubkeys);
const pubkeys = aggregatePublicKeys(signatureSet.pubkeys);
timer?.();
return pubkeys;
}
Expand Down Expand Up @@ -51,19 +50,6 @@ export function chunkifyMaximizeChunkSize<T>(arr: T[], minPerChunk: number): T[]
return arrArr;
}

/**
* `rand` must not be exactly zero. Otherwise it would allow the verification of invalid signatures
* See https://github.com/ChainSafe/blst-ts/issues/45
*/
export function randomBytesNonZero(bytesCount: number): Uint8Array {
const rand = crypto.getRandomValues(new Uint8Array(bytesCount));
for (let i = 0; i < bytesCount; i++) {
if (rand[i] !== 0) return rand;
}
rand[0] = 1;
return rand;
}

export function getJobResultError(jobResult: WorkResultError | null, i: number): Error {
const workerError = jobResult ? Error(jobResult.error.message) : Error(`No jobResult for index ${i}`);
if (jobResult?.error?.stack) workerError.stack = jobResult.error.stack;
Expand Down
15 changes: 10 additions & 5 deletions packages/beacon-node/src/chain/bls/verifySets.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import bls from "@chainsafe/bls";
import {
asyncVerify,
asyncVerifyMultipleAggregateSignatures,
verify,
verifyMultipleAggregateSignatures,
} from "@chainsafe/blst";
import {WorkRequestSet} from "./types.js";

const MIN_SET_COUNT_TO_BATCH = 2;
Expand All @@ -10,7 +15,7 @@ const MIN_SET_COUNT_TO_BATCH = 2;
export function verifySets(sets: WorkRequestSet[]): boolean {
try {
if (sets.length >= MIN_SET_COUNT_TO_BATCH) {
return bls.verifyMultipleSignatures(sets);
return verifyMultipleAggregateSignatures(sets);
}

// .every on an empty array returns true
Expand All @@ -19,7 +24,7 @@ export function verifySets(sets: WorkRequestSet[]): boolean {
}

// If too few signature sets verify them without batching
return sets.every(({message, publicKey, signature}) => bls.verify(publicKey, message, signature));
return sets.every(({message, publicKey, signature}) => verify(message, publicKey, signature));
} catch (_) {
// A signature could be malformed, in that case fromBytes throws error
// blst-ts `verifyMultipleSignatures` is also a fallible operation if mul_n_aggregate fails
Expand All @@ -31,7 +36,7 @@ export function verifySets(sets: WorkRequestSet[]): boolean {
export async function asyncVerifySets(sets: WorkRequestSet[]): Promise<boolean> {
try {
if (sets.length >= MIN_SET_COUNT_TO_BATCH) {
return await bls.asyncVerifyMultipleSignatures(sets);
return await asyncVerifyMultipleAggregateSignatures(sets);
}

// .every on an empty array returns true
Expand All @@ -40,7 +45,7 @@ export async function asyncVerifySets(sets: WorkRequestSet[]): Promise<boolean>
}

const promises = await Promise.all(
sets.map(({message, publicKey, signature}) => bls.asyncVerify(publicKey, message, signature))
sets.map(({message, publicKey, signature}) => asyncVerify(message, publicKey, signature))
);
// If too few signature sets verify them without batching
return promises.every((isValid) => isValid);
Expand Down
2 changes: 1 addition & 1 deletion packages/beacon-node/src/chain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ export class BeaconChain implements IBeaconChain {
RegenCaller.produceBlock
);
const proposerIndex = state.epochCtx.getBeaconProposer(slot);
const proposerPubKey = state.epochCtx.index2pubkey[proposerIndex].toBytes();
const proposerPubKey = state.epochCtx.index2pubkey[proposerIndex].serialize();

const {body, blobs, executionPayloadValue, shouldOverrideBuilder} = await produceBlockBody.call(
this,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import bls from "@chainsafe/bls";
import {toHexString} from "@chainsafe/ssz";
import {aggregateSignatures} from "@chainsafe/blst";
import {ForkName, ForkSeq, MAX_ATTESTATIONS, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params";
import {phase0, Epoch, Slot, ssz, ValidatorIndex, RootHex} from "@lodestar/types";
import {
Expand Down Expand Up @@ -383,7 +383,7 @@ export function aggregateInto(attestation1: AttestationWithIndex, attestation2:

const signature1 = signatureFromBytesNoCheck(attestation1.attestation.signature);
const signature2 = signatureFromBytesNoCheck(attestation2.attestation.signature);
attestation1.attestation.signature = bls.Signature.aggregate([signature1, signature2]).toBytes();
attestation1.attestation.signature = aggregateSignatures([signature1, signature2]).serialize();
}

/**
Expand Down
10 changes: 3 additions & 7 deletions packages/beacon-node/src/chain/opPools/attestationPool.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {PointFormat, Signature} from "@chainsafe/bls/types";
import bls from "@chainsafe/bls";
import {Signature, aggregateSignatures} from "@chainsafe/blst";
import {BitArray} from "@chainsafe/ssz";
import {phase0, Slot, RootHex} from "@lodestar/types";
import {MapDef} from "@lodestar/utils";
Expand Down Expand Up @@ -191,10 +190,7 @@ function aggregateAttestationInto(aggregate: AggregateFast, attestation: phase0.
}

aggregate.aggregationBits.set(bitIndex, true);
aggregate.signature = bls.Signature.aggregate([
aggregate.signature,
signatureFromBytesNoCheck(attestation.signature),
]);
aggregate.signature = aggregateSignatures([aggregate.signature, signatureFromBytesNoCheck(attestation.signature)]);
return InsertOutcome.Aggregated;
}

Expand All @@ -217,6 +213,6 @@ function fastToAttestation(aggFast: AggregateFast): phase0.Attestation {
return {
data: aggFast.data,
aggregationBits: aggFast.aggregationBits,
signature: aggFast.signature.toBytes(PointFormat.compressed),
signature: aggFast.signature.serialize(true),
};
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {PointFormat, Signature} from "@chainsafe/bls/types";
import bls from "@chainsafe/bls";
import {Signature, aggregateSignatures} from "@chainsafe/blst";
import {BitArray, toHexString} from "@chainsafe/ssz";
import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params";
import {altair, Root, Slot, SubcommitteeIndex} from "@lodestar/types";
Expand Down Expand Up @@ -108,7 +107,7 @@ export class SyncCommitteeMessagePool {
return {
...contribution,
aggregationBits: contribution.aggregationBits,
signature: contribution.signature.toBytes(PointFormat.compressed),
signature: contribution.signature.serialize(true),
};
}

Expand Down Expand Up @@ -136,7 +135,7 @@ function aggregateSignatureInto(
}

contribution.aggregationBits.set(indexInSubcommittee, true);
contribution.signature = bls.Signature.aggregate([
contribution.signature = aggregateSignatures([
contribution.signature,
signatureFromBytesNoCheck(signature.signature),
]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type {Signature} from "@chainsafe/bls/types";
import bls from "@chainsafe/bls";
import {Signature, aggregateSignatures} from "@chainsafe/blst";
import {BitArray, toHexString} from "@chainsafe/ssz";
import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params";
import {altair, Slot, Root, ssz} from "@lodestar/types";
Expand Down Expand Up @@ -182,6 +181,6 @@ export function aggregate(bestContributionBySubnet: Map<number, SyncContribution
}
return {
syncCommitteeBits,
syncCommitteeSignature: bls.Signature.aggregate(signatures).toBytes(),
syncCommitteeSignature: aggregateSignatures(signatures).serialize(),
};
}
5 changes: 2 additions & 3 deletions packages/beacon-node/src/chain/opPools/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import bls from "@chainsafe/bls";
import {CoordType, Signature} from "@chainsafe/bls/types";
import {CoordType, Signature} from "@chainsafe/blst";
import {BLS_WITHDRAWAL_PREFIX} from "@lodestar/params";
import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
import {Slot, capella} from "@lodestar/types";
Expand Down Expand Up @@ -30,7 +29,7 @@ export function pruneBySlot(map: Map<Slot, unknown>, slot: Slot, slotsRetained:
* No need to verify Signature is valid, already run sig-verify = false
*/
export function signatureFromBytesNoCheck(signature: Uint8Array): Signature {
return bls.Signature.fromBytes(signature, CoordType.affine, false);
return Signature.deserialize(signature, CoordType.affine);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {PublicKey} from "@chainsafe/bls/types";
import {PublicKey} from "@chainsafe/blst";
import {DOMAIN_AGGREGATE_AND_PROOF} from "@lodestar/params";
import {ssz} from "@lodestar/types";
import {Epoch, phase0} from "@lodestar/types";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {PublicKey} from "@chainsafe/bls/types";
import {PublicKey} from "@chainsafe/blst";
import {DOMAIN_SELECTION_PROOF} from "@lodestar/params";
import {phase0, Slot, ssz} from "@lodestar/types";
import {computeSigningRoot, createSingleSignatureSetFromComponents, ISignatureSet} from "@lodestar/state-transition";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {PublicKey} from "@chainsafe/bls/types";
import {PublicKey} from "@chainsafe/blst";
import {altair, ssz} from "@lodestar/types";
import {DOMAIN_SYNC_COMMITTEE} from "@lodestar/params";
import {CachedBeaconStateAltair, computeSigningRoot, ISignatureSet, SignatureSetType} from "@lodestar/state-transition";
Expand Down
4 changes: 2 additions & 2 deletions packages/beacon-node/src/node/utils/interop/deposits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function interopDeposits(
const withdrawalCredentialsPrefix = withEth1Credentials ? ETH1_ADDRESS_WITHDRAWAL_PREFIX : BLS_WITHDRAWAL_PREFIX;

return interopSecretKeys(validatorCount).map((secretKey, i) => {
const pubkey = secretKey.toPublicKey().toBytes();
const pubkey = secretKey.toPublicKey().serialize();

// create DepositData
const withdrawalCredentials = digest(pubkey);
Expand All @@ -40,7 +40,7 @@ export function interopDeposits(

const domain = computeDomain(DOMAIN_DEPOSIT, config.GENESIS_FORK_VERSION, ZERO_HASH);
const signingRoot = computeSigningRoot(ssz.phase0.DepositMessage, data, domain);
data.signature = secretKey.sign(signingRoot).toBytes();
data.signature = secretKey.sign(signingRoot).serialize();

// Add to merkle tree
depositDataRootList.push(ssz.phase0.DepositData.hashTreeRoot(data));
Expand Down

0 comments on commit f411caf

Please sign in to comment.