zig
zig copied to clipboard
A proposal to improve trust of blobs and precompiled packages
Right now, packages come with a signature. Which is great: no matter how and where the files are distributed, one can check that they match an actual package that was made by the official build pipeline.
That doesn't solve everything, though. The signature doesn't include any information about the source code and environment that were used in order to build the package. Andrew still has the ability to become super evil and ship packages that include a backdoor. Or, more realistically, the CI pipeline can still be compromised.
Similar concerns can be expressed about the WebAssembly blob used to bootstrap the compiler.
Fully reproducible builds are a prerequisite to solve this. But having them is not very useful in practice if they are not actually verified.
Minisign signatures authenticate the actual payload, but can also authenticate a "trusted comment". This is public information and is designed to describe what has been signed. It can't be altered without invalidating the signature,
By default, this is just the file name, but nothing prevents it from being a machine-parsable description of the exact environment (can be the hash of a public OCI image) that was used to produce the binary, including the git commit hash of the source code.
Just from a signature, it's then possible to rebuild the package (or the wasm file) and verify that we get exactly the same output.
Paranoid users can do it on their own system, distro package maintainers can do it as well. But ideally, it should benefit everyone, without much effort.
And that can be achieved by having multiple builders, operated by distinct entities, that don't collude.
When a new snapshot or release has to be built, the regular Zig CI pipeline kicks in, runs all the tests, publishes the result.
Independent builders detect the new packages (by polling and/or by getting a trigger from the Zig CI pipeline), verify the signature, and rebuild the code using the instructions included in the signature. Note that they don't have to run test suites, only to rebuild the wasm file or tarballs. The source code comes from GitHub, not from tarballs, so that the commit hash can be verified.
After a build has been successfully reproduced, builders sign the package with their own key, and send the signature to the Zig CI, that updates the public signature to adds the one that was just sent by a 3rd-party builder. The payload itself never changes.
At that point, a package available for download offers a signature file that describes how to rebuild the package, but also a set of signatures attesting that it was independently rebuilt by multiple non-colluding parties, from the same material. Having multiple signatures doesn't add much overhead. About 64 bytes per signature, including the public key identifier.
From here, a Zig tarball can be easily verified, using exactly the same minisign
command as today and just adding a parameter such as -Q 3
to check that the package was reproducibly built by at least 3 parties. Of course, trusting a single signature (and the one made by the official Zig pipeline will always be the first one) remains possible. We may also want to support the ability to require signatures from specific public keys, but that's just a CLI design issue.
We don't need a blockchain. We don't need a lot of builders. It's also fine if they fail to sign some builds, as long as the user-defined threshold is still met. But we need the set of builders not too change too frequently, so that distributing the set of public keys is not a hassle.
That scheme can also be smoothly integrated into transparency logs later. They solve a different issue (and are not enough on their own: when a malicious package is published into the log, it's already too late), but also need 3rd-party participants to work.