Wallet Logo

Zeus: Bitcoin/Lightning Wallet

latest release: 0.5.2 ( 13th July 2021 ) last analysed  7th April 2021 Not reproducible from source provided 
3.6 ★★★★★
34 ratings
1 thousand
7th July 2020

Jump to verdict 

Help spread awareness for build reproducibility

Please help us spread the word, asking Zeus: Bitcoin/Lightning Wallet to support reproducible builds  via their Twitter!

Do your own research!

Try out searching for "lost bitcoins", "stole my money" or "scammers" together with the wallet's name, even if you think the wallet is generally trustworthy. For all the bigger wallets you will find accusations. Make sure you understand why they were made and if you are comfortable with the provider's reaction.

If you find something we should include, you can create an issue or edit this analysis yourself and create a merge request for your changes.

The Analysis 

This app is a bit special as it does not hold your private keys but neither is it custodial. It remote-controls your lightning node that you can run for example at home. So it is a wallet in that you can use it to send and receive Bitcoins.

And … best of all:

Furthermore our builds have no proprietary dependencies, are reproducible, and are distributed on F-Droid.

they claim to have reproducible builds! Being on F-Droid this is highly likely to be reproducible for us, too. Let’s see how it goes:

On the repository there is no special mention of reproducible builds. Only that the Play Store release is built from the play-releases branch.

In that play-releases branch there is no special mention on reproducibility neither. The build instructions end in:

npm i
react-native run-android

but react-native run-android is not a command to create the apk. It’s to install the app on a connected device. We’ll go with

cd android
./gradlew assembleRelease

instead.

Also we will need version 0.5.1 which is the latest version we got from the Play Store. (The following is the pruned version after some detours.)

$ git clone https://github.com/ZeusLN/zeus
$ cd zeus/
$ git tag | grep 0.5.1
v0.5.1
$ git checkout v0.5.1 
$ docker run -it --volume $PWD:/mnt --workdir /mnt --rm beevelop/cordova bash
root@b5e24bbdc208:/mnt# npm install  
root@b5e24bbdc208:/mnt# npm install stream
root@b5e24bbdc208:/mnt# yes | $ANDROID_HOME/tools/bin/sdkmanager "platforms;android-28"
root@c6e507f0b5dc:/mnt# npx react-native run-android
root@b5e24bbdc208:/mnt# cd android
root@c6e507f0b5dc:/mnt/android# echo -e "\nMYAPP_RELEASE_KEY_ALIAS=a\nMYAPP_RELEASE_KEY_PASSWORD=aaaaaa\nMYAPP_RELEASE_STORE_PASSWORD=aaaaaa\nMYAPP_RELEASE_STORE_FILE=../dummy.keystore"  >> gradle.properties
root@c6e507f0b5dc:/mnt# keytool -genkey -v -keystore dummy.keystore -alias a -keyalg RSA -keysize 2048 -validity 10

(entering password aaaaaa and all the rest defaults.)

root@b5e24bbdc208:/mnt/android# ./gradlew assembleRelease
BUILD SUCCESSFUL in 40s
564 actionable tasks: 279 executed, 285 up-to-date
root@c6e507f0b5dc:/mnt/android# ls -alh app/build/outputs/apk/release/
total 126M
drwxr-xr-x 2 root root 4.0K Apr  8 04:28 .
drwxr-xr-x 4 root root 4.0K Apr  8 04:28 ..
-rw-r--r-- 1 root root  18M Apr  8 04:28 app-arm64-v8a-release.apk
-rw-r--r-- 1 root root  17M Apr  8 04:28 app-armeabi-v7a-release.apk
-rw-r--r-- 1 root root  55M Apr  8 04:28 app-universal-release.apk
-rw-r--r-- 1 root root  19M Apr  8 04:28 app-x86-release.apk
-rw-r--r-- 1 root root  19M Apr  8 04:28 app-x86_64-release.apk
-rw-r--r-- 1 root root 1.7K Apr  8 04:28 output.json
root@c6e507f0b5dc:/mnt/android# exit
$ apktool d -o fromGoogle Zeus\ 0.5.1\ \(app.zeusln.zeus\).apk 
$ apktool d -o fromBuild android/app/build/outputs/apk/release/app-universal-release.apk 
$ diff --brief --recursive from{Google,Build}
Files fromGoogle/AndroidManifest.xml and fromBuild/AndroidManifest.xml differ
Files fromGoogle/apktool.yml and fromBuild/apktool.yml differ
Files fromGoogle/assets/index.android.bundle and fromBuild/assets/index.android.bundle differ
Files fromGoogle/lib/arm64-v8a/libimagepipeline.so and fromBuild/lib/arm64-v8a/libimagepipeline.so differ
Files fromGoogle/lib/arm64-v8a/libnative-filters.so and fromBuild/lib/arm64-v8a/libnative-filters.so differ
Files fromGoogle/lib/arm64-v8a/libnative-imagetranscoder.so and fromBuild/lib/arm64-v8a/libnative-imagetranscoder.so differ
Files fromGoogle/lib/arm64-v8a/libsifir_android.so and fromBuild/lib/arm64-v8a/libsifir_android.so differ
Files fromGoogle/lib/arm64-v8a/libv8android.so and fromBuild/lib/arm64-v8a/libv8android.so differ
Files fromGoogle/lib/armeabi-v7a/libimagepipeline.so and fromBuild/lib/armeabi-v7a/libimagepipeline.so differ
Files fromGoogle/lib/armeabi-v7a/libnative-filters.so and fromBuild/lib/armeabi-v7a/libnative-filters.so differ
Files fromGoogle/lib/armeabi-v7a/libnative-imagetranscoder.so and fromBuild/lib/armeabi-v7a/libnative-imagetranscoder.so differ
Files fromGoogle/lib/armeabi-v7a/libsifir_android.so and fromBuild/lib/armeabi-v7a/libsifir_android.so differ
Files fromGoogle/lib/armeabi-v7a/libv8android.so and fromBuild/lib/armeabi-v7a/libv8android.so differ
Files fromGoogle/lib/x86/libimagepipeline.so and fromBuild/lib/x86/libimagepipeline.so differ
Files fromGoogle/lib/x86/libnative-filters.so and fromBuild/lib/x86/libnative-filters.so differ
Files fromGoogle/lib/x86/libnative-imagetranscoder.so and fromBuild/lib/x86/libnative-imagetranscoder.so differ
Files fromGoogle/lib/x86/libsifir_android.so and fromBuild/lib/x86/libsifir_android.so differ
Files fromGoogle/lib/x86/libv8android.so and fromBuild/lib/x86/libv8android.so differ
Files fromGoogle/lib/x86_64/libimagepipeline.so and fromBuild/lib/x86_64/libimagepipeline.so differ
Files fromGoogle/lib/x86_64/libnative-filters.so and fromBuild/lib/x86_64/libnative-filters.so differ
Files fromGoogle/lib/x86_64/libnative-imagetranscoder.so and fromBuild/lib/x86_64/libnative-imagetranscoder.so differ
Files fromGoogle/lib/x86_64/libsifir_android.so and fromBuild/lib/x86_64/libsifir_android.so differ
Files fromGoogle/lib/x86_64/libv8android.so and fromBuild/lib/x86_64/libv8android.so differ
Files fromGoogle/original/AndroidManifest.xml and fromBuild/original/AndroidManifest.xml differ
Only in fromBuild/original/META-INF: CERT.RSA
Only in fromBuild/original/META-INF: CERT.SF
Only in fromGoogle/original/META-INF: GOOGPLAY.RSA
Only in fromGoogle/original/META-INF: GOOGPLAY.SF
Files fromGoogle/original/META-INF/MANIFEST.MF and fromBuild/original/META-INF/MANIFEST.MF differ
Only in fromGoogle/res/raw: node_modules_browserifyaes_modes_list.json
Only in fromGoogle/res/raw: node_modules_browserifysign_browser_algorithms.json
Only in fromGoogle/res/raw: node_modules_browserifysign_browser_curves.json
Only in fromGoogle/res/raw: node_modules_diffiehellman_lib_primes.json
Files fromGoogle/res/raw/node_modules_elliptic_package.json and fromBuild/res/raw/node_modules_elliptic_package.json differ
Only in fromGoogle/res/raw: node_modules_parseasn1_aesid.json
Files fromGoogle/res/values/public.xml and fromBuild/res/values/public.xml differ

and that’s a lot of diffs in a lot of different files. The app cannot be reproduced from the existing source code given the not given build instructions(?). The app is not verifiable.

(lw)

Verdict Explained

We could not verify that the provided code matches the binary!

As part of our Methodology, we ask:

Is the published binary matching the published source code? If not, we tag it Unreproducible! 

Published code doesn’t help much if it is not what the published binary was built from. That is why we try to reproduce the binary. We

  1. obtain the binary from the provider
  2. compile the published source code using the published build instructions into a binary
  3. compare the two binaries
  4. we might spend some time working around issues that are easy to work around

If this fails, we might search if other revisions match or if we can deduct the source of the mismatch but generally consider it on the provider to provide the correct source code and build instructions to reproduce the build, so we usually open a ticket in their code repository.

In any case, the result is a discrepancy between the binary we can create and the binary we can find for download and any discrepancy might leak your backup to the server on purpose or by accident.

As we cannot verify that the source provided is the source the binary was compiled from, this category is only slightly better than closed source but for now we have hope projects come around and fix verifiability issues.

The product cannot be independently verified. If the provider puts your funds at risk on purpose or by accident, you will probably not know about the issue before people start losing money. If the provider is more criminally inclined he might have collected all the backups of all the wallets, ready to be emptied at the press of a button. The product might have a formidable track record but out of distress or change in management turns out to be evil from some point on, with nobody outside ever knowing before it is too late.