尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Monero 可引导构建完全指南:基于 Guix 实现可审计、可复现的二进制构建

Monero 可引导构建完全指南:基于 Guix 实现可审计、可复现的二进制构建 区块链金融科技【免费下载链接】moneroMonero: the secure, private, untraceable cryptocurrency项目地址https://gitcode.com/gh_mirrors/mo/monero点击查看免费下载本文以 Monero 仓库contrib/guix目录下的官方文档为核心系统讲解如何借助 GNU Guix 这一函数式包管理器对 Monero 全平台二进制产物进行可引导Bootstrappable构建。你将掌握guix-build、guix-clean、guix-attest、guix-verify四个核心脚本的完整用法、全部可识别的环境变量、三种安全模型的选择方法以及构建产物签名认证与校验的完整流程从而在不盲信任何预编译二进制的前提下亲手复现出与官方一致的 Monero 发行包。什么是可引导Bootstrappable构建为什么 Monero 需要它传统的软件发布流程中用户要么直接下载官方预编译的二进制文件要么信任自己的发行版仓库。这两种方式都有一个共同的信任缺口工具链本身——编译器、链接器、标准库——是从哪里来的如果攻击者能够篡改某次工具链的二进制分发那么用这套工具链编译出的任何软件包括 Monero都可能被植入后门而审计者往往只会审查最终产物的源码不会回头核查工具链。contrib/guix/README.md开篇就给出了这一问题的答案可引导性Bootstrappability。它通过允许构建者审计并复现工具链而不是盲目信任二进制下载进一步强化了 Monero 的二进制安全保障。换句话说可引导构建把信任边界从某个服务器给的二进制推进到了我能自己从头构建出这个工具链。Monero 实现可引导构建的方式是使用Guix作为函数式包管理器。Guix 以内容寻址的方式管理软件包每个包由其全部依赖的哈希唯一确定构建过程在纯净、隔离的环境中执行因此同一输入必然产生逐字节一致的输出——这正是位级可复现bit-for-bit reproducible构建的基础。contrib/guix目录下与构建直接相关的文件包括guix-build主构建脚本负责在 Guix 容器中为各平台编译 Moneroguix-clean清理中间工作目录以释放磁盘空间guix-attest汇总构建产物哈希并生成 GPG 签名完成认证guix-verify校验其他签名者提交的认证是否与本地构建一致manifest.scm定义构建 Monero 所需的完整 Guix 包集合与交叉编译工具链libexec/prelude.bash 与 libexec/build.sh前者的公共前置逻辑环境检查、版本推导、时间机器调用后者的容器内实际构建脚本INSTALL.mdGuix 本身的安装与配置教程patches对 glibc、gcc、winpthreads 等工具链组件的修补用于保证可复现性与交叉编译正确性rustRust 依赖的 vendoring 方案cargo.scm、cargo.sh、config.toml。硬件与环境要求官方文档给出了保守的硬件预估。你需要一台x86_64架构的机器并且/gnu/store所在分区至少预留 16GB 空闲磁盘空间Guix 的所有构建产物都会进入这个存储目录每构建一个平台三元组platform triple额外需要 8GB 空闲空间。所谓平台三元组指的是形如x86_64-linux-gnu、aarch64-linux-gnu这样的目标平台标识。默认情况下 Monero 会一次性构建 8 个平台三元组见下文HOSTS环境变量因此全量构建的磁盘需求约为 16GB 8 × 8GB 80GB。如果磁盘或内存紧张可以通过HOSTS环境变量只构建自己需要的子集。Guix 的安装与初始化一次性工作Guix 的完整安装过程记录在 contrib/guix/INSTALL.md每台机器只需执行一次。官方文档提供三条安装路径信任模型与难度各不相同安装方式维护者难度特点官方 shell 安装脚本Guix 开发者最简单自动完成大部分配置适用于几乎所有 Linux 发行版只能装最新版纯二进制安装需要较高信任级别需以 root 运行运行前应审阅脚本内容官方二进制 tarballGuix 开发者普通需完整手动配置几乎适用于所有发行版可安装任意版本同样是二进制安装从源码构建你自己困难但值得可安装任意 commit粒度更细源码安装信任要求更低无论选择哪条路径有两个关键点需要注意/etc/profile.d集成二进制安装完成后为了让guix pull和guix install的成果进入$PATH、$INFOPATH、$XDG_DATA_DIRS等环境变量官方建议在/etc/profile.d/guix.sh中添加一条 profile 条目脚本内容详见 contrib/guix/INSTALL.md 的 Add an/etc/profile.dentry 一节。该配置要等下一次登录会话才生效。从源码构建的额外步骤如果选择源码安装还需要以root身份执行一次guix pull如sudo --login guix pull --branchversion-版本因为 Guix 的 init 脚本期望的guix-daemon路径需要由首次guix pull生成同时需要创建一个指向手工安装二进制的guix-daemon-original服务以 systemd 为例的完整命令见 INSTALL.md并在guix pull完成后切换回标准的guix-daemon服务。完成安装后可以用以下清单自检详见 INSTALL.md Checking everything/etc/profile.d/guix.sh存在且每次登录被加载guix describe能正确输出当前的 generation、commit 等信息而不是报failed to determine originguix-daemon正从${localstatedir}/guix/profiles/per-user/root/current-guix运行。一键构建guix-build 的完整执行流程在干净的仓库根目录下用默认选项构建 Monero 只需一条命令./contrib/guix/guix-build但这行命令背后是相当严谨的一整套流程。通过阅读 contrib/guix/guix-build 与 libexec/prelude.bash 的源码可以还原出它的完整执行链路前置工具检查脚本要求cat、env、git、realpath、mkdir、make、getent、curl、guix等命令可用且必须在仓库顶层目录执行脚本会用git root校验当前目录。拒绝GUIX_BUILD_OPTIONSGuix 自身识别一个名为GUIX_BUILD_OPTIONS的环境变量但它的取值会被追加到命令行选项之后并覆盖自定义参数体验不佳。因此脚本会直接报错引导用户改用ADDITIONAL_GUIX_COMMON_FLAGS或ADDITIONAL_GUIX_CMD_FLAGS。工作区健康检查自动执行git submodule update --init --recursive拉取子模块如果工作树有未提交改动dirty worktree脚本会中止构建可用FORCE_DIRTY_WORKTREE强制跳过。版本与目录推导通过git_head_version推导构建版本号并建立guix/guix-build-版本/下的output/、logs/、var/profiles等目录结构。daemon 与系统环境检查通过guix gc --list-failures验证能连接guix-daemon通过getent services http https ftp检查系统服务数据库/etc/services存在基本条目在 Docker 等精简镜像中常缺失Debian/Ubuntu 需安装netbaseArch 需安装iana-etc。Rust 依赖 vendoringMonero 的部分组件如fcmp_pp依赖 Rust 生态。脚本会先检查/gnu/store中是否存在固定哈希的 Rust 依赖归档rust_deps-版本.tar.gz不存在则通过 contrib/guix/rust/cargo.scm 定义的环境和 contrib/guix/rust/cargo.sh 脚本在容器中打包依赖并校验其哈希与RUST_DEPS_HASH严格一致防止供应链被篡改。depends 源码预下载因为构建容器没有网络脚本会先在宿主机上对每个平台执行make download-平台如download-linux、download-win、download-osx、download-android把依赖源码下载到SOURCES_PATH指定的缓存目录。在 Guix 容器中构建对HOSTS列表中的每个平台脚本通过guix time-machine shell启动一个--container --pure --no-cwd的隔离容器--container在隔离的命名空间中运行最小化机器间差异是可复现性的关键--pure清空宿主机环境变量避免外部变量渗入构建--no-cwd不把当前工作目录映射为容器内同路径同一路径本身就是不可复现来源而是通过--share$PWD/monero固定映射到/monero--share还将SOURCES_PATH依赖源码缓存、BASE_CACHE依赖构建缓存、DISTSRC_BASE、OUTDIR_BASE、LOGDIR_BASE挂载进容器并--exposeRust 依赖归档和 git 公共目录--writable-root允许修改容器根文件系统以便把 env 和 shell 符号链接到常规路径避免到处修改脚本 shebang--root为环境建立 GC root防止 Guix 垃圾回收误删最终在容器内执行bash contrib/guix/libexec/build.sh并把HOST、VERSION、JOBS、COMMIT_TIMESTAMP等作为环境变量传入。时间机器固定版本所有guix命令都通过 prelude.bash 中定义的time-machine()函数调用固定到 commit0c2eff26bdf0cb9b3300c7b4883a2e471757940d的 Guix 版本可通过GUIX_REPO环境变量覆盖仓库地址。这意味着即使多年后 Guix 上游发生了破坏性变更Monero 的构建依然能复现出与当年完全一致的包集合。构建产物与中间目录构建完成后产物会落在版本目录下以guix/guix-build-版本/为根output/平台三元组/最终的可分发产物源码归档、二进制 tarballlogs/平台三元组/每个平台的构建日志以及用于复现性调试的guix-env.txt容器内环境变量快照和guix-hashes.txt/gnu/store内容清单var/profiles/平台三元组/Guix 环境的 GC rootdepends/work、guix-build-*/distsrc-*depends 树与各平台的源码工作目录。清理中间工作目录guix-clean默认情况下guix-build会保留所有中间文件如depends/work、guix-build-*/distsrc-*方便用户调试但这些目录非常占磁盘。因此提供了 guix-clean 脚本./contrib/guix/guix-clean它的实现基于git clean -xdff但有两个贴心设计见源码读取每次构建时在var/precious_dirs中记录的珍贵目录SOURCES_PATH、BASE_CACHE、OUTDIR_BASE、LOGDIR_BASE、PROFILES_BASE用--exclude把它们排除在清理范围之外避免误删下载缓存和构建缓存默认先以--dry-run预览将删除的文件并要求输入y确认设置NO_CONFIRM1可跳过确认。支持的环境变量一览官方文档在Recognized environment variables一节中完整定义了以下变量prelude.bash 与 guix-build 的源码也一一印证环境变量作用默认值HOSTS以空格分隔的平台三元组列表决定为哪些平台构建x86_64-linux-gnu、aarch64-linux-gnu、riscv64-linux-gnu、x86_64-w64-mingw32、x86_64-unknown-freebsd、x86_64-apple-darwin、arm64-apple-darwin、aarch64-linux-androidSOURCES_PATHdepends 树的源码下载缓存目录跨多次构建共享可避免重复下载未设置BASE_CACHEdepends 树的已构建包缓存目录跨构建共享可避免重复编译未设置JOBS同时运行的作业数会传给guix--cores、make--jobs和xargs-P容器外nproc的值SOURCE_DATE_EPOCH用于位级复现的参考 UNIX 时间戳符合 reproducible-builds 的 source-date-epoch 标准git -c log.showSignaturefalse log --format%at -1的输出即最近一次提交的时间戳V非空时给所有make调用传V1输出详细日志注意任何值都被视为开启V空串与未设置等价V0与V1效果相同未设置SUBSTITUTE_URLS空格分隔的预编译包下载源列表仅当 URL 的签名密钥已授权时才会被使用未设置默认用官方构建农场ADDITIONAL_GUIX_COMMON_FLAGS追加到所有guix命令的额外参数空ADDITIONAL_GUIX_TIMEMACHINE_FLAGS追加给guix time-machine的额外参数空ADDITIONAL_GUIX_ENVIRONMENT_FLAGS追加给time-machine内部guix shell调用的额外参数空此外从脚本源码还能发现几个未写入文档表格但同样生效的变量GUIX_REPO覆盖 Guix 仓库地址、FORCE_VERSION强制指定构建版本、FORCE_DIRTY_WORKTREE允许脏工作树构建、DEPENDS_ONLY仅构建 depends、DRY_RUNCI 预热缓存的空跑模式、VERSION_BASE_DIR自定义版本目录根位置。两个缓存目录SOURCES_PATH与BASE_CACHE有明确限制指向的路径必须是真实目录不能是符号链接guix-build 源码中会专门检查-L并报错。常见构建调用模式与示例把缓存放到工作树之外如果你经常构建且有多个 worktree把 depends 的下载缓存和构建缓存放在 worktree 之外可以避免重复下载与重复编译env SOURCES_PATH$HOME/depends-SOURCES_PATH BASE_CACHE$HOME/depends-BASE_CACHE ./contrib/guix/guix-build只构建部分平台用空格分隔的HOSTS覆盖默认的 8 个平台列表例如只构建 Windows 和 macOS 版本env HOSTSx86_64-w64-mingw32 x86_64-apple-darwin ./contrib/guix/guix-build控制 Guix 构建线程数guix构建命令有两个容易混淆的线程控制参数--cores控制构建**单个 derivation可理解为单个包**使用的 CPU 核心数该值会作为--jobs传给make--max-jobs控制同时并行构建多少个 derivation默认值为 1。因此默认行为是一次只构建一个包用满$JOBS个线程。JOBS环境变量只修改--cores要修改--max-jobs需要通过ADDITIONAL_GUIX_COMMON_FLAGS。例如内存充裕的机器可以export ADDITIONAL_GUIX_COMMON_FLAGS--max-jobs8即最多同时构建 8 个包每个包使用$JOBS个线程。反之如果某个包在多线程下偶发构建失败可以单线程构建包、同时并行多个包export JOBS1 ADDITIONAL_GUIX_COMMON_FLAGS--max-jobs8选择你的安全模型无论 Guix 如何安装你都需要在构建前明确自己的安全模型。Guix 的价值在于可以用自己的 CPU 时间从零构建一切但它不剥夺用户的选择权用户完全可以决定是否使用substitutes预编译包。官方文档给出三种选项。选项一使用 substitutes预编译包第 1 步授权签名密钥。Guix 构建农场的密钥可能已经在你安装 Guix 时被授权官方 shell 安装脚本会询问Debian 包则在安装时授权。当前已授权密钥列表保存在/etc/guix/acl。仅含构建农场密钥的/etc/guix/acl形如(acl (entry (public-key (ecc (curve Ed25519) (q #8D156F295D24B0D9A86FA5741A840FF2D24F60F7B6C4134814AD55625971B394#) ) ) (tag (guix import) ) ) )若确认农场密钥未被授权以 root 执行guix archive --authorize /var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub如果该路径不存在改用guix archive --authorize PREFIX/share/guix/ci.guix.gnu.org.pub其中PREFIX通常是/usr发行版包安装或/usr/local从源码安装且未指定 prefix。移除已授权密钥直接编辑/etc/guix/acl删除对应的(entry (public-key ...))条目即可。第 2 步指定 substitute 服务器。密钥授权后官方构建农场会被自动使用除非传入--no-substitutes。默认服务器列表既可以在guix-daemon层面覆盖也可以在每次调用guix命令时覆盖通过SUBSTITUTE_URLS环境变量脚本会将其转为--substitute-urls。选项二临时禁用 substitutes如果本次构建不想用任何预编译包直接加--no-substitutes。首次构建会比较慢但产出的包会被缓存供后续构建复用。直接调用guix命令guix cmd --no-substitutes对contrib/guix下的脚本export ADDITIONAL_GUIX_COMMON_FLAGS--no-substitutes选项三默认禁用 substitutesguix-daemon自身接受--no-substitutes标志这样除非在命令行显式覆盖否则一律不使用预编译包。如果通过 init 脚本启动guix-daemon编辑该脚本加上此标志即可。认证构建产物guix-attest可复现构建的价值在于多方独立构建、互相印证。与 Gitian 时代把认证提交到gitian.sigs仓库类似Guix 时代的认证存放在独立的guix.sigs仓库每个签名者一个目录。克隆好该仓库后对当前工作树的 commit/tag 进行认证env GUIX_SIGS_REPOpath/to/guix.sigs SIGNERgpg-key-name ./contrib/guix/guix-attestguix-attest 的源码揭示了内部流程校验GUIX_SIGS_REPO是存在的目录、SIGNER指定的 GPG 私钥可用扫描LOGDIR_BASE下各平台构建日志目录中的SHA256SUMS.part片段将每个片段里的文件名统一替换为 basename因为不同平台产物路径前缀不同合并排序生成all.SHA256SUMS若all.SHA256SUMS已存在用diff严格比对内容不一致则报错并提示删除旧文件后重试用指定的 GPG 密钥对all.SHA256SUMS做分离式签名--detach-sign --digest-algo sha256 --armor输出all.SHA256SUMS.asc写入guix.sigs/版本/签名者/目录。SIGNER支持两种格式直接给 GPG 密钥名如SIGNERachow101或用密钥显示名覆盖签名目录名如SIGNER0x96AB007F1A7ED999dongcarl。如果只想生成哈希清单而不签名可加NO_SIGN1。更多细节可用./contrib/guix/guix-attest --help查看脚本内部的 usage 文本给出了全部示例。校验他人的认证guix-verify当至少一位其他签名者已把签名上传到 guix.sigs 仓库后你可以拉取其签名并与自己的构建结果比对git -C path/to/guix.sigs pull env GUIX_SIGS_REPOpath/to/guix.sigs ./contrib/guix/guix-verifyguix-verify 的逻辑很直接源码见文件本身先以 GPG 验证每个签名目录下all.SHA256SUMS.asc对all.SHA256SUMS的签名有效性再用diff将各签名者的清单与基准清单逐字节比对。基准默认取第一个找到的清单也可用SIGNERsigner指定以某位签名者的清单为基准。任一签名无效或清单不一致都会以非零状态退出。如果出现不一致首先要反思自己的构建是否完整例如只通过HOSTS构建了部分平台时guix-attest会明确提示你之前可能认证过一个部分构建此时应删除旧认证rm all.SHA256SUMS{,.asc}后重新执行。深入底层manifest.scm 与 build.sh 的可复现性设计交叉工具链的构造contrib/guix/manifest.scm 是构建环境的配方。它使用 Guix 的交叉编译基础设施为每个目标平台构造完整的交叉工具链其构造顺序源码中make-cross-toolchain的注释清晰可见为用基础 gcc 构建一个不带 libc 目标的交叉 gccxgcc-sans-libc用该 gcc 交叉编译内核头文件基于linux-libre-headers用不带 libc 的 gcc 和内核头文件交叉编译 libcglibc 等用交叉 libc 构建最终面向目标的交叉 gcc。针对特定平台的已知问题仓库提供了修补文件例如 patches/glibc-2.27-no-librt.patch、patches/glibc-2.27-riscv64-fix-incorrect-jal-with-HIDDEN_JUMPTARGET.patch、patches/gcc-remap-guix-store.patch、patches/winpthreads-remap-guix-store.patch后两者把工具链中硬编码的/gnu/store前缀重映射保证二进制可在不同 Guix 环境间复现。容器内构建脚本的复现性细节libexec/build.sh 在隔离容器内执行真正的构建其中有不少较真的细节开头的umask 0022保证所有产物权限一致Guix 会为自身包设置 umask但不会为guix shell设置因此脚本必须自行处理固定SOURCE_DATE_EPOCH1397818193用于 depends 构建使不涉及构建系统改动的 commit 之间哈希一致源码归档与二进制 tarball 则使用 commit 日期把/gnu/store内容清单guix-hashes.txt和容器内环境变量快照guix-env.txt过滤掉路径类变量写入日志目录为复现性问题的排查留下完整现场主动unset掉 Guix 自动设置但未必指向正确工具链的LIBRARY_PATH、CPATH、C_INCLUDE_PATH等变量再根据HOST平台darwin/mingw 用动态库路径其余平台追加静态库路径精确重建包含路径产物命名统一为monero-平台三元组-版本.tar.bz2对应DISTNAMEmonero-${HOST}-${VERSION}。常见故障排查contrib/guix/INSTALL.md 的 Troubleshooting 一节总结了源码构建 Guix 过程中最常见的坑这里摘录要点Derivation 构建失败当输出中出现一连串cannot build derivation ... failed时第一行 failed 才是根因后续都是连锁失败。多数情况是某个包如foo的测试在多线程下偶发失败。可单线程重建该 derivationguix build --cores1 /gnu/store/...-foo-3.6.12.drv按需追加--no-substitutes等参数。日志可用bzcat /var/log/guix/drvs/...-foo-3.6.12.drv.bz2 | less查看失败构建的目录保留在/tmp/guix-build-foo-3.6.12.drv-0。python(-minimal): [Errno 84] Invalid or incomplete multibyte or wide character$TMPDIR默认/tmp所在文件系统拒绝了非 UTF-8 字符典型场景是开启了utf8onlyon的 ZFS。openssl-1.1.1l/openssl-1.1.1n/GnuTLS test-suite FAIL这些包的测试用到了已过期的硬编码证书GnuTLS 的证书于 2020-10-24 过期。最省事的办法是安装更新版本的 Guix也可单独为该 derivation 使用 substituteguix build --substitute-urlshttps://ci.guix.gnu.org drv或临时把系统时间拨回 2020-10-01 再构建记得构建完恢复并重新开启 NTPsudo timedatectl set-ntp no sudo date --set 01 oct 2020 15:00:00 guix build /gnu/store/vhphki5sg9xkdhh2pbc8gi6vhpfzryf0-gnutls-3.6.12.drv sudo timedatectl set-ntp yescoreutils: FAIL: tests/tail-2/inotify-dir-recreateoverlayfsDocker 默认文件系统等远程文件系统被误判为本地导致 inotify 测试失败。解决办法是在/tmpguix-daemon构建位置挂载传统文件系统Docker 用户可用 volume、bind mount 或--tmpfs。清理与卸载 Guix如果 Guix 安装被不可逆地搞坏可以彻底清除后重装按安装方式卸载 Guix 本体如sudo apt purge guix或sudo make uninstall删除构建用户与组用getent passwd | grep guix、getent group | grep guix查询再sudo userdel/sudo groupdel删除所有 Guix 相关目录/var/guix/、/var/log/guix/、/gnu/、/etc/guix/以及各用户主目录下的.config/guix/、.cache/guix/、.guix-profile/。结语从信任下载到亲手复现Monero 的 Guix 构建体系把发布安全从信任某个官方二进制推进到任何人都能用固定版本的 Guix、从源码重建出逐字节一致的产物并与其他独立构建者的签名互相印证。这套体系的关键支柱可以概括为四点Guix 时间机器固定工具链版本、容器隔离与纯净环境保证复现、可审计的交叉工具链配方manifest.scm patches、guix-attest/guix-verify 的多方签名认证闭环。对于关注二进制供应链安全的开发者与审计者而言contrib/guix目录既是 Monero 的发布流水线也是一份值得逐行研读的可复现构建参考实现。赞分享区块链金融科技【免费下载链接】moneroMonero: the secure, private, untraceable cryptocurrency项目地址https://gitcode.com/gh_mirrors/mo/monero点击查看免费下载相关推荐Bitcoin Core 的 Guix 引导式构建指南可审计、可复现的多平台二进制构建与签名验证全流程Bitcoin Core 的 Guix 引导式构建指南可审计、可复现的多平台二进制构建与签名验证全流程 本文以 Bitcoin Core 仓库中 contri区块链金融科技网络密码学Android APK签名复制终极指南实现完全可重现构建Android APK签名复制终极指南实现完全可重现构建 在Android应用开发和安全审计过程中如何验证不同构建环境产生的APK文件是否完全相同apks开发工具构建工具供应链安全TensorRT Progress Monitor API 实战指南基于 sampleProgressMonitor 实现引擎构建进度可视化TensorRT Progress Monitor API 实战指南基于 sampleProgressMonitor 实现引擎构建进度可视化 本篇技术指南围绕人工智能推理引擎深度学习本地部署模型优化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表