Files
AnyPS5/core/libs/tests/GuestPosixRandom.cpp
David 7083b2941a feat(libScePosixForWebKit): implement arc4random
Implement arc4random (UISQ-dQzw28) in libScePosixForWebKit on top of the
existing arc4random_buf, so both draw from the same thread-local host
std::random_device. Like FreeBSD 11.4 lib/libc/gen/arc4random.c
(8c639945) it returns a uniformly distributed 32-bit value and has no
failure result.

Cloud Play (PPSA99600) imports it: the import audit in #3249 on main
ccf9ff90 lists `UISQ-dQzw28` `arc4random` among nine absent imports
("no PR or issue found"). The ps5-payload-dev SDK stubs (f5d40f02,
sce_stubs/libScePosixForWebKit.c) place arc4random, arc4random_buf and
fnmatch in libScePosixForWebKit; arc4random_uniform is in neither that
set nor libSceLibcInternal, so it is not added.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 95da68017f6817abec785864e682530e9b135a2b)
2026-10-11 11:14:30 +00:00

58 lines
2.4 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <source_location>
extern "C" void APS5_VABI arc4random_buf_nid_postfix(void*, std::size_t);
extern "C" std::uint32_t APS5_VABI arc4random_nid_postfix();
void Require(bool condition, std::source_location location = std::source_location::current()) {
if (!condition) {
std::fprintf(stderr, "Posix random check failed at line %u\n", location.line());
std::abort();
}
}
int main() {
std::array<unsigned char, 4099> first{};
std::array<unsigned char, 4099> second{};
first.fill(0xa5);
arc4random_buf_nid_postfix(first.data(), 0);
Require(std::all_of(first.begin(), first.end(), [](unsigned char value) { return value == 0xa5; }));
for (const std::size_t size : {1u, 3u, 5u, 4098u}) {
first.fill(0xa5);
arc4random_buf_nid_postfix(first.data(), size);
Require(std::all_of(first.begin() + static_cast<std::ptrdiff_t>(size), first.end(),
[](unsigned char value) { return value == 0xa5; }));
}
arc4random_buf_nid_postfix(first.data(), first.size());
arc4random_buf_nid_postfix(second.data(), second.size());
Require(first != second);
std::array<std::size_t, 256> counts{};
for (const auto value : first) ++counts[value];
Require(*std::max_element(counts.begin(), counts.end()) < 64);
constexpr std::size_t Draws = 65536;
static std::array<std::uint32_t, Draws> words{};
for (auto& word : words) word = arc4random_nid_postfix();
std::array<std::size_t, 32> bits{};
std::array<std::size_t, 16> nibbles{};
for (const auto word : words) {
for (std::size_t bit = 0; bit < bits.size(); ++bit) bits[bit] += (word >> bit) & 1u;
++nibbles[word >> 28];
}
for (const auto count : bits) Require(count > Draws / 2 - 1500 && count < Draws / 2 + 1500);
for (const auto count : nibbles) Require(count > Draws / 16 - 600 && count < Draws / 16 + 600);
Require(*std::min_element(words.begin(), words.end()) < 0x00100000u);
Require(*std::max_element(words.begin(), words.end()) > 0xfff00000u);
std::sort(words.begin(), words.end());
std::size_t repeats = 0;
for (std::size_t index = 1; index < Draws; ++index) repeats += words[index] == words[index - 1];
Require(repeats < 16);
return 0;
}