1
0

random.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at http://mozilla.org/MPL/2.0/.
  6. package util
  7. import (
  8. "crypto/md5"
  9. cryptoRand "crypto/rand"
  10. "encoding/binary"
  11. "io"
  12. mathRand "math/rand"
  13. )
  14. // randomCharset contains the characters that can make up a randomString().
  15. const randomCharset = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"
  16. // PredictableRandom is an RNG that will always have the same sequence. It
  17. // will be seeded with the device ID during startup, so that the sequence is
  18. // predictable but varies between instances.
  19. var PredictableRandom = mathRand.New(mathRand.NewSource(42))
  20. func init() {
  21. // The default RNG should be seeded with something good.
  22. mathRand.Seed(RandomInt64())
  23. }
  24. // RandomString returns a string of random characters (taken from
  25. // randomCharset) of the specified length.
  26. func RandomString(l int) string {
  27. bs := make([]byte, l)
  28. for i := range bs {
  29. bs[i] = randomCharset[mathRand.Intn(len(randomCharset))]
  30. }
  31. return string(bs)
  32. }
  33. // RandomInt64 returns a strongly random int64, slowly
  34. func RandomInt64() int64 {
  35. var bs [8]byte
  36. _, err := io.ReadFull(cryptoRand.Reader, bs[:])
  37. if err != nil {
  38. panic("randomness failure: " + err.Error())
  39. }
  40. return SeedFromBytes(bs[:])
  41. }
  42. // SeedFromBytes calculates a weak 64 bit hash from the given byte slice,
  43. // suitable for use a predictable random seed.
  44. func SeedFromBytes(bs []byte) int64 {
  45. h := md5.New()
  46. h.Write(bs)
  47. s := h.Sum(nil)
  48. // The MD5 hash of the byte slice is 16 bytes long. We interpret it as two
  49. // uint64s and XOR them together.
  50. return int64(binary.BigEndian.Uint64(s[0:]) ^ binary.BigEndian.Uint64(s[8:]))
  51. }