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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

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}