test_sync_ibf.c (6976B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file util/test_sync_ibf.c 18 * @brief tests for the sync invertible bloom filter (DD 92) 19 * @author Iván Ávalos 20 */ 21 #include "platform.h" 22 #include <gnunet/gnunet_util_lib.h> 23 #include "sync/sync_ibf.h" 24 25 26 #define FAILIF(cond) \ 27 do { \ 28 if (! (cond)) break; \ 29 GNUNET_break (0); \ 30 return 1; \ 31 } while (0) 32 33 34 /** 35 * Deterministic element: nonce and hash filled with distinct bytes 36 * derived from @a i. 37 * 38 * @param i element number 39 * @param[out] key set to the element 40 */ 41 static void 42 key_of (unsigned int i, 43 struct SYNC_IBFKey *key) 44 { 45 memset (key, 46 i + 1, 47 sizeof (*key)); 48 key->nonce[0] = (unsigned char) i; 49 key->hash[0] = (unsigned char) (i >> 8); 50 } 51 52 53 /** 54 * Insert and remove leave the filter empty again. 55 * 56 * @return 0 on success 57 */ 58 static int 59 test_insert_remove (void) 60 { 61 struct SYNC_IBF *ibf; 62 struct SYNC_IBFKey key; 63 size_t size; 64 void *data; 65 66 ibf = SYNC_ibf_create (SYNC_IBF_MIN_BUCKETS, 67 SYNC_IBF_HASH_NUM, 68 0); 69 FAILIF (NULL == ibf); 70 for (unsigned int i = 0; i < 100; i++) 71 { 72 key_of (i, 73 &key); 74 SYNC_ibf_insert (ibf, 75 &key); 76 } 77 for (unsigned int i = 0; i < 100; i++) 78 { 79 key_of (i, 80 &key); 81 SYNC_ibf_remove (ibf, 82 &key); 83 } 84 size = SYNC_ibf_get_serialized_size (ibf); 85 data = GNUNET_malloc (size); 86 SYNC_ibf_serialize (ibf, 87 data); 88 for (size_t i = 0; i < size; i++) 89 if (0 != ((const unsigned char *) data)[i]) 90 { 91 GNUNET_break (0); 92 GNUNET_free (data); 93 SYNC_ibf_destroy (ibf); 94 return 1; 95 } 96 GNUNET_free (data); 97 SYNC_ibf_destroy (ibf); 98 return 0; 99 } 100 101 102 /** 103 * The symmetric difference of two filters decodes to exactly the 104 * differing elements, with the correct side. 105 * 106 * Sets: A = {0..9} union {20..29}, B = {10..19} union {20..29}. 107 * After subtracting B from A, the difference holds 0..9 with side +1 108 * and 10..19 with side -1; 20..29 cancel out. 109 * 110 * @return 0 on success 111 */ 112 static int 113 test_decode_difference (void) 114 { 115 struct SYNC_IBF *ibf_a = SYNC_ibf_create (SYNC_IBF_MIN_BUCKETS, 116 SYNC_IBF_HASH_NUM, 117 0); 118 struct SYNC_IBF *ibf_b = SYNC_ibf_create (SYNC_IBF_MIN_BUCKETS, 119 SYNC_IBF_HASH_NUM, 120 0); 121 struct SYNC_IBFKey key; 122 123 FAILIF ( (NULL == ibf_a) || 124 (NULL == ibf_b) ); 125 for (unsigned int i = 0; i < 30; i++) 126 { 127 key_of (i, 128 &key); 129 if ( (i < 10) || 130 (i >= 20) ) 131 SYNC_ibf_insert (ibf_a, 132 &key); 133 if ( (i >= 10) ) 134 SYNC_ibf_insert (ibf_b, 135 &key); 136 } 137 138 SYNC_ibf_subtract (ibf_a, 139 ibf_b); 140 { 141 bool have[30] = { false }; 142 int16_t side[30] = { 0 }; 143 144 for (;;) 145 { 146 enum GNUNET_GenericReturnValue res; 147 int16_t got_side; 148 struct SYNC_IBFKey got_key; 149 150 res = SYNC_ibf_decode (ibf_a, 151 &got_side, 152 &got_key); 153 if (GNUNET_YES != res) 154 { 155 FAILIF (GNUNET_NO != res); 156 break; 157 } 158 { 159 const unsigned int i = (unsigned int) got_key.nonce[0]; 160 161 FAILIF (i >= 30); 162 FAILIF ((got_side != 1) && (got_side != -1)); 163 FAILIF (have[i]); 164 have[i] = true; 165 side[i] = got_side; 166 } 167 } 168 for (unsigned int i = 0; i < 30; i++) 169 { 170 if (i < 10) 171 FAILIF (! have[i] || (1 != side[i])); 172 else if (i < 20) 173 FAILIF (! have[i] || (-1 != side[i])); 174 else 175 FAILIF (have[i]); 176 } 177 } 178 SYNC_ibf_destroy (ibf_b); 179 SYNC_ibf_destroy (ibf_a); 180 return 0; 181 } 182 183 184 /** 185 * The serialized form round-trips, and mismatching parameters are 186 * rejected. 187 * 188 * @return 0 on success 189 */ 190 static int 191 test_serialize (void) 192 { 193 struct SYNC_IBF *ibf; 194 struct SYNC_IBF *ibf2; 195 struct SYNC_IBFKey key; 196 struct SYNC_IBFKey got_key; 197 size_t size; 198 void *data; 199 200 ibf = SYNC_ibf_create (SYNC_IBF_MIN_BUCKETS, 201 SYNC_IBF_HASH_NUM, 202 42); 203 FAILIF (NULL == ibf); 204 for (unsigned int i = 0; i < 20; i++) 205 { 206 key_of (i, 207 &key); 208 SYNC_ibf_insert (ibf, 209 &key); 210 } 211 size = SYNC_ibf_get_serialized_size (ibf); 212 FAILIF (size != ((size_t) SYNC_IBF_MIN_BUCKETS) * SYNC_IBF_BUCKET_SIZE); 213 data = GNUNET_malloc (size); 214 SYNC_ibf_serialize (ibf, 215 data); 216 ibf2 = SYNC_ibf_deserialize (data, 217 SYNC_IBF_MIN_BUCKETS, 218 SYNC_IBF_HASH_NUM, 219 42); 220 FAILIF (NULL == ibf2); 221 FAILIF (NULL != 222 SYNC_ibf_deserialize (data, 223 0, 224 SYNC_IBF_HASH_NUM, 225 42)); 226 { 227 int16_t side; 228 unsigned int got = 0; 229 230 for (;;) 231 { 232 enum GNUNET_GenericReturnValue res; 233 234 res = SYNC_ibf_decode (ibf2, 235 &side, 236 &got_key); 237 if (GNUNET_YES != res) 238 { 239 FAILIF (GNUNET_NO != res); 240 break; 241 } 242 got++; 243 } 244 FAILIF (got != 20); 245 } 246 SYNC_ibf_destroy (ibf2); 247 GNUNET_free (data); 248 SYNC_ibf_destroy (ibf); 249 return 0; 250 } 251 252 253 /** 254 * Bucket counts are powers of two within the bounds. 255 * 256 * @return 0 on success 257 */ 258 static int 259 test_compute_bucket_count (void) 260 { 261 FAILIF (SYNC_ibf_compute_bucket_count (0) != SYNC_IBF_MIN_BUCKETS); 262 FAILIF (SYNC_ibf_compute_bucket_count (1) != SYNC_IBF_MIN_BUCKETS); 263 FAILIF (SYNC_ibf_compute_bucket_count (1000) != 1024); 264 FAILIF (SYNC_ibf_compute_bucket_count (100000) != SYNC_IBF_MAX_BUCKETS); 265 return 0; 266 } 267 268 269 int 270 main (int argc, 271 char **argv) 272 { 273 (void) argc; 274 (void) argv; 275 FAILIF (0 != test_insert_remove ()); 276 FAILIF (0 != test_decode_difference ()); 277 FAILIF (0 != test_serialize ()); 278 FAILIF (0 != test_compute_bucket_count ()); 279 return 0; 280 } 281 282 283 /* end of test_sync_ibf.c */