Hey everyone,
I’m wh00hw, a blockchain developer. I’ve spent most of my career working on cross-chain protocols integrations, but I actually started out studying embedded systems and robotics.
I’ve been in Zcash since launch, and cybersecurity has always been a passion of mine. The hardware wallet landscape for shielded Zcash has always been pour. So I thought: let me see if I can build an Orchard wallet on a Flipper Zero, with the help of Claude as my coding partner.
FlipZcash - Zcash Wallet on an ARM Cortex-M4 at 64 MHz with 256 KB of RAM, 4 KB of stack
The challenge was that “none” (read until the end) of the Orchard primitives existed in C for embedded targets. The entire Zcash Orchard stack (librustzcash) is written in Rust and requires gigabytes of RAM for proof generation. So I had to implement everything from scratch in C:
-
Pallas elliptic curve arithmetic — custom 254-bit field math with constant-time Montgomery ladder
-
Sinsemilla hash — the most painful one: ~51 iterations of GroupHash, 12+ minutes on first run at 64 MHz. I built a checkpoint system and a precomputed lookup table to make it survivable
-
FF1-AES-256 — format-preserving encryption for diversifier derivation
-
F4Jumble + Bech32m — for ZIP-316 Unified Address encoding
-
RedPallas signatures — Schnorr-style spend authorization (~5 seconds per signature)
-
Full ZIP-32 key derivation from BIP-39 seed
Once it worked, I split the project into proper deliverables
1. libzcash-orchard-c — Portable Embedded Zcash Library
The extracted cryptographic core. Pure C11, no OS calls, runs on bare metal.
-
Full ZIP-32 Orchard key derivation
-
Pallas curve arithmetic with constant-time operations
-
Sinsemilla hash with 3 acceleration strategies (compute on-the-fly / embed in flash / load from SD)
-
RedPallas signatures, FF1-AES-256, F4Jumble, Bech32m
For the lower-level primitives — bignum arithmetic, BIP-39, SHA-2, HMAC, PBKDF2, and RNG — I pulled in well-tested code from trezor-crypto rather than rolling my own. No reason to rewrite what Trezor has already battle-tested across millions of devices.
Everything Orchard-specific — Pallas field math, Sinsemilla, RedPallas, FF1, F4Jumble, ZIP-32 derivation — is original, written from scratch because no C implementation existed for embedded targets.
To be fair, I later discovered that zcash-ledger by hanh already implements Pallas arithmetic and Orchard signing in C for the Ledger Nano. So I didn’t invent something entirely new — but I don’t think I reinvented the wheel either because zcash-ledger is tightly coupled to Ledger’s secure element and proprietary SDK.
This library is portable and standalone. It compiles on any MCU with a C11 compiler: ESP32, STM32, RISC-V, Flipper Zero. It’s focused exclusively on Orchard and designed as an SDK that any hardware vendor can drop into their firmware. It also integrates with the PCZT standard, meaning any companion wallet that speaks PCZT can work with it — you’re not locked into one manufacturer’s protocol.
2. zcash-hw-wallet-sdk — Rust SDK for Companion Apps
A transport-agnostic Rust SDK (~3,100 LOC) that handles the companion-app side of hardware wallet signing. It speaks the HWP v2 binary protocol over USB serial or QR codes, manages PCZT (Partially Created Zcash Transaction) flows, and integrates with librustzcash for proof generation.
Any wallet app can use this SDK to add hardware wallet support without understanding the low-level protocol.
3. zipher-cli – the companion app
So I forked zipher-cli by Atmosphere Labs (CipherPay), which already had a solid Rust engine built on librustzcash with light client sync, and integrated my zcash-hw-wallet-sdk into it. That gave me a working desktop wallet with hardware wallet signing support without reinventing the wheel on the wallet side.
4. FlipZcash — The Flipper Zero Zcash Wallet
The full application that ties it all together on the Flipper:
-
BIP-39 mnemonic generation (12/18/24 words) with passphrase
-
Unified Address display with QR codes
-
Encrypted wallet storage on SD card
-
Delegated signing: the spending key (
ask) never leaves the device. The companion app generates Halo2 proofs (too heavy for 256 KB RAM), sends just the sighash, and FlipZcash signs it.How the signing flow works
zipher-cli (desktop) FlipZ (Flipper Zero) ───────────────── ──────────────────── 1. Sync chain via FVK (view-only) 2. User: "send 0.001 ZEC to u1..." 3. Build PCZT, generate Halo2 proof 4. Send sighash + randomizer ──────→ 5. Display tx on screen 6. User presses button 7. Compute RedPallas sig (~5s) ←────── 8. Return signature 9. Inject sig, broadcast tx Spending key never left device ✓
5. zcash-hw-wallet-esp32 — ESP32 Reference Implementation
A reference port of libzcash-orchard-c to ESP32-S2, proving the library works beyond Flipper Zero. The ESP32 is cheaper, more accessible, and could be the basis for a dedicated Zcash signing device.
Where I’d love this to go
I’ll be honest about what this is and what it isn’t.
What it is: a working proof of concept that Zcash Orchard shielded signing is achievable on constrained embedded hardware, with a clean separation between portable library, protocol SDK, and application layer.
What it isn’t (yet): production-hardened, audited code. The C crypto implementations are carefully written with constant-time operations, but they need professional eyes on them.
My hope is that libzcash-orchard-c + zcash-hw-wallet-sdk could become a standard that hardware wallet vendors adopt to integrate Zcash Orchard support into their products. The same library could power signing in apps like Zodl or other wallets through the companion SDK. The building blocks are all there — they just need to be polished and verified.
To get there, I’d love to secure a grant that would allow me to:
-
Commission an independent security audit of the C cryptographic implementations — this is the single most important step before anyone should trust this in production
-
Harden the serial protocol and add multi-action transaction support
-
Write comprehensive documentation and integration guides for hardware vendors
-
Publish on the Flipper App Store and build multi-platform companion binaries
-
Maintain the ecosystem long-term
If you’re interested in the technical details, everything is open source:
-
libzcash-orchard-c: GitHub
-
zcash-hw-wallet-sdk: GitHub
-
zipher-cli (fork): GitHub
-
FlipZcash: GitHub
-
zcash-hw-wallet-esp32: GitHub
I’d really appreciate any feedback.
Thanks for reading!
— wh00hw
EDIT: Following hanh’s feedback — which I completely agree with — I’ve implemented on-device ZIP-244 sighash verification. The device no longer blindly signs whatever sighash the companion sends.
The signing flow now works as a staged verification protocol (HWP v2):
-
The companion sends transaction metadata (version, branch ID, lock time, orchard flags, value balance, anchor, transparent/sapling digests — 125 bytes)
-
The companion sends each Orchard action individually (cv_net, nullifier, rk, cmx, ephemeral_key, enc_ciphertext, out_ciphertext — 820 bytes per action)
-
The companion sends the expected sighash as a sentinel
-
The device independently computes the ZIP-244 sighash from all the data it received and compares it against the companion’s. If they don’t match →
SIGHASH_MISMATCHerror, signing refused -
Only after successful verification does the device allow
SIGN_REQto proceed
This is enforced at the library level: OrchardSignerCtx in libzcash-orchard-c is a state machine that makes it impossible to call sign() without completing ZIP-244 verification first. The firmware cannot bypass this invariant — it’s a compile-time guarantee, not a runtime check.
The approach is inspired by zcash-ledger’s staged verification, adapted for the HWP serial protocol. The transparent and sapling digests are still provided by the companion (since the device only has access to Orchard data), but the full orchard digest is computed on-device from the raw action data.