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