// 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 } }