random.go 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  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. // RandomString returns a string of random characters (taken from
  17. // randomCharset) of the specified length.
  18. func RandomString(l int) string {
  19. bs := make([]byte, l)
  20. for i := range bs {
  21. bs[i] = randomCharset[mathRand.Intn(len(randomCharset))]
  22. }
  23. return string(bs)
  24. }
  25. // RandomInt64 returns a strongly random int64, slowly
  26. func RandomInt64() int64 {
  27. var bs [8]byte
  28. _, err := io.ReadFull(cryptoRand.Reader, bs[:])
  29. if err != nil {
  30. panic("randomness failure: " + err.Error())
  31. }
  32. return SeedFromBytes(bs[:])
  33. }
  34. // SeedFromBytes calculates a weak 64 bit hash from the given byte slice,
  35. // suitable for use a predictable random seed.
  36. func SeedFromBytes(bs []byte) int64 {
  37. h := md5.New()
  38. h.Write(bs)
  39. s := h.Sum(nil)
  40. // The MD5 hash of the byte slice is 16 bytes long. We interpret it as two
  41. // uint64s and XOR them together.
  42. return int64(binary.BigEndian.Uint64(s[0:]) ^ binary.BigEndian.Uint64(s[8:]))
  43. }