Skip to content

Commit

Permalink
BLS: speedup parallel batch verify with Miller loops on local threads
Browse files Browse the repository at this point in the history
  • Loading branch information
mratsim committed Sep 18, 2023
1 parent 75ef07b commit 51c0df8
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 1 deletion.
12 changes: 12 additions & 0 deletions constantine/math/pairings/miller_accumulators.nim
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ func update*[FF1, FF2, FpK](ctx: var MillerAccumulator[FF1, FF2, FpK], P: ECP_Sh
ctx.len += 1
return true

func handover*(ctx: var MillerAccumulator) {.inline.} =
## Prepare accumulator for cheaper merging.
##
## In a multi-threaded context, multiple accumulators can be created and process subsets of the batch in parallel.
## Accumulators can then be merged:
## merger_accumulator += mergee_accumulator
## Merging will involve an expensive reduction operation when an accumulation threshold of 8 is reached.
## However merging two reduced accumulators is 136x cheaper.
##
## `Handover` forces this reduction on local threads to limit the burden on the merger thread.
ctx.consumeBuffers()

func merge*(ctxDst: var MillerAccumulator, ctxSrc: MillerAccumulator) =
## Merge ctxDst <- ctxDst + ctxSrc
var sCur = 0'u
Expand Down
12 changes: 12 additions & 0 deletions constantine/signatures/bls_signatures.nim
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,18 @@ func update*[Pubkey, Sig: ECP_ShortW_Aff](
signature: Sig): bool {.inline.} =
ctx.update(pubkey, message, signature)

func handover*(ctx: var BLSBatchSigAccumulator) {.inline.} =
## Prepare accumulator for cheaper merging.
##
## In a multi-threaded context, multiple accumulators can be created and process subsets of the batch in parallel.
## Accumulators can then be merged:
## merger_accumulator += mergee_accumulator
## Merging will involve an expensive reduction operation when an accumulation threshold of 8 is reached.
## However merging two reduced accumulators is 136x cheaper.
##
## `Handover` forces this reduction on local threads to limit the burden on the merger thread.
ctx.millerAccum.handover()

func merge*(ctxDst: var BLSBatchSigAccumulator, ctxSrc: BLSBatchSigAccumulator): bool =
## Merge 2 BLS signature accumulators: ctxDst <- ctxDst + ctxSrc
##
Expand Down
3 changes: 2 additions & 1 deletion constantine/signatures/bls_signatures_parallel.nim
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ proc batchVerify_parallel*[Msg, Pubkey, Sig](
if not ctx[].update(pubkeys[i], messages[i], signatures[i]):
return false

ctx[].handover()
return true

let partialStates = allocStackArray(Flowvar[bool], numAccums)
Expand All @@ -173,7 +174,7 @@ proc batchVerify_parallel*[Msg, Pubkey, Sig](

# Stage 2: Reduce partial pairings
# --------------------------------
if true: # numAccums < 4: # Linear merge
if numAccums < 4: # Linear merge
result = sync partialStates[0]
for i in 1 ..< numAccums:
result = result and sync partialStates[i]
Expand Down

0 comments on commit 51c0df8

Please sign in to comment.