Reproducible build
We want to invite the wider community to participate in the verification of the firmware built by Trezor Company. With reasonable effort you should be able to build the firmware and verify that it's identical to the official firmware.
Trezor Firmware uses Nix, Poetry and Cargo to make the build environment deterministic. We also provide a Docker-based script so that the build can be performed with a single command on usual x86 Linux system.
Building
First you need to determine which version tag you want to build:
- for Trezor One it is
legacy/vX.Y.Z
, e.g.legacy/v1.10.3
, - for newer models, it is
core/vX.Y.Z
, e.g.core/v2.4.2
.
Assuming you want to build core/v2.8.3
:
- install Docker
- clone the firmware repository:
git clone https://github.com/trezor/trezor-firmware.git
- go into the firmware directory:
cd trezor-firmware
- checkout the version tag:
git checkout core/v2.8.3
- run:
bash build-docker.sh core/v2.8.3
After the build finishes the firmware images are located in:
build/legacy/firmware/firmware.bin
andbuild/legacy-bitcoinonly/firmware/firmware.bin
for Trezor One,build/core-<model>/firmware/firmware.bin
andbuild/core-<model>-bitcoinonly/firmware/firmware.bin
for later models.
Model identifiers
You can speed up the build process by adding options to the script:
--skip-core
if you are only building for Trezor One,--skip-legacy --models=A,B,C
to only build for specific model(s) which are not Trezor One.
The following models are supported:
T
- Trezor Model TR
- Trezor Safe 3 rev.AT3B1
- Trezor Safe 3 rev.BT3T1
- Trezor Safe 5
Examples:
bash build-docker.sh --skip-core legacy/v1.10.3 # build only for Trezor One
bash build-docker.sh --skip-legacy --models=T3T1 core/v2.8.3 # build only for Trezor Safe 5
Verifying
The result won't be bit-by-bit identical with the official images because the official images are signed while local builds aren't.
Trezor T and the Safe family
You can use trezorctl
to download the official firmware image for your device:
trezorctl firmware download --model t3t1 --version 2.8.3
Or locate the firmware image in the Trezor Data repository.
The firmware binary starts with a vendor header whose size is:
- Model T: 4608 bytes
- Safe 3: 512 bytes
- Safe 5: 1024 bytes
The vendor header is followed by a firmware header
that contains a 65-byte signature at offset 0x3bf
(959 in decimal).
You will need to calculate the right offset for the signature based on the model:
- Model T: 4608 + 959 = 5567
- Safe 3: 512 + 959 = 1471
- Safe 5: 1024 + 959 = 1983
Zero out the signature data to obtain an image identical to the one built locally:
OFFSET=<your offset here>
# the following line removes 65 bytes of signature data from the official firmware
dd if=/dev/zero of=trezor-t3t1-2.8.3.bin bs=1 seek=$OFFSET count=65 conv=notrunc
# the following two lines print out the hashes of the firmwares
sha256sum trezor-t3t1-2.8.3.bin
sha256sum build/core-T3T1/firmware/firmware.bin
Trezor One
You can use trezorctl
to download the official firmware image for your device:
trezorctl firmware download --model 1 --version 1.10.3
Or locate the firmware image in the Trezor Data repository.
Official Trezor One firmware older than 1.12 starts with 256-byte legacy header used for compatibility with old bootloaders. Locally built firmware doesn't have this header.
# strip legacy header
tail -c +257 trezor-1.10.3.bin > trezor-1.10.3-nolegacyhdr.bin
The v2 header has 3x65 bytes of signature data at offset 0x220. Overwrite by zeros to obtain image identical to the one built locally.
dd if=/dev/zero of=trezor-1.10.3-nolegacyhdr.bin bs=1 seek=544 count=195 conv=notrunc
sha256sum trezor-1.10.3-nolegacyhdr.bin
sha256sum build/legacy/firmware/firmware.bin
Note: Fingerprints displayed for T1 at the end of build-docker.sh
do not match fingerprints of
official firmware due to the legacy header.
Note: T1 firmware built this way won't boot because unsigned firmware needs to be built with
PRODUCTION=0
.