[WIP] Skewed RNGs that trigger corner cases (#59)
* Add a RNG skewed to high hamming weights * Add libsecp256k1 skewed RNG that found a CVE in OpenSSL * Add initial skewed RNGs tests to finite fields * Add Fp towers skewed tests * Add ellptic curve skewed tests
This commit is contained in:
parent
a2a2495351
commit
e491f3b91d
|
@ -8,8 +8,10 @@
|
|||
|
||||
import
|
||||
../constantine/arithmetic/bigints,
|
||||
../constantine/primitives,
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective]
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective],
|
||||
../constantine/io/io_bigints
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
|
@ -79,17 +81,65 @@ func next(rng: var RngState): uint64 =
|
|||
|
||||
rng.s[7] = rotl(rng.s[7], 21);
|
||||
|
||||
# Integer ranges
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func random_unsafe*(rng: var RngState, maxExclusive: uint32): uint32 =
|
||||
## Generate a random integer in 0 ..< maxExclusive
|
||||
## Uses an unbiaised generation method
|
||||
## See Lemire's algorithm modified by Melissa O'Neill
|
||||
## https://www.pcg-random.org/posts/bounded-rands.html
|
||||
let max = maxExclusive
|
||||
var x = uint32 rng.next()
|
||||
var m = x.uint64 * max.uint64
|
||||
var l = uint32 m
|
||||
if l < max:
|
||||
var t = not(max) + 1 # -max
|
||||
if t >= max:
|
||||
t -= max
|
||||
if t >= max:
|
||||
t = t mod max
|
||||
while l < t:
|
||||
x = uint32 rng.next()
|
||||
m = x.uint64 * max.uint64
|
||||
l = uint32 m
|
||||
return uint32(m shr 32)
|
||||
|
||||
func random_unsafe*[T: SomeInteger](rng: var RngState, inclRange: Slice[T]): T =
|
||||
## Return a random integer in the given range.
|
||||
## The range bounds must fit in an int32.
|
||||
let maxExclusive = inclRange.b + 1 - inclRange.a
|
||||
result = T(rng.random_unsafe(uint32 maxExclusive))
|
||||
result += inclRange.a
|
||||
|
||||
# Containers
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func sample_unsafe*[T](rng: var RngState, src: openarray[T]): T =
|
||||
## Return a random sample from an array
|
||||
result = src[rng.random_unsafe(uint32 src.len)]
|
||||
|
||||
# BigInts and Fields
|
||||
# ------------------------------------------------------------
|
||||
#
|
||||
# Statistics note:
|
||||
# - A skewed distribution is not symmetric, it has a longer tail in one direction.
|
||||
# for example a RNG that is not centered over 0.5 distribution of 0 and 1 but
|
||||
# might produces more 1 than 0 or vice-versa.
|
||||
# - A bias is a result that is consistently off from the true value i.e.
|
||||
# a deviation of an estimate from the quantity under observation
|
||||
|
||||
func random_unsafe(rng: var RngState, a: var BigInt) =
|
||||
## Initialize a standalone BigInt
|
||||
for i in 0 ..< a.limbs.len:
|
||||
a.limbs[i] = SecretWord(rng.next())
|
||||
|
||||
func random_unsafe[T](rng: var RngState, a: var T, C: static Curve) =
|
||||
## Recursively initialize a BigInt (part of a field) or Field element
|
||||
## Unsafe: for testing and benchmarking purposes only
|
||||
when T is BigInt:
|
||||
var reduced, unreduced{.noInit.}: T
|
||||
|
||||
for i in 0 ..< unreduced.limbs.len:
|
||||
unreduced.limbs[i] = SecretWord(rng.next())
|
||||
rng.random_unsafe(unreduced)
|
||||
|
||||
# Note: a simple modulo will be biaised but it's simple and "fast"
|
||||
reduced.reduce(unreduced, C.Mod)
|
||||
|
@ -99,10 +149,79 @@ func random_unsafe[T](rng: var RngState, a: var T, C: static Curve) =
|
|||
for field in fields(a):
|
||||
rng.random_unsafe(field, C)
|
||||
|
||||
func random_unsafe(rng: var RngState, a: var BigInt) =
|
||||
func random_word_highHammingWeight(rng: var RngState): BaseType =
|
||||
let numZeros = rng.random_unsafe(WordBitWidth div 3) # Average Hamming Weight is 1-0.33/2 = 0.83
|
||||
result = high(BaseType)
|
||||
for _ in 0 ..< numZeros:
|
||||
result = result.clearBit rng.random_unsafe(WordBitWidth)
|
||||
|
||||
func random_highHammingWeight(rng: var RngState, a: var BigInt) =
|
||||
## Initialize a standalone BigInt
|
||||
## with high Hamming weight
|
||||
## to have a higher probability of triggering carries
|
||||
for i in 0 ..< a.limbs.len:
|
||||
a.limbs[i] = SecretWord(rng.next())
|
||||
a.limbs[i] = SecretWord rng.random_word_highHammingWeight()
|
||||
|
||||
func random_highHammingWeight[T](rng: var RngState, a: var T, C: static Curve) =
|
||||
## Recursively initialize a BigInt (part of a field) or Field element
|
||||
## Unsafe: for testing and benchmarking purposes only
|
||||
## The result will have a high Hamming Weight
|
||||
## to have a higher probability of triggering carries
|
||||
when T is BigInt:
|
||||
var reduced, unreduced{.noInit.}: T
|
||||
rng.random_highHammingWeight(unreduced)
|
||||
|
||||
# Note: a simple modulo will be biaised but it's simple and "fast"
|
||||
reduced.reduce(unreduced, C.Mod)
|
||||
a.montyResidue(reduced, C.Mod, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
|
||||
|
||||
else:
|
||||
for field in fields(a):
|
||||
rng.random_highHammingWeight(field, C)
|
||||
|
||||
func random_long01Seq(rng: var RngState, a: var openArray[byte]) =
|
||||
## Initialize a bytearray
|
||||
## It is skewed towards producing strings of 1111... and 0000
|
||||
## to trigger edge cases
|
||||
# See libsecp256k1: https://github.com/bitcoin-core/secp256k1/blob/dbd41db1/src/testrand_impl.h#L90-L104
|
||||
let Bits = a.len * 8
|
||||
var bit = 0
|
||||
zeroMem(a[0].addr, a.len)
|
||||
while bit < Bits :
|
||||
var now = 1 + (rng.random_unsafe(1 shl 6) * rng.random_unsafe(1 shl 5) + 16) div 31
|
||||
let val = rng.sample_unsafe([0, 1])
|
||||
while now > 0 and bit < Bits:
|
||||
a[bit shr 3] = a[bit shr 3] or byte(val shl (bit and 7))
|
||||
dec now
|
||||
inc bit
|
||||
|
||||
func random_long01Seq(rng: var RngState, a: var BigInt) =
|
||||
## Initialize a bigint
|
||||
## It is skewed towards producing strings of 1111... and 0000
|
||||
## to trigger edge cases
|
||||
var buf: array[(a.bits + 7) div 8, byte]
|
||||
rng.random_long01Seq(buf)
|
||||
let order = rng.sample_unsafe([bigEndian, littleEndian])
|
||||
if order == bigEndian:
|
||||
a.fromRawUint(buf, bigEndian)
|
||||
else:
|
||||
a.fromRawUint(buf, littleEndian)
|
||||
|
||||
func random_long01Seq[T](rng: var RngState, a: var T, C: static Curve) =
|
||||
## Recursively initialize a BigInt (part of a field) or Field element
|
||||
## It is skewed towards producing strings of 1111... and 0000
|
||||
## to trigger edge cases
|
||||
when T is BigInt:
|
||||
var reduced, unreduced{.noInit.}: T
|
||||
rng.random_long01Seq(unreduced)
|
||||
|
||||
# Note: a simple modulo will be biaised but it's simple and "fast"
|
||||
reduced.reduce(unreduced, C.Mod)
|
||||
a.montyResidue(reduced, C.Mod, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
|
||||
|
||||
else:
|
||||
for field in fields(a):
|
||||
rng.random_highHammingWeight(field, C)
|
||||
|
||||
# Elliptic curves
|
||||
# ------------------------------------------------------------
|
||||
|
@ -132,44 +251,65 @@ func random_unsafe_with_randZ[F](rng: var RngState, a: var ECP_SWei_Proj[F]) =
|
|||
rng.random_unsafe(fieldElem, F.C)
|
||||
success = trySetFromCoordsXandZ(a, fieldElem, Z)
|
||||
|
||||
# Integer ranges
|
||||
func random_highHammingWeight[F](rng: var RngState, a: var ECP_SWei_Proj[F]) =
|
||||
## Initialize a random curve point with Z coordinate == 1
|
||||
## This will be generated with a biaised RNG with high Hamming Weight
|
||||
## to trigger carry bugs
|
||||
var fieldElem {.noInit.}: F
|
||||
var success = CtFalse
|
||||
|
||||
while not bool(success):
|
||||
# Euler's criterion: there are (p-1)/2 squares in a field with modulus `p`
|
||||
# so we have a probability of ~0.5 to get a good point
|
||||
rng.random_highHammingWeight(fieldElem, F.C)
|
||||
success = trySetFromCoordX(a, fieldElem)
|
||||
|
||||
func random_highHammingWeight_with_randZ[F](rng: var RngState, a: var ECP_SWei_Proj[F]) =
|
||||
## Initialize a random curve point with Z coordinate == 1
|
||||
## This will be generated with a biaised RNG with high Hamming Weight
|
||||
## to trigger carry bugs
|
||||
var Z{.noInit.}: F
|
||||
rng.random_highHammingWeight(Z, F.C) # If Z is zero, X will be zero and that will be an infinity point
|
||||
|
||||
var fieldElem {.noInit.}: F
|
||||
var success = CtFalse
|
||||
|
||||
while not bool(success):
|
||||
rng.random_highHammingWeight(fieldElem, F.C)
|
||||
success = trySetFromCoordsXandZ(a, fieldElem, Z)
|
||||
|
||||
func random_long01Seq[F](rng: var RngState, a: var ECP_SWei_Proj[F]) =
|
||||
## Initialize a random curve point with Z coordinate == 1
|
||||
## This will be generated with a biaised RNG
|
||||
## that produces long bitstrings of 0 and 1
|
||||
## to trigger edge cases
|
||||
var fieldElem {.noInit.}: F
|
||||
var success = CtFalse
|
||||
|
||||
while not bool(success):
|
||||
# Euler's criterion: there are (p-1)/2 squares in a field with modulus `p`
|
||||
# so we have a probability of ~0.5 to get a good point
|
||||
rng.random_long01Seq(fieldElem, F.C)
|
||||
success = trySetFromCoordX(a, fieldElem)
|
||||
|
||||
func random_long01Seq_with_randZ[F](rng: var RngState, a: var ECP_SWei_Proj[F]) =
|
||||
## Initialize a random curve point with Z coordinate == 1
|
||||
## This will be generated with a biaised RNG
|
||||
## that produces long bitstrings of 0 and 1
|
||||
## to trigger edge cases
|
||||
var Z{.noInit.}: F
|
||||
rng.random_long01Seq(Z, F.C) # If Z is zero, X will be zero and that will be an infinity point
|
||||
|
||||
var fieldElem {.noInit.}: F
|
||||
var success = CtFalse
|
||||
|
||||
while not bool(success):
|
||||
rng.random_long01Seq(fieldElem, F.C)
|
||||
success = trySetFromCoordsXandZ(a, fieldElem, Z)
|
||||
|
||||
# Generic over any Constantine type
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func random_unsafe*(rng: var RngState, maxExclusive: uint32): uint32 =
|
||||
## Generate a random integer in 0 ..< maxExclusive
|
||||
## Uses an unbiaised generation method
|
||||
## See Lemire's algorithm modified by Melissa O'Neill
|
||||
## https://www.pcg-random.org/posts/bounded-rands.html
|
||||
let max = maxExclusive
|
||||
var x = uint32 rng.next()
|
||||
var m = x.uint64 * max.uint64
|
||||
var l = uint32 m
|
||||
if l < max:
|
||||
var t = not(max) + 1 # -max
|
||||
if t >= max:
|
||||
t -= max
|
||||
if t >= max:
|
||||
t = t mod max
|
||||
while l < t:
|
||||
x = uint32 rng.next()
|
||||
m = x.uint64 * max.uint64
|
||||
l = uint32 m
|
||||
return uint32(m shr 32)
|
||||
|
||||
# Generic over any supported type
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func sample_unsafe*[T](rng: var RngState, src: openarray[T]): T =
|
||||
## Return a random sample from an array
|
||||
result = src[rng.random_unsafe(uint32 src.len)]
|
||||
|
||||
func random_unsafe*[T: SomeInteger](rng: var RngState, inclRange: Slice[T]): T =
|
||||
## Return a random integer in the given range.
|
||||
## The range bounds must fit in an int32.
|
||||
let maxExclusive = inclRange.b + 1 - inclRange.a
|
||||
result = T(rng.random_unsafe(uint32 maxExclusive))
|
||||
result += inclRange.a
|
||||
|
||||
func random_unsafe*(rng: var RngState, T: typedesc): T =
|
||||
## Create a random Field or Extension Field or Curve Element
|
||||
## Unsafe: for testing and benchmarking purposes only
|
||||
|
@ -187,11 +327,45 @@ func random_unsafe_with_randZ*(rng: var RngState, T: typedesc[ECP_SWei_Proj]): T
|
|||
## Unsafe: for testing and benchmarking purposes only
|
||||
rng.random_unsafe_with_randZ(result)
|
||||
|
||||
func random_highHammingWeight*(rng: var RngState, T: typedesc): T =
|
||||
## Create a random Field or Extension Field or Curve Element
|
||||
## Skewed towards high Hamming Weight
|
||||
when T is ECP_SWei_Proj:
|
||||
rng.random_highHammingWeight(result)
|
||||
elif T is SomeNumber:
|
||||
cast[T](rng.next()) # TODO: Rely on casting integer actually converting in C (i.e. uint64->uint32 is valid)
|
||||
elif T is BigInt:
|
||||
rng.random_highHammingWeight(result)
|
||||
else: # Fields
|
||||
rng.random_highHammingWeight(result, T.C)
|
||||
|
||||
func random_highHammingWeight_with_randZ*(rng: var RngState, T: typedesc[ECP_SWei_Proj]): T =
|
||||
## Create a random curve element with a random Z coordinate
|
||||
## Skewed towards high Hamming Weight
|
||||
rng.random_highHammingWeight_with_randZ(result)
|
||||
|
||||
func random_long01Seq*(rng: var RngState, T: typedesc): T =
|
||||
## Create a random Field or Extension Field or Curve Element
|
||||
## Skewed towards long bitstrings of 0 or 1
|
||||
when T is ECP_SWei_Proj:
|
||||
rng.random_long01Seq(result)
|
||||
elif T is SomeNumber:
|
||||
cast[T](rng.next()) # TODO: Rely on casting integer actually converting in C (i.e. uint64->uint32 is valid)
|
||||
elif T is BigInt:
|
||||
rng.random_long01Seq(result)
|
||||
else: # Fields
|
||||
rng.random_long01Seq(result, T.C)
|
||||
|
||||
func random_long01Seq_with_randZ*(rng: var RngState, T: typedesc[ECP_SWei_Proj]): T =
|
||||
## Create a random curve element with a random Z coordinate
|
||||
## Skewed towards long bitstrings of 0 or 1
|
||||
rng.random_long01Seq_with_randZ(result)
|
||||
|
||||
# Sanity checks
|
||||
# ------------------------------------------------------------
|
||||
|
||||
when isMainModule:
|
||||
import std/[tables, times]
|
||||
import std/[tables, times, strutils]
|
||||
|
||||
var rng: RngState
|
||||
let timeSeed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
|
@ -211,3 +385,22 @@ when isMainModule:
|
|||
test(0..2)
|
||||
test(1..52)
|
||||
test(-10..10)
|
||||
|
||||
echo "\n-----------------------------\n"
|
||||
echo "High Hamming Weight check"
|
||||
for _ in 0 ..< 10:
|
||||
let word = rng.random_word_highHammingWeight()
|
||||
echo "0b", cast[BiggestInt](word).toBin(WordBitWidth), " - 0x", word.toHex()
|
||||
|
||||
echo "\n-----------------------------\n"
|
||||
echo "Long strings of 0 or 1 check"
|
||||
for _ in 0 ..< 10:
|
||||
var a: BigInt[127]
|
||||
rng.random_long01seq(a)
|
||||
stdout.write "0b"
|
||||
for word in a.limbs:
|
||||
stdout.write cast[BiggestInt](word).toBin(WordBitWidth)
|
||||
stdout.write " - 0x"
|
||||
for word in a.limbs:
|
||||
stdout.write word.BaseType.toHex()
|
||||
stdout.write '\n'
|
||||
|
|
|
@ -25,6 +25,28 @@ import
|
|||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult
|
||||
|
||||
type
|
||||
RandomGen = enum
|
||||
Uniform
|
||||
HighHammingWeight
|
||||
Long01Sequence
|
||||
|
||||
func random_point(rng: var RngState, F: typedesc, randZ: static bool, gen: static RandomGen): F {.inline, noInit.} =
|
||||
when not randZ:
|
||||
when gen == Uniform:
|
||||
result = rng.random_unsafe(F)
|
||||
elif gen == HighHammingWeight:
|
||||
result = rng.random_highHammingWeight(F)
|
||||
else:
|
||||
result = rng.random_long01Seq(F)
|
||||
else:
|
||||
when gen == Uniform:
|
||||
result = rng.random_unsafe_with_randZ(F)
|
||||
elif gen == HighHammingWeight:
|
||||
result = rng.random_highHammingWeight_with_randZ(F)
|
||||
else:
|
||||
result = rng.random_long01Seq_with_randZ(F)
|
||||
|
||||
proc run_EC_addition_tests*(
|
||||
ec: typedesc,
|
||||
Iters: static int,
|
||||
|
@ -47,17 +69,14 @@ proc run_EC_addition_tests*(
|
|||
|
||||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitwidth & "-bit mode]":
|
||||
test "The infinity point is the neutral element w.r.t. to EC " & G1_or_G2 & " addition":
|
||||
proc test(EC: typedesc, randZ: static bool) =
|
||||
proc test(EC: typedesc, randZ: static bool, gen: static RandomGen) =
|
||||
var inf {.noInit.}: EC
|
||||
inf.setInf()
|
||||
check: bool inf.isInf()
|
||||
|
||||
for _ in 0 ..< Iters:
|
||||
var r{.noInit.}: EC
|
||||
when randZ:
|
||||
let P = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let P = rng.random_unsafe(EC)
|
||||
let P = rng.random_point(EC, randZ, gen)
|
||||
|
||||
r.sum(P, inf)
|
||||
check: bool(r == P)
|
||||
|
@ -65,17 +84,18 @@ proc run_EC_addition_tests*(
|
|||
r.sum(inf, P)
|
||||
check: bool(r == P)
|
||||
|
||||
test(ec, randZ = false)
|
||||
test(ec, randZ = true)
|
||||
test(ec, randZ = false, gen = Uniform)
|
||||
test(ec, randZ = true, gen = Uniform)
|
||||
test(ec, randZ = false, gen = HighHammingWeight)
|
||||
test(ec, randZ = true, gen = HighHammingWeight)
|
||||
test(ec, randZ = false, gen = Long01Sequence)
|
||||
test(ec, randZ = true, gen = Long01Sequence)
|
||||
|
||||
test "Adding opposites gives an infinity point":
|
||||
proc test(EC: typedesc, randZ: static bool) =
|
||||
proc test(EC: typedesc, randZ: static bool, gen: static RandomGen) =
|
||||
for _ in 0 ..< Iters:
|
||||
var r{.noInit.}: EC
|
||||
when randZ:
|
||||
let P = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let P = rng.random_unsafe(EC)
|
||||
let P = rng.random_point(EC, randZ, gen)
|
||||
var Q = P
|
||||
Q.neg()
|
||||
|
||||
|
@ -85,38 +105,37 @@ proc run_EC_addition_tests*(
|
|||
r.sum(Q, P)
|
||||
check: bool r.isInf()
|
||||
|
||||
test(ec, randZ = false)
|
||||
test(ec, randZ = true)
|
||||
test(ec, randZ = false, gen = Uniform)
|
||||
test(ec, randZ = true, gen = Uniform)
|
||||
test(ec, randZ = false, gen = HighHammingWeight)
|
||||
test(ec, randZ = true, gen = HighHammingWeight)
|
||||
test(ec, randZ = false, gen = Long01Sequence)
|
||||
test(ec, randZ = true, gen = Long01Sequence)
|
||||
|
||||
test "EC " & G1_or_G2 & " add is commutative":
|
||||
proc test(EC: typedesc, randZ: static bool) =
|
||||
proc test(EC: typedesc, randZ: static bool, gen: static RandomGen) =
|
||||
for _ in 0 ..< Iters:
|
||||
var r0{.noInit.}, r1{.noInit.}: EC
|
||||
when randZ:
|
||||
let P = rng.random_unsafe_with_randZ(EC)
|
||||
let Q = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let P = rng.random_unsafe(EC)
|
||||
let Q = rng.random_unsafe(EC)
|
||||
let P = rng.random_point(EC, randZ, gen)
|
||||
let Q = rng.random_point(EC, randZ, gen)
|
||||
|
||||
r0.sum(P, Q)
|
||||
r1.sum(Q, P)
|
||||
check: bool(r0 == r1)
|
||||
|
||||
test(ec, randZ = false)
|
||||
test(ec, randZ = true)
|
||||
test(ec, randZ = false, gen = Uniform)
|
||||
test(ec, randZ = true, gen = Uniform)
|
||||
test(ec, randZ = false, gen = HighHammingWeight)
|
||||
test(ec, randZ = true, gen = HighHammingWeight)
|
||||
test(ec, randZ = false, gen = Long01Sequence)
|
||||
test(ec, randZ = true, gen = Long01Sequence)
|
||||
|
||||
test "EC " & G1_or_G2 & " add is associative":
|
||||
proc test(EC: typedesc, randZ: static bool) =
|
||||
proc test(EC: typedesc, randZ: static bool, gen: static RandomGen) =
|
||||
for _ in 0 ..< Iters:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
let b = rng.random_unsafe_with_randZ(EC)
|
||||
let c = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
let b = rng.random_unsafe(EC)
|
||||
let c = rng.random_unsafe(EC)
|
||||
let a = rng.random_point(EC, randZ, gen)
|
||||
let b = rng.random_point(EC, randZ, gen)
|
||||
let c = rng.random_point(EC, randZ, gen)
|
||||
|
||||
var tmp1{.noInit.}, tmp2{.noInit.}: EC
|
||||
|
||||
|
@ -153,16 +172,17 @@ proc run_EC_addition_tests*(
|
|||
bool(r0 == r3)
|
||||
bool(r0 == r4)
|
||||
|
||||
test(ec, randZ = false)
|
||||
test(ec, randZ = true)
|
||||
test(ec, randZ = false, gen = Uniform)
|
||||
test(ec, randZ = true, gen = Uniform)
|
||||
test(ec, randZ = false, gen = HighHammingWeight)
|
||||
test(ec, randZ = true, gen = HighHammingWeight)
|
||||
test(ec, randZ = false, gen = Long01Sequence)
|
||||
test(ec, randZ = true, gen = Long01Sequence)
|
||||
|
||||
test "EC " & G1_or_G2 & " double and EC " & G1_or_G2 & " add are consistent":
|
||||
proc test(EC: typedesc, randZ: static bool) =
|
||||
proc test(EC: typedesc, randZ: static bool, gen: static RandomGen) =
|
||||
for _ in 0 ..< Iters:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
let a = rng.random_point(EC, randZ, gen)
|
||||
|
||||
var r0{.noInit.}, r1{.noInit.}: EC
|
||||
|
||||
|
@ -171,8 +191,12 @@ proc run_EC_addition_tests*(
|
|||
|
||||
check: bool(r0 == r1)
|
||||
|
||||
test(ec, randZ = false)
|
||||
test(ec, randZ = true)
|
||||
test(ec, randZ = false, gen = Uniform)
|
||||
test(ec, randZ = true, gen = Uniform)
|
||||
test(ec, randZ = false, gen = HighHammingWeight)
|
||||
test(ec, randZ = true, gen = HighHammingWeight)
|
||||
test(ec, randZ = false, gen = Long01Sequence)
|
||||
test(ec, randZ = true, gen = Long01Sequence)
|
||||
|
||||
proc run_EC_mul_sanity_tests*(
|
||||
ec: typedesc,
|
||||
|
@ -196,12 +220,9 @@ proc run_EC_mul_sanity_tests*(
|
|||
|
||||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitwidth & "-bit mode]":
|
||||
test "EC " & G1_or_G2 & " mul [0]P == Inf":
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool, gen: static RandomGen) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
let a = rng.random_point(EC, randZ, gen)
|
||||
|
||||
# zeroInit
|
||||
var exponentCanonical: array[(bits+7) div 8, byte]
|
||||
|
@ -218,16 +239,17 @@ proc run_EC_mul_sanity_tests*(
|
|||
bool(impl.isInf())
|
||||
bool(reference.isInf())
|
||||
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Uniform)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Uniform)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = HighHammingWeight)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = HighHammingWeight)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Long01Sequence)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Long01Sequence)
|
||||
|
||||
test "EC " & G1_or_G2 & " mul [1]P == P":
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool, gen: static RandomGen) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
let a = rng.random_point(EC, randZ, gen)
|
||||
|
||||
var exponent{.noInit.}: BigInt[bits]
|
||||
exponent.setOne()
|
||||
|
@ -246,16 +268,17 @@ proc run_EC_mul_sanity_tests*(
|
|||
bool(impl == a)
|
||||
bool(reference == a)
|
||||
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Uniform)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Uniform)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = HighHammingWeight)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = HighHammingWeight)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Long01Sequence)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Long01Sequence)
|
||||
|
||||
test "EC " & G1_or_G2 & " mul [2]P == P.double()":
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool, gen: static RandomGen) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
let a = rng.random_point(EC, randZ, gen)
|
||||
|
||||
var doubleA{.noInit.}: EC
|
||||
doubleA.double(a)
|
||||
|
@ -276,8 +299,12 @@ proc run_EC_mul_sanity_tests*(
|
|||
bool(impl == doubleA)
|
||||
bool(reference == doubleA)
|
||||
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Uniform)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Uniform)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = HighHammingWeight)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = HighHammingWeight)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Long01Sequence)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Long01Sequence)
|
||||
|
||||
proc run_EC_mul_distributive_tests*(
|
||||
ec: typedesc,
|
||||
|
@ -302,14 +329,10 @@ proc run_EC_mul_distributive_tests*(
|
|||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitwidth & "-bit mode]":
|
||||
|
||||
test "EC " & G1_or_G2 & " mul is distributive over EC add":
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool, gen: static RandomGen) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
let b = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
let b = rng.random_unsafe_with_randZ(EC)
|
||||
let a = rng.random_point(EC, randZ, gen)
|
||||
let b = rng.random_point(EC, randZ, gen)
|
||||
|
||||
let exponent = rng.random_unsafe(BigInt[bits])
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
|
@ -349,8 +372,12 @@ proc run_EC_mul_distributive_tests*(
|
|||
bool(fReference == kakbRef)
|
||||
bool(fImpl == fReference)
|
||||
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Uniform)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Uniform)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = HighHammingWeight)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = HighHammingWeight)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Long01Sequence)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Long01Sequence)
|
||||
|
||||
proc run_EC_mul_vs_ref_impl*(
|
||||
ec: typedesc,
|
||||
|
@ -374,12 +401,9 @@ proc run_EC_mul_vs_ref_impl*(
|
|||
|
||||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitwidth & "-bit mode]":
|
||||
test "EC " & G1_or_G2 & " mul constant-time is equivalent to a simple double-and-add algorithm":
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool, gen: static RandomGen) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
let a = rng.random_point(EC, randZ, gen)
|
||||
|
||||
let exponent = rng.random_unsafe(BigInt[bits])
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
|
@ -395,5 +419,9 @@ proc run_EC_mul_vs_ref_impl*(
|
|||
|
||||
check: bool(impl == reference)
|
||||
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Uniform)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Uniform)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = HighHammingWeight)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = HighHammingWeight)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Long01Sequence)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Long01Sequence)
|
||||
|
|
|
@ -115,15 +115,47 @@ proc randomCurve(C: static Curve) =
|
|||
|
||||
doAssert bool(r_mul == r_sqr)
|
||||
|
||||
proc randomHighHammingWeight(C: static Curve) =
|
||||
let a = rng.random_highHammingWeight(Fp[C])
|
||||
|
||||
var r_mul, r_sqr: Fp[C]
|
||||
|
||||
r_mul.prod(a, a)
|
||||
r_sqr.square(a)
|
||||
|
||||
doAssert bool(r_mul == r_sqr)
|
||||
|
||||
proc random_long01Seq(C: static Curve) =
|
||||
let a = rng.random_long01Seq(Fp[C])
|
||||
|
||||
var r_mul, r_sqr: Fp[C]
|
||||
|
||||
r_mul.prod(a, a)
|
||||
r_sqr.square(a)
|
||||
|
||||
doAssert bool(r_mul == r_sqr)
|
||||
|
||||
suite "Random Modular Squaring is consistent with Modular Multiplication" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Random squaring mod P-224 [FastSquaring = " & $P224.canUseNoCarryMontySquare & "]":
|
||||
for _ in 0 ..< Iters:
|
||||
randomCurve(P224)
|
||||
for _ in 0 ..< Iters:
|
||||
randomHighHammingWeight(P224)
|
||||
for _ in 0 ..< Iters:
|
||||
random_long01Seq(P224)
|
||||
|
||||
test "Random squaring mod P-256 [FastSquaring = " & $P256.canUseNoCarryMontySquare & "]":
|
||||
for _ in 0 ..< Iters:
|
||||
randomCurve(P256)
|
||||
for _ in 0 ..< Iters:
|
||||
randomHighHammingWeight(P256)
|
||||
for _ in 0 ..< Iters:
|
||||
random_long01Seq(P256)
|
||||
|
||||
test "Random squaring mod BLS12_381 [FastSquaring = " & $BLS12_381.canUseNoCarryMontySquare & "]":
|
||||
for _ in 0 ..< Iters:
|
||||
randomCurve(BLS12_381)
|
||||
for _ in 0 ..< Iters:
|
||||
randomHighHammingWeight(BLS12_381)
|
||||
for _ in 0 ..< Iters:
|
||||
random_long01Seq(BLS12_381)
|
||||
|
|
|
@ -170,6 +170,26 @@ proc main() =
|
|||
a2.double()
|
||||
check: bool(a == a2)
|
||||
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.randomHighHammingWeight(Fp[curve])
|
||||
var a2 = a
|
||||
a2.double()
|
||||
a2.div2()
|
||||
check: bool(a == a2)
|
||||
a2.div2()
|
||||
a2.double()
|
||||
check: bool(a == a2)
|
||||
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_long01Seq(Fp[curve])
|
||||
var a2 = a
|
||||
a2.double()
|
||||
a2.div2()
|
||||
check: bool(a == a2)
|
||||
a2.div2()
|
||||
a2.double()
|
||||
check: bool(a == a2)
|
||||
|
||||
testRandomDiv2 P224
|
||||
testRandomDiv2 BN254_Nogami
|
||||
testRandomDiv2 BN254_Snarks
|
||||
|
@ -245,6 +265,22 @@ proc main() =
|
|||
r.prod(aInv, a)
|
||||
check: bool r.isOne()
|
||||
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.randomHighHammingWeight(Fp[curve])
|
||||
aInv.inv(a)
|
||||
r.prod(a, aInv)
|
||||
check: bool r.isOne()
|
||||
r.prod(aInv, a)
|
||||
check: bool r.isOne()
|
||||
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_long01Seq(Fp[curve])
|
||||
aInv.inv(a)
|
||||
r.prod(a, aInv)
|
||||
check: bool r.isOne()
|
||||
r.prod(aInv, a)
|
||||
check: bool r.isOne()
|
||||
|
||||
testRandomInv P224
|
||||
testRandomInv BN254_Nogami
|
||||
testRandomInv BN254_Snarks
|
||||
|
|
|
@ -83,27 +83,38 @@ proc exhaustiveCheck_p3mod4(C: static Curve, modulus: static int) =
|
|||
bool (a == a2) # a shouldn't be modified
|
||||
|
||||
proc randomSqrtCheck_p3mod4(C: static Curve) =
|
||||
template testImpl(a: untyped): untyped {.dirty.} =
|
||||
var na{.noInit.}: Fp[C]
|
||||
na.neg(a)
|
||||
|
||||
var a2 = a
|
||||
var na2 = na
|
||||
a2.square()
|
||||
na2.square()
|
||||
check:
|
||||
bool a2 == na2
|
||||
bool a2.isSquare()
|
||||
|
||||
var r, s = a2
|
||||
r.sqrt()
|
||||
let ok = s.sqrt_if_square()
|
||||
check:
|
||||
bool ok
|
||||
bool(r == s)
|
||||
bool(r == a or r == na)
|
||||
|
||||
test "Random square root check for p ≡ 3 (mod 4) on " & $Curve(C):
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_unsafe(Fp[C])
|
||||
var na{.noInit.}: Fp[C]
|
||||
na.neg(a)
|
||||
testImpl(a)
|
||||
|
||||
var a2 = a
|
||||
var na2 = na
|
||||
a2.square()
|
||||
na2.square()
|
||||
check:
|
||||
bool a2 == na2
|
||||
bool a2.isSquare()
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.randomHighHammingWeight(Fp[C])
|
||||
testImpl(a)
|
||||
|
||||
var r, s = a2
|
||||
r.sqrt()
|
||||
let ok = s.sqrt_if_square()
|
||||
check:
|
||||
bool ok
|
||||
bool(r == s)
|
||||
bool(r == a or r == na)
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_long01Seq(Fp[C])
|
||||
testImpl(a)
|
||||
|
||||
proc main() =
|
||||
suite "Modular square root" & " [" & $WordBitwidth & "-bit mode]":
|
||||
|
|
|
@ -35,6 +35,20 @@ template ExtField(degree: static int, curve: static Curve): untyped =
|
|||
else:
|
||||
{.error: "Unconfigured extension degree".}
|
||||
|
||||
type
|
||||
RandomGen = enum
|
||||
Uniform
|
||||
HighHammingWeight
|
||||
Long01Sequence
|
||||
|
||||
func random_elem(rng: var RngState, F: typedesc, gen: static RandomGen): F {.inline, noInit.} =
|
||||
when gen == Uniform:
|
||||
result = rng.random_unsafe(F)
|
||||
elif gen == HighHammingWeight:
|
||||
result = rng.random_highHammingWeight(F)
|
||||
else:
|
||||
result = rng.random_long01Seq(F)
|
||||
|
||||
proc runTowerTests*[N](
|
||||
ExtDegree: static int,
|
||||
Iters: static int,
|
||||
|
@ -63,19 +77,19 @@ proc runTowerTests*[N](
|
|||
test(ExtField(ExtDegree, curve))
|
||||
|
||||
test "Addition, substraction negation are consistent":
|
||||
proc test(Field: typedesc, Iters: static int) =
|
||||
proc test(Field: typedesc, Iters: static int, gen: static RandomGen) =
|
||||
# Try to exercise all code paths for in-place/out-of-place add/sum/sub/diff/double/neg
|
||||
# (1 - (-a) - b + (-a) - 2a) + (2a + 2b + (-b)) == 1
|
||||
var accum {.noInit.}, One {.noInit.}, a{.noInit.}, na{.noInit.}, b{.noInit.}, nb{.noInit.}, a2 {.noInit.}, b2 {.noInit.}: Field
|
||||
|
||||
for _ in 0 ..< Iters:
|
||||
One.setOne()
|
||||
a = rng.random_unsafe(Field)
|
||||
a = rng.random_elem(Field, gen)
|
||||
a2 = a
|
||||
a2.double()
|
||||
na.neg(a)
|
||||
|
||||
b = rng.random_unsafe(Field)
|
||||
b = rng.random_elem(Field, gen)
|
||||
b2.double(b)
|
||||
nb.neg(b)
|
||||
|
||||
|
@ -92,12 +106,14 @@ proc runTowerTests*[N](
|
|||
check: bool accum.isOne()
|
||||
|
||||
staticFor(curve, TestCurves):
|
||||
test(ExtField(ExtDegree, curve), Iters)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Uniform)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence)
|
||||
|
||||
test "Division by 2":
|
||||
proc test(Field: typedesc, Iters: static int) =
|
||||
proc test(Field: typedesc, Iters: static int, gen: static RandomGen) =
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_unsafe(Field)
|
||||
let a = rng.random_elem(Field, gen)
|
||||
var a2 = a
|
||||
a2.double()
|
||||
a2.div2()
|
||||
|
@ -107,7 +123,9 @@ proc runTowerTests*[N](
|
|||
check: bool(a == a2)
|
||||
|
||||
staticFor(curve, TestCurves):
|
||||
test(ExtField(ExtDegree, curve), Iters)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Uniform)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence)
|
||||
|
||||
test "Squaring 1 returns 1":
|
||||
proc test(Field: typedesc) =
|
||||
|
@ -247,9 +265,9 @@ proc runTowerTests*[N](
|
|||
check: bool(r == x)
|
||||
|
||||
test "Multiplication and Squaring are consistent":
|
||||
proc test(Field: typedesc, Iters: static int) =
|
||||
proc test(Field: typedesc, Iters: static int, gen: static RandomGen) =
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_unsafe(Field)
|
||||
let a = rng.random_elem(Field, gen)
|
||||
var rMul{.noInit.}, rSqr{.noInit.}: Field
|
||||
|
||||
rMul.prod(a, a)
|
||||
|
@ -258,12 +276,14 @@ proc runTowerTests*[N](
|
|||
check: bool(rMul == rSqr)
|
||||
|
||||
staticFor(curve, TestCurves):
|
||||
test(ExtField(ExtDegree, curve), Iters)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Uniform)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence)
|
||||
|
||||
test "Squaring the opposite gives the same result":
|
||||
proc test(Field: typedesc, Iters: static int) =
|
||||
proc test(Field: typedesc, Iters: static int, gen: static RandomGen) =
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_unsafe(Field)
|
||||
let a = rng.random_elem(Field, gen)
|
||||
var na{.noInit.}: Field
|
||||
na.neg(a)
|
||||
|
||||
|
@ -275,14 +295,16 @@ proc runTowerTests*[N](
|
|||
check: bool(rSqr == rNegSqr)
|
||||
|
||||
staticFor(curve, TestCurves):
|
||||
test(ExtField(ExtDegree, curve), Iters)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Uniform)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence)
|
||||
|
||||
test "Multiplication and Addition/Substraction are consistent":
|
||||
proc test(Field: typedesc, Iters: static int) =
|
||||
proc test(Field: typedesc, Iters: static int, gen: static RandomGen) =
|
||||
for _ in 0 ..< Iters:
|
||||
let factor = rng.random_unsafe(-30..30)
|
||||
|
||||
let a = rng.random_unsafe(Field)
|
||||
let a = rng.random_elem(Field, gen)
|
||||
|
||||
if factor == 0: continue
|
||||
|
||||
|
@ -309,14 +331,16 @@ proc runTowerTests*[N](
|
|||
check: bool(r == sum)
|
||||
|
||||
staticFor(curve, TestCurves):
|
||||
test(ExtField(ExtDegree, curve), Iters)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Uniform)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence)
|
||||
|
||||
test "Addition is associative and commutative":
|
||||
proc test(Field: typedesc, Iters: static int) =
|
||||
proc test(Field: typedesc, Iters: static int, gen: static RandomGen) =
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_unsafe(Field)
|
||||
let b = rng.random_unsafe(Field)
|
||||
let c = rng.random_unsafe(Field)
|
||||
let a = rng.random_elem(Field, gen)
|
||||
let b = rng.random_elem(Field, gen)
|
||||
let c = rng.random_elem(Field, gen)
|
||||
|
||||
var tmp1{.noInit.}, tmp2{.noInit.}: Field
|
||||
|
||||
|
@ -354,14 +378,16 @@ proc runTowerTests*[N](
|
|||
bool(r0 == r4)
|
||||
|
||||
staticFor(curve, TestCurves):
|
||||
test(ExtField(ExtDegree, curve), Iters)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Uniform)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence)
|
||||
|
||||
test "Multiplication is associative and commutative":
|
||||
proc test(Field: typedesc, Iters: static int) =
|
||||
proc test(Field: typedesc, Iters: static int, gen: static RandomGen) =
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_unsafe(Field)
|
||||
let b = rng.random_unsafe(Field)
|
||||
let c = rng.random_unsafe(Field)
|
||||
let a = rng.random_elem(Field, gen)
|
||||
let b = rng.random_elem(Field, gen)
|
||||
let c = rng.random_elem(Field, gen)
|
||||
|
||||
var tmp1{.noInit.}, tmp2{.noInit.}: Field
|
||||
|
||||
|
@ -399,14 +425,16 @@ proc runTowerTests*[N](
|
|||
bool(r0 == r4)
|
||||
|
||||
staticFor(curve, TestCurves):
|
||||
test(ExtField(ExtDegree, curve), Iters)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Uniform)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence)
|
||||
|
||||
test "Extension field multiplicative inverse":
|
||||
proc test(Field: typedesc, Iters: static int) =
|
||||
proc test(Field: typedesc, Iters: static int, gen: static RandomGen) =
|
||||
var aInv, r{.noInit.}: Field
|
||||
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_unsafe(Field)
|
||||
let a = rng.random_elem(Field, gen)
|
||||
aInv.inv(a)
|
||||
r.prod(a, aInv)
|
||||
check: bool(r.isOne())
|
||||
|
@ -414,7 +442,9 @@ proc runTowerTests*[N](
|
|||
check: bool(r.isOne())
|
||||
|
||||
staticFor(curve, TestCurves):
|
||||
test(ExtField(ExtDegree, curve), Iters)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Uniform)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight)
|
||||
test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence)
|
||||
|
||||
test "0 does not have a multiplicative inverse and should return 0 for projective/jacobian => affine coordinates conversion":
|
||||
proc test(Field: typedesc) =
|
||||
|
|
Loading…
Reference in New Issue