decred.org/dcrdex@v1.0.5/server/matcher/mt19937/mt19937.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 // Package mt19937 implements the 64-bit version of the Mersenne Twister (MT) 5 // pseudo-random number generator (PRNG) with a period of 2^19937-1, also known 6 // as mt19937_64, according to the reference implementation by Matsumoto and 7 // Nishimura at http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html 8 // 9 // MT is not cryptographically secure. Given a sufficiently long sequence of the 10 // generated values, one may predict additional values without knowing the seed. 11 // A secure hashing algorithm should be used with MT if a CSPRNG is required. 12 // 13 // When possible, the MT generator should be seeded with a slice of bytes or 14 // uint64 values to address known "zero-excess" seed initialization issues where 15 // "shifted" sequences may be generated for seeds with only a few non-zero bits. 16 // For more information, see 17 // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html 18 package mt19937 19 20 import ( 21 "encoding/binary" 22 ) 23 24 const ( 25 defaultSeed int64 = 5489 26 sliceSeed int64 = 19650218 27 28 n = 312 // state size 29 m = 156 // shift size 30 31 msbm uint64 = 0xffffffff80000000 // 33 most sig. bits 32 lsbm uint64 = 0x000000007fffffff // 31 least sig. bits 33 34 a uint64 = 0xb5026f5aa96619e9 // xor mask 35 36 // tempering shift sizes and xor masks 37 uShift uint64 = 29 38 uMask uint64 = 0x5555555555555555 39 sShift uint64 = 17 40 sMask uint64 = 0x71d67fffeda60000 41 tShift uint64 = 37 42 tMask uint64 = 0xfff7eee000000000 43 lShift uint64 = 43 44 45 // initialization values for seeding the state sequence 46 ivInt uint64 = 6364136223846793005 47 ivSlice0 uint64 = 3935559000370003845 48 ivSlice1 uint64 = 2862933555777941757 49 ) 50 51 // Source is a pseudo-random number generator that satisfies both 52 // math/rand.Source and math/rand.Source64. 53 type Source struct { 54 state [n]uint64 55 index int 56 } 57 58 // NewSource creates a new unseeded Source. 59 func NewSource() *Source { 60 return &Source{ 61 index: n + 1, // not seeded 62 } 63 } 64 65 // Seed initializes the source with the provided value. Note that SeedBytes or 66 // SeedValues should be preferred since Mersenne Twister suffers from a 67 // "zero-excess" initial state defect where seeds with many zero bits can result 68 // in similar/"shifted" sequences. The authors describe the issues: 69 // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html 70 func (s *Source) Seed(seed int64) { 71 s.state[0] = uint64(seed) 72 prev := s.state[0] 73 for i := 1; i < n; i++ { 74 s.state[i] = ivInt*(prev^prev>>62) + uint64(i) 75 prev = s.state[i] 76 } 77 s.index = n 78 } 79 80 // SeedBytes seeds the mt19937 engine with up to 2496 bytes from a slice. Only 81 // the first 2496 bytes of the slice are used. Additional elements are unused. 82 func (s *Source) SeedBytes(b []byte) { 83 // Pad the slice to a multiple of 8 elements if not already. 84 numVals := len(b) / 8 85 if len(b)%8 != 0 { 86 numVals++ 87 bx := make([]byte, numVals*8) 88 copy(bx, b) 89 b = bx 90 } 91 92 // Convert the byte slice to a uint64 slice. 93 vals := make([]uint64, numVals) 94 for i := range vals { 95 ib := i * 8 96 vals[i] = binary.BigEndian.Uint64(b[ib : ib+8]) 97 } 98 99 s.SeedVals(vals) 100 } 101 102 // SeedVals seeds the mt19937 engine with up to 312 uint64 values. Only the 103 // first 312 values of the slice are used. Additional elements are unused. 104 func (s *Source) SeedVals(v []uint64) { 105 s.Seed(sliceSeed) 106 107 is := 1 // state index 108 next := func() { 109 is++ 110 if is >= n { 111 is = 1 112 s.state[0] = s.state[n-1] 113 } 114 } 115 116 i := n // iterator 117 if len(v) > n { 118 i = len(v) // TODO: test this case 119 } 120 121 for iv := 0; i > 0; i-- { 122 s.state[is] = v[iv] + uint64(iv) + (s.state[is] ^ ((s.state[is-1] ^ (s.state[is-1] >> 62)) * ivSlice0)) 123 next() 124 iv++ 125 if iv >= len(v) { 126 iv = 0 127 } 128 } 129 130 for i = n - 1; i > 0; i-- { 131 s.state[is] = (s.state[is] ^ ((s.state[is-1] ^ (s.state[is-1] >> 62)) * ivSlice1)) - uint64(is) 132 next() 133 } 134 135 s.state[0] = 1 << 63 136 } 137 138 func (s *Source) newState() { 139 var i int 140 for ; i < n-m; i++ { 141 x := s.state[i]&msbm | s.state[i+1]&lsbm 142 x = x>>1 ^ a*(x&1) 143 s.state[i] = s.state[i+m] ^ x 144 } 145 for ; i < n-1; i++ { 146 x := s.state[i]&msbm | s.state[i+1]&lsbm 147 x = x>>1 ^ a*(x&1) 148 s.state[i] = s.state[i+m-n] ^ x 149 } 150 x := s.state[n-1]&msbm | s.state[0]&lsbm 151 x = x>>1 ^ a*(x&1) 152 s.state[n-1] = s.state[m-1] ^ x 153 s.index = 0 154 } 155 156 // Uint64 returns the next pseudo-random integer on [0, 2^64-1) in the sequence. 157 // Uint64 satisfies math/rand.Source. 158 func (s *Source) Uint64() uint64 { 159 if s.index >= n { 160 if s.index == n+1 { 161 s.Seed(defaultSeed) 162 } 163 s.newState() 164 } 165 166 x := s.state[s.index] 167 x ^= x >> uShift & uMask 168 x ^= x << sShift & sMask 169 x ^= x << tShift & tMask 170 x ^= x >> lShift 171 172 s.index++ 173 return x 174 } 175 176 // Int63 returns the next pseudo-random integer on [0, 2^63-1) in the sequence. 177 // Both Uint64 and Int63 advance the sequence. Int63 satisfies 178 // math/rand.Source64. 179 func (s *Source) Int63() int64 { 180 // TODO: shift or mask? 181 //return int64(s.Uint64() & 0x7fffffffffffffff) 182 return int64(s.Uint64() >> 1) 183 } 184 185 // TODO: implement io.Reader