Mycelium Bitcoin Wallet
Latest release: 3.16.0.13 ( 13th September 2022 ) π Last analysed 4th November 2022 . Not reproducible from source providedWe 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 the answer is "no", we mark it as "Not reproducible from source provided".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
- obtain the binary from the provider
- compile the published source code using the published build instructions into a binary
- compare the two binaries
- 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.Show Older Reviews
Help spread awareness for build reproducibility
Please help us spread the word, asking Mycelium Bitcoin 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 ¶
Update 2022-11-04: After the provider had failed to publish the source code resulting in a No Source! on 2022-11-01, the source was released today and we ran our test script again:
===== Begin Results =====
appId: com.mycelium.wallet
signer: b8e59d4a60b65290efb2716319e50b94e298d7a72c76c2119eb7d8d3afac302e
apkVersionName: 3.16.0.13
apkVersionCode: 3160013
verdict:
appHash: 76a431f30c9257c478c6d1072aeaaaddc4807f2a9f9379791c768866ec4bdec7
commit: 1544c49cdde85dc060875ae601415016537f5419
Diff:
Files /tmp/fromPlay_com.mycelium.wallet_3160013/classes3.dex and /tmp/fromBuild_com.mycelium.wallet_3160013/classes3.dex differ
Files /tmp/fromPlay_com.mycelium.wallet_3160013/META-INF/CERT.RSA and /tmp/fromBuild_com.mycelium.wallet_3160013/META-INF/CERT.RSA differ
Files /tmp/fromPlay_com.mycelium.wallet_3160013/META-INF/CERT.SF and /tmp/fromBuild_com.mycelium.wallet_3160013/META-INF/CERT.SF differ
Files /tmp/fromPlay_com.mycelium.wallet_3160013/META-INF/MANIFEST.MF and /tmp/fromBuild_com.mycelium.wallet_3160013/META-INF/MANIFEST.MF differ
Revision, tag (and its signature):
===== End Results =====
With a diff in classes3.dex this product is not verifiable from its source
code.
The diffoscope output for classes3.dex:
βββ classes3.dex
β βββ classes3.jar
β β βββ zipinfo {}
β β β @@ -1,8 +1,8 @@
β β β -Zip file size: 16107502 bytes, number of entries: 7492
β β β +Zip file size: 16107503 bytes, number of entries: 7492
β β β ?rwxrwxr-x 2.0 unx 245 b- stor 80-Jan-01 00:00 com/mrd/bitlib/model/AddressType$Companion.class
β β β ?rwxrwxr-x 2.0 unx 1087 b- stor 80-Jan-01 00:00 com/mrd/bitlib/model/AddressType.class
β β β ?rwxrwxr-x 2.0 unx 81 b- stor 80-Jan-01 00:00 com/mrd/bitlib/model/Bech32$1.class
β β β ?rwxrwxr-x 2.0 unx 366 b- stor 80-Jan-01 00:00 com/mrd/bitlib/model/Bech32$Bech32Data.class
β β β ?rwxrwxr-x 2.0 unx 180 b- stor 80-Jan-01 00:00 com/mrd/bitlib/model/Bech32$Bech32Exception.class
β β β ?rwxrwxr-x 2.0 unx 3870 b- stor 80-Jan-01 00:00 com/mrd/bitlib/model/Bech32.class
β β β ?rwxrwxr-x 2.0 unx 649 b- stor 80-Jan-01 00:00 com/mrd/bitlib/model/BitcoinAddress$1.class
β β β @@ -7487,8 +7487,8 @@
β β β ?rwxrwxr-x 2.0 unx 689 b- stor 80-Jan-01 00:00 com/mycelium/wallet/activity/receive/ReceiveCoinsViewModel$init$1.class
β β β ?rwxrwxr-x 2.0 unx 698 b- stor 80-Jan-01 00:00 com/mycelium/wallet/activity/receive/ReceiveCoinsViewModel$isInitialized$1.class
β β β ?rwxrwxr-x 2.0 unx 698 b- stor 80-Jan-01 00:00 com/mycelium/wallet/activity/send/model/SendCoinsViewModel$isInitialized$1.class
β β β ?rwxrwxr-x 2.0 unx 1099 b- stor 80-Jan-01 00:00 com/mycelium/wapi/wallet/bch/bip44/Bip44BCHAccount.class
β β β ?rwxrwxr-x 2.0 unx 1292 b- stor 80-Jan-01 00:00 com/mycelium/wapi/wallet/bch/single/SingleAddressBCHAccount.class
β β β ?rwxrwxr-x 2.0 unx 5651 b- stor 80-Jan-01 00:00 com/mycelium/wapi/wallet/btc/bip44/HDAccountExternalSignature.class
β β β ?rwxrwxr-x 2.0 unx 1139 b- stor 80-Jan-01 00:00 com/mycelium/wapi/wallet/btc/bip44/HDPubOnlyAccount.class
β β β -7492 files, 17610442 bytes uncompressed, 14518228 bytes compressed: 17.6%
β β β +7492 files, 17610442 bytes uncompressed, 14518229 bytes compressed: 17.6%
β β βββ com/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl.class
β β β βββ procyon -ec {}
β β β β @@ -30,16 +30,16 @@
β β β β
β β β β public class FragmentChangelly2ExchangeBindingImpl extends FragmentChangelly2ExchangeBinding
β β β β {
β β β β private static final ViewDataBinding$IncludedLayouts sIncludes;
β β β β private static final SparseIntArray sViewsWithIds;
β β β β private ViewDataBinding$PropertyChangedInverseListener buyLayoutvalue;
β β β β private long mDirtyFlags;
β β β β - private InverseBindingListener mOldEventValue2130743879;
β β β β - private InverseBindingListener mOldEventValue880387685;
β β β β + private InverseBindingListener mOldEventValue1158656703;
β β β β + private InverseBindingListener mOldEventValue881725763;
β β β β private final FrameLayout mboundView0;
β β β β private final ConstraintLayout mboundView1;
β β β β private final TextView mboundView7;
β β β β private ViewDataBinding$PropertyChangedInverseListener sellLayoutvalue;
β β β β
β β β β static {
β β β β final ViewDataBinding$IncludedLayouts viewDataBinding$IncludedLayouts = sIncludes = new ViewDataBinding$IncludedLayouts(18);
β β β β @@ -1067,17 +1067,17 @@
β β β β }
β β β β if ((mDirtyFlags & n3) != n30) {
β β β β this.buyLayout.setFiatValue(fiatValue2);
β β β β }
β β β β final long n32 = 0x4000000L & mDirtyFlags;
β β β β if (n32 != n30) {
β β β β this.buyLayout.setPartLabel(this.getRoot().getResources().getString(2131951799));
β β β β - setBindingInverseListener((ViewDataBinding)this.buyLayout, this.mOldEventValue2130743879, this.buyLayoutvalue);
β β β β + setBindingInverseListener((ViewDataBinding)this.buyLayout, this.mOldEventValue1158656703, this.buyLayoutvalue);
β β β β this.sellLayout.setPartLabel(this.getRoot().getResources().getString(2131951800));
β β β β - setBindingInverseListener((ViewDataBinding)this.sellLayout, this.mOldEventValue880387685, this.sellLayoutvalue);
β β β β + setBindingInverseListener((ViewDataBinding)this.sellLayout, this.mOldEventValue881725763, this.sellLayoutvalue);
β β β β }
β β β β final long n33 = 0x5004000L & mDirtyFlags;
β β β β final long n34 = 0L;
β β β β if (n33 != n34) {
β β β β this.buyLayout.setValue(value2);
β β β β }
β β β β if ((0x5002000L & mDirtyFlags) != n34) {
β β β β @@ -1128,16 +1128,16 @@
β β β β if ((mDirtyFlags & 0x5800000L) != n36) {
β β β β this.swapAccount.setEnabled(enabled);
β β β β if (getBuildSdkInt() >= 11) {
β β β β this.swapAccount.setAlpha(alpha);
β β β β }
β β β β }
β β β β if (n32 != 0L) {
β β β β - this.mOldEventValue2130743879 = (InverseBindingListener)this.buyLayoutvalue;
β β β β - this.mOldEventValue880387685 = (InverseBindingListener)this.sellLayoutvalue;
β β β β + this.mOldEventValue1158656703 = (InverseBindingListener)this.buyLayoutvalue;
β β β β + this.mOldEventValue881725763 = (InverseBindingListener)this.sellLayoutvalue;
β β β β }
β β β β executeBindingsOn((ViewDataBinding)this.sellLayout);
β β β β executeBindingsOn((ViewDataBinding)this.buyLayout);
β β β β }
β β β β }
β β β β
β β β β public boolean hasPendingBindings() {
...
βββ smali_classes3/com/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl.smali
β @@ -10,17 +10,17 @@
β
β
β # instance fields
β .field private buyLayoutvalue:Landroidx/databinding/ViewDataBinding$PropertyChangedInverseListener;
β
β .field private mDirtyFlags:J
β
β -.field private mOldEventValue2130743879:Landroidx/databinding/InverseBindingListener;
β +.field private mOldEventValue1158656703:Landroidx/databinding/InverseBindingListener;
β
β -.field private mOldEventValue880387685:Landroidx/databinding/InverseBindingListener;
β +.field private mOldEventValue881725763:Landroidx/databinding/InverseBindingListener;
β
β .field private final mboundView0:Landroid/widget/FrameLayout;
β
β .field private final mboundView1:Landroidx/constraintlayout/widget/ConstraintLayout;
β
β .field private final mboundView7:Landroid/widget/TextView;
β
β @@ -3076,15 +3076,15 @@
β move-result-object v10
β
β invoke-virtual {v4, v10}, Lcom/mycelium/wallet/databinding/LayoutChangelly2CoinValueBinding;->setPartLabel(Ljava/lang/String;)V
β
β .line 989
β iget-object v4, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->buyLayout:Lcom/mycelium/wallet/databinding/LayoutChangelly2CoinValueBinding;
β
β - iget-object v10, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->mOldEventValue2130743879:Landroidx/databinding/InverseBindingListener;
β + iget-object v10, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->mOldEventValue1158656703:Landroidx/databinding/InverseBindingListener;
β
β iget-object v11, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->buyLayoutvalue:Landroidx/databinding/ViewDataBinding$PropertyChangedInverseListener;
β
β invoke-static {v4, v10, v11}, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->setBindingInverseListener(Landroidx/databinding/ViewDataBinding;Landroidx/databinding/InverseBindingListener;Landroidx/databinding/ViewDataBinding$PropertyChangedInverseListener;)V
β
β .line 990
β iget-object v4, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->sellLayout:Lcom/mycelium/wallet/databinding/LayoutChangelly2CoinValueBinding;
β @@ -3104,15 +3104,15 @@
β move-result-object v10
β
β invoke-virtual {v4, v10}, Lcom/mycelium/wallet/databinding/LayoutChangelly2CoinValueBinding;->setPartLabel(Ljava/lang/String;)V
β
β .line 991
β iget-object v4, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->sellLayout:Lcom/mycelium/wallet/databinding/LayoutChangelly2CoinValueBinding;
β
β - iget-object v10, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->mOldEventValue880387685:Landroidx/databinding/InverseBindingListener;
β + iget-object v10, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->mOldEventValue881725763:Landroidx/databinding/InverseBindingListener;
β
β iget-object v11, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->sellLayoutvalue:Landroidx/databinding/ViewDataBinding$PropertyChangedInverseListener;
β
β invoke-static {v4, v10, v11}, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->setBindingInverseListener(Landroidx/databinding/ViewDataBinding;Landroidx/databinding/InverseBindingListener;Landroidx/databinding/ViewDataBinding$PropertyChangedInverseListener;)V
β
β :cond_50
β const-wide/32 v10, 0x5004000
β @@ -3384,20 +3384,20 @@
β cmp-long v0, v7, v2
β
β if-eqz v0, :cond_60
β
β .line 1078
β iget-object v0, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->buyLayoutvalue:Landroidx/databinding/ViewDataBinding$PropertyChangedInverseListener;
β
β - iput-object v0, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->mOldEventValue2130743879:Landroidx/databinding/InverseBindingListener;
β + iput-object v0, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->mOldEventValue1158656703:Landroidx/databinding/InverseBindingListener;
β
β .line 1079
β iget-object v0, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->sellLayoutvalue:Landroidx/databinding/ViewDataBinding$PropertyChangedInverseListener;
β
β - iput-object v0, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->mOldEventValue880387685:Landroidx/databinding/InverseBindingListener;
β + iput-object v0, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->mOldEventValue881725763:Landroidx/databinding/InverseBindingListener;
β
β .line 1081
β :cond_60
β iget-object v0, v1, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->sellLayout:Lcom/mycelium/wallet/databinding/LayoutChangelly2CoinValueBinding;
β
β invoke-static {v0}, Lcom/mycelium/wallet/databinding/FragmentChangelly2ExchangeBindingImpl;->executeBindingsOn(Landroidx/databinding/ViewDataBinding;)V
The diff looks benign. Two geenrated variable names differ between the two binaries.
Disclaimer: Authors of this project have contributed to Mycelium.
Independent re-builds:
Here we test if the latest version also can be reproduced, following the known procedure expressed in our test script (?):
+ git clone --quiet --branch v3.16.0.13 --depth 1 https://github.com/mycelium-com/wallet-android app
warning: Could not find remote branch v3.16.0.13 to clone.
fatal: Remote branch v3.16.0.13 not found in upstream origin
+ exit 1
This is not good. The current version on Play Store is v3.16.0.13 yet the
latest version
on their public repository is 3.16.0.8
authored on 2022-07-27, more than three months ago!
This wallet is not verifiable!
(lw)
Share on
Twitter Facebook LinkedInOr embed a widget in your website
<iframe
src="https://walletscrutiny.com/widget/#appId=android/com.mycelium.wallet&theme=auto&style=short" name="_ts"
style="min-width:180px;border:0;border-radius:10px;max-width:280px;min-height:30px;">
</iframe>
and
<iframe
src="https://walletscrutiny.com/widget/#appId=android/com.mycelium.wallet&theme=auto&style=long"
style="max-width:100%;width:342px;border:0;border-radius:10px;min-height:290px;">
</iframe>