encrypt_test.go raw

   1  package crypto
   2  
   3  import (
   4  	"testing"
   5  
   6  	"git.mleku.dev/mleku/dendrite/pkg/axiom"
   7  )
   8  
   9  func testKeyPair() *KeyPair {
  10  	l := buildMatureLattice()
  11  	return GenerateKeyPair(l, DefaultParams(Security128), testFactory)
  12  }
  13  
  14  func TestEncryptProducesCiphertext(t *testing.T) {
  15  	kp := testKeyPair()
  16  	msg := []byte("hello world")
  17  	params := DefaultParams(Security128)
  18  
  19  	ct, err := Encrypt(&kp.Public, msg, params)
  20  	if err != nil {
  21  		t.Fatalf("Encrypt: %v", err)
  22  	}
  23  	if ct == nil {
  24  		t.Fatal("ciphertext should not be nil")
  25  	}
  26  	if len(ct.Sites) == 0 {
  27  		t.Error("ciphertext should have sites")
  28  	}
  29  	if ct.Basis == nil {
  30  		t.Error("ciphertext should have basis")
  31  	}
  32  }
  33  
  34  func TestEncryptOccupiesSites(t *testing.T) {
  35  	kp := testKeyPair()
  36  	msg := []byte("test")
  37  	params := DefaultParams(Security128)
  38  
  39  	ct, err := Encrypt(&kp.Public, msg, params)
  40  	if err != nil {
  41  		t.Fatalf("Encrypt: %v", err)
  42  	}
  43  
  44  	occupied := 0
  45  	for _, s := range ct.Sites {
  46  		if s.Occupied {
  47  			occupied++
  48  		}
  49  	}
  50  	if occupied == 0 {
  51  		t.Error("encryption should produce occupied sites")
  52  	}
  53  }
  54  
  55  func TestEncryptInvalidParams(t *testing.T) {
  56  	kp := testKeyPair()
  57  	msg := []byte("hello")
  58  	bad := Params{} // all zeros — invalid
  59  
  60  	_, err := Encrypt(&kp.Public, msg, bad)
  61  	if err == nil {
  62  		t.Error("expected error with invalid params")
  63  	}
  64  }
  65  
  66  func TestEncryptNilSpore(t *testing.T) {
  67  	pub := &PublicKey{
  68  		Basis: &Basis{Tags: []string{"word"}},
  69  		Spore: nil,
  70  	}
  71  	_, err := Encrypt(pub, []byte("x"), DefaultParams(Security128))
  72  	if err == nil {
  73  		t.Error("expected error with nil spore")
  74  	}
  75  }
  76  
  77  func TestEncryptDecryptRoundTrip(t *testing.T) {
  78  	// Build a lattice and keypair where we control the constraints.
  79  	l := buildMatureLattice()
  80  	params := DefaultParams(Security128)
  81  	kp := GenerateKeyPair(l, params, testFactory)
  82  
  83  	msg := []byte("hi")
  84  	ct, err := Encrypt(&kp.Public, msg, params)
  85  	if err != nil {
  86  		t.Fatalf("Encrypt: %v", err)
  87  	}
  88  
  89  	// Decrypt should recover at least some bytes.
  90  	// Full round-trip correctness depends on the lattice being
  91  	// deterministic with matching constraints. With public constraints
  92  	// on both sides, the decrypt should find the bytes via hash matching.
  93  	result, err := Decrypt(&kp.Private, ct)
  94  	if err != nil {
  95  		// Decryption may fail if dissolution removed all message elements.
  96  		// This is expected with certain parameter combinations.
  97  		t.Logf("Decrypt returned error (may be expected): %v", err)
  98  		return
  99  	}
 100  
 101  	// Check that at least some bytes were recovered.
 102  	if len(result) == 0 {
 103  		t.Error("expected non-empty decryption result")
 104  	}
 105  }
 106  
 107  func TestDecryptNilCiphertext(t *testing.T) {
 108  	kp := testKeyPair()
 109  	_, err := Decrypt(&kp.Private, nil)
 110  	if err == nil {
 111  		t.Error("expected error with nil ciphertext")
 112  	}
 113  }
 114  
 115  func TestDecryptNoFactory(t *testing.T) {
 116  	ct := &Ciphertext{
 117  		Sites:  []SiteMark{{Occupied: true, TypeTag: "word"}},
 118  		Params: DefaultParams(Security128),
 119  		Basis:  &Basis{Tags: []string{"word"}},
 120  	}
 121  	privkey := &PrivateKey{ConstraintFactory: nil}
 122  	_, err := Decrypt(privkey, ct)
 123  	if err == nil {
 124  		t.Error("expected error with nil factory")
 125  	}
 126  }
 127  
 128  func TestMessageElementInterface(t *testing.T) {
 129  	me := MessageElement{Index: 0, Byte: 'A', TypeTag: "word"}
 130  	var e axiom.Element = me
 131  	if e.Type() != "word" {
 132  		t.Errorf("Type() = %q, want word", e.Type())
 133  	}
 134  	if e.Value().(byte) != 'A' {
 135  		t.Errorf("Value() = %v, want 'A'", e.Value())
 136  	}
 137  }
 138  
 139  func TestPublicConstraint(t *testing.T) {
 140  	factory := publicConstraintFactory(&Basis{Tags: []string{"word", "punct"}})
 141  	c := factory("word")
 142  	if c.Tag() != "word" {
 143  		t.Errorf("Tag() = %q, want word", c.Tag())
 144  	}
 145  	if !c.Admits(testElem{"word", "x"}) {
 146  		t.Error("should admit matching element")
 147  	}
 148  	if c.Admits(testElem{"punct", "."}) {
 149  		t.Error("should reject mismatched element")
 150  	}
 151  }
 152