Skip to content

Commit 4c949d4

Browse files
committed
feat: openkal.random on getentropy(2)
⭐ **号来自机器,不来自记忆。** `.github/workflows/numbers.yml` 从 SDK 自己的 `sys/syscall.h` 读出本实现用到的每一个号,在本仓库针对的两个 runner 上都读, 而两者都答 `SYS_getentropy 500`。那个 workflow 存在的理由正是: 一个凭记忆写下的号,在它出错的那天之前一直是对的。 ⚠️ **不用 `arc4random_buf`**,虽然 libc++ 在这个系统上默认会去找它。 那个名字在 libSystem 里,而伸手进 libSystem 正是本后端要避免的 —— 它直接发这个内核的调用,`sys.h` 的注释记着这一点。`getentropy` 是底下那一层。 ⚠️ **这个内核单次上限 256 字节。** 那是这个系统的限制而不是本接口的, 所以循环把它变成 `kal_random_fill` 承诺的「全有或全无」。 失败时缓冲区不恢复 —— 契约如此:失败的填充留下未指定内容而非原内容。
1 parent f24a96e commit 4c949d4

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

src/random.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// openkal.random on this system --- getentropy(2).
2+
//
3+
// ⭐ THE NUMBER CAME FROM THE MACHINE, NOT FROM MEMORY. `.github/workflows/
4+
// numbers.yml` reads every number this implementation uses out of the SDK's own
5+
// `sys/syscall.h`, on both runners this repository targets, and both answered
6+
// `SYS_getentropy 500`. That workflow exists because a number recalled rather
7+
// than read is a number that is right until the day it is not.
8+
//
9+
// ⚠️ AND NOT `arc4random_buf`, WHICH IS WHAT libc++ WOULD REACH FOR HERE.
10+
// That name is in libSystem, and reaching into libSystem is what this backend
11+
// exists to avoid: it issues this kernel's calls directly, as the note in
12+
// `sys.h` records. `getentropy` is the call underneath.
13+
//
14+
// ⚠️ THE KERNEL CAPS A CALL AT 256 BYTES. That is this system's limit and not
15+
// this interface's, so the loop below turns it into the all-or-nothing
16+
// `kal_random_fill` promises.
17+
#include "sys.h"
18+
#include <openkal/random.h>
19+
20+
extern "C" int kal_random_fill(void* out, kal_uintptr len) {
21+
if (len == 0) return kal_ok;
22+
if (out == nullptr) return kal_err_invalid;
23+
24+
auto* p = static_cast<unsigned char*>(out);
25+
kal_uintptr filled = 0;
26+
while (filled < len) {
27+
const kal_uintptr chunk = (len - filled) > 256 ? 256 : (len - filled);
28+
const okm_long r = okm::sys(okm::nr_getentropy,
29+
reinterpret_cast<okm_long>(p + filled),
30+
static_cast<okm_long>(chunk), 0, 0);
31+
if (r < 0) {
32+
// ⚠️ The buffer is not restored, and the contract says it need not
33+
// be: a failed fill leaves it unspecified rather than unchanged.
34+
if (r == -4 /* EINTR */) continue;
35+
return kal_err_io;
36+
}
37+
filled += chunk;
38+
}
39+
return kal_ok;
40+
}
41+
42+
// Neither blocking nor hardware. This kernel's generator is seeded before a
43+
// process runs, so there is no wait to report; and whether the seed came from a
44+
// hardware source is not something this backend can observe.
45+
extern "C" const kal_uintptr kal_random_props = 0;

src/sys.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ enum : okm_long {
134134
nr_dup2 = 90, nr_fsync = 95, nr_gettimeofday = 116,
135135
nr_readv = 120, nr_writev = 121, nr_ftruncate = 201,
136136
nr_utimes = 138, nr_futimes = 139,
137+
nr_getentropy = 500,
137138
// This kernel has no call that reports the working directory --- the
138139
// measurement is in .github/workflows/numbers.yml, where SYS___getcwd is
139140
// absent from the system's own table. What it has instead is an enquiry

0 commit comments

Comments
 (0)