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