Repository: bitcoin/bitcoin
File: src/random.cpp (C++)

Code before:
 * compatible way to get cryptographic randomness on UNIX-ish platforms.
 */
[[maybe_unused]] void GetDevURandom(unsigned char *ent32)
{
    int f = open("/dev/urandom", O_RDONLY);
    if (f == -1) {
        RandFailure();
    }
    int have = 0;
    do {
        ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
        if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
            close(f);
            RandFailure();
        }
        have += n;
    } while (have < NUM_OS_RANDOM_BYTES);
    close(f);
}
#endif

/** Get 32 bytes of system entropy. */
void GetOSRand(unsigned char *ent32)
{
#if defined(WIN32)
    HCRYPTPROV hProvider;
    int ret = CryptAcquireContextW(&hProvider, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
    if (!ret) {
        RandFailure();
    }
    ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32);
    if (!ret) {
        RandFailure();
    }
    CryptReleaseContext(hProvider, 0);
#elif defined(HAVE_GETRANDOM)
    /* Linux. From the getrandom(2) man page:
     * "If the urandom source has been initialized, reads of up to 256 bytes
     * will always return as many bytes as requested and will not be
     * interrupted by signals."
     */
    if (getrandom(ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) {
        RandFailure();
    }
#elif defined(__OpenBSD__)
    /* OpenBSD. From the arc4random(3) man page:
       "Use of these functions is encouraged for almost all random number
        consumption because the other interfaces are deficient in either
        quality, portability, standardization, or availability."
       The function call is always successful.
     */

Review comment (suggestion):
Usage looks correct according to documentation:
- `hAlgorithm`=`NULL`:  required (see below)
- `pbBuffer`=`ent32`: "The address of a buffer that receives the random number. "
- `cbBuffer`=`NUM_OS_RANDOM_BYTES`: "The size, in bytes, of the pbBuffer buffer."
- `dwFlags`=`BCRYPT_USE_SYSTEM_PREFERRED_RNG`: "Use the system-preferred random number generator algorithm. The hAlgorithm parameter must be NULL."

Nit: Might want to use named arguments here.


Code after:
 */
[[maybe_unused]] void GetDevURandom(unsigned char *ent32)
{
    int f = open("/dev/urandom", O_RDONLY);
    if (f == -1) {
        RandFailure();
    }
    int have = 0;
    do {
        ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
        if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
            close(f);
            RandFailure();
        }
        have += n;
    } while (have < NUM_OS_RANDOM_BYTES);
    close(f);
}
#endif

/** Get 32 bytes of system entropy. */
void GetOSRand(unsigned char *ent32)
{
#if defined(WIN32)
    constexpr uint32_t STATUS_SUCCESS{0x00000000};
    NTSTATUS status = BCryptGenRandom(/*hAlgorithm=*/NULL,
                                      /*pbBuffer=*/ent32,
                                      /*cbBuffer=*/NUM_OS_RANDOM_BYTES,
                                      /*dwFlags=*/BCRYPT_USE_SYSTEM_PREFERRED_RNG);

    if (status != STATUS_SUCCESS) {
        RandFailure();
    }
#elif defined(HAVE_GETRANDOM)
    /* Linux. From the getrandom(2) man page:
     * "If the urandom source has been initialized, reads of up to 256 bytes
     * will always return as many bytes as requested and will not be
     * interrupted by signals."
     */
    if (getrandom(ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) {
        RandFailure();
    }
#elif defined(__OpenBSD__)
    /* OpenBSD. From the arc4random(3) man page:
       "Use of these functions is encouraged for almost all random number
        consumption because the other interfaces are deficient in either
        quality, portability, standardization, or availability."
       The function call is always successful.
     */
    arc4random_buf(ent32, NUM_OS_RANDOM_BYTES);
#elif defined(HAVE_GETENTROPY_RAND) && defined(__APPLE__)