317 lines
6.4 KiB
Go
317 lines
6.4 KiB
Go
//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")
|
|
}
|
|
}
|
|
}
|