Blockstream / Blockstream/green_qt
[Reproducible Builds] 4 small CI changes would make the Linux AppImage verifiable (SOURCE_DATE_EPOCH, QML mtimes, tool pinning, LWK determinism)
- Dominant language
- C++
- Stars
- 262
- Forks
- 44
- PR merge metrics
- No merged PRs in 30d
Description
## 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.` symbol churn) — reproduces with two identical consecutive builds | separate issue filed: [Blockstream/lwk#165](https://github.com/Blockstream/lwk/issues/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.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.