| // 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 |