Reproducible Builds With Gitian (2/2)

Justin Moon

Posted on December 29, 2020

In the last article we explored the problem of reproducibility and the Gitian build environment Bitcoin Core uses to achieve it. We encoutered the gitian.sigs git repository, where anyone can upload signed claims about the correct hashs for different releases of the Bitcoin software. In this post you'll learn to verify your own Bitcoin software downloads against gitian.sigs and learn to submit your own claims. This is a nice way to get involved in Bitcoin Core development. You help increase overall confidence that the software is being built correctly, and familiarity with the command line is the only prerequisite knowledge.

Verify Bitcoin Software

As was the case in the SHA256SUMS.asc post, let's focus on a specific build of Bitcoin Core: bitcoin-0.20.1-aarch64-linux-gnu.tar.gz. Instead of comparing the hash of this file against SHA256SUMS.asc, let's instead compare against the .assert files submitted by everyone who executed the 0.20.1 Gitian build targeting Linux. Instead of trusting a website, we trust an army of paranoid independent volunteers. This is the way!

The Gitian build project requires a certain folder structure, let's make a new folder to contain everything. If you follow along to the end, you'll make a pull request to gitian.sigs. For this reason, you'll also want to fork gitian.sigs.

Click here for instructions on how to fork a GitHub repo if you've never done it before.

$ mkdir gitian-building
$ cd gitian-building
$ git clone <your gitian.sigs fork>

Now let's download bitcoin-0.20.1-aarch64-linux-gnu.tar.gz from bitcoincore.org and hash it:

$ curl -O https://bitcoincore.org/bin/bitcoin-core-0.20.1/bitcoin-0.20.1-aarch64-linux-gnu.tar.gz
$ sha256sum bitcoin-0.20.1-aarch64-linux-gnu.tar.gz
60c93e3462c303eb080be7cf623f1a7684b37fd47a018ad3848bc23e13c84e1c  bitcoin-0.20.1-aarch64-linux-gnu.tar.gz

Next we need to choose one of the Gitian signers for the 0.20.1 release. I'll choose luke-jr because his GPG key is all over the place.

Here's his .assert file for the 0.20.1 release. Note that line 4 contains exactly the same hash we produced above. To convince ourselves Luke authored this proof, we need to PGP-verify this .assert file:

# Download Luke's PGP pubkey
$ curl -O https://bitcoin.org/luke-jr.asc

# Import into gpg
$ gpg --import luke-jr.asc

# Signature verification
$ gpg --verify  gitian.sigs/0.20.1-linux/luke-jr/bitcoin-core-linux-0.20-build.assert.sig
gpg: assuming signed data in 'gitian.sigs/0.20.1-linux/luke-jr/bitcoin-core-linux-0.20-build.assert'
gpg: Signature made Sun 02 Aug 2020 11:02:03 AM CDT
gpg:                using RSA key E463A93F5F3117EEDE6C7316BD02942421F4889F
gpg: Good signature from "Luke Dashjr <luke@dashjr.org>" [unknown]
gpg:                 aka "Luke Dashjr <luke-jr@dashjr.org>" [unknown]
gpg:                 aka "Luke Dashjr <luke-jr+git@utopios.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: E463 A93F 5F31 17EE DE6C  7316 BD02 9424 21F4 889F

The signature is good, but once again we see a warning that Luke's key isn't "trusted" because we haven't marked this pubkey with a high degree of trust.

Before we try to verify the signatures of other Gitian builders, let's compare Luke's .assert with Jon Atack's. We'll use the Unix diff tool, which generates a report of differences between text files:

$ diff gitian.sigs/0.20.1-linux/luke-jr/bitcoin-core-linux-0.20-build.assert \
       gitian.sigs/0.20.1-linux/jonatack/bitcoin-core-linux-0.20-build.assert

Here's what I get. Lines starting with < lines mean luke-jr has that line but jonatack doesn't, and > means the opposite. The string bitcoin doesn't appear in the diff, but it is present in all filenames in out_manifest and in_manifest sections of each .assert file. This means there is no disagreement about inputs to the build -- source code or build instructions contained in Gitian descriptor -- or releases output by the build. All differences are in the base_system section which contains hashes of dependencies. Apparently this isn't a problem, but it is strange Gitian fails to exactly pin dependencies ...

At this point we could continue doing everything by hand and go searching for Jon Atack's PGP key. But doing so for every builder would be tedious. Luckily, regular Gitian builders add their PGP key fingerprints directly to the Bitcoin Core git repo here. Let's follow those instructions to import the PGP public keys for regular Gitian builders:

$ git clone git@github.com:bitcoin/bitcoin.git
$ pushd bitcoin/contrib/gitian-keys
$ while read fingerprint keyholder_name; do gpg --keyserver hkp://subset.pool.sks-keyservers.net --recv-keys ${fingerprint}; done < ./keys.txt
$ popd

pushd / popd are commands to enter and exit a directory back to where you were before. After this we should have PGP keys for many of the Gitian builders. For instance, we can now verify Jon Atack's .assert.sig files from earlier:

$ gpg --verify gitian.sigs/0.20.1-linux/jonatack/bitcoin-core-linux-0.20-build.assert.sig
...
gpg: Good signature from "Jon Atack <jon@atack.com>" [unknown]
...

Gitian's gverify script we encountered last time can automate this signature verification for us. Recall that gverify requires a path to a "Gitian descriptor" file. This is located in the bitcoin repo at the git tag v0.20.1:

$ git clone https://github.com/devrandom/gitian-builder.git
$ cd bitcoin
$ git checkout v0.20.1
$ cd ../gitian-builder
$ bin/gverify --destination ../gitian.sigs/ --release 0.20.1-linux ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
$ cd ..

For all signers contained in the keys.txt file from earlier you should see <username>: OK. For signers who weren't in that file, you should see:

gpg: Can't check signature: No public key
<username>: BAD SIGNATURE

Let's look at the gverify script to get a better idea what it's doing:

Become A Gitian Builder

You, too, can become a Gitian builder. There are a few quality guides available so I won't write a new one here:

I encourage you to try Jon's guide, now!

Commentary on Jon's Guide

So far with Gitian we've just been building and verifying for Linux to keep things simple. But Bitcoin Core also has MacOS and Windows releases. Both of these platforms have "code signing" systems that require developers to complete a non-PGP proprietary code signing process so that these operating systems will trust their apps. You've likely seen what happens when developers screw this up:

image

Individual Bitcoin Core developers control the keys for MacOS and Windows code signing. When a new release is tagged in git, they wait for a few people to upload matching builds to gitian.sigs. Then they create "detached signatures" like so which Gitian builders can utilize to produce final MacOS and Windows "code signed" releases. For each platform you end up with 5 builds: Linux, unsigned MacOS, code-signed MacOS, unsigned Windows, code-signed Windows. I believe the "unsigned MacOS/Windows" builds are inputs into the "detached signatures" process. Jon Attack's guide builds the unsigned releases here and the code-signed releases here

The MacOS Gitian build requires you extract files from SDKs published by Apple. Jon's guide downloads these extracted files (4th snippet here). The official guide shows you how to extract these yourself, which is tedious but increases the independence of your Gitian build.

Bitcoin Core has a gitian-build.py script which can build, sign and make commits to gitian.sigs for each of the 5 release targets. You need to copy it to your base folder containing the other repositories and run it so:

$ cp bitcoin/contrib/gitian-build.py .
$ ./gitian-build.py -b <username> <version, e.g. 0.20.1>

This script reduces the typing / copypasta required by Jon's guide, but when it fails you need to run the whole thing over again. Not sure if it helps or hurts.

Lastly, only make PRs to gitian.sigs if you have a PGP key you plan to take care of. Provide a way for other developers to download your PGP public key in your PR. For example, upload it to a key server and provide the 40-character fingerprint in your PR.

Conclusion

Now you have the tools to achieve a much higher degree of confidence in the Bitcoin software you use, and help others increase their confidence by contributing to gitian.sigs.

One last question: What are you trusting now? Where might the NSA hide their precious chain split bug? Stop and think about this for a moment.

...

Gitian uses Ubuntu to run the actual builds and downloads all dependencies from Ubuntu's package manager. We are trusting Ubuntu and its package ecosystem.

Due to concerns like this, Bitcoin Core is transitioning to a system called Guix which promises to deterministically build not just Bitcoin Core but the entire toolchain and environment used to build Bitcoin Core.

We'll discuss Guix next time.

Mooniversity Newsletter

Receive emails about new articles and courses