diff --git a/hash.go b/hash.go new file mode 100644 index 000000000..165b1e153 --- /dev/null +++ b/hash.go @@ -0,0 +1,18 @@ +package crypto + +import ( + "crypto/sha256" + "golang.org/x/crypto/ripemd160" +) + +func Sha256(bytes []byte) []byte { + hasher := sha256.New() + hasher.Write(bytes) + return hasher.Sum(nil) +} + +func Ripemd160(bytes []byte) []byte { + hasher := ripemd160.New() + hasher.Write(bytes) + return hasher.Sum(nil) +} diff --git a/pub_key.go b/pub_key.go index c5d3cadc2..4cfe815ce 100644 --- a/pub_key.go +++ b/pub_key.go @@ -15,6 +15,7 @@ type PubKey interface { Address() []byte KeyString() string VerifyBytes(msg []byte, sig Signature) bool + Equals(PubKey) bool } // Types of PubKey implementations diff --git a/random.go b/random.go new file mode 100644 index 000000000..803386843 --- /dev/null +++ b/random.go @@ -0,0 +1,100 @@ +package crypto + +import ( + "crypto/aes" + "crypto/cipher" + crand "crypto/rand" + "encoding/hex" + "io" + "sync" + + . "github.com/tendermint/go-common" +) + +var gRandInfo *randInfo + +func init() { + gRandInfo = &randInfo{} + gRandInfo.AddSeed(randBytes(32)) // Init +} + +// Add additional bytes of randomness, e.g. from hardware, user-input, etc. +// It is OK to call it multiple times. It does not deminish security. +func Seed(seedBytes []byte) { + gRandInfo.AddSeed(seedBytes) +} + +// This only uses the OS's randomness +func randBytes(numBytes int) []byte { + b := make([]byte, numBytes) + _, err := crand.Read(b) + if err != nil { + PanicCrisis(err) + } + return b +} + +// This uses the OS and the Seed(s). +func CRandBytes(numBytes int) []byte { + b := make([]byte, numBytes) + _, err := gRandInfo.Read(b) + if err != nil { + PanicCrisis(err) + } + return b +} + +// RandHex(24) gives 96 bits of randomness, strong enough for most purposes. +func CRandHex(numDigits int) string { + return hex.EncodeToString(CRandBytes(numDigits / 2)) +} + +// Returns a crand.Reader mixed with user-supplied entropy +func CReader() io.Reader { + return gRandInfo +} + +//-------------------------------------------------------------------------------- + +type randInfo struct { + mtx sync.Mutex + seedBytes [32]byte + cipherAES256 cipher.Block + streamAES256 cipher.Stream + reader io.Reader +} + +// You can call this as many times as you'd like. +// XXX TODO review +func (ri *randInfo) AddSeed(seedBytes []byte) { + ri.mtx.Lock() + defer ri.mtx.Unlock() + // Make new ri.seedBytes + hashBytes := Sha256(seedBytes) + hashBytes32 := [32]byte{} + copy(hashBytes32[:], hashBytes) + ri.seedBytes = xorBytes32(ri.seedBytes, hashBytes32) + // Create new cipher.Block + var err error + ri.cipherAES256, err = aes.NewCipher(ri.seedBytes[:]) + if err != nil { + PanicSanity("Error creating AES256 cipher: " + err.Error()) + } + // Create new stream + ri.streamAES256 = cipher.NewCTR(ri.cipherAES256, randBytes(aes.BlockSize)) + // Create new reader + ri.reader = &cipher.StreamReader{S: ri.streamAES256, R: crand.Reader} +} + +func (ri *randInfo) Read(b []byte) (n int, err error) { + ri.mtx.Lock() + defer ri.mtx.Unlock() + return ri.reader.Read(b) +} + +func xorBytes32(bytesA [32]byte, bytesB [32]byte) (res [32]byte) { + for i, b := range bytesA { + res[i] = b ^ bytesB[i] + } + return res +} diff --git a/signature_test.go b/signature_test.go index 6a803b697..e4e72e48d 100644 --- a/signature_test.go +++ b/signature_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/tendermint/ed25519" - . "github.com/tendermint/go-common" "github.com/tendermint/go-wire" )