random123

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

kat_cpp.cpp (8917B)


      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 #include "kat_main.h"
     33 
     34 // With C++, it's a little trickier to create the mapping from
     35 // method-name/round-count to functions
     36 // because the round-counts are template arguments that have to be
     37 // specified at compile-time.  Thus, we can't just do #define RNGNxW_TPL
     38 // and #include "rngNxW.h".  We have to build a static map from:
     39 //  pair<generator, rounds> to functions that apply the right generator
     40 // with the right number of rounds.
     41 
     42 #ifdef _MSC_FULL_VER
     43 // Engines have multiple copy constructors, quite legal C++, disable MSVC complaint
     44 #pragma warning (disable : 4521)
     45 #endif
     46 
     47 #include <map>
     48 #include <cstring>
     49 #include <utility>
     50 #include <stdexcept>
     51 #include <Random123/MicroURNG.hpp>
     52 #include <Random123/conventional/Engine.hpp>
     53 
     54 using namespace std;
     55 
     56 typedef map<pair<method_e, unsigned>, void (*)(kat_instance *)> genmap_t;
     57 genmap_t genmap;
     58 
     59 void dev_execute_tests(kat_instance *tests, unsigned ntests){
     60     unsigned i;
     61     for(i=0; i<ntests; ++i){
     62         kat_instance *ti = &tests[i];
     63         genmap_t::iterator p = genmap.find(make_pair(ti->method, ti->nrounds));
     64         if(p == genmap.end())
     65             throw std::runtime_error("pair<generator, nrounds> not in map.  You probably need to add more genmap entries in kat_cpp.cpp");
     66 
     67         p->second(ti);
     68         // TODO: check that the corresponding Engine and MicroURNG
     69         //  return the same values.  Note that we have ut_Engine and
     70         //  ut_MicroURNG, which check basic functionality, but they
     71         //  don't have the breadth of the kat_vectors.
     72     }
     73 }
     74 
     75 static int murng_reported;
     76 static int engine_reported;
     77 
     78 template <typename GEN>
     79 void do_test(kat_instance* ti){
     80     GEN g;
     81     struct gdata{
     82         typename GEN::ctr_type ctr;
     83         typename GEN::ukey_type ukey;
     84         typename GEN::ctr_type expected;
     85         typename GEN::ctr_type computed;
     86     };
     87     gdata data;
     88     // use memcpy.  A reinterpret_cast would violate strict aliasing.
     89     memcpy(&data, &ti->u, sizeof(data));
     90     data.computed = g(data.ctr, data.ukey);
     91 
     92     // Before we return, let's make sure that MicroURNG<GEN,1> and
     93     // Engine<GEN> work as expeccted.  This doesn't really "fit" the
     94     // execution model of kat.c, which just expects us to fill in
     95     // ti->u.computed, so we report the error by failing to write back
     96     // the computed data item in the (hopefully unlikely) event that
     97     // things don't match up as expected.
     98     int errs = 0;
     99 
    100     // MicroURNG:  throws if the top 32 bits of the high word of ctr
    101     // are non-zero.
    102     typedef typename GEN::ctr_type::value_type value_type;
    103     
    104     value_type hibits = data.ctr[data.ctr.size()-1]>>( std::numeric_limits<value_type>::digits - 32 );
    105     try{
    106         r123::MicroURNG<GEN> urng(data.ctr, data.ukey);
    107         if(hibits)
    108             errs++; // Should have thrown.
    109         for (size_t i = 0; i < data.expected.size(); i++) {
    110 	    size_t j = data.expected.size() - i - 1;
    111 	    if (data.expected[j] != urng()) {
    112                 errs++;
    113 	    }
    114 	}
    115     }catch(std::runtime_error& /*ignored*/){
    116         // A runtime_error is expected from the constructor
    117         // when hibit is set.
    118         if(!hibits)
    119             errs++;
    120     }
    121     if(errs && (murng_reported++ == 0))
    122         cerr << "Error in MicroURNG<GEN>, will appear as \"computed\" value of zero in error summary\n";
    123 
    124     // Engine
    125     // N.B.  exercising discard() arguably belongs in ut_Engine.cpp
    126     typedef r123::Engine<GEN> Etype;
    127     typedef typename GEN::ctr_type::value_type value_type;
    128     Etype e(data.ukey);
    129     typename GEN::ctr_type c = data.ctr;
    130     value_type c0;
    131     if( c[0] > 0 ){
    132         c0 = c[0]-1;
    133     }else{
    134         // N.B.  Assume that if c[0] is 0, then so are all the
    135         // others.  Arrange to "roll over" to {0,..,0} on the first
    136         // counter-increment.  Alternatively, we could just
    137         // skip the test for this case...
    138         c.fill(std::numeric_limits<value_type>::max());
    139         c0 = c[0];
    140     }
    141     c[0] /= 3;
    142     e.setcounter(c, 0);
    143     if( c0 > c[0] ){
    144         // skip one value by calling  e()
    145         (void)e();
    146         if (c0 > c[0]+1) {
    147 	    // skip many values by calling discard()
    148 	    R123_ULONG_LONG ndiscard = (c0 - c[0] - 1);
    149             // Take care not to overflow the long long
    150             if( ndiscard >= std::numeric_limits<R123_ULONG_LONG>::max() / c.size() ){
    151                 for(size_t j=0; j<c.size(); ++j){
    152                     e.discard(ndiscard);
    153                 }
    154             }else{
    155                 ndiscard *= c.size();
    156                 e.discard(ndiscard);
    157             }
    158 	}
    159 	// skip a few more by calling e().
    160 	for (size_t i = 1; i < c.size(); i++) {
    161 	    (void) e();
    162 	}
    163         // we should be back to where we started...
    164     }
    165     for (size_t i = 0; i < data.expected.size(); i++) {
    166 	value_type val = e();
    167 	size_t j = data.expected.size() - i - 1;
    168 	if (data.expected[j] != val) {
    169             cerr << hex;
    170             cerr << "Engine check, j=" << j << " expected: " << data.expected[j] << " val: " << val << "\n";
    171 	    errs++;
    172             if(engine_reported++ == 0)
    173                 cerr << "Error in Engine<GEN, 1>, will appear as \"computed\" value of zero in error summary\n";
    174 	}
    175     }
    176 
    177     // Signal an error to the caller by *not* copying back
    178     // the computed data object into the ti
    179     if(errs == 0)
    180         memcpy(&ti->u, &data, sizeof(data));
    181 }
    182 
    183 void host_execute_tests(kat_instance *tests, unsigned ntests){
    184     // In C++1x, this could be staticly declared with an initializer list.
    185     genmap[make_pair(threefry2x32_e, 13u)] = do_test<r123::Threefry2x32_R<13> >;
    186     genmap[make_pair(threefry2x32_e, 20u)] = do_test<r123::Threefry2x32_R<20> >;
    187     genmap[make_pair(threefry2x32_e, 32u)] = do_test<r123::Threefry2x32_R<32> >;
    188 #if R123_USE_64BIT
    189     genmap[make_pair(threefry2x64_e, 13u)] = do_test<r123::Threefry2x64_R<13> >;
    190     genmap[make_pair(threefry2x64_e, 20u)] = do_test<r123::Threefry2x64_R<20> >;
    191     genmap[make_pair(threefry2x64_e, 32u)] = do_test<r123::Threefry2x64_R<32> >;
    192 #endif
    193 
    194     genmap[make_pair(threefry4x32_e, 13u)] = do_test<r123::Threefry4x32_R<13> >;
    195     genmap[make_pair(threefry4x32_e, 20u)] = do_test<r123::Threefry4x32_R<20> >;
    196     genmap[make_pair(threefry4x32_e, 72u)] = do_test<r123::Threefry4x32_R<72> >;
    197 #if R123_USE_64BIT
    198     genmap[make_pair(threefry4x64_e, 13u)] = do_test<r123::Threefry4x64_R<13> >;
    199     genmap[make_pair(threefry4x64_e, 20u)] = do_test<r123::Threefry4x64_R<20> >;
    200     genmap[make_pair(threefry4x64_e, 72u)] = do_test<r123::Threefry4x64_R<72> >;
    201 #endif
    202 
    203     genmap[make_pair(philox2x32_e, 7u)] = do_test<r123::Philox2x32_R<7> >;
    204     genmap[make_pair(philox2x32_e, 10u)] = do_test<r123::Philox2x32_R<10> >;
    205     genmap[make_pair(philox4x32_e, 7u)] = do_test<r123::Philox4x32_R<7> >;
    206     genmap[make_pair(philox4x32_e, 10u)] = do_test<r123::Philox4x32_R<10> >;
    207 
    208 #if R123_USE_PHILOX_64BIT
    209     genmap[make_pair(philox2x64_e, 7u)] = do_test<r123::Philox2x64_R<7> >;
    210     genmap[make_pair(philox2x64_e, 10u)] = do_test<r123::Philox2x64_R<10> >;
    211     genmap[make_pair(philox4x64_e, 7u)] = do_test<r123::Philox4x64_R<7> >;
    212     genmap[make_pair(philox4x64_e, 10u)] = do_test<r123::Philox4x64_R<10> >;
    213 #endif
    214 
    215 #if R123_USE_AES_NI
    216     genmap[make_pair(aesni4x32_e, 10u)] = do_test<r123::AESNI4x32 >;
    217     genmap[make_pair(ars4x32_e, 7u)] = do_test<r123::ARS4x32_R<7> >;
    218     genmap[make_pair(ars4x32_e, 10u)] = do_test<r123::ARS4x32_R<10> >;
    219 #endif
    220 
    221     dev_execute_tests(tests, ntests);
    222 }