Bitcoin wallets compared — Winnow

32 min read Original article ↗

Winnow compare · Bitcoin on iPhone

How Winnow compares with seven other open-source iPhone wallets that hold your own Bitcoin keys: features, code size, complexity and what each one depends on. Everything is measured from source and rebuilt every day.

At a glance

Each wallet below holds its own keys on the phone, with the exception noted in the fourth column. Four of them (Phoenix, Bitkit, Blixt and Zeus) are Lightning-first wallets with an on-chain side; this page looks only at their Bitcoin wallet and ignores their Lightning features. The table shows defaults; most of these wallets let you change the chain source.

WalletBuilt withWhere the on-chain wallet livesChain dataWho else must signOn iPhone
WinnowSwift (SwiftUI)Its own, in Swift (WalletCore), in the same repository: keys, PSBTs, scripts, compact-filter sync, peer networking Package.swift:19 README.md:7BIP157/158 compact filters from Bitcoin peers found through a signed peer list and DNS seeds; Advanced mode adds your own peers README.md:7 CensusCatalog.swift:28 SettingsView.swift:83Nobody for the everyday wallet; shared accounts need the co-owners' keys, with no co-signing server README.md:9 SharedSavingsViews.swift:104App Store; pre-release builds on TestFlight README.md:5 appstore-submit.yml:3
BlueWalletReact Native (TypeScript) with small native modulesIts own TypeScript (class/wallets) on bitcoinjs-lib 7 and @noble/secp256k1; chain data through a fork of the Electrum client abstract-hd-electrum-wallet.ts:1075 package.json:132 package.json:144Electrum servers: electrum1.bluewallet.io by default, a short hardcoded fallback list; any host and port can be set in Settings > Network BlueElectrum.ts:90 ElectrumSettings.tsx:193Nobody for on-chain funds. The optional LNDhub (custodial) and Ark wallet types depend on their own servers abstract-hd-electrum-wallet.ts:1075 lightning-custodian-wallet.ts:80 lightning-ark-wallet.ts:94App Store; builds go through TestFlight README.md:10 Fastfile:1306
GreenSwift (UIKit) over Blockstream's gdkgdk 0.78.0 (C++ for multisig, Rust for singlesig), linked as a prebuilt static library fetch_gdk_binaries.sh:29 session_impl.cpp:79Singlesig: Blockstream's Electrum server, or your own in Settings. Multisig: Blockstream's backend, not replaceable network_parameters.cpp:472 network_parameters.cpp:333 AppSettingsViewModel.swift:52Nobody for singlesig. Multisig (2-of-2, 2-of-3) needs Blockstream's server to co-sign every spend ga_auth_handlers.cpp:808 ga_auth_handlers.cpp:835App Store
MuunSwift (UIKit) with a Go library, libwalletlibwallet, Muun's own Go library in the same repository: keys, 2-of-2 and MuSig2 signing, addresses, fees. Muun's server holds the second key README.md:26 V5.go:16Muun's own server (Houston API): history, spendable coins, fees and block height. The person cannot change it Environment.swift:42 SettingsPresenter.swift:154 init.go:160Muun's server must co-sign every spend. Without it the person needs the Emergency Kit, the Recovery Code and Muun's separate Recovery Tool V4.go:47 V5.go:26 RecoveryToolViewController.swift:69App Store, per its fastlane release lane
PhoenixSwift (SwiftUI) over Kotlin Multiplatform shared codelightning-kmp 1.13.2 (Kotlin Multiplatform): Electrum client, swap-in wallet and final (BIP84) wallet build.gradle.kts:85 SwapInWallet.kt:14 FinalWallet.kt:15An Electrum server picked at random from a built-in list of 15, trusted as given; the person can enter their own server in Settings AppConfigurationManager.kt:66 ElectrumConfigurationView.swift:59ACINQ co-signs swap-in deposits (MuSig2 2-of-2) until a refund delay of about six months, and is the channel peer for every on-chain send. The final wallet is the person's alone SwapInProtocol.kt:11 NodeParams.kt:94 ValidateView.swift:1970App Store
BitkitSwift (SwiftUI) on Rust librariesLDK Node 0.7.0-rc.66 (Synonym's fork, Rust); its on-chain wallet is BDK Cargo.toml:48 builder.rs:1384Synonym's Electrum server (bitkit.to); the person can change it in Settings > Advanced > Electrum Server Env.swift:191 ElectrumSettingsScreen.swift:56Nobody LightningService.swift:796App Store
BlixtReact Native (TypeScript) with Go (LND)Embedded LND 0.21.1 (Go); the on-chain wallet is btcwallet, run in-process through react-native-turbo-lnd btcwallet.go:83Neutrino (BIP157/158) through six default peers, four run by Blixt; the person can change the peers in Settings constants.ts:30 Settings.tsx:1670Nobody OnChain.ts:217TestFlight
ZeusReact Native (TypeScript) with native modules and prebuilt Go and Rust librariesEmbedded LND 0.21.4 (Go, Zeus's fork); the on-chain wallet is btcwallet. LDK Node (BDK) is an option, and remote nodes can be driven too btcwallet.go:83 WalletCreationUtils.ts:109 WalletCreationUtils.ts:71Neutrino (BIP157/158) through five default peers, two run by Olympus; the person can add peers or allow only their own. The LDK Node option uses an Esplora server SettingsStore.ts:1476 LndMobileUtils.ts:222 LdkNodeUtils.ts:26Nobody for on-chain funds; they sit in the embedded wallet under one key on the phone EmbeddedLND.ts:100 btcwallet.go:83App Store

Features

What a person can do in each iPhone app today with the wallet’s Bitcoin, checked against the code. Where a wallet has several account types, a cell shows the best one it offers, and its note says which. Hover or focus a cell for the note; every cell links to its evidence below. The cells were last checked by hand on 2 October 2026. Since that review, 11 of the 420 cited passages have changed (in Winnow, BlueWallet, Bitkit and Zeus) and 32 have moved within their file in the code measured below.

FeatureWinnowBlueWalletGreenMuunPhoenixBitkitBlixtZeus
Keys and signing
Multisig or shared accounts Yes Yes Yes Partial Partial No No No
Hardware or external signer Partial Yes Yes No No Yes No Yes
PSBT import and export Partial Yes Yes No No No No Yes
Watch-only wallets Partial Yes Yes No No Partial No Yes
BIP 39 passphrase No Partial Yes No No Yes Partial No
Spending
Coin control No Yes Yes No No Yes No Yes
Speed up a stuck payment (RBF or CPFP) Partial Partial Yes Partial Partial Yes Partial Yes
Taproot receive addresses Yes Yes Partial Yes Yes Yes Yes Yes
Output descriptors Partial Yes Yes Partial Partial Yes No Partial
Chain data and privacy
Use your own node or server Yes Yes Yes No Yes Yes Yes Yes
Checks chain data on the phone Yes No No No No Partial Yes Yes
Tor or I2P Partial Partial Yes No Partial No Yes No
Backup and recovery
Standard BIP 39 recovery phrase Yes Yes Yes Partial Partial Yes Partial Partial
Encrypted backup off the phone Yes No Partial Yes Yes Partial No Partial
License
Source licenseMITMITGPL-3.0MITApache-2.0MITMITAGPL-3.0

Yes · Partial · Engine only · No · Unknown

Notes and code evidence for every cell

Links open the exact line that was checked, at the revision reviewed on 2 October 2026.

Cited code that has changed since the review, and so is due a fresh look:

Winnow

BlueWallet

Green

Muun

Phoenix

Bitkit

Blixt

Zeus

Code size

Winnow counts 21,997 lines of code: 8,965 for the app and 13,032 for its own Bitcoin library, which lives in the same repository. The other wallets count 1.7 to 8.7 times as many lines. That is the app, plus a Bitcoin library of its own for Muun.

The count leaves out the engines that Green, Phoenix, Bitkit, Blixt and Zeus embed: gdk, lightning-kmp, LDK Node, and LND. Each is a separate project the wallet is built on, and four of the five are Lightning nodes, so their lines are shown in the table and not in the totals. BlueWallet takes its Bitcoin primitives from npm packages, which the dependency tables count. The gap would be wider with the engines added.

Winnow’s lines are denser, at about 33 characters each against 19–29 for the others. Counted in characters, the gap is 1.3 to 5.2 times.

  • App
  • Own Bitcoin library

Winnow22k719k

BlueWallet58k1.6M

Green70k2.0M

Muun88k2.4M

Phoenix73k1.9M

Bitkit101k2.8M

Blixt36k948k

Zeus192k3.7M

Code that builds into each iPhone app, without tests, generated files or comments, and without embedded engines. Snapshot of 10 October 2026.
Lines of code by part
WalletAppOwn Bitcoin libraryTotal linesCharactersvs WinnowEmbedded engine, not in the total
Winnow8,96513,03221,9970.72M—None embedded
BlueWallet57,858—57,8581.64M2.6× · 2.3×None embedded
Green70,474—70,4742.03M3.2× · 2.8×34,374 Blockstream/gdk release_0.78.0
Muun59,66028,46988,1292.44M4.0× · 3.4×None embedded
Phoenix72,881—72,8811.90M3.3× · 2.6×28,779 ACINQ/lightning-kmp v1.13.2
Bitkit100,640—100,6402.83M4.6× · 3.9×127,646 synonymdev/ldk-node 0.7.0-rc.66, lightningdevkit/rust-lightning v0.2.6
Blixt36,360—36,3600.95M1.7× · 1.3×238,947 hsjoberg/lnd@ae185f2 (0.21.1)
Zeus191,851—191,8513.73M8.7× · 5.2×242,900 ZeusLN/lnd v0.21.4-beta-zeus.1

“vs Winnow” divides each total by Winnow’s, first in lines, then in characters. The engine column shows each engine at the version the app pins, so its size can be read beside the wallet’s.

Languages

Share of each wallet’s counted lines, app and own Bitcoin library together. Winnow is written in one language; most of the others combine a user-interface language with a library in another.

WalletSwiftKotlinRustGoTypeScript/JSC family
Winnow100%—————
BlueWallet6%———94%<1%
Green68%—9%——23%
Muun68%—<1%32%—<1%
Phoenix60%40%———1%
Bitkit44%—56%———
Blixt<1%——87%13%<1%
Zeus1%——56%43%<1%

Complexity and CRAP

CRAP scores each function by its cyclomatic complexity (CC, the number of paths through it) and how much of it the tests run: CRAP = CC² × (1 − coverage)³ + CC. Coverage needs each project’s test suite run with instrumentation, on a Mac for the Swift apps, so it is not measured here. Testing can only bring CRAP down to CC, so the complexity alone sets a floor: a function above 12 scores above 12 however well it is tested, and one above 30 fails crap4j’s default threshold whatever its tests. Complexity is measured on each wallet’s counted code, not on embedded engines.

1.5% of Winnow’s functions are above 12, against 0.8–8.0% for the others. Winnow’s most complex function scores 27. Its mean is 3.3; the others’ range from 1.9 to 5.3. Winnow’s CI also rejects any function over 8 as SwiftLint counts complexity, which leaves out case arms, &&, ||, ?? and ternaries; this page counts all of them, so its numbers are higher.

Cyclomatic complexity per function, app and own Bitcoin library together
WalletFunctionsMean CC90th pctMaxCRAP above 12 at any coverageCRAP above 30 at any coverage
Winnow1,6203.372724 (1.5%)0 (0.00%)
BlueWallet1,7645.310242141 (8.0%)42 (2.38%)
Green6,9052.244585 (1.2%)7 (0.10%)
Muun6,6791.946354 (0.8%)2 (0.03%)
Phoenix4,7032.5515577 (1.6%)9 (0.19%)
Bitkit6,0143.06119109 (1.8%)14 (0.23%)
Blixt1,0573.6713456 (5.3%)19 (1.80%)
Zeus4,8204.710252350 (7.3%)77 (1.60%)
By part: app and own Bitcoin library

Dependencies and vendored code

Winnow depends on 1 third-party package: swift-secp256k1, which builds Bitcoin Core’s libsecp256k1 from source. The others depend on 58 to 1,457. These counts include what the embedded engines pull in, because that code ships in the app too. Package counts from different ecosystems are not equal units: an npm package is often a few hundred lines, a Rust crate or Go module often more. Read them per row.

Third-party packages each app resolves and ships, beyond the code counted above
KindWinnowBlueWalletGreenMuunPhoenixBitkitBlixtZeus
Swift packages1—31—195——
Kotlin libraries————39———
Rust crates, inside prebuilt libraries——126——693—407
Go modules, inside the Go library———111——120140
npm packages—922————553907
CocoaPods from the trunk—2—28——83
Third-party packages1924157139586986811,457
Main libraries, the Bitcoin code outside the counted code, and code that arrives other than as source packages
WalletMain librariesBitcoin code not counted abovePrebuilt binariesThird-party code copied into the repositoryPatched dependencies
Winnowswift-secp256k1 0.23.2 (Bitcoin Core's libsecp256k1), the only third-party dependency Package.swift:16 README.md:11—None in the repository; the app links the swift-secp256k1 package that SwiftPM fetches Package.swift:16NoneNone
BlueWalletbitcoinjs-lib, bip32, bip39, ecpair, @noble/secp256k1, BlueWallet forks of coinselect, rn-electrum-client, bip47, SilentPayments and slip39-js, aezeed, bolt11, payjoin-client, bc-ur (Keystone and NGRAVE), realm, react-native-keychain, @arkade-os/sdk and boltz-swap, Bugsnag. package.json:93bitcoinjs-lib, bip32 and @noble/secp256k1, from npmNo binaries are checked in. The build links React Native's prebuilt Hermes and React-Core-prebuilt pods, and the patched react-native-background-fetch pod vendors the npm package's TSBackgroundFetch.xcframework. Podfile.lock:28 Podfile.lock:97 react-native-background-fetch+4.4.2.patch:85,136 lines in blue_modules: pako, bbqr, uint8array-extras, bc-ur, bc-bech32Four patch-package patches on npm packages: react-native-background-fetch (iOS xcframework with Catalyst), react-native-notifications (Android token), react-native-context-menu-view (Android menus), react-native-screens (iOS accessibility id; patch is for 4.27.0 while package.json pins 4.28.0). Several dependencies also come from BlueWallet forks pinned to git commits.
Greengdk (libwally-core, rust-bitcoin, Tor), Liquid Wallet Kit, Greenlight SDK, Firebase, Countly, Zendesk, Rive, Charts, SwiftCBOR, AsyncBluetooth Package.resolved:77 Package.resolved:149 Package.resolved:68libwally-core, rust-bitcoin, rust-elements (inside the prebuilt gdk)gdk static library (libgreen_gdk_full.a) from Blockstream's release tarballs, checked against pinned SHA-256 sums; Google's grpc-binary and abseil-cpp-binary packages fetch_gdk_binaries.sh:29NoneCountly's iOS SDK comes from a fork (angelix/countly-sdk-ios 23.6.1-ave). gdk's own build patches libevent and bc-ur, outside the app.
MuunSwift: Firebase (Analytics, Crashlytics, Messaging), GoogleSignIn and Google Drive API, GRDB.swift, RxSwift, Dip, grpc-swift, Lottie. Go: btcd, lnd (lnwire, zpay32), lightning-onion, go-lnurl, gofpdf, pdfcpu, gorm with SQLite, gRPC. Podfile:15 Package.swift:15 go.mod:6btcd and lnd, as Go modules. Copies inside libwallet (btcsuitew, musig2v040) are countedRust zero-knowledge proof verifier (plonky2) linked as the static library multi-apple-ios-librs.a, built by libwallet/librs/makelibs.sh and not in the tree; FirebaseAnalytics and GoogleAppMeasurement xcframeworks from dl.google.com librs.go:16 pods_dependency_registry.txt:4 pods_dependency_registry.txt:14101,694 lines in falcon/app/Pods: GRDB.swift, FirebaseCrashlytics, RxSwift, GTMSessionFetcher, FirebaseMessaging, GoogleAPIClientForREST and 19 moreGo 1.24.7 toolchain is patched for cgo struct alignment (falcon/0001-align-to-ptrsize.patch); golang.org/x/mobile is replaced by the muun/mobile fork (libwallet/go.mod:200)
Phoenixbitcoin-kmp with secp256k1-kmp, Ktor, kotlinx-serialization, SQLDelight (Kotlin side); Firebase Messaging and a few small SwiftUI packages (Swift side) build.gradle.kts:88 build.gradle.kts:85 project.pbxproj:387bitcoin-kmpKotlin libraries (lightning-kmp, bitcoin-kmp, secp256k1-kmp native code, Ktor, SQLDelight) as compiled klibs from Maven Central; Firebase through Swift Package Manager build.gradle.kts:85 build.gradle.kts:18NoneNone
BitkitLDK Node (with BDK), bitkit-core, Paykit, VSS client, Lottie, swift-secp256k1 project.pbxproj:1176BDK, rust-bitcoinLDK Node, bitkit-core, Paykit and the VSS client, as XCFrameworks Package.swift:28 Package.swift:29 Package.swift:27 Package.swift:28NoneNone
BlixtReact Native, react-native-turbo-lnd, @bufbuild/protobuf, secp256k1, bech32, react-native-nitro-tor, react-native-keychain, easy-peasy package.json:70 package.json:104 package.json:122 package.json:134 package.json:145btcwallet (with btcd, neutrino) under LNDLndmobile.xcframework (LND), downloaded from the react-native-turbo-lnd release for the pinned LND commit react-native-turbo-lnd.podspec:19NoneNone in the app (no patch files); LND is Blixt's own fork (hsjoberg/lnd) with an added gossip speedloader
ZeusReact Native, bitcoinjs-lib, noble and scure cryptography, bc-ur registries (Keystone, NGRAVE), Nostr (NDK), react-native-nitro-tor, Cashu CDK package.json:53 package.json:55 package.json:56 package.json:59 package.json:77 package.json:86 package.json:117 package.json:148btcwallet (with btcd, neutrino) under LND; bitcoinjs-lib; BDK in the optional LDK NodeLndmobile.xcframework (LND), LDKNodeFFI.xcframework (LDK Node), and the Cashu CDK and restore xcframeworks, downloaded from release archives pinned by SHA-256 fetch-libraries-versions.json:2 fetch-libraries.sh:374,605 lines in zeus_modules, zeus_modules/@lightninglabs: lnc-core, lnc-rn, bc-ur, bc-bech32, noble_ecc, urSix postinstall scripts rewrite installed npm packages (two are Android-only: jcenter and notifications; four reach iOS: NativeEventEmitter, keychain cloudSync, noble-hashes exports, reanimated C++); rn-nodeify shims crypto, stream and dgram
  • Swift packages are every package Swift Package Manager resolves. Phoenix links Firebase Messaging, which brings in Google’s package graph.
  • Kotlin libraries are the 39 libraries Phoenix’s iOS framework links besides lightning-kmp, resolved for the iPhone target.
  • Rust crates are compiled into prebuilt libraries. Bitkit’s four libraries each carry their own copies: 693 distinct crates, 1,085 counting each library’s copy. Green’s gdk adds 126. gdk’s C++ dependencies are not counted.
  • Go modules are linked into Muun’s libwallet (111), and into LND in Blixt and Zeus.
  • npm packages are everything the app’s runtime dependencies pull in (99 declared by BlueWallet, 87 by Blixt, 110 by Zeus), not build tools. The bundler includes only what the app imports.
  • CocoaPods counts pods from the CocoaPods trunk. Another 109 pods in BlueWallet, 99 in Blixt and 112 in Zeus are the native halves of npm packages and React Native itself.
  • Muun commits the sources of its CocoaPods into its repository: 101,694 lines of third-party code that build into the app, with a registry of each pod’s upstream and checksum.

Over time

The comparison is measured again every day from each wallet’s latest code. Wallet repositories are read at the head of their main branch, except Phoenix, which is read at its latest iOS release (ios-v2.8.4): when we checked, its default branch was configured for testnet. Every engine and library is read at the version its wallet pins. A snapshot is recorded whenever any of them moves: 9 since 2 October 2026, when this page began counting Bitcoin wallets only. Changes are shown against that first snapshot. Hover or focus a line for each snapshot. The 4 earlier snapshots (27 September 2026 to 1 October 2026) compared Lightning wallets and counted their Lightning engines; they are in data.json.

WalletLines of codeThird-party packagesFunctions above CC 12
Winnow21,997no change1no change24no change
BlueWallet57,858+233 (+0.4%)924−6 (−0.6%)141+2 (+1.4%)
Green70,474no change157no change85no change
Muun88,129no change139no change54no change
Phoenix72,881no change58no change77no change
Bitkit100,640+6,951 (+7.4%)698+7 (+1.0%)109+17 (+18.5%)
Blixt36,360no change681no change56no change
Zeus191,851+1,867 (+1.0%)1,457−10 (−0.7%)350+5 (+1.4%)
Every snapshot
Lines of code
SnapshotWinnowBlueWalletGreenMuunPhoenixBitkitBlixtZeusSources that moved
10 October 202621,99757,85870,47488,12972,881100,64036,360191,851bitkit, paykit-rs, zeus
9 October 202621,99757,85870,47488,12972,881100,23936,360190,159bitkit, zeus, lnd-zeus
8 October 202621,99757,85870,47488,12972,88199,67136,360190,500bitkit, paykit-rs, zeus, bluewallet
7 October 202621,99757,85870,47488,12972,88198,06836,360190,456bitkit, zeus, bluewallet
6 October 202621,99757,81670,47488,12972,88197,92136,360190,382bitkit, zeus
5 October 202621,99757,81670,47488,12972,88194,77436,360190,363bitkit, zeus, zeus-ldk-node, bluewallet
4 October 202621,99757,81670,47488,12972,88193,68936,360190,001zeus, bluewallet
3 October 202621,99757,62570,47488,12972,88193,68936,360190,005winnow, zeus, lnd-zeus
2 October 202621,99757,62570,47488,12972,88193,68936,360189,984First snapshot
Third-party packages
SnapshotWinnowBlueWalletGreenMuunPhoenixBitkitBlixtZeus
10 October 20261924157139586986811,457
9 October 20261924157139586986811,457
8 October 20261924157139586986811,457
7 October 20261930157139586916811,457
6 October 20261930157139586916811,466
5 October 20261930157139586916811,466
4 October 20261930157139586916811,466
3 October 20261930157139586916811,466
2 October 20261930157139586916811,467
Functions above CC 12
SnapshotWinnowBlueWalletGreenMuunPhoenixBitkitBlixtZeus
10 October 20262414185547710956350
9 October 20262414185547710556345
8 October 20262414185547710156347
7 October 2026241418554779656347
6 October 2026241418554779656347
5 October 2026241418554779356347
4 October 2026241418554779256347
3 October 2026241398554779256346
2 October 2026241398554779256345

What the numbers leave out

Less code is not proof of safety

A smaller codebase is quicker to read and review. It does not show the code is correct, and it says nothing about whether anyone independent has reviewed it. Check each project’s own security page.

The wallets do different amounts of work

Each count is the whole app, not only its on-chain wallet. Zeus also manages remote LND and Core Lightning nodes and includes Cashu, Nostr Wallet Connect and a point of sale. Bitkit includes Pubky contacts, Paykit and Trezor support. Winnow includes shared accounts with MuSig2 and 2-of-3 signing. BlueWallet includes Lightning wallet types (an LNDHub custodian and an Ark one). Green’s count includes its lightning folder. Muun includes Lightning payments through swaps.

Engines are not counted

Phoenix, Bitkit, Blixt, Zeus and Green build their Bitcoin wallet on an engine that is a separate project: lightning-kmp, LDK Node with BDK, LND and gdk. The code size and complexity here are for the wallet itself, so those wallets look smaller than everything they ship. Winnow, Muun and BlueWallet have no such engine. Winnow and Muun keep their own Bitcoin library in the repository, which is counted.

Who can move on-chain funds

Where a service has to cosign, the wallet cannot spend without it, or only after a delay. The fourth column of the table at the top says which wallets that applies to, and the notes under each cell give the account type.

How we measured

  • Lines: cloc 2.06 counted non-blank, non-comment lines in each app’s programming languages, for code that builds into the iPhone app. Characters were counted after removing comments and all whitespace. Excluded: tests; Android, desktop and web code; build tools; files marked as generated (protobuf, sqlc and UniFFI bindings); and vendored third-party code. Rust test modules inside source files were removed.
  • Complexity: each file was parsed with tree-sitter, and one rule applied to every language. CC is 1, plus 1 for each if or guard, loop, catch, ternary, &&, ||, ?? or elvis, and non-default case, when or match arm. Closures, lambdas and nested functions count toward the function that contains them, so a React screen written as one function component counts as one function. Tree-sitter could not fully parse at most 5% of any wallet’s files; it recovers locally, so their functions are still counted.
  • Dependencies: read from each app’s own lockfiles (Swift Package Manager, CocoaPods, npm, yarn and bun). Kotlin libraries were resolved from Maven Central’s metadata for the iPhone target. Rust crates come from cargo tree for aarch64-apple-ios at each prebuilt library’s pinned source. Go modules come from go list -deps for iOS, with the build tags LND’s own iOS build uses or, for Muun, none.
  • Vendored code: each repository was searched for third-party code committed into it: vendor directories, committed CocoaPods, copied npm packages, license files below the root, committed binaries and dependency patches.
  • Features: each cell was checked by hand in the app’s and the engine’s source on 2 October 2026, at the revisions in reviewed.json. The build compares every cited passage with today’s code and lists any that have changed. The rows and what each value means are in features/rows.json.
  • Embedded engines: counted at the version each app pins, as the named library only, and kept out of every total. Phoenix’s lightning-kmp comes from its Gradle catalog. Bitkit’s LDK Node and libraries come from its Package.resolved, and rust-lightning from LDK Node’s lockfile. Blixt’s LND is the fork its react-native-turbo-lnd release builds. Zeus’s LND, LDK Node and Cashu versions come from its fetch-libraries-versions.json, and its count uses its default embedded LND. Green’s gdk is the release its fetch_gdk_binaries.sh downloads.
Exact sources

Each project changes often. These numbers are measured again every day, and each snapshot is dated. They are a measurement, not a ranking.

Reproduce it

Everything on this page is generated from the source repository. It pins every project to an exact commit, and data.json holds every measurement, including the full package lists. To rebuild it:

git clone https://github.com/winnowwallet/compare
cd compare
npm ci && pip install -r requirements.txt
./build          # fetch the pinned sources, measure, render
git diff         # nothing changes if the measurement reproduces

It needs Python 3.11, Node, Go and Cargo, plus network access to GitHub, crates.io, the Go module proxy and Maven Central. Feature cells and profile facts are reviewed by hand. The build checks that every citation resolves at the revision it was reviewed against, and reports which cited code has changed since.

Not compared

This comparison needs the iPhone app’s source, so closed-source and custodial wallets cannot be measured and are left out, however widely they are used. Other open-source wallets could be added.

  • Exodus, Cash App and Strike are widely used iPhone wallets whose apps are closed source, so there is no code to measure or cite.
  • Envoy, Bull Bitcoin, Bitcoin Keeper, Cake Wallet and Edge publish source code and may be added. Each needs a measured iPhone build and a hand review of its features.