# 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 was planned
- Initial transaction content review
- Improved RedJubJub implementation and support
- Sapling v4 transaction deserialization
- Reference Rust library + integrations test and examples
Milestone 2 has been challenging. Having less than 3KB of RAM is not easy 😃
We are happy to announce that we have managed to successfully fit all the functionality in the very limited amount of available memory. All the building blocks are now there! We expect the follow up work to be easier now!
Milestone 2 is a very technical release, where we have focused on developing and testing all the necessary building blocks. We slightly shifted priorities to concentrate on the most critical areas such as Pedersen commitments and Key agreement. At this point, we are happy that we can ensure we can run everything in such a limited amount of memory ( A Ledger Nano S with 2820 bytes of available RAM ).
# Parsing and user interface
Unshielded Transaction Parsing + Signing
- It is already possible to review and sign unshielded transactions.
Shielded Transaction Parsing
- Parsing for shielded transactions is almost ready, however, we still need to bind the user interface to note decryption (ChaChaPoly1305).
# Cryptographic Building Blocks
- We have designed a hybrid approach that combines standard BIP39/BIP32 with ZIP32. This means that it should be possible to migrate away from Ledger devices to other wallets by exposing a ZIP32 seeds in the device screen.
- Due to memory constraints, it was necessary to completely reimplement Pedersen commitments in a very optimized and memory efficient approach. We are very happy it works so well now!
- Support for JubJub key agreement is ready. Our next step is to integrate with note encryption/decryption for full support of incoming/outgoing transactions.
Value/note commitments and computing nullifiers
- Support for note and value commitments, as well as computing note nullifiers, is ready.
- Chacha20Poly1305 encryption and decryption is now integrated. Our next step is to connect to thethe UI so notes can be decrypted and shown in the device screen.
In this milestone, we are also making public two integration libraries:
- Js Library + integration tests npm
- Basic Rust Library + integration tests
We will soon publish them as packages (npm and rust crate) to facilitate third-party integration into web and desktop wallets.
In the following weeks, the collaboration with the ZecWallet team starts. We expect that all the elements required for Ledger support will be ready by the time we close Milestone 3.
# Milestone 3
What is planned
- Complete sapling support
- Complete tx review in UI (for shielded and unshielded addresses)
- Complete integration tests (libraries)