package crypto import ( "errors" "io" "sync" "testing" ) // mockKEM is a minimal KEM implementation for testing the registry. type mockKEM struct { schemeID uint16 } func (m *mockKEM) SchemeID() uint16 { return m.schemeID } func (m *mockKEM) GenerateKeyPair( rand io.Reader, ) ( RecipientPub, RecipientPriv, error, ) { return nil, nil, nil } func (m *mockKEM) Encapsulate( pub RecipientPub, rand io.Reader, ) ( ciphertext []byte, sharedSecret []byte, err error, ) { return nil, nil, nil } func (m *mockKEM) Decapsulate( priv RecipientPriv, ciphertext []byte, ) ( sharedSecret []byte, err error, ) { return nil, nil } func (m *mockKEM) LoadPriv( raw []byte, ) ( RecipientPriv, error, ) { return &mockRecipient{schemeIDValue: m.schemeID, rawBytes: raw}, nil } // mockRecipient implements RecipientPub and RecipientPriv for tests. type mockRecipient struct { schemeIDValue uint16 rawBytes []byte } func (r *mockRecipient) SchemeID() uint16 { return r.schemeIDValue } func (r *mockRecipient) KeyID() []byte { return r.rawBytes } func (r *mockRecipient) Raw() []byte { return r.rawBytes } func TestRegistry_RegisterAndLookup(t *testing.T) { registry := NewRegistry() factory := func() KEM { return &mockKEM{schemeID: 0x0001} } err := registry.Register(0x0001, factory) if err != nil { t.Fatalf("unexpected error registering scheme: %v", err) } foundFactory, err := registry.Lookup(0x0001) if err != nil { t.Fatalf("unexpected error looking up scheme: %v", err) } kem := foundFactory() if kem.SchemeID() != 0x0001 { t.Errorf("expected schemeID 0x0001, got 0x%04x", kem.SchemeID()) } } func TestRegistry_LookupUnknownScheme(t *testing.T) { registry := NewRegistry() _, err := registry.Lookup(0x9999) if err == nil { t.Fatal("expected error for unknown scheme, got nil") } if !errors.Is(err, ErrUnknownScheme) { t.Errorf("expected ErrUnknownScheme, got %v", err) } } func TestRegistry_RegisterDuplicateScheme(t *testing.T) { registry := NewRegistry() factory := func() KEM { return &mockKEM{schemeID: 0x0001} } err := registry.Register(0x0001, factory) if err != nil { t.Fatalf("unexpected error on first register: %v", err) } err = registry.Register(0x0001, factory) if err == nil { t.Fatal("expected error for duplicate scheme, got nil") } if !errors.Is(err, ErrDuplicateScheme) { t.Errorf("expected ErrDuplicateScheme, got %v", err) } } func TestRegistry_ConcurrentAccess(t *testing.T) { registry := NewRegistry() const goroutines = 100 var waitGroup sync.WaitGroup waitGroup.Add(goroutines) for index := range goroutines { go func(schemeID uint16) { defer waitGroup.Done() factory := func() KEM { return &mockKEM{schemeID: schemeID} } _ = registry.Register(schemeID, factory) _, _ = registry.Lookup(schemeID) }(uint16(index + 1)) } waitGroup.Wait() } func TestRegistry_LookupReturnsIndependentInstances(t *testing.T) { registry := NewRegistry() factory := func() KEM { return &mockKEM{schemeID: 0x0001} } _ = registry.Register(0x0001, factory) factoryOne, _ := registry.Lookup(0x0001) factoryTwo, _ := registry.Lookup(0x0001) kemOne := factoryOne() kemTwo := factoryTwo() if kemOne == kemTwo { t.Error("expected independent KEM instances from factory") } }