Blockstream / Blockstream/Jade
REPRODUCIBLE.MD issues/comments
- Dominant language
- C
- Stars
- 496
- Forks
- 127
- PR merge metrics
- No merged PRs in 30d
Description
I was able to successfully compile the firmware and verify the release but discovered some issues along the way. I documented the steps I took below (highlighting the differences from the instructions in bold) as it may help others:
## Compile and Compare Instructions
Initial instructions are here: https://github.com/Blockstream/Jade/blob/master/REPRODUCIBLE.md
Below assumes docker is installed and user added to docker group (so "sudo docker" is not needed)
# Compile the firmware from the source
1. Clone Jade master repository here: https://github.com/Blockstream/Jade/tree/master
```
cd
git clone https://github.com/Blockstream/Jade.git
```
2. Checkout release tag to be verified (https://github.com/Blockstream/Jade/tags)
```
cd Jade
git checkout 1.0.40
```
3. Pull in missing dependances (**change from instructions**)
```
git submodule update --init --recursive
```
4. Create docker image
```
DOCKER_BUILDKIT=1 docker build -f ./Dockerfile -t jade_builder .
```
5. Run docker image (**added rm option from instructions to delete container when done**)
```
docker run --rm -v ${PWD}:/builds/blockstream/jade --name jade_builder -it jade_builder bash
```
6. Prepare the environment inside docker container
(**Note command ". /root/esp/esp-idf/export.sh" no longer works but is not needed**)
```
cd /builds/blockstream/jade
git config --global --add safe.directory /builds/blockstream/jade
```
7. Confirm "git describe" now works
```
git describe
```
```console
1.0.40
```
8. Generate config file for hardware / build type. From instructions:
| Jade Hardware Type | Configuration | Command |
| --------------------------- | ------------- | ------------------------------------------|
| Jade 1.0 (true wheel) | BLE-enabled | ./tools/switch_to.sh jade |
| | no-radio | ./tools/switch_to.sh jade --noradio |
| Jade 1.1 (rocker/jog-wheel) | BLE-enabled | ./tools/switch_to.sh jade_v1_1 |
| | no-radio | ./tools/switch_to.sh jade_v1_1 --noradio |
| Jade 2.0 (two buttons) | BLE-enabled | ./tools/switch_to.sh jade_v2 |
| | no-radio | ./tools/switch_to.sh jade_v2 --noradio |
For example, execute:
```
./tools/switch_to.sh jade_v2
```
9. Build firmware (target will be here: ./build/jade.bin)
```
idf.py fullclean all
```
10. Sign target and exit container (**note signin key filename change from instructions**)
```
espsecure.py sign_data --keyfile ./release/scripts/dev_fw_signing_key_A.pem --version 2 --output ./build/jade_signed.bin ./build/jade.bin
exit
```
11. Compare signed and unsigned to understand signing block location
```
cd
xxd ./Jade/build/jade.bin ./jade.xxd
xxd ./Jade/build/jade_signed.bin ./jade_signed.xxd
diff -C 0 jade.xxd jade_signed.xxd
```
Diff shows only difference is added data end of file
Output snippet example:
```console
*** jade.xxd 2026-08-17 10:03:54.425821995 -0500
--- jade_signed.xxd 2026-08-17 10:04:02.499384205 -0500
***************
*** 81920 ****
--- 81921,82176 ----
+ 00140000: e702 0000 0869 ac1f 08c1 b344 9ae3 b1f3 .....i.....D....
```
Note location of new data (e.g. lines 81921 to 82176 for above example).
# Download official firmware to check vs compiled code.
12. Get expected hashes from offical json
Use from HW table in instructions and note hw-target value
| Jade Hardware Type | flag |
| ---------------------------------- | -------------------- |
| Jade 1.0 (true wheel) | --hw-target jade |
| Jade 1.1 (rocker/jog-wheel) | --hw-target jade1.1 |
| Jade 2.0 (two buttons) | --hw-target jade2.0 |
| Jade 2.0c (2.0, no camera/battery) | --hw-target jade2.0c |
Display stable versions available and checksums (note URL has hw-target). For example:
```
curl https://jadefw.blockstream.com/bin/jade2.0/index.json | jq ".stable"
```
Copy built version info desired (e.g. jade2.0 above was the following for latest ble stable):
```
{
"filename": "1.0.40_ble_1314816_fw.bin",
"version": "1.0.40",
"config": "ble",
"fwsize": 1314816,
"cmphash": "6623dadf8090b3debc9e47902ab8d927109ccfa58662f7d5e6bde4b46fb8e64e",
"fwhash": "6c1a0f4e932bfb05b8876bb3e6a4a541b55377db75453999b346d6dad1bcfff9"
}
```
13. Download firmware
Two options to download the firmware:
* Option 1: Download firmware directly from server using the above file name in step 12 (note hw-target is in URL)
```
curl -O https://jadefw.blockstream.com/bin/jade2.0/1.0.40_ble_1314816_fw.bin
```
* Option 2: Download firmware using jade\_ota.py per instructions (**Note latest jade_ota.py does not work**)
Use 1.0.36 version of jade\_ota.py to download firmware:
```
cd Jade
git checkout 1.0.36
docker run --rm -v ${PWD}:/builds/blockstream/jade --name jade_builder -it jade_builder bash
```
Run jade\_ota.py (Note hw-target as described above in step 12):
```
cd /builds/blockstream/jade
python ./jade_ota.py --skipserial --skipble --write-compressed --download-firmware --release stable --hw-target jade2.0
```
Output:
```console
The fw file will be downloaded/verified but the actual OTA will be skipped
Downloading firmware index file https://jadefw.blockstream.com/bin/jade2.0/index.json
Full firmwares
1) 1.0.40 - noradio
2) 1.0.40 - ble
-
Delta patches
-
Select firmware: 2
Downloading firmware https://jadefw.blockstream.com/bin/jade2.0/1.0.40_ble_1314816_fw.bin
Downloaded 892251 byte firmware
Downloaded file hash verified
Written file build/1.0.40_ble_1314816_fw.bin
Written file build/1.0.40_ble_1314816_fw.bin.hash
Got fw file of length 892251 with expected uncompressed final fw length 1314816
Final fw hash: 6c1a0f4e932bfb05b8876bb3e6a4a541b55377db75453999b346d6dad1bcfff9
```
Exit docker container:
```
exit
```
Copy firmware into home directory:
```
cd
cp ./Jade/build/1.0.40_ble_1314816_fw.bin .
```
* After either Option 1 or Option 2, continue to the next step
14. Compute compressed fm hash:
```
sha256sum 1.0.40_ble_1314816_fw.bin
```
```console
6623dadf8090b3debc9e47902ab8d927109ccfa58662f7d5e6bde4b46fb8e64e 1.0.40_ble_1314816_fw.bin
```
Compare output with cmphash downloaded above in step 12
15. Compute uncompressed hash
install pigz if needed per instructions
```
apt update && apt install pigz
```
Uncompress firmware
```
cp 1.0.40_ble_1314816_fw.bin downloaded.bin.gz
pigz -z -d downloaded.bin.gz
```
Compute uncompressed hash:
```
sha256sum downloaded.bin
```
```console
6c1a0f4e932bfb05b8876bb3e6a4a541b55377db75453999b346d6dad1bcfff9 downloaded.bin
```
Compare output with fwhash above in step 12
16. Compare signed downloaded with unsigned compiled
```
xxd downloaded.bin downloaded.xxd
diff -C 0 jade.xxd downloaded.xxd
```
Example output snippet:
```console
*** jade.xxd 2026-08-17 10:03:54.425821995 -0500
--- downloaded.xxd 2026-08-18 10:31:24.209831450 -0500
***************
*** 81920 ****
--- 81921,82176 ----
+ 00140000: e702 0000 0869 ac1f 08c1 b344 9ae3 b1f3 .....i.....D....
```
Diff shows new data at 81921 to 82176 (just like signed and unsigned diff above in step 11)
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.