From 3ba3f9846257bbbd452fe14e6607a28a840de7e1 Mon Sep 17 00:00:00 2001 From: Mamy Ratsimbazafy Date: Fri, 12 Jul 2024 17:21:37 +0200 Subject: [PATCH] feat(bench): add pairing and G2 bench for zkalc and nimble build script --- .github/workflows/ci.yml | 14 +++ .gitignore | 4 +- benchmarks/zkalc.nim | 118 +++++++++--------- bin/.gitignore | 12 ++ constantine.nimble | 9 ++ constantine/lowlevel_extension_fields.nim | 1 - .../math/pairings/pairings_generic.nim | 4 +- constantine/named/zoo_subgroups.nim | 2 +- 8 files changed, 100 insertions(+), 64 deletions(-) create mode 100644 bin/.gitignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a63ba8b87..ac0a36eb2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -337,6 +337,20 @@ jobs: cd constantine CTT_ASM=0 cargo test -- --nocapture + - name: Compile Constantine Zkalc benchmark (no assembly) + if: matrix.target.BACKEND == 'NO_ASM' + shell: bash + run: | + cd constantine + CTT_ASM=0 nimble make_zkalc + + - name: Compile Constantine Zkalc benchmark (with assembly) + if: matrix.target.BACKEND == 'ASM' + shell: bash + run: | + cd constantine + nimble make_zkalc + - name: Run Constantine in-depth tests (Unix - with GMP, with Assembly) if: runner.os != 'Windows' && matrix.target.BACKEND == 'ASM' shell: bash diff --git a/.gitignore b/.gitignore index b17171963..6b026cd8c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# Executables shall be put in an ignored build/ directory +# Build artifacts shall be put in an ignored build/ directory # Ignore dynamic, static libs and libtool archive files # ----------------------------------------------------------------------------------------- build/ @@ -54,4 +54,4 @@ Cargo.lock # Perf artifacts # ----------------------------------------------------------------------------------------- perf.data -perf.data.old \ No newline at end of file +perf.data.old diff --git a/benchmarks/zkalc.nim b/benchmarks/zkalc.nim index e376b0f78..1006868b8 100644 --- a/benchmarks/zkalc.nim +++ b/benchmarks/zkalc.nim @@ -16,13 +16,15 @@ # https://github.com/mmaker/zkalc import + constantine/threadpool, constantine/hashes, constantine/lowlevel_fields, + # constantine/lowlevel_extension_fields, + constantine/math/extension_fields, constantine/lowlevel_elliptic_curves, constantine/lowlevel_elliptic_curves_parallel, - # constantine/lowlevel_extension_fields, constantine/lowlevel_pairing_curves, - constantine/threadpool, + # Helpers helpers/prng_unsafe, # Standard library @@ -278,13 +280,13 @@ proc benchEcMul(rng: var RngState, EC: typedesc, useVartime: bool): ZkalcBenchDe type BenchMsmContext[EC] = object numInputs: int - coefs: seq[getBigInt(EC.F.Name, kScalarField)] + coefs: seq[getBigInt(EC.getName(), kScalarField)] points: seq[affine(EC)] proc createBenchMsmContext*(rng: var RngState, EC: typedesc, maxNumInputs: int): BenchMsmContext[EC] = let tp = Threadpool.new() - type Big = EC.F.Name.getBigInt(kScalarField) + type Big = typeof(result.coefs[0]) type ECaff = affine(EC) result.numInputs = maxNumInputs @@ -327,7 +329,7 @@ proc benchEcMsm[EC](ctx: BenchMsmContext[EC]): ZkalcBenchDetails = const G = when EC.G == G1: "𝔾1" else: "𝔾2" - const curve = EC.F.Name + const curve = EC.getName() let tp = Threadpool.new() var size = 2 @@ -405,46 +407,46 @@ func random_point*(rng: var RngState, EC: typedesc): EC {.noInit.} = result = rng.random_unsafe(EC) result.clearCofactor() -# proc benchPairing*(rng: var RngState, curve: static Algebra): ZkalcBenchDetails = -# let -# P = rng.random_point(EC_ShortW_Aff[Fp[curve], G1]) -# Q = rng.random_point(EC_ShortW_Aff[Fp2[curve], G2]) +proc benchPairing*(rng: var RngState, curve: static Algebra): ZkalcBenchDetails = + let + P = rng.random_point(EC_ShortW_Aff[Fp[curve], G1]) + Q = rng.random_point(EC_ShortW_Aff[Fp2[curve], G2]) -# var f: Fp12[curve] -# let stats = bench(): -# f.pairing(P, Q) + var f: Fp12[curve] + let stats = bench(): + f.pairing(P, Q) -# report("Pairing", curve, stats) -# stats.toZkalc() + report("Pairing", curve, stats) + stats.toZkalc() -# proc benchMultiPairing*(rng: var RngState, curve: static Algebra, maxNumInputs: int): ZkalcBenchDetails = -# var -# Ps = newSeq[EC_ShortW_Aff[Fp[curve], G1]](maxNumInputs) -# Qs = newSeq[EC_ShortW_Aff[Fp2[curve], G2]](maxNumInputs) +proc benchMultiPairing*(rng: var RngState, curve: static Algebra, maxNumInputs: int): ZkalcBenchDetails = + var + Ps = newSeq[EC_ShortW_Aff[Fp[curve], G1]](maxNumInputs) + Qs = newSeq[EC_ShortW_Aff[Fp2[curve], G2]](maxNumInputs) -# stdout.write &"Generating {maxNumInputs} (𝔾1, 𝔾2) pairs ... " -# stdout.flushFile() + stdout.write &"Generating {maxNumInputs} (𝔾1, 𝔾2) pairs ... " + stdout.flushFile() -# let start = getMonotime() + let start = getMonotime() -# for i in 0 ..< maxNumInputs: -# Ps[i] = rng.random_point(typeof(Ps[0])) -# Qs[i] = rng.random_point(typeof(Qs[0])) + for i in 0 ..< maxNumInputs: + Ps[i] = rng.random_point(typeof(Ps[0])) + Qs[i] = rng.random_point(typeof(Qs[0])) -# let stop = getMonotime() -# stdout.write &"in {float64(inNanoSeconds(stop-start)) / 1e6:6.3f} ms\n" -# separator() + let stop = getMonotime() + stdout.write &"in {float64(inNanoSeconds(stop-start)) / 1e6:6.3f} ms\n" + separator() -# var size = 2 -# while size <= maxNumInputs: -# var f{.noInit.}: Fp12[curve] -# let stats = bench(): -# f.pairing(Ps.toOpenArray(0, size-1), Qs.toOpenArray(0, size-1)) + var size = 2 + while size <= maxNumInputs: + var f{.noInit.}: Fp12[curve] + let stats = bench(): + f.pairing(Ps.toOpenArray(0, size-1), Qs.toOpenArray(0, size-1)) -# report("Multipairing " & align($size, 5), curve, stats) -# result.append(stats, size) + report("Multipairing " & align($size, 5), curve, stats) + result.append(stats, size) -# size *= 2 + size *= 2 # Run benches # ------------------------------------------------------------------------------------- @@ -480,35 +482,35 @@ proc runBenches(curve: static Algebra, useVartime: bool) = zkalc.hash_G1 = rng.benchEcHashToCurve(EcG1) separator() - # # Pairing-friendly curve only - # # -------------------------------------------------------------------- + # Pairing-friendly curve only + # -------------------------------------------------------------------- - # when curve.isPairingFriendly(): + when curve.isPairingFriendly(): - # # Elliptic curve 𝔾2 - # # -------------------------------------------------------------------- + # Elliptic curve 𝔾2 + # -------------------------------------------------------------------- - # type EcG2 = EC_ShortW_Jac[Fp2[curve], G2] # For now we only supports G2 on Fp2 (not Fp like BW6 or Fp4 like BLS24) + type EcG2 = EC_ShortW_Jac[Fp2[curve], G2] # For now we only supports G2 on Fp2 (not Fp like BW6 or Fp4 like BLS24) - # zkalc.add_g2 = rng.benchEcAdd(EcG2, useVartime) - # zkalc.mul_g2 = rng.benchEcMul(EcG2, useVartime) - # separator() - # let ctxG2 = rng.createBenchMsmContext(EcG2, maxNumInputs = 2097152) - # separator() - # zkalc.msm_g2 = benchEcMsm(ctxG2) - # separator() - # zkalc.is_in_sub_G2 = rng.benchEcIsInSubgroup(EcG2) - # when curve in {BN254_Snarks, BLS12_381}: - # zkalc.hash_G2 = rng.benchEcHashToCurve(EcG2) - # separator() + zkalc.add_g2 = rng.benchEcAdd(EcG2, useVartime) + zkalc.mul_g2 = rng.benchEcMul(EcG2, useVartime) + separator() + let ctxG2 = rng.createBenchMsmContext(EcG2, maxNumInputs = 2097152) + separator() + zkalc.msm_g2 = benchEcMsm(ctxG2) + separator() + zkalc.is_in_sub_G2 = rng.benchEcIsInSubgroup(EcG2) + when curve in {BN254_Snarks, BLS12_381}: + zkalc.hash_G2 = rng.benchEcHashToCurve(EcG2) + separator() - # # Pairings - # # -------------------------------------------------------------------- + # Pairings + # -------------------------------------------------------------------- - # zkalc.pairing = rng.benchPairing(curve) - # separator() - # zkalc.multipairing = rng.benchMultiPairing(curve, maxNumInputs = 1024) - # separator() + zkalc.pairing = rng.benchPairing(curve) + separator() + zkalc.multipairing = rng.benchMultiPairing(curve, maxNumInputs = 1024) + separator() proc main() = let cmd = commandLineParams() diff --git a/bin/.gitignore b/bin/.gitignore new file mode 100644 index 000000000..03fff8904 --- /dev/null +++ b/bin/.gitignore @@ -0,0 +1,12 @@ +# Ignore all +* + +# Unignore all with extensions +!*.* + +# Unignore all dirs +!*/ + +# Reignore executables +*.exe +*.out diff --git a/constantine.nimble b/constantine.nimble index 831d1e14a..28fc2deee 100644 --- a/constantine.nimble +++ b/constantine.nimble @@ -277,6 +277,14 @@ task make_lib_rust, "Build Constantine library (use within a Rust build.rs scrip else: "--passC:-fPIC" genStaticLib(rustOutDir, rustOutDir/"nimcache", extflags) +task make_zkalc, "Build a benchmark executable for zkalc (with Clang)": + exec "nim c --cc:clang " & + releaseBuildOptions(bmBinary) & + " --threads:on " & + " --out:bin/constantine-bench-zkalc " & + " --nimcache:nimcache/bench_zkalc " & + " benchmarks/zkalc.nim" + proc testLib(path, testName: string, useGMP: bool) = let dynlibName = if defined(windows): "constantine.dll" elif defined(macosx) or defined(macos): "libconstantine.dylib" @@ -639,6 +647,7 @@ const benchDesc = [ "bench_eth_eip2537_subgroup_checks_impact", "bench_verkle_primitives", "bench_eth_evm_precompiles", + # "zkalc", # Already tested through make_zkalc ] # For temporary (hopefully) investigation that can only be reproduced in CI diff --git a/constantine/lowlevel_extension_fields.nim b/constantine/lowlevel_extension_fields.nim index bc472a3b4..554550851 100644 --- a/constantine/lowlevel_extension_fields.nim +++ b/constantine/lowlevel_extension_fields.nim @@ -45,7 +45,6 @@ export # ------------------------------------------------------------ export - extension_fields.Name, extension_fields.Fp2, # TODO: deal with Fp2->Fp6 vs Fp3->Fp6 and Fp2->Fp6->Fp12 vs Fp2->Fp4->Fp12 # extension_fields.Fp4, diff --git a/constantine/math/pairings/pairings_generic.nim b/constantine/math/pairings/pairings_generic.nim index 3464209a5..a8a79f696 100644 --- a/constantine/math/pairings/pairings_generic.nim +++ b/constantine/math/pairings/pairings_generic.nim @@ -21,13 +21,13 @@ func pairing*[Name: static Algebra](gt: var Fp12[Name], P, Q: auto) {.inline.} = else: {.error: "Pairing not implemented for " & $Name.} -func millerLoop*[Name](gt: var Fp12[Name], Q, P: auto, n: int) {.inline.} = +func millerLoop*[Name: static Algebra](gt: var Fp12[Name], Q, P: auto, n: int) {.inline.} = when Name == BN254_Snarks: gt.millerLoopGenericBN(Q, P, n) else: gt.millerLoopAddchain(Q, P, n) -func finalExp*[Name](gt: var Fp12[Name]){.inline.} = +func finalExp*[Name: static Algebra](gt: var Fp12[Name]){.inline.} = gt.finalExpEasy() when family(Name) == BarretoNaehrig: gt.finalExpHard_BN() diff --git a/constantine/named/zoo_subgroups.nim b/constantine/named/zoo_subgroups.nim index 2942ade07..2a9e584ef 100644 --- a/constantine/named/zoo_subgroups.nim +++ b/constantine/named/zoo_subgroups.nim @@ -33,7 +33,7 @@ export func clearCofactor*[EC](P: var EC) {.inline.} = ## Clear the cofactor of a point on the curve ## From a point on the curve, returns a point on the subgroup of order r - when EC.F.Name in {BN254_Nogami, BN254_Snarks, BLS12_377, BLS12_381}: + when EC.getName() in {BN254_Nogami, BN254_Snarks, BLS12_377, BLS12_381}: P.clearCofactorFast() else: P.clearCofactorReference()