Architecture

Wallet Architecture

The Morana wallet is built with Rust and Tauri and runs on Linux, Windows, macOS, Android and iPhone. All versions share a Rust core; each platform has its own build. The interface is available in 16 languages. Keys are created and stored only on the device; transactions, private ones included, are assembled locally without calling a node. The code is split into Rust packages called crates.

Crates

  • wallet-crypto — keys and signatures. Public addresses: a 24-word phrase (BIP39) → BIP84, P2WPKH. Private: ZIP-32 from the same phrase. It also holds the Groth16 prover and the Sapling parameters included in the build.
  • morana-address — public, private and unified addresses.
  • wallet-storage — the encrypted database with addresses, outputs, transactions and sync state.
  • wallet-core — wallet logic: syncing, balances and transfer preparation. The app’s interface accesses it through Tauri commands.
  • lightd-client — the client for the morana-lightd gateway, the server the wallet uses to read the blockchain.

Two kinds of transactions

Morana is a fork of Bitcoin Core 31.1. SegWit is active from the first block. Transactions can contain public inputs and outputs alongside a Sapling shielded component.

  • A public transaction works as in Bitcoin: SegWit v0, P2WPKH, BIP143 signatures.
  • A transaction with a private part carries a Sapling bundle in the same transaction. Its public inputs are signed under ZIP-243 (SIGHASH_ALL only), private spends carry their own signatures, and the whole private part is covered by a binding signature.

Storage

The database is encrypted with SQLCipher. Its key is derived from your password using Argon2id; a newly created vault uses 19 MiB of memory, 2 passes and p = 1. Each vault stores its own KDF parameters. The recovery phrase has an additional layer of XChaCha20-Poly1305 encryption. File access is restricted to your operating-system account, and writes are atomic. The database is bound to its network: a testnet wallet cannot be switched to mainnet.

Backup

A .morbak backup contains an encrypted database snapshot bound to its network. MORBAK04 uses XChaCha20-Poly1305, with a key derived from the wallet password using Argon2id (256 MiB of memory, 4 passes, p = 1). Only the metadata needed to read the file remains unencrypted. The backup contains no recovery phrase or private keys. Restore the wallet with the same 24 words before importing it. See Backup.

Sync

The wallet reads the chain through the morana-lightd gateway and checks what the gateway serves.

  • Private funds: compact blocks in pages of 100; headers are verified from the built-in first block (genesis); the wallet can roll back its state for chain reorganizations up to 100 blocks deep; Sapling witnesses (the data needed to spend a private coin) are computed on the device. The gateway cannot decrypt your private coins (notes).
  • Public funds: history in pages of 500 rows and a list of outputs per address. This way the gateway learns your public addresses. The more private option is block-filter sync (BIP157/158), which does not reveal addresses.

Sending

Sending takes three steps: prepare → review → send. A prepared transfer can be sent once within a limited time. If the data it relies on changes, the wallet asks you to prepare it again.

The fee for a public transfer depends on transaction size (1 atom per virtual byte by default). Private operations cost more; the wallet shows the fee before you send.

“Sent” means the gateway has acknowledged the transaction. Inclusion in a block is confirmed separately.