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