securesource_test.go 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
  6. package rand
  7. import "testing"
  8. func TestSecureSource(t *testing.T) {
  9. // This is not a test to verify that the random numbers are secure,
  10. // merely that the numbers look random at all and that we've haven't
  11. // broken the implementation by masking off half the bits or always
  12. // returning "4" (chosen by fair dice roll),
  13. const nsamples = 10000
  14. // Create a new source and sample values from it.
  15. s := newSecureSource()
  16. res0 := make([]int64, nsamples)
  17. for i := range res0 {
  18. res0[i] = s.Int63()
  19. }
  20. // Do it again
  21. s = newSecureSource()
  22. res1 := make([]int64, nsamples)
  23. for i := range res1 {
  24. res1[i] = s.Int63()
  25. }
  26. // There should (statistically speaking) be no repetition of the values,
  27. // neither within the samples from a source nor between sources.
  28. for _, v0 := range res0 {
  29. for _, v1 := range res1 {
  30. if v0 == v1 {
  31. t.Errorf("Suspicious coincidence, %d repeated between res0/res1", v0)
  32. }
  33. }
  34. }
  35. for i, v0 := range res0 {
  36. for _, v1 := range res0[i+1:] {
  37. if v0 == v1 {
  38. t.Errorf("Suspicious coincidence, %d repeated within res0", v0)
  39. }
  40. }
  41. }
  42. for i, v0 := range res1 {
  43. for _, v1 := range res1[i+1:] {
  44. if v0 == v1 {
  45. t.Errorf("Suspicious coincidence, %d repeated within res1", v0)
  46. }
  47. }
  48. }
  49. // Count how many times each bit was set. On average each bit ought to
  50. // be set in half of the samples, except the topmost bit which must
  51. // never be set (int63). We raise an alarm if a single bit is set in
  52. // fewer than 1/3 of the samples or more often than 2/3 of the samples.
  53. var bits [64]int
  54. for _, v := range res0 {
  55. for i := range bits {
  56. if v&1 == 1 {
  57. bits[i]++
  58. }
  59. v >>= 1
  60. }
  61. }
  62. for bit, count := range bits {
  63. switch bit {
  64. case 63:
  65. // The topmost bit is never set
  66. if count != 0 {
  67. t.Errorf("The topmost bit was set %d times in %d samples (should be 0)", count, nsamples)
  68. }
  69. default:
  70. if count < nsamples/3 {
  71. t.Errorf("Bit %d was set only %d times out of %d", bit, count, nsamples)
  72. }
  73. if count > nsamples/3*2 {
  74. t.Errorf("Bit %d was set fully %d times out of %d", bit, count, nsamples)
  75. }
  76. }
  77. }
  78. }
  79. var sink int64
  80. func BenchmarkSecureSource(b *testing.B) {
  81. s := newSecureSource()
  82. for i := 0; i < b.N; i++ {
  83. sink = s.Int63()
  84. }
  85. b.ReportAllocs()
  86. }