144 lines
3.7 KiB
Go
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)
|
|
}
|