Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add verifySignatureSetsSameMessage BLS api #5747

Merged
merged 10 commits into from
Jul 21, 2023
13 changes: 13 additions & 0 deletions packages/beacon-node/src/chain/bls/interface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {PublicKey} from "@chainsafe/bls/types";
import {ISignatureSet} from "@lodestar/state-transition";

export type VerifySignatureOpts = {
Expand Down Expand Up @@ -45,6 +46,18 @@ export interface IBlsVerifier {
*/
verifySignatureSets(sets: ISignatureSet[], opts?: VerifySignatureOpts): Promise<boolean>;

/**
* Similar to verifySignatureSets but:
* - all signatures have the same message
* - return an array of boolean, each element indicates whether the corresponding signature set is valid
* - only support `batchable` option
*/
verifySignatureSetsSameMessage(
sets: {publicKey: PublicKey; signature: Uint8Array}[],
messsage: Uint8Array,
opts?: Omit<VerifySignatureOpts, "verifyOnMainThread">
): Promise<boolean[]>;

/** For multithread pool awaits terminating all workers */
close(): Promise<void>;

Expand Down
47 changes: 27 additions & 20 deletions packages/beacon-node/src/chain/bls/maybeBatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,33 @@ export type SignatureSetDeserialized = {
* Abstracted in a separate file to be consumed by the threaded pool and the main thread implementation.
*/
export function verifySignatureSetsMaybeBatch(sets: SignatureSetDeserialized[]): boolean {
if (sets.length >= MIN_SET_COUNT_TO_BATCH) {
return bls.Signature.verifyMultipleSignatures(
sets.map((s) => ({
publicKey: s.publicKey,
message: s.message,
// true = validate signature
signature: bls.Signature.fromBytes(s.signature, CoordType.affine, true),
}))
);
}
try {
if (sets.length >= MIN_SET_COUNT_TO_BATCH) {
return bls.Signature.verifyMultipleSignatures(
sets.map((s) => ({
publicKey: s.publicKey,
message: s.message,
// true = validate signature
signature: bls.Signature.fromBytes(s.signature, CoordType.affine, true),
}))
);
}

// .every on an empty array returns true
if (sets.length === 0) {
throw Error("Empty signature set");
}
// .every on an empty array returns true
if (sets.length === 0) {
throw Error("Empty signature set");
}

// If too few signature sets verify them without batching
return sets.every((set) => {
// true = validate signature
const sig = bls.Signature.fromBytes(set.signature, CoordType.affine, true);
return sig.verify(set.publicKey, set.message);
});
// If too few signature sets verify them without batching
return sets.every((set) => {
// true = validate signature
const sig = bls.Signature.fromBytes(set.signature, CoordType.affine, true);
return sig.verify(set.publicKey, set.message);
});
} 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
// see https://github.com/ChainSafe/blst-ts/blob/b1ba6333f664b08e5c50b2b0d18c4f079203962b/src/lib.ts#L291
return false;
}
}
Loading