220 lines
5.8 KiB
Nim
220 lines
5.8 KiB
Nim
# 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
|
||
# Standard library
|
||
std/[tables, unittest, times],
|
||
# Internals
|
||
../constantine/config/common,
|
||
../constantine/[arithmetic, primitives],
|
||
../constantine/towers,
|
||
../constantine/config/curves,
|
||
../constantine/io/io_towers,
|
||
# Test utilities
|
||
../helpers/[prng_unsafe, static_for]
|
||
|
||
const
|
||
Iters = 2
|
||
TestCurves = [
|
||
BN254_Snarks,
|
||
BLS12_381
|
||
]
|
||
|
||
type
|
||
RandomGen = enum
|
||
Uniform
|
||
HighHammingWeight
|
||
Long01Sequence
|
||
|
||
var rng: RngState
|
||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||
rng.seed(seed)
|
||
echo "\n------------------------------------------------------\n"
|
||
echo "test_fp12_exponentiation xoshiro512** seed: ", seed
|
||
|
||
func random_elem(rng: var RngState, F: typedesc, gen: RandomGen): F {.inline, noInit.} =
|
||
if gen == Uniform:
|
||
result = rng.random_unsafe(F)
|
||
elif gen == HighHammingWeight:
|
||
result = rng.random_highHammingWeight(F)
|
||
else:
|
||
result = rng.random_long01Seq(F)
|
||
|
||
proc test_sameBaseProduct(C: static Curve, gen: RandomGen) =
|
||
## xᴬ xᴮ = xᴬ⁺ᴮ - product of power
|
||
let x = rng.random_elem(Fp12[C], gen)
|
||
|
||
var a = rng.random_elem(BigInt[128], gen)
|
||
var b = rng.random_elem(BigInt[128], gen)
|
||
# div by 2 to ensure their sum doesn't overflow
|
||
# 128 bits
|
||
a.div2()
|
||
b.div2()
|
||
|
||
var xa = x
|
||
xa.powUnsafeExponent(a, window = 3)
|
||
|
||
var xb = x
|
||
xb.powUnsafeExponent(b, window = 3)
|
||
|
||
var xapb = x
|
||
var apb: BigInt[128]
|
||
discard apb.sum(a, b)
|
||
xapb.powUnsafeExponent(apb, window = 3)
|
||
|
||
xa *= xb
|
||
check: bool(xa == xapb)
|
||
|
||
proc test_powpow(C: static Curve, gen: RandomGen) =
|
||
## (xᴬ)ᴮ = xᴬᴮ - power of power
|
||
var x = rng.random_elem(Fp12[C], gen)
|
||
|
||
var a = rng.random_elem(BigInt[128], gen)
|
||
var b = rng.random_elem(BigInt[128], gen)
|
||
|
||
var ab: BigInt[256]
|
||
ab.prod(a, b)
|
||
|
||
var y = x
|
||
|
||
x.powUnsafeExponent(a, window = 3)
|
||
x.powUnsafeExponent(b, window = 3)
|
||
|
||
y.powUnsafeExponent(ab, window = 3)
|
||
check: bool(x == y)
|
||
|
||
proc test_powprod(C: static Curve, gen: RandomGen) =
|
||
## (xy)ᴬ = xᴬyᴬ - power of product
|
||
var x = rng.random_elem(Fp12[C], gen)
|
||
var y = rng.random_elem(Fp12[C], gen)
|
||
|
||
let a = rng.random_elem(BigInt[128], gen)
|
||
|
||
var xy{.noInit.}: Fp12[C]
|
||
xy.prod(x, y)
|
||
|
||
xy.powUnsafeExponent(a, window=3)
|
||
|
||
x.powUnsafeExponent(a, window=3)
|
||
y.powUnsafeExponent(a, window=3)
|
||
|
||
x *= y
|
||
|
||
check: bool(x == xy)
|
||
|
||
proc test_pow0(C: static Curve, gen: RandomGen) =
|
||
## x⁰ = 1
|
||
var x = rng.random_elem(Fp12[C], gen)
|
||
var a: BigInt[128] # 0-init
|
||
|
||
x.powUnsafeExponent(a, window=3)
|
||
check: bool x.isOne()
|
||
|
||
proc test_0pow0(C: static Curve, gen: RandomGen) =
|
||
## 0⁰ = 1
|
||
var x: Fp12[C] # 0-init
|
||
var a: BigInt[128] # 0-init
|
||
|
||
x.powUnsafeExponent(a, window=3)
|
||
check: bool x.isOne()
|
||
|
||
proc test_powinv(C: static Curve, gen: RandomGen) =
|
||
## xᴬ / xᴮ = xᴬ⁻ᴮ - quotient of power
|
||
let x = rng.random_elem(Fp12[C], gen)
|
||
|
||
var a = rng.random_elem(BigInt[128], gen)
|
||
var b = rng.random_elem(BigInt[128], gen)
|
||
# div by 2 to ensure their sum doesn't overflow
|
||
# 128 bits
|
||
a.div2()
|
||
b.div2()
|
||
# Ensure a > b
|
||
cswap(a, b, a < b)
|
||
|
||
var xa = x
|
||
xa.powUnsafeExponent(a, window = 3)
|
||
|
||
var xb = x
|
||
xb.powUnsafeExponent(b, window = 3)
|
||
|
||
xb.inv()
|
||
xa *= xb
|
||
|
||
var xamb = x
|
||
var amb: BigInt[128]
|
||
discard amb.diff(a, b)
|
||
xamb.powUnsafeExponent(amb, window = 3)
|
||
|
||
check: bool(xa == xamb)
|
||
|
||
proc test_invpow(C: static Curve, gen: RandomGen) =
|
||
## (x / y)ᴬ = xᴬ / yᴬ - power of quotient
|
||
let x = rng.random_elem(Fp12[C], gen)
|
||
let y = rng.random_elem(Fp12[C], gen)
|
||
|
||
var a = rng.random_elem(BigInt[128], gen)
|
||
|
||
var xa = x
|
||
xa.powUnsafeExponent(a, window = 3)
|
||
|
||
var ya = y
|
||
ya.powUnsafeExponent(a, window = 3)
|
||
ya.inv()
|
||
xa *= ya
|
||
|
||
var xqya = x
|
||
var invy = y
|
||
invy.inv()
|
||
xqya *= invy
|
||
xqya.powUnsafeExponent(a, window = 3)
|
||
|
||
check: bool(xa == xqya)
|
||
|
||
suite "Exponentiation in 𝔽p12" & " [" & $WordBitwidth & "-bit mode]":
|
||
staticFor(curve, TestCurves):
|
||
test "xᴬ xᴮ = xᴬ⁺ᴮ on " & $curve:
|
||
test_sameBaseProduct(curve, gen = Uniform)
|
||
test_sameBaseProduct(curve, gen = HighHammingWeight)
|
||
test_sameBaseProduct(curve, gen = Long01Sequence)
|
||
|
||
staticFor(curve, TestCurves):
|
||
test "(xᴬ)ᴮ = xᴬᴮ on " & $curve:
|
||
test_powpow(curve, gen = Uniform)
|
||
test_powpow(curve, gen = HighHammingWeight)
|
||
test_powpow(curve, gen = Long01Sequence)
|
||
|
||
staticFor(curve, TestCurves):
|
||
test "(xy)ᴬ = xᴬyᴬ on " & $curve:
|
||
test_powprod(curve, gen = Uniform)
|
||
test_powprod(curve, gen = HighHammingWeight)
|
||
test_powprod(curve, gen = Long01Sequence)
|
||
|
||
staticFor(curve, TestCurves):
|
||
test "x⁰ = 1 on " & $curve:
|
||
test_pow0(curve, gen = Uniform)
|
||
test_pow0(curve, gen = HighHammingWeight)
|
||
test_pow0(curve, gen = Long01Sequence)
|
||
|
||
staticFor(curve, TestCurves):
|
||
test "0⁰ = 1 on " & $curve:
|
||
test_0pow0(curve, gen = Uniform)
|
||
test_0pow0(curve, gen = HighHammingWeight)
|
||
test_0pow0(curve, gen = Long01Sequence)
|
||
|
||
staticFor(curve, TestCurves):
|
||
test "xᴬ / xᴮ = xᴬ⁻ᴮ on " & $curve:
|
||
test_powinv(curve, gen = Uniform)
|
||
test_powinv(curve, gen = HighHammingWeight)
|
||
test_powinv(curve, gen = Long01Sequence)
|
||
|
||
staticFor(curve, TestCurves):
|
||
test "(x / y)ᴬ = xᴬ / yᴬ on " & $curve:
|
||
test_invpow(curve, gen = Uniform)
|
||
test_invpow(curve, gen = HighHammingWeight)
|
||
test_invpow(curve, gen = Long01Sequence)
|