Repository: LadybirdBrowser/ladybird
File: AK/Random.cpp (C++)

Code before:
 * Copyright (c) 2024, the Ladybird developers.
 * Copyright (c) 2025, Colleirose <criticskate@pm.me>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <AK/Platform.h>
#include <AK/Random.h>
#include <AK/Assertions.h>
#include <AK/UFixedBigInt.h>
#include <AK/UFixedBigIntDivision.h>

#include <openssl/rand.h>

#if defined(AK_OS_LINUX)
#   include <sys/random.h>
#endif

#if defined(AK_OS_WINDOWS)
#    include <windows.h>
#    include <AK/NumericLimits.h>
#    include <AK/Windows.h>
#endif

#if defined(AK_OS_LINUX)
static inline int csprng_chunk(void * const buf, const size_t size)
{
    int ret;

    VERIFY(size <= 256U);
    do {
        ret = getrandom(buf, size, 0);
    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));

    return ret;
}
#endif

static int csprng(void * const buf, size_t size)
{
#if defined(AK_OS_SERENITY) || defined(AK_OS_ANDROID) || defined(AK_OS_BSD_GENERIC) || defined(AK_OS_HAIKU) || AK_LIBC_GLIBC_PREREQ(2, 36)
    arc4random_buf(buf, size);
#elif defined(AK_OS_LINUX)
    size_t chunk_size = 256U;

    do {
        if (size < chunk_size) {
            chunk_size = size;
            VERIFY(chunk_size > (size_t) 0U);
        }


Review comment (suggestion):
This method is only used in one spot; consider just putting the code there instead of having a separate method.

If you want to keep it as a separate method: using `ErrorOr<void>` would be the idiomatic way of returning a potential error. Let's try to not expose any OS-specific error codes if we've dealt with them and work with our own error system as soon as possible.

Code after:
 * Copyright (c) 2024, the Ladybird developers.
 * Copyright (c) 2025-2026, Colleirose <criticskate@pm.me>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <AK/Assertions.h>
#include <AK/Platform.h>
#include <AK/Random.h>
#include <AK/UFixedBigInt.h>
#include <AK/UFixedBigIntDivision.h>

#if defined(AK_OS_LINUX)
#    include <sys/random.h>
#endif

#if defined(AK_OS_WINDOWS)
#    include <AK/Windows.h>
#endif

static inline ErrorOr<void> csprng(void* const buf, size_t size)
{
    // We shouldn't use OpenSSL's RAND_bytes function here, because we want to avoid adding dependencies to AK.
    // Therefore, we will use the best platform-specific CSPRNG.
#if defined(AK_OS_SERENITY) || defined(AK_OS_ANDROID) || defined(AK_OS_BSD_GENERIC) || defined(AK_OS_HAIKU) || AK_LIBC_GLIBC_PREREQ(2, 36)
    // This target also covers MacOS and iOS and they both seem to support arc4random_buf
    arc4random_buf(buf, size);
#elif defined(AK_OS_LINUX)
    unsigned char* out = (unsigned char*)buf;
    while (size > 0u) {
        // EINTR can be handled safely by just trying again. Others are fatal
        // See manual for more details
        int ret = getrandom(out, size, 0);
        if (ret == -1 && errno != EINTR) [[unlikely]]
            return Error::from_errno(errno);

        // If ret > 0 then ret indicates how much was copied
        if (ret > 0) [[likely]] {
            size -= ret;
            out += ret;
        }
    }
#elif defined(AK_OS_WINDOWS)
    // Documented to always return TRUE
    g_system.ProcessPrng((PBYTE)buf, size);
#else
    static_assert(false, "This build target doesn't have a valid CSPRNG interface specified in AK/Random.cpp.");
#endif
    return {};
}