Implement 𝔽p12 inversion, enable 𝔽p12 tests and bench

This commit is contained in:
Mamy André-Ratsimbazafy 2020-04-09 14:28:01 +02:00
parent 3a1a5f8847
commit a6e4517be2
No known key found for this signature in database
GPG Key ID: 7B88AD1FE79492E1
6 changed files with 123 additions and 2 deletions

54
benchmarks/bench_fp12.nim Normal file
View File

@ -0,0 +1,54 @@
# 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/config/curves,
../constantine/tower_field_extensions/[abelian_groups, fp12_quad_fp6],
# Helpers
../helpers/static_for,
./bench_fields_template,
# Standard library
std/strutils
# ############################################################
#
# Benchmark of 𝔽p12
#
# ############################################################
const Iters = 10_000
const InvIters = 1000
const AvailableCurves = [
# Pairing-Friendly curves
BN254,
BLS12_377,
BLS12_381,
BN446,
FKM12_447,
BLS12_461,
BN462
]
proc main() =
echo "-".repeat(80)
staticFor i, 0, AvailableCurves.len:
const curve = AvailableCurves[i]
addBench(Fp12[curve], Iters)
subBench(Fp12[curve], Iters)
negBench(Fp12[curve], Iters)
mulBench(Fp12[curve], Iters)
sqrBench(Fp12[curve], Iters)
invBench(Fp12[curve], InvIters)
echo "-".repeat(80)
main()
echo "Notes:"
echo " GCC is significantly slower than Clang on multiprecision arithmetic."

View File

@ -18,7 +18,7 @@ import
# ############################################################
#
# Benchmark of 𝔽p2 = 𝔽p[𝑖]
# Benchmark of 𝔽p6
#
# ############################################################

View File

@ -51,6 +51,7 @@ task test, "Run all tests":
# Towers of extension fields
test "", "tests/test_fp2.nim"
test "", "tests/test_fp6.nim"
test "", "tests/test_fp12.nim"
if sizeof(int) == 8: # 32-bit tests
# Primitives
@ -74,6 +75,7 @@ task test, "Run all tests":
# Towers of extension fields
test "-d:Constantine32", "tests/test_fp2.nim"
test "-d:Constantine32", "tests/test_fp6.nim"
test "-d:Constantine32", "tests/test_fp12.nim"
task test_no_gmp, "Run tests that don't require GMP":
# -d:testingCurves is configured in a *.nim.cfg for convenience
@ -95,6 +97,7 @@ task test_no_gmp, "Run tests that don't require GMP":
# Towers of extension fields
test "", "tests/test_fp2.nim"
test "", "tests/test_fp6.nim"
test "", "tests/test_fp12.nim"
if sizeof(int) == 8: # 32-bit tests
# Primitives
@ -114,6 +117,7 @@ task test_no_gmp, "Run tests that don't require GMP":
# Towers of extension fields
test "-d:Constantine32", "tests/test_fp2.nim"
test "-d:Constantine32", "tests/test_fp6.nim"
test "-d:Constantine32", "tests/test_fp12.nim"
proc runBench(benchName: string, compiler = "") =
if not dirExists "build":
@ -152,3 +156,12 @@ task bench_fp6_gcc, "Run benchmark 𝔽p6 with gcc":
task bench_fp6_clang, "Run benchmark 𝔽p6 with clang":
runBench("bench_fp6", "clang")
task bench_fp12, "Run benchmark with 𝔽p12 your default compiler":
runBench("bench_fp12")
task bench_fp12_gcc, "Run benchmark 𝔽p12 with gcc":
runBench("bench_fp12", "gcc")
task bench_fp12_clang, "Run benchmark 𝔽p12 with clang":
runBench("bench_fp12", "clang")

View File

@ -127,3 +127,27 @@ func prod*[C](r: var Fp12[C], a, b: Fp12[C]) =
# r0 <- a0 b0 + γ a1 b1
r.c0 += Gamma * t
func inv*[C](r: var Fp12[C], a: Fp12[C]) =
## Compute the multiplicative inverse of ``a``
#
# Algorithm: (the inverse exist if a != 0 which might cause constant-time issue)
#
# 1 / (a0 + a1 w) <=> (a0 - a1 w) / (a0 + a1 w)(a0 - a1 w)
# <=> (a0 - a1 w) / (a0² - a1² w²)
# In our case 𝔽p12 = 𝔽p6[γ], we have w² = γ
# So the inverse is (a0 - a1 w) / (a0² - γ a1²)
# [2 Sqr, 1 Add]
var v0 {.noInit.}, v1 {.noInit.}: Fp6[C]
v0.square(a.c0)
v1.square(a.c1)
v0 -= Gamma * v1 # v0 = a0² - γ a1² (the norm / squared magnitude of a)
# [1 Inv, 2 Sqr, 1 Add]
v1.inv(v0) # v1 = 1 / (a0² - γ a1²)
# [1 Inv, 2 Mul, 2 Sqr, 1 Add, 1 Neg]
r.c0.prod(a.c0, v1) # r0 = a0 / (a0² - γ a1²)
v0.neg(v1) # v0 = -1 / (a0² - γ a1²)
r.c1.prod(a.c1, v0) # r1 = -a1 / (a0² - γ a1²)

View File

@ -418,3 +418,33 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
commutativeRing(FKM12_447)
commutativeRing(BLS12_461)
commutativeRing(BN462)
test "𝔽p6 = 𝔽p2[∛(1+𝑖)] extension field multiplicative inverse":
proc mulInvOne(curve: static Curve) =
var one: Fp12[curve]
one.setOne()
block: # Inverse of 1 is 1
var r {.noInit.}: Fp12[curve]
r.inv(one)
check: bool(r == one)
var aInv, r{.noInit.}: Fp12[curve]
for _ in 0 ..< Iters:
let a = rng.random(Fp12[curve])
aInv.inv(a)
r.prod(a, aInv)
check: bool(r == one)
r.prod(aInv, a)
check: bool(r == one)
mulInvOne(BN254)
mulInvOne(BLS12_377)
mulInvOne(BLS12_381)
mulInvOne(BN446)
mulInvOne(FKM12_447)
mulInvOne(BLS12_461)
mulInvOne(BN462)

View File

@ -431,7 +431,7 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
var aInv, r{.noInit.}: Fp6[curve]
for _ in 0 ..< 1: # Iters:
for _ in 0 ..< Iters:
let a = rng.random(Fp6[curve])
aInv.inv(a)