Security in a cryptocurrency wallet is not one feature. It is a chain of controls covering randomness, key storage, transaction construction, user authorization, network data, backups, token protocols, and external applications.

Kaspire is designed around one central rule:

Core principleNetwork services may provide data, but they are never trusted to decide what the wallet signs.

Instead, sensitive operations are kept inside Android’s native security boundary and Kaspire’s pinned Rust signing core. This post explains the protections currently implemented in Kaspire and how they work.

01

Secure seed generation

New Kaspire wallets use 24-word English BIP-39 recovery phrases.

A 24-word phrase represents 256 bits of entropy plus the BIP-39 checksum. The entropy is generated inside the native Rust core using a cryptographically secure random-number generator.

On Android, Rust obtains its randomness through the operating system’s secure random source. Kaspire does not generate wallets with timestamps, application-level pseudo-random generators, device identifiers, or other predictable values.

Before a newly generated wallet is stored, Kaspire requires the user to verify randomly selected recovery words. This reduces the risk of creating a wallet without first confirming that the recovery phrase was recorded.

Sensitive recovery screens use Android’s FLAG_SECURE, which prevents normal screenshots and recent-app previews.

02

BIP-39 passphrase support

Kaspire supports an optional BIP-39 passphrase, sometimes called the “25th word.”

The passphrase is not simply an extra password protecting the same wallet. It becomes part of the BIP-39 seed derivation and therefore creates an entirely different wallet.

Kaspire uses the standard BIP-39 derivation:

  • PBKDF2-HMAC-SHA512
  • 2,048 iterations
  • The mnemonic as the input
  • "mnemonic" + passphrase as the salt

Capitalization, spaces, and every character matter. A different passphrase produces a different wallet, while losing the passphrase makes the corresponding wallet unrecoverable from the recovery words alone.

Kaspire therefore requires explicit acknowledgement that the passphrase has been backed up separately.

The 2,048-iteration parameter is part of the BIP-39 standard. It should not be confused with Kaspire’s stronger Argon2id protection for encrypted backup files.

03

Modern and legacy HD derivation

Kaspire uses BIP-44 hierarchical deterministic derivation.

The modern Kaspa path is:

m/44'/111111'/account'/change/index

The first address of the first account is:

m/44'/111111'/0'/0/0

For compatibility with older Kaspa wallets, Kaspire also recognizes the legacy coin type:

m/44'/972'/account'/change/index

During mnemonic import, Kaspire scans both the modern and legacy coin types. It checks receive and change branches, uses a gap limit, and proceeds through accounts until it reaches the first unused account.

This allows funds created by older Kaspa web wallets to be discovered without changing the seed.

Accounts and address-index subwallets are separate levels of the path. For example, m/44'/111111'/0'/0/1 is Subwallet 1 inside Account 0, while m/44'/111111'/1'/0/0 is the first receive address of a separate Account 1.

Kaspire displays discovered receive indices independently and can create the next KasWare-compatible subwallet without confusing it with a new BIP-44 account.

04

Multiple accounts under one seed

Kaspire supports multiple BIP-44 accounts under the same recovery phrase.

For example:

m/44'/111111'/0'/0/0m/44'/111111'/1'/0/0m/44'/111111'/2'/0/0

Accounts can be selected independently in the wallet manager. Kaspire’s Rust core can derive account numbers from 0 through 100.

Before Android registers a derived address, it asks the Rust core to derive that address again from the encrypted wallet secret. The supplied path and resulting address must match. This prevents manipulated application data from registering an address that the seed does not control.

When signing, Kaspire selects the derivation path associated with the exact sender address. Switching the visible account cannot silently cause another account’s key to sign a transaction.

Kaspire also supports multiple completely separate signing wallets, each with its own seed or imported private key.

05

Seed encryption at rest

Wallet secrets are not stored as plaintext.

Each signing wallet is encrypted with:

  • AES-256-GCM
  • A unique randomized initialization vector
  • A non-exportable key generated by Android Keystore

On Android 9 and newer, Kaspire first attempts to generate the encryption key inside StrongBox. If StrongBox is unavailable, it falls back to the device’s supported Android Keystore implementation, which may use a Trusted Execution Environment.

The AES key is not derived from the application PIN and is not stored in application preferences. The Android Keystore controls access to it.

AES-GCM provides both confidentiality and authentication. Modification of encrypted seed data causes decryption to fail instead of producing a silently corrupted wallet.

Users can inspect whether the active device reports the key as hardware-backed.

06

Native security boundary

Recovery phrases and private keys are kept out of Flutter’s Dart layer, JavaScript, WebViews, analytics, and the clipboard.

Wallet creation, import, encrypted storage, seed decryption, HD derivation, transaction signing, and secret export are handled by Android’s native layer and the Rust core.

Derived public addresses and transaction-review data may be returned to Flutter because they are not secret.

Rust uses zeroizing containers for sensitive key and seed buffers. These buffers are overwritten when they leave scope.

One important technical limitation should be stated clearly: JNI requires some sensitive values to cross the Android native/Rust boundary as JVM strings during authorized operations. Java strings cannot be reliably overwritten. Kaspire limits their lifetime and never returns them to Dart, but this is not equivalent to keeping every decrypted byte exclusively in zeroizable native memory.

07

Biometric and PIN authorization

Every value-moving action requires fresh authorization.

This includes:

  • Sending KAS
  • Sending KRC-20 tokens
  • Sending KRC-721 NFTs
  • KNS operations
  • Sending KCC20 covenant tokens
  • UTXO compounding
  • Wallet import and export
  • Recovery phrase or private-key export
  • Wallet deletion
  • WalletConnect payments
  • WalletConnect personal-message signatures

Connecting a dApp does not authorize future transactions. Every signing request receives a separate review and biometric or PIN prompt.

Kaspire supports Android biometrics and an optional 4–8 digit application PIN.

The PIN verifier uses:

  • PBKDF2-HMAC-SHA256
  • A random salt
  • 210,000 iterations
  • A 256-bit derived verifier

The PIN does not directly encrypt the seed. Seed encryption remains protected by the Android Keystore.

After repeated incorrect PIN entries, Kaspire applies an escalating temporary lockout. This limits rapid online guessing through the application interface.

08

Transaction reconstruction in Rust

Kaspire does not ask a server to return a transaction and then blindly sign it.

The wallet retrieves UTXO information, treats that response as untrusted, and passes it to the pinned Rust core. The core verifies that every spendable UTXO:

  • Belongs to the expected sender
  • Contains the expected sender script
  • Has a valid transaction ID and output index
  • Has a valid amount
  • Is not a rejected coinbase input
  • Matches the expected Kaspa Mainnet address type

The Rust core then independently constructs the transaction, selects inputs, creates outputs and change, calculates transaction mass, derives the required fee, and generates the canonical signing payload.

The server does not choose the final recipient output, change output, fee, or signed transaction.

09

Review-hash binding

Preparing and signing a transaction are separate operations.

During preparation, the Rust core produces a review containing security-relevant information such as:

  • Network
  • Sender and recipient
  • Amount
  • Total input value
  • Change
  • Network fee
  • Transaction mass
  • Input outpoints
  • Output scripts
  • Payload
  • Token or covenant-specific state

The core serializes this canonical review and calculates a SHA-256 review hash.

When the user approves the transaction, the exact request and approved review hash are sent back to the signer. The Rust core reconstructs the transaction and refuses to sign if the hash differs.

This prevents application state, network responses, fees, outputs, or token parameters from being changed between review and signature.

10

Local transaction-ID verification

After signing, Kaspire calculates the transaction ID locally.

When the transaction is broadcast, the node must return the same transaction ID. A missing or mismatching result is treated as an error.

This protects against a transport or gateway claiming that a different transaction was submitted.

11

Watch-only isolation

Watch-only wallets can display balances and activity but cannot sign.

Before a payment, token transfer, message signature, or UTXO compound operation, Kaspire verifies that an encrypted native wallet controls the exact sender address.

A watch-only address cannot silently fall back to another stored signing wallet.

12

UTXO compounding safety

Kaspire can consolidate fragmented KAS UTXOs by creating a transaction that sends selected funds back to the same wallet address.

The compound flow:

  1. Loads the current UTXO set.
  2. Selects up to 80 inputs.
  3. Constructs a self-transfer in the Rust core.
  4. Calculates mass and fees locally.
  5. Shows the number of inputs, resulting output, and exact fee.
  6. Requires biometric or PIN authorization.
  7. Verifies the returned broadcast transaction ID.

For very large UTXO sets, multiple bounded compound operations are required instead of constructing an excessively large transaction.

13

KRC-20, KRC-721, and KNS commit/reveal protection

Kasplex-style operations use commit/reveal transactions.

Kaspire constructs the canonical protocol payload locally. Commit and reveal are reviewed separately and require explicit authorization.

The reveal transaction is bound to the expected commit address, script, amount, and outpoint. If the reveal cannot complete immediately, Kaspire records the pending operation for recovery rather than hiding the incomplete state.

Broadcast transaction IDs must match the locally generated IDs for both stages.

14

Typed KCC20 covenant signing

KCC20 transactions require more extensive validation than ordinary transfers.

Kaspire does not provide a generic “sign any covenant” interface. It supports one typed KCC20 transfer path.

Before signing, Kaspire requires:

  • A Kascov verified token status
  • A complete mapping of live token cells
  • A known covenant identifier
  • A matching audited template
  • A valid P2PK sender and recipient
  • Valid token amounts
  • Valid current state ownership
  • Sufficient mass-safe KAS funding

The Rust core recompiles the vendored SilverScript KCC20 template and reconstructs current and future covenant states.

It independently enforces:

  • Token-supply conservation
  • Total transaction-value conservation
  • Ownership transitions
  • Covenant reserve handling
  • Separate accounting for token quantity and locked KAS
  • Sender change for partial transfers
  • Mass and compute limits
  • Exact Toccata fee rules
  • Local script execution for every signed input

Unknown templates, unknown payloads, minter cells, generic covenant requests, coinbase inputs, incomplete lineage, and unsafe mass candidates are rejected.

Kascov preflight results are treated as advisory diagnostics. They do not replace local validation. The final signed KCC20 transaction is broadcast through a Toccata-compatible node transport that preserves the compute budget, and the returned ID must match the locally signed transaction.

15

WalletConnect isolation

Kaspire uses WalletConnect v2 with a proprietary, versioned Kaspa namespace because Kaspa does not currently have an official WalletConnect namespace.

Only explicitly supported methods are advertised. Unknown methods are rejected.

Supported operations include account retrieval, KIP-5 personal signing, KAS payments, and typed KRC20/KCC20 transfers.

Security properties include:

  • Mainnet-only chain validation
  • Encrypted WalletConnect sessions
  • One-time pairing topics
  • Pairing URIs kept in memory instead of persistent storage
  • Pairing secrets redacted from errors
  • No transaction result returned through an arbitrary callback URL
  • Separate authorization for every signature or payment
  • Exact matching between the approved session account and signing wallet
  • Rejection of watch-only session accounts
  • Rejection of WalletConnect v1 and unknown pairing fields

Android App Links verify the association with Kaspire’s HTTPS domain before routing a pairing link into the application.

Human-readable dApp metadata is never considered proof of transaction contents. The Rust-generated transaction review remains authoritative.

16

Secure personal-message signing

Personal signatures follow Kaspa’s KIP-5 message-signing format.

Kaspire verifies that the selected encrypted wallet controls the requested address and requires fresh biometric or PIN approval.

A dApp cannot use the message-signing endpoint to request an arbitrary transaction signature.

17

Encrypted portable backups

Current Kaspire releases create kaspire-backup-v2 backups.

The backup contains the encrypted wallet secret, registered HD addresses, derivation metadata, and integrity-protected wallet information.

The backup password is processed with Argon2id v1.3 using:

  • 32 MiB of memory
  • Three iterations
  • Parallelism of one
  • A random 32-byte salt
  • A 256-bit output key

The resulting key encrypts the backup with AES-256-GCM.

Argon2id is memory-hard. Each password guess requires not only computation but also a significant amount of memory, making large GPU and ASIC guessing attacks more expensive than a simple hash loop.

The relatively small iteration number must not be compared directly with PBKDF2’s iteration count. Each Argon2id iteration processes the configured memory region.

Kaspire continues to import the older kaspire-backup-v1 format, which uses PBKDF2-HMAC-SHA256 with 600,000 iterations. New exports use Argon2id.

During restoration, Kaspire verifies:

  • Backup format
  • KDF identifier
  • Exact supported KDF parameters
  • Salt length
  • AES-GCM authentication tag
  • Recovered wallet address
  • Every stored HD derivation path and address

A manipulated backup therefore fails restoration instead of registering unverified addresses.

No password-strengthening algorithm can compensate for a weak password. A long, unique passphrase—preferably several randomly selected words—is still essential.

18

Screen and clipboard protections

Screens that display recovery phrases, private keys, backup material, PIN entry, or other sensitive information use Android’s secure-window protection.

Kaspire does not automatically copy recovery phrases or private keys to the clipboard.

Public addresses and transaction IDs can be copied explicitly because they are not secret.

19

Network security and local infrastructure

Kaspire uses HTTPS endpoints and defaults to the Kaspire-operated Kaspa gateway backed by its own pruned node and local indexer infrastructure.

Network timeouts are applied so stalled services do not leave sensitive operations indefinitely pending.

However, HTTPS and self-operated infrastructure do not make RPC data trusted. UTXO and transaction information is still validated locally before signing.

20

Pinned native signing code

The signing core is compiled into the Android application for ARM64 and ARMv7.

It is pinned to Rusty Kaspa v2.0.1 and reproducibly locked dependencies. Signing logic cannot be replaced through an over-the-air web update.

The APK includes the same native security logic that was reviewed and built for that release.

21

Security as a system

Kaspire’s security model combines multiple layers:

  • OS-backed generation of 256-bit seed entropy
  • BIP-39 recovery phrases and optional passphrases
  • Modern and legacy BIP-44 discovery
  • Multiple isolated accounts and wallets
  • Android Keystore and StrongBox-backed AES-256-GCM storage
  • Biometric or throttled PIN authorization
  • Native Rust transaction construction
  • Strict UTXO and sender-script validation
  • Review-hash binding
  • Local transaction-ID verification
  • Typed token and covenant signers
  • Encrypted WalletConnect sessions
  • Argon2id-protected portable backups
  • Fail-closed handling of unsupported operations

No single layer is expected to carry the entire security burden. Network data is treated as untrusted, dApp sessions receive limited authority, signing is bound to what the user reviewed, and encrypted wallet material remains separated from the Flutter interface.

That layered approach is the foundation of Kaspire’s security architecture—and the basis for the further audits and hardening required before describing it as fully production-assured.