Metro Vault
com.gorunjinian.metrovault
Zapstore _@zapstore.dev Air-gapped Bitcoin signer for offline cold storage. QR-only, no network.
Republished from GitHub / F-Droid by the Zapstore main account.
MetroVault turns an Android phone into a secure, air-gapped Bitcoin signing device like a cold-storage hardware wallet. It acts as an offline signer for your watch-only wallets (such as Sparrow, BlueWallet, or Electrum) running on an online device. Your private keys are generated and kept on a phone that never connects to the internet; all communication happens through QR codes, and network access is blocked at the Android level. Because the keys never touch an online device, the attack surface for theft and malware is dramatically reduced. MetroVault is fully open source and auditable, built on a custom Kotlin Bitcoin library so every cryptographic operation can be reviewed. Security * Air-gapped operation — designed for devices with no internet (airplane mode, Wi-Fi/Bluetooth off) * Dual-layer encryption — AES-256-GCM with PBKDF2 (210k iterations) plus the Android Keystore * Biometric unlock — hardware-backed fingerprint/face authentication * Plausible deniability — separate "Main" and "Decoy" wallets behind different passwords * Brute-force protection — exponential backoff with lockout, and an optional automatic wipe after repeated failed logins * Screenshots and screen recording are blocked app-wide Wallets * Single-sig and multi-sig (collaborative custody) support * Address types: Native SegWit (bc1q), Taproot (bc1p), Nested SegWit (3...) and Legacy (1...) * BIP-352 Silent Payments support, both to send to or spend from an SP wallet * BIP-39 passphrase support, saved locally or kept in memory only * BIP-85 derivation of child seeds and passwords * Custom entropy from dice rolls or coin flips, plus mnemonic checksum tools * Testnet4 support for testing Transaction signing * PSBT workflow (BIP-174) for single-sig and multi-sig * Air-gapped flow: scan PSBT, verify, sign, export — entirely by QR * Animated QR support: BC-UR (v1/v2) and BBQr for large transactions * On-device address verification and watch-only XPUB/descriptor export * Message signing and verification Permissions MetroVault requests only the camera (optional, for scanning QR codes) and biometric permissions. It has no internet permission and cannot connect to any network.
First release: Aug 4, 2026, 3 total releases.
Most recent release: Oct 25, 2026.
Appears in 0 app stacks.
0 sats / 0 zaps received in the past year.
Sats Received
Underlying data available via MCP: app_zaps, app_releases.
Zap Count
Underlying data available via MCP: app_zaps, app_releases.
Releases
- Oct 25, 2026 4.0.0
- Sep 4, 2026 3.9.5# MetroVault v3.9.5 - Release Notes ## Taproot Signing Hardening - **Master fingerprint fix**: Taproot BIP-32 derivation fingerprints are now parsed as unsigned 32-bit values, so wallets whose fingerprint has the high bit set resolve their keys correctly instead of being skipped - **BIP-86 output-key verification**: key-path signing checks that the input's scriptPubKey commits to the tweaked output key (not the raw internal key) before signing, so every produced signature actually satisfies the spent output - **Strict sighash policy**: undefined or ambiguous hashtypes are rejected for both Taproot and ECDSA inputs (`SigHash.isValidTaproot` / `isValidEcdsa`); silent-payment spends enforce the same Taproot policy - **BIP-341 signature encoding**: `SIGHASH_DEFAULT` yields 64-byte signatures; every other hashtype appends the sighash byte - **x-only key matching**: Taproot inputs resolve even when the PSBT only carries x-only keys
More…
--- ## Partial-Signing Transparency - **Refusals are explained**: a new `InputSigningRefusal` hierarchy records *why* a matched input was declined (script-tree commitment, script-path key, unsupported sighash type) - **Warning cards in the UI**: the PSBT scan screen and the signed-PSBT export show exactly which inputs were left unsigned and why, instead of silently returning a partially signed transaction --- ## Coordinator Export (Nunchuk, Sparrow, Coldcard) - **Public-only export to coordinators** (#13): new "Export to wallet coordinator" flow exporting the active account as a Nunchuk signer-record QR or a Coldcard "Generic JSON" QR that Sparrow's Coldcard importer consumes, plus a JSON file export through the Storage Access Framework; the export never contains private material and rejects private extended-key prefixes - **Multi-account and combined exports** (#15): pick any account number, or export a combined JSON that bundles all supported single-sig and multisig (BIP-48) sections into one payload - **Animated QR playback**: large exports use BBQr or BC-UR with pause, manual frame stepping and a frame counter; frames are recycled when leaving the screen - **Live verification details**: fingerprint, derivation path and first receive address update for the selected account and format - **Standardized address display**: new `AddressFormatter` groups addresses in 5-character blocks and bolds the first/last segments for easier checking --- ## UI and Usability - **Show/hide password toggle** (#14) on every secure password field (setup, unlock, sensitive-operation verification, biometric and decoy setup, password changes); hidden by default, independent per field, resets when cleared or recreated - **Sensitive clipboard auto-clear**: clipboard handling is centralized in `SecurityUtils`; private keys, BIP-85 secrets and other sensitive values are wiped from the clipboard after 20 seconds --- ## Smaller APK ### Compact secp256k1 tables The bundled secp256k1 cryptography library is now built with compact precomputed multiplication tables, cutting roughly **4 MB from the APK** (and about twice that from on-device install size, since the native libraries are extracted at install): - **~1.1 MB → ~2.5 KB per ABI**: the precomputed tables (`ECMULT_WINDOW_SIZE=4`, `ECMULT_GEN_KB=2`) made up over 80% of each native library (the stock 0.24.0 `.so` is 1.28–1.48 MB per ABI); they are now sized like a dedicated hardware signer's build instead of a full node's - **No functional change**: table size is a pure speed/size trade in the reference bitcoin-core/secp256k1 library — signatures are byte-identical (deterministic nonces per RFC 6979 / BIP-340) and signing remains constant-time - **Applied identically on both sides**: the release CI (`.github/reproducible-build.sh`) and the F-Droid recipe patch the same two flags into the from-source build, so the published APK still reproduces byte-for-byte ### Leaner dependencies - **R8 and dependency cleanup**: `MainActivity` moved from `AppCompatActivity` to `FragmentActivity`, Material Components and `material-icons-extended` were dropped in favor of local vector assets, and broad keep rules were replaced by targeted ones for ZXing and the secp256k1 JNI (letting R8 prune unused Tink/Protobuf code) - **Assets and packaging**: logo and profile images converted to WebP; redundant `META-INF` entries, Kotlin metadata and coroutine debug probes excluded from the release APK --- ## secp256k1 0.24.0 - **Library update**: ACINQ secp256k1-kmp 0.23.0 → 0.24.0, bundling bitcoin-core/secp256k1 0.8.0 - **Hardened JNI bindings**: invalid arguments (including MuSig2 inputs without a parse step) now surface as a `Secp256k1Exception` instead of the library's default `abort()` callback; context initialization fails early if it cannot complete --- ## Tests - **Signing**: `TaprootPsbtSigningTest`, `TaprootSighashPolicyTest`, `SegwitV0SighashTest`; `SilentPaymentReceiveSignerTest` extended for the sighash policy - **Serialization codecs**: `MultisigConfigJsonTest`, `WalletKeysJsonTest`, `WalletMetadataJsonTest` (including the v1.x passphrase-setting migration) and `QuickShortcutStorageTest` - **Coordinator export**: `CoordinatorExportServiceTest` covers the Nunchuk record, Coldcard/Sparrow JSON and combined exports --- ## Technical Details ### Key Files Modified Paths below are relative to `app/src/main/java/com/gorunjinian/metrovault/` unless noted. **Signing** - `lib/bitcoin/Psbt.kt`, `lib/bitcoin/PsbtTypes.kt` - BIP-341 signature encoding, Taproot fingerprint parsing - `lib/bitcoin/SigHash.kt` - `isValidTaproot` / `isValidEcdsa` sighash policy - `lib/bitcoin/Bip371Fields.kt` - `PSBT_IN_TAP_MERKLE_ROOT` - `domain/service/psbt/PsbtSigner.kt`, `domain/service/psbt/PsbtKeyResolver.kt` - BIP-86 output-key verification, x-only matching, refusal reporting - `domain/service/bitcoin/WalletSigningService.kt` - signing-refusal plumbing - `data/model/PsbtModels.kt` - `InputSigningRefusal` - `feature/transaction/ScanPSBTScreen.kt`, `feature/transaction/components/SignedPSBTDisplay.kt` - partial-signing warning cards **Coordinator export** - `domain/service/bitcoin/CoordinatorExportService.kt`, `data/model/CoordinatorExport.kt` - Nunchuk / Coldcard-Sparrow JSON / combined exports - `feature/wallet/details/CoordinatorExportScreen.kt`, `feature/wallet/details/components/AccountExportComponents.kt` - unified export screen, account selector - `core/qr/AnimatedQREncoder.kt`, `core/qr/CoordinatorQREncoder.kt`, `core/ui/components/AnimatedQrDisplay.kt` - animated QR encoding and playback - `core/ui/util/AddressFormatter.kt` - styled address display **Build and size** (repo-relative) - `app/build.gradle.kts`, `app/proguard-rules.pro` - version 3.9.5 (8), packaging exclusions, targeted keep rules - `gradle/libs.versions.toml` - secp256k1-kmp 0.24.0; AGP 9.3.2, Navigation 2.10.0, Gradle 9.7.1 - `.github/reproducible-build.sh` - builds the v0.24.0 tag from source with the compact-table flags (mirrored in the fdroiddata recipe) - `docs/FDROID_BUILD.md` - updated pins (tag `e9d5c95`, submodule `6e2c8bc` = upstream v0.8.0) and the recipe's new `prebuild` step - `docs/SECURITY.md` - secp256k1 build configuration documented under Cryptographic Standards - `fastlane/metadata/android/en-US/changelogs/8.txt` - F-Droid changelog - `app/src/main/java/com/gorunjinian/metrovault/feature/settings/LibUsedScreen.kt` - library versions ## More Info * Add password visibility controls by @charbelgereige in https://github.com/gorunjinian/MetroVault/pull/14 * Add Nunchuk and Sparrow coordinator exports by @charbelgereige in https://github.com/gorunjinian/MetroVault/pull/13 * Refactor export flows for multi-account support and QR enhancements by @gorunjinian in https://github.com/gorunjinian/MetroVault/pull/15 ## New Contributors * @charbelgereige made their first contribution in https://github.com/gorunjinian/MetroVault/pull/14 **Full Changelog**: https://github.com/gorunjinian/MetroVault/compare/v3.9.0...v3.9.5 - Aug 4, 2026 3.9.0# MetroVault v3.9.0 - Release Notes ## Multisig Setup File Import Import multisig wallets directly from vendor setup files via QR: - **Broad Vendor Support**: Parses multisig setup files (`Name:` / `Policy:` / `Derivation:` format) from Passport, Jade, Sparrow and ColdCard - **SLIP-132 Normalization**: Ypub/Zpub extended keys (and testnet variants) are automatically converted to standard xpubs - **Smart Name Pre-Fill**: Wallet names are pre-filled from setup file headers or QR transport metadata - **Improved BC-UR Decoding**: `UR:BYTES` payload support and wallet name extraction from `UR:OUTPUT-DESCRIPTOR` envelopes
More…
- **Unified Format Detection**: One import path now auto-detects setup files, BSMS records, and plain descriptors --- ## Security Hardening Upgrades to the credential and key-derivation architecture: - **Stronger Password KDF**: PBKDF2 iterations raised to 600,000 for newly created vaults - **Verifier-Only Storage**: Passwords are checked against domain-separated HKDF verifiers — the derived encryption key is never persisted to disk - **Dual-Clock Rate Limiting**: Login lockouts track both wall-clock and monotonic time, preventing lockout bypass via system clock manipulation - **Stricter Biometrics**: `BIOMETRIC_STRONG` (Class 3) enforced on Android 11+; biometric unlock is automatically disabled when it becomes stale after a password change - **Hardened Schnorr Signing**: BIP-340 signing now always mixes in 32 bytes of fresh `SecureRandom` auxiliary data, hardening nonces against side-channel attacks - **Safer Defaults**: "Save passphrase locally" is now OFF by default when creating a wallet - **Memory Safety**: Improved thread safety and atomicity in `SecureByteArray`, `SecureSeedCache`, and the password change flow --- ## Architecture Improvements Large-scale refactor of screens into MVVM with shared components: - **Session Orchestration**: New `AppSessionViewModel` handles session expiry, auto-open logic, and wallet key unloading — moved out of the navigation composable - **Dedicated ViewModels**: Stateless import and message signing flows migrated to `ImportStatelessViewModel` and `SignMessageViewModel` - **Unified Password Dialog**: New `VerifyPasswordDialog` replaces per-screen password checking across account details, settings, and export screens — verification always runs off the main thread - **Single-Pass Password Classification**: `SecureStorage.classifyPassword` identifies main vs. decoy vault passwords in one PBKDF2 pass instead of two - **Shared Wizard Steps**: Wallet configuration and BIP39 passphrase steps deduplicated across the Create, Import, and Stateless flows - **Centralized QR Export**: New `TapToCopyQRCard` component and `DescriptorQREncoder` utility standardize QR display and descriptor encoding across all export screens --- ## Additional Improvements ### UX - **Entropy Info Dialog**: Wallet creation now explains seed generation and system entropy usage - **Responsive Multisig Export**: Descriptor generation runs on a background thread with a progress indicator instead of blocking the UI - **Smoother Home Pager**: Removed custom fling/spring behavior in favor of default, more predictable paging - **Silent Payments**: Quick-action label corrected to singular "Address" for Silent Payment wallets ### Build & Dependencies - **Toolchain**: Gradle 9.6.1, Android Gradle Plugin 9.3.1, Kotlin 2.4.10 - **Libraries**: Compose BOM 2026.06.01, AndroidX Biometric 1.4.0-alpha07, Lifecycle 2.11.0, Core-KTX 1.19.0 ### Testing - **New Test Suites**: Vendor setup file parsing with cross-format address equivalence, descriptor format detection, QR transport unwrapping, pinned AES-GCM/HKDF-SHA256 compatibility vectors, and password hash verification --- ## Technical Details ### Key Files Modified **Multisig Setup File Import** - `ColdCardSetupFile.kt` - New parser for vendor setup files with SLIP-132 normalization - `MultisigDescriptorParser.kt` - Refactored into a format-detection router - `DescriptorQRScanner.kt` - `UR:BYTES` support and transport-embedded name extraction - `ImportMultisigViewModel.kt` - Wallet name pre-fill from setup file metadata **Security** - `KeyDerivation.kt` - New shared crypto utility (PBKDF2 → HKDF, AES-GCM) - `SecureStorage.kt` - Domain-separated HKDF verifiers, `classifyPassword` single-pass lookup - `LoginAttemptManager.kt` - Dual-clock (wall + monotonic) rate limiting - `BiometricAuthManager.kt` / `BiometricPasswordManager.kt` - STRONG biometric enforcement, stale credential invalidation - `Crypto.kt` - BIP-340 auxiliary randomness in Schnorr signing **Architecture** - `AppSessionViewModel.kt` - Session expiry, auto-open, and wallet loading orchestration - `ImportStatelessViewModel.kt` / `SignMessageViewModel.kt` - New ViewModels for stateless import and message signing - `WalletWizardSteps.kt` - Shared wallet configuration and passphrase wizard steps - `TapToCopyQRCard.kt` / `DescriptorQREncoder.kt` - Shared QR display component and centralized descriptor QR encoding - `VerifyPasswordDialog` (`SecurityDialogs.kt`) - Unified off-main-thread password verification **Full Changelog**: https://github.com/gorunjinian/MetroVault/compare/v3.8.7...v3.9.0