diff --git a/benchmarks/bench_fields_template.nim b/benchmarks/bench_fields_template.nim index ca9c414b..8a0acf11 100644 --- a/benchmarks/bench_fields_template.nim +++ b/benchmarks/bench_fields_template.nim @@ -233,9 +233,8 @@ proc powBench*(T: typedesc, iters: int) = var r = x r.pow(exponent) -proc powUnsafeBench*(T: typedesc, iters: int) = +proc powVartimeBench*(T: typedesc, iters: int) = let x = rng.random_unsafe(T) let exponent = rng.random_unsafe(BigInt[Fr[T.Name].bits()]) - bench("Exp curve order (Leak exponent bits) - " & $exponent.bits & "-bit", T, iters): - var r = x + bench("Exp by curve order (vartime) - " & $exponent.bits & "-bit", T, iters): r.pow_vartime(exponent) diff --git a/benchmarks/bench_fp.nim b/benchmarks/bench_fp.nim index 9867e3cb..7678340b 100644 --- a/benchmarks/bench_fp.nim +++ b/benchmarks/bench_fp.nim @@ -70,7 +70,7 @@ proc main() = sqrtRatioVartimeBench(Fp[curve], ExponentIters) # Exponentiation by a "secret" of size ~the curve order powBench(Fp[curve], ExponentIters) - powUnsafeBench(Fp[curve], ExponentIters) + powVartimeBench(Fp[curve], ExponentIters) separator() main() diff --git a/benchmarks/bench_gt.nim b/benchmarks/bench_gt.nim new file mode 100644 index 00000000..aeb4d93d --- /dev/null +++ b/benchmarks/bench_gt.nim @@ -0,0 +1,64 @@ +# 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/named/algebras, + constantine/math/extension_fields, + # Helpers + ./bench_gt_template + +# ############################################################ +# +# Benchmark of the 𝔾ₜ group of +# Pairing Friendly curves +# +# ############################################################ + +const Iters = 10000 +const ExpIters = 1000 +const AvailableCurves = [ + # BN254_Nogami, + BN254_Snarks, + # BLS12_377, + BLS12_381, +] + +proc main() = + separator() + staticFor i, 0, AvailableCurves.len: + const curve = AvailableCurves[i] + const bits = Fr[curve].bits() + separator() + mulBench(Fp12[curve], Iters) + sqrBench(Fp12[curve], Iters) + invBench(Fp12[curve], Iters) + separator() + cyclotomicSquare_Bench(Fp12[curve], Iters) + cyclotomicInv_Bench(Fp12[curve], Iters) + cyclotomicSquareCompressed_Bench(Fp12[curve], Iters) + cyclotomicDecompression_Bench(Fp12[curve], Iters) + separator() + powVartimeBench(Fp12[curve], window = 2, ExpIters) + powVartimeBench(Fp12[curve], window = 3, ExpIters) + powVartimeBench(Fp12[curve], window = 4, ExpIters) + separator() + gtExp_sqrmul_vartimeBench(Fp12[curve], ExpIters) + gtExp_minHammingWeight_vartimeBench(Fp12[curve], ExpIters) + separator() + gtExp_wNAF_vartimeBench(Fp12[curve], window = 2, ExpIters) + gtExp_wNAF_vartimeBench(Fp12[curve], window = 3, ExpIters) + gtExp_wNAF_vartimeBench(Fp12[curve], window = 4, ExpIters) + separator() + gtExp_endo_wNAF_vartimeBench(Fp12[curve], window = 2, ExpIters) + gtExp_endo_wNAF_vartimeBench(Fp12[curve], window = 3, ExpIters) + gtExp_endo_wNAF_vartimeBench(Fp12[curve], window = 4, ExpIters) + separator() + +main() +notes() diff --git a/benchmarks/bench_gt_template.nim b/benchmarks/bench_gt_template.nim new file mode 100644 index 00000000..f27420a9 --- /dev/null +++ b/benchmarks/bench_gt_template.nim @@ -0,0 +1,167 @@ +# 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. + +# ############################################################ +# +# Summary of the performance of a curve +# +# ############################################################ + +import + # Internals + constantine/platforms/abstractions, + constantine/named/algebras, + constantine/math/[arithmetic, extension_fields], + constantine/math/pairings/[ + pairings_generic, + cyclotomic_subgroups, + gt_exponentiations_vartime + ], + # Helpers + helpers/prng_unsafe, + ./bench_blueprint + + +export notes +export abstractions +proc separator*() = separator(168) + +proc report(op, domain: string, start, stop: MonoTime, startClk, stopClk: int64, iters: int) = + let ns = inNanoseconds((stop-start) div iters) + let throughput = 1e9 / float64(ns) + when SupportsGetTicks: + echo &"{op:<68} {domain:<20} {throughput:>15.3f} ops/s {ns:>9} ns/op {(stopClk - startClk) div iters:>9} CPU cycles (approx)" + else: + echo &"{op:<68} {domain:<20} {throughput:>15.3f} ops/s {ns:>9} ns/op" + +macro fixFieldDisplay(T: typedesc): untyped = + # At compile-time, enums are integers and their display is buggy + # we get the Curve ID instead of the curve name. + let instantiated = T.getTypeInst() + var name = $instantiated[1][0] # Fp + name.add "[" & $Algebra(instantiated[1][1].intVal) & "]" + result = newLit name + +func fixDisplay(T: typedesc): string = + when T is (Fp or Fp2 or Fp4 or Fp6 or Fp12): + fixFieldDisplay(T) + else: + $T + +func fixDisplay(T: Algebra): string = + $T + +template bench(op: string, T: typed, iters: int, body: untyped): untyped = + measure(iters, startTime, stopTime, startClk, stopClk, body) + report(op, fixDisplay(T), startTime, stopTime, startClk, stopClk, iters) + +func random_gt*(rng: var RngState, F: typedesc): F {.inline, noInit.} = + result = rng.random_unsafe(F) + result.finalExp() + +proc mulBench*(T: typedesc, iters: int) = + var r: T + let x = rng.random_gt(T) + let y = rng.random_gt(T) + preventOptimAway(r) + bench("Multiplication", T, iters): + r.prod(x, y) + +proc sqrBench*(T: typedesc, iters: int) = + var r: T + let x = rng.random_gt(T) + preventOptimAway(r) + bench("Squaring", T, iters): + r.square(x) + +proc invBench*(T: typedesc, iters: int) = + var r: T + let x = rng.random_gt(T) + preventOptimAway(r) + bench("Inversion", T, iters): + r.inv(x) + +proc cyclotomicSquare_Bench*(T: typedesc, iters: int) = + var f = rng.random_gt(T) + + bench("Squaring in cyclotomic subgroup", T, iters): + f.cyclotomic_square() + +proc cyclotomicInv_Bench*(T: typedesc, iters: int) = + var f = rng.random_gt(T) + + bench("Inversion in cyclotomic subgroup", T, iters): + f.cyclotomic_inv() + +proc cyclotomicSquareCompressed_Bench*(T: typedesc, iters: int) = + var f = rng.random_gt(T) + + when T is Fp12: + type F = Fp2[T.Name] + else: + {.error: "Only compression of Fp12 extension is configured".} + + var g: G2345[F] + g.fromFpk(f) + + bench("Cyclotomic Compressed Squaring", T, iters): + g.cyclotomic_square_compressed() + +proc cyclotomicDecompression_Bench*(T: typedesc, iters: int) = + var f = rng.random_gt(T) + + when T is Fp12: + type F = Fp2[T.Name] + else: + {.error: "Only compression of Fp12 extension is configured".} + + var gs: array[1, G2345[F]] + gs[0].fromFpk(f) + + var g1s_ratio: array[1, tuple[g1_num, g1_den: F]] + var g0s, g1s: array[1, F] + + bench("Cyclotomic Decompression", T, iters): + recover_g1(g1s_ratio[0].g1_num, g1s_ratio[0].g1_den, gs[0]) + g1s.batch_ratio_g1s(g1s_ratio) + g0s[0].recover_g0(g1s[0], gs[0]) + +proc powVartimeBench*(T: typedesc, window: static int, iters: int) = + let x = rng.random_gt(T) + let exponent = rng.random_unsafe(BigInt[Fr[T.Name].bits()]) + var r = x + bench("Field Exponentiation " & $exponent.bits & "-bit (window-" & $window & ", vartime)", T, iters): + r.pow_vartime(exponent, window) + +proc gtExp_sqrmul_vartimeBench*(T: typedesc, iters: int) = + let x = rng.random_gt(T) + let exponent = rng.random_unsafe(BigInt[Fr[T.Name].bits()]) + var r {.noInit.}: T + bench("𝔾ₜ Exponentiation " & $exponent.bits & "-bit (cyclotomic square-multiply, vartime)", T, iters): + r.gtExp_sqrmul_vartime(x, exponent) + +proc gtExp_minHammingWeight_vartimeBench*(T: typedesc, iters: int) = + let x = rng.random_gt(T) + let exponent = rng.random_unsafe(BigInt[Fr[T.Name].bits()]) + var r {.noInit.}: T + bench("𝔾ₜ Exponentiation " & $exponent.bits & "-bit (signed recoding, vartime)", T, iters): + r.gtExp_minHammingWeight_vartime(x, exponent) + +proc gtExp_wNAF_vartimeBench*(T: typedesc, window: static int, iters: int) = + let x = rng.random_gt(T) + let exponent = rng.random_unsafe(BigInt[Fr[T.Name].bits()]) + var r {.noInit.}: T + bench("𝔾ₜ Exponentiation " & $exponent.bits & "-bit (wNAF-" & $window & ", vartime)", T, iters): + r.gtExp_minHammingWeight_windowed_vartime(x, exponent, window) + +proc gtExp_endo_wNAF_vartimeBench*(T: typedesc, window: static int, iters: int) = + let x = rng.random_gt(T) + let exponent = rng.random_unsafe(BigInt[Fr[T.Name].bits()]) + var r {.noInit.}: T + bench("𝔾ₜ Exponentiation " & $exponent.bits & "-bit (endomorphism, wNAF-" & $window & ", vartime)", T, iters): + r.gtExpEndo_minHammingWeight_windowed_vartime(x, exponent, window) diff --git a/constantine.nimble b/constantine.nimble index a6cb8a4a..4ad7e001 100644 --- a/constantine.nimble +++ b/constantine.nimble @@ -563,6 +563,7 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[ # ("tests/math_pairings/t_pairing_bls12_381_optate.nim", false), ("tests/math_pairings/t_pairing_bn254_snarks_gt_exp.nim", false), + ("tests/math_pairings/t_pairing_bls12_381_gt_exp.nim", false), # Multi-Pairing # ---------------------------------------------------------- @@ -652,6 +653,7 @@ const benchDesc = [ "bench_pairing_bls12_381", "bench_pairing_bn254_nogami", "bench_pairing_bn254_snarks", + "bench_gt", "bench_summary_bls12_377", "bench_summary_bls12_381", "bench_summary_bn254_nogami", @@ -1028,6 +1030,12 @@ task bench_ec_g2, "Run benchmark on Elliptic Curve group 𝔾2 - CC compiler": task bench_ec_g2_scalar_mul, "Run benchmark on Elliptic Curve group 𝔾2 (Multi-Scalar-Mul) - CC compiler": runBench("bench_ec_g2_scalar_mul") +# 𝔾ₜ +# ------------------------------------------ + +task bench_gt, "Run 𝔾ₜ benchmarks - CC compiler": + runBench("bench_gt") + # Pairings # ------------------------------------------ diff --git a/tests/math_pairings/t_pairing_bls12_381_gt_exp.nim b/tests/math_pairings/t_pairing_bls12_381_gt_exp.nim new file mode 100644 index 00000000..2309c628 --- /dev/null +++ b/tests/math_pairings/t_pairing_bls12_381_gt_exp.nim @@ -0,0 +1,15 @@ +# 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 + # Test utilities + ./t_pairing_template + +runGTexponentiationTests( + Iters = 4, + GT = Fp12[BLS12_381])