Today we conclude chapter 9 about reproducible builds and Guix.
If you’re in Atlanta this week for Tabconf, come say hi!
The key is to make everything open source and everything a deterministic build. Every library, every printer driver, every compiler — everything. For Bitcoin Core to truly be a deterministic build, each of its dependencies needs to be a deterministic build, as does every tool that’s used to build it, including the compiler. Ideally the hardware is as well, but that’s a whole other can of worms.
This is where Guix enters the picture. This GNU project has been around for a decade, but a few years ago, Carl Dong from Chaincode Labs began work on replacing Gitian with Guix, which finally happened in Bitcoin Core version 22. This involved making changes on both the Bitcoin Core and the Guix side of things.
The ambition of Guix is roughly as follows (see also Carl Dong’s presentation): You start with a few hundred bytes of actual machine code. That’s the binary code that you must trust. Even binary code can be seen as source code. It’s simply a series of instructions for the CPU. And this particular machine code is well documented. From there on, all it does is read source code and compile it. But how do you do that when there isn’t a compiler?
Well, this first binary blob performs a bootstrap. It’s able to read some machine code that’s typed by a human, or entered some other way, and then run that program.
The first program you feed it is an extremely simple compiler. And once it has the rudimentary compiler, this new compiler reads another piece of source code, which then builds a slightly more complicated compiler. And then that slightly more complicated compiler builds another compiler. And this goes on for quite a while, until eventually, you have the modern C compiler that we all know and love, which is itself, of course, open source.
This compiler then builds a bunch of tools from source, ultimately producing a system very similar to Gitian — that is, a build system that avoids timestamps, doesn’t use anything else from your computer, etc. In principle, it could build an entire operating system. So then your virtual machine or your physical machine would be running an operating system that you’ve built from scratch. But in this case, it just builds the compiler tools, and once those compiled tools are there, it can just start building Bitcoin Core as it would otherwise do.
This solves two things. First, it has no untrusted dependencies, so it’s not using random libraries. And second, it’s always using the same versions of libraries, which means that everybody can produce the same result.
Note that Guix doesn’t solve the problem of dependencies entirely. It’s a significant improvement over Gitian, but it’s still critical to keep the number of dependencies small. Where Guix really shines is in mitigating the problem of trusting the build system.