1import (
2	"math/big"
3	"fmt"
4	"testing"
5
6	"github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr"
7    "github.com/leanovate/gopter"
8	"github.com/leanovate/gopter/prop"
9)
10
11// ------------------------------------------------------------
12// examples
13
14func ExampleMillerLoop() {
15
16	// samples a random scalar r
17	var r big.Int
18	var rFr fr.Element
19	rFr.SetRandom()
20	rFr.ToBigIntRegular(&r)
21
22	// computes r*g1Gen, r*g2Gen
23	var rg1 G1Affine
24	var rg2 G2Affine
25	rg1.ScalarMultiplication(&g1GenAff, &r)
26	rg2.ScalarMultiplication(&g2GenAff, &r)
27
28	// Computes e(g1GenAff, ag2) and e(ag1, g2GenAff)
29	e1, _ := Pair([]G1Affine{g1GenAff}, []G2Affine{rg2})
30	E2, _ := Pair([]G1Affine{rg1}, []G2Affine{g2GenAff})
31
32	// checks that bilinearity property holds
33	check := e1.Equal(&E2)
34
35	fmt.Printf("%t\n", check)
36	// Output: true
37
38}
39
40// ------------------------------------------------------------
41// tests
42
43func TestPairing(t *testing.T) {
44
45	parameters := gopter.DefaultTestParameters()
46	parameters.MinSuccessfulTests = 100
47
48	properties := gopter.NewProperties(parameters)
49
50	genA := GenE12()
51	genR1 := GenFr()
52	genR2 := GenFr()
53
54	properties.Property("[{{ toUpper .Name}}] Having the receiver as operand (final expo) should output the same result", prop.ForAll(
55		func(a *GT) bool {
56			var b GT
57			b.Set(a)
58			b = FinalExponentiation(a)
59			*a = FinalExponentiation(a)
60			return a.Equal(&b)
61		},
62		genA,
63	))
64
65    properties.Property("[{{ toUpper .Name}}] Exponentiating FinalExpo(a) to r should output 1", prop.ForAll(
66		func(a *GT) bool {
67			var one GT
68			e := fr.Modulus()
69			one.SetOne()
70			*a = FinalExponentiation(a)
71			a.Exp(a, *e)
72			return a.Equal(&one)
73		},
74		genA,
75	))
76
77	properties.Property("[{{ toUpper .Name}}] bilinearity", prop.ForAll(
78		func(a, b fr.Element) bool {
79
80			var res, resa, resb, resab, zero GT
81
82			var ag1 G1Affine
83			var bg2 G2Affine
84
85			var abigint, bbigint, ab big.Int
86
87			a.ToBigIntRegular(&abigint)
88			b.ToBigIntRegular(&bbigint)
89			ab.Mul(&abigint, &bbigint)
90
91			ag1.ScalarMultiplication(&g1GenAff, &abigint)
92			bg2.ScalarMultiplication(&g2GenAff, &bbigint)
93
94			res, _ = Pair([]G1Affine{g1GenAff}, []G2Affine{g2GenAff})
95			resa, _ = Pair([]G1Affine{ag1}, []G2Affine{g2GenAff})
96			resb, _ = Pair([]G1Affine{g1GenAff}, []G2Affine{bg2})
97
98			resab.Exp(&res, ab)
99			resa.Exp(&resa, bbigint)
100			resb.Exp(&resb, abigint)
101
102			return resab.Equal(&resa) && resab.Equal(&resb) && !res.Equal(&zero)
103
104		},
105		genR1,
106		genR2,
107	))
108
109	properties.Property("[{{ toUpper .Name}}] MillerLoop of pairs should be equal to the product of MillerLoops", prop.ForAll(
110		func(a, b fr.Element) bool {
111
112			var simpleProd, factorizedProd GT
113
114			var ag1 G1Affine
115			var bg2 G2Affine
116
117			var abigint, bbigint big.Int
118
119			a.ToBigIntRegular(&abigint)
120			b.ToBigIntRegular(&bbigint)
121
122			ag1.ScalarMultiplication(&g1GenAff, &abigint)
123			bg2.ScalarMultiplication(&g2GenAff, &bbigint)
124
125			P0 := []G1Affine{g1GenAff}
126			P1 := []G1Affine{ag1}
127			Q0 := []G2Affine{g2GenAff}
128			Q1 := []G2Affine{bg2}
129
130			// FE( ML(a,b) * ML(c,d) * ML(e,f) * ML(g,h) )
131			M1, _ := MillerLoop(P0, Q0)
132			M2, _ := MillerLoop(P1, Q0)
133			M3, _ := MillerLoop(P0, Q1)
134			M4, _ := MillerLoop(P1, Q1)
135			simpleProd.Mul(&M1, &M2).Mul(&simpleProd, &M3).Mul(&simpleProd, &M4)
136			simpleProd = FinalExponentiation(&simpleProd)
137
138			tabP := []G1Affine{g1GenAff, ag1, g1GenAff, ag1}
139			tabQ := []G2Affine{g2GenAff, g2GenAff, bg2, bg2}
140
141			// FE( ML([a,c,e,g] ; [b,d,f,h]) ) -> saves 3 squares in Fqk
142			factorizedProd, _ = Pair(tabP, tabQ)
143
144			return simpleProd.Equal(&factorizedProd)
145		},
146		genR1,
147		genR2,
148	))
149
150	properties.Property("[{{ toUpper .Name}}] PairingCheck", prop.ForAll(
151		func(a, b fr.Element) bool {
152
153			var g1GenAffNeg G1Affine
154			g1GenAffNeg.Neg(&g1GenAff)
155			tabP := []G1Affine{g1GenAff, g1GenAffNeg}
156			tabQ := []G2Affine{g2GenAff, g2GenAff}
157
158			res, _ := PairingCheck(tabP, tabQ)
159
160			return res
161		},
162		genR1,
163		genR2,
164	))
165	properties.TestingRun(t, gopter.ConsoleReporter(false))
166}
167
168// ------------------------------------------------------------
169// benches
170
171func BenchmarkPairing(b *testing.B) {
172
173	var g1GenAff G1Affine
174	var g2GenAff G2Affine
175
176	g1GenAff.FromJacobian(&g1Gen)
177	g2GenAff.FromJacobian(&g2Gen)
178
179	b.ResetTimer()
180	for i := 0; i < b.N; i++ {
181		Pair([]G1Affine{g1GenAff}, []G2Affine{g2GenAff})
182	}
183}
184
185func BenchmarkMillerLoop(b *testing.B) {
186
187	var g1GenAff G1Affine
188	var g2GenAff G2Affine
189
190	g1GenAff.FromJacobian(&g1Gen)
191	g2GenAff.FromJacobian(&g2Gen)
192
193	b.ResetTimer()
194	for i := 0; i < b.N; i++ {
195		MillerLoop([]G1Affine{g1GenAff}, []G2Affine{g2GenAff})
196	}
197}
198
199func BenchmarkFinalExponentiation(b *testing.B) {
200
201	var a GT
202	a.SetRandom()
203
204	b.ResetTimer()
205	for i := 0; i < b.N; i++ {
206		FinalExponentiation(&a)
207	}
208
209}
210