package pkg_test import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/rwadurian/mpc-system/pkg/crypto" ) func TestGenerateRandomBytes(t *testing.T) { t.Run("should generate random bytes of correct length", func(t *testing.T) { lengths := []int{16, 32, 64, 128} for _, length := range lengths { bytes, err := crypto.GenerateRandomBytes(length) require.NoError(t, err) assert.Len(t, bytes, length) } }) t.Run("should generate different bytes each time", func(t *testing.T) { bytes1, _ := crypto.GenerateRandomBytes(32) bytes2, _ := crypto.GenerateRandomBytes(32) assert.NotEqual(t, bytes1, bytes2) }) } func TestHashMessage(t *testing.T) { t.Run("should hash message consistently", func(t *testing.T) { message := []byte("test message") hash1 := crypto.HashMessage(message) hash2 := crypto.HashMessage(message) assert.Equal(t, hash1, hash2) assert.Len(t, hash1, 32) // SHA-256 produces 32 bytes }) t.Run("should produce different hashes for different messages", func(t *testing.T) { hash1 := crypto.HashMessage([]byte("message1")) hash2 := crypto.HashMessage([]byte("message2")) assert.NotEqual(t, hash1, hash2) }) } func TestEncryptDecrypt(t *testing.T) { t.Run("should encrypt and decrypt data successfully", func(t *testing.T) { key := make([]byte, 32) rand.Read(key) plaintext := []byte("secret data to encrypt") ciphertext, err := crypto.Encrypt(key, plaintext) require.NoError(t, err) assert.NotEqual(t, plaintext, ciphertext) decrypted, err := crypto.Decrypt(key, ciphertext) require.NoError(t, err) assert.Equal(t, plaintext, decrypted) }) t.Run("should fail decryption with wrong key", func(t *testing.T) { key1 := make([]byte, 32) key2 := make([]byte, 32) rand.Read(key1) rand.Read(key2) plaintext := []byte("secret data") ciphertext, _ := crypto.Encrypt(key1, plaintext) _, err := crypto.Decrypt(key2, ciphertext) assert.Error(t, err) }) t.Run("should produce different ciphertext for same plaintext", func(t *testing.T) { key := make([]byte, 32) rand.Read(key) plaintext := []byte("secret data") ciphertext1, _ := crypto.Encrypt(key, plaintext) ciphertext2, _ := crypto.Encrypt(key, plaintext) // Due to random nonce, ciphertexts should be different assert.NotEqual(t, ciphertext1, ciphertext2) }) } func TestDeriveKey(t *testing.T) { t.Run("should derive key consistently", func(t *testing.T) { secret := []byte("master secret") salt := []byte("random salt") key1, err := crypto.DeriveKey(secret, salt, 32) require.NoError(t, err) key2, err := crypto.DeriveKey(secret, salt, 32) require.NoError(t, err) assert.Equal(t, key1, key2) assert.Len(t, key1, 32) }) t.Run("should derive different keys with different salts", func(t *testing.T) { secret := []byte("master secret") key1, _ := crypto.DeriveKey(secret, []byte("salt1"), 32) key2, _ := crypto.DeriveKey(secret, []byte("salt2"), 32) assert.NotEqual(t, key1, key2) }) } func TestSignAndVerify(t *testing.T) { t.Run("should sign and verify successfully", func(t *testing.T) { privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err) message := []byte("message to sign") signature, err := crypto.SignMessage(privateKey, message) require.NoError(t, err) assert.NotEmpty(t, signature) // Hash the message for verification (SignMessage internally hashes) messageHash := crypto.HashMessage(message) valid := crypto.VerifySignature(&privateKey.PublicKey, messageHash, signature) assert.True(t, valid) }) t.Run("should fail verification with wrong message", func(t *testing.T) { privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) signature, _ := crypto.SignMessage(privateKey, []byte("original message")) wrongHash := crypto.HashMessage([]byte("different message")) valid := crypto.VerifySignature(&privateKey.PublicKey, wrongHash, signature) assert.False(t, valid) }) t.Run("should fail verification with wrong public key", func(t *testing.T) { privateKey1, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) privateKey2, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) message := []byte("message") signature, _ := crypto.SignMessage(privateKey1, message) messageHash := crypto.HashMessage(message) valid := crypto.VerifySignature(&privateKey2.PublicKey, messageHash, signature) assert.False(t, valid) }) } func TestEncodeDecodeHex(t *testing.T) { t.Run("should encode and decode hex successfully", func(t *testing.T) { original := []byte("test data") encoded := crypto.EncodeToHex(original) assert.NotEmpty(t, encoded) decoded, err := crypto.DecodeFromHex(encoded) require.NoError(t, err) assert.Equal(t, original, decoded) }) t.Run("should fail to decode invalid hex", func(t *testing.T) { _, err := crypto.DecodeFromHex("invalid-hex-string!") assert.Error(t, err) }) } func TestPublicKeyMarshaling(t *testing.T) { t.Run("should marshal and unmarshal public key", func(t *testing.T) { privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) encoded := crypto.MarshalPublicKey(&privateKey.PublicKey) assert.NotEmpty(t, encoded) decoded, err := crypto.ParsePublicKey(encoded) require.NoError(t, err) // Verify keys are equal by comparing coordinates assert.Equal(t, privateKey.PublicKey.X.Bytes(), decoded.X.Bytes()) assert.Equal(t, privateKey.PublicKey.Y.Bytes(), decoded.Y.Bytes()) }) } func TestCompareBytes(t *testing.T) { t.Run("should return true for equal byte slices", func(t *testing.T) { a := []byte("test data") b := []byte("test data") assert.True(t, crypto.CompareBytes(a, b)) }) t.Run("should return false for different byte slices", func(t *testing.T) { a := []byte("test data 1") b := []byte("test data 2") assert.False(t, crypto.CompareBytes(a, b)) }) t.Run("should return false for different length byte slices", func(t *testing.T) { a := []byte("short") b := []byte("longer string") assert.False(t, crypto.CompareBytes(a, b)) }) }