package fair_test import ( "bytes" "testing" "github.com/drjones/quantum-arcade/pkg/fair" ) func TestCommitmentHidesSeed(t *testing.T) { s := fair.NewServerSeed() c := s.Commitment() raw := s.Bytes() if bytes.Contains(c[:], raw[:8]) { t.Fatal("commitment leaks seed bytes") } } func TestCommitmentVerifies(t *testing.T) { s := fair.NewServerSeed() c := s.Commitment() if !fair.VerifyCommitment(c, s) { t.Fatal("valid seed failed its own commitment") } other := fair.NewServerSeed() if fair.VerifyCommitment(c, other) { t.Fatal("a different seed satisfied the commitment") } } func TestClientSeedDependsOnEveryParticipant(t *testing.T) { a := []byte("player-a-pubkey") b := []byte("player-b-pubkey") c := []byte("player-c-pubkey") withAll := fair.ClientSeed([][]byte{a, b, c}) withoutC := fair.ClientSeed([][]byte{a, b}) if withAll == withoutC { t.Fatal("removing a participant did not change the client seed") } } // Join order must matter in a defined way, but the same set in the same order // must always produce the same seed. func TestClientSeedIsStable(t *testing.T) { keys := [][]byte{[]byte("k1"), []byte("k2")} if fair.ClientSeed(keys) != fair.ClientSeed(keys) { t.Fatal("client seed is not stable for identical input") } } func TestRoundSeedIsDeterministic(t *testing.T) { s := fair.NewServerSeed() cs := fair.ClientSeed([][]byte{[]byte("p1")}) first := fair.RoundSeed(s, cs, 7) for i := 0; i < 50; i++ { if fair.RoundSeed(s, cs, 7) != first { t.Fatal("round seed is not deterministic") } } } func TestNonceSeparatesOutcomes(t *testing.T) { s := fair.NewServerSeed() cs := fair.ClientSeed([][]byte{[]byte("p1")}) seen := map[[32]byte]bool{} for n := uint64(0); n < 1000; n++ { seed := fair.RoundSeed(s, cs, n) if seen[seed] { t.Fatalf("nonce %d collided with an earlier round seed", n) } seen[seed] = true } } // The full protocol as a player would check it: the commitment published before // the round must match the seed revealed after, and the seed must reproduce the // outcome. func TestEndToEndVerification(t *testing.T) { server := fair.NewServerSeed() published := server.Commitment() participants := [][]byte{[]byte("alice"), []byte("bob")} cs := fair.ClientSeed(participants) const nonce = 42 seed := fair.RoundSeed(server, cs, nonce) // After the round the server reveals the seed. A player recomputes: if !fair.VerifyCommitment(published, server) { t.Fatal("revealed seed does not match published commitment") } recomputed := fair.RoundSeed(server, fair.ClientSeed(participants), nonce) if recomputed != seed { t.Fatal("independent recomputation produced a different seed") } } func TestServerSeedsAreUnique(t *testing.T) { seen := map[[32]byte]bool{} for i := 0; i < 1000; i++ { s := fair.NewServerSeed() if seen[s.Bytes()] { t.Fatal("NewServerSeed returned a duplicate") } seen[s.Bytes()] = true } }