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