You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1874 lines
40 KiB

// Copyright 2020 ConsenSys Software Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Code generated by consensys/gnark-crypto DO NOT EDIT
package ff
import (
"crypto/rand"
"math/big"
"math/bits"
"testing"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/prop"
)
// -------------------------------------------------------------------------------------------------
// benchmarks
// most benchmarks are rudimentary and should sample a large number of random inputs
// or be run multiple times to ensure it didn't measure the fastest path of the function
var benchResElement Element
func BenchmarkElementSetBytes(b *testing.B) {
var x Element
x.SetRandom()
bb := x.Bytes()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.SetBytes(bb[:])
}
}
func BenchmarkElementMulByConstants(b *testing.B) {
b.Run("mulBy3", func(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
MulBy3(&benchResElement)
}
})
b.Run("mulBy5", func(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
MulBy5(&benchResElement)
}
})
b.Run("mulBy13", func(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
MulBy13(&benchResElement)
}
})
}
func BenchmarkElementInverse(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Inverse(&x)
}
}
func BenchmarkElementButterfly(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Butterfly(&x, &benchResElement)
}
}
func BenchmarkElementExp(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b1, _ := rand.Int(rand.Reader, Modulus())
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Exp(x, b1)
}
}
func BenchmarkElementDouble(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Double(&benchResElement)
}
}
func BenchmarkElementAdd(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Add(&x, &benchResElement)
}
}
func BenchmarkElementSub(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Sub(&x, &benchResElement)
}
}
func BenchmarkElementNeg(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Neg(&benchResElement)
}
}
func BenchmarkElementDiv(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Div(&x, &benchResElement)
}
}
func BenchmarkElementFromMont(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.FromMont()
}
}
func BenchmarkElementToMont(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.ToMont()
}
}
func BenchmarkElementSquare(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Square(&benchResElement)
}
}
func BenchmarkElementSqrt(b *testing.B) {
var a Element
a.SetUint64(4)
a.Neg(&a)
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Sqrt(&a)
}
}
func BenchmarkElementMul(b *testing.B) {
x := Element{
1997599621687373223,
6052339484930628067,
10108755138030829701,
150537098327114917,
}
benchResElement.SetOne()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Mul(&benchResElement, &x)
}
}
func BenchmarkElementCmp(b *testing.B) {
x := Element{
1997599621687373223,
6052339484930628067,
10108755138030829701,
150537098327114917,
}
benchResElement = x
benchResElement[0] = 0
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Cmp(&x)
}
}
func TestElementCmp(t *testing.T) {
var x, y Element
if x.Cmp(&y) != 0 {
t.Fatal("x == y")
}
one := One()
y.Sub(&y, &one)
if x.Cmp(&y) != -1 {
t.Fatal("x < y")
}
if y.Cmp(&x) != 1 {
t.Fatal("x < y")
}
x = y
if x.Cmp(&y) != 0 {
t.Fatal("x == y")
}
x.Sub(&x, &one)
if x.Cmp(&y) != -1 {
t.Fatal("x < y")
}
if y.Cmp(&x) != 1 {
t.Fatal("x < y")
}
}
func TestElementIsRandom(t *testing.T) {
for i := 0; i < 50; i++ {
var x, y Element
x.SetRandom()
y.SetRandom()
if x.Equal(&y) {
t.Fatal("2 random numbers are unlikely to be equal")
}
}
}
// -------------------------------------------------------------------------------------------------
// Gopter tests
// most of them are generated with a template
const (
nbFuzzShort = 200
nbFuzz = 1000
)
// special values to be used in tests
var staticTestValues []Element
func init() {
staticTestValues = append(staticTestValues, Element{}) // zero
staticTestValues = append(staticTestValues, One()) // one
staticTestValues = append(staticTestValues, rSquare) // r^2
var e, one Element
one.SetOne()
e.Sub(&qElement, &one)
staticTestValues = append(staticTestValues, e) // q - 1
e.Double(&one)
staticTestValues = append(staticTestValues, e) // 2
{
a := qElement
a[3]--
staticTestValues = append(staticTestValues, a)
}
{
a := qElement
a[0]--
staticTestValues = append(staticTestValues, a)
}
for i := 0; i <= 3; i++ {
staticTestValues = append(staticTestValues, Element{uint64(i)})
staticTestValues = append(staticTestValues, Element{0, uint64(i)})
}
{
a := qElement
a[3]--
a[0]++
staticTestValues = append(staticTestValues, a)
}
}
func TestElementNegZero(t *testing.T) {
var a, b Element
b.SetZero()
for a.IsZero() {
a.SetRandom()
}
a.Neg(&b)
if !a.IsZero() {
t.Fatal("neg(0) != 0")
}
}
func TestElementReduce(t *testing.T) {
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, s := range testValues {
expected := s
reduce(&s)
_reduceGeneric(&expected)
if !s.Equal(&expected) {
t.Fatal("reduce failed: asm and generic impl don't match")
}
}
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := genFull()
properties.Property("reduce should output a result smaller than modulus", prop.ForAll(
func(a Element) bool {
b := a
reduce(&a)
_reduceGeneric(&b)
return !a.biggerOrEqualModulus() && a.Equal(&b)
},
genA,
))
properties.TestingRun(t, gopter.ConsoleReporter(false))
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
supportAdx = true
}
}
func TestElementBytes(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("SetBytes(Bytes()) should stayt constant", prop.ForAll(
func(a testPairElement) bool {
var b Element
bytes := a.element.Bytes()
b.SetBytes(bytes[:])
return a.element.Equal(&b)
},
genA,
))
properties.TestingRun(t, gopter.ConsoleReporter(false))
}
func TestElementInverseExp(t *testing.T) {
// inverse must be equal to exp^-2
exp := Modulus()
exp.Sub(exp, new(big.Int).SetUint64(2))
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("inv == exp^-2", prop.ForAll(
func(a testPairElement) bool {
var b Element
b.Set(&a.element)
a.element.Inverse(&a.element)
b.Exp(b, exp)
return a.element.Equal(&b)
},
genA,
))
properties.TestingRun(t, gopter.ConsoleReporter(false))
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
supportAdx = true
}
}
func TestElementMulByConstants(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
implemented := []uint8{0, 1, 2, 3, 5, 13}
properties.Property("mulByConstant", prop.ForAll(
func(a testPairElement) bool {
for _, c := range implemented {
var constant Element
constant.SetUint64(uint64(c))
b := a.element
b.Mul(&b, &constant)
aa := a.element
mulByConstant(&aa, c)
if !aa.Equal(&b) {
return false
}
}
return true
},
genA,
))
properties.Property("MulBy3(x) == Mul(x, 3)", prop.ForAll(
func(a testPairElement) bool {
var constant Element
constant.SetUint64(3)
b := a.element
b.Mul(&b, &constant)
MulBy3(&a.element)
return a.element.Equal(&b)
},
genA,
))
properties.Property("MulBy5(x) == Mul(x, 5)", prop.ForAll(
func(a testPairElement) bool {
var constant Element
constant.SetUint64(5)
b := a.element
b.Mul(&b, &constant)
MulBy5(&a.element)
return a.element.Equal(&b)
},
genA,
))
properties.Property("MulBy13(x) == Mul(x, 13)", prop.ForAll(
func(a testPairElement) bool {
var constant Element
constant.SetUint64(13)
b := a.element
b.Mul(&b, &constant)
MulBy13(&a.element)
return a.element.Equal(&b)
},
genA,
))
properties.TestingRun(t, gopter.ConsoleReporter(false))
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
supportAdx = true
}
}
func TestElementLegendre(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("legendre should output same result than big.Int.Jacobi", prop.ForAll(
func(a testPairElement) bool {
return a.element.Legendre() == big.Jacobi(&a.bigint, Modulus())
},
genA,
))
properties.TestingRun(t, gopter.ConsoleReporter(false))
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
supportAdx = true
}
}
func TestElementButterflies(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("butterfly0 == a -b; a +b", prop.ForAll(
func(a, b testPairElement) bool {
a0, b0 := a.element, b.element
_butterflyGeneric(&a.element, &b.element)
Butterfly(&a0, &b0)
return a.element.Equal(&a0) && b.element.Equal(&b0)
},
genA,
genA,
))
properties.TestingRun(t, gopter.ConsoleReporter(false))
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
supportAdx = true
}
}
func TestElementLexicographicallyLargest(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("element.Cmp should match LexicographicallyLargest output", prop.ForAll(
func(a testPairElement) bool {
var negA Element
negA.Neg(&a.element)
cmpResult := a.element.Cmp(&negA)
lResult := a.element.LexicographicallyLargest()
if lResult && cmpResult == 1 {
return true
}
if !lResult && cmpResult != 1 {
return true
}
return false
},
genA,
))
properties.TestingRun(t, gopter.ConsoleReporter(false))
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
supportAdx = true
}
}
func TestElementAdd(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
genB := gen()
properties.Property("Add: having the receiver as operand should output the same result", prop.ForAll(
func(a, b testPairElement) bool {
var c, d Element
d.Set(&a.element)
c.Add(&a.element, &b.element)
a.element.Add(&a.element, &b.element)
b.element.Add(&d, &b.element)
return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c)
},
genA,
genB,
))
properties.Property("Add: operation result must match big.Int result", prop.ForAll(
func(a, b testPairElement) bool {
{
var c Element
c.Add(&a.element, &b.element)
var d, e big.Int
d.Add(&a.bigint, &b.bigint).Mod(&d, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
return false
}
}
// fixed elements
// a is random
// r takes special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, r := range testValues {
var d, e, rb big.Int
r.ToBigIntRegular(&rb)
var c Element
c.Add(&a.element, &r)
d.Add(&a.bigint, &rb).Mod(&d, Modulus())
// checking generic impl against asm path
var cGeneric Element
_addGeneric(&cGeneric, &a.element, &r)
if !cGeneric.Equal(&c) {
// need to give context to failing error.
return false
}
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
return false
}
}
return true
},
genA,
genB,
))
properties.Property("Add: operation result must be smaller than modulus", prop.ForAll(
func(a, b testPairElement) bool {
var c Element
c.Add(&a.element, &b.element)
return !c.biggerOrEqualModulus()
},
genA,
genB,
))
properties.Property("Add: assembly implementation must be consistent with generic one", prop.ForAll(
func(a, b testPairElement) bool {
var c, d Element
c.Add(&a.element, &b.element)
_addGeneric(&d, &a.element, &b.element)
return c.Equal(&d)
},
genA,
genB,
))
specialValueTest := func() {
// test special values against special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, a := range testValues {
var aBig big.Int
a.ToBigIntRegular(&aBig)
for _, b := range testValues {
var bBig, d, e big.Int
b.ToBigIntRegular(&bBig)
var c Element
c.Add(&a, &b)
d.Add(&aBig, &bBig).Mod(&d, Modulus())
// checking asm against generic impl
var cGeneric Element
_addGeneric(&cGeneric, &a, &b)
if !cGeneric.Equal(&c) {
t.Fatal("Add failed special test values: asm and generic impl don't match")
}
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
t.Fatal("Add failed special test values")
}
}
}
}
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
supportAdx = true
}
}
func TestElementSub(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
genB := gen()
properties.Property("Sub: having the receiver as operand should output the same result", prop.ForAll(
func(a, b testPairElement) bool {
var c, d Element
d.Set(&a.element)
c.Sub(&a.element, &b.element)
a.element.Sub(&a.element, &b.element)
b.element.Sub(&d, &b.element)
return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c)
},
genA,
genB,
))
properties.Property("Sub: operation result must match big.Int result", prop.ForAll(
func(a, b testPairElement) bool {
{
var c Element
c.Sub(&a.element, &b.element)
var d, e big.Int
d.Sub(&a.bigint, &b.bigint).Mod(&d, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
return false
}
}
// fixed elements
// a is random
// r takes special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, r := range testValues {
var d, e, rb big.Int
r.ToBigIntRegular(&rb)
var c Element
c.Sub(&a.element, &r)
d.Sub(&a.bigint, &rb).Mod(&d, Modulus())
// checking generic impl against asm path
var cGeneric Element
_subGeneric(&cGeneric, &a.element, &r)
if !cGeneric.Equal(&c) {
// need to give context to failing error.
return false
}
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
return false
}
}
return true
},
genA,
genB,
))
properties.Property("Sub: operation result must be smaller than modulus", prop.ForAll(
func(a, b testPairElement) bool {
var c Element
c.Sub(&a.element, &b.element)
return !c.biggerOrEqualModulus()
},
genA,
genB,
))
properties.Property("Sub: assembly implementation must be consistent with generic one", prop.ForAll(
func(a, b testPairElement) bool {
var c, d Element
c.Sub(&a.element, &b.element)
_subGeneric(&d, &a.element, &b.element)
return c.Equal(&d)
},
genA,
genB,
))
specialValueTest := func() {
// test special values against special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, a := range testValues {
var aBig big.Int
a.ToBigIntRegular(&aBig)
for _, b := range testValues {
var bBig, d, e big.Int
b.ToBigIntRegular(&bBig)
var c Element
c.Sub(&a, &b)
d.Sub(&aBig, &bBig).Mod(&d, Modulus())
// checking asm against generic impl
var cGeneric Element
_subGeneric(&cGeneric, &a, &b)
if !cGeneric.Equal(&c) {
t.Fatal("Sub failed special test values: asm and generic impl don't match")
}
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
t.Fatal("Sub failed special test values")
}
}
}
}
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
supportAdx = true
}
}
func TestElementMul(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
genB := gen()
properties.Property("Mul: having the receiver as operand should output the same result", prop.ForAll(
func(a, b testPairElement) bool {
var c, d Element
d.Set(&a.element)
c.Mul(&a.element, &b.element)
a.element.Mul(&a.element, &b.element)
b.element.Mul(&d, &b.element)
return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c)
},
genA,
genB,
))
properties.Property("Mul: operation result must match big.Int result", prop.ForAll(
func(a, b testPairElement) bool {
{
var c Element
c.Mul(&a.element, &b.element)
var d, e big.Int
d.Mul(&a.bigint, &b.bigint).Mod(&d, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
return false
}
}
// fixed elements
// a is random
// r takes special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, r := range testValues {
var d, e, rb big.Int
r.ToBigIntRegular(&rb)
var c Element
c.Mul(&a.element, &r)
d.Mul(&a.bigint, &rb).Mod(&d, Modulus())
// checking generic impl against asm path
var cGeneric Element
_mulGeneric(&cGeneric, &a.element, &r)
if !cGeneric.Equal(&c) {
// need to give context to failing error.
return false
}
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
return false
}
}
return true
},
genA,
genB,
))
properties.Property("Mul: operation result must be smaller than modulus", prop.ForAll(
func(a, b testPairElement) bool {
var c Element
c.Mul(&a.element, &b.element)
return !c.biggerOrEqualModulus()
},
genA,
genB,
))
properties.Property("Mul: assembly implementation must be consistent with generic one", prop.ForAll(
func(a, b testPairElement) bool {
var c, d Element
c.Mul(&a.element, &b.element)
_mulGeneric(&d, &a.element, &b.element)
return c.Equal(&d)
},
genA,
genB,
))
specialValueTest := func() {
// test special values against special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, a := range testValues {
var aBig big.Int
a.ToBigIntRegular(&aBig)
for _, b := range testValues {
var bBig, d, e big.Int
b.ToBigIntRegular(&bBig)
var c Element
c.Mul(&a, &b)
d.Mul(&aBig, &bBig).Mod(&d, Modulus())
// checking asm against generic impl
var cGeneric Element
_mulGeneric(&cGeneric, &a, &b)
if !cGeneric.Equal(&c) {
t.Fatal("Mul failed special test values: asm and generic impl don't match")
}
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
t.Fatal("Mul failed special test values")
}
}
}
}
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
supportAdx = true
}
}
func TestElementDiv(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
genB := gen()
properties.Property("Div: having the receiver as operand should output the same result", prop.ForAll(
func(a, b testPairElement) bool {
var c, d Element
d.Set(&a.element)
c.Div(&a.element, &b.element)
a.element.Div(&a.element, &b.element)
b.element.Div(&d, &b.element)
return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c)
},
genA,
genB,
))
properties.Property("Div: operation result must match big.Int result", prop.ForAll(
func(a, b testPairElement) bool {
{
var c Element
c.Div(&a.element, &b.element)
var d, e big.Int
d.ModInverse(&b.bigint, Modulus())
d.Mul(&d, &a.bigint).Mod(&d, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
return false
}
}
// fixed elements
// a is random
// r takes special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, r := range testValues {
var d, e, rb big.Int
r.ToBigIntRegular(&rb)
var c Element
c.Div(&a.element, &r)
d.ModInverse(&rb, Modulus())
d.Mul(&d, &a.bigint).Mod(&d, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
return false
}
}
return true
},
genA,
genB,
))
properties.Property("Div: operation result must be smaller than modulus", prop.ForAll(
func(a, b testPairElement) bool {
var c Element
c.Div(&a.element, &b.element)
return !c.biggerOrEqualModulus()
},
genA,
genB,
))
specialValueTest := func() {
// test special values against special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, a := range testValues {
var aBig big.Int
a.ToBigIntRegular(&aBig)
for _, b := range testValues {
var bBig, d, e big.Int
b.ToBigIntRegular(&bBig)
var c Element
c.Div(&a, &b)
d.ModInverse(&bBig, Modulus())
d.Mul(&d, &aBig).Mod(&d, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
t.Fatal("Div failed special test values")
}
}
}
}
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
supportAdx = true
}
}
func TestElementExp(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
genB := gen()
properties.Property("Exp: having the receiver as operand should output the same result", prop.ForAll(
func(a, b testPairElement) bool {
var c, d Element
d.Set(&a.element)
c.Exp(a.element, &b.bigint)
a.element.Exp(a.element, &b.bigint)
b.element.Exp(d, &b.bigint)
return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c)
},
genA,
genB,
))
properties.Property("Exp: operation result must match big.Int result", prop.ForAll(
func(a, b testPairElement) bool {
{
var c Element
c.Exp(a.element, &b.bigint)
var d, e big.Int
d.Exp(&a.bigint, &b.bigint, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
return false
}
}
// fixed elements
// a is random
// r takes special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, r := range testValues {
var d, e, rb big.Int
r.ToBigIntRegular(&rb)
var c Element
c.Exp(a.element, &rb)
d.Exp(&a.bigint, &rb, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
return false
}
}
return true
},
genA,
genB,
))
properties.Property("Exp: operation result must be smaller than modulus", prop.ForAll(
func(a, b testPairElement) bool {
var c Element
c.Exp(a.element, &b.bigint)
return !c.biggerOrEqualModulus()
},
genA,
genB,
))
specialValueTest := func() {
// test special values against special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, a := range testValues {
var aBig big.Int
a.ToBigIntRegular(&aBig)
for _, b := range testValues {
var bBig, d, e big.Int
b.ToBigIntRegular(&bBig)
var c Element
c.Exp(a, &bBig)
d.Exp(&aBig, &bBig, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
t.Fatal("Exp failed special test values")
}
}
}
}
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
t.Log("disabling ADX")
supportAdx = false
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
supportAdx = true
}
}
func TestElementSquare(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("Square: having the receiver as operand should output the same result", prop.ForAll(
func(a testPairElement) bool {
var b Element
b.Square(&a.element)
a.element.Square(&a.element)
return a.element.Equal(&b)
},
genA,
))
properties.Property("Square: operation result must match big.Int result", prop.ForAll(
func(a testPairElement) bool {
var c Element
c.Square(&a.element)
var d, e big.Int
d.Mul(&a.bigint, &a.bigint).Mod(&d, Modulus())
return c.FromMont().ToBigInt(&e).Cmp(&d) == 0
},
genA,
))
properties.Property("Square: operation result must be smaller than modulus", prop.ForAll(
func(a testPairElement) bool {
var c Element
c.Square(&a.element)
return !c.biggerOrEqualModulus()
},
genA,
))
specialValueTest := func() {
// test special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, a := range testValues {
var aBig big.Int
a.ToBigIntRegular(&aBig)
var c Element
c.Square(&a)
var d, e big.Int
d.Mul(&aBig, &aBig).Mod(&d, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
t.Fatal("Square failed special test values")
}
}
}
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
supportAdx = false
t.Log("disabling ADX")
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
supportAdx = true
}
}
func TestElementInverse(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("Inverse: having the receiver as operand should output the same result", prop.ForAll(
func(a testPairElement) bool {
var b Element
b.Inverse(&a.element)
a.element.Inverse(&a.element)
return a.element.Equal(&b)
},
genA,
))
properties.Property("Inverse: operation result must match big.Int result", prop.ForAll(
func(a testPairElement) bool {
var c Element
c.Inverse(&a.element)
var d, e big.Int
d.ModInverse(&a.bigint, Modulus())
return c.FromMont().ToBigInt(&e).Cmp(&d) == 0
},
genA,
))
properties.Property("Inverse: operation result must be smaller than modulus", prop.ForAll(
func(a testPairElement) bool {
var c Element
c.Inverse(&a.element)
return !c.biggerOrEqualModulus()
},
genA,
))
specialValueTest := func() {
// test special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, a := range testValues {
var aBig big.Int
a.ToBigIntRegular(&aBig)
var c Element
c.Inverse(&a)
var d, e big.Int
d.ModInverse(&aBig, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
t.Fatal("Inverse failed special test values")
}
}
}
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
supportAdx = false
t.Log("disabling ADX")
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
supportAdx = true
}
}
func TestElementSqrt(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("Sqrt: having the receiver as operand should output the same result", prop.ForAll(
func(a testPairElement) bool {
b := a.element
b.Sqrt(&a.element)
a.element.Sqrt(&a.element)
return a.element.Equal(&b)
},
genA,
))
properties.Property("Sqrt: operation result must match big.Int result", prop.ForAll(
func(a testPairElement) bool {
var c Element
c.Sqrt(&a.element)
var d, e big.Int
d.ModSqrt(&a.bigint, Modulus())
return c.FromMont().ToBigInt(&e).Cmp(&d) == 0
},
genA,
))
properties.Property("Sqrt: operation result must be smaller than modulus", prop.ForAll(
func(a testPairElement) bool {
var c Element
c.Sqrt(&a.element)
return !c.biggerOrEqualModulus()
},
genA,
))
specialValueTest := func() {
// test special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, a := range testValues {
var aBig big.Int
a.ToBigIntRegular(&aBig)
var c Element
c.Sqrt(&a)
var d, e big.Int
d.ModSqrt(&aBig, Modulus())
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
t.Fatal("Sqrt failed special test values")
}
}
}
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
supportAdx = false
t.Log("disabling ADX")
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
supportAdx = true
}
}
func TestElementDouble(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("Double: having the receiver as operand should output the same result", prop.ForAll(
func(a testPairElement) bool {
var b Element
b.Double(&a.element)
a.element.Double(&a.element)
return a.element.Equal(&b)
},
genA,
))
properties.Property("Double: operation result must match big.Int result", prop.ForAll(
func(a testPairElement) bool {
var c Element
c.Double(&a.element)
var d, e big.Int
d.Lsh(&a.bigint, 1).Mod(&d, Modulus())
return c.FromMont().ToBigInt(&e).Cmp(&d) == 0
},
genA,
))
properties.Property("Double: operation result must be smaller than modulus", prop.ForAll(
func(a testPairElement) bool {
var c Element
c.Double(&a.element)
return !c.biggerOrEqualModulus()
},
genA,
))
properties.Property("Double: assembly implementation must be consistent with generic one", prop.ForAll(
func(a testPairElement) bool {
var c, d Element
c.Double(&a.element)
_doubleGeneric(&d, &a.element)
return c.Equal(&d)
},
genA,
))
specialValueTest := func() {
// test special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, a := range testValues {
var aBig big.Int
a.ToBigIntRegular(&aBig)
var c Element
c.Double(&a)
var d, e big.Int
d.Lsh(&aBig, 1).Mod(&d, Modulus())
// checking asm against generic impl
var cGeneric Element
_doubleGeneric(&cGeneric, &a)
if !cGeneric.Equal(&c) {
t.Fatal("Double failed special test values: asm and generic impl don't match")
}
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
t.Fatal("Double failed special test values")
}
}
}
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
supportAdx = false
t.Log("disabling ADX")
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
supportAdx = true
}
}
func TestElementNeg(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("Neg: having the receiver as operand should output the same result", prop.ForAll(
func(a testPairElement) bool {
var b Element
b.Neg(&a.element)
a.element.Neg(&a.element)
return a.element.Equal(&b)
},
genA,
))
properties.Property("Neg: operation result must match big.Int result", prop.ForAll(
func(a testPairElement) bool {
var c Element
c.Neg(&a.element)
var d, e big.Int
d.Neg(&a.bigint).Mod(&d, Modulus())
return c.FromMont().ToBigInt(&e).Cmp(&d) == 0
},
genA,
))
properties.Property("Neg: operation result must be smaller than modulus", prop.ForAll(
func(a testPairElement) bool {
var c Element
c.Neg(&a.element)
return !c.biggerOrEqualModulus()
},
genA,
))
properties.Property("Neg: assembly implementation must be consistent with generic one", prop.ForAll(
func(a testPairElement) bool {
var c, d Element
c.Neg(&a.element)
_negGeneric(&d, &a.element)
return c.Equal(&d)
},
genA,
))
specialValueTest := func() {
// test special values
testValues := make([]Element, len(staticTestValues))
copy(testValues, staticTestValues)
for _, a := range testValues {
var aBig big.Int
a.ToBigIntRegular(&aBig)
var c Element
c.Neg(&a)
var d, e big.Int
d.Neg(&aBig).Mod(&d, Modulus())
// checking asm against generic impl
var cGeneric Element
_negGeneric(&cGeneric, &a)
if !cGeneric.Equal(&c) {
t.Fatal("Neg failed special test values: asm and generic impl don't match")
}
if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 {
t.Fatal("Neg failed special test values")
}
}
}
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
// if we have ADX instruction enabled, test both path in assembly
if supportAdx {
supportAdx = false
t.Log("disabling ADX")
properties.TestingRun(t, gopter.ConsoleReporter(false))
specialValueTest()
supportAdx = true
}
}
func TestElementHalve(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
var twoInv Element
twoInv.SetUint64(2)
twoInv.Inverse(&twoInv)
properties.Property("z.Halve must match z / 2", prop.ForAll(
func(a testPairElement) bool {
c := a.element
d := a.element
c.Halve()
d.Mul(&d, &twoInv)
return c.Equal(&d)
},
genA,
))
properties.TestingRun(t, gopter.ConsoleReporter(false))
}
func TestElementFromMont(t *testing.T) {
parameters := gopter.DefaultTestParameters()
if testing.Short() {
parameters.MinSuccessfulTests = nbFuzzShort
} else {
parameters.MinSuccessfulTests = nbFuzz
}
properties := gopter.NewProperties(parameters)
genA := gen()
properties.Property("Assembly implementation must be consistent with generic one", prop.ForAll(
func(a testPairElement) bool {
c := a.element
d := a.element
c.FromMont()
_fromMontGeneric(&d)
return c.Equal(&d)
},
genA,
))
properties.Property("x.FromMont().ToMont() == x", prop.ForAll(
func(a testPairElement) bool {
c := a.element
c.FromMont().ToMont()
return c.Equal(&a.element)
},
genA,
))
properties.TestingRun(t, gopter.ConsoleReporter(false))
}
type testPairElement struct {
element Element
bigint big.Int
}
func (z *Element) biggerOrEqualModulus() bool {
if z[3] > qElement[3] {
return true
}
if z[3] < qElement[3] {
return false
}
if z[2] > qElement[2] {
return true
}
if z[2] < qElement[2] {
return false
}
if z[1] > qElement[1] {
return true
}
if z[1] < qElement[1] {
return false
}
return z[0] >= qElement[0]
}
func gen() gopter.Gen {
return func(genParams *gopter.GenParameters) *gopter.GenResult {
var g testPairElement
g.element = Element{
genParams.NextUint64(),
genParams.NextUint64(),
genParams.NextUint64(),
genParams.NextUint64(),
}
if qElement[3] != ^uint64(0) {
g.element[3] %= (qElement[3] + 1)
}
for g.element.biggerOrEqualModulus() {
g.element = Element{
genParams.NextUint64(),
genParams.NextUint64(),
genParams.NextUint64(),
genParams.NextUint64(),
}
if qElement[3] != ^uint64(0) {
g.element[3] %= (qElement[3] + 1)
}
}
g.element.ToBigIntRegular(&g.bigint)
genResult := gopter.NewGenResult(g, gopter.NoShrinker)
return genResult
}
}
func genFull() gopter.Gen {
return func(genParams *gopter.GenParameters) *gopter.GenResult {
genRandomFq := func() Element {
var g Element
g = Element{
genParams.NextUint64(),
genParams.NextUint64(),
genParams.NextUint64(),
genParams.NextUint64(),
}
if qElement[3] != ^uint64(0) {
g[3] %= (qElement[3] + 1)
}
for g.biggerOrEqualModulus() {
g = Element{
genParams.NextUint64(),
genParams.NextUint64(),
genParams.NextUint64(),
genParams.NextUint64(),
}
if qElement[3] != ^uint64(0) {
g[3] %= (qElement[3] + 1)
}
}
return g
}
a := genRandomFq()
var carry uint64
a[0], carry = bits.Add64(a[0], qElement[0], carry)
a[1], carry = bits.Add64(a[1], qElement[1], carry)
a[2], carry = bits.Add64(a[2], qElement[2], carry)
a[3], _ = bits.Add64(a[3], qElement[3], carry)
genResult := gopter.NewGenResult(a, gopter.NoShrinker)
return genResult
}
}