hamadryad_test.go raw
1 package crypto
2
3 import (
4 "bytes"
5 "testing"
6 )
7
8 func TestHamadryadHashDeterministic(t *testing.T) {
9 msg := []byte("hello world")
10 h1 := Hash(msg)
11 h2 := Hash(msg)
12 if h1 != h2 {
13 t.Error("same input produced different hashes")
14 }
15 }
16
17 func TestHamadryadHashDistinct(t *testing.T) {
18 h1 := Hash([]byte("hello"))
19 h2 := Hash([]byte("world"))
20 if h1 == h2 {
21 t.Error("different inputs produced same hash")
22 }
23 }
24
25 func TestHamadryadHashEmpty(t *testing.T) {
26 h := Hash([]byte{})
27 if h.IsZero() {
28 t.Error("hash of empty input should not be zero")
29 }
30 }
31
32 func TestHamadryadHashLong(t *testing.T) {
33 // Test with input longer than one block (128 bytes).
34 msg := bytes.Repeat([]byte("a"), 500)
35 h := Hash(msg)
36 if h.IsZero() {
37 t.Error("hash of long input should not be zero")
38 }
39
40 // Changing one byte should change the hash.
41 msg2 := make([]byte, len(msg))
42 copy(msg2, msg)
43 msg2[250] = 'b'
44 h2 := Hash(msg2)
45 if h == h2 {
46 t.Error("changing one byte did not change hash")
47 }
48 }
49
50 func TestHamadryadDisperse(t *testing.T) {
51 h := Hash([]byte("test shard extraction"))
52 s := h.Disperse()
53
54 // Shard should be the first 6 bytes of the Hamadryad.
55 if !bytes.Equal(s[:], h[:ShardBytes]) {
56 t.Error("Disperse did not extract first 6 bytes")
57 }
58 }
59
60 func TestHamPackUnpack(t *testing.T) {
61 // Create known coefficients, pack, unpack, verify round-trip.
62 var coeffs [HamN]uint16
63 for i := range HamN {
64 coeffs[i] = uint16(i) % HamR
65 }
66
67 packed := packCoeffs(coeffs)
68 unpacked := unpackCoeffs(packed)
69
70 for i := range HamN {
71 if unpacked[i] != coeffs[i] {
72 t.Errorf("round-trip failed at [%d]: got %d, want %d", i, unpacked[i], coeffs[i])
73 }
74 }
75 }
76
77 func TestHamPackMaxValues(t *testing.T) {
78 // All coefficients at max value (127).
79 var coeffs [HamN]uint16
80 for i := range HamN {
81 coeffs[i] = HamR - 1
82 }
83
84 packed := packCoeffs(coeffs)
85 unpacked := unpackCoeffs(packed)
86
87 for i := range HamN {
88 if unpacked[i] != HamR-1 {
89 t.Errorf("[%d]: got %d, want %d", i, unpacked[i], HamR-1)
90 }
91 }
92 }
93
94 func TestHamadryadSum(t *testing.T) {
95 h1 := Hash([]byte("alpha"))
96 h2 := Hash([]byte("beta"))
97 sum := h1.Sum(h2)
98
99 // Sum should be different from both inputs.
100 if sum == h1 || sum == h2 {
101 t.Error("sum should differ from both inputs")
102 }
103
104 // Sum should be deterministic.
105 sum2 := h1.Sum(h2)
106 if sum != sum2 {
107 t.Error("sum not deterministic")
108 }
109 }
110
111 func TestHamadryadHashValue(t *testing.T) {
112 // HashValue should produce consistent results for same input.
113 h1 := HashValue(42)
114 h2 := HashValue(42)
115 if h1 != h2 {
116 t.Error("HashValue not deterministic")
117 }
118
119 // Different values should produce different hashes.
120 h3 := HashValue(43)
121 if h1 == h3 {
122 t.Error("different values produced same hash")
123 }
124 }
125
126 func TestHamadryadCompress(t *testing.T) {
127 // Verify that hamCompress produces values in Z_257.
128 var block [hamInputBytes]byte
129 for i := range block {
130 block[i] = byte(i)
131 }
132
133 result := hamCompress(&block)
134 for i, v := range result {
135 if v >= HamP {
136 t.Errorf("coefficient [%d] = %d, exceeds p=%d", i, v, HamP)
137 }
138 }
139 }
140
141 func TestHamadryadLengthExtension(t *testing.T) {
142 // "abc" and "abc\x00" should produce different hashes.
143 h1 := Hash([]byte("abc"))
144 h2 := Hash([]byte("abc\x00"))
145 if h1 == h2 {
146 t.Error("length extension: different-length inputs produced same hash")
147 }
148 }
149
150 func BenchmarkHamadryadHash128(b *testing.B) {
151 msg := make([]byte, 128)
152 for i := range msg {
153 msg[i] = byte(i)
154 }
155 b.ResetTimer()
156 for range b.N {
157 Hash(msg)
158 }
159 }
160
161 func BenchmarkHamadryadHash1K(b *testing.B) {
162 msg := make([]byte, 1024)
163 for i := range msg {
164 msg[i] = byte(i)
165 }
166 b.ResetTimer()
167 for range b.N {
168 Hash(msg)
169 }
170 }
171