randomid.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. package identity
  2. import (
  3. cryptorand "crypto/rand"
  4. "fmt"
  5. "io"
  6. "math/big"
  7. )
  8. var (
  9. // idReader is used for random id generation. This declaration allows us to
  10. // replace it for testing.
  11. idReader = cryptorand.Reader
  12. )
  13. // parameters for random identifier generation. We can tweak this when there is
  14. // time for further analysis.
  15. const (
  16. randomIDEntropyBytes = 17
  17. randomIDBase = 36
  18. // To ensure that all identifiers are fixed length, we make sure they
  19. // get padded out or truncated to 25 characters.
  20. //
  21. // For academics, f5lxx1zz5pnorynqglhzmsp33 == 2^128 - 1. This value
  22. // was calculated from floor(log(2^128-1, 36)) + 1.
  23. //
  24. // While 128 bits is the largest whole-byte size that fits into 25
  25. // base-36 characters, we generate an extra byte of entropy to fill
  26. // in the high bits, which would otherwise be 0. This gives us a more
  27. // even distribution of the first character.
  28. //
  29. // See http://mathworld.wolfram.com/NumberLength.html for more information.
  30. maxRandomIDLength = 25
  31. )
  32. // NewID generates a new identifier for use where random identifiers with low
  33. // collision probability are required.
  34. //
  35. // With the parameters in this package, the generated identifier will provide
  36. // ~129 bits of entropy encoded with base36. Leading padding is added if the
  37. // string is less 25 bytes. We do not intend to maintain this interface, so
  38. // identifiers should be treated opaquely.
  39. func NewID() string {
  40. var p [randomIDEntropyBytes]byte
  41. if _, err := io.ReadFull(idReader, p[:]); err != nil {
  42. panic(fmt.Errorf("failed to read random bytes: %v", err))
  43. }
  44. p[0] |= 0x80 // set high bit to avoid the need for padding
  45. return (&big.Int{}).SetBytes(p[:]).Text(randomIDBase)[1 : maxRandomIDLength+1]
  46. }