go-ethereum/crypto/bls12381/fp_test.go
2024-04-08 16:10:46 +02:00

2238 lines
47 KiB
Go

package bls12381
import (
"bytes"
"crypto/rand"
"math/big"
"testing"
)
func TestFpSerialization(t *testing.T) {
t.Run("zero", func(t *testing.T) {
in := make([]byte, fpByteSize)
fe, err := fromBytes(in)
if err != nil {
t.Fatal(err)
}
if !fe.isZero() {
t.Fatal("serialization failed")
}
if !bytes.Equal(in, toBytes(fe)) {
t.Fatal("serialization failed")
}
})
t.Run("bytes", func(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, err := fromBytes(toBytes(a))
if err != nil {
t.Fatal(err)
}
if !a.equal(b) {
t.Fatal("serialization failed")
}
}
})
t.Run("string", func(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, err := fromString(toString(a))
if err != nil {
t.Fatal(err)
}
if !a.equal(b) {
t.Fatal("encoding or decoding failed")
}
}
})
t.Run("big", func(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, err := fromBig(toBig(a))
if err != nil {
t.Fatal(err)
}
if !a.equal(b) {
t.Fatal("encoding or decoding failed")
}
}
})
}
func TestFpAdditionCrossAgainstBigInt(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, _ := new(fe).rand(rand.Reader)
c := new(fe)
big_a := a.big()
big_b := b.big()
big_c := new(big.Int)
add(c, a, b)
out_1 := c.bytes()
out_2 := padBytes(big_c.Add(big_a, big_b).Mod(big_c, modulus.big()).Bytes(), fpByteSize)
if !bytes.Equal(out_1, out_2) {
t.Fatal("cross test against big.Int is failed A")
}
double(c, a)
out_1 = c.bytes()
out_2 = padBytes(big_c.Add(big_a, big_a).Mod(big_c, modulus.big()).Bytes(), fpByteSize)
if !bytes.Equal(out_1, out_2) {
t.Fatal("cross test against big.Int is failed B")
}
sub(c, a, b)
out_1 = c.bytes()
out_2 = padBytes(big_c.Sub(big_a, big_b).Mod(big_c, modulus.big()).Bytes(), fpByteSize)
if !bytes.Equal(out_1, out_2) {
t.Fatal("cross test against big.Int is failed C")
}
neg(c, a)
out_1 = c.bytes()
out_2 = padBytes(big_c.Neg(big_a).Mod(big_c, modulus.big()).Bytes(), fpByteSize)
if !bytes.Equal(out_1, out_2) {
t.Fatal("cross test against big.Int is failed D")
}
}
}
func TestFpAdditionCrossAgainstBigIntAssigned(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, _ := new(fe).rand(rand.Reader)
big_a, big_b := a.big(), b.big()
addAssign(a, b)
out_1 := a.bytes()
out_2 := padBytes(big_a.Add(big_a, big_b).Mod(big_a, modulus.big()).Bytes(), fpByteSize)
if !bytes.Equal(out_1, out_2) {
t.Fatal("cross test against big.Int is failed A")
}
a, _ = new(fe).rand(rand.Reader)
big_a = a.big()
doubleAssign(a)
out_1 = a.bytes()
out_2 = padBytes(big_a.Add(big_a, big_a).Mod(big_a, modulus.big()).Bytes(), fpByteSize)
if !bytes.Equal(out_1, out_2) {
t.Fatal("cross test against big.Int is failed B")
}
a, _ = new(fe).rand(rand.Reader)
b, _ = new(fe).rand(rand.Reader)
big_a, big_b = a.big(), b.big()
subAssign(a, b)
out_1 = a.bytes()
out_2 = padBytes(big_a.Sub(big_a, big_b).Mod(big_a, modulus.big()).Bytes(), fpByteSize)
if !bytes.Equal(out_1, out_2) {
t.Fatal("cross test against big.Int is failed A")
}
}
}
func TestFpAdditionProperties(t *testing.T) {
for i := 0; i < fuz; i++ {
zero := new(fe).zero()
a, _ := new(fe).rand(rand.Reader)
b, _ := new(fe).rand(rand.Reader)
c1, c2 := new(fe), new(fe)
add(c1, a, zero)
if !c1.equal(a) {
t.Fatal("a + 0 == a")
}
sub(c1, a, zero)
if !c1.equal(a) {
t.Fatal("a - 0 == a")
}
double(c1, zero)
if !c1.equal(zero) {
t.Fatal("2 * 0 == 0")
}
neg(c1, zero)
if !c1.equal(zero) {
t.Fatal("-0 == 0")
}
sub(c1, zero, a)
neg(c2, a)
if !c1.equal(c2) {
t.Fatal("0-a == -a")
}
double(c1, a)
add(c2, a, a)
if !c1.equal(c2) {
t.Fatal("2 * a == a + a")
}
add(c1, a, b)
add(c2, b, a)
if !c1.equal(c2) {
t.Fatal("a + b = b + a")
}
sub(c1, a, b)
sub(c2, b, a)
neg(c2, c2)
if !c1.equal(c2) {
t.Fatal("a - b = - ( b - a )")
}
cx, _ := new(fe).rand(rand.Reader)
add(c1, a, b)
add(c1, c1, cx)
add(c2, a, cx)
add(c2, c2, b)
if !c1.equal(c2) {
t.Fatal("(a + b) + c == (a + c ) + b")
}
sub(c1, a, b)
sub(c1, c1, cx)
sub(c2, a, cx)
sub(c2, c2, b)
if !c1.equal(c2) {
t.Fatal("(a - b) - c == (a - c ) -b")
}
}
}
func TestFpAdditionPropertiesAssigned(t *testing.T) {
for i := 0; i < fuz; i++ {
zero := new(fe).zero()
a, b := new(fe), new(fe)
_, _ = a.rand(rand.Reader)
b.set(a)
addAssign(a, zero)
if !a.equal(b) {
t.Fatal("a + 0 == a")
}
subAssign(a, zero)
if !a.equal(b) {
t.Fatal("a - 0 == a")
}
a.set(zero)
doubleAssign(a)
if !a.equal(zero) {
t.Fatal("2 * 0 == 0")
}
a.set(zero)
subAssign(a, b)
neg(b, b)
if !a.equal(b) {
t.Fatal("0-a == -a")
}
_, _ = a.rand(rand.Reader)
b.set(a)
doubleAssign(a)
addAssign(b, b)
if !a.equal(b) {
t.Fatal("2 * a == a + a")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
c1, c2 := new(fe).set(a), new(fe).set(b)
addAssign(c1, b)
addAssign(c2, a)
if !c1.equal(c2) {
t.Fatal("a + b = b + a")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
c1.set(a)
c2.set(b)
subAssign(c1, b)
subAssign(c2, a)
neg(c2, c2)
if !c1.equal(c2) {
t.Fatal("a - b = - ( b - a )")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
c, _ := new(fe).rand(rand.Reader)
a0 := new(fe).set(a)
addAssign(a, b)
addAssign(a, c)
addAssign(b, c)
addAssign(b, a0)
if !a.equal(b) {
t.Fatal("(a + b) + c == (b + c) + a")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
_, _ = c.rand(rand.Reader)
a0.set(a)
subAssign(a, b)
subAssign(a, c)
subAssign(a0, c)
subAssign(a0, b)
if !a.equal(a0) {
t.Fatal("(a - b) - c == (a - c) -b")
}
}
}
func TestFpLazyOperations(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, _ := new(fe).rand(rand.Reader)
c, _ := new(fe).rand(rand.Reader)
c0 := new(fe)
c1 := new(fe)
ladd(c0, a, b)
add(c1, a, b)
mul(c0, c0, c)
mul(c1, c1, c)
if !c0.equal(c1) {
t.Fatal("(a + b) * c == (a l+ b) * c")
}
_, _ = a.rand(rand.Reader)
b.set(a)
ldouble(a, a)
ladd(b, b, b)
if !a.equal(b) {
t.Fatal("2 l* a = a l+ a")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
_, _ = c.rand(rand.Reader)
a0 := new(fe).set(a)
lsubAssign(a, b)
laddAssign(a, &modulus)
mul(a, a, c)
subAssign(a0, b)
mul(a0, a0, c)
if !a.equal(a0) {
t.Fatal("((a l- b) + p) * c = (a-b) * c")
}
}
}
func TestFpMultiplicationCrossAgainstBigInt(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, _ := new(fe).rand(rand.Reader)
c := new(fe)
big_a := toBig(a)
big_b := toBig(b)
big_c := new(big.Int)
mul(c, a, b)
out_1 := toBytes(c)
out_2 := padBytes(big_c.Mul(big_a, big_b).Mod(big_c, modulus.big()).Bytes(), fpByteSize)
if !bytes.Equal(out_1, out_2) {
t.Fatal("cross test against big.Int is failed")
}
}
}
func TestFpMultiplicationProperties(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, _ := new(fe).rand(rand.Reader)
zero, one := new(fe).zero(), new(fe).one()
c1, c2 := new(fe), new(fe)
mul(c1, a, zero)
if !c1.equal(zero) {
t.Fatal("a * 0 == 0")
}
mul(c1, a, one)
if !c1.equal(a) {
t.Fatal("a * 1 == a")
}
mul(c1, a, b)
mul(c2, b, a)
if !c1.equal(c2) {
t.Fatal("a * b == b * a")
}
cx, _ := new(fe).rand(rand.Reader)
mul(c1, a, b)
mul(c1, c1, cx)
mul(c2, cx, b)
mul(c2, c2, a)
if !c1.equal(c2) {
t.Fatal("(a * b) * c == (a * c) * b")
}
square(a, zero)
if !a.equal(zero) {
t.Fatal("0^2 == 0")
}
square(a, one)
if !a.equal(one) {
t.Fatal("1^2 == 1")
}
_, _ = a.rand(rand.Reader)
square(c1, a)
mul(c2, a, a)
if !c1.equal(c1) {
t.Fatal("a^2 == a*a")
}
}
}
func TestFpExponentiation(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
u := new(fe)
exp(u, a, big.NewInt(0))
if !u.isOne() {
t.Fatal("a^0 == 1")
}
exp(u, a, big.NewInt(1))
if !u.equal(a) {
t.Fatal("a^1 == a")
}
v := new(fe)
mul(u, a, a)
mul(u, u, u)
mul(u, u, u)
exp(v, a, big.NewInt(8))
if !u.equal(v) {
t.Fatal("((a^2)^2)^2 == a^8")
}
p := modulus.big()
exp(u, a, p)
if !u.equal(a) {
t.Fatal("a^p == a")
}
exp(u, a, p.Sub(p, big.NewInt(1)))
if !u.isOne() {
t.Fatal("a^(p-1) == 1")
}
}
}
func TestFpInversion(t *testing.T) {
for i := 0; i < fuz; i++ {
u := new(fe)
zero, one := new(fe).zero(), new(fe).one()
inverse(u, zero)
if !u.equal(zero) {
t.Fatal("(0^-1) == 0)")
}
inverse(u, one)
if !u.equal(one) {
t.Fatal("(1^-1) == 1)")
}
a, _ := new(fe).rand(rand.Reader)
inverse(u, a)
mul(u, u, a)
if !u.equal(one) {
t.Fatal("(r*a) * r*(a^-1) == r)")
}
v := new(fe)
p := modulus.big()
exp(u, a, p.Sub(p, big.NewInt(2)))
inverse(v, a)
if !v.equal(u) {
t.Fatal("a^(p-2) == a^-1")
}
}
}
func TestFpBatchInversion(t *testing.T) {
n := 20
for i := 0; i < n; i++ {
e0 := make([]fe, n)
e1 := make([]fe, n)
for j := 0; j < n; j++ {
if j != i {
e, err := new(fe).rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
e0[j].set(e)
}
inverse(&e1[j], &e0[j])
}
inverseBatch(e0)
for j := 0; j < n; j++ {
if !e0[j].equal(&e1[j]) {
t.Fatal("batch inversion failed")
}
}
}
}
func TestFpSquareRoot(t *testing.T) {
if sqrt(new(fe), nonResidue1) {
t.Fatal("non residue cannot have a sqrt")
}
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
r0, r1 := new(fe), new(fe)
d0 := sqrt(r0, a)
d1 := _sqrt(r1, a)
if d0 != d1 {
t.Fatal("sqrt decision failed")
}
if d0 {
square(r0, r0)
square(r1, r1)
if !r0.equal(r1) {
t.Fatal("sqrt failed")
}
if !r0.equal(a) {
t.Fatal("sqrt failed")
}
}
}
}
func TestFpNonResidue(t *testing.T) {
if !isQuadraticNonResidue(nonResidue1) {
t.Fatal("element is quadratic non residue, 1")
}
if isQuadraticNonResidue(new(fe).one()) {
t.Fatal("one is not quadratic non residue")
}
if !isQuadraticNonResidue(new(fe).zero()) {
t.Fatal("should accept zero as quadratic non residue")
}
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
square(a, a)
if isQuadraticNonResidue(a) {
t.Fatal("element is not quadratic non residue")
}
}
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
if !sqrt(new(fe), a) {
if !isQuadraticNonResidue(a) {
t.Fatal("element is quadratic non residue, 2", i)
}
} else {
i -= 1
}
}
}
func TestWFp(t *testing.T) {
w := new(wfe)
a := new(fe)
fromWide(a, w)
if !a.isZero() {
t.Fatal("expect zero")
}
w[0] = r1[0]
w[1] = r1[1]
w[2] = r1[2]
w[3] = r1[3]
w[4] = r1[4]
w[5] = r1[5]
fromWide(a, w)
if !(a[0] == 1 && a[1] == 0 && a[2] == 0 && a[3] == 0 && a[4] == 0 && a[5] == 0) {
t.Fatal("expect one")
}
}
func TestWFpAddition(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, _ := new(fe).rand(rand.Reader)
w0, w1 := new(wfe), new(wfe)
c0, c1 := new(fe), new(fe)
wmul(w0, a, b)
w1.set(w0)
wadd(w0, w0, w0)
wadd(w0, w0, w0)
wadd(w0, w0, w0)
lwadd(w1, w1, w1)
lwadd(w1, w1, w1)
lwadd(w1, w1, w1)
fromWide(c0, w0)
fromWide(c1, w1)
if !c1.equal(c0) {
t.Fatal("addition failed")
}
wmul(w0, a, b)
w1.set(w0)
wdouble(w0, w0)
wdouble(w0, w0)
wdouble(w0, w0)
lwdouble(w1, w1)
lwdouble(w1, w1)
lwdouble(w1, w1)
fromWide(c0, w0)
fromWide(c1, w1)
if !c1.equal(c0) {
t.Fatal("doubling failed")
}
wmul(w0, a, &fe{10001})
wmul(w1, a, &fe{10000})
w2 := new(wfe)
wsub(w2, w0, w1)
lwsub(w0, w0, w1)
fromWide(c0, w2)
fromWide(c1, w0)
fromMont(a, a)
if !c1.equal(a) {
t.Fatal("subtraction failed")
}
if !c0.equal(a) {
t.Fatal("subtraction failed")
}
wmul(w0, a, &fe{10001})
wmul(w1, a, &fe{10000})
wsub(w0, w1, w0)
fromWide(c0, w0)
neg(a, a)
fromMont(a, a)
if !c0.equal(a) {
t.Fatal("subtraction failed")
}
}
}
func TestWFpMultiplication(t *testing.T) {
for i := 0; i < fuz; i++ {
a0, _ := new(fe).rand(rand.Reader)
b0, _ := new(fe).rand(rand.Reader)
a1, _ := new(fe).rand(rand.Reader)
b1, _ := new(fe).rand(rand.Reader)
w0, w1, w2, w3 := new(wfe), new(wfe), new(wfe), new(wfe)
c0, c1 := new(fe), new(fe)
r0, r1 := new(fe), new(fe)
wmul(w0, a0, b0)
fromWide(r0, w0)
mul(r1, a0, b0)
if !r1.equal(r0) {
t.Fatal("multiplication failed")
}
wmul(w0, a0, b0)
wmul(w1, a1, b1)
lwadd(w0, w0, w1)
fromWide(r0, w0)
mul(c0, a0, b0)
mul(c1, a1, b1)
add(r1, c0, c1)
if !r1.equal(r0) {
t.Fatal("multiplication failed")
}
wmul(w0, a0, b0)
wmul(w1, a0, b1)
wmul(w2, a1, b0)
wmul(w3, a1, b1)
lwadd(w0, w0, w1)
lwadd(w0, w0, w2)
lwadd(w0, w0, w3)
fromWide(r0, w0)
add(c0, a0, a1)
add(c1, b0, b1)
mul(r1, c0, c1)
if !r1.equal(r0) {
t.Fatal("multiplication failed")
}
}
}
func TestFp2Serialization(t *testing.T) {
f := newFp2()
for i := 0; i < fuz; i++ {
a, _ := new(fe2).rand(rand.Reader)
b, err := f.fromBytes(f.toBytes(a))
if err != nil {
t.Fatal(err)
}
if !a.equal(b) {
t.Fatal("serialization failed")
}
}
}
func TestFp2AdditionProperties(t *testing.T) {
f := newFp2()
for i := 0; i < fuz; i++ {
zero := f.zero()
a, _ := new(fe2).rand(rand.Reader)
b, _ := new(fe2).rand(rand.Reader)
c1 := f.new()
c2 := f.new()
fp2Add(c1, a, zero)
if !c1.equal(a) {
t.Fatal("a + 0 == a")
}
fp2Sub(c1, a, zero)
if !c1.equal(a) {
t.Fatal("a - 0 == a")
}
fp2Double(c1, zero)
if !c1.equal(zero) {
t.Fatal("2 * 0 == 0")
}
fp2Neg(c1, zero)
if !c1.equal(zero) {
t.Fatal("-0 == 0")
}
fp2Sub(c1, zero, a)
fp2Neg(c2, a)
if !c1.equal(c2) {
t.Fatal("0-a == -a")
}
fp2Double(c1, a)
fp2Add(c2, a, a)
if !c1.equal(c2) {
t.Fatal("2 * a == a + a")
}
fp2Add(c1, a, b)
fp2Add(c2, b, a)
if !c1.equal(c2) {
t.Fatal("a + b = b + a")
}
fp2Sub(c1, a, b)
fp2Sub(c2, b, a)
fp2Neg(c2, c2)
if !c1.equal(c2) {
t.Fatal("a - b = - ( b - a )")
}
cx, _ := new(fe2).rand(rand.Reader)
fp2Add(c1, a, b)
fp2Add(c1, c1, cx)
fp2Add(c2, a, cx)
fp2Add(c2, c2, b)
if !c1.equal(c2) {
t.Fatal("(a + b) + c == (a + c ) + b")
}
fp2Sub(c1, a, b)
fp2Sub(c1, c1, cx)
fp2Sub(c2, a, cx)
fp2Sub(c2, c2, b)
if !c1.equal(c2) {
t.Fatal("(a - b) - c == (a - c ) -b")
}
}
}
func TestFp2AdditionPropertiesAssigned(t *testing.T) {
for i := 0; i < fuz; i++ {
zero := new(fe2).zero()
a, b := new(fe2), new(fe2)
_, _ = a.rand(rand.Reader)
b.set(a)
fp2AddAssign(a, zero)
if !a.equal(b) {
t.Fatal("a + 0 == a")
}
fp2SubAssign(a, zero)
if !a.equal(b) {
t.Fatal("a - 0 == a")
}
a.set(zero)
fp2DoubleAssign(a)
if !a.equal(zero) {
t.Fatal("2 * 0 == 0")
}
a.set(zero)
fp2SubAssign(a, b)
fp2Neg(b, b)
if !a.equal(b) {
t.Fatal("0-a == -a")
}
_, _ = a.rand(rand.Reader)
b.set(a)
fp2DoubleAssign(a)
fp2AddAssign(b, b)
if !a.equal(b) {
t.Fatal("2 * a == a + a")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
c1, c2 := new(fe2).set(a), new(fe2).set(b)
fp2AddAssign(c1, b)
fp2AddAssign(c2, a)
if !c1.equal(c2) {
t.Fatal("a + b = b + a")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
c1.set(a)
c2.set(b)
fp2SubAssign(c1, b)
fp2SubAssign(c2, a)
fp2Neg(c2, c2)
if !c1.equal(c2) {
t.Fatal("a - b = - ( b - a )")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
c, _ := new(fe2).rand(rand.Reader)
a0 := new(fe2).set(a)
fp2AddAssign(a, b)
fp2AddAssign(a, c)
fp2AddAssign(b, c)
fp2AddAssign(b, a0)
if !a.equal(b) {
t.Fatal("(a + b) + c == (b + c) + a")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
_, _ = c.rand(rand.Reader)
a0.set(a)
fp2SubAssign(a, b)
fp2SubAssign(a, c)
fp2SubAssign(a0, c)
fp2SubAssign(a0, b)
if !a.equal(a0) {
t.Fatal("(a - b) - c == (a - c) -b")
}
}
}
func TestFp2LazyOperations(t *testing.T) {
f := newFp2()
for i := 0; i < fuz; i++ {
a, _ := new(fe2).rand(rand.Reader)
b, _ := new(fe2).rand(rand.Reader)
c, _ := new(fe2).rand(rand.Reader)
c0 := new(fe2)
c1 := new(fe2)
fp2Ladd(c0, a, b)
fp2Add(c1, a, b)
fp2LaddAssign(a, b)
f.mulAssign(c0, c)
f.mulAssign(c1, c)
f.mulAssign(a, c)
if !c0.equal(c1) {
t.Fatal("(a + b) * c == (a l+ b) * c")
}
if !c0.equal(c1) {
t.Fatal("(a + b) * c == (a l+ b) * c")
}
}
}
func TestFp2MulByNonResidue(t *testing.T) {
f := newFp2()
for i := 0; i < fuz; i++ {
a, _ := new(fe2).rand(rand.Reader)
r0, r1, r2, r3 := new(fe2), new(fe2), new(fe2), new(fe2)
f.mul(r1, a, nonResidue2)
mulByNonResidue(r0, a)
r2.set(a)
mulByNonResidueAssign(r2)
_fp2MulByNonResidue(r3, a)
if !r0.equal(r1) {
t.Fatal("mul by non residue failed")
}
if !r0.equal(r2) {
t.Fatal("mul by non residue failed")
}
if !r0.equal(r3) {
t.Fatal("mul by non residue failed")
}
}
}
func TestFp2MultiplicationProperties(t *testing.T) {
f := newFp2()
for i := 0; i < fuz; i++ {
a, _ := new(fe2).rand(rand.Reader)
b, _ := new(fe2).rand(rand.Reader)
zero := f.zero()
one := f.one()
c1, c2 := f.new(), f.new()
f.mul(c1, a, zero)
if !c1.equal(zero) {
t.Fatal("a * 0 == 0")
}
f.mul(c1, a, one)
if !c1.equal(a) {
t.Fatal("a * 1 == a")
}
f.mul(c1, a, b)
f.mul(c2, b, a)
if !c1.equal(c2) {
t.Fatal("a * b == b * a")
}
cx, _ := new(fe2).rand(rand.Reader)
f.mul(c1, a, b)
f.mul(c1, c1, cx)
f.mul(c2, cx, b)
f.mul(c2, c2, a)
if !c1.equal(c2) {
t.Fatal("(a * b) * c == (a * c) * b")
}
f.square(a, zero)
if !a.equal(zero) {
t.Fatal("0^2 == 0")
}
f.square(a, one)
if !a.equal(one) {
t.Fatal("1^2 == 1")
}
_, _ = a.rand(rand.Reader)
f.square(c1, a)
f.mul(c2, a, a)
if !c2.equal(c1) {
t.Fatal("a^2 == a*a")
}
}
}
func TestFp2MultiplicationPropertiesAssigned(t *testing.T) {
f := newFp2()
for i := 0; i < fuz; i++ {
a, _ := new(fe2).rand(rand.Reader)
zero, one := new(fe2).zero(), new(fe2).one()
f.mulAssign(a, zero)
if !a.equal(zero) {
t.Fatal("a * 0 == 0")
}
_, _ = a.rand(rand.Reader)
a0 := new(fe2).set(a)
f.mulAssign(a, one)
if !a.equal(a0) {
t.Fatal("a * 1 == a")
}
_, _ = a.rand(rand.Reader)
b, _ := new(fe2).rand(rand.Reader)
a0.set(a)
f.mulAssign(a, b)
f.mulAssign(b, a0)
if !a.equal(b) {
t.Fatal("a * b == b * a")
}
c, _ := new(fe2).rand(rand.Reader)
a0.set(a)
f.mulAssign(a, b)
f.mulAssign(a, c)
f.mulAssign(a0, c)
f.mulAssign(a0, b)
if !a.equal(a0) {
t.Fatal("(a * b) * c == (a * c) * b")
}
a0.set(a)
f.squareAssign(a)
f.mulAssign(a0, a0)
if !a.equal(a0) {
t.Fatal("a^2 == a*a")
}
}
}
func TestFp2Exponentiation(t *testing.T) {
f := newFp2()
for i := 0; i < fuz; i++ {
a, _ := new(fe2).rand(rand.Reader)
u := f.new()
f.exp(u, a, big.NewInt(0))
if !u.equal(f.one()) {
t.Fatal("a^0 == 1")
}
f.exp(u, a, big.NewInt(1))
if !u.equal(a) {
t.Fatal("a^1 == a")
}
v := f.new()
f.mul(u, a, a)
f.mul(u, u, u)
f.mul(u, u, u)
f.exp(v, a, big.NewInt(8))
if !u.equal(v) {
t.Fatal("((a^2)^2)^2 == a^8")
}
}
}
func TestFp2Inversion(t *testing.T) {
f := newFp2()
u := f.new()
zero := f.zero()
one := f.one()
f.inverse(u, zero)
if !u.equal(zero) {
t.Fatal("(0 ^ -1) == 0)")
}
f.inverse(u, one)
if !u.equal(one) {
t.Fatal("(1 ^ -1) == 1)")
}
for i := 0; i < fuz; i++ {
a, _ := new(fe2).rand(rand.Reader)
f.inverse(u, a)
f.mul(u, u, a)
if !u.equal(one) {
t.Fatal("(r * a) * r * (a ^ -1) == r)")
}
}
}
func TestFp2BatchInversion(t *testing.T) {
f := newFp2()
n := 20
for i := 0; i < n; i++ {
e0 := make([]fe2, n)
e1 := make([]fe2, n)
for j := 0; j < n; j++ {
if j != i {
e, err := new(fe2).rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
e0[j].set(e)
}
f.inverse(&e1[j], &e0[j])
}
f.inverseBatch(e0)
for j := 0; j < n; j++ {
if !e0[j].equal(&e1[j]) {
t.Fatal("batch inversion failed")
}
}
}
}
func TestFp2SquareRoot(t *testing.T) {
e := newFp2()
if e.sqrtBLST(e.new(), nonResidue2) {
t.Fatal("non residue cannot have a sqrt")
}
for i := 0; i < fuz; i++ {
a, _ := new(fe2).rand(rand.Reader)
r0, r1 := new(fe2), new(fe2)
d0 := e.sqrt(r0, a)
d1 := e.sqrtBLST(r1, a)
if d0 != d1 {
t.Fatal("sqrt decision failed")
}
if d0 {
e.square(r0, r0)
e.square(r1, r1)
if !r0.equal(r1) {
t.Fatal("sqrt failed")
}
if !r0.equal(a) {
t.Fatal("sqrt failed")
}
}
}
}
func TestFp2NonResidue(t *testing.T) {
f := newFp2()
if !f.isQuadraticNonResidue(nonResidue2) {
t.Fatal("element is quadratic non residue, 1")
}
if f.isQuadraticNonResidue(new(fe2).one()) {
t.Fatal("one is not quadratic non residue")
}
if !f.isQuadraticNonResidue(new(fe2).zero()) {
t.Fatal("should accept zero as quadratic non residue")
}
for i := 0; i < fuz; i++ {
a, _ := new(fe2).rand(rand.Reader)
f.squareAssign(a)
if f.isQuadraticNonResidue(a) {
t.Fatal("element is not quadratic non residue")
}
}
for i := 0; i < fuz; i++ {
a, _ := new(fe2).rand(rand.Reader)
if !f.sqrt(new(fe2), a) {
if !f.isQuadraticNonResidue(a) {
t.Fatal("element is quadratic non residue, 2", i)
}
} else {
i -= 1
}
}
}
func TestWFp2Addition(t *testing.T) {
for i := 0; i < fuz; i++ {
r0, _ := new(fe2).rand(rand.Reader)
r1, _ := new(fe2).rand(rand.Reader)
r2, _ := new(fe2).rand(rand.Reader)
rw0, rw1, w0, w1 := new(wfe2), new(wfe2), new(wfe2), new(wfe2)
wfp2Mul(w0, r0, r1)
wfp2Mul(w1, r0, r2)
_wfp2Add(rw0, w0, w1)
wfp2Add(rw1, w0, w1)
if !rw0.equal(rw1) {
t.Fatal("add failed")
}
rw1.set(w0)
wfp2AddAssign(rw1, w1)
if !rw0.equal(rw1) {
t.Fatal("assigned add failed")
}
_wfp2AddMixed(rw0, w0, w1)
wfp2AddMixed(rw1, w0, w1)
if !rw0.equal(rw1) {
t.Fatal("add mixed failed")
}
rw1.set(w0)
wfp2AddMixedAssign(rw1, w1)
if !rw0.equal(rw1) {
t.Fatal("assigned mixed add failed")
}
_wfp2Ladd(rw0, w0, w1)
wfp2Ladd(rw1, w0, w1)
if !rw0.equal(rw1) {
t.Fatal("lazy add failed")
}
rw1.set(w0)
wfp2LaddAssign(rw1, w1)
if !rw0.equal(rw1) {
t.Fatal("assigned lazy add failed")
}
_wfp2Sub(rw0, w0, w1)
wfp2Sub(rw1, w0, w1)
if !rw0.equal(rw1) {
t.Fatal("sub failed")
}
rw1.set(w0)
wfp2SubAssign(rw1, w1)
if !rw0.equal(rw1) {
t.Fatal("assigned sub failed")
}
_wfp2SubMixed(rw0, w0, w1)
wfp2SubMixed(rw1, w0, w1)
if !rw0.equal(rw1) {
t.Fatal("sub mixed failed")
}
rw1.set(w0)
wfp2SubMixedAssign(rw1, w1)
if !rw0.equal(rw1) {
t.Fatal("assigned sub mixed failed")
}
_wfp2Double(rw0, w0)
wfp2Double(rw1, w0)
if !rw0.equal(rw1) {
t.Fatal("doubling failed")
}
rw1.set(w0)
wfp2DoubleAssign(rw1)
if !rw0.equal(rw1) {
t.Fatal("assigned doubling failed")
}
}
}
func TestFp2MultiplicationCross(t *testing.T) {
f := newFp2()
a, b, c0, c1 := new(fe2), new(fe2), new(fe2), new(fe2)
w0, w1 := new(wfe2), new(wfe2)
for i := 0; i < fuz; i++ {
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
_wfp2Mul(w0, a, b)
wfp2Mul(w1, a, b)
if !w0.equal(w1) {
t.Fatal("multiplication failed")
}
c0.fromWide(w0)
f.mul(c1, a, b)
if !c0.equal(c1) {
t.Fatal("multiplication failed")
}
}
}
func TestFp2SquareCross(t *testing.T) {
f := newFp2()
a, c0, c1 := new(fe2), new(fe2), new(fe2)
w0, w1 := new(wfe2), new(wfe2)
for i := 0; i < fuz; i++ {
_, _ = a.rand(rand.Reader)
_wfp2Square(w0, a)
wfp2Square(w1, a)
if !w0.equal(w1) {
t.Fatal("squaring failed")
}
c0.fromWide(w0)
f.square(c1, a)
if !c0.equal(c1) {
t.Fatal("squaring failed")
}
}
}
func TestWFp2MulByNonResidue(t *testing.T) {
f := newFp2()
a, b, c0, c1 := new(fe2), new(fe2), new(fe2), new(fe2)
w0, w1, w2, w3 := new(wfe2), new(wfe2), new(wfe2), new(wfe2)
for i := 0; i < fuz; i++ {
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
r := new(fe2)
f.mul(r, a, b)
wfp2Mul(w0, a, b)
mulByNonResidue(c0, r)
wfp2MulByNonResidue(w1, w0)
w2.set(w0)
wfp2MulByNonResidueAssign(w2)
_wfp2MulByNonResidue(w3, w0)
if !w1.equal(w2) {
t.Fatal("mul by non residue failed")
}
if !w1.equal(w3) {
t.Fatal("mul by non residue failed")
}
c1.fromWide(w1)
if !c0.equal(c1) {
t.Fatal("mul by non residue failed")
}
}
}
func TestFp6Serialization(t *testing.T) {
f := newFp6(nil)
for i := 0; i < fuz; i++ {
a, _ := new(fe6).rand(rand.Reader)
b, err := f.fromBytes(f.toBytes(a))
if err != nil {
t.Fatal(err)
}
if !a.equal(b) {
t.Fatal("serialization")
}
}
}
func TestFp6AdditionProperties(t *testing.T) {
f := newFp6(nil)
for i := 0; i < fuz; i++ {
zero := f.zero()
a, _ := new(fe6).rand(rand.Reader)
b, _ := new(fe6).rand(rand.Reader)
c1 := f.new()
c2 := f.new()
fp6Add(c1, a, zero)
if !c1.equal(a) {
t.Fatal("a + 0 == a")
}
fp6Sub(c1, a, zero)
if !c1.equal(a) {
t.Fatal("a - 0 == a")
}
fp6Double(c1, zero)
if !c1.equal(zero) {
t.Fatal("2 * 0 == 0")
}
fp6Neg(c1, zero)
if !c1.equal(zero) {
t.Fatal("-0 == 0")
}
fp6Sub(c1, zero, a)
fp6Neg(c2, a)
if !c1.equal(c2) {
t.Fatal("0-a == -a")
}
fp6Double(c1, a)
fp6Add(c2, a, a)
if !c1.equal(c2) {
t.Fatal("2 * a == a + a")
}
fp6Add(c1, a, b)
fp6Add(c2, b, a)
if !c1.equal(c2) {
t.Fatal("a + b = b + a")
}
fp6Sub(c1, a, b)
fp6Sub(c2, b, a)
fp6Neg(c2, c2)
if !c1.equal(c2) {
t.Fatal("a - b = - ( b - a )")
}
cx, _ := new(fe6).rand(rand.Reader)
fp6Add(c1, a, b)
fp6Add(c1, c1, cx)
fp6Add(c2, a, cx)
fp6Add(c2, c2, b)
if !c1.equal(c2) {
t.Fatal("(a + b) + c == (a + c ) + b")
}
fp6Sub(c1, a, b)
fp6Sub(c1, c1, cx)
fp6Sub(c2, a, cx)
fp6Sub(c2, c2, b)
if !c1.equal(c2) {
t.Fatal("(a - b) - c == (a - c ) -b")
}
}
}
func TestFp6AdditionPropertiesAssigned(t *testing.T) {
for i := 0; i < fuz; i++ {
zero := new(fe6).zero()
a, b := new(fe6), new(fe6)
_, _ = a.rand(rand.Reader)
b.set(a)
fp6AddAssign(a, zero)
if !a.equal(b) {
t.Fatal("a + 0 == a")
}
fp6SubAssign(a, zero)
if !a.equal(b) {
t.Fatal("a - 0 == a")
}
a.set(zero)
fp6DoubleAssign(a)
if !a.equal(zero) {
t.Fatal("2 * 0 == 0")
}
a.set(zero)
fp6SubAssign(a, b)
fp6Neg(b, b)
if !a.equal(b) {
t.Fatal("0-a == -a")
}
_, _ = a.rand(rand.Reader)
b.set(a)
fp6DoubleAssign(a)
fp6AddAssign(b, b)
if !a.equal(b) {
t.Fatal("2 * a == a + a")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
c1, c2 := new(fe6).set(a), new(fe6).set(b)
fp6AddAssign(c1, b)
fp6AddAssign(c2, a)
if !c1.equal(c2) {
t.Fatal("a + b = b + a")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
c1.set(a)
c2.set(b)
fp6SubAssign(c1, b)
fp6SubAssign(c2, a)
fp6Neg(c2, c2)
if !c1.equal(c2) {
t.Fatal("a - b = - ( b - a )")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
c, _ := new(fe6).rand(rand.Reader)
a0 := new(fe6).set(a)
fp6AddAssign(a, b)
fp6AddAssign(a, c)
fp6AddAssign(b, c)
fp6AddAssign(b, a0)
if !a.equal(b) {
t.Fatal("(a + b) + c == (b + c) + a")
}
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
_, _ = c.rand(rand.Reader)
a0.set(a)
fp6SubAssign(a, b)
fp6SubAssign(a, c)
fp6SubAssign(a0, c)
fp6SubAssign(a0, b)
if !a.equal(a0) {
t.Fatal("(a - b) - c == (a - c) -b")
}
}
}
func TestFp6LazyOperations(t *testing.T) {
f := newFp6(nil)
for i := 0; i < fuz; i++ {
a, _ := new(fe6).rand(rand.Reader)
b, _ := new(fe6).rand(rand.Reader)
c, _ := new(fe6).rand(rand.Reader)
c0 := new(fe6)
c1 := new(fe6)
fp6Ladd(c0, a, b)
fp6Add(c1, a, b)
f.mulAssign(c0, c)
f.mulAssign(c1, c)
if !c0.equal(c1) {
t.Fatal("(a + b) * c == (a l+ b) * c")
}
if !c0.equal(c1) {
t.Fatal("(a + b) * c == (a l+ b) * c")
}
}
}
func TestFp6SparseMultiplication(t *testing.T) {
fp6 := newFp6(nil)
var a, b, u *fe6
for i := 0; i < fuz; i++ {
a, _ = new(fe6).rand(rand.Reader)
b, _ = new(fe6).rand(rand.Reader)
u, _ = new(fe6).rand(rand.Reader)
b[2].zero()
fp6.mul(u, a, b)
fp6._mul01(a, a, &b[0], &b[1])
if !a.equal(u) {
t.Fatal("mul by 01")
}
}
for i := 0; i < fuz; i++ {
a, _ = new(fe6).rand(rand.Reader)
b, _ = new(fe6).rand(rand.Reader)
u, _ = new(fe6).rand(rand.Reader)
b[2].zero()
b[0].zero()
fp6.mul(u, a, b)
fp6._mul1(a, a, &b[1])
if !a.equal(u) {
t.Fatal("mul by 1")
}
}
}
func TestFp6MultiplicationProperties(t *testing.T) {
f := newFp6(nil)
for i := 0; i < fuz; i++ {
a, _ := new(fe6).rand(rand.Reader)
b, _ := new(fe6).rand(rand.Reader)
zero := f.zero()
one := f.one()
c1, c2 := f.new(), f.new()
f.mul(c1, a, zero)
if !c1.equal(zero) {
t.Fatal("a * 0 == 0")
}
f.mul(c1, a, one)
if !c1.equal(a) {
t.Fatal("a * 1 == a")
}
f.mul(c1, a, b)
f.mul(c2, b, a)
if !c1.equal(c2) {
t.Fatal("a * b == b * a")
}
cx, _ := new(fe6).rand(rand.Reader)
f.mul(c1, a, b)
f.mul(c1, c1, cx)
f.mul(c2, cx, b)
f.mul(c2, c2, a)
if !c1.equal(c2) {
t.Fatal("(a * b) * c == (a * c) * b")
}
f.square(a, zero)
if !a.equal(zero) {
t.Fatal("0^2 == 0")
}
f.square(a, one)
if !a.equal(one) {
t.Fatal("1^2 == 1")
}
_, _ = a.rand(rand.Reader)
f.square(c1, a)
f.mul(c2, a, a)
if !c2.equal(c1) {
t.Fatal("a^2 == a*a")
}
}
}
func TestFp6MultiplicationPropertiesAssigned(t *testing.T) {
f := newFp6(nil)
for i := 0; i < fuz; i++ {
a, _ := new(fe6).rand(rand.Reader)
zero, one := new(fe6).zero(), new(fe6).one()
f.mulAssign(a, zero)
if !a.equal(zero) {
t.Fatal("a * 0 == 0")
}
_, _ = a.rand(rand.Reader)
a0 := new(fe6).set(a)
f.mulAssign(a, one)
if !a.equal(a0) {
t.Fatal("a * 1 == a")
}
_, _ = a.rand(rand.Reader)
b, _ := new(fe6).rand(rand.Reader)
a0.set(a)
f.mulAssign(a, b)
f.mulAssign(b, a0)
if !a.equal(b) {
t.Fatal("a * b == b * a")
}
c, _ := new(fe6).rand(rand.Reader)
a0.set(a)
f.mulAssign(a, b)
f.mulAssign(a, c)
f.mulAssign(a0, c)
f.mulAssign(a0, b)
if !a.equal(a0) {
t.Fatal("(a * b) * c == (a * c) * b")
}
}
}
func TestFp6Exponentiation(t *testing.T) {
f := newFp6(nil)
for i := 0; i < fuz; i++ {
a, _ := new(fe6).rand(rand.Reader)
u := f.new()
f.exp(u, a, big.NewInt(0))
if !u.equal(f.one()) {
t.Fatal("a^0 == 1")
}
f.exp(u, a, big.NewInt(1))
if !u.equal(a) {
t.Fatal("a^1 == a")
}
v := f.new()
f.exp(v, a, big.NewInt(8))
f.square(u, a)
f.square(u, u)
f.square(u, u)
if !u.equal(v) {
t.Fatal("((a^2)^2)^2 == a^8", i)
}
}
}
func TestFp6Inversion(t *testing.T) {
f := newFp6(nil)
for i := 0; i < fuz; i++ {
u := f.new()
zero := f.zero()
one := f.one()
f.inverse(u, zero)
if !u.equal(zero) {
t.Fatal("(0^-1) == 0)")
}
f.inverse(u, one)
if !u.equal(one) {
t.Fatal("(1^-1) == 1)")
}
a, _ := new(fe6).rand(rand.Reader)
f.inverse(u, a)
f.mul(u, u, a)
if !u.equal(one) {
t.Fatal("(r*a) * r*(a^-1) == r)")
}
}
}
func TestFp6MultiplicationCross(t *testing.T) {
f := newFp6(nil)
a, b, c0, c1, c2, c3 := new(fe6), new(fe6), new(fe6), new(fe6), new(fe6), new(fe6)
w0 := new(wfe6)
for i := 0; i < fuz; i++ {
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
f.wmul(w0, a, b)
c0.fromWide(w0)
f.mul(c1, a, b)
f._mul(c2, a, b)
c3.set(a)
f.mulAssign(c3, b)
if !c0.equal(c1) {
t.Fatal("multiplication failed")
}
if !c0.equal(c2) {
t.Fatal("multiplication failed")
}
if !c0.equal(c3) {
t.Fatal("multiplication failed")
}
}
}
func TestFp6SquareCross(t *testing.T) {
f := newFp6(nil)
a, c0, c1, c2 := new(fe6), new(fe6), new(fe6), new(fe6)
w0 := new(wfe6)
for i := 0; i < fuz; i++ {
_, _ = a.rand(rand.Reader)
f.wsquare(w0, a)
c0.fromWide(w0)
f.square(c1, a)
f._square(c2, a)
if !c0.equal(c2) {
t.Fatal("squaring failed")
}
if !c0.equal(c1) {
t.Fatal("squaring failed")
}
}
}
func TestFp6SparseMultiplicationCross(t *testing.T) {
f := newFp6(nil)
a, c0, c1, c2 := new(fe6), new(fe6), new(fe6), new(fe6)
w0 := new(wfe6)
for i := 0; i < fuz; i++ {
// mul01
{
_, _ = a.rand(rand.Reader)
b0, _ := new(fe2).rand(rand.Reader)
b1, _ := new(fe2).rand(rand.Reader)
b := new(fe6)
b[0].set(b0)
b[1].set(b1)
f.wmul01(w0, a, b0, b1)
c0.fromWide(w0)
f._mul01(c1, a, b0, b1)
f._mul(c2, a, b)
if !c2.equal(c1) {
t.Fatal("sparse multiplication 01 failed")
}
if !c0.equal(c1) {
t.Fatal("sparse multiplication 01 failed")
}
}
// mul0
{
_, _ = a.rand(rand.Reader)
b1, _ := new(fe2).rand(rand.Reader)
b := new(fe6)
b[1].set(b1)
f.wmul1(w0, a, b1)
c0.fromWide(w0)
f._mul1(c1, a, b1)
f._mul(c2, a, b)
if !c2.equal(c0) {
t.Fatal("sparse multiplication 0 failed")
}
if !c2.equal(c1) {
t.Fatal("sparse multiplication 0 failed")
}
}
}
}
func TestFp12Serialization(t *testing.T) {
f := newFp12(nil)
for i := 0; i < fuz; i++ {
a, _ := new(fe12).rand(rand.Reader)
b, err := f.fromBytes(f.toBytes(a))
if err != nil {
t.Fatal(err)
}
if !a.equal(b) {
t.Fatal("serialization")
}
}
}
func TestFp12AdditionProperties(t *testing.T) {
f := newFp12(nil)
for i := 0; i < fuz; i++ {
zero := f.zero()
a, _ := new(fe12).rand(rand.Reader)
b, _ := new(fe12).rand(rand.Reader)
c1 := f.new()
c2 := f.new()
fp12Add(c1, a, zero)
if !c1.equal(a) {
t.Fatal("a + 0 == a")
}
fp12Sub(c1, a, zero)
if !c1.equal(a) {
t.Fatal("a - 0 == a")
}
fp12Double(c1, zero)
if !c1.equal(zero) {
t.Fatal("2 * 0 == 0")
}
fp12Neg(c1, zero)
if !c1.equal(zero) {
t.Fatal("-0 == 0")
}
fp12Sub(c1, zero, a)
fp12Neg(c2, a)
if !c1.equal(c2) {
t.Fatal("0-a == -a")
}
fp12Double(c1, a)
fp12Add(c2, a, a)
if !c1.equal(c2) {
t.Fatal("2 * a == a + a")
}
fp12Add(c1, a, b)
fp12Add(c2, b, a)
if !c1.equal(c2) {
t.Fatal("a + b = b + a")
}
fp12Sub(c1, a, b)
fp12Sub(c2, b, a)
fp12Neg(c2, c2)
if !c1.equal(c2) {
t.Fatal("a - b = - ( b - a )")
}
cx, _ := new(fe12).rand(rand.Reader)
fp12Add(c1, a, b)
fp12Add(c1, c1, cx)
fp12Add(c2, a, cx)
fp12Add(c2, c2, b)
if !c1.equal(c2) {
t.Fatal("(a + b) + c == (a + c ) + b")
}
fp12Sub(c1, a, b)
fp12Sub(c1, c1, cx)
fp12Sub(c2, a, cx)
fp12Sub(c2, c2, b)
if !c1.equal(c2) {
t.Fatal("(a - b) - c == (a - c ) -b")
}
}
}
func TestFp12MultiplicationProperties(t *testing.T) {
f := newFp12(nil)
for i := 0; i < fuz; i++ {
a, _ := new(fe12).rand(rand.Reader)
b, _ := new(fe12).rand(rand.Reader)
zero := f.zero()
one := f.one()
c1, c2 := f.new(), f.new()
f.mul(c1, a, zero)
if !c1.equal(zero) {
t.Fatal("a * 0 == 0")
}
f.mul(c1, a, one)
if !c1.equal(a) {
t.Fatal("a * 1 == a")
}
f.mul(c1, a, b)
f.mul(c2, b, a)
if !c1.equal(c2) {
t.Fatal("a * b == b * a")
}
cx, _ := new(fe12).rand(rand.Reader)
f.mul(c1, a, b)
f.mul(c1, c1, cx)
f.mul(c2, cx, b)
f.mul(c2, c2, a)
if !c1.equal(c2) {
t.Fatal("(a * b) * c == (a * c) * b")
}
f.square(a, zero)
if !a.equal(zero) {
t.Fatal("0^2 == 0")
}
f.square(a, one)
if !a.equal(one) {
t.Fatal("1^2 == 1")
}
_, _ = a.rand(rand.Reader)
f.square(c1, a)
f.mul(c2, a, a)
if !c2.equal(c1) {
t.Fatal("a^2 == a*a")
}
}
}
func TestFp12MultiplicationPropertiesAssigned(t *testing.T) {
f := newFp12(nil)
zero, one := new(fe12).zero(), new(fe12).one()
for i := 0; i < fuz; i++ {
a, _ := new(fe12).rand(rand.Reader)
f.mulAssign(a, zero)
if !a.equal(zero) {
t.Fatal("a * 0 == 0")
}
_, _ = a.rand(rand.Reader)
a0 := new(fe12).set(a)
f.mulAssign(a, one)
if !a.equal(a0) {
t.Fatal("a * 1 == a")
}
_, _ = a.rand(rand.Reader)
b, _ := new(fe12).rand(rand.Reader)
a0.set(a)
f.mulAssign(a, b)
f.mulAssign(b, a0)
if !a.equal(b) {
t.Fatal("a * b == b * a")
}
c, _ := new(fe12).rand(rand.Reader)
a0.set(a)
f.mul(a, a, b)
f.mul(a, a, c)
f.mul(a0, a0, c)
f.mul(a0, a0, b)
if !a.equal(a0) {
t.Fatal("(a * b) * c == (a * c) * b")
}
}
}
func TestFp12SparseMultiplication(t *testing.T) {
fp12 := newFp12(nil)
var a, b, u *fe12
for j := 0; j < fuz; j++ {
a, _ = new(fe12).rand(rand.Reader)
b, _ = new(fe12).rand(rand.Reader)
u, _ = new(fe12).rand(rand.Reader)
b[0][2].zero()
b[1][0].zero()
b[1][2].zero()
fp12.mul(u, a, b)
fp12.mul014(a, &b[0][0], &b[0][1], &b[1][1])
if !a.equal(u) {
t.Fatal("mul by 01")
}
}
}
func TestFp12Exponentiation(t *testing.T) {
f := newFp12(nil)
for i := 0; i < fuz; i++ {
a, _ := new(fe12).rand(rand.Reader)
u := f.new()
f.exp(u, a, big.NewInt(0))
if !u.equal(f.one()) {
t.Fatal("a^0 == 1")
}
f.exp(u, a, big.NewInt(1))
if !u.equal(a) {
t.Fatal("a^1 == a")
}
v := f.new()
f.mul(u, a, a)
f.mul(u, u, u)
f.mul(u, u, u)
f.exp(v, a, big.NewInt(8))
if !u.equal(v) {
t.Fatal("((a^2)^2)^2 == a^8")
}
}
}
func TestFp12Inversion(t *testing.T) {
f := newFp12(nil)
for i := 0; i < fuz; i++ {
u := f.new()
zero := f.zero()
one := f.one()
f.inverse(u, zero)
if !u.equal(zero) {
t.Fatal("(0^-1) == 0)")
}
f.inverse(u, one)
if !u.equal(one) {
t.Fatal("(1^-1) == 1)")
}
a, _ := new(fe12).rand(rand.Reader)
f.inverse(u, a)
f.mul(u, u, a)
if !u.equal(one) {
t.Fatal("(r*a) * r*(a^-1) == r)")
}
}
}
func TestFrobeniusMapping2(t *testing.T) {
f := newFp2()
a, _ := new(fe2).rand(rand.Reader)
b0, b1, b2, b3 := new(fe2), new(fe2), new(fe2), new(fe2)
f.exp(b0, a, modulus.big())
fp2Conjugate(b1, a)
b2.set(a)
f.frobeniusMap1(b2)
b3.set(a)
f.frobeniusMap(b3, 1)
if !b0.equal(b3) {
t.Fatal("frobenius map failed")
}
if !b1.equal(b3) {
t.Fatal("frobenius map failed")
}
if !b2.equal(b3) {
t.Fatal("frobenius map failed")
}
}
func TestFrobeniusMapping6(t *testing.T) {
{
f := newFp2()
z := nonResidue2
for i := 0; i < 6; i++ {
p, r, e := modulus.big(), new(fe2), big.NewInt(0)
// p ^ i
p.Exp(p, big.NewInt(int64(i)), nil)
// (p ^ i - 1) / 3
e.Sub(p, big.NewInt(1)).Div(e, big.NewInt(3))
// r = z ^ (p ^ i - 1) / 3
f.exp(r, z, e)
if !r.equal(&frobeniusCoeffs61[i]) {
t.Fatalf("bad frobenius fp6 1q coefficient")
}
}
for i := 0; i < 6; i++ {
p, r, e := modulus.big(), new(fe2), big.NewInt(0)
// p ^ i
p.Exp(p, big.NewInt(int64(i)), nil).Mul(p, big.NewInt(2))
// (2 * p ^ i - 2) / 3
e.Sub(p, big.NewInt(2)).Div(e, big.NewInt(3))
// r = z ^ (2 * p ^ i - 2) / 3
f.exp(r, z, e)
if !r.equal(&frobeniusCoeffs62[i]) {
t.Fatalf("bad frobenius fp6 2q coefficient")
}
}
}
f := newFp6(nil)
r0, r1 := f.new(), f.new()
e, _ := new(fe6).rand(rand.Reader)
r0.set(e)
r1.set(e)
f.frobeniusMap(r1, 1)
f.frobeniusMap1(r0)
if !r0.equal(r1) {
t.Fatalf("frobenius mapping by 1 failed")
}
r0.set(e)
r1.set(e)
f.frobeniusMap(r1, 2)
f.frobeniusMap2(r0)
if !r0.equal(r1) {
t.Fatalf("frobenius mapping by 2 failed")
}
r0.set(e)
r1.set(e)
f.frobeniusMap(r1, 3)
f.frobeniusMap3(r0)
if !r0.equal(r1) {
t.Fatalf("frobenius mapping by 3 failed")
}
}
func TestFrobeniusMapping12(t *testing.T) {
{
f := newFp2()
z := nonResidue2
for i := 0; i < 12; i++ {
p, r, e := modulus.big(), new(fe2), big.NewInt(0)
// p ^ i
p.Exp(p, big.NewInt(int64(i)), nil)
// (p ^ i - 1) / 6
e.Sub(p, big.NewInt(1)).Div(e, big.NewInt(6))
// r = z ^ (p ^ i - 1) / 6
f.exp(r, z, e)
if !r.equal(&frobeniusCoeffs12[i]) {
t.Fatalf("bad frobenius fp12 coefficient")
}
}
}
f := newFp12(nil)
r0, r1 := f.new(), f.new()
e, _ := new(fe12).rand(rand.Reader)
p := modulus.big()
f.exp(r0, e, p)
r1.set(e)
f.frobeniusMap1(r1)
if !r0.equal(r1) {
t.Fatalf("frobenius mapping by 1 failed")
}
p.Mul(p, modulus.big())
f.exp(r0, e, p)
r1.set(e)
f.frobeniusMap2(r1)
if !r0.equal(r1) {
t.Fatalf("frobenius mapping by 2 failed")
}
p.Mul(p, modulus.big())
f.exp(r0, e, p)
r1.set(e)
f.frobeniusMap3(r1)
if !r0.equal(r1) {
t.Fatalf("frobenius mapping by 2 failed")
}
}
func TestFp12MultiplicationCross(t *testing.T) {
f := newFp12(nil)
a, b, c0, c1, c2 := new(fe12), new(fe12), new(fe12), new(fe12), new(fe12)
for i := 0; i < fuz; i++ {
_, _ = a.rand(rand.Reader)
_, _ = b.rand(rand.Reader)
f.mul(c0, a, b)
c1.set(a)
f.mulAssign(c1, b)
f._mul(c2, a, b)
if !c0.equal(c1) {
t.Fatal("multiplication failed")
}
if !c0.equal(c2) {
t.Fatal("multiplication failed")
}
}
}
func TestFp12SparseMultiplicationCross(t *testing.T) {
f := newFp12(nil)
a, c0, c1 := new(fe12), new(fe12), new(fe12)
for i := 0; i < fuz; i++ {
_, _ = a.rand(rand.Reader)
b0, _ := new(fe2).rand(rand.Reader)
b1, _ := new(fe2).rand(rand.Reader)
b4, _ := new(fe2).rand(rand.Reader)
b := new(fe12)
b[0][0].set(b0)
b[0][1].set(b1)
b[1][1].set(b4)
c0.set(a)
f.mul014(c0, b0, b1, b4)
f._mul(c1, a, b)
if !c0.equal(c1) {
t.Fatal("sparse multiplication 014 failed")
}
}
}
func TestFp4MultiplicationCross(t *testing.T) {
f := newFp12(nil)
a0, a1, b0, b1 := new(fe2), new(fe2), new(fe2), new(fe2)
c0, c1 := new(fe2), new(fe2)
for i := 0; i < fuz; i++ {
_, _ = a0.rand(rand.Reader)
_, _ = a1.rand(rand.Reader)
_, _ = b0.rand(rand.Reader)
_, _ = b1.rand(rand.Reader)
c0.set(a0)
c1.set(a1)
f._fp4Square(a0, a1, b0, b1)
f.fp4Square(c0, c1, b0, b1)
if !a0.equal(c0) {
t.Fatal("fp4 multiplication failed")
}
if !a1.equal(c1) {
t.Fatal("fp4 multiplication failed")
}
}
}
func BenchmarkFpMul(t *testing.B) {
a, _ := new(fe).rand(rand.Reader)
b, _ := new(fe).rand(rand.Reader)
c := new(fe)
t.ResetTimer()
for i := 0; i < t.N; i++ {
mul(c, a, b)
}
}
func (fe *wfe) bytes() []byte {
out := make([]byte, fpByteSize*2)
var a int
for i := 0; i < 2*fpNumberOfLimbs; i++ {
a = fpByteSize*2 - i*8
out[a-1] = byte(fe[i])
out[a-2] = byte(fe[i] >> 8)
out[a-3] = byte(fe[i] >> 16)
out[a-4] = byte(fe[i] >> 24)
out[a-5] = byte(fe[i] >> 32)
out[a-6] = byte(fe[i] >> 40)
out[a-7] = byte(fe[i] >> 48)
out[a-8] = byte(fe[i] >> 56)
}
return out
}
func (fe *wfe) equal(fe2 *wfe) bool {
return fe2[0] == fe[0] && fe2[1] == fe[1] && fe2[2] == fe[2] && fe2[3] == fe[3] && fe2[4] == fe[4] && fe2[5] == fe[5] && fe2[6] == fe[6] && fe2[7] == fe[7] && fe2[8] == fe[8] && fe2[9] == fe[9] && fe2[10] == fe[10] && fe2[11] == fe[11]
}
func (fe *wfe2) equal(fe2 *wfe2) bool {
return fe[0].equal(&fe2[0]) && fe[1].equal(&fe2[1])
}
func _fp2MulByNonResidue(c, a *fe2) {
t0 := &fe{}
add(t0, &a[0], &a[1])
sub(&c[0], &a[0], &a[1])
c[1].set(t0)
}
func _wfp2Add(c, a, b *wfe2) {
wadd(&c[0], &a[0], &b[0])
wadd(&c[1], &a[1], &b[1])
}
func _wfp2Ladd(c, a, b *wfe2) {
lwadd(&c[0], &a[0], &b[0])
lwadd(&c[1], &a[1], &b[1])
}
func _wfp2AddMixed(c, a, b *wfe2) {
wadd(&c[0], &a[0], &b[0])
lwadd(&c[1], &a[1], &b[1])
}
func _wfp2Sub(c, a, b *wfe2) {
wsub(&c[0], &a[0], &b[0])
wsub(&c[1], &a[1], &b[1])
}
func _wfp2SubMixed(c, a, b *wfe2) {
wsub(&c[0], &a[0], &b[0])
lwsub(&c[1], &a[1], &b[1])
}
func _wfp2Double(c, a *wfe2) {
wdouble(&c[0], &a[0])
wdouble(&c[1], &a[1])
}
func _wfp2MulByNonResidue(c, a *wfe2) {
wt0 := &wfe{}
wadd(wt0, &a[0], &a[1])
wsub(&c[0], &a[0], &a[1])
c[1].set(wt0)
}
func _wfp2Mul(c *wfe2, a, b *fe2) {
wt0, wt1 := new(wfe), new(wfe)
t0, t1 := new(fe), new(fe)
wmul(wt0, &a[0], &b[0]) // a0b0
wmul(wt1, &a[1], &b[1]) // a1b1
wsub(&c[0], wt0, wt1) // c0 = a0b0 - a1b1
lwaddAssign(wt0, wt1) // a0b0 + a1b1
ladd(t0, &a[0], &a[1]) // a0 + a1
ladd(t1, &b[0], &b[1]) // b0 + b1
wmul(wt1, t0, t1) // (a0 + a1)(b0 + b1)
lwsub(&c[1], wt1, wt0) // c1 = (a0 + a1)(b0 + b1) - (a0b0 + a1b1)
}
func _wfp2Square(c *wfe2, a *fe2) {
t0, t1, t2 := new(fe), new(fe), new(fe)
ladd(t0, &a[0], &a[1]) // (a0 + a1)
sub(t1, &a[0], &a[1]) // (a0 - a1)
ldouble(t2, &a[0]) // 2a0
wmul(&c[0], t1, t0) // c0 = (a0 + a1)(a0 - a1)
wmul(&c[1], t2, &a[1]) // c1 = 2a0a1
}
func (e *fp6) _mul(c, a, b *fe6) {
t0, t1, t2, t3, t4, t5 := new(fe2), new(fe2), new(fe2), new(fe2), new(fe2), new(fe2)
e.fp2.mul(t0, &a[0], &b[0]) // v0 = a0b0
e.fp2.mul(t1, &a[1], &b[1]) // v1 = a1b1
e.fp2.mul(t2, &a[2], &b[2]) // v2 = a2b2
fp2Add(t3, &a[1], &a[2]) // a1 + a2
fp2Add(t4, &b[1], &b[2]) // b1 + b2
e.fp2.mulAssign(t3, t4) // (a1 + a2)(b1 + b2)
fp2Add(t4, t1, t2) // v1 + v2
fp2SubAssign(t3, t4) // (a1 + a2)(b1 + b2) - v1 - v2
mulByNonResidueAssign(t3) // ((a1 + a2)(b1 + b2) - v1 - v2)β
fp2AddAssign(t3, t0) // c0 = ((a1 + a2)(b1 + b2) - v1 - v2)β + v0
fp2Add(t5, &a[0], &a[1]) // a0 + a1
fp2Add(t4, &b[0], &b[1]) // b0 + b1
e.fp2.mulAssign(t5, t4) // (a0 + a1)(b0 + b1)
fp2Add(t4, t0, t1) // v0 + v1
fp2SubAssign(t5, t4) // (a0 + a1)(b0 + b1) - v0 - v1
mulByNonResidue(t4, t2) // βv2
fp2Add(&c[1], t5, t4) // c1 = (a0 + a1)(b0 + b1) - v0 - v1 + βv2
fp2Add(t5, &a[0], &a[2]) // a0 + a2
fp2Add(t4, &b[0], &b[2]) // b0 + b2
e.fp2.mulAssign(t5, t4) // (a0 + a2)(b0 + b2)
fp2Add(t4, t0, t2) // v0 + v2
fp2SubAssign(t5, t4) // (a0 + a2)(b0 + b2) - v0 - v2
fp2Add(&c[2], t1, t5) // c2 = (a0 + a2)(b0 + b2) - v0 - v2 + v1
c[0].set(t3)
}
func (e *fp6) _mul01(c, a *fe6, b0, b1 *fe2) {
t0, t1, t2, t3, t4 := new(fe2), new(fe2), new(fe2), new(fe2), new(fe2)
e.fp2.mul(t0, &a[0], b0) // v0 = b0a0
e.fp2.mul(t1, &a[1], b1) // v1 = a1b1
fp2Add(t2, &a[1], &a[2]) // a1 + a2
e.fp2.mulAssign(t2, b1) // b1(a1 + a2)
fp2SubAssign(t2, t1) // b1(a1 + a2) - v1
mulByNonResidueAssign(t2) // (b1(a1 + a2) - v1)β
fp2Add(t3, &a[0], &a[2]) // a0 + a2
e.fp2.mulAssign(t3, b0) // b0(a0 + a2)
fp2SubAssign(t3, t0) // b0(a0 + a2) - v0
fp2Add(&c[2], t3, t1) // b0(a0 + a2) - v0 + v1
fp2Add(t4, b0, b1) // (b0 + b1)
fp2Add(t3, &a[0], &a[1]) // (a0 + a1)
e.fp2.mulAssign(t4, t3) // (a0 + a1)(b0 + b1)
fp2SubAssign(t4, t0) // (a0 + a1)(b0 + b1) - v0
fp2Sub(&c[1], t4, t1) // (a0 + a1)(b0 + b1) - v0 - v1
fp2Add(&c[0], t2, t0) // (b1(a1 + a2) - v1)β + v0
}
func (e *fp6) _mul1(c, a *fe6, b1 *fe2) {
t := new(fe2)
e.fp2.mul(t, &a[2], b1)
e.fp2.mul(&c[2], &a[1], b1)
e.fp2.mul(&c[1], &a[0], b1)
mulByNonResidue(&c[0], t)
}
func (e *fp6) _square(c, a *fe6) {
t0, t1, t2, t3, t4, t5 := new(fe2), new(fe2), new(fe2), new(fe2), new(fe2), new(fe2)
e.fp2.square(t0, &a[0])
e.fp2.mul(t1, &a[0], &a[1])
fp2DoubleAssign(t1)
fp2Sub(t2, &a[0], &a[1])
fp2AddAssign(t2, &a[2])
e.fp2.squareAssign(t2)
e.fp2.mul(t3, &a[1], &a[2])
fp2DoubleAssign(t3)
e.fp2.square(t4, &a[2])
mulByNonResidue(t5, t3)
fp2Add(&c[0], t0, t5)
mulByNonResidue(t5, t4)
fp2Add(&c[1], t1, t5)
fp2AddAssign(t1, t2)
fp2AddAssign(t1, t3)
fp2AddAssign(t0, t4)
fp2Sub(&c[2], t1, t0)
}
func (e *fp12) _mul(c, a, b *fe12) {
t0, t1, t2, t3 := new(fe6), new(fe6), new(fe6), new(fe6)
e.fp6.mul(t1, &a[0], &b[0]) // v0 = a0b0
e.fp6.mul(t2, &a[1], &b[1]) // v1 = a1b1
fp6Add(t0, &a[0], &a[1]) // a0 + a1
fp6Add(t3, &b[0], &b[1]) // b0 + b1
e.fp6.mulAssign(t0, t3) // (a0 + a1)(b0 + b1)
fp6SubAssign(t0, t1) // (a0 + a1)(b0 + b1) - v0
fp6Sub(&c[1], t0, t2) // c1 = (a0 + a1)(b0 + b1) - v0 - v1
e.fp6.mulByNonResidue(t2, t2) // βv1
fp6Add(&c[0], t1, t2) // c0 = v0 + βv1
}
func (e *fp12) _fp4Square(c0, c1, a0, a1 *fe2) {
t, fp2 := e.t2, e.fp2()
fp2.square(t[0], a0) // a0^2
fp2.square(t[1], a1) // a1^2
mulByNonResidue(t[2], t[1]) // βa1^2
fp2Add(c0, t[2], t[0]) // c0 = βa1^2 + a0^2
fp2Add(t[2], a0, a1) // a0 + a1
fp2.squareAssign(t[2]) // (a0 + a1)^2
fp2SubAssign(t[2], t[0]) // (a0 + a1)^2 - a0^2
fp2Sub(c1, t[2], t[1]) // (a0 + a1)^2 - a0^2 - a1^2
}