Skip to content

Commit

Permalink
EIP-2537 - BLS12-381 precompiles for the EVM (#368)
Browse files Browse the repository at this point in the history
* eip2537: initial metering

* eip2537: improve markdown reporting

* eip2537: iterate on reporting

* eip2537: iterate on reporting 2

* eip2537: fix constant-time scalar mul

* eip2537: add projective coordinates

* eip2537: more comprehensive metering

* eip2537: use Clang and also add benchmarks

* eip2537: fix bench table

* eip2537: add pic

* eip2537: add vartime benches

* eip2537: benches for rollcall and https://ethereum-magicians.org/t/eip-2537-bls12-precompile-discussion-thread/4187/66

* eip2537: create bench with subgroup checks

* eip2537: fix import of MSM on G2 - frobenius endomorphism

* commit subgroup check benches from https://github.com/mratsim/constantine/pull/368\#issuecomment-2047473465

* EVM: move modexp precompiles above the rest of elliptic precompiles

* EVM: implement BLS12381_G1ADD and BLS12381_G2ADD

* eip2537: bn254 tests properly call renamed procedure

* EVM: implement BLS12381_G1MUL and BLS12381_G2MUL

* EVM: implement BLS12381_G1MSM and BLS12381_G2MSM

* EVM: Pass geth and EIP-2537 precompiles test suite

* MSM: fix types for field coefficients

* EVM: implement map to field and pass all tests

* bench: consistent use of eth prefix for Ethereum benches

* EVM: add precompiles benchmark

* EVM: add BLS12 pairings

* EVM: fix bench bls sig
  • Loading branch information
mratsim authored May 1, 2024
1 parent 3d49a8a commit d7871d7
Show file tree
Hide file tree
Showing 67 changed files with 3,997 additions and 929 deletions.
6 changes: 2 additions & 4 deletions benchmarks/bench_ec_g2_scalar_mul.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ import
ec_shortweierstrass_projective,
ec_shortweierstrass_jacobian],
# Helpers
./bench_elliptic_template,
# Standard library
std/strutils
./bench_elliptic_template

# ############################################################
#
Expand All @@ -29,7 +27,7 @@ import


const Iters = 10_000
const MulIters = 500
const MulIters = 100
const AvailableCurves = [
# P224,
BN254_Nogami,
Expand Down
50 changes: 50 additions & 0 deletions benchmarks/bench_ec_msm_bls12_381_g2.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 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/math/config/curves,
../constantine/math/extension_fields,
../constantine/math/elliptic/[
ec_shortweierstrass_projective,
ec_shortweierstrass_jacobian],
# Helpers
../helpers/prng_unsafe,
./bench_elliptic_parallel_template

# ############################################################
#
# Benchmark of the G1 group of
# Short Weierstrass elliptic curves
# in (homogeneous) projective coordinates
#
# ############################################################


const Iters = 10_000
const AvailableCurves = [
BLS12_381,
]

# const testNumPoints = [10, 100, 1000, 10000, 100000]
const testNumPoints = [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192]

proc main() =
separator()
staticFor i, 0, AvailableCurves.len:
const curve = AvailableCurves[i]
var ctx = createBenchMsmContext(ECP_ShortW_Jac[Fp2[curve], G2], testNumPoints)
separator()
for numPoints in testNumPoints:
let batchIters = max(1, Iters div numPoints)
ctx.msmParallelBench(numPoints, batchIters)
separator()
separator()

main()
notes()
32 changes: 28 additions & 4 deletions benchmarks/bench_elliptic_template.nim
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ macro fixEllipticDisplay(EC: typedesc): untyped =
var name = $instantiated[1][0] # EllipticEquationFormCoordinates
let fieldName = $instantiated[1][1][0]
let curveName = $Curve(instantiated[1][1][1].intVal)
name.add "[" & fieldName & "[" & curveName & "]]"
name.add "[" &
fieldName & "[" & curveName & "]" &
(if family(Curve(instantiated[1][1][1].intVal)) != NoFamily:
", " & $Subgroup(instantiated[1][2].intVal)
else: "") &
"]"
result = newLit name

proc report(op, elliptic: string, start, stop: MonoTime, startClk, stopClk: int64, iters: int) =
Expand Down Expand Up @@ -155,7 +160,7 @@ proc scalarMulGenericBench*(EC: typedesc, bits, window: static int, iters: int)

let exponent = rng.random_unsafe(BigInt[bits])

bench("EC ScalarMul " & $bits & "-bit " & $EC.G & " (window-" & $window & ", generic)", EC, iters):
bench("EC ScalarMul " & $bits & "-bit " & $EC.G & " (window-" & $window & ", constant-time)", EC, iters):
r = P
r.scalarMulGeneric(exponent, window)

Expand All @@ -166,7 +171,7 @@ proc scalarMulEndo*(EC: typedesc, bits: static int, iters: int) =

let exponent = rng.random_unsafe(BigInt[bits])

bench("EC ScalarMul " & $bits & "-bit " & $EC.G & " (endomorphism accelerated)", EC, iters):
bench("EC ScalarMul " & $bits & "-bit " & $EC.G & " (constant-time, endomorphism)", EC, iters):
r = P
r.scalarMulEndo(exponent)

Expand All @@ -177,7 +182,7 @@ proc scalarMulEndoWindow*(EC: typedesc, bits: static int, iters: int) =

let exponent = rng.random_unsafe(BigInt[bits])

bench("EC ScalarMul " & $bits & "-bit " & $EC.G & " (window-2, endomorphism accelerated)", EC, iters):
bench("EC ScalarMul " & $bits & "-bit " & $EC.G & " (constant-time, window-2, endomorphism)", EC, iters):
r = P
when EC.F is Fp:
r.scalarMulGLV_m2w2(exponent)
Expand Down Expand Up @@ -228,6 +233,25 @@ proc scalarMulVartimeEndoWNAFBench*(EC: typedesc, bits, window: static int, iter
r = P
r.scalarMulEndo_minHammingWeight_windowed_vartime(exponent, window)

proc subgroupCheckBench*(EC: typedesc, iters: int) =
var P = rng.random_unsafe(EC)
P.clearCofactor()

bench("Subgroup check", EC, iters):
discard P.isInSubgroup()

proc subgroupCheckScalarMulVartimeEndoWNAFBench*(EC: typedesc, bits, window: static int, iters: int) =
var r {.noInit.}: EC
var P = rng.random_unsafe(EC)
P.clearCofactor()

let exponent = rng.random_unsafe(BigInt[bits])

bench("EC subgroup check + ScalarMul " & $bits & "-bit " & $EC.G & " (vartime endo + wNAF-" & $window & ")", EC, iters):
r = P
discard r.isInSubgroup()
r.scalarMulEndo_minHammingWeight_windowed_vartime(exponent, window)

proc multiAddBench*(EC: typedesc, numPoints: int, useBatching: bool, iters: int) =
var points = newSeq[ECP_ShortW_Aff[EC.F, EC.G]](numPoints)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ 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)
let cycles = (stopClk - startClk) div iters
when SupportsGetTicks:
echo &"{op:<88} {curve:<15} {throughput:>15.3f} ops/s {ns:>9} ns/op {(stopClk - startClk) div iters:>9} CPU cycles (approx)"
echo &"{op:<88} {curve:<15} {throughput:>15.3f} ops/s {ns:>9} ns/op {cycles:>9} CPU cycles (approx)"
else:
echo &"{op:<8} {curve:<15} {throughput:>15.3f} ops/s {ns:>9} ns/op"
echo &"{op:<88} {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)
Expand Down Expand Up @@ -156,7 +157,7 @@ proc benchVerifyMulti*(numSigs, iters: int) =
sig.sign(sk, hashedMsg)
triplets.add (pk, hashedMsg, sig)

bench("BLS verif of " & $numSigs & " msgs by "& $numSigs & " pubkeys", "BLS12_381", iters):
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 == cttEthBls_Success
Expand Down
File renamed without changes.
77 changes: 77 additions & 0 deletions benchmarks/bench_eth_eip2537_subgroup_checks_impact.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# 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/math/config/curves,
../constantine/math/arithmetic,
../constantine/math/extension_fields,
../constantine/math/elliptic/ec_shortweierstrass_jacobian,
# Helpers
./bench_elliptic_template

# ############################################################
#
# EIP-2537 benchmarks for
# subgroup checks discussion
#
# ############################################################


const Iters = 10_000
const MulIters = 100
const AvailableCurves = [
BLS12_381,
]

proc main() =
separator()
staticFor i, 0, AvailableCurves.len:
const curve = AvailableCurves[i]
const bits = curve.getCurveOrderBitwidth()

# G1
separator()
scalarMulVartimeDoubleAddBench(ECP_ShortW_Jac[Fp[curve], G1], bits, MulIters)
separator()
scalarMulVartimeWNAFBench(ECP_ShortW_Jac[Fp[curve], G1], bits, window = 3, MulIters)
scalarMulVartimeWNAFBench(ECP_ShortW_Jac[Fp[curve], G1], bits, window = 4, MulIters)
scalarMulVartimeWNAFBench(ECP_ShortW_Jac[Fp[curve], G1], bits, window = 5, MulIters)
separator()
scalarMulVartimeEndoWNAFBench(ECP_ShortW_Jac[Fp[curve], G1], bits, window = 3, MulIters)
scalarMulVartimeEndoWNAFBench(ECP_ShortW_Jac[Fp[curve], G1], bits, window = 4, MulIters)
scalarMulVartimeEndoWNAFBench(ECP_ShortW_Jac[Fp[curve], G1], bits, window = 5, MulIters)
separator()
scalarMulEndo( ECP_ShortW_Jac[Fp[curve], G1], bits, MulIters)
scalarMulEndoWindow(ECP_ShortW_Jac[Fp[curve], G1], bits, MulIters)
separator()
subgroupCheckBench(ECP_ShortW_Jac[Fp[curve], G1], MulIters)
subgroupCheckScalarMulVartimeEndoWNAFBench(ECP_ShortW_Jac[Fp[curve], G1], bits, window = 3, MulIters)
subgroupCheckScalarMulVartimeEndoWNAFBench(ECP_ShortW_Jac[Fp[curve], G1], bits, window = 4, MulIters)
subgroupCheckScalarMulVartimeEndoWNAFBench(ECP_ShortW_Jac[Fp[curve], G1], bits, window = 5, MulIters)
separator()

# G2
separator()
scalarMulVartimeDoubleAddBench(ECP_ShortW_Jac[Fp2[curve], G2], bits, MulIters)
separator()
scalarMulVartimeWNAFBench(ECP_ShortW_Jac[Fp2[curve], G2], bits, window = 3, MulIters)
scalarMulVartimeWNAFBench(ECP_ShortW_Jac[Fp2[curve], G2], bits, window = 4, MulIters)
separator()
scalarMulVartimeEndoWNAFBench(ECP_ShortW_Jac[Fp2[curve], G2], bits, window = 3, MulIters)
scalarMulVartimeEndoWNAFBench(ECP_ShortW_Jac[Fp2[curve], G2], bits, window = 4, MulIters)
separator()
scalarMulEndo(ECP_ShortW_Jac[Fp2[curve], G2], bits, MulIters)
separator()
subgroupCheckBench(ECP_ShortW_Jac[Fp2[curve], G2], MulIters)
subgroupCheckScalarMulVartimeEndoWNAFBench(ECP_ShortW_Jac[Fp2[curve], G2], bits, window = 3, MulIters)
subgroupCheckScalarMulVartimeEndoWNAFBench(ECP_ShortW_Jac[Fp2[curve], G2], bits, window = 4, MulIters)
separator()

main()
notes()
File renamed without changes.
1 change: 1 addition & 0 deletions benchmarks/bench_eth_eip4844_kzg.nim.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--threads:on
File renamed without changes.
Loading

0 comments on commit d7871d7

Please sign in to comment.