174 lines
3.2 KiB
Go
174 lines
3.2 KiB
Go
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")
|
|
}
|
|
}
|