avx2_bench_test.go raw

   1  //go:build !nocgo && !js && !wasm && !tinygo && !wasm32
   2  
   3  package bench
   4  
   5  import (
   6  	"crypto/rand"
   7  	"testing"
   8  
   9  	"next.orly.dev/pkg/p256k1"
  10  	"next.orly.dev/pkg/p256k1/signer"
  11  )
  12  
  13  // This file contains benchmarks comparing:
  14  // 1. P256K1 Pure Go implementation
  15  // 2. P256K1 with AVX2 scalar operations (where applicable)
  16  // 3. libsecp256k1.so via purego (if available)
  17  
  18  var (
  19  	avxBenchSeckey    []byte
  20  	avxBenchMsghash   []byte
  21  	avxBenchSigner    *signer.P256K1Signer
  22  	avxBenchSigner2   *signer.P256K1Signer
  23  	avxBenchSig       []byte
  24  	avxBenchLibSecp   *p256k1.LibSecp256k1
  25  )
  26  
  27  func initAVXBenchData() {
  28  	if avxBenchSeckey == nil {
  29  		avxBenchSeckey = []byte{
  30  			0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  31  			0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  32  			0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  33  			0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  34  		}
  35  
  36  		for {
  37  			testSigner := signer.NewP256K1Signer()
  38  			if err := testSigner.InitSec(avxBenchSeckey); err == nil {
  39  				break
  40  			}
  41  			if _, err := rand.Read(avxBenchSeckey); err != nil {
  42  				panic(err)
  43  			}
  44  		}
  45  
  46  		avxBenchMsghash = make([]byte, 32)
  47  		if _, err := rand.Read(avxBenchMsghash); err != nil {
  48  			panic(err)
  49  		}
  50  	}
  51  
  52  	// Setup P256K1Signer
  53  	s := signer.NewP256K1Signer()
  54  	if err := s.InitSec(avxBenchSeckey); err != nil {
  55  		panic(err)
  56  	}
  57  	avxBenchSigner = s
  58  
  59  	var err error
  60  	avxBenchSig, err = s.Sign(avxBenchMsghash)
  61  	if err != nil {
  62  		panic(err)
  63  	}
  64  
  65  	// Generate second key pair for ECDH
  66  	seckey2 := make([]byte, 32)
  67  	for {
  68  		if _, err := rand.Read(seckey2); err != nil {
  69  			panic(err)
  70  		}
  71  		testSigner := signer.NewP256K1Signer()
  72  		if err := testSigner.InitSec(seckey2); err == nil {
  73  			break
  74  		}
  75  	}
  76  
  77  	s2 := signer.NewP256K1Signer()
  78  	if err := s2.InitSec(seckey2); err != nil {
  79  		panic(err)
  80  	}
  81  	avxBenchSigner2 = s2
  82  
  83  	// Try to load libsecp256k1
  84  	avxBenchLibSecp, _ = p256k1.GetLibSecp256k1()
  85  }
  86  
  87  // Pure Go benchmarks (AVX2 disabled)
  88  func BenchmarkPureGo_PubkeyDerivation(b *testing.B) {
  89  	if avxBenchSeckey == nil {
  90  		initAVXBenchData()
  91  	}
  92  
  93  	p256k1.SetAVX2Enabled(false)
  94  	defer p256k1.SetAVX2Enabled(true)
  95  
  96  	b.ResetTimer()
  97  	for i := 0; i < b.N; i++ {
  98  		s := signer.NewP256K1Signer()
  99  		if err := s.InitSec(avxBenchSeckey); err != nil {
 100  			b.Fatalf("failed to create signer: %v", err)
 101  		}
 102  		_ = s.Pub()
 103  	}
 104  }
 105  
 106  func BenchmarkPureGo_Sign(b *testing.B) {
 107  	if avxBenchSeckey == nil {
 108  		initAVXBenchData()
 109  	}
 110  
 111  	p256k1.SetAVX2Enabled(false)
 112  	defer p256k1.SetAVX2Enabled(true)
 113  
 114  	b.ResetTimer()
 115  	for i := 0; i < b.N; i++ {
 116  		_, err := avxBenchSigner.Sign(avxBenchMsghash)
 117  		if err != nil {
 118  			b.Fatalf("failed to sign: %v", err)
 119  		}
 120  	}
 121  }
 122  
 123  func BenchmarkPureGo_Verify(b *testing.B) {
 124  	if avxBenchSeckey == nil {
 125  		initAVXBenchData()
 126  	}
 127  
 128  	p256k1.SetAVX2Enabled(false)
 129  	defer p256k1.SetAVX2Enabled(true)
 130  
 131  	b.ResetTimer()
 132  	for i := 0; i < b.N; i++ {
 133  		verifier := signer.NewP256K1Signer()
 134  		if err := verifier.InitPub(avxBenchSigner.Pub()); err != nil {
 135  			b.Fatalf("failed to create verifier: %v", err)
 136  		}
 137  		valid, err := verifier.Verify(avxBenchMsghash, avxBenchSig)
 138  		if err != nil {
 139  			b.Fatalf("verification error: %v", err)
 140  		}
 141  		if !valid {
 142  			b.Fatalf("verification failed")
 143  		}
 144  	}
 145  }
 146  
 147  func BenchmarkPureGo_ECDH(b *testing.B) {
 148  	if avxBenchSeckey == nil {
 149  		initAVXBenchData()
 150  	}
 151  
 152  	p256k1.SetAVX2Enabled(false)
 153  	defer p256k1.SetAVX2Enabled(true)
 154  
 155  	b.ResetTimer()
 156  	for i := 0; i < b.N; i++ {
 157  		_, err := avxBenchSigner.ECDH(avxBenchSigner2.Pub())
 158  		if err != nil {
 159  			b.Fatalf("ECDH failed: %v", err)
 160  		}
 161  	}
 162  }
 163  
 164  // AVX2-enabled benchmarks
 165  func BenchmarkAVX2_PubkeyDerivation(b *testing.B) {
 166  	if avxBenchSeckey == nil {
 167  		initAVXBenchData()
 168  	}
 169  
 170  	if !p256k1.HasAVX2CPU() {
 171  		b.Skip("AVX2 not available")
 172  	}
 173  
 174  	p256k1.SetAVX2Enabled(true)
 175  
 176  	b.ResetTimer()
 177  	for i := 0; i < b.N; i++ {
 178  		s := signer.NewP256K1Signer()
 179  		if err := s.InitSec(avxBenchSeckey); err != nil {
 180  			b.Fatalf("failed to create signer: %v", err)
 181  		}
 182  		_ = s.Pub()
 183  	}
 184  }
 185  
 186  func BenchmarkAVX2_Sign(b *testing.B) {
 187  	if avxBenchSeckey == nil {
 188  		initAVXBenchData()
 189  	}
 190  
 191  	if !p256k1.HasAVX2CPU() {
 192  		b.Skip("AVX2 not available")
 193  	}
 194  
 195  	p256k1.SetAVX2Enabled(true)
 196  
 197  	b.ResetTimer()
 198  	for i := 0; i < b.N; i++ {
 199  		_, err := avxBenchSigner.Sign(avxBenchMsghash)
 200  		if err != nil {
 201  			b.Fatalf("failed to sign: %v", err)
 202  		}
 203  	}
 204  }
 205  
 206  func BenchmarkAVX2_Verify(b *testing.B) {
 207  	if avxBenchSeckey == nil {
 208  		initAVXBenchData()
 209  	}
 210  
 211  	if !p256k1.HasAVX2CPU() {
 212  		b.Skip("AVX2 not available")
 213  	}
 214  
 215  	p256k1.SetAVX2Enabled(true)
 216  
 217  	b.ResetTimer()
 218  	for i := 0; i < b.N; i++ {
 219  		verifier := signer.NewP256K1Signer()
 220  		if err := verifier.InitPub(avxBenchSigner.Pub()); err != nil {
 221  			b.Fatalf("failed to create verifier: %v", err)
 222  		}
 223  		valid, err := verifier.Verify(avxBenchMsghash, avxBenchSig)
 224  		if err != nil {
 225  			b.Fatalf("verification error: %v", err)
 226  		}
 227  		if !valid {
 228  			b.Fatalf("verification failed")
 229  		}
 230  	}
 231  }
 232  
 233  func BenchmarkAVX2_ECDH(b *testing.B) {
 234  	if avxBenchSeckey == nil {
 235  		initAVXBenchData()
 236  	}
 237  
 238  	if !p256k1.HasAVX2CPU() {
 239  		b.Skip("AVX2 not available")
 240  	}
 241  
 242  	p256k1.SetAVX2Enabled(true)
 243  
 244  	b.ResetTimer()
 245  	for i := 0; i < b.N; i++ {
 246  		_, err := avxBenchSigner.ECDH(avxBenchSigner2.Pub())
 247  		if err != nil {
 248  			b.Fatalf("ECDH failed: %v", err)
 249  		}
 250  	}
 251  }
 252  
 253  // libsecp256k1.so benchmarks via purego
 254  func BenchmarkLibSecp_Sign(b *testing.B) {
 255  	if avxBenchSeckey == nil {
 256  		initAVXBenchData()
 257  	}
 258  
 259  	if avxBenchLibSecp == nil || !avxBenchLibSecp.IsLoaded() {
 260  		b.Skip("libsecp256k1.so not available")
 261  	}
 262  
 263  	b.ResetTimer()
 264  	for i := 0; i < b.N; i++ {
 265  		_, err := avxBenchLibSecp.SchnorrSign(avxBenchMsghash, avxBenchSeckey)
 266  		if err != nil {
 267  			b.Fatalf("signing failed: %v", err)
 268  		}
 269  	}
 270  }
 271  
 272  func BenchmarkLibSecp_PubkeyDerivation(b *testing.B) {
 273  	if avxBenchSeckey == nil {
 274  		initAVXBenchData()
 275  	}
 276  
 277  	if avxBenchLibSecp == nil || !avxBenchLibSecp.IsLoaded() {
 278  		b.Skip("libsecp256k1.so not available")
 279  	}
 280  
 281  	b.ResetTimer()
 282  	for i := 0; i < b.N; i++ {
 283  		_, err := avxBenchLibSecp.CreatePubkey(avxBenchSeckey)
 284  		if err != nil {
 285  			b.Fatalf("pubkey creation failed: %v", err)
 286  		}
 287  	}
 288  }
 289  
 290  func BenchmarkLibSecp_Verify(b *testing.B) {
 291  	if avxBenchSeckey == nil {
 292  		initAVXBenchData()
 293  	}
 294  
 295  	if avxBenchLibSecp == nil || !avxBenchLibSecp.IsLoaded() {
 296  		b.Skip("libsecp256k1.so not available")
 297  	}
 298  
 299  	// Sign with libsecp to get compatible signature
 300  	sig, err := avxBenchLibSecp.SchnorrSign(avxBenchMsghash, avxBenchSeckey)
 301  	if err != nil {
 302  		b.Fatalf("signing failed: %v", err)
 303  	}
 304  
 305  	pubkey, err := avxBenchLibSecp.CreatePubkey(avxBenchSeckey)
 306  	if err != nil {
 307  		b.Fatalf("pubkey creation failed: %v", err)
 308  	}
 309  
 310  	b.ResetTimer()
 311  	for i := 0; i < b.N; i++ {
 312  		if !avxBenchLibSecp.SchnorrVerify(sig, avxBenchMsghash, pubkey) {
 313  			b.Fatalf("verification failed")
 314  		}
 315  	}
 316  }
 317