OSDN Git Service

new repo
[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         "encoding/hex"
8         "io"
9         "sync"
10
11         . "github.com/tendermint/tmlibs/common"
12 )
13
14 var gRandInfo *randInfo
15
16 func init() {
17         gRandInfo = &randInfo{}
18         gRandInfo.MixEntropy(randBytes(32)) // Init
19 }
20
21 // Mix additional bytes of randomness, e.g. from hardware, user-input, etc.
22 // It is OK to call it multiple times.  It does not diminish security.
23 func MixEntropy(seedBytes []byte) {
24         gRandInfo.MixEntropy(seedBytes)
25 }
26
27 // This only uses the OS's randomness
28 func randBytes(numBytes int) []byte {
29         b := make([]byte, numBytes)
30         _, err := crand.Read(b)
31         if err != nil {
32                 PanicCrisis(err)
33         }
34         return b
35 }
36
37 // This uses the OS and the Seed(s).
38 func CRandBytes(numBytes int) []byte {
39         b := make([]byte, numBytes)
40         _, err := gRandInfo.Read(b)
41         if err != nil {
42                 PanicCrisis(err)
43         }
44         return b
45 }
46
47 // RandHex(24) gives 96 bits of randomness, strong enough for most purposes.
48 func CRandHex(numDigits int) string {
49         return hex.EncodeToString(CRandBytes(numDigits / 2))
50 }
51
52 // Returns a crand.Reader mixed with user-supplied entropy
53 func CReader() io.Reader {
54         return gRandInfo
55 }
56
57 //--------------------------------------------------------------------------------
58
59 type randInfo struct {
60         mtx          sync.Mutex
61         seedBytes    [32]byte
62         cipherAES256 cipher.Block
63         streamAES256 cipher.Stream
64         reader       io.Reader
65 }
66
67 // You can call this as many times as you'd like.
68 // XXX TODO review
69 func (ri *randInfo) MixEntropy(seedBytes []byte) {
70         ri.mtx.Lock()
71         defer ri.mtx.Unlock()
72         // Make new ri.seedBytes
73         hashBytes := Sha256(seedBytes)
74         hashBytes32 := [32]byte{}
75         copy(hashBytes32[:], hashBytes)
76         ri.seedBytes = xorBytes32(ri.seedBytes, hashBytes32)
77         // Create new cipher.Block
78         var err error
79         ri.cipherAES256, err = aes.NewCipher(ri.seedBytes[:])
80         if err != nil {
81                 PanicSanity("Error creating AES256 cipher: " + err.Error())
82         }
83         // Create new stream
84         ri.streamAES256 = cipher.NewCTR(ri.cipherAES256, randBytes(aes.BlockSize))
85         // Create new reader
86         ri.reader = &cipher.StreamReader{S: ri.streamAES256, R: crand.Reader}
87 }
88
89 func (ri *randInfo) Read(b []byte) (n int, err error) {
90         ri.mtx.Lock()
91         defer ri.mtx.Unlock()
92         return ri.reader.Read(b)
93 }
94
95 func xorBytes32(bytesA [32]byte, bytesB [32]byte) (res [32]byte) {
96         for i, b := range bytesA {
97                 res[i] = b ^ bytesB[i]
98         }
99         return res
100 }