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 }