xref: /isa-l_crypto/rolling_hash/rolling_hash2_test.c (revision 1e0b122e090c8ad3a8d8c56e182f754ea26fe70d)
1 /**********************************************************************
2   Copyright(c) 2011-2017 Intel Corporation All rights reserved.
3 
4   Redistribution and use in source and binary forms, with or without
5   modification, are permitted provided that the following conditions
6   are met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above copyright
10       notice, this list of conditions and the following disclaimer in
11       the documentation and/or other materials provided with the
12       distribution.
13     * Neither the name of Intel Corporation nor the names of its
14       contributors may be used to endorse or promote products derived
15       from this software without specific prior written permission.
16 
17   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 **********************************************************************/
29 
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include "isal_crypto_api.h"
35 #include "rolling_hashx.h"
36 
37 #ifndef FUT_run
38 #define FUT_run isal_rolling_hash2_run
39 #endif
40 #ifndef FUT_init
41 #define FUT_init isal_rolling_hash2_init
42 #endif
43 #ifndef FUT_reset
44 #define FUT_reset isal_rolling_hash2_reset
45 #endif
46 #ifndef FUT_ref
47 #define FUT_ref rolling_hash2_ref
48 #endif
49 
50 #define str(s)  #s
51 #define xstr(s) str(s)
52 
53 #define MAX_BUFFER_SIZE        128 * 1024 * 1024
54 #define MAX_ROLLING_HASH_WIDTH 32
55 
56 #ifndef RANDOMS
57 #define RANDOMS 200
58 #endif
59 #ifndef TEST_SEED
60 #define TEST_SEED 0x1234
61 #endif
62 
63 #ifndef FIPS_MODE
64 static uint64_t
rolling_hash2_ref(struct isal_rh_state2 * state,unsigned char * p,int len,uint64_t hash_init)65 rolling_hash2_ref(struct isal_rh_state2 *state, unsigned char *p, int len, uint64_t hash_init)
66 {
67         int i;
68         uint64_t h = hash_init;
69 
70         for (i = 0; i < len; i++) {
71                 h = (h << 1) | (h >> (64 - 1));
72                 h ^= state->table1[*p++];
73         }
74         return h;
75 }
76 
77 static int
ones_in_mask(uint32_t in)78 ones_in_mask(uint32_t in)
79 {
80         int count;
81 
82         for (count = 0; in != 0; in &= (in - 1))
83                 count++;
84 
85         return count;
86 }
87 
88 /*
89  * Utility function to pick a random mask.  Not uniform in number of bits.
90  */
91 static uint32_t
pick_rand_mask_in_range(int min_bits,int max_bits)92 pick_rand_mask_in_range(int min_bits, int max_bits)
93 {
94         uint32_t mask = 0;
95         int ones;
96 
97         do {
98                 mask = rand();
99 #if defined(_WIN32) || defined(_WIN64)
100                 mask = (mask << 16) ^ rand();
101 #endif
102                 ones = ones_in_mask(mask);
103         } while (ones < min_bits || ones > max_bits);
104 
105         return mask;
106 }
107 #endif
108 
109 int
main(void)110 main(void)
111 {
112 #ifndef FIPS_MODE
113         uint8_t *buffer;
114         uint64_t hash;
115         uint32_t w, max, mask, trigger, offset = 0;
116         int i, r, ret, match, errors = 0;
117         uint32_t offset_fut;
118         struct isal_rh_state2 state;
119 
120         printf(xstr(FUT_run) ": " xstr(MAX_BUFFER_SIZE));
121 
122         buffer = malloc(MAX_BUFFER_SIZE);
123         if (buffer == NULL) {
124                 printf("cannot allocate mem\n");
125                 return -1;
126         }
127         srand(TEST_SEED);
128 
129         // Test case 1, compare trigger case at boundary with reference hash
130         w = 32;
131         mask = 0xffff0;
132         trigger = 0x3df0;
133         trigger &= mask;
134 
135         for (i = 0; i < MAX_BUFFER_SIZE; i++)
136                 buffer[i] = rand();
137 
138         FUT_init(&state, w);
139         FUT_reset(&state, buffer);
140 
141         uint8_t *p = buffer;
142         uint32_t remain = MAX_BUFFER_SIZE;
143         match = ISAL_FINGERPRINT_RET_HIT;
144 
145         while ((match == ISAL_FINGERPRINT_RET_HIT) && (remain > 0)) {
146                 ret = FUT_run(&state, p, remain, mask, trigger, &offset, &match);
147 
148                 if (ret != ISAL_CRYPTO_ERR_NONE) {
149                         printf(" %s (TC1) returned error %d\n", xstr(FUT_run), ret);
150                         errors++;
151                 }
152 
153                 if (offset > remain) {
154                         printf(" error offset past remaining limit\n");
155                         errors++;
156                 }
157 
158                 if ((match == ISAL_FINGERPRINT_RET_HIT) && (&p[offset] > &buffer[w])) {
159                         hash = FUT_ref(&state, &p[offset] - w, w, 0);
160                         if ((hash & mask) != trigger) {
161                                 printf("   mismatch chunk from ref");
162                                 printf(" hit: offset=%u %llx %llx\n", (unsigned) offset,
163                                        (unsigned long long) state.hash, (unsigned long long) hash);
164                                 errors++;
165                         }
166                 }
167                 p += offset;
168                 remain -= offset;
169                 putchar('.');
170         }
171 
172         putchar('.'); // Finished test 1
173 
174         // Test case 2, check if reference function hits same chunk boundary as test
175 
176         w = 32;
177         mask = 0xffff;
178         trigger = rand();
179         trigger &= mask;
180         p = buffer;
181 
182         // Function under test
183         FUT_init(&state, w);
184         FUT_reset(&state, p);
185         FUT_run(&state, p + w, MAX_BUFFER_SIZE - w, mask, trigger, &offset_fut, &match);
186         offset_fut += w;
187 
188         // Reference
189         for (p++, offset = w + 1; offset < MAX_BUFFER_SIZE; offset++) {
190                 hash = FUT_ref(&state, p++, w, 0);
191                 if ((hash & mask) == trigger)
192                         break;
193         }
194 
195         if (offset != offset_fut) {
196                 printf("\ncase 2, offset of chunk different from ref\n");
197                 printf("  case 2: stop fut at offset=%d\n", offset_fut);
198                 printf("  case 2: stop ref at offset=%d\n", offset);
199                 errors++;
200                 goto end;
201         }
202         putchar('.'); // Finished test 2
203 
204         // Do case 2 above with random args
205 
206         for (r = 0; r < RANDOMS; r++) {
207                 w = rand() % MAX_ROLLING_HASH_WIDTH;
208                 if (w < 3)
209                         continue;
210 
211                 mask = pick_rand_mask_in_range(4, 20);
212                 trigger = rand() & mask;
213                 p = buffer;
214 
215                 // Function under test
216                 FUT_init(&state, w);
217                 FUT_reset(&state, p);
218                 FUT_run(&state, p + w, MAX_BUFFER_SIZE - w, mask, trigger, &offset_fut, &match);
219                 offset_fut += w;
220 
221                 // Reference
222                 for (p++, offset = w + 1; offset < MAX_BUFFER_SIZE; offset++) {
223                         hash = FUT_ref(&state, p++, w, 0);
224                         if ((hash & mask) == trigger)
225                                 break;
226                 }
227 
228                 if (offset != offset_fut) {
229                         printf("\nrand case 2 #%d: w=%d, mask=0x%x, trigger=0x%x\n", r, w, mask,
230                                trigger);
231                         printf("  offset of chunk different from ref\n");
232                         printf("  case 2r: stop fut at offset=%d\n", offset_fut);
233                         printf("  case 2r: stop ref at offset=%d\n", offset);
234                         errors++;
235                         goto end;
236                 }
237                 putchar('.');
238         }
239 
240         // Test case 3, check if max bound is same
241 
242         w = 32;
243         mask = 0xfffff;
244         trigger = rand();
245         trigger &= mask;
246         putchar('|');
247 
248         for (max = w + 1; max < 500; max++) {
249                 p = buffer;
250                 FUT_init(&state, w);
251                 FUT_reset(&state, p);
252 
253                 ret = FUT_run(&state, p + w, max - w, mask, trigger, &offset_fut, &match);
254 
255                 if (ret != ISAL_CRYPTO_ERR_NONE) {
256                         printf(" %s (TC3) returned error %d\n", xstr(FUT_run), ret);
257                         errors++;
258                 }
259 
260                 offset_fut += w;
261 
262                 int ret_ref = ISAL_FINGERPRINT_RET_MAX;
263                 for (p++, offset = w + 1; offset < max; offset++) {
264                         hash = FUT_ref(&state, p++, w, 0);
265                         if ((hash & mask) == trigger) {
266                                 ret_ref = ISAL_FINGERPRINT_RET_HIT;
267                                 break;
268                         }
269                 }
270 
271                 if (offset != offset_fut || match != ret_ref) {
272                         printf("\ncase 3 max=%d, offset of chunk different from ref\n", max);
273                         printf("  case 3: stop fut at offset=%d\n", offset_fut);
274                         printf("  case 3: stop ref at offset=%d\n", offset);
275                         printf("  case 3: ret_fut=%d ret_ref=%d\n", match, ret_ref);
276                         errors++;
277                         goto end;
278                 }
279                 putchar('.'); // Finished test 3
280         }
281 
282         // Test case 4, check if max bound is same under random params
283 
284         for (r = 0; r < RANDOMS; r++) {
285                 p = buffer;
286                 mask = pick_rand_mask_in_range(24, 30); // Pick an unlikely mask
287                 trigger = rand() & mask;
288                 w = rand() % MAX_ROLLING_HASH_WIDTH;
289                 max = rand() % 1024;
290 
291                 if (w < 3 || max < 2 * MAX_ROLLING_HASH_WIDTH)
292                         continue;
293 
294                 FUT_init(&state, w);
295                 FUT_reset(&state, p);
296 
297                 ret = FUT_run(&state, p, max, mask, trigger, &offset_fut, &match);
298 
299                 if (ret != ISAL_CRYPTO_ERR_NONE) {
300                         printf(" %s (TC4) returned error %d\n", xstr(FUT_run), ret);
301                         errors++;
302                 }
303 
304                 if (offset_fut <= w)
305                         continue;
306 
307                 int ret_ref = ISAL_FINGERPRINT_RET_MAX;
308                 for (p++, offset = w + 1; offset < max; offset++) {
309                         hash = FUT_ref(&state, p++, w, 0);
310                         if ((hash & mask) == trigger) {
311                                 ret_ref = ISAL_FINGERPRINT_RET_HIT;
312                                 break;
313                         }
314                 }
315 
316                 if (offset != offset_fut || match != ret_ref) {
317                         printf("\ncase 4 rand case different from ref, max=%d w=%d\n", max, w);
318                         printf("  case 4: stop fut at offset=%d\n", offset_fut);
319                         printf("  case 4: stop ref at offset=%d\n", offset);
320                         printf("  case 4: ret_fut=%d ret_ref=%d\n", match, ret_ref);
321                         errors++;
322                         goto end;
323                 }
324                 putchar('.'); // Finished test 4
325 
326                 if (match == ISAL_FINGERPRINT_RET_HIT) {
327                         p[-1] = rand(); // Keep hits from repeating
328                 }
329         }
330 
331 end:
332         if (buffer != NULL)
333                 free(buffer);
334 
335         if (errors > 0)
336                 printf(" Fail: %d\n", errors);
337         else
338                 printf(" Pass\n");
339         return errors;
340 #else
341         printf("FIPS Mode enabled. Test not run\n");
342 
343         return 0;
344 #endif
345 }
346