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 uint32_t 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 = (uint32_t) ((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 = (uint32_t) (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 = (uint32_t) (uintptr_t) (ctx->user_data); 150 buf_ptr[i] += UPDATE_SIZE; 151 152 len_done = (uint32_t) ((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 = (uint32_t) (uintptr_t) (ctx->user_data); // Get index of 222 // the returned 223 // ctx 224 buf_ptr[j] = bufs[j] + ctx->total_length; 225 len_rand = (rand() % SHA256_BLOCK_SIZE) * 226 (rand() % MAX_RAND_UPDATE_BLOCKS); 227 len_rem = lens[j] - (uint32_t) ctx->total_length; 228 229 if (len_rem <= 230 len_rand) // submit the rest of the job as LAST 231 ctx = sha256_ctx_mgr_submit(mgr, &ctxpool[j], 232 buf_ptr[j], len_rem, 233 HASH_LAST); 234 else // submit the random update length as UPDATE 235 ctx = sha256_ctx_mgr_submit(mgr, &ctxpool[j], 236 buf_ptr[j], len_rand, 237 HASH_UPDATE); 238 } // Either continue submitting any contexts returned here as 239 // UPDATE/LAST, or 240 // go back to submitting new jobs using the index i. 241 242 i++; 243 } 244 } 245 246 // Start flushing finished jobs, end on last flushed 247 ctx = sha256_ctx_mgr_flush(mgr); 248 while (ctx) { 249 if (hash_ctx_complete(ctx)) { 250 debug_char('-'); 251 ctx = sha256_ctx_mgr_flush(mgr); 252 continue; 253 } 254 // Resubmit unfinished job 255 i = (uint32_t) (uintptr_t) (ctx->user_data); 256 buf_ptr[i] = bufs[i] + ctx->total_length; // update buffer pointer 257 len_rem = lens[i] - (uint32_t) ctx->total_length; 258 len_rand = (rand() % SHA256_BLOCK_SIZE) * (rand() % MAX_RAND_UPDATE_BLOCKS); 259 debug_char('+'); 260 if (len_rem <= len_rand) 261 ctx = sha256_ctx_mgr_submit(mgr, &ctxpool[i], buf_ptr[i], len_rem, 262 HASH_LAST); 263 else 264 ctx = sha256_ctx_mgr_submit(mgr, &ctxpool[i], buf_ptr[i], len_rand, 265 HASH_UPDATE); 266 267 if (ctx == NULL) 268 ctx = sha256_ctx_mgr_flush(mgr); 269 } 270 271 // Check result digest 272 for (i = 0; i < jobs; i++) { 273 for (j = 0; j < SHA256_DIGEST_NWORDS; j++) { 274 if (ctxpool[i].job.result_digest[j] != digest_ref[i][j]) { 275 fail++; 276 printf("Test%d, digest%d fail %8X <=> %8X\n", i, j, 277 ctxpool[i].job.result_digest[j], digest_ref[i][j]); 278 } 279 } 280 } 281 if (fail) { 282 printf("Test failed function check %d\n", fail); 283 goto end; 284 } 285 286 putchar('.'); 287 fflush(0); 288 } // random test t 289 290 end: 291 for (i = 0; i < TEST_BUFS; i++) 292 free(bufs[i]); 293 aligned_free(mgr); 294 295 if (fail) 296 printf("Test failed function check %d\n", fail); 297 else 298 printf(" multibinary_sha256_update rand: Pass\n"); 299 300 return fail; 301 } 302