Skip to content

feat: openkal.random on ProcessPrng - #8

Merged
Sunrisepeak merged 8 commits into
mainfrom
feat/openkal-random
Aug 24, 2026
Merged

feat: openkal.random on ProcessPrng#8
Sunrisepeak merged 8 commits into
mainfrom
feat/openkal-random

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

ProcessPrng 而不是 BCryptGenRandom,差别是一个句柄。 后者要算法句柄,本接口得每次打开或缓存它,而缓存意味着有了初始化顺序。ProcessPrng 是同一个生成器、没有句柄。Chromium 与 Rust 标准库都因此改用了它。

⚠️ 也不是 RtlGenRandom——未文档化、按序号导出、每个调用者自写声明。

⚠️ 导入库不存在,而本包自己生成它

lld: error: unable to find library -lbcryptprimitives

⭐ 本包本来就用 port/*.def + dlltool 生成导入库,那机制的理由正是「本包声明自己用到哪些 Win32 名字」。加一份只导出 ProcessPrng 的 def 并接进 build.mcpp,是该机制的正确用法。

实测:PE32+ 产物导入表含 bcryptprimitives.dll,wine 里跑通,std::random_device 返回两个不同值。依赖 mcpplibs/openkal#8

⭐ **ProcessPrng 而不是 BCryptGenRandom,差别是一个句柄。** 后者是文档化的
CNG 入口,要一个算法句柄 —— 本接口得在每次调用时打开它,或缓存它,
而缓存意味着有了初始化顺序。`ProcessPrng` 是同一个生成器,没有句柄,
除调用本身外没有失败模式。Chromium 与 Rust 标准库都因这些理由改用了它。

⚠️ **也不是 `RtlGenRandom`(`SystemFunction036`)**,那是更老的答案:
未文档化、由 advapi32 按序号导出、每个调用者自己写一份声明。它能用,
而本后端不需要它 —— `ProcessPrng` 覆盖本包支持的每一个版本。

⚠️ 无循环。`ProcessPrng` 要么填满整个缓冲区要么失败;不像 read 那样有短返回,
所以循环会是一个永远只跑一次的循环,并暗示一个本接口没有的部分状态。

── ⚠️ 导入库不存在,而本包自己生成它 ────────────────────

    lld: error: unable to find library -lbcryptprimitives

这套载荷里没有那个 `.a`。⭐ 而本包本来就用 `port/*.def` + `dlltool`
自己生成导入库 —— 那机制存在的理由正是「本包声明自己用到哪些 Win32 名字」。
加一份 `port/bcryptprimitives.def`(只导出 `ProcessPrng` 一个名字)
并接进 `build.mcpp`,是那套机制该有的用法而不是绕过。

`props = 0`:系统的生成器在进程运行前已播种,没有等待可报;
而种子是否来自硬件源不是这个后端能观察的。

实测:交叉构建产出 PE32+,导入表含 `bcryptprimitives.dll`,
**在 wine 里跑通** —— `std::random_device` 返回两个不同的值。
…host

⚠️ **一个在一台宿主上能链、另一台不能的后端,不是后端。**

`ProcessPrng` 先被选中(更少的活动部件,Chromium 与 Rust 用的也是它),
交叉构建通过、原生 Windows 失败:

    lld-link: error: undefined symbol: __declspec(dllimport) ProcessPrng

⭐ 真因是**本包只在交叉时生成自己的导入库** —— `build.mcpp` 在 Windows
宿主上立即返回,因为那里有真的 SDK。而两个工具链的 SDK 都不导出那个名字:
mingw 带 `libbcrypt.a`,不带 primitives。

改用 `BCryptGenRandom`,它在 `libbcrypt.a` 里、两侧都有。⭐ 句柄那个顾虑
由 `BCRYPT_USE_SYSTEM_PREFERRED_RNG` 消掉 —— 那个 flag 正是为「用系统自己的
生成器、传空句柄」而设,于是本接口仍然没有初始化顺序。

⚠️ 这是我在一台 Linux 宿主上看不见的一条,与本仓库 README 里那类
「一台宿主看不见」同族。

实测:wine 里 `std::random_device` 返回两个不同的值。
…t of this

⚠️ 我判断 `ProcessPrng` 不可用的依据是 `/usr/x86_64-w64-mingw32/lib` 里
没有它。**那个参照物是错的** —— mingw 不属于这套体系,它正是
`build.mcpp` 开头那段注释所说、这个包写出来就是为了不再依赖的东西:

> files that exist on a machine with mingw installed and nowhere else …
> a green that came from history the new machine does not have

本后端链接的要么是厂商 SDK(Windows 宿主),要么是本包从 `port/*.def`
自己生成的(交叉时),**从来不是第三方的**。

结论仍然成立,理由换成对的:Windows SDK 出 `bcrypt.lib` 而**不出**
`bcryptprimitives.dll` 的导入库 —— `ProcessPrng` 文档化了却没有 `.lib`。
`BCryptGenRandom` 由 `bcrypt.lib` 列出,两条路都能解析。
规范新增 `openkal.random`,版本升到 0.7.0。CI 的版本同步门要求实现与规范
同步声明 —— 它的诊断说得很准:「Nothing is wrong with either; they are not
in step.」
…il now

一致性矩阵的两个 Windows 格都失败:

    lld-link: error: undefined symbol: __declspec(dllimport) BCryptGenRandom

⚠️ 而链接行里**一个 `-l` 都没有** —— 不是库里没这个名字,是那段 `ldflags`
挂在 `cfg(all(windows, not(env = "msvc")))` 下,两格都被排除:
一格是 `msvc@system`,另一格 `llvm@20.1.7` 在 Windows 宿主上默认目标
就是 `windows-msvc`。

⭐ MSVC 那侧此前**不需要任何库列表** —— SDK 隐式链接常用的一套,写 `ldflags`
纯属噪声。`openkal.random` 改变了这一点:`bcrypt.lib` 不在两个工具链的
隐式集合里。两侧各写一次,因为它们对库的拼法不同、不共用列表。

⚠️ 我先前判断「Windows SDK 出 bcrypt.lib 所以能解析」——**那句是凭印象**,
与我几小时前查 mingw 目录犯的是同一个错。真正的判据是那个 job 的链接行,
而它一个 `-l` 都没有。
The MSVC conformance row still failed after the last commit named the
library, because it named it in the other side's spelling. `ldflags`
reaches the command line verbatim, and the two rows this predicate
selects do not drive the same program:

    LINK : warning LNK4044: unrecognized option '/lbcrypt'; ignored
    random.obj : error LNK2019: unresolved external symbol
                 __imp_BCryptGenRandom

clang drives lld-link and translates GNU spellings for it; `msvc@system`
drives LINK.EXE directly, and LINK reads `-` and `/` as the same option
prefix.

One spelling serves both. Measured, rather than assumed, before changing
the row that was already green:

    clang --target=x86_64-pc-windows-msvc -fuse-ld=lld -### t.c bcrypt.lib
        → 'bcrypt.lib'
    clang --target=x86_64-pc-windows-msvc -fuse-ld=lld -### t.c -lbcrypt
        → "bcrypt.lib"

The clang link line is byte-identical under both, so this cannot regress
the row it is not aimed at.
`src/win.cpp` records the four Win32 libraries this backend calls into
as linker directives in the object, under `#if defined(_MSC_VER)`, and
`mcpp.toml` says so four lines below the block I was editing. Two
manifest spellings were pushed before reading that, and neither could
have worked: `ldflags` reaches the command line verbatim, and the two
toolchains `env = "msvc"` selects reject each other's word for a
library.

    LINK.EXE      -lbcrypt   → LNK4044: unrecognized option '/lbcrypt'
    clang++       bcrypt.lib → error: no such file or directory

`cfg()` cannot separate them: its four keys name the target, and which
compiler drives the link is not a property of the target. The directive
mechanism needs no key, and both toolchains on that side read it.

    clang++ --target=x86_64-pc-windows-msvc -c
        → Directive(s): /DEFAULTLIB:bcrypt.lib
    clang++ --target=x86_64-w64-windows-gnu
        → _MSC_VER undefined, ignored; the GNU list in the manifest carries it

The pragma is in `src/random.cpp` rather than beside the other four
because a directive travels in the object that carries it, and the
object a linker pulls in for `kal_random_fill` is that one.
The branch carried 0.1.4, which is the version on `main` and the version
already in the index. Following openkal 0.7.0 changes what this package
declares, and on two of these repositories it also adds an interface, so
the content behind that number is no longer the content published under
it.

openkal takes a minor bump for a new interface and an implementation
following it takes a patch bump --- the shape of 0.5.2 → 0.6.0 with
0.5.2 → 0.5.3 beneath it.
@Sunrisepeak
Sunrisepeak merged commit 1c24825 into main Aug 24, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant