exchange_test.go raw
1 package crypto
2
3 import (
4 "testing"
5
6 "git.mleku.dev/mleku/dendrite/pkg/axiom"
7 "git.mleku.dev/mleku/dendrite/pkg/lattice"
8 "git.mleku.dev/mleku/dendrite/pkg/ratio"
9 "git.mleku.dev/mleku/dendrite/pkg/spore"
10 )
11
12 func buildSporeWithTags(tags []string, nodesPerTag int) *spore.Spore {
13 l := lattice.New()
14 for _, tag := range tags {
15 var nodes []*lattice.Node
16 for range nodesPerTag {
17 n := l.AddNode([]axiom.Constraint{tagConstraint{tag}})
18 nodes = append(nodes, n)
19 }
20 for i := range nodes {
21 l.Connect(nodes[i], nodes[(i+1)%len(nodes)])
22 }
23 }
24 return spore.Extract(l)
25 }
26
27 func TestExchangeSameStructure(t *testing.T) {
28 tags := []string{"word", "punct", "space"}
29 s1 := buildSporeWithTags(tags, 10)
30 s2 := buildSporeWithTags(tags, 10)
31
32 ss, err := Exchange(s1, s2)
33 if err != nil {
34 t.Fatalf("Exchange: %v", err)
35 }
36
37 if len(ss.CommonTags) != 3 {
38 t.Errorf("common tags = %d, want 3", len(ss.CommonTags))
39 }
40 if !ss.Confidence.Equal(ratio.One) {
41 t.Errorf("confidence = %s, want 1/1", ss.Confidence)
42 }
43 if ss.Secret == (Hamadryad{}) {
44 t.Error("secret should not be zero")
45 }
46 }
47
48 func TestExchangePartialOverlap(t *testing.T) {
49 s1 := buildSporeWithTags([]string{"word", "punct"}, 10)
50 s2 := buildSporeWithTags([]string{"punct", "space"}, 10)
51
52 ss, err := Exchange(s1, s2)
53 if err != nil {
54 t.Fatalf("Exchange: %v", err)
55 }
56
57 if len(ss.CommonTags) != 1 {
58 t.Errorf("common tags = %d, want 1 (punct)", len(ss.CommonTags))
59 }
60 if ss.CommonTags[0] != "punct" {
61 t.Errorf("common tag = %q, want punct", ss.CommonTags[0])
62 }
63 // Confidence: 1 common / max(2, 2) = 1/2
64 if !ss.Confidence.Equal(ratio.Half) {
65 t.Errorf("confidence = %s, want 1/2", ss.Confidence)
66 }
67 }
68
69 func TestExchangeNoOverlap(t *testing.T) {
70 s1 := buildSporeWithTags([]string{"word"}, 10)
71 s2 := buildSporeWithTags([]string{"punct"}, 10)
72
73 ss, err := Exchange(s1, s2)
74 if err != nil {
75 t.Fatalf("Exchange: %v", err)
76 }
77
78 if len(ss.CommonTags) != 0 {
79 t.Errorf("common tags = %d, want 0", len(ss.CommonTags))
80 }
81 if !ss.Confidence.Equal(ratio.Zero) {
82 t.Errorf("confidence = %s, want 0", ss.Confidence)
83 }
84 }
85
86 func TestExchangeSymmetry(t *testing.T) {
87 s1 := buildSporeWithTags([]string{"word", "punct"}, 8)
88 s2 := buildSporeWithTags([]string{"word", "punct", "space"}, 6)
89
90 ss1, err := Exchange(s1, s2)
91 if err != nil {
92 t.Fatalf("Exchange(1,2): %v", err)
93 }
94 ss2, err := Exchange(s2, s1)
95 if err != nil {
96 t.Fatalf("Exchange(2,1): %v", err)
97 }
98
99 if ss1.Secret != ss2.Secret {
100 t.Error("exchange should be symmetric: both parties derive the same secret")
101 }
102 if !ss1.Confidence.Equal(ss2.Confidence) {
103 t.Error("confidence should be symmetric")
104 }
105 }
106
107 func TestExchangeNilSpore(t *testing.T) {
108 s := buildSporeWithTags([]string{"word"}, 5)
109 _, err := Exchange(nil, s)
110 if err == nil {
111 t.Error("expected error with nil spore")
112 }
113 _, err = Exchange(s, nil)
114 if err == nil {
115 t.Error("expected error with nil spore")
116 }
117 }
118
119 func TestDeriveKey(t *testing.T) {
120 ss := &SharedSecret{
121 CommonTags: []string{"word"},
122 Secret: Hamadryad{1, 2, 3},
123 Confidence: ratio.One,
124 }
125
126 key16 := DeriveKey(ss, "aes-128", 16)
127 if len(key16) != 16 {
128 t.Errorf("key length = %d, want 16", len(key16))
129 }
130
131 key32 := DeriveKey(ss, "aes-256", 32)
132 if len(key32) != 32 {
133 t.Errorf("key length = %d, want 32", len(key32))
134 }
135
136 key64 := DeriveKey(ss, "extended", 64)
137 if len(key64) != 64 {
138 t.Errorf("key length = %d, want 64", len(key64))
139 }
140
141 // Different contexts should produce different keys.
142 keyA := DeriveKey(ss, "context-a", 32)
143 keyB := DeriveKey(ss, "context-b", 32)
144 if string(keyA) == string(keyB) {
145 t.Error("different contexts should produce different keys")
146 }
147 }
148
149 func TestDeriveKeyDeterministic(t *testing.T) {
150 ss := &SharedSecret{
151 CommonTags: []string{"word"},
152 Secret: Hamadryad{42},
153 Confidence: ratio.One,
154 }
155
156 key1 := DeriveKey(ss, "test", 32)
157 key2 := DeriveKey(ss, "test", 32)
158 if string(key1) != string(key2) {
159 t.Error("same inputs should produce same key")
160 }
161 }
162