github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/rand/rand.gno (about) 1 package rand 2 3 // Disclaimer: this package is unsafe and won't prevent others to 4 // guess values in advance. 5 // 6 // the goal of this package is to implement a random library that 7 // is fully deterministic for validators while being hard to guess. 8 // 9 // We use the Bernstein's hash djb2 to be CPU-cycle efficient. 10 11 import ( 12 "math/rand" 13 "std" 14 "time" 15 ) 16 17 type Instance struct { 18 seed int64 19 } 20 21 func New() *Instance { 22 r := Instance{seed: 5381} 23 r.addEntropy() 24 return &r 25 } 26 27 func FromSeed(seed int64) *Instance { 28 r := Instance{seed: seed} 29 r.addEntropy() 30 return &r 31 } 32 33 func (i *Instance) Seed() int64 { 34 return i.seed 35 } 36 37 func (i *Instance) djb2String(input string) { 38 for _, c := range input { 39 i.djb2Int64(int64(c)) 40 } 41 } 42 43 // super fast random algorithm. 44 // http://www.cse.yorku.ca/~oz/hash.html 45 func (i *Instance) djb2Int64(input int64) { 46 i.seed = (i.seed << 5) + i.seed + input 47 } 48 49 // AddEntropy uses various runtime variables to add entropy to the existing seed. 50 func (i *Instance) addEntropy() { 51 // FIXME: reapply the 5381 initial value? 52 53 // inherit previous entropy 54 // nothing to do 55 56 // handle callers 57 { 58 caller1 := std.GetCallerAt(1).String() 59 i.djb2String(caller1) 60 caller2 := std.GetCallerAt(2).String() 61 i.djb2String(caller2) 62 } 63 64 // height 65 { 66 height := std.GetHeight() 67 i.djb2Int64(height) 68 } 69 70 // time 71 { 72 secs := time.Now().Second() 73 i.djb2Int64(int64(secs)) 74 nsecs := time.Now().Nanosecond() 75 i.djb2Int64(int64(nsecs)) 76 } 77 78 // FIXME: compute other hard-to-guess but deterministic variables, like real gas? 79 } 80 81 func (i *Instance) Float32() float32 { 82 i.addEntropy() 83 return rand.New(rand.NewSource(i.seed)).Float32() 84 } 85 86 func (i *Instance) Float64() float64 { 87 i.addEntropy() 88 return rand.New(rand.NewSource(i.seed)).Float64() 89 } 90 91 func (i *Instance) Int() int { 92 i.addEntropy() 93 return rand.New(rand.NewSource(i.seed)).Int() 94 } 95 96 func (i *Instance) Intn(n int) int { 97 i.addEntropy() 98 return rand.New(rand.NewSource(i.seed)).Intn(n) 99 } 100 101 func (i *Instance) Int63() int64 { 102 i.addEntropy() 103 return rand.New(rand.NewSource(i.seed)).Int63() 104 } 105 106 func (i *Instance) Int63n(n int64) int64 { 107 i.addEntropy() 108 return rand.New(rand.NewSource(i.seed)).Int63n(n) 109 } 110 111 func (i *Instance) Int31() int32 { 112 i.addEntropy() 113 return rand.New(rand.NewSource(i.seed)).Int31() 114 } 115 116 func (i *Instance) Int31n(n int32) int32 { 117 i.addEntropy() 118 return rand.New(rand.NewSource(i.seed)).Int31n(n) 119 } 120 121 func (i *Instance) Uint32() uint32 { 122 i.addEntropy() 123 return rand.New(rand.NewSource(i.seed)).Uint32() 124 } 125 126 func (i *Instance) Uint64() uint64 { 127 i.addEntropy() 128 return rand.New(rand.NewSource(i.seed)).Uint64() 129 } 130 131 func (i *Instance) Read(p []byte) (n int, err error) { 132 i.addEntropy() 133 return rand.New(rand.NewSource(i.seed)).Read(p) 134 } 135 136 func (i *Instance) Shuffle(n int, swap func(i, j int)) { 137 i.addEntropy() 138 rand.New(rand.NewSource(i.seed)).Shuffle(n, swap) 139 }