group_4x64_test.go raw
1 //go:build amd64 && !purego
2
3 package p256k1
4
5 import (
6 "crypto/rand"
7 "testing"
8 )
9
10 func TestGroup4x64DoubleVsOriginal(t *testing.T) {
11 // Create a random point
12 for i := 0; i < 100; i++ {
13 var aBytes [32]byte
14 rand.Read(aBytes[:])
15 aBytes[0] &= 0x7F // Ensure < p
16
17 // Create original point
18 var aField FieldElement
19 aField.setB32(aBytes[:])
20
21 var origAffine GroupElementAffine
22 if !origAffine.setXOVar(&aField, false) {
23 continue // Not on curve, skip
24 }
25
26 var origJac GroupElementJacobian
27 origJac.setGE(&origAffine)
28
29 // Convert to 4x64
30 var jac4x64 GroupElement4x64Jacobian
31 jac4x64.FromGroupElementJacobian(&origJac)
32
33 // Double with both implementations
34 var origResult GroupElementJacobian
35 origResult.double(&origJac)
36
37 var result4x64 GroupElement4x64Jacobian
38 result4x64.double(&jac4x64)
39
40 // Convert 4x64 result back
41 var result4x64Jac GroupElementJacobian
42 result4x64.ToGroupElementJacobian(&result4x64Jac)
43
44 // Compare by converting to affine
45 var origAff, result4x64Aff GroupElementAffine
46 origAff.setGEJ(&origResult)
47 result4x64Aff.setGEJ(&result4x64Jac)
48
49 origAff.x.normalize()
50 origAff.y.normalize()
51 result4x64Aff.x.normalize()
52 result4x64Aff.y.normalize()
53
54 if !origAff.x.equal(&result4x64Aff.x) || !origAff.y.equal(&result4x64Aff.y) {
55 t.Errorf("Iteration %d: Double mismatch", i)
56 }
57 }
58 }
59
60 func TestGroup4x64AddVsOriginal(t *testing.T) {
61 // Create random points
62 for i := 0; i < 100; i++ {
63 var aBytes, bBytes [32]byte
64 rand.Read(aBytes[:])
65 rand.Read(bBytes[:])
66 aBytes[0] &= 0x7F
67 bBytes[0] &= 0x7F
68
69 // Create original points
70 var aField, bField FieldElement
71 aField.setB32(aBytes[:])
72 bField.setB32(bBytes[:])
73
74 var aAffine, bAffine GroupElementAffine
75 if !aAffine.setXOVar(&aField, false) {
76 continue
77 }
78 if !bAffine.setXOVar(&bField, false) {
79 continue
80 }
81
82 var aJac, bJac GroupElementJacobian
83 aJac.setGE(&aAffine)
84 bJac.setGE(&bAffine)
85
86 // Convert to 4x64
87 var aJac4x64, bJac4x64 GroupElement4x64Jacobian
88 aJac4x64.FromGroupElementJacobian(&aJac)
89 bJac4x64.FromGroupElementJacobian(&bJac)
90
91 // Add with both implementations
92 var origResult GroupElementJacobian
93 origResult.addVar(&aJac, &bJac)
94
95 var result4x64 GroupElement4x64Jacobian
96 result4x64.addVar(&aJac4x64, &bJac4x64)
97
98 // Convert 4x64 result back
99 var result4x64Jac GroupElementJacobian
100 result4x64.ToGroupElementJacobian(&result4x64Jac)
101
102 // Compare by converting to affine
103 var origAff, result4x64Aff GroupElementAffine
104 origAff.setGEJ(&origResult)
105 result4x64Aff.setGEJ(&result4x64Jac)
106
107 origAff.x.normalize()
108 origAff.y.normalize()
109 result4x64Aff.x.normalize()
110 result4x64Aff.y.normalize()
111
112 if !origAff.x.equal(&result4x64Aff.x) || !origAff.y.equal(&result4x64Aff.y) {
113 t.Errorf("Iteration %d: Add mismatch", i)
114 }
115 }
116 }
117
118 func TestGroup4x64AddGEVsOriginal(t *testing.T) {
119 // Test addGE (Jacobian + Affine)
120 for i := 0; i < 100; i++ {
121 var aBytes, bBytes [32]byte
122 rand.Read(aBytes[:])
123 rand.Read(bBytes[:])
124 aBytes[0] &= 0x7F
125 bBytes[0] &= 0x7F
126
127 // Create original points
128 var aField, bField FieldElement
129 aField.setB32(aBytes[:])
130 bField.setB32(bBytes[:])
131
132 var aAffine, bAffine GroupElementAffine
133 if !aAffine.setXOVar(&aField, false) {
134 continue
135 }
136 if !bAffine.setXOVar(&bField, false) {
137 continue
138 }
139
140 var aJac GroupElementJacobian
141 aJac.setGE(&aAffine)
142
143 // Convert to 4x64
144 var aJac4x64 GroupElement4x64Jacobian
145 var bAffine4x64 GroupElement4x64Affine
146 aJac4x64.FromGroupElementJacobian(&aJac)
147 bAffine4x64.FromGroupElementAffine(&bAffine)
148
149 // Add with both implementations
150 var origResult GroupElementJacobian
151 origResult.addGE(&aJac, &bAffine)
152
153 var result4x64 GroupElement4x64Jacobian
154 result4x64.addGE(&aJac4x64, &bAffine4x64)
155
156 // Convert 4x64 result back
157 var result4x64Jac GroupElementJacobian
158 result4x64.ToGroupElementJacobian(&result4x64Jac)
159
160 // Compare by converting to affine
161 var origAff, result4x64Aff GroupElementAffine
162 origAff.setGEJ(&origResult)
163 result4x64Aff.setGEJ(&result4x64Jac)
164
165 origAff.x.normalize()
166 origAff.y.normalize()
167 result4x64Aff.x.normalize()
168 result4x64Aff.y.normalize()
169
170 if !origAff.x.equal(&result4x64Aff.x) || !origAff.y.equal(&result4x64Aff.y) {
171 t.Errorf("Iteration %d: AddGE mismatch", i)
172 }
173 }
174 }
175
176 // Benchmarks comparing 4x64 vs original group operations
177
178 func BenchmarkGroup4x64Double(b *testing.B) {
179 // Create a test point
180 var xBytes [32]byte
181 xBytes[31] = 0x02 // Small value that's on the curve
182 var xField FieldElement
183 xField.setB32(xBytes[:])
184
185 var aff GroupElementAffine
186 aff.setXOVar(&xField, false)
187
188 var jac GroupElement4x64Jacobian
189 var affine4x64 GroupElement4x64Affine
190 affine4x64.FromGroupElementAffine(&aff)
191 jac.setGE(&affine4x64)
192
193 var r GroupElement4x64Jacobian
194
195 b.ResetTimer()
196 b.ReportAllocs()
197 for i := 0; i < b.N; i++ {
198 r.double(&jac)
199 }
200 }
201
202 func BenchmarkGroupOriginalDouble(b *testing.B) {
203 // Create a test point
204 var xBytes [32]byte
205 xBytes[31] = 0x02
206 var xField FieldElement
207 xField.setB32(xBytes[:])
208
209 var aff GroupElementAffine
210 aff.setXOVar(&xField, false)
211
212 var jac GroupElementJacobian
213 jac.setGE(&aff)
214
215 var r GroupElementJacobian
216
217 b.ResetTimer()
218 b.ReportAllocs()
219 for i := 0; i < b.N; i++ {
220 r.double(&jac)
221 }
222 }
223
224 func BenchmarkGroup4x64AddGE(b *testing.B) {
225 // Create test points
226 var xBytes, yBytes [32]byte
227 xBytes[31] = 0x02
228 yBytes[31] = 0x03
229
230 var xField, yField FieldElement
231 xField.setB32(xBytes[:])
232 yField.setB32(yBytes[:])
233
234 var aAff, bAff GroupElementAffine
235 aAff.setXOVar(&xField, false)
236 bAff.setXOVar(&yField, false)
237
238 var aAff4x64, bAff4x64 GroupElement4x64Affine
239 aAff4x64.FromGroupElementAffine(&aAff)
240 bAff4x64.FromGroupElementAffine(&bAff)
241
242 var aJac4x64 GroupElement4x64Jacobian
243 aJac4x64.setGE(&aAff4x64)
244
245 var r GroupElement4x64Jacobian
246
247 b.ResetTimer()
248 b.ReportAllocs()
249 for i := 0; i < b.N; i++ {
250 r.addGE(&aJac4x64, &bAff4x64)
251 }
252 }
253
254 func BenchmarkGroupOriginalAddGE(b *testing.B) {
255 // Create test points
256 var xBytes, yBytes [32]byte
257 xBytes[31] = 0x02
258 yBytes[31] = 0x03
259
260 var xField, yField FieldElement
261 xField.setB32(xBytes[:])
262 yField.setB32(yBytes[:])
263
264 var aAff, bAff GroupElementAffine
265 aAff.setXOVar(&xField, false)
266 bAff.setXOVar(&yField, false)
267
268 var aJac GroupElementJacobian
269 aJac.setGE(&aAff)
270
271 var r GroupElementJacobian
272
273 b.ResetTimer()
274 b.ReportAllocs()
275 for i := 0; i < b.N; i++ {
276 r.addGE(&aJac, &bAff)
277 }
278 }
279
280 func BenchmarkGroup4x64AddVar(b *testing.B) {
281 // Create test points
282 var xBytes, yBytes [32]byte
283 xBytes[31] = 0x02
284 yBytes[31] = 0x03
285
286 var xField, yField FieldElement
287 xField.setB32(xBytes[:])
288 yField.setB32(yBytes[:])
289
290 var aAff, bAff GroupElementAffine
291 aAff.setXOVar(&xField, false)
292 bAff.setXOVar(&yField, false)
293
294 var aAff4x64, bAff4x64 GroupElement4x64Affine
295 aAff4x64.FromGroupElementAffine(&aAff)
296 bAff4x64.FromGroupElementAffine(&bAff)
297
298 var aJac4x64, bJac4x64 GroupElement4x64Jacobian
299 aJac4x64.setGE(&aAff4x64)
300 bJac4x64.setGE(&bAff4x64)
301
302 var r GroupElement4x64Jacobian
303
304 b.ResetTimer()
305 b.ReportAllocs()
306 for i := 0; i < b.N; i++ {
307 r.addVar(&aJac4x64, &bJac4x64)
308 }
309 }
310
311 func BenchmarkGroupOriginalAddVar(b *testing.B) {
312 // Create test points
313 var xBytes, yBytes [32]byte
314 xBytes[31] = 0x02
315 yBytes[31] = 0x03
316
317 var xField, yField FieldElement
318 xField.setB32(xBytes[:])
319 yField.setB32(yBytes[:])
320
321 var aAff, bAff GroupElementAffine
322 aAff.setXOVar(&xField, false)
323 bAff.setXOVar(&yField, false)
324
325 var aJac, bJac GroupElementJacobian
326 aJac.setGE(&aAff)
327 bJac.setGE(&bAff)
328
329 var r GroupElementJacobian
330
331 b.ResetTimer()
332 b.ReportAllocs()
333 for i := 0; i < b.N; i++ {
334 r.addVar(&aJac, &bJac)
335 }
336 }
337