random123

Counter-based Random Number Generators
git clone git://git.meso-star.com/random123.git
Log | Files | Refs | README | LICENSE

kat_main.h (11978B)


      1 /*
      2 Copyright 2010-2011, D. E. Shaw Research.
      3 All rights reserved.
      4 
      5 Redistribution and use in source and binary forms, with or without
      6 modification, are permitted provided that the following conditions are
      7 met:
      8 
      9 * Redistributions of source code must retain the above copyright
     10   notice, this list of conditions, and the following disclaimer.
     11 
     12 * Redistributions in binary form must reproduce the above copyright
     13   notice, this list of conditions, and the following disclaimer in the
     14   documentation and/or other materials provided with the distribution.
     15 
     16 * Neither the name of D. E. Shaw Research nor the names of its
     17   contributors may be used to endorse or promote products derived from
     18   this software without specific prior written permission.
     19 
     20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 */
     32 /* Known Answer Test */
     33 
     34 /* We use the same source files to implement the Known Answer Test
     35    (KAT) in C, C++, OpenCL and CUDA.  Supporting all four environments
     36    with a single source file, and getting it all to work with 'make'
     37    is a bit involved:
     38 
     39    There are five "top-level" files:
     40      kat_c.c
     41      kat_cpp.cpp
     42      kat_cuda.c
     43      kat_opencl.c
     44      kat_metal.m
     45 
     46    These correspond to make targets: kat_c, kat_cpp, kat_cuda,
     47    kat_opencl and kat_metal.
     48 
     49    Those files are relatively simple.  First, they #include this file,
     50    which contains all the machinery for reading test vectors,
     51    complaining about errors, etc..  Then they implement the function
     52    host_execute_tests() in the appropriate environment.  host_execute_tests
     53    looks very different in C/C++/CUDA/OpenCL/Metal.
     54 
     55    host_execute_tests contrives to call/launch "dev_execute_tests"
     56    on the device.  Except for a few environment-specific keywords,
     57    (e.g., __global, __kernel), which are #defined in kat_XXX.c,
     58    dev_execute_tests is obtained by including a common source file:
     59       #include <kat_dev_execute.h>
     60 
     61    One final complication:  in order to fully "bake" the source code
     62    into the binary at compile-time, dev_execute_tests for opencl is implemented in
     63    kat_opencl_kernel.ocl, which is processed by gencl.sh into
     64    kat_opencl_kernel.i, which is thein #include-ed by kat_opencl.c.
     65    
     66 */
     67 #include "util.h"
     68 #include "kat.h"
     69 
     70 #define LINESIZE 1024
     71 
     72 int have_aesni = 0;
     73 int verbose = 0;
     74 int debug = 0;
     75 unsigned nfailed = 0;
     76 const char *progname;
     77 
     78 extern void host_execute_tests(kat_instance *tests, unsigned ntests);
     79                 
     80 /* A little hack to keep track of the test vectors that we don't know how to deal with: */
     81 int nunknowns = 0;
     82 #define MAXUNKNOWNS 20
     83 const char *unknown_names[MAXUNKNOWNS];
     84 int unknown_counts[MAXUNKNOWNS];
     85 
     86 void register_unknown(const char *name){
     87     int i;
     88     for(i=0; i<nunknowns; ++i){
     89         if( strcmp(name, unknown_names[i]) == 0 ){
     90             unknown_counts[i]++;
     91             return;
     92         }
     93     }
     94     if( i >= MAXUNKNOWNS ){
     95         fprintf(stderr, "Too many unknown rng types.  Bye.\n");
     96         exit(1);
     97     }
     98     nunknowns++;
     99     unknown_names[i] = ntcsdup(name);
    100     unknown_counts[i] = 1;
    101 }
    102 
    103 void report_unknowns(){
    104     int i;
    105     for(i=0; i<nunknowns; ++i){
    106         printf("%d test vectors of type %s skipped\n", unknown_counts[i], unknown_names[i]);
    107     }
    108 }
    109 
    110 /* read_<GEN>NxW */
    111 #define RNGNxW_TPL(base, N, W) \
    112 int read_##base##N##x##W(const char *line, kat_instance* tinst){        \
    113     size_t i;                                                           \
    114     int nchar;                                                          \
    115     const char *p = line;                                               \
    116     char *newp;                                                         \
    117     size_t nkey = sizeof(tinst->u.base##N##x##W##_data.ukey.v)/sizeof(tinst->u.base##N##x##W##_data.ukey.v[0]); \
    118     tinst->method = base##N##x##W##_e;                                  \
    119     sscanf(p,  "%u%n", &tinst->nrounds, &nchar);                        \
    120     p += nchar;                                                         \
    121     for(i=0;  i<N; ++i){                                                \
    122         tinst->u.base##N##x##W##_data.ctr.v[i] = strtou##W(p, &newp, 16); \
    123         p = newp;                                                       \
    124     }                                                                   \
    125     for(i=0; i<nkey; ++i){                                              \
    126         tinst->u.base##N##x##W##_data.ukey.v[i] = strtou##W(p, &newp, 16); \
    127         p = newp;                                                       \
    128     }                                                                   \
    129     for(i=0;  i<N; ++i){                                                \
    130         tinst->u.base##N##x##W##_data.expected.v[i] = strtou##W(p, &newp, 16); \
    131         p = newp;                                                       \
    132     }                                                                   \
    133     /* set the computed to 0xca.  If the test fails to set computed, we'll see cacacaca in the FAILURE notices */ \
    134     memset(tinst->u.base##N##x##W##_data.computed.v, 0xca, sizeof(tinst->u.base##N##x##W##_data.computed.v));                  \
    135     return 1;                                                           \
    136 }
    137 #include "rngNxW.h"
    138 #undef RNGNxW_TPL
    139 
    140 /* readtest:  dispatch to one of the read_<GEN>NxW functions */
    141 static int readtest(const char *line, kat_instance* tinst){
    142     int nchar;
    143     char name[LINESIZE];
    144     if( line[0] == '#') return 0;                                       
    145     sscanf(line, "%s%n", name, &nchar);
    146     if(!have_aesni){
    147         /* skip any tests that require AESNI */ 
    148         if(strncmp(name, "aes", 3)==0 ||
    149            strncmp(name, "ars", 3)==0){
    150             register_unknown(name);
    151             return 0;
    152         }
    153     }
    154 #define RNGNxW_TPL(base, N, W) if(strcmp(name, #base #N "x" #W) == 0) return read_##base##N##x##W(line+nchar, tinst);
    155 #include "rngNxW.h"
    156 #undef RNGNxW_TPL
    157 
    158     register_unknown(name);
    159     return 0;
    160 }
    161 
    162 #define RNGNxW_TPL(base, N, W) \
    163 void report_##base##N##x##W##error(const kat_instance *ti){ \
    164  size_t i;                                                     \
    165  size_t nkey = sizeof(ti->u.base##N##x##W##_data.ukey.v)/sizeof(ti->u.base##N##x##W##_data.ukey.v[0]); \
    166  fprintf(stderr, "FAIL:  expected: ");                                \
    167  fprintf(stderr, #base #N "x" #W " %d", ti->nrounds);                   \
    168  for(i=0; i<N; ++i){                                                    \
    169      fprintf(stderr, " "); prtu##W(ti->u.base##N##x##W##_data.ctr.v[i]); \
    170  }                                                                      \
    171  for(i=0; i<nkey; ++i){                                                 \
    172      fprintf(stderr, " "); prtu##W(ti->u.base##N##x##W##_data.ukey.v[i]); \
    173  }                                                                      \
    174  for(i=0; i<N; ++i){                                                    \
    175      fprintf(stderr, " "); prtu##W(ti->u.base##N##x##W##_data.expected.v[i]); \
    176  }                                                                      \
    177  fprintf(stderr, "\n");                                                 \
    178                                                                         \
    179  fprintf(stderr, "FAIL:  computed: ");                                \
    180  fprintf(stderr, #base #N "x" #W " %d", ti->nrounds);                   \
    181  for(i=0; i<N; ++i){                                                    \
    182      fprintf(stderr, " "); prtu##W(ti->u.base##N##x##W##_data.ctr.v[i]); \
    183  }                                                                      \
    184  for(i=0; i<nkey; ++i){                                                 \
    185      fprintf(stderr, " "); prtu##W(ti->u.base##N##x##W##_data.ukey.v[i]); \
    186  }                                                                      \
    187  for(i=0; i<N; ++i){                                                    \
    188      fprintf(stderr, " "); prtu##W(ti->u.base##N##x##W##_data.computed.v[i]); \
    189  }                                                                      \
    190  fprintf(stderr, "\n");                                                 \
    191  nfailed++;                                                             \
    192 }
    193 #include "rngNxW.h"
    194 #undef RNGNxW_TPL
    195 
    196 // dispatch to one of the report_<GEN>NxW() functions
    197 void analyze_tests(const kat_instance *tests, unsigned ntests){
    198     unsigned i;
    199     char zeros[512] = {0};
    200     for(i=0; i<ntests; ++i){
    201         const kat_instance *ti = &tests[i];
    202         switch(tests[i].method){
    203 #define RNGNxW_TPL(base, N, W) case base##N##x##W##_e: \
    204             if (memcmp(zeros, ti->u.base##N##x##W##_data.expected.v, N*W/8)==0){ \
    205                 fprintf(stderr, "kat expected all zeros?   Something is wrong with the test harness!\n"); \
    206                 nfailed++; \
    207             } \
    208             if (memcmp(ti->u.base##N##x##W##_data.computed.v, ti->u.base##N##x##W##_data.expected.v, N*W/8)) \
    209 		report_##base##N##x##W##error(ti); \
    210 	    break;
    211 #include "rngNxW.h"
    212 #undef RNGNxW_TPL
    213         case last: ;
    214         }
    215     }
    216 }
    217 
    218 #define NTESTS 1000
    219 
    220 int main(int argc, char **argv){
    221     kat_instance *tests;
    222     unsigned t, ntests = NTESTS;
    223     char linebuf[LINESIZE];
    224     FILE *inpfile;
    225     const char *p;
    226     const char *inname;
    227     char filename[LINESIZE];
    228     
    229     progname = argv[0];
    230 
    231     /* If there's an argument, open that file.
    232        else if getenv("srcdir") is non-empty open getenv("srcdir")/kat_vectors
    233        else open "./kat_vectors" */
    234     if( argc > 1 )
    235         inname = argv[1];
    236     else{
    237         const char *e = getenv("srcdir");
    238         if(!e)
    239             e = ".";
    240         sprintf(filename, "%s/kat_vectors", e);
    241         inname = filename;
    242     }
    243 
    244     if (strcmp(inname, "-") == 0) {
    245 	inpfile = stdin;
    246     } else {
    247 	inpfile = fopen(inname, "r");
    248 	if (inpfile == NULL) {
    249 	    fprintf(stderr, "%s: error opening input file %s for reading: %s\n",
    250 		    progname, inname, strerror(errno));
    251 	    exit(1);
    252 	}
    253     }
    254     if ((p = getenv("KATC_VERBOSE")) != NULL) {
    255 	verbose = atoi(p);
    256     }
    257     if ((p = getenv("KATC_DEBUG")) != NULL) {
    258 	debug = atoi(p);
    259     }
    260 
    261 #if R123_USE_AES_NI
    262     have_aesni = haveAESNI();
    263 #else
    264     have_aesni = 0;
    265 #endif
    266 
    267     tests = (kat_instance *) malloc(sizeof(tests[0])*ntests);
    268     if (tests == NULL) {
    269 	fprintf(stderr, "Could not allocate %lu bytes for tests\n",
    270 		(unsigned long) ntests);
    271 	exit(1);
    272     }
    273     t = 0;
    274     while (fgets(linebuf, sizeof linebuf, inpfile) != NULL) {
    275         if( t==ntests ){
    276 	    ntests *= 2;
    277 	    tests = (kat_instance *)realloc(tests, sizeof(tests[0])*ntests);
    278 	    if (tests == NULL) {
    279 		fprintf(stderr, "Could not grow tests to %lu bytes\n",
    280 			(unsigned long) ntests);
    281 		exit(1);
    282 	    }
    283         }
    284         if( readtest(linebuf, &tests[t]) )
    285             ++t;
    286     }
    287     if(t==ntests){
    288 	fprintf(stderr, "No more space for tests?  Recompile with a larger NTESTS\n");
    289 	exit(1);
    290     }
    291     tests[t].method = last; // N.B  *not* t++ - the 'ntests' value passed to host_execute_tests does not count the 'last' one.
    292 
    293     report_unknowns();
    294     printf("Perform %lu tests.\n", (unsigned long)t);
    295     host_execute_tests(tests, t);
    296 
    297     analyze_tests(tests, t);
    298     free(tests);
    299     if(nfailed != 0){
    300         printf("FAILED %u out of %u\n", nfailed, t);
    301         return 1;
    302     }else{
    303         printf("PASSED %u known answer tests\n", t);
    304         return 0;
    305     }
    306 }