UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

90 lines (75 loc) 2.75 kB
import {PublicKey, Signature, aggregatePublicKeys, aggregateSignatures, verify} from "@chainsafe/blst"; import {ISignatureSet, PubkeyCache} from "@lodestar/state-transition"; import {Metrics} from "../../metrics/index.js"; import {IBlsVerifier} from "./interface.js"; import {verifySignatureSetsMaybeBatch} from "./maybeBatch.js"; import {getAggregatedPubkey, getAggregatedPubkeysCount} from "./utils.js"; export class BlsSingleThreadVerifier implements IBlsVerifier { private readonly metrics: Metrics | null; private readonly pubkeyCache: PubkeyCache; constructor({metrics = null, pubkeyCache}: {metrics: Metrics | null; pubkeyCache: PubkeyCache}) { this.metrics = metrics; this.pubkeyCache = pubkeyCache; } async verifySignatureSets(sets: ISignatureSet[]): Promise<boolean> { this.metrics?.bls.aggregatedPubkeys.inc(getAggregatedPubkeysCount(sets)); const setsAggregated = sets.map((set) => ({ publicKey: getAggregatedPubkey(set, this.pubkeyCache, this.metrics), message: set.signingRoot, signature: set.signature, })); // Count time after aggregating const timer = this.metrics?.blsThreadPool.mainThreadDurationInThreadPool.startTimer(); const isValid = verifySignatureSetsMaybeBatch(setsAggregated); // Don't use a try/catch, only count run without exceptions if (timer) { timer(); } return isValid; } async verifySignatureSetsSameMessage( sets: {publicKey: PublicKey; signature: Uint8Array}[], message: Uint8Array ): Promise<boolean[]> { const timer = this.metrics?.blsThreadPool.mainThreadDurationInThreadPool.startTimer(); const pubkey = aggregatePublicKeys(sets.map((set) => set.publicKey)); let isAllValid = true; // validate signature = true const signatures = sets.map((set) => { try { return Signature.fromBytes(set.signature, true); } catch (_) { // at least one set has malformed signature isAllValid = false; return null; } }); if (isAllValid) { const signature = aggregateSignatures(signatures as Signature[]); isAllValid = verify(message, pubkey, signature); } let result: boolean[]; if (isAllValid) { result = sets.map(() => true); } else { result = sets.map((set, i) => { const sig = signatures[i]; if (sig === null) { return false; } return verify(message, set.publicKey, sig); }); } if (timer) { timer(); } return result; } async close(): Promise<void> { // nothing to do } canAcceptWork(): boolean { // Since sigs are verified blocking the main thread, there's no mechanism to throttle return true; } }