OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / tendermint / go-crypto / random.go
1 package crypto
2
3 import (
4         "crypto/aes"
5         "crypto/cipher"
6         crand "crypto/rand"
7         "io"
8         "sync"
9
10         . "github.com/tendermint/tmlibs/common"
11 )
12
13 var gRandInfo *randInfo
14
15 func init() {
16         gRandInfo = &randInfo{}
17         gRandInfo.MixEntropy(randBytes(32)) // Init
18 }
19
20 // Mix additional bytes of randomness, e.g. from hardware, user-input, etc.
21 // It is OK to call it multiple times.  It does not diminish security.
22 func MixEntropy(seedBytes []byte) {
23         gRandInfo.MixEntropy(seedBytes)
24 }
25
26 // This only uses the OS's randomness
27 func randBytes(numBytes int) []byte {
28         b := make([]byte, numBytes)
29         _, err := crand.Read(b)
30         if err != nil {
31                 PanicCrisis(err)
32         }
33         return b
34 }
35
36 // This uses the OS and the Seed(s).
37 func CRandBytes(numBytes int) []byte {
38         b := make([]byte, numBytes)
39         _, err := gRandInfo.Read(b)
40         if err != nil {
41                 PanicCrisis(err)
42         }
43         return b
44 }
45
46 //--------------------------------------------------------------------------------
47
48 type randInfo struct {
49         mtx          sync.Mutex
50         seedBytes    [32]byte
51         cipherAES256 cipher.Block
52         streamAES256 cipher.Stream
53         reader       io.Reader
54 }
55
56 // You can call this as many times as you'd like.
57 // XXX TODO review
58 func (ri *randInfo) MixEntropy(seedBytes []byte) {
59         ri.mtx.Lock()
60         defer ri.mtx.Unlock()
61         // Make new ri.seedBytes
62         hashBytes := Sha256(seedBytes)
63         hashBytes32 := [32]byte{}
64         copy(hashBytes32[:], hashBytes)
65         ri.seedBytes = xorBytes32(ri.seedBytes, hashBytes32)
66         // Create new cipher.Block
67         var err error
68         ri.cipherAES256, err = aes.NewCipher(ri.seedBytes[:])
69         if err != nil {
70                 PanicSanity("Error creating AES256 cipher: " + err.Error())
71         }
72         // Create new stream
73         ri.streamAES256 = cipher.NewCTR(ri.cipherAES256, randBytes(aes.BlockSize))
74         // Create new reader
75         ri.reader = &cipher.StreamReader{S: ri.streamAES256, R: crand.Reader}
76 }
77
78 func (ri *randInfo) Read(b []byte) (n int, err error) {
79         ri.mtx.Lock()
80         defer ri.mtx.Unlock()
81         return ri.reader.Read(b)
82 }
83
84 func xorBytes32(bytesA [32]byte, bytesB [32]byte) (res [32]byte) {
85         for i, b := range bytesA {
86                 res[i] = b ^ bytesB[i]
87         }
88         return res
89 }