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