# Zcash Ledger App
We've done a lot of Ledger Nano apps but it is fair to say that the Zcash App is the most complex app till today. This project involves many challenges:
- Mixed C/Rust implementation
- Complex cryptography and workflow (sapling’s redjubjub)
- Rust/LLVM code and non-constant time operations in cortex-m0
- Sapling memory requirements
- Do not use in production. The app is not ready yet!
- Do not use a Ledger device with funds for development purposes.
- Have a separate and marked device that is used ONLY for development and testing
- The code is not optimized yet. Milestone 2 will bring a lot of implementation changes what we have been experimenting with
# Milestone 1
Prototype / research
- Basic APDU functionality and specs
- Basic project structure and continuous integration
- Initial RedJubJub support (address generation)
- Address Generation / HD support based on BIP32/44
- Secp256k1 signatures
- Basic user interface. On-screen review of transactions is not yet supported
Milestone 1 - Warnings
- The code is not production-ready. DO NOT USE!
- Some design decisions are still not final.
- The main challenge to overcome at this stage was call stack limitations and a working end-to-end shielded address generation process.
- The standard Rust-based JubJub crate is not hardware accelerated. We are currently working on a more efficient alternative.
We are glad to make public our milestone 1 submission.
This milestone required us to improved our internal tooling. At the same time we reach milestone 1, we are making available one of our internal tools Zemu to the open source community. We invite everyone to contribute with code and ideas.
So what did we do during this milestone?
# Development Process
Our development process has improved significantly over time, however, this project was not simple and required further improvements:
- Simplified project structure
- Mixed C / Rust project with adequate testing structure:
- C++ unit tests
- Rust unit tests
- Integration tests
- Ledger app debugging
- More about this in Zemu
- Continuous Integration (based on CircleCI)
- We have a clean configuration and infrastructure to run unit, integration and emulation tests on every change and PR.
- App test images
- Web wallet integration project, typically needs a pre-release app. While we have improved the process, not everyone want to go through the process.
- We get CircleCI to automatically release a
zxtool.shfile for each release. Third-parties can test wallet integrations without having to build themselves the app.
# Ledger App
- We provide a working z-address implementation that fits well within Ledger Nano S constraints. Bech32 encoding is ready and part of M1 deliverables.
- We provide a working t-address implementation. We have completed Base58Check encoding for secp256k1 addressed.
- We also provide an arbitrary example of secp256k1 signatures
- We have a design and prototype for ZIP32-based addresses that will be finalized as part of M2. More information about this in the following paragraphs.
Ledger BIP32 mnemonics, address recovery and future ZIP32 compatibility
Ledger does not have SDK support for ZIP32. In addition, a key feature of Ledger devices is that addresses are recoverable based on a mnemonic. This means that Zcash keys should be recoverable with only the device mnemonic. Storing app specific keys in memory is not a good idea.
To allow recoverability, we link the device mnemonic to shielded addresses seed by using Ed25519+BIP32 (Khovratovich, 2017) derivation, where we use a fixed, fully hardened BIP44 derivation path (
It is important to remember that Ed25519 private keys are expected to be "32 octets (256 bits, corresponding to b) of cryptographically secure random data.” ref We use this seed to feed a ZIP32 implementation (not delivered in this milestone). ZIP32 in turn generates the secret key we use generate shielded addresses.
With this approach we can:
- Migrate from a Ledger device to a standard ZIP32 wallet. The device can eventually show the ZIP32 seed.
- Extend existing wallets with BIP39 mnemonics. This only requires an additional step to go from mnemonic to ZIP32 seed.
- Provide recoverable addresses in Ledger devices that only support BIP39/BIP32/BIP44.
To clarify, in the deliverables of this milestone we go directly from BIP32 to addresses without passing through ZIP32. We are currently evaluating the approach and will incorporate ZIP32 as part of the workflow in the following weeks.
Zcash primitives & JubJub crate and our Zcash light implementation
We initially intended to use existing Zcash code to increase maintainability. After different tests, working on no_std support and memory benchmarking, we recognized two main issues:
- The zcash-primitives crate was too complex for the purpose of this project.
- Adequate HW acceleration was missing in the JubJub crate. At the moment, the JubJub crate is taking ~30 seconds to calculate an address.
For this reason, we have rewritten a minimal, very lean and memory efficient Rust implementation that allows generating shielded addresses within less that 2.8kB of RAM:
- We may eventually decouple and publish this Zcash light crate as an independent component. We believe that it can be useful in other memory constrained scenarios.
- We have plans for a more optimized JubJub implementation that will be made available during M2.
- We can analyze asm output to confirm that non-constant time opcodes exist in our binary output.
- As a safety net, we patch and redirect gnu eabi calls to avoid accidental use of MULS opcodes by LLVM generated code. We redirected this functions to Ledger's SDK math library.
# Third-party integration
- APDU Documentation
- We have documented the basic APDUs that the app provides. We have also analysed the legacy BTC-based app and planning to support a subset of the CLA=0xE0 for backwards compatibility purposes.
- We already provide an early JS integration library that will be later published in npm.
- Emulation tests already use this JS library to minimize future integration problems.
# Zemu Framework
Integration and end-to-end testing of Ledger Apps is a manual and time consuming process. The Ledger apps ecosystem is lacking an adequate approach with respect to testing until today.
The Zemu Framework is our solution to this problem. We stand on the shoulders of the giant greenknot’s speculos and we provide a simple to use npm package that abstracts away app testing.
- Compatible with continuous integration (examples for CircleCI)
- Easy JS API (Mocha / Jest compatible)
- Device screenshots and UI checks with images.
- Abstracted device control (buttons, reset, etc.) directly in JS
- Seed testing
- Test isolation. Each simulation is indepedent.
- Easy app debugging (including mixed c/rust code)
- CLion and vscode configuration for app debugging.
- Minimal configuration + Docker based
You can find instructions here:
# Milestone 2
What is planned
- Initial transaction content review
- Improved RedJubJub implementation and support
- Sapling v4 transaction deserialization
- Reference Rust library + integrations test and examples
# Milestone 3
What is planned
- Complete sapling support
- Complete tx review in UI (for shielded and unshielded addresses)
- Complete integration tests (libraries)