speed up LC signature verification (#5268)

We know the aggregate publickey of a fully participating sync committee.
Because participation is typically very high (>95%), it is faster to
start from that aggregate publickey and subtract the individual keys of
non-participants, than summing up all the participating pubkeys.
This commit is contained in:
Etan Kissling 2023-08-09 08:50:07 +02:00 committed by GitHub
parent 8e398001fe
commit 973e9e9a98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 9 deletions

View File

@ -25,7 +25,7 @@
import
# Status
stew/[endians2, objects, results, byteutils],
stew/[bitseqs, endians2, objects, results, byteutils],
blscurve,
chronicles,
bearssl/rand,
@ -314,6 +314,68 @@ proc blsFastAggregateVerify*(
let parsedSig = signature.load()
parsedSig.isSome and blsFastAggregateVerify(publicKeys, message, parsedSig.get())
proc blsFastAggregateVerify*(
fullParticipationAggregatePublicKey: ValidatorPubKey,
nonParticipatingPublicKeys: openArray[ValidatorPubKey],
message: openArray[byte],
signature: CookedSig
): bool =
let unwrappedFull = fullParticipationAggregatePublicKey.loadWithCache.valueOr:
return false
var unwrapped = newSeqOfCap[PublicKey](nonParticipatingPublicKeys.len)
for pubkey in nonParticipatingPublicKeys:
let realkey = pubkey.loadWithCache.valueOr:
return false
unwrapped.add PublicKey(realkey)
fastAggregateVerify(
PublicKey(unwrappedFull), unwrapped,
message, blscurve.Signature(signature))
proc blsFastAggregateVerify*(
fullParticipationAggregatePublicKey: ValidatorPubKey,
nonParticipatingPublicKeys: openArray[ValidatorPubKey],
message: openArray[byte],
signature: ValidatorSig
): bool =
let parsedSig = signature.load()
parsedSig.isSome and blsFastAggregateVerify(
fullParticipationAggregatePublicKey, nonParticipatingPublicKeys,
message, parsedSig.get())
proc blsFastAggregateVerify*(
allPublicKeys: openArray[ValidatorPubKey],
fullParticipationAggregatePublicKey: ValidatorPubKey,
participantBits: BitArray,
message: openArray[byte],
signature: ValidatorSig
): bool =
const maxParticipants = participantBits.bits
var numParticipants = 0
for idx in 0 ..< maxParticipants:
if participantBits[idx]:
inc numParticipants
return
if numParticipants < 1:
false
elif numParticipants > maxParticipants div 2:
var nonParticipatingPublicKeys = newSeqOfCap[ValidatorPubKey](
maxParticipants - numParticipants)
for idx, pubkey in allPublicKeys:
if not participantBits[idx]:
nonParticipatingPublicKeys.add pubkey
blsFastAggregateVerify(
fullParticipationAggregatePublicKey, nonParticipatingPublicKeys,
message, signature)
else:
var publicKeys = newSeqOfCap[ValidatorPubKey](numParticipants)
for idx, pubkey in allPublicKeys:
if participantBits[idx]:
publicKeys.add pubkey
blsFastAggregateVerify(publicKeys, message, signature)
# Codecs
# ----------------------------------------------------------------------

View File

@ -8,7 +8,7 @@
{.push raises: [].}
import
stew/[bitops2, objects],
stew/[bitops2, bitseqs, objects],
datatypes/altair,
helpers
@ -141,20 +141,19 @@ proc validate_light_client_update*(
unsafeAddr store.current_sync_committee
else:
unsafeAddr store.next_sync_committee
var participant_pubkeys =
newSeqOfCap[ValidatorPubKey](num_active_participants)
for idx, bit in sync_aggregate.sync_committee_bits:
if bit:
participant_pubkeys.add(sync_committee.pubkeys.data[idx])
let
fork_version_slot = max(update.signature_slot, 1.Slot) - 1
fork_version = cfg.forkVersionAtEpoch(fork_version_slot.epoch)
domain = compute_domain(
DOMAIN_SYNC_COMMITTEE, fork_version, genesis_validators_root)
signing_root = compute_signing_root(update.attested_header.beacon, domain)
const maxParticipants = typeof(sync_aggregate.sync_committee_bits).bits
if not blsFastAggregateVerify(
participant_pubkeys, signing_root.data,
sync_aggregate.sync_committee_signature):
allPublicKeys = sync_committee.pubkeys.data,
fullParticipationAggregatePublicKey = sync_committee.aggregate_pubkey,
bitseqs.BitArray[maxParticipants](
bytes: sync_aggregate.sync_committee_bits.bytes),
signing_root.data, sync_aggregate.sync_committee_signature):
return err(VerifierError.UnviableFork)
ok()