Add verifyMultipleSignatures method

This commit is contained in:
dapplion 2020-12-02 21:44:25 +00:00
parent e8d81fef96
commit a8f7256fcd
4 changed files with 51 additions and 1 deletions

View File

@ -28,6 +28,14 @@ export class Signature implements ISignature {
return new Signature(agg.toSignature()); return new Signature(agg.toSignature());
} }
static verifyMultipleSignatures(publicKeys: PublicKey[], messages: Uint8Array[], signatures: Signature[]): boolean {
return blst.verifyMultipleAggregateSignatures(
messages,
publicKeys.map((publicKey) => publicKey.affine),
signatures.map((signature) => signature.affine)
);
}
verify(publicKey: PublicKey, message: Uint8Array): boolean { verify(publicKey: PublicKey, message: Uint8Array): boolean {
// Individual infinity signatures are NOT okay. Aggregated signatures MAY be infinity // Individual infinity signatures are NOT okay. Aggregated signatures MAY be infinity
if (this.affine.value.is_inf()) { if (this.affine.value.is_inf()) {

View File

@ -106,6 +106,36 @@ export function functionalInterfaceFactory({
} }
} }
/**
* Verifies multiple signatures at once returning true if all valid or false
* if at least one is not. Optimized method when knowing which signature is
* wrong is not relevant, i.e. verifying an Eth2.0 block.
* https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
*/
function verifyMultipleSignatures(
publicKeys: Uint8Array[],
messages: Uint8Array[],
signatures: Uint8Array[]
): boolean {
validateBytes(publicKeys, "publicKey");
validateBytes(messages, "message");
validateBytes(signatures, "signatures");
if (publicKeys.length === 0 || publicKeys.length !== messages.length || publicKeys.length !== signatures.length) {
return false;
}
try {
return Signature.verifyMultipleSignatures(
publicKeys.map((publicKey) => PublicKey.fromBytes(publicKey)),
messages.map((msg) => msg),
signatures.map((signature) => Signature.fromBytes(signature))
);
} catch (e) {
if (e instanceof NotInitializedError) throw e;
return false;
}
}
/** /**
* Computes a public key from a secret key * Computes a public key from a secret key
*/ */
@ -121,6 +151,7 @@ export function functionalInterfaceFactory({
verify, verify,
verifyAggregate, verifyAggregate,
verifyMultiple, verifyMultiple,
verifyMultipleSignatures,
secretKeyToPublicKey, secretKeyToPublicKey,
}; };
} }

View File

@ -1,5 +1,5 @@
import {SIGNATURE_LENGTH} from "../constants"; import {SIGNATURE_LENGTH} from "../constants";
import {SignatureType} from "bls-eth-wasm"; import {SignatureType, multiVerify} from "bls-eth-wasm";
import {getContext} from "./context"; import {getContext} from "./context";
import {PublicKey} from "./publicKey"; import {PublicKey} from "./publicKey";
import {bytesToHex, hexToBytes, isZeroUint8Array} from "../helpers"; import {bytesToHex, hexToBytes, isZeroUint8Array} from "../helpers";
@ -45,6 +45,14 @@ export class Signature implements ISignature {
return new Signature(signature); return new Signature(signature);
} }
static verifyMultipleSignatures(publicKeys: PublicKey[], messages: Uint8Array[], signatures: Signature[]): boolean {
return multiVerify(
publicKeys.map((publicKey) => publicKey.value),
signatures.map((signature) => signature.value),
messages
);
}
verify(publicKey: PublicKey, message: Uint8Array): boolean { verify(publicKey: PublicKey, message: Uint8Array): boolean {
return publicKey.value.verify(this.value, message); return publicKey.value.verify(this.value, message);
} }

View File

@ -13,6 +13,7 @@ export interface IBls {
fromBytes(bytes: Uint8Array): Signature; fromBytes(bytes: Uint8Array): Signature;
fromHex(hex: string): Signature; fromHex(hex: string): Signature;
aggregate(signatures: Signature[]): Signature; aggregate(signatures: Signature[]): Signature;
verifyMultipleSignatures(publicKeys: PublicKey[], messages: Uint8Array[], signatures: Signature[]): boolean;
}; };
sign(secretKey: Uint8Array, message: Uint8Array): Uint8Array; sign(secretKey: Uint8Array, message: Uint8Array): Uint8Array;
@ -21,6 +22,7 @@ export interface IBls {
verify(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean; verify(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean;
verifyAggregate(publicKeys: Uint8Array[], message: Uint8Array, signature: Uint8Array): boolean; verifyAggregate(publicKeys: Uint8Array[], message: Uint8Array, signature: Uint8Array): boolean;
verifyMultiple(publicKeys: Uint8Array[], messages: Uint8Array[], signature: Uint8Array): boolean; verifyMultiple(publicKeys: Uint8Array[], messages: Uint8Array[], signature: Uint8Array): boolean;
verifyMultipleSignatures(publicKeys: Uint8Array[], messages: Uint8Array[], signatures: Uint8Array[]): boolean;
secretKeyToPublicKey(secretKey: Uint8Array): Uint8Array; secretKeyToPublicKey(secretKey: Uint8Array): Uint8Array;
init(): Promise<void>; init(): Promise<void>;
@ -49,6 +51,7 @@ export declare class Signature {
static fromBytes(bytes: Uint8Array): Signature; static fromBytes(bytes: Uint8Array): Signature;
static fromHex(hex: string): Signature; static fromHex(hex: string): Signature;
static aggregate(signatures: Signature[]): Signature; static aggregate(signatures: Signature[]): Signature;
static verifyMultipleSignatures(publicKeys: PublicKey[], messages: Uint8Array[], signatures: Signature[]): boolean;
verify(publicKey: PublicKey, message: Uint8Array): boolean; verify(publicKey: PublicKey, message: Uint8Array): boolean;
verifyAggregate(publicKeys: PublicKey[], message: Uint8Array): boolean; verifyAggregate(publicKeys: PublicKey[], message: Uint8Array): boolean;
verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[]): boolean; verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[]): boolean;