Updates, downloads and outside code
How to check that a download is the real one, how AirWallet controls the outside code it is built from, and how to update both devices safely.
A wallet can be attacked before you ever open it: through a swapped download, a tampered library, or a script slipped into a page. This page covers what AirWallet does about each, and what you can check yourself.
Check a download before you open it
Every release comes with a list of its files' SHA-256 checksums, SHA256SUMS.txt, signed with AirWallet's release key. Four files go with the downloads:
SHA256SUMS.txt, the listSHA256SUMS.txt.sig, its signatureRELEASE-SIGNING-KEY.txt, the public keyVERIFY.txt, these same steps
You need only ssh-keygen, which macOS, Linux and Windows 10 and 11 already have. Put the 4 files next to your download, then follow the 3 steps below.
1. Check the key
The release key's fingerprint is:
SHA256:SV031wxY3OKk8aYTY4a6b7UYa80onuXiDi0tFobgOFE
Also compare it with what the person who gave you the download told you some other way: in person, on a call, or in another app. A swapped file could come with a swapped key.
2. Check the list's signature
On a Mac or Linux, in Terminal:
ssh-keygen -Y verify -f RELEASE-SIGNING-KEY.txt -I airwallet-release -n airwallet-release -s SHA256SUMS.txt.sig < SHA256SUMS.txt
On Windows, in PowerShell:
Get-Content SHA256SUMS.txt -Raw | ssh-keygen -Y verify -f RELEASE-SIGNING-KEY.txt -I airwallet-release -n airwallet-release -s SHA256SUMS.txt.sig
It must say Good "airwallet-release" signature for airwallet-release with ED25519 key, followed by the fingerprint above.
3. Check your file is on the list
On a Mac or Linux:
shasum -a 256 -c SHA256SUMS.txt --ignore-missing
It must say OK next to your file. On Windows, run certutil -hashfile <the file> SHA256, then find that number in SHA256SUMS.txt.
What the signing tool refuses
The release tool signs with an Ed25519 key through ssh-keygen -Y sign, under the name airwallet-release, and checks its own signature before it writes VERIFY.txt. It refuses to sign when:
- the key does not match the published
RELEASE-SIGNING-KEY.txt - any file in the list is empty
- any file is more than 2 days older than the newest one, which usually means it was left over from an older build
What the operating systems check
The operating systems' own signatures help less for now:
- Mac: the app is sealed with its signature, but Apple has not notarized it yet
- Windows: the
.exeis not code-signed yet - Android: APKs are signed, and Android installs an update over the old app only if it has the same key
On Android, if the system asks you to uninstall the old app first, the new file is not ours: stop. See Install for the first-open steps on each system.
Builds are not reproducible yet
You cannot yet rebuild AirWallet from its source and get byte-identical files. The signed checksum list proves a file is the one that was signed, but not that it matches the published source. Reproducible builds and an F-Droid listing are on the to-do list.
Every piece of outside code is fingerprinted
AirWallet keeps one list of all the outside code its apps are built from, third_party.json in the source. Each entry records what the code is, its license, where it comes from and a fingerprint. A test, tests/test_third_party.py, checks every fingerprint. A new version, a different dependency or an edited file fails the test until a person has reviewed it and updated the list.
| Outside code | What it is for |
|---|---|
| Google's Brotli decoder, at a pinned commit, unchanged | Unpacking the Monero and Zcash engines |
| monero-ts 0.11.20 and its npm packages | Monero's own wallet library, as WebAssembly |
| Our rebuild of monero-ts for older web engines | Monero in the Android apps, from Android System WebView 74 |
| The Zcash engine's crates (librustzcash, orchard, sapling-crypto and others), one of them patched | The Zcash wallet, as WebAssembly |
| The Zcash prover's crates (Zakura) | Zcash's shielded proofs |
| The Monero vanity engine's crates, with a vendored curve25519-dalek | The desktop's Monero vanity search |
Python packages from requirements.txt (PyNaCl, base58 and the rest) | The desktop apps' Python code |
| Python runtimes (python-build-standalone, CPython 3.12.15) | The Python inside each desktop app |
| esbuild | Bundling the JavaScript (build tool, not shipped) |
| wasi-sdk, wasm-bindgen, binaryen | Building the Zcash WebAssembly (build tools, not shipped) |
| r8 and apksig, from Google's Maven | Building and signing the Android APKs (build tools, not shipped) |
| The AppImage runtime (AppImage/type2-runtime) | The start of every Linux AppImage |
Each is also checked where it is installed, and the test makes sure every crate, npm package and Python requirement keeps its hash:
- every downloaded tool has a pinned SHA-256, checked before the download is used
- JavaScript packages come from a lockfile with each package's hash (
npm ci, with install scripts turned off) - Rust crates are built with
cargo --locked, so each crate's checksum is checked - Python packages are installed with
--require-hashes, so a changed, missing or unpinned file stops the build
Nothing is downloaded and run later
Every engine ships inside the package, and the apps never fetch code while they run. The one thing fetched later is data. The first time you spend a Zcash Sapling coin or pay a Sapling address, the online app downloads Zcash's Sapling parameters, and checks their SHA-256 before it keeps them.
Pages run only their own scripts
Each AirWallet page tells the web engine exactly which scripts may run, by their SHA-256 fingerprints, through a Content-Security-Policy without unsafe-inline. Text that reaches the page any other way can never run as code. That includes a token's name, a transaction memo and an address book entry.
| Where | How the policy is set |
|---|---|
| Android apps | Written into the page when it is built |
| Desktop apps | Sent with the page by the app's local server, which fingerprints the page's scripts when it starts |
| airwallet.tech/online | Sent by the web server. The page's one inline script is listed by its fingerprint, and the Monero and Zcash engines are separate files from the same site. |
| Chrome extension | Only the extension's own script files run (script-src 'self'), with no inline script at all |
Web engines older than Chrome 97 can run WebAssembly only if the policy also allows unsafe-eval. AirWallet's Monero and Zcash engines are WebAssembly, so on those old engines, and only there, the page's policy includes it. AirWallet's code never evaluates text as code, and the list of scripts allowed to run stays the same.
AirWallet Online changes when the site changes
AirWallet Online is watch-only. It never holds a key and sends nothing to airwallet.tech. But the page itself comes from airwallet.tech, so a change to the site changes the page. If you want a copy that never changes under you, open its Settings, select Save this page, and open the saved file from your disk. The saved copy works for Bitcoin, Ethereum and Solana. Monero's and Zcash's engines are separate files, so they do not come with it.
Updating
You do not have to update both devices together. An offline device can stay on the version you installed while your everyday copy updates, and the other way round:
- newer copies keep making codes that older offline devices read, and every copy reads the codes and answers of every older one
- a newer copy may add something an older one cannot do; that one code says it was "made by a newer version of AirWallet", and everything else keeps working
- your offline device's watch code tells the everyday copy which version it runs; show it again after you update the offline device
Each release is kept and tested against later ones in both directions: the newer copy signing with the older one and the older with the newer, for Bitcoin, Ethereum and Solana. Monero and Zcash codes follow those coins' own wallet formats, so after one of their network upgrades both devices need the update.
Two things do need an update:
- a coin's network upgrade, when an older copy cannot make valid transactions under the new rules. AirWallet says so, and only that coin stops until you update.
- data or a backup saved by a newer version. An older copy will not open it, rather than misread it.
The everyday device
Install the new version over the old one. Your wallets, settings and app lock stay, because they live in the device's storage, not inside the app. On a Mac, for example, they are in ~/Library/Application Support/AirWallet.
For the Chrome extension, replace the contents of its folder with the new version's, then select the reload button (↻) on its card in chrome://extensions. Its data stays. Removing the extension from Chrome deletes its data, so keep your recovery phrases.
The offline device
The offline device cannot download anything, so you carry the update over yourself:
- Download the update on your online computer and check it there, as above. The app has no signature check of its own for update files yet.
- Copy it to the offline device by USB cable or SD card. Airplane mode can stay on.
- Install it over the old version.
Network upgrades
Sometimes a coin's network changes its rules, and an older signer can no longer make valid transactions. Zcash's NU7 upgrade is due around November 5, 2026. Monero's FCMP++ upgrade has no date yet. When a network moves to rules your copy does not know, AirWallet refuses to send and asks you to update both devices. See Clocks, old phones and other edge cases.
AirWallet