feat: openkal.random on ProcessPrng - #8
Merged
Merged
Conversation
⭐ **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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
⭐ ProcessPrng 而不是 BCryptGenRandom,差别是一个句柄。 后者要算法句柄,本接口得每次打开或缓存它,而缓存意味着有了初始化顺序。ProcessPrng 是同一个生成器、没有句柄。Chromium 与 Rust 标准库都因此改用了它。
RtlGenRandom——未文档化、按序号导出、每个调用者自写声明。⭐ 本包本来就用
port/*.def+dlltool生成导入库,那机制的理由正是「本包声明自己用到哪些 Win32 名字」。加一份只导出ProcessPrng的 def 并接进build.mcpp,是该机制的正确用法。实测:PE32+ 产物导入表含
bcryptprimitives.dll,wine 里跑通,std::random_device返回两个不同值。依赖 mcpplibs/openkal#8。