The following assumes the jade repo is cloned, checked-out to the appropriate release tag, and all submodules updated.
To initalize and update submodules, run the following:
git submodule init git submodule update
NOTE: DO NOT TRY TO FLASH OR OTA THESE BUILD ARTIFACTS ONTO A JADE OR ANY OTHER ESP32 HARDWARE.
They contain settings to encrypt the flash and to enable 'secure boot' - this burns 'efuses' on the device - a one-way operation, and may render the device unusable.
As the built firmware does not include the Blockstream signature, the fw will not run on an official Blockstream Jade device.
The purpose of these builds is purely to reproduce the build and hence verify the firmware offered by Blockstream is indeed built from the publicly available tagged source code.
- Create Docker image
Use Dockerfile
to create a docker image for building the Jade firmware - this builds/installs the required tools from their public repos on a Debian base - the resultant image should be the same as the one used to build the official firmware binaries.
(NOTE: Because the Dockerfile executes 'apt install' commands, the point versions of some tools may change, so the image may not be completely identical - but these differences should be minor and are not expected to affect the build result in most cases.)
DOCKER_BUILDKIT=1 docker build -f ./Dockerfile -t jade_builder .
- Run the container
docker run -v ${PWD}:/builds/blockstream/jade --name jade_builder -it jade_builder bash
NOTE: The path where the jade repo is mapped (/builds/blockstream/jade
) is encoded into the intermediate build files jade.map
and jade.elf
, and a hash of the ELF file is included in the final binary - so this path must be correct for the binaries to correctly reflect the Blockstream official build.
All following commands are to be run inside the 'jade_builder' docker container.
- Prepare the build environment
. /root/esp/esp-idf/export.sh
cd /builds/blockstream/jade
git config --global --add safe.directory /builds/blockstream/jade
Since the mounted source repository will have a different owner from the user running the shell in the container, git describe
(which is used internally in the build process to generate/include an application version tag) may fail. The git config
command above should address this and ensure the correct version tag is included in the firmware image being built.
- RE-RUN FROM HERE TO BUILD DIFFERENT CONFIGURATIONS
- Copy the relevant config file
Copy the relevant config file onto ./sdkconfig.defaults
. The production build configs are in the directory production
, as follows:
Jade Hardware Type | Configuration | sdkconfig.defaults source file |
---|---|---|
Jade 1.0 (true wheel) | BLE-enabled | ./production/sdkconfig_jade_prod.defaults |
no-radio | ./production/sdkconfig_jade_noradio_prod.defaults | |
Jade 1.1 (rocker/jog-wheel) | BLE-enabled | ./production/sdkconfig_jade_v1_1_prod.defaults |
no-radio | ./production/sdkconfig_jade_v1_1_noradio_prod.defaults |
eg:
cp ./production/sdkconfig_jade_prod.defaults sdkconfig.defaults
rm -f sdkconfig
NOTE: The rm -f sdkconfig
step is not necessary on a fresh/clean repo, but always best to ensure this file does not exist and is recreated from the sdkconfig.defaults
file. This is vital if the sdkconfig.defaults
file is changed (eg. to build another configuration).
- Build
idf.py fullclean all
This makes a fw file build/jade.bin
.
- Sign the binary with the 'dev' key
espsecure.py sign_data --keyfile ./release/scripts/dev_fw_signing_key.pem --version 2 --output ./build/jade_signed.bin ./build/jade.bin
- Compare signed and unsigned binaries
A diff of ./build/jade_signed.bin
against ./build/jade.bin
should just show extra padding and data suffixed to the binary - this is the signature block.
(A hex dump can be obtained using xxd
, which is perhaps easier to diff)
- Download the official Blockstream Jade firmware, suppliying the relevant
hw-target
flag:
Jade Hardware Type | --hw-target flag |
---|---|
Jade 1.0 (true wheel) | --hw-target jade |
Jade 1.1 (rocker/jog-wheel) | --hw-target jade1.1 |
eg:
pip install -r ./requirements.txt
python ./jade_ota.py --skipserial --skipble --write-compressed --download-firmware --release stable --hw-target jade
Select the full firmware image as appropriate (BLE-enabled or no-radio) - NOTE: ignore the 'deltas' at this time.
2) 0.1.33 - ble
This should write the compressed firmware image to the build/ directory, eg ./build/0.1.33_ble_1118208_fw.bin
A .hash
file may also be written. If so, this contains the hex hash of the firmware image when uncompresed.
NOTE: Ensure no Jade is connected, and that --skipserial --skipble
are definitely present on the command line - otherwise jade_ota.py
may attempt to upload the firmware onto the connected Jade!
NOTE: this initial step can be skipped if the downloaded firmware is already present, eg. from a prior run of jade_ota.py
or update_jade_fw.py
.
- Uncompress the downloaded firmware
apt update && apt install pigz
mv build/0.1.33_ble_1118208_fw.bin build/0.1.33_ble_1118208_fw.bin.gz && pigz -z -d build/0.1.33_ble_1118208_fw.bin.gz
This should write the uncompressed firmware to the build directory, eg: ./build/0.1.33_ble_1118208_fw.bin
NOTE: the sha25sum hash of this uncompressed file should match the value in the associated .hash file, if present.
- Compare
A diff of the uncompressed downloaded binary against the locally built ./build/jade.bin
should just show extra padding and data suffixed to the binary - this is the Blockstream signature block.
A diff of the uncompressed downloaded binary against ./build/jade_signed.bin
should just show differences in that trailing the signature block.
(A hex dump can be obtained using xxd
, which is perhaps easier to diff)
Since 0.1.33
it has been possible to update Jade firmware using binary deltas. In this case a 'diff' between the currently running firmware and the desired target firmware is uploaded and applied. These deltas are much smaller than a complete firmware image. Verifying these patches is straightforward assuming the relevant full firmware images have been verified as above, as the patch is simply a binary diff between two signed firmware images.
- Obtain signed/downloaded full firmware images
Take two signed firmware images provided by Blockstream, eg. 0.1.33_ble_1118208_fw.bin
and 0.1.34_ble_1118208_fw.bin
NOTE: it may be necessary to pass --release previous
when downloading the firmware, in order to access older versions.
- If necessary, verify these images
Verify these firmware images match the tagged source code using the steps described above.
- Create patches
Create the compressed binary diff patches between the two signed/downloaded firmware images
mkdir patches
./tools/mkpatch.py 0.1.33_ble_1118208_fw.bin 0.1.34_ble_1118208_fw.bin patches
This should create two patches for converting between these firmware images, one for each 'direction'.
NOTE: it may be necessary to compile the bsdiff
tool:
gcc -O2 -DBSDIFF_EXECUTABLE -o tools/bsdiff components/esp32_bsdiff/bsdiff.c
- Download the Blockstream provided patch
python ./jade_ota.py --skipserial --skipble --write-compressed --download-firmware --release stable --hw-target jade
Select the relevant delta/patch - eg:
6) 0.1.34 - ble FROM 0.1.33 - ble
- Compare
The dowloaded patch file and the patch created locally ought to be identical.
This can be verified with diff
, or better still with sha256sum
- the hashes of the files should be identical.