constantine/benchmarks/bench_ethereum_bls_signatur...

262 lines
7.8 KiB
Nim
Raw Normal View History

# Constantine
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
# Internals
../constantine/[
ethereum_bls_signatures_parallel,
ethereum_eip2333_bls12381_key_derivation],
../constantine/math/arithmetic,
../constantine/threadpool/threadpool,
# Std
std/[os, cpuinfo],
# Helpers
../helpers/prng_unsafe,
./bench_blueprint
proc separator*() = separator(180)
proc report(op, curve: string, startTime, stopTime: MonoTime, startClk, stopClk: int64, iters: int) =
let ns = inNanoseconds((stopTime-startTime) div iters)
let throughput = 1e9 / float64(ns)
when SupportsGetTicks:
echo &"{op:<88} {curve:<15} {throughput:>15.3f} ops/s {ns:>9} ns/op {(stopClk - startClk) div iters:>9} CPU cycles (approx)"
else:
echo &"{op:<8} {curve:<15} {throughput:>15.3f} ops/s {ns:>9} ns/op"
template bench(op: string, curve: string, iters: int, body: untyped): untyped =
measure(iters, startTime, stopTime, startClk, stopClk, body)
report(op, curve, startTime, stopTime, startClk, stopClk, iters)
proc demoKeyGen(): tuple[seckey: SecretKey, pubkey: PublicKey] =
# Don't do this at home, this is for benchmarking purposes
# The RNG is NOT cryptographically secure
# The API for keygen is not ready in ethereum_bls_signatures
let ikm = rng.random_byte_seq(32)
doAssert cast[ptr BigInt[255]](result.seckey.addr)[].derive_master_secretKey(ikm)
result.pubkey.derive_pubkey(result.seckey)
proc benchDeserPubkey*(iters: int) =
let (sk, pk) = demoKeyGen()
var pk_comp{.noInit.}: array[48, byte]
# Serialize compressed
let status = pk_comp.serialize_pubkey_compressed(pk)
doAssert status == cttCodecEcc_Success
var pk2{.noInit.}: PublicKey
bench("Pubkey deserialization (full checks)", "BLS12_381 G1", iters):
let status = pk2.deserialize_pubkey_compressed(pk_comp)
proc benchDeserPubkeyUnchecked*(iters: int) =
let (sk, pk) = demoKeyGen()
var pk_comp{.noInit.}: array[48, byte]
# Serialize compressed
let status = pk_comp.serialize_pubkey_compressed(pk)
doAssert status == cttCodecEcc_Success
var pk2{.noInit.}: PublicKey
bench("Pubkey deserialization (skip checks)", "BLS12_381 G1", iters):
let status = pk2.deserialize_pubkey_compressed_unchecked(pk_comp)
proc benchDeserSig*(iters: int) =
let (sk, pk) = demoKeyGen()
const msg = "abcdef0123456789"
var
sig_comp{.noInit.}: array[96, byte]
sig {.noInit.}: Signature
sig.sign(sk, msg)
# Serialize compressed
let status = sig_comp.serialize_signature_compressed(sig)
doAssert status == cttCodecEcc_Success
var sig2{.noInit.}: Signature
bench("Signature deserialization (full checks)", "BLS12_381 G2", iters):
let status = sig2.deserialize_signature_compressed(sig_comp)
proc benchDeserSigUnchecked*(iters: int) =
let (sk, pk) = demoKeyGen()
const msg = "abcdef0123456789"
var
sig_comp{.noInit.}: array[96, byte]
sig {.noInit.}: Signature
sig.sign(sk, msg)
# Serialize compressed
let status = sig_comp.serialize_signature_compressed(sig)
doAssert status == cttCodecEcc_Success
var sig2{.noInit.}: Signature
bench("Signature deserialization (skip checks)", "BLS12_381 G2", iters):
let status = sig2.deserialize_signature_compressed_unchecked(sig_comp)
proc benchSign*(iters: int) =
let (sk, pk) = demoKeyGen()
let msg = "Mr F was here"
var sig: Signature
bench("BLS signature", "BLS12_381 G2", iters):
sig.sign(sk, msg)
proc benchVerify*(iters: int) =
let (sk, pk) = demoKeyGen()
let msg = "Mr F was here"
var sig: Signature
sig.sign(sk, msg)
bench("BLS verification", "BLS12_381", iters):
let valid = pk.verify(msg, sig)
proc benchFastAggregateVerify*(numKeys, iters: int) =
## Verification of N pubkeys signing 1 message
let msg = "Mr F was here"
var validators = newSeq[PublicKey](numKeys)
var sigs = newSeq[Signature](numKeys)
var aggSig: Signature
for i in 0 ..< numKeys:
let (sk, pk) = demoKeyGen()
validators[i] = pk
sigs[i].sign(sk, msg)
aggSig.aggregate_signatures_unstable_api(sigs)
bench("BLS agg verif of 1 msg by " & $numKeys & " pubkeys", "BLS12_381", iters):
let valid = validators.fast_aggregate_verify(msg, aggSig)
proc benchVerifyMulti*(numSigs, iters: int) =
## Verification of N pubkeys signing for N messages
var triplets: seq[tuple[pubkey: PublicKey, msg: array[32, byte], sig: Signature]]
var hashedMsg: array[32, byte]
var sig: Signature
for i in 0 ..< numSigs:
let (sk, pk) = demoKeyGen()
sha256.hash(hashedMsg, "msg" & $i)
sig.sign(sk, hashedMsg)
triplets.add (pk, hashedMsg, sig)
bench("BLS verif of " & $numSigs & " msgs by "& $numSigs & " pubkeys", "BLS12_381", iters):
for i in 0 ..< triplets.len:
let ok = triplets[i].pubkey.verify(triplets[i].msg, triplets[i].sig)
doAssert ok == cttBLS_Success
proc benchVerifyBatched*(numSigs, iters: int) =
## Verification of N pubkeys signing for N messages
var
pubkeys: seq[PublicKey]
messages: seq[array[32, byte]]
signatures: seq[Signature]
var hashedMsg: array[32, byte]
var sig: Signature
for i in 0 ..< numSigs:
let (sk, pk) = demoKeyGen()
sha256.hash(hashedMsg, "msg" & $i)
sig.sign(sk, hashedMsg)
pubkeys.add pk
messages.add hashedMsg
signatures.add sig
let secureBlindingBytes = sha256.hash("Mr F was here")
bench("BLS serial batch verify of " & $numSigs & " msgs by "& $numSigs & " pubkeys (with blinding)", "BLS12_381", iters):
let ok = batch_verify(pubkeys, messages, signatures, secureBlindingBytes)
doAssert ok == cttBLS_Success
proc benchVerifyBatchedParallel*(numSigs, iters: int) =
## Verification of N pubkeys signing for N messages
var
tp: Threadpool
pubkeys: seq[PublicKey]
messages: seq[array[32, byte]]
signatures: seq[Signature]
var hashedMsg: array[32, byte]
var sig: Signature
var numThreads: int
if existsEnv"CTT_NUM_THREADS":
numThreads = getEnv"CTT_NUM_THREADS".parseInt()
else:
numThreads = countProcessors()
tp = Threadpool.new(numThreads)
for i in 0 ..< numSigs:
let (sk, pk) = demoKeyGen()
sha256.hash(hashedMsg, "msg" & $i)
sig.sign(sk, hashedMsg)
pubkeys.add pk
messages.add hashedMsg
signatures.add sig
let secureBlindingBytes = sha256.hash("Mr F was here")
bench("BLS parallel batch verify (" & $tp.numThreads & " threads) of " & $numSigs & " msgs by "& $numSigs & " pubkeys (with blinding)", "BLS12_381", iters):
let ok = tp.batch_verify_parallel(pubkeys, messages, signatures, secureBlindingBytes)
doAssert ok == cttBLS_Success, "invalid status: " & $ok
tp.shutdown()
const Iters = 1000
proc main() =
separator()
benchDeserPubkey(Iters)
benchDeserPubkeyUnchecked(Iters)
benchDeserSig(Iters)
benchDeserSigUnchecked(Iters)
separator()
benchSign(Iters)
benchVerify(Iters)
separator()
benchFastAggregateVerify(numKeys = 128, iters = 10)
separator()
# Simulate Block verification (at most 6 signatures per block)
benchVerifyMulti(numSigs = 6, iters = 10)
benchVerifyBatched(numSigs = 6, iters = 10)
benchVerifyBatchedParallel(numSigs = 6, iters = 10)
separator()
# Simulate 10 blocks verification
benchVerifyMulti(numSigs = 60, iters = 10)
benchVerifyBatched(numSigs = 60, iters = 10)
benchVerifyBatchedParallel(numSigs = 60, iters = 10)
separator()
# Simulate 30 blocks verification
benchVerifyMulti(numSigs = 180, iters = 10)
benchVerifyBatched(numSigs = 180, iters = 10)
benchVerifyBatchedParallel(numSigs = 180, iters = 10)
separator()
main()
notes()