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