-
Notifications
You must be signed in to change notification settings - Fork 31
/
rng.go
66 lines (52 loc) · 1.95 KB
/
rng.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package types
import (
"crypto/sha256"
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
)
const RandPrec = 20 // the precision for generated random numbers
const SeedBytesLength = 32 //
// RNG is a random number generator
type RNG interface {
GetRand() big.Rat // interface which returns a random number between [0,1)
}
// PRNG represents a pseudo-random number implementation based on block or oracle for RNG
type PRNG struct {
BlockHash []byte // hash of some block
BlockTimestamp int64 // timestamp of the next block
TxInitiator sdk.AccAddress // address initiating the request tx
OracleSeed []byte // oracle seed
Oracle bool // oracle method
}
// MakePRNG constructs a PRNG
func MakePRNG(blockHash []byte, blockTimestampt int64, txInitiator sdk.AccAddress, oracleSeed []byte, oracle bool) PRNG {
return PRNG{
BlockHash: blockHash,
BlockTimestamp: blockTimestampt,
TxInitiator: txInitiator,
OracleSeed: oracleSeed,
Oracle: oracle,
}
}
// GetRand implements RNG
func (p PRNG) GetRand() *big.Rat {
seedBT := big.NewInt(p.BlockTimestamp)
seedBH := new(big.Int).Div(new(big.Int).SetBytes(SHA256(p.BlockHash)), seedBT)
seedTI := new(big.Int).Div(new(big.Int).SetBytes(SHA256(p.TxInitiator)), seedBT)
seedSum := new(big.Int).Add(seedBT, seedBH)
seedSum = new(big.Int).Add(seedSum, seedTI)
if p.Oracle {
seedOS := new(big.Int).Div(new(big.Int).SetBytes(SHA256(p.OracleSeed)), seedBT)
seedSum = new(big.Int).Add(seedSum, seedOS)
}
seed := new(big.Int).SetBytes(SHA256(seedSum.Bytes()))
precision := new(big.Int).Exp(big.NewInt(10), big.NewInt(RandPrec), nil)
// Generate a random number between [0,1) with `RandPrec` precision from seed
random := new(big.Rat).SetFrac(new(big.Int).Mod(seed, precision), precision)
return random
}
// SHA256 wraps sha256.Sum256 with result converted to slice
func SHA256(data []byte) []byte {
sum := sha256.Sum256(data)
return sum[:]
}