1 /********************************************************************** 2 Copyright(c) 2011-2016 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 <stdio.h> 31 #include <stdlib.h> 32 #include "sha1_mb.h" 33 34 #define TEST_LEN (1024*1024) 35 #define TEST_BUFS 100 36 #ifndef RANDOMS 37 # define RANDOMS 10 38 #endif 39 #ifndef TEST_SEED 40 # define TEST_SEED 0x1234 41 #endif 42 43 #define UPDATE_SIZE 13*SHA1_BLOCK_SIZE 44 #define MAX_RAND_UPDATE_BLOCKS (TEST_LEN/(16*SHA1_BLOCK_SIZE)) 45 46 #ifdef DEBUG 47 # define debug_char(x) putchar(x) 48 #else 49 # define debug_char(x) do {} while (0) 50 #endif 51 52 /* Reference digest global to reduce stack usage */ 53 static uint32_t digest_ref[TEST_BUFS][SHA1_DIGEST_NWORDS]; 54 55 extern void sha1_ref(uint8_t * input_data, uint32_t * digest, uint32_t len); 56 57 // Generates pseudo-random data 58 59 void rand_buffer(unsigned char *buf, const long buffer_size) 60 { 61 long i; 62 for (i = 0; i < buffer_size; i++) 63 buf[i] = rand(); 64 } 65 66 int main(void) 67 { 68 SHA1_HASH_CTX_MGR *mgr = NULL; 69 SHA1_HASH_CTX ctxpool[TEST_BUFS], *ctx = NULL; 70 uint32_t i, j, fail = 0; 71 int len_done, len_rem, len_rand; 72 unsigned char *bufs[TEST_BUFS] = { 0 }; 73 unsigned char *buf_ptr[TEST_BUFS]; 74 uint32_t lens[TEST_BUFS]; 75 unsigned int joblen, jobs, t; 76 int ret; 77 78 printf("multibinary_sha1_update test, %d sets of %dx%d max: ", RANDOMS, TEST_BUFS, 79 TEST_LEN); 80 81 srand(TEST_SEED); 82 83 ret = posix_memalign((void *)&mgr, 16, sizeof(SHA1_HASH_CTX_MGR)); 84 if ((ret != 0) || (mgr == NULL)) { 85 printf("posix_memalign failed test aborted\n"); 86 return 1; 87 } 88 89 sha1_ctx_mgr_init(mgr); 90 91 for (i = 0; i < TEST_BUFS; i++) { 92 // Allocate and fill buffer 93 bufs[i] = (unsigned char *)malloc(TEST_LEN); 94 buf_ptr[i] = bufs[i]; 95 if (bufs[i] == NULL) { 96 printf("malloc failed test aborted\n"); 97 fail++; 98 goto end; 99 } 100 rand_buffer(bufs[i], TEST_LEN); 101 102 // Init ctx contents 103 hash_ctx_init(&ctxpool[i]); 104 ctxpool[i].user_data = (void *)((uint64_t) i); 105 106 // Run reference test 107 sha1_ref(bufs[i], digest_ref[i], TEST_LEN); 108 } 109 110 // Run sb_sha1 tests 111 for (i = 0; i < TEST_BUFS;) { 112 len_done = (int)((unsigned long)buf_ptr[i] - (unsigned long)bufs[i]); 113 len_rem = TEST_LEN - len_done; 114 115 if (len_done == 0) 116 ctx = sha1_ctx_mgr_submit(mgr, 117 &ctxpool[i], 118 buf_ptr[i], UPDATE_SIZE, HASH_FIRST); 119 else if (len_rem <= UPDATE_SIZE) 120 ctx = sha1_ctx_mgr_submit(mgr, 121 &ctxpool[i], buf_ptr[i], len_rem, HASH_LAST); 122 else 123 ctx = sha1_ctx_mgr_submit(mgr, 124 &ctxpool[i], 125 buf_ptr[i], UPDATE_SIZE, HASH_UPDATE); 126 127 // Add jobs while available or finished 128 if ((ctx == NULL) || hash_ctx_complete(ctx)) { 129 i++; 130 continue; 131 } 132 // Resubmit unfinished job 133 i = (unsigned long)(ctx->user_data); 134 buf_ptr[i] += UPDATE_SIZE; 135 } 136 137 // Start flushing finished jobs, end on last flushed 138 ctx = sha1_ctx_mgr_flush(mgr); 139 while (ctx) { 140 if (hash_ctx_complete(ctx)) { 141 debug_char('-'); 142 ctx = sha1_ctx_mgr_flush(mgr); 143 continue; 144 } 145 // Resubmit unfinished job 146 i = (unsigned long)(ctx->user_data); 147 buf_ptr[i] += UPDATE_SIZE; 148 149 len_done = (int)((unsigned long)buf_ptr[i] 150 - (unsigned long)bufs[i]); 151 len_rem = TEST_LEN - len_done; 152 153 if (len_rem <= UPDATE_SIZE) 154 ctx = sha1_ctx_mgr_submit(mgr, 155 &ctxpool[i], buf_ptr[i], len_rem, HASH_LAST); 156 else 157 ctx = sha1_ctx_mgr_submit(mgr, 158 &ctxpool[i], 159 buf_ptr[i], UPDATE_SIZE, HASH_UPDATE); 160 161 if (ctx == NULL) 162 ctx = sha1_ctx_mgr_flush(mgr); 163 } 164 165 // Check digests 166 for (i = 0; i < TEST_BUFS; i++) { 167 for (j = 0; j < SHA1_DIGEST_NWORDS; j++) { 168 if (ctxpool[i].job.result_digest[j] != digest_ref[i][j]) { 169 fail++; 170 printf("Test%d fixed size, digest%d fail %8X <=> %8X", 171 i, j, ctxpool[i].job.result_digest[j], 172 digest_ref[i][j]); 173 } 174 } 175 } 176 putchar('.'); 177 178 // Run tests with random size and number of jobs 179 for (t = 0; t < RANDOMS; t++) { 180 jobs = rand() % (TEST_BUFS); 181 182 for (i = 0; i < jobs; i++) { 183 joblen = rand() % (TEST_LEN); 184 rand_buffer(bufs[i], joblen); 185 lens[i] = joblen; 186 buf_ptr[i] = bufs[i]; 187 sha1_ref(bufs[i], digest_ref[i], lens[i]); 188 } 189 190 sha1_ctx_mgr_init(mgr); 191 192 // Run sha1_sb jobs 193 i = 0; 194 while (i < jobs) { 195 // Submit a new job 196 len_rand = SHA1_BLOCK_SIZE + 197 SHA1_BLOCK_SIZE * (rand() % MAX_RAND_UPDATE_BLOCKS); 198 199 if (lens[i] > len_rand) 200 ctx = sha1_ctx_mgr_submit(mgr, 201 &ctxpool[i], 202 buf_ptr[i], len_rand, HASH_FIRST); 203 else 204 ctx = sha1_ctx_mgr_submit(mgr, 205 &ctxpool[i], 206 buf_ptr[i], lens[i], HASH_ENTIRE); 207 208 // Returned ctx could be: 209 // - null context (we are just getting started and lanes aren't full yet), or 210 // - finished already (an ENTIRE we submitted or a previous LAST is returned), or 211 // - an unfinished ctx, we will resubmit 212 213 if ((ctx == NULL) || hash_ctx_complete(ctx)) { 214 i++; 215 continue; 216 } else { 217 // unfinished ctx returned, choose another random update length and submit either 218 // UPDATE or LAST depending on the amount of buffer remaining 219 while ((ctx != NULL) && !(hash_ctx_complete(ctx))) { 220 j = (unsigned long)(ctx->user_data); // Get index of the returned ctx 221 buf_ptr[j] = bufs[j] + ctx->total_length; 222 len_rand = (rand() % SHA1_BLOCK_SIZE) 223 * (rand() % MAX_RAND_UPDATE_BLOCKS); 224 len_rem = lens[j] - ctx->total_length; 225 226 if (len_rem <= len_rand) // submit the rest of the job as LAST 227 ctx = sha1_ctx_mgr_submit(mgr, 228 &ctxpool[j], 229 buf_ptr[j], 230 len_rem, HASH_LAST); 231 else // submit the random update length as UPDATE 232 ctx = sha1_ctx_mgr_submit(mgr, 233 &ctxpool[j], 234 buf_ptr[j], 235 len_rand, 236 HASH_UPDATE); 237 } // Either continue submitting any contexts returned here as UPDATE/LAST, or 238 // go back to submitting new jobs using the index i. 239 240 i++; 241 } 242 } 243 244 // Start flushing finished jobs, end on last flushed 245 ctx = sha1_ctx_mgr_flush(mgr); 246 while (ctx) { 247 if (hash_ctx_complete(ctx)) { 248 debug_char('-'); 249 ctx = sha1_ctx_mgr_flush(mgr); 250 continue; 251 } 252 // Resubmit unfinished job 253 i = (unsigned long)(ctx->user_data); 254 buf_ptr[i] = bufs[i] + ctx->total_length; // update buffer pointer 255 len_rem = lens[i] - ctx->total_length; 256 len_rand = (rand() % SHA1_BLOCK_SIZE) 257 * (rand() % MAX_RAND_UPDATE_BLOCKS); 258 debug_char('+'); 259 if (len_rem <= len_rand) 260 ctx = sha1_ctx_mgr_submit(mgr, 261 &ctxpool[i], 262 buf_ptr[i], len_rem, HASH_LAST); 263 else 264 ctx = sha1_ctx_mgr_submit(mgr, 265 &ctxpool[i], 266 buf_ptr[i], len_rand, HASH_UPDATE); 267 268 if (ctx == NULL) 269 ctx = sha1_ctx_mgr_flush(mgr); 270 } 271 272 // Check result digest 273 for (i = 0; i < jobs; i++) { 274 for (j = 0; j < SHA1_DIGEST_NWORDS; j++) { 275 if (ctxpool[i].job.result_digest[j] != digest_ref[i][j]) { 276 fail++; 277 printf("Test%d, digest%d fail %8X <=> %8X\n", 278 i, j, ctxpool[i].job.result_digest[j], 279 digest_ref[i][j]); 280 } 281 } 282 } 283 if (fail) { 284 printf("Test failed function check %d\n", fail); 285 goto end; 286 } 287 288 putchar('.'); 289 fflush(0); 290 } // random test t 291 292 end: 293 for (i = 0; i < TEST_BUFS; i++) 294 free(bufs[i]); 295 aligned_free(mgr); 296 297 if (fail) 298 printf("Test failed function check %d\n", fail); 299 else 300 printf(" multibinary_sha1_update rand: Pass\n"); 301 302 return fail; 303 } 304