1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: math_TinyMt.cpp 4 5 Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Rev: 47727 $ 14 *---------------------------------------------------------------------------*/ 15 16 #include <nn/types.h> 17 #include <nn/assert.h> 18 #include <nn/math/math_TinyMt.h> 19 #include <nn/crypto.h> 20 #include <algorithm> 21 22 namespace nn { namespace math { 23 24 namespace 25 { MixMsb2(bit32 v)26 inline bit32 MixMsb2(bit32 v) 27 { 28 return v ^ (v >> 30); 29 } 30 MixMsb5(bit32 v)31 inline bit32 MixMsb5(bit32 v) 32 { 33 return v ^ (v >> 27); 34 } 35 } 36 // anonymous namespace 37 38 39 40 /* ------------------------------------------------------------------------ 41 public 42 ------------------------------------------------------------------------ */ 43 Initialize()44 void TinyMt::Initialize() 45 { 46 crypto::GenerateRandomBytes(m_State, sizeof(m_State)); 47 } 48 Initialize(bit32 seed)49 void TinyMt::Initialize(bit32 seed) 50 { 51 m_State[0] = seed; 52 m_State[1] = PARAMETER_MAT1; 53 m_State[2] = PARAMETER_MAT2; 54 m_State[3] = PARAMETER_TMAT;; 55 56 { 57 for( int i = 1; i < MIN_LOOP; ++i ) 58 { 59 const bit32 v = MixMsb2(m_State[(i - 1) % PARAMETER_N]); 60 m_State[i % PARAMETER_N] ^= v * 0x6c078965 + i; 61 } 62 } 63 64 FinalizeInitialization(); 65 } 66 Initialize(const bit32 * pSeed,int numSeed)67 void TinyMt::Initialize(const bit32* pSeed, int numSeed) 68 { 69 m_State[0] = 0; 70 m_State[1] = PARAMETER_MAT1; 71 m_State[2] = PARAMETER_MAT2; 72 m_State[3] = PARAMETER_TMAT;; 73 74 { 75 const int numLoop = Max(numSeed + 1, MIN_LOOP) - 1; 76 77 GenerateInitialValuePlus(m_State, 0, numSeed); 78 79 int offset = 1; 80 for( int i = 0; i < numLoop; ++i ) 81 { 82 const bit32 seed = (i < numSeed) ? pSeed[i]: 0; 83 GenerateInitialValuePlus(m_State, (offset + i) % PARAMETER_N, seed); 84 } 85 86 offset = numLoop + 1; 87 for( int i = 0; i < PARAMETER_N; ++i ) 88 { 89 GenerateInitialValueXor(m_State, (offset + i) % PARAMETER_N); 90 } 91 } 92 93 FinalizeInitialization(); 94 } 95 SaveState(TinyMt::State * pStateBuffer)96 void TinyMt::SaveState(TinyMt::State* pStateBuffer) 97 { 98 NN_POINTER_TASSERT_(pStateBuffer); 99 100 std::memcpy(pStateBuffer->state, m_State, sizeof(pStateBuffer->state)); 101 } 102 RestoreState(const TinyMt::State * pStateBuffer)103 void TinyMt::RestoreState(const TinyMt::State* pStateBuffer) 104 { 105 NN_POINTER_TASSERT_(pStateBuffer); 106 107 std::memcpy(m_State, pStateBuffer->state, sizeof(m_State)); 108 } 109 GenerateRandomU32()110 u32 TinyMt::GenerateRandomU32() 111 { 112 // Update the state 113 const bit32 a = (m_State[0] & BIT31_MASK) ^ m_State[1] ^ m_State[2]; 114 const bit32 b = m_State[3]; 115 const bit32 c = a ^ (a << 1); 116 const bit32 d = b ^ (b >> 1) ^ c; 117 118 const bit32 s0 = m_State[1]; 119 bit32 s1 = m_State[2]; 120 bit32 s2 = c ^ (d << 10); 121 const bit32 s3 = d; 122 123 if( (d & 1) != 0 ) 124 { 125 s1 ^= PARAMETER_MAT1; 126 s2 ^= PARAMETER_MAT2; 127 } 128 129 m_State[0] = s0; 130 m_State[1] = s1; 131 m_State[2] = s2; 132 m_State[3] = s3; 133 134 // tempering 135 bit32 t = s0 + (s2 >> 8); 136 bit32 v = s3 ^ t; 137 138 if( (t & 1) != 0 ) 139 { 140 v ^= PARAMETER_TMAT; 141 } 142 143 return v; 144 } 145 GenerateRandomBytes(void * p,size_t size)146 void TinyMt::GenerateRandomBytes(void* p, size_t size) 147 { 148 uptr begin = reinterpret_cast<uptr>(p); 149 uptr end = begin + size; 150 uptr begin4 = RoundUp(begin, 4); 151 uptr end4 = RoundDown(end, 4); 152 153 if( begin < begin4 ) 154 { 155 bit32 v = GenerateRandomU32(); 156 std::memcpy(reinterpret_cast<void*>(begin), &v, begin4 - begin); 157 } 158 159 { 160 bit32* p32 = reinterpret_cast<bit32*>(begin4); 161 bit32* pEnd = reinterpret_cast<bit32*>(end4); 162 163 while( p32 < pEnd ) 164 { 165 *p32++ = GenerateRandomU32(); 166 } 167 } 168 169 if( end4 < end ) 170 { 171 bit32 v = GenerateRandomU32(); 172 std::memcpy(reinterpret_cast<void*>(end4), &v, end - end4); 173 } 174 } 175 176 177 178 /* ------------------------------------------------------------------------ 179 private 180 ------------------------------------------------------------------------ */ 181 GenerateInitialValuePlus(bit32 * p,int d,bit32 k)182 void TinyMt::GenerateInitialValuePlus(bit32* p, int d, bit32 k) 183 { 184 bit32& s0 = p[d]; 185 bit32& s1 = p[(d + 1) % PARAMETER_N]; 186 bit32& s2 = p[(d + 2) % PARAMETER_N]; 187 bit32& s3 = p[(d + 3) % PARAMETER_N]; 188 189 const bit32 a = MixMsb5(s0 ^ s1 ^ s3) * 0x0019660d; 190 const bit32 b = a + d + k; 191 192 s0 = b; 193 s1 += a; 194 s2 += b; 195 } 196 GenerateInitialValueXor(bit32 * p,int d)197 void TinyMt::GenerateInitialValueXor(bit32* p, int d) 198 { 199 bit32& s0 = p[d]; 200 bit32& s1 = p[(d + 1) % PARAMETER_N]; 201 bit32& s2 = p[(d + 2) % PARAMETER_N]; 202 bit32& s3 = p[(d + 3) % PARAMETER_N]; 203 204 const bit32 a = MixMsb5(s0 + s1 + s3) * 0x5d588b65; 205 const bit32 b = a - d; 206 207 s0 = b; 208 s1 ^= a; 209 s2 ^= b; 210 } 211 FinalizeInitialization()212 void TinyMt::FinalizeInitialization() 213 { 214 const bit32 state031 = (m_State[0] & BIT31_MASK); 215 216 if( (state031 == 0) && (m_State[1] == 0) 217 && (m_State[2] == 0) && (m_State[3] == 0) ) 218 { 219 m_State[0] = 'T'; 220 m_State[1] = 'I'; 221 m_State[2] = 'N'; 222 m_State[3] = 'Y'; 223 } 224 225 for( int i = 0; i < NUM_SKIP; ++i ) 226 { 227 GenerateRandomU32(); 228 } 229 } 230 231 232 233 }} 234 235