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