entropy.gno
1.92 Kb ยท 97 lines
1// Entropy generates fully deterministic, cost-effective, and hard to guess
2// numbers.
3//
4// It is designed both for single-usage, like seeding math/rand or for being
5// reused which increases the entropy and its cost effectiveness.
6//
7// Disclaimer: this package is unsafe and won't prevent others to guess values
8// in advance.
9//
10// It uses the Bernstein's hash djb2 to be CPU-cycle efficient.
11package entropy
12
13import (
14 "math"
15 "std"
16 "time"
17)
18
19type Instance struct {
20 value uint32
21}
22
23func New() *Instance {
24 r := Instance{value: 5381}
25 r.addEntropy()
26 return &r
27}
28
29func FromSeed(seed uint32) *Instance {
30 r := Instance{value: seed}
31 r.addEntropy()
32 return &r
33}
34
35func (i *Instance) Seed() uint32 {
36 return i.value
37}
38
39func (i *Instance) djb2String(input string) {
40 for _, c := range input {
41 i.djb2Uint32(uint32(c))
42 }
43}
44
45// super fast random algorithm.
46// http://www.cse.yorku.ca/~oz/hash.html
47func (i *Instance) djb2Uint32(input uint32) {
48 i.value = (i.value << 5) + i.value + input
49}
50
51// AddEntropy uses various runtime variables to add entropy to the existing seed.
52func (i *Instance) addEntropy() {
53 // FIXME: reapply the 5381 initial value?
54
55 // inherit previous entropy
56 // nothing to do
57
58 // handle callers
59 {
60 currentRealm := std.CurrentRealm().Address().String()
61 i.djb2String(currentRealm)
62 originCaller := std.OriginCaller().String()
63 i.djb2String(originCaller)
64 }
65
66 // height
67 {
68 height := std.ChainHeight()
69 if height >= math.MaxUint32 {
70 height -= math.MaxUint32
71 }
72 i.djb2Uint32(uint32(height))
73 }
74
75 // time
76 {
77 secs := time.Now().Second()
78 i.djb2Uint32(uint32(secs))
79 nsecs := time.Now().Nanosecond()
80 i.djb2Uint32(uint32(nsecs))
81 }
82
83 // FIXME: compute other hard-to-guess but deterministic variables, like real gas?
84}
85
86func (i *Instance) Value() uint32 {
87 i.addEntropy()
88 return i.value
89}
90
91func (i *Instance) Value64() uint64 {
92 i.addEntropy()
93 high := i.value
94 i.addEntropy()
95
96 return (uint64(high) << 32) | uint64(i.value)
97}