forked from TheThingsNetwork/lorawan-stack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrandom.go
More file actions
94 lines (79 loc) · 2.74 KB
/
random.go
File metadata and controls
94 lines (79 loc) · 2.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright © 2019 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package random implements goroutine-safe utilities on top of a secure random source.
package random
import (
"crypto/rand"
"encoding/base64"
"io"
"math/big"
mathrand "math/rand"
"time"
)
// Interface for random.
type Interface interface {
io.Reader
Intn(n int) int
String(n int) string
Bytes(n int) []byte
}
// TTNRandom is used as a wrapper around crypto/rand.
type TTNRandom struct {
io.Reader
}
func init() {
mathrand.Seed(time.Now().UTC().UnixNano())
}
// New returns a new Random, in most cases you can also just use the global funcs.
func New() Interface {
return &TTNRandom{
Reader: rand.Reader,
}
}
var global = New()
// Intn returns a random number in the range [0,n). This func uses the global TTNRandom.
func Intn(n int) int { return global.Intn(n) }
// Intn returns a random number in the range [0,n).
func (r *TTNRandom) Intn(n int) int {
i, err := rand.Int(r.Reader, big.NewInt(int64(n)))
if err != nil {
panic(err) // r.Reader is (very) broken.
}
return int(i.Int64())
}
// Bytes generates a random byte slice of length n. This func uses the global TTNRandom.
func Bytes(n int) []byte { return global.Bytes(n) }
// Bytes generates a random byte slice of length n.
func (r *TTNRandom) Bytes(n int) []byte {
p := make([]byte, n)
r.Read(p)
return p
}
// Read fills the byte slice with random bytes. This func uses the global TTNRandom.
func Read(b []byte) (int, error) { return global.Read(b) }
// String returns a random string of length n, it uses the characters of base64.URLEncoding.
// This func uses the global TTNRandom.
func String(n int) string { return global.String(n) }
// String returns a random string of length n, it uses the characters of base64.URLEncoding.
func (r *TTNRandom) String(n int) string {
b := r.Bytes(n * 6 / 8)
return base64.RawURLEncoding.EncodeToString(b)
}
// Jitter returns a random number around d where p is the maximum percentage of change applied to d.
// With d=100 and p=0.1, the duration returned will be in [90,110].
func Jitter(d time.Duration, p float64) time.Duration {
df := float64(d)
v := time.Duration(mathrand.Int63n(int64(df*p*2)) - int64(df*p))
return d + v
}