blob: 3308db762904e111af5d451af0be4eabac9400b5 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// 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 util
import (
cryptorand "crypto/rand"
"fmt"
"math/big"
mathrand "math/rand"
"sync"
)
// Random is an interface that provides utility functions for generating random
// bytes, and integers.
type Random interface {
// RandomBytes returns the specified |num| bytes of random data from a uniform
// distribution or error if the underlying source of entropy fails.
RandomBytes(num uint32) ([]byte, error)
// RandomUint63 returns a uniformly random, 63-bit integer in the range
// [0, max). |max| must be in the range (0, 2^63). Fails with an error if
// |max| is invalid or if the underlying source of entropy fails.
RandomUint63(max uint64) (uint64, error)
}
// DeterministicRandom uses a deterministic PRNG to generate random values
// using the less secure "math/rand" library apis.
type DeterministicRandom struct {
mu sync.RWMutex
rand *mathrand.Rand
}
// NewDeterministicRandom creates and seeds the Deterministic PRNG.
func NewDeterministicRandom(seed int64) *DeterministicRandom {
return &DeterministicRandom{
rand: mathrand.New(mathrand.NewSource(seed)),
}
}
// RandomBytes returns specified |num| bytes of random data from a uniform
// distribution or error if the underlying source of entropy fails.
func (r *DeterministicRandom) RandomBytes(num uint32) ([]byte, error) {
var bytes = make([]byte, num)
r.mu.Lock()
defer r.mu.Unlock()
_, err := r.rand.Read(bytes)
return bytes, err
}
// RandomUint63 returns a uniformly random, 63-bit integer in the range
// [0, max). |max| must be in the range (0, 2^63). Fails with an error if
// |max| is invalid or if the underlying source of entropy fails.
func (r *DeterministicRandom) RandomUint63(max uint64) (uint64, error) {
if max <= 0 || max >= 1<<63 {
return 0, fmt.Errorf("Invalid |max| value [%v]", max)
}
r.mu.Lock()
defer r.mu.Unlock()
// Int63n returns a non-negative int64 pseudo-random number in [0,max).
return uint64(r.rand.Int63n(int64(max))), nil
}
// SecureRandom generates non-deterministic random values using the secure
// crypto/rand PRNG.
type SecureRandom struct{}
// RandomBytes returns specified |num| bytes of random data from a uniform
// distribution or error if the underlying source of entropy fails.
func (r *SecureRandom) RandomBytes(num uint32) ([]byte, error) {
var bytes = make([]byte, num)
_, err := cryptorand.Read(bytes)
return bytes, err
}
// RandomUint63 returns a uniformly random, 63-bit integer in the range
// [0, max). |max| must be in the range (0, 2^63). Fails with an error if
// |max| is invalid or if the underlying source of entropy fails.
func (r *SecureRandom) RandomUint63(max uint64) (uint64, error) {
if max <= 0 || max >= 1<<63 {
return 0, fmt.Errorf("Invalid |max| value [%v]", max)
}
var z big.Int
z.SetUint64(max)
nBig, err := cryptorand.Int(cryptorand.Reader, &z)
if err != nil {
return 0, err
}
return nBig.Uint64(), nil
}