Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

entropy.gno

1.96 Kb · 98 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	"chain/runtime"
15	"chain/runtime/unsafe"
16	"math"
17	"time"
18)
19
20type Instance struct {
21	value uint32
22}
23
24func New() *Instance {
25	r := Instance{value: 5381}
26	r.addEntropy()
27	return &r
28}
29
30func FromSeed(seed uint32) *Instance {
31	r := Instance{value: seed}
32	r.addEntropy()
33	return &r
34}
35
36func (i *Instance) Seed() uint32 {
37	return i.value
38}
39
40func (i *Instance) djb2String(input string) {
41	for _, c := range input {
42		i.djb2Uint32(uint32(c))
43	}
44}
45
46// super fast random algorithm.
47// http://www.cse.yorku.ca/~oz/hash.html
48func (i *Instance) djb2Uint32(input uint32) {
49	i.value = (i.value << 5) + i.value + input
50}
51
52// AddEntropy uses various runtime variables to add entropy to the existing seed.
53func (i *Instance) addEntropy() {
54	// FIXME: reapply the 5381 initial value?
55
56	// inherit previous entropy
57	// nothing to do
58
59	// handle callers
60	{
61		currentRealm := unsafe.CurrentRealm().Address().String()
62		i.djb2String(currentRealm)
63		originCaller := unsafe.OriginCaller().String()
64		i.djb2String(originCaller)
65	}
66
67	// height
68	{
69		height := runtime.ChainHeight()
70		if height >= math.MaxUint32 {
71			height -= math.MaxUint32
72		}
73		i.djb2Uint32(uint32(height))
74	}
75
76	// time
77	{
78		secs := time.Now().Second()
79		i.djb2Uint32(uint32(secs))
80		nsecs := time.Now().Nanosecond()
81		i.djb2Uint32(uint32(nsecs))
82	}
83
84	// FIXME: compute other hard-to-guess but deterministic variables, like real gas?
85}
86
87func (i *Instance) Value() uint32 {
88	i.addEntropy()
89	return i.value
90}
91
92func (i *Instance) Value64() uint64 {
93	i.addEntropy()
94	high := i.value
95	i.addEntropy()
96
97	return (uint64(high) << 32) | uint64(i.value)
98}