Files
crypto/core/curves/native/bls12381/g2_test.go

570 lines
14 KiB
Go

package bls12381
import (
crand "crypto/rand"
"encoding/hex"
"testing"
"github.com/stretchr/testify/require"
"github.com/sonr-io/crypto/core/curves/native"
)
func TestG2IsOnCurve(t *testing.T) {
require.Equal(t, 1, new(G2).Identity().IsOnCurve())
require.Equal(t, 1, new(G2).Generator().IsOnCurve())
z := fp2{
A: fp{
0xba7a_fa1f_9a6f_e250,
0xfa0f_5b59_5eaf_e731,
0x3bdc_4776_94c3_06e7,
0x2149_be4b_3949_fa24,
0x64aa_6e06_49b2_078c,
0x12b1_08ac_3364_3c3e,
},
B: fp{
0x1253_25df_3d35_b5a8,
0xdc46_9ef5_555d_7fe3,
0x02d7_16d2_4431_06a9,
0x05a1_db59_a6ff_37d0,
0x7cf7_784e_5300_bb8f,
0x16a8_8922_c7a5_e844,
},
}
test := new(G2).Generator()
test.x.Mul(&test.x, &z)
test.y.Mul(&test.y, &z)
test.z.Set(&z)
require.Equal(t, 1, test.IsOnCurve())
test.x.Set(&z)
require.Equal(t, 0, test.IsOnCurve())
}
func TestG2Equal(t *testing.T) {
a := new(G2).Generator()
b := new(G2).Identity()
require.Equal(t, 1, a.Equal(a))
require.Equal(t, 0, a.Equal(b))
require.Equal(t, 1, b.Equal(b))
}
func TestG2ToAffine(t *testing.T) {
a := new(G2).Generator()
z := fp2{
A: fp{
0xba7afa1f9a6fe250,
0xfa0f5b595eafe731,
0x3bdc477694c306e7,
0x2149be4b3949fa24,
0x64aa6e0649b2078c,
0x12b108ac33643c3e,
},
B: fp{
0x125325df3d35b5a8,
0xdc469ef5555d7fe3,
0x02d716d2443106a9,
0x05a1db59a6ff37d0,
0x7cf7784e5300bb8f,
0x16a88922c7a5e844,
},
}
a.x.Mul(&a.x, &z)
a.y.Mul(&a.y, &z)
a.z.Set(&z)
require.Equal(t, 1, a.ToAffine(a).Equal(new(G2).Generator()))
}
func TestG2Double(t *testing.T) {
a := new(G2).Identity()
require.Equal(t, 1, a.Double(a).IsIdentity())
a.Generator()
a.Double(a)
e := G2{
x: fp2{
A: fp{
0xe9d9e2da9620f98b,
0x54f1199346b97f36,
0x3db3b820376bed27,
0xcfdb31c9b0b64f4c,
0x41d7c12786354493,
0x05710794c255c064,
},
B: fp{
0xd6c1d3ca6ea0d06e,
0xda0cbd905595489f,
0x4f5352d43479221d,
0x8ade5d736f8c97e0,
0x48cc8433925ef70e,
0x08d7ea71ea91ef81,
},
},
y: fp2{
A: fp{
0x15ba26eb4b0d186f,
0x0d086d64b7e9e01e,
0xc8b848dd652f4c78,
0xeecf46a6123bae4f,
0x255e8dd8b6dc812a,
0x164142af21dcf93f,
},
B: fp{
0xf9b4a1a895984db4,
0xd417b114cccff748,
0x6856301fc89f086e,
0x41c777878931e3da,
0x3556b155066a2105,
0x00acf7d325cb89cf,
},
},
z: *((&fp2{}).SetOne()),
}
require.Equal(t, 1, e.Equal(a))
}
func TestG2Add(t *testing.T) {
a := new(G2).Identity()
b := new(G2).Identity()
c := new(G2).Add(a, b)
require.Equal(t, 1, c.IsIdentity())
b.Generator()
c.Add(a, b)
require.Equal(t, 1, c.Equal(b))
a.Generator()
a.Double(a)
a.Double(a)
b.Double(b)
c.Add(a, b)
d := new(G2).Generator()
e := new(G2).Generator()
for i := 0; i < 5; i++ {
e.Add(e, d)
}
require.Equal(t, 1, e.Equal(c))
// Degenerate case
beta := fp2{
A: fp{
0xcd03c9e48671f071,
0x5dab22461fcda5d2,
0x587042afd3851b95,
0x8eb60ebe01bacb9e,
0x03f97d6e83d050d2,
0x18f0206554638741,
},
B: fp{},
}
beta.Square(&beta)
b.x.Mul(&a.x, &beta)
b.y.Neg(&a.y)
b.z.Set(&a.z)
require.Equal(t, 1, b.IsOnCurve())
c.Add(a, b)
e.x.Set(&fp2{
A: fp{
0x705abc799ca773d3,
0xfe132292c1d4bf08,
0xf37ece3e07b2b466,
0x887e1c43f447e301,
0x1e0970d033bc77e8,
0x1985c81e20a693f2,
},
B: fp{
0x1d79b25db36ab924,
0x23948e4d529639d3,
0x471ba7fb0d006297,
0x2c36d4b4465dc4c0,
0x82bbc3cfec67f538,
0x051d2728b67bf952,
},
})
e.y.Set(&fp2{
A: fp{
0x41b1bbf6576c0abf,
0xb6cc93713f7a0f9a,
0x6b65b43e48f3f01f,
0xfb7a4cfcaf81be4f,
0x3e32dadc6ec22cb6,
0x0bb0fc49d79807e3,
},
B: fp{
0x7d1397788f5f2ddf,
0xab2907144ff0d8e8,
0x5b7573e0cdb91f92,
0x4cb8932dd31daf28,
0x62bbfac6db052a54,
0x11f95c16d14c3bbe,
},
})
e.z.SetOne()
require.Equal(t, 1, e.Equal(c))
}
func TestG2Neg(t *testing.T) {
a := new(G2).Generator()
b := new(G2).Neg(a)
require.Equal(t, 1, new(G2).Add(a, b).IsIdentity())
require.Equal(t, 1, new(G2).Sub(a, b.Neg(b)).IsIdentity())
a.Identity()
require.Equal(t, 1, a.Neg(a).IsIdentity())
}
func TestG2Mul(t *testing.T) {
g := new(G2).Generator()
a := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{
0x2b56_8297_a56d_a71c,
0xd8c3_9ecb_0ef3_75d1,
0x435c_38da_67bf_bf96,
0x8088_a050_26b6_59b2,
})
b := Bls12381FqNew().SetRaw(&[native.FieldLimbs]uint64{
0x785f_dd9b_26ef_8b85,
0xc997_f258_3769_5c18,
0x4c8d_bc39_e7b7_56c1,
0x70d9_b6cc_6d87_df20,
})
c := Bls12381FqNew().Mul(a, b)
t1 := new(G2).Generator()
t1.Mul(t1, a)
t1.Mul(t1, b)
require.Equal(t, 1, t1.Equal(g.Mul(g, c)))
}
func TestG2InCorrectSubgroup(t *testing.T) {
a := G2{
x: fp2{
A: fp{
0x89f550c813db6431,
0xa50be8c456cd8a1a,
0xa45b374114cae851,
0xbb6190f5bf7fff63,
0x970ca02c3ba80bc7,
0x02b85d24e840fbac,
},
B: fp{
0x6888bc53d70716dc,
0x3dea6b4117682d70,
0xd8f5f930500ca354,
0x6b5ecb6556f5c155,
0xc96bef0434778ab0,
0x05081505515006ad,
},
},
y: fp2{
A: fp{
0x3cf1ea0d434b0f40,
0x1a0dc610e603e333,
0x7f89956160c72fa0,
0x25ee03decf6431c5,
0xeee8e206ec0fe137,
0x097592b226dfef28,
},
B: fp{
0x71e8bb5f29247367,
0xa5fe049e211831ce,
0x0ce6b354502a3896,
0x93b012000997314e,
0x6759f3b6aa5b42ac,
0x156944c4dfe92bbb,
},
},
z: *(&fp2{}).SetOne(),
}
require.Equal(t, 0, a.InCorrectSubgroup())
require.Equal(t, 1, new(G2).Identity().InCorrectSubgroup())
require.Equal(t, 1, new(G2).Generator().InCorrectSubgroup())
}
func TestG2MulByX(t *testing.T) {
// multiplying by `x` a point in G2 is the same as multiplying by
// the equivalent scalar.
x := Bls12381FqNew().SetUint64(paramX)
x.Neg(x)
t1 := new(G2).Generator()
t1.MulByX(t1)
t2 := new(G2).Generator()
t2.Mul(t2, x)
require.Equal(t, 1, t1.Equal(t2))
point := new(G2).Generator()
a := Bls12381FqNew().SetUint64(42)
point.Mul(point, a)
t1.MulByX(point)
t2.Mul(point, x)
require.Equal(t, 1, t1.Equal(t2))
}
func TestG2Psi(t *testing.T) {
generator := new(G2).Generator()
z := fp2{
A: fp{
0x0ef2ddffab187c0a,
0x2424522b7d5ecbfc,
0xc6f341a3398054f4,
0x5523ddf409502df0,
0xd55c0b5a88e0dd97,
0x066428d704923e52,
},
B: fp{
0x538bbe0c95b4878d,
0xad04a50379522881,
0x6d5c05bf5c12fb64,
0x4ce4a069a2d34787,
0x59ea6c8d0dffaeaf,
0x0d42a083a75bd6f3,
},
}
// `point` is a random point in the curve
point := G2{
x: fp2{
A: fp{
0xee4c8cb7c047eaf2,
0x44ca22eee036b604,
0x33b3affb2aefe101,
0x15d3e45bbafaeb02,
0x7bfc2154cd7419a4,
0x0a2d0c2b756e5edc,
},
B: fp{
0xfc224361029a8777,
0x4cbf2baab8740924,
0xc5008c6ec6592c89,
0xecc2c57b472a9c2d,
0x8613eafd9d81ffb1,
0x10fe54daa2d3d495,
},
},
y: fp2{
A: fp{
0x7de7edc43953b75c,
0x58be1d2de35e87dc,
0x5731d30b0e337b40,
0xbe93b60cfeaae4c9,
0x8b22c203764bedca,
0x01616c8d1033b771,
},
B: fp{
0xea126fe476b5733b,
0x85cee68b5dae1652,
0x98247779f7272b04,
0xa649c8b468c6e808,
0xb5b9a62dff0c4e45,
0x1555b67fc7bbe73d,
},
},
z: *(&fp2{}).Set(&z),
}
point.x.Mul(&point.x, &z)
point.z.Square(&point.z)
point.z.Mul(&point.z, &z)
require.Equal(t, 1, point.IsOnCurve())
// psi2(P) = psi(psi(P))
tv1 := new(G2).psi2(generator)
tv2 := new(G2).psi(generator)
tv2.psi(tv2)
require.Equal(t, 1, tv1.Equal(tv2))
tv1.psi2(&point)
tv2.psi(&point)
tv2.psi(tv2)
require.Equal(t, 1, tv1.Equal(tv2))
// psi(P) is a morphism
tv1.Double(generator)
tv1.psi(tv1)
tv2.psi(generator)
tv2.Double(tv2)
require.Equal(t, 1, tv1.Equal(tv2))
tv1.psi(&point)
tv2.psi(generator)
tv1.Add(tv1, tv2)
tv2.Set(&point)
tv3 := new(G2).Generator()
tv2.Add(tv2, tv3)
tv2.psi(tv2)
require.Equal(t, 1, tv1.Equal(tv2))
}
func TestG2ClearCofactor(t *testing.T) {
z := fp2{
A: fp{
0x0ef2ddffab187c0a,
0x2424522b7d5ecbfc,
0xc6f341a3398054f4,
0x5523ddf409502df0,
0xd55c0b5a88e0dd97,
0x066428d704923e52,
},
B: fp{
0x538bbe0c95b4878d,
0xad04a50379522881,
0x6d5c05bf5c12fb64,
0x4ce4a069a2d34787,
0x59ea6c8d0dffaeaf,
0x0d42a083a75bd6f3,
},
}
// `point` is a random point in the curve
point := G2{
x: fp2{
A: fp{
0xee4c8cb7c047eaf2,
0x44ca22eee036b604,
0x33b3affb2aefe101,
0x15d3e45bbafaeb02,
0x7bfc2154cd7419a4,
0x0a2d0c2b756e5edc,
},
B: fp{
0xfc224361029a8777,
0x4cbf2baab8740924,
0xc5008c6ec6592c89,
0xecc2c57b472a9c2d,
0x8613eafd9d81ffb1,
0x10fe54daa2d3d495,
},
},
y: fp2{
A: fp{
0x7de7edc43953b75c,
0x58be1d2de35e87dc,
0x5731d30b0e337b40,
0xbe93b60cfeaae4c9,
0x8b22c203764bedca,
0x01616c8d1033b771,
},
B: fp{
0xea126fe476b5733b,
0x85cee68b5dae1652,
0x98247779f7272b04,
0xa649c8b468c6e808,
0xb5b9a62dff0c4e45,
0x1555b67fc7bbe73d,
},
},
z: fp2{},
}
point.x.Mul(&point.x, &z)
point.z.Square(&z)
point.z.Mul(&point.z, &z)
require.Equal(t, 1, point.IsOnCurve())
require.Equal(t, 0, point.InCorrectSubgroup())
clearedPoint := new(G2).ClearCofactor(&point)
require.Equal(t, 1, clearedPoint.IsOnCurve())
require.Equal(t, 1, clearedPoint.InCorrectSubgroup())
// the generator (and the identity) are always on the curve,
// even after clearing the cofactor
generator := new(G2).Generator()
generator.ClearCofactor(generator)
require.Equal(t, 1, generator.InCorrectSubgroup())
id := new(G2).Identity()
id.ClearCofactor(id)
require.Equal(t, 1, id.InCorrectSubgroup())
// test the effect on q-torsion points multiplying by h_eff modulo q
// h_eff % q = 0x2b116900400069009a40200040001ffff
hEffModq := [native.FieldBytes]byte{
0xff, 0xff, 0x01, 0x00, 0x04, 0x00, 0x02, 0xa4, 0x09, 0x90, 0x06, 0x00, 0x04, 0x90, 0x16,
0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
}
generator.Generator()
generator.multiply(generator, &hEffModq)
point.Generator().ClearCofactor(&point)
require.Equal(t, 1, point.Equal(generator))
point.ClearCofactor(clearedPoint)
require.Equal(t, 1, point.Equal(clearedPoint.multiply(clearedPoint, &hEffModq)))
}
func TestG2Hash(t *testing.T) {
dst := []byte("QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_")
tests := []struct {
input, expected string
}{
{
"",
"05cb8437535e20ecffaef7752baddf98034139c38452458baeefab379ba13dff5bf5dd71b72418717047f5b0f37da03d0141ebfbdca40eb85b87142e130ab689c673cf60f1a3e98d69335266f30d9b8d4ac44c1038e9dcdd5393faf5c41fb78a12424ac32561493f3fe3c260708a12b7c620e7be00099a974e259ddc7d1f6395c3c811cdd19f1e8dbf3e9ecfdcbab8d60503921d7f6a12805e72940b963c0cf3471c7b2a524950ca195d11062ee75ec076daf2d4bc358c4b190c0c98064fdd92",
},
{
"abc",
"139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd802c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e600aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd161787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48",
},
{
"abcdef0123456789",
"190d119345b94fbd15497bcba94ecf7db2cbfd1e1fe7da034d26cbba169fb3968288b3fafb265f9ebd380512a71c3f2c121982811d2491fde9ba7ed31ef9ca474f0e1501297f68c298e9f4c0028add35aea8bb83d53c08cfc007c1e005723cd00bb5e7572275c567462d91807de765611490205a941a5a6af3b1691bfe596c31225d3aabdf15faff860cb4ef17c7c3be05571a0f8d3c08d094576981f4a3b8eda0a8e771fcdcc8ecceaf1356a6acf17574518acb506e435b639353c2e14827c8",
},
{
"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
"0934aba516a52d8ae479939a91998299c76d39cc0c035cd18813bec433f587e2d7a4fef038260eef0cef4d02aae3eb9119a84dd7248a1066f737cc34502ee5555bd3c19f2ecdb3c7d9e24dc65d4e25e50d83f0f77105e955d78f4762d33c17da09bcccfa036b4847c9950780733633f13619994394c23ff0b32fa6b795844f4a0673e20282d07bc69641cee04f5e566214f81cd421617428bc3b9fe25afbb751d934a00493524bc4e065635b0555084dd54679df1536101b2c979c0152d09192",
},
{
"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"11fca2ff525572795a801eed17eb12785887c7b63fb77a42be46ce4a34131d71f7a73e95fee3f812aea3de78b4d0156901a6ba2f9a11fa5598b2d8ace0fbe0a0eacb65deceb476fbbcb64fd24557c2f4b18ecfc5663e54ae16a84f5ab7f6253403a47f8e6d1763ba0cad63d6114c0accbef65707825a511b251a660a9b3994249ae4e63fac38b23da0c398689ee2ab520b6798718c8aed24bc19cb27f866f1c9effcdbf92397ad6448b5c9db90d2b9da6cbabf48adc1adf59a1a28344e79d57e",
},
}
pt := new(G2).Identity()
ept := new(G2).Identity()
var b [DoubleWideFieldBytes]byte
for _, tst := range tests {
i := []byte(tst.input)
e, _ := hex.DecodeString(tst.expected)
copy(b[:], e)
_, _ = ept.FromUncompressed(&b)
pt.Hash(native.EllipticPointHasherSha256(), i, dst)
require.Equal(t, 1, pt.Equal(ept))
}
}
func TestG2SumOfProducts(t *testing.T) {
var b [64]byte
h0, _ := new(G2).Random(crand.Reader)
_, _ = crand.Read(b[:])
s := Bls12381FqNew().SetBytesWide(&b)
_, _ = crand.Read(b[:])
sTilde := Bls12381FqNew().SetBytesWide(&b)
_, _ = crand.Read(b[:])
c := Bls12381FqNew().SetBytesWide(&b)
lhs := new(G2).Mul(h0, s)
rhs, _ := new(G2).SumOfProducts([]*G2{h0}, []*native.Field{s})
require.Equal(t, 1, lhs.Equal(rhs))
u := new(G2).Mul(h0, s)
uTilde := new(G2).Mul(h0, sTilde)
sHat := Bls12381FqNew().Mul(c, s)
sHat.Sub(sTilde, sHat)
rhs.Mul(u, c)
rhs.Add(rhs, new(G2).Mul(h0, sHat))
require.Equal(t, 1, uTilde.Equal(rhs))
_, _ = rhs.SumOfProducts([]*G2{u, h0}, []*native.Field{c, sHat})
require.Equal(t, 1, uTilde.Equal(rhs))
}