benchmark_test.go raw

   1  package encryption
   2  
   3  import (
   4  	"testing"
   5  
   6  	"next.orly.dev/pkg/nostr/interfaces/signer/p8k"
   7  	"lukechampine.com/frand"
   8  )
   9  
  10  // createTestConversationKey creates a test conversation key
  11  func createTestConversationKey() []byte {
  12  	return frand.Bytes(32)
  13  }
  14  
  15  // createTestKeyPair creates a key pair for ECDH testing
  16  func createTestKeyPair() (*p8k.Signer, []byte) {
  17  	signer := p8k.MustNew()
  18  	if err := signer.Generate(); err != nil {
  19  		panic(err)
  20  	}
  21  	return signer, signer.Pub()
  22  }
  23  
  24  // BenchmarkNIP44Encrypt benchmarks NIP-44 encryption
  25  func BenchmarkNIP44Encrypt(b *testing.B) {
  26  	conversationKey := createTestConversationKey()
  27  	plaintext := []byte("This is a test message for encryption benchmarking")
  28  
  29  	b.ResetTimer()
  30  	b.ReportAllocs()
  31  
  32  	for i := 0; i < b.N; i++ {
  33  		_, err := Encrypt(conversationKey, plaintext, nil)
  34  		if err != nil {
  35  			b.Fatal(err)
  36  		}
  37  	}
  38  }
  39  
  40  // BenchmarkNIP44EncryptSmall benchmarks encryption of small messages
  41  func BenchmarkNIP44EncryptSmall(b *testing.B) {
  42  	conversationKey := createTestConversationKey()
  43  	plaintext := []byte("a")
  44  
  45  	b.ResetTimer()
  46  	b.ReportAllocs()
  47  
  48  	for i := 0; i < b.N; i++ {
  49  		_, err := Encrypt(conversationKey, plaintext, nil)
  50  		if err != nil {
  51  			b.Fatal(err)
  52  		}
  53  	}
  54  }
  55  
  56  // BenchmarkNIP44EncryptLarge benchmarks encryption of large messages
  57  func BenchmarkNIP44EncryptLarge(b *testing.B) {
  58  	conversationKey := createTestConversationKey()
  59  	plaintext := make([]byte, 4096)
  60  	for i := range plaintext {
  61  		plaintext[i] = byte(i % 256)
  62  	}
  63  
  64  	b.ResetTimer()
  65  	b.ReportAllocs()
  66  
  67  	for i := 0; i < b.N; i++ {
  68  		_, err := Encrypt(conversationKey, plaintext, nil)
  69  		if err != nil {
  70  			b.Fatal(err)
  71  		}
  72  	}
  73  }
  74  
  75  // BenchmarkNIP44Decrypt benchmarks NIP-44 decryption
  76  func BenchmarkNIP44Decrypt(b *testing.B) {
  77  	conversationKey := createTestConversationKey()
  78  	plaintext := []byte("This is a test message for encryption benchmarking")
  79  	ciphertext, err := Encrypt(conversationKey, plaintext, nil)
  80  	if err != nil {
  81  		b.Fatal(err)
  82  	}
  83  
  84  	b.ResetTimer()
  85  	b.ReportAllocs()
  86  
  87  	for i := 0; i < b.N; i++ {
  88  		_, err := Decrypt(conversationKey, ciphertext)
  89  		if err != nil {
  90  			b.Fatal(err)
  91  		}
  92  	}
  93  }
  94  
  95  // BenchmarkNIP44DecryptSmall benchmarks decryption of small messages
  96  func BenchmarkNIP44DecryptSmall(b *testing.B) {
  97  	conversationKey := createTestConversationKey()
  98  	plaintext := []byte("a")
  99  	ciphertext, err := Encrypt(conversationKey, plaintext, nil)
 100  	if err != nil {
 101  		b.Fatal(err)
 102  	}
 103  
 104  	b.ResetTimer()
 105  	b.ReportAllocs()
 106  
 107  	for i := 0; i < b.N; i++ {
 108  		_, err := Decrypt(conversationKey, ciphertext)
 109  		if err != nil {
 110  			b.Fatal(err)
 111  		}
 112  	}
 113  }
 114  
 115  // BenchmarkNIP44DecryptLarge benchmarks decryption of large messages
 116  func BenchmarkNIP44DecryptLarge(b *testing.B) {
 117  	conversationKey := createTestConversationKey()
 118  	plaintext := make([]byte, 4096)
 119  	for i := range plaintext {
 120  		plaintext[i] = byte(i % 256)
 121  	}
 122  	ciphertext, err := Encrypt(conversationKey, plaintext, nil)
 123  	if err != nil {
 124  		b.Fatal(err)
 125  	}
 126  
 127  	b.ResetTimer()
 128  	b.ReportAllocs()
 129  
 130  	for i := 0; i < b.N; i++ {
 131  		_, err := Decrypt(conversationKey, ciphertext)
 132  		if err != nil {
 133  			b.Fatal(err)
 134  		}
 135  	}
 136  }
 137  
 138  // BenchmarkNIP44RoundTrip benchmarks encrypt/decrypt round trip
 139  func BenchmarkNIP44RoundTrip(b *testing.B) {
 140  	conversationKey := createTestConversationKey()
 141  	plaintext := []byte("This is a test message for encryption benchmarking")
 142  
 143  	b.ResetTimer()
 144  	b.ReportAllocs()
 145  
 146  	for i := 0; i < b.N; i++ {
 147  		ciphertext, err := Encrypt(conversationKey, plaintext, nil)
 148  		if err != nil {
 149  			b.Fatal(err)
 150  		}
 151  		_, err = Decrypt(conversationKey, ciphertext)
 152  		if err != nil {
 153  			b.Fatal(err)
 154  		}
 155  	}
 156  }
 157  
 158  // BenchmarkNIP4Encrypt benchmarks NIP-4 encryption
 159  func BenchmarkNIP4Encrypt(b *testing.B) {
 160  	key := createTestConversationKey()
 161  	msg := []byte("This is a test message for NIP-4 encryption benchmarking")
 162  
 163  	b.ResetTimer()
 164  	b.ReportAllocs()
 165  
 166  	for i := 0; i < b.N; i++ {
 167  		_, err := EncryptNip4(msg, key)
 168  		if err != nil {
 169  			b.Fatal(err)
 170  		}
 171  	}
 172  }
 173  
 174  // BenchmarkNIP4Decrypt benchmarks NIP-4 decryption
 175  func BenchmarkNIP4Decrypt(b *testing.B) {
 176  	key := createTestConversationKey()
 177  	msg := []byte("This is a test message for NIP-4 encryption benchmarking")
 178  	ciphertext, err := EncryptNip4(msg, key)
 179  	if err != nil {
 180  		b.Fatal(err)
 181  	}
 182  
 183  	b.ResetTimer()
 184  	b.ReportAllocs()
 185  
 186  	for i := 0; i < b.N; i++ {
 187  		decrypted, err := DecryptNip4(ciphertext, key)
 188  		if err != nil {
 189  			b.Fatal(err)
 190  		}
 191  		if len(decrypted) == 0 {
 192  			b.Fatal("decrypted message is empty")
 193  		}
 194  	}
 195  }
 196  
 197  // BenchmarkNIP4RoundTrip benchmarks NIP-4 encrypt/decrypt round trip
 198  func BenchmarkNIP4RoundTrip(b *testing.B) {
 199  	key := createTestConversationKey()
 200  	msg := []byte("This is a test message for NIP-4 encryption benchmarking")
 201  
 202  	b.ResetTimer()
 203  	b.ReportAllocs()
 204  
 205  	for i := 0; i < b.N; i++ {
 206  		ciphertext, err := EncryptNip4(msg, key)
 207  		if err != nil {
 208  			b.Fatal(err)
 209  		}
 210  		_, err = DecryptNip4(ciphertext, key)
 211  		if err != nil {
 212  			b.Fatal(err)
 213  		}
 214  	}
 215  }
 216  
 217  // BenchmarkGenerateConversationKey benchmarks conversation key generation
 218  func BenchmarkGenerateConversationKey(b *testing.B) {
 219  	signer1, _ := createTestKeyPair()
 220  	signer2, _ := createTestKeyPair()
 221  
 222  	// Get compressed public keys
 223  	pub1, err := signer1.PubCompressed()
 224  	if err != nil {
 225  		b.Fatal(err)
 226  	}
 227  	pub2, err := signer2.PubCompressed()
 228  	if err != nil {
 229  		b.Fatal(err)
 230  	}
 231  
 232  	b.ResetTimer()
 233  	b.ReportAllocs()
 234  
 235  	for i := 0; i < b.N; i++ {
 236  		_, err := GenerateConversationKey(signer1.Sec(), pub1)
 237  		if err != nil {
 238  			b.Fatal(err)
 239  		}
 240  		// Use signer2's pubkey for next iteration to vary inputs
 241  		pub1 = pub2
 242  	}
 243  }
 244  
 245  // BenchmarkCalcPadding benchmarks padding calculation
 246  func BenchmarkCalcPadding(b *testing.B) {
 247  	sizes := []int{
 248  		1, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
 249  	}
 250  
 251  	b.ResetTimer()
 252  	b.ReportAllocs()
 253  
 254  	for i := 0; i < b.N; i++ {
 255  		size := sizes[i%len(sizes)]
 256  		_ = calcPadding(size)
 257  	}
 258  }
 259  
 260  // BenchmarkGetKeys benchmarks key derivation
 261  func BenchmarkGetKeys(b *testing.B) {
 262  	conversationKey := createTestConversationKey()
 263  	nonce := frand.Bytes(32)
 264  
 265  	b.ResetTimer()
 266  	b.ReportAllocs()
 267  
 268  	for i := 0; i < b.N; i++ {
 269  		_, _, _, err := MessageKeys(conversationKey, nonce)
 270  		if err != nil {
 271  			b.Fatal(err)
 272  		}
 273  	}
 274  }
 275  
 276  // BenchmarkEncryptInternal benchmarks internal encrypt function
 277  func BenchmarkEncryptInternal(b *testing.B) {
 278  	key := createTestConversationKey()
 279  	nonce := frand.Bytes(12)
 280  	message := make([]byte, 256)
 281  	for i := range message {
 282  		message[i] = byte(i % 256)
 283  	}
 284  
 285  	b.ResetTimer()
 286  	b.ReportAllocs()
 287  
 288  	for i := 0; i < b.N; i++ {
 289  		_, err := chacha20_(key, nonce, message)
 290  		if err != nil {
 291  			b.Fatal(err)
 292  		}
 293  	}
 294  }
 295  
 296  // BenchmarkSHA256Hmac benchmarks HMAC calculation
 297  func BenchmarkSHA256Hmac(b *testing.B) {
 298  	key := createTestConversationKey()
 299  	nonce := frand.Bytes(32)
 300  	ciphertext := make([]byte, 256)
 301  	for i := range ciphertext {
 302  		ciphertext[i] = byte(i % 256)
 303  	}
 304  
 305  	b.ResetTimer()
 306  	b.ReportAllocs()
 307  
 308  	for i := 0; i < b.N; i++ {
 309  		_, err := sha256Hmac(key, ciphertext, nonce)
 310  		if err != nil {
 311  			b.Fatal(err)
 312  		}
 313  	}
 314  }
 315