Skip to content

[Reproducible Builds] 4 small CI changes would make the Linux AppImage verifiable (SOURCE_DATE_EPOCH, QML mtimes, tool pinning, LWK determinism) #187

Description

@xrviv

Summary

We (WalletScrutiny) rebuilt the green_qt 3.4.0 x86_64 AppImage from source in a CI-equivalent container and got remarkably close to the official artifact: the main blockstream binary is size-identical with zero differing bytes in .text, and every Qt 6.11 library, all GDK output, QML resources, and assets are byte-identical. Green desktop is, in substance, nearly reproducible today — the remaining differences are all environmental, and each has a concrete, low-cost fix in CI:

# Remaining diff Cause Fix
1 OpenSSL built on: string in blockstream OpenSSL embeds build time; CI doesn't set SOURCE_DATE_EPOCH export SOURCE_DATE_EPOCH (e.g. the tag's commit timestamp) in the release pipeline — OpenSSL honors it
2 ~3.2 KB of .rodata in blockstream qmlcachegen embeds each QML file's mtime (QV4::CompiledData sourceTimeStamp); git sets mtimes to CI checkout time normalize source mtimes before build (e.g. git ls-files -z | xargs -0 touch -d @$SOURCE_DATE_EPOCH)
3 AppImage plugin set + AppRun linuxdeploy/linuxdeploy-plugin-qt/appimagetool fetched from floating continuous tags pin tool releases (and checksums) in CI
4 usr/lib/liblwk.so (~2.5 MB unstripped) LWK release builds are nondeterministic (ThinLTO .llvm.<hash> symbol churn) — reproduces with two identical consecutive builds separate issue filed: Blockstream/lwk#165

With 1–4 addressed, the AppImage is plausibly byte-for-byte reproducible — the closest of any desktop wallet we have verified.

What we verified (evidence)

  • Official Blockstream_Green_x86_64.AppImage 3.4.0, SHA256 0d5ae746f85c... (matches signed SHA256SUMS).
  • Rebuild: green_qt at 88056710, GDK 0.77.4 @ 2b43409a, Rust 1.85.0, LWK @ bdbf0904, Qt 6.11.0, jammy-based container.
  • Result: 18 payload diff lines total.
  • blockstream: 41,703,528 bytes both; cmp -l clusters mapped with readelf -SW: zero diffs in .text; the 6 .rodata clusters decode as millisecond Unix timestamps inside QML compilation-unit metadata (official: 0x019E8770BAC5 = 2026-06-02 08:29 UTC — your CI's checkout moment; ours: our build moment); plus exactly one differing string: OpenSSL built on: Mon Jun 1 18:35:53 2026 UTC.
  • Qt/GDK/QML/resources: byte-identical.
  • Packaging: official bundles networkinformation/ plugins + glib chain + libQt6ShaderTools.so.6; ours has apprun-hooks/; AppRun differs — consistent with different continuous snapshots of the AppImage tools.
  • Minor: blockstream.desktop / linux_production.png are mode 666 in the official AppImage (CI umask), and libsystemd/libudev show jammy package drift between image dates.

Why it's worth it

Users (and verifiers like us) can then confirm that the shipped binary corresponds exactly to the public source — for a wallet, that's a meaningful trust upgrade, and green_qt is unusually close already. We're happy to share our full rebuild scripts, diff analysis, and to re-verify once any subset of the changes lands.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions