sync

Backup service to store encrypted wallet databases (experimental)
Log | Files | Refs | Submodules | README | LICENSE

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 */