Files
galaxy-game/ui/core/keypair/keypair_test.go
T
Ilia Denisov dc1c9b109c phase 3
2026-05-07 09:40:37 +02:00

144 lines
3.7 KiB
Go

package keypair_test
import (
"bytes"
"crypto/ed25519"
"crypto/rand"
"encoding/base64"
"testing"
"galaxy/core/keypair"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGenerateProducesIndependentCopies(t *testing.T) {
t.Parallel()
priv, pub, err := keypair.Generate(rand.Reader)
require.NoError(t, err)
require.Len(t, priv, ed25519.PrivateKeySize)
require.Len(t, pub, ed25519.PublicKeySize)
// Mutating the returned slices must not affect a fresh call.
priv[0] ^= 0xFF
pub[0] ^= 0xFF
priv2, pub2, err := keypair.Generate(rand.Reader)
require.NoError(t, err)
assert.NotEqual(t, priv[:8], priv2[:8])
assert.NotEqual(t, pub[:8], pub2[:8])
}
func TestGenerateIsDeterministicForFixedSeed(t *testing.T) {
t.Parallel()
seed := bytes.Repeat([]byte{0x42}, ed25519.SeedSize)
priv1, pub1, err := keypair.Generate(bytes.NewReader(seed))
require.NoError(t, err)
priv2, pub2, err := keypair.Generate(bytes.NewReader(seed))
require.NoError(t, err)
assert.Equal(t, priv1, priv2)
assert.Equal(t, pub1, pub2)
}
func TestGenerateRejectsNilReader(t *testing.T) {
t.Parallel()
_, _, err := keypair.Generate(nil)
require.Error(t, err)
}
func TestSignRoundTrip(t *testing.T) {
t.Parallel()
priv, pub, err := keypair.Generate(rand.Reader)
require.NoError(t, err)
message := []byte("ui-core-roundtrip")
signature, err := keypair.Sign(priv, message)
require.NoError(t, err)
assert.Len(t, signature, ed25519.SignatureSize)
assert.True(t, keypair.Verify(pub, message, signature))
assert.False(t, keypair.Verify(pub, []byte("tampered"), signature))
tampered := append([]byte(nil), signature...)
tampered[0] ^= 0xFF
assert.False(t, keypair.Verify(pub, message, tampered))
}
func TestSignRejectsInvalidPrivateKey(t *testing.T) {
t.Parallel()
_, err := keypair.Sign([]byte("short"), []byte("message"))
require.ErrorIs(t, err, keypair.ErrInvalidPrivateKey)
}
func TestVerifyRejectsInvalidLengths(t *testing.T) {
t.Parallel()
priv, pub, err := keypair.Generate(rand.Reader)
require.NoError(t, err)
signature, err := keypair.Sign(priv, []byte("message"))
require.NoError(t, err)
assert.False(t, keypair.Verify(pub[:8], []byte("message"), signature))
assert.False(t, keypair.Verify(pub, []byte("message"), signature[:8]))
}
func TestMarshalUnmarshalPublicKeyRoundTrip(t *testing.T) {
t.Parallel()
_, pub, err := keypair.Generate(rand.Reader)
require.NoError(t, err)
encoded, err := keypair.MarshalPublicKey(pub)
require.NoError(t, err)
require.NotEmpty(t, encoded)
// Encoding must be base64 StdEncoding to match docs/ARCHITECTURE.md §15.
expected := base64.StdEncoding.EncodeToString(pub)
assert.Equal(t, expected, encoded)
decoded, err := keypair.UnmarshalPublicKey(encoded)
require.NoError(t, err)
assert.Equal(t, pub, decoded)
}
func TestMarshalPublicKeyRejectsInvalidLength(t *testing.T) {
t.Parallel()
_, err := keypair.MarshalPublicKey([]byte("short"))
require.ErrorIs(t, err, keypair.ErrInvalidPublicKey)
}
func TestUnmarshalPublicKeyRejectsBadEncoding(t *testing.T) {
t.Parallel()
_, err := keypair.UnmarshalPublicKey("%%%not-base64%%%")
require.ErrorIs(t, err, keypair.ErrInvalidPublicKeyEncoding)
}
func TestUnmarshalPublicKeyRejectsWrongLength(t *testing.T) {
t.Parallel()
_, err := keypair.UnmarshalPublicKey(base64.StdEncoding.EncodeToString([]byte("short")))
require.ErrorIs(t, err, keypair.ErrInvalidPublicKey)
}
func TestPublicKeyFromPrivate(t *testing.T) {
t.Parallel()
priv, pub, err := keypair.Generate(rand.Reader)
require.NoError(t, err)
derived, err := keypair.PublicKeyFromPrivate(priv)
require.NoError(t, err)
assert.Equal(t, pub, derived)
_, err = keypair.PublicKeyFromPrivate([]byte("short"))
require.ErrorIs(t, err, keypair.ErrInvalidPrivateKey)
}