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