1// Entropy generates fully deterministic, cost-effective, and hard to guess2// numbers.3//4// It is designed both for single-usage, like seeding math/rand or for being5// reused which increases the entropy and its cost effectiveness.6//7// Disclaimer: this package is unsafe and won't prevent others to guess values8// in advance.9//10// It uses the Bernstein's hash djb2 to be CPU-cycle efficient.11package entropy1213import (14 "chain/runtime"15 "chain/runtime/unsafe"16 "math"17 "time"18)1920type Instance struct {21 value uint3222}2324func New() *Instance {25 r := Instance{value: 5381}26 r.addEntropy()27 return &r28}2930func FromSeed(seed uint32) *Instance {31 r := Instance{value: seed}32 r.addEntropy()33 return &r34}3536func (i *Instance) Seed() uint32 {37 return i.value38}3940func (i *Instance) djb2String(input string) {41 for _, c := range input {42 i.djb2Uint32(uint32(c))43 }44}4546// super fast random algorithm.47// http://www.cse.yorku.ca/~oz/hash.html48func (i *Instance) djb2Uint32(input uint32) {49 i.value = (i.value << 5) + i.value + input50}5152// AddEntropy uses various runtime variables to add entropy to the existing seed.53func (i *Instance) addEntropy() {54 // FIXME: reapply the 5381 initial value?5556 // inherit previous entropy57 // nothing to do5859 // handle callers60 {61 currentRealm := unsafe.CurrentRealm().Address().String()62 i.djb2String(currentRealm)63 originCaller := unsafe.OriginCaller().String()64 i.djb2String(originCaller)65 }6667 // height68 {69 height := runtime.ChainHeight()70 if height >= math.MaxUint32 {71 height -= math.MaxUint3272 }73 i.djb2Uint32(uint32(height))74 }7576 // time77 {78 secs := time.Now().Second()79 i.djb2Uint32(uint32(secs))80 nsecs := time.Now().Nanosecond()81 i.djb2Uint32(uint32(nsecs))82 }8384 // FIXME: compute other hard-to-guess but deterministic variables, like real gas?85}8687func (i *Instance) Value() uint32 {88 i.addEntropy()89 return i.value90}9192func (i *Instance) Value64() uint64 {93 i.addEntropy()94 high := i.value95 i.addEntropy()9697 return (uint64(high) << 32) | uint64(i.value)98}99Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.