少し前にBitcoin Core v0.21.0がリリースされたけど、このBitcoin CoreのリリースにはGitian Buildという決定性ビルドプロセスが使われている。
https://github.com/bitcoin/bitcoin/blob/master/doc/release-process.md
Gitian Buildとは?
公式サイトによると、複数のビルダーが、同一のバイナリを生成するビルドツールで、それぞれのビルダーが同じバイナリに署名し、バイナリが同じソースから生成されたもので改竄されていないことを保証する。
Gitian Builderとは?
Gitian Builderは、qemuベースのVMでソフトウェアをビルドする際に使用するツール。現在サポートされているVMは、
- KVM
- LXC
- Docker
- Virtual Box
の4つ。今回はDocker使ってみる。
Bitcoin Coreのビルド
先日リリースされたBitcoin Core v0.21.0をGitian Buildでビルドしてみよう。ビルド方法はこのドキュメントに記載されてる。
セットアップ
Bitcoin Coreには、gitian-build.pyという自動スクリプトが用意されているので、これを使う。
まず、スクリプトをコピー。
$ cp bitcoin/contrib/gitian-build.py .
続いて、セットアップを実行(-d
はdockerを使用するオプションで、-k
だとkvm、指定されてなかったらlxc)。
$ ./gitian-build.py -d --setup
すると、必要なソフトウェアがインストールされ、以下のリポジトリがcloneされる(最初にスクリプトをコピーしたのは、スクリプトのディレクトリにこれらがcloneされるから)。
自分のPGP鍵で署名するには、gitian.sigs
リポジトリをフォークして、リモートリポジトリとして登録する↓
$ export NAME = azuchi $ cd gitian.sigs $ git remote add $NAME git@github.com:$NAME/gitian.sigs.git
mac用のビルドへの署名用のセットアップ
mac用のビルドに署名する場合は、追加のセットアップが必要になる。まず、Appleのダウンロードページから*1、Xcode_11.3.1.xipをダウンロードする*2。Xcodeのバージョン7以降は、非macOSでSDKを展開するのが楽になるようXcode.appから.xipに変わったらしい。Ubuntuでは以下の方法で、Xcode.appを展開し、Xcode-11.3.1-11C505-extracted-SDK-with-libcxx-headers.tar.gz
を生成する(Xcode_11.3.1.xipは同じディレクトリに配置しとく)。
$ sudo apt-get install cpio $ git clone https://github.com/bitcoin-core/apple-sdk-tools.git $ python3 apple-sdk-tools/extract_xcode.py -f Xcode_11.3.1.xip | cpio -d -i
↑が終わると、Xcode.appというディレクトリが作成されており、Xcodeのデータが展開されてる。ちなみにmacOSの場合は、xip -x Xcode_11.3.1.xip
を実行するだけ。
続いて、bitcoinのgen-sdk
スクリプトを使って、Xcode-11.3.1-11C505-extracted-SDK-with-libcxx-headers.tar.gz
を生成する。
$ ./bitcoin/contrib/macdeploy/gen-sdk 'Xcode.appのパス'
実行ディレクトリに↑のファイルが生成されるので、それをgitian-builder/inputs
に配置する。
$ mkdir -p gitian-builder/inputs $ cp Xcode-11.3.1-11C505-extracted-SDK-with-libcxx-headers.tar.gz gitian-builder/inputs
ビルド
Bitcoin Core 0.21.0をビルドするためには↓を実行する。
$ export VERSION=0.21.0 $ ./gitian-build.py -j 3 -m 5000 -d --detach-sign --no-commit -b $NAME $VERSION
各オプションは:
-j
オプションはVMに割り当てるコア数+1。-m
はVMに割り当てたRAMより少し小さい値(MB単位)で、-j
と合わせてビルドの高速化のためのオプション。--detach-sign
は、デタッチ署名のアサートファイルを作成し、何もコミットしないオプション。--no-commit
は、gitに何もコミットしないオプション。-b
は、Gitian Buildを行う指示。
ちなみにこの実行にはマシンスペックにもよるけどかなり時間かかる。実行が終わるとbitcoin-binaries/0.21.0
にLinux、macOS、Windows用の各バイナリが生成されている。
$ ls bitcoin-binaries/0.21.0 bitcoin-0.21.0-aarch64-linux-gnu-debug.tar.gz bitcoin-0.21.0-riscv64-linux-gnu.tar.gz bitcoin-0.21.0-aarch64-linux-gnu.tar.gz bitcoin-0.21.0-win64-debug.zip bitcoin-0.21.0-arm-linux-gnueabihf-debug.tar.gz bitcoin-0.21.0-win64-setup-unsigned.exe bitcoin-0.21.0-arm-linux-gnueabihf.tar.gz bitcoin-0.21.0-win64.zip bitcoin-0.21.0-osx-unsigned.dmg bitcoin-0.21.0-x86_64-linux-gnu-debug.tar.gz bitcoin-0.21.0-osx64.tar.gz bitcoin-0.21.0-x86_64-linux-gnu.tar.gz bitcoin-0.21.0-riscv64-linux-gnu-debug.tar.gz bitcoin-0.21.0.tar.gz
実行中のログにも表示されるが、これらのバイナリのハッシュ値は、公開されているBitcoin Coreのダウンロードサイトに記載されているハッシュ値と等しい。
そして、gitian.sigs/
に以下の3つのassertファイルが生成されてる。
0.21.0-linux/azuchi/bitcoin-core-linux-0.21-build.assert
0.21.0-osx-unsigned/azuchi/bitcoin-core-osx-0.21-build.assert
0.21.0-win-unsigned/azuchi/bitcoin-core-win-0.21-build.assert
以下のコマンドでこれらに署名する。
$ gpg --output ${VERSION}-linux/${NAME}/bitcoin-core-linux-${VERSION%\.*}-build.assert.sig --detach-sign ${VERSION}-linux/$NAME/bitcoin-core-linux-${VERSION%\.*}-build.assert $ gpg --output ${VERSION}-osx-unsigned/$NAME/bitcoin-core-osx-${VERSION%\.*}-build.assert.sig --detach-sign ${VERSION}-osx-unsigned/$NAME/bitcoin-core-osx-${VERSION%\.*}-build.assert $ gpg --output ${VERSION}-win-unsigned/$NAME/bitcoin-core-win-${VERSION%\.*}-build.assert.sig --detach-sign ${VERSION}-win-unsigned/$NAME/bitcoin-core-win-${VERSION%\.*}-build.assert
すろと、以下の3つの署名ファイルが生成される。
0.21.0-linux/azuchi/bitcoin-core-linux-0.21-build.assert.sig
0.21.0-osx-unsigned/azuchi/bitcoin-core-osx-0.21-build.assert.sig
0.21.0-win-unsigned/azuchi/bitcoin-core-win-0.21-build.assert.sig
各OS毎の.assert
ファイルと.assert.sig
ファイルをコミットし、bitcoin-core/gitian.sigsリポジトリにPRを送ると。
$ git checkout -b ${VERSION}-not-codesigned $ git commit -S -a -m "Add $NAME $VERSION non-code signed signatures" $ git push --set-upstream $NAME $VERSION-not-codesigned
そしてコード署名者のみ、Windows/macOSのdetached signaturesを作成する。コード署名をするのは1人のみで、Windows/macOSのビルドがそれぞれ3つの一致する署名がある場合のみ、それぞれのリリース鍵で署名できる。
コード署名者以外は、Windows/macOSのdetached signaturesが作られるのを待つ。detached signaturesは、bitcoin-detached-sigsリポジトリにコミットされるらしいが、リポジトリ見る限り0.11.0以降はコミットされてないっぽい(プロセスが変わってる?)。
その後、署名されたWindows/macOS用のバイナリを作成する。さらに各ビルダーは署名されたバイナリへの署名を作成する。この署名がgitian.sigsリポジトリの${VERSION}-osx-signed/"${SIGNER}"
と${VERSION}-win-signed/"${SIGNER}"
にコミットされる。
そして最後に、ビルドされた成果物に対して、SHA256SUMS.asc
が生成され、それにGPG署名される。