From 9f7c8515a4534a62267b8faf56d61cd1b3abe7fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mamy=20Andr=C3=A9-Ratsimbazafy?= Date: Tue, 25 Feb 2020 23:52:56 +0100 Subject: [PATCH] Prepare RNG with 2^512 bit of state for random testing on Fp2 --- .../tower_field_extensions/fp2_complex.nim | 4 +- tests/prng.nim | 102 ++++++++++++++++++ tests/test_fp2.nim | 23 ++++ 3 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 tests/prng.nim create mode 100644 tests/test_fp2.nim diff --git a/constantine/tower_field_extensions/fp2_complex.nim b/constantine/tower_field_extensions/fp2_complex.nim index d496313..eb5bf46 100644 --- a/constantine/tower_field_extensions/fp2_complex.nim +++ b/constantine/tower_field_extensions/fp2_complex.nim @@ -47,7 +47,7 @@ import ./abelian_groups type - Fp2[C: static Curve] = object + Fp2*[C: static Curve] = object ## Element of the extension field ## š¯”½p2 = š¯”½p[š¯‘–] of a prime p ## @@ -125,7 +125,7 @@ func prod*(r: var Fp2, a, b: Fp2) = r.c0.sum(a.c0, a.c1) # r0 = (a0 + a1) # [2 Mul, 1 Add] r.c1.sum(b.c0, b.c1) # r1 = (b0 + b1) # [2 Mul, 2 Add] - r.c1 *= c.c0 # r1 = (b0 + b1)(a0 + a1) # [3 Mul, 2 Add] - š¯”½p temporary + r.c1 *= r.c0 # r1 = (b0 + b1)(a0 + a1) # [3 Mul, 2 Add] - š¯”½p temporary r.c0.diff(a0b0, a1b1) # r0 = a0 b0 - a1 b1 # [3 Mul, 2 Add, 1 Sub] r.c1 -= a0b0 # r1 = (b0 + b1)(a0 + a1) - a0b0 # [3 Mul, 2 Add, 2 Sub] diff --git a/tests/prng.nim b/tests/prng.nim new file mode 100644 index 0000000..3b8c8f8 --- /dev/null +++ b/tests/prng.nim @@ -0,0 +1,102 @@ +# 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 + ../constantine/arithmetic/bigints_checked, + ../constantine/config/[common, curves] + +# ############################################################ +# +# Pseudo-Random Number Generator +# +# ############################################################ +# +# Our field elements for elliptic curve cryptography +# are in the 2^256~2^512 range. +# For pairings, with embedding degrees of 12 to 48 +# We would need 12~48 field elements per point on the curve +# +# The recommendation by Vigna at http://prng.di.unimi.it +# is to have a period of t^2 if we need t values (i.e. about 2^1024) +# but also that for all practical purposes 2^256 period is enough +# +# We use 2^512 to cover the range the base field elements + +type RngState* = object + s: array[8, uint64] + +func splitMix64(state: var uint64): uint64 = + state += 0x9e3779b97f4a7c15'u64 + result = state + result = (result xor (result shr 30)) * 0xbf58476d1ce4e5b9'u64 + result = (result xor (result shr 27)) * 0xbf58476d1ce4e5b9'u64 + result = result xor (result shr 31) + +func seed*(rng: var RngState, x: SomeInteger) = + ## Seed the random number generator with a fixed seed + var sm64 = uint64(x) + rng.s[0] = splitMix64(sm64) + rng.s[1] = splitMix64(sm64) + rng.s[2] = splitMix64(sm64) + rng.s[3] = splitMix64(sm64) + rng.s[4] = splitMix64(sm64) + rng.s[5] = splitMix64(sm64) + rng.s[6] = splitMix64(sm64) + rng.s[7] = splitMix64(sm64) + +func rotl(x: uint64, k: static int): uint64 {.inline.} = + return (x shl k) or (x shr (64 - k)) + +template `^=`(x: var uint64, y: uint64) = + x = x xor y + +func next(rng: var RngState): uint64 = + ## Compute a random uint64 from the input state + ## using xoshiro512** algorithm by Vigna et al + ## State is updated. + result = rotl(rng.s[1] * 5, 7) * 9 + + let t = rng.s[1] shl 11 + rng.s[2] ^= rng.s[0]; + rng.s[5] ^= rng.s[1]; + rng.s[1] ^= rng.s[2]; + rng.s[7] ^= rng.s[3]; + rng.s[3] ^= rng.s[4]; + rng.s[4] ^= rng.s[5]; + rng.s[0] ^= rng.s[6]; + rng.s[6] ^= rng.s[7]; + + rng.s[6] ^= t; + + rng.s[7] = rotl(rng.s[7], 21); + +# ############################################################ +# +# Create a random BigInt or Field element +# +# ############################################################ + +func random[T](rng: var RngState, a: var T, C: static Curve) {.noInit.}= + ## Recursively initialize a BigInt or Field element + when T is BigInt: + var unreduced{.noInit.}: T + + unreduced.setInternalBitLength() + for i in 0 ..< unreduced.limbs.len: + unreduced.limbs[i] = Word(rng.next()) + + # Note: a simple modulo will be biaised but it's simple and "fast" + a.reduce(unreduced, C.Mod.mres) + + else: + for field in fields(a): + rng.random(field, C) + +func random*(rng: var RngState, T: typedesc): T = + ## Create a random Field or Extension FIeld Element + rng.random(result, T.C) diff --git a/tests/test_fp2.nim b/tests/test_fp2.nim new file mode 100644 index 0000000..a0fb799 --- /dev/null +++ b/tests/test_fp2.nim @@ -0,0 +1,23 @@ +# 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 + unittest, times, + # Internals + ../constantine/tower_field_extensions/[abelian_groups, fp2_complex], + ../constantine/config/[common, curves], + ../constantine/arithmetic/bigints_checked, + # Test utilities + ./prng + + +var rng: RngState +let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32 +rng.seed(seed) +echo "test_fp2 xoshiro512** seed: ", seed