diff options
Diffstat (limited to 'src/gnunet/service/dht/blocks/filters_test.go')
-rw-r--r-- | src/gnunet/service/dht/blocks/filters_test.go | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/src/gnunet/service/dht/blocks/filters_test.go b/src/gnunet/service/dht/blocks/filters_test.go new file mode 100644 index 0000000..ef1331c --- /dev/null +++ b/src/gnunet/service/dht/blocks/filters_test.go | |||
@@ -0,0 +1,110 @@ | |||
1 | // This file is part of gnunet-go, a GNUnet-implementation in Golang. | ||
2 | // Copyright (C) 2019-2022 Bernd Fix >Y< | ||
3 | // | ||
4 | // gnunet-go is free software: you can redistribute it and/or modify it | ||
5 | // under the terms of the GNU Affero General Public License as published | ||
6 | // by the Free Software Foundation, either version 3 of the License, | ||
7 | // or (at your option) any later version. | ||
8 | // | ||
9 | // gnunet-go is distributed in the hope that it will be useful, but | ||
10 | // WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | // Affero General Public License for more details. | ||
13 | // | ||
14 | // You should have received a copy of the GNU Affero General Public License | ||
15 | // along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | // | ||
17 | // SPDX-License-Identifier: AGPL3.0-or-later | ||
18 | |||
19 | package blocks | ||
20 | |||
21 | import ( | ||
22 | "bytes" | ||
23 | "crypto/rand" | ||
24 | "sort" | ||
25 | "testing" | ||
26 | ) | ||
27 | |||
28 | type Entry []byte | ||
29 | |||
30 | type EntryList []Entry | ||
31 | |||
32 | func (list EntryList) Len() int { return len(list) } | ||
33 | func (list EntryList) Swap(i, j int) { list[i], list[j] = list[j], list[i] } | ||
34 | func (list EntryList) Less(i, j int) bool { return bytes.Compare(list[i], list[j]) < 0 } | ||
35 | |||
36 | func (list EntryList) Contains(e Entry) bool { | ||
37 | size := len(list) | ||
38 | i := sort.Search(size, func(i int) bool { return bytes.Compare(list[i], e) >= 0 }) | ||
39 | return i != size | ||
40 | } | ||
41 | |||
42 | func TestBloomfilter(t *testing.T) { | ||
43 | F := 500 // number of expected entries | ||
44 | |||
45 | // The K-value for the HELLO_BF Bloom filter is always 16. The size S of | ||
46 | // the Bloom filter in bytes depends on the number of elements F known to | ||
47 | // be filtered at the initiator. If F is zero, the size S is just 8 (bytes). | ||
48 | // Otherwise, S is set to the minimum of 2^15 and the lowest power of 2 that | ||
49 | // is strictly larger than K*F/4 (in bytes). The wire format of HELLO_BF is | ||
50 | // the resulting byte array. In particular, K is never transmitted. | ||
51 | S := 1 | ||
52 | for S < 4*F && S < 32768 { | ||
53 | S <<= 1 | ||
54 | } | ||
55 | t.Logf("BloomFilter size in bytes: %d\n", S) | ||
56 | |||
57 | // generate positives (entries in the set) | ||
58 | positives := make(EntryList, F) | ||
59 | for i := 0; i < F; i++ { | ||
60 | data := make(Entry, 32) | ||
61 | if _, err := rand.Read(data); err != nil { | ||
62 | t.Fatal(err) | ||
63 | } | ||
64 | positives[i] = data | ||
65 | } | ||
66 | sort.Sort(positives) | ||
67 | |||
68 | // generate negatives (entries outside the set) | ||
69 | negatives := make(EntryList, F) | ||
70 | for i := 0; i < F; { | ||
71 | data := make(Entry, 32) | ||
72 | if _, err := rand.Read(data); err != nil { | ||
73 | t.Fatal(err) | ||
74 | } | ||
75 | if !positives.Contains(data) { | ||
76 | negatives[i] = data | ||
77 | i++ | ||
78 | } | ||
79 | } | ||
80 | |||
81 | // create BloomFilter | ||
82 | bf := NewBloomFilter(S) | ||
83 | |||
84 | // add positives to bloomfilter | ||
85 | for _, e := range positives { | ||
86 | bf.Add(e) | ||
87 | } | ||
88 | |||
89 | // check lookup of positives | ||
90 | count := 0 | ||
91 | for _, e := range positives { | ||
92 | if !bf.Contains(e) { | ||
93 | count++ | ||
94 | } | ||
95 | } | ||
96 | if count > 0 { | ||
97 | t.Logf("FAILED with %d false-negatives", count) | ||
98 | } | ||
99 | |||
100 | // check lookup of negatives | ||
101 | count = 0 | ||
102 | for _, e := range negatives { | ||
103 | if bf.Contains(e) { | ||
104 | count++ | ||
105 | } | ||
106 | } | ||
107 | if count > 0 { | ||
108 | t.Logf("FAILED with %d false-positives", count) | ||
109 | } | ||
110 | } | ||