可重现构建在已发布的源代码与发布的二进制文件之间建立了可验证的联系。我们当前的可重现构建覆盖范围适用于 Android F-Droid 版本。我们计划将该覆盖范围扩展到更多 Android 和 iOS 分发渠道。
Android
F-Droid
Gem Wallet 使用独立的 F-Droid 构建基础设施来重新构建 F-Droid APK,并在发布前对其进行验证。
验证模型
Gem Wallet 为每个版本发布经过签名的 F-Droid APK。与此同时,F-Droid 构建服务器在干净的环境中执行公开的构建配方:
- F-Droid 元数据指定确切的 Git 提交和 Android NDK 版本。
- F-Droid 从公开的 Gem Wallet 代码仓库检出该提交。
- 公开的可重现构建脚本安装锁定版本的原生工具链并运行
:app:assembleFdroidRelease。 - 构建生成未签名的 APK。F-Droid 下载对应的开发者签名 APK,并确认其签名证书指纹与
AllowedAPKSigningKeys中声明的一致。 - F-Droid 将 APK 签名复制到重新构建的产物上并进行验证。Android APK Signature Scheme v2/v3 签名覆盖签名块之外的完整 APK,因此验证成功的前提是重新构建的 APK 载荷必须与 Gem Wallet 发布版本逐字节一致。
- 只有在验证成功时,F-Droid 才会发布开发者签名的 APK。无法重现的版本不会被发布。
确定性构建控制
Gem Wallet 包含 Rust 原生库,这使得构建输出对编译器、链接器、NDK、宿主平台和优化器的差异非常敏感。F-Droid 构建通过以下方式控制这些输入:
- 在
android/reproducible/versions.sh中锁定 Rust 工具链和cargo-ndk的版本; - 使用
--locked安装cargo-ndk,而应用的 Rust 依赖则由已提交的Cargo.lock解析; - 在 Android 项目和 F-Droid 元数据中同时锁定确切的 Android NDK 修订版本;
- 在 Linux
x86_64主机上构建,并显式指定 NDK 链接器和归档器路径; - 将原生 APK 目标限制为
armeabi-v7a和arm64-v8a,与x86_64构建主机无关; - 使用专用的
fdroid产品渠道,不包含 Google 推送和评价模块; - 使用
-dontoptimize禁用 R8 优化,以避免非确定性的 DEX 输出和映射标识符; - 运行 Gradle 时不使用守护进程或配置缓存,并在发布构建前清除转换缓存。
确切的源代码提交、构建命令、输出路径、NDK 修订版本、上游 APK URL 和允许的签名证书都公开在 F-Droid 元数据中。用于配置 Rust、Cargo、NDK 工具链和 Gradle 的脚本与应用源代码一同维护在 android/reproducible 目录下。
安全属性与局限性
F-Droid 验证成功表明,Gem Wallet 发布的已签名 APK 可以从声明的源代码提交和构建配方中重现。重新构建在 Gem Wallet 基础设施之外进行,从而减少了对我们发布流水线作为单一信任点的依赖。
可重现性并不能证明源代码没有漏洞、每个依赖都值得信任,或所选的编译器工具链未被入侵。这些风险需要在可重现构建之外,通过源代码审查、依赖管控和工具链安全来应对。
构建状态和已验证的版本可在 Gem Wallet F-Droid 页面查看。
Universal APK 与 Google Play
Gem Wallet 的 Universal APK 和 Google Play 版本目前尚未纳入上述 F-Droid 验证。针对这些 Android 分发渠道的可重现构建支持已列入未来计划。
iOS
App Store 版本目前尚不可重现。针对 iOS 的可重现构建支持以及对 App Store 二进制文件的独立验证已列入未来计划。