blob: 460af9f4d7d01607e930484e0787f9d46a04f0ac [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/lib/crypto_util/random.h"
#include <cmath>
#include <memory>
#include <vector>
#include <openssl/rand.h>
namespace cobalt::crypto {
namespace {
constexpr size_t kMaxRandomBits = 256;
constexpr size_t kBitsPerByte = 8;
constexpr size_t kBytesPerU32 = 4;
constexpr size_t kBytesPerU64 = 8;
} // namespace
void Random::RandomBytes(byte* buf, std::size_t num) { RAND_bytes(buf, num); }
void Random::RandomString(std::string* buf) {
RandomBytes(reinterpret_cast<byte*>(&((*buf)[0])), buf->size());
}
uint32_t Random::RandomUint32() {
uint32_t x;
RandomBytes(reinterpret_cast<byte*>(&x), kBytesPerU32);
return x;
}
uint64_t Random::RandomUint64() {
uint64_t x;
RandomBytes(reinterpret_cast<byte*>(&x), kBytesPerU64);
return x;
}
bool Random::RandomBits(float p, byte* buffer, std::size_t size) {
// For every byte, returned by this function we need to allocate 32 bytes.
// In order to prevent excessive allocations, this function will only
// return up to 256 bytes.
if (size > kMaxRandomBits) {
return false;
}
if (p <= 0.0 || p > 1.0) {
for (std::size_t i = 0; i < size; i++) {
buffer[i] = 0;
}
return true;
}
// threshold is the integer n in the range [0, 2^32] such that
// n/2^32 best approximates p.
auto threshold =
static_cast<uint64_t>(round(static_cast<double>(p) * (static_cast<double>(UINT32_MAX) + 1)));
// For every bit in the output, we need a 32 bit number.
std::vector<uint32_t> random_bytes(kBitsPerByte * size);
RandomBytes(reinterpret_cast<byte*>(random_bytes.data()), kBitsPerByte * size * sizeof(uint32_t));
for (std::size_t byte_index = 0; byte_index < size; byte_index++) {
buffer[byte_index] = 0;
for (size_t i = 0; i < kBitsPerByte; i++) {
uint8_t random_bit = (random_bytes[byte_index + i] < threshold);
buffer[byte_index] |= random_bit << i;
}
}
return true;
}
} // namespace cobalt::crypto