//go:build !nocgo package bench import ( "crypto/rand" "testing" "p256k1.mleku.dev" "p256k1.mleku.dev/signer" ) // This file contains benchmarks comparing: // 1. P256K1 Pure Go implementation // 2. P256K1 with AVX2 scalar operations (where applicable) // 3. libsecp256k1.so via purego (if available) var ( avxBenchSeckey []byte avxBenchMsghash []byte avxBenchSigner *signer.P256K1Signer avxBenchSigner2 *signer.P256K1Signer avxBenchSig []byte avxBenchLibSecp *p256k1.LibSecp256k1 ) func initAVXBenchData() { if avxBenchSeckey == nil { avxBenchSeckey = []byte{ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, } for { testSigner := signer.NewP256K1Signer() if err := testSigner.InitSec(avxBenchSeckey); err == nil { break } if _, err := rand.Read(avxBenchSeckey); err != nil { panic(err) } } avxBenchMsghash = make([]byte, 32) if _, err := rand.Read(avxBenchMsghash); err != nil { panic(err) } } // Setup P256K1Signer s := signer.NewP256K1Signer() if err := s.InitSec(avxBenchSeckey); err != nil { panic(err) } avxBenchSigner = s var err error avxBenchSig, err = s.Sign(avxBenchMsghash) if err != nil { panic(err) } // Generate second key pair for ECDH seckey2 := make([]byte, 32) for { if _, err := rand.Read(seckey2); err != nil { panic(err) } testSigner := signer.NewP256K1Signer() if err := testSigner.InitSec(seckey2); err == nil { break } } s2 := signer.NewP256K1Signer() if err := s2.InitSec(seckey2); err != nil { panic(err) } avxBenchSigner2 = s2 // Try to load libsecp256k1 avxBenchLibSecp, _ = p256k1.GetLibSecp256k1() } // Pure Go benchmarks (AVX2 disabled) func BenchmarkPureGo_PubkeyDerivation(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } p256k1.SetAVX2Enabled(false) defer p256k1.SetAVX2Enabled(true) b.ResetTimer() for i := 0; i < b.N; i++ { s := signer.NewP256K1Signer() if err := s.InitSec(avxBenchSeckey); err != nil { b.Fatalf("failed to create signer: %v", err) } _ = s.Pub() } } func BenchmarkPureGo_Sign(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } p256k1.SetAVX2Enabled(false) defer p256k1.SetAVX2Enabled(true) b.ResetTimer() for i := 0; i < b.N; i++ { _, err := avxBenchSigner.Sign(avxBenchMsghash) if err != nil { b.Fatalf("failed to sign: %v", err) } } } func BenchmarkPureGo_Verify(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } p256k1.SetAVX2Enabled(false) defer p256k1.SetAVX2Enabled(true) b.ResetTimer() for i := 0; i < b.N; i++ { verifier := signer.NewP256K1Signer() if err := verifier.InitPub(avxBenchSigner.Pub()); err != nil { b.Fatalf("failed to create verifier: %v", err) } valid, err := verifier.Verify(avxBenchMsghash, avxBenchSig) if err != nil { b.Fatalf("verification error: %v", err) } if !valid { b.Fatalf("verification failed") } } } func BenchmarkPureGo_ECDH(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } p256k1.SetAVX2Enabled(false) defer p256k1.SetAVX2Enabled(true) b.ResetTimer() for i := 0; i < b.N; i++ { _, err := avxBenchSigner.ECDH(avxBenchSigner2.Pub()) if err != nil { b.Fatalf("ECDH failed: %v", err) } } } // AVX2-enabled benchmarks func BenchmarkAVX2_PubkeyDerivation(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } if !p256k1.HasAVX2CPU() { b.Skip("AVX2 not available") } p256k1.SetAVX2Enabled(true) b.ResetTimer() for i := 0; i < b.N; i++ { s := signer.NewP256K1Signer() if err := s.InitSec(avxBenchSeckey); err != nil { b.Fatalf("failed to create signer: %v", err) } _ = s.Pub() } } func BenchmarkAVX2_Sign(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } if !p256k1.HasAVX2CPU() { b.Skip("AVX2 not available") } p256k1.SetAVX2Enabled(true) b.ResetTimer() for i := 0; i < b.N; i++ { _, err := avxBenchSigner.Sign(avxBenchMsghash) if err != nil { b.Fatalf("failed to sign: %v", err) } } } func BenchmarkAVX2_Verify(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } if !p256k1.HasAVX2CPU() { b.Skip("AVX2 not available") } p256k1.SetAVX2Enabled(true) b.ResetTimer() for i := 0; i < b.N; i++ { verifier := signer.NewP256K1Signer() if err := verifier.InitPub(avxBenchSigner.Pub()); err != nil { b.Fatalf("failed to create verifier: %v", err) } valid, err := verifier.Verify(avxBenchMsghash, avxBenchSig) if err != nil { b.Fatalf("verification error: %v", err) } if !valid { b.Fatalf("verification failed") } } } func BenchmarkAVX2_ECDH(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } if !p256k1.HasAVX2CPU() { b.Skip("AVX2 not available") } p256k1.SetAVX2Enabled(true) b.ResetTimer() for i := 0; i < b.N; i++ { _, err := avxBenchSigner.ECDH(avxBenchSigner2.Pub()) if err != nil { b.Fatalf("ECDH failed: %v", err) } } } // libsecp256k1.so benchmarks via purego func BenchmarkLibSecp_Sign(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } if avxBenchLibSecp == nil || !avxBenchLibSecp.IsLoaded() { b.Skip("libsecp256k1.so not available") } b.ResetTimer() for i := 0; i < b.N; i++ { _, err := avxBenchLibSecp.SchnorrSign(avxBenchMsghash, avxBenchSeckey) if err != nil { b.Fatalf("signing failed: %v", err) } } } func BenchmarkLibSecp_PubkeyDerivation(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } if avxBenchLibSecp == nil || !avxBenchLibSecp.IsLoaded() { b.Skip("libsecp256k1.so not available") } b.ResetTimer() for i := 0; i < b.N; i++ { _, err := avxBenchLibSecp.CreatePubkey(avxBenchSeckey) if err != nil { b.Fatalf("pubkey creation failed: %v", err) } } } func BenchmarkLibSecp_Verify(b *testing.B) { if avxBenchSeckey == nil { initAVXBenchData() } if avxBenchLibSecp == nil || !avxBenchLibSecp.IsLoaded() { b.Skip("libsecp256k1.so not available") } // Sign with libsecp to get compatible signature sig, err := avxBenchLibSecp.SchnorrSign(avxBenchMsghash, avxBenchSeckey) if err != nil { b.Fatalf("signing failed: %v", err) } pubkey, err := avxBenchLibSecp.CreatePubkey(avxBenchSeckey) if err != nil { b.Fatalf("pubkey creation failed: %v", err) } b.ResetTimer() for i := 0; i < b.N; i++ { if !avxBenchLibSecp.SchnorrVerify(sig, avxBenchMsghash, pubkey) { b.Fatalf("verification failed") } } }